- new "activity log" for user actions (create/update/delete) of (systems/connections/signatures), resolves #280, relates #271
- new added cronjob to delete old statistics data (older 1 year) (weekly) - updated main menu structure (added new headlines,...) - updated "feature page", added new section for "statistics" - updated "system delete" function. systems with no changes (description/alias) will now get deleted instead of set "active = 0", #184 - changed max expire time from file caching (/tmp/cache) from 20d -> 10d - changed "character log" TTL from 10s to 5s - changed cronjob interval for "deleteExpiredData" from "weekly" to "downtime" - changed "delete" icon (e.g. context menu on map) from "eraser" to "trash" - removed cronjob output logging (cron_deactivateMapData.log) - fixed non click-able character panels on login page, closed #332
This commit is contained in:
15
app/cron.ini
15
app/cron.ini
@@ -17,15 +17,18 @@ sixthHour = */10 * * * *
|
||||
halfHour = */30 * * * *
|
||||
|
||||
[CRON.jobs]
|
||||
; delete character log data
|
||||
deleteLogData = Cron\CharacterUpdate->deleteLogData, @sixthHour
|
||||
|
||||
; delete expired signatures
|
||||
deleteSignatures = Cron\MapUpdate->deleteSignatures, @halfHour
|
||||
|
||||
; import system data (jump, kill,..) from CCP API
|
||||
importSystemData = Cron\CcpSystemsUpdate->importSystemData, @hourly
|
||||
|
||||
; disable outdated maps
|
||||
deactivateMapData = Cron\MapUpdate->deactivateMapData, @hourly
|
||||
|
||||
; delete character log data
|
||||
deleteLogData = Cron\CharacterUpdate->deleteLogData, @sixthHour
|
||||
|
||||
; delete disabled maps
|
||||
deleteMapData = Cron\MapUpdate->deleteMapData, @downtime
|
||||
|
||||
@@ -33,7 +36,7 @@ deleteMapData = Cron\MapUpdate->deleteMapData, @downtime
|
||||
deleteAuthenticationData = Cron\CharacterUpdate->deleteAuthenticationData, @downtime
|
||||
|
||||
; delete expired cache files
|
||||
deleteExpiredCacheData = Cron\Cache->deleteExpiredData, @weekly
|
||||
deleteExpiredCacheData = Cron\Cache->deleteExpiredData, @downtime
|
||||
|
||||
; delete expired signatures
|
||||
deleteSignatures = Cron\MapUpdate->deleteSignatures, @halfHour
|
||||
; delete old statistics (activity log) data
|
||||
deleteStatisticsData = Cron\StatisticsUpdate->deleteStatisticsData, @weekly
|
||||
@@ -10,7 +10,7 @@ namespace Controller\Api;
|
||||
use Controller;
|
||||
use Model;
|
||||
|
||||
class Connection extends Controller\AccessController{
|
||||
class Connection extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* @param \Base $f3
|
||||
|
||||
@@ -174,6 +174,14 @@ class Map extends Controller\AccessController {
|
||||
];
|
||||
$return->maxSharedCount = $maxSharedCount;
|
||||
|
||||
// get activity log options per map ---------------------------------------------------------------------------
|
||||
$activityLogging = [
|
||||
'character' => $f3->get('PATHFINDER.MAP.PRIVATE.ACTIVITY_LOGGING'),
|
||||
'corporation' => $f3->get('PATHFINDER.MAP.CORPORATION.ACTIVITY_LOGGING'),
|
||||
'alliance' => $f3->get('PATHFINDER.MAP.ALLIANCE.ACTIVITY_LOGGING'),
|
||||
];
|
||||
$return->activityLogging = $activityLogging;
|
||||
|
||||
// get program routes -----------------------------------------------------------------------------------------
|
||||
$return->routes = [
|
||||
'ssoLogin' => $this->getF3()->alias( 'sso', ['action' => 'requestAuthorization'] )
|
||||
@@ -223,11 +231,13 @@ class Map extends Controller\AccessController {
|
||||
* @var $system Model\SystemModel
|
||||
*/
|
||||
$system = Model\BasicModel::getNew('SystemModel');
|
||||
$system->setActivityLogging(false);
|
||||
|
||||
/**
|
||||
* @var $connection Model\ConnectionModel
|
||||
*/
|
||||
$connection = Model\BasicModel::getNew('ConnectionModel');
|
||||
$connection->setActivityLogging(false);
|
||||
|
||||
foreach($importData['mapData'] as $mapData){
|
||||
if(
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
namespace Controller\Api;
|
||||
use Controller;
|
||||
use Model;
|
||||
|
||||
|
||||
@@ -15,7 +16,7 @@ use Model;
|
||||
* Class Route
|
||||
* @package Controller\Api
|
||||
*/
|
||||
class Route extends \Controller\AccessController {
|
||||
class Route extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* cache time for static jump data (e.g. K-Space stargates)
|
||||
|
||||
@@ -11,7 +11,7 @@ use Controller;
|
||||
use Model;
|
||||
|
||||
|
||||
class Signature extends Controller\AccessController{
|
||||
class Signature extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* event handler
|
||||
|
||||
291
app/main/controller/api/statistic.php
Normal file
291
app/main/controller/api/statistic.php
Normal file
@@ -0,0 +1,291 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 03.10.2016
|
||||
* Time: 00:29
|
||||
*/
|
||||
|
||||
namespace controller\api;
|
||||
|
||||
use Controller;
|
||||
use Model\CharacterModel;
|
||||
|
||||
class Statistic extends Controller\AccessController {
|
||||
|
||||
/**
|
||||
* concat a year and calendar week number
|
||||
* week numbers > 10 will get prefixed with "0"
|
||||
* -> e.g. year 2016, week 2 => "201602"
|
||||
* @param int $year
|
||||
* @param int $week
|
||||
* @return string
|
||||
*/
|
||||
protected function concatYearWeek($year, $week){
|
||||
return strval($year) . str_pad($week, 2, 0, STR_PAD_LEFT);
|
||||
}
|
||||
|
||||
/**
|
||||
* get max count of weeks in a year
|
||||
* @param $year
|
||||
* @return int
|
||||
*/
|
||||
protected function getIsoWeeksInYear($year) {
|
||||
$date = new \DateTime;
|
||||
$date->setISODate($year, 53);
|
||||
return ($date->format('W') === '53' ? 53 : 52);
|
||||
}
|
||||
|
||||
/**
|
||||
* get number of weeks for a given period
|
||||
* @param string $period
|
||||
* @param int $year
|
||||
* @return int
|
||||
*/
|
||||
protected function getWeekCount($period, $year){
|
||||
$weeksInYear = $this->getIsoWeeksInYear($year);
|
||||
|
||||
switch($period){
|
||||
case 'yearly':
|
||||
$weekCount = $weeksInYear;
|
||||
break;
|
||||
case 'monthly':
|
||||
$weekCount = 4;
|
||||
break;
|
||||
case 'weekly':
|
||||
default:
|
||||
$weekCount = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
return $weekCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* calculate calendar week and year for a given offset (weekCount)
|
||||
* -> count forward OR backward
|
||||
* @param int $year
|
||||
* @param int $week
|
||||
* @param int $weekCount
|
||||
* @param bool $backwards
|
||||
* @return array
|
||||
*/
|
||||
protected function calculateYearWeekOffset($year, $week, $weekCount, $backwards = false){
|
||||
$offset = [
|
||||
'year' => (int)$year,
|
||||
'week' => (int)$week
|
||||
];
|
||||
|
||||
$weeksInYear = $this->getIsoWeeksInYear($year);
|
||||
|
||||
// just for security...
|
||||
if($offset['week'] > $weeksInYear){
|
||||
$offset['week'] = $weeksInYear;
|
||||
}elseif($offset['week'] <= 0){
|
||||
$offset['week'] = 1;
|
||||
}
|
||||
|
||||
for($i = 1; $i < $weekCount; $i++){
|
||||
|
||||
if($backwards){
|
||||
// calculate backward
|
||||
$offset['week']--;
|
||||
|
||||
if($offset['week'] <= 0){
|
||||
// year change -> reset yearWeeks
|
||||
$offset['year']--;
|
||||
$offset['week'] = $this->getIsoWeeksInYear($offset['year']);
|
||||
}
|
||||
}else{
|
||||
// calculate forward
|
||||
$offset['week']++;
|
||||
|
||||
if($offset['week'] > $weeksInYear){
|
||||
// year change -> reset yearWeeks
|
||||
$offset['week'] = 1;
|
||||
$offset['year']++;
|
||||
$weeksInYear = $this->getIsoWeeksInYear($offset['year']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* query statistic data for "activity log"
|
||||
* -> group result by characterId
|
||||
* @param CharacterModel $character
|
||||
* @param int $typeId
|
||||
* @param int $yearStart
|
||||
* @param int $weekStart
|
||||
* @param int $yearEnd
|
||||
* @param int $weekEnd
|
||||
* @return array
|
||||
*/
|
||||
protected function queryStatistic( CharacterModel $character, $typeId, $yearStart, $weekStart, $yearEnd, $weekEnd){
|
||||
$data = [];
|
||||
|
||||
// can be either "characterId" || "corporationId" || "allianceId"
|
||||
// -> is required (>0) to limit the result to only accessible data for the given character!
|
||||
$objectId = 0;
|
||||
|
||||
// add map-"typeId" (private/corp/ally) condition -------------------------------------------------------------
|
||||
// check if "ACTIVITY_LOGGING" is active for a given "typeId"
|
||||
$sqlMapType = "";
|
||||
|
||||
switch($typeId){
|
||||
case 2:
|
||||
if( $this->getF3()->get('PATHFINDER.MAP.PRIVATE.ACTIVITY_LOGGING') ){
|
||||
$sqlMapType .= " AND `character`.`id` = :objectId ";
|
||||
$objectId = $character->_id;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if(
|
||||
$this->getF3()->get('PATHFINDER.MAP.CORPORATION.ACTIVITY_LOGGING') &&
|
||||
$character->hasCorporation()
|
||||
){
|
||||
$sqlMapType .= " AND `character`.`corporationId` = :objectId ";
|
||||
$objectId = $character->get('corporationId', true);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
if(
|
||||
$this->getF3()->get('PATHFINDER.MAP.ALLIANCE.ACTIVITY_LOGGING') &&
|
||||
$character->hasAlliance()
|
||||
){
|
||||
$sqlMapType .= " AND `character`.`allianceId` = :objectId ";
|
||||
$objectId = $character->get('allianceId', true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if($objectId > 0){
|
||||
|
||||
$queryData = [
|
||||
':active' => 1,
|
||||
':objectId' => $objectId
|
||||
];
|
||||
|
||||
// date offset condition ----------------------------------------------------------------------------------
|
||||
$sqlDateOffset = " AND CONCAT(`log`.`year`, `log`.`week`) BETWEEN :yearWeekStart AND :yearWeekEnd ";
|
||||
|
||||
$queryData[':yearWeekStart'] = $this->concatYearWeek($yearStart, $weekStart);
|
||||
$queryData[':yearWeekEnd'] = $this->concatYearWeek($yearEnd, $weekEnd);
|
||||
|
||||
// build query --------------------------------------------------------------------------------------------
|
||||
$sql = "SELECT
|
||||
`log`.`year`,
|
||||
`log`.`week`,
|
||||
`log`.`characterId`,
|
||||
`character`.`name`,
|
||||
`character`.`lastLogin`,
|
||||
SUM(`log`.`systemCreate`) `systemCreate`,
|
||||
SUM(`log`.`systemUpdate`) `systemUpdate`,
|
||||
SUM(`log`.`systemDelete`) `systemDelete`,
|
||||
SUM(`log`.`connectionCreate`) `connectionCreate`,
|
||||
SUM(`log`.`connectionUpdate`) `connectionUpdate`,
|
||||
SUM(`log`.`connectionDelete`) `connectionDelete`,
|
||||
SUM(`log`.`signatureCreate`) `signatureCreate`,
|
||||
SUM(`log`.`signatureUpdate`) `signatureUpdate`,
|
||||
SUM(`log`.`signatureDelete`) `signatureDelete`
|
||||
FROM
|
||||
`activity_log` `log` INNER JOIN
|
||||
`character` ON
|
||||
`character`.`id` = `log`.`characterId`
|
||||
WHERE
|
||||
`log`.`active` = :active
|
||||
" . $sqlMapType . "
|
||||
" . $sqlDateOffset . "
|
||||
GROUP BY
|
||||
`log`.`year`,
|
||||
`log`.`week`,
|
||||
`log`.`characterId`
|
||||
ORDER BY
|
||||
`log`.`year` DESC, `log`.`week` DESC";
|
||||
|
||||
$result = $this->getDB()->exec($sql, $queryData);
|
||||
|
||||
if( !empty($result) ){
|
||||
// group result by characterId
|
||||
foreach ($result as $key => &$entry) {
|
||||
$tmp = $entry;
|
||||
unset($tmp['characterId']);
|
||||
unset($tmp['name']);
|
||||
unset($tmp['lastLogin']);
|
||||
$data[$entry['characterId']]['name'] = $entry['name'];
|
||||
$data[$entry['characterId']]['lastLogin'] = strtotime($entry['lastLogin']);
|
||||
$data[$entry['characterId']]['weeks'][ $entry['year'] . $entry['week'] ] = $tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* get statistics data
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function getData(\Base $f3){
|
||||
$postData = (array)$f3->get('POST');
|
||||
$return = (object) [];
|
||||
|
||||
$period = $postData['period'];
|
||||
$typeId = (int)$postData['typeId'];
|
||||
$yearStart = (int)$postData['year'];
|
||||
$weekStart = (int)$postData['week'];
|
||||
|
||||
$currentYear = (int)date('o');
|
||||
$currentWeek = (int)date('W');
|
||||
|
||||
if(
|
||||
$yearStart &&
|
||||
$weekStart
|
||||
){
|
||||
$weekCount = $this->getWeekCount($period, $yearStart);
|
||||
}else{
|
||||
// if start date is not set -> calculate it from current data
|
||||
$tmpYear = $currentYear;
|
||||
if($period == 'yearly'){
|
||||
$tmpYear--;
|
||||
}
|
||||
$weekCount = $this->getWeekCount($period, $tmpYear);
|
||||
$offsetStart = $this->calculateYearWeekOffset($currentYear, $currentWeek, $weekCount, true);
|
||||
$yearStart = $offsetStart['year'];
|
||||
$weekStart = $offsetStart['week'];
|
||||
}
|
||||
|
||||
// date offset for statistics query
|
||||
$offset = $this->calculateYearWeekOffset($yearStart, $weekStart, $weekCount);
|
||||
|
||||
$activeCharacter = $this->getCharacter();
|
||||
|
||||
$return->statistics = $this->queryStatistic($activeCharacter, $typeId, $yearStart, $weekStart, $offset['year'], $offset['week']);
|
||||
$return->period = $period;
|
||||
$return->typeId = $typeId;
|
||||
$return->weekCount = $weekCount;
|
||||
$return->yearWeeks = [
|
||||
$yearStart => $this->getIsoWeeksInYear($yearStart),
|
||||
($yearStart + 1) => $this->getIsoWeeksInYear($yearStart + 1)
|
||||
];
|
||||
|
||||
// pagination offset
|
||||
$offsetNext = $this->calculateYearWeekOffset($yearStart, $weekStart, $weekCount + 1);
|
||||
$offsetPrev = $this->calculateYearWeekOffset($yearStart, $weekStart, $weekCount + 1, true);
|
||||
|
||||
// check if "next" button is available (not in future)
|
||||
$currentCurrentDataConcat = intval( $this->concatYearWeek($currentYear, $currentWeek) );
|
||||
$offsetNextDateConcat = intval( $this->concatYearWeek($offsetNext['year'], $offsetNext['week']) );
|
||||
if( $offsetNextDateConcat <= $currentCurrentDataConcat){
|
||||
$return->next = $offsetNext;
|
||||
}
|
||||
|
||||
$return->prev = $offsetPrev;
|
||||
$return->start = ['year' => $yearStart, 'week' => $weekStart];
|
||||
$return->offset = $offset;
|
||||
|
||||
echo json_encode($return);
|
||||
}
|
||||
}
|
||||
@@ -7,11 +7,12 @@
|
||||
*/
|
||||
|
||||
namespace Controller\Api;
|
||||
use Controller;
|
||||
use Controller\Ccp\Sso;
|
||||
use Data\Mapper as Mapper;
|
||||
use Model;
|
||||
|
||||
class System extends \Controller\AccessController {
|
||||
class System extends Controller\AccessController {
|
||||
|
||||
private $mainQuery = "SELECT
|
||||
map_sys.constellationID `connstallation_id`,
|
||||
@@ -68,7 +69,6 @@ class System extends \Controller\AccessController {
|
||||
* @param \Base $f3
|
||||
*/
|
||||
function beforeroute(\Base $f3) {
|
||||
|
||||
parent::beforeroute($f3);
|
||||
|
||||
// set header for all routes
|
||||
@@ -80,7 +80,6 @@ class System extends \Controller\AccessController {
|
||||
* @return string
|
||||
*/
|
||||
private function _getQuery(){
|
||||
|
||||
$query = $this->mainQuery;
|
||||
$query .= ' ' . $this->whereQuery;
|
||||
$query .= ' ' . $this->havingQuery;
|
||||
@@ -419,8 +418,17 @@ class System extends \Controller\AccessController {
|
||||
foreach($systemIds as $systemId){
|
||||
$system->getById($systemId);
|
||||
if( $system->hasAccess($activeCharacter) ){
|
||||
$system->setActive(false);
|
||||
$system->save();
|
||||
// check whether system should be deleted OR set "inactive"
|
||||
if(
|
||||
empty($system->alias) &&
|
||||
empty($system->description)
|
||||
){
|
||||
$system->erase();
|
||||
}else{
|
||||
// keep data -> set "inactive"
|
||||
$system->setActive(false);
|
||||
$system->save();
|
||||
}
|
||||
$system->reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,6 +95,9 @@ class Controller {
|
||||
* @param \Base $f3
|
||||
*/
|
||||
public function afterroute(\Base $f3){
|
||||
// store all user activities that are buffered for logging in this request
|
||||
self::storeActivities();
|
||||
|
||||
if($this->getTemplate()){
|
||||
// Ajax calls don´t need a page render..
|
||||
// this happens on client side
|
||||
@@ -779,6 +782,13 @@ class Controller {
|
||||
return LogController::getLogger($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* store activity log data to DB
|
||||
*/
|
||||
static function storeActivities(){
|
||||
LogController::instance()->storeActivities();
|
||||
}
|
||||
|
||||
/**
|
||||
* removes illegal characters from a Hive-key that are not allowed
|
||||
* @param $key
|
||||
|
||||
@@ -7,10 +7,128 @@
|
||||
*/
|
||||
|
||||
namespace controller;
|
||||
use DB;
|
||||
|
||||
class LogController extends \Prefab {
|
||||
|
||||
class LogController extends Controller {
|
||||
/**
|
||||
* buffered activity log data for this singleton LogController() class
|
||||
* -> this buffered data can be stored somewhere (e.g. DB) before HTTP response
|
||||
* -> should be cleared afterwards!
|
||||
* @var array
|
||||
*/
|
||||
protected $activityLogBuffer = [];
|
||||
|
||||
/**
|
||||
* reserve a "new" character activity for logging
|
||||
* @param $characterId
|
||||
* @param $mapId
|
||||
* @param $action
|
||||
*/
|
||||
public function bufferActivity($characterId, $mapId, $action){
|
||||
$characterId = (int)$characterId;
|
||||
$mapId = (int)$mapId;
|
||||
|
||||
if(
|
||||
$characterId > 0 &&
|
||||
$mapId > 0
|
||||
){
|
||||
$key = $this->getBufferedActivityKey($characterId, $mapId);
|
||||
|
||||
if( is_null($key) ){
|
||||
$activity = [
|
||||
'characterId' => $characterId,
|
||||
'mapId' => $mapId,
|
||||
$action => 1
|
||||
];
|
||||
$this->activityLogBuffer[] = $activity;
|
||||
}else{
|
||||
$this->activityLogBuffer[$key][$action]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* store all buffered activity log data to DB
|
||||
*/
|
||||
public function storeActivities(){
|
||||
if( !empty($this->activityLogBuffer) ){
|
||||
$db = DB\Database::instance()->getDB('PF');
|
||||
|
||||
$quoteStr = function($str) use ($db) {
|
||||
return $db->quotekey($str);
|
||||
};
|
||||
|
||||
$placeholderStr = function($str){
|
||||
return ':' . $str;
|
||||
};
|
||||
|
||||
$updateRule = function($str){
|
||||
return $str . " = " . $str . " + VALUES(" . $str . ")";
|
||||
};
|
||||
|
||||
$year = (int)date('o');
|
||||
$yearWeek = (int)date('W');
|
||||
$db->begin();
|
||||
|
||||
foreach($this->activityLogBuffer as $activityData){
|
||||
$activityData['year'] = $year;
|
||||
$activityData['week'] = $yearWeek;
|
||||
|
||||
$columns = array_keys($activityData);
|
||||
$columnsQuoted = array_map($quoteStr, $columns);
|
||||
$placeholder = array_map($placeholderStr, $columns);
|
||||
$args = array_combine($placeholder, $activityData);
|
||||
|
||||
// "filter" columns that can be updated
|
||||
$columnsForUpdate = array_diff($columns, ['year', 'week', 'characterId', 'mapId']);
|
||||
$updateSql = array_map($updateRule, $columnsForUpdate);
|
||||
|
||||
$sql = "INSERT DELAYED INTO
|
||||
activity_log (" . implode(', ', $columnsQuoted) . ") values(
|
||||
" . implode(', ', $placeholder) . "
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
updated = NOW(),
|
||||
" . implode(', ', $updateSql) . "
|
||||
";
|
||||
|
||||
$db->exec($sql, $args);
|
||||
}
|
||||
|
||||
$db->commit();
|
||||
|
||||
// clear activity data for this instance
|
||||
$this->activityLogBuffer = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get array key from "buffered activity log" array
|
||||
* @param int $characterId
|
||||
* @param int $mapId
|
||||
* @return int|null
|
||||
*/
|
||||
private function getBufferedActivityKey($characterId, $mapId){
|
||||
$activityKey = null;
|
||||
|
||||
if(
|
||||
$characterId > 0 &&
|
||||
$mapId > 0
|
||||
){
|
||||
foreach($this->activityLogBuffer as $key => $activityData){
|
||||
if(
|
||||
$activityData['characterId'] === $characterId &&
|
||||
$activityData['mapId'] === $mapId
|
||||
){
|
||||
$activityKey = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $activityKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* get Logger instance
|
||||
|
||||
@@ -86,6 +86,8 @@ class Setup extends Controller {
|
||||
'Model\ConnectionModel',
|
||||
'Model\SystemSignatureModel',
|
||||
|
||||
'Model\ActivityLogModel',
|
||||
|
||||
'Model\SystemShipKillModel',
|
||||
'Model\SystemPodKillModel',
|
||||
'Model\SystemFactionKillModel',
|
||||
|
||||
@@ -47,7 +47,7 @@ class CharacterUpdate {
|
||||
* delete expired character authentication data
|
||||
* authentication data is used for cookie based login
|
||||
* >> php index.php "/cron/deleteAuthenticationData"
|
||||
* @param $f3
|
||||
* @param \Base $f3
|
||||
*/
|
||||
function deleteAuthenticationData($f3){
|
||||
DB\Database::instance()->getDB('PF');
|
||||
|
||||
@@ -35,11 +35,6 @@ class MapUpdate {
|
||||
TIMESTAMPDIFF(DAY, map.updated, NOW() ) > :lifetime";
|
||||
|
||||
$pfDB->exec($sqlDeactivateExpiredMaps, ['lifetime' => $privateMapLifetime]);
|
||||
$deactivatedMapsCount = $pfDB->count();
|
||||
|
||||
// Log ------------------------
|
||||
$log = new \Log('cron_' . __FUNCTION__ . '.log');
|
||||
$log->write( sprintf(self::LOG_TEXT_MAPS, __FUNCTION__, $deactivatedMapsCount) );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,13 +73,13 @@ class MapUpdate {
|
||||
if($signatureExpire > 0){
|
||||
$pfDB = DB\Database::instance()->getDB('PF');
|
||||
|
||||
$sqlDeleteExpiredSignatures = "DELETE `sys` FROM
|
||||
`system_signature` `sys` INNER JOIN
|
||||
$sqlDeleteExpiredSignatures = "DELETE `sigs` FROM
|
||||
`system_signature` `sigs` INNER JOIN
|
||||
`system` ON
|
||||
`system`.`id` = `sys`.`systemId`
|
||||
`system`.`id` = `sigs`.`systemId`
|
||||
WHERE
|
||||
`system`.`active` = 0 AND
|
||||
TIMESTAMPDIFF(SECOND, `sys`.`updated`, NOW() ) > :lifetime
|
||||
TIMESTAMPDIFF(SECOND, `sigs`.`updated`, NOW() ) > :lifetime
|
||||
";
|
||||
|
||||
$pfDB->exec($sqlDeleteExpiredSignatures, ['lifetime' => $signatureExpire]);
|
||||
|
||||
46
app/main/cron/statisticsupdate.php
Normal file
46
app/main/cron/statisticsupdate.php
Normal file
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 16.10.2016
|
||||
* Time: 21:31
|
||||
*/
|
||||
|
||||
namespace cron;
|
||||
use DB;
|
||||
|
||||
class StatisticsUpdate {
|
||||
|
||||
const LOG_TEXT_STATISTICS = '%s (%d rows)';
|
||||
|
||||
/**
|
||||
* delete old statistics
|
||||
* -> older than 1 year
|
||||
* >> php index.php "/cron/deleteStatisticsData"
|
||||
* @param \Base $f3
|
||||
*/
|
||||
function deleteStatisticsData(\Base $f3){
|
||||
$currentYear = (int)date('o');
|
||||
$currentWeek = (int)date('W');
|
||||
$expiredYear = $currentYear - 1;
|
||||
|
||||
$pfDB = DB\Database::instance()->getDB('PF');
|
||||
|
||||
$queryData = [
|
||||
'yearWeekEnd' => strval($expiredYear) . str_pad($currentWeek, 2, 0, STR_PAD_LEFT)
|
||||
];
|
||||
|
||||
$sql = "DELETE FROM
|
||||
activity_log
|
||||
WHERE
|
||||
CONCAT(`year`, `week`) < :yearWeekEnd";
|
||||
|
||||
$pfDB->exec($sql, $queryData);
|
||||
|
||||
$deletedLogsCount = $pfDB->count();
|
||||
|
||||
// Log ------------------------
|
||||
$log = new \Log('cron_' . __FUNCTION__ . '.log');
|
||||
$log->write( sprintf(self::LOG_TEXT_STATISTICS, __FUNCTION__, $deletedLogsCount) );
|
||||
}
|
||||
}
|
||||
150
app/main/model/activitylogmodel.php
Normal file
150
app/main/model/activitylogmodel.php
Normal file
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by PhpStorm.
|
||||
* User: Exodus
|
||||
* Date: 01.10.2016
|
||||
* Time: 15:11
|
||||
*/
|
||||
|
||||
namespace Model;
|
||||
|
||||
use DB\SQL\Schema;
|
||||
|
||||
class ActivityLogModel extends BasicModel {
|
||||
|
||||
protected $table = 'activity_log';
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
'characterId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\CharacterModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'character',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'mapId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
'belongs-to-one' => 'Model\MapModel',
|
||||
'constraint' => [
|
||||
[
|
||||
'table' => 'map',
|
||||
'on-delete' => 'SET NULL' // keep log data on map delete
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
// system actions -----------------------------------------------------
|
||||
|
||||
'systemCreate' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'systemUpdate' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'systemDelete' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
|
||||
// connection actions -------------------------------------------------
|
||||
|
||||
'connectionCreate' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'connectionUpdate' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'connectionDelete' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
|
||||
// signature actions -------------------------------------------------
|
||||
|
||||
'signatureCreate' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'signatureUpdate' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
'signatureDelete' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
public function __construct($db = NULL, $table = NULL, $fluid = NULL, $ttl = 0){
|
||||
$this->addStaticDateFieldConfig();
|
||||
|
||||
parent::__construct($db, $table, $fluid, $ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* extent the fieldConf Array with static fields for each table
|
||||
*/
|
||||
private function addStaticDateFieldConfig(){
|
||||
if(is_array($this->fieldConf)){
|
||||
$staticFieldConfig = [
|
||||
'year' => [
|
||||
'type' => Schema::DT_SMALLINT,
|
||||
'nullable' => false,
|
||||
'default' => date('o'), // 01.01 could be week 53 -> NOT "current" year!
|
||||
'index' => true
|
||||
],
|
||||
'week' => [ // week in year [1-53]
|
||||
'type' => Schema::DT_TINYINT,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
],
|
||||
];
|
||||
$this->fieldConf = array_merge($staticFieldConfig, $this->fieldConf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrites parent
|
||||
* @param null $db
|
||||
* @param null $table
|
||||
* @param null $fields
|
||||
* @return bool
|
||||
*/
|
||||
public static function setup($db=null, $table=null, $fields=null){
|
||||
$status = parent::setup($db,$table,$fields);
|
||||
|
||||
if($status === true){
|
||||
$status = parent::setMultiColumnIndex(['year', 'week', 'characterId', 'mapId'], true);
|
||||
if($status === true){
|
||||
$status = parent::setMultiColumnIndex(['year', 'week', 'characterId']);
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,14 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
*/
|
||||
protected $allowActiveChange = false;
|
||||
|
||||
/**
|
||||
* enables check for $fieldChanges on update/insert
|
||||
* -> fields that should be checked need an "activity-log" flag
|
||||
* in $fieldConf config
|
||||
* @var bool
|
||||
*/
|
||||
protected $enableActivityLogging = true;
|
||||
|
||||
/**
|
||||
* getData() cache key prefix
|
||||
* -> do not change, otherwise cached data is lost
|
||||
@@ -77,6 +85,12 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
*/
|
||||
public static $enableDataImport = false;
|
||||
|
||||
/**
|
||||
* changed fields (columns) on update/insert
|
||||
* -> e.g. for character "activity logging"
|
||||
* @var array
|
||||
*/
|
||||
protected $fieldChanges = [];
|
||||
|
||||
public function __construct($db = NULL, $table = NULL, $fluid = NULL, $ttl = 0){
|
||||
|
||||
@@ -157,10 +171,54 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
if(!$valid){
|
||||
$this->throwValidationError($key);
|
||||
}else{
|
||||
$this->checkFieldForActivityLogging($key, $val);
|
||||
|
||||
return parent::set($key, $val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* change default "activity logging" status
|
||||
* -> enable/disable
|
||||
* @param $status
|
||||
*/
|
||||
public function setActivityLogging($status){
|
||||
$this->enableActivityLogging = (bool) $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* check column for value changes,
|
||||
* --> if column is marked for "activity logging"
|
||||
* @param string $key
|
||||
* @param mixed $val
|
||||
*/
|
||||
protected function checkFieldForActivityLogging($key, $val){
|
||||
if( $this->enableActivityLogging ){
|
||||
$fieldConf = $this->fieldConf[$key];
|
||||
|
||||
// check for value changes if field has "activity logging" active
|
||||
if($fieldConf['activity-log'] === true){
|
||||
if(
|
||||
is_numeric($val) ||
|
||||
$fieldConf['type'] === Schema::DT_BOOL
|
||||
){
|
||||
$val = (int)$val;
|
||||
}
|
||||
|
||||
if( $fieldConf['type'] === self::DT_JSON){
|
||||
$currentValue = $this->get($key);
|
||||
}else{
|
||||
$currentValue = $this->get($key, true);
|
||||
}
|
||||
|
||||
if($currentValue !== $val){
|
||||
// field has changed
|
||||
in_array($key, $this->fieldChanges) ?: $this->fieldChanges[] = $key;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* setter for "active" status
|
||||
* -> default: keep current "active" status
|
||||
@@ -638,6 +696,18 @@ abstract class BasicModel extends \DB\Cortex {
|
||||
return ['added' => $addedCount, 'updated' => $updatedCount, 'deleted' => $deletedCount];
|
||||
}
|
||||
|
||||
/**
|
||||
* buffer a new activity (action) logging
|
||||
* -> increment buffered counter
|
||||
* -> log character activity create/update/delete events
|
||||
* @param int $characterId
|
||||
* @param int $mapId
|
||||
* @param string $action
|
||||
*/
|
||||
protected function bufferActivity($characterId, $mapId, $action){
|
||||
Controller\LogController::instance()->bufferActivity($characterId, $mapId, $action);
|
||||
}
|
||||
|
||||
/**
|
||||
* get the current class name
|
||||
* -> namespace not included
|
||||
|
||||
@@ -18,11 +18,11 @@ class CharacterLogModel extends BasicModel {
|
||||
|
||||
/**
|
||||
* caching for relational data
|
||||
* -> 10s matches REST API - Expire: Header-Data
|
||||
* -> 5s matches REST API - Expire: Header-Data
|
||||
* for "Location" calls
|
||||
* @var int
|
||||
*/
|
||||
protected $rel_ttl = 10;
|
||||
protected $rel_ttl = 5;
|
||||
|
||||
protected $fieldConf = [
|
||||
'active' => [
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
|
||||
namespace Model;
|
||||
|
||||
use Controller\Api\Route;
|
||||
use DB\SQL\Schema;
|
||||
use Controller;
|
||||
use Controller\Api\Route;
|
||||
|
||||
class ConnectionModel extends BasicModel{
|
||||
|
||||
@@ -42,7 +43,8 @@ class ConnectionModel extends BasicModel{
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'activity-log' => true
|
||||
],
|
||||
'target' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -53,15 +55,18 @@ class ConnectionModel extends BasicModel{
|
||||
'table' => 'system',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'activity-log' => true
|
||||
],
|
||||
'scope' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
'default' => '',
|
||||
'activity-log' => true
|
||||
],
|
||||
'type' => [
|
||||
'type' => self::DT_JSON
|
||||
'type' => self::DT_JSON,
|
||||
'activity-log' => true
|
||||
],
|
||||
'eolUpdated' => [
|
||||
'type' => Schema::DT_TIMESTAMP,
|
||||
@@ -212,6 +217,66 @@ class ConnectionModel extends BasicModel{
|
||||
return parent::beforeInsertEvent($self, $pkeys);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterInsertEvent($self, $pkeys){
|
||||
parent::afterInsertEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('connectionCreate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterUpdateEvent($self, $pkeys){
|
||||
parent::afterUpdateEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('connectionUpdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterEraseEvent($self, $pkeys){
|
||||
parent::afterUpdateEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('connectionDelete');
|
||||
}
|
||||
|
||||
/**
|
||||
* log character activity create/update/delete events
|
||||
* @param string $action
|
||||
*/
|
||||
protected function logActivity($action){
|
||||
|
||||
if(
|
||||
$this->enableActivityLogging &&
|
||||
(
|
||||
$action === 'connectionDelete' ||
|
||||
!empty($this->fieldChanges)
|
||||
) &&
|
||||
$this->get('mapId')->isActivityLogEnabled()
|
||||
){
|
||||
// TODO implement "dependency injection" for active character object...
|
||||
$controller = new Controller\Controller();
|
||||
$currentActiveCharacter = $controller->getCharacter();
|
||||
$characterId = is_null($currentActiveCharacter) ? 0 : $currentActiveCharacter->_id;
|
||||
$mapId = $this->get('mapId', true);
|
||||
|
||||
parent::bufferActivity($characterId, $mapId, $action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* save connection and check if obj is valid
|
||||
* @return ConnectionModel|false
|
||||
|
||||
@@ -609,6 +609,31 @@ class MapModel extends BasicModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if "activity logging" is enabled for this map type
|
||||
* @return bool
|
||||
*/
|
||||
public function isActivityLogEnabled(){
|
||||
$f3 = self::getF3();
|
||||
$activityLogEnabled = false;
|
||||
|
||||
if( $this->isAlliance() ){
|
||||
if( $f3->get('PATHFINDER.MAP.ALLIANCE.ACTIVITY_LOGGING') ){
|
||||
$activityLogEnabled = true;
|
||||
}
|
||||
}elseif( $this->isCorporation() ){
|
||||
if( $f3->get('PATHFINDER.MAP.CORPORATION.ACTIVITY_LOGGING') ){
|
||||
$activityLogEnabled = true;
|
||||
}
|
||||
}elseif( $this->isPrivate() ){
|
||||
if( $f3->get('PATHFINDER.MAP.PRIVATE.ACTIVITY_LOGGING') ){
|
||||
$activityLogEnabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
return $activityLogEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* checks whether this map is private map
|
||||
* @return bool
|
||||
|
||||
@@ -24,7 +24,8 @@ class SystemModel extends BasicModel {
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 1,
|
||||
'index' => true
|
||||
'index' => true,
|
||||
'activity-log' => true
|
||||
],
|
||||
'mapId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -49,7 +50,8 @@ class SystemModel extends BasicModel {
|
||||
'alias' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
'default' => '',
|
||||
'activity-log' => true
|
||||
],
|
||||
'regionId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -106,12 +108,14 @@ class SystemModel extends BasicModel {
|
||||
'table' => 'system_status',
|
||||
'on-delete' => 'CASCADE'
|
||||
]
|
||||
]
|
||||
],
|
||||
'activity-log' => true
|
||||
],
|
||||
'locked' => [
|
||||
'type' => Schema::DT_BOOL,
|
||||
'nullable' => false,
|
||||
'default' => 0
|
||||
'default' => 0,
|
||||
'activity-log' => true
|
||||
],
|
||||
'rallyUpdated' => [
|
||||
'type' => Schema::DT_TIMESTAMP,
|
||||
@@ -125,7 +129,8 @@ class SystemModel extends BasicModel {
|
||||
'description' => [
|
||||
'type' => Schema::DT_VARCHAR512,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
'default' => '',
|
||||
'activity-log' => true
|
||||
],
|
||||
'posX' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -351,6 +356,18 @@ class SystemModel extends BasicModel {
|
||||
return $rally;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterInsertEvent($self, $pkeys){
|
||||
parent::afterInsertEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('systemCreate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
@@ -360,6 +377,8 @@ class SystemModel extends BasicModel {
|
||||
* @return bool
|
||||
*/
|
||||
public function beforeUpdateEvent($self, $pkeys){
|
||||
$status = parent::beforeUpdateEvent($self, $pkeys);
|
||||
|
||||
if( !$self->isActive()){
|
||||
// system becomes inactive
|
||||
// reset "rally point" fields
|
||||
@@ -372,7 +391,8 @@ class SystemModel extends BasicModel {
|
||||
$connection->erase();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -382,6 +402,8 @@ class SystemModel extends BasicModel {
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterUpdateEvent($self, $pkeys){
|
||||
parent::afterUpdateEvent($self, $pkeys);
|
||||
|
||||
// check if rally point mail should be send
|
||||
if(
|
||||
$self->newRallyPointSet &&
|
||||
@@ -389,6 +411,41 @@ class SystemModel extends BasicModel {
|
||||
){
|
||||
$self->sendRallyPointMail();
|
||||
}
|
||||
|
||||
$activity = ($self->isActive()) ? 'systemUpdate' : 'systemDelete';
|
||||
$self->logActivity($activity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterEraseEvent($self, $pkeys){
|
||||
parent::afterUpdateEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('systemDelete');
|
||||
}
|
||||
|
||||
/**
|
||||
* log character activity create/update/delete events
|
||||
* @param string $action
|
||||
*/
|
||||
protected function logActivity($action){
|
||||
if(
|
||||
$this->enableActivityLogging &&
|
||||
(
|
||||
$action === 'systemDelete' ||
|
||||
!empty($this->fieldChanges)
|
||||
) &&
|
||||
$this->get('mapId')->isActivityLogEnabled()
|
||||
){
|
||||
$characterId = $this->get('updatedCharacterId', true);
|
||||
$mapId = $this->get('mapId', true);
|
||||
|
||||
parent::bufferActivity($characterId, $mapId, $action);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -37,22 +37,26 @@ class SystemSignatureModel extends BasicModel {
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
'index' => true,
|
||||
'activity-log' => true
|
||||
],
|
||||
'typeId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'nullable' => false,
|
||||
'default' => 0,
|
||||
'index' => true,
|
||||
'activity-log' => true
|
||||
],
|
||||
'name' => [
|
||||
'type' => Schema::DT_VARCHAR128,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
'default' => '',
|
||||
'activity-log' => true
|
||||
],
|
||||
'description' => [
|
||||
'type' => Schema::DT_VARCHAR512,
|
||||
'nullable' => false,
|
||||
'default' => ''
|
||||
'default' => '',
|
||||
'activity-log' => true
|
||||
],
|
||||
'createdCharacterId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
@@ -172,6 +176,68 @@ class SystemSignatureModel extends BasicModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterInsertEvent($self, $pkeys){
|
||||
parent::afterInsertEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('signatureCreate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* return false will stop any further action
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterUpdateEvent($self, $pkeys){
|
||||
parent::afterUpdateEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('signatureUpdate');
|
||||
}
|
||||
|
||||
/**
|
||||
* Event "Hook" function
|
||||
* can be overwritten
|
||||
* @param self $self
|
||||
* @param $pkeys
|
||||
*/
|
||||
public function afterEraseEvent($self, $pkeys){
|
||||
parent::afterUpdateEvent($self, $pkeys);
|
||||
|
||||
$self->logActivity('signatureDelete');
|
||||
}
|
||||
|
||||
/**
|
||||
* log character activity create/update/delete events
|
||||
* @param string $action
|
||||
*/
|
||||
protected function logActivity($action){
|
||||
if($this->enableActivityLogging){
|
||||
/**
|
||||
* @var $map MapModel
|
||||
*/
|
||||
$map = $this->get('systemId')->get('mapId');
|
||||
|
||||
if(
|
||||
(
|
||||
$action === 'signatureDelete' ||
|
||||
!empty($this->fieldChanges)
|
||||
) &&
|
||||
$map->isActivityLogEnabled()
|
||||
){
|
||||
$characterId = $this->get('updatedCharacterId', true);
|
||||
$mapId = $map->_id;
|
||||
|
||||
parent::bufferActivity($characterId, $mapId, $action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* overwrites parent
|
||||
* @param null $db
|
||||
|
||||
@@ -45,23 +45,32 @@ LOGIN = templates/view/login.html
|
||||
|
||||
; MAP =============================================================================================
|
||||
; Map settings for "private", "corporation" and "alliance" maps
|
||||
; LIFETIME: Map will be deleted after "X" days, by cronjob
|
||||
; MAX_COUNT: Users can create/view up to "X" maps of a type
|
||||
; MAX_SHARED: Max number of shared entities per map
|
||||
; LIFETIME (days):
|
||||
; - Map will be deleted after "X" days, by cronjob
|
||||
; MAX_COUNT:
|
||||
; - Users can create/view up to "X" maps of a type
|
||||
; MAX_SHARED:
|
||||
; - Max number of shared entities per map
|
||||
; ACTIVITY_LOGGING (0: disable, 1: enable):
|
||||
; - Whether user activity should be logged for a map type
|
||||
; - E.g. create/update/delete of systems/connections/signatures
|
||||
[PATHFINDER.MAP.PRIVATE]
|
||||
LIFETIME = 14
|
||||
MAX_COUNT = 3
|
||||
MAX_SHARED = 10
|
||||
ACTIVITY_LOGGING = 1
|
||||
|
||||
[PATHFINDER.MAP.CORPORATION]
|
||||
LIFETIME = 99999
|
||||
MAX_COUNT = 3
|
||||
MAX_SHARED = 3
|
||||
ACTIVITY_LOGGING = 1
|
||||
|
||||
[PATHFINDER.MAP.ALLIANCE]
|
||||
LIFETIME = 99999
|
||||
MAX_COUNT = 3
|
||||
MAX_SHARED = 2
|
||||
ACTIVITY_LOGGING = 0
|
||||
|
||||
; Route search ====================================================================================
|
||||
[PATHFINDER.ROUTE]
|
||||
@@ -108,8 +117,8 @@ EXECUTION_LIMIT = 50
|
||||
CHARACTER_LOG = 300
|
||||
; expire time for static system data (seconds) (default: 20d)
|
||||
CONSTELLATION_SYSTEMS = 1728000
|
||||
; max expire time. Expired cache files will be deleted by cronjob (seconds) (default: 20d)
|
||||
EXPIRE_MAX = 1728000
|
||||
; max expire time. Expired cache files will be deleted by cronjob (seconds) (default: 10d)
|
||||
EXPIRE_MAX = 864000
|
||||
; expire time for signatures (inactive systems) (seconds) (default 3d)
|
||||
EXPIRE_SIGNATURES = 259200
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ requirejs.config({
|
||||
raphael: 'lib/raphael-min', // v2.1.2 Raphaël - required for morris (dependency)
|
||||
bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com
|
||||
easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart
|
||||
peityInlineChart: 'lib/jquery.peity.min', // v3.2.0 Inline Chart - http://benpickles.github.io/peity/
|
||||
dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select
|
||||
hoverIntent: 'lib/jquery.hoverIntent.minified', // v1.8.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
|
||||
fullScreen: 'lib/jquery.fullscreen.min', // v0.5.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
|
||||
@@ -123,6 +124,9 @@ requirejs.config({
|
||||
easyPieChart: {
|
||||
deps : ['jquery']
|
||||
},
|
||||
peityInlineChart: {
|
||||
deps : ['jquery']
|
||||
},
|
||||
dragToSelect: {
|
||||
deps : ['jquery']
|
||||
},
|
||||
|
||||
@@ -35,7 +35,6 @@ define(['jquery'], function($) {
|
||||
getSystemGraphData: 'api/system/graphData', // ajax URL - get all system graph data
|
||||
getConstellationData: 'api/system/constellationData', // ajax URL - get system constellation data
|
||||
setDestination: 'api/system/setDestination', // ajax URL - set destination
|
||||
|
||||
// connection API
|
||||
saveConnection: 'api/connection/save', // ajax URL - save new connection to map
|
||||
deleteConnection: 'api/connection/delete', // ajax URL - delete connection from map
|
||||
@@ -45,6 +44,8 @@ define(['jquery'], function($) {
|
||||
deleteSignatureData: 'api/signature/delete', // ajax URL - delete signature data for system
|
||||
// route API
|
||||
searchRoute: 'api/route/search', // ajax URL - search system routes
|
||||
// stats API
|
||||
getStatisticsData: 'api/statistic/getData', // ajax URL - get statistics data (activity log)
|
||||
// GitHub API
|
||||
gitHubReleases: 'api/github/releases' // ajax URL - get release info from GitHub
|
||||
},
|
||||
@@ -52,6 +53,12 @@ define(['jquery'], function($) {
|
||||
ccpImageServer: 'https://image.eveonline.com/', // CCP image Server
|
||||
zKillboard: 'https://zkillboard.com/api/' // killboard api
|
||||
},
|
||||
breakpoints: [
|
||||
{ name: 'desktop', width: Infinity },
|
||||
{ name: 'tablet', width: 1200 },
|
||||
{ name: 'fablet', width: 780 },
|
||||
{ name: 'phone', width: 480 }
|
||||
],
|
||||
animationSpeed: {
|
||||
splashOverlay: 300, // "splash" loading overlay
|
||||
headerLink: 100, // links in head bar
|
||||
|
||||
119
js/app/login.js
119
js/app/login.js
@@ -105,6 +105,14 @@ define([
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* set link observer for "version info" dialog
|
||||
*/
|
||||
var setVersionLinkObserver = function(){
|
||||
$('.' + config.navigationVersionLinkClass).off('click').on('click', function(e){
|
||||
$.fn.releasesDialog();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* set page observer
|
||||
@@ -121,11 +129,6 @@ define([
|
||||
setCookie('cookie', 1, 365);
|
||||
});
|
||||
|
||||
// releases -----------------------------------------------------------
|
||||
$('.' + config.navigationVersionLinkClass).on('click', function(e){
|
||||
$.fn.releasesDialog();
|
||||
});
|
||||
|
||||
// manual -------------------------------------------------------------
|
||||
$('.' + config.navigationLinkManualClass).on('click', function(e){
|
||||
e.preventDefault();
|
||||
@@ -138,6 +141,9 @@ define([
|
||||
$.fn.showCreditsDialog(false, true);
|
||||
});
|
||||
|
||||
// releases -----------------------------------------------------------
|
||||
setVersionLinkObserver();
|
||||
|
||||
// tooltips -----------------------------------------------------------
|
||||
var mapTooltipOptions = {
|
||||
toggle: 'tooltip',
|
||||
@@ -329,6 +335,9 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* init "YouTube" video preview
|
||||
*/
|
||||
var initYoutube = function(){
|
||||
|
||||
$('.youtube').each(function() {
|
||||
@@ -468,6 +477,8 @@ define([
|
||||
notificationPanel.velocity('transition.slideUpIn', {
|
||||
duration: 300,
|
||||
complete: function(){
|
||||
setVersionLinkObserver();
|
||||
|
||||
// mark panel as "shown"
|
||||
Util.getLocalStorage().setItem(storageKey, currentVersion);
|
||||
}
|
||||
@@ -565,75 +576,71 @@ define([
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
// request character data for each character panel
|
||||
$('.' + config.characterSelectionClass + ' .pf-dynamic-area').each(function(){
|
||||
var characterElement = $(this);
|
||||
requirejs(['text!templates/ui/character_panel.html', 'mustache'], function(template, Mustache){
|
||||
|
||||
characterElement.showLoadingAnimation();
|
||||
$('.' + config.characterSelectionClass + ' .pf-dynamic-area').each(function(){
|
||||
var characterElement = $(this);
|
||||
|
||||
var requestData = {
|
||||
cookie: characterElement.data('cookie')
|
||||
};
|
||||
characterElement.showLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.getCookieCharacterData,
|
||||
data: requestData,
|
||||
dataType: 'json',
|
||||
context: {
|
||||
href: characterElement.data('href'),
|
||||
cookieName: requestData.cookie,
|
||||
characterElement: characterElement
|
||||
}
|
||||
}).done(function(responseData, textStatus, request){
|
||||
var characterElement = this.characterElement;
|
||||
characterElement.hideLoadingAnimation();
|
||||
var requestData = {
|
||||
cookie: characterElement.data('cookie')
|
||||
};
|
||||
|
||||
if(
|
||||
responseData.error &&
|
||||
responseData.error.length > 0
|
||||
){
|
||||
$('.' + config.dynamicMessageContainerClass).showMessage({
|
||||
type: responseData.error[0].type,
|
||||
title: 'Character verification failed',
|
||||
text: responseData.error[0].message
|
||||
});
|
||||
}
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.getCookieCharacterData,
|
||||
data: requestData,
|
||||
dataType: 'json',
|
||||
context: {
|
||||
cookieName: requestData.cookie,
|
||||
characterElement: characterElement
|
||||
}
|
||||
}).done(function(responseData, textStatus, request){
|
||||
this.characterElement.hideLoadingAnimation();
|
||||
|
||||
if(responseData.hasOwnProperty('character')){
|
||||
if(
|
||||
responseData.error &&
|
||||
responseData.error.length > 0
|
||||
){
|
||||
$('.' + config.dynamicMessageContainerClass).showMessage({
|
||||
type: responseData.error[0].type,
|
||||
title: 'Character verification failed',
|
||||
text: responseData.error[0].message
|
||||
});
|
||||
}
|
||||
|
||||
var data = {
|
||||
link: this.href,
|
||||
cookieName: this.cookieName,
|
||||
character: responseData.character
|
||||
};
|
||||
if(responseData.hasOwnProperty('character')){
|
||||
|
||||
var data = {
|
||||
link: this.characterElement.data('href'),
|
||||
cookieName: this.cookieName,
|
||||
character: responseData.character
|
||||
};
|
||||
|
||||
requirejs(['text!templates/ui/character_panel.html', 'mustache'], function(template, Mustache) {
|
||||
var content = Mustache.render(template, data);
|
||||
characterElement.html(content);
|
||||
this.characterElement.html(content);
|
||||
|
||||
// show character panel (animation settings)
|
||||
initCharacterAnimation(characterElement.find('.' + config.characterImageWrapperClass));
|
||||
});
|
||||
}else{
|
||||
initCharacterAnimation(this.characterElement.find('.' + config.characterImageWrapperClass));
|
||||
}else{
|
||||
// character data not available -> remove panel
|
||||
removeCharacterPanel(this.characterElement);
|
||||
}
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var characterElement = this.characterElement;
|
||||
characterElement.hideLoadingAnimation();
|
||||
|
||||
// character data not available -> remove panel
|
||||
removeCharacterPanel(this.characterElement);
|
||||
}
|
||||
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var characterElement = this.characterElement;
|
||||
characterElement.hideLoadingAnimation();
|
||||
|
||||
// character data not available -> remove panel
|
||||
removeCharacterPanel(this.characterElement);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* default ajax error handler
|
||||
* -> show user notifications
|
||||
|
||||
@@ -1415,7 +1415,7 @@ define([
|
||||
{subIcon: '', subAction: 'filter_jumpbridge', subText: 'jumpbridge'}
|
||||
]},
|
||||
{divider: true, action: 'delete_systems'},
|
||||
{icon: 'fa-eraser', action: 'delete_systems', text: 'delete systems'}
|
||||
{icon: 'fa-trash', action: 'delete_systems', text: 'delete systems'}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1452,7 +1452,7 @@ define([
|
||||
|
||||
]},
|
||||
{divider: true, action: 'delete_connection'},
|
||||
{icon: 'fa-eraser', action: 'delete_connection', text: 'delete'}
|
||||
{icon: 'fa-trash', action: 'delete_connection', text: 'delete'}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1495,7 +1495,7 @@ define([
|
||||
{subIcon: 'fa-step-forward', subAction: 'add_last_waypoint', subText: 'add new [end]'}
|
||||
]},
|
||||
{divider: true, action: 'delete_system'},
|
||||
{icon: 'fa-eraser', action: 'delete_system', text: 'delete system(s)'}
|
||||
{icon: 'fa-trash', action: 'delete_system', text: 'delete system(s)'}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ define([
|
||||
Init.maxSharedCount = initData.maxSharedCount;
|
||||
Init.routes = initData.routes;
|
||||
Init.notificationStatus = initData.notificationStatus;
|
||||
Init.activityLogging = initData.activityLogging;
|
||||
|
||||
// init tab change observer, Once the timers are available
|
||||
Page.initTabChangeObserver();
|
||||
|
||||
119
js/app/page.js
119
js/app/page.js
@@ -12,6 +12,7 @@ define([
|
||||
'text!templates/modules/header.html',
|
||||
'text!templates/modules/footer.html',
|
||||
'dialog/notification',
|
||||
'dialog/stats',
|
||||
'dialog/map_info',
|
||||
'dialog/account_settings',
|
||||
'dialog/manual',
|
||||
@@ -115,6 +116,22 @@ define([
|
||||
setDocumentObserver();
|
||||
};
|
||||
|
||||
/**
|
||||
* get main menu title element
|
||||
* @param title
|
||||
* @returns {JQuery|*|jQuery}
|
||||
*/
|
||||
var getMenuHeadline = function(title){
|
||||
return $('<div>', {
|
||||
class: 'panel-heading'
|
||||
}).prepend(
|
||||
$('<h2>',{
|
||||
class: 'panel-title',
|
||||
text: title
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* load left menu content options
|
||||
*/
|
||||
@@ -132,20 +149,27 @@ define([
|
||||
class: 'fa fa-home fa-fw'
|
||||
})
|
||||
)
|
||||
).append(
|
||||
getMenuHeadline('Information')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Settings').prepend(
|
||||
}).html(' Statistics').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-sliders fa-fw'
|
||||
class: 'fa fa-line-chart fa-fw'
|
||||
})
|
||||
).append(
|
||||
$('<span>',{
|
||||
class: 'badge bg-color bg-color-gray txt-color txt-color-warning',
|
||||
text: 'beta'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
$(document).triggerMenuEvent('ShowStatsDialog');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Effect info').prepend(
|
||||
$('<i>',{
|
||||
@@ -156,7 +180,7 @@ define([
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Jump info').prepend(
|
||||
$('<i>',{
|
||||
@@ -165,6 +189,19 @@ define([
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowJumpInfo');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Settings')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Account').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-sliders fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item hide', // trigger by js
|
||||
@@ -197,9 +234,11 @@ define([
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('NotificationTest');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Danger zone')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-danger',
|
||||
href: '#'
|
||||
}).html(' Delete account').prepend(
|
||||
$('<i>',{
|
||||
@@ -210,7 +249,7 @@ define([
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-warning',
|
||||
href: '#'
|
||||
}).html(' Logout').prepend(
|
||||
$('<i>',{
|
||||
@@ -240,24 +279,26 @@ define([
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Info').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-info fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
}).html(' Status').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-info fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Settings')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Settings').prepend(
|
||||
}).html(' Map config').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-sliders fa-fw'
|
||||
class: 'fa fa-gears fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapSettings', {tab: 'settings'});
|
||||
})
|
||||
$(document).triggerMenuEvent('ShowMapSettings', {tab: 'settings'});
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
@@ -289,34 +330,38 @@ define([
|
||||
});
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Task-Manager').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-tasks fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowTaskManager');
|
||||
})
|
||||
getMenuHeadline('Help')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Manual').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-info fa-fw'
|
||||
class: 'fa fa-book fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('Manual');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Delete').prepend(
|
||||
}).html(' Task-Manager').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-eraser fa-fw'
|
||||
class: 'fa fa-tasks fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowTaskManager');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Danger zone')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item list-group-item-danger',
|
||||
href: '#'
|
||||
}).html(' Delete map').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-trash fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('DeleteMap');
|
||||
@@ -494,8 +539,14 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowStatsDialog', function(e){
|
||||
// show user activity stats dialog
|
||||
$.fn.showStatsDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowSystemEffectInfo', function(e){
|
||||
// show system effects info box
|
||||
// show system effects dialog
|
||||
$.fn.showSystemEffectInfoDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -295,12 +295,7 @@ define([
|
||||
order: [[ 9, 'desc' ], [ 3, 'asc' ]],
|
||||
autoWidth: false,
|
||||
responsive: {
|
||||
breakpoints: [
|
||||
{ name: 'desktop', width: Infinity },
|
||||
{ name: 'tablet', width: 1200 },
|
||||
{ name: 'fablet', width: 780 },
|
||||
{ name: 'phone', width: 480 }
|
||||
],
|
||||
breakpoints: Init.breakpoints,
|
||||
details: false
|
||||
},
|
||||
hover: false,
|
||||
|
||||
711
js/app/ui/dialog/stats.js
Normal file
711
js/app/ui/dialog/stats.js
Normal file
@@ -0,0 +1,711 @@
|
||||
/**
|
||||
* activity stats dialog
|
||||
*/
|
||||
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox'
|
||||
], function($, Init, Util, Render, bootbox, MapUtil) {
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
// dialog
|
||||
statsDialogId: 'pf-stats-dialog', // id for "stats" dialog
|
||||
dialogNavigationClass: 'pf-dialog-navigation-list', // class for dialog navigation bar
|
||||
dialogNavigationListItemClass: 'pf-dialog-navigation-list-item', // class for map manual li main navigation elements
|
||||
|
||||
dialogNavigationOffsetClass : 'pf-dialog-navigation-offset', // class for "current" offset filter
|
||||
dialogNavigationPrevClass : 'pf-dialog-navigation-prev', // class for "prev" period load
|
||||
dialogNavigationNextClass : 'pf-dialog-navigation-next', // class for "next" period load
|
||||
|
||||
// stats/dataTable
|
||||
statsContainerId: 'pf-stats-dialog-container', // class for statistics container (dynamic ajax content)
|
||||
statsTableId: 'pf-stats-table', // id for statistics table element
|
||||
tableImageCellClass: 'pf-table-image-cell', // class for table "image" cells
|
||||
|
||||
// charts
|
||||
statsLineChartClass: 'pf-line-chart' // class for inline chart elements
|
||||
};
|
||||
|
||||
/**
|
||||
* init blank statistics dataTable
|
||||
* @param dialogElement
|
||||
*/
|
||||
var initStatsTable = function(dialogElement){
|
||||
var columnNumberWidth = 35;
|
||||
var lineColor = '#477372';
|
||||
|
||||
// render function for inline-chart columns
|
||||
var renderInlineChartColumn = function(data, type, row, meta){
|
||||
/*
|
||||
switch(data.type){
|
||||
case 'C': lineColor = '#5cb85c'; break;
|
||||
case 'U': lineColor = '#e28a0d'; break;
|
||||
case 'D': lineColor = '#a52521'; break;
|
||||
}*/
|
||||
|
||||
if( /^\d+$/.test(data.data) ){
|
||||
// single digit (e.g. single week filter)
|
||||
return data.data;
|
||||
}else{
|
||||
// period -> prepare line chart
|
||||
return '<span class="' + config.statsLineChartClass + '" data-peity=\'{ "stroke": "' + lineColor + '" }\'>' + data.data + '</span>';
|
||||
}
|
||||
};
|
||||
|
||||
// render function for numeric columns
|
||||
var renderNumericColumn = function(data, type, row, meta){
|
||||
return data.toLocaleString();
|
||||
};
|
||||
|
||||
// get table element
|
||||
// Due to "complex" table headers, they are already rendered and part of the stats.html file
|
||||
var table = dialogElement.find('#' + config.statsTableId);
|
||||
|
||||
var statsTable = table.DataTable({
|
||||
pageLength: 30,
|
||||
lengthMenu: [[10, 20, 30, 50], [10, 20, 30, 50]],
|
||||
paging: true,
|
||||
ordering: true,
|
||||
order: [ 16, 'desc' ],
|
||||
info: true,
|
||||
searching: true,
|
||||
hover: false,
|
||||
autoWidth: false,
|
||||
language: {
|
||||
emptyTable: 'No statistics found',
|
||||
zeroRecords: 'No characters found',
|
||||
lengthMenu: 'Show _MENU_ characters',
|
||||
info: 'Showing _START_ to _END_ of _TOTAL_ characters'
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
title: '<i class="fa fa-hashtag"></i>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: 10,
|
||||
class: 'text-right',
|
||||
data: 'character.id'
|
||||
},{
|
||||
targets: 1,
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: 26,
|
||||
className: ['text-center', config.tableImageCellClass].join(' '),
|
||||
data: 'character',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
return '<img src="' + Init.url.ccpImageServer + 'Character/' + data.id + '_32.jpg" />';
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 2,
|
||||
title: 'name',
|
||||
width: 200,
|
||||
data: 'character',
|
||||
render: {
|
||||
_: 'name',
|
||||
sort: 'name'
|
||||
}
|
||||
},{
|
||||
targets: 3,
|
||||
title: 'last login',
|
||||
searchable: false,
|
||||
width: 70,
|
||||
className: ['text-right', 'separator-right'].join(' '),
|
||||
data: 'character',
|
||||
render: {
|
||||
_: 'lastLogin',
|
||||
sort: 'lastLogin'
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
$(cell).initTimestampCounter();
|
||||
}
|
||||
},{
|
||||
targets: 4,
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'systemCreate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'systemUpdate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 6,
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'systemDelete',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 7,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm', 'separator-right'].join(' '),
|
||||
data: 'systemSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'connectionCreate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 9,
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'connectionUpdate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 10,
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'connectionDelete',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 11,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm', 'separator-right'].join(' '),
|
||||
data: 'connectionSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
},{
|
||||
targets: 12,
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'signatureCreate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 13,
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'signatureUpdate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 14,
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'signatureDelete',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 15,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm', 'separator-right'].join(' '),
|
||||
data: 'signatureSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
},{
|
||||
targets: 16,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: 'text-right',
|
||||
data: 'totalSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
}
|
||||
],
|
||||
initComplete: function(settings){
|
||||
var tableApi = this.api();
|
||||
|
||||
// initial statistics data request
|
||||
var requestData = getRequestDataFromTabPanels(dialogElement);
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
this.api().rows().nodes().to$().each(function(i, row){
|
||||
$(row).find('.' + config.statsLineChartClass).peity('line', {
|
||||
fill: 'transparent',
|
||||
height: 18,
|
||||
min: 0,
|
||||
width: 50
|
||||
});
|
||||
});
|
||||
},
|
||||
footerCallback: function ( row, data, start, end, display ) {
|
||||
var api = this.api();
|
||||
var sumColumnIndexes = [7, 11, 15, 16];
|
||||
|
||||
// column data for "sum" columns over this page
|
||||
var pageTotalColumns = api
|
||||
.columns( sumColumnIndexes, { page: 'current'} )
|
||||
.data();
|
||||
|
||||
// sum columns for "total" sum
|
||||
pageTotalColumns.each(function(colData, index){
|
||||
pageTotalColumns[index] = colData.reduce(function(a, b){
|
||||
return a + b;
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$(sumColumnIndexes).each(function(index, value){
|
||||
$( api.column( value ).footer() ).text( renderNumericColumn(pageTotalColumns[index]) );
|
||||
});
|
||||
},
|
||||
data: [] // will be added dynamic
|
||||
});
|
||||
|
||||
statsTable.on('order.dt search.dt', function(){
|
||||
statsTable.column(0, {search:'applied', order:'applied'}).nodes().each(function(cell, i){
|
||||
$(cell).html( (i + 1) + '. ');
|
||||
});
|
||||
}).draw();
|
||||
|
||||
var tooltipElements = dialogElement.find('[data-toggle="tooltip"]');
|
||||
tooltipElements.tooltip();
|
||||
};
|
||||
|
||||
/**
|
||||
* request raw statistics data and execute callback
|
||||
* @param requestData
|
||||
* @param context
|
||||
*/
|
||||
var getStatsData = function(requestData, context){
|
||||
|
||||
context.dynamicArea = $('#' + config.statsContainerId + ' .pf-dynamic-area');
|
||||
context.dynamicArea.showLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.getStatisticsData,
|
||||
data: requestData,
|
||||
dataType: 'json',
|
||||
context: context
|
||||
}).done(function(data){
|
||||
this.dynamicArea.hideLoadingAnimation();
|
||||
|
||||
this.callback(data);
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': loadStatistics', text: reason, type: 'warning'});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* update dataTable with response data
|
||||
* update "header"/"filter" elements in dialog
|
||||
* @param responseData
|
||||
*/
|
||||
var drawStatsTable = function(responseData){
|
||||
var dialogElement = $('#' + config.statsDialogId);
|
||||
|
||||
// update filter/header -----------------------------------------------------------------------------
|
||||
var navigationListElements = $('.' + config.dialogNavigationClass);
|
||||
navigationListElements.find('a[data-type="typeId"][data-value="' + responseData.typeId + '"]').tab('show');
|
||||
navigationListElements.find('a[data-type="period"][data-value="' + responseData.period + '"]').tab('show');
|
||||
|
||||
// update period pagination -------------------------------------------------------------------------
|
||||
var prevButton = dialogElement.find('.' + config.dialogNavigationPrevClass);
|
||||
prevButton.data('newOffset', responseData.prev);
|
||||
prevButton.find('span').text('Week ' + responseData.prev.week + ', ' + responseData.prev.year);
|
||||
prevButton.css('visibility', 'visible');
|
||||
|
||||
var nextButton = dialogElement.find('.' + config.dialogNavigationNextClass);
|
||||
if(responseData.next){
|
||||
nextButton.data('newOffset', responseData.next);
|
||||
nextButton.find('span').text('Week ' + responseData.next.week + ', ' + responseData.next.year);
|
||||
nextButton.css('visibility', 'visible');
|
||||
}else{
|
||||
nextButton.css('visibility', 'hidden');
|
||||
}
|
||||
|
||||
// update current period information label ----------------------------------------------------------
|
||||
// if period == "weekly" there is no "offset" -> just a single week
|
||||
var offsetText = 'Week ' + responseData.start.week + ', ' + responseData.start.year;
|
||||
if(responseData.period !== 'weekly'){
|
||||
offsetText += ' <small><i class="fa fa-fw fa-minus"></i></small> ' +
|
||||
'Week ' + responseData.offset.week + ', ' + responseData.offset.year;
|
||||
}
|
||||
dialogElement.find('.' + config.dialogNavigationOffsetClass)
|
||||
.data('start', responseData.start)
|
||||
.data('period', responseData.period)
|
||||
.html(offsetText);
|
||||
|
||||
// clear and (re)-fill table ------------------------------------------------------------------------
|
||||
var formattedData = formatStatisticsData(responseData);
|
||||
this.tableApi.clear();
|
||||
this.tableApi.rows.add(formattedData).draw();
|
||||
};
|
||||
|
||||
/**
|
||||
* format statistics data for dataTable
|
||||
* -> e.g. format inline-chart data
|
||||
* @param statsData
|
||||
* @returns {Array}
|
||||
*/
|
||||
var formatStatisticsData = function(statsData){
|
||||
var formattedData = [];
|
||||
var yearStart = statsData.start.year;
|
||||
var weekStart = statsData.start.week;
|
||||
var weekCount = statsData.weekCount;
|
||||
var yearWeeks = statsData.yearWeeks;
|
||||
|
||||
var tempRand = function(min, max){
|
||||
return Math.random() * (max - min) + min;
|
||||
};
|
||||
|
||||
// format/sum week statistics data for inline charts
|
||||
var formatWeekData = function(weeksData){
|
||||
var currentYear = yearStart;
|
||||
var currentWeek = weekStart;
|
||||
|
||||
var formattedWeeksData = {
|
||||
systemCreate: [],
|
||||
systemUpdate: [],
|
||||
systemDelete: [],
|
||||
connectionCreate: [],
|
||||
connectionUpdate: [],
|
||||
connectionDelete: [],
|
||||
signatureCreate: [],
|
||||
signatureUpdate: [],
|
||||
signatureDelete: [],
|
||||
systemSum: 0,
|
||||
connectionSum: 0,
|
||||
signatureSum: 0
|
||||
};
|
||||
|
||||
for(let i = 0; i < weekCount; i++){
|
||||
let yearWeekProp = currentYear + '' + currentWeek;
|
||||
|
||||
if(weeksData.hasOwnProperty( yearWeekProp )){
|
||||
let weekData = weeksData[ yearWeekProp ];
|
||||
|
||||
// system -------------------------------------------------------------------------------
|
||||
formattedWeeksData.systemCreate.push( weekData.systemCreate );
|
||||
formattedWeeksData.systemSum += parseInt( weekData.systemCreate );
|
||||
|
||||
formattedWeeksData.systemUpdate.push( weekData.systemUpdate );
|
||||
formattedWeeksData.systemSum += parseInt( weekData.systemUpdate );
|
||||
|
||||
formattedWeeksData.systemDelete.push( weekData.systemDelete );
|
||||
formattedWeeksData.systemSum += parseInt( weekData.systemDelete );
|
||||
|
||||
// connection ---------------------------------------------------------------------------
|
||||
formattedWeeksData.connectionCreate.push( weekData.connectionCreate );
|
||||
formattedWeeksData.connectionSum += parseInt( weekData.connectionCreate );
|
||||
|
||||
formattedWeeksData.connectionUpdate.push( weekData.connectionUpdate );
|
||||
formattedWeeksData.connectionSum += parseInt( weekData.connectionUpdate );
|
||||
|
||||
formattedWeeksData.connectionDelete.push( weekData.connectionDelete );
|
||||
formattedWeeksData.connectionSum += parseInt( weekData.connectionDelete );
|
||||
|
||||
// signature ----------------------------------------------------------------------------
|
||||
formattedWeeksData.signatureCreate.push( weekData.signatureCreate );
|
||||
formattedWeeksData.signatureSum += parseInt( weekData.signatureCreate );
|
||||
|
||||
formattedWeeksData.signatureUpdate.push( weekData.signatureUpdate );
|
||||
formattedWeeksData.signatureSum += parseInt( weekData.signatureUpdate );
|
||||
|
||||
formattedWeeksData.signatureDelete.push( weekData.signatureDelete );
|
||||
formattedWeeksData.signatureSum += parseInt( weekData.signatureDelete );
|
||||
}else{
|
||||
// system -------------------------------------------------------------------------------
|
||||
formattedWeeksData.systemCreate.push(0);
|
||||
formattedWeeksData.systemUpdate.push(0);
|
||||
formattedWeeksData.systemDelete.push(0);
|
||||
|
||||
// connection ---------------------------------------------------------------------------
|
||||
formattedWeeksData.connectionCreate.push(0);
|
||||
formattedWeeksData.connectionUpdate.push(0);
|
||||
formattedWeeksData.connectionDelete.push(0);
|
||||
|
||||
// signature ----------------------------------------------------------------------------
|
||||
formattedWeeksData.signatureCreate.push(0);
|
||||
formattedWeeksData.signatureUpdate.push(0);
|
||||
formattedWeeksData.signatureDelete.push(0);
|
||||
}
|
||||
|
||||
currentWeek++;
|
||||
|
||||
if( currentWeek > yearWeeks[currentYear] ){
|
||||
currentWeek = 1;
|
||||
currentYear++;
|
||||
}
|
||||
}
|
||||
|
||||
// system ---------------------------------------------------------------------------------------
|
||||
formattedWeeksData.systemCreate = formattedWeeksData.systemCreate.join(',');
|
||||
formattedWeeksData.systemUpdate = formattedWeeksData.systemUpdate.join(',');
|
||||
formattedWeeksData.systemDelete = formattedWeeksData.systemDelete.join(',');
|
||||
|
||||
// connection -----------------------------------------------------------------------------------
|
||||
formattedWeeksData.connectionCreate = formattedWeeksData.connectionCreate.join(',');
|
||||
formattedWeeksData.connectionUpdate = formattedWeeksData.connectionUpdate.join(',');
|
||||
formattedWeeksData.connectionDelete = formattedWeeksData.connectionDelete.join(',');
|
||||
|
||||
// signature ------------------------------------------------------------------------------------
|
||||
formattedWeeksData.signatureCreate = formattedWeeksData.signatureCreate.join(',');
|
||||
formattedWeeksData.signatureUpdate = formattedWeeksData.signatureUpdate.join(',');
|
||||
formattedWeeksData.signatureDelete = formattedWeeksData.signatureDelete.join(',');
|
||||
|
||||
return formattedWeeksData;
|
||||
};
|
||||
|
||||
$.each(statsData.statistics, function(characterId, data){
|
||||
|
||||
var formattedWeeksData = formatWeekData(data.weeks);
|
||||
|
||||
var rowData = {
|
||||
character: {
|
||||
id: characterId,
|
||||
name: data.name,
|
||||
lastLogin: data.lastLogin
|
||||
},
|
||||
systemCreate: {
|
||||
type: 'C',
|
||||
data: formattedWeeksData.systemCreate
|
||||
},
|
||||
systemUpdate: {
|
||||
type: 'U',
|
||||
data: formattedWeeksData.systemUpdate
|
||||
},
|
||||
systemDelete: {
|
||||
type: 'D',
|
||||
data: formattedWeeksData.systemDelete
|
||||
},
|
||||
systemSum: formattedWeeksData.systemSum,
|
||||
connectionCreate: {
|
||||
type: 'C',
|
||||
data: formattedWeeksData.connectionCreate
|
||||
},
|
||||
connectionUpdate: {
|
||||
type: 'U',
|
||||
data: formattedWeeksData.connectionUpdate
|
||||
},
|
||||
connectionDelete: {
|
||||
type: 'D',
|
||||
data: formattedWeeksData.connectionDelete
|
||||
},
|
||||
connectionSum: formattedWeeksData.connectionSum,
|
||||
signatureCreate: {
|
||||
type: 'C',
|
||||
data: formattedWeeksData.signatureCreate
|
||||
},
|
||||
signatureUpdate: {
|
||||
type: 'U',
|
||||
data: formattedWeeksData.signatureUpdate
|
||||
},
|
||||
signatureDelete: {
|
||||
type: 'D',
|
||||
data: formattedWeeksData.signatureDelete
|
||||
},
|
||||
signatureSum: formattedWeeksData.signatureSum,
|
||||
totalSum: formattedWeeksData.systemSum + formattedWeeksData.connectionSum + formattedWeeksData.signatureSum
|
||||
};
|
||||
|
||||
formattedData.push(rowData);
|
||||
});
|
||||
|
||||
return formattedData;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dialogElement
|
||||
* @returns {{}}
|
||||
*/
|
||||
var getRequestDataFromTabPanels = function(dialogElement){
|
||||
var requestData = {};
|
||||
|
||||
// get data from "tab" panel links ------------------------------------------------------------------
|
||||
var navigationListElements = dialogElement.find('.' + config.dialogNavigationClass);
|
||||
navigationListElements.find('.' + config.dialogNavigationListItemClass + '.active a').each(function(){
|
||||
var linkElement = $(this);
|
||||
requestData[linkElement.data('type')]= linkElement.data('value');
|
||||
});
|
||||
|
||||
// get current period (no offset) data (if available) -----------------------------------------------
|
||||
var navigationOffsetElement = dialogElement.find('.' + config.dialogNavigationOffsetClass);
|
||||
var startData = navigationOffsetElement.data('start');
|
||||
var periodOld = navigationOffsetElement.data('period');
|
||||
|
||||
// if period switch was detected
|
||||
// -> "year" and "week" should not be send
|
||||
// -> start from "now"
|
||||
if(
|
||||
requestData.period === periodOld &&
|
||||
startData
|
||||
){
|
||||
requestData.year = startData.year;
|
||||
requestData.week = startData.week;
|
||||
}
|
||||
|
||||
return requestData;
|
||||
};
|
||||
|
||||
/**
|
||||
* check if "activity log" type is enabled for a group
|
||||
* @param type
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var isTabTypeEnabled = function(type){
|
||||
var enabled = false;
|
||||
|
||||
switch(type){
|
||||
case 'private':
|
||||
if(Init.activityLogging.character){
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
case 'corporation':
|
||||
if(
|
||||
Init.activityLogging.corporation &&
|
||||
Util.getCurrentUserInfo('corporationId')
|
||||
){
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
case 'alliance':
|
||||
if(
|
||||
Init.activityLogging.alliance &&
|
||||
Util.getCurrentUserInfo('allianceId')
|
||||
){
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* show activity stats dialog
|
||||
*/
|
||||
$.fn.showStatsDialog = function(){
|
||||
requirejs(['text!templates/dialog/stats.html', 'mustache', 'peityInlineChart'], function(template, Mustache) {
|
||||
|
||||
var data = {
|
||||
id: config.statsDialogId,
|
||||
dialogNavigationClass: config.dialogNavigationClass,
|
||||
dialogNavLiClass: config.dialogNavigationListItemClass,
|
||||
enablePrivateTab: isTabTypeEnabled('private'),
|
||||
enableCorporationTab: isTabTypeEnabled('corporation'),
|
||||
enableAllianceTab: isTabTypeEnabled('alliance'),
|
||||
statsContainerId: config.statsContainerId,
|
||||
statsTableId: config.statsTableId,
|
||||
dialogNavigationOffsetClass: config.dialogNavigationOffsetClass,
|
||||
dialogNavigationPrevClass: config.dialogNavigationPrevClass,
|
||||
dialogNavigationNextClass: config.dialogNavigationNextClass
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, data);
|
||||
|
||||
var statsDialog = bootbox.dialog({
|
||||
title: 'Statistics',
|
||||
message: content,
|
||||
size: 'large',
|
||||
show: false,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'close',
|
||||
className: 'btn-default'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// model events
|
||||
statsDialog.on('show.bs.modal', function(e) {
|
||||
var dialogElement = $(e.target);
|
||||
|
||||
initStatsTable(dialogElement);
|
||||
});
|
||||
|
||||
// Tab module events
|
||||
statsDialog.find('a[data-toggle="tab"]').on('show.bs.tab', function (e, b, c) {
|
||||
if( $(e.target).parent().hasClass('disabled') ){
|
||||
// no action on "disabled" tabs
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
statsDialog.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var requestData = getRequestDataFromTabPanels(statsDialog);
|
||||
var tableApi = statsDialog.find('#' + config.statsTableId).DataTable();
|
||||
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
});
|
||||
|
||||
// offset change links
|
||||
statsDialog.find('.' + config.dialogNavigationPrevClass + ', .' + config.dialogNavigationNextClass).on('click', function(){
|
||||
var offsetData = $(this).data('newOffset');
|
||||
if(offsetData){
|
||||
// this should NEVER fail!
|
||||
// get "base" request data (e.g. typeId, period)
|
||||
// --> overwrite period data with new period data
|
||||
var tmpRequestData = getRequestDataFromTabPanels(statsDialog);
|
||||
var requestData = $.extend({}, tmpRequestData, offsetData);
|
||||
var tableApi = statsDialog.find('#' + config.statsTableId).DataTable();
|
||||
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
}
|
||||
});
|
||||
|
||||
// show dialog
|
||||
statsDialog.modal('show');
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -316,7 +316,7 @@ define([
|
||||
var settingsDialog = bootbox.dialog({
|
||||
title: 'Route settings',
|
||||
message: content,
|
||||
show: false,
|
||||
show: false,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'cancel',
|
||||
@@ -444,7 +444,6 @@ define([
|
||||
data: requestData,
|
||||
context: context
|
||||
}).done(function(routesData){
|
||||
|
||||
this.moduleElement.hideLoadingAnimation();
|
||||
|
||||
// execute callback
|
||||
@@ -886,7 +885,14 @@ define([
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* draw route table
|
||||
* @param mapId
|
||||
* @param moduleElement
|
||||
* @param systemFromData
|
||||
* @param routesTable
|
||||
* @param systemsTo
|
||||
*/
|
||||
var drawRouteTable = function(mapId, moduleElement, systemFromData, routesTable, systemsTo){
|
||||
var requestRouteData = [];
|
||||
var currentTimestamp = Util.getServerTime().getTime();
|
||||
|
||||
@@ -121,7 +121,9 @@ define([
|
||||
var loadingElement = $(this);
|
||||
var overlay = loadingElement.find('.' + config.ajaxOverlayClass );
|
||||
|
||||
$(overlay).velocity('reverse', {
|
||||
// important: "stop" is required to stop "show" animation
|
||||
// -> otherwise "complete" callback is not fired!
|
||||
$(overlay).velocity('stop').velocity('reverse', {
|
||||
complete: function(){
|
||||
$(this).remove();
|
||||
// enable all events
|
||||
|
||||
13
js/lib/jquery.peity.min.js
vendored
Normal file
13
js/lib/jquery.peity.min.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Peity jQuery plugin version 3.2.0
|
||||
// (c) 2015 Ben Pickles
|
||||
//
|
||||
// http://benpickles.github.io/peity
|
||||
//
|
||||
// Released under MIT license.
|
||||
(function(k,w,h,v){var d=k.fn.peity=function(a,b){y&&this.each(function(){var e=k(this),c=e.data("_peity");c?(a&&(c.type=a),k.extend(c.opts,b)):(c=new x(e,a,k.extend({},d.defaults[a],e.data("peity"),b)),e.change(function(){c.draw()}).data("_peity",c));c.draw()});return this},x=function(a,b,e){this.$el=a;this.type=b;this.opts=e},o=x.prototype,q=o.svgElement=function(a,b){return k(w.createElementNS("http://www.w3.org/2000/svg",a)).attr(b)},y="createElementNS"in w&&q("svg",{})[0].createSVGRect;o.draw=
|
||||
function(){var a=this.opts;d.graphers[this.type].call(this,a);a.after&&a.after.call(this,a)};o.fill=function(){var a=this.opts.fill;return k.isFunction(a)?a:function(b,e){return a[e%a.length]}};o.prepare=function(a,b){this.$svg||this.$el.hide().after(this.$svg=q("svg",{"class":"peity"}));return this.$svg.empty().data("peity",this).attr({height:b,width:a})};o.values=function(){return k.map(this.$el.text().split(this.opts.delimiter),function(a){return parseFloat(a)})};d.defaults={};d.graphers={};d.register=
|
||||
function(a,b,e){this.defaults[a]=b;this.graphers[a]=e};d.register("pie",{fill:["#ff9900","#fff4dd","#ffc66e"],radius:8},function(a){if(!a.delimiter){var b=this.$el.text().match(/[^0-9\.]/);a.delimiter=b?b[0]:","}b=k.map(this.values(),function(a){return 0<a?a:0});if("/"==a.delimiter)var e=b[0],b=[e,h.max(0,b[1]-e)];for(var c=0,e=b.length,t=0;c<e;c++)t+=b[c];t||(e=2,t=1,b=[0,1]);var l=2*a.radius,l=this.prepare(a.width||l,a.height||l),c=l.width(),f=l.height(),j=c/2,d=f/2,f=h.min(j,d),a=a.innerRadius;
|
||||
"donut"==this.type&&!a&&(a=0.5*f);for(var r=h.PI,s=this.fill(),g=this.scale=function(a,b){var c=a/t*r*2-r/2;return[b*h.cos(c)+j,b*h.sin(c)+d]},m=0,c=0;c<e;c++){var u=b[c],i=u/t;if(0!=i){if(1==i)if(a)var i=j-0.01,p=d-f,n=d-a,i=q("path",{d:["M",j,p,"A",f,f,0,1,1,i,p,"L",i,n,"A",a,a,0,1,0,j,n].join(" ")});else i=q("circle",{cx:j,cy:d,r:f});else p=m+u,n=["M"].concat(g(m,f),"A",f,f,0,0.5<i?1:0,1,g(p,f),"L"),a?n=n.concat(g(p,a),"A",a,a,0,0.5<i?1:0,0,g(m,a)):n.push(j,d),m+=u,i=q("path",{d:n.join(" ")});
|
||||
i.attr("fill",s.call(this,u,c,b));l.append(i)}}});d.register("donut",k.extend(!0,{},d.defaults.pie),function(a){d.graphers.pie.call(this,a)});d.register("line",{delimiter:",",fill:"#c6d9fd",height:16,min:0,stroke:"#4d89f9",strokeWidth:1,width:32},function(a){var b=this.values();1==b.length&&b.push(b[0]);for(var e=h.max.apply(h,a.max==v?b:b.concat(a.max)),c=h.min.apply(h,a.min==v?b:b.concat(a.min)),d=this.prepare(a.width,a.height),l=a.strokeWidth,f=d.width(),j=d.height()-l,k=e-c,e=this.x=function(a){return a*
|
||||
(f/(b.length-1))},r=this.y=function(a){var b=j;k&&(b-=(a-c)/k*j);return b+l/2},s=r(h.max(c,0)),g=[0,s],m=0;m<b.length;m++)g.push(e(m),r(b[m]));g.push(f,s);a.fill&&d.append(q("polygon",{fill:a.fill,points:g.join(" ")}));l&&d.append(q("polyline",{fill:"none",points:g.slice(2,g.length-2).join(" "),stroke:a.stroke,"stroke-width":l,"stroke-linecap":"square"}))});d.register("bar",{delimiter:",",fill:["#4D89F9"],height:16,min:0,padding:0.1,width:32},function(a){for(var b=this.values(),e=h.max.apply(h,a.max==
|
||||
v?b:b.concat(a.max)),c=h.min.apply(h,a.min==v?b:b.concat(a.min)),d=this.prepare(a.width,a.height),l=d.width(),f=d.height(),j=e-c,a=a.padding,k=this.fill(),r=this.x=function(a){return a*l/b.length},s=this.y=function(a){return f-(j?(a-c)/j*f:1)},g=0;g<b.length;g++){var m=r(g+a),u=r(g+1-a)-m,i=b[g],p=s(i),n=p,o;j?0>i?n=s(h.min(e,0)):p=s(h.max(c,0)):o=1;o=p-n;0==o&&(o=1,0<e&&j&&n--);d.append(q("rect",{fill:k.call(this,i,g,b),x:m,y:n,width:u,height:o}))}})})(jQuery,document,Math);
|
||||
File diff suppressed because one or more lines are too long
BIN
public/img/landing/statistics_2.jpg
Normal file
BIN
public/img/landing/statistics_2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 55 KiB |
BIN
public/img/landing/thumbs/statistics_2.jpg
Normal file
BIN
public/img/landing/thumbs/statistics_2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.6 KiB |
@@ -38,6 +38,7 @@ requirejs.config({
|
||||
raphael: 'lib/raphael-min', // v2.1.2 Raphaël - required for morris (dependency)
|
||||
bootbox: 'lib/bootbox.min', // v4.4.0 Bootbox.js - custom dialogs - http://bootboxjs.com
|
||||
easyPieChart: 'lib/jquery.easypiechart.min', // v2.1.6 Easy Pie Chart - HTML 5 pie charts - http://rendro.github.io/easy-pie-chart
|
||||
peityInlineChart: 'lib/jquery.peity.min', // v3.2.0 Inline Chart - http://benpickles.github.io/peity/
|
||||
dragToSelect: 'lib/jquery.dragToSelect', // v1.1 Drag to Select - http://andreaslagerkvist.com/jquery/drag-to-select
|
||||
hoverIntent: 'lib/jquery.hoverIntent.minified', // v1.8.0 Hover intention - http://cherne.net/brian/resources/jquery.hoverIntent.html
|
||||
fullScreen: 'lib/jquery.fullscreen.min', // v0.5.0 Full screen mode - https://github.com/private-face/jquery.fullscreen
|
||||
@@ -123,6 +124,9 @@ requirejs.config({
|
||||
easyPieChart: {
|
||||
deps : ['jquery']
|
||||
},
|
||||
peityInlineChart: {
|
||||
deps : ['jquery']
|
||||
},
|
||||
dragToSelect: {
|
||||
deps : ['jquery']
|
||||
},
|
||||
|
||||
@@ -35,7 +35,6 @@ define(['jquery'], function($) {
|
||||
getSystemGraphData: 'api/system/graphData', // ajax URL - get all system graph data
|
||||
getConstellationData: 'api/system/constellationData', // ajax URL - get system constellation data
|
||||
setDestination: 'api/system/setDestination', // ajax URL - set destination
|
||||
|
||||
// connection API
|
||||
saveConnection: 'api/connection/save', // ajax URL - save new connection to map
|
||||
deleteConnection: 'api/connection/delete', // ajax URL - delete connection from map
|
||||
@@ -45,6 +44,8 @@ define(['jquery'], function($) {
|
||||
deleteSignatureData: 'api/signature/delete', // ajax URL - delete signature data for system
|
||||
// route API
|
||||
searchRoute: 'api/route/search', // ajax URL - search system routes
|
||||
// stats API
|
||||
getStatisticsData: 'api/statistic/getData', // ajax URL - get statistics data (activity log)
|
||||
// GitHub API
|
||||
gitHubReleases: 'api/github/releases' // ajax URL - get release info from GitHub
|
||||
},
|
||||
@@ -52,6 +53,12 @@ define(['jquery'], function($) {
|
||||
ccpImageServer: 'https://image.eveonline.com/', // CCP image Server
|
||||
zKillboard: 'https://zkillboard.com/api/' // killboard api
|
||||
},
|
||||
breakpoints: [
|
||||
{ name: 'desktop', width: Infinity },
|
||||
{ name: 'tablet', width: 1200 },
|
||||
{ name: 'fablet', width: 780 },
|
||||
{ name: 'phone', width: 480 }
|
||||
],
|
||||
animationSpeed: {
|
||||
splashOverlay: 300, // "splash" loading overlay
|
||||
headerLink: 100, // links in head bar
|
||||
|
||||
@@ -105,6 +105,14 @@ define([
|
||||
return '';
|
||||
};
|
||||
|
||||
/**
|
||||
* set link observer for "version info" dialog
|
||||
*/
|
||||
var setVersionLinkObserver = function(){
|
||||
$('.' + config.navigationVersionLinkClass).off('click').on('click', function(e){
|
||||
$.fn.releasesDialog();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* set page observer
|
||||
@@ -121,11 +129,6 @@ define([
|
||||
setCookie('cookie', 1, 365);
|
||||
});
|
||||
|
||||
// releases -----------------------------------------------------------
|
||||
$('.' + config.navigationVersionLinkClass).on('click', function(e){
|
||||
$.fn.releasesDialog();
|
||||
});
|
||||
|
||||
// manual -------------------------------------------------------------
|
||||
$('.' + config.navigationLinkManualClass).on('click', function(e){
|
||||
e.preventDefault();
|
||||
@@ -138,6 +141,9 @@ define([
|
||||
$.fn.showCreditsDialog(false, true);
|
||||
});
|
||||
|
||||
// releases -----------------------------------------------------------
|
||||
setVersionLinkObserver();
|
||||
|
||||
// tooltips -----------------------------------------------------------
|
||||
var mapTooltipOptions = {
|
||||
toggle: 'tooltip',
|
||||
@@ -329,6 +335,9 @@ define([
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* init "YouTube" video preview
|
||||
*/
|
||||
var initYoutube = function(){
|
||||
|
||||
$('.youtube').each(function() {
|
||||
@@ -468,6 +477,8 @@ define([
|
||||
notificationPanel.velocity('transition.slideUpIn', {
|
||||
duration: 300,
|
||||
complete: function(){
|
||||
setVersionLinkObserver();
|
||||
|
||||
// mark panel as "shown"
|
||||
Util.getLocalStorage().setItem(storageKey, currentVersion);
|
||||
}
|
||||
|
||||
@@ -1415,7 +1415,7 @@ define([
|
||||
{subIcon: '', subAction: 'filter_jumpbridge', subText: 'jumpbridge'}
|
||||
]},
|
||||
{divider: true, action: 'delete_systems'},
|
||||
{icon: 'fa-eraser', action: 'delete_systems', text: 'delete systems'}
|
||||
{icon: 'fa-trash', action: 'delete_systems', text: 'delete systems'}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1452,7 +1452,7 @@ define([
|
||||
|
||||
]},
|
||||
{divider: true, action: 'delete_connection'},
|
||||
{icon: 'fa-eraser', action: 'delete_connection', text: 'delete'}
|
||||
{icon: 'fa-trash', action: 'delete_connection', text: 'delete'}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -1495,7 +1495,7 @@ define([
|
||||
{subIcon: 'fa-step-forward', subAction: 'add_last_waypoint', subText: 'add new [end]'}
|
||||
]},
|
||||
{divider: true, action: 'delete_system'},
|
||||
{icon: 'fa-eraser', action: 'delete_system', text: 'delete system(s)'}
|
||||
{icon: 'fa-trash', action: 'delete_system', text: 'delete system(s)'}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -62,6 +62,7 @@ define([
|
||||
Init.maxSharedCount = initData.maxSharedCount;
|
||||
Init.routes = initData.routes;
|
||||
Init.notificationStatus = initData.notificationStatus;
|
||||
Init.activityLogging = initData.activityLogging;
|
||||
|
||||
// init tab change observer, Once the timers are available
|
||||
Page.initTabChangeObserver();
|
||||
|
||||
@@ -12,6 +12,7 @@ define([
|
||||
'text!templates/modules/header.html',
|
||||
'text!templates/modules/footer.html',
|
||||
'dialog/notification',
|
||||
'dialog/stats',
|
||||
'dialog/map_info',
|
||||
'dialog/account_settings',
|
||||
'dialog/manual',
|
||||
@@ -115,6 +116,22 @@ define([
|
||||
setDocumentObserver();
|
||||
};
|
||||
|
||||
/**
|
||||
* get main menu title element
|
||||
* @param title
|
||||
* @returns {JQuery|*|jQuery}
|
||||
*/
|
||||
var getMenuHeadline = function(title){
|
||||
return $('<div>', {
|
||||
class: 'panel-heading'
|
||||
}).prepend(
|
||||
$('<h2>',{
|
||||
class: 'panel-title',
|
||||
text: title
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* load left menu content options
|
||||
*/
|
||||
@@ -132,20 +149,27 @@ define([
|
||||
class: 'fa fa-home fa-fw'
|
||||
})
|
||||
)
|
||||
).append(
|
||||
getMenuHeadline('Information')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Settings').prepend(
|
||||
}).html(' Statistics').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-sliders fa-fw'
|
||||
class: 'fa fa-line-chart fa-fw'
|
||||
})
|
||||
).append(
|
||||
$('<span>',{
|
||||
class: 'badge bg-color bg-color-gray txt-color txt-color-warning',
|
||||
text: 'beta'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
$(document).triggerMenuEvent('ShowStatsDialog');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Effect info').prepend(
|
||||
$('<i>',{
|
||||
@@ -156,7 +180,7 @@ define([
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Jump info').prepend(
|
||||
$('<i>',{
|
||||
@@ -165,6 +189,19 @@ define([
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowJumpInfo');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Settings')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Account').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-sliders fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowSettingsDialog');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item hide', // trigger by js
|
||||
@@ -197,9 +234,11 @@ define([
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('NotificationTest');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Danger zone')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-danger',
|
||||
href: '#'
|
||||
}).html(' Delete account').prepend(
|
||||
$('<i>',{
|
||||
@@ -210,7 +249,7 @@ define([
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-warning',
|
||||
href: '#'
|
||||
}).html(' Logout').prepend(
|
||||
$('<i>',{
|
||||
@@ -240,24 +279,26 @@ define([
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Info').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-info fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
}).html(' Status').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-info fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapInfo');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Settings')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Settings').prepend(
|
||||
}).html(' Map config').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-sliders fa-fw'
|
||||
class: 'fa fa-gears fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowMapSettings', {tab: 'settings'});
|
||||
})
|
||||
$(document).triggerMenuEvent('ShowMapSettings', {tab: 'settings'});
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
@@ -289,34 +330,38 @@ define([
|
||||
});
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
href: '#'
|
||||
}).html(' Task-Manager').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-tasks fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowTaskManager');
|
||||
})
|
||||
getMenuHeadline('Help')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Manual').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-info fa-fw'
|
||||
class: 'fa fa-book fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('Manual');
|
||||
})
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item',
|
||||
class: 'list-group-item list-group-item-info',
|
||||
href: '#'
|
||||
}).html(' Delete').prepend(
|
||||
}).html(' Task-Manager').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-eraser fa-fw'
|
||||
class: 'fa fa-tasks fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('ShowTaskManager');
|
||||
})
|
||||
).append(
|
||||
getMenuHeadline('Danger zone')
|
||||
).append(
|
||||
$('<a>', {
|
||||
class: 'list-group-item list-group-item-danger',
|
||||
href: '#'
|
||||
}).html(' Delete map').prepend(
|
||||
$('<i>',{
|
||||
class: 'fa fa-trash fa-fw'
|
||||
})
|
||||
).on('click', function(){
|
||||
$(document).triggerMenuEvent('DeleteMap');
|
||||
@@ -494,8 +539,14 @@ define([
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowStatsDialog', function(e){
|
||||
// show user activity stats dialog
|
||||
$.fn.showStatsDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
$(document).on('pf:menuShowSystemEffectInfo', function(e){
|
||||
// show system effects info box
|
||||
// show system effects dialog
|
||||
$.fn.showSystemEffectInfoDialog();
|
||||
return false;
|
||||
});
|
||||
|
||||
@@ -295,12 +295,7 @@ define([
|
||||
order: [[ 9, 'desc' ], [ 3, 'asc' ]],
|
||||
autoWidth: false,
|
||||
responsive: {
|
||||
breakpoints: [
|
||||
{ name: 'desktop', width: Infinity },
|
||||
{ name: 'tablet', width: 1200 },
|
||||
{ name: 'fablet', width: 780 },
|
||||
{ name: 'phone', width: 480 }
|
||||
],
|
||||
breakpoints: Init.breakpoints,
|
||||
details: false
|
||||
},
|
||||
hover: false,
|
||||
|
||||
711
public/js/v1.1.6/app/ui/dialog/stats.js
Normal file
711
public/js/v1.1.6/app/ui/dialog/stats.js
Normal file
@@ -0,0 +1,711 @@
|
||||
/**
|
||||
* activity stats dialog
|
||||
*/
|
||||
|
||||
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox'
|
||||
], function($, Init, Util, Render, bootbox, MapUtil) {
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
// dialog
|
||||
statsDialogId: 'pf-stats-dialog', // id for "stats" dialog
|
||||
dialogNavigationClass: 'pf-dialog-navigation-list', // class for dialog navigation bar
|
||||
dialogNavigationListItemClass: 'pf-dialog-navigation-list-item', // class for map manual li main navigation elements
|
||||
|
||||
dialogNavigationOffsetClass : 'pf-dialog-navigation-offset', // class for "current" offset filter
|
||||
dialogNavigationPrevClass : 'pf-dialog-navigation-prev', // class for "prev" period load
|
||||
dialogNavigationNextClass : 'pf-dialog-navigation-next', // class for "next" period load
|
||||
|
||||
// stats/dataTable
|
||||
statsContainerId: 'pf-stats-dialog-container', // class for statistics container (dynamic ajax content)
|
||||
statsTableId: 'pf-stats-table', // id for statistics table element
|
||||
tableImageCellClass: 'pf-table-image-cell', // class for table "image" cells
|
||||
|
||||
// charts
|
||||
statsLineChartClass: 'pf-line-chart' // class for inline chart elements
|
||||
};
|
||||
|
||||
/**
|
||||
* init blank statistics dataTable
|
||||
* @param dialogElement
|
||||
*/
|
||||
var initStatsTable = function(dialogElement){
|
||||
var columnNumberWidth = 35;
|
||||
var lineColor = '#477372';
|
||||
|
||||
// render function for inline-chart columns
|
||||
var renderInlineChartColumn = function(data, type, row, meta){
|
||||
/*
|
||||
switch(data.type){
|
||||
case 'C': lineColor = '#5cb85c'; break;
|
||||
case 'U': lineColor = '#e28a0d'; break;
|
||||
case 'D': lineColor = '#a52521'; break;
|
||||
}*/
|
||||
|
||||
if( /^\d+$/.test(data.data) ){
|
||||
// single digit (e.g. single week filter)
|
||||
return data.data;
|
||||
}else{
|
||||
// period -> prepare line chart
|
||||
return '<span class="' + config.statsLineChartClass + '" data-peity=\'{ "stroke": "' + lineColor + '" }\'>' + data.data + '</span>';
|
||||
}
|
||||
};
|
||||
|
||||
// render function for numeric columns
|
||||
var renderNumericColumn = function(data, type, row, meta){
|
||||
return data.toLocaleString();
|
||||
};
|
||||
|
||||
// get table element
|
||||
// Due to "complex" table headers, they are already rendered and part of the stats.html file
|
||||
var table = dialogElement.find('#' + config.statsTableId);
|
||||
|
||||
var statsTable = table.DataTable({
|
||||
pageLength: 30,
|
||||
lengthMenu: [[10, 20, 30, 50], [10, 20, 30, 50]],
|
||||
paging: true,
|
||||
ordering: true,
|
||||
order: [ 16, 'desc' ],
|
||||
info: true,
|
||||
searching: true,
|
||||
hover: false,
|
||||
autoWidth: false,
|
||||
language: {
|
||||
emptyTable: 'No statistics found',
|
||||
zeroRecords: 'No characters found',
|
||||
lengthMenu: 'Show _MENU_ characters',
|
||||
info: 'Showing _START_ to _END_ of _TOTAL_ characters'
|
||||
},
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
title: '<i class="fa fa-hashtag"></i>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: 10,
|
||||
class: 'text-right',
|
||||
data: 'character.id'
|
||||
},{
|
||||
targets: 1,
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: 26,
|
||||
className: ['text-center', config.tableImageCellClass].join(' '),
|
||||
data: 'character',
|
||||
render: {
|
||||
_: function(data, type, row, meta){
|
||||
return '<img src="' + Init.url.ccpImageServer + 'Character/' + data.id + '_32.jpg" />';
|
||||
}
|
||||
}
|
||||
},{
|
||||
targets: 2,
|
||||
title: 'name',
|
||||
width: 200,
|
||||
data: 'character',
|
||||
render: {
|
||||
_: 'name',
|
||||
sort: 'name'
|
||||
}
|
||||
},{
|
||||
targets: 3,
|
||||
title: 'last login',
|
||||
searchable: false,
|
||||
width: 70,
|
||||
className: ['text-right', 'separator-right'].join(' '),
|
||||
data: 'character',
|
||||
render: {
|
||||
_: 'lastLogin',
|
||||
sort: 'lastLogin'
|
||||
},
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
$(cell).initTimestampCounter();
|
||||
}
|
||||
},{
|
||||
targets: 4,
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'systemCreate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'systemUpdate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 6,
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'systemDelete',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 7,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm', 'separator-right'].join(' '),
|
||||
data: 'systemSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'connectionCreate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 9,
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'connectionUpdate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 10,
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'connectionDelete',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 11,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm', 'separator-right'].join(' '),
|
||||
data: 'connectionSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
},{
|
||||
targets: 12,
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'signatureCreate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 13,
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'signatureUpdate',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 14,
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
width: columnNumberWidth,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm'].join(' '),
|
||||
data: 'signatureDelete',
|
||||
render: {
|
||||
_: renderInlineChartColumn
|
||||
}
|
||||
},{
|
||||
targets: 15,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: ['text-right', 'hidden-xs', 'hidden-sm', 'separator-right'].join(' '),
|
||||
data: 'signatureSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
},{
|
||||
targets: 16,
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
className: 'text-right',
|
||||
data: 'totalSum',
|
||||
render: {
|
||||
_: renderNumericColumn
|
||||
}
|
||||
}
|
||||
],
|
||||
initComplete: function(settings){
|
||||
var tableApi = this.api();
|
||||
|
||||
// initial statistics data request
|
||||
var requestData = getRequestDataFromTabPanels(dialogElement);
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
this.api().rows().nodes().to$().each(function(i, row){
|
||||
$(row).find('.' + config.statsLineChartClass).peity('line', {
|
||||
fill: 'transparent',
|
||||
height: 18,
|
||||
min: 0,
|
||||
width: 50
|
||||
});
|
||||
});
|
||||
},
|
||||
footerCallback: function ( row, data, start, end, display ) {
|
||||
var api = this.api();
|
||||
var sumColumnIndexes = [7, 11, 15, 16];
|
||||
|
||||
// column data for "sum" columns over this page
|
||||
var pageTotalColumns = api
|
||||
.columns( sumColumnIndexes, { page: 'current'} )
|
||||
.data();
|
||||
|
||||
// sum columns for "total" sum
|
||||
pageTotalColumns.each(function(colData, index){
|
||||
pageTotalColumns[index] = colData.reduce(function(a, b){
|
||||
return a + b;
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$(sumColumnIndexes).each(function(index, value){
|
||||
$( api.column( value ).footer() ).text( renderNumericColumn(pageTotalColumns[index]) );
|
||||
});
|
||||
},
|
||||
data: [] // will be added dynamic
|
||||
});
|
||||
|
||||
statsTable.on('order.dt search.dt', function(){
|
||||
statsTable.column(0, {search:'applied', order:'applied'}).nodes().each(function(cell, i){
|
||||
$(cell).html( (i + 1) + '. ');
|
||||
});
|
||||
}).draw();
|
||||
|
||||
var tooltipElements = dialogElement.find('[data-toggle="tooltip"]');
|
||||
tooltipElements.tooltip();
|
||||
};
|
||||
|
||||
/**
|
||||
* request raw statistics data and execute callback
|
||||
* @param requestData
|
||||
* @param context
|
||||
*/
|
||||
var getStatsData = function(requestData, context){
|
||||
|
||||
context.dynamicArea = $('#' + config.statsContainerId + ' .pf-dynamic-area');
|
||||
context.dynamicArea.showLoadingAnimation();
|
||||
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: Init.path.getStatisticsData,
|
||||
data: requestData,
|
||||
dataType: 'json',
|
||||
context: context
|
||||
}).done(function(data){
|
||||
this.dynamicArea.hideLoadingAnimation();
|
||||
|
||||
this.callback(data);
|
||||
}).fail(function( jqXHR, status, error) {
|
||||
var reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': loadStatistics', text: reason, type: 'warning'});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* update dataTable with response data
|
||||
* update "header"/"filter" elements in dialog
|
||||
* @param responseData
|
||||
*/
|
||||
var drawStatsTable = function(responseData){
|
||||
var dialogElement = $('#' + config.statsDialogId);
|
||||
|
||||
// update filter/header -----------------------------------------------------------------------------
|
||||
var navigationListElements = $('.' + config.dialogNavigationClass);
|
||||
navigationListElements.find('a[data-type="typeId"][data-value="' + responseData.typeId + '"]').tab('show');
|
||||
navigationListElements.find('a[data-type="period"][data-value="' + responseData.period + '"]').tab('show');
|
||||
|
||||
// update period pagination -------------------------------------------------------------------------
|
||||
var prevButton = dialogElement.find('.' + config.dialogNavigationPrevClass);
|
||||
prevButton.data('newOffset', responseData.prev);
|
||||
prevButton.find('span').text('Week ' + responseData.prev.week + ', ' + responseData.prev.year);
|
||||
prevButton.css('visibility', 'visible');
|
||||
|
||||
var nextButton = dialogElement.find('.' + config.dialogNavigationNextClass);
|
||||
if(responseData.next){
|
||||
nextButton.data('newOffset', responseData.next);
|
||||
nextButton.find('span').text('Week ' + responseData.next.week + ', ' + responseData.next.year);
|
||||
nextButton.css('visibility', 'visible');
|
||||
}else{
|
||||
nextButton.css('visibility', 'hidden');
|
||||
}
|
||||
|
||||
// update current period information label ----------------------------------------------------------
|
||||
// if period == "weekly" there is no "offset" -> just a single week
|
||||
var offsetText = 'Week ' + responseData.start.week + ', ' + responseData.start.year;
|
||||
if(responseData.period !== 'weekly'){
|
||||
offsetText += ' <small><i class="fa fa-fw fa-minus"></i></small> ' +
|
||||
'Week ' + responseData.offset.week + ', ' + responseData.offset.year;
|
||||
}
|
||||
dialogElement.find('.' + config.dialogNavigationOffsetClass)
|
||||
.data('start', responseData.start)
|
||||
.data('period', responseData.period)
|
||||
.html(offsetText);
|
||||
|
||||
// clear and (re)-fill table ------------------------------------------------------------------------
|
||||
var formattedData = formatStatisticsData(responseData);
|
||||
this.tableApi.clear();
|
||||
this.tableApi.rows.add(formattedData).draw();
|
||||
};
|
||||
|
||||
/**
|
||||
* format statistics data for dataTable
|
||||
* -> e.g. format inline-chart data
|
||||
* @param statsData
|
||||
* @returns {Array}
|
||||
*/
|
||||
var formatStatisticsData = function(statsData){
|
||||
var formattedData = [];
|
||||
var yearStart = statsData.start.year;
|
||||
var weekStart = statsData.start.week;
|
||||
var weekCount = statsData.weekCount;
|
||||
var yearWeeks = statsData.yearWeeks;
|
||||
|
||||
var tempRand = function(min, max){
|
||||
return Math.random() * (max - min) + min;
|
||||
};
|
||||
|
||||
// format/sum week statistics data for inline charts
|
||||
var formatWeekData = function(weeksData){
|
||||
var currentYear = yearStart;
|
||||
var currentWeek = weekStart;
|
||||
|
||||
var formattedWeeksData = {
|
||||
systemCreate: [],
|
||||
systemUpdate: [],
|
||||
systemDelete: [],
|
||||
connectionCreate: [],
|
||||
connectionUpdate: [],
|
||||
connectionDelete: [],
|
||||
signatureCreate: [],
|
||||
signatureUpdate: [],
|
||||
signatureDelete: [],
|
||||
systemSum: 0,
|
||||
connectionSum: 0,
|
||||
signatureSum: 0
|
||||
};
|
||||
|
||||
for(let i = 0; i < weekCount; i++){
|
||||
let yearWeekProp = currentYear + '' + currentWeek;
|
||||
|
||||
if(weeksData.hasOwnProperty( yearWeekProp )){
|
||||
let weekData = weeksData[ yearWeekProp ];
|
||||
|
||||
// system -------------------------------------------------------------------------------
|
||||
formattedWeeksData.systemCreate.push( weekData.systemCreate );
|
||||
formattedWeeksData.systemSum += parseInt( weekData.systemCreate );
|
||||
|
||||
formattedWeeksData.systemUpdate.push( weekData.systemUpdate );
|
||||
formattedWeeksData.systemSum += parseInt( weekData.systemUpdate );
|
||||
|
||||
formattedWeeksData.systemDelete.push( weekData.systemDelete );
|
||||
formattedWeeksData.systemSum += parseInt( weekData.systemDelete );
|
||||
|
||||
// connection ---------------------------------------------------------------------------
|
||||
formattedWeeksData.connectionCreate.push( weekData.connectionCreate );
|
||||
formattedWeeksData.connectionSum += parseInt( weekData.connectionCreate );
|
||||
|
||||
formattedWeeksData.connectionUpdate.push( weekData.connectionUpdate );
|
||||
formattedWeeksData.connectionSum += parseInt( weekData.connectionUpdate );
|
||||
|
||||
formattedWeeksData.connectionDelete.push( weekData.connectionDelete );
|
||||
formattedWeeksData.connectionSum += parseInt( weekData.connectionDelete );
|
||||
|
||||
// signature ----------------------------------------------------------------------------
|
||||
formattedWeeksData.signatureCreate.push( weekData.signatureCreate );
|
||||
formattedWeeksData.signatureSum += parseInt( weekData.signatureCreate );
|
||||
|
||||
formattedWeeksData.signatureUpdate.push( weekData.signatureUpdate );
|
||||
formattedWeeksData.signatureSum += parseInt( weekData.signatureUpdate );
|
||||
|
||||
formattedWeeksData.signatureDelete.push( weekData.signatureDelete );
|
||||
formattedWeeksData.signatureSum += parseInt( weekData.signatureDelete );
|
||||
}else{
|
||||
// system -------------------------------------------------------------------------------
|
||||
formattedWeeksData.systemCreate.push(0);
|
||||
formattedWeeksData.systemUpdate.push(0);
|
||||
formattedWeeksData.systemDelete.push(0);
|
||||
|
||||
// connection ---------------------------------------------------------------------------
|
||||
formattedWeeksData.connectionCreate.push(0);
|
||||
formattedWeeksData.connectionUpdate.push(0);
|
||||
formattedWeeksData.connectionDelete.push(0);
|
||||
|
||||
// signature ----------------------------------------------------------------------------
|
||||
formattedWeeksData.signatureCreate.push(0);
|
||||
formattedWeeksData.signatureUpdate.push(0);
|
||||
formattedWeeksData.signatureDelete.push(0);
|
||||
}
|
||||
|
||||
currentWeek++;
|
||||
|
||||
if( currentWeek > yearWeeks[currentYear] ){
|
||||
currentWeek = 1;
|
||||
currentYear++;
|
||||
}
|
||||
}
|
||||
|
||||
// system ---------------------------------------------------------------------------------------
|
||||
formattedWeeksData.systemCreate = formattedWeeksData.systemCreate.join(',');
|
||||
formattedWeeksData.systemUpdate = formattedWeeksData.systemUpdate.join(',');
|
||||
formattedWeeksData.systemDelete = formattedWeeksData.systemDelete.join(',');
|
||||
|
||||
// connection -----------------------------------------------------------------------------------
|
||||
formattedWeeksData.connectionCreate = formattedWeeksData.connectionCreate.join(',');
|
||||
formattedWeeksData.connectionUpdate = formattedWeeksData.connectionUpdate.join(',');
|
||||
formattedWeeksData.connectionDelete = formattedWeeksData.connectionDelete.join(',');
|
||||
|
||||
// signature ------------------------------------------------------------------------------------
|
||||
formattedWeeksData.signatureCreate = formattedWeeksData.signatureCreate.join(',');
|
||||
formattedWeeksData.signatureUpdate = formattedWeeksData.signatureUpdate.join(',');
|
||||
formattedWeeksData.signatureDelete = formattedWeeksData.signatureDelete.join(',');
|
||||
|
||||
return formattedWeeksData;
|
||||
};
|
||||
|
||||
$.each(statsData.statistics, function(characterId, data){
|
||||
|
||||
var formattedWeeksData = formatWeekData(data.weeks);
|
||||
|
||||
var rowData = {
|
||||
character: {
|
||||
id: characterId,
|
||||
name: data.name,
|
||||
lastLogin: data.lastLogin
|
||||
},
|
||||
systemCreate: {
|
||||
type: 'C',
|
||||
data: formattedWeeksData.systemCreate
|
||||
},
|
||||
systemUpdate: {
|
||||
type: 'U',
|
||||
data: formattedWeeksData.systemUpdate
|
||||
},
|
||||
systemDelete: {
|
||||
type: 'D',
|
||||
data: formattedWeeksData.systemDelete
|
||||
},
|
||||
systemSum: formattedWeeksData.systemSum,
|
||||
connectionCreate: {
|
||||
type: 'C',
|
||||
data: formattedWeeksData.connectionCreate
|
||||
},
|
||||
connectionUpdate: {
|
||||
type: 'U',
|
||||
data: formattedWeeksData.connectionUpdate
|
||||
},
|
||||
connectionDelete: {
|
||||
type: 'D',
|
||||
data: formattedWeeksData.connectionDelete
|
||||
},
|
||||
connectionSum: formattedWeeksData.connectionSum,
|
||||
signatureCreate: {
|
||||
type: 'C',
|
||||
data: formattedWeeksData.signatureCreate
|
||||
},
|
||||
signatureUpdate: {
|
||||
type: 'U',
|
||||
data: formattedWeeksData.signatureUpdate
|
||||
},
|
||||
signatureDelete: {
|
||||
type: 'D',
|
||||
data: formattedWeeksData.signatureDelete
|
||||
},
|
||||
signatureSum: formattedWeeksData.signatureSum,
|
||||
totalSum: formattedWeeksData.systemSum + formattedWeeksData.connectionSum + formattedWeeksData.signatureSum
|
||||
};
|
||||
|
||||
formattedData.push(rowData);
|
||||
});
|
||||
|
||||
return formattedData;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param dialogElement
|
||||
* @returns {{}}
|
||||
*/
|
||||
var getRequestDataFromTabPanels = function(dialogElement){
|
||||
var requestData = {};
|
||||
|
||||
// get data from "tab" panel links ------------------------------------------------------------------
|
||||
var navigationListElements = dialogElement.find('.' + config.dialogNavigationClass);
|
||||
navigationListElements.find('.' + config.dialogNavigationListItemClass + '.active a').each(function(){
|
||||
var linkElement = $(this);
|
||||
requestData[linkElement.data('type')]= linkElement.data('value');
|
||||
});
|
||||
|
||||
// get current period (no offset) data (if available) -----------------------------------------------
|
||||
var navigationOffsetElement = dialogElement.find('.' + config.dialogNavigationOffsetClass);
|
||||
var startData = navigationOffsetElement.data('start');
|
||||
var periodOld = navigationOffsetElement.data('period');
|
||||
|
||||
// if period switch was detected
|
||||
// -> "year" and "week" should not be send
|
||||
// -> start from "now"
|
||||
if(
|
||||
requestData.period === periodOld &&
|
||||
startData
|
||||
){
|
||||
requestData.year = startData.year;
|
||||
requestData.week = startData.week;
|
||||
}
|
||||
|
||||
return requestData;
|
||||
};
|
||||
|
||||
/**
|
||||
* check if "activity log" type is enabled for a group
|
||||
* @param type
|
||||
* @returns {boolean}
|
||||
*/
|
||||
var isTabTypeEnabled = function(type){
|
||||
var enabled = false;
|
||||
|
||||
switch(type){
|
||||
case 'private':
|
||||
if(Init.activityLogging.character){
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
case 'corporation':
|
||||
if(
|
||||
Init.activityLogging.corporation &&
|
||||
Util.getCurrentUserInfo('corporationId')
|
||||
){
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
case 'alliance':
|
||||
if(
|
||||
Init.activityLogging.alliance &&
|
||||
Util.getCurrentUserInfo('allianceId')
|
||||
){
|
||||
enabled = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return enabled;
|
||||
};
|
||||
|
||||
/**
|
||||
* show activity stats dialog
|
||||
*/
|
||||
$.fn.showStatsDialog = function(){
|
||||
requirejs(['text!templates/dialog/stats.html', 'mustache', 'peityInlineChart'], function(template, Mustache) {
|
||||
|
||||
var data = {
|
||||
id: config.statsDialogId,
|
||||
dialogNavigationClass: config.dialogNavigationClass,
|
||||
dialogNavLiClass: config.dialogNavigationListItemClass,
|
||||
enablePrivateTab: isTabTypeEnabled('private'),
|
||||
enableCorporationTab: isTabTypeEnabled('corporation'),
|
||||
enableAllianceTab: isTabTypeEnabled('alliance'),
|
||||
statsContainerId: config.statsContainerId,
|
||||
statsTableId: config.statsTableId,
|
||||
dialogNavigationOffsetClass: config.dialogNavigationOffsetClass,
|
||||
dialogNavigationPrevClass: config.dialogNavigationPrevClass,
|
||||
dialogNavigationNextClass: config.dialogNavigationNextClass
|
||||
};
|
||||
|
||||
var content = Mustache.render(template, data);
|
||||
|
||||
var statsDialog = bootbox.dialog({
|
||||
title: 'Statistics',
|
||||
message: content,
|
||||
size: 'large',
|
||||
show: false,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'close',
|
||||
className: 'btn-default'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// model events
|
||||
statsDialog.on('show.bs.modal', function(e) {
|
||||
var dialogElement = $(e.target);
|
||||
|
||||
initStatsTable(dialogElement);
|
||||
});
|
||||
|
||||
// Tab module events
|
||||
statsDialog.find('a[data-toggle="tab"]').on('show.bs.tab', function (e, b, c) {
|
||||
if( $(e.target).parent().hasClass('disabled') ){
|
||||
// no action on "disabled" tabs
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
statsDialog.find('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
|
||||
var requestData = getRequestDataFromTabPanels(statsDialog);
|
||||
var tableApi = statsDialog.find('#' + config.statsTableId).DataTable();
|
||||
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
});
|
||||
|
||||
// offset change links
|
||||
statsDialog.find('.' + config.dialogNavigationPrevClass + ', .' + config.dialogNavigationNextClass).on('click', function(){
|
||||
var offsetData = $(this).data('newOffset');
|
||||
if(offsetData){
|
||||
// this should NEVER fail!
|
||||
// get "base" request data (e.g. typeId, period)
|
||||
// --> overwrite period data with new period data
|
||||
var tmpRequestData = getRequestDataFromTabPanels(statsDialog);
|
||||
var requestData = $.extend({}, tmpRequestData, offsetData);
|
||||
var tableApi = statsDialog.find('#' + config.statsTableId).DataTable();
|
||||
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
}
|
||||
});
|
||||
|
||||
// show dialog
|
||||
statsDialog.modal('show');
|
||||
});
|
||||
};
|
||||
});
|
||||
@@ -316,7 +316,7 @@ define([
|
||||
var settingsDialog = bootbox.dialog({
|
||||
title: 'Route settings',
|
||||
message: content,
|
||||
show: false,
|
||||
show: false,
|
||||
buttons: {
|
||||
close: {
|
||||
label: 'cancel',
|
||||
@@ -444,7 +444,6 @@ define([
|
||||
data: requestData,
|
||||
context: context
|
||||
}).done(function(routesData){
|
||||
|
||||
this.moduleElement.hideLoadingAnimation();
|
||||
|
||||
// execute callback
|
||||
@@ -886,7 +885,14 @@ define([
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* draw route table
|
||||
* @param mapId
|
||||
* @param moduleElement
|
||||
* @param systemFromData
|
||||
* @param routesTable
|
||||
* @param systemsTo
|
||||
*/
|
||||
var drawRouteTable = function(mapId, moduleElement, systemFromData, routesTable, systemsTo){
|
||||
var requestRouteData = [];
|
||||
var currentTimestamp = Util.getServerTime().getTime();
|
||||
|
||||
13
public/js/v1.1.6/lib/jquery.peity.min.js
vendored
Normal file
13
public/js/v1.1.6/lib/jquery.peity.min.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
// Peity jQuery plugin version 3.2.0
|
||||
// (c) 2015 Ben Pickles
|
||||
//
|
||||
// http://benpickles.github.io/peity
|
||||
//
|
||||
// Released under MIT license.
|
||||
(function(k,w,h,v){var d=k.fn.peity=function(a,b){y&&this.each(function(){var e=k(this),c=e.data("_peity");c?(a&&(c.type=a),k.extend(c.opts,b)):(c=new x(e,a,k.extend({},d.defaults[a],e.data("peity"),b)),e.change(function(){c.draw()}).data("_peity",c));c.draw()});return this},x=function(a,b,e){this.$el=a;this.type=b;this.opts=e},o=x.prototype,q=o.svgElement=function(a,b){return k(w.createElementNS("http://www.w3.org/2000/svg",a)).attr(b)},y="createElementNS"in w&&q("svg",{})[0].createSVGRect;o.draw=
|
||||
function(){var a=this.opts;d.graphers[this.type].call(this,a);a.after&&a.after.call(this,a)};o.fill=function(){var a=this.opts.fill;return k.isFunction(a)?a:function(b,e){return a[e%a.length]}};o.prepare=function(a,b){this.$svg||this.$el.hide().after(this.$svg=q("svg",{"class":"peity"}));return this.$svg.empty().data("peity",this).attr({height:b,width:a})};o.values=function(){return k.map(this.$el.text().split(this.opts.delimiter),function(a){return parseFloat(a)})};d.defaults={};d.graphers={};d.register=
|
||||
function(a,b,e){this.defaults[a]=b;this.graphers[a]=e};d.register("pie",{fill:["#ff9900","#fff4dd","#ffc66e"],radius:8},function(a){if(!a.delimiter){var b=this.$el.text().match(/[^0-9\.]/);a.delimiter=b?b[0]:","}b=k.map(this.values(),function(a){return 0<a?a:0});if("/"==a.delimiter)var e=b[0],b=[e,h.max(0,b[1]-e)];for(var c=0,e=b.length,t=0;c<e;c++)t+=b[c];t||(e=2,t=1,b=[0,1]);var l=2*a.radius,l=this.prepare(a.width||l,a.height||l),c=l.width(),f=l.height(),j=c/2,d=f/2,f=h.min(j,d),a=a.innerRadius;
|
||||
"donut"==this.type&&!a&&(a=0.5*f);for(var r=h.PI,s=this.fill(),g=this.scale=function(a,b){var c=a/t*r*2-r/2;return[b*h.cos(c)+j,b*h.sin(c)+d]},m=0,c=0;c<e;c++){var u=b[c],i=u/t;if(0!=i){if(1==i)if(a)var i=j-0.01,p=d-f,n=d-a,i=q("path",{d:["M",j,p,"A",f,f,0,1,1,i,p,"L",i,n,"A",a,a,0,1,0,j,n].join(" ")});else i=q("circle",{cx:j,cy:d,r:f});else p=m+u,n=["M"].concat(g(m,f),"A",f,f,0,0.5<i?1:0,1,g(p,f),"L"),a?n=n.concat(g(p,a),"A",a,a,0,0.5<i?1:0,0,g(m,a)):n.push(j,d),m+=u,i=q("path",{d:n.join(" ")});
|
||||
i.attr("fill",s.call(this,u,c,b));l.append(i)}}});d.register("donut",k.extend(!0,{},d.defaults.pie),function(a){d.graphers.pie.call(this,a)});d.register("line",{delimiter:",",fill:"#c6d9fd",height:16,min:0,stroke:"#4d89f9",strokeWidth:1,width:32},function(a){var b=this.values();1==b.length&&b.push(b[0]);for(var e=h.max.apply(h,a.max==v?b:b.concat(a.max)),c=h.min.apply(h,a.min==v?b:b.concat(a.min)),d=this.prepare(a.width,a.height),l=a.strokeWidth,f=d.width(),j=d.height()-l,k=e-c,e=this.x=function(a){return a*
|
||||
(f/(b.length-1))},r=this.y=function(a){var b=j;k&&(b-=(a-c)/k*j);return b+l/2},s=r(h.max(c,0)),g=[0,s],m=0;m<b.length;m++)g.push(e(m),r(b[m]));g.push(f,s);a.fill&&d.append(q("polygon",{fill:a.fill,points:g.join(" ")}));l&&d.append(q("polyline",{fill:"none",points:g.slice(2,g.length-2).join(" "),stroke:a.stroke,"stroke-width":l,"stroke-linecap":"square"}))});d.register("bar",{delimiter:",",fill:["#4D89F9"],height:16,min:0,padding:0.1,width:32},function(a){for(var b=this.values(),e=h.max.apply(h,a.max==
|
||||
v?b:b.concat(a.max)),c=h.min.apply(h,a.min==v?b:b.concat(a.min)),d=this.prepare(a.width,a.height),l=d.width(),f=d.height(),j=e-c,a=a.padding,k=this.fill(),r=this.x=function(a){return a*l/b.length},s=this.y=function(a){return f-(j?(a-c)/j*f:1)},g=0;g<b.length;g++){var m=r(g+a),u=r(g+1-a)-m,i=b[g],p=s(i),n=p,o;j?0>i?n=s(h.min(e,0)):p=s(h.max(c,0)):o=1;o=p-n;0==o&&(o=1,0<e&&j&&n--);d.append(q("rect",{fill:k.call(this,i,g,b),x:m,y:n,width:u,height:o}))}})})(jQuery,document,Math);
|
||||
@@ -58,7 +58,7 @@
|
||||
<li><i class="fa fa-plus fa-fw"></i> Add a new system at the position, you clicked at</li>
|
||||
<li><i class="fa fa-object-ungroup fa-fw"></i> Select all (unlocked) systems on the map</li>
|
||||
<li><i class="fa fa-filter fa-fw"></i> Filter map connections by a scope <small><a href="#" data-target="#pf-manual-scrollspy-anchor-connection-scope">more</a></small></li>
|
||||
<li><i class="fa fa-eraser fa-fw"></i> Delete selected systems <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a></small></li>
|
||||
<li><i class="fa fa-trash fa-fw"></i> Delete selected systems <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a></small></li>
|
||||
</ul>
|
||||
<h4 id="pf-manual-scrollspy-anchor-map-select"><i class="fa fa-object-ungroup fa-fw"></i> Select methods</h4>
|
||||
<ul class="list-unstyled" style=" margin-left: 10px;">
|
||||
@@ -98,7 +98,7 @@
|
||||
|
||||
<p>
|
||||
Systems are represented by rectangle boxes on a map <small>(<i class="fa fa-code-fork fa-fw"></i><a href="#" data-target="#pf-manual-map">more</a>)</small>.
|
||||
Pilots can interact with systems like "delete systems" <small>(<i class="fa fa-eraser fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a>)</small> or
|
||||
Pilots can interact with systems like "delete systems" <small>(<i class="fa fa-trash fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a>)</small> or
|
||||
"move systems" <small>(<i class="fa fa-arrows-alt fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-move">more</a>)</small>.
|
||||
</p>
|
||||
<h4 id="pf-manual-scrollspy-anchor-system-active">Active system</h4>
|
||||
@@ -176,13 +176,13 @@
|
||||
<li><i class="fa fa-users fa-fw"></i> Set "Rally Point" for this system <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-rally">more</a></small></li>
|
||||
<li><i class="fa fa-tags fa-fw"></i> Changes the status of this system <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-status">more</a></small></li>
|
||||
<li><i class="fa fa-reply fa-rotate-180 fa-fw"></i> Waypoint options for this system <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-waypoint">more</a></small></li>
|
||||
<li><i class="fa fa-eraser fa-fw"></i> Delete this system and all connections <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a></small></li>
|
||||
<li><i class="fa fa-trash fa-fw"></i> Delete this system and all connections <small><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a></small></li>
|
||||
</ul>
|
||||
<h4 id="pf-manual-scrollspy-anchor-system-locked"><i class="fa fa-lock fa-fw"></i> Locked system</h4>
|
||||
<p>
|
||||
Locked systems can´t be selected <small>(<a href="#" data-target="#pf-manual-scrollspy-anchor-map-select">more</a>)</small>,
|
||||
moved <small>(<i class="fa fa-arrows-alt fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-move">more</a>)</small>
|
||||
or deleted <small>(<i class="fa fa-eraser fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a>)</small>.
|
||||
or deleted <small>(<i class="fa fa-trash fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-delete">more</a>)</small>.
|
||||
</p>
|
||||
<h4 id="pf-manual-scrollspy-anchor-system-rally"><i class="fa fa-users fa-fw"></i> Rally point</h4>
|
||||
<p>
|
||||
@@ -199,7 +199,7 @@
|
||||
<li>add new [start] -<small> (add new waypoint in front of your waypoint queue)</small></li>
|
||||
<li>add new [end] -<small> (add new waypoint to the end of your waypoint queue)</small></li>
|
||||
</ul>
|
||||
<h4 id="pf-manual-scrollspy-anchor-system-delete"><i class="fa fa-eraser fa-fw"></i> Delete system</h4>
|
||||
<h4 id="pf-manual-scrollspy-anchor-system-delete"><i class="fa fa-trash fa-fw"></i> Delete system</h4>
|
||||
<p>
|
||||
Any system that is not "Locked" <small>(<i class="fa fa-lock fa-fw"></i><a href="#" data-target="#pf-manual-scrollspy-anchor-system-locked">more</a>)</small> can be deleted from a map.
|
||||
</p>
|
||||
@@ -263,7 +263,7 @@
|
||||
<li><i class="fa fa-warning fa-fw"></i> Toggles this connection as <em>"Preserve Mass"</em> <small><a href="#" data-target="#pf-manual-scrollspy-anchor-connection-mass">more</a></small></li>
|
||||
<li><i class="fa fa-crosshairs fa-fw"></i> Changes the scope of this connection <small><a href="#" data-target="#pf-manual-scrollspy-anchor-connection-scope">more</a></small></li>
|
||||
<li><i class="fa fa-reply fa-rotate-180 fa-fw"></i> Changes the status of this connection <small><a href="#" data-target="#pf-manual-scrollspy-anchor-connection-status">more</a></small></li>
|
||||
<li><i class="fa fa-eraser fa-fw"></i> Delete this connection <small><a href="#" data-target="#pf-manual-scrollspy-anchor-connection-delete">more</a></small></li>
|
||||
<li><i class="fa fa-trash fa-fw"></i> Delete this connection <small><a href="#" data-target="#pf-manual-scrollspy-anchor-connection-delete">more</a></small></li>
|
||||
</ul>
|
||||
<h4 id="pf-manual-scrollspy-anchor-connection-frig"><i class="fa fa-plane fa-fw"></i> Frigate hole</h4>
|
||||
<p>
|
||||
@@ -276,7 +276,7 @@
|
||||
Let your mates know about critical connections that should be mass-saved
|
||||
(e.g. <span class="pf-system-sec-highSec">H</span> security exits) <small>(<a href="#" data-target="#pf-manual-scrollspy-anchor-system-security">more</a>)</small>.
|
||||
</p>
|
||||
<h4 id="pf-manual-scrollspy-anchor-connection-delete"><i class="fa fa-eraser fa-fw"></i> Delete connection</h4>
|
||||
<h4 id="pf-manual-scrollspy-anchor-connection-delete"><i class="fa fa-trash fa-fw"></i> Delete connection</h4>
|
||||
<p>
|
||||
Connections can be detached by several ways.
|
||||
</p>
|
||||
@@ -322,7 +322,7 @@
|
||||
<kbd>click</kbd> the browser tab were <em class="pf-brand">pathfinder</em> is open. Then press <kbd>ctrl</kbd> + <kbd>v</kbd>.<br>
|
||||
<em class="pf-brand">pathfinder</em> automatically detect the data format and updates the <em>"Signature table"</em>.
|
||||
</p>
|
||||
<h4><i class="fa fa-eraser fa-fw"></i> Delete signatures</h4>
|
||||
<h4><i class="fa fa-trash fa-fw"></i> Delete signatures</h4>
|
||||
<p>
|
||||
Signatures can be detached by several ways.
|
||||
</p>
|
||||
|
||||
117
public/templates/dialog/stats.html
Normal file
117
public/templates/dialog/stats.html
Normal file
@@ -0,0 +1,117 @@
|
||||
<div id="{{id}}">
|
||||
<nav class="navbar navbar-default" role="navigation">
|
||||
<div class="navbar-header pull-left">
|
||||
<ul class="nav navbar-nav {{dialogNavigationClass}}">
|
||||
<li class="{{dialogNavLiClass}} {{^enablePrivateTab}} disabled {{/enablePrivateTab}}">
|
||||
<a role="tab" data-toggle="tab" data-type="typeId" data-value="2" href="#{{statsContainerId}}">Private</a>
|
||||
</li>
|
||||
<li class="{{dialogNavLiClass}} active {{^enableCorporationTab}} disabled {{/enableCorporationTab}}">
|
||||
<a role="tab" data-toggle="tab" data-type="typeId" data-value="3" href="#{{statsContainerId}}">Corporation</a>
|
||||
</li>
|
||||
<li class="{{dialogNavLiClass}} {{^enableAllianceTab}} disabled {{/enableAllianceTab}}">
|
||||
<a role="tab" data-toggle="tab" data-type="typeId" data-value="4" href="#{{statsContainerId}}">Alliance</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="navbar-header pull-right">
|
||||
<p class="navbar-text">
|
||||
<i class="fa fa-filter fa-fw fa-lg"></i>
|
||||
</p>
|
||||
<ul class="nav navbar-nav {{dialogNavigationClass}}">
|
||||
<li class="{{dialogNavLiClass}}">
|
||||
<a role="tab" data-toggle="tab" data-type="period" data-value="weekly" href="#{{statsContainerId}}">Weekly</a>
|
||||
</li>
|
||||
<li class="{{dialogNavLiClass}} active">
|
||||
<a role="tab" data-toggle="tab" data-type="period" data-value="monthly" href="#{{statsContainerId}}">Monthly</a>
|
||||
</li>
|
||||
<li class="{{dialogNavLiClass}}">
|
||||
<a role="tab" data-toggle="tab" data-type="period" data-value="yearly" href="#{{statsContainerId}}">Yearly</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="alert alert-info fade in hidden-md hidden-lg">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-label="Close"><i class="fa fa-close"></i></button>
|
||||
<span class="txt-color txt-color-information">Info</span>
|
||||
<small> Your browser window is to small. Resize it to obtain more columns.</small>
|
||||
</div>
|
||||
|
||||
<div class="tab-content">
|
||||
<div role="tabpanel" class="tab-pane fade in active" id="{{statsContainerId}}">
|
||||
|
||||
<h5 class="text-center">
|
||||
{{! previous button }}
|
||||
<span class="pull-left pf-dialog-icon-button collapsed {{dialogNavigationPrevClass}}" style="visibility: hidden; min-width: 120px">
|
||||
<i class="fa fa-fw fa-arrow-left"></i>
|
||||
<span> </span>
|
||||
</span>
|
||||
|
||||
{{! offset label }}
|
||||
<span class="{{dialogNavigationOffsetClass}}"> </span>
|
||||
|
||||
{{! next button }}
|
||||
<span class="pull-right pf-dialog-icon-button collapsed {{dialogNavigationNextClass}}" style="visibility: hidden; min-width: 120px">
|
||||
<span> </span>
|
||||
<i class="fa fa-fw fa-arrow-right"></i>
|
||||
</span>
|
||||
</h5>
|
||||
|
||||
<div class="pf-dynamic-area">
|
||||
<table class="compact stripe order-column row-border nowrap" id="{{statsTableId}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="4" class="separator-right">character</th>
|
||||
<th colspan="4" class="separator-right hidden-xs hidden-sm">systems</th>
|
||||
<th colspan="4" class="separator-right hidden-xs hidden-sm">connection</th>
|
||||
<th colspan="4" class="separator-right hidden-xs hidden-sm">signatures</th>
|
||||
<th class="text-right">sum</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th class="bg-color bg-color-grayDarker"></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th class="bg-color bg-color-grayDarker"></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th></th>
|
||||
<th class="bg-color bg-color-grayDarker"></th>
|
||||
<th class="bg-color bg-color-tealDarker txt-color txt-color-orange"></th>
|
||||
</tr>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,16 +1,24 @@
|
||||
<div class="row text-center">
|
||||
<div class="col-xs-12 col-md-8 col-md-offset-2 pf-landing-pricing-panel">
|
||||
<div class="panel panel-info pricing-big">
|
||||
<div class="panel panel-primary pricing-big">
|
||||
<div class="panel-heading" >
|
||||
<h3 class="panel-title">New release v1.1.5</h3>
|
||||
<h3 class="panel-title">New release v1.1.6</h3>
|
||||
</div>
|
||||
<div class="panel-body no-padding text-align-center">
|
||||
<div class="price-features" style="min-height: inherit;">
|
||||
<ul class="list-unstyled text-left">
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New: Support for multiple active characters</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New: Customizable default routes</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New: Filter option for "<em>EOL</em>" connections added to route finder</li>
|
||||
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New: "<em><a target="_self" href="#pf-landing-feature-user-statistics">User Statistics</a></em>" module</li>
|
||||
<li>
|
||||
<ul class="list-unstyled text-left">
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>'private', 'corporation', 'alliance' - statistics</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>New: "<em>Activity Log</em>" history</li>
|
||||
<li>
|
||||
<ul class="list-unstyled text-left">
|
||||
<li><i class="fa fa-fw fa-angle-right"></i>'weekly', 'monthly', 'yearly' - filters</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i class="fa fa-fw fa-angle-double-right"></i>Complete <a href="javascript:void(0)" class="pf-navbar-version-info">changelog</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Pathfinder</h4>
|
||||
<h4>Pathfinder</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i><span class="txt-color txt-color-greenDark"><e class="fa fa-fw fa-lock"></e>SSL</span> encrypted connection</li>
|
||||
<li><i></i>User friendly <a class="pf-navbar-manual" href="#">manual</a></li>
|
||||
@@ -250,7 +250,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Map module</h4>
|
||||
<h4>Map module</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Live synchronisation between clients</li>
|
||||
<li><i></i>Multiple map support</li>
|
||||
@@ -329,7 +329,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>System module</h4>
|
||||
<h4>System module</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Quick access to all relevant information</li>
|
||||
<li>
|
||||
@@ -368,7 +368,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Signature module</h4>
|
||||
<h4>Signature module</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Share system signature information</li>
|
||||
<li><i></i>Add/Update multiple signatures at once <kbd>ctrl</kbd> + <kbd>c</kbd></li>
|
||||
@@ -407,7 +407,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Killboard module</h4>
|
||||
<h4>Killboard module</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i><em><a target="_blank" href="https://github.com/zKillboard/zKillboard/wiki">zkillboard.com</a></em> API integration</li>
|
||||
<li><i></i>Detailed information about all recent activities in a system</li>
|
||||
@@ -440,7 +440,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Route module</h4>
|
||||
<h4>Route module</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Search for routes between systems</li>
|
||||
<li><i></i>Predefined trade hub routes</li>
|
||||
@@ -477,19 +477,20 @@
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-12 col-sm-3 col-lg-2">
|
||||
<a class="pf-animate-on-visible pf-animate" href="public/img/landing/statistics_1.jpg" data-description="Statistics" data-gallery="#pf-gallery">
|
||||
<img class="pf-landing-image-preview pf-landing-image-preview-small" data-original="public/img/landing/thumbs/statistics_1.jpg" width="160" height="160" alt="Statistics">
|
||||
<a class="pf-animate-on-visible pf-animate" href="public/img/landing/statistics_1.jpg" data-description="System statistics" data-gallery="#pf-gallery">
|
||||
<img class="pf-landing-image-preview pf-landing-image-preview-small" data-original="public/img/landing/thumbs/statistics_1.jpg" width="160" height="160" alt="System statistics">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Statistics module</h4>
|
||||
<h4>System statistics module</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Integrated live data for all systems</li>
|
||||
<li><i></i>Live in-game system data</li>
|
||||
<li>
|
||||
<ul class="fa-ul">
|
||||
<li><i></i>System jumps</li>
|
||||
<li><i></i>System jump data</li>
|
||||
<li><i></i>Ship/POD kills</li>
|
||||
<li><i></i>NPC kills</li>
|
||||
</ul>
|
||||
@@ -497,9 +498,36 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="clearfix visible-xs visible-sm visible-md"></div>
|
||||
|
||||
<div class="col-xs-12 col-sm-3 col-lg-2" id="pf-landing-feature-user-statistics">
|
||||
<a class="pf-animate-on-visible pf-animate" href="public/img/landing/statistics_2.jpg" data-description="User statistics" data-gallery="#pf-gallery">
|
||||
<img class="pf-landing-image-preview pf-landing-image-preview-small" data-original="public/img/landing/thumbs/statistics_2.jpg" width="160" height="160" alt="User statistics">
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4>User statistics <span class="label label-success">new</span> </h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>User activity logging</li>
|
||||
<li>
|
||||
<ul class="fa-ul">
|
||||
<li><i></i>Private statistics</li>
|
||||
<li><i></i>Corporation statistics</li>
|
||||
<li><i></i>Alliance statistics</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><i></i>Log history</li>
|
||||
<li>
|
||||
<ul class="fa-ul">
|
||||
<li><i></i>Weekly</li>
|
||||
<li><i></i>Monthly</li>
|
||||
<li><i></i>Yearly</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="row text-center hidden-xs">
|
||||
@@ -634,7 +662,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-server"></i>Requirements check</h4>
|
||||
<h4><i class="fa fa-fw fa-server"></i> Requirements check</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Checks your server type/status</li>
|
||||
<li><i></i>Checks your installed PHP version</li>
|
||||
@@ -656,7 +684,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-9 col-lg-4">
|
||||
<h4><i class="fa fa-fw fa-database"></i>Database setup</h4>
|
||||
<h4><i class="fa fa-fw fa-database"></i> Database setup</h4>
|
||||
<ul class="fa-ul pf-landing-list">
|
||||
<li><i></i>Check DB connections</li>
|
||||
<li><i></i>Check DB version</li>
|
||||
@@ -692,7 +720,7 @@
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6 col-sm-offset-1 col-md-offset-1 col-lg-offset-1">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>About Me</h4>
|
||||
<h4>About Me</h4>
|
||||
<p>
|
||||
I am playing <em><a target="_blank" href="https://www.eveonline.com/">EVE Online</a></em> since almost 4 years.
|
||||
The majority of time (3+ years), my characters were a part of the <em><a target="_blank" href="https://www.themittani.com/news/j150020-three-alliances-enter-none-leave">"No Holes Barred"</a></em> alliance.
|
||||
@@ -728,7 +756,7 @@
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-sm-6 col-md-6 col-lg-6">
|
||||
<h4><i class="fa fa-fw fa-angle-double-right"></i>Technology stack</h4>
|
||||
<h4>Technology stack</h4>
|
||||
<p>
|
||||
If you are planning to get deeper into the project or even think about hosting it on your own webserver, you should be aware of some important key points.
|
||||
<em>Pathfinder</em> is not comparable with any "out of the box" web applications or common CMS systems that come along with an auto-install feature.
|
||||
|
||||
@@ -157,7 +157,7 @@
|
||||
<div class="panel-body no-padding text-align-center">
|
||||
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<thead>
|
||||
<repeat group="{{ @serverInformation }}" value="{{ @information }}">
|
||||
<tr>
|
||||
<td>{{@information.label}}</td>
|
||||
@@ -165,7 +165,7 @@
|
||||
</tr>
|
||||
</repeat>
|
||||
|
||||
</tbody>
|
||||
</thead>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
@@ -235,7 +235,7 @@
|
||||
|
||||
<div class="panel-body no-padding text-align-center">
|
||||
<table class="table">
|
||||
<tbody>
|
||||
<thead>
|
||||
<repeat group="{{ @environmentInformation }}" value="{{ @environmentData }}">
|
||||
<tr>
|
||||
<td>{{@environmentData.label}}</td>
|
||||
@@ -251,7 +251,7 @@
|
||||
</td>
|
||||
</tr>
|
||||
</repeat>
|
||||
</tbody>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@@ -264,11 +264,36 @@
|
||||
<div class="panel panel-default pricing-big">
|
||||
|
||||
<div class="panel-heading text-left">
|
||||
<h3 class="panel-title">Map restrictions</h3>
|
||||
<h3 class="panel-title">Registration</h3>
|
||||
</div>
|
||||
|
||||
<div class="panel-body no-padding text-align-center">
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td class="text-right col-md-2">
|
||||
<check if="{{ @PATHFINDER.REGISTRATION.STATUS }}">
|
||||
<true>
|
||||
<kbd class="txt-color txt-color-success">enabled</kbd>
|
||||
</true>
|
||||
<false>
|
||||
<kbd class="txt-color txt-color-warning">disabled</kbd>
|
||||
</false>
|
||||
</check>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="panel-footer text-left">
|
||||
<h3 class="panel-title">Map restrictions</h3>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -295,17 +320,17 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Max. shared users (private map)</td>
|
||||
<td>Max. shared users (private maps)</td>
|
||||
<td class="text-right col-md-2"><kbd>{{ @PATHFINDER.MAP.PRIVATE.MAX_SHARED }}</kbd></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Max. shared users (corporation map)</td>
|
||||
<td>Max. shared users (corporation maps)</td>
|
||||
<td class="text-right"><kbd>{{ @PATHFINDER.MAP.CORPORATION.MAX_SHARED }}</kbd></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max. shared users (alliance map)</td>
|
||||
<td>Max. shared users (alliance maps)</td>
|
||||
<td class="text-right"><kbd>{{ @PATHFINDER.MAP.ALLIANCE.MAX_SHARED }}</kbd></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
@@ -318,32 +343,60 @@
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Private map</td>
|
||||
<td>Private maps</td>
|
||||
<td class="text-right col-md-2"><kbd>{{ @PATHFINDER.MAP.PRIVATE.LIFETIME }}</kbd></td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Corporation map</td>
|
||||
<td>Corporation maps</td>
|
||||
<td class="text-right"><kbd>{{ @PATHFINDER.MAP.CORPORATION.LIFETIME }}</kbd></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alliance map</td>
|
||||
<td>Alliance maps</td>
|
||||
<td class="text-right"><kbd>{{ @PATHFINDER.MAP.ALLIANCE.LIFETIME }}</kbd></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="panel-footer text-left">
|
||||
<h3 class="panel-title">Registration</h3>
|
||||
<h3 class="panel-title">User activity logging</h3>
|
||||
</div>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Status</td>
|
||||
<td>Private maps</td>
|
||||
<td class="text-right col-md-2">
|
||||
<check if="{{ @PATHFINDER.REGISTRATION.STATUS }}">
|
||||
<check if="{{ @PATHFINDER.MAP.PRIVATE.ACTIVITY_LOGGING }}">
|
||||
<true>
|
||||
<kbd class="txt-color txt-color-success">enabled</kbd>
|
||||
</true>
|
||||
<false>
|
||||
<kbd class="txt-color txt-color-warning">disabled</kbd>
|
||||
</false>
|
||||
</check>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Corporation maps</td>
|
||||
<td class="text-right">
|
||||
<check if="{{ @PATHFINDER.MAP.CORPORATION.ACTIVITY_LOGGING }}">
|
||||
<true>
|
||||
<kbd class="txt-color txt-color-success">enabled</kbd>
|
||||
</true>
|
||||
<false>
|
||||
<kbd class="txt-color txt-color-warning">disabled</kbd>
|
||||
</false>
|
||||
</check>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Alliance maps</td>
|
||||
<td class="text-right">
|
||||
<check if="{{ @PATHFINDER.MAP.ALLIANCE.ACTIVITY_LOGGING }}">
|
||||
<true>
|
||||
<kbd class="txt-color txt-color-success">enabled</kbd>
|
||||
</true>
|
||||
@@ -353,13 +406,9 @@
|
||||
</check>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
&.txt-color-redDarker { color: $red-darker !important; }
|
||||
&.txt-color-yellow { color: $yellow !important; }
|
||||
&.txt-color-orange { color: $orange !important; }
|
||||
&.txt-color-orangeDark { color: $orangeDark !important; }
|
||||
&.txt-color-orangeDark { color: $orange-dark !important; }
|
||||
&.txt-color-pink { color: $pink !important; }
|
||||
&.txt-color-pinkDark { color: $pinkDark !important; }
|
||||
&.txt-color-purple { color: $purple !important; }
|
||||
@@ -58,7 +58,9 @@
|
||||
&.bg-color-darken { background-color: $darken !important; }
|
||||
&.bg-color-lighten { background-color: $lighten !important; }
|
||||
&.bg-color-white { background-color: $white !important; }
|
||||
&.bg-color-gray { background-color: $gray !important; }
|
||||
&.bg-color-grayDark { background-color: $greyDark !important; }
|
||||
&.bg-color-grayDarker { background-color: $gray-darker !important; }
|
||||
&.bg-color-magenta { background-color: $magenta !important; }
|
||||
&.bg-color-tealLighter { background-color: $teal-lighter !important; }
|
||||
&.bg-color-tealDarker { background-color: $teal-darker !important; }
|
||||
|
||||
@@ -551,7 +551,7 @@ $modal-backdrop-opacity: .3;
|
||||
$modal-header-border-color: #e5e5e5;
|
||||
$modal-footer-border-color: $modal-header-border-color;
|
||||
|
||||
$modal-lg: 820px;
|
||||
$modal-lg: 1100px;
|
||||
$modal-md: 600px;
|
||||
$modal-sm: 300px;
|
||||
|
||||
|
||||
@@ -196,6 +196,7 @@ select:active, select:hover {
|
||||
|
||||
img{
|
||||
width: 26px; // smaller image (default 32)
|
||||
box-sizing: content-box;
|
||||
border-left: 1px solid $gray;
|
||||
border-right: 1px solid $gray;
|
||||
}
|
||||
@@ -227,6 +228,18 @@ select:active, select:hover {
|
||||
}
|
||||
}
|
||||
|
||||
// column separator
|
||||
td, th{
|
||||
&.separator-right{
|
||||
border-right: 1px solid $gray;
|
||||
}
|
||||
|
||||
svg.peity{
|
||||
// center vertical in column
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// table styles ===================================================================================
|
||||
@@ -293,7 +306,7 @@ table{
|
||||
|
||||
// navbar li =====================================================================================
|
||||
.navbar-nav {
|
||||
li{
|
||||
li:not(.disabled){
|
||||
&:hover, &.active{
|
||||
|
||||
&:before{
|
||||
|
||||
@@ -194,10 +194,7 @@ html.sb-static .sb-slidebar,
|
||||
*/
|
||||
|
||||
.sb-slide, #sb-site, .sb-site-container, .sb-slidebar {
|
||||
-webkit-transition: -webkit-transform 400ms ease;
|
||||
-moz-transition: -moz-transform 400ms ease;
|
||||
-o-transition: -o-transform 400ms ease;
|
||||
transition: transform 400ms ease;
|
||||
@include transition( transform 180ms ease-out );
|
||||
-webkit-transition-property: -webkit-transform, left, right; /* Add left/right for Android < 4.4. */
|
||||
-webkit-backface-visibility: hidden; /* Prevents flickering. This is non essential, and you may remove it if your having problems with fixed background images in Chrome. */
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user