summaryrefslogtreecommitdiffstats
path: root/deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js
diff options
context:
space:
mode:
Diffstat (limited to 'deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js')
-rw-r--r--deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js621
1 files changed, 621 insertions, 0 deletions
diff --git a/deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js b/deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js
new file mode 100644
index 0000000..f59068c
--- /dev/null
+++ b/deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js
@@ -0,0 +1,621 @@
+/**
+ * scheduler.js
+ * The client-side javascript code for the Scheduler plugin.
+ *
+ * Copyright (C) samuel337 2011
+ *
+ * This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with
+ * the additional special exception to link portions of this program with the OpenSSL library.
+ * See LICENSE for more details.
+ *
+ */
+
+Ext.ns('Deluge.ux');
+
+Deluge.ux.ScheduleSelector = Ext.extend(Ext.form.FieldSet, {
+ title: _('Schedule'),
+ autoHeight: true,
+ style: 'margin-bottom: 0px; padding-bottom: 0px;',
+ border: false,
+
+ states: [
+ {
+ name: 'Normal',
+ backgroundColor: 'LightGreen',
+ borderColor: 'DarkGreen',
+ value: 0,
+ },
+ {
+ name: 'Throttled',
+ backgroundColor: 'Yellow',
+ borderColor: 'Gold',
+ value: 1,
+ },
+ {
+ name: 'Paused',
+ backgroundColor: 'OrangeRed',
+ borderColor: 'FireBrick',
+ value: 2,
+ },
+ ],
+ daysOfWeek: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+
+ initComponent: function () {
+ Deluge.ux.ScheduleSelector.superclass.initComponent.call(this);
+
+ // ExtJS' radiogroup implementation is very broken for styling.
+ /*this.stateBrush = this.add({
+ xtype: 'radiogroup',
+ fieldLabel: _('State Brush'),
+ name: 'current_state_brush',
+ submitValue: false,
+ items: [
+ { boxLabel: 'Normal', name: 'current_state_brush', inputValue: 0 },
+ { boxLabel: 'Throttled', name: 'current_state_brush', inputValue: 1, checked: true },
+ { boxLabel: 'Paused', name: 'current_state_brush', inputValue: 2 },
+ ]
+ });*/
+ },
+
+ onRender: function (ct, position) {
+ Deluge.ux.ScheduleSelector.superclass.onRender.call(this, ct, position);
+
+ var dom = this.body.dom;
+
+ function createEl(parent, type) {
+ var el = document.createElement(type);
+ parent.appendChild(el);
+ return el;
+ }
+
+ // create state brushes
+ // tack a random number to the end to avoid clashes
+ this.stateBrushName =
+ 'schedule-state-brush-' + Math.round(Math.random() * 10000);
+
+ var el1 = createEl(dom, 'div');
+
+ var el2 = createEl(el1, 'div');
+ this.stateBrush = el2;
+ el2.id = this.stateBrushName;
+
+ // for webkit
+ var floatAttr = 'float';
+ if (el2.style.float == undefined) {
+ // for firefox
+ if (el2.style.cssFloat != undefined) floatAttr = 'cssFloat';
+ // for IE
+ if (el2.style.styleFloat != undefined) floatAttr = 'styleFloat';
+ }
+ el2.style[floatAttr] = 'right';
+
+ for (var i = 0; i < this.states.length; i++) {
+ var el3 = createEl(el2, 'input');
+ el3.type = 'radio';
+ el3.value = this.states[i].value;
+ el3.name = this.stateBrushName;
+ el3.id = this.stateBrushName + '-' + this.states[i].name;
+
+ // isn't the first one
+ if (i > 0) el3.style.marginLeft = '7px';
+
+ // assume the first is the default state, so make the 2nd one the default brush
+ if (i == 1) el3.checked = true;
+
+ var el4 = createEl(el2, 'label');
+ el4.appendChild(document.createTextNode(this.states[i].name));
+ el4.htmlFor = el3.id;
+ el4.style.backgroundColor = this.states[i].backgroundColor;
+ el4.style.borderBottom = '2px solid ' + this.states[i].borderColor;
+ el4.style.padding = '2px 3px';
+ el4.style.marginLeft = '3px';
+ }
+
+ el1.appendChild(document.createTextNode('Select a state brush:'));
+
+ el1.style.marginBottom = '10px';
+
+ // keep the radio buttons separate from the time bars
+ createEl(dom, 'div').style.clear = 'both';
+
+ var table = createEl(dom, 'table');
+ table.cellSpacing = 0;
+
+ // cache access to cells for easier access later
+ this.scheduleCells = {};
+
+ Ext.each(
+ this.daysOfWeek,
+ function (day) {
+ var cells = [];
+ var row = createEl(table, 'tr');
+ var label = createEl(row, 'th');
+ label.setAttribute(
+ 'style',
+ 'font-weight: bold; padding-right: 5px;'
+ );
+ label.appendChild(document.createTextNode(day));
+ for (var hour = 0; hour < 24; hour++) {
+ var cell = createEl(row, 'td');
+
+ // assume the first state is the default state
+ cell.currentValue = cell.oldValue = this.states[0].value;
+ cell.day = day;
+ cell.hour = hour;
+
+ cell.width = '16px';
+ cell.height = '20px';
+
+ cell.style.border = '1px solid #999999';
+ // don't repeat borders in between cells
+ if (hour != 23)
+ // not the last cell
+ cell.style.borderRight = 'none';
+
+ this.updateCell(cell);
+
+ cells.push(cell);
+
+ cell = Ext.get(cell);
+ cell.on('click', this.onCellClick, this);
+ cell.on('mouseover', this.onCellMouseOver, this);
+ cell.on('mouseout', this.onCellMouseOut, this);
+ cell.on('mousedown', this.onCellMouseDown, this);
+ cell.on('mouseup', this.onCellMouseUp, this);
+ }
+
+ // insert gap row to provide visual separation
+ row = createEl(table, 'tr');
+ // blank cell to create gap
+ createEl(row, 'td').height = '3px';
+
+ this.scheduleCells[day] = cells;
+ },
+ this
+ );
+ },
+
+ updateCell: function (cell) {
+ // sanity check
+ if (cell.currentValue == undefined) return;
+
+ for (var i in this.states) {
+ var curState = this.states[i];
+ if (curState.value == cell.currentValue) {
+ cell.style.background = curState.backgroundColor;
+ break;
+ }
+ }
+ },
+
+ getCurrentBrushValue: function () {
+ var v = null;
+ var brushes = Ext.get(this.body.dom).findParent('form').elements[
+ this.stateBrushName
+ ];
+ Ext.each(brushes, function (b) {
+ if (b.checked) v = b.value;
+ });
+
+ return v;
+ },
+
+ onCellClick: function (event, cell) {
+ cell.oldValue = cell.currentValue;
+
+ this.dragAnchor = null;
+ },
+
+ onCellMouseDown: function (event, cell) {
+ this.dragAnchor = cell;
+ },
+
+ onCellMouseUp: function (event, cell) {
+ // if we're dragging...
+ if (this.dragAnchor) {
+ // set all those between here and the anchor to the new values
+ if (cell.hour > this.dragAnchor.hour)
+ this.confirmCells(cell.day, this.dragAnchor.hour, cell.hour);
+ else if (cell.hour < this.dragAnchor.hour)
+ this.confirmCells(cell.day, cell.hour, this.dragAnchor.hour);
+ else this.confirmCells(cell.day, cell.hour, cell.hour);
+
+ this.hideCellLeftTooltip();
+ this.hideCellRightTooltip();
+ this.dragAnchor = null;
+ }
+ },
+
+ onCellMouseOver: function (event, cell) {
+ // LEFT TOOL TIP
+ // if it isn't showing and we're dragging, show it.
+ // otherwise if dragging, leave it alone unless we're dragging to the left.
+ // if we're not dragging, show it.
+ var leftTooltipCell = null;
+ if (!this.dragAnchor) leftTooltipCell = cell;
+ else if (
+ (this.dragAnchor && this.isCellLeftTooltipHidden()) ||
+ (this.dragAnchor && this.dragAnchor.hour > cell.hour)
+ )
+ leftTooltipCell = this.dragAnchor;
+
+ if (leftTooltipCell) {
+ var hour = leftTooltipCell.hour;
+ var pm = false;
+
+ // convert to 12-hour time
+ if (hour >= 12) {
+ pm = true;
+ if (hour > 12) hour -= 12;
+ } else if (hour == 0) {
+ // change 0 hour to 12am
+ hour = 12;
+ }
+ this.showCellLeftTooltip(
+ hour + ' ' + (pm ? 'pm' : 'am'),
+ leftTooltipCell
+ );
+ }
+
+ // RIGHT TOOL TIP
+ var rightTooltipCell = null;
+ if (this.dragAnchor) {
+ if (this.dragAnchor.hour == cell.hour) this.hideCellRightTooltip();
+ else if (
+ this.dragAnchor.hour > cell.hour &&
+ this.isCellRightTooltipHidden()
+ )
+ rightTooltipCell = this.dragAnchor;
+ // cell.hour > this.dragAnchor.hour
+ else rightTooltipCell = cell;
+ }
+
+ if (rightTooltipCell) {
+ var hour = rightTooltipCell.hour;
+ var pm = false;
+
+ // convert to 12-hour time
+ if (hour >= 12) {
+ pm = true;
+ if (hour > 12) hour -= 12;
+ } else if (hour == 0) {
+ // change 0 hour to 12am
+ hour = 12;
+ }
+ this.showCellRightTooltip(
+ hour + ' ' + (pm ? 'pm' : 'am'),
+ rightTooltipCell
+ );
+ }
+
+ // preview colour change and
+ // revert state for all those on the outer side of the drag if dragging
+ if (this.dragAnchor) {
+ if (cell.day != this.dragAnchor.day) {
+ // dragged into another day. Abort! Abort!
+ Ext.each(
+ this.daysOfWeek,
+ function (day) {
+ this.revertCells(day, 0, 23);
+ },
+ this
+ );
+ this.dragAnchor = null;
+ this.hideCellLeftTooltip();
+ this.hideCellRightTooltip();
+ } else if (cell.hour > this.dragAnchor.hour) {
+ // dragging right
+ this.revertCells(cell.day, cell.hour + 1, 23);
+ this.previewCells(cell.day, this.dragAnchor.hour, cell.hour);
+ } else if (cell.hour < this.dragAnchor.hour) {
+ // dragging left
+ this.revertCells(cell.day, 0, cell.hour - 1);
+ this.previewCells(cell.day, cell.hour, this.dragAnchor.hour);
+ } else {
+ // back to anchor cell
+ // don't know if it is from right or left, so revert all except this
+ this.revertCells(cell.day, cell.hour + 1, 23);
+ this.revertCells(cell.day, 0, cell.hour - 1);
+ }
+ } else {
+ // not dragging, just preview this cell
+ this.previewCells(cell.day, cell.hour, cell.hour);
+ }
+ },
+
+ onCellMouseOut: function (event, cell) {
+ if (!this.dragAnchor) this.hideCellLeftTooltip();
+
+ // revert state. If new state has been set, old and new will be equal.
+ // if dragging, this will be handled by the next mouse over
+ if (this.dragAnchor == null && cell.oldValue != cell.currentValue) {
+ this.revertCells(cell.day, cell.hour, cell.hour);
+ }
+ },
+
+ previewCells: function (day, fromHour, toHour) {
+ var cells = this.scheduleCells[day];
+ var curBrushValue = this.getCurrentBrushValue();
+
+ if (toHour > cells.length) toHour = cells.length;
+
+ for (var i = fromHour; i <= toHour; i++) {
+ if (cells[i].currentValue != curBrushValue) {
+ cells[i].oldValue = cells[i].currentValue;
+ cells[i].currentValue = curBrushValue;
+ this.updateCell(cells[i]);
+ }
+ }
+ },
+
+ revertCells: function (day, fromHour, toHour) {
+ var cells = this.scheduleCells[day];
+
+ if (toHour > cells.length) toHour = cells.length;
+
+ for (var i = fromHour; i <= toHour; i++) {
+ cells[i].currentValue = cells[i].oldValue;
+ this.updateCell(cells[i]);
+ }
+ },
+
+ confirmCells: function (day, fromHour, toHour) {
+ var cells = this.scheduleCells[day];
+
+ if (toHour > cells.length) toHour = cells.length;
+
+ for (var i = fromHour; i <= toHour; i++) {
+ if (cells[i].currentValue != cells[i].oldValue) {
+ cells[i].oldValue = cells[i].currentValue;
+ }
+ }
+ },
+
+ showCellLeftTooltip: function (text, cell) {
+ var tooltip = this.cellLeftTooltip;
+
+ if (!tooltip) {
+ // no cached left tooltip exists, create one
+ tooltip = document.createElement('div');
+ this.cellLeftTooltip = tooltip;
+ this.body.dom.appendChild(tooltip);
+ tooltip.style.position = 'absolute';
+ tooltip.style.backgroundColor = '#F2F2F2';
+ tooltip.style.border = '1px solid #333333';
+ tooltip.style.padding = '1px 3px';
+ tooltip.style.opacity = 0.8;
+ }
+
+ // remove all existing children
+ while (tooltip.childNodes.length > 0) {
+ tooltip.removeChild(tooltip.firstChild);
+ }
+ // add the requested text
+ tooltip.appendChild(document.createTextNode(text));
+
+ // place the tooltip
+ Ext.get(tooltip).alignTo(cell, 'br-tr');
+
+ // make it visible
+ tooltip.style.visibility = 'visible';
+ },
+
+ hideCellLeftTooltip: function () {
+ if (this.cellLeftTooltip) {
+ this.cellLeftTooltip.style.visibility = 'hidden';
+ }
+ },
+
+ isCellLeftTooltipHidden: function () {
+ if (this.cellLeftTooltip)
+ return this.cellLeftTooltip.style.visibility == 'hidden';
+ else return true;
+ },
+
+ showCellRightTooltip: function (text, cell) {
+ var tooltip = this.cellRightTooltip;
+
+ if (!tooltip) {
+ // no cached left tooltip exists, create one
+ tooltip = document.createElement('div');
+ this.cellRightTooltip = tooltip;
+ this.body.dom.appendChild(tooltip);
+ tooltip.style.position = 'absolute';
+ tooltip.style.backgroundColor = '#F2F2F2';
+ tooltip.style.border = '1px solid #333333';
+ tooltip.style.padding = '1px 3px';
+ tooltip.style.opacity = 0.8;
+ }
+
+ // remove all existing children
+ while (tooltip.childNodes.length > 0) {
+ tooltip.removeChild(tooltip.firstChild);
+ }
+ // add the requested text
+ tooltip.appendChild(document.createTextNode(text));
+
+ // place the tooltip
+ Ext.get(tooltip).alignTo(cell, 'bl-tl');
+
+ // make it visible
+ tooltip.style.visibility = 'visible';
+ },
+
+ hideCellRightTooltip: function () {
+ if (this.cellRightTooltip) {
+ this.cellRightTooltip.style.visibility = 'hidden';
+ }
+ },
+
+ isCellRightTooltipHidden: function () {
+ if (this.cellRightTooltip)
+ return this.cellRightTooltip.style.visibility == 'hidden';
+ else return true;
+ },
+
+ getConfig: function () {
+ var config = [];
+
+ for (var i = 0; i < 24; i++) {
+ var hourConfig = [0, 0, 0, 0, 0, 0, 0];
+
+ for (var j = 0; j < this.daysOfWeek.length; j++) {
+ hourConfig[j] = parseInt(
+ this.scheduleCells[this.daysOfWeek[j]][i].currentValue
+ );
+ }
+
+ config.push(hourConfig);
+ }
+
+ return config;
+ },
+
+ setConfig: function (config) {
+ for (var i = 0; i < 24; i++) {
+ var hourConfig = config[i];
+
+ for (var j = 0; j < this.daysOfWeek.length; j++) {
+ if (this.scheduleCells == undefined) {
+ var cell = hourConfig[j];
+ } else {
+ var cell = this.scheduleCells[this.daysOfWeek[j]][i];
+ }
+ cell.currentValue = cell.oldValue = hourConfig[j];
+ this.updateCell(cell);
+ }
+ }
+ },
+});
+
+Ext.ns('Deluge.ux.preferences');
+
+Deluge.ux.preferences.SchedulerPage = Ext.extend(Ext.Panel, {
+ border: false,
+ title: _('Scheduler'),
+ header: false,
+ layout: 'fit',
+
+ initComponent: function () {
+ Deluge.ux.preferences.SchedulerPage.superclass.initComponent.call(this);
+
+ this.form = this.add({
+ xtype: 'form',
+ layout: 'form',
+ border: false,
+ autoHeight: true,
+ });
+
+ this.schedule = this.form.add(new Deluge.ux.ScheduleSelector());
+
+ this.slowSettings = this.form.add({
+ xtype: 'fieldset',
+ border: false,
+ title: _('Throttled Settings'),
+ autoHeight: true,
+ defaultType: 'spinnerfield',
+ defaults: {
+ minValue: -1,
+ maxValue: 99999,
+ },
+ style: 'margin-top: 5px; margin-bottom: 0px; padding-bottom: 0px;',
+ labelWidth: 200,
+ });
+
+ this.downloadLimit = this.slowSettings.add({
+ fieldLabel: _('Maximum Download Speed (KiB/s)'),
+ name: 'download_limit',
+ width: 80,
+ value: -1,
+ decimalPrecision: 0,
+ });
+ this.uploadLimit = this.slowSettings.add({
+ fieldLabel: _('Maximum Upload Speed (KiB/s)'),
+ name: 'upload_limit',
+ width: 80,
+ value: -1,
+ decimalPrecision: 0,
+ });
+ this.activeTorrents = this.slowSettings.add({
+ fieldLabel: _('Active Torrents'),
+ name: 'active_torrents',
+ width: 80,
+ value: -1,
+ decimalPrecision: 0,
+ });
+ this.activeDownloading = this.slowSettings.add({
+ fieldLabel: _('Active Downloading'),
+ name: 'active_downloading',
+ width: 80,
+ value: -1,
+ decimalPrecision: 0,
+ });
+ this.activeSeeding = this.slowSettings.add({
+ fieldLabel: _('Active Seeding'),
+ name: 'active_seeding',
+ width: 80,
+ value: -1,
+ decimalPrecision: 0,
+ });
+
+ this.on('show', this.updateConfig, this);
+ },
+
+ onRender: function (ct, position) {
+ Deluge.ux.preferences.SchedulerPage.superclass.onRender.call(
+ this,
+ ct,
+ position
+ );
+ this.form.layout = new Ext.layout.FormLayout();
+ this.form.layout.setContainer(this);
+ this.form.doLayout();
+ },
+
+ onApply: function () {
+ // build settings object
+ var config = {};
+
+ config['button_state'] = this.schedule.getConfig();
+ config['low_down'] = this.downloadLimit.getValue();
+ config['low_up'] = this.uploadLimit.getValue();
+ config['low_active'] = this.activeTorrents.getValue();
+ config['low_active_down'] = this.activeDownloading.getValue();
+ config['low_active_up'] = this.activeSeeding.getValue();
+
+ deluge.client.scheduler.set_config(config);
+ },
+
+ onOk: function () {
+ this.onApply();
+ },
+
+ updateConfig: function () {
+ deluge.client.scheduler.get_config({
+ success: function (config) {
+ this.schedule.setConfig(config['button_state']);
+ this.downloadLimit.setValue(config['low_down']);
+ this.uploadLimit.setValue(config['low_up']);
+ this.activeTorrents.setValue(config['low_active']);
+ this.activeDownloading.setValue(config['low_active_down']);
+ this.activeSeeding.setValue(config['low_active_up']);
+ },
+ scope: this,
+ });
+ },
+});
+
+Deluge.plugins.SchedulerPlugin = Ext.extend(Deluge.Plugin, {
+ name: 'Scheduler',
+
+ onDisable: function () {
+ deluge.preferences.removePage(this.prefsPage);
+ },
+
+ onEnable: function () {
+ this.prefsPage = deluge.preferences.addPage(
+ new Deluge.ux.preferences.SchedulerPage()
+ );
+ },
+});
+Deluge.registerPlugin('Scheduler', Deluge.plugins.SchedulerPlugin);