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 |