Upgrade to ExtJS 3.2.2 - Released 06/02/2010
[extjs.git] / src / widgets / layout / TableLayout.js
1 /*!
2  * Ext JS Library 3.2.2
3  * Copyright(c) 2006-2010 Ext JS, Inc.
4  * licensing@extjs.com
5  * http://www.extjs.com/license
6  */
7 /**
8  * @class Ext.layout.TableLayout
9  * @extends Ext.layout.ContainerLayout
10  * <p>This layout allows you to easily render content into an HTML table.  The total number of columns can be
11  * specified, and rowspan and colspan can be used to create complex layouts within the table.
12  * This class is intended to be extended or created via the layout:'table' {@link Ext.Container#layout} config,
13  * and should generally not need to be created directly via the new keyword.</p>
14  * <p>Note that when creating a layout via config, the layout-specific config properties must be passed in via
15  * the {@link Ext.Container#layoutConfig} object which will then be applied internally to the layout.  In the
16  * case of TableLayout, the only valid layout config property is {@link #columns}.  However, the items added to a
17  * TableLayout can supply the following table-specific config properties:</p>
18  * <ul>
19  * <li><b>rowspan</b> Applied to the table cell containing the item.</li>
20  * <li><b>colspan</b> Applied to the table cell containing the item.</li>
21  * <li><b>cellId</b> An id applied to the table cell containing the item.</li>
22  * <li><b>cellCls</b> A CSS class name added to the table cell containing the item.</li>
23  * </ul>
24  * <p>The basic concept of building up a TableLayout is conceptually very similar to building up a standard
25  * HTML table.  You simply add each panel (or "cell") that you want to include along with any span attributes
26  * specified as the special config properties of rowspan and colspan which work exactly like their HTML counterparts.
27  * Rather than explicitly creating and nesting rows and columns as you would in HTML, you simply specify the
28  * total column count in the layoutConfig and start adding panels in their natural order from left to right,
29  * top to bottom.  The layout will automatically figure out, based on the column count, rowspans and colspans,
30  * how to position each panel within the table.  Just like with HTML tables, your rowspans and colspans must add
31  * up correctly in your overall layout or you'll end up with missing and/or extra cells!  Example usage:</p>
32  * <pre><code>
33 // This code will generate a layout table that is 3 columns by 2 rows
34 // with some spanning included.  The basic layout will be:
35 // +--------+-----------------+
36 // |   A    |   B             |
37 // |        |--------+--------|
38 // |        |   C    |   D    |
39 // +--------+--------+--------+
40 var table = new Ext.Panel({
41     title: 'Table Layout',
42     layout:'table',
43     defaults: {
44         // applied to each contained panel
45         bodyStyle:'padding:20px'
46     },
47     layoutConfig: {
48         // The total column count must be specified here
49         columns: 3
50     },
51     items: [{
52         html: '&lt;p&gt;Cell A content&lt;/p&gt;',
53         rowspan: 2
54     },{
55         html: '&lt;p&gt;Cell B content&lt;/p&gt;',
56         colspan: 2
57     },{
58         html: '&lt;p&gt;Cell C content&lt;/p&gt;',
59         cellCls: 'highlight'
60     },{
61         html: '&lt;p&gt;Cell D content&lt;/p&gt;'
62     }]
63 });
64 </code></pre>
65  */
66 Ext.layout.TableLayout = Ext.extend(Ext.layout.ContainerLayout, {
67     /**
68      * @cfg {Number} columns
69      * The total number of columns to create in the table for this layout.  If not specified, all Components added to
70      * this layout will be rendered into a single row using one column per Component.
71      */
72
73     // private
74     monitorResize:false,
75
76     type: 'table',
77
78     targetCls: 'x-table-layout-ct',
79
80     /**
81      * @cfg {Object} tableAttrs
82      * <p>An object containing properties which are added to the {@link Ext.DomHelper DomHelper} specification
83      * used to create the layout's <tt>&lt;table&gt;</tt> element. Example:</p><pre><code>
84 {
85     xtype: 'panel',
86     layout: 'table',
87     layoutConfig: {
88         tableAttrs: {
89             style: {
90                 width: '100%'
91             }
92         },
93         columns: 3
94     }
95 }</code></pre>
96      */
97     tableAttrs:null,
98
99     // private
100     setContainer : function(ct){
101         Ext.layout.TableLayout.superclass.setContainer.call(this, ct);
102
103         this.currentRow = 0;
104         this.currentColumn = 0;
105         this.cells = [];
106     },
107     
108     // private
109     onLayout : function(ct, target){
110         var cs = ct.items.items, len = cs.length, c, i;
111
112         if(!this.table){
113             target.addClass('x-table-layout-ct');
114
115             this.table = target.createChild(
116                 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
117         }
118         this.renderAll(ct, target);
119     },
120
121     // private
122     getRow : function(index){
123         var row = this.table.tBodies[0].childNodes[index];
124         if(!row){
125             row = document.createElement('tr');
126             this.table.tBodies[0].appendChild(row);
127         }
128         return row;
129     },
130
131     // private
132     getNextCell : function(c){
133         var cell = this.getNextNonSpan(this.currentColumn, this.currentRow);
134         var curCol = this.currentColumn = cell[0], curRow = this.currentRow = cell[1];
135         for(var rowIndex = curRow; rowIndex < curRow + (c.rowspan || 1); rowIndex++){
136             if(!this.cells[rowIndex]){
137                 this.cells[rowIndex] = [];
138             }
139             for(var colIndex = curCol; colIndex < curCol + (c.colspan || 1); colIndex++){
140                 this.cells[rowIndex][colIndex] = true;
141             }
142         }
143         var td = document.createElement('td');
144         if(c.cellId){
145             td.id = c.cellId;
146         }
147         var cls = 'x-table-layout-cell';
148         if(c.cellCls){
149             cls += ' ' + c.cellCls;
150         }
151         td.className = cls;
152         if(c.colspan){
153             td.colSpan = c.colspan;
154         }
155         if(c.rowspan){
156             td.rowSpan = c.rowspan;
157         }
158         this.getRow(curRow).appendChild(td);
159         return td;
160     },
161
162     // private
163     getNextNonSpan: function(colIndex, rowIndex){
164         var cols = this.columns;
165         while((cols && colIndex >= cols) || (this.cells[rowIndex] && this.cells[rowIndex][colIndex])) {
166             if(cols && colIndex >= cols){
167                 rowIndex++;
168                 colIndex = 0;
169             }else{
170                 colIndex++;
171             }
172         }
173         return [colIndex, rowIndex];
174     },
175
176     // private
177     renderItem : function(c, position, target){
178         // Ensure we have our inner table to get cells to render into.
179         if(!this.table){
180             this.table = target.createChild(
181                 Ext.apply({tag:'table', cls:'x-table-layout', cellspacing: 0, cn: {tag: 'tbody'}}, this.tableAttrs), null, true);
182         }
183         if(c && !c.rendered){
184             c.render(this.getNextCell(c));
185             this.configureItem(c, position);
186         }else if(c && !this.isValidParent(c, target)){
187             var container = this.getNextCell(c);
188             container.insertBefore(c.getPositionEl().dom, null);
189             c.container = Ext.get(container);
190             this.configureItem(c, position);
191         }
192     },
193
194     // private
195     isValidParent : function(c, target){
196         return c.getPositionEl().up('table', 5).dom.parentNode === (target.dom || target);
197     },
198     
199     destroy: function(){
200         delete this.table;
201         Ext.layout.TableLayout.superclass.destroy.call(this);
202     }
203
204     /**
205      * @property activeItem
206      * @hide
207      */
208 });
209
210 Ext.Container.LAYOUTS['table'] = Ext.layout.TableLayout;