Ext.namespace('MODx.grid'); MODx.grid.Grid = function(config) { config = config || {}; this.config = config; this._loadStore(); this._loadColumnModel(); Ext.applyIf(config,{ store: this.store ,cm: this.cm ,sm: new Ext.grid.RowSelectionModel({singleSelect:true}) ,paging: (config.bbar ? true : false) ,loadMask: true ,autoHeight: true ,collapsible: true ,stripeRows: true ,header: false ,cls: 'modx-grid' ,preventRender: true ,preventSaveRefresh: true ,showPerPage: true ,stateful: false ,menuConfig: { defaultAlign: 'tl-b?' ,enableScrolling: false } ,viewConfig: { forceFit: true ,enableRowBody: true ,autoFill: true ,showPreview: true ,scrollOffset: 0 ,emptyText: config.emptyText || _('ext_emptymsg') } ,groupingConfig: { enableGroupingMenu: true } }); if (config.paging) { var pgItms = config.showPerPage ? [_('per_page')+':',{ xtype: 'textfield' ,cls: 'x-tbar-page-size' ,value: config.pageSize || (parseInt(MODx.config.default_per_page) || 20) ,listeners: { 'change': {fn:this.onChangePerPage,scope:this} ,'render': {fn: function(cmp) { new Ext.KeyMap(cmp.getEl(), { key: Ext.EventObject.ENTER ,fn: this.blur ,scope: cmp }); },scope:this} } }] : []; if (config.pagingItems) { for (var i=0;i 1 ? "' + (config.pluralText || _('records')) + '" : "' + (config.singleText || _('record')) + '"]})' }; Ext.applyIf(config.groupingConfig, groupingConfig); Ext.applyIf(config,{ view: new Ext.grid.GroupingView(config.groupingConfig) }); } if (config.tbar) { for (var ix = 0;ix' : '') + data.msg; }, this); } if (Ext.isEmpty(msg)) { // Still no valid message so far, let's use some fallback msg = this.autosaveErrorMsg || _('error'); } MODx.msg.alert(_('error'), msg); } } ,onChangePerPage: function(tf,nv) { if (Ext.isEmpty(nv)) return false; nv = parseInt(nv); this.getBottomToolbar().pageSize = nv; this.store.load({params:{ start:0 ,limit: nv }}); } ,loadWindow: function(btn,e,win,or) { var r = this.menu.record; if (!this.windows[win.xtype] || win.force) { Ext.applyIf(win,{ record: win.blankValues ? {} : r ,grid: this ,listeners: { 'success': {fn:win.success || this.refresh,scope:win.scope || this} } }); if (or) { Ext.apply(win,or); } this.windows[win.xtype] = Ext.ComponentMgr.create(win); } if (this.windows[win.xtype].setValues && win.blankValues !== true && r != undefined) { this.windows[win.xtype].setValues(r); } this.windows[win.xtype].show(e.target); } ,confirm: function(type,text) { var p = { action: type }; var k = this.config.primaryKey || 'id'; p[k] = this.menu.record[k]; MODx.msg.confirm({ title: _(type) ,text: _(text) || _('confirm_remove') ,url: this.config.url ,params: p ,listeners: { 'success': {fn:this.refresh,scope:this} } }); } ,remove: function(text, action) { if (this.destroying) { return MODx.grid.Grid.superclass.remove.apply(this, arguments); } var r = this.menu.record; text = text || 'confirm_remove'; var p = this.config.saveParams || {}; Ext.apply(p,{ action: action || 'remove' }); //console.log(action, p); var k = this.config.primaryKey || 'id'; p[k] = r[k]; if (this.fireEvent('beforeRemoveRow',r)) { MODx.msg.confirm({ title: _('warning') ,text: _(text, r) ,url: this.config.url ,params: p ,listeners: { 'success': {fn:function() { this.removeActiveRow(r); },scope:this} } }); } } ,removeActiveRow: function(r) { if (this.fireEvent('afterRemoveRow',r)) { var rx = this.getSelectionModel().getSelected(); this.getStore().remove(rx); } } ,_loadMenu: function() { this.menu = new Ext.menu.Menu(this.config.menuConfig); } ,_showMenu: function(g,ri,e) { e.stopEvent(); e.preventDefault(); this.menu.record = this.getStore().getAt(ri).data; if (!this.getSelectionModel().isSelected(ri)) { this.getSelectionModel().selectRow(ri); } this.menu.removeAll(); if (this.getMenu) { var m = this.getMenu(g,ri,e); if (m && m.length && m.length > 0) { this.addContextMenuItem(m); } } if ((!m || m.length <= 0) && this.menu.record.menu) { this.addContextMenuItem(this.menu.record.menu); } if (this.menu.items.length > 0) { this.menu.showAt(e.xy); } } ,_loadStore: function() { if (this.config.grouping) { this.store = new Ext.data.GroupingStore({ url: this.config.url ,baseParams: this.config.baseParams || { action: this.config.action || 'getList'} ,reader: new Ext.data.JsonReader({ totalProperty: 'total' ,root: 'results' ,fields: this.config.fields }) ,sortInfo:{ field: this.config.sortBy || 'id' ,direction: this.config.sortDir || 'ASC' } ,remoteSort: this.config.remoteSort || false ,groupField: this.config.groupBy || 'name' ,storeId: this.config.storeId || Ext.id() ,autoDestroy: true ,listeners:{ load: function(){ var cmp = Ext.getCmp('modx-content'); if(typeof cmp !== "undefined") { cmp.doLayout(); /* Fix layout bug with absolute positioning */ } } } }); } else { this.store = new Ext.data.JsonStore({ url: this.config.url ,baseParams: this.config.baseParams || { action: this.config.action || 'getList' } ,fields: this.config.fields ,root: 'results' ,totalProperty: 'total' ,remoteSort: this.config.remoteSort || false ,storeId: this.config.storeId || Ext.id() ,autoDestroy: true ,listeners:{ load: function(){ var cmp = Ext.getCmp('modx-content'); if(typeof cmp !== "undefined") { cmp.doLayout(); /* Fix layout bug with absolute positioning */ } } } }); } } ,_loadColumnModel: function() { if (this.config.columns) { var c = this.config.columns; for (var i=0;i 1 ? "' +(config.pluralText || _('records')) + '" : "' +(config.singleText || _('record'))+'"]})' ) }) }); } if (config.tbar) { for (var i = 0;itrue to toggle selected row(s) between expanded/collapsed when the enter * key is pressed (defaults to true). */ expandOnEnter : true, /** * @cfg {Boolean} expandOnDblClick * true to toggle a row between expanded/collapsed when double clicked * (defaults to true). */ expandOnDblClick : true, header : '', width : 20, sortable : false, fixed : true, hideable: false, menuDisabled : true, dataIndex : '', id : 'expander', lazyRender : true, enableCaching : true, constructor: function(config){ Ext.apply(this, config); this.addEvents({ /** * @event beforeexpand * Fires before the row expands. Have the listener return false to prevent the row from expanding. * @param {Object} this RowExpander object. * @param {Object} Ext.data.Record Record for the selected row. * @param {Object} body body element for the secondary row. * @param {Number} rowIndex The current row index. */ beforeexpand: true, /** * @event expand * Fires after the row expands. * @param {Object} this RowExpander object. * @param {Object} Ext.data.Record Record for the selected row. * @param {Object} body body element for the secondary row. * @param {Number} rowIndex The current row index. */ expand: true, /** * @event beforecollapse * Fires before the row collapses. Have the listener return false to prevent the row from collapsing. * @param {Object} this RowExpander object. * @param {Object} Ext.data.Record Record for the selected row. * @param {Object} body body element for the secondary row. * @param {Number} rowIndex The current row index. */ beforecollapse: true, /** * @event collapse * Fires after the row collapses. * @param {Object} this RowExpander object. * @param {Object} Ext.data.Record Record for the selected row. * @param {Object} body body element for the secondary row. * @param {Number} rowIndex The current row index. */ collapse: true }); Ext.ux.grid.RowExpander.superclass.constructor.call(this); if(this.tpl){ if(typeof this.tpl == 'string'){ this.tpl = new Ext.Template(this.tpl); } this.tpl.compile(); } this.state = {}; this.bodyContent = {}; }, getRowClass : function(record, rowIndex, p, ds){ p.cols = p.cols-1; var content = this.bodyContent[record.id]; if(!content && !this.lazyRender){ content = this.getBodyContent(record, rowIndex); } if(content){ p.body = content; } return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed'; }, init : function(grid){ this.grid = grid; var view = grid.getView(); view.getRowClass = this.getRowClass.createDelegate(this); view.enableRowBody = true; grid.on('render', this.onRender, this); grid.on('destroy', this.onDestroy, this); }, // @private onRender: function() { var grid = this.grid; var mainBody = grid.getView().mainBody; mainBody.on('mousedown', this.onMouseDown, this, {delegate: '.x-grid3-row-expander'}); if (this.expandOnEnter) { this.keyNav = new Ext.KeyNav(this.grid.getGridEl(), { 'enter' : this.onEnter, scope: this }); } if (this.expandOnDblClick) { grid.on('rowdblclick', this.onRowDblClick, this); } }, // @private onDestroy: function() { if(this.keyNav){ this.keyNav.disable(); delete this.keyNav; } /* * A majority of the time, the plugin will be destroyed along with the grid, * which means the mainBody won't be available. On the off chance that the plugin * isn't destroyed with the grid, take care of removing the listener. */ var mainBody = this.grid.getView().mainBody; if(mainBody){ mainBody.un('mousedown', this.onMouseDown, this); } }, // @private onRowDblClick: function(grid, rowIdx, e) { this.toggleRow(rowIdx); }, onEnter: function(e) { var g = this.grid; var sm = g.getSelectionModel(); var sels = sm.getSelections(); for (var i = 0, len = sels.length; i < len; i++) { var rowIdx = g.getStore().indexOf(sels[i]); this.toggleRow(rowIdx); } }, getBodyContent : function(record, index){ if(!this.enableCaching){ return this.tpl.apply(record.data); } var content = this.bodyContent[record.id]; if(!content){ content = this.tpl.apply(record.data); this.bodyContent[record.id] = content; } return content; }, onMouseDown : function(e, t){ e.stopEvent(); var row = e.getTarget('.x-grid3-row'); this.toggleRow(row); }, renderer : function(v, p, record){ p.cellAttr = 'rowspan="2"'; return '
 
'; }, beforeExpand : function(record, body, rowIndex){ if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){ if(this.tpl && this.lazyRender){ body.innerHTML = this.getBodyContent(record, rowIndex); } return true; }else{ return false; } }, toggleRow : function(row){ if(typeof row == 'number'){ row = this.grid.view.getRow(row); } this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row); }, expandRow : function(row){ if(typeof row == 'number'){ row = this.grid.view.getRow(row); } var record = this.grid.store.getAt(row.rowIndex); var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row); if(this.beforeExpand(record, body, row.rowIndex)){ this.state[record.id] = true; Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded'); this.fireEvent('expand', this, record, body, row.rowIndex); } }, collapseRow : function(row){ if(typeof row == 'number'){ row = this.grid.view.getRow(row); } var record = this.grid.store.getAt(row.rowIndex); var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true); if(this.fireEvent('beforecollapse', this, record, body, row.rowIndex) !== false){ this.state[record.id] = false; Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed'); this.fireEvent('collapse', this, record, body, row.rowIndex); } } }); Ext.preg('rowexpander', Ext.ux.grid.RowExpander); //backwards compat Ext.grid.RowExpander = Ext.ux.grid.RowExpander; Ext.ns('Ext.ux.grid');Ext.ux.grid.CheckColumn=function(a){Ext.apply(this,a);if(!this.id){this.id=Ext.id()}this.renderer=this.renderer.createDelegate(this)};Ext.ux.grid.CheckColumn.prototype={init:function(b){this.grid=b;this.grid.on('render',function(){var a=this.grid.getView();a.mainBody.on('mousedown',this.onMouseDown,this)},this);this.grid.on('destroy',this.onDestroy,this)},onMouseDown:function(e,t){this.grid.fireEvent('rowclick');if(t.className&&t.className.indexOf('x-grid3-cc-'+this.id)!=-1){e.stopEvent();var a=this.grid.getView().findRowIndex(t);var b=this.grid.store.getAt(a);b.set(this.dataIndex,!b.data[this.dataIndex]);this.grid.fireEvent('afteredit')}},renderer:function(v,p,a){p.css+=' x-grid3-check-col-td';return'
 
'},onDestroy:function(){var mainBody = this.grid.getView().mainBody; if(mainBody){ mainBody.un('mousedown', this.onMouseDown, this); }}};Ext.preg('checkcolumn',Ext.ux.grid.CheckColumn);Ext.grid.CheckColumn=Ext.ux.grid.CheckColumn; Ext.grid.PropertyColumnModel=function(a,b){var g=Ext.grid,f=Ext.form;this.grid=a;g.PropertyColumnModel.superclass.constructor.call(this,[{header:this.nameText,width:50,sortable:true,dataIndex:'name',id:'name',menuDisabled:true},{header:this.valueText,width:50,resizable:false,dataIndex:'value',id:'value',menuDisabled:true}]);this.store=b;var c=new f.Field({autoCreate:{tag:'select',children:[{tag:'option',value:'true',html:'true'},{tag:'option',value:'false',html:'false'}]},getValue:function(){return this.el.dom.value=='true'}});this.editors={'date':new g.GridEditor(new f.DateField({selectOnFocus:true})),'string':new g.GridEditor(new f.TextField({selectOnFocus:true})),'number':new g.GridEditor(new f.NumberField({selectOnFocus:true,style:'text-align:left;'})),'boolean':new g.GridEditor(c)};this.renderCellDelegate=this.renderCell.createDelegate(this);this.renderPropDelegate=this.renderProp.createDelegate(this)};Ext.extend(Ext.grid.PropertyColumnModel,Ext.grid.ColumnModel,{nameText:'Name',valueText:'Value',dateFormat:'m/j/Y',renderDate:function(a){return a.dateFormat(this.dateFormat)},renderBool:function(a){return a?'true':'false'},isCellEditable:function(a,b){return a==1},getRenderer:function(a){return a==1?this.renderCellDelegate:this.renderPropDelegate},renderProp:function(v){return this.getPropertyName(v)},renderCell:function(a){var b=a;if(Ext.isDate(a)){b=this.renderDate(a)}else if(typeof a=='boolean'){b=this.renderBool(a)}return Ext.util.Format.htmlEncode(b)},getPropertyName:function(a){var b=this.grid.propertyNames;return b&&b[a]?b[a]:a},getCellEditor:function(a,b){var p=this.store.getProperty(b),n=p.data.name,val=p.data.value;if(this.grid.customEditors[n]){return this.grid.customEditors[n]}if(Ext.isDate(val)){return this.editors.date}else if(typeof val=='number'){return this.editors.number}else if(typeof val=='boolean'){return this.editors['boolean']}else{return this.editors.string}},destroy:function(){Ext.grid.PropertyColumnModel.superclass.destroy.call(this);for(var a in this.editors){Ext.destroy(a)}}});