]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/layout/container/Dashboard.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / layout / container / Dashboard.js
CommitLineData
6527f429
DM
1/**\r
2 * This layout extends `Ext.layout.container.Column` and adds splitters between adjacent\r
3 * columns allowing the user to resize them.\r
4 * @private\r
5 */\r
6Ext.define('Ext.layout.container.Dashboard', {\r
7 extend: 'Ext.layout.container.Column',\r
8 alias: 'layout.dashboard',\r
9\r
10 requires: [\r
11 'Ext.layout.container.ColumnSplitter'\r
12 ],\r
13\r
14 type: 'dashboard',\r
15\r
16 firstColumnCls: Ext.baseCSSPrefix + 'dashboard-column-first',\r
17\r
18 lastColumnCls: Ext.baseCSSPrefix + 'dashboard-column-last',\r
19\r
20 /*\r
21 * The geometry of a Column layout with splitters between respective items:\r
22 *\r
23 * 0 1 2 3 4\r
24 * +-----------------------------------------------+\r
25 * | +-----------+ || +---------+ || +-----------+ | \\r
26 * | | | || | | || | | | \\r
27 * | | | || | | || | | | \\r
28 * | | | || | | || | | | \\r
29 * | +-----------+ || | | || | | | row[0]\r
30 * | || | | || | | | /\r
31 * | || | | || | | | /\r
32 * | || | | || +-----------+ | /\r
33 * | || | | || | /\r
34 * | || +---------+ || |\r
35 * | +-------------------+ || +------------------+ | \\r
36 * | | | || | | | \\r
37 * | | | || | | | \\r
38 * | | | || | | | row[1]\r
39 * | | | || | | | /\r
40 * | | | || +------------------+ | /\r
41 * | +-------------------+ || | /\r
42 * +-----------------------------------------------+\r
43 * 6 7 8\r
44 *\r
45 * The splitter between 4 and 6 will be hidden but still present in the items. It is\r
46 * considered part of row[0].\r
47 */\r
48\r
49 getSplitterConfig: function () {\r
50 return {\r
51 xtype: 'columnsplitter'\r
52 };\r
53 },\r
54\r
55 /**\r
56 * @private\r
57 * Returns a filtered item list sans splitters\r
58 * @param items\r
59 * @return {Array|*}\r
60 */\r
61 getColumns : function(items) {\r
62 var array = Ext.Array;\r
63 return array.filter(array.from(items), function(item) {\r
64 return item.target && item.target.isSplitter !== true;\r
65 });\r
66 },\r
67\r
68 beginLayout: function (ownerContext) {\r
69 var me = this;\r
70 me.callParent([ownerContext]);\r
71\r
72 // We need to reset the heights of the splitters so that they don't influence the\r
73 // layout (mostly overflow management).\r
74 var childItems = ownerContext.childItems,\r
75 rows = (ownerContext.rows = []),\r
76 length = childItems.length,\r
77 totalWidth = 2,\r
78 columnTargets = 0,\r
79 lastRow = 0,\r
80 maxColumns = me.owner.getMaxColumns(),\r
81 child, i, prev, row, splitter, target, width;\r
82\r
83 for (i = 0; i < length; ++i) {\r
84 target = (child = childItems[i]).target;\r
85 splitter = target && target.isSplitter;\r
86 columnTargets += (splitter ? 0 : 1);\r
87 width = splitter ? 0 : target.columnWidth || 1;\r
88\r
89 if (totalWidth + width > 1 || (maxColumns && (columnTargets > maxColumns))) {\r
90 if (prev) {\r
91 // We have wrapped and we have a previous item which is a splitter by\r
92 // definition. We have previously seen that splitter and setHeight(0)\r
93 // on it. We now setHeight(0) to effectively hide it.\r
94 prev.orphan = 1;\r
95 prev.el.setHeight(0);\r
96 }\r
97 totalWidth = 0;\r
98 columnTargets = 1;\r
99\r
100 if (rows.length) {\r
101 // We have encountered a row break condition\r
102 // As this is floating layout, classify the current row\r
103 // before proceeding\r
104 lastRow = rows.length - 1;\r
105 me.syncFirstLast(\r
106 me.getColumns(rows[lastRow].items)\r
107 );\r
108 }\r
109 rows.push(row = {\r
110 index: rows.length,\r
111 items: [],\r
112 maxHeight: 0\r
113 });\r
114 }\r
115\r
116 totalWidth += width;\r
117 row.items.push(child);\r
118 child.row = row;\r
119 target.rowIndex = row.index;\r
120\r
121 if (splitter) {\r
122 child.el.setHeight(1);\r
123 }\r
124\r
125 prev = child;\r
126 }\r
127\r
128 if (rows.length ) {\r
129 me.syncFirstLast(\r
130 me.getColumns(rows[rows.length-1].items)\r
131 );\r
132 }\r
133 },\r
134\r
135 beforeLayoutCycle: function (ownerContext) {\r
136 var me = this,\r
137 items = me.owner.items;\r
138\r
139 // We need to do this in beforeLayoutCycle because this changes the child items\r
140 // and hence needs to be considered before recursing.\r
141 if (me.splitterGen !== items.generation) {\r
142 me.syncSplitters();\r
143\r
144 // The syncSplitters call will change items.generation so do this last.\r
145 me.splitterGen = items.generation;\r
146 }\r
147\r
148 me.callParent(arguments);\r
149 },\r
150\r
151 finishedLayout: function (ownerContext) {\r
152 var items = ownerContext.childItems,\r
153 len = items.length,\r
154 box, child, i, target, row;\r
155\r
156 this.callParent([ownerContext]);\r
157\r
158 for (i = 0; i < len; i += 2) {\r
159 target = (child = items[i]).target;\r
160 box = target.lastBox;\r
161 row = child.row;\r
162 row.maxHeight = Math.max(row.maxHeight, box.height);\r
163\r
164 // Put this on the component so that it gets saved (we use this to fix up\r
165 // columnWidth on restore)\r
166 target.width = box.width;\r
167 }\r
168\r
169 for (i = 1; i < len; i += 2) {\r
170 target = (child = items[i]).target;\r
171 if (!child.orphan) {\r
172 target.el.setHeight(child.row.maxHeight);\r
173 }\r
174 }\r
175 },\r
176\r
177 /**\r
178 * This method synchronizes the splitters so that we have exactly one between each\r
179 * column.\r
180 * @private\r
181 */\r
182 syncSplitters: function () {\r
183 var me = this,\r
184 owner = me.owner,\r
185 items = owner.items.items,\r
186 index = items.length,\r
187 ok = true,\r
188 shouldBeSplitter = false,\r
189 item, splitter;\r
190\r
191 // Walk backwards over the items so that an insertion index is stable.\r
192 while (index-- > 0) {\r
193 item = items[index];\r
194\r
195 if (shouldBeSplitter) {\r
196 if (item.isSplitter) {\r
197 shouldBeSplitter = false;\r
198 } else {\r
199 // An item is adjacent to an item, so inject a splitter beyond\r
200 // the current item to separate the columns. Keep shouldBeSplitter\r
201 // at true since we just encountered an item.\r
202 if (ok) {\r
203 ok = false;\r
204 owner.suspendLayouts();\r
205 }\r
206 splitter = owner.add(index+1, me.getSplitterConfig());\r
207 }\r
208 } else {\r
209 if (item.isSplitter) {\r
210 // A splitter is adjacent to a splitter so we remove this one. We\r
211 // leave shouldBeSplitter at false because the next thing we see\r
212 // should still not be a splitter.\r
213 if (ok) {\r
214 ok = false;\r
215 owner.suspendLayouts();\r
216 }\r
217 owner.remove(item);\r
218 } else {\r
219 shouldBeSplitter = true;\r
220 }\r
221 }\r
222 }\r
223\r
224 // It is possible to exit the above with a splitter as the first item, but\r
225 // this is invalid so remove any such splitters.\r
226 while (items.length && (item = items[0]).isSplitter) {\r
227 if (ok) {\r
228 ok = false;\r
229 owner.suspendLayouts();\r
230 }\r
231 owner.remove(item);\r
232 }\r
233\r
234 if (!ok) {\r
235 owner.resumeLayouts();\r
236 }\r
237 },\r
238\r
239 syncFirstLast: function (items) {\r
240 var me = this,\r
241 firstCls = me.firstColumnCls,\r
242 lastCls = me.lastColumnCls,\r
243 len,\r
244 firstAndLast = [firstCls, lastCls],\r
245 i, item, last;\r
246\r
247 items = Ext.Array.from(items);\r
248 len = items.length;\r
249\r
250 for (i = 0; i < len; ++i ) {\r
251 item = items[i].target;\r
252 last = (i === len-1);\r
253\r
254 if (!i) { // if (first)\r
255 if (last) {\r
256 item.addCls(firstAndLast);\r
257 } else {\r
258 item.addCls(firstCls);\r
259 item.removeCls(lastCls);\r
260 }\r
261 } else if (last) {\r
262 item.addCls(lastCls);\r
263 item.removeCls(firstCls);\r
264 } else {\r
265 item.removeCls(firstAndLast);\r
266 }\r
267 }\r
268 }\r
269});\r