From d1772d410235592b482e3b08b1863f6624d9fe6b Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 19 Feb 2023 15:52:21 +0100 Subject: Adding upstream version 2.0.3. Signed-off-by: Daniel Baumann --- .../Scheduler/deluge_scheduler/data/scheduler.js | 621 +++++++++++++++++++++ 1 file changed, 621 insertions(+) create mode 100644 deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js (limited to 'deluge/plugins/Scheduler/deluge_scheduler/data/scheduler.js') 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..13bec46 --- /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); -- cgit v1.2.3