Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2007 Apple Inc. All rights reserved. | 2 * Copyright (C) 2007 Apple Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 */ | 27 */ |
| 28 | 28 |
| 29 /** | 29 /** |
| 30 * @unrestricted | 30 * @unrestricted |
| 31 */ | 31 */ |
| 32 UI.TreeOutline = class extends Common.Object { | 32 UI.TreeOutline = class extends Common.Object { |
| 33 /** | 33 /** |
| 34 * @param {boolean=} nonFocusable | 34 * @param {boolean=} nonFocusable |
| 35 */ | 35 */ |
| 36 constructor(nonFocusable) { | 36 constructor(nonFocusable) { |
|
pfeldman
2017/01/30 18:43:07
I'd remove this and only leave the setFocusable fo
einbinder
2017/02/01 22:51:35
Done.
| |
| 37 super(); | 37 super(); |
| 38 this._createRootElement(); | 38 this._createRootElement(); |
| 39 | 39 |
| 40 /** @type {?UI.TreeElement} */ | |
| 40 this.selectedTreeElement = null; | 41 this.selectedTreeElement = null; |
| 41 this.expandTreeElementsWhenArrowing = false; | 42 this.expandTreeElementsWhenArrowing = false; |
| 42 /** @type {?function(!UI.TreeElement, !UI.TreeElement):number} */ | 43 /** @type {?function(!UI.TreeElement, !UI.TreeElement):number} */ |
| 43 this._comparator = null; | 44 this._comparator = null; |
| 44 | 45 |
| 45 this.contentElement = this._rootElement._childrenListNode; | 46 this.contentElement = this._rootElement._childrenListNode; |
| 46 this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this) , true); | 47 this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this) , true); |
| 47 this.contentElement.addEventListener('focus', setFocused.bind(this, true), f alse); | |
| 48 this.contentElement.addEventListener('blur', setFocused.bind(this, false), f alse); | |
| 49 | 48 |
| 50 this.setFocusable(!nonFocusable); | 49 this._focusable = !nonFocusable; |
| 51 | 50 |
| 52 this.element = this.contentElement; | 51 this.element = this.contentElement; |
| 53 | 52 |
| 54 // Adjust to allow computing margin-left for the selection element. | 53 // Adjust to allow computing margin-left for the selection element. |
| 55 // Check the padding-left for the li element for correct value. | 54 // Check the padding-left for the li element for correct value. |
| 56 this._paddingSize = 0; | 55 this._paddingSize = 0; |
| 57 | |
| 58 /** | |
| 59 * @param {boolean} isFocused | |
| 60 * @this {UI.TreeOutline} | |
| 61 */ | |
| 62 function setFocused(isFocused) { | |
| 63 this._focused = isFocused; | |
| 64 if (this.selectedTreeElement) | |
| 65 this.selectedTreeElement._setFocused(this._focused); | |
| 66 } | |
| 67 } | 56 } |
| 68 | 57 |
| 69 _createRootElement() { | 58 _createRootElement() { |
| 70 this._rootElement = new UI.TreeElement(); | 59 this._rootElement = new UI.TreeElement(); |
| 71 this._rootElement.treeOutline = this; | 60 this._rootElement.treeOutline = this; |
| 72 this._rootElement.root = true; | 61 this._rootElement.root = true; |
| 73 this._rootElement.selectable = false; | 62 this._rootElement.selectable = false; |
| 74 this._rootElement.expanded = true; | 63 this._rootElement.expanded = true; |
| 75 this._rootElement._childrenListNode.classList.remove('children'); | 64 this._rootElement._childrenListNode.classList.remove('children'); |
| 76 } | 65 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 139 return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; | 128 return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; |
| 140 } | 129 } |
| 141 | 130 |
| 142 /** | 131 /** |
| 143 * @param {?function(!UI.TreeElement, !UI.TreeElement):number} comparator | 132 * @param {?function(!UI.TreeElement, !UI.TreeElement):number} comparator |
| 144 */ | 133 */ |
| 145 setComparator(comparator) { | 134 setComparator(comparator) { |
| 146 this._comparator = comparator; | 135 this._comparator = comparator; |
| 147 } | 136 } |
| 148 | 137 |
| 149 /** | |
| 150 * @param {boolean} focusable | |
| 151 */ | |
| 152 setFocusable(focusable) { | |
| 153 if (focusable) | |
| 154 this.contentElement.setAttribute('tabIndex', 0); | |
| 155 else | |
| 156 this.contentElement.removeAttribute('tabIndex'); | |
| 157 } | |
| 158 | |
| 159 focus() { | 138 focus() { |
| 160 this.contentElement.focus(); | 139 if (this.selectedTreeElement) |
|
pfeldman
2017/01/30 18:43:07
What if there is no selected element? Can there be
einbinder
2017/02/01 22:51:35
Selecting the contentElement now, and restoring fo
| |
| 140 this.selectedTreeElement.listItemElement.focus(); | |
| 161 } | 141 } |
| 162 | 142 |
| 163 /** | 143 /** |
| 164 * @param {!UI.TreeElement} element | 144 * @param {!UI.TreeElement} element |
| 165 */ | 145 */ |
| 166 _bindTreeElement(element) { | 146 _bindTreeElement(element) { |
| 167 if (element.treeOutline) | 147 if (element.treeOutline) |
| 168 console.error('Binding element for the second time: ' + new Error().stack) ; | 148 console.error('Binding element for the second time: ' + new Error().stack) ; |
| 169 element.treeOutline = this; | 149 element.treeOutline = this; |
| 170 element.onbind(); | 150 element.onbind(); |
| 171 } | 151 } |
| 172 | 152 |
| 173 /** | 153 /** |
| 174 * @param {!UI.TreeElement} element | 154 * @param {!UI.TreeElement} element |
| 175 */ | 155 */ |
| 176 _unbindTreeElement(element) { | 156 _unbindTreeElement(element) { |
| 177 if (!element.treeOutline) | 157 if (!element.treeOutline) |
| 178 console.error('Unbinding element that was not bound: ' + new Error().stack ); | 158 console.error('Unbinding element that was not bound: ' + new Error().stack ); |
| 179 | 159 |
| 180 element.deselect(); | 160 element.deselect(); |
| 181 element.onunbind(); | 161 element.onunbind(); |
| 182 element.treeOutline = null; | 162 element.treeOutline = null; |
| 163 element.listItemElement.removeAttribute('tabIndex'); | |
|
pfeldman
2017/01/30 18:43:07
It seems like you are now balancing this in the se
einbinder
2017/02/01 22:51:35
Yep, that is better.
| |
| 183 } | 164 } |
| 184 | 165 |
| 185 /** | 166 /** |
| 186 * @return {boolean} | 167 * @return {boolean} |
| 187 */ | 168 */ |
| 188 selectPrevious() { | 169 selectPrevious() { |
| 189 var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeEleme nt(true); | 170 var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeEleme nt(true); |
| 190 while (nextSelectedElement && !nextSelectedElement.selectable) | 171 while (nextSelectedElement && !nextSelectedElement.selectable) |
| 191 nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!thi s.expandTreeElementsWhenArrowing); | 172 nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!thi s.expandTreeElementsWhenArrowing); |
| 192 if (nextSelectedElement) { | 173 if (nextSelectedElement) { |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 216 * @param {number} paddingSize | 197 * @param {number} paddingSize |
| 217 */ | 198 */ |
| 218 setPaddingSize(paddingSize) { | 199 setPaddingSize(paddingSize) { |
| 219 this._paddingSize = paddingSize; | 200 this._paddingSize = paddingSize; |
| 220 } | 201 } |
| 221 | 202 |
| 222 /** | 203 /** |
| 223 * @param {!Event} event | 204 * @param {!Event} event |
| 224 */ | 205 */ |
| 225 _treeKeyDown(event) { | 206 _treeKeyDown(event) { |
| 226 if (event.target !== this.contentElement) | 207 if (!this.selectedTreeElement || event.target !== this.selectedTreeElement.l istItemElement || event.shiftKey || |
| 227 return; | 208 event.metaKey || event.ctrlKey) |
| 228 | |
| 229 if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ct rlKey) | |
| 230 return; | 209 return; |
| 231 | 210 |
| 232 var handled = false; | 211 var handled = false; |
| 233 if (event.key === 'ArrowUp' && !event.altKey) { | 212 if (event.key === 'ArrowUp' && !event.altKey) { |
| 234 handled = this.selectPrevious(); | 213 handled = this.selectPrevious(); |
| 235 } else if (event.key === 'ArrowDown' && !event.altKey) { | 214 } else if (event.key === 'ArrowDown' && !event.altKey) { |
| 236 handled = this.selectNext(); | 215 handled = this.selectNext(); |
| 237 } else if (event.key === 'ArrowLeft') { | 216 } else if (event.key === 'ArrowLeft') { |
| 238 handled = this.selectedTreeElement.collapseOrAscend(event.altKey); | 217 handled = this.selectedTreeElement.collapseOrAscend(event.altKey); |
| 239 } else if (event.key === 'ArrowRight') { | 218 } else if (event.key === 'ArrowRight') { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 280 ElementAttached: Symbol('ElementAttached'), | 259 ElementAttached: Symbol('ElementAttached'), |
| 281 ElementExpanded: Symbol('ElementExpanded'), | 260 ElementExpanded: Symbol('ElementExpanded'), |
| 282 ElementCollapsed: Symbol('ElementCollapsed'), | 261 ElementCollapsed: Symbol('ElementCollapsed'), |
| 283 ElementSelected: Symbol('ElementSelected') | 262 ElementSelected: Symbol('ElementSelected') |
| 284 }; | 263 }; |
| 285 | 264 |
| 286 /** | 265 /** |
| 287 * @unrestricted | 266 * @unrestricted |
| 288 */ | 267 */ |
| 289 UI.TreeOutlineInShadow = class extends UI.TreeOutline { | 268 UI.TreeOutlineInShadow = class extends UI.TreeOutline { |
| 290 constructor() { | 269 /** |
| 291 super(); | 270 * @param {boolean=} nonFocusable |
| 271 */ | |
| 272 constructor(nonFocusable) { | |
| 273 super(nonFocusable); | |
| 292 this.contentElement.classList.add('tree-outline'); | 274 this.contentElement.classList.add('tree-outline'); |
| 293 | 275 |
| 294 // Redefine element to the external one. | 276 // Redefine element to the external one. |
| 295 this.element = createElement('div'); | 277 this.element = createElement('div'); |
| 296 this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/treeo utline.css'); | 278 this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/treeo utline.css'); |
| 297 this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline- disclosure'); | 279 this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline- disclosure'); |
| 298 this._disclosureElement.appendChild(this.contentElement); | 280 this._disclosureElement.appendChild(this.contentElement); |
| 299 this._renderSelection = true; | 281 this._renderSelection = true; |
| 300 } | 282 } |
| 301 | 283 |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 675 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons '); | 657 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons '); |
| 676 this._trailingIconsElement.classList.add('icons-container'); | 658 this._trailingIconsElement.classList.add('icons-container'); |
| 677 this._listItemNode.appendChild(this._trailingIconsElement); | 659 this._listItemNode.appendChild(this._trailingIconsElement); |
| 678 this._ensureSelection(); | 660 this._ensureSelection(); |
| 679 } | 661 } |
| 680 this._trailingIconsElement.removeChildren(); | 662 this._trailingIconsElement.removeChildren(); |
| 681 for (var icon of icons) | 663 for (var icon of icons) |
| 682 this._trailingIconsElement.appendChild(icon); | 664 this._trailingIconsElement.appendChild(icon); |
| 683 } | 665 } |
| 684 | 666 |
| 685 /** | |
| 686 * @param {boolean} focused | |
| 687 */ | |
| 688 _setFocused(focused) { | |
| 689 this._focused = focused; | |
| 690 this._listItemNode.classList.toggle('force-white-icons', focused); | |
| 691 } | |
| 692 | 667 |
| 693 /** | 668 /** |
| 694 * @return {string} | 669 * @return {string} |
| 695 */ | 670 */ |
| 696 get tooltip() { | 671 get tooltip() { |
| 697 return this._tooltip || ''; | 672 return this._tooltip || ''; |
| 698 } | 673 } |
| 699 | 674 |
| 700 /** | 675 /** |
| 701 * @param {string} x | 676 * @param {string} x |
| (...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1021 | 996 |
| 1022 if (this.treeOutline.selectedTreeElement) | 997 if (this.treeOutline.selectedTreeElement) |
| 1023 this.treeOutline.selectedTreeElement.deselect(); | 998 this.treeOutline.selectedTreeElement.deselect(); |
| 1024 this.treeOutline.selectedTreeElement = null; | 999 this.treeOutline.selectedTreeElement = null; |
| 1025 | 1000 |
| 1026 if (this.treeOutline._rootElement === this) | 1001 if (this.treeOutline._rootElement === this) |
| 1027 return false; | 1002 return false; |
| 1028 | 1003 |
| 1029 this.selected = true; | 1004 this.selected = true; |
| 1030 | 1005 |
| 1006 this.treeOutline.selectedTreeElement = this; | |
| 1007 if (this.treeOutline._focusable) | |
| 1008 this._listItemNode.setAttribute('tabIndex', 0); | |
| 1031 if (!omitFocus) | 1009 if (!omitFocus) |
| 1032 this.treeOutline.focus(); | 1010 this.listItemElement.focus(); |
| 1033 | 1011 |
| 1034 // Focusing on another node may detach "this" from tree. | |
| 1035 if (!this.treeOutline) | |
| 1036 return false; | |
| 1037 this.treeOutline.selectedTreeElement = this; | |
| 1038 this._listItemNode.classList.add('selected'); | 1012 this._listItemNode.classList.add('selected'); |
| 1039 this._setFocused(this.treeOutline._focused); | |
| 1040 this.treeOutline.dispatchEventToListeners(UI.TreeOutline.Events.ElementSelec ted, this); | 1013 this.treeOutline.dispatchEventToListeners(UI.TreeOutline.Events.ElementSelec ted, this); |
| 1041 return this.onselect(selectedByUser); | 1014 return this.onselect(selectedByUser); |
| 1042 } | 1015 } |
| 1043 | 1016 |
| 1044 /** | 1017 /** |
| 1045 * @param {boolean=} omitFocus | 1018 * @param {boolean=} omitFocus |
| 1046 */ | 1019 */ |
| 1047 revealAndSelect(omitFocus) { | 1020 revealAndSelect(omitFocus) { |
| 1048 this.reveal(true); | 1021 this.reveal(true); |
| 1049 this.select(omitFocus); | 1022 this.select(omitFocus); |
| 1050 } | 1023 } |
| 1051 | 1024 |
| 1052 /** | 1025 /** |
| 1053 * @param {boolean=} supressOnDeselect | 1026 * @param {boolean=} supressOnDeselect |
| 1054 */ | 1027 */ |
| 1055 deselect(supressOnDeselect) { | 1028 deselect(supressOnDeselect) { |
| 1056 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !t his.selected) | 1029 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !t his.selected) |
|
pfeldman
2017/01/30 18:43:07
You might want to remove the tabIndex unconditiona
einbinder
2017/02/01 22:51:35
Done.
| |
| 1057 return; | 1030 return; |
| 1058 | 1031 |
| 1059 this.selected = false; | 1032 this.selected = false; |
| 1060 this.treeOutline.selectedTreeElement = null; | 1033 this.treeOutline.selectedTreeElement = null; |
| 1061 this._listItemNode.classList.remove('selected'); | 1034 this._listItemNode.classList.remove('selected'); |
| 1062 this._setFocused(false); | 1035 this._listItemNode.removeAttribute('tabIndex'); |
| 1063 } | 1036 } |
| 1064 | 1037 |
| 1065 _populateIfNeeded() { | 1038 _populateIfNeeded() { |
| 1066 if (this.treeOutline && this._expandable && !this._children) { | 1039 if (this.treeOutline && this._expandable && !this._children) { |
| 1067 this._children = []; | 1040 this._children = []; |
| 1068 this.onpopulate(); | 1041 this.onpopulate(); |
| 1069 } | 1042 } |
| 1070 } | 1043 } |
| 1071 | 1044 |
| 1072 onpopulate() { | 1045 onpopulate() { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1204 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLe ft; | 1177 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLe ft; |
| 1205 console.assert(paddingLeftValue.endsWith('px')); | 1178 console.assert(paddingLeftValue.endsWith('px')); |
| 1206 var computedLeftPadding = parseFloat(paddingLeftValue); | 1179 var computedLeftPadding = parseFloat(paddingLeftValue); |
| 1207 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; | 1180 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
| 1208 return event.pageX >= left && event.pageX <= left + UI.TreeElement._ArrowTog gleWidth && this._expandable; | 1181 return event.pageX >= left && event.pageX <= left + UI.TreeElement._ArrowTog gleWidth && this._expandable; |
| 1209 } | 1182 } |
| 1210 }; | 1183 }; |
| 1211 | 1184 |
| 1212 /** @const */ | 1185 /** @const */ |
| 1213 UI.TreeElement._ArrowToggleWidth = 10; | 1186 UI.TreeElement._ArrowToggleWidth = 10; |
| OLD | NEW |