Skip to content
Snippets Groups Projects
Verified Commit 75f43c3a authored by Dominik František Bučík's avatar Dominik František Bučík
Browse files

feat: :guitar: Displaying statistics

parent ee29b35d
No related branches found
No related tags found
1 merge request!26feat: 🎸 Displaying statistics
Showing
with 1398 additions and 243 deletions
...@@ -12,14 +12,20 @@ ...@@ -12,14 +12,20 @@
{ {
"name": "Michal Prochazka", "name": "Michal Prochazka",
"email": "michalp@ics.muni.cz" "email": "michalp@ics.muni.cz"
},
{
"name": "Dominik Frantisek Bucik",
"email": "bucik@ics.muni.cz"
} }
], ],
"require": { "require": {
"simplesamlphp/composer-module-installer": "~1.0", "simplesamlphp/composer-module-installer": "~1.0",
"simplesamlphp/simplesamlphp": "~v1.19.0", "simplesamlphp/simplesamlphp": "~v1.19.0",
"cesnet/simplesamlphp-module-perun": "^v7.2.0", "cesnet/simplesamlphp-module-perun": "^v7.2.0",
"cesnet/simplesamlphp-module-proxystatistics": "^v7.0.2",
"ext-json": "*", "ext-json": "*",
"ext-curl": "*" "ext-curl": "*",
"ext-pdo": "*"
}, },
"require-dev": { "require-dev": {
"symplify/easy-coding-standard": "^9.4" "symplify/easy-coding-standard": "^9.4"
......
This diff is collapsed.
<?php declare(strict_types=1);
namespace SimpleSAML\Module\elixir\stats;
use SimpleSAML\Auth\Simple;
use SimpleSAML\Configuration;
use SimpleSAML\Logger;
use SimpleSAML\Module;
use SimpleSAML\Module\proxystatistics\Config;
use SimpleSAML\Module\proxystatistics\DatabaseCommand;
use SimpleSAML\XHTML\Template;
class Templates
{
private const INSTANCE_NAME = 'instance_name';
public static function showProviders($side, $tab)
{
assert(in_array($side, ['identity', 'service'], true));
$t = new Template(Configuration::getInstance(), 'proxystatistics:providers-tpl.php');
$t->data['side'] = $side;
$t->data['tab'] = $tab;
$t->show();
}
public static function pieChart($id)
{
?>
<!-- <canvas id="--><?php //echo $id; ?><!--" class="pieChart chart---><?php //echo $id; ?><!--"></canvas>-->
<div class="pie-chart-container row">
<div class="canvas-container">
<canvas id="<?php echo $id; ?>" class="pieChart chart-<?php echo $id; ?>"></canvas>
</div>
</div>
<?php
}
public static function timeRange($vars = [])
{
$t = new Template(Configuration::getInstance(), 'proxystatistics:timeRange-tpl.php');
$t->data['lastDays'] = self::getSelectedTimeRange();
foreach ($vars as $var => $value) {
$t->data[$var] = $value;
}
$t->show();
}
public static function loginsDashboard()
{
$t = new Template(Configuration::getInstance(), 'proxystatistics:loginsDashboard-tpl.php');
$t->show();
}
public static function showDetail($side)
{
$t = new Template(Configuration::getInstance(), 'proxystatistics:detail-tpl.php');
$lastDays = self::getSelectedTimeRange();
$id = filter_input(INPUT_GET, 'id', FILTER_VALIDATE_INT, [
'options' => [
'min_range' => 0,
],
]);
$t->data['id'] = $id;
$t->data['detailGraphClass'] = '';
if (Config::getInstance()->getMode() === Utils::theOther(Config::SIDES, $side)) {
$t->data['detailGraphClass'] = 'hidden';
}
self::loadIncludes($t);
$dbCmd = new DatabaseCommand();
$t->data['head'] .= Utils::metaData(
'loginCountPerDay',
$dbCmd->getLoginCountPerDay($lastDays, [
$side => $id,
])
);
$t->data['head'] .= Utils::metaData(
'accessCounts',
$dbCmd->getAccessCount(Utils::theOther(Config::SIDES, $side), $lastDays, [
$side => $id,
])
);
$translations = [
'count' => $t->t('{proxystatistics:stats:count}'),
'other' => $t->t('{proxystatistics:stats:other}'),
'of_logins' => $t->t('{proxystatistics:stats:of_logins}'),
'of_users' => $t->t('{proxystatistics:stats:of_users}'),
];
foreach (Config::SIDES as $s) {
$translations['tables_' . $s] = $t->t('{proxystatistics:stats:side_' . $s . '}');
}
$t->data['head'] .= Utils::metaData('translations', $translations);
$name = $dbCmd->getNameById($side, $id);
$t->data['header'] = $t->t('{proxystatistics:stats:' . $side . 'Detail_header_name}') . $name;
$t->data['side'] = $side;
$t->data['other_side'] = Utils::theOther(Config::SIDES, $side);
$t->show();
}
public static function showIndex()
{
$config = Config::getInstance();
$authSource = $config->getRequiredAuthSource();
if ($authSource) {
$as = new Simple($authSource);
$as->requireAuth();
}
$t = new Template(Configuration::getInstance(), 'proxystatistics:index-tpl.php');
$lastDays = self::getSelectedTimeRange();
$t->data['tab'] = filter_input(
INPUT_GET,
'tab',
FILTER_VALIDATE_INT,
[
'options' => [
'default' => 0,
'min_range' => 0,
'max_range' => 2,
],
]
); // indexed from 0
$t->data['tabsAttributes'] = [
'PROXY' => 'id="tab-1" href="' . Module::getModuleURL('elixir/summary.php') . '?lastDays=' . $lastDays . '"',
'IDP' => 'id="tab-2" href="' . Module::getModuleURL('elixir/identityProviders.php') . '?lastDays=' . $lastDays . '"',
'SP' => 'id="tab-3" href="' . Module::getModuleURL('elixir/serviceProviders.php') . '?lastDays=' . $lastDays . '"',
];
$mode = $config->getMode();
if (Config::MODE_PROXY !== $mode) {
$t->data['tabsAttributes'][$mode] = 'class="hidden" ' . $t->data['tabsAttributes'][$mode];
}
$t->data['header'] = $t->t('{proxystatistics:stats:statistics_header}');
$instanceName = Configuration::getInstance()->getString(self::INSTANCE_NAME, null);
if (null !== $instanceName) {
$t->data['header'] = $instanceName . ' ' . $t->data['header'];
} else {
Logger::warning('Missing configuration: config.php - instance_name is not set.');
}
self::loadIncludes($t);
$dbCmd = new DatabaseCommand();
$t->data['head'] .= Utils::metaData('loginCountPerDay', $dbCmd->getLoginCountPerDay($lastDays));
$translations = [
'count' => $t->t('{proxystatistics:stats:count}'),
'other' => $t->t('{proxystatistics:stats:other}'),
'of_logins' => $t->t('{proxystatistics:stats:of_logins}'),
'of_users' => $t->t('{proxystatistics:stats:of_users}'),
];
foreach (Config::SIDES as $side) {
$otherSide = Utils::theOther(Config::SIDES, $side);
$t->data['head'] .= Utils::metaData(
'loginCountPer' . $side,
$dbCmd->getAccessCount($side, $lastDays, [
$otherSide => null,
])
);
$translations['tables_' . $side] = $t->t('{proxystatistics:stats:side_' . $side . '}');
}
$t->data['head'] .= Utils::metaData('translations', $translations);
$t->show();
}
public static function showLegend($t, $side)
{
$mode = Config::getInstance()->getMode();
echo $t->t(
'{proxystatistics:stats:chart_legend}',
[
'!side_of' => $t->t('{proxystatistics:stats:chart_legend_side_of_' . $side . '}'),
'!side_on' => $t->t('{proxystatistics:stats:chart_legend_side_on_' . $side . '}'),
]
);
if (Config::MODE_SP === $side && Config::MODE_SP !== $mode) {
echo ' ';
echo $t->t(
'{proxystatistics:stats:first_access_only}',
[
'!through_mode' => $t->t('{proxystatistics:stats:through_mode_' . $mode . '}'),
]
);
}
}
public static function showSummary()
{
$t = new Template(Configuration::getInstance(), 'proxystatistics:summary-tpl.php');
$t->data['tab'] = 0;
$mode = Config::getInstance()->getMode();
$t->data['mode'] = $mode;
$t->data['summaryGraphs'] = [];
if (Config::MODE_PROXY === $mode || Config::MODE_MULTI_IDP === $mode) {
foreach (Config::SIDES as $side) {
$t->data['summaryGraphs'][$side] = [];
$t->data['summaryGraphs'][$side]['Providers'] = 'col-md-6 graph';
$t->data['summaryGraphs'][$side]['ProvidersLegend'] = 'col-md-12';
$t->data['summaryGraphs'][$side]['ProvidersGraph'] = 'col-md-12';
}
} else {
$side = $mode;
$t->data['summaryGraphs'][$side] = [];
$t->data['summaryGraphs'][$side]['Providers'] = 'hidden';
$t->data['summaryGraphs'][$side]['ProvidersLegend'] = '';
$t->data['summaryGraphs'][$side]['ProvidersGraph'] = '';
$otherSide = Utils::theOther(Config::SIDES, $side);
$t->data['summaryGraphs'][$otherSide] = [];
$t->data['summaryGraphs'][$otherSide]['Providers'] = 'col-md-12 graph';
$t->data['summaryGraphs'][$otherSide]['ProvidersLegend'] = 'col-md-6';
$t->data['summaryGraphs'][$otherSide]['ProvidersGraph'] = 'col-md-6 col-md-offset-3';
}
$t->show();
}
private static function getSelectedTimeRange()
{
return filter_input(
INPUT_GET,
'lastDays',
FILTER_VALIDATE_INT,
[
'options' => [
'default' => 0,
'min_range' => 0,
],
]
);
}
private static function loadIncludes($t)
{
if (empty($t->data['head'])) {
$t->data['head'] = '';
}
$t->data['head'] .= '<link rel="stylesheet" media="screen" type="text/css" href="' .
Module::getModuleUrl('elixir/res/css/jquery-ui.min.css') . '" />';
$t->data['head'] .= '<link rel="stylesheet" media="screen" type="text/css" href="' .
MOdule::getModuleURL('elixir/res/css/stats.css') . '" />';
if (empty($t->data['scripts'])) {
$t->data['scripts'] = '';
}
$t->data['scripts'] .= '<script type="text/javascript" src="' .
Module::getModuleUrl('elixir/res/js/jquery-ui.min.js') . '"></script>';
$t->data['scripts'] .= '<script type="text/javascript" src="' .
self::getFullUrl('assets/js/moment-with-locales.min.js') . '"></script>';
$t->data['scripts'] .= '<script type="text/javascript" src="' .
self::getFullUrl('assets/js/chart.min.js') . '"></script>';
$t->data['scripts'] .= '<script type="text/javascript" src="' .
self::getFullUrl('assets/js/hammer.min.js') . '"></script>';
$t->data['scripts'] .= '<script type="text/javascript" src="' .
self::getFullUrl('assets/js/chartjs-plugin-zoom.min.js') . '"></script>';
$t->data['scripts'] .= '<script type="text/javascript" src="' .
self::getFullUrl('assets/js/chartjs-adapter-moment.js') . '"></script>';
$t->data['scripts'] .= '<script type="text/javascript" src="' .
Module::getModuleUrl('elixir/res/js/charts.js') . '"></script>';
$t->data['head'] .= Utils::metaData('module_url_base', Module::getModuleUrl('elixir/'));
}
private static function getFullUrl($path = ''): string
{
return Module::getModuleUrl('proxystatistics/') . $path;
}
}
<?php declare(strict_types=1);
namespace SimpleSAML\Module\elixir\stats;
use SimpleSAML\Auth\Simple;
use SimpleSAML\Configuration;
use SimpleSAML\Logger;
use SimpleSAML\Module;
use SimpleSAML\XHTML\Template;
class Utils
{
public static function theOther($arr, $val)
{
return current(array_diff($arr, [$val]));
}
public static function metaData($id, $data)
{
return '<meta name="' . $id . '" id="' . $id . '" ' .
'content="' . htmlspecialchars(json_encode($data, JSON_NUMERIC_CHECK)) . '">';
}
}
<?php declare(strict_types=1);
use SimpleSAML\Module;
if (!empty($this->data['htmlinject']['htmlContentPost'])) {
foreach ($this->data['htmlinject']['htmlContentPost'] as $c) {
echo $c;
}
}
?>
</div> <!-- ENDCOL -->
</div> <!-- ENDROW -->
<footer>
<div class="footer offset-1 col-10 offset-sm-1 col-sm-10 offset-md-2 col-md-8 offset-lg-3 col-lg-6 offset-xl-3 col-xl-6">
<div class="footer-contact">
<a class="contact-link" href="mailto:support@aai.lifescience-ri.eu">Contact us</a>
</div>
<div class="footer-policy">
<a class="footer-policy-link" href="https://lifescience-ri.eu/ls-login/ls-aai-aup.html">Privacy Policy</a>
</div>
</div>
</footer>
<script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/jquery-3.5.1.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/bootstrap.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/cmservice.js'); ?>"></script>
<?php
if (array_key_exists('scripts', $this->data)) {
echo $this->data['scripts'];
}
?>
</body>
</html>
...@@ -27,5 +27,10 @@ if (!empty($this->data['htmlinject']['htmlContentPost'])) { ...@@ -27,5 +27,10 @@ if (!empty($this->data['htmlinject']['htmlContentPost'])) {
<script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/jquery-3.5.1.min.js'); ?>"></script> <script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/jquery-3.5.1.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/bootstrap.min.js'); ?>"></script> <script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/bootstrap.min.js'); ?>"></script>
<script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/cmservice.js'); ?>"></script> <script type="text/javascript" src="<?php echo Module::getModuleURL('elixir/res/js/cmservice.js'); ?>"></script>
<?php
if (array_key_exists('scripts', $this->data)) {
echo $this->data['scripts'];
}
?>
</body> </body>
</html> </html>
<?php declare(strict_types=1);
use SimpleSAML\Module;
/*
* Support the htmlinject hook, which allows modules to change header, pre and post body on all pages.
*/
$this->data['htmlinject'] = [
'htmlContentPre' => [],
'htmlContentPost' => [],
'htmlContentHead' => [],
];
$jquery = [];
if (array_key_exists('jquery', $this->data)) {
$jquery = $this->data['jquery'];
}
if (array_key_exists('pageid', $this->data)) {
$hookinfo = [
'pre' => &$this->data['htmlinject']['htmlContentPre'],
'post' => &$this->data['htmlinject']['htmlContentPost'],
'head' => &$this->data['htmlinject']['htmlContentHead'],
'jquery' => &$jquery,
'page' => $this->data['pageid'],
];
Module::callHooks('htmlinject', $hookinfo);
}
// - o - o - o - o - o - o - o - o - o - o - o - o -
/*
* Do not allow to frame SimpleSAMLphp pages from another location. This prevents clickjacking attacks in modern
* browsers.
*
* If you don't want any framing at all you can even change this to 'DENY', or comment it out if you actually want to
* allow foreign sites to put SimpleSAMLphp in a frame. The latter is however probably not a good security practice.
*/
header('X-Frame-Options: SAMEORIGIN');
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="<?php echo Module::getModuleUrl('elixir/res/css/bootstrap.min.css'); ?>" rel="stylesheet" type="text/css"/>
<link href="<?php echo Module::getModuleUrl('elixir/res/css/eduteams.css'); ?>" rel="stylesheet" type="text/css"/>
<link href="<?php echo Module::getModuleUrl('elixir/res/css/cmservice.css'); ?>" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="/<?php echo $this->data['baseurlpath']; ?>resources/script.js"></script>
<title><?php echo (array_key_exists('header', $this->data)) ? $this->data['header'] : 'SimpleSAMLphp'; ?></title>
<?php
if (!empty($this->data['htmlinject']['htmlContentHead'])) {
foreach ($this->data['htmlinject']['htmlContentHead'] as $c) {
echo $c;
}
}
?>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap" rel="stylesheet">
<?php
if (array_key_exists('head', $this->data)) {
echo '<!-- head -->' . $this->data['head'] . '<!-- /head -->';
}
?>
</head>
<body>
<div class="row">
<div class="offset-1 col-10 offset-sm-1 col-sm-10 offset-md-2 col-md-8 offset-lg-3 col-lg-6 offset-xl-3 col-xl-6">
<div class="text-center">
<img class="card-img-top" src="<?php echo Module::getModuleURL('elixir/res/img/lsaai_logo.png'); ?>" alt="Life Science Login logo">
<div class="card-body">
<?php
if (isset($this->data['header'])) {
echo '<h1>' . PHP_EOL;
echo $this->data['header'];
echo '</h1>' . PHP_EOL;
}
?>
</div>
</div>
</div>
<div class="col-12">
<?php declare(strict_types=1);
use SimpleSAML\Module\elixir\stats\Templates;
$this->includeAtTemplateBase('includes/header-full.php');
?>
<div class="row">
<div class="col-12 col-md-8 order-1 order-md-0">
<?php Templates::timeRange([
'side' => $this->data['side'],
'id' => $this->data['id'],
]); ?>
</div>
<div class="col-12 col-md-4 text-md-right order-0 order-md-1 mb-4 mb-md-0 ">
<div class="go-to-stats-btn">
<a href="./stats.php" class="btn btn-primary">
<?php echo $this->t('{proxystatistics:stats:back_to_stats}'); ?>
</a>
</div>
</div>
</div>
<div class="row mt-5">
<div class="col-12">
<h3><?php echo $this->t('{proxystatistics:stats:' . $this->data['side'] . 'Detail_dashboard_header}'); ?></h3>
<p><?php echo $this->t('{proxystatistics:stats:' . $this->data['side'] . 'Detail_dashboard_legend}'); ?></p>
</div>
<div class="col-12">
<?php Templates::loginsDashboard(); ?>
</div>
</div>
<div class="row mt-5 mb-4">
<div class="col-12">
<h3><?php echo $this->t('{proxystatistics:stats:' . $this->data['side'] . 'Detail_graph_header}'); ?></h3>
<p><?php echo $this->t('{proxystatistics:stats:' . $this->data['side'] . 'Detail_graph_legend}'); ?></p>
</div>
<div class="col-12">
<div class="row">
<div class="col-md-8">
<?php Templates::pieChart('detail' . $this->data['other_side'] . 'Chart'); ?>
</div>
<div class="col-md-4">
<div id="detail<?php echo $this->data['other_side']; ?>Table" class="table-container"></div>
</div>
</div>
</div>
</div>
<?php
$this->includeAtTemplateBase('includes/footer-full.php');
<?php
declare(strict_types=1);
use SimpleSAML\Module\proxystatistics\Config;
$this->data['header'] = 'LifeScience AAI Statistics';
$this->includeAtTemplateBase('includes/header-full.php');
?>
<div id="tabdiv" data-activetab="<?php echo htmlspecialchars(strval($this->data['tab'])); ?>">
<ul class="tabset_tabs nav" width="100px">
<li class="nav-item">
<a class="nav-link" <?php echo $this->data['tabsAttributes']['PROXY']; ?>>
<?php echo $this->t('{proxystatistics:stats:summary}'); ?>
</a>
</li>
<?php foreach (Config::SIDES as $side) { ?>
<li class="nav-item">
<a class="nav-link" <?php echo $this->data['tabsAttributes'][$side]; ?>>
<?php echo $this->t('{proxystatistics:stats:side' . $side . 'Detail}'); ?>
</a>
</li>
<?php } ?>
</ul>
</div>
<?php
$this->includeAtTemplateBase('includes/footer-full.php');
?>
<?php declare(strict_types=1);
?>
<div class="canvas-container">
<canvas id="loginsDashboard" data-locale="<?php echo $this->getLanguage(); ?>" height="250"></canvas>
</div>
<?php declare(strict_types=1);
use SimpleSAML\Module\elixir\stats\Templates;
?>
<div class="row">
<div class="col-12"><?php Templates::timeRange([
'tab' => $this->data['tab'],
]); ?></div>
</div>
<div class="row mt-4">
<h3 class="col-12"><?php echo $this->t('{proxystatistics:stats:side_' . $this->data['side'] . 's}'); ?></h3>
<p class="col-12"><?php Templates::showLegend($this, $this->data['side']); ?></p>
</div>
<div class="row tableMaxHehigh mt-4 mb-4">
<div class="col-md-8">
<?php
Templates::pieChart($this->data['side'] . 'Chart');
?>
</div>
<div class="col-md-4">
<div id="<?php echo $this->data['side']; ?>Table" class="table-container"></div>
</div>
</div>
<?php declare(strict_types=1);
use SimpleSAML\Module\elixir\stats\Templates;
use SimpleSAML\Module\proxystatistics\Config;
?>
<div class="row">
<div class="col-12"><?php Templates::timeRange([
'tab' => $this->data['tab'],
]); ?></div>
</div>
<div class="row mt-4">
<h3 class="col-12"><?php echo $this->t('{proxystatistics:stats:graphs_logins}'); ?></h3>
<p class="col-12"><?php echo $this->t('{proxystatistics:stats:summary_logins_info}'); ?></p>
<div class="col-12">
<?php Templates::loginsDashboard(); ?>
</div>
</div>
<div class="row tableMaxHehigh mt-4 mb-4">
<?php foreach (Config::SIDES as $side) { ?>
<div class="<?php echo $this->data['summaryGraphs'][$side]['Providers']; ?>">
<h3><?php echo $this->t('{proxystatistics:stats:side_' . $side . 's}'); ?></h3>
<p><?php Templates::showLegend($this, $side); ?></p>
<div>
<?php Templates::pieChart($side . 'Chart'); ?>
</div>
</div>
<?php } ?>
</div>
<?php declare(strict_types=1);
?>
<div class="timeRange">
<h3><?php echo $this->t('{proxystatistics:stats:select_time_range}'); ?></h3>
<form id="dateSelector" method="GET">
<?php
foreach (['tab', 'side', 'id'] as $var) {
if (isset($this->data[$var])) {
?>
<input name="<?php echo $var; ?>" type="hidden"
value="<?php echo htmlspecialchars(strval($this->data[$var])); ?>">
<?php
}
}
?>
<?php
$values = [
0 => 'all',
7 => 'week',
30 => 'month',
90 => 'three_months',
365 => 'year',
];
$i = 0;
?>
<?php foreach ($values as $value => $str) { ?>
<label>
<input id="<?php echo $i; ?>" type="radio" name="lastDays" value="<?php echo $value; ?>"
<?php echo $this->data['lastDays'] === $value ? 'checked=true' : ''; ?>>
<?php echo $this->t('{proxystatistics:stats:time_range_' . $str . '}'); ?>
</label>
<?php ++$i; ?>
<?php } ?>
</form>
</div>
<?php
declare(strict_types=1);
use SimpleSAML\Module\elixir\stats\Templates;
use SimpleSAML\Module\proxystatistics\Config;
if (empty($_GET['side']) || !in_array($_GET['side'], Config::SIDES, true)) {
throw new \Exception('Invalid argument');
}
Templates::showDetail($_GET['side']);
<?php
declare(strict_types=1);
use SimpleSAML\Module\elixir\stats\Templates;
use SimpleSAML\Module\proxystatistics\Config;
Templates::showProviders(Config::MODE_IDP, 1);
/*! jQuery UI - v1.13.1 - 2022-01-20
* http://jqueryui.com
* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css
* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6
* Copyright jQuery Foundation and other contributors; Licensed MIT */
.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;-ms-filter:"alpha(opacity=25)";opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:pointer;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;-ms-filter:"alpha(opacity=70)";font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;-ms-filter:"alpha(opacity=35)";background-image:none}.ui-state-disabled .ui-icon{-ms-filter:"alpha(opacity=35)"}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank.ui-icon-blank.ui-icon-blank{background-image:none}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;-ms-filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666}
\ No newline at end of file
#loginsDashboard {
height: 500px;
}
#dateSelector label{
font-weight: normal;
}
.legend-container, .canvas-container, .table-container {
height: 90vh;
max-height: 500px;
width: 100%;
}
.hidden {
display: none;
}
.pie-chart-container .legend-container, .table-container {
overflow-y: auto;
}
.chart-legend .item {
display: inline-block;
text-indent: -2.5em;
margin-left: 2.5em;
}
.chart-legend li .item:before {
content: '';
display: inline-block;
width: 2em;
height: 0.7em;
margin-right: 0.5em;
}
.chart-legend li:nth-child(20n+1) .item:before { background-color: #3366CC; }
.chart-legend li:nth-child(20n+2) .item:before { background-color: #DC3912; }
.chart-legend li:nth-child(20n+3) .item:before { background-color: #FF9900; }
.chart-legend li:nth-child(20n+4) .item:before { background-color: #109618; }
.chart-legend li:nth-child(20n+5) .item:before { background-color: #990099; }
.chart-legend li:nth-child(20n+6) .item:before { background-color: #3B3EAC; }
.chart-legend li:nth-child(20n+7) .item:before { background-color: #0099C6; }
.chart-legend li:nth-child(20n+8) .item:before { background-color: #DD4477; }
.chart-legend li:nth-child(20n+9) .item:before { background-color: #66AA00; }
.chart-legend li:nth-child(20n+10) .item:before { background-color: #B82E2E; }
.chart-legend li:nth-child(20n+11) .item:before { background-color: #316395; }
.chart-legend li:nth-child(20n+12) .item:before { background-color: #994499; }
.chart-legend li:nth-child(20n+13) .item:before { background-color: #22AA99; }
.chart-legend li:nth-child(20n+14) .item:before { background-color: #AAAA11; }
.chart-legend li:nth-child(20n+15) .item:before { background-color: #6633CC; }
.chart-legend li:nth-child(20n+16) .item:before { background-color: #E67300; }
.chart-legend li:nth-child(20n+17) .item:before { background-color: #8B0707; }
.chart-legend li:nth-child(20n+18) .item:before { background-color: #329262; }
.chart-legend li:nth-child(20n+19) .item:before { background-color: #5574A6; }
.chart-legend li:nth-child(20n) .item:before { background-color: #3B3EAC; }
.chart-legend li.other .item:before { background-color: #DDDDDD; }
.legend-container ul, .legend-container li {
list-style-type: none;
}
.table-container.scrolling th {
background-color: white;
box-shadow: 0 4px 5px -5px #666;
}
.table-container a, .chart-legend a {
border: 0;
}
.table-container a:not(:hover):not(:focus):not(:active),
.chart-legend a:not(:hover):not(:focus):not(:active) {
text-decoration: none;
}
'use strict';
/* global Chart moment */
function getStatisticsData(name) {
return $.parseJSON($('#' + name).attr('content'));
}
function getStatisticsDataYMDC(name, field) {
return getStatisticsData(name).map(function mapItemToDate(item) {
const d = new Date(item.day * 1000);
d.setHours(0);
return {
x: d,
y: item[field]
};
});
}
function getTranslation(str) {
return $.parseJSON($('#translations').attr('content'))[str];
}
function extendData(data, minX, maxX) {
let i = 0;
const extendedData = [];
for (let d = new Date(minX); d <= maxX; d.setDate(d.getDate() + 1),d.setHours(0)) {
if (data[i].x.getTime() === d.getTime()) {
extendedData.push(data[i]);
i += 1;
} else if (data[i].x.getTime() > d.getTime()) {
extendedData.push({ x: new Date(d), y: 0 });
} else {
throw new Error("Data is not sorted");
}
}
return extendedData;
}
function drawLoginsChart(getEl) {
const el = getEl();
if (!el) return;
const ctx = el;
const previousChart = Chart.getChart(ctx);
if (previousChart) {
previousChart.destroy();
}
let data = getStatisticsDataYMDC('loginCountPerDay', 'count');
let data2 = getStatisticsDataYMDC('loginCountPerDay', 'users');
if (!data.length || !data2.length) {
$(el).parent().replaceWith('<p class="text-muted">No data has been recorded in the selected period...</p>');
return;
}
const minX = Math.min(data[0].x, data2[0].x);
const maxX = Math.max(data[data.length - 1].x, data2[data2.length - 1].x);
data = extendData(data, minX, maxX);
data2 = extendData(data2, minX, maxX);
new Chart(ctx, { // eslint-disable-line no-new
type: 'bar',
options: {
maintainAspectRatio: false,
plugins: {
tooltips: {
intersect: false,
mode: 'index',
callbacks: {
label: function showLabel(tooltipItem) {
let label = tooltipItem.label || '';
if (label) {
label += ': ';
}
label += tooltipItem.parsed;
return label;
}
}
}
},
scales: {
x: {
beginAtZero: true,
type: 'time',
time: { // do not set round: 'day', because it breaks zooming out from 7 or fewer days
isoWeekday: true,
minUnit: 'day',
tooltipFormat: 'l'
}
},
y: {
beginAtZero: true,
title: {
display: false
}
}
},
zoom: {
limits: {
x: {min: minX, max: maxX}
},
pan: {
enabled: true,
mode: 'x'
},
zoom: {
wheel: {
enabled: true
},
pinch: {
enabled: true
},
/*drag: {
enabled: false
},*/
mode: 'x'
},
}
},
"data": {
"datasets": [
{
label: getTranslation('of_users'),
data: data2,
type: 'line',
pointRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2,
backgroundColor: '#3b3eac',
borderColor: '#3b3eac'
},
{
label: getTranslation('of_logins'),
data: data,
type: 'line',
pointRadius: 0,
fill: false,
lineTension: 0,
borderWidth: 2,
backgroundColor: '#f90',
borderColor: '#f90'
}
]
}
});
}
const pieColors = [
'#3366CC', '#DC3912', '#FF9900', '#109618', '#990099', '#3B3EAC', '#0099C6', '#DD4477', '#66AA00', '#B82E2E',
'#316395', '#994499', '#22AA99', '#AAAA11', '#6633CC', '#E67300', '#8B0707', '#329262', '#5574A6', '#3B3EAC'
];
const minPieFraction = 0.005;
const minPieOtherFraction = 0.01;
const maxPieOtherFraction = 0.20;
const pieOtherOnlyIfNeeded = false;
function processDataForPieChart(data, viewCols) {
if (pieOtherOnlyIfNeeded && data.length <= pieColors.length) {
return data;
}
const col = viewCols || [0, 1];
const total = data.reduce(function getSum(accumulator, currentValue) {
return accumulator + currentValue[col[1]];
}, 0);
let i = data.length;
let othersFraction = 0;
while (i > 1
&& (i > pieColors.length
|| (data[i - 1][col[1]] / total < minPieFraction
&& data[i - 1][col[1]] / total + othersFraction < maxPieOtherFraction))) {
i -= 1;
othersFraction += data[i][col[1]] / total;
}
if (othersFraction < minPieOtherFraction) {
i = Math.min(data.length, pieColors.length);
othersFraction = 0;
}
const processedData = data.slice(0, i);
if (i < data.length && othersFraction > 0) {
const theOthers = [null, null, null];
theOthers[col[1]] = Math.round(othersFraction * total);
theOthers[col[0]] = getTranslation('other');
processedData.push(theOthers);
}
return { data: processedData, other: othersFraction > 0, total: total };
}
function drawPieChart(dataName, viewCols, url, getEl) {
const el = getEl();
if (!el) return;
const ctx = el.getContext('2d');
const previousChart = Chart.getChart(ctx);
if (previousChart) {
previousChart.destroy();
}
const processedData = processDataForPieChart(getStatisticsData(dataName), viewCols);
const data = processedData.data;
if (!data.length) {
$(el).parent().parent().replaceWith('<p class="text-muted">No data has been recorded in the selected period...</p>');
return;
}
const other = processedData.other;
const total = processedData.total;
const col = viewCols || [0, 1];
const colors = pieColors.slice();
if (other) {
colors[data.length - 1] = '#DDDDDD';
}
const chart = new Chart(ctx, {
type: 'pie',
data: {
labels: data.map(function getFirst(row) {
return row[col[0]];
}),
datasets: [{
data: data.map(function getSecond(row) {
return row[col[1]];
}),
backgroundColor: colors,
borderWidth: 1
}]
},
options: {
maintainAspectRatio: false,
plugins: {
legend: {
position: 'right',
},
tooltip: {
callbacks: {
label: function generateLabel(tooltipItem) {
let label = tooltipItem.label || '';
if (label) {
label += ': ';
}
const value = tooltipItem.parsed;
label += value + ' (';
label += Math.round((value / total) * 1000) / 10;
label += ' %)';
return label;
}
}
}
}
}
});
if (url) {
el.addEventListener('click', function pieClick(evt) {
const activePoints = chart.getElementsAtEventForMode(evt, 'nearest', {intersect: true}, false);
if (activePoints.length) {
window.location.href = url + encodeURIComponent(data[activePoints[0].index][1]);
}
});
}
}
function getDrawChart(side) {
return drawPieChart.bind(
null,
'loginCountPer' + side,
[0, 2],
getStatisticsData('module_url_base') + 'detail.php?side=' + side + '&id='
);
}
function drawCountTable(cols, dataCol, countCol, dataName, allowHTML, url, getEl) {
const el = getEl();
if (!el) return;
const viewCols = [dataCol, countCol];
const tableDiv = el.appendChild(document.createElement('div'));
tableDiv.className = 'table-responsive';
const table = tableDiv.appendChild(document.createElement('table'));
table.className = 'table table-striped table-hover table-condensed';
const data = getStatisticsData(dataName);
if (!data.length) {
$(el).replaceWith('');
return;
}
const thead = table.appendChild(document.createElement('thead'));
let tr = thead.appendChild(document.createElement('tr'));
let th;
let i;
for (i = 0; i < viewCols.length; i++) {
th = tr.appendChild(document.createElement('th'));
th.innerText = getTranslation(cols[i]);
if (viewCols[i] === countCol) {
th.className = 'text-right';
}
}
const tbody = table.appendChild(document.createElement('tbody'));
let td;
let a;
for (let j = 0; j < data.length; j++) {
tr = tbody.appendChild(document.createElement('tr'));
for (i = 0; i < viewCols.length; i++) {
td = tr.appendChild(document.createElement('td'));
if (viewCols[i] === countCol) {
td.className = 'text-right';
}
if (url && viewCols[i] === dataCol) {
a = document.createElement('a');
a[allowHTML ? 'innerHTML' : 'innerText'] = data[j][viewCols[i]];
a.href = url + encodeURIComponent(data[j][1]);
td.appendChild(a);
} else {
td[allowHTML ? 'innerHTML' : 'innerText'] = data[j][viewCols[i]];
}
}
}
el.addEventListener('scroll', function floatingTableHead() {
const scrolling = el.scrollTop > 0;
el.classList.toggle('scrolling', scrolling);
el.querySelectorAll('th').forEach(function floatTh(the) {
the.style.transform = scrolling ? ('translateY(' + el.scrollTop + 'px)') : ''; // eslint-disable-line no-param-reassign
});
});
}
function getDrawTable(side) {
return drawCountTable.bind(null,
['tables_' + side, 'count'], 0, 2, 'loginCountPer' + side, false,
getStatisticsData('module_url_base') + 'detail.php?side=' + side + '&id=');
}
function getDrawCountTable(side) {
return drawCountTable.bind(null, ['tables_' + side, 'count'], 0, 2, 'accessCounts', true, null);
}
function getterLoadCallback(getEl, callback) {
callback(getEl);
}
function classLoadCallback(className, callback) {
getterLoadCallback(function () { return $('.' + className + ':visible')[0]; }, callback); // eslint-disable-line func-names
}
function idLoadCallback(id, callback) {
getterLoadCallback(document.getElementById.bind(document, id), callback);
}
function chartInit() {
idLoadCallback('loginsDashboard', drawLoginsChart);
['IDP', 'SP'].forEach(function callbacksForSide(side) {
classLoadCallback('chart-' + side + 'Chart', getDrawChart(side));
idLoadCallback(side + 'Table', getDrawTable(side));
idLoadCallback('detail' + side + 'Chart', drawPieChart.bind(null, 'accessCounts', [0, 2], null));
idLoadCallback('detail' + side + 'Table', getDrawCountTable(side));
});
$('#dateSelector input[name=lastDays]').on('click', function submitForm() {
this.form.submit();
});
}
$(document).ready(function docReady() {
const loginsDashboard = document.getElementById('loginsDashboard');
if (loginsDashboard !== null && loginsDashboard.dataset.locale) {
moment.locale(loginsDashboard.dataset.locale);
}
$('#tabdiv').tabs({
selected: $('#tabdiv').data('activetab'),
load: chartInit
});
chartInit();
});
This diff is collapsed.
This diff is collapsed.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment