diff --git a/.gitattributes b/.gitattributes index 9c21c1616..656fcff1f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,7 +10,7 @@ generate_pot.py export-ignore deluge/ui/web/css/*-debug.css export-ignore deluge/ui/web/js/*-debug.js export-ignore deluge/ui/web/js/deluge-all/ export-ignore -deluge/ui/web/js/ext-extensions/ export-ignore +deluge/ui/web/js/extjs/ext-extensions/ export-ignore deluge/ui/web/gen_gettext.py export-ignore deluge/ui/web/build export-ignore deluge/ui/web/docs/ export-ignore diff --git a/deluge/ui/web/docs/deluge-docs.xml b/deluge/ui/web/docs/deluge-docs.xml index 561764770..f3ce1d4a2 100644 --- a/deluge/ui/web/docs/deluge-docs.xml +++ b/deluge/ui/web/docs/deluge-docs.xml @@ -1,9 +1,9 @@ - - - + + + diff --git a/deluge/ui/web/js/ext-all-debug.js b/deluge/ui/web/js/extjs/ext-all-debug.js similarity index 100% rename from deluge/ui/web/js/ext-all-debug.js rename to deluge/ui/web/js/extjs/ext-all-debug.js diff --git a/deluge/ui/web/js/ext-all.js b/deluge/ui/web/js/extjs/ext-all.js similarity index 100% rename from deluge/ui/web/js/ext-all.js rename to deluge/ui/web/js/extjs/ext-all.js diff --git a/deluge/ui/web/js/ext-base-debug.js b/deluge/ui/web/js/extjs/ext-base-debug.js similarity index 100% rename from deluge/ui/web/js/ext-base-debug.js rename to deluge/ui/web/js/extjs/ext-base-debug.js diff --git a/deluge/ui/web/js/ext-base.js b/deluge/ui/web/js/extjs/ext-base.js similarity index 100% rename from deluge/ui/web/js/ext-base.js rename to deluge/ui/web/js/extjs/ext-base.js diff --git a/deluge/ui/web/js/extjs/ext-extensions-debug.js b/deluge/ui/web/js/extjs/ext-extensions-debug.js new file mode 100644 index 000000000..adb080fd6 --- /dev/null +++ b/deluge/ui/web/js/extjs/ext-extensions-debug.js @@ -0,0 +1,2758 @@ +/*! + * Ext.ux.layout.FormLayoutFix.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ + +// Taken from http://extjs.com/forum/showthread.php?t=75273 +// remove spaces for hidden elements and make show(), hide(), enable() and disable() act on +// the label. don't use hideLabel with this. +Ext.override(Ext.layout.FormLayout, { + renderItem : function(c, position, target){ + if(c && !c.rendered && (c.isFormField || c.fieldLabel) && c.inputType != 'hidden'){ + var args = this.getTemplateArgs(c); + if(typeof position == 'number'){ + position = target.dom.childNodes[position] || null; + } + if(position){ + c.formItem = this.fieldTpl.insertBefore(position, args, true); + }else{ + c.formItem = this.fieldTpl.append(target, args, true); + } + c.actionMode = 'formItem'; + c.render('x-form-el-'+c.id); + c.container = c.formItem; + c.actionMode = 'container'; + }else { + Ext.layout.FormLayout.superclass.renderItem.apply(this, arguments); + } + } +}); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.tree'); + +/** + * @class Ext.ux.tree.TreeGrid + * @extends Ext.tree.TreePanel + * + * @xtype treegrid + */ +Ext.ux.tree.TreeGrid = Ext.extend(Ext.tree.TreePanel, { + rootVisible : false, + useArrows : true, + lines : false, + borderWidth : Ext.isBorderBox ? 0 : 2, // the combined left/right border for each cell + cls : 'x-treegrid', + + columnResize : true, + enableSort : true, + reserveScrollOffset : true, + enableHdMenu : true, + + columnsText : 'Columns', + + initComponent : function() { + if(!this.root) { + this.root = new Ext.tree.AsyncTreeNode({text: 'Root'}); + } + + // initialize the loader + var l = this.loader; + if(!l){ + l = new Ext.ux.tree.TreeGridLoader({ + dataUrl: this.dataUrl, + requestMethod: this.requestMethod, + store: this.store + }); + }else if(Ext.isObject(l) && !l.load){ + l = new Ext.ux.tree.TreeGridLoader(l); + } + this.loader = l; + + Ext.ux.tree.TreeGrid.superclass.initComponent.call(this); + + this.initColumns(); + + if(this.enableSort) { + this.treeGridSorter = new Ext.ux.tree.TreeGridSorter(this, this.enableSort); + } + + if(this.columnResize){ + this.colResizer = new Ext.tree.ColumnResizer(this.columnResize); + this.colResizer.init(this); + } + + var c = this.columns; + if(!this.internalTpl){ + this.internalTpl = new Ext.XTemplate( + '
', + '
', + '
', + '', + '', + '', + '', + '', + '
', + '
', + this.enableHdMenu ? '' : '', + '{header}', + '
', + '
', + '
', + '
', + '
', + '
', + '
' + ); + } + + if(!this.colgroupTpl) { + this.colgroupTpl = new Ext.XTemplate( + '' + ); + } + }, + + initColumns : function() { + var cs = this.columns, + len = cs.length, + columns = [], + i, c; + + for(i = 0; i < len; i++){ + c = cs[i]; + if(!c.isColumn) { + c.xtype = c.xtype ? (/^tg/.test(c.xtype) ? c.xtype : 'tg' + c.xtype) : 'tgcolumn'; + c = Ext.create(c); + } + c.init(this); + columns.push(c); + + if(this.enableSort !== false && c.sortable !== false) { + c.sortable = true; + this.enableSort = true; + } + } + + this.columns = columns; + }, + + onRender : function(){ + Ext.tree.TreePanel.superclass.onRender.apply(this, arguments); + + this.el.addClass('x-treegrid'); + + this.outerCt = this.body.createChild({ + cls:'x-tree-root-ct x-treegrid-ct ' + (this.useArrows ? 'x-tree-arrows' : this.lines ? 'x-tree-lines' : 'x-tree-no-lines') + }); + + this.internalTpl.overwrite(this.outerCt, {columns: this.columns}); + + this.mainHd = Ext.get(this.outerCt.dom.firstChild); + this.innerHd = Ext.get(this.mainHd.dom.firstChild); + this.innerBody = Ext.get(this.outerCt.dom.lastChild); + this.innerCt = Ext.get(this.innerBody.dom.firstChild); + + this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns}); + + if(this.hideHeaders){ + this.el.child('.x-grid3-header').setDisplayed('none'); + } + else if(this.enableHdMenu !== false){ + this.hmenu = new Ext.menu.Menu({id: this.id + '-hctx'}); + if(this.enableColumnHide !== false){ + this.colMenu = new Ext.menu.Menu({id: this.id + '-hcols-menu'}); + this.colMenu.on({ + scope: this, + beforeshow: this.beforeColMenuShow, + itemclick: this.handleHdMenuClick + }); + this.hmenu.add({ + itemId:'columns', + hideOnClick: false, + text: this.columnsText, + menu: this.colMenu, + iconCls: 'x-cols-icon' + }); + } + this.hmenu.on('itemclick', this.handleHdMenuClick, this); + } + }, + + setRootNode : function(node){ + node.attributes.uiProvider = Ext.ux.tree.TreeGridRootNodeUI; + node = Ext.ux.tree.TreeGrid.superclass.setRootNode.call(this, node); + if(this.innerCt) { + this.colgroupTpl.insertFirst(this.innerCt, {columns: this.columns}); + } + return node; + }, + + clearInnerCt : function(){ + if(Ext.isIE){ + var dom = this.innerCt.dom; + while(dom.firstChild){ + dom.removeChild(dom.firstChild); + } + }else{ + Ext.ux.tree.TreeGrid.superclass.clearInnerCt.call(this); + } + }, + + initEvents : function() { + Ext.ux.tree.TreeGrid.superclass.initEvents.apply(this, arguments); + + this.mon(this.innerBody, 'scroll', this.syncScroll, this); + this.mon(this.innerHd, 'click', this.handleHdDown, this); + this.mon(this.mainHd, { + scope: this, + mouseover: this.handleHdOver, + mouseout: this.handleHdOut + }); + }, + + onResize : function(w, h) { + Ext.ux.tree.TreeGrid.superclass.onResize.apply(this, arguments); + + var bd = this.innerBody.dom; + var hd = this.innerHd.dom; + + if(!bd){ + return; + } + + if(Ext.isNumber(h)){ + bd.style.height = this.body.getHeight(true) - hd.offsetHeight + 'px'; + } + + if(Ext.isNumber(w)){ + var sw = Ext.num(this.scrollOffset, Ext.getScrollBarWidth()); + if(this.reserveScrollOffset || ((bd.offsetWidth - bd.clientWidth) > 10)){ + this.setScrollOffset(sw); + }else{ + var me = this; + setTimeout(function(){ + me.setScrollOffset(bd.offsetWidth - bd.clientWidth > 10 ? sw : 0); + }, 10); + } + } + }, + + updateColumnWidths : function() { + var cols = this.columns, + colCount = cols.length, + groups = this.outerCt.query('colgroup'), + groupCount = groups.length, + c, g, i, j; + + for(i = 0; i 0 && this.columns[index]) { + this.setColumnVisible(index, !item.checked); + } + } + + return true; + }, + + setColumnVisible : function(index, visible) { + this.columns[index].hidden = !visible; + this.updateColumnWidths(); + }, + + /** + * Scrolls the grid to the top + */ + scrollToTop : function(){ + this.innerBody.dom.scrollTop = 0; + this.innerBody.dom.scrollLeft = 0; + }, + + // private + syncScroll : function(){ + this.syncHeaderScroll(); + var mb = this.innerBody.dom; + this.fireEvent('bodyscroll', mb.scrollLeft, mb.scrollTop); + }, + + // private + syncHeaderScroll : function(){ + var mb = this.innerBody.dom; + this.innerHd.dom.scrollLeft = mb.scrollLeft; + this.innerHd.dom.scrollLeft = mb.scrollLeft; // second time for IE (1/2 time first fails, other browsers ignore) + }, + + registerNode : function(n) { + Ext.ux.tree.TreeGrid.superclass.registerNode.call(this, n); + if(!n.uiProvider && !n.isRoot && !n.ui.isTreeGridNodeUI) { + n.ui = new Ext.ux.tree.TreeGridNodeUI(n); + } + } +}); + +Ext.reg('treegrid', Ext.ux.tree.TreeGrid); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +/** + * @class Ext.tree.ColumnResizer + * @extends Ext.util.Observable + */ +Ext.tree.ColumnResizer = Ext.extend(Ext.util.Observable, { + /** + * @cfg {Number} minWidth The minimum width the column can be dragged to. + * Defaults to 14. + */ + minWidth: 14, + + constructor: function(config){ + Ext.apply(this, config); + Ext.tree.ColumnResizer.superclass.constructor.call(this); + }, + + init : function(tree){ + this.tree = tree; + tree.on('render', this.initEvents, this); + }, + + initEvents : function(tree){ + tree.mon(tree.innerHd, 'mousemove', this.handleHdMove, this); + this.tracker = new Ext.dd.DragTracker({ + onBeforeStart: this.onBeforeStart.createDelegate(this), + onStart: this.onStart.createDelegate(this), + onDrag: this.onDrag.createDelegate(this), + onEnd: this.onEnd.createDelegate(this), + tolerance: 3, + autoStart: 300 + }); + this.tracker.initEl(tree.innerHd); + tree.on('beforedestroy', this.tracker.destroy, this.tracker); + }, + + handleHdMove : function(e, t){ + var hw = 5, + x = e.getPageX(), + hd = e.getTarget('.x-treegrid-hd', 3, true); + + if(hd){ + var r = hd.getRegion(), + ss = hd.dom.style, + pn = hd.dom.parentNode; + + if(x - r.left <= hw && hd.dom !== pn.firstChild) { + var ps = hd.dom.previousSibling; + while(ps && Ext.fly(ps).hasClass('x-treegrid-hd-hidden')) { + ps = ps.previousSibling; + } + if(ps) { + this.activeHd = Ext.get(ps); + ss.cursor = Ext.isWebKit ? 'e-resize' : 'col-resize'; + } + } else if(r.right - x <= hw) { + var ns = hd.dom; + while(ns && Ext.fly(ns).hasClass('x-treegrid-hd-hidden')) { + ns = ns.previousSibling; + } + if(ns) { + this.activeHd = Ext.get(ns); + ss.cursor = Ext.isWebKit ? 'w-resize' : 'col-resize'; + } + } else{ + delete this.activeHd; + ss.cursor = ''; + } + } + }, + + onBeforeStart : function(e){ + this.dragHd = this.activeHd; + return !!this.dragHd; + }, + + onStart : function(e){ + this.dragHeadersDisabled = this.tree.headersDisabled; + this.tree.headersDisabled = true; + this.proxy = this.tree.body.createChild({cls:'x-treegrid-resizer'}); + this.proxy.setHeight(this.tree.body.getHeight()); + + var x = this.tracker.getXY()[0]; + + this.hdX = this.dragHd.getX(); + this.hdIndex = this.tree.findHeaderIndex(this.dragHd); + + this.proxy.setX(this.hdX); + this.proxy.setWidth(x-this.hdX); + + this.maxWidth = this.tree.outerCt.getWidth() - this.tree.innerBody.translatePoints(this.hdX).left; + }, + + onDrag : function(e){ + var cursorX = this.tracker.getXY()[0]; + this.proxy.setWidth((cursorX-this.hdX).constrain(this.minWidth, this.maxWidth)); + }, + + onEnd : function(e){ + var nw = this.proxy.getWidth(), + tree = this.tree, + disabled = this.dragHeadersDisabled; + + this.proxy.remove(); + delete this.dragHd; + + tree.columns[this.hdIndex].width = nw; + tree.updateColumnWidths(); + + setTimeout(function(){ + tree.headersDisabled = disabled; + }, 100); + } +});/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +(function() { + Ext.override(Ext.list.Column, { + init : function() { + var types = Ext.data.Types, + st = this.sortType; + + if(this.type){ + if(Ext.isString(this.type)){ + this.type = Ext.data.Types[this.type.toUpperCase()] || types.AUTO; + } + }else{ + this.type = types.AUTO; + } + + // named sortTypes are supported, here we look them up + if(Ext.isString(st)){ + this.sortType = Ext.data.SortTypes[st]; + }else if(Ext.isEmpty(st)){ + this.sortType = this.type.sortType; + } + } + }); + + Ext.tree.Column = Ext.extend(Ext.list.Column, {}); + Ext.tree.NumberColumn = Ext.extend(Ext.list.NumberColumn, {}); + Ext.tree.DateColumn = Ext.extend(Ext.list.DateColumn, {}); + Ext.tree.BooleanColumn = Ext.extend(Ext.list.BooleanColumn, {}); + + Ext.reg('tgcolumn', Ext.tree.Column); + Ext.reg('tgnumbercolumn', Ext.tree.NumberColumn); + Ext.reg('tgdatecolumn', Ext.tree.DateColumn); + Ext.reg('tgbooleancolumn', Ext.tree.BooleanColumn); +})(); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +/** + * @class Ext.ux.tree.TreeGridLoader + * @extends Ext.tree.TreeLoader + */ +Ext.ux.tree.TreeGridLoader = Ext.extend(Ext.tree.TreeLoader, { + createNode : function(attr) { + if (!attr.uiProvider) { + attr.uiProvider = Ext.ux.tree.TreeGridNodeUI; + } + return Ext.tree.TreeLoader.prototype.createNode.call(this, attr); + } +});/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +/** + * @class Ext.ux.tree.TreeGridNodeUI + * @extends Ext.tree.TreeNodeUI + */ +Ext.ux.tree.TreeGridNodeUI = Ext.extend(Ext.tree.TreeNodeUI, { + isTreeGridNodeUI: true, + + renderElements : function(n, a, targetNode, bulkRender){ + var t = n.getOwnerTree(), + cols = t.columns, + c = cols[0], + i, buf, len; + + this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : ''; + + buf = [ + '', + '', + '', + '', this.indentMarkup, "", + '', + '', + '', + '', (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text), '', + '' + ]; + + for(i = 1, len = cols.length; i < len; i++){ + c = cols[i]; + buf.push( + '', + '
', + (c.tpl ? c.tpl.apply(a) : a[c.dataIndex]), + '
', + '' + ); + } + + buf.push( + '', + '' + ); + for(i = 0, len = cols.length; i'); + } + buf.push(''); + + if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){ + this.wrap = Ext.DomHelper.insertHtml("beforeBegin", n.nextSibling.ui.getEl(), buf.join('')); + }else{ + this.wrap = Ext.DomHelper.insertHtml("beforeEnd", targetNode, buf.join('')); + } + + this.elNode = this.wrap.childNodes[0]; + this.ctNode = this.wrap.childNodes[1].firstChild.firstChild; + var cs = this.elNode.firstChild.childNodes; + this.indentNode = cs[0]; + this.ecNode = cs[1]; + this.iconNode = cs[2]; + this.anchor = cs[3]; + this.textNode = cs[3].firstChild; + }, + + // private + animExpand : function(cb){ + this.ctNode.style.display = ""; + Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this, cb); + } +}); + +Ext.ux.tree.TreeGridRootNodeUI = Ext.extend(Ext.tree.TreeNodeUI, { + isTreeGridNodeUI: true, + + // private + render : function(){ + if(!this.rendered){ + this.wrap = this.ctNode = this.node.ownerTree.innerCt.dom; + this.node.expanded = true; + } + + if(Ext.isWebKit) { + // weird table-layout: fixed issue in webkit + var ct = this.ctNode; + ct.style.tableLayout = null; + (function() { + ct.style.tableLayout = 'fixed'; + }).defer(1); + } + }, + + destroy : function(){ + if(this.elNode){ + Ext.dd.Registry.unregister(this.elNode.id); + } + delete this.node; + }, + + collapse : Ext.emptyFn, + expand : Ext.emptyFn +});/*! + * Ext.ux.tree.TreeGridNodeUIFix.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ + +Ext.override(Ext.ux.tree.TreeGridNodeUI, { + + updateColumns: function() { + if (!this.rendered) return; + + var a = this.node.attributes, + t = this.node.getOwnerTree(), + cols = t.columns, + c = cols[0]; + + // Update the first column + this.anchor.firstChild.innerHTML = (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text); + + // Update the remaining columns + for(i = 1, len = cols.length; i < len; i++) { + c = cols[i]; + this.elNode.childNodes[i].firstChild.innerHTML = (c.tpl ? c.tpl.apply(a) : a[c.dataIndex] || c.text); + } + } + +}); +Ext.tree.RenderColumn = Ext.extend(Ext.tree.Column, { + + constructor: function(c) { + c.tpl = c.tpl || new Ext.XTemplate('{' + c.dataIndex + ':this.format}'); + c.tpl.format = c.renderer; + c.tpl.col = this; + Ext.tree.RenderColumn.superclass.constructor.call(this, c); + } +}); +Ext.reg('tgrendercolumn', Ext.tree.RenderColumn); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.tree'); + +/** + * @class Ext.ux.tree.TreeGridSorter + * @extends Ext.tree.TreeSorter + * Provides sorting of nodes in a {@link Ext.ux.tree.TreeGrid}. The TreeGridSorter automatically monitors events on the + * associated TreeGrid that might affect the tree's sort order (beforechildrenrendered, append, insert and textchange). + * Example usage:
+ *

+ new Ext.ux.tree.TreeGridSorter(myTreeGrid, {
+     folderSort: true,
+     dir: "desc",
+     sortType: function(node) {
+         // sort by a custom, typed attribute:
+         return parseInt(node.id, 10);
+     }
+ });
+ 
+ * @constructor + * @param {TreeGrid} tree + * @param {Object} config + */ +Ext.ux.tree.TreeGridSorter = Ext.extend(Ext.tree.TreeSorter, { + /** + * @cfg {Array} sortClasses The CSS classes applied to a header when it is sorted. (defaults to ['sort-asc', 'sort-desc']) + */ + sortClasses : ['sort-asc', 'sort-desc'], + /** + * @cfg {String} sortAscText The text displayed in the 'Sort Ascending' menu item (defaults to 'Sort Ascending') + */ + sortAscText : 'Sort Ascending', + /** + * @cfg {String} sortDescText The text displayed in the 'Sort Descending' menu item (defaults to 'Sort Descending') + */ + sortDescText : 'Sort Descending', + + constructor : function(tree, config) { + if(!Ext.isObject(config)) { + config = { + property: tree.columns[0].dataIndex || 'text', + folderSort: true + } + } + + Ext.ux.tree.TreeGridSorter.superclass.constructor.apply(this, arguments); + + this.tree = tree; + tree.on('headerclick', this.onHeaderClick, this); + tree.ddAppendOnly = true; + + var me = this; + this.defaultSortFn = function(n1, n2){ + + var desc = me.dir && me.dir.toLowerCase() == 'desc', + prop = me.property || 'text', + sortType = me.sortType, + caseSensitive = me.caseSensitive === true, + leafAttr = me.leafAttr || 'leaf', + attr1 = n1.attributes, + attr2 = n2.attributes; + + if(me.folderSort){ + if(attr1[leafAttr] && !attr2[leafAttr]){ + return 1; + } + if(!attr1[leafAttr] && attr2[leafAttr]){ + return -1; + } + } + var prop1 = attr1[prop], + prop2 = attr2[prop], + v1 = sortType ? sortType(prop1) : (caseSensitive ? prop1 : prop1.toUpperCase()); + v2 = sortType ? sortType(prop2) : (caseSensitive ? prop2 : prop2.toUpperCase()); + + if(v1 < v2){ + return desc ? +1 : -1; + }else if(v1 > v2){ + return desc ? -1 : +1; + }else{ + return 0; + } + }; + + tree.on('afterrender', this.onAfterTreeRender, this, {single: true}); + tree.on('headermenuclick', this.onHeaderMenuClick, this); + }, + + onAfterTreeRender : function() { + if(this.tree.hmenu){ + this.tree.hmenu.insert(0, + {itemId:'asc', text: this.sortAscText, cls: 'xg-hmenu-sort-asc'}, + {itemId:'desc', text: this.sortDescText, cls: 'xg-hmenu-sort-desc'} + ); + } + this.updateSortIcon(0, 'asc'); + }, + + onHeaderMenuClick : function(c, id, index) { + if(id === 'asc' || id === 'desc') { + this.onHeaderClick(c, null, index); + return false; + } + }, + + onHeaderClick : function(c, el, i) { + if(c && !this.tree.headersDisabled){ + var me = this; + + me.property = c.dataIndex; + me.dir = c.dir = (c.dir === 'desc' ? 'asc' : 'desc'); + me.sortType = c.sortType; + me.caseSensitive === Ext.isBoolean(c.caseSensitive) ? c.caseSensitive : this.caseSensitive; + me.sortFn = c.sortFn || this.defaultSortFn; + + this.tree.root.cascade(function(n) { + if(!n.isLeaf()) { + me.updateSort(me.tree, n); + } + }); + + this.updateSortIcon(i, c.dir); + } + }, + + // private + updateSortIcon : function(col, dir){ + var sc = this.sortClasses, + hds = this.tree.innerHd.select('td').removeClass(sc); + hds.item(col).addClass(sc[dir == 'desc' ? 1 : 0]); + } +}); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.grid'); + +/** + * @class Ext.ux.grid.BufferView + * @extends Ext.grid.GridView + * A custom GridView which renders rows on an as-needed basis. + */ +Ext.ux.grid.BufferView = Ext.extend(Ext.grid.GridView, { + /** + * @cfg {Number} rowHeight + * The height of a row in the grid. + */ + rowHeight: 19, + + /** + * @cfg {Number} borderHeight + * The combined height of border-top and border-bottom of a row. + */ + borderHeight: 2, + + /** + * @cfg {Boolean/Number} scrollDelay + * The number of milliseconds before rendering rows out of the visible + * viewing area. Defaults to 100. Rows will render immediately with a config + * of false. + */ + scrollDelay: 100, + + /** + * @cfg {Number} cacheSize + * The number of rows to look forward and backwards from the currently viewable + * area. The cache applies only to rows that have been rendered already. + */ + cacheSize: 20, + + /** + * @cfg {Number} cleanDelay + * The number of milliseconds to buffer cleaning of extra rows not in the + * cache. + */ + cleanDelay: 500, + + initTemplates : function(){ + Ext.ux.grid.BufferView.superclass.initTemplates.call(this); + var ts = this.templates; + // empty div to act as a place holder for a row + ts.rowHolder = new Ext.Template( + '
' + ); + ts.rowHolder.disableFormats = true; + ts.rowHolder.compile(); + + ts.rowBody = new Ext.Template( + '', + '{cells}', + (this.enableRowBody ? '' : ''), + '
{body}
' + ); + ts.rowBody.disableFormats = true; + ts.rowBody.compile(); + }, + + getStyleRowHeight : function(){ + return Ext.isBorderBox ? (this.rowHeight + this.borderHeight) : this.rowHeight; + }, + + getCalculatedRowHeight : function(){ + return this.rowHeight + this.borderHeight; + }, + + getVisibleRowCount : function(){ + var rh = this.getCalculatedRowHeight(), + visibleHeight = this.scroller.dom.clientHeight; + return (visibleHeight < 1) ? 0 : Math.ceil(visibleHeight / rh); + }, + + getVisibleRows: function(){ + var count = this.getVisibleRowCount(), + sc = this.scroller.dom.scrollTop, + start = (sc === 0 ? 0 : Math.floor(sc/this.getCalculatedRowHeight())-1); + return { + first: Math.max(start, 0), + last: Math.min(start + count + 2, this.ds.getCount()-1) + }; + }, + + doRender : function(cs, rs, ds, startRow, colCount, stripe, onlyBody){ + var ts = this.templates, + ct = ts.cell, + rt = ts.row, + rb = ts.rowBody, + last = colCount-1, + rh = this.getStyleRowHeight(), + vr = this.getVisibleRows(), + tstyle = 'width:'+this.getTotalWidth()+';height:'+rh+'px;', + // buffers + buf = [], + cb, + c, + p = {}, + rp = {tstyle: tstyle}, + r; + for (var j = 0, len = rs.length; j < len; j++) { + r = rs[j]; cb = []; + var rowIndex = (j+startRow), + visible = rowIndex >= vr.first && rowIndex <= vr.last; + if (visible) { + for (var i = 0; i < colCount; i++) { + c = cs[i]; + p.id = c.id; + p.css = i === 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : ''); + p.attr = p.cellAttr = ""; + p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds); + p.style = c.style; + if (p.value === undefined || p.value === "") { + p.value = " "; + } + if (r.dirty && typeof r.modified[c.name] !== 'undefined') { + p.css += ' x-grid3-dirty-cell'; + } + cb[cb.length] = ct.apply(p); + } + } + var alt = []; + if(stripe && ((rowIndex+1) % 2 === 0)){ + alt[0] = "x-grid3-row-alt"; + } + if(r.dirty){ + alt[1] = " x-grid3-dirty-row"; + } + rp.cols = colCount; + if(this.getRowClass){ + alt[2] = this.getRowClass(r, rowIndex, rp, ds); + } + rp.alt = alt.join(" "); + rp.cells = cb.join(""); + buf[buf.length] = !visible ? ts.rowHolder.apply(rp) : (onlyBody ? rb.apply(rp) : rt.apply(rp)); + } + return buf.join(""); + }, + + isRowRendered: function(index){ + var row = this.getRow(index); + return row && row.childNodes.length > 0; + }, + + syncScroll: function(){ + Ext.ux.grid.BufferView.superclass.syncScroll.apply(this, arguments); + this.update(); + }, + + // a (optionally) buffered method to update contents of gridview + update: function(){ + if (this.scrollDelay) { + if (!this.renderTask) { + this.renderTask = new Ext.util.DelayedTask(this.doUpdate, this); + } + this.renderTask.delay(this.scrollDelay); + }else{ + this.doUpdate(); + } + }, + + onRemove : function(ds, record, index, isUpdate){ + Ext.ux.grid.BufferView.superclass.onRemove.apply(this, arguments); + if(isUpdate !== true){ + this.update(); + } + }, + + doUpdate: function(){ + if (this.getVisibleRowCount() > 0) { + var g = this.grid, + cm = g.colModel, + ds = g.store, + cs = this.getColumnData(), + vr = this.getVisibleRows(), + row; + for (var i = vr.first; i <= vr.last; i++) { + // if row is NOT rendered and is visible, render it + if(!this.isRowRendered(i) && (row = this.getRow(i))){ + var html = this.doRender(cs, [ds.getAt(i)], ds, i, cm.getColumnCount(), g.stripeRows, true); + row.innerHTML = html; + } + } + this.clean(); + } + }, + + // a buffered method to clean rows + clean : function(){ + if(!this.cleanTask){ + this.cleanTask = new Ext.util.DelayedTask(this.doClean, this); + } + this.cleanTask.delay(this.cleanDelay); + }, + + doClean: function(){ + if (this.getVisibleRowCount() > 0) { + var vr = this.getVisibleRows(); + vr.first -= this.cacheSize; + vr.last += this.cacheSize; + + var i = 0, rows = this.getRows(); + // if first is less than 0, all rows have been rendered + // so lets clean the end... + if(vr.first <= 0){ + i = vr.last + 1; + } + for(var len = this.ds.getCount(); i < len; i++){ + // if current row is outside of first and last and + // has content, update the innerHTML to nothing + if ((i < vr.first || i > vr.last) && rows[i].innerHTML) { + rows[i].innerHTML = ''; + } + } + } + }, + + removeTask: function(name){ + var task = this[name]; + if(task && task.cancel){ + task.cancel(); + this[name] = null; + } + }, + + destroy : function(){ + this.removeTask('cleanTask'); + this.removeTask('renderTask'); + Ext.ux.grid.BufferView.superclass.destroy.call(this); + }, + + layout: function(){ + Ext.ux.grid.BufferView.superclass.layout.call(this); + this.update(); + } +}); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.form'); + +/** + * @class Ext.ux.form.FileUploadField + * @extends Ext.form.TextField + * Creates a file upload field. + * @xtype fileuploadfield + */ +Ext.ux.form.FileUploadField = Ext.extend(Ext.form.TextField, { + /** + * @cfg {String} buttonText The button text to display on the upload button (defaults to + * 'Browse...'). Note that if you supply a value for {@link #buttonCfg}, the buttonCfg.text + * value will be used instead if available. + */ + buttonText: 'Browse...', + /** + * @cfg {Boolean} buttonOnly True to display the file upload field as a button with no visible + * text field (defaults to false). If true, all inherited TextField members will still be available. + */ + buttonOnly: false, + /** + * @cfg {Number} buttonOffset The number of pixels of space reserved between the button and the text field + * (defaults to 3). Note that this only applies if {@link #buttonOnly} = false. + */ + buttonOffset: 3, + /** + * @cfg {Object} buttonCfg A standard {@link Ext.Button} config object. + */ + + // private + readOnly: true, + + /** + * @hide + * @method autoSize + */ + autoSize: Ext.emptyFn, + + // private + initComponent: function(){ + Ext.ux.form.FileUploadField.superclass.initComponent.call(this); + + this.addEvents( + /** + * @event fileselected + * Fires when the underlying file input field's value has changed from the user + * selecting a new file from the system file selection dialog. + * @param {Ext.ux.form.FileUploadField} this + * @param {String} value The file value returned by the underlying file input field + */ + 'fileselected' + ); + }, + + // private + onRender : function(ct, position){ + Ext.ux.form.FileUploadField.superclass.onRender.call(this, ct, position); + + this.wrap = this.el.wrap({cls:'x-form-field-wrap x-form-file-wrap'}); + this.el.addClass('x-form-file-text'); + this.el.dom.removeAttribute('name'); + this.createFileInput(); + + var btnCfg = Ext.applyIf(this.buttonCfg || {}, { + text: this.buttonText + }); + this.button = new Ext.Button(Ext.apply(btnCfg, { + renderTo: this.wrap, + cls: 'x-form-file-btn' + (btnCfg.iconCls ? ' x-btn-icon' : '') + })); + + if(this.buttonOnly){ + this.el.hide(); + this.wrap.setWidth(this.button.getEl().getWidth()); + } + + this.bindListeners(); + this.resizeEl = this.positionEl = this.wrap; + }, + + bindListeners: function(){ + this.fileInput.on({ + scope: this, + mouseenter: function() { + this.button.addClass(['x-btn-over','x-btn-focus']) + }, + mouseleave: function(){ + this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click']) + }, + mousedown: function(){ + this.button.addClass('x-btn-click') + }, + mouseup: function(){ + this.button.removeClass(['x-btn-over','x-btn-focus','x-btn-click']) + }, + change: function(){ + var v = this.fileInput.dom.value; + this.setValue(v); + this.fireEvent('fileselected', this, v); + } + }); + }, + + createFileInput : function() { + this.fileInput = this.wrap.createChild({ + id: this.getFileInputId(), + name: this.name||this.getId(), + cls: 'x-form-file', + tag: 'input', + type: 'file', + size: 1 + }); + }, + + reset : function(){ + if (this.rendered) { + this.fileInput.remove(); + this.createFileInput(); + this.bindListeners(); + } + Ext.ux.form.FileUploadField.superclass.reset.call(this); + }, + + // private + getFileInputId: function(){ + return this.id + '-file'; + }, + + // private + onResize : function(w, h){ + Ext.ux.form.FileUploadField.superclass.onResize.call(this, w, h); + + this.wrap.setWidth(w); + + if(!this.buttonOnly){ + var w = this.wrap.getWidth() - this.button.getEl().getWidth() - this.buttonOffset; + this.el.setWidth(w); + } + }, + + // private + onDestroy: function(){ + Ext.ux.form.FileUploadField.superclass.onDestroy.call(this); + Ext.destroy(this.fileInput, this.button, this.wrap); + }, + + onDisable: function(){ + Ext.ux.form.FileUploadField.superclass.onDisable.call(this); + this.doDisable(true); + }, + + onEnable: function(){ + Ext.ux.form.FileUploadField.superclass.onEnable.call(this); + this.doDisable(false); + + }, + + // private + doDisable: function(disabled){ + this.fileInput.dom.disabled = disabled; + this.button.setDisabled(disabled); + }, + + + // private + preFocus : Ext.emptyFn, + + // private + alignErrorIcon : function(){ + this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]); + } + +}); + +Ext.reg('fileuploadfield', Ext.ux.form.FileUploadField); + +// backwards compat +Ext.form.FileUploadField = Ext.ux.form.FileUploadField; +/*! + * Ext.ux.form.RadioGroup.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ + +// Allow radiogroups to be treated as a single form element. +Ext.override(Ext.form.RadioGroup, { + + afterRender: function() { + this.items.each(function(i) { + this.relayEvents(i, ['check']); + }, this); + if (this.lazyValue) { + this.setValue(this.value); + delete this.value; + delete this.lazyValue; + } + Ext.form.RadioGroup.superclass.afterRender.call(this) + }, + + getName: function() { + return this.items.first().getName(); + }, + + getValue: function() { + return this.items.first().getGroupValue(); + }, + + setValue: function(v) { + if (!this.items.each) { + this.value = v; + this.lazyValue = true; + return; + } + this.items.each(function(item) { + if (item.rendered) { + var checked = (item.el.getValue() == String(v)); + item.el.dom.checked = checked; + item.el.dom.defaultChecked = checked; + item.wrap[checked ? 'addClass' : 'removeClass'](item.checkedCls); + } + }); + } +}); +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns('Ext.ux.form'); + +/** + * @class Ext.ux.form.SpinnerField + * @extends Ext.form.NumberField + * Creates a field utilizing Ext.ux.Spinner + * @xtype spinnerfield + */ +Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, { + actionMode: 'wrap', + deferHeight: true, + autoSize: Ext.emptyFn, + onBlur: Ext.emptyFn, + adjustSize: Ext.BoxComponent.prototype.adjustSize, + + constructor: function(config) { + var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass'); + + var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig); + + var plugins = config.plugins + ? (Ext.isArray(config.plugins) + ? config.plugins.push(spl) + : [config.plugins, spl]) + : spl; + + Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins})); + }, + + // private + getResizeEl: function(){ + return this.wrap; + }, + + // private + getPositionEl: function(){ + return this.wrap; + }, + + // private + alignErrorIcon: function(){ + if (this.wrap) { + this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]); + } + }, + + validateBlur: function(){ + return true; + } +}); + +Ext.reg('spinnerfield', Ext.ux.form.SpinnerField); + +//backwards compat +Ext.form.SpinnerField = Ext.ux.form.SpinnerField; +/*! + * Ext.ux.form.SpinnerField.js + * + * Copyright (c) Damien Churchill 2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ + +Ext.override(Ext.ux.form.SpinnerField, { + onBlur: Ext.form.Field.prototype.onBlur +}); +/*! + * Ext.ux.form.SpinnerGroup.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.ns('Ext.ux.form'); + +/** + * + */ +Ext.ux.form.SpinnerGroup = Ext.extend(Ext.form.CheckboxGroup, { + + // private + defaultType: 'spinnerfield', + anchor: '98%', + + // private + groupCls: 'x-form-spinner-group', + + colCfg: {}, + + // private + onRender : function(ct, position){ + if(!this.el){ + var panelCfg = { + cls: this.groupCls, + layout: 'column', + border: false, + renderTo: ct + }; + var colCfg = Ext.apply({ + defaultType: this.defaultType, + layout: 'form', + border: false, + labelWidth: 60, + defaults: { + hideLabel: true, + anchor: '60%' + } + }, this.colCfg); + + if(this.items[0].items){ + + // The container has standard ColumnLayout configs, so pass them in directly + + Ext.apply(panelCfg, { + layoutConfig: {columns: this.items.length}, + defaults: this.defaults, + items: this.items + }) + for(var i=0, len=this.items.length; i0 && i%rows==0){ + ri++; + } + if(this.items[i].fieldLabel){ + this.items[i].hideLabel = false; + } + cols[ri].items.push(this.items[i]); + }; + }else{ + for(var i=0, len=this.items.length; i + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.namespace("Ext.ux.form"); + +/** + * Ext.ux.form.ToggleField class + * + * @author Damien Churchill + * @version v0.1 + * + * @class Ext.ux.form.ToggleField + * @extends Ext.form.TriggerField + */ +Ext.ux.form.ToggleField = Ext.extend(Ext.form.Field, { + + cls: 'x-toggle-field', + + initComponent: function() { + Ext.ux.form.ToggleField.superclass.initComponent.call(this); + + this.toggle = new Ext.form.Checkbox(); + this.toggle.on('check', this.onToggleCheck, this); + + this.input = new Ext.form.TextField({ + disabled: true + }); + }, + + onRender: function(ct, position) { + if (!this.el) { + this.panel = new Ext.Panel({ + cls: this.groupCls, + layout: 'table', + layoutConfig: { + columns: 2 + }, + border: false, + renderTo: ct + }); + this.panel.ownerCt = this; + this.el = this.panel.getEl(); + + this.panel.add(this.toggle); + this.panel.add(this.input); + this.panel.doLayout(); + + this.toggle.getEl().parent().setStyle('padding-right', '10px'); + } + Ext.ux.form.ToggleField.superclass.onRender.call(this, ct, position); + }, + + // private + onResize: function(w, h) { + this.panel.setSize(w, h); + this.panel.doLayout(); + + // we substract 10 for the padding :-) + var inputWidth = w - this.toggle.getSize().width - 25; + this.input.setSize(inputWidth, h); + }, + + onToggleCheck: function(toggle, checked) { + this.input.setDisabled(!checked); + } +}); +Ext.reg('togglefield', Ext.ux.form.ToggleField); +Ext.ux.JSLoader = function(options) { + Ext.ux.JSLoader.scripts[++Ext.ux.JSLoader.index] = { + url: options.url, + success: true, + jsLoadObj: null, + options: options, + onLoad: options.onLoad || Ext.emptyFn, + onError: options.onError || Ext.ux.JSLoader.stdError, + scope: options.scope || this + }; + + Ext.Ajax.request({ + url: options.url, + scriptIndex: Ext.ux.JSLoader.index, + success: function(response, options) { + var script = Ext.ux.JSLoader.scripts[options.scriptIndex]; + try { + eval(response.responseText); + } catch(e) { + script.success = false; + script.onError(script.options, e); + } + if (script.success) { + script.onLoad.call(script.scope, script.options); + } + }, + failure: function(response, options) { + var script = Ext.ux.JSLoader.scripts[options.scriptIndex]; + script.success = false; + script.onError(script.options, response.status); + } + }); +} +Ext.ux.JSLoader.index = 0; +Ext.ux.JSLoader.scripts = []; +Ext.ux.JSLoader.stdError = function(options, e) { + window.alert('Error loading script:\n\n' + options.url + '\n\nstatus: ' + e); +} +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +/** + * @class Ext.ux.Spinner + * @extends Ext.util.Observable + * Creates a Spinner control utilized by Ext.ux.form.SpinnerField + */ +Ext.ux.Spinner = Ext.extend(Ext.util.Observable, { + incrementValue: 1, + alternateIncrementValue: 5, + triggerClass: 'x-form-spinner-trigger', + splitterClass: 'x-form-spinner-splitter', + alternateKey: Ext.EventObject.shiftKey, + defaultValue: 0, + accelerate: false, + + constructor: function(config){ + Ext.ux.Spinner.superclass.constructor.call(this, config); + Ext.apply(this, config); + this.mimicing = false; + }, + + init: function(field){ + this.field = field; + + field.afterMethod('onRender', this.doRender, this); + field.afterMethod('onEnable', this.doEnable, this); + field.afterMethod('onDisable', this.doDisable, this); + field.afterMethod('afterRender', this.doAfterRender, this); + field.afterMethod('onResize', this.doResize, this); + field.afterMethod('onFocus', this.doFocus, this); + field.beforeMethod('onDestroy', this.doDestroy, this); + }, + + doRender: function(ct, position){ + var el = this.el = this.field.getEl(); + var f = this.field; + + if (!f.wrap) { + f.wrap = this.wrap = el.wrap({ + cls: "x-form-field-wrap" + }); + } + else { + this.wrap = f.wrap.addClass('x-form-field-wrap'); + } + + this.trigger = this.wrap.createChild({ + tag: "img", + src: Ext.BLANK_IMAGE_URL, + cls: "x-form-trigger " + this.triggerClass + }); + + if (!f.width) { + this.wrap.setWidth(el.getWidth() + this.trigger.getWidth()); + } + + this.splitter = this.wrap.createChild({ + tag: 'div', + cls: this.splitterClass, + style: 'width:13px; height:2px;' + }); + this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show(); + + this.proxy = this.trigger.createProxy('', this.splitter, true); + this.proxy.addClass("x-form-spinner-proxy"); + this.proxy.setStyle('left', '0px'); + this.proxy.setSize(14, 1); + this.proxy.hide(); + this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", { + dragElId: this.proxy.id + }); + + this.initTrigger(); + this.initSpinner(); + }, + + doAfterRender: function(){ + var y; + if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) { + this.el.position(); + this.el.setY(y); + } + }, + + doEnable: function(){ + if (this.wrap) { + this.disabled = false; + this.wrap.removeClass(this.field.disabledClass); + } + }, + + doDisable: function(){ + if (this.wrap) { + this.disabled = true; + this.wrap.addClass(this.field.disabledClass); + this.el.removeClass(this.field.disabledClass); + } + }, + + doResize: function(w, h){ + if (typeof w == 'number') { + this.el.setWidth(w - this.trigger.getWidth()); + } + this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth()); + }, + + doFocus: function(){ + if (!this.mimicing) { + this.wrap.addClass('x-trigger-wrap-focus'); + this.mimicing = true; + Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, { + delay: 10 + }); + this.el.on('keydown', this.checkTab, this); + } + }, + + // private + checkTab: function(e){ + if (e.getKey() == e.TAB) { + this.triggerBlur(); + } + }, + + // private + mimicBlur: function(e){ + if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) { + this.triggerBlur(); + } + }, + + // private + triggerBlur: function(){ + this.mimicing = false; + Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this); + this.el.un("keydown", this.checkTab, this); + this.field.beforeBlur(); + this.wrap.removeClass('x-trigger-wrap-focus'); + this.field.onBlur.call(this.field); + }, + + initTrigger: function(){ + this.trigger.addClassOnOver('x-form-trigger-over'); + this.trigger.addClassOnClick('x-form-trigger-click'); + }, + + initSpinner: function(){ + this.field.addEvents({ + 'spin': true, + 'spinup': true, + 'spindown': true + }); + + this.keyNav = new Ext.KeyNav(this.el, { + "up": function(e){ + e.preventDefault(); + this.onSpinUp(); + }, + + "down": function(e){ + e.preventDefault(); + this.onSpinDown(); + }, + + "pageUp": function(e){ + e.preventDefault(); + this.onSpinUpAlternate(); + }, + + "pageDown": function(e){ + e.preventDefault(); + this.onSpinDownAlternate(); + }, + + scope: this + }); + + this.repeater = new Ext.util.ClickRepeater(this.trigger, { + accelerate: this.accelerate + }); + this.field.mon(this.repeater, "click", this.onTriggerClick, this, { + preventDefault: true + }); + + this.field.mon(this.trigger, { + mouseover: this.onMouseOver, + mouseout: this.onMouseOut, + mousemove: this.onMouseMove, + mousedown: this.onMouseDown, + mouseup: this.onMouseUp, + scope: this, + preventDefault: true + }); + + this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this); + + this.dd.setXConstraint(0, 0, 10) + this.dd.setYConstraint(1500, 1500, 10); + this.dd.endDrag = this.endDrag.createDelegate(this); + this.dd.startDrag = this.startDrag.createDelegate(this); + this.dd.onDrag = this.onDrag.createDelegate(this); + }, + + onMouseOver: function(){ + if (this.disabled) { + return; + } + var middle = this.getMiddle(); + this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown'; + this.trigger.addClass(this.tmpHoverClass); + }, + + //private + onMouseOut: function(){ + this.trigger.removeClass(this.tmpHoverClass); + }, + + //private + onMouseMove: function(){ + if (this.disabled) { + return; + } + var middle = this.getMiddle(); + if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") || + ((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) { + } + }, + + //private + onMouseDown: function(){ + if (this.disabled) { + return; + } + var middle = this.getMiddle(); + this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown'; + this.trigger.addClass(this.tmpClickClass); + }, + + //private + onMouseUp: function(){ + this.trigger.removeClass(this.tmpClickClass); + }, + + //private + onTriggerClick: function(){ + if (this.disabled || this.el.dom.readOnly) { + return; + } + var middle = this.getMiddle(); + var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down'; + this['onSpin' + ud](); + }, + + //private + getMiddle: function(){ + var t = this.trigger.getTop(); + var h = this.trigger.getHeight(); + var middle = t + (h / 2); + return middle; + }, + + //private + //checks if control is allowed to spin + isSpinnable: function(){ + if (this.disabled || this.el.dom.readOnly) { + Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly + return false; + } + return true; + }, + + handleMouseWheel: function(e){ + //disable scrolling when not focused + if (this.wrap.hasClass('x-trigger-wrap-focus') == false) { + return; + } + + var delta = e.getWheelDelta(); + if (delta > 0) { + this.onSpinUp(); + e.stopEvent(); + } + else + if (delta < 0) { + this.onSpinDown(); + e.stopEvent(); + } + }, + + //private + startDrag: function(){ + this.proxy.show(); + this._previousY = Ext.fly(this.dd.getDragEl()).getTop(); + }, + + //private + endDrag: function(){ + this.proxy.hide(); + }, + + //private + onDrag: function(){ + if (this.disabled) { + return; + } + var y = Ext.fly(this.dd.getDragEl()).getTop(); + var ud = ''; + + if (this._previousY > y) { + ud = 'Up'; + } //up + if (this._previousY < y) { + ud = 'Down'; + } //down + if (ud != '') { + this['onSpin' + ud](); + } + + this._previousY = y; + }, + + //private + onSpinUp: function(){ + if (this.isSpinnable() == false) { + return; + } + if (Ext.EventObject.shiftKey == true) { + this.onSpinUpAlternate(); + return; + } + else { + this.spin(false, false); + } + this.field.fireEvent("spin", this); + this.field.fireEvent("spinup", this); + }, + + //private + onSpinDown: function(){ + if (this.isSpinnable() == false) { + return; + } + if (Ext.EventObject.shiftKey == true) { + this.onSpinDownAlternate(); + return; + } + else { + this.spin(true, false); + } + this.field.fireEvent("spin", this); + this.field.fireEvent("spindown", this); + }, + + //private + onSpinUpAlternate: function(){ + if (this.isSpinnable() == false) { + return; + } + this.spin(false, true); + this.field.fireEvent("spin", this); + this.field.fireEvent("spinup", this); + }, + + //private + onSpinDownAlternate: function(){ + if (this.isSpinnable() == false) { + return; + } + this.spin(true, true); + this.field.fireEvent("spin", this); + this.field.fireEvent("spindown", this); + }, + + spin: function(down, alternate){ + var v = parseFloat(this.field.getValue()); + var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue; + (down == true) ? v -= incr : v += incr; + + v = (isNaN(v)) ? this.defaultValue : v; + v = this.fixBoundries(v); + this.field.setRawValue(v); + }, + + fixBoundries: function(value){ + var v = value; + + if (this.field.minValue != undefined && v < this.field.minValue) { + v = this.field.minValue; + } + if (this.field.maxValue != undefined && v > this.field.maxValue) { + v = this.field.maxValue; + } + + return this.fixPrecision(v); + }, + + // private + fixPrecision: function(value){ + var nan = isNaN(value); + if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) { + return nan ? '' : value; + } + return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision)); + }, + + doDestroy: function(){ + if (this.trigger) { + this.trigger.remove(); + } + if (this.wrap) { + this.wrap.remove(); + delete this.field.wrap; + } + + if (this.splitter) { + this.splitter.remove(); + } + + if (this.dd) { + this.dd.unreg(); + this.dd = null; + } + + if (this.proxy) { + this.proxy.remove(); + } + + if (this.repeater) { + this.repeater.purgeListeners(); + } + if (this.mimicing){ + Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this); + } + } +}); + +//backwards compat +Ext.form.Spinner = Ext.ux.Spinner; +/*! + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +/** + * @class Ext.ux.StatusBar + *

Basic status bar component that can be used as the bottom toolbar of any {@link Ext.Panel}. In addition to + * supporting the standard {@link Ext.Toolbar} interface for adding buttons, menus and other items, the StatusBar + * provides a greedy status element that can be aligned to either side and has convenient methods for setting the + * status text and icon. You can also indicate that something is processing using the {@link #showBusy} method.

+ *

+new Ext.Panel({
+    title: 'StatusBar',
+    // etc.
+    bbar: new Ext.ux.StatusBar({
+        id: 'my-status',
+
+        // defaults to use when the status is cleared:
+        defaultText: 'Default status text',
+        defaultIconCls: 'default-icon',
+
+        // values to set initially:
+        text: 'Ready',
+        iconCls: 'ready-icon',
+
+        // any standard Toolbar items:
+        items: [{
+            text: 'A Button'
+        }, '-', 'Plain Text']
+    })
+});
+
+// Update the status bar later in code:
+var sb = Ext.getCmp('my-status');
+sb.setStatus({
+    text: 'OK',
+    iconCls: 'ok-icon',
+    clear: true // auto-clear after a set interval
+});
+
+// Set the status bar to show that something is processing:
+sb.showBusy();
+
+// processing....
+
+sb.clearStatus(); // once completeed
+
+ * @extends Ext.Toolbar + * @constructor + * Creates a new StatusBar + * @param {Object/Array} config A config object + */ +Ext.ux.StatusBar = Ext.extend(Ext.Toolbar, { + /** + * @cfg {String} statusAlign + * The alignment of the status element within the overall StatusBar layout. When the StatusBar is rendered, + * it creates an internal div containing the status text and icon. Any additional Toolbar items added in the + * StatusBar's {@link #items} config, or added via {@link #add} or any of the supported add* methods, will be + * rendered, in added order, to the opposite side. The status element is greedy, so it will automatically + * expand to take up all sapce left over by any other items. Example usage: + *

+// Create a left-aligned status bar containing a button,
+// separator and text item that will be right-aligned (default):
+new Ext.Panel({
+    title: 'StatusBar',
+    // etc.
+    bbar: new Ext.ux.StatusBar({
+        defaultText: 'Default status text',
+        id: 'status-id',
+        items: [{
+            text: 'A Button'
+        }, '-', 'Plain Text']
+    })
+});
+
+// By adding the statusAlign config, this will create the
+// exact same toolbar, except the status and toolbar item
+// layout will be reversed from the previous example:
+new Ext.Panel({
+    title: 'StatusBar',
+    // etc.
+    bbar: new Ext.ux.StatusBar({
+        defaultText: 'Default status text',
+        id: 'status-id',
+        statusAlign: 'right',
+        items: [{
+            text: 'A Button'
+        }, '-', 'Plain Text']
+    })
+});
+
+ */ + /** + * @cfg {String} defaultText + * The default {@link #text} value. This will be used anytime the status bar is cleared with the + * useDefaults:true option (defaults to ''). + */ + /** + * @cfg {String} defaultIconCls + * The default {@link #iconCls} value (see the iconCls docs for additional details about customizing the icon). + * This will be used anytime the status bar is cleared with the useDefaults:true option (defaults to ''). + */ + /** + * @cfg {String} text + * A string that will be initially set as the status message. This string + * will be set as innerHTML (html tags are accepted) for the toolbar item. + * If not specified, the value set for {@link #defaultText} + * will be used. + */ + /** + * @cfg {String} iconCls + * A CSS class that will be initially set as the status bar icon and is + * expected to provide a background image (defaults to ''). + * Example usage:

+// Example CSS rule:
+.x-statusbar .x-status-custom {
+    padding-left: 25px;
+    background: transparent url(images/custom-icon.gif) no-repeat 3px 2px;
+}
+
+// Setting a default icon:
+var sb = new Ext.ux.StatusBar({
+    defaultIconCls: 'x-status-custom'
+});
+
+// Changing the icon:
+sb.setStatus({
+    text: 'New status',
+    iconCls: 'x-status-custom'
+});
+
+ */ + + /** + * @cfg {String} cls + * The base class applied to the containing element for this component on render (defaults to 'x-statusbar') + */ + cls : 'x-statusbar', + /** + * @cfg {String} busyIconCls + * The default {@link #iconCls} applied when calling + * {@link #showBusy} (defaults to 'x-status-busy'). + * It can be overridden at any time by passing the iconCls + * argument into {@link #showBusy}. + */ + busyIconCls : 'x-status-busy', + /** + * @cfg {String} busyText + * The default {@link #text} applied when calling + * {@link #showBusy} (defaults to 'Loading...'). + * It can be overridden at any time by passing the text + * argument into {@link #showBusy}. + */ + busyText : 'Loading...', + /** + * @cfg {Number} autoClear + * The number of milliseconds to wait after setting the status via + * {@link #setStatus} before automatically clearing the status + * text and icon (defaults to 5000). Note that this only applies + * when passing the clear argument to {@link #setStatus} + * since that is the only way to defer clearing the status. This can + * be overridden by specifying a different wait value in + * {@link #setStatus}. Calls to {@link #clearStatus} + * always clear the status bar immediately and ignore this value. + */ + autoClear : 5000, + + /** + * @cfg {String} emptyText + * The text string to use if no text has been set. Defaults to + * ' '). If there are no other items in the toolbar using + * an empty string ('') for this value would end up in the toolbar + * height collapsing since the empty string will not maintain the toolbar + * height. Use '' if the toolbar should collapse in height + * vertically when no text is specified and there are no other items in + * the toolbar. + */ + emptyText : ' ', + + // private + activeThreadId : 0, + + // private + initComponent : function(){ + if(this.statusAlign=='right'){ + this.cls += ' x-status-right'; + } + Ext.ux.StatusBar.superclass.initComponent.call(this); + }, + + // private + afterRender : function(){ + Ext.ux.StatusBar.superclass.afterRender.call(this); + + var right = this.statusAlign == 'right'; + this.currIconCls = this.iconCls || this.defaultIconCls; + this.statusEl = new Ext.Toolbar.TextItem({ + cls: 'x-status-text ' + (this.currIconCls || ''), + text: this.text || this.defaultText || '' + }); + + if(right){ + this.add('->'); + this.add(this.statusEl); + }else{ + this.insert(0, this.statusEl); + this.insert(1, '->'); + } + this.doLayout(); + }, + + /** + * Sets the status {@link #text} and/or {@link #iconCls}. Also supports automatically clearing the + * status that was set after a specified interval. + * @param {Object/String} config A config object specifying what status to set, or a string assumed + * to be the status text (and all other options are defaulted as explained below). A config + * object containing any or all of the following properties can be passed:
    + *
  • text {String} : (optional) The status text to display. If not specified, any current + * status text will remain unchanged.
  • + *
  • iconCls {String} : (optional) The CSS class used to customize the status icon (see + * {@link #iconCls} for details). If not specified, any current iconCls will remain unchanged.
  • + *
  • clear {Boolean/Number/Object} : (optional) Allows you to set an internal callback that will + * automatically clear the status text and iconCls after a specified amount of time has passed. If clear is not + * specified, the new status will not be auto-cleared and will stay until updated again or cleared using + * {@link #clearStatus}. If true is passed, the status will be cleared using {@link #autoClear}, + * {@link #defaultText} and {@link #defaultIconCls} via a fade out animation. If a numeric value is passed, + * it will be used as the callback interval (in milliseconds), overriding the {@link #autoClear} value. + * All other options will be defaulted as with the boolean option. To customize any other options, + * you can pass an object in the format:
      + *
    • wait {Number} : (optional) The number of milliseconds to wait before clearing + * (defaults to {@link #autoClear}).
    • + *
    • anim {Number} : (optional) False to clear the status immediately once the callback + * executes (defaults to true which fades the status out).
    • + *
    • useDefaults {Number} : (optional) False to completely clear the status text and iconCls + * (defaults to true which uses {@link #defaultText} and {@link #defaultIconCls}).
    • + *
+ * Example usage:

+// Simple call to update the text
+statusBar.setStatus('New status');
+
+// Set the status and icon, auto-clearing with default options:
+statusBar.setStatus({
+    text: 'New status',
+    iconCls: 'x-status-custom',
+    clear: true
+});
+
+// Auto-clear with custom options:
+statusBar.setStatus({
+    text: 'New status',
+    iconCls: 'x-status-custom',
+    clear: {
+        wait: 8000,
+        anim: false,
+        useDefaults: false
+    }
+});
+
+ * @return {Ext.ux.StatusBar} this + */ + setStatus : function(o){ + o = o || {}; + + if(typeof o == 'string'){ + o = {text:o}; + } + if(o.text !== undefined){ + this.setText(o.text); + } + if(o.iconCls !== undefined){ + this.setIcon(o.iconCls); + } + + if(o.clear){ + var c = o.clear, + wait = this.autoClear, + defaults = {useDefaults: true, anim: true}; + + if(typeof c == 'object'){ + c = Ext.applyIf(c, defaults); + if(c.wait){ + wait = c.wait; + } + }else if(typeof c == 'number'){ + wait = c; + c = defaults; + }else if(typeof c == 'boolean'){ + c = defaults; + } + + c.threadId = this.activeThreadId; + this.clearStatus.defer(wait, this, [c]); + } + return this; + }, + + /** + * Clears the status {@link #text} and {@link #iconCls}. Also supports clearing via an optional fade out animation. + * @param {Object} config (optional) A config object containing any or all of the following properties. If this + * object is not specified the status will be cleared using the defaults below:
    + *
  • anim {Boolean} : (optional) True to clear the status by fading out the status element (defaults + * to false which clears immediately).
  • + *
  • useDefaults {Boolean} : (optional) True to reset the text and icon using {@link #defaultText} and + * {@link #defaultIconCls} (defaults to false which sets the text to '' and removes any existing icon class).
  • + *
+ * @return {Ext.ux.StatusBar} this + */ + clearStatus : function(o){ + o = o || {}; + + if(o.threadId && o.threadId !== this.activeThreadId){ + // this means the current call was made internally, but a newer + // thread has set a message since this call was deferred. Since + // we don't want to overwrite a newer message just ignore. + return this; + } + + var text = o.useDefaults ? this.defaultText : this.emptyText, + iconCls = o.useDefaults ? (this.defaultIconCls ? this.defaultIconCls : '') : ''; + + if(o.anim){ + // animate the statusEl Ext.Element + this.statusEl.el.fadeOut({ + remove: false, + useDisplay: true, + scope: this, + callback: function(){ + this.setStatus({ + text: text, + iconCls: iconCls + }); + + this.statusEl.el.show(); + } + }); + }else{ + // hide/show the el to avoid jumpy text or icon + this.statusEl.hide(); + this.setStatus({ + text: text, + iconCls: iconCls + }); + this.statusEl.show(); + } + return this; + }, + + /** + * Convenience method for setting the status text directly. For more flexible options see {@link #setStatus}. + * @param {String} text (optional) The text to set (defaults to '') + * @return {Ext.ux.StatusBar} this + */ + setText : function(text){ + this.activeThreadId++; + this.text = text || ''; + if(this.rendered){ + this.statusEl.setText(this.text); + } + return this; + }, + + /** + * Returns the current status text. + * @return {String} The status text + */ + getText : function(){ + return this.text; + }, + + /** + * Convenience method for setting the status icon directly. For more flexible options see {@link #setStatus}. + * See {@link #iconCls} for complete details about customizing the icon. + * @param {String} iconCls (optional) The icon class to set (defaults to '', and any current icon class is removed) + * @return {Ext.ux.StatusBar} this + */ + setIcon : function(cls){ + this.activeThreadId++; + cls = cls || ''; + + if(this.rendered){ + if(this.currIconCls){ + this.statusEl.removeClass(this.currIconCls); + this.currIconCls = null; + } + if(cls.length > 0){ + this.statusEl.addClass(cls); + this.currIconCls = cls; + } + }else{ + this.currIconCls = cls; + } + return this; + }, + + /** + * Convenience method for setting the status text and icon to special values that are pre-configured to indicate + * a "busy" state, usually for loading or processing activities. + * @param {Object/String} config (optional) A config object in the same format supported by {@link #setStatus}, or a + * string to use as the status text (in which case all other options for setStatus will be defaulted). Use the + * text and/or iconCls properties on the config to override the default {@link #busyText} + * and {@link #busyIconCls} settings. If the config argument is not specified, {@link #busyText} and + * {@link #busyIconCls} will be used in conjunction with all of the default options for {@link #setStatus}. + * @return {Ext.ux.StatusBar} this + */ + showBusy : function(o){ + if(typeof o == 'string'){ + o = {text:o}; + } + o = Ext.applyIf(o || {}, { + text: this.busyText, + iconCls: this.busyIconCls + }); + return this.setStatus(o); + } +}); +Ext.reg('statusbar', Ext.ux.StatusBar); diff --git a/deluge/ui/web/js/extjs/ext-extensions.js b/deluge/ui/web/js/extjs/ext-extensions.js new file mode 100644 index 000000000..be6f182cb --- /dev/null +++ b/deluge/ui/web/js/extjs/ext-extensions.js @@ -0,0 +1,269 @@ +/* + * Ext.ux.layout.FormLayoutFix.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.override(Ext.layout.FormLayout,{renderItem:function(e,a,d){if(e&&!e.rendered&&(e.isFormField||e.fieldLabel)&&e.inputType!="hidden"){var b=this.getTemplateArgs(e);if(typeof a=="number"){a=d.dom.childNodes[a]||null}if(a){e.formItem=this.fieldTpl.insertBefore(a,b,true)}else{e.formItem=this.fieldTpl.append(d,b,true)}e.actionMode="formItem";e.render("x-form-el-"+e.id);e.container=e.formItem;e.actionMode="container"}else{Ext.layout.FormLayout.superclass.renderItem.apply(this,arguments)}}}); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns("Ext.ux.tree");Ext.ux.tree.TreeGrid=Ext.extend(Ext.tree.TreePanel,{rootVisible:false,useArrows:true,lines:false,borderWidth:Ext.isBorderBox?0:2,cls:"x-treegrid",columnResize:true,enableSort:true,reserveScrollOffset:true,enableHdMenu:true,columnsText:"Columns",initComponent:function(){if(!this.root){this.root=new Ext.tree.AsyncTreeNode({text:"Root"})}var a=this.loader;if(!a){a=new Ext.ux.tree.TreeGridLoader({dataUrl:this.dataUrl,requestMethod:this.requestMethod,store:this.store})}else{if(Ext.isObject(a)&&!a.load){a=new Ext.ux.tree.TreeGridLoader(a)}}this.loader=a;Ext.ux.tree.TreeGrid.superclass.initComponent.call(this);this.initColumns();if(this.enableSort){this.treeGridSorter=new Ext.ux.tree.TreeGridSorter(this,this.enableSort)}if(this.columnResize){this.colResizer=new Ext.tree.ColumnResizer(this.columnResize);this.colResizer.init(this)}var b=this.columns;if(!this.internalTpl){this.internalTpl=new Ext.XTemplate('
','
','
','','','','","","
','
',this.enableHdMenu?'':"",'{header}',"
","
","
","
",'
','
',"
")}if(!this.colgroupTpl){this.colgroupTpl=new Ext.XTemplate('')}},initColumns:function(){var e=this.columns,a=e.length,d=[],b,f;for(b=0;b10)){this.setScrollOffset(a)}else{var d=this;setTimeout(function(){d.setScrollOffset(e.offsetWidth-e.clientWidth>10?a:0)},10)}}},updateColumnWidths:function(){var k=this.columns,m=k.length,a=this.outerCt.query("colgroup"),l=a.length,h,e,d,b;for(d=0;d0&&this.columns[a]){this.setColumnVisible(a,!b.checked)}}return true},setColumnVisible:function(a,b){this.columns[a].hidden=!b;this.updateColumnWidths()},scrollToTop:function(){this.innerBody.dom.scrollTop=0;this.innerBody.dom.scrollLeft=0},syncScroll:function(){this.syncHeaderScroll();var a=this.innerBody.dom;this.fireEvent("bodyscroll",a.scrollLeft,a.scrollTop)},syncHeaderScroll:function(){var a=this.innerBody.dom;this.innerHd.dom.scrollLeft=a.scrollLeft;this.innerHd.dom.scrollLeft=a.scrollLeft},registerNode:function(a){Ext.ux.tree.TreeGrid.superclass.registerNode.call(this,a);if(!a.uiProvider&&!a.isRoot&&!a.ui.isTreeGridNodeUI){a.ui=new Ext.ux.tree.TreeGridNodeUI(a)}}});Ext.reg("treegrid",Ext.ux.tree.TreeGrid); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.tree.ColumnResizer=Ext.extend(Ext.util.Observable,{minWidth:14,constructor:function(a){Ext.apply(this,a);Ext.tree.ColumnResizer.superclass.constructor.call(this)},init:function(a){this.tree=a;a.on("render",this.initEvents,this)},initEvents:function(a){a.mon(a.innerHd,"mousemove",this.handleHdMove,this);this.tracker=new Ext.dd.DragTracker({onBeforeStart:this.onBeforeStart.createDelegate(this),onStart:this.onStart.createDelegate(this),onDrag:this.onDrag.createDelegate(this),onEnd:this.onEnd.createDelegate(this),tolerance:3,autoStart:300});this.tracker.initEl(a.innerHd);a.on("beforedestroy",this.tracker.destroy,this.tracker)},handleHdMove:function(f,k){var g=5,j=f.getPageX(),d=f.getTarget(".x-treegrid-hd",3,true);if(d){var b=d.getRegion(),l=d.dom.style,c=d.dom.parentNode;if(j-b.left<=g&&d.dom!==c.firstChild){var a=d.dom.previousSibling;while(a&&Ext.fly(a).hasClass("x-treegrid-hd-hidden")){a=a.previousSibling}if(a){this.activeHd=Ext.get(a);l.cursor=Ext.isWebKit?"e-resize":"col-resize"}}else{if(b.right-j<=g){var h=d.dom;while(h&&Ext.fly(h).hasClass("x-treegrid-hd-hidden")){h=h.previousSibling}if(h){this.activeHd=Ext.get(h);l.cursor=Ext.isWebKit?"w-resize":"col-resize"}}else{delete this.activeHd;l.cursor=""}}}},onBeforeStart:function(a){this.dragHd=this.activeHd;return !!this.dragHd},onStart:function(b){this.dragHeadersDisabled=this.tree.headersDisabled;this.tree.headersDisabled=true;this.proxy=this.tree.body.createChild({cls:"x-treegrid-resizer"});this.proxy.setHeight(this.tree.body.getHeight());var a=this.tracker.getXY()[0];this.hdX=this.dragHd.getX();this.hdIndex=this.tree.findHeaderIndex(this.dragHd);this.proxy.setX(this.hdX);this.proxy.setWidth(a-this.hdX);this.maxWidth=this.tree.outerCt.getWidth()-this.tree.innerBody.translatePoints(this.hdX).left},onDrag:function(b){var a=this.tracker.getXY()[0];this.proxy.setWidth((a-this.hdX).constrain(this.minWidth,this.maxWidth))},onEnd:function(d){var b=this.proxy.getWidth(),a=this.tree,c=this.dragHeadersDisabled;this.proxy.remove();delete this.dragHd;a.columns[this.hdIndex].width=b;a.updateColumnWidths();setTimeout(function(){a.headersDisabled=c},100)}}); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +(function(){Ext.override(Ext.list.Column,{init:function(){var b=Ext.data.Types,a=this.sortType;if(this.type){if(Ext.isString(this.type)){this.type=Ext.data.Types[this.type.toUpperCase()]||b.AUTO}}else{this.type=b.AUTO}if(Ext.isString(a)){this.sortType=Ext.data.SortTypes[a]}else{if(Ext.isEmpty(a)){this.sortType=this.type.sortType}}}});Ext.tree.Column=Ext.extend(Ext.list.Column,{});Ext.tree.NumberColumn=Ext.extend(Ext.list.NumberColumn,{});Ext.tree.DateColumn=Ext.extend(Ext.list.DateColumn,{});Ext.tree.BooleanColumn=Ext.extend(Ext.list.BooleanColumn,{});Ext.reg("tgcolumn",Ext.tree.Column);Ext.reg("tgnumbercolumn",Ext.tree.NumberColumn);Ext.reg("tgdatecolumn",Ext.tree.DateColumn);Ext.reg("tgbooleancolumn",Ext.tree.BooleanColumn)})(); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ux.tree.TreeGridLoader=Ext.extend(Ext.tree.TreeLoader,{createNode:function(a){if(!a.uiProvider){a.uiProvider=Ext.ux.tree.TreeGridNodeUI}return Ext.tree.TreeLoader.prototype.createNode.call(this,a)}}); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ux.tree.TreeGridNodeUI=Ext.extend(Ext.tree.TreeNodeUI,{isTreeGridNodeUI:true,renderElements:function(d,l,h,m){var o=d.getOwnerTree(),k=o.columns,j=k[0],e,b,g;this.indentMarkup=d.parentNode?d.parentNode.ui.getChildIndent():"";b=['','','','',this.indentMarkup,"",'','','",'',(j.tpl?j.tpl.apply(l):l[j.dataIndex]||j.text),"",""];for(e=1,g=k.length;e','
",(j.tpl?j.tpl.apply(l):l[j.dataIndex]),"
","")}b.push('','');for(e=0,g=k.length;e')}b.push("");if(m!==true&&d.nextSibling&&d.nextSibling.ui.getEl()){this.wrap=Ext.DomHelper.insertHtml("beforeBegin",d.nextSibling.ui.getEl(),b.join(""))}else{this.wrap=Ext.DomHelper.insertHtml("beforeEnd",h,b.join(""))}this.elNode=this.wrap.childNodes[0];this.ctNode=this.wrap.childNodes[1].firstChild.firstChild;var f=this.elNode.firstChild.childNodes;this.indentNode=f[0];this.ecNode=f[1];this.iconNode=f[2];this.anchor=f[3];this.textNode=f[3].firstChild},animExpand:function(a){this.ctNode.style.display="";Ext.ux.tree.TreeGridNodeUI.superclass.animExpand.call(this,a)}});Ext.ux.tree.TreeGridRootNodeUI=Ext.extend(Ext.tree.TreeNodeUI,{isTreeGridNodeUI:true,render:function(){if(!this.rendered){this.wrap=this.ctNode=this.node.ownerTree.innerCt.dom;this.node.expanded=true}if(Ext.isWebKit){var a=this.ctNode;a.style.tableLayout=null;(function(){a.style.tableLayout="fixed"}).defer(1)}},destroy:function(){if(this.elNode){Ext.dd.Registry.unregister(this.elNode.id)}delete this.node},collapse:Ext.emptyFn,expand:Ext.emptyFn}); +/* + * Ext.ux.tree.TreeGridNodeUIFix.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.override(Ext.ux.tree.TreeGridNodeUI,{updateColumns:function(){if(!this.rendered){return}var b=this.node.attributes,d=this.node.getOwnerTree(),e=d.columns,f=e[0];this.anchor.firstChild.innerHTML=(f.tpl?f.tpl.apply(b):b[f.dataIndex]||f.text);for(i=1,len=e.length;iv2){return j?-1:+1}else{return 0}}};a.on("afterrender",this.onAfterTreeRender,this,{single:true});a.on("headermenuclick",this.onHeaderMenuClick,this)},onAfterTreeRender:function(){if(this.tree.hmenu){this.tree.hmenu.insert(0,{itemId:"asc",text:this.sortAscText,cls:"xg-hmenu-sort-asc"},{itemId:"desc",text:this.sortDescText,cls:"xg-hmenu-sort-desc"})}this.updateSortIcon(0,"asc")},onHeaderMenuClick:function(d,b,a){if(b==="asc"||b==="desc"){this.onHeaderClick(d,null,a);return false}},onHeaderClick:function(e,b,a){if(e&&!this.tree.headersDisabled){var d=this;d.property=e.dataIndex;d.dir=e.dir=(e.dir==="desc"?"asc":"desc");d.sortType=e.sortType;d.caseSensitive===Ext.isBoolean(e.caseSensitive)?e.caseSensitive:this.caseSensitive;d.sortFn=e.sortFn||this.defaultSortFn;this.tree.root.cascade(function(c){if(!c.isLeaf()){d.updateSort(d.tree,c)}});this.updateSortIcon(a,e.dir)}},updateSortIcon:function(b,a){var d=this.sortClasses,c=this.tree.innerHd.select("td").removeClass(d);c.item(b).addClass(d[a=="desc"?1:0])}}); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns("Ext.ux.grid");Ext.ux.grid.BufferView=Ext.extend(Ext.grid.GridView,{rowHeight:19,borderHeight:2,scrollDelay:100,cacheSize:20,cleanDelay:500,initTemplates:function(){Ext.ux.grid.BufferView.superclass.initTemplates.call(this);var a=this.templates;a.rowHolder=new Ext.Template('
');a.rowHolder.disableFormats=true;a.rowHolder.compile();a.rowBody=new Ext.Template('',"{cells}",(this.enableRowBody?'':""),"
{body}
");a.rowBody.disableFormats=true;a.rowBody.compile()},getStyleRowHeight:function(){return Ext.isBorderBox?(this.rowHeight+this.borderHeight):this.rowHeight},getCalculatedRowHeight:function(){return this.rowHeight+this.borderHeight},getVisibleRowCount:function(){var b=this.getCalculatedRowHeight(),a=this.scroller.dom.clientHeight;return(a<1)?0:Math.ceil(a/b)},getVisibleRows:function(){var a=this.getVisibleRowCount(),b=this.scroller.dom.scrollTop,c=(b===0?0:Math.floor(b/this.getCalculatedRowHeight())-1);return{first:Math.max(c,0),last:Math.min(c+a+2,this.ds.getCount()-1)}},doRender:function(g,k,u,a,s,A,l){var b=this.templates,f=b.cell,h=b.row,x=b.rowBody,n=s-1,t=this.getStyleRowHeight(),z=this.getVisibleRows(),d="width:"+this.getTotalWidth()+";height:"+t+"px;",D=[],w,E,v={},m={tstyle:d},q;for(var y=0,C=k.length;y=z.first&&o<=z.last;if(e){for(var B=0;B0},syncScroll:function(){Ext.ux.grid.BufferView.superclass.syncScroll.apply(this,arguments);this.update()},update:function(){if(this.scrollDelay){if(!this.renderTask){this.renderTask=new Ext.util.DelayedTask(this.doUpdate,this)}this.renderTask.delay(this.scrollDelay)}else{this.doUpdate()}},onRemove:function(d,a,b,c){Ext.ux.grid.BufferView.superclass.onRemove.apply(this,arguments);if(c!==true){this.update()}},doUpdate:function(){if(this.getVisibleRowCount()>0){var f=this.grid,b=f.colModel,h=f.store,e=this.getColumnData(),a=this.getVisibleRows(),j;for(var d=a.first;d<=a.last;d++){if(!this.isRowRendered(d)&&(j=this.getRow(d))){var c=this.doRender(e,[h.getAt(d)],h,d,b.getColumnCount(),f.stripeRows,true);j.innerHTML=c}}this.clean()}},clean:function(){if(!this.cleanTask){this.cleanTask=new Ext.util.DelayedTask(this.doClean,this)}this.cleanTask.delay(this.cleanDelay)},doClean:function(){if(this.getVisibleRowCount()>0){var b=this.getVisibleRows();b.first-=this.cacheSize;b.last+=this.cacheSize;var c=0,d=this.getRows();if(b.first<=0){c=b.last+1}for(var a=this.ds.getCount();cb.last)&&d[c].innerHTML){d[c].innerHTML=""}}}},removeTask:function(b){var a=this[b];if(a&&a.cancel){a.cancel();this[b]=null}},destroy:function(){this.removeTask("cleanTask");this.removeTask("renderTask");Ext.ux.grid.BufferView.superclass.destroy.call(this)},layout:function(){Ext.ux.grid.BufferView.superclass.layout.call(this);this.update()}}); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns("Ext.ux.form");Ext.ux.form.FileUploadField=Ext.extend(Ext.form.TextField,{buttonText:"Browse...",buttonOnly:false,buttonOffset:3,readOnly:true,autoSize:Ext.emptyFn,initComponent:function(){Ext.ux.form.FileUploadField.superclass.initComponent.call(this);this.addEvents("fileselected")},onRender:function(c,a){Ext.ux.form.FileUploadField.superclass.onRender.call(this,c,a);this.wrap=this.el.wrap({cls:"x-form-field-wrap x-form-file-wrap"});this.el.addClass("x-form-file-text");this.el.dom.removeAttribute("name");this.createFileInput();var b=Ext.applyIf(this.buttonCfg||{},{text:this.buttonText});this.button=new Ext.Button(Ext.apply(b,{renderTo:this.wrap,cls:"x-form-file-btn"+(b.iconCls?" x-btn-icon":"")}));if(this.buttonOnly){this.el.hide();this.wrap.setWidth(this.button.getEl().getWidth())}this.bindListeners();this.resizeEl=this.positionEl=this.wrap},bindListeners:function(){this.fileInput.on({scope:this,mouseenter:function(){this.button.addClass(["x-btn-over","x-btn-focus"])},mouseleave:function(){this.button.removeClass(["x-btn-over","x-btn-focus","x-btn-click"])},mousedown:function(){this.button.addClass("x-btn-click")},mouseup:function(){this.button.removeClass(["x-btn-over","x-btn-focus","x-btn-click"])},change:function(){var a=this.fileInput.dom.value;this.setValue(a);this.fireEvent("fileselected",this,a)}})},createFileInput:function(){this.fileInput=this.wrap.createChild({id:this.getFileInputId(),name:this.name||this.getId(),cls:"x-form-file",tag:"input",type:"file",size:1})},reset:function(){if(this.rendered){this.fileInput.remove();this.createFileInput();this.bindListeners()}Ext.ux.form.FileUploadField.superclass.reset.call(this)},getFileInputId:function(){return this.id+"-file"},onResize:function(a,b){Ext.ux.form.FileUploadField.superclass.onResize.call(this,a,b);this.wrap.setWidth(a);if(!this.buttonOnly){var a=this.wrap.getWidth()-this.button.getEl().getWidth()-this.buttonOffset;this.el.setWidth(a)}},onDestroy:function(){Ext.ux.form.FileUploadField.superclass.onDestroy.call(this);Ext.destroy(this.fileInput,this.button,this.wrap)},onDisable:function(){Ext.ux.form.FileUploadField.superclass.onDisable.call(this);this.doDisable(true)},onEnable:function(){Ext.ux.form.FileUploadField.superclass.onEnable.call(this);this.doDisable(false)},doDisable:function(a){this.fileInput.dom.disabled=a;this.button.setDisabled(a)},preFocus:Ext.emptyFn,alignErrorIcon:function(){this.errorIcon.alignTo(this.wrap,"tl-tr",[2,0])}});Ext.reg("fileuploadfield",Ext.ux.form.FileUploadField);Ext.form.FileUploadField=Ext.ux.form.FileUploadField; +/* + * Ext.ux.form.RadioGroup.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.override(Ext.form.RadioGroup,{afterRender:function(){this.items.each(function(a){this.relayEvents(a,["check"])},this);if(this.lazyValue){this.setValue(this.value);delete this.value;delete this.lazyValue}Ext.form.RadioGroup.superclass.afterRender.call(this)},getName:function(){return this.items.first().getName()},getValue:function(){return this.items.first().getGroupValue()},setValue:function(a){if(!this.items.each){this.value=a;this.lazyValue=true;return}this.items.each(function(c){if(c.rendered){var b=(c.el.getValue()==String(a));c.el.dom.checked=b;c.el.dom.defaultChecked=b;c.wrap[b?"addClass":"removeClass"](c.checkedCls)}})}}); +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ns("Ext.ux.form");Ext.ux.form.SpinnerField=Ext.extend(Ext.form.NumberField,{actionMode:"wrap",deferHeight:true,autoSize:Ext.emptyFn,onBlur:Ext.emptyFn,adjustSize:Ext.BoxComponent.prototype.adjustSize,constructor:function(c){var b=Ext.copyTo({},c,"incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass");var d=this.spinner=new Ext.ux.Spinner(b);var a=c.plugins?(Ext.isArray(c.plugins)?c.plugins.push(d):[c.plugins,d]):d;Ext.ux.form.SpinnerField.superclass.constructor.call(this,Ext.apply(c,{plugins:a}))},getResizeEl:function(){return this.wrap},getPositionEl:function(){return this.wrap},alignErrorIcon:function(){if(this.wrap){this.errorIcon.alignTo(this.wrap,"tl-tr",[2,0])}},validateBlur:function(){return true}});Ext.reg("spinnerfield",Ext.ux.form.SpinnerField);Ext.form.SpinnerField=Ext.ux.form.SpinnerField; +/* + * Ext.ux.form.SpinnerField.js + * + * Copyright (c) Damien Churchill 2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.override(Ext.ux.form.SpinnerField,{onBlur:Ext.form.Field.prototype.onBlur}); +/* + * Ext.ux.form.SpinnerGroup.js + * + * Copyright (c) Damien Churchill 2009-2010 + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.ns("Ext.ux.form");Ext.ux.form.SpinnerGroup=Ext.extend(Ext.form.CheckboxGroup,{defaultType:"spinnerfield",anchor:"98%",groupCls:"x-form-spinner-group",colCfg:{},onRender:function(h,f){if(!this.el){var o={cls:this.groupCls,layout:"column",border:false,renderTo:h};var a=Ext.apply({defaultType:this.defaultType,layout:"form",border:false,labelWidth:60,defaults:{hideLabel:true,anchor:"60%"}},this.colCfg);if(this.items[0].items){Ext.apply(o,{layoutConfig:{columns:this.items.length},defaults:this.defaults,items:this.items});for(var e=0,k=this.items.length;e0&&e%q==0){n++}if(this.items[e].fieldLabel){this.items[e].hideLabel=false}m[n].items.push(this.items[e])}}else{for(var e=0,k=this.items.length;e + * + * 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 3, 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, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + * + * In addition, as a special exception, the copyright holders give + * permission to link the code of portions of this program with the OpenSSL + * library. + * You must obey the GNU General Public License in all respects for all of + * the code used other than OpenSSL. If you modify file(s) with this + * exception, you may extend this exception to your version of the file(s), + * but you are not obligated to do so. If you do not wish to do so, delete + * this exception statement from your version. If you delete this exception + * statement from all source files in the program, then also delete it here. + */ +Ext.namespace("Ext.ux.form");Ext.ux.form.ToggleField=Ext.extend(Ext.form.Field,{cls:"x-toggle-field",initComponent:function(){Ext.ux.form.ToggleField.superclass.initComponent.call(this);this.toggle=new Ext.form.Checkbox();this.toggle.on("check",this.onToggleCheck,this);this.input=new Ext.form.TextField({disabled:true})},onRender:function(b,a){if(!this.el){this.panel=new Ext.Panel({cls:this.groupCls,layout:"table",layoutConfig:{columns:2},border:false,renderTo:b});this.panel.ownerCt=this;this.el=this.panel.getEl();this.panel.add(this.toggle);this.panel.add(this.input);this.panel.doLayout();this.toggle.getEl().parent().setStyle("padding-right","10px")}Ext.ux.form.ToggleField.superclass.onRender.call(this,b,a)},onResize:function(a,b){this.panel.setSize(a,b);this.panel.doLayout();var c=a-this.toggle.getSize().width-25;this.input.setSize(c,b)},onToggleCheck:function(a,b){this.input.setDisabled(!b)}});Ext.reg("togglefield",Ext.ux.form.ToggleField);Ext.ux.JSLoader=function(options){Ext.ux.JSLoader.scripts[++Ext.ux.JSLoader.index]={url:options.url,success:true,jsLoadObj:null,options:options,onLoad:options.onLoad||Ext.emptyFn,onError:options.onError||Ext.ux.JSLoader.stdError,scope:options.scope||this};Ext.Ajax.request({url:options.url,scriptIndex:Ext.ux.JSLoader.index,success:function(response,options){var script=Ext.ux.JSLoader.scripts[options.scriptIndex];try{eval(response.responseText)}catch(e){script.success=false;script.onError(script.options,e)}if(script.success){script.onLoad.call(script.scope,script.options)}},failure:function(response,options){var script=Ext.ux.JSLoader.scripts[options.scriptIndex];script.success=false;script.onError(script.options,response.status)}})};Ext.ux.JSLoader.index=0;Ext.ux.JSLoader.scripts=[];Ext.ux.JSLoader.stdError=function(a,b){window.alert("Error loading script:\n\n"+a.url+"\n\nstatus: "+b)} +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +;Ext.ux.Spinner=Ext.extend(Ext.util.Observable,{incrementValue:1,alternateIncrementValue:5,triggerClass:"x-form-spinner-trigger",splitterClass:"x-form-spinner-splitter",alternateKey:Ext.EventObject.shiftKey,defaultValue:0,accelerate:false,constructor:function(a){Ext.ux.Spinner.superclass.constructor.call(this,a);Ext.apply(this,a);this.mimicing=false},init:function(a){this.field=a;a.afterMethod("onRender",this.doRender,this);a.afterMethod("onEnable",this.doEnable,this);a.afterMethod("onDisable",this.doDisable,this);a.afterMethod("afterRender",this.doAfterRender,this);a.afterMethod("onResize",this.doResize,this);a.afterMethod("onFocus",this.doFocus,this);a.beforeMethod("onDestroy",this.doDestroy,this)},doRender:function(b,a){var c=this.el=this.field.getEl();var d=this.field;if(!d.wrap){d.wrap=this.wrap=c.wrap({cls:"x-form-field-wrap"})}else{this.wrap=d.wrap.addClass("x-form-field-wrap")}this.trigger=this.wrap.createChild({tag:"img",src:Ext.BLANK_IMAGE_URL,cls:"x-form-trigger "+this.triggerClass});if(!d.width){this.wrap.setWidth(c.getWidth()+this.trigger.getWidth())}this.splitter=this.wrap.createChild({tag:"div",cls:this.splitterClass,style:"width:13px; height:2px;"});this.splitter.setRight((Ext.isIE)?1:2).setTop(10).show();this.proxy=this.trigger.createProxy("",this.splitter,true);this.proxy.addClass("x-form-spinner-proxy");this.proxy.setStyle("left","0px");this.proxy.setSize(14,1);this.proxy.hide();this.dd=new Ext.dd.DDProxy(this.splitter.dom.id,"SpinnerDrag",{dragElId:this.proxy.id});this.initTrigger();this.initSpinner()},doAfterRender:function(){var a;if(Ext.isIE&&this.el.getY()!=(a=this.trigger.getY())){this.el.position();this.el.setY(a)}},doEnable:function(){if(this.wrap){this.disabled=false;this.wrap.removeClass(this.field.disabledClass)}},doDisable:function(){if(this.wrap){this.disabled=true;this.wrap.addClass(this.field.disabledClass);this.el.removeClass(this.field.disabledClass)}},doResize:function(a,b){if(typeof a=="number"){this.el.setWidth(a-this.trigger.getWidth())}this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth())},doFocus:function(){if(!this.mimicing){this.wrap.addClass("x-trigger-wrap-focus");this.mimicing=true;Ext.get(Ext.isIE?document.body:document).on("mousedown",this.mimicBlur,this,{delay:10});this.el.on("keydown",this.checkTab,this)}},checkTab:function(a){if(a.getKey()==a.TAB){this.triggerBlur()}},mimicBlur:function(a){if(!this.wrap.contains(a.target)&&this.field.validateBlur(a)){this.triggerBlur()}},triggerBlur:function(){this.mimicing=false;Ext.get(Ext.isIE?document.body:document).un("mousedown",this.mimicBlur,this);this.el.un("keydown",this.checkTab,this);this.field.beforeBlur();this.wrap.removeClass("x-trigger-wrap-focus");this.field.onBlur.call(this.field)},initTrigger:function(){this.trigger.addClassOnOver("x-form-trigger-over");this.trigger.addClassOnClick("x-form-trigger-click")},initSpinner:function(){this.field.addEvents({spin:true,spinup:true,spindown:true});this.keyNav=new Ext.KeyNav(this.el,{up:function(a){a.preventDefault();this.onSpinUp()},down:function(a){a.preventDefault();this.onSpinDown()},pageUp:function(a){a.preventDefault();this.onSpinUpAlternate()},pageDown:function(a){a.preventDefault();this.onSpinDownAlternate()},scope:this});this.repeater=new Ext.util.ClickRepeater(this.trigger,{accelerate:this.accelerate});this.field.mon(this.repeater,"click",this.onTriggerClick,this,{preventDefault:true});this.field.mon(this.trigger,{mouseover:this.onMouseOver,mouseout:this.onMouseOut,mousemove:this.onMouseMove,mousedown:this.onMouseDown,mouseup:this.onMouseUp,scope:this,preventDefault:true});this.field.mon(this.wrap,"mousewheel",this.handleMouseWheel,this);this.dd.setXConstraint(0,0,10);this.dd.setYConstraint(1500,1500,10);this.dd.endDrag=this.endDrag.createDelegate(this);this.dd.startDrag=this.startDrag.createDelegate(this);this.dd.onDrag=this.onDrag.createDelegate(this)},onMouseOver:function(){if(this.disabled){return}var a=this.getMiddle();this.tmpHoverClass=(Ext.EventObject.getPageY()a)&&this.tmpHoverClass=="x-form-spinner-overup")||((Ext.EventObject.getPageY()0){this.onSpinUp();a.stopEvent()}else{if(b<0){this.onSpinDown();a.stopEvent()}}},startDrag:function(){this.proxy.show();this._previousY=Ext.fly(this.dd.getDragEl()).getTop()},endDrag:function(){this.proxy.hide()},onDrag:function(){if(this.disabled){return}var b=Ext.fly(this.dd.getDragEl()).getTop();var a="";if(this._previousY>b){a="Up"}if(this._previousYthis.field.maxValue){a=this.field.maxValue}return this.fixPrecision(a)},fixPrecision:function(b){var a=isNaN(b);if(!this.field.allowDecimals||this.field.decimalPrecision==-1||a||!b){return a?"":b}return parseFloat(parseFloat(b).toFixed(this.field.decimalPrecision))},doDestroy:function(){if(this.trigger){this.trigger.remove()}if(this.wrap){this.wrap.remove();delete this.field.wrap}if(this.splitter){this.splitter.remove()}if(this.dd){this.dd.unreg();this.dd=null}if(this.proxy){this.proxy.remove()}if(this.repeater){this.repeater.purgeListeners()}if(this.mimicing){Ext.get(Ext.isIE?document.body:document).un("mousedown",this.mimicBlur,this)}}});Ext.form.Spinner=Ext.ux.Spinner; +/* + * Ext JS Library 3.4.0 + * Copyright(c) 2006-2011 Sencha Inc. + * licensing@sencha.com + * http://www.sencha.com/license + */ +Ext.ux.StatusBar=Ext.extend(Ext.Toolbar,{cls:"x-statusbar",busyIconCls:"x-status-busy",busyText:"Loading...",autoClear:5000,emptyText:" ",activeThreadId:0,initComponent:function(){if(this.statusAlign=="right"){this.cls+=" x-status-right"}Ext.ux.StatusBar.superclass.initComponent.call(this)},afterRender:function(){Ext.ux.StatusBar.superclass.afterRender.call(this);var a=this.statusAlign=="right";this.currIconCls=this.iconCls||this.defaultIconCls;this.statusEl=new Ext.Toolbar.TextItem({cls:"x-status-text "+(this.currIconCls||""),text:this.text||this.defaultText||""});if(a){this.add("->");this.add(this.statusEl)}else{this.insert(0,this.statusEl);this.insert(1,"->")}this.doLayout()},setStatus:function(d){d=d||{};if(typeof d=="string"){d={text:d}}if(d.text!==undefined){this.setText(d.text)}if(d.iconCls!==undefined){this.setIcon(d.iconCls)}if(d.clear){var e=d.clear,b=this.autoClear,a={useDefaults:true,anim:true};if(typeof e=="object"){e=Ext.applyIf(e,a);if(e.wait){b=e.wait}}else{if(typeof e=="number"){b=e;e=a}else{if(typeof e=="boolean"){e=a}}}e.threadId=this.activeThreadId;this.clearStatus.defer(b,this,[e])}return this},clearStatus:function(c){c=c||{};if(c.threadId&&c.threadId!==this.activeThreadId){return this}var b=c.useDefaults?this.defaultText:this.emptyText,a=c.useDefaults?(this.defaultIconCls?this.defaultIconCls:""):"";if(c.anim){this.statusEl.el.fadeOut({remove:false,useDisplay:true,scope:this,callback:function(){this.setStatus({text:b,iconCls:a});this.statusEl.el.show()}})}else{this.statusEl.hide();this.setStatus({text:b,iconCls:a});this.statusEl.show()}return this},setText:function(a){this.activeThreadId++;this.text=a||"";if(this.rendered){this.statusEl.setText(this.text)}return this},getText:function(){return this.text},setIcon:function(a){this.activeThreadId++;a=a||"";if(this.rendered){if(this.currIconCls){this.statusEl.removeClass(this.currIconCls);this.currIconCls=null}if(a.length>0){this.statusEl.addClass(a);this.currIconCls=a}}else{this.currIconCls=a}return this},showBusy:function(a){if(typeof a=="string"){a={text:a}}a=Ext.applyIf(a||{},{text:this.busyText,iconCls:this.busyIconCls});return this.setStatus(a)}});Ext.reg("statusbar",Ext.ux.StatusBar); \ No newline at end of file diff --git a/deluge/ui/web/js/ext-extensions/.build b/deluge/ui/web/js/extjs/ext-extensions/.build similarity index 100% rename from deluge/ui/web/js/ext-extensions/.build rename to deluge/ui/web/js/extjs/ext-extensions/.build diff --git a/deluge/ui/web/js/ext-extensions/JSLoader.js b/deluge/ui/web/js/extjs/ext-extensions/JSLoader.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/JSLoader.js rename to deluge/ui/web/js/extjs/ext-extensions/JSLoader.js diff --git a/deluge/ui/web/js/ext-extensions/Spinner.js b/deluge/ui/web/js/extjs/ext-extensions/Spinner.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/Spinner.js rename to deluge/ui/web/js/extjs/ext-extensions/Spinner.js diff --git a/deluge/ui/web/js/ext-extensions/StatusBar.js b/deluge/ui/web/js/extjs/ext-extensions/StatusBar.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/StatusBar.js rename to deluge/ui/web/js/extjs/ext-extensions/StatusBar.js diff --git a/deluge/ui/web/js/ext-extensions/form/FileUploadField.js b/deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/form/FileUploadField.js rename to deluge/ui/web/js/extjs/ext-extensions/form/FileUploadField.js diff --git a/deluge/ui/web/js/ext-extensions/form/RadioGroupFix.js b/deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/form/RadioGroupFix.js rename to deluge/ui/web/js/extjs/ext-extensions/form/RadioGroupFix.js diff --git a/deluge/ui/web/js/ext-extensions/form/SpinnerField.js b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/form/SpinnerField.js rename to deluge/ui/web/js/extjs/ext-extensions/form/SpinnerField.js diff --git a/deluge/ui/web/js/ext-extensions/form/SpinnerFieldFix.js b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerFieldFix.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/form/SpinnerFieldFix.js rename to deluge/ui/web/js/extjs/ext-extensions/form/SpinnerFieldFix.js diff --git a/deluge/ui/web/js/ext-extensions/form/SpinnerGroup.js b/deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/form/SpinnerGroup.js rename to deluge/ui/web/js/extjs/ext-extensions/form/SpinnerGroup.js diff --git a/deluge/ui/web/js/ext-extensions/form/ToggleField.js b/deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/form/ToggleField.js rename to deluge/ui/web/js/extjs/ext-extensions/form/ToggleField.js diff --git a/deluge/ui/web/js/ext-extensions/grid/BufferView.js b/deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/grid/BufferView.js rename to deluge/ui/web/js/extjs/ext-extensions/grid/BufferView.js diff --git a/deluge/ui/web/js/ext-extensions/layout/FormLayoutFix.js b/deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/layout/FormLayoutFix.js rename to deluge/ui/web/js/extjs/ext-extensions/layout/FormLayoutFix.js diff --git a/deluge/ui/web/js/ext-extensions/tree/MultiSelectionModelFix.js b/deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/MultiSelectionModelFix.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/MultiSelectionModelFix.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGrid.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGrid.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGrid.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridColumnResizer.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridColumnResizer.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumnResizer.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridColumns.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridColumns.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridColumns.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridLoader.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridLoader.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridLoader.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridNodeUI.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridNodeUI.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUI.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridNodeUIFix.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridNodeUIFix.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridNodeUIFix.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridRenderColumn.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridRenderColumn.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridRenderColumn.js diff --git a/deluge/ui/web/js/ext-extensions/tree/TreeGridSorter.js b/deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js similarity index 100% rename from deluge/ui/web/js/ext-extensions/tree/TreeGridSorter.js rename to deluge/ui/web/js/extjs/ext-extensions/tree/TreeGridSorter.js diff --git a/deluge/ui/web/server.py b/deluge/ui/web/server.py index 7f1b211fe..2f2a13003 100644 --- a/deluge/ui/web/server.py +++ b/deluge/ui/web/server.py @@ -442,21 +442,21 @@ class TopLevel(resource.Resource): js = ScriptResource() # configure the dev scripts - js.add_script("ext-base-debug.js", rpath("js", "ext-base-debug.js"), "dev") - js.add_script("ext-all-debug.js", rpath("js", "ext-all-debug.js"), "dev") - js.add_script_folder("ext-extensions", rpath("js", "ext-extensions"), "dev") + js.add_script("ext-base-debug.js", rpath("js", "extjs", "ext-base-debug.js"), "dev") + js.add_script("ext-all-debug.js", rpath("js", "extjs", "ext-all-debug.js"), "dev") + js.add_script_folder("ext-extensions", rpath("js", "extjs", "ext-extensions"), "dev") js.add_script_folder("deluge-all", rpath("js", "deluge-all"), "dev") # configure the debug scripts - js.add_script("ext-base-debug.js", rpath("js", "ext-base-debug.js"), "debug") - js.add_script("ext-all-debug.js", rpath("js", "ext-all-debug.js"), "debug") - js.add_script("ext-extensions-debug.js", rpath("js", "ext-extensions-debug.js"), "debug") + js.add_script("ext-base-debug.js", rpath("js", "extjs", "ext-base-debug.js"), "debug") + js.add_script("ext-all-debug.js", rpath("js", "extjs", "ext-all-debug.js"), "debug") + js.add_script("ext-extensions-debug.js", rpath("js", "extjs", "ext-extensions-debug.js"), "debug") js.add_script("deluge-all-debug.js", rpath("js", "deluge-all-debug.js"), "debug") # configure the normal scripts - js.add_script("ext-base.js", rpath("js", "ext-base.js")) - js.add_script("ext-all.js", rpath("js", "ext-all.js")) - js.add_script("ext-extensions.js", rpath("js", "ext-extensions.js")) + js.add_script("ext-base.js", rpath("js", "extjs", "ext-base.js")) + js.add_script("ext-all.js", rpath("js", "extjs", "ext-all.js")) + js.add_script("ext-extensions.js", rpath("js", "extjs", "ext-extensions.js")) js.add_script("deluge-all.js", rpath("js", "deluge-all.js")) self.putChild("js", js)