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 12 matching lines...) Expand all Loading... |
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
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 constructor() { |
34 * @param {boolean=} nonFocusable | |
35 */ | |
36 constructor(nonFocusable) { | |
37 super(); | 34 super(); |
38 this._createRootElement(); | 35 this._createRootElement(); |
39 | 36 |
| 37 /** @type {?UI.TreeElement} */ |
40 this.selectedTreeElement = null; | 38 this.selectedTreeElement = null; |
41 this.expandTreeElementsWhenArrowing = false; | 39 this.expandTreeElementsWhenArrowing = false; |
42 /** @type {?function(!UI.TreeElement, !UI.TreeElement):number} */ | 40 /** @type {?function(!UI.TreeElement, !UI.TreeElement):number} */ |
43 this._comparator = null; | 41 this._comparator = null; |
44 | 42 |
45 this.contentElement = this._rootElement._childrenListNode; | 43 this.contentElement = this._rootElement._childrenListNode; |
46 this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this)
, true); | 44 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 | 45 |
50 this.setFocusable(!nonFocusable); | 46 this._focusable = true; |
51 | 47 this.setFocusable(this._focusable); |
| 48 if (this._focusable) |
| 49 this.contentElement.setAttribute('tabIndex', -1); |
52 this.element = this.contentElement; | 50 this.element = this.contentElement; |
53 | 51 |
54 // Adjust to allow computing margin-left for the selection element. | 52 // Adjust to allow computing margin-left for the selection element. |
55 // Check the padding-left for the li element for correct value. | 53 // Check the padding-left for the li element for correct value. |
56 this._paddingSize = 0; | 54 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 } | 55 } |
68 | 56 |
69 _createRootElement() { | 57 _createRootElement() { |
70 this._rootElement = new UI.TreeElement(); | 58 this._rootElement = new UI.TreeElement(); |
71 this._rootElement.treeOutline = this; | 59 this._rootElement.treeOutline = this; |
72 this._rootElement.root = true; | 60 this._rootElement.root = true; |
73 this._rootElement.selectable = false; | 61 this._rootElement.selectable = false; |
74 this._rootElement.expanded = true; | 62 this._rootElement.expanded = true; |
75 this._rootElement._childrenListNode.classList.remove('children'); | 63 this._rootElement._childrenListNode.classList.remove('children'); |
76 } | 64 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
143 * @param {?function(!UI.TreeElement, !UI.TreeElement):number} comparator | 131 * @param {?function(!UI.TreeElement, !UI.TreeElement):number} comparator |
144 */ | 132 */ |
145 setComparator(comparator) { | 133 setComparator(comparator) { |
146 this._comparator = comparator; | 134 this._comparator = comparator; |
147 } | 135 } |
148 | 136 |
149 /** | 137 /** |
150 * @param {boolean} focusable | 138 * @param {boolean} focusable |
151 */ | 139 */ |
152 setFocusable(focusable) { | 140 setFocusable(focusable) { |
153 if (focusable) | 141 if (focusable) { |
154 this.contentElement.setAttribute('tabIndex', 0); | 142 this._focusable = true; |
155 else | 143 this.contentElement.setAttribute('tabIndex', -1); |
| 144 if (this.selectedTreeElement) |
| 145 this.selectedTreeElement._setFocusable(true); |
| 146 } else { |
| 147 this._focusable = false; |
156 this.contentElement.removeAttribute('tabIndex'); | 148 this.contentElement.removeAttribute('tabIndex'); |
| 149 if (this.selectedTreeElement) |
| 150 this.selectedTreeElement._setFocusable(false); |
| 151 } |
157 } | 152 } |
158 | 153 |
159 focus() { | 154 focus() { |
160 this.contentElement.focus(); | 155 if (this.selectedTreeElement) |
| 156 this.selectedTreeElement.listItemElement.focus(); |
| 157 else |
| 158 this.contentElement.focus(); |
161 } | 159 } |
162 | 160 |
163 /** | 161 /** |
164 * @param {!UI.TreeElement} element | 162 * @param {!UI.TreeElement} element |
165 */ | 163 */ |
166 _bindTreeElement(element) { | 164 _bindTreeElement(element) { |
167 if (element.treeOutline) | 165 if (element.treeOutline) |
168 console.error('Binding element for the second time: ' + new Error().stack)
; | 166 console.error('Binding element for the second time: ' + new Error().stack)
; |
169 element.treeOutline = this; | 167 element.treeOutline = this; |
170 element.onbind(); | 168 element.onbind(); |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
216 * @param {number} paddingSize | 214 * @param {number} paddingSize |
217 */ | 215 */ |
218 setPaddingSize(paddingSize) { | 216 setPaddingSize(paddingSize) { |
219 this._paddingSize = paddingSize; | 217 this._paddingSize = paddingSize; |
220 } | 218 } |
221 | 219 |
222 /** | 220 /** |
223 * @param {!Event} event | 221 * @param {!Event} event |
224 */ | 222 */ |
225 _treeKeyDown(event) { | 223 _treeKeyDown(event) { |
226 if (event.target !== this.contentElement) | 224 if (!this.selectedTreeElement || event.target !== this.selectedTreeElement.l
istItemElement || event.shiftKey || |
227 return; | 225 event.metaKey || event.ctrlKey) |
228 | |
229 if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ct
rlKey) | |
230 return; | 226 return; |
231 | 227 |
232 var handled = false; | 228 var handled = false; |
233 if (event.key === 'ArrowUp' && !event.altKey) { | 229 if (event.key === 'ArrowUp' && !event.altKey) { |
234 handled = this.selectPrevious(); | 230 handled = this.selectPrevious(); |
235 } else if (event.key === 'ArrowDown' && !event.altKey) { | 231 } else if (event.key === 'ArrowDown' && !event.altKey) { |
236 handled = this.selectNext(); | 232 handled = this.selectNext(); |
237 } else if (event.key === 'ArrowLeft') { | 233 } else if (event.key === 'ArrowLeft') { |
238 handled = this.selectedTreeElement.collapseOrAscend(event.altKey); | 234 handled = this.selectedTreeElement.collapseOrAscend(event.altKey); |
239 } else if (event.key === 'ArrowRight') { | 235 } else if (event.key === 'ArrowRight') { |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
322 /** | 318 /** |
323 * @param {(string|!Node)=} title | 319 * @param {(string|!Node)=} title |
324 * @param {boolean=} expandable | 320 * @param {boolean=} expandable |
325 */ | 321 */ |
326 constructor(title, expandable) { | 322 constructor(title, expandable) { |
327 /** @type {?UI.TreeOutline} */ | 323 /** @type {?UI.TreeOutline} */ |
328 this.treeOutline = null; | 324 this.treeOutline = null; |
329 this.parent = null; | 325 this.parent = null; |
330 this.previousSibling = null; | 326 this.previousSibling = null; |
331 this.nextSibling = null; | 327 this.nextSibling = null; |
| 328 this._boundOnFocus = this._onFocus.bind(this); |
| 329 this._boundOnBlur = this._onBlur.bind(this); |
332 | 330 |
333 this._listItemNode = createElement('li'); | 331 this._listItemNode = createElement('li'); |
334 this._titleElement = this._listItemNode.createChild('span', 'tree-element-ti
tle'); | 332 this._titleElement = this._listItemNode.createChild('span', 'tree-element-ti
tle'); |
335 this._listItemNode.treeElement = this; | 333 this._listItemNode.treeElement = this; |
336 if (title) | 334 if (title) |
337 this.title = title; | 335 this.title = title; |
338 this._listItemNode.addEventListener('mousedown', this._handleMouseDown.bind(
this), false); | 336 this._listItemNode.addEventListener('mousedown', this._handleMouseDown.bind(
this), false); |
339 this._listItemNode.addEventListener('click', this._treeElementToggled.bind(t
his), false); | 337 this._listItemNode.addEventListener('click', this._treeElementToggled.bind(t
his), false); |
340 this._listItemNode.addEventListener('dblclick', this._handleDoubleClick.bind
(this), false); | 338 this._listItemNode.addEventListener('dblclick', this._handleDoubleClick.bind
(this), false); |
341 | 339 |
(...skipping 323 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons
'); | 663 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons
'); |
666 this._trailingIconsElement.classList.add('icons-container'); | 664 this._trailingIconsElement.classList.add('icons-container'); |
667 this._listItemNode.appendChild(this._trailingIconsElement); | 665 this._listItemNode.appendChild(this._trailingIconsElement); |
668 this._ensureSelection(); | 666 this._ensureSelection(); |
669 } | 667 } |
670 this._trailingIconsElement.removeChildren(); | 668 this._trailingIconsElement.removeChildren(); |
671 for (var icon of icons) | 669 for (var icon of icons) |
672 this._trailingIconsElement.appendChild(icon); | 670 this._trailingIconsElement.appendChild(icon); |
673 } | 671 } |
674 | 672 |
675 /** | |
676 * @param {boolean} focused | |
677 */ | |
678 _setFocused(focused) { | |
679 this._focused = focused; | |
680 this._listItemNode.classList.toggle('force-white-icons', focused); | |
681 } | |
682 | 673 |
683 /** | 674 /** |
684 * @return {string} | 675 * @return {string} |
685 */ | 676 */ |
686 get tooltip() { | 677 get tooltip() { |
687 return this._tooltip || ''; | 678 return this._tooltip || ''; |
688 } | 679 } |
689 | 680 |
690 /** | 681 /** |
691 * @param {string} x | 682 * @param {string} x |
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1011 | 1002 |
1012 if (this.treeOutline.selectedTreeElement) | 1003 if (this.treeOutline.selectedTreeElement) |
1013 this.treeOutline.selectedTreeElement.deselect(); | 1004 this.treeOutline.selectedTreeElement.deselect(); |
1014 this.treeOutline.selectedTreeElement = null; | 1005 this.treeOutline.selectedTreeElement = null; |
1015 | 1006 |
1016 if (this.treeOutline._rootElement === this) | 1007 if (this.treeOutline._rootElement === this) |
1017 return false; | 1008 return false; |
1018 | 1009 |
1019 this.selected = true; | 1010 this.selected = true; |
1020 | 1011 |
1021 if (!omitFocus) | 1012 this.treeOutline.selectedTreeElement = this; |
1022 this.treeOutline.focus(); | 1013 if (this.treeOutline._focusable) |
| 1014 this._setFocusable(true); |
| 1015 if (!omitFocus || this.treeOutline.contentElement.hasFocus()) |
| 1016 this.listItemElement.focus(); |
1023 | 1017 |
1024 // Focusing on another node may detach "this" from tree. | |
1025 if (!this.treeOutline) | |
1026 return false; | |
1027 this.treeOutline.selectedTreeElement = this; | |
1028 this._listItemNode.classList.add('selected'); | 1018 this._listItemNode.classList.add('selected'); |
1029 this._setFocused(this.treeOutline._focused); | |
1030 this.treeOutline.dispatchEventToListeners(UI.TreeOutline.Events.ElementSelec
ted, this); | 1019 this.treeOutline.dispatchEventToListeners(UI.TreeOutline.Events.ElementSelec
ted, this); |
1031 return this.onselect(selectedByUser); | 1020 return this.onselect(selectedByUser); |
1032 } | 1021 } |
1033 | 1022 |
1034 /** | 1023 /** |
| 1024 * @param {boolean} focusable |
| 1025 */ |
| 1026 _setFocusable(focusable) { |
| 1027 if (focusable) { |
| 1028 this._listItemNode.setAttribute('tabIndex', 0); |
| 1029 this._listItemNode.addEventListener('focus', this._boundOnFocus, false); |
| 1030 this._listItemNode.addEventListener('blur', this._boundOnBlur, false); |
| 1031 } else { |
| 1032 this._listItemNode.removeAttribute('tabIndex'); |
| 1033 this._listItemNode.removeEventListener('focus', this._boundOnFocus, false)
; |
| 1034 this._listItemNode.removeEventListener('blur', this._boundOnBlur, false); |
| 1035 } |
| 1036 } |
| 1037 |
| 1038 _onFocus() { |
| 1039 this._listItemNode.classList.add('force-white-icons'); |
| 1040 } |
| 1041 |
| 1042 _onBlur() { |
| 1043 this._listItemNode.classList.remove('force-white-icons'); |
| 1044 } |
| 1045 |
| 1046 /** |
1035 * @param {boolean=} omitFocus | 1047 * @param {boolean=} omitFocus |
1036 */ | 1048 */ |
1037 revealAndSelect(omitFocus) { | 1049 revealAndSelect(omitFocus) { |
1038 this.reveal(true); | 1050 this.reveal(true); |
1039 this.select(omitFocus); | 1051 this.select(omitFocus); |
1040 } | 1052 } |
1041 | 1053 |
1042 /** | 1054 deselect() { |
1043 * @param {boolean=} supressOnDeselect | 1055 var hadFocus = this._listItemNode.hasFocus(); |
1044 */ | 1056 this.selected = false; |
1045 deselect(supressOnDeselect) { | 1057 this._listItemNode.classList.remove('selected'); |
1046 if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !t
his.selected) | 1058 this._setFocusable(false); |
1047 return; | |
1048 | 1059 |
1049 this.selected = false; | 1060 if (this.treeOutline && this.treeOutline.selectedTreeElement === this) { |
1050 this.treeOutline.selectedTreeElement = null; | 1061 this.treeOutline.selectedTreeElement = null; |
1051 this._listItemNode.classList.remove('selected'); | 1062 if (hadFocus) |
1052 this._setFocused(false); | 1063 this.treeOutline.focus(); |
| 1064 } |
1053 } | 1065 } |
1054 | 1066 |
1055 _populateIfNeeded() { | 1067 _populateIfNeeded() { |
1056 if (this.treeOutline && this._expandable && !this._children) { | 1068 if (this.treeOutline && this._expandable && !this._children) { |
1057 this._children = []; | 1069 this._children = []; |
1058 this.onpopulate(); | 1070 this.onpopulate(); |
1059 } | 1071 } |
1060 } | 1072 } |
1061 | 1073 |
1062 onpopulate() { | 1074 onpopulate() { |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1194 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLe
ft; | 1206 var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLe
ft; |
1195 console.assert(paddingLeftValue.endsWith('px')); | 1207 console.assert(paddingLeftValue.endsWith('px')); |
1196 var computedLeftPadding = parseFloat(paddingLeftValue); | 1208 var computedLeftPadding = parseFloat(paddingLeftValue); |
1197 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; | 1209 var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
1198 return event.pageX >= left && event.pageX <= left + UI.TreeElement._ArrowTog
gleWidth && this._expandable; | 1210 return event.pageX >= left && event.pageX <= left + UI.TreeElement._ArrowTog
gleWidth && this._expandable; |
1199 } | 1211 } |
1200 }; | 1212 }; |
1201 | 1213 |
1202 /** @const */ | 1214 /** @const */ |
1203 UI.TreeElement._ArrowToggleWidth = 10; | 1215 UI.TreeElement._ArrowToggleWidth = 10; |
OLD | NEW |