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 19 matching lines...) Expand all Loading... | |
| 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) { |
| 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 | |
| 54 /** | |
| 55 * @param {boolean} isFocused | |
| 56 * @this {UI.TreeOutline} | |
| 57 */ | |
| 58 function setFocused(isFocused) { | |
| 59 this._focused = isFocused; | |
| 60 if (this.selectedTreeElement) | |
| 61 this.selectedTreeElement._setFocused(this._focused); | |
| 62 } | |
| 63 } | 52 } |
| 64 | 53 |
| 65 _createRootElement() { | 54 _createRootElement() { |
| 66 this._rootElement = new UI.TreeElement(); | 55 this._rootElement = new UI.TreeElement(); |
| 67 this._rootElement.treeOutline = this; | 56 this._rootElement.treeOutline = this; |
| 68 this._rootElement.root = true; | 57 this._rootElement.root = true; |
| 69 this._rootElement.selectable = false; | 58 this._rootElement.selectable = false; |
| 70 this._rootElement.expanded = true; | 59 this._rootElement.expanded = true; |
| 71 this._rootElement._childrenListNode.classList.remove('children'); | 60 this._rootElement._childrenListNode.classList.remove('children'); |
| 72 } | 61 } |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 135 return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; | 124 return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; |
| 136 } | 125 } |
| 137 | 126 |
| 138 /** | 127 /** |
| 139 * @param {?function(!UI.TreeElement, !UI.TreeElement):number} comparator | 128 * @param {?function(!UI.TreeElement, !UI.TreeElement):number} comparator |
| 140 */ | 129 */ |
| 141 setComparator(comparator) { | 130 setComparator(comparator) { |
| 142 this._comparator = comparator; | 131 this._comparator = comparator; |
| 143 } | 132 } |
| 144 | 133 |
| 145 /** | 134 focus() { |
| 146 * @param {boolean} focusable | 135 if (this.selectedTreeElement) |
| 147 */ | 136 this.selectedTreeElement.listItemElement.focus(); |
| 148 setFocusable(focusable) { | |
| 149 if (focusable) | |
| 150 this.contentElement.setAttribute('tabIndex', 0); | |
| 151 else | 137 else |
| 152 this.contentElement.removeAttribute('tabIndex'); | 138 this.contentElement.focus(); |
|
pfeldman
2017/01/21 04:57:34
There is no tabIndex on contentElement, is it focu
einbinder
2017/01/21 06:20:32
Ah, it isn't. I think its ok for empty TreeOutline
| |
| 153 } | |
| 154 | |
| 155 focus() { | |
| 156 this.contentElement.focus(); | |
| 157 } | 139 } |
| 158 | 140 |
| 159 /** | 141 /** |
| 160 * @param {!UI.TreeElement} element | 142 * @param {!UI.TreeElement} element |
| 161 */ | 143 */ |
| 162 _bindTreeElement(element) { | 144 _bindTreeElement(element) { |
| 163 if (element.treeOutline) | 145 if (element.treeOutline) |
| 164 console.error('Binding element for the second time: ' + new Error().stack) ; | 146 console.error('Binding element for the second time: ' + new Error().stack) ; |
| 165 element.treeOutline = this; | 147 element.treeOutline = this; |
| 166 element.onbind(); | 148 element.onbind(); |
| 149 if (this._focusable) | |
| 150 element.tabIndex = -1; | |
|
pfeldman
2017/01/21 04:57:34
element does not have tabIndex property. use setAt
einbinder
2017/01/21 06:20:32
Ok!
| |
| 167 } | 151 } |
| 168 | 152 |
| 169 /** | 153 /** |
| 170 * @param {!UI.TreeElement} element | 154 * @param {!UI.TreeElement} element |
| 171 */ | 155 */ |
| 172 _unbindTreeElement(element) { | 156 _unbindTreeElement(element) { |
| 173 if (!element.treeOutline) | 157 if (!element.treeOutline) |
| 174 console.error('Unbinding element that was not bound: ' + new Error().stack ); | 158 console.error('Unbinding element that was not bound: ' + new Error().stack ); |
| 175 | 159 |
| 176 element.deselect(); | 160 element.deselect(); |
| 177 element.onunbind(); | 161 element.onunbind(); |
| 178 element.treeOutline = null; | 162 element.treeOutline = null; |
| 163 element.listItemElement.removeAttribute('tabIndex'); | |
| 179 } | 164 } |
| 180 | 165 |
| 181 /** | 166 /** |
| 182 * @return {boolean} | 167 * @return {boolean} |
| 183 */ | 168 */ |
| 184 selectPrevious() { | 169 selectPrevious() { |
| 185 var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeEleme nt(true); | 170 var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeEleme nt(true); |
| 186 while (nextSelectedElement && !nextSelectedElement.selectable) | 171 while (nextSelectedElement && !nextSelectedElement.selectable) |
| 187 nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!thi s.expandTreeElementsWhenArrowing); | 172 nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!thi s.expandTreeElementsWhenArrowing); |
| 188 if (nextSelectedElement) { | 173 if (nextSelectedElement) { |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 205 nextSelectedElement.select(false, true); | 190 nextSelectedElement.select(false, true); |
| 206 return true; | 191 return true; |
| 207 } | 192 } |
| 208 return false; | 193 return false; |
| 209 } | 194 } |
| 210 | 195 |
| 211 /** | 196 /** |
| 212 * @param {!Event} event | 197 * @param {!Event} event |
| 213 */ | 198 */ |
| 214 _treeKeyDown(event) { | 199 _treeKeyDown(event) { |
| 215 if (event.target !== this.contentElement) | 200 if (!this.selectedTreeElement || event.target !== this.selectedTreeElement.l istItemElement || event.shiftKey || |
|
pfeldman
2017/01/21 04:57:34
listItemElement can have focusable children, if li
einbinder
2017/01/21 06:20:31
This was specifically to guard against that scenar
| |
| 216 return; | 201 event.metaKey || event.ctrlKey) |
| 217 | |
| 218 if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ct rlKey) | |
| 219 return; | 202 return; |
| 220 | 203 |
| 221 var handled = false; | 204 var handled = false; |
| 222 if (event.key === 'ArrowUp' && !event.altKey) { | 205 if (event.key === 'ArrowUp' && !event.altKey) { |
| 223 handled = this.selectPrevious(); | 206 handled = this.selectPrevious(); |
| 224 } else if (event.key === 'ArrowDown' && !event.altKey) { | 207 } else if (event.key === 'ArrowDown' && !event.altKey) { |
| 225 handled = this.selectNext(); | 208 handled = this.selectNext(); |
| 226 } else if (event.key === 'ArrowLeft') { | 209 } else if (event.key === 'ArrowLeft') { |
| 227 handled = this.selectedTreeElement.collapseOrAscend(event.altKey); | 210 handled = this.selectedTreeElement.collapseOrAscend(event.altKey); |
| 228 } else if (event.key === 'ArrowRight') { | 211 } else if (event.key === 'ArrowRight') { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 269 ElementAttached: Symbol('ElementAttached'), | 252 ElementAttached: Symbol('ElementAttached'), |
| 270 ElementExpanded: Symbol('ElementExpanded'), | 253 ElementExpanded: Symbol('ElementExpanded'), |
| 271 ElementCollapsed: Symbol('ElementCollapsed'), | 254 ElementCollapsed: Symbol('ElementCollapsed'), |
| 272 ElementSelected: Symbol('ElementSelected') | 255 ElementSelected: Symbol('ElementSelected') |
| 273 }; | 256 }; |
| 274 | 257 |
| 275 /** | 258 /** |
| 276 * @unrestricted | 259 * @unrestricted |
| 277 */ | 260 */ |
| 278 UI.TreeOutlineInShadow = class extends UI.TreeOutline { | 261 UI.TreeOutlineInShadow = class extends UI.TreeOutline { |
| 279 constructor() { | 262 /** |
| 280 super(); | 263 * @param {boolean=} nonFocusable |
| 264 */ | |
| 265 constructor(nonFocusable) { | |
| 266 super(nonFocusable); | |
| 281 this.contentElement.classList.add('tree-outline'); | 267 this.contentElement.classList.add('tree-outline'); |
| 282 | 268 |
| 283 // Redefine element to the external one. | 269 // Redefine element to the external one. |
| 284 this.element = createElement('div'); | 270 this.element = createElement('div'); |
| 285 this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/treeo utline.css'); | 271 this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/treeo utline.css'); |
| 286 this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline- disclosure'); | 272 this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline- disclosure'); |
| 287 this._disclosureElement.appendChild(this.contentElement); | 273 this._disclosureElement.appendChild(this.contentElement); |
| 288 this._renderSelection = true; | 274 this._renderSelection = true; |
| 289 } | 275 } |
| 290 | 276 |
| (...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 664 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons '); | 650 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons '); |
| 665 this._trailingIconsElement.classList.add('icons-container'); | 651 this._trailingIconsElement.classList.add('icons-container'); |
| 666 this._listItemNode.appendChild(this._trailingIconsElement); | 652 this._listItemNode.appendChild(this._trailingIconsElement); |
| 667 this._ensureSelection(); | 653 this._ensureSelection(); |
| 668 } | 654 } |
| 669 this._trailingIconsElement.removeChildren(); | 655 this._trailingIconsElement.removeChildren(); |
| 670 for (var icon of icons) | 656 for (var icon of icons) |
| 671 this._trailingIconsElement.appendChild(icon); | 657 this._trailingIconsElement.appendChild(icon); |
| 672 } | 658 } |
| 673 | 659 |
| 674 /** | |
| 675 * @param {boolean} focused | |
| 676 */ | |
| 677 _setFocused(focused) { | |
| 678 this._focused = focused; | |
| 679 this._listItemNode.classList.toggle('force-white-icons', focused); | |
| 680 } | |
| 681 | 660 |
| 682 /** | 661 /** |
| 683 * @return {string} | 662 * @return {string} |
| 684 */ | 663 */ |
| 685 get tooltip() { | 664 get tooltip() { |
| 686 return this._tooltip || ''; | 665 return this._tooltip || ''; |
| 687 } | 666 } |
| 688 | 667 |
| 689 /** | 668 /** |
| 690 * @param {string} x | 669 * @param {string} x |
| (...skipping 303 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 994 | 973 |
| 995 if (this.treeOutline.selectedTreeElement) | 974 if (this.treeOutline.selectedTreeElement) |
| 996 this.treeOutline.selectedTreeElement.deselect(); | 975 this.treeOutline.selectedTreeElement.deselect(); |
| 997 this.treeOutline.selectedTreeElement = null; | 976 this.treeOutline.selectedTreeElement = null; |
| 998 | 977 |
| 999 if (this.treeOutline._rootElement === this) | 978 if (this.treeOutline._rootElement === this) |
| 1000 return false; | 979 return false; |
| 1001 | 980 |
| 1002 this.selected = true; | 981 this.selected = true; |
| 1003 | 982 |
| 983 this.treeOutline.selectedTreeElement = this; | |
| 984 if (this.treeOutline._focusable) | |
| 985 this._listItemNode.tabIndex = 0; | |
| 1004 if (!omitFocus) | 986 if (!omitFocus) |
| 1005 this.treeOutline.focus(); | 987 this.treeOutline.focus(); |
|
pfeldman
2017/01/21 04:57:34
Why going into treeOutline just to focus the node
einbinder
2017/01/21 06:20:32
No great reason.
| |
| 1006 | 988 |
| 1007 // Focusing on another node may detach "this" from tree. | |
| 1008 if (!this.treeOutline) | |
|
pfeldman
2017/01/21 04:57:34
I'm pretty sure this was happening :(, so removing
einbinder
2017/01/21 06:20:32
I don't see how this can happen, it just calls foc
| |
| 1009 return false; | |
| 1010 this.treeOutline.selectedTreeElement = this; | |
| 1011 this._listItemNode.classList.add('selected'); | 989 this._listItemNode.classList.add('selected'); |
| 1012 this._setFocused(this.treeOutline._focused); | |
| 1013 this.treeOutline.dispatchEventToListeners(UI.TreeOutline.Events.ElementSelec ted, this); | 990 this.treeOutline.dispatchEventToListeners(UI.TreeOutline.Events.ElementSelec ted, this); |
| 1014 return this.onselect(selectedByUser); | 991 return this.onselect(selectedByUser); |
| 1015 } | 992 } |
| 1016 | 993 |
| 1017 /** | 994 /** |
| 1018 * @param {boolean=} omitFocus | 995 * @param {boolean=} omitFocus |
| 1019 */ | 996 */ |
| 1020 revealAndSelect(omitFocus) { | 997 revealAndSelect(omitFocus) { |
| 1021 this.reveal(true); | 998 this.reveal(true); |
| 1022 this.select(omitFocus); | 999 this.select(omitFocus); |
| 1023 } | 1000 } |
| 1024 | 1001 |
| 1025 /** | 1002 /** |
| 1026 * @param {boolean=} supressOnDeselect | 1003 * @param {boolean=} supressOnDeselect |
| 1027 */ | 1004 */ |
| 1028 deselect(supressOnDeselect) { | 1005 deselect(supressOnDeselect) { |
| 1029 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !t his.selected) | 1006 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !t his.selected) |
| 1030 return; | 1007 return; |
| 1031 | 1008 |
| 1032 this.selected = false; | 1009 this.selected = false; |
| 1033 this.treeOutline.selectedTreeElement = null; | 1010 this.treeOutline.selectedTreeElement = null; |
| 1034 this._listItemNode.classList.remove('selected'); | 1011 this._listItemNode.classList.remove('selected'); |
| 1035 this._setFocused(false); | 1012 this._listItemNode.tabIndex = -1; |
| 1036 } | 1013 } |
| 1037 | 1014 |
| 1038 _populateIfNeeded() { | 1015 _populateIfNeeded() { |
| 1039 if (this.treeOutline && this._expandable && !this._children) { | 1016 if (this.treeOutline && this._expandable && !this._children) { |
| 1040 this._children = []; | 1017 this._children = []; |
| 1041 this.onpopulate(); | 1018 this.onpopulate(); |
| 1042 } | 1019 } |
| 1043 } | 1020 } |
| 1044 | 1021 |
| 1045 onpopulate() { | 1022 onpopulate() { |
| (...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1177 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLe ft; | 1154 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLe ft; |
| 1178 console.assert(paddingLeftValue.endsWith('px')); | 1155 console.assert(paddingLeftValue.endsWith('px')); |
| 1179 var computedLeftPadding = parseFloat(paddingLeftValue); | 1156 var computedLeftPadding = parseFloat(paddingLeftValue); |
| 1180 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; | 1157 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
| 1181 return event.pageX >= left && event.pageX <= left + UI.TreeElement._ArrowTog gleWidth && this._expandable; | 1158 return event.pageX >= left && event.pageX <= left + UI.TreeElement._ArrowTog gleWidth && this._expandable; |
| 1182 } | 1159 } |
| 1183 }; | 1160 }; |
| 1184 | 1161 |
| 1185 /** @const */ | 1162 /** @const */ |
| 1186 UI.TreeElement._ArrowToggleWidth = 10; | 1163 UI.TreeElement._ArrowToggleWidth = 10; |
| OLD | NEW |