- Improved performance of JS window.setInterval() update counters
This commit is contained in:
@@ -13,8 +13,8 @@
|
||||
// Define globals exposed by Node.js.
|
||||
"node": true,
|
||||
|
||||
// Allow ES6.
|
||||
"esversion": 7,
|
||||
// Allow ES8.
|
||||
"esversion": 8,
|
||||
|
||||
/*
|
||||
* ENFORCING OPTIONS
|
||||
|
||||
@@ -37,6 +37,7 @@ requirejs.config({
|
||||
slidebars: 'lib/slidebars', // v2.0.2 Slidebars - side menu plugin https://www.adchsm.com/slidebars/
|
||||
jsPlumb: 'lib/jsplumb', // v2.9.3 jsPlumb main map draw plugin http://jsplumb.github.io/jsplumb/home.html
|
||||
farahey: 'lib/farahey', // v1.1.2 jsPlumb "magnetizing" plugin extension - https://github.com/ThomasChan/farahey
|
||||
easyTimer: 'lib/easytimer.min', // v4.0.2 EasyTimer - Timer/Chronometer/Countdown library - http://albert-gonzalez.github.io/easytimer.js
|
||||
customScrollbar: 'lib/jquery.mCustomScrollbar.min', // v3.1.5 Custom scroll bars - http://manos.malihu.gr
|
||||
mousewheel: 'lib/jquery.mousewheel.min', // v3.1.13 Mousewheel - https://github.com/jquery/jquery-mousewheel
|
||||
xEditable: 'lib/bootstrap-editable.min', // v1.5.1 X-editable - in placed editing
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util'
|
||||
], ($, Init, Util) => {
|
||||
'app/util',
|
||||
'app/lib/cron'
|
||||
], ($, Init, Util, Cron) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
counterDigitSmallClass: 'pf-digit-counter-small',
|
||||
counterDigitLargeClass: 'pf-digit-counter-large'
|
||||
counterTaskAttr: 'data-counter-task', // element attr name with initialized counter name
|
||||
counterStopClass: 'stopCounter', // class for counter elements where counter should be destroyed
|
||||
counterDigitSmallClass: 'pf-digit-counter-small', // class for 'small' counter DOM elements (e.g. 'hour' number)
|
||||
counterDigitLargeClass: 'pf-digit-counter-large' // class for 'large' counter DOM elements (e.g. 'days' number)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -57,73 +60,58 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
element.html(parts.join(' '));
|
||||
};
|
||||
|
||||
/**
|
||||
* destroy all active counter recursive
|
||||
*/
|
||||
$.fn.destroyTimestampCounter = function(recursive){
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
let counterSelector = '[data-counter="init"]';
|
||||
let counterElements = element.filter(counterSelector);
|
||||
if(recursive){
|
||||
counterElements = counterElements.add(element.find(counterSelector));
|
||||
}
|
||||
let destroyTimestampCounter = (element, recursive) => {
|
||||
let counterTaskSelector = '[' + config.counterTaskAttr + ']';
|
||||
let counterElements = element.filter(counterTaskSelector);
|
||||
if(recursive){
|
||||
counterElements = counterElements.add(element.find(counterTaskSelector));
|
||||
}
|
||||
|
||||
counterElements.each(function(){
|
||||
let element = $(this);
|
||||
let interval = element.data('interval');
|
||||
if(interval){
|
||||
clearInterval(interval);
|
||||
element.removeAttr('data-counter').removeData('interval').removeClass('stopCounter');
|
||||
}
|
||||
});
|
||||
counterElements.each(function(){
|
||||
let element = $(this);
|
||||
let taskName = element.attr(config.counterTaskAttr);
|
||||
|
||||
if(Cron.delete(taskName)){
|
||||
element.removeAttr(config.counterTaskAttr).removeClass(config.counterStopClass);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* init a live counter based on a unix timestamp
|
||||
* @param round string e.g. 'd' => round days
|
||||
* @param element
|
||||
* @param round e.g. 'd' => round days
|
||||
* @returns {void|*|undefined}
|
||||
*/
|
||||
$.fn.initTimestampCounter = function(round){
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
let timestamp = parseInt( element.text() );
|
||||
let initTimestampCounter = (element, round) => {
|
||||
let timestamp = parseInt(element.text());
|
||||
// do not init twice
|
||||
if(timestamp > 0){
|
||||
let taskName = element.attr('id') || Util.getRandomString();
|
||||
let date = new Date( timestamp * 1000);
|
||||
updateDateDiff(element, date, round);
|
||||
|
||||
// do not init twice
|
||||
if(timestamp > 0){
|
||||
// mark as init
|
||||
element.attr('data-counter', 'init');
|
||||
// show element (if invisible) after first update
|
||||
element.css({'visibility': 'initial'});
|
||||
|
||||
let date = new Date( timestamp * 1000);
|
||||
let counterTask = Cron.new(taskName, {precision: 'seconds', interval: 1, timeout: 100});
|
||||
counterTask.task = () => {
|
||||
if(element.hasClass(config.counterStopClass)){
|
||||
destroyTimestampCounter(element);
|
||||
}else{
|
||||
updateDateDiff(element, date, round);
|
||||
}
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
|
||||
updateDateDiff(element, date, round);
|
||||
|
||||
// show element (if invisible) after first update
|
||||
element.css({'visibility': 'initial'});
|
||||
|
||||
// calc ms until next second
|
||||
// -> makes sure all counter update in sync no matter when init
|
||||
let msUntilSecond = 1500 - new Date().getMilliseconds();
|
||||
setTimeout(function(){
|
||||
let refreshIntervalId = window.setInterval(function(){
|
||||
|
||||
// update element with current time
|
||||
if( !element.hasClass('stopCounter')){
|
||||
updateDateDiff(element, date, round);
|
||||
}else{
|
||||
clearInterval( element.data('interval') );
|
||||
}
|
||||
}, 500);
|
||||
|
||||
element.data('interval', refreshIntervalId);
|
||||
}, msUntilSecond);
|
||||
}
|
||||
});
|
||||
element.attr(config.counterTaskAttr, taskName);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -134,30 +122,33 @@ define([
|
||||
*/
|
||||
let initTableCounter = (tableElement, columnSelector, round) => {
|
||||
let tableApi = tableElement.api();
|
||||
let taskName = tableElement.attr('id');
|
||||
|
||||
// mark as init
|
||||
tableElement.attr('data-counter', 'init');
|
||||
|
||||
let updateTableCount = () => {
|
||||
tableApi.cells(null, columnSelector).every(function(rowIndex, colIndex, tableLoopCount, cellLoopCount){
|
||||
let cell = this;
|
||||
let node = cell.node();
|
||||
let data = cell.data();
|
||||
if(data && Number.isInteger(data) && !node.classList.contains('stopCounter')){
|
||||
// timestamp expected int > 0
|
||||
let date = new Date(data * 1000);
|
||||
updateDateDiff( cell.nodes().to$(), date, round);
|
||||
}
|
||||
});
|
||||
let cellUpdate = function(rowIndex, colIndex, tableLoopCount, cellLoopCount){
|
||||
let cell = this;
|
||||
let node = cell.node();
|
||||
let data = cell.data();
|
||||
if(data && Number.isInteger(data) && !node.classList.contains(config.counterStopClass)){
|
||||
// timestamp expected int > 0
|
||||
let date = new Date(data * 1000);
|
||||
updateDateDiff(cell.nodes().to$(), date, round);
|
||||
}
|
||||
};
|
||||
|
||||
let refreshIntervalId = window.setInterval(updateTableCount, 500);
|
||||
let counterTask = Cron.new(taskName, {precision: 'seconds', interval: 1, timeout: 100});
|
||||
counterTask.task = timer => {
|
||||
tableApi.cells(null, columnSelector).every(cellUpdate);
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
|
||||
tableElement.data('interval', refreshIntervalId);
|
||||
tableElement.attr(config.counterTaskAttr, taskName);
|
||||
};
|
||||
|
||||
return {
|
||||
config: config,
|
||||
updateDateDiff: updateDateDiff,
|
||||
initTableCounter: initTableCounter
|
||||
initTimestampCounter: initTimestampCounter,
|
||||
initTableCounter: initTableCounter,
|
||||
destroyTimestampCounter: destroyTimestampCounter
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/counter',
|
||||
'app/promises/promise.deferred',
|
||||
'app/promises/promise.timeout',
|
||||
'datatables.net',
|
||||
@@ -8,7 +9,7 @@ define([
|
||||
'datatables.net-buttons-html',
|
||||
'datatables.net-responsive',
|
||||
'datatables.net-select'
|
||||
], ($, Init, DeferredPromise, TimeoutPromise) => {
|
||||
], ($, Init, Counter, DeferredPromise, TimeoutPromise) => {
|
||||
'use strict';
|
||||
|
||||
// all Datatables stuff is available...
|
||||
@@ -42,7 +43,7 @@ define([
|
||||
}
|
||||
|
||||
// remove all active counters in table
|
||||
table.destroyTimestampCounter(true);
|
||||
Counter.destroyTimestampCounter(table, true);
|
||||
});
|
||||
|
||||
// Status Plugin ==============================================================================================
|
||||
|
||||
@@ -126,13 +126,13 @@ define([], () => {
|
||||
let Cache = class Cache {
|
||||
|
||||
constructor(config){
|
||||
this.config = Object.assign({
|
||||
this.config = Object.assign({},{
|
||||
name: 'Default', // custom name for identification
|
||||
ttl: 3600,
|
||||
maxSize: 600,
|
||||
bufferSize: 10, // in percent
|
||||
strategy: 'FIFO',
|
||||
debug: false
|
||||
ttl: 3600, // default ttl for cache entries
|
||||
maxSize: 600, // max cache entries
|
||||
bufferSize: 10, // cache entry count in percent to be removed if maxSize reached
|
||||
strategy: 'FIFO', // cache strategy policy
|
||||
debug: false // debug output in console
|
||||
}, config);
|
||||
|
||||
this.store = new Map();
|
||||
318
js/app/lib/cron.js
Normal file
318
js/app/lib/cron.js
Normal file
@@ -0,0 +1,318 @@
|
||||
define([
|
||||
'easyTimer',
|
||||
'app/promises/promise.timeout',
|
||||
], (easytimer, TimeoutPromise) => {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
Example1 run task every second ------------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 1, timeout: 100});
|
||||
task1.task = (timer) => {
|
||||
console.log('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
|
||||
Example2 run task every 3 seconds ---------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 3, timeout: 100});
|
||||
task1.task = (timer) => {
|
||||
console.log('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
|
||||
Example3 resolve Promise on run ----------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 1, timeout: 100});
|
||||
task1.task = (timer, task) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('task1 Promise1():', timer.getTotalTimeValues(), task.get('interval'));
|
||||
//task.set('interval', task.get('interval') + 1) // increase run interval every time by 1s
|
||||
resolve('OK1');
|
||||
}).then(payload => {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('task2 Promise2():', timer.getTotalTimeValues(), payload);
|
||||
resolve('OK2');
|
||||
});
|
||||
});
|
||||
};
|
||||
Cron.set(task1);
|
||||
|
||||
Example4 run task once at given Date() --------------------------------------------------------------------------
|
||||
let dueDate = new Date();
|
||||
dueDate.setSeconds(dueDate.getSeconds() + 5);
|
||||
let task2 = Cron.new('task2', {precision: 'seconds', timeout: 100, dueDate: dueDate});
|
||||
task2.task = () => 'OK task2';
|
||||
Cron.set(task2);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Task instances represent a task that should be executed at a given interval or dueDate
|
||||
* -> Task´s are managed by CronManager()
|
||||
* @type {Task}
|
||||
*/
|
||||
let Task = class Task {
|
||||
constructor(name, config){
|
||||
if(typeof name !== 'string'){
|
||||
throw new TypeError('Task "name" must be instance of String, Type of "' + typeof name + '" given');
|
||||
}
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._name = name; // unique name for identification
|
||||
this._task = undefined; // task to run, instanceof Function, can also return a Promise
|
||||
this._manager = undefined; // reference to CronManager() that handles this task
|
||||
this._runQueue = new Map(); // current run() processes. > 1 requires config.isParallel: true
|
||||
this._runCount = 0; // total run counter for this task
|
||||
this._lastTotalTimeValues = undefined; // time values of last run()
|
||||
}
|
||||
|
||||
get name(){
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get precision(){
|
||||
return this._config.precision;
|
||||
}
|
||||
|
||||
get task(){
|
||||
return this._task;
|
||||
}
|
||||
|
||||
set task(task){
|
||||
if(task instanceof Function){
|
||||
this._task = task;
|
||||
}else{
|
||||
throw new TypeError('Task "task" must be instance of "function", Type of "' + typeof task + '" given');
|
||||
}
|
||||
}
|
||||
|
||||
get(option){
|
||||
return this._config[option];
|
||||
}
|
||||
|
||||
set(option, value){
|
||||
this._config[option] = value;
|
||||
}
|
||||
|
||||
setManager(manager){
|
||||
this._manager = manager;
|
||||
}
|
||||
|
||||
isRunning(){
|
||||
return !!this._runQueue.size;
|
||||
}
|
||||
|
||||
delete(){
|
||||
let isDeleted = false;
|
||||
if(this._manager){
|
||||
isDeleted = this._manager.delete(this.name);
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
isDue(timer){
|
||||
if(this._config.dueDate instanceof Date){
|
||||
// run once at dueDate
|
||||
if(new Date().getTime() >= this._config.dueDate.getTime()){
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
// periodic execution
|
||||
let totalTimeValues = timer.getTotalTimeValues();
|
||||
let totalTimeValuePrecision = totalTimeValues[this.precision];
|
||||
totalTimeValuePrecision -= this._lastTotalTimeValues ? this._lastTotalTimeValues[this.precision] : 0;
|
||||
if(
|
||||
this._config.interval === 1 ||
|
||||
totalTimeValuePrecision % this._config.interval === 0
|
||||
){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
invoke(timer){
|
||||
if(
|
||||
this.isDue(timer) &&
|
||||
(!this.isRunning() || this._config.isParallel)
|
||||
){
|
||||
this.run(timer);
|
||||
}
|
||||
}
|
||||
|
||||
run(timer){
|
||||
this._lastTotalTimeValues = Object.assign({}, timer.getTotalTimeValues());
|
||||
let runId = 'run_' + (++this._runCount);
|
||||
let runExec = resolve => {
|
||||
resolve(this.task(timer, this));
|
||||
};
|
||||
|
||||
let myProm = this._config.timeout > 0 ? new TimeoutPromise(runExec, this._config.timeout) : new Promise(runExec);
|
||||
myProm.then(payload => {
|
||||
// resolved within timeout -> wait for finally() block
|
||||
}).catch(error => {
|
||||
if(error instanceof Error){
|
||||
// either timeout error or error from rejected deferredPromise
|
||||
console.warn(error);
|
||||
}
|
||||
}).finally(() => {
|
||||
// no matter if TimeoutPromise is resolved or rejected
|
||||
// -> remove from _runQueue
|
||||
this._runQueue.delete(runId);
|
||||
|
||||
// remove this task from store after run
|
||||
if(this._config.dueDate instanceof Date){
|
||||
this.delete();
|
||||
}
|
||||
});
|
||||
|
||||
this._runQueue.set(runId, myProm);
|
||||
}
|
||||
};
|
||||
|
||||
Task.defaultConfig = {
|
||||
precision: 'seconds', // updateEvent this tasked will be subscribed to
|
||||
isParallel: false, // if true this task can run parallel, e.g. if prev execution has not finished
|
||||
interval: 1, // relates to 'precision'. 'interval' = 3 and 'precision' = "seconds" -> run every 3 seconds
|
||||
dueDate: undefined, // if Date() instance is set, task only runs once at dueDate
|
||||
timeout: 50 // if > 0, execution time that exceeds timeout (ms) throw error
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An instance of CronManager() handles multiple Task()´s
|
||||
* -> Task()´s can be set()/delete() from CronManager() instance
|
||||
* @type {CronManager}
|
||||
*/
|
||||
let CronManager = class CronManager {
|
||||
|
||||
constructor(config){
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._timerConfig = Object.assign({}, this.constructor.defaultTimerConfig);
|
||||
|
||||
this._tasks = new Map();
|
||||
this._timer = new easytimer.Timer();
|
||||
|
||||
// init Easytimer update events
|
||||
this._config.precisions.map(precision => precision + 'Updated').forEach(eventName => {
|
||||
this._timer.on(eventName, e => {
|
||||
let precision = e.type.substring(0, e.type.indexOf('Updated'));
|
||||
this.tasksByPrecision(precision).forEach(task => task.invoke(e.detail.timer));
|
||||
});
|
||||
});
|
||||
|
||||
this.debug = (msg,...data) => {
|
||||
if(this._config.debug){
|
||||
data = (data || []);
|
||||
console.info(msg, ...data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
new(name, config){
|
||||
return new Task(name, config);
|
||||
}
|
||||
|
||||
set(task){
|
||||
if(task instanceof Task){
|
||||
// check for unique task name, or update existing task
|
||||
if(!this.has(task.name) || (this.get(task.name) === task)){
|
||||
// set new or update existing task
|
||||
task.setManager(this);
|
||||
this._tasks.set(task.name, task);
|
||||
this.debug('SET/UPDATE task: %o config: %o', task.name, task);
|
||||
// start timer (if it is not already running)
|
||||
this.auto();
|
||||
}else{
|
||||
console.warn('FAILED to set task. Task name %o already exists', task.name);
|
||||
}
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of Task');
|
||||
}
|
||||
}
|
||||
|
||||
setNew(name, config){
|
||||
this.set(this.new(name, config));
|
||||
}
|
||||
|
||||
get(name){
|
||||
return this._tasks.get(name);
|
||||
}
|
||||
|
||||
has(name){
|
||||
return this._tasks.has(name);
|
||||
}
|
||||
|
||||
delete(name){
|
||||
let isDeleted = this._tasks.delete(name);
|
||||
if(isDeleted){
|
||||
this.debug('DELETE task: %o', name);
|
||||
this.auto();
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
clear(){
|
||||
this.debug('CLEAR all %o task(s)', this._tasks.size);
|
||||
this._tasks.clear();
|
||||
this.auto();
|
||||
}
|
||||
|
||||
tasksByPrecision(precision){
|
||||
let tasks = [];
|
||||
this._tasks.forEach(task => {
|
||||
if(precision === task.precision){
|
||||
tasks.push(task);
|
||||
}
|
||||
});
|
||||
return tasks;
|
||||
}
|
||||
|
||||
// EasyTimer controls -----------------------------------------------------------------------------------------
|
||||
start(){
|
||||
this._timer.start(this._timerConfig);
|
||||
}
|
||||
|
||||
stop(){
|
||||
this._timer.stop();
|
||||
}
|
||||
|
||||
pause(){
|
||||
this._timer.pause();
|
||||
}
|
||||
|
||||
reset(){
|
||||
this._timer.reset();
|
||||
}
|
||||
|
||||
auto(){
|
||||
if(this._tasks.size){
|
||||
if(!this._timer.isRunning()){
|
||||
this.start();
|
||||
this.debug('START [auto] timer. %o task(s) found.', this._tasks.size);
|
||||
}
|
||||
}else{
|
||||
this.stop();
|
||||
this.debug('STOP [auto] timer. No tasks set.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CronManager.defaultConfig = {
|
||||
precisions: [
|
||||
'secondTenths',
|
||||
'seconds',
|
||||
'minutes',
|
||||
'hours',
|
||||
'days'
|
||||
],
|
||||
debug: false // debug output in console
|
||||
};
|
||||
|
||||
CronManager.defaultTimerConfig = {
|
||||
precision: 'secondTenths', // Timer update frequency. Values: 'secondTenths', 'seconds', 'minutes', 'hours'
|
||||
countdown: false // If true, the timer is a countdown
|
||||
};
|
||||
|
||||
return new CronManager({
|
||||
debug: false
|
||||
});
|
||||
});
|
||||
@@ -6,8 +6,9 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/counter',
|
||||
'bootbox'
|
||||
], ($, Init, Util, bootbox) => {
|
||||
], ($, Init, Util, Counter, bootbox) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -31,11 +32,11 @@ define([
|
||||
* updated "sync status" dynamic dialog area
|
||||
*/
|
||||
let updateSyncStatus = () => {
|
||||
|
||||
// check if task manager dialog is open
|
||||
let logDialog = $('#' + config.taskDialogId);
|
||||
if(logDialog.length){
|
||||
// dialog is open
|
||||
let statusArea = logDialog.find('.' + config.taskDialogStatusAreaClass);
|
||||
requirejs(['text!templates/modules/sync_status.html', 'mustache'], (templateSyncStatus, Mustache) => {
|
||||
let data = {
|
||||
timestampCounterClass: config.timestampCounterClass,
|
||||
@@ -49,10 +50,12 @@ define([
|
||||
};
|
||||
|
||||
let syncStatusElement = $(Mustache.render(templateSyncStatus, data ));
|
||||
Counter.destroyTimestampCounter(statusArea, true);
|
||||
|
||||
logDialog.find('.' + config.taskDialogStatusAreaClass).html( syncStatusElement );
|
||||
statusArea.html(syncStatusElement);
|
||||
|
||||
logDialog.find('.' + config.timestampCounterClass).initTimestampCounter();
|
||||
let counterElements = syncStatusElement.find('.' + config.timestampCounterClass);
|
||||
Counter.initTimestampCounter(counterElements);
|
||||
|
||||
syncStatusElement.initTooltips({
|
||||
placement: 'right'
|
||||
|
||||
@@ -6,6 +6,7 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/counter',
|
||||
'app/logging',
|
||||
'mustache',
|
||||
'app/map/util',
|
||||
@@ -26,7 +27,7 @@ define([
|
||||
'dialog/credit',
|
||||
'xEditable',
|
||||
'app/module_map'
|
||||
], ($, Init, Util, Logging, Mustache, MapUtil, MapContextMenu, SlideBars, TplHead, TplFooter) => {
|
||||
], ($, Init, Util, Counter, Logging, Mustache, MapUtil, MapContextMenu, SlideBars, TplHead, TplFooter) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -879,7 +880,6 @@ define([
|
||||
// global "modal" callback --------------------------------------------------------------------------------
|
||||
bodyElement.on('hide.bs.modal', '> .modal', e => {
|
||||
let modalElement = $(e.target);
|
||||
modalElement.destroyTimestampCounter(true);
|
||||
|
||||
// destroy all form validators
|
||||
// -> does not work properly. validation functions still used (js error) after 'destroy'
|
||||
@@ -892,6 +892,14 @@ define([
|
||||
modalElement.find('.' + Util.config.select2Class)
|
||||
.filter((i, element) => $(element).data('select2'))
|
||||
.select2('destroy');
|
||||
|
||||
// destroy DataTable instances
|
||||
for(let table of modalElement.find('table.dataTable')){
|
||||
$(table).DataTable().destroy(true);
|
||||
}
|
||||
|
||||
// destroy counter
|
||||
Counter.destroyTimestampCounter(modalElement, true);
|
||||
});
|
||||
|
||||
// global "close" trigger for context menus ---------------------------------------------------------------
|
||||
|
||||
@@ -7,10 +7,10 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox',
|
||||
'app/counter',
|
||||
'bootbox',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, Render, bootbox, Counter, MapUtil) => {
|
||||
], ($, Init, Util, Render, Counter, bootbox, MapUtil) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -182,7 +182,7 @@ define([
|
||||
mapElement.append(dlElementRight);
|
||||
|
||||
// init map lifetime counter
|
||||
$('.' + config.mapInfoLifetimeCounterClass).initTimestampCounter();
|
||||
Counter.initTimestampCounter($('.' + config.mapInfoLifetimeCounterClass));
|
||||
|
||||
mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){
|
||||
let mapUrl = $(this).find('span').text().trim();
|
||||
|
||||
@@ -8,9 +8,10 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'app/counter',
|
||||
'bootbox',
|
||||
'peityInlineChart'
|
||||
], ($, Init, Util, Render, bootbox) => {
|
||||
], ($, Init, Util, Render, Counter, bootbox) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -37,7 +38,7 @@ define([
|
||||
* init blank statistics dataTable
|
||||
* @param dialogElement
|
||||
*/
|
||||
let initStatsTable = function(dialogElement){
|
||||
let initStatsTable = dialogElement => {
|
||||
let columnNumberWidth = 28;
|
||||
let cellPadding = 4;
|
||||
let lineChartWidth = columnNumberWidth + (2 * cellPadding);
|
||||
@@ -114,6 +115,7 @@ define([
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
name: 'rowIndex',
|
||||
title: '<i class="fas fa-hashtag"></i>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -122,6 +124,7 @@ define([
|
||||
data: 'character.id'
|
||||
},{
|
||||
targets: 1,
|
||||
name: 'image',
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -135,6 +138,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 2,
|
||||
name: 'name',
|
||||
title: 'name',
|
||||
width: 200,
|
||||
data: 'character',
|
||||
@@ -144,20 +148,16 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 3,
|
||||
name: 'lastLogin',
|
||||
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();
|
||||
}
|
||||
data: 'character.lastLogin',
|
||||
defaultContent: ''
|
||||
},{
|
||||
targets: 4,
|
||||
name: 'mapCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -169,6 +169,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
name: 'mapUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -180,6 +181,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 6,
|
||||
name: 'mapDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -191,6 +193,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 7,
|
||||
name: 'mapSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -201,6 +204,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
name: 'systemCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -212,6 +216,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 9,
|
||||
name: 'systemUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -223,6 +228,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 10,
|
||||
name: 'systemDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -234,6 +240,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 11,
|
||||
name: 'systemSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -244,6 +251,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 12,
|
||||
name: 'connectionCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -255,6 +263,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 13,
|
||||
name: 'connectionUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -266,6 +275,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 14,
|
||||
name: 'connectionDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -277,6 +287,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 15,
|
||||
name: 'connectionSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -287,6 +298,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 16,
|
||||
name: 'signatureCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -298,6 +310,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 17,
|
||||
name: 'signatureUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -309,6 +322,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 18,
|
||||
name: 'signatureDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -320,6 +334,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 19,
|
||||
name: 'signatureSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -330,6 +345,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 20,
|
||||
name: 'totalSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -346,6 +362,8 @@ define([
|
||||
// initial statistics data request
|
||||
let requestData = getRequestDataFromTabPanels(dialogElement);
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
|
||||
Counter.initTableCounter(this, ['lastLogin:name']);
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
this.api().rows().nodes().to$().each(function(i, row){
|
||||
@@ -374,7 +392,7 @@ define([
|
||||
});
|
||||
|
||||
$(sumColumnIndexes).each(function(index, value){
|
||||
$( api.column( value ).footer() ).text( renderNumericColumn(pageTotalColumns[index], 'display') );
|
||||
$(api.column(value).footer()).text( renderNumericColumn(pageTotalColumns[index], 'display') );
|
||||
});
|
||||
},
|
||||
data: [] // will be added dynamic
|
||||
@@ -404,8 +422,7 @@ define([
|
||||
* @param requestData
|
||||
* @param context
|
||||
*/
|
||||
let getStatsData = function(requestData, context){
|
||||
|
||||
let getStatsData = (requestData, context) => {
|
||||
context.dynamicArea = $('#' + config.statsContainerId + ' .' + Util.config.dynamicAreaClass);
|
||||
context.dynamicArea.showLoadingAnimation();
|
||||
|
||||
@@ -418,7 +435,7 @@ define([
|
||||
}).done(function(data){
|
||||
this.dynamicArea.hideLoadingAnimation();
|
||||
|
||||
this.callback(data);
|
||||
this.callback(data, this);
|
||||
}).fail(function(jqXHR, status, error){
|
||||
let reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': loadStatistics', text: reason, type: 'warning'});
|
||||
@@ -430,7 +447,7 @@ define([
|
||||
* update "header"/"filter" elements in dialog
|
||||
* @param responseData
|
||||
*/
|
||||
let drawStatsTable = function(responseData){
|
||||
let drawStatsTable = (responseData, context) => {
|
||||
let dialogElement = $('#' + config.statsDialogId);
|
||||
|
||||
// update filter/header -----------------------------------------------------------------------------
|
||||
@@ -467,8 +484,8 @@ define([
|
||||
|
||||
// clear and (re)-fill table ------------------------------------------------------------------------
|
||||
let formattedData = formatStatisticsData(responseData);
|
||||
this.tableApi.clear();
|
||||
this.tableApi.rows.add(formattedData).draw();
|
||||
context.tableApi.clear();
|
||||
context.tableApi.rows.add(formattedData).draw();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -477,7 +494,7 @@ define([
|
||||
* @param statsData
|
||||
* @returns {Array}
|
||||
*/
|
||||
let formatStatisticsData = function(statsData){
|
||||
let formatStatisticsData = statsData => {
|
||||
let formattedData = [];
|
||||
let yearStart = statsData.start.year;
|
||||
let weekStart = statsData.start.week;
|
||||
@@ -687,7 +704,7 @@ define([
|
||||
* @param dialogElement
|
||||
* @returns {{}}
|
||||
*/
|
||||
let getRequestDataFromTabPanels = function(dialogElement){
|
||||
let getRequestDataFromTabPanels = dialogElement => {
|
||||
let requestData = {};
|
||||
|
||||
// get data from "tab" panel links ------------------------------------------------------------------
|
||||
|
||||
@@ -7,8 +7,9 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'bootbox',
|
||||
'app/counter',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, bootbox, MapUtil) => {
|
||||
], ($, Init, Util, bootbox, Counter, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -827,10 +828,7 @@ define([
|
||||
title: 'log',
|
||||
width: 55,
|
||||
className: ['text-right', config.tableCellCounterClass].join(' '),
|
||||
data: 'created.created',
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
$(cell).initTimestampCounter('d');
|
||||
}
|
||||
data: 'created.created'
|
||||
},{
|
||||
targets: 5,
|
||||
name: 'edit',
|
||||
@@ -931,6 +929,9 @@ define([
|
||||
}
|
||||
}
|
||||
],
|
||||
initComplete: function(settings, json){
|
||||
Counter.initTableCounter(this, ['created:name']);
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
let animationRows = this.api().rows().nodes().to$().filter(function(a,b ){
|
||||
return (
|
||||
|
||||
@@ -6,9 +6,8 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/cache',
|
||||
'morris'
|
||||
], ($, Init, Util, Cache, Morris) => {
|
||||
'app/lib/cache'
|
||||
], ($, Init, Util, Cache) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
|
||||
@@ -6,13 +6,13 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/cache',
|
||||
'bootbox',
|
||||
'app/counter',
|
||||
'app/map/map',
|
||||
'app/map/util',
|
||||
'app/lib/cache',
|
||||
'app/ui/form_element'
|
||||
], ($, Init, Util, Cache, bootbox, Counter, Map, MapUtil, FormElement) => {
|
||||
], ($, Init, Util, bootbox, Counter, Map, MapUtil, Cache, FormElement) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -482,7 +482,7 @@ define([
|
||||
// hide row
|
||||
|
||||
// stop sig counter by adding a stopClass to each <td>, remove padding
|
||||
cellElements.addClass('stopCounter')
|
||||
cellElements.addClass(Counter.config.counterStopClass)
|
||||
.velocity({
|
||||
paddingTop: [0, '4px'],
|
||||
paddingBottom: [0, '4px'],
|
||||
|
||||
@@ -742,7 +742,7 @@ define([
|
||||
|
||||
let defaultOptions = {
|
||||
dismissible: true,
|
||||
messageId: 'pf-alert-' + Math.random().toString(36).substring(7),
|
||||
messageId: getRandomString('pf-alert-'),
|
||||
messageTypeClass: messageTypeClass,
|
||||
messageTextClass: messageTextClass,
|
||||
insertElement: 'replace'
|
||||
@@ -873,7 +873,8 @@ define([
|
||||
|
||||
if(!resourceVariant){
|
||||
switch(resourceType){
|
||||
case 'factions': resourceType = 'corporations'; // faction icons are on 'corporations' endpoint.. CCP fail?!
|
||||
// faction icons are on 'corporations' endpoint.. CCP fail?!
|
||||
case 'factions': resourceType = 'corporations'; // jshint ignore:line
|
||||
case 'alliances':
|
||||
case 'corporations': resourceVariant = 'logo'; break;
|
||||
case 'characters': resourceVariant = 'portrait'; break;
|
||||
@@ -1580,6 +1581,14 @@ define([
|
||||
return Init.timer[updateKey].CURRENT_DELAY;
|
||||
};
|
||||
|
||||
/**
|
||||
* get a random string
|
||||
* -> e.g. as for Ids
|
||||
* @param prefix
|
||||
* @returns {string}
|
||||
*/
|
||||
let getRandomString = (prefix = 'id_') => prefix + Math.random().toString(36).substring(2,10);
|
||||
|
||||
/**
|
||||
* get date obj with current EVE Server Time.
|
||||
* @returns {Date}
|
||||
@@ -1857,7 +1866,7 @@ define([
|
||||
let key = 'tabId';
|
||||
let tabId = sessionStorage.getItem(key);
|
||||
if(tabId === null){
|
||||
tabId = Math.random().toString(36).substr(2, 5);
|
||||
tabId = getRandomString();
|
||||
sessionStorage.setItem(key, tabId);
|
||||
}
|
||||
return tabId;
|
||||
@@ -3521,6 +3530,7 @@ define([
|
||||
initDefaultSelect2Config: initDefaultSelect2Config,
|
||||
initDefaultEditableConfig: initDefaultEditableConfig,
|
||||
getCurrentTriggerDelay: getCurrentTriggerDelay,
|
||||
getRandomString: getRandomString,
|
||||
getServerTime: getServerTime,
|
||||
convertTimestampToServerTime: convertTimestampToServerTime,
|
||||
getTimeDiffParts: getTimeDiffParts,
|
||||
|
||||
7
js/lib/easytimer.min.js
vendored
Normal file
7
js/lib/easytimer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -26,7 +26,7 @@
|
||||
"gulp-requirejs-optimize": "1.3.x",
|
||||
"gulp-sourcemaps": "^2.6.5",
|
||||
"gulp-uglify": "^3.0.2",
|
||||
"jshint": "^2.10.2",
|
||||
"jshint": "^2.10.3",
|
||||
"jshint-stylish": "^2.x.x",
|
||||
"lodash.padend": "4.6.x",
|
||||
"node-notifier": "^5.4.0",
|
||||
|
||||
@@ -37,6 +37,7 @@ requirejs.config({
|
||||
slidebars: 'lib/slidebars', // v2.0.2 Slidebars - side menu plugin https://www.adchsm.com/slidebars/
|
||||
jsPlumb: 'lib/jsplumb', // v2.9.3 jsPlumb main map draw plugin http://jsplumb.github.io/jsplumb/home.html
|
||||
farahey: 'lib/farahey', // v1.1.2 jsPlumb "magnetizing" plugin extension - https://github.com/ThomasChan/farahey
|
||||
easyTimer: 'lib/easytimer.min', // v4.0.2 EasyTimer - Timer/Chronometer/Countdown library - http://albert-gonzalez.github.io/easytimer.js
|
||||
customScrollbar: 'lib/jquery.mCustomScrollbar.min', // v3.1.5 Custom scroll bars - http://manos.malihu.gr
|
||||
mousewheel: 'lib/jquery.mousewheel.min', // v3.1.13 Mousewheel - https://github.com/jquery/jquery-mousewheel
|
||||
xEditable: 'lib/bootstrap-editable.min', // v1.5.1 X-editable - in placed editing
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util'
|
||||
], ($, Init, Util) => {
|
||||
'app/util',
|
||||
'app/lib/cron'
|
||||
], ($, Init, Util, Cron) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
counterDigitSmallClass: 'pf-digit-counter-small',
|
||||
counterDigitLargeClass: 'pf-digit-counter-large'
|
||||
counterTaskAttr: 'data-counter-task', // element attr name with initialized counter name
|
||||
counterStopClass: 'stopCounter', // class for counter elements where counter should be destroyed
|
||||
counterDigitSmallClass: 'pf-digit-counter-small', // class for 'small' counter DOM elements (e.g. 'hour' number)
|
||||
counterDigitLargeClass: 'pf-digit-counter-large' // class for 'large' counter DOM elements (e.g. 'days' number)
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -57,73 +60,58 @@ define([
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
element.html(parts.join(' '));
|
||||
};
|
||||
|
||||
/**
|
||||
* destroy all active counter recursive
|
||||
*/
|
||||
$.fn.destroyTimestampCounter = function(recursive){
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
let counterSelector = '[data-counter="init"]';
|
||||
let counterElements = element.filter(counterSelector);
|
||||
if(recursive){
|
||||
counterElements = counterElements.add(element.find(counterSelector));
|
||||
}
|
||||
let destroyTimestampCounter = (element, recursive) => {
|
||||
let counterTaskSelector = '[' + config.counterTaskAttr + ']';
|
||||
let counterElements = element.filter(counterTaskSelector);
|
||||
if(recursive){
|
||||
counterElements = counterElements.add(element.find(counterTaskSelector));
|
||||
}
|
||||
|
||||
counterElements.each(function(){
|
||||
let element = $(this);
|
||||
let interval = element.data('interval');
|
||||
if(interval){
|
||||
clearInterval(interval);
|
||||
element.removeAttr('data-counter').removeData('interval').removeClass('stopCounter');
|
||||
}
|
||||
});
|
||||
counterElements.each(function(){
|
||||
let element = $(this);
|
||||
let taskName = element.attr(config.counterTaskAttr);
|
||||
|
||||
if(Cron.delete(taskName)){
|
||||
element.removeAttr(config.counterTaskAttr).removeClass(config.counterStopClass);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* init a live counter based on a unix timestamp
|
||||
* @param round string e.g. 'd' => round days
|
||||
* @param element
|
||||
* @param round e.g. 'd' => round days
|
||||
* @returns {void|*|undefined}
|
||||
*/
|
||||
$.fn.initTimestampCounter = function(round){
|
||||
return this.each(function(){
|
||||
let element = $(this);
|
||||
let timestamp = parseInt( element.text() );
|
||||
let initTimestampCounter = (element, round) => {
|
||||
let timestamp = parseInt(element.text());
|
||||
// do not init twice
|
||||
if(timestamp > 0){
|
||||
let taskName = element.attr('id') || Util.getRandomString();
|
||||
let date = new Date( timestamp * 1000);
|
||||
updateDateDiff(element, date, round);
|
||||
|
||||
// do not init twice
|
||||
if(timestamp > 0){
|
||||
// mark as init
|
||||
element.attr('data-counter', 'init');
|
||||
// show element (if invisible) after first update
|
||||
element.css({'visibility': 'initial'});
|
||||
|
||||
let date = new Date( timestamp * 1000);
|
||||
let counterTask = Cron.new(taskName, {precision: 'seconds', interval: 1, timeout: 100});
|
||||
counterTask.task = () => {
|
||||
if(element.hasClass(config.counterStopClass)){
|
||||
destroyTimestampCounter(element);
|
||||
}else{
|
||||
updateDateDiff(element, date, round);
|
||||
}
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
|
||||
updateDateDiff(element, date, round);
|
||||
|
||||
// show element (if invisible) after first update
|
||||
element.css({'visibility': 'initial'});
|
||||
|
||||
// calc ms until next second
|
||||
// -> makes sure all counter update in sync no matter when init
|
||||
let msUntilSecond = 1500 - new Date().getMilliseconds();
|
||||
setTimeout(function(){
|
||||
let refreshIntervalId = window.setInterval(function(){
|
||||
|
||||
// update element with current time
|
||||
if( !element.hasClass('stopCounter')){
|
||||
updateDateDiff(element, date, round);
|
||||
}else{
|
||||
clearInterval( element.data('interval') );
|
||||
}
|
||||
}, 500);
|
||||
|
||||
element.data('interval', refreshIntervalId);
|
||||
}, msUntilSecond);
|
||||
}
|
||||
});
|
||||
element.attr(config.counterTaskAttr, taskName);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -134,30 +122,33 @@ define([
|
||||
*/
|
||||
let initTableCounter = (tableElement, columnSelector, round) => {
|
||||
let tableApi = tableElement.api();
|
||||
let taskName = tableElement.attr('id');
|
||||
|
||||
// mark as init
|
||||
tableElement.attr('data-counter', 'init');
|
||||
|
||||
let updateTableCount = () => {
|
||||
tableApi.cells(null, columnSelector).every(function(rowIndex, colIndex, tableLoopCount, cellLoopCount){
|
||||
let cell = this;
|
||||
let node = cell.node();
|
||||
let data = cell.data();
|
||||
if(data && Number.isInteger(data) && !node.classList.contains('stopCounter')){
|
||||
// timestamp expected int > 0
|
||||
let date = new Date(data * 1000);
|
||||
updateDateDiff( cell.nodes().to$(), date, round);
|
||||
}
|
||||
});
|
||||
let cellUpdate = function(rowIndex, colIndex, tableLoopCount, cellLoopCount){
|
||||
let cell = this;
|
||||
let node = cell.node();
|
||||
let data = cell.data();
|
||||
if(data && Number.isInteger(data) && !node.classList.contains(config.counterStopClass)){
|
||||
// timestamp expected int > 0
|
||||
let date = new Date(data * 1000);
|
||||
updateDateDiff(cell.nodes().to$(), date, round);
|
||||
}
|
||||
};
|
||||
|
||||
let refreshIntervalId = window.setInterval(updateTableCount, 500);
|
||||
let counterTask = Cron.new(taskName, {precision: 'seconds', interval: 1, timeout: 100});
|
||||
counterTask.task = timer => {
|
||||
tableApi.cells(null, columnSelector).every(cellUpdate);
|
||||
};
|
||||
Cron.set(counterTask);
|
||||
|
||||
tableElement.data('interval', refreshIntervalId);
|
||||
tableElement.attr(config.counterTaskAttr, taskName);
|
||||
};
|
||||
|
||||
return {
|
||||
config: config,
|
||||
updateDateDiff: updateDateDiff,
|
||||
initTableCounter: initTableCounter
|
||||
initTimestampCounter: initTimestampCounter,
|
||||
initTableCounter: initTableCounter,
|
||||
destroyTimestampCounter: destroyTimestampCounter
|
||||
};
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/counter',
|
||||
'app/promises/promise.deferred',
|
||||
'app/promises/promise.timeout',
|
||||
'datatables.net',
|
||||
@@ -8,7 +9,7 @@ define([
|
||||
'datatables.net-buttons-html',
|
||||
'datatables.net-responsive',
|
||||
'datatables.net-select'
|
||||
], ($, Init, DeferredPromise, TimeoutPromise) => {
|
||||
], ($, Init, Counter, DeferredPromise, TimeoutPromise) => {
|
||||
'use strict';
|
||||
|
||||
// all Datatables stuff is available...
|
||||
@@ -42,7 +43,7 @@ define([
|
||||
}
|
||||
|
||||
// remove all active counters in table
|
||||
table.destroyTimestampCounter(true);
|
||||
Counter.destroyTimestampCounter(table, true);
|
||||
});
|
||||
|
||||
// Status Plugin ==============================================================================================
|
||||
|
||||
@@ -126,13 +126,13 @@ define([], () => {
|
||||
let Cache = class Cache {
|
||||
|
||||
constructor(config){
|
||||
this.config = Object.assign({
|
||||
this.config = Object.assign({},{
|
||||
name: 'Default', // custom name for identification
|
||||
ttl: 3600,
|
||||
maxSize: 600,
|
||||
bufferSize: 10, // in percent
|
||||
strategy: 'FIFO',
|
||||
debug: false
|
||||
ttl: 3600, // default ttl for cache entries
|
||||
maxSize: 600, // max cache entries
|
||||
bufferSize: 10, // cache entry count in percent to be removed if maxSize reached
|
||||
strategy: 'FIFO', // cache strategy policy
|
||||
debug: false // debug output in console
|
||||
}, config);
|
||||
|
||||
this.store = new Map();
|
||||
318
public/js/v1.5.5/app/lib/cron.js
Normal file
318
public/js/v1.5.5/app/lib/cron.js
Normal file
@@ -0,0 +1,318 @@
|
||||
define([
|
||||
'easyTimer',
|
||||
'app/promises/promise.timeout',
|
||||
], (easytimer, TimeoutPromise) => {
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
Example1 run task every second ------------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 1, timeout: 100});
|
||||
task1.task = (timer) => {
|
||||
console.log('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
|
||||
Example2 run task every 3 seconds ---------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 3, timeout: 100});
|
||||
task1.task = (timer) => {
|
||||
console.log('task1 function():', timer.getTotalTimeValues());
|
||||
return 'OK';
|
||||
};
|
||||
Cron.set(task1);
|
||||
|
||||
Example3 resolve Promise on run ----------------------------------------------------------------------------------
|
||||
let task1 = Cron.new('task1', {precision: 'seconds', interval: 1, timeout: 100});
|
||||
task1.task = (timer, task) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('task1 Promise1():', timer.getTotalTimeValues(), task.get('interval'));
|
||||
//task.set('interval', task.get('interval') + 1) // increase run interval every time by 1s
|
||||
resolve('OK1');
|
||||
}).then(payload => {
|
||||
return new Promise((resolve, reject) => {
|
||||
console.log('task2 Promise2():', timer.getTotalTimeValues(), payload);
|
||||
resolve('OK2');
|
||||
});
|
||||
});
|
||||
};
|
||||
Cron.set(task1);
|
||||
|
||||
Example4 run task once at given Date() --------------------------------------------------------------------------
|
||||
let dueDate = new Date();
|
||||
dueDate.setSeconds(dueDate.getSeconds() + 5);
|
||||
let task2 = Cron.new('task2', {precision: 'seconds', timeout: 100, dueDate: dueDate});
|
||||
task2.task = () => 'OK task2';
|
||||
Cron.set(task2);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Task instances represent a task that should be executed at a given interval or dueDate
|
||||
* -> Task´s are managed by CronManager()
|
||||
* @type {Task}
|
||||
*/
|
||||
let Task = class Task {
|
||||
constructor(name, config){
|
||||
if(typeof name !== 'string'){
|
||||
throw new TypeError('Task "name" must be instance of String, Type of "' + typeof name + '" given');
|
||||
}
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._name = name; // unique name for identification
|
||||
this._task = undefined; // task to run, instanceof Function, can also return a Promise
|
||||
this._manager = undefined; // reference to CronManager() that handles this task
|
||||
this._runQueue = new Map(); // current run() processes. > 1 requires config.isParallel: true
|
||||
this._runCount = 0; // total run counter for this task
|
||||
this._lastTotalTimeValues = undefined; // time values of last run()
|
||||
}
|
||||
|
||||
get name(){
|
||||
return this._name;
|
||||
}
|
||||
|
||||
get precision(){
|
||||
return this._config.precision;
|
||||
}
|
||||
|
||||
get task(){
|
||||
return this._task;
|
||||
}
|
||||
|
||||
set task(task){
|
||||
if(task instanceof Function){
|
||||
this._task = task;
|
||||
}else{
|
||||
throw new TypeError('Task "task" must be instance of "function", Type of "' + typeof task + '" given');
|
||||
}
|
||||
}
|
||||
|
||||
get(option){
|
||||
return this._config[option];
|
||||
}
|
||||
|
||||
set(option, value){
|
||||
this._config[option] = value;
|
||||
}
|
||||
|
||||
setManager(manager){
|
||||
this._manager = manager;
|
||||
}
|
||||
|
||||
isRunning(){
|
||||
return !!this._runQueue.size;
|
||||
}
|
||||
|
||||
delete(){
|
||||
let isDeleted = false;
|
||||
if(this._manager){
|
||||
isDeleted = this._manager.delete(this.name);
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
isDue(timer){
|
||||
if(this._config.dueDate instanceof Date){
|
||||
// run once at dueDate
|
||||
if(new Date().getTime() >= this._config.dueDate.getTime()){
|
||||
return true;
|
||||
}
|
||||
}else{
|
||||
// periodic execution
|
||||
let totalTimeValues = timer.getTotalTimeValues();
|
||||
let totalTimeValuePrecision = totalTimeValues[this.precision];
|
||||
totalTimeValuePrecision -= this._lastTotalTimeValues ? this._lastTotalTimeValues[this.precision] : 0;
|
||||
if(
|
||||
this._config.interval === 1 ||
|
||||
totalTimeValuePrecision % this._config.interval === 0
|
||||
){
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
invoke(timer){
|
||||
if(
|
||||
this.isDue(timer) &&
|
||||
(!this.isRunning() || this._config.isParallel)
|
||||
){
|
||||
this.run(timer);
|
||||
}
|
||||
}
|
||||
|
||||
run(timer){
|
||||
this._lastTotalTimeValues = Object.assign({}, timer.getTotalTimeValues());
|
||||
let runId = 'run_' + (++this._runCount);
|
||||
let runExec = resolve => {
|
||||
resolve(this.task(timer, this));
|
||||
};
|
||||
|
||||
let myProm = this._config.timeout > 0 ? new TimeoutPromise(runExec, this._config.timeout) : new Promise(runExec);
|
||||
myProm.then(payload => {
|
||||
// resolved within timeout -> wait for finally() block
|
||||
}).catch(error => {
|
||||
if(error instanceof Error){
|
||||
// either timeout error or error from rejected deferredPromise
|
||||
console.warn(error);
|
||||
}
|
||||
}).finally(() => {
|
||||
// no matter if TimeoutPromise is resolved or rejected
|
||||
// -> remove from _runQueue
|
||||
this._runQueue.delete(runId);
|
||||
|
||||
// remove this task from store after run
|
||||
if(this._config.dueDate instanceof Date){
|
||||
this.delete();
|
||||
}
|
||||
});
|
||||
|
||||
this._runQueue.set(runId, myProm);
|
||||
}
|
||||
};
|
||||
|
||||
Task.defaultConfig = {
|
||||
precision: 'seconds', // updateEvent this tasked will be subscribed to
|
||||
isParallel: false, // if true this task can run parallel, e.g. if prev execution has not finished
|
||||
interval: 1, // relates to 'precision'. 'interval' = 3 and 'precision' = "seconds" -> run every 3 seconds
|
||||
dueDate: undefined, // if Date() instance is set, task only runs once at dueDate
|
||||
timeout: 50 // if > 0, execution time that exceeds timeout (ms) throw error
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* An instance of CronManager() handles multiple Task()´s
|
||||
* -> Task()´s can be set()/delete() from CronManager() instance
|
||||
* @type {CronManager}
|
||||
*/
|
||||
let CronManager = class CronManager {
|
||||
|
||||
constructor(config){
|
||||
this._config = Object.assign({}, this.constructor.defaultConfig, config);
|
||||
this._timerConfig = Object.assign({}, this.constructor.defaultTimerConfig);
|
||||
|
||||
this._tasks = new Map();
|
||||
this._timer = new easytimer.Timer();
|
||||
|
||||
// init Easytimer update events
|
||||
this._config.precisions.map(precision => precision + 'Updated').forEach(eventName => {
|
||||
this._timer.on(eventName, e => {
|
||||
let precision = e.type.substring(0, e.type.indexOf('Updated'));
|
||||
this.tasksByPrecision(precision).forEach(task => task.invoke(e.detail.timer));
|
||||
});
|
||||
});
|
||||
|
||||
this.debug = (msg,...data) => {
|
||||
if(this._config.debug){
|
||||
data = (data || []);
|
||||
console.info(msg, ...data);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
new(name, config){
|
||||
return new Task(name, config);
|
||||
}
|
||||
|
||||
set(task){
|
||||
if(task instanceof Task){
|
||||
// check for unique task name, or update existing task
|
||||
if(!this.has(task.name) || (this.get(task.name) === task)){
|
||||
// set new or update existing task
|
||||
task.setManager(this);
|
||||
this._tasks.set(task.name, task);
|
||||
this.debug('SET/UPDATE task: %o config: %o', task.name, task);
|
||||
// start timer (if it is not already running)
|
||||
this.auto();
|
||||
}else{
|
||||
console.warn('FAILED to set task. Task name %o already exists', task.name);
|
||||
}
|
||||
}else{
|
||||
throw new TypeError('Parameter must be instance of Task');
|
||||
}
|
||||
}
|
||||
|
||||
setNew(name, config){
|
||||
this.set(this.new(name, config));
|
||||
}
|
||||
|
||||
get(name){
|
||||
return this._tasks.get(name);
|
||||
}
|
||||
|
||||
has(name){
|
||||
return this._tasks.has(name);
|
||||
}
|
||||
|
||||
delete(name){
|
||||
let isDeleted = this._tasks.delete(name);
|
||||
if(isDeleted){
|
||||
this.debug('DELETE task: %o', name);
|
||||
this.auto();
|
||||
}
|
||||
return isDeleted;
|
||||
}
|
||||
|
||||
clear(){
|
||||
this.debug('CLEAR all %o task(s)', this._tasks.size);
|
||||
this._tasks.clear();
|
||||
this.auto();
|
||||
}
|
||||
|
||||
tasksByPrecision(precision){
|
||||
let tasks = [];
|
||||
this._tasks.forEach(task => {
|
||||
if(precision === task.precision){
|
||||
tasks.push(task);
|
||||
}
|
||||
});
|
||||
return tasks;
|
||||
}
|
||||
|
||||
// EasyTimer controls -----------------------------------------------------------------------------------------
|
||||
start(){
|
||||
this._timer.start(this._timerConfig);
|
||||
}
|
||||
|
||||
stop(){
|
||||
this._timer.stop();
|
||||
}
|
||||
|
||||
pause(){
|
||||
this._timer.pause();
|
||||
}
|
||||
|
||||
reset(){
|
||||
this._timer.reset();
|
||||
}
|
||||
|
||||
auto(){
|
||||
if(this._tasks.size){
|
||||
if(!this._timer.isRunning()){
|
||||
this.start();
|
||||
this.debug('START [auto] timer. %o task(s) found.', this._tasks.size);
|
||||
}
|
||||
}else{
|
||||
this.stop();
|
||||
this.debug('STOP [auto] timer. No tasks set.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CronManager.defaultConfig = {
|
||||
precisions: [
|
||||
'secondTenths',
|
||||
'seconds',
|
||||
'minutes',
|
||||
'hours',
|
||||
'days'
|
||||
],
|
||||
debug: false // debug output in console
|
||||
};
|
||||
|
||||
CronManager.defaultTimerConfig = {
|
||||
precision: 'secondTenths', // Timer update frequency. Values: 'secondTenths', 'seconds', 'minutes', 'hours'
|
||||
countdown: false // If true, the timer is a countdown
|
||||
};
|
||||
|
||||
return new CronManager({
|
||||
debug: false
|
||||
});
|
||||
});
|
||||
@@ -6,8 +6,9 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/counter',
|
||||
'bootbox'
|
||||
], ($, Init, Util, bootbox) => {
|
||||
], ($, Init, Util, Counter, bootbox) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -31,11 +32,11 @@ define([
|
||||
* updated "sync status" dynamic dialog area
|
||||
*/
|
||||
let updateSyncStatus = () => {
|
||||
|
||||
// check if task manager dialog is open
|
||||
let logDialog = $('#' + config.taskDialogId);
|
||||
if(logDialog.length){
|
||||
// dialog is open
|
||||
let statusArea = logDialog.find('.' + config.taskDialogStatusAreaClass);
|
||||
requirejs(['text!templates/modules/sync_status.html', 'mustache'], (templateSyncStatus, Mustache) => {
|
||||
let data = {
|
||||
timestampCounterClass: config.timestampCounterClass,
|
||||
@@ -49,10 +50,12 @@ define([
|
||||
};
|
||||
|
||||
let syncStatusElement = $(Mustache.render(templateSyncStatus, data ));
|
||||
Counter.destroyTimestampCounter(statusArea, true);
|
||||
|
||||
logDialog.find('.' + config.taskDialogStatusAreaClass).html( syncStatusElement );
|
||||
statusArea.html(syncStatusElement);
|
||||
|
||||
logDialog.find('.' + config.timestampCounterClass).initTimestampCounter();
|
||||
let counterElements = syncStatusElement.find('.' + config.timestampCounterClass);
|
||||
Counter.initTimestampCounter(counterElements);
|
||||
|
||||
syncStatusElement.initTooltips({
|
||||
placement: 'right'
|
||||
|
||||
@@ -6,6 +6,7 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/counter',
|
||||
'app/logging',
|
||||
'mustache',
|
||||
'app/map/util',
|
||||
@@ -26,7 +27,7 @@ define([
|
||||
'dialog/credit',
|
||||
'xEditable',
|
||||
'app/module_map'
|
||||
], ($, Init, Util, Logging, Mustache, MapUtil, MapContextMenu, SlideBars, TplHead, TplFooter) => {
|
||||
], ($, Init, Util, Counter, Logging, Mustache, MapUtil, MapContextMenu, SlideBars, TplHead, TplFooter) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -879,7 +880,6 @@ define([
|
||||
// global "modal" callback --------------------------------------------------------------------------------
|
||||
bodyElement.on('hide.bs.modal', '> .modal', e => {
|
||||
let modalElement = $(e.target);
|
||||
modalElement.destroyTimestampCounter(true);
|
||||
|
||||
// destroy all form validators
|
||||
// -> does not work properly. validation functions still used (js error) after 'destroy'
|
||||
@@ -892,6 +892,14 @@ define([
|
||||
modalElement.find('.' + Util.config.select2Class)
|
||||
.filter((i, element) => $(element).data('select2'))
|
||||
.select2('destroy');
|
||||
|
||||
// destroy DataTable instances
|
||||
for(let table of modalElement.find('table.dataTable')){
|
||||
$(table).DataTable().destroy(true);
|
||||
}
|
||||
|
||||
// destroy counter
|
||||
Counter.destroyTimestampCounter(modalElement, true);
|
||||
});
|
||||
|
||||
// global "close" trigger for context menus ---------------------------------------------------------------
|
||||
|
||||
@@ -7,10 +7,10 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'bootbox',
|
||||
'app/counter',
|
||||
'bootbox',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, Render, bootbox, Counter, MapUtil) => {
|
||||
], ($, Init, Util, Render, Counter, bootbox, MapUtil) => {
|
||||
|
||||
'use strict';
|
||||
|
||||
@@ -182,7 +182,7 @@ define([
|
||||
mapElement.append(dlElementRight);
|
||||
|
||||
// init map lifetime counter
|
||||
$('.' + config.mapInfoLifetimeCounterClass).initTimestampCounter();
|
||||
Counter.initTimestampCounter($('.' + config.mapInfoLifetimeCounterClass));
|
||||
|
||||
mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){
|
||||
let mapUrl = $(this).find('span').text().trim();
|
||||
|
||||
@@ -8,9 +8,10 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/render',
|
||||
'app/counter',
|
||||
'bootbox',
|
||||
'peityInlineChart'
|
||||
], ($, Init, Util, Render, bootbox) => {
|
||||
], ($, Init, Util, Render, Counter, bootbox) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -37,7 +38,7 @@ define([
|
||||
* init blank statistics dataTable
|
||||
* @param dialogElement
|
||||
*/
|
||||
let initStatsTable = function(dialogElement){
|
||||
let initStatsTable = dialogElement => {
|
||||
let columnNumberWidth = 28;
|
||||
let cellPadding = 4;
|
||||
let lineChartWidth = columnNumberWidth + (2 * cellPadding);
|
||||
@@ -114,6 +115,7 @@ define([
|
||||
columnDefs: [
|
||||
{
|
||||
targets: 0,
|
||||
name: 'rowIndex',
|
||||
title: '<i class="fas fa-hashtag"></i>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -122,6 +124,7 @@ define([
|
||||
data: 'character.id'
|
||||
},{
|
||||
targets: 1,
|
||||
name: 'image',
|
||||
title: '',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -135,6 +138,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 2,
|
||||
name: 'name',
|
||||
title: 'name',
|
||||
width: 200,
|
||||
data: 'character',
|
||||
@@ -144,20 +148,16 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 3,
|
||||
name: 'lastLogin',
|
||||
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();
|
||||
}
|
||||
data: 'character.lastLogin',
|
||||
defaultContent: ''
|
||||
},{
|
||||
targets: 4,
|
||||
name: 'mapCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -169,6 +169,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 5,
|
||||
name: 'mapUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -180,6 +181,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 6,
|
||||
name: 'mapDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -191,6 +193,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 7,
|
||||
name: 'mapSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -201,6 +204,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 8,
|
||||
name: 'systemCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -212,6 +216,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 9,
|
||||
name: 'systemUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -223,6 +228,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 10,
|
||||
name: 'systemDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -234,6 +240,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 11,
|
||||
name: 'systemSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -244,6 +251,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 12,
|
||||
name: 'connectionCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -255,6 +263,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 13,
|
||||
name: 'connectionUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -266,6 +275,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 14,
|
||||
name: 'connectionDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -277,6 +287,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 15,
|
||||
name: 'connectionSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -287,6 +298,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 16,
|
||||
name: 'signatureCreate',
|
||||
title: '<span title="created" data-toggle="tooltip">C </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -298,6 +310,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 17,
|
||||
name: 'signatureUpdate',
|
||||
title: '<span title="updated" data-toggle="tooltip">U </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -309,6 +322,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 18,
|
||||
name: 'signatureDelete',
|
||||
title: '<span title="deleted" data-toggle="tooltip">D </span>',
|
||||
orderable: false,
|
||||
searchable: false,
|
||||
@@ -320,6 +334,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 19,
|
||||
name: 'signatureSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -330,6 +345,7 @@ define([
|
||||
}
|
||||
},{
|
||||
targets: 20,
|
||||
name: 'totalSum',
|
||||
title: 'Σ ',
|
||||
searchable: false,
|
||||
width: 20,
|
||||
@@ -346,6 +362,8 @@ define([
|
||||
// initial statistics data request
|
||||
let requestData = getRequestDataFromTabPanels(dialogElement);
|
||||
getStatsData(requestData, {tableApi: tableApi, callback: drawStatsTable});
|
||||
|
||||
Counter.initTableCounter(this, ['lastLogin:name']);
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
this.api().rows().nodes().to$().each(function(i, row){
|
||||
@@ -374,7 +392,7 @@ define([
|
||||
});
|
||||
|
||||
$(sumColumnIndexes).each(function(index, value){
|
||||
$( api.column( value ).footer() ).text( renderNumericColumn(pageTotalColumns[index], 'display') );
|
||||
$(api.column(value).footer()).text( renderNumericColumn(pageTotalColumns[index], 'display') );
|
||||
});
|
||||
},
|
||||
data: [] // will be added dynamic
|
||||
@@ -404,8 +422,7 @@ define([
|
||||
* @param requestData
|
||||
* @param context
|
||||
*/
|
||||
let getStatsData = function(requestData, context){
|
||||
|
||||
let getStatsData = (requestData, context) => {
|
||||
context.dynamicArea = $('#' + config.statsContainerId + ' .' + Util.config.dynamicAreaClass);
|
||||
context.dynamicArea.showLoadingAnimation();
|
||||
|
||||
@@ -418,7 +435,7 @@ define([
|
||||
}).done(function(data){
|
||||
this.dynamicArea.hideLoadingAnimation();
|
||||
|
||||
this.callback(data);
|
||||
this.callback(data, this);
|
||||
}).fail(function(jqXHR, status, error){
|
||||
let reason = status + ' ' + error;
|
||||
Util.showNotify({title: jqXHR.status + ': loadStatistics', text: reason, type: 'warning'});
|
||||
@@ -430,7 +447,7 @@ define([
|
||||
* update "header"/"filter" elements in dialog
|
||||
* @param responseData
|
||||
*/
|
||||
let drawStatsTable = function(responseData){
|
||||
let drawStatsTable = (responseData, context) => {
|
||||
let dialogElement = $('#' + config.statsDialogId);
|
||||
|
||||
// update filter/header -----------------------------------------------------------------------------
|
||||
@@ -467,8 +484,8 @@ define([
|
||||
|
||||
// clear and (re)-fill table ------------------------------------------------------------------------
|
||||
let formattedData = formatStatisticsData(responseData);
|
||||
this.tableApi.clear();
|
||||
this.tableApi.rows.add(formattedData).draw();
|
||||
context.tableApi.clear();
|
||||
context.tableApi.rows.add(formattedData).draw();
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -477,7 +494,7 @@ define([
|
||||
* @param statsData
|
||||
* @returns {Array}
|
||||
*/
|
||||
let formatStatisticsData = function(statsData){
|
||||
let formatStatisticsData = statsData => {
|
||||
let formattedData = [];
|
||||
let yearStart = statsData.start.year;
|
||||
let weekStart = statsData.start.week;
|
||||
@@ -687,7 +704,7 @@ define([
|
||||
* @param dialogElement
|
||||
* @returns {{}}
|
||||
*/
|
||||
let getRequestDataFromTabPanels = function(dialogElement){
|
||||
let getRequestDataFromTabPanels = dialogElement => {
|
||||
let requestData = {};
|
||||
|
||||
// get data from "tab" panel links ------------------------------------------------------------------
|
||||
|
||||
@@ -7,8 +7,9 @@ define([
|
||||
'app/init',
|
||||
'app/util',
|
||||
'bootbox',
|
||||
'app/counter',
|
||||
'app/map/util'
|
||||
], ($, Init, Util, bootbox, MapUtil) => {
|
||||
], ($, Init, Util, bootbox, Counter, MapUtil) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -827,10 +828,7 @@ define([
|
||||
title: 'log',
|
||||
width: 55,
|
||||
className: ['text-right', config.tableCellCounterClass].join(' '),
|
||||
data: 'created.created',
|
||||
createdCell: function(cell, cellData, rowData, rowIndex, colIndex){
|
||||
$(cell).initTimestampCounter('d');
|
||||
}
|
||||
data: 'created.created'
|
||||
},{
|
||||
targets: 5,
|
||||
name: 'edit',
|
||||
@@ -931,6 +929,9 @@ define([
|
||||
}
|
||||
}
|
||||
],
|
||||
initComplete: function(settings, json){
|
||||
Counter.initTableCounter(this, ['created:name']);
|
||||
},
|
||||
drawCallback: function(settings){
|
||||
let animationRows = this.api().rows().nodes().to$().filter(function(a,b ){
|
||||
return (
|
||||
|
||||
@@ -6,9 +6,8 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/cache',
|
||||
'morris'
|
||||
], ($, Init, Util, Cache, Morris) => {
|
||||
'app/lib/cache'
|
||||
], ($, Init, Util, Cache) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
|
||||
@@ -6,13 +6,13 @@ define([
|
||||
'jquery',
|
||||
'app/init',
|
||||
'app/util',
|
||||
'app/cache',
|
||||
'bootbox',
|
||||
'app/counter',
|
||||
'app/map/map',
|
||||
'app/map/util',
|
||||
'app/lib/cache',
|
||||
'app/ui/form_element'
|
||||
], ($, Init, Util, Cache, bootbox, Counter, Map, MapUtil, FormElement) => {
|
||||
], ($, Init, Util, bootbox, Counter, Map, MapUtil, Cache, FormElement) => {
|
||||
'use strict';
|
||||
|
||||
let config = {
|
||||
@@ -482,7 +482,7 @@ define([
|
||||
// hide row
|
||||
|
||||
// stop sig counter by adding a stopClass to each <td>, remove padding
|
||||
cellElements.addClass('stopCounter')
|
||||
cellElements.addClass(Counter.config.counterStopClass)
|
||||
.velocity({
|
||||
paddingTop: [0, '4px'],
|
||||
paddingBottom: [0, '4px'],
|
||||
|
||||
@@ -742,7 +742,7 @@ define([
|
||||
|
||||
let defaultOptions = {
|
||||
dismissible: true,
|
||||
messageId: 'pf-alert-' + Math.random().toString(36).substring(7),
|
||||
messageId: getRandomString('pf-alert-'),
|
||||
messageTypeClass: messageTypeClass,
|
||||
messageTextClass: messageTextClass,
|
||||
insertElement: 'replace'
|
||||
@@ -873,7 +873,8 @@ define([
|
||||
|
||||
if(!resourceVariant){
|
||||
switch(resourceType){
|
||||
case 'factions': resourceType = 'corporations'; // faction icons are on 'corporations' endpoint.. CCP fail?!
|
||||
// faction icons are on 'corporations' endpoint.. CCP fail?!
|
||||
case 'factions': resourceType = 'corporations'; // jshint ignore:line
|
||||
case 'alliances':
|
||||
case 'corporations': resourceVariant = 'logo'; break;
|
||||
case 'characters': resourceVariant = 'portrait'; break;
|
||||
@@ -1580,6 +1581,14 @@ define([
|
||||
return Init.timer[updateKey].CURRENT_DELAY;
|
||||
};
|
||||
|
||||
/**
|
||||
* get a random string
|
||||
* -> e.g. as for Ids
|
||||
* @param prefix
|
||||
* @returns {string}
|
||||
*/
|
||||
let getRandomString = (prefix = 'id_') => prefix + Math.random().toString(36).substring(2,10);
|
||||
|
||||
/**
|
||||
* get date obj with current EVE Server Time.
|
||||
* @returns {Date}
|
||||
@@ -1857,7 +1866,7 @@ define([
|
||||
let key = 'tabId';
|
||||
let tabId = sessionStorage.getItem(key);
|
||||
if(tabId === null){
|
||||
tabId = Math.random().toString(36).substr(2, 5);
|
||||
tabId = getRandomString();
|
||||
sessionStorage.setItem(key, tabId);
|
||||
}
|
||||
return tabId;
|
||||
@@ -3521,6 +3530,7 @@ define([
|
||||
initDefaultSelect2Config: initDefaultSelect2Config,
|
||||
initDefaultEditableConfig: initDefaultEditableConfig,
|
||||
getCurrentTriggerDelay: getCurrentTriggerDelay,
|
||||
getRandomString: getRandomString,
|
||||
getServerTime: getServerTime,
|
||||
convertTimestampToServerTime: convertTimestampToServerTime,
|
||||
getTimeDiffParts: getTimeDiffParts,
|
||||
|
||||
7
public/js/v1.5.5/lib/easytimer.min.js
vendored
Normal file
7
public/js/v1.5.5/lib/easytimer.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user