/*! * 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', // 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);