X-Git-Url: http://git.ithinksw.org/extjs.git/blobdiff_plain/f5240829880f87e0cf581c6a296e436fdef0ef80..3789b528d8dd8aad4558e38e22d775bcab1cbd36:/examples/ux/RowExpander.js?ds=inline
diff --git a/examples/ux/RowExpander.js b/examples/ux/RowExpander.js
index 19533d0b..77d2a6ff 100644
--- a/examples/ux/RowExpander.js
+++ b/examples/ux/RowExpander.js
@@ -1,241 +1,217 @@
-/*!
- * Ext JS Library 3.3.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
- */
-Ext.ns('Ext.ux.grid');
+// feature idea to enable Ajax loading and then the content
+// cache would actually make sense. Should we dictate that they use
+// data or support raw html as well?
/**
- * @class Ext.ux.grid.RowExpander
- * @extends Ext.util.Observable
+ * @class Ext.ux.RowExpander
+ * @extends Ext.AbstractPlugin
* Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
* a second row body which expands/contracts. The expand/contract behavior is configurable to react
* on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
*
* @ptype rowexpander
*/
-Ext.ux.grid.RowExpander = Ext.extend(Ext.util.Observable, {
+Ext.define('Ext.ux.RowExpander', {
+ extend: 'Ext.AbstractPlugin',
+ alias: 'plugin.rowexpander',
+
+ rowBodyTpl: null,
+
/**
* @cfg {Boolean} expandOnEnter
* true to toggle selected row(s) between expanded/collapsed when the enter
* key is pressed (defaults to true).
*/
- expandOnEnter : 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();
- }
+ expandOnDblClick: true,
- this.state = {};
- this.bodyContent = {};
- },
+ /**
+ * @cfg {Boolean} selectRowOnExpand
+ * true to select a row when clicking on the expander icon
+ * (defaults to false).
+ */
+ selectRowOnExpand: false,
- 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';
- },
+ rowBodyTrSelector: '.x-grid-rowbody-tr',
+ rowBodyHiddenCls: 'x-grid-row-body-hidden',
+ rowCollapsedCls: 'x-grid-row-collapsed',
- init : function(grid){
- this.grid = grid;
- var view = grid.getView();
- view.getRowClass = this.getRowClass.createDelegate(this);
- view.enableRowBody = true;
+ renderer: function(value, metadata, record, rowIdx, colIdx) {
+ if (colIdx === 0) {
+ metadata.tdCls = 'x-grid-td-expander';
+ }
+ return '
';
+ },
+ /**
+ * @event expandbody
+ *
+ * @param {HtmlElement} rowNode The <tr> element which owns the expanded row.
+ * @param {Ext.data.Model} record The record providing the data.
+ * @param {HtmlElement} expandRow The <tr> element containing the expanded data.
+ */
+ /**
+ * @event collapsebody
+ *
+ * @param {HtmlElement} rowNode The <tr> element which owns the expanded row.
+ * @param {Ext.data.Model} record The record providing the data.
+ * @param {HtmlElement} expandRow The <tr> element containing the expanded data.
+ */
- grid.on('render', this.onRender, this);
- grid.on('destroy', this.onDestroy, this);
+ constructor: function() {
+ this.callParent(arguments);
+ var grid = this.getCmp();
+ this.recordsExpanded = {};
+ //
+ if (!this.rowBodyTpl) {
+ Ext.Error.raise("The 'rowBodyTpl' config is required and is not defined.");
+ }
+ //
+ // TODO: if XTemplate/Template receives a template as an arg, should
+ // just return it back!
+ var rowBodyTpl = Ext.create('Ext.XTemplate', this.rowBodyTpl),
+ features = [{
+ ftype: 'rowbody',
+ columnId: this.getHeaderId(),
+ recordsExpanded: this.recordsExpanded,
+ rowBodyHiddenCls: this.rowBodyHiddenCls,
+ rowCollapsedCls: this.rowCollapsedCls,
+ getAdditionalData: this.getRowBodyFeatureData,
+ getRowBodyContents: function(data) {
+ return rowBodyTpl.applyTemplate(data);
+ }
+ },{
+ ftype: 'rowwrap'
+ }];
+
+ if (grid.features) {
+ grid.features = features.concat(grid.features);
+ } else {
+ grid.features = features;
+ }
+
+ grid.columns.unshift(this.getHeaderConfig());
+ grid.on('afterlayout', this.onGridAfterLayout, this, {single: true});
},
- // @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);
+ getHeaderId: function() {
+ if (!this.headerId) {
+ this.headerId = Ext.id();
}
+ return this.headerId;
},
-
- // @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);
- }
+
+ getRowBodyFeatureData: function(data, idx, record, orig) {
+ var o = Ext.grid.feature.RowBody.prototype.getAdditionalData.apply(this, arguments),
+ id = this.columnId;
+ o.rowBodyColspan = o.rowBodyColspan - 1;
+ o.rowBody = this.getRowBodyContents(data);
+ o.rowCls = this.recordsExpanded[record.internalId] ? '' : this.rowCollapsedCls;
+ o.rowBodyCls = this.recordsExpanded[record.internalId] ? '' : this.rowBodyHiddenCls;
+ o[id + '-tdAttr'] = ' valign="top" rowspan="2" ';
+ if (orig[id+'-tdAttr']) {
+ o[id+'-tdAttr'] += orig[id+'-tdAttr'];
+ }
+ return o;
},
- // @private
- onRowDblClick: function(grid, rowIdx, e) {
- this.toggleRow(rowIdx);
+
+ onGridAfterLayout: function() {
+ var grid = this.getCmp(),
+ view, viewEl;
+
+ if (!grid.hasView) {
+ this.getCmp().on('afterlayout', this.onGridAfterLayout, this, {single: true});
+ } else {
+ view = grid.down('gridview');
+ viewEl = view.getEl();
+
+ if (this.expandOnEnter) {
+ this.keyNav = Ext.create('Ext.KeyNav', viewEl, {
+ 'enter' : this.onEnter,
+ scope: this
+ });
+ }
+ if (this.expandOnDblClick) {
+ view.on('itemdblclick', this.onDblClick, this);
+ }
+ this.view = view;
+ }
},
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]);
+ var view = this.view,
+ ds = view.store,
+ sm = view.getSelectionModel(),
+ sels = sm.getSelection(),
+ ln = sels.length,
+ i = 0,
+ rowIdx;
+
+ for (; i < ln; i++) {
+ rowIdx = ds.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;
+ toggleRow: function(rowIdx) {
+ var rowNode = this.view.getNode(rowIdx),
+ row = Ext.get(rowNode),
+ nextBd = Ext.get(row).down(this.rowBodyTrSelector),
+ record = this.view.getRecord(rowNode);
+
+ if (row.hasCls(this.rowCollapsedCls)) {
+ row.removeCls(this.rowCollapsedCls);
+ nextBd.removeCls(this.rowBodyHiddenCls);
+ this.recordsExpanded[record.internalId] = true;
+ this.view.fireEvent('expandbody', rowNode, record, nextBd.dom);
+ } else {
+ row.addCls(this.rowCollapsedCls);
+ nextBd.addCls(this.rowBodyHiddenCls);
+ this.recordsExpanded[record.internalId] = false;
+ this.view.fireEvent('collapsebody', rowNode, record, nextBd.dom);
+ }
+ this.view.up('gridpanel').invalidateScroller();
},
- onMouseDown : function(e, t){
- e.stopEvent();
- var row = e.getTarget('.x-grid3-row');
- this.toggleRow(row);
- },
+ onDblClick: function(view, cell, rowIdx, cellIndex, e) {
- renderer : function(v, p, record){
- p.cellAttr = 'rowspan="2"';
- return '
';
+ this.toggleRow(rowIdx);
},
- 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);
+ getHeaderConfig: function() {
+ var me = this,
+ toggleRow = Ext.Function.bind(me.toggleRow, me),
+ selectRowOnExpand = me.selectRowOnExpand;
+
+ return {
+ id: this.getHeaderId(),
+ width: 24,
+ sortable: false,
+ fixed: true,
+ draggable: false,
+ hideable: false,
+ menuDisabled: true,
+ cls: Ext.baseCSSPrefix + 'grid-header-special',
+ renderer: function(value, metadata) {
+ metadata.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
+
+ return '
';
+ },
+ processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
+ if (type == "mousedown" && e.getTarget('.x-grid-row-expander')) {
+ var row = e.getTarget('.x-grid-row');
+ toggleRow(row);
+ return selectRowOnExpand;
+ }
}
- 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;
\ No newline at end of file