OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview This implements a table control. | 6 * @fileoverview This implements a table control. |
7 */ | 7 */ |
8 | 8 |
9 cr.define('cr.ui', function() { | 9 cr.define('cr.ui', function() { |
10 /** @const */ var ListSelectionModel = cr.ui.ListSelectionModel; | 10 /** @const */ var ListSelectionModel = cr.ui.ListSelectionModel; |
(...skipping 14 matching lines...) Expand all Loading... |
25 Table.prototype = { | 25 Table.prototype = { |
26 __proto__: HTMLDivElement.prototype, | 26 __proto__: HTMLDivElement.prototype, |
27 | 27 |
28 columnModel_: new TableColumnModel([]), | 28 columnModel_: new TableColumnModel([]), |
29 | 29 |
30 /** | 30 /** |
31 * The table data model. | 31 * The table data model. |
32 * | 32 * |
33 * @type {cr.ui.ArrayDataModel} | 33 * @type {cr.ui.ArrayDataModel} |
34 */ | 34 */ |
35 get dataModel() { | 35 get dataModel() { return this.list_.dataModel; }, |
36 return this.list_.dataModel; | |
37 }, | |
38 set dataModel(dataModel) { | 36 set dataModel(dataModel) { |
39 if (this.list_.dataModel != dataModel) { | 37 if (this.list_.dataModel != dataModel) { |
40 if (this.list_.dataModel) { | 38 if (this.list_.dataModel) { |
41 this.list_.dataModel.removeEventListener('sorted', | 39 this.list_.dataModel.removeEventListener( |
42 this.boundHandleSorted_); | 40 'sorted', this.boundHandleSorted_); |
43 this.list_.dataModel.removeEventListener('change', | 41 this.list_.dataModel.removeEventListener( |
44 this.boundHandleChangeList_); | 42 'change', this.boundHandleChangeList_); |
45 this.list_.dataModel.removeEventListener('splice', | 43 this.list_.dataModel.removeEventListener( |
46 this.boundHandleChangeList_); | 44 'splice', this.boundHandleChangeList_); |
47 } | 45 } |
48 this.list_.dataModel = dataModel; | 46 this.list_.dataModel = dataModel; |
49 if (this.list_.dataModel) { | 47 if (this.list_.dataModel) { |
50 this.list_.dataModel.addEventListener('sorted', | 48 this.list_.dataModel.addEventListener( |
51 this.boundHandleSorted_); | 49 'sorted', this.boundHandleSorted_); |
52 this.list_.dataModel.addEventListener('change', | 50 this.list_.dataModel.addEventListener( |
53 this.boundHandleChangeList_); | 51 'change', this.boundHandleChangeList_); |
54 this.list_.dataModel.addEventListener('splice', | 52 this.list_.dataModel.addEventListener( |
55 this.boundHandleChangeList_); | 53 'splice', this.boundHandleChangeList_); |
56 } | 54 } |
57 this.header_.redraw(); | 55 this.header_.redraw(); |
58 } | 56 } |
59 }, | 57 }, |
60 | 58 |
61 /** | 59 /** |
62 * The list of table. | 60 * The list of table. |
63 * | 61 * |
64 * @type {cr.ui.List} | 62 * @type {cr.ui.List} |
65 */ | 63 */ |
66 get list() { | 64 get list() { return this.list_; }, |
67 return this.list_; | |
68 }, | |
69 | 65 |
70 /** | 66 /** |
71 * The table column model. | 67 * The table column model. |
72 * | 68 * |
73 * @type {cr.ui.table.TableColumnModel} | 69 * @type {cr.ui.table.TableColumnModel} |
74 */ | 70 */ |
75 get columnModel() { | 71 get columnModel() { return this.columnModel_; }, |
76 return this.columnModel_; | |
77 }, | |
78 set columnModel(columnModel) { | 72 set columnModel(columnModel) { |
79 if (this.columnModel_ != columnModel) { | 73 if (this.columnModel_ != columnModel) { |
80 if (this.columnModel_) | 74 if (this.columnModel_) |
81 this.columnModel_.removeEventListener('resize', this.boundResize_); | 75 this.columnModel_.removeEventListener('resize', this.boundResize_); |
82 this.columnModel_ = columnModel; | 76 this.columnModel_ = columnModel; |
83 | 77 |
84 if (this.columnModel_) | 78 if (this.columnModel_) |
85 this.columnModel_.addEventListener('resize', this.boundResize_); | 79 this.columnModel_.addEventListener('resize', this.boundResize_); |
86 this.list_.invalidate(); | 80 this.list_.invalidate(); |
87 this.redraw(); | 81 this.redraw(); |
88 } | 82 } |
89 }, | 83 }, |
90 | 84 |
91 /** | 85 /** |
92 * The table selection model. | 86 * The table selection model. |
93 * | 87 * |
94 * @type | 88 * @type |
95 * {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} | 89 * {cr.ui.ListSelectionModel|cr.ui.ListSingleSelectionModel} |
96 */ | 90 */ |
97 get selectionModel() { | 91 get selectionModel() { return this.list_.selectionModel; }, |
98 return this.list_.selectionModel; | |
99 }, | |
100 set selectionModel(selectionModel) { | 92 set selectionModel(selectionModel) { |
101 if (this.list_.selectionModel != selectionModel) { | 93 if (this.list_.selectionModel != selectionModel) { |
102 if (this.dataModel) | 94 if (this.dataModel) |
103 selectionModel.adjustLength(this.dataModel.length); | 95 selectionModel.adjustLength(this.dataModel.length); |
104 this.list_.selectionModel = selectionModel; | 96 this.list_.selectionModel = selectionModel; |
105 } | 97 } |
106 }, | 98 }, |
107 | 99 |
108 /** | 100 /** |
109 * The accessor to "autoExpands" property of the list. | 101 * The accessor to "autoExpands" property of the list. |
110 * | 102 * |
111 * @type {boolean} | 103 * @type {boolean} |
112 */ | 104 */ |
113 get autoExpands() { | 105 get autoExpands() { return this.list_.autoExpands; }, |
114 return this.list_.autoExpands; | 106 set autoExpands(autoExpands) { this.list_.autoExpands = autoExpands; }, |
115 }, | |
116 set autoExpands(autoExpands) { | |
117 this.list_.autoExpands = autoExpands; | |
118 }, | |
119 | 107 |
120 get fixedHeight() { | 108 get fixedHeight() { return this.list_.fixedHeight; }, |
121 return this.list_.fixedHeight; | 109 set fixedHeight(fixedHeight) { this.list_.fixedHeight = fixedHeight; }, |
122 }, | |
123 set fixedHeight(fixedHeight) { | |
124 this.list_.fixedHeight = fixedHeight; | |
125 }, | |
126 | 110 |
127 /** | 111 /** |
128 * Returns render function for row. | 112 * Returns render function for row. |
129 * @return {function(*, cr.ui.Table): HTMLElement} Render function. | 113 * @return {function(*, cr.ui.Table): HTMLElement} Render function. |
130 */ | 114 */ |
131 getRenderFunction: function() { | 115 getRenderFunction: function() { return this.list_.renderFunction_; }, |
132 return this.list_.renderFunction_; | |
133 }, | |
134 | 116 |
135 /** | 117 /** |
136 * Sets render function for row. | 118 * Sets render function for row. |
137 * @param {function(*, cr.ui.Table): HTMLElement} renderFunction Render | 119 * @param {function(*, cr.ui.Table): HTMLElement} renderFunction Render |
138 * function. | 120 * function. |
139 */ | 121 */ |
140 setRenderFunction: function(renderFunction) { | 122 setRenderFunction: function(renderFunction) { |
141 if (renderFunction === this.list_.renderFunction_) | 123 if (renderFunction === this.list_.renderFunction_) |
142 return; | 124 return; |
143 | 125 |
144 this.list_.renderFunction_ = renderFunction; | 126 this.list_.renderFunction_ = renderFunction; |
145 cr.dispatchSimpleEvent(this, 'change'); | 127 cr.dispatchSimpleEvent(this, 'change'); |
146 }, | 128 }, |
147 | 129 |
148 /** | 130 /** |
149 * The header of the table. | 131 * The header of the table. |
150 * | 132 * |
151 * @type {cr.ui.table.TableColumnModel} | 133 * @type {cr.ui.table.TableColumnModel} |
152 */ | 134 */ |
153 get header() { | 135 get header() { return this.header_; }, |
154 return this.header_; | |
155 }, | |
156 | 136 |
157 /** | 137 /** |
158 * Initializes the element. | 138 * Initializes the element. |
159 */ | 139 */ |
160 decorate: function() { | 140 decorate: function() { |
161 this.header_ = this.ownerDocument.createElement('div'); | 141 this.header_ = this.ownerDocument.createElement('div'); |
162 this.list_ = this.ownerDocument.createElement('list'); | 142 this.list_ = this.ownerDocument.createElement('list'); |
163 | 143 |
164 this.appendChild(this.header_); | 144 this.appendChild(this.header_); |
165 this.appendChild(this.list_); | 145 this.appendChild(this.list_); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
212 resize: function() { | 192 resize: function() { |
213 // We resize columns only instead of full redraw. | 193 // We resize columns only instead of full redraw. |
214 this.list_.resize(); | 194 this.list_.resize(); |
215 this.header_.resize(); | 195 this.header_.resize(); |
216 }, | 196 }, |
217 | 197 |
218 /** | 198 /** |
219 * Ensures that a given index is inside the viewport. | 199 * Ensures that a given index is inside the viewport. |
220 * @param {number} i The index of the item to scroll into view. | 200 * @param {number} i The index of the item to scroll into view. |
221 */ | 201 */ |
222 scrollIndexIntoView: function(i) { | 202 scrollIndexIntoView: function(i) { this.list_.scrollIndexIntoView(i); }, |
223 this.list_.scrollIndexIntoView(i); | |
224 }, | |
225 | 203 |
226 /** | 204 /** |
227 * Find the list item element at the given index. | 205 * Find the list item element at the given index. |
228 * @param {number} index The index of the list item to get. | 206 * @param {number} index The index of the list item to get. |
229 * @return {cr.ui.ListItem} The found list item or null if not found. | 207 * @return {cr.ui.ListItem} The found list item or null if not found. |
230 */ | 208 */ |
231 getListItemByIndex: function(index) { | 209 getListItemByIndex: function(index) { |
232 return this.list_.getListItemByIndex(index); | 210 return this.list_.getListItemByIndex(index); |
233 }, | 211 }, |
234 | 212 |
235 /** | 213 /** |
236 * This handles data model 'sorted' event. | 214 * This handles data model 'sorted' event. |
237 * After sorting we need to redraw header | 215 * After sorting we need to redraw header |
238 * @param {Event} e The 'sorted' event. | 216 * @param {Event} e The 'sorted' event. |
239 */ | 217 */ |
240 handleSorted_: function(e) { | 218 handleSorted_: function(e) { this.header_.redraw(); }, |
241 this.header_.redraw(); | |
242 }, | |
243 | 219 |
244 /** | 220 /** |
245 * This handles data model 'change' and 'splice' events. | 221 * This handles data model 'change' and 'splice' events. |
246 * Since they may change the visibility of scrollbar, table may need to | 222 * Since they may change the visibility of scrollbar, table may need to |
247 * re-calculation the width of column headers. | 223 * re-calculation the width of column headers. |
248 * @param {Event} e The 'change' or 'splice' event. | 224 * @param {Event} e The 'change' or 'splice' event. |
249 */ | 225 */ |
250 handleChangeList_: function(e) { | 226 handleChangeList_: function(e) { |
251 requestAnimationFrame(this.header_.updateWidth.bind(this.header_)); | 227 requestAnimationFrame(this.header_.updateWidth.bind(this.header_)); |
252 }, | 228 }, |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 var container = doc.createElement('li'); | 311 var container = doc.createElement('li'); |
336 container.style.display = 'inline-block'; | 312 container.style.display = 'inline-block'; |
337 container.style.textAlign = 'start'; | 313 container.style.textAlign = 'start'; |
338 // The container will have width of the longest cell. | 314 // The container will have width of the longest cell. |
339 container.style.webkitBoxOrient = 'vertical'; | 315 container.style.webkitBoxOrient = 'vertical'; |
340 | 316 |
341 // Ensure all needed data available. | 317 // Ensure all needed data available. |
342 dm.prepareSort(columnId, function() { | 318 dm.prepareSort(columnId, function() { |
343 // Select at most MAXIMUM_ROWS_TO_MEASURE items around visible area. | 319 // Select at most MAXIMUM_ROWS_TO_MEASURE items around visible area. |
344 var items = list.getItemsInViewPort(list.scrollTop, listHeight); | 320 var items = list.getItemsInViewPort(list.scrollTop, listHeight); |
345 var firstIndex = Math.floor(Math.max(0, | 321 var firstIndex = Math.floor(Math.max( |
346 (items.last + items.first - MAXIMUM_ROWS_TO_MEASURE) / 2)); | 322 0, (items.last + items.first - MAXIMUM_ROWS_TO_MEASURE) / 2)); |
347 var lastIndex = Math.min(dm.length, | 323 var lastIndex = |
348 firstIndex + MAXIMUM_ROWS_TO_MEASURE); | 324 Math.min(dm.length, firstIndex + MAXIMUM_ROWS_TO_MEASURE); |
349 for (var i = firstIndex; i < lastIndex; i++) { | 325 for (var i = firstIndex; i < lastIndex; i++) { |
350 var item = dm.item(i); | 326 var item = dm.item(i); |
351 var div = doc.createElement('div'); | 327 var div = doc.createElement('div'); |
352 div.className = 'table-row-cell'; | 328 div.className = 'table-row-cell'; |
353 div.appendChild(render(item, columnId, table)); | 329 div.appendChild(render(item, columnId, table)); |
354 container.appendChild(div); | 330 container.appendChild(div); |
355 } | 331 } |
356 list.appendChild(container); | 332 list.appendChild(container); |
357 var width = parseFloat(window.getComputedStyle(container).width); | 333 var width = parseFloat(window.getComputedStyle(container).width); |
358 list.removeChild(container); | 334 list.removeChild(container); |
359 cm.setWidth(index, width); | 335 cm.setWidth(index, width); |
360 }); | 336 }); |
361 }, | 337 }, |
362 | 338 |
363 normalizeColumns: function() { | 339 normalizeColumns: function() { |
364 this.columnModel.normalizeWidths(this.clientWidth); | 340 this.columnModel.normalizeWidths(this.clientWidth); |
365 } | 341 } |
366 }; | 342 }; |
367 | 343 |
368 /** | 344 /** |
369 * Whether the table or one of its descendents has focus. This is necessary | 345 * Whether the table or one of its descendents has focus. This is necessary |
370 * because table contents can contain controls that can be focused, and for | 346 * because table contents can contain controls that can be focused, and for |
371 * some purposes (e.g., styling), the table can still be conceptually focused | 347 * some purposes (e.g., styling), the table can still be conceptually focused |
372 * at that point even though it doesn't actually have the page focus. | 348 * at that point even though it doesn't actually have the page focus. |
373 */ | 349 */ |
374 cr.defineProperty(Table, 'hasElementFocus', cr.PropertyKind.BOOL_ATTR); | 350 cr.defineProperty(Table, 'hasElementFocus', cr.PropertyKind.BOOL_ATTR); |
375 | 351 |
376 return { | 352 return {Table: Table}; |
377 Table: Table | |
378 }; | |
379 }); | 353 }); |
OLD | NEW |