3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
15 // feature idea to enable Ajax loading and then the content
16 // cache would actually make sense. Should we dictate that they use
17 // data or support raw html as well?
20 * @class Ext.ux.RowExpander
21 * @extends Ext.AbstractPlugin
22 * Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
23 * a second row body which expands/contracts. The expand/contract behavior is configurable to react
24 * on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
28 Ext.define('Ext.ux.RowExpander', {
29 extend: 'Ext.AbstractPlugin',
30 alias: 'plugin.rowexpander',
35 * @cfg {Boolean} expandOnEnter
36 * <tt>true</tt> to toggle selected row(s) between expanded/collapsed when the enter
37 * key is pressed (defaults to <tt>true</tt>).
42 * @cfg {Boolean} expandOnDblClick
43 * <tt>true</tt> to toggle a row between expanded/collapsed when double clicked
44 * (defaults to <tt>true</tt>).
46 expandOnDblClick: true,
49 * @cfg {Boolean} selectRowOnExpand
50 * <tt>true</tt> to select a row when clicking on the expander icon
51 * (defaults to <tt>false</tt>).
53 selectRowOnExpand: false,
55 rowBodyTrSelector: '.x-grid-rowbody-tr',
56 rowBodyHiddenCls: 'x-grid-row-body-hidden',
57 rowCollapsedCls: 'x-grid-row-collapsed',
61 renderer: function(value, metadata, record, rowIdx, colIdx) {
63 metadata.tdCls = 'x-grid-td-expander';
65 return '<div class="x-grid-row-expander"> </div>';
70 * <b<Fired through the grid's View</b>
71 * @param {HtmlElement} rowNode The <tr> element which owns the expanded row.
72 * @param {Ext.data.Model} record The record providing the data.
73 * @param {HtmlElement} expandRow The <tr> element containing the expanded data.
77 * <b<Fired through the grid's View.</b>
78 * @param {HtmlElement} rowNode The <tr> element which owns the expanded row.
79 * @param {Ext.data.Model} record The record providing the data.
80 * @param {HtmlElement} expandRow The <tr> element containing the expanded data.
83 constructor: function() {
84 this.callParent(arguments);
85 var grid = this.getCmp();
86 this.recordsExpanded = {};
88 if (!this.rowBodyTpl) {
89 Ext.Error.raise("The 'rowBodyTpl' config is required and is not defined.");
92 // TODO: if XTemplate/Template receives a template as an arg, should
93 // just return it back!
94 var rowBodyTpl = Ext.create('Ext.XTemplate', this.rowBodyTpl),
97 columnId: this.getHeaderId(),
98 recordsExpanded: this.recordsExpanded,
99 rowBodyHiddenCls: this.rowBodyHiddenCls,
100 rowCollapsedCls: this.rowCollapsedCls,
101 getAdditionalData: this.getRowBodyFeatureData,
102 getRowBodyContents: function(data) {
103 return rowBodyTpl.applyTemplate(data);
110 grid.features = features.concat(grid.features);
112 grid.features = features;
115 grid.columns.unshift(this.getHeaderConfig());
116 grid.on('afterlayout', this.onGridAfterLayout, this, {single: true});
119 getHeaderId: function() {
120 if (!this.headerId) {
121 this.headerId = Ext.id();
123 return this.headerId;
126 getRowBodyFeatureData: function(data, idx, record, orig) {
127 var o = Ext.grid.feature.RowBody.prototype.getAdditionalData.apply(this, arguments),
129 o.rowBodyColspan = o.rowBodyColspan - 1;
130 o.rowBody = this.getRowBodyContents(data);
131 o.rowCls = this.recordsExpanded[record.internalId] ? '' : this.rowCollapsedCls;
132 o.rowBodyCls = this.recordsExpanded[record.internalId] ? '' : this.rowBodyHiddenCls;
133 o[id + '-tdAttr'] = ' valign="top" rowspan="2" ';
134 if (orig[id+'-tdAttr']) {
135 o[id+'-tdAttr'] += orig[id+'-tdAttr'];
140 onGridAfterLayout: function() {
141 var grid = this.getCmp(),
145 this.getCmp().on('afterlayout', this.onGridAfterLayout, this, {single: true});
147 view = grid.down('gridview');
148 viewEl = view.getEl();
150 if (this.expandOnEnter) {
151 this.keyNav = Ext.create('Ext.KeyNav', viewEl, {
152 'enter' : this.onEnter,
156 if (this.expandOnDblClick) {
157 view.on('itemdblclick', this.onDblClick, this);
163 onEnter: function(e) {
164 var view = this.view,
166 sm = view.getSelectionModel(),
167 sels = sm.getSelection(),
172 for (; i < ln; i++) {
173 rowIdx = ds.indexOf(sels[i]);
174 this.toggleRow(rowIdx);
178 toggleRow: function(rowIdx) {
179 var rowNode = this.view.getNode(rowIdx),
180 row = Ext.get(rowNode),
181 nextBd = Ext.get(row).down(this.rowBodyTrSelector),
182 record = this.view.getRecord(rowNode);
184 if (row.hasCls(this.rowCollapsedCls)) {
185 row.removeCls(this.rowCollapsedCls);
186 nextBd.removeCls(this.rowBodyHiddenCls);
187 this.recordsExpanded[record.internalId] = true;
188 this.view.fireEvent('expandbody', rowNode, record, nextBd.dom);
190 row.addCls(this.rowCollapsedCls);
191 nextBd.addCls(this.rowBodyHiddenCls);
192 this.recordsExpanded[record.internalId] = false;
193 this.view.fireEvent('collapsebody', rowNode, record, nextBd.dom);
195 this.view.up('gridpanel').invalidateScroller();
198 onDblClick: function(view, cell, rowIdx, cellIndex, e) {
200 this.toggleRow(rowIdx);
203 getHeaderConfig: function() {
205 toggleRow = Ext.Function.bind(me.toggleRow, me),
206 selectRowOnExpand = me.selectRowOnExpand;
209 id: this.getHeaderId(),
216 cls: Ext.baseCSSPrefix + 'grid-header-special',
217 renderer: function(value, metadata) {
218 metadata.tdCls = Ext.baseCSSPrefix + 'grid-cell-special';
220 return '<div class="' + Ext.baseCSSPrefix + 'grid-row-expander"> </div>';
222 processEvent: function(type, view, cell, recordIndex, cellIndex, e) {
223 if (type == "mousedown" && e.getTarget('.x-grid-row-expander')) {
224 var row = e.getTarget('.x-grid-row');
226 return selectRowOnExpand;