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