Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / docs / source / Table.html
1 <!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-layout.container.Table'>/**
2 </span> * @class Ext.layout.container.Table
3  * @extends Ext.layout.container.Auto
4  * &lt;p&gt;This layout allows you to easily render content into an HTML table.  The total number of columns can be
5  * specified, and rowspan and colspan can be used to create complex layouts within the table.
6  * This class is intended to be extended or created via the &lt;code&gt;layout: {type: 'table'}&lt;/code&gt;
7  * {@link Ext.container.Container#layout} config, and should generally not need to be created directly via the new keyword.&lt;/p&gt;
8  * &lt;p&gt;Note that when creating a layout via config, the layout-specific config properties must be passed in via
9  * the {@link Ext.container.Container#layout} object which will then be applied internally to the layout.  In the
10  * case of TableLayout, the only valid layout config properties are {@link #columns} and {@link #tableAttrs}.
11  * However, the items added to a TableLayout can supply the following table-specific config properties:&lt;/p&gt;
12  * &lt;ul&gt;
13  * &lt;li&gt;&lt;b&gt;rowspan&lt;/b&gt; Applied to the table cell containing the item.&lt;/li&gt;
14  * &lt;li&gt;&lt;b&gt;colspan&lt;/b&gt; Applied to the table cell containing the item.&lt;/li&gt;
15  * &lt;li&gt;&lt;b&gt;cellId&lt;/b&gt; An id applied to the table cell containing the item.&lt;/li&gt;
16  * &lt;li&gt;&lt;b&gt;cellCls&lt;/b&gt; A CSS class name added to the table cell containing the item.&lt;/li&gt;
17  * &lt;/ul&gt;
18  * &lt;p&gt;The basic concept of building up a TableLayout is conceptually very similar to building up a standard
19  * HTML table.  You simply add each panel (or &quot;cell&quot;) that you want to include along with any span attributes
20  * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
21  * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
22  * total column count in the layoutConfig and start adding panels in their natural order from left to right,
23  * top to bottom.  The layout will automatically figure out, based on the column count, rowspans and colspans,
24  * how to position each panel within the table.  Just like with HTML tables, your rowspans and colspans must add
25  * up correctly in your overall layout or you'll end up with missing and/or extra cells!  Example usage:&lt;/p&gt;
26  * {@img Ext.layout.container.Table/Ext.layout.container.Table.png Ext.layout.container.Table container layout}
27  * &lt;pre&gt;&lt;code&gt;
28 // This code will generate a layout table that is 3 columns by 2 rows
29 // with some spanning included.  The basic layout will be:
30 // +--------+-----------------+
31 // |   A    |   B             |
32 // |        |--------+--------|
33 // |        |   C    |   D    |
34 // +--------+--------+--------+
35     Ext.create('Ext.panel.Panel', {
36         title: 'Table Layout',
37         width: 300,
38         height: 150,
39         layout: {
40             type: 'table',
41             // The total column count must be specified here
42             columns: 3
43         },
44         defaults: {
45             // applied to each contained panel
46             bodyStyle:'padding:20px'
47         },
48         items: [{
49             html: 'Cell A content',
50             rowspan: 2
51         },{
52             html: 'Cell B content',
53             colspan: 2
54         },{
55             html: 'Cell C content',
56             cellCls: 'highlight'
57         },{
58             html: 'Cell D content'
59         }],
60         renderTo: Ext.getBody()
61     });
62 &lt;/code&gt;&lt;/pre&gt;
63  */
64
65 Ext.define('Ext.layout.container.Table', {
66
67     /* Begin Definitions */
68
69     alias: ['layout.table'],
70     extend: 'Ext.layout.container.Auto',
71     alternateClassName: 'Ext.layout.TableLayout',
72
73     /* End Definitions */
74
75 <span id='Ext-layout.container.Table-cfg-columns'>    /**
76 </span>     * @cfg {Number} columns
77      * The total number of columns to create in the table for this layout.  If not specified, all Components added to
78      * this layout will be rendered into a single row using one column per Component.
79      */
80
81     // private
82     monitorResize:false,
83
84     type: 'table',
85
86     // Table layout is a self-sizing layout. When an item of for example, a dock layout, the Panel must expand to accommodate
87     // a table layout. See in particular AbstractDock::onLayout for use of this flag.
88     autoSize: true,
89
90     clearEl: true, // Base class will not create it if already truthy. Not needed in tables.
91
92     targetCls: Ext.baseCSSPrefix + 'table-layout-ct',
93     tableCls: Ext.baseCSSPrefix + 'table-layout',
94     cellCls: Ext.baseCSSPrefix + 'table-layout-cell',
95
96 <span id='Ext-layout.container.Table-cfg-tableAttrs'>    /**
97 </span>     * @cfg {Object} tableAttrs
98      * &lt;p&gt;An object containing properties which are added to the {@link Ext.core.DomHelper DomHelper} specification
99      * used to create the layout's &lt;tt&gt;&amp;lt;table&amp;gt;&lt;/tt&gt; element. Example:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
100 {
101     xtype: 'panel',
102     layout: {
103         type: 'table',
104         columns: 3,
105         tableAttrs: {
106             style: {
107                 width: '100%'
108             }
109         }
110     }
111 }&lt;/code&gt;&lt;/pre&gt;
112      */
113     tableAttrs:null,
114
115 <span id='Ext-layout.container.Table-method-renderItems'>    /**
116 </span>     * @private
117      * Iterates over all passed items, ensuring they are rendered in a cell in the proper
118      * location in the table structure.
119      */
120     renderItems: function(items) {
121         var tbody = this.getTable().tBodies[0],
122             rows = tbody.rows,
123             i = 0,
124             len = items.length,
125             cells, curCell, rowIdx, cellIdx, item, trEl, tdEl, itemCt;
126
127         // Calculate the correct cell structure for the current items
128         cells = this.calculateCells(items);
129
130         // Loop over each cell and compare to the current cells in the table, inserting/
131         // removing/moving cells as needed, and making sure each item is rendered into
132         // the correct cell.
133         for (; i &lt; len; i++) {
134             curCell = cells[i];
135             rowIdx = curCell.rowIdx;
136             cellIdx = curCell.cellIdx;
137             item = items[i];
138
139             // If no row present, create and insert one
140             trEl = rows[rowIdx];
141             if (!trEl) {
142                 trEl = tbody.insertRow(rowIdx);
143             }
144
145             // If no cell present, create and insert one
146             itemCt = tdEl = Ext.get(trEl.cells[cellIdx] || trEl.insertCell(cellIdx));
147             if (this.needsDivWrap()) { //create wrapper div if needed - see docs below
148                 itemCt = tdEl.first() || tdEl.createChild({tag: 'div'});
149                 itemCt.setWidth(null);
150             }
151
152             // Render or move the component into the cell
153             if (!item.rendered) {
154                 this.renderItem(item, itemCt, 0);
155             }
156             else if (!this.isValidParent(item, itemCt, 0)) {
157                 this.moveItem(item, itemCt, 0);
158             }
159
160             // Set the cell properties
161             tdEl.set({
162                 colSpan: item.colspan || 1,
163                 rowSpan: item.rowspan || 1,
164                 id: item.cellId || '',
165                 cls: this.cellCls + ' ' + (item.cellCls || '')
166             });
167
168             // If at the end of a row, remove any extra cells
169             if (!cells[i + 1] || cells[i + 1].rowIdx !== rowIdx) {
170                 cellIdx++;
171                 while (trEl.cells[cellIdx]) {
172                     trEl.deleteCell(cellIdx);
173                 }
174             }
175         }
176
177         // Delete any extra rows
178         rowIdx++;
179         while (tbody.rows[rowIdx]) {
180             tbody.deleteRow(rowIdx);
181         }
182     },
183
184     afterLayout: function() {
185         this.callParent();
186
187         if (this.needsDivWrap()) {
188             // set wrapper div width to match layed out item - see docs below
189             Ext.Array.forEach(this.getLayoutItems(), function(item) {
190                 Ext.fly(item.el.dom.parentNode).setWidth(item.getWidth());
191             });
192         }
193     },
194
195 <span id='Ext-layout.container.Table-method-calculateCells'>    /**
196 </span>     * @private
197      * Determine the row and cell indexes for each component, taking into consideration
198      * the number of columns and each item's configured colspan/rowspan values.
199      * @param {Array} items The layout components
200      * @return {Array} List of row and cell indexes for each of the components
201      */
202     calculateCells: function(items) {
203         var cells = [],
204             rowIdx = 0,
205             colIdx = 0,
206             cellIdx = 0,
207             totalCols = this.columns || Infinity,
208             rowspans = [], //rolling list of active rowspans for each column
209             i = 0, j,
210             len = items.length,
211             item;
212
213         for (; i &lt; len; i++) {
214             item = items[i];
215
216             // Find the first available row/col slot not taken up by a spanning cell
217             while (colIdx &gt;= totalCols || rowspans[colIdx] &gt; 0) {
218                 if (colIdx &gt;= totalCols) {
219                     // move down to next row
220                     colIdx = 0;
221                     cellIdx = 0;
222                     rowIdx++;
223
224                     // decrement all rowspans
225                     for (j = 0; j &lt; totalCols; j++) {
226                         if (rowspans[j] &gt; 0) {
227                             rowspans[j]--;
228                         }
229                     }
230                 } else {
231                     colIdx++;
232                 }
233             }
234
235             // Add the cell info to the list
236             cells.push({
237                 rowIdx: rowIdx,
238                 cellIdx: cellIdx
239             });
240
241             // Increment
242             rowspans[colIdx] = item.rowspan || 1;
243             colIdx += item.colspan || 1;
244             cellIdx++;
245         }
246
247         return cells;
248     },
249
250 <span id='Ext-layout.container.Table-method-getTable'>    /**
251 </span>     * @private
252      * Return the layout's table element, creating it if necessary.
253      */
254     getTable: function() {
255         var table = this.table;
256         if (!table) {
257             table = this.table = this.getTarget().createChild(
258                 Ext.apply({
259                     tag: 'table',
260                     role: 'presentation',
261                     cls: this.tableCls,
262                     cellspacing: 0, //TODO should this be specified or should CSS handle it?
263                     cn: {tag: 'tbody'}
264                 }, this.tableAttrs),
265                 null, true
266             );
267         }
268         return table;
269     },
270
271 <span id='Ext-layout.container.Table-method-needsDivWrap'>    /**
272 </span>     * @private
273      * Opera 10.5 has a bug where if a table cell's child has box-sizing:border-box and padding, it
274      * will include that padding in the size of the cell, making it always larger than the
275      * shrink-wrapped size of its contents. To get around this we have to wrap the contents in a div
276      * and then set that div's width to match the item rendered within it afterLayout. This method
277      * determines whether we need the wrapper div; it currently does a straight UA sniff as this bug
278      * seems isolated to just Opera 10.5, but feature detection could be added here if needed.
279      */
280     needsDivWrap: function() {
281         return Ext.isOpera10_5;
282     }
283 });</pre></pre></body></html>