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 |