Chromium Code Reviews| 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 // require: array_data_model.js | 5 // require: array_data_model.js |
| 6 // require: list_selection_model.js | 6 // require: list_selection_model.js |
| 7 // require: list_selection_controller.js | 7 // require: list_selection_controller.js |
| 8 // require: list_item.js | 8 // require: list_item.js |
| 9 | 9 |
| 10 /** | 10 /** |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 185 this.boundHandleDataModelPermuted_); | 185 this.boundHandleDataModelPermuted_); |
| 186 this.dataModel_.removeEventListener('change', | 186 this.dataModel_.removeEventListener('change', |
| 187 this.boundHandleDataModelChange_); | 187 this.boundHandleDataModelChange_); |
| 188 this.dataModel_.removeEventListener('splice', | 188 this.dataModel_.removeEventListener('splice', |
| 189 this.boundHandleDataModelChange_); | 189 this.boundHandleDataModelChange_); |
| 190 } | 190 } |
| 191 | 191 |
| 192 this.dataModel_ = dataModel; | 192 this.dataModel_ = dataModel; |
| 193 | 193 |
| 194 this.cachedItems_ = {}; | 194 this.cachedItems_ = {}; |
| 195 this.cachedItemSizes_ = {}; | 195 this.cachedItemHeights_ = {}; |
| 196 this.selectionModel.clear(); | 196 this.selectionModel.clear(); |
| 197 if (dataModel) | 197 if (dataModel) |
| 198 this.selectionModel.adjustLength(dataModel.length); | 198 this.selectionModel.adjustLength(dataModel.length); |
| 199 | 199 |
| 200 if (this.dataModel_) { | 200 if (this.dataModel_) { |
| 201 this.dataModel_.addEventListener( | 201 this.dataModel_.addEventListener( |
| 202 'permuted', | 202 'permuted', |
| 203 this.boundHandleDataModelPermuted_); | 203 this.boundHandleDataModelPermuted_); |
| 204 this.dataModel_.addEventListener('change', | 204 this.dataModel_.addEventListener('change', |
| 205 this.boundHandleDataModelChange_); | 205 this.boundHandleDataModelChange_); |
| (...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 376 this.addEventListener('blur', this.handleElementBlur_, true); | 376 this.addEventListener('blur', this.handleElementBlur_, true); |
| 377 this.addEventListener('scroll', this.handleScroll.bind(this)); | 377 this.addEventListener('scroll', this.handleScroll.bind(this)); |
| 378 this.setAttribute('role', 'listbox'); | 378 this.setAttribute('role', 'listbox'); |
| 379 | 379 |
| 380 // Make list focusable | 380 // Make list focusable |
| 381 if (!this.hasAttribute('tabindex')) | 381 if (!this.hasAttribute('tabindex')) |
| 382 this.tabIndex = 0; | 382 this.tabIndex = 0; |
| 383 }, | 383 }, |
| 384 | 384 |
| 385 /** | 385 /** |
| 386 * @param {ListItem=} item The list item to use to do the measuring. | |
|
James Hawkins
2012/01/26 01:34:05
"The list item to measure."
yoshiki
2012/01/26 10:10:45
Done.
| |
| 387 * @return {number} The height of the given item. If the fixed height on CSS | |
| 388 * is set, uses that value. Otherwise, measures the size. | |
|
mazda
2012/01/26 09:37:16
Please note that the fixed height is used only if
yoshiki
2012/01/26 10:10:45
Done.
| |
| 389 * @private | |
| 390 */ | |
| 391 measureItemHeight_: function(item) { | |
| 392 var height = item.style.height; | |
| 393 // Uses the fixed height if set it on CSS, to save a time of rayout | |
|
James Hawkins
2012/01/26 01:34:05
s/rayout/layout/
yoshiki
2012/01/26 10:10:45
Done.
| |
| 394 // calculation. | |
| 395 if (height && height.substr(-2) == 'px') | |
| 396 return parseInt(height.substr(0, height.length - 2)); | |
| 397 | |
| 398 return measureItem(this, item).height; | |
| 399 }, | |
| 400 | |
| 401 /** | |
| 386 * @return {number} The height of default item, measuring it if necessary. | 402 * @return {number} The height of default item, measuring it if necessary. |
| 387 * @private | 403 * @private |
| 388 */ | 404 */ |
| 389 getDefaultItemHeight_: function() { | 405 getDefaultItemHeight_: function() { |
| 390 return this.getDefaultItemSize_().height; | 406 return this.getDefaultItemSize_().height; |
| 391 }, | 407 }, |
| 392 | 408 |
| 393 /** | 409 /** |
| 394 * @param {number} index The index of the item. | 410 * @param {number} index The index of the item. |
| 395 * @return {number} The height of the item. | 411 * @return {number} The height of the item, measuring it if necessary. |
| 396 */ | 412 */ |
| 397 getItemHeightByIndex_: function(index) { | 413 getItemHeightByIndex_: function(index) { |
| 398 // If |this.fixedHeight_| is true, all the rows have same default height. | 414 // If |this.fixedHeight_| is true, all the rows have same default height. |
| 399 if (this.fixedHeight_) | 415 if (this.fixedHeight_) |
| 400 return this.getDefaultItemHeight_(); | 416 return this.getDefaultItemHeight_(); |
| 401 | 417 |
| 402 if (this.cachedItemSizes_[index]) | 418 if (this.cachedItemHeights_[index]) |
| 403 return this.cachedItemSizes_[index].height; | 419 return this.cachedItemHeights_[index]; |
| 404 | 420 |
| 405 var item = this.getListItemByIndex(index); | 421 var item = this.getListItemByIndex(index); |
| 406 if (item) | 422 if (item) |
| 407 return this.getItemSize_(item).height; | 423 return this.measureItemHeight_(item); |
| 408 | 424 |
| 409 return this.getDefaultItemHeight_(); | 425 return this.getDefaultItemHeight_(); |
| 410 }, | 426 }, |
| 411 | 427 |
| 412 /** | 428 /** |
| 413 * @return {number} The width of default item, measuring it if necessary. | |
| 414 * @private | |
| 415 */ | |
| 416 getDefaultItemWidth_: function() { | |
| 417 return this.getDefaultItemSize_().width; | |
| 418 }, | |
| 419 | |
| 420 /** | |
| 421 * @return {{height: number, width: number}} The height and width | 429 * @return {{height: number, width: number}} The height and width |
| 422 * of default item, measuring it if necessary. | 430 * of default item, measuring it if necessary. |
| 423 * @private | 431 * @private |
| 424 */ | 432 */ |
| 425 getDefaultItemSize_: function() { | 433 getDefaultItemSize_: function() { |
| 426 if (!this.measured_ || !this.measured_.height) { | 434 if (!this.measured_ || !this.measured_.height) { |
| 427 this.measured_ = measureItem(this); | 435 this.measured_ = measureItem(this); |
| 428 } | 436 } |
| 429 return this.measured_; | 437 return this.measured_; |
| 430 }, | 438 }, |
| 431 | 439 |
| 432 /** | 440 /** |
| 433 * @return {{height: number, width: number}} The height and width | |
| 434 * of an item, measuring it if necessary. | |
| 435 * @private | |
| 436 */ | |
| 437 getItemSize_: function(item) { | |
| 438 if (this.cachedItemSizes_[item.listIndex]) | |
| 439 return this.cachedItemSizes_[item.listIndex]; | |
| 440 | |
| 441 var size = measureItem(this, item); | |
| 442 if (!isNaN(size.height) && !isNaN(size.weight)) | |
| 443 this.cachedItemSizes_[item.listIndex] = size; | |
| 444 | |
| 445 return size; | |
| 446 }, | |
| 447 | |
| 448 /** | |
| 449 * Callback for the double click event. | 441 * Callback for the double click event. |
| 450 * @param {Event} e The mouse event object. | 442 * @param {Event} e The mouse event object. |
| 451 * @private | 443 * @private |
| 452 */ | 444 */ |
| 453 handleDoubleClick_: function(e) { | 445 handleDoubleClick_: function(e) { |
| 454 if (this.disabled) | 446 if (this.disabled) |
| 455 return; | 447 return; |
| 456 | 448 |
| 457 var target = this.getListItemAncestor(e.target); | 449 var target = this.getListItemAncestor(e.target); |
| 458 if (target) | 450 if (target) |
| (...skipping 514 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 973 while (currentIndex < lastIndex) | 965 while (currentIndex < lastIndex) |
| 974 insert(this); | 966 insert(this); |
| 975 }, | 967 }, |
| 976 | 968 |
| 977 /** | 969 /** |
| 978 * Ensures that all the item sizes in the list have been already cached. | 970 * Ensures that all the item sizes in the list have been already cached. |
| 979 */ | 971 */ |
| 980 ensureAllItemSizesInCache: function() { | 972 ensureAllItemSizesInCache: function() { |
| 981 var measuringIndexes = []; | 973 var measuringIndexes = []; |
| 982 for (var y = 0; y < this.dataModel.length; y++) { | 974 for (var y = 0; y < this.dataModel.length; y++) { |
| 983 if (!this.cachedItemSizes_[y]) | 975 if (!this.cachedItemHeights_[y]) |
| 984 measuringIndexes.push(y); | 976 measuringIndexes.push(y); |
| 985 } | 977 } |
| 986 | 978 |
| 987 var measuringItems = []; | 979 var measuringItems = []; |
| 988 // Adds temporary elements. | 980 // Adds temporary elements. |
| 989 for (var y = 0; y < measuringIndexes.length; y++) { | 981 for (var y = 0; y < measuringIndexes.length; y++) { |
| 990 var index = measuringIndexes[y]; | 982 var index = measuringIndexes[y]; |
| 991 var dataItem = this.dataModel.item(index); | 983 var dataItem = this.dataModel.item(index); |
| 992 var listItem = this.cachedItems_[index] || this.createItem(dataItem); | 984 var listItem = this.cachedItems_[index] || this.createItem(dataItem); |
| 993 listItem.listIndex = index; | 985 listItem.listIndex = index; |
| 994 this.appendChild(listItem); | 986 this.appendChild(listItem); |
| 995 this.cachedItems_[index] = listItem; | 987 this.cachedItems_[index] = listItem; |
| 996 measuringItems.push(listItem); | 988 measuringItems.push(listItem); |
| 997 } | 989 } |
| 998 | 990 |
| 999 // All mesurings must be placed after adding all the elements, to prevent | 991 // All mesurings must be placed after adding all the elements, to prevent |
| 1000 // performance reducing. | 992 // performance reducing. |
| 1001 for (var y = 0; y < measuringIndexes.length; y++) { | 993 for (var y = 0; y < measuringIndexes.length; y++) { |
| 1002 var index = measuringIndexes[y]; | 994 var index = measuringIndexes[y]; |
| 1003 this.cachedItemSizes_[index] = measureItem(this, measuringItems[y]); | 995 var height = this.measureItemHeight_(measuringItems[y]); |
|
James Hawkins
2012/01/26 01:34:05
No need to temp variable, just assign directly.
yoshiki
2012/01/26 10:10:45
Done.
| |
| 996 this.cachedItemHeights_[index] = height; | |
| 1004 } | 997 } |
| 1005 | 998 |
| 1006 // Removes all the temprary elements. | 999 // Removes all the temprary elements. |
| 1007 for (var y = 0; y < measuringIndexes.length; y++) { | 1000 for (var y = 0; y < measuringIndexes.length; y++) { |
| 1008 this.removeChild(measuringItems[y]); | 1001 this.removeChild(measuringItems[y]); |
| 1009 } | 1002 } |
| 1010 }, | 1003 }, |
| 1011 | 1004 |
| 1012 /** | 1005 /** |
| 1013 * Returns the height of after filler in the list. | 1006 * Returns the height of after filler in the list. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1051 | 1044 |
| 1052 // We cache the list items since creating the DOM nodes is the most | 1045 // We cache the list items since creating the DOM nodes is the most |
| 1053 // expensive part of redrawing. | 1046 // expensive part of redrawing. |
| 1054 var cachedItems = this.cachedItems_ || {}; | 1047 var cachedItems = this.cachedItems_ || {}; |
| 1055 var newCachedItems = {}; | 1048 var newCachedItems = {}; |
| 1056 | 1049 |
| 1057 var autoExpands = this.autoExpands_; | 1050 var autoExpands = this.autoExpands_; |
| 1058 var scrollTop = this.scrollTop; | 1051 var scrollTop = this.scrollTop; |
| 1059 var clientHeight = this.clientHeight; | 1052 var clientHeight = this.clientHeight; |
| 1060 | 1053 |
| 1061 var lastItemHeights = this.getHeightsForIndex_(dataModel.length - 1); | |
| 1062 var desiredScrollHeight = lastItemHeights.top + lastItemHeights.height; | |
| 1063 | |
| 1064 var itemsInViewPort = this.getItemsInViewPort(scrollTop, clientHeight); | 1054 var itemsInViewPort = this.getItemsInViewPort(scrollTop, clientHeight); |
| 1065 // Draws the hidden rows just above/below the viewport to prevent | 1055 // Draws the hidden rows just above/below the viewport to prevent |
| 1066 // flashing in scroll. | 1056 // flashing in scroll. |
| 1067 var firstIndex = Math.max(0, itemsInViewPort.first - 1); | 1057 var firstIndex = Math.max(0, itemsInViewPort.first - 1); |
| 1068 var lastIndex = Math.min(itemsInViewPort.last + 1, dataModel.length); | 1058 var lastIndex = Math.min(itemsInViewPort.last + 1, dataModel.length); |
| 1069 | 1059 |
| 1070 var beforeFillerHeight = | 1060 var beforeFillerHeight = |
| 1071 this.autoExpands ? 0 : this.getItemTop(firstIndex); | 1061 this.autoExpands ? 0 : this.getItemTop(firstIndex); |
| 1072 var afterFillerHeight = | 1062 var afterFillerHeight = |
| 1073 this.autoExpands ? 0 : this.getAfterFillerHeight(lastIndex); | 1063 this.autoExpands ? 0 : this.getAfterFillerHeight(lastIndex); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1106 this.firstIndex_ = firstIndex; | 1096 this.firstIndex_ = firstIndex; |
| 1107 this.lastIndex_ = lastIndex; | 1097 this.lastIndex_ = lastIndex; |
| 1108 | 1098 |
| 1109 this.remainingSpace_ = itemsInViewPort.last > dataModel.length; | 1099 this.remainingSpace_ = itemsInViewPort.last > dataModel.length; |
| 1110 this.cachedItems_ = newCachedItems; | 1100 this.cachedItems_ = newCachedItems; |
| 1111 | 1101 |
| 1112 // Mesurings must be placed after adding all the elements, to prevent | 1102 // Mesurings must be placed after adding all the elements, to prevent |
| 1113 // performance reducing. | 1103 // performance reducing. |
| 1114 if (!this.fixedHeight_) { | 1104 if (!this.fixedHeight_) { |
| 1115 for (var y = firstIndex; y < lastIndex; y++) | 1105 for (var y = firstIndex; y < lastIndex; y++) |
| 1116 this.cachedItemSizes_[y] = measureItem(this, newCachedItems[y]); | 1106 var height = this.measureItemHeight_(newCachedItems[y]); |
| 1107 this.cachedItemHeights_[y] = height; | |
| 1117 } | 1108 } |
| 1118 | 1109 |
| 1119 // Measure again in case the item height has changed due to a page zoom. | 1110 // Measure again in case the item height has changed due to a page zoom. |
| 1120 // | 1111 // |
| 1121 // The measure above is only done the first time but this measure is done | 1112 // The measure above is only done the first time but this measure is done |
| 1122 // after every redraw. It is done in a timeout so it will not trigger | 1113 // after every redraw. It is done in a timeout so it will not trigger |
| 1123 // a reflow (which made the redraw speed 3 times slower on my system). | 1114 // a reflow (which made the redraw speed 3 times slower on my system). |
| 1124 // By using a timeout the measuring will happen later when there is no | 1115 // By using a timeout the measuring will happen later when there is no |
| 1125 // need for a reflow. | 1116 // need for a reflow. |
| 1126 if (listItem && this.fixedHeight_) { | 1117 if (listItem && this.fixedHeight_) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1169 * because list items can contain controls that can be focused, and for some | 1160 * because list items can contain controls that can be focused, and for some |
| 1170 * purposes (e.g., styling), the list can still be conceptually focused at | 1161 * purposes (e.g., styling), the list can still be conceptually focused at |
| 1171 * that point even though it doesn't actually have the page focus. | 1162 * that point even though it doesn't actually have the page focus. |
| 1172 */ | 1163 */ |
| 1173 cr.defineProperty(List, 'hasElementFocus', cr.PropertyKind.BOOL_ATTR); | 1164 cr.defineProperty(List, 'hasElementFocus', cr.PropertyKind.BOOL_ATTR); |
| 1174 | 1165 |
| 1175 return { | 1166 return { |
| 1176 List: List | 1167 List: List |
| 1177 } | 1168 } |
| 1178 }); | 1169 }); |
| OLD | NEW |