mirror of
https://github.com/nzbget/nzbget.git
synced 2025-12-23 22:27:45 -05:00
1735 lines
41 KiB
JavaScript
1735 lines
41 KiB
JavaScript
/*
|
|
* This file is part of nzbget. See <http://nzbget.net>.
|
|
*
|
|
* Copyright (C) 2012-2019 Andrey Prygunkov <hugbug@users.sourceforge.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/*
|
|
* In this module:
|
|
* 1) Status Infos on main page (speed, time, paused state etc.);
|
|
* 2) Statistics and Status dialog;
|
|
* 3) Limit dialog (speed and active news servers);
|
|
* 4) Filter menu.
|
|
*/
|
|
|
|
/*** STATUS INFOS ON MAIN PAGE AND STATISTICS DIALOG ****************************************/
|
|
|
|
var Status = (new function($)
|
|
{
|
|
'use strict';
|
|
|
|
// Properties (public)
|
|
this.status;
|
|
|
|
// Controls
|
|
var $CHPauseDownload;
|
|
var $CHPausePostProcess;
|
|
var $CHPauseScan;
|
|
var $StatusSpeed;
|
|
var $StatusSpeedIcon;
|
|
var $StatusTimeIcon;
|
|
var $StatusTime;
|
|
var $PlayBlock;
|
|
var $PlayButton;
|
|
var $PauseButton;
|
|
var $PlayAnimation;
|
|
var $ScheduledPauseDialog;
|
|
var $PauseForInput;
|
|
var $PauseForPreview;
|
|
|
|
// State
|
|
var status;
|
|
var lastPlayState = 0;
|
|
var lastAnimState = 0;
|
|
var playInitialized = false;
|
|
var modalShown = false;
|
|
var titleGen = [];
|
|
|
|
var validTimePatterns = [
|
|
/^=\d{1,2}(:[0-5][0-9])?$/, // 24h exact
|
|
/^=\d{1,2}(:[0-5][0-9])?(AM|PM)$/i, // 12h exact
|
|
/^\d+(:[0-5][0-9])?$/, // 24h relative
|
|
/^\d+(h|m)?$/i, // relative minutes or hours
|
|
];
|
|
|
|
this.init = function()
|
|
{
|
|
$CHPauseDownload = $('#CHPauseDownload');
|
|
$CHPausePostProcess = $('#CHPausePostProcess');
|
|
$CHPauseScan = $('#CHPauseScan');
|
|
$PlayBlock = $('#PlayBlock');
|
|
$PlayButton = $('#PlayButton');
|
|
$PauseButton = $('#PauseButton');
|
|
$PlayAnimation = $('#PlayAnimation');
|
|
$StatusSpeed = $('#StatusSpeed');
|
|
$StatusSpeedIcon = $('#StatusSpeedIcon');
|
|
$StatusTimeIcon = $('#StatusTimeIcon');
|
|
$StatusTime = $('#StatusTime');
|
|
$ScheduledPauseDialog = $('#ScheduledPauseDialog');
|
|
$PauseForInput = $('#PauseForInput');
|
|
$PauseForPreview = $('#PauseForPreview');
|
|
|
|
if (UISettings.setFocus)
|
|
{
|
|
$ScheduledPauseDialog.on('shown', function()
|
|
{
|
|
$('#PauseForInput').focus();
|
|
});
|
|
}
|
|
|
|
$PlayAnimation.hover(function() { $PlayBlock.addClass('hover'); }, function() { $PlayBlock.removeClass('hover'); });
|
|
$PauseForInput.keyup(function(e)
|
|
{
|
|
if (e.which == 13) return;
|
|
|
|
calculateSeconds($(this).val());
|
|
});
|
|
|
|
// temporary pause the play animation if any modal is shown (to avoid artifacts in safari)
|
|
$('body >.modal').on('show', modalShow);
|
|
$('body > .modal').on('hide', modalHide);
|
|
|
|
StatDialog.init();
|
|
FilterMenu.init();
|
|
initTitle();
|
|
}
|
|
|
|
this.update = function()
|
|
{
|
|
var _this = this;
|
|
RPC.call('status', [],
|
|
function(curStatus)
|
|
{
|
|
status = curStatus;
|
|
_this.status = status;
|
|
StatDialog.update();
|
|
});
|
|
}
|
|
|
|
this.redraw = function()
|
|
{
|
|
redrawInfo();
|
|
StatDialog.redraw();
|
|
}
|
|
|
|
function redrawInfo()
|
|
{
|
|
Util.show($CHPauseDownload, status.DownloadPaused);
|
|
Util.show($CHPausePostProcess, status.PostPaused);
|
|
Util.show($CHPauseScan, status.ScanPaused);
|
|
|
|
updatePlayAnim();
|
|
updatePlayButton();
|
|
|
|
if (status.ServerStandBy)
|
|
{
|
|
$StatusSpeed.html('--- MB/s');
|
|
if (status.ResumeTime > 0)
|
|
{
|
|
$StatusTime.html(Util.formatTimeLeft(status.ResumeTime - status.ServerTime));
|
|
}
|
|
else if (status.RemainingSizeMB > 0 || status.RemainingSizeLo > 0)
|
|
{
|
|
if (status.AverageDownloadRate > 0)
|
|
{
|
|
$StatusTime.html(Util.formatTimeLeft(status.RemainingSizeMB*1024/(status.AverageDownloadRate/1024)));
|
|
}
|
|
else
|
|
{
|
|
$StatusTime.html('--h --m');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$StatusTime.html('0h 0m');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$StatusSpeed.html(Util.formatSpeed(status.DownloadRate));
|
|
if (status.DownloadRate > 0)
|
|
{
|
|
$StatusTime.html(Util.formatTimeLeft(
|
|
(status.DownloadPaused ? status.ForcedSizeMB : status.RemainingSizeMB) *1024/(status.DownloadRate/1024)));
|
|
}
|
|
else
|
|
{
|
|
$StatusTime.html('--h --m');
|
|
}
|
|
}
|
|
|
|
var limit = status.DownloadLimit > 0;
|
|
if (!limit)
|
|
{
|
|
for (var i=0; i < Status.status.NewsServers.length; i++)
|
|
{
|
|
limit = !Status.status.NewsServers[i].Active;
|
|
if (limit)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
$StatusSpeedIcon.toggleClass('icon-plane', !limit);
|
|
$StatusSpeedIcon.toggleClass('icon-truck', limit);
|
|
|
|
var statWarning = (status.ServerStandBy && status.ResumeTime > 0) || status.QuotaReached;
|
|
$StatusTime.toggleClass('orange', statWarning);
|
|
$StatusTimeIcon.toggleClass('icon-time', !statWarning);
|
|
$StatusTimeIcon.toggleClass('icon-time-orange', statWarning);
|
|
|
|
updateTitle();
|
|
}
|
|
|
|
function updatePlayButton()
|
|
{
|
|
var Play = !status.DownloadPaused;
|
|
if (Play === lastPlayState)
|
|
{
|
|
return;
|
|
}
|
|
|
|
lastPlayState = Play;
|
|
|
|
var hideBtn = Play ? $PlayButton : $PauseButton;
|
|
var showBtn = !Play ? $PlayButton : $PauseButton;
|
|
|
|
if (playInitialized)
|
|
{
|
|
hideBtn.fadeOut(500);
|
|
showBtn.fadeIn(500);
|
|
if (!Play && !status.ServerStandBy)
|
|
{
|
|
PopupNotification.show('#Notif_Downloads_Pausing');
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hideBtn.hide();
|
|
showBtn.show();
|
|
}
|
|
|
|
if (Play)
|
|
{
|
|
$PlayAnimation.removeClass('pause').addClass('play');
|
|
}
|
|
else
|
|
{
|
|
$PlayAnimation.removeClass('play').addClass('pause');
|
|
}
|
|
|
|
playInitialized = true;
|
|
}
|
|
|
|
function updatePlayAnim()
|
|
{
|
|
// Animate if either any downloads or post-processing is in progress
|
|
var Anim = (!status.ServerStandBy || status.FeedActive || status.QueueScriptCount > 0 ||
|
|
(status.PostJobCount > 0 && !status.PostPaused) ||
|
|
(status.UrlCount > 0 && (!status.DownloadPaused || Options.option('UrlForce') === 'yes'))) &&
|
|
(UISettings.refreshInterval !== 0) && !UISettings.connectionError && UISettings.activityAnimation;
|
|
if (Anim === lastAnimState)
|
|
{
|
|
return;
|
|
}
|
|
|
|
lastAnimState = Anim;
|
|
|
|
if (!modalShown)
|
|
{
|
|
if (Anim)
|
|
{
|
|
$PlayAnimation.fadeIn(1000);
|
|
}
|
|
else
|
|
{
|
|
$PlayAnimation.fadeOut(1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
this.playClick = function()
|
|
{
|
|
//PopupNotification.show('#Notif_Play');
|
|
|
|
if (lastPlayState)
|
|
{
|
|
// pause all activities
|
|
RPC.call('pausedownload', [],
|
|
function(){RPC.call('pausepost', [],
|
|
function(){RPC.call('pausescan', [], Refresher.update)})});
|
|
}
|
|
else
|
|
{
|
|
// resume all activities
|
|
RPC.call('resumedownload', [],
|
|
function(){RPC.call('resumepost', [],
|
|
function(){RPC.call('resumescan', [], Refresher.update)})});
|
|
}
|
|
}
|
|
|
|
this.pauseClick = function(data)
|
|
{
|
|
switch (data)
|
|
{
|
|
case 'download':
|
|
var method = status.DownloadPaused ? 'resumedownload' : 'pausedownload';
|
|
break;
|
|
case 'post':
|
|
var method = status.PostPaused ? 'resumepost' : 'pausepost';
|
|
break;
|
|
case 'scan':
|
|
var method = status.ScanPaused ? 'resumescan' : 'pausescan';
|
|
break;
|
|
}
|
|
RPC.call(method, [], Refresher.update);
|
|
}
|
|
|
|
this.statDialogClick = function()
|
|
{
|
|
StatDialog.showModal();
|
|
}
|
|
|
|
this.scheduledPauseClick = function(seconds)
|
|
{
|
|
RPC.call('pausedownload', [],
|
|
function(){RPC.call('pausepost', [],
|
|
function(){RPC.call('pausescan', [],
|
|
function(){RPC.call('scheduleresume', [seconds], Refresher.update)})})});
|
|
}
|
|
|
|
this.scheduledPauseDialogClick = function()
|
|
{
|
|
$PauseForInput.val('');
|
|
$PauseForPreview.addClass('invisible');
|
|
$ScheduledPauseDialog.modal();
|
|
}
|
|
|
|
this.pauseForClick = function()
|
|
{
|
|
var val = $PauseForInput.val();
|
|
var seconds = calculateSeconds(val);
|
|
|
|
if (isNaN(seconds) || seconds <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
$ScheduledPauseDialog.modal('hide');
|
|
this.scheduledPauseClick(seconds);
|
|
}
|
|
|
|
function isTimeInputValid(str)
|
|
{
|
|
for (var i = 0; i < validTimePatterns.length; i++)
|
|
{
|
|
if (validTimePatterns[i].test(str)) return true;
|
|
}
|
|
}
|
|
|
|
function calculateSeconds(parsable) {
|
|
parsable = parsable.toLowerCase();
|
|
|
|
if (!isTimeInputValid(parsable))
|
|
{
|
|
$PauseForPreview.addClass('invisible');
|
|
return;
|
|
}
|
|
|
|
var now = new Date(), future = new Date();
|
|
var hours = 0, minutes = 0;
|
|
|
|
var mode = /^=/.test(parsable) ? 'exact' : 'relative';
|
|
var indicator = (parsable.match(/h|m|am|pm$/i) || [])[0];
|
|
var parsedTime = parsable.match(/(\d+):?(\d+)?/) || [];
|
|
var primaryValue = parsedTime[1];
|
|
var secondaryValue = parsedTime[2];
|
|
var is12H = (indicator === 'am' || indicator === 'pm');
|
|
|
|
if (indicator === undefined && secondaryValue === undefined)
|
|
{
|
|
if (mode === 'exact') hours = parseInt(primaryValue);
|
|
else minutes = parseInt(primaryValue);
|
|
}
|
|
else if (indicator === 'm')
|
|
{
|
|
minutes = parseInt(primaryValue);
|
|
}
|
|
else
|
|
{
|
|
hours = parseInt(primaryValue);
|
|
if (secondaryValue) minutes = parseInt(secondaryValue);
|
|
if (indicator === 'pm' && hours < 12) hours += 12;
|
|
}
|
|
|
|
if ((mode !== 'exact' && (is12H || (hours > 0 && minutes > 59))) ||
|
|
(mode === 'exact' && (hours < 0 || hours > 23 || minutes < 0 || minutes > 59)))
|
|
{
|
|
$PauseForPreview.addClass('invisible');
|
|
return;
|
|
}
|
|
|
|
if (mode === 'exact')
|
|
{
|
|
future.setHours(hours, minutes, 0, 0);
|
|
|
|
if (future < now) future.setDate(now.getDate() + 1);
|
|
}
|
|
else
|
|
{
|
|
future.setHours(now.getHours() + hours, now.getMinutes() + minutes);
|
|
}
|
|
|
|
$PauseForPreview.find('strong')
|
|
.text((future.getDay() !== now.getDay()) ? future.toLocaleString() : future.toLocaleTimeString())
|
|
.end()
|
|
.removeClass('invisible');
|
|
|
|
return (future - now)/1000;
|
|
}
|
|
|
|
function modalShow()
|
|
{
|
|
modalShown = true;
|
|
if (lastAnimState)
|
|
{
|
|
$PlayAnimation.hide();
|
|
}
|
|
}
|
|
|
|
function modalHide()
|
|
{
|
|
if (lastAnimState)
|
|
{
|
|
$PlayAnimation.show();
|
|
}
|
|
modalShown = false;
|
|
}
|
|
|
|
this.serverName = function(server)
|
|
{
|
|
var name = Options.option('Server' + server.ID + '.Name');
|
|
if (name === null || name === '')
|
|
{
|
|
var host = Options.option('Server' + server.ID + '.Host');
|
|
var port = Options.option('Server' + server.ID + '.Port');
|
|
name = (host === null ? '' : host) + ':' + (port === null ? '119' : port);
|
|
}
|
|
return name;
|
|
}
|
|
|
|
function initTitle()
|
|
{
|
|
function format(pattern, paramFunc)
|
|
{
|
|
if (UISettings.connectionError)
|
|
{
|
|
var value = '?';
|
|
var isEmpty = false;
|
|
}
|
|
else
|
|
{
|
|
var param = paramFunc();
|
|
var value = param[0];
|
|
var isEmpty = param[1];
|
|
}
|
|
|
|
if (isEmpty && pattern != '%VAR%')
|
|
{
|
|
return '';
|
|
}
|
|
|
|
switch (pattern)
|
|
{
|
|
case '%VAR%': return value;
|
|
case '%VAR-%': return '' + value + ' - ';
|
|
case '%(VAR)%': return '(' + value + ')';
|
|
case '%(VAR-)%': return '(' + value + ') - ';
|
|
case '%[VAR]%': return '[' + value + ']';
|
|
case '%[VAR-]%': return '[' + value + '] - ';
|
|
}
|
|
|
|
return Downloads.groups.length > 0 ? '' + Downloads.groups.length + ' - ' : '';
|
|
};
|
|
|
|
function fill(varname, paramFunc)
|
|
{
|
|
titleGen['%' + varname + '%'] = function() { return format('%VAR%', paramFunc); };
|
|
titleGen['%' + varname + '-%'] = function() { return format('%VAR-%', paramFunc); };
|
|
titleGen['%(' + varname + ')%'] = function() { return format('%(VAR)%', paramFunc); };
|
|
titleGen['%(' + varname + '-)%'] = function() { return format('%(VAR-)%', paramFunc); };
|
|
titleGen['%[' + varname + ']%'] = function() { return format('%[VAR]%', paramFunc); };
|
|
titleGen['%[' + varname + '-]%'] = function() { return format('%[VAR-]%', paramFunc); };
|
|
}
|
|
|
|
fill('COUNT', function() { return [Downloads.groups.length, Downloads.groups.length == 0]; });
|
|
fill('SPEED', function() { return [$StatusSpeed.text(), status.ServerStandBy]; });
|
|
fill('TIME', function() { return [$StatusTime.text(), status.ServerStandBy]; });
|
|
fill('PAUSE', function() { return ['||', !status.DownloadPaused]; });
|
|
}
|
|
|
|
function updateTitle()
|
|
{
|
|
var title = UISettings.windowTitle;
|
|
|
|
for (var name in titleGen)
|
|
{
|
|
if (title.indexOf(name) > -1)
|
|
{
|
|
var value = titleGen[name]();
|
|
title = title.replace(name, value);
|
|
}
|
|
}
|
|
|
|
title = title.trim();
|
|
|
|
window.document.title = title;
|
|
}
|
|
this.updateTitle = updateTitle;
|
|
}(jQuery));
|
|
|
|
|
|
/*** STATISTICS DIALOG *******************************************************/
|
|
|
|
var StatDialog = (new function($)
|
|
{
|
|
'use strict';
|
|
|
|
// Controls
|
|
var $StatDialog;
|
|
var $StatDialog_DataVersion;
|
|
var $StatDialog_DataUptime;
|
|
var $StatDialog_DataDownloadTime;
|
|
var $StatDialog_DataTotalDownloaded;
|
|
var $StatDialog_DataRemaining;
|
|
var $StatDialog_DataFree;
|
|
var $StatDialog_DataAverageSpeed;
|
|
var $StatDialog_DataCurrentSpeed;
|
|
var $StatDialog_DataSpeedLimit;
|
|
var $StatDialog_ArticleCache;
|
|
var $StatDialog_QueueScripts;
|
|
var $StatDialog_ChartBlock;
|
|
var $StatRangeDialog;
|
|
var $StatRangeDialog_PeriodInput;
|
|
var $StatDialog_Tooltip;
|
|
var $StatDialog_TodaySize;
|
|
var $StatDialog_MonthSize;
|
|
var $StatDialog_AllTimeSize;
|
|
var $StatDialog_CustomSize;
|
|
var $StatDialog_Custom;
|
|
|
|
// State
|
|
var visible = false;
|
|
var lastPage;
|
|
var lastTab = null;
|
|
var lastFullscreen;
|
|
var servervolumes = null;
|
|
var prevServervolumes = null;
|
|
var curRange = 'MIN';
|
|
var redrawLock = 0;
|
|
var needChartUpdate = false;
|
|
var curServer = 0;
|
|
var monthListInitialized = false;
|
|
var curMonth = null;
|
|
var monYear = false;
|
|
var monStartIndex = 0;
|
|
var monEndIndex = 0;
|
|
var monStartDate;
|
|
var chartData = null;
|
|
var mouseOverIndex = -1;
|
|
var clockOK = false;
|
|
var volumeMode = false;
|
|
|
|
var monthNames = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
|
|
|
|
this.init = function()
|
|
{
|
|
$StatDialog = $('#StatDialog');
|
|
$StatDialog_DataVersion = $('#StatDialog_DataVersion');
|
|
$StatDialog_DataUptime = $('#StatDialog_DataUptime');
|
|
$StatDialog_DataDownloadTime = $('#StatDialog_DataDownloadTime');
|
|
$StatDialog_DataTotalDownloaded = $('#StatDialog_DataTotalDownloaded');
|
|
$StatDialog_DataRemaining = $('#StatDialog_DataRemaining');
|
|
$StatDialog_DataFree = $('#StatDialog_DataFree');
|
|
$StatDialog_DataAverageSpeed = $('#StatDialog_DataAverageSpeed');
|
|
$StatDialog_DataCurrentSpeed = $('#StatDialog_DataCurrentSpeed');
|
|
$StatDialog_DataSpeedLimit = $('#StatDialog_DataSpeedLimit');
|
|
$StatDialog_ArticleCache = $('#StatDialog_ArticleCache');
|
|
$StatDialog_QueueScripts = $('#StatDialog_QueueScripts');
|
|
$StatDialog_ChartBlock = $('#StatDialog_ChartBlock');
|
|
$StatRangeDialog = $('#StatRangeDialog');
|
|
$StatRangeDialog_PeriodInput = $('#StatRangeDialog_PeriodInput');
|
|
$StatDialog_Tooltip = $('#StatDialog_Tooltip');
|
|
$StatDialog_TodaySize = $('#StatDialog_TodaySize');
|
|
$StatDialog_MonthSize = $('#StatDialog_MonthSize');
|
|
$StatDialog_AllTimeSize = $('#StatDialog_AllTimeSize');
|
|
$StatDialog_CustomSize = $('#StatDialog_CustomSize');
|
|
$StatDialog_Custom = $('#StatDialog_Custom');
|
|
|
|
$('#StatDialog_ServerMenuAll').click(chooseServer);
|
|
$('#StatDialog_Volumes').click(tabClick);
|
|
$('#StatDialog_Back').click(backClick);
|
|
|
|
$StatDialog.on('hidden', function()
|
|
{
|
|
// cleanup
|
|
lastTab = null;
|
|
servervolumes = null;
|
|
prevServervolumes = null;
|
|
$StatDialog_ChartBlock.empty();
|
|
visible = false;
|
|
});
|
|
|
|
if (UISettings.setFocus)
|
|
{
|
|
$StatRangeDialog.on('shown', function()
|
|
{
|
|
$StatRangeDialog_PeriodInput.focus();
|
|
});
|
|
}
|
|
|
|
$StatRangeDialog.on('hidden', StatRangeDialogHidden);
|
|
|
|
TabDialog.extend($StatDialog);
|
|
}
|
|
|
|
this.update = function()
|
|
{
|
|
if (visible)
|
|
{
|
|
RPC.call('servervolumes', [], servervolumes_loaded);
|
|
}
|
|
else
|
|
{
|
|
RPC.next();
|
|
}
|
|
}
|
|
|
|
function servervolumes_loaded(volumes)
|
|
{
|
|
prevServervolumes = servervolumes;
|
|
servervolumes = volumes;
|
|
RPC.next();
|
|
}
|
|
|
|
function firstLoadStatisticsData()
|
|
{
|
|
RPC.call('servervolumes', [], function (volumes)
|
|
{
|
|
prevServervolumes = servervolumes;
|
|
servervolumes = volumes;
|
|
updateMonthList();
|
|
StatDialog.redraw();
|
|
});
|
|
}
|
|
|
|
this.showModal = function(serverId)
|
|
{
|
|
volumeMode = serverId !== undefined;
|
|
curServer = serverId !== undefined ? serverId : 0;
|
|
|
|
$('#StatDialog_GeneralTab').show();
|
|
$('#StatDialog_VolumesTab').hide();
|
|
$('#StatDialog_Back').hide();
|
|
$('#StatDialog_BackSpace').show();
|
|
$('#StatDialog_Title').text('Statistics and Status');
|
|
Util.show('#StatDialog_ArticleCache_Row', Options.option('ArticleCache') !== '0');
|
|
Util.show('#StatDialog_QueueScripts_Row', Status.status.QueueScriptCount > 0);
|
|
$StatDialog.removeClass('modal-large').addClass('modal-mini');
|
|
|
|
if (Options.option('QuotaStartDay') != '1')
|
|
{
|
|
$('#StatDialog_MonthTitle').text('Billing month:');
|
|
}
|
|
|
|
$('#StatDialog_Volume_MONTH, #StatDialog_Volume_MONTH2').text(monthNames[(new Date()).getMonth()] + ' ' + (new Date()).getFullYear());
|
|
|
|
monthListInitialized = false;
|
|
updateServerList();
|
|
lastTab = null;
|
|
$StatDialog.restoreTab();
|
|
visible = true;
|
|
redrawStatistics();
|
|
$StatDialog.modal();
|
|
firstLoadStatisticsData();
|
|
|
|
if (volumeMode)
|
|
{
|
|
$('#StatDialog_Volumes').click();
|
|
}
|
|
}
|
|
|
|
this.redraw = function()
|
|
{
|
|
if (visible)
|
|
{
|
|
redrawStatistics();
|
|
if (servervolumes !== null && lastTab === '#StatDialog_VolumesTab')
|
|
{
|
|
if (redrawLock > 0)
|
|
{
|
|
needChartUpdate = true;
|
|
}
|
|
else
|
|
{
|
|
if (!monthListInitialized)
|
|
{
|
|
updateMonthList();
|
|
}
|
|
redrawChart();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function redrawStatistics()
|
|
{
|
|
var status = Status.status;
|
|
|
|
$StatDialog_DataVersion.text(Options.option('Version'));
|
|
$StatDialog_DataUptime.text(Util.formatTimeHMS(status.UpTimeSec));
|
|
$StatDialog_DataDownloadTime.text(Util.formatTimeHMS(status.DownloadTimeSec));
|
|
$StatDialog_DataTotalDownloaded.html(Util.formatSizeMB(status.DownloadedSizeMB));
|
|
$StatDialog_DataRemaining.html(Util.formatSizeMB(status.RemainingSizeMB));
|
|
$StatDialog_DataFree.html(Util.formatSizeMB(status.FreeDiskSpaceMB));
|
|
$StatDialog_DataAverageSpeed.html(Util.formatSpeed(status.AverageDownloadRate));
|
|
$StatDialog_DataCurrentSpeed.html(Util.formatSpeed(status.DownloadRate));
|
|
$StatDialog_DataSpeedLimit.html(Util.formatSpeed(status.DownloadLimit));
|
|
$StatDialog_ArticleCache.html(Util.formatSizeMB(status.ArticleCacheMB, status.ArticleCacheLo));
|
|
$StatDialog_QueueScripts.html(status.QueueScriptCount);
|
|
|
|
var content = '';
|
|
content += '<tr><td>Download</td><td class="text-right">' +
|
|
(status.DownloadPaused ?
|
|
'<span class="label label-status label-warning">paused</span>' :
|
|
'<span class="label label-status label-success">active</span>') +
|
|
'</td></tr>';
|
|
|
|
content += '<tr><td>Post-processing</td><td class="text-right">' + (Options.option('PostProcess') === '' ?
|
|
'<span class="label label-status">disabled</span>' :
|
|
(status.PostPaused ?
|
|
'<span class="label label-status label-warning">paused</span>' :
|
|
'<span class="label label-status label-success">active</span>')) +
|
|
'</td></tr>';
|
|
|
|
content += '<tr><td>NZB-Directory scan</td><td class="text-right">' + (Options.option('NzbDirInterval') === '0' ?
|
|
'<span class="label label-status">disabled</span>' :
|
|
(status.ScanPaused ?
|
|
'<span class="label label-status label-warning">paused</span>' :
|
|
'<span class="label label-status label-success">active</span>')) +
|
|
'</td></tr>';
|
|
|
|
if (status.QuotaReached)
|
|
{
|
|
content += '<tr><td>Download quota</td><td class="text-right"><span class="label label-status label-warning">reached</span></td></tr>';
|
|
}
|
|
|
|
if (status.ResumeTime > 0)
|
|
{
|
|
content += '<tr><td>Autoresume</td><td class="text-right">' + Util.formatTimeHMS(status.ResumeTime - status.ServerTime) + '<i class="icon-empty"/></td></tr>';
|
|
}
|
|
|
|
$('#StatusTable tbody').html(content);
|
|
}
|
|
|
|
function tabClick(e)
|
|
{
|
|
e.preventDefault();
|
|
|
|
if (!volumeMode)
|
|
{
|
|
$('#StatDialog_Back').fadeIn(500);
|
|
$('#StatDialog_BackSpace').hide();
|
|
}
|
|
lastTab = '#' + $(this).attr('data-tab');
|
|
lastPage = $(lastTab);
|
|
lastFullscreen = ($(this).attr('data-fullscreen') === 'true') && !UISettings.miniTheme;
|
|
redrawLock++;
|
|
$StatDialog.switchTab($('#StatDialog_GeneralTab'), lastPage,
|
|
e.shiftKey || !UISettings.slideAnimation || volumeMode ? 0 : 500,
|
|
{ fullscreen: lastFullscreen,
|
|
toggleClass: 'modal-mini modal-large',
|
|
mini: UISettings.miniTheme,
|
|
complete: tabSwitchCompleted});
|
|
if (lastTab === '#StatDialog_VolumesTab')
|
|
{
|
|
if (servervolumes)
|
|
{
|
|
redrawChart();
|
|
}
|
|
$('#StatDialog_Title').text('Downloaded volumes');
|
|
}
|
|
}
|
|
|
|
function backClick(e)
|
|
{
|
|
e.preventDefault();
|
|
$('#StatDialog_Back').fadeOut(500, function()
|
|
{
|
|
$('#StatDialog_BackSpace').show();
|
|
});
|
|
|
|
$StatDialog.switchTab(lastPage, $('#StatDialog_GeneralTab'),
|
|
e.shiftKey || !UISettings.slideAnimation ? 0 : 500,
|
|
{ fullscreen: lastFullscreen,
|
|
toggleClass: 'modal-mini modal-large',
|
|
mini: UISettings.miniTheme,
|
|
back: true});
|
|
lastTab = null;
|
|
|
|
$('#StatDialog_Title').text('Statistics and Status');
|
|
}
|
|
|
|
function tabSwitchCompleted()
|
|
{
|
|
redrawLock--;
|
|
if (needChartUpdate)
|
|
{
|
|
needChartUpdate = false;
|
|
if (!monthListInitialized)
|
|
{
|
|
updateMonthList();
|
|
}
|
|
redrawChart();
|
|
}
|
|
Frontend.alignPopupMenu('#StatDialog_MonthMenu', true);
|
|
}
|
|
|
|
function size64(size)
|
|
{
|
|
return size.SizeMB < 2000 ? size.SizeLo / 1024.0 / 1024.0 : size.SizeMB;
|
|
}
|
|
|
|
function redrawChart()
|
|
{
|
|
var serverNo = curServer;
|
|
var lineLabels = [];
|
|
var dataLabels = [];
|
|
var chartDataTB = [];
|
|
var chartDataGB = [];
|
|
var chartDataMB = [];
|
|
var chartDataKB = [];
|
|
var chartDataB = [];
|
|
var curPoint = null;
|
|
var sumMB = 0;
|
|
var sumLo = 0;
|
|
var maxSizeMB = 0;
|
|
var maxSizeLo = 0;
|
|
|
|
function addData(bytes, dataLab, lineLab)
|
|
{
|
|
dataLabels.push(dataLab);
|
|
lineLabels.push(lineLab);
|
|
|
|
if (bytes === null)
|
|
{
|
|
chartDataTB.push(null);
|
|
chartDataGB.push(null);
|
|
chartDataMB.push(null);
|
|
chartDataKB.push(null);
|
|
chartDataB.push(null);
|
|
return;
|
|
}
|
|
chartDataTB.push(bytes.SizeMB / 1024.0 / 1024.0);
|
|
chartDataGB.push(bytes.SizeMB / 1024.0);
|
|
chartDataMB.push(size64(bytes));
|
|
chartDataKB.push(bytes.SizeLo / 1024.0);
|
|
chartDataB.push(bytes.SizeLo);
|
|
if (bytes.SizeMB > maxSizeMB)
|
|
{
|
|
maxSizeMB = bytes.SizeMB;
|
|
}
|
|
if (bytes.SizeLo > maxSizeLo)
|
|
{
|
|
maxSizeLo = bytes.SizeLo;
|
|
}
|
|
sumMB += bytes.SizeMB;
|
|
sumLo += bytes.SizeLo;
|
|
}
|
|
|
|
function drawMinuteGraph()
|
|
{
|
|
// the current slot may be not fully filled yet,
|
|
// to make the chart smoother for current slot we use the data from the previous reading
|
|
// and we show the previous slot as current.
|
|
curPoint = servervolumes[serverNo].SecSlot;
|
|
for (var i = 0; i < 60; i++)
|
|
{
|
|
addData((i == curPoint && prevServervolumes !== null ? prevServervolumes : servervolumes)[serverNo].BytesPerSeconds[i],
|
|
i + 's', i % 10 == 0 || i == 59 ? i : '');
|
|
}
|
|
if (prevServervolumes !== null)
|
|
{
|
|
curPoint = curPoint > 0 ? curPoint-1 : 59;
|
|
}
|
|
}
|
|
|
|
function drawHourGraph()
|
|
{
|
|
for (var i = 0; i < 60; i++)
|
|
{
|
|
addData(servervolumes[serverNo].BytesPerMinutes[i],
|
|
i + 'm', i % 10 == 0 || i == 59 ? i : '');
|
|
}
|
|
curPoint = servervolumes[serverNo].MinSlot;
|
|
}
|
|
|
|
function drawDayGraph()
|
|
{
|
|
for (var i = 0; i < 24; i++)
|
|
{
|
|
addData(servervolumes[serverNo].BytesPerHours[i],
|
|
i + 'h', i % 3 == 0 || i == 23 ? i : '');
|
|
}
|
|
curPoint = servervolumes[serverNo].HourSlot;
|
|
}
|
|
|
|
function drawMonthGraph()
|
|
{
|
|
var len = servervolumes[serverNo].BytesPerDays.length;
|
|
var daySlot = servervolumes[serverNo].DaySlot;
|
|
var slotDelta = servervolumes[0].FirstDay - servervolumes[serverNo].FirstDay;
|
|
var dt = new Date(monStartDate.getTime());
|
|
var day = 1;
|
|
for (var i = monStartIndex; i <= monEndIndex; i++, day++)
|
|
{
|
|
dt.setDate(day);
|
|
var slot = i + slotDelta;
|
|
addData((slot >= 0 && slot < len ? servervolumes[serverNo].BytesPerDays[slot] : null),
|
|
dt.toDateString(), (day == 1 || day % 5 == 0 || (day < 30 && i === monEndIndex) ? day : ''));
|
|
if (slot === daySlot)
|
|
{
|
|
curPoint = day-1;
|
|
}
|
|
}
|
|
// ensure the line has always the same length (looks nicer)
|
|
for (; day < 32; day++)
|
|
{
|
|
addData(null, null, null);
|
|
}
|
|
}
|
|
|
|
function drawYearGraph()
|
|
{
|
|
var firstMon = -1;
|
|
var lastMon = -1;
|
|
var monDataMB = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
var monDataLo = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
|
|
|
// aggregate daily volumes into months
|
|
var daySlot = servervolumes[serverNo].DaySlot;
|
|
var slotDelta = servervolumes[0].FirstDay - servervolumes[serverNo].FirstDay;
|
|
var day = 0;
|
|
for (var i = monStartIndex; i <= monEndIndex; i++, day++)
|
|
{
|
|
var dt = new Date(monStartDate.getTime() + day*24*60*60*1000);
|
|
var slot = i + slotDelta;
|
|
var bytes = servervolumes[serverNo].BytesPerDays[slot];
|
|
if (bytes)
|
|
{
|
|
var mon = dt.getMonth();
|
|
monDataMB[mon] += bytes.SizeMB;
|
|
monDataLo[mon] += bytes.SizeLo;
|
|
if (firstMon === -1)
|
|
{
|
|
firstMon = mon;
|
|
}
|
|
if (mon > lastMon)
|
|
{
|
|
lastMon = mon;
|
|
}
|
|
if (slot === daySlot)
|
|
{
|
|
curPoint = mon;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (var i = 0; i < 12; i++)
|
|
{
|
|
addData(firstMon > -1 && i >= firstMon && i <= lastMon ? {SizeMB: monDataMB[i], SizeLo: monDataLo[i]} : null,
|
|
monthNames[i] + ' ' + curMonth, monthNames[i].substr(0, 3));
|
|
}
|
|
}
|
|
|
|
if (curRange === 'MIN')
|
|
{
|
|
drawMinuteGraph();
|
|
}
|
|
else if (curRange === 'HOUR')
|
|
{
|
|
drawHourGraph();
|
|
}
|
|
else if (curRange === 'DAY')
|
|
{
|
|
drawDayGraph();
|
|
}
|
|
else if (curRange === 'MONTH' && !monYear)
|
|
{
|
|
drawMonthGraph();
|
|
}
|
|
else if (curRange === 'MONTH' && monYear)
|
|
{
|
|
drawYearGraph();
|
|
}
|
|
|
|
var serieData = maxSizeMB > 1024*1024 ? chartDataTB :
|
|
maxSizeMB > 1024 ? chartDataGB :
|
|
maxSizeMB > 1 || maxSizeLo == 0 ? chartDataMB :
|
|
maxSizeLo > 1024 ? chartDataKB : chartDataB;
|
|
|
|
var units = maxSizeMB > 1024*1024 ? ' TB' :
|
|
maxSizeMB > 1024 ? ' GB' :
|
|
maxSizeMB > 1 || maxSizeLo == 0 ? ' MB' :
|
|
maxSizeLo > 1024 ? ' KB' : ' B';
|
|
|
|
var curPointData = [];
|
|
for (var i = 0; i < serieData.length; i++)
|
|
{
|
|
curPointData.push(i===curPoint ? serieData[i] : null);
|
|
}
|
|
|
|
chartData = {
|
|
serieData: serieData,
|
|
serieDataMB: chartDataMB,
|
|
serieDataLo: chartDataB,
|
|
sumMB: sumMB,
|
|
sumLo: sumLo,
|
|
dataLabels: dataLabels
|
|
};
|
|
|
|
$StatDialog_ChartBlock.empty();
|
|
$StatDialog_ChartBlock.html('<div id="StatDialog_Chart"></div>');
|
|
$('#StatDialog_Chart').chart({
|
|
values: { serie1 : serieData, serie2: curPointData },
|
|
labels: lineLabels,
|
|
type: 'line',
|
|
margins: [10, 15, 20, 60],
|
|
defaultSeries: {
|
|
rounded: 0.5,
|
|
fill: true,
|
|
plotProps: {
|
|
'stroke-width': 3.0
|
|
},
|
|
dot: true,
|
|
dotProps: {
|
|
stroke: '#FFF',
|
|
size: 3.0,
|
|
'stroke-width': 1.0,
|
|
fill: '#5AF'
|
|
},
|
|
highlight: {
|
|
scaleSpeed: 0,
|
|
scaleEasing: '>',
|
|
scale: 2.0
|
|
},
|
|
tooltip: {
|
|
active: false,
|
|
},
|
|
color: '#5AF'
|
|
},
|
|
series: {
|
|
serie2: {
|
|
dotProps: {
|
|
stroke: '#F21860',
|
|
fill: '#F21860',
|
|
size: 3.5,
|
|
'stroke-width': 2.5
|
|
},
|
|
highlight: {
|
|
scale: 1.5
|
|
},
|
|
}
|
|
},
|
|
defaultAxis: {
|
|
labels: true,
|
|
labelsProps: {
|
|
'font-size': 13
|
|
},
|
|
labelsDistance: 12
|
|
},
|
|
axis: {
|
|
l: {
|
|
labels: true,
|
|
suffix: units
|
|
}
|
|
},
|
|
features: {
|
|
grid: {
|
|
draw: [true, false],
|
|
forceBorder: true,
|
|
props: {
|
|
stroke: '#e0e0e0',
|
|
'stroke-width': 1
|
|
},
|
|
ticks: {
|
|
active: [true, false, false],
|
|
size: [6, 0],
|
|
props: {
|
|
stroke: '#e0e0e0'
|
|
}
|
|
}
|
|
},
|
|
mousearea: {
|
|
type: 'axis',
|
|
onMouseOver: chartMouseOver,
|
|
onMouseExit: chartMouseExit,
|
|
onMouseOut: chartMouseExit
|
|
},
|
|
}
|
|
});
|
|
|
|
simulateMouseEvent();
|
|
|
|
updateCounters();
|
|
}
|
|
|
|
function chartMouseOver(env, serie, index, mouseAreaData)
|
|
{
|
|
if (mouseOverIndex > -1)
|
|
{
|
|
var env = $('#StatDialog_Chart').data('elycharts_env');
|
|
$.elycharts.mousemanager.onMouseOutArea(env, false, mouseOverIndex, env.mouseAreas[mouseOverIndex]);
|
|
}
|
|
mouseOverIndex = index;
|
|
$StatDialog_Tooltip.html(chartData.dataLabels[index] + ': <span class="stat-size">' +
|
|
Util.formatSizeMB(chartData.serieDataMB[index], chartData.serieDataLo[index]) + '</span>');
|
|
}
|
|
|
|
function chartMouseExit(env, serie, index, mouseAreaData)
|
|
{
|
|
mouseOverIndex = -1;
|
|
var title = curRange === 'MIN' ? '60 seconds' :
|
|
curRange === 'HOUR' ? '60 minutes' :
|
|
curRange === 'DAY' ? '24 hours' :
|
|
curRange === 'MONTH' ? $('#StatDialog_Volume_MONTH').text() : 'Sum';
|
|
|
|
$StatDialog_Tooltip.html(title + ': <span class="stat-size">' + Util.formatSizeMB(chartData.sumMB, chartData.sumLo) + '</span>');
|
|
}
|
|
|
|
function simulateMouseEvent()
|
|
{
|
|
if (mouseOverIndex > -1)
|
|
{
|
|
var env = $('#StatDialog_Chart').data('elycharts_env');
|
|
$.elycharts.mousemanager.onMouseOverArea(env, false, mouseOverIndex, env.mouseAreas[mouseOverIndex]);
|
|
}
|
|
else
|
|
{
|
|
chartMouseExit()
|
|
}
|
|
}
|
|
|
|
this.chooseRange = function(range)
|
|
{
|
|
curRange = range;
|
|
updateRangeButtons();
|
|
mouseOverIndex = -1;
|
|
redrawChart();
|
|
}
|
|
|
|
function updateRangeButtons()
|
|
{
|
|
$('#StatDialog_Toolbar .volume-range').removeClass('btn-inverse');
|
|
$('#StatDialog_Volume_' + curRange + ',#StatDialog_Volume_' + curRange + '2,#StatDialog_Volume_' + curRange + '3').addClass('btn-inverse');
|
|
}
|
|
|
|
function updateServerList()
|
|
{
|
|
var menu = $('#StatDialog_ServerMenu');
|
|
var menuItemTemplate = $('.volume-server-template', menu);
|
|
var insertPos = $('#StatDialog_ServerMenuDivider', menu);
|
|
|
|
$('.volume-server', menu).remove();
|
|
for (var i=0; i < Status.status.NewsServers.length; i++)
|
|
{
|
|
var server = Status.status.NewsServers[i];
|
|
var name = server.ID + '. ' + Status.serverName(server);
|
|
var item = menuItemTemplate.clone().removeClass('volume-server-template hide').addClass('volume-server');
|
|
var a = $('a', item);
|
|
a.html('<i class="' + (i === curServer-1 ? 'icon-ok' : 'icon-empty') + '"></i>' + Util.textToHtml(name));
|
|
a.attr('data-id', server.ID);
|
|
a.click(chooseServer);
|
|
insertPos.before(item);
|
|
}
|
|
|
|
$('#StatDialog_ServerCap').text(curServer > 0 ? Status.serverName(Status.status.NewsServers[curServer-1]) : 'All news servers');
|
|
$('#StatDialog_ServerMenuAll i').toggleClass('icon-ok', curServer === 0).toggleClass('icon-empty', curServer !== 0);
|
|
}
|
|
|
|
function chooseServer(server)
|
|
{
|
|
curServer = parseInt($(this).attr('data-id'));
|
|
updateServerList();
|
|
redrawChart();
|
|
}
|
|
|
|
function dayToDate(epochDay)
|
|
{
|
|
var dt = new Date(epochDay * 24*60*60 * 1000);
|
|
dt = new Date(dt.getTime() + dt.getTimezoneOffset() * 60*1000);
|
|
return dt;
|
|
}
|
|
|
|
function dateToDay(date)
|
|
{
|
|
var epochDay = Math.ceil((date.getTime() - date.getTimezoneOffset() * 60*1000) / (1000*24*60*60));
|
|
return epochDay;
|
|
}
|
|
|
|
function updateMonthList()
|
|
{
|
|
monthListInitialized = true;
|
|
|
|
var firstDay = servervolumes[0].FirstDay;
|
|
var curDay = firstDay + servervolumes[0].DaySlot;
|
|
var firstDt = dayToDate(firstDay);
|
|
var curDt = dayToDate(curDay);
|
|
|
|
var menu = $('#StatDialog_MonthMenu');
|
|
var menuItemTemplate = $('.volume-month-template', menu);
|
|
var insertPos = $('#StatDialog_MonthMenuYears', menu);
|
|
|
|
$('.volume-month', menu).remove();
|
|
|
|
// does computer running NZBGet has correct date (after 1-Jan-2013)?
|
|
clockOK = firstDay > 0 && servervolumes[0].DaySlot > -1;
|
|
|
|
if (!clockOK)
|
|
{
|
|
updatePeriod();
|
|
return;
|
|
}
|
|
|
|
// show last three months in the menu
|
|
firstDt.setDate(1);
|
|
var monDt = new Date(curDt.getTime());
|
|
monDt.setDate(1);
|
|
for (var i=0; i<3; i++)
|
|
{
|
|
if (monDt < firstDt)
|
|
{
|
|
break;
|
|
}
|
|
|
|
var name = monthNames[monDt.getMonth()] + ' ' + monDt.getFullYear();
|
|
var monId = '' + monDt.getFullYear() + '-' + monDt.getMonth();
|
|
|
|
if (curMonth === null)
|
|
{
|
|
curMonth = monId;
|
|
}
|
|
|
|
var item = menuItemTemplate.clone().removeClass('volume-month-template hide').addClass('volume-month');
|
|
var a = $('a', item);
|
|
a.html('<i class="' + (monId === curMonth ? 'icon-ok' : 'icon-empty') + '"></i>' + name);
|
|
a.attr('data-id', monId);
|
|
a.click(chooseMonth);
|
|
insertPos.before(item);
|
|
|
|
monDt.setMonth(monDt.getMonth() - 1);
|
|
}
|
|
|
|
// show last two years in the menu
|
|
var insertPos = $('#StatDialog_MonthMenuDivider', menu);
|
|
firstDt.setMonth(0);
|
|
monDt = new Date(curDt.getTime());
|
|
monDt.setDate(1);
|
|
monDt.setMonth(0);
|
|
for (var i=0; i<2; i++)
|
|
{
|
|
if (monDt < firstDt)
|
|
{
|
|
break;
|
|
}
|
|
|
|
var name = monDt.getFullYear();
|
|
var monId = '' + monDt.getFullYear();
|
|
|
|
var item = menuItemTemplate.clone().removeClass('volume-month-template hide').addClass('volume-month');
|
|
var a = $('a', item);
|
|
a.html('<i class="' + (monId === curMonth ? 'icon-ok' : 'icon-empty') + '"></i>' + name);
|
|
a.attr('data-id', monId);
|
|
a.click(chooseMonth);
|
|
insertPos.before(item);
|
|
|
|
monDt.setFullYear(monDt.getFullYear() - 1);
|
|
}
|
|
|
|
updatePeriod();
|
|
}
|
|
|
|
function updatePeriod()
|
|
{
|
|
if (!clockOK)
|
|
{
|
|
monStartDate = new Date(2000, 1);
|
|
monStartIndex = -1;
|
|
monEndIndex = -1;
|
|
return;
|
|
}
|
|
|
|
var cap;
|
|
var monStart;
|
|
var monEnd;
|
|
|
|
monYear = curMonth.indexOf('-') === -1;
|
|
if (monYear)
|
|
{
|
|
cap = curMonth;
|
|
var year = parseInt(curMonth);
|
|
monStart = new Date(year, 0);
|
|
monEnd = new Date(year, 11, 31);
|
|
}
|
|
else
|
|
{
|
|
var month = parseInt(curMonth.substr(5, 2));
|
|
var year = parseInt(curMonth.substring(0, 4));
|
|
cap = monthNames[month] + ' ' + year;
|
|
monStart = new Date(year, month);
|
|
monEnd = new Date(year, month + 1);
|
|
monEnd.setDate(0);
|
|
}
|
|
|
|
$('#StatDialog_Volume_MONTH, #StatDialog_Volume_MONTH2').text(cap);
|
|
|
|
monStartDate = monStart;
|
|
var firstDay = servervolumes[0].FirstDay;
|
|
monStart = dateToDay(monStart);
|
|
monEnd = dateToDay(monEnd);
|
|
monStartIndex = monStart - firstDay;
|
|
monEndIndex = monEnd - firstDay;
|
|
}
|
|
|
|
function updateCounters()
|
|
{
|
|
$StatDialog_TodaySize.html(Util.formatSizeMB(Status.status.DaySizeMB, Status.status.DaySizeLo));
|
|
$StatDialog_MonthSize.html(Util.formatSizeMB(Status.status.MonthSizeMB, Status.status.MonthSizeLo));
|
|
$StatDialog_AllTimeSize.html(Util.formatSizeMB(servervolumes[curServer].TotalSizeMB, servervolumes[curServer].TotalSizeLo));
|
|
$StatDialog_CustomSize.html(Util.formatSizeMB(servervolumes[curServer].CustomSizeMB, servervolumes[curServer].CustomSizeLo));
|
|
$StatDialog_Custom.attr('title', 'reset on ' + Util.formatDateTime(servervolumes[curServer].CustomTime));
|
|
}
|
|
|
|
function chooseMonth()
|
|
{
|
|
setMonth($(this).attr('data-id'));
|
|
}
|
|
|
|
function setMonth(month)
|
|
{
|
|
curRange = 'MONTH';
|
|
curMonth = month;
|
|
updateRangeButtons();
|
|
updateMonthList();
|
|
redrawChart();
|
|
}
|
|
|
|
this.chooseOtherMonth = function()
|
|
{
|
|
$StatRangeDialog_PeriodInput.val('');
|
|
redrawLock++;
|
|
$StatRangeDialog.modal({backdrop: false});
|
|
}
|
|
|
|
function StatRangeDialogHidden()
|
|
{
|
|
redrawLock--;
|
|
StatDialog.redraw();
|
|
}
|
|
|
|
this.setPeriod = function()
|
|
{
|
|
var period = $StatRangeDialog_PeriodInput.val();
|
|
if (period.indexOf('-') === -1)
|
|
{
|
|
var year = parseInt(period);
|
|
if (year < 2013 || year > 2050)
|
|
{
|
|
PopupNotification.show('#Notif_StatRangeError');
|
|
return;
|
|
}
|
|
period = '' + year;
|
|
}
|
|
else
|
|
{
|
|
var month = parseInt(period.substr(5, 2));
|
|
var year = parseInt(period.substring(0, 4));
|
|
if (year < 2013 || year > 2050 || month < 1 || month > 12)
|
|
{
|
|
PopupNotification.show('#Notif_StatRangeError');
|
|
return;
|
|
}
|
|
period = year + '-' + (month-1);
|
|
}
|
|
|
|
$StatRangeDialog.modal('hide');
|
|
setMonth(period);
|
|
}
|
|
|
|
this.resetCounter = function()
|
|
{
|
|
$('#StatDialogResetConfirmDialog_Server').text(curServer === 0 ? 'all news servers' : $('#StatDialog_ServerCap').text());
|
|
$('#StatDialogResetConfirmDialog_Time').text(Util.formatDateTime(servervolumes[curServer].CustomTime));
|
|
ConfirmDialog.showModal('StatDialogResetConfirmDialog', doResetCounter);
|
|
}
|
|
|
|
function doResetCounter()
|
|
{
|
|
RPC.call('resetservervolume', [curServer === 0 ? -1 : curServer, 'CUSTOM'], function()
|
|
{
|
|
PopupNotification.show('#Notif_StatReset');
|
|
Refresher.update();
|
|
});
|
|
}
|
|
}(jQuery));
|
|
|
|
|
|
/*** LIMIT DIALOG *******************************************************/
|
|
|
|
var LimitDialog = (new function($)
|
|
{
|
|
'use strict'
|
|
|
|
// Controls
|
|
var $LimitDialog;
|
|
var $ServerTable;
|
|
var $LimitDialog_SpeedInput;
|
|
|
|
// State
|
|
var changed;
|
|
|
|
this.init = function()
|
|
{
|
|
$LimitDialog = $('#LimitDialog');
|
|
$LimitDialog_SpeedInput = $('#LimitDialog_SpeedInput');
|
|
$('#LimitDialog_Save').click(save);
|
|
$ServerTable = $('#LimitDialog_ServerTable');
|
|
|
|
$ServerTable.fasttable(
|
|
{
|
|
pagerContainer: '#LimitDialog_ServerTable_pager',
|
|
rowSelect: UISettings.rowSelect,
|
|
pageSize: 100
|
|
});
|
|
|
|
if (UISettings.setFocus)
|
|
{
|
|
$LimitDialog.on('shown', function()
|
|
{
|
|
$('#LimitDialog_SpeedInput').focus();
|
|
});
|
|
}
|
|
|
|
$LimitDialog.on('hidden', function()
|
|
{
|
|
// cleanup
|
|
$ServerTable.fasttable('update', []);
|
|
});
|
|
}
|
|
|
|
this.clicked = function(e)
|
|
{
|
|
if (e.metaKey || e.ctrlKey)
|
|
{
|
|
toggleLimit();
|
|
}
|
|
else
|
|
{
|
|
showModal();
|
|
}
|
|
}
|
|
|
|
function showModal()
|
|
{
|
|
var rate = Util.round0(Status.status.DownloadLimit / 1024);
|
|
$LimitDialog_SpeedInput.val(rate > 0 ? rate : '');
|
|
updateTable();
|
|
$LimitDialog.modal({backdrop: 'static'});
|
|
}
|
|
|
|
function updateTable()
|
|
{
|
|
var data = [];
|
|
for (var i=0; i < Status.status.NewsServers.length; i++)
|
|
{
|
|
var server = Status.status.NewsServers[i];
|
|
var name = Status.serverName(server);
|
|
var fields = ['<div class="check img-check"></div>', server.ID + '. ' + name];
|
|
var item =
|
|
{
|
|
id: server.ID,
|
|
fields: fields,
|
|
};
|
|
data.push(item);
|
|
|
|
$ServerTable.fasttable('checkRow', server.ID, server.Active);
|
|
}
|
|
$ServerTable.fasttable('update', data);
|
|
Util.show('#LimitDialog_ServerBlock', data.length > 0);
|
|
}
|
|
|
|
function save(e)
|
|
{
|
|
var val = $LimitDialog_SpeedInput.val();
|
|
var rate = 0;
|
|
if (val == '')
|
|
{
|
|
rate = 0;
|
|
}
|
|
else
|
|
{
|
|
rate = parseInt(val);
|
|
if (isNaN(rate))
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
|
|
var checkedRows = $ServerTable.fasttable('checkedRows');
|
|
var servers = [];
|
|
|
|
for (var i=0; i < Status.status.NewsServers.length; i++)
|
|
{
|
|
var server = Status.status.NewsServers[i];
|
|
var selected = checkedRows[server.ID] !== undefined;
|
|
if (server.Active != selected)
|
|
{
|
|
servers.push([server.ID, selected]);
|
|
}
|
|
}
|
|
|
|
saveLimit(rate, servers);
|
|
}
|
|
|
|
function saveLimit(rate, servers)
|
|
{
|
|
function saveServers()
|
|
{
|
|
if (servers.length > 0)
|
|
{
|
|
changed = true;
|
|
RPC.call('editserver', servers, function()
|
|
{
|
|
completed();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
completed();
|
|
}
|
|
}
|
|
|
|
changed = false;
|
|
var oldRate = Util.round0(Status.status.DownloadLimit / 1024);
|
|
|
|
if (rate != oldRate)
|
|
{
|
|
changed = true;
|
|
RPC.call('rate', [rate], function()
|
|
{
|
|
saveServers();
|
|
});
|
|
}
|
|
else
|
|
{
|
|
saveServers();
|
|
}
|
|
}
|
|
|
|
function completed()
|
|
{
|
|
$LimitDialog.modal('hide');
|
|
if (changed)
|
|
{
|
|
PopupNotification.show('#Notif_SetSpeedLimit');
|
|
}
|
|
Refresher.update();
|
|
}
|
|
|
|
function toggleLimit()
|
|
{
|
|
var limited = Status.status.DownloadLimit > 0;
|
|
for (var i=0; i < Status.status.NewsServers.length; i++)
|
|
{
|
|
var server = Status.status.NewsServers[i];
|
|
limited = limited || !server.Active;
|
|
}
|
|
|
|
var defRate = Options.option('DownloadRate');
|
|
var rate = limited ? 0 : parseInt(defRate === '' ? 0 : defRate);
|
|
var servers = [];
|
|
|
|
for (var i=0; i < Status.status.NewsServers.length; i++)
|
|
{
|
|
var server = Status.status.NewsServers[i];
|
|
var defActive = Options.option('Server' + (i + 1) + '.Active') === 'yes';
|
|
var newActive = limited ? true : defActive;
|
|
if (server.Active != newActive)
|
|
{
|
|
servers.push([server.ID, newActive]);
|
|
}
|
|
}
|
|
|
|
saveLimit(rate, servers);
|
|
}
|
|
}(jQuery));
|
|
|
|
/*** FILTER MENU *********************************************************/
|
|
|
|
var FilterMenu = (new function($)
|
|
{
|
|
'use strict';
|
|
|
|
var $SaveFilterDialog;
|
|
var $SaveFilterInput;
|
|
var $Table_filter;
|
|
var ignoreClick = false;
|
|
var $Table_filter;
|
|
var tabName;
|
|
var items;
|
|
|
|
this.init = function()
|
|
{
|
|
$SaveFilterDialog = $('#SaveFilterDialog');
|
|
$SaveFilterInput = $('#SaveFilterInput');
|
|
|
|
if (UISettings.setFocus)
|
|
{
|
|
$SaveFilterDialog.on('shown', function ()
|
|
{
|
|
$SaveFilterInput.focus();
|
|
});
|
|
}
|
|
}
|
|
|
|
this.setTab = function(tabname)
|
|
{
|
|
tabName = tabname;
|
|
$Table_filter = $('#' + tabName + 'Table_filter');
|
|
load();
|
|
}
|
|
|
|
this.redraw = function()
|
|
{
|
|
var menu = $('#FilterMenu');
|
|
var menuItemTemplate = $('.filter-menu-template', menu);
|
|
var insertPos = $('#FilterMenu_Divider', menu);
|
|
|
|
$('.filter-menu', menu).remove();
|
|
|
|
for (var i = 0; i < items.length; i++)
|
|
{
|
|
var name = items[i].name;
|
|
var item = menuItemTemplate.clone().removeClass('filter-menu-template').removeClass('hide').addClass('filter-menu');
|
|
var t = $('span', item);
|
|
t.text(name);
|
|
var a = $('a', item);
|
|
a.click(applyFilter);
|
|
a.attr('data-id', i);
|
|
var im = $('button', item);
|
|
im.click(deleteFilter);
|
|
im.attr('data-id', i);
|
|
insertPos.before(item);
|
|
}
|
|
|
|
Util.show('#FilterMenu_Empty', items.length === 0);
|
|
|
|
if (UISettings.miniTheme)
|
|
{
|
|
Frontend.alignPopupMenu('#FilterMenu');
|
|
}
|
|
}
|
|
|
|
function applyFilter()
|
|
{
|
|
if (ignoreClick)
|
|
{
|
|
ignoreClick = false;
|
|
return;
|
|
}
|
|
var id = parseInt($(this).attr('data-id'));
|
|
$Table_filter.val(items[id].filter);
|
|
$('#' + tabName +'Table').fasttable('applyFilter', $Table_filter.val());
|
|
}
|
|
|
|
function deleteFilter()
|
|
{
|
|
ignoreClick = true;
|
|
var id = parseInt($(this).attr('data-id'));
|
|
items.splice(id, 1);
|
|
save();
|
|
}
|
|
|
|
this.saveDialogClick = function()
|
|
{
|
|
if ($Table_filter.val() === '')
|
|
{
|
|
PopupNotification.show('#Notif_SaveFilterEmpty');
|
|
return;
|
|
}
|
|
|
|
var filter = $Table_filter.val();
|
|
var name = filter;
|
|
|
|
// reuse the name if the filter already exists
|
|
for (var i = 0; i < items.length; i++)
|
|
{
|
|
if (items[i].filter === filter)
|
|
{
|
|
name = items[i].name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
$SaveFilterInput.val(name);
|
|
$SaveFilterDialog.modal();
|
|
}
|
|
|
|
this.saveClick = function()
|
|
{
|
|
$SaveFilterDialog.modal('hide');
|
|
|
|
var name = $SaveFilterInput.val();
|
|
var filter = $Table_filter.val();
|
|
|
|
// rename if already exists
|
|
for (var i = 0; i < items.length; i++)
|
|
{
|
|
if (items[i].filter === filter)
|
|
{
|
|
items[i].name = name;
|
|
save();
|
|
return;
|
|
}
|
|
}
|
|
|
|
// doesn't exist - add new
|
|
items.push({name: name, filter: filter});
|
|
save();
|
|
}
|
|
|
|
function load()
|
|
{
|
|
items = JSON.parse(UISettings.read('Filter_' + tabName, '[]'));
|
|
}
|
|
|
|
function save()
|
|
{
|
|
UISettings.write('Filter_' + tabName, JSON.stringify(items));
|
|
}
|
|
}(jQuery));
|