Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / examples / docs / source / RowExpander.html
1 <html>
2 <head>
3   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />    
4   <title>The source code</title>
5     <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
6     <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
7 </head>
8 <body  onload="prettyPrint();">
9     <pre class="prettyprint lang-js">/*!
10  * Ext JS Library 3.3.1
11  * Copyright(c) 2006-2010 Sencha Inc.
12  * licensing@sencha.com
13  * http://www.sencha.com/license
14  */
15 Ext.ns('Ext.ux.grid');
16
17 <div id="cls-Ext.ux.grid.RowExpander"></div>/**
18  * @class Ext.ux.grid.RowExpander
19  * @extends Ext.util.Observable
20  * Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
21  * a second row body which expands/contracts.  The expand/contract behavior is configurable to react
22  * on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
23  *
24  * @ptype rowexpander
25  */
26 Ext.ux.grid.RowExpander = Ext.extend(Ext.util.Observable, {
27     <div id="cfg-Ext.ux.grid.RowExpander-expandOnEnter"></div>/**
28      * @cfg {Boolean} expandOnEnter
29      * <tt>true</tt> to toggle selected row(s) between expanded/collapsed when the enter
30      * key is pressed (defaults to <tt>true</tt>).
31      */
32     expandOnEnter : true,
33     <div id="cfg-Ext.ux.grid.RowExpander-expandOnDblClick"></div>/**
34      * @cfg {Boolean} expandOnDblClick
35      * <tt>true</tt> to toggle a row between expanded/collapsed when double clicked
36      * (defaults to <tt>true</tt>).
37      */
38     expandOnDblClick : true,
39
40     header : '',
41     width : 20,
42     sortable : false,
43     fixed : true,
44     hideable: false,
45     menuDisabled : true,
46     dataIndex : '',
47     id : 'expander',
48     lazyRender : true,
49     enableCaching : true,
50
51     constructor: function(config){
52         Ext.apply(this, config);
53
54         this.addEvents({
55             <div id="event-Ext.ux.grid.RowExpander-beforeexpand"></div>/**
56              * @event beforeexpand
57              * Fires before the row expands. Have the listener return false to prevent the row from expanding.
58              * @param {Object} this RowExpander object.
59              * @param {Object} Ext.data.Record Record for the selected row.
60              * @param {Object} body body element for the secondary row.
61              * @param {Number} rowIndex The current row index.
62              */
63             beforeexpand: true,
64             <div id="event-Ext.ux.grid.RowExpander-expand"></div>/**
65              * @event expand
66              * Fires after the row expands.
67              * @param {Object} this RowExpander object.
68              * @param {Object} Ext.data.Record Record for the selected row.
69              * @param {Object} body body element for the secondary row.
70              * @param {Number} rowIndex The current row index.
71              */
72             expand: true,
73             <div id="event-Ext.ux.grid.RowExpander-beforecollapse"></div>/**
74              * @event beforecollapse
75              * Fires before the row collapses. Have the listener return false to prevent the row from collapsing.
76              * @param {Object} this RowExpander object.
77              * @param {Object} Ext.data.Record Record for the selected row.
78              * @param {Object} body body element for the secondary row.
79              * @param {Number} rowIndex The current row index.
80              */
81             beforecollapse: true,
82             <div id="event-Ext.ux.grid.RowExpander-collapse"></div>/**
83              * @event collapse
84              * Fires after the row collapses.
85              * @param {Object} this RowExpander object.
86              * @param {Object} Ext.data.Record Record for the selected row.
87              * @param {Object} body body element for the secondary row.
88              * @param {Number} rowIndex The current row index.
89              */
90             collapse: true
91         });
92
93         Ext.ux.grid.RowExpander.superclass.constructor.call(this);
94
95         if(this.tpl){
96             if(typeof this.tpl == 'string'){
97                 this.tpl = new Ext.Template(this.tpl);
98             }
99             this.tpl.compile();
100         }
101
102         this.state = {};
103         this.bodyContent = {};
104     },
105
106     getRowClass : function(record, rowIndex, p, ds){
107         p.cols = p.cols-1;
108         var content = this.bodyContent[record.id];
109         if(!content && !this.lazyRender){
110             content = this.getBodyContent(record, rowIndex);
111         }
112         if(content){
113             p.body = content;
114         }
115         return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed';
116     },
117
118     init : function(grid){
119         this.grid = grid;
120
121         var view = grid.getView();
122         view.getRowClass = this.getRowClass.createDelegate(this);
123
124         view.enableRowBody = true;
125
126
127         grid.on('render', this.onRender, this);
128         grid.on('destroy', this.onDestroy, this);
129     },
130
131     // @private
132     onRender: function() {
133         var grid = this.grid;
134         var mainBody = grid.getView().mainBody;
135         mainBody.on('mousedown', this.onMouseDown, this, {delegate: '.x-grid3-row-expander'});
136         if (this.expandOnEnter) {
137             this.keyNav = new Ext.KeyNav(this.grid.getGridEl(), {
138                 'enter' : this.onEnter,
139                 scope: this
140             });
141         }
142         if (this.expandOnDblClick) {
143             grid.on('rowdblclick', this.onRowDblClick, this);
144         }
145     },
146     
147     // @private    
148     onDestroy: function() {
149         if(this.keyNav){
150             this.keyNav.disable();
151             delete this.keyNav;
152         }
153         /*
154          * A majority of the time, the plugin will be destroyed along with the grid,
155          * which means the mainBody won't be available. On the off chance that the plugin
156          * isn't destroyed with the grid, take care of removing the listener.
157          */
158         var mainBody = this.grid.getView().mainBody;
159         if(mainBody){
160             mainBody.un('mousedown', this.onMouseDown, this);
161         }
162     },
163     // @private
164     onRowDblClick: function(grid, rowIdx, e) {
165         this.toggleRow(rowIdx);
166     },
167
168     onEnter: function(e) {
169         var g = this.grid;
170         var sm = g.getSelectionModel();
171         var sels = sm.getSelections();
172         for (var i = 0, len = sels.length; i < len; i++) {
173             var rowIdx = g.getStore().indexOf(sels[i]);
174             this.toggleRow(rowIdx);
175         }
176     },
177
178     getBodyContent : function(record, index){
179         if(!this.enableCaching){
180             return this.tpl.apply(record.data);
181         }
182         var content = this.bodyContent[record.id];
183         if(!content){
184             content = this.tpl.apply(record.data);
185             this.bodyContent[record.id] = content;
186         }
187         return content;
188     },
189
190     onMouseDown : function(e, t){
191         e.stopEvent();
192         var row = e.getTarget('.x-grid3-row');
193         this.toggleRow(row);
194     },
195
196     renderer : function(v, p, record){
197         p.cellAttr = 'rowspan="2"';
198         return '<div class="x-grid3-row-expander">&#160;</div>';
199     },
200
201     beforeExpand : function(record, body, rowIndex){
202         if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){
203             if(this.tpl && this.lazyRender){
204                 body.innerHTML = this.getBodyContent(record, rowIndex);
205             }
206             return true;
207         }else{
208             return false;
209         }
210     },
211
212     toggleRow : function(row){
213         if(typeof row == 'number'){
214             row = this.grid.view.getRow(row);
215         }
216         this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row);
217     },
218
219     expandRow : function(row){
220         if(typeof row == 'number'){
221             row = this.grid.view.getRow(row);
222         }
223         var record = this.grid.store.getAt(row.rowIndex);
224         var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
225         if(this.beforeExpand(record, body, row.rowIndex)){
226             this.state[record.id] = true;
227             Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
228             this.fireEvent('expand', this, record, body, row.rowIndex);
229         }
230     },
231
232     collapseRow : function(row){
233         if(typeof row == 'number'){
234             row = this.grid.view.getRow(row);
235         }
236         var record = this.grid.store.getAt(row.rowIndex);
237         var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
238         if(this.fireEvent('beforecollapse', this, record, body, row.rowIndex) !== false){
239             this.state[record.id] = false;
240             Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
241             this.fireEvent('collapse', this, record, body, row.rowIndex);
242         }
243     }
244 });
245
246 Ext.preg('rowexpander', Ext.ux.grid.RowExpander);
247
248 //backwards compat
249 Ext.grid.RowExpander = Ext.ux.grid.RowExpander;</pre>    
250 </body>
251 </html>