blob: 32bfecdd234e2217d1c687f64e887c249fcb5144 [file] [log] [blame]
Blink Reformat4c46d092018-04-07 15:32:371/*
2 * Copyright (C) 2007 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
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
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.
27 */
28
29/**
30 * @unrestricted
31 */
Tim van der Lippe0830b3d2019-10-03 13:20:0732export class TreeOutline extends Common.Object {
Blink Reformat4c46d092018-04-07 15:32:3733 constructor() {
34 super();
35 this._createRootElement();
36
Tim van der Lippe0830b3d2019-10-03 13:20:0737 /** @type {?TreeElement} */
Blink Reformat4c46d092018-04-07 15:32:3738 this.selectedTreeElement = null;
39 this.expandTreeElementsWhenArrowing = false;
Tim van der Lippe0830b3d2019-10-03 13:20:0740 /** @type {?function(!TreeElement, !TreeElement):number} */
Blink Reformat4c46d092018-04-07 15:32:3741 this._comparator = null;
42
43 this.contentElement = this._rootElement._childrenListNode;
Erik Luoea8f5092018-09-19 22:37:1344 this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this), false);
Blink Reformat4c46d092018-04-07 15:32:3745
Erik Luocc14b812018-11-03 01:33:0946 this._preventTabOrder = false;
Erik Luod6bf97b2018-08-25 02:06:5147 this._showSelectionOnKeyboardFocus = false;
Blink Reformat4c46d092018-04-07 15:32:3748 this._focusable = true;
49 this.setFocusable(this._focusable);
Tim van der Lippe1d6e57a2019-09-30 11:55:3450 if (this._focusable) {
Blink Reformat4c46d092018-04-07 15:32:3751 this.contentElement.setAttribute('tabIndex', -1);
Tim van der Lippe1d6e57a2019-09-30 11:55:3452 }
Blink Reformat4c46d092018-04-07 15:32:3753 this.element = this.contentElement;
54 UI.ARIAUtils.markAsTree(this.element);
Blink Reformat4c46d092018-04-07 15:32:3755 }
56
Erik Luod6bf97b2018-08-25 02:06:5157 /**
58 * @param {boolean} show
Erik Luocc14b812018-11-03 01:33:0959 * @param {boolean=} preventTabOrder
Erik Luod6bf97b2018-08-25 02:06:5160 */
Erik Luocc14b812018-11-03 01:33:0961 setShowSelectionOnKeyboardFocus(show, preventTabOrder) {
Erik Luod6bf97b2018-08-25 02:06:5162 this.contentElement.classList.toggle('hide-selection-when-blurred', show);
Erik Luocc14b812018-11-03 01:33:0963 this._preventTabOrder = !!preventTabOrder;
Erik Luod6bf97b2018-08-25 02:06:5164 this._showSelectionOnKeyboardFocus = show;
65 }
66
Blink Reformat4c46d092018-04-07 15:32:3767 _createRootElement() {
Tim van der Lippe0830b3d2019-10-03 13:20:0768 this._rootElement = new TreeElement();
Blink Reformat4c46d092018-04-07 15:32:3769 this._rootElement.treeOutline = this;
70 this._rootElement.root = true;
71 this._rootElement.selectable = false;
72 this._rootElement.expanded = true;
73 this._rootElement._childrenListNode.classList.remove('children');
74 }
75
76 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0777 * @return {!TreeElement}
Blink Reformat4c46d092018-04-07 15:32:3778 */
79 rootElement() {
80 return this._rootElement;
81 }
82
83 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0784 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:3785 */
86 firstChild() {
87 return this._rootElement.firstChild();
88 }
89
90 /**
Tim van der Lippe0830b3d2019-10-03 13:20:0791 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:3792 */
93 _lastDescendent() {
94 let last = this._rootElement.lastChild();
Tim van der Lippe1d6e57a2019-09-30 11:55:3495 while (last.expanded && last.childCount()) {
Blink Reformat4c46d092018-04-07 15:32:3796 last = last.lastChild();
Tim van der Lippe1d6e57a2019-09-30 11:55:3497 }
Blink Reformat4c46d092018-04-07 15:32:3798 return last;
99 }
100
101 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07102 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37103 */
104 appendChild(child) {
105 this._rootElement.appendChild(child);
106 }
107
108 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07109 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37110 * @param {number} index
111 */
112 insertChild(child, index) {
113 this._rootElement.insertChild(child, index);
114 }
115
116 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07117 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37118 */
119 removeChild(child) {
120 this._rootElement.removeChild(child);
121 }
122
123 removeChildren() {
124 this._rootElement.removeChildren();
125 }
126
127 /**
128 * @param {number} x
129 * @param {number} y
Tim van der Lippe0830b3d2019-10-03 13:20:07130 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:37131 */
132 treeElementFromPoint(x, y) {
133 const node = this.contentElement.ownerDocument.deepElementFromPoint(x, y);
Tim van der Lippe1d6e57a2019-09-30 11:55:34134 if (!node) {
Blink Reformat4c46d092018-04-07 15:32:37135 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:34136 }
Blink Reformat4c46d092018-04-07 15:32:37137
138 const listNode = node.enclosingNodeOrSelfWithNodeNameInArray(['ol', 'li']);
Tim van der Lippe1d6e57a2019-09-30 11:55:34139 if (listNode) {
Blink Reformat4c46d092018-04-07 15:32:37140 return listNode.parentTreeElement || listNode.treeElement;
Tim van der Lippe1d6e57a2019-09-30 11:55:34141 }
Blink Reformat4c46d092018-04-07 15:32:37142 return null;
143 }
144
145 /**
146 * @param {?Event} event
Tim van der Lippe0830b3d2019-10-03 13:20:07147 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:37148 */
149 treeElementFromEvent(event) {
150 return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null;
151 }
152
153 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07154 * @param {?function(!TreeElement, !TreeElement):number} comparator
Blink Reformat4c46d092018-04-07 15:32:37155 */
156 setComparator(comparator) {
157 this._comparator = comparator;
158 }
159
160 /**
161 * @param {boolean} focusable
162 */
163 setFocusable(focusable) {
164 if (focusable) {
165 this._focusable = true;
166 this.contentElement.setAttribute('tabIndex', -1);
Tim van der Lippe1d6e57a2019-09-30 11:55:34167 if (this.selectedTreeElement) {
Blink Reformat4c46d092018-04-07 15:32:37168 this.selectedTreeElement._setFocusable(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34169 }
Blink Reformat4c46d092018-04-07 15:32:37170 } else {
171 this._focusable = false;
172 this.contentElement.removeAttribute('tabIndex');
Tim van der Lippe1d6e57a2019-09-30 11:55:34173 if (this.selectedTreeElement) {
Blink Reformat4c46d092018-04-07 15:32:37174 this.selectedTreeElement._setFocusable(false);
Tim van der Lippe1d6e57a2019-09-30 11:55:34175 }
Blink Reformat4c46d092018-04-07 15:32:37176 }
177 }
178
179 focus() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34180 if (this.selectedTreeElement) {
Blink Reformat4c46d092018-04-07 15:32:37181 this.selectedTreeElement.listItemElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34182 } else {
Blink Reformat4c46d092018-04-07 15:32:37183 this.contentElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:34184 }
Blink Reformat4c46d092018-04-07 15:32:37185 }
186
Pavel Feldman7ad5b272019-01-08 03:01:00187 useLightSelectionColor() {
188 this._useLightSelectionColor = true;
189 }
190
Blink Reformat4c46d092018-04-07 15:32:37191 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07192 * @param {!TreeElement} element
Blink Reformat4c46d092018-04-07 15:32:37193 */
194 _bindTreeElement(element) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34195 if (element.treeOutline) {
Blink Reformat4c46d092018-04-07 15:32:37196 console.error('Binding element for the second time: ' + new Error().stack);
Tim van der Lippe1d6e57a2019-09-30 11:55:34197 }
Blink Reformat4c46d092018-04-07 15:32:37198 element.treeOutline = this;
199 element.onbind();
200 }
201
202 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07203 * @param {!TreeElement} element
Blink Reformat4c46d092018-04-07 15:32:37204 */
205 _unbindTreeElement(element) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34206 if (!element.treeOutline) {
Blink Reformat4c46d092018-04-07 15:32:37207 console.error('Unbinding element that was not bound: ' + new Error().stack);
Tim van der Lippe1d6e57a2019-09-30 11:55:34208 }
Blink Reformat4c46d092018-04-07 15:32:37209
210 element.deselect();
211 element.onunbind();
212 element.treeOutline = null;
213 }
214
215 /**
216 * @return {boolean}
217 */
218 selectPrevious() {
219 let nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34220 while (nextSelectedElement && !nextSelectedElement.selectable) {
Blink Reformat4c46d092018-04-07 15:32:37221 nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing);
Tim van der Lippe1d6e57a2019-09-30 11:55:34222 }
223 if (!nextSelectedElement) {
Blink Reformat4c46d092018-04-07 15:32:37224 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34225 }
Blink Reformat4c46d092018-04-07 15:32:37226 nextSelectedElement.select(false, true);
227 return true;
228 }
229
230 /**
231 * @return {boolean}
232 */
233 selectNext() {
234 let nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34235 while (nextSelectedElement && !nextSelectedElement.selectable) {
Blink Reformat4c46d092018-04-07 15:32:37236 nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing);
Tim van der Lippe1d6e57a2019-09-30 11:55:34237 }
238 if (!nextSelectedElement) {
Blink Reformat4c46d092018-04-07 15:32:37239 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34240 }
Blink Reformat4c46d092018-04-07 15:32:37241 nextSelectedElement.select(false, true);
242 return true;
243 }
244
Erik Luo31c21f62018-12-13 03:39:39245 forceSelect() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34246 if (this.selectedTreeElement) {
Erik Luo31c21f62018-12-13 03:39:39247 this.selectedTreeElement.deselect();
Tim van der Lippe1d6e57a2019-09-30 11:55:34248 }
Erik Luo31c21f62018-12-13 03:39:39249 this._selectFirst();
250 }
251
Blink Reformat4c46d092018-04-07 15:32:37252 /**
253 * @return {boolean}
254 */
Erik Luo31c21f62018-12-13 03:39:39255 _selectFirst() {
Blink Reformat4c46d092018-04-07 15:32:37256 let first = this.firstChild();
Tim van der Lippe1d6e57a2019-09-30 11:55:34257 while (first && !first.selectable) {
Blink Reformat4c46d092018-04-07 15:32:37258 first = first.traverseNextTreeElement(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34259 }
260 if (!first) {
Blink Reformat4c46d092018-04-07 15:32:37261 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34262 }
Blink Reformat4c46d092018-04-07 15:32:37263 first.select(false, true);
264 return true;
265 }
266
267 /**
268 * @return {boolean}
269 */
270 _selectLast() {
271 let last = this._lastDescendent();
Tim van der Lippe1d6e57a2019-09-30 11:55:34272 while (last && !last.selectable) {
Blink Reformat4c46d092018-04-07 15:32:37273 last = last.traversePreviousTreeElement(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34274 }
275 if (!last) {
Blink Reformat4c46d092018-04-07 15:32:37276 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34277 }
Blink Reformat4c46d092018-04-07 15:32:37278 last.select(false, true);
279 return true;
280 }
281
282 /**
Blink Reformat4c46d092018-04-07 15:32:37283 * @param {!Event} event
284 */
285 _treeKeyDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34286 if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey || UI.isEditing()) {
Blink Reformat4c46d092018-04-07 15:32:37287 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34288 }
Blink Reformat4c46d092018-04-07 15:32:37289
290 let handled = false;
291 if (event.key === 'ArrowUp' && !event.altKey) {
292 handled = this.selectPrevious();
293 } else if (event.key === 'ArrowDown' && !event.altKey) {
294 handled = this.selectNext();
295 } else if (event.key === 'ArrowLeft') {
296 handled = this.selectedTreeElement.collapseOrAscend(event.altKey);
297 } else if (event.key === 'ArrowRight') {
298 if (!this.selectedTreeElement.revealed()) {
299 this.selectedTreeElement.reveal();
300 handled = true;
301 } else {
302 handled = this.selectedTreeElement.descendOrExpand(event.altKey);
303 }
304 } else if (event.keyCode === 8 /* Backspace */ || event.keyCode === 46 /* Delete */) {
305 handled = this.selectedTreeElement.ondelete();
306 } else if (isEnterKey(event)) {
307 handled = this.selectedTreeElement.onenter();
308 } else if (event.keyCode === UI.KeyboardShortcut.Keys.Space.code) {
309 handled = this.selectedTreeElement.onspace();
310 } else if (event.key === 'Home') {
Erik Luo31c21f62018-12-13 03:39:39311 handled = this._selectFirst();
Blink Reformat4c46d092018-04-07 15:32:37312 } else if (event.key === 'End') {
313 handled = this._selectLast();
314 }
315
Tim van der Lippe1d6e57a2019-09-30 11:55:34316 if (handled) {
Blink Reformat4c46d092018-04-07 15:32:37317 event.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34318 }
Blink Reformat4c46d092018-04-07 15:32:37319 }
320
321 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07322 * @param {!TreeElement} treeElement
Blink Reformat4c46d092018-04-07 15:32:37323 * @param {boolean} center
324 */
325 _deferredScrollIntoView(treeElement, center) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34326 if (!this._treeElementToScrollIntoView) {
Blink Reformat4c46d092018-04-07 15:32:37327 this.element.window().requestAnimationFrame(deferredScrollIntoView.bind(this));
Tim van der Lippe1d6e57a2019-09-30 11:55:34328 }
Blink Reformat4c46d092018-04-07 15:32:37329 this._treeElementToScrollIntoView = treeElement;
330 this._centerUponScrollIntoView = center;
331 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07332 * @this {TreeOutline}
Blink Reformat4c46d092018-04-07 15:32:37333 */
334 function deferredScrollIntoView() {
335 this._treeElementToScrollIntoView.listItemElement.scrollIntoViewIfNeeded(this._centerUponScrollIntoView);
336 delete this._treeElementToScrollIntoView;
337 delete this._centerUponScrollIntoView;
338 }
339 }
Tim van der Lippe0830b3d2019-10-03 13:20:07340}
Blink Reformat4c46d092018-04-07 15:32:37341
342/** @enum {symbol} */
Tim van der Lippe0830b3d2019-10-03 13:20:07343const Events = {
Blink Reformat4c46d092018-04-07 15:32:37344 ElementAttached: Symbol('ElementAttached'),
Erik Luo96fee7b2019-06-21 04:30:29345 ElementsDetached: Symbol('ElementsDetached'),
Blink Reformat4c46d092018-04-07 15:32:37346 ElementExpanded: Symbol('ElementExpanded'),
347 ElementCollapsed: Symbol('ElementCollapsed'),
348 ElementSelected: Symbol('ElementSelected')
349};
350
351/**
352 * @unrestricted
353 */
Tim van der Lippe0830b3d2019-10-03 13:20:07354export class TreeOutlineInShadow extends TreeOutline {
Blink Reformat4c46d092018-04-07 15:32:37355 constructor() {
356 super();
357 this.contentElement.classList.add('tree-outline');
358
359 // Redefine element to the external one.
360 this.element = createElement('div');
361 this._shadowRoot = UI.createShadowRootWithCoreStyles(this.element, 'ui/treeoutline.css');
362 this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline-disclosure');
363 this._disclosureElement.appendChild(this.contentElement);
364 this._renderSelection = true;
365 }
366
367 /**
368 * @param {string} cssFile
369 */
370 registerRequiredCSS(cssFile) {
371 UI.appendStyle(this._shadowRoot, cssFile);
372 }
373
374 hideOverflow() {
375 this._disclosureElement.classList.add('tree-outline-disclosure-hide-overflow');
376 }
377
378 makeDense() {
379 this.contentElement.classList.add('tree-outline-dense');
380 }
Tim van der Lippe0830b3d2019-10-03 13:20:07381}
Blink Reformat4c46d092018-04-07 15:32:37382
383/**
384 * @unrestricted
385 */
Tim van der Lippe0830b3d2019-10-03 13:20:07386export class TreeElement {
Blink Reformat4c46d092018-04-07 15:32:37387 /**
388 * @param {(string|!Node)=} title
389 * @param {boolean=} expandable
390 */
391 constructor(title, expandable) {
Tim van der Lippe0830b3d2019-10-03 13:20:07392 /** @type {?TreeOutline} */
Blink Reformat4c46d092018-04-07 15:32:37393 this.treeOutline = null;
394 this.parent = null;
395 this.previousSibling = null;
396 this.nextSibling = null;
397 this._boundOnFocus = this._onFocus.bind(this);
398 this._boundOnBlur = this._onBlur.bind(this);
399
400 this._listItemNode = createElement('li');
Tim van der Lippeffa78622019-09-16 12:07:12401 /** @protected */
402 this.titleElement = this._listItemNode.createChild('span', 'tree-element-title');
Blink Reformat4c46d092018-04-07 15:32:37403 this._listItemNode.treeElement = this;
Tim van der Lippe1d6e57a2019-09-30 11:55:34404 if (title) {
Blink Reformat4c46d092018-04-07 15:32:37405 this.title = title;
Tim van der Lippe1d6e57a2019-09-30 11:55:34406 }
Blink Reformat4c46d092018-04-07 15:32:37407 this._listItemNode.addEventListener('mousedown', this._handleMouseDown.bind(this), false);
408 this._listItemNode.addEventListener('click', this._treeElementToggled.bind(this), false);
409 this._listItemNode.addEventListener('dblclick', this._handleDoubleClick.bind(this), false);
410 UI.ARIAUtils.markAsTreeitem(this._listItemNode);
411
412 this._childrenListNode = createElement('ol');
413 this._childrenListNode.parentTreeElement = this;
414 this._childrenListNode.classList.add('children');
415 UI.ARIAUtils.markAsGroup(this._childrenListNode);
416
417 this._hidden = false;
418 this._selectable = true;
419 this.expanded = false;
420 this.selected = false;
421 this.setExpandable(expandable || false);
422 this._collapsible = true;
423 }
424
425 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07426 * @param {?TreeElement} ancestor
Blink Reformat4c46d092018-04-07 15:32:37427 * @return {boolean}
428 */
429 hasAncestor(ancestor) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34430 if (!ancestor) {
Blink Reformat4c46d092018-04-07 15:32:37431 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34432 }
Blink Reformat4c46d092018-04-07 15:32:37433
434 let currentNode = this.parent;
435 while (currentNode) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34436 if (ancestor === currentNode) {
Blink Reformat4c46d092018-04-07 15:32:37437 return true;
Tim van der Lippe1d6e57a2019-09-30 11:55:34438 }
Blink Reformat4c46d092018-04-07 15:32:37439 currentNode = currentNode.parent;
440 }
441
442 return false;
443 }
444
445 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07446 * @param {?TreeElement} ancestor
Blink Reformat4c46d092018-04-07 15:32:37447 * @return {boolean}
448 */
449 hasAncestorOrSelf(ancestor) {
450 return this === ancestor || this.hasAncestor(ancestor);
451 }
452
453 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07454 * @return {!Array.<!TreeElement>}
Blink Reformat4c46d092018-04-07 15:32:37455 */
456 children() {
457 return this._children || [];
458 }
459
460 /**
461 * @return {number}
462 */
463 childCount() {
464 return this._children ? this._children.length : 0;
465 }
466
467 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07468 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:37469 */
470 firstChild() {
471 return this._children ? this._children[0] : null;
472 }
473
474 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07475 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:37476 */
477 lastChild() {
478 return this._children ? this._children[this._children.length - 1] : null;
479 }
480
481 /**
482 * @param {number} index
Tim van der Lippe0830b3d2019-10-03 13:20:07483 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:37484 */
485 childAt(index) {
486 return this._children ? this._children[index] : null;
487 }
488
489 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07490 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37491 * @return {number}
492 */
493 indexOfChild(child) {
494 return this._children ? this._children.indexOf(child) : -1;
495 }
496
497 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07498 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37499 */
500 appendChild(child) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34501 if (!this._children) {
Blink Reformat4c46d092018-04-07 15:32:37502 this._children = [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34503 }
Blink Reformat4c46d092018-04-07 15:32:37504
505 let insertionIndex;
Tim van der Lippe1d6e57a2019-09-30 11:55:34506 if (this.treeOutline && this.treeOutline._comparator) {
Blink Reformat4c46d092018-04-07 15:32:37507 insertionIndex = this._children.lowerBound(child, this.treeOutline._comparator);
Tim van der Lippe1d6e57a2019-09-30 11:55:34508 } else {
Blink Reformat4c46d092018-04-07 15:32:37509 insertionIndex = this._children.length;
Tim van der Lippe1d6e57a2019-09-30 11:55:34510 }
Blink Reformat4c46d092018-04-07 15:32:37511 this.insertChild(child, insertionIndex);
512 }
513
514 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07515 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37516 * @param {number} index
517 */
518 insertChild(child, index) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34519 if (!this._children) {
Blink Reformat4c46d092018-04-07 15:32:37520 this._children = [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34521 }
Blink Reformat4c46d092018-04-07 15:32:37522
Tim van der Lippe1d6e57a2019-09-30 11:55:34523 if (!child) {
Blink Reformat4c46d092018-04-07 15:32:37524 throw 'child can\'t be undefined or null';
Tim van der Lippe1d6e57a2019-09-30 11:55:34525 }
Blink Reformat4c46d092018-04-07 15:32:37526
527 console.assert(
528 !child.parent, 'Attempting to insert a child that is already in the tree, reparenting is not supported.');
529
530 const previousChild = (index > 0 ? this._children[index - 1] : null);
531 if (previousChild) {
532 previousChild.nextSibling = child;
533 child.previousSibling = previousChild;
534 } else {
535 child.previousSibling = null;
536 }
537
538 const nextChild = this._children[index];
539 if (nextChild) {
540 nextChild.previousSibling = child;
541 child.nextSibling = nextChild;
542 } else {
543 child.nextSibling = null;
544 }
545
546 this._children.splice(index, 0, child);
547
548 this.setExpandable(true);
549 child.parent = this;
550
Tim van der Lippe1d6e57a2019-09-30 11:55:34551 if (this.treeOutline) {
Blink Reformat4c46d092018-04-07 15:32:37552 this.treeOutline._bindTreeElement(child);
Tim van der Lippe1d6e57a2019-09-30 11:55:34553 }
Blink Reformat4c46d092018-04-07 15:32:37554 for (let current = child.firstChild(); this.treeOutline && current;
Tim van der Lippe1d6e57a2019-09-30 11:55:34555 current = current.traverseNextTreeElement(false, child, true)) {
Blink Reformat4c46d092018-04-07 15:32:37556 this.treeOutline._bindTreeElement(current);
Tim van der Lippe1d6e57a2019-09-30 11:55:34557 }
Blink Reformat4c46d092018-04-07 15:32:37558 child.onattach();
559 child._ensureSelection();
Tim van der Lippe1d6e57a2019-09-30 11:55:34560 if (this.treeOutline) {
Tim van der Lippe0830b3d2019-10-03 13:20:07561 this.treeOutline.dispatchEventToListeners(Events.ElementAttached, child);
Tim van der Lippe1d6e57a2019-09-30 11:55:34562 }
Blink Reformat4c46d092018-04-07 15:32:37563 const nextSibling = child.nextSibling ? child.nextSibling._listItemNode : null;
564 this._childrenListNode.insertBefore(child._listItemNode, nextSibling);
565 this._childrenListNode.insertBefore(child._childrenListNode, nextSibling);
Tim van der Lippe1d6e57a2019-09-30 11:55:34566 if (child.selected) {
Blink Reformat4c46d092018-04-07 15:32:37567 child.select();
Tim van der Lippe1d6e57a2019-09-30 11:55:34568 }
569 if (child.expanded) {
Blink Reformat4c46d092018-04-07 15:32:37570 child.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34571 }
Blink Reformat4c46d092018-04-07 15:32:37572 }
573
574 /**
575 * @param {number} childIndex
576 */
577 removeChildAtIndex(childIndex) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34578 if (childIndex < 0 || childIndex >= this._children.length) {
Blink Reformat4c46d092018-04-07 15:32:37579 throw 'childIndex out of range';
Tim van der Lippe1d6e57a2019-09-30 11:55:34580 }
Blink Reformat4c46d092018-04-07 15:32:37581
582 const child = this._children[childIndex];
583 this._children.splice(childIndex, 1);
584
585 const parent = child.parent;
586 if (this.treeOutline && this.treeOutline.selectedTreeElement &&
587 this.treeOutline.selectedTreeElement.hasAncestorOrSelf(child)) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34588 if (child.nextSibling) {
Blink Reformat4c46d092018-04-07 15:32:37589 child.nextSibling.select(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34590 } else if (child.previousSibling) {
Blink Reformat4c46d092018-04-07 15:32:37591 child.previousSibling.select(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34592 } else if (parent) {
Blink Reformat4c46d092018-04-07 15:32:37593 parent.select(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34594 }
Blink Reformat4c46d092018-04-07 15:32:37595 }
596
Tim van der Lippe1d6e57a2019-09-30 11:55:34597 if (child.previousSibling) {
Blink Reformat4c46d092018-04-07 15:32:37598 child.previousSibling.nextSibling = child.nextSibling;
Tim van der Lippe1d6e57a2019-09-30 11:55:34599 }
600 if (child.nextSibling) {
Blink Reformat4c46d092018-04-07 15:32:37601 child.nextSibling.previousSibling = child.previousSibling;
Tim van der Lippe1d6e57a2019-09-30 11:55:34602 }
Blink Reformat4c46d092018-04-07 15:32:37603 child.parent = null;
604
Tim van der Lippe1d6e57a2019-09-30 11:55:34605 if (this.treeOutline) {
Blink Reformat4c46d092018-04-07 15:32:37606 this.treeOutline._unbindTreeElement(child);
Tim van der Lippe1d6e57a2019-09-30 11:55:34607 }
Blink Reformat4c46d092018-04-07 15:32:37608 for (let current = child.firstChild(); this.treeOutline && current;
Tim van der Lippe1d6e57a2019-09-30 11:55:34609 current = current.traverseNextTreeElement(false, child, true)) {
Blink Reformat4c46d092018-04-07 15:32:37610 this.treeOutline._unbindTreeElement(current);
Tim van der Lippe1d6e57a2019-09-30 11:55:34611 }
Blink Reformat4c46d092018-04-07 15:32:37612
613 child._detach();
Tim van der Lippe1d6e57a2019-09-30 11:55:34614 if (this.treeOutline) {
Tim van der Lippe0830b3d2019-10-03 13:20:07615 this.treeOutline.dispatchEventToListeners(Events.ElementsDetached);
Tim van der Lippe1d6e57a2019-09-30 11:55:34616 }
Blink Reformat4c46d092018-04-07 15:32:37617 }
618
619 /**
Tim van der Lippe0830b3d2019-10-03 13:20:07620 * @param {!TreeElement} child
Blink Reformat4c46d092018-04-07 15:32:37621 */
622 removeChild(child) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34623 if (!child) {
Blink Reformat4c46d092018-04-07 15:32:37624 throw 'child can\'t be undefined or null';
Tim van der Lippe1d6e57a2019-09-30 11:55:34625 }
626 if (child.parent !== this) {
Blink Reformat4c46d092018-04-07 15:32:37627 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34628 }
Blink Reformat4c46d092018-04-07 15:32:37629
630 const childIndex = this._children.indexOf(child);
Tim van der Lippe1d6e57a2019-09-30 11:55:34631 if (childIndex === -1) {
Blink Reformat4c46d092018-04-07 15:32:37632 throw 'child not found in this node\'s children';
Tim van der Lippe1d6e57a2019-09-30 11:55:34633 }
Blink Reformat4c46d092018-04-07 15:32:37634
635 this.removeChildAtIndex(childIndex);
636 }
637
638 removeChildren() {
639 if (!this.root && this.treeOutline && this.treeOutline.selectedTreeElement &&
Tim van der Lippe1d6e57a2019-09-30 11:55:34640 this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) {
Blink Reformat4c46d092018-04-07 15:32:37641 this.select(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:34642 }
Blink Reformat4c46d092018-04-07 15:32:37643
644 for (let i = 0; this._children && i < this._children.length; ++i) {
645 const child = this._children[i];
646 child.previousSibling = null;
647 child.nextSibling = null;
648 child.parent = null;
649
Tim van der Lippe1d6e57a2019-09-30 11:55:34650 if (this.treeOutline) {
Blink Reformat4c46d092018-04-07 15:32:37651 this.treeOutline._unbindTreeElement(child);
Tim van der Lippe1d6e57a2019-09-30 11:55:34652 }
Blink Reformat4c46d092018-04-07 15:32:37653 for (let current = child.firstChild(); this.treeOutline && current;
Tim van der Lippe1d6e57a2019-09-30 11:55:34654 current = current.traverseNextTreeElement(false, child, true)) {
Blink Reformat4c46d092018-04-07 15:32:37655 this.treeOutline._unbindTreeElement(current);
Tim van der Lippe1d6e57a2019-09-30 11:55:34656 }
Blink Reformat4c46d092018-04-07 15:32:37657 child._detach();
658 }
659 this._children = [];
Tim van der Lippe1d6e57a2019-09-30 11:55:34660 if (this.treeOutline) {
Tim van der Lippe0830b3d2019-10-03 13:20:07661 this.treeOutline.dispatchEventToListeners(Events.ElementsDetached);
Tim van der Lippe1d6e57a2019-09-30 11:55:34662 }
Blink Reformat4c46d092018-04-07 15:32:37663 }
664
665 get selectable() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34666 if (this._hidden) {
Blink Reformat4c46d092018-04-07 15:32:37667 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:34668 }
Blink Reformat4c46d092018-04-07 15:32:37669 return this._selectable;
670 }
671
672 set selectable(x) {
673 this._selectable = x;
674 }
675
676 get listItemElement() {
677 return this._listItemNode;
678 }
679
Blink Reformat4c46d092018-04-07 15:32:37680 get childrenListElement() {
681 return this._childrenListNode;
682 }
683
684 /**
685 * @return {string|!Node}
686 */
687 get title() {
688 return this._title;
689 }
690
691 /**
692 * @param {string|!Node} x
693 */
694 set title(x) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34695 if (this._title === x) {
Blink Reformat4c46d092018-04-07 15:32:37696 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34697 }
Blink Reformat4c46d092018-04-07 15:32:37698 this._title = x;
699
700 if (typeof x === 'string') {
Tim van der Lippeffa78622019-09-16 12:07:12701 this.titleElement.textContent = x;
Blink Reformat4c46d092018-04-07 15:32:37702 this.tooltip = x;
703 } else {
Tim van der Lippeffa78622019-09-16 12:07:12704 this.titleElement = x;
Blink Reformat4c46d092018-04-07 15:32:37705 this.tooltip = '';
706 }
707
708 this._listItemNode.removeChildren();
Tim van der Lippe1d6e57a2019-09-30 11:55:34709 if (this._leadingIconsElement) {
Blink Reformat4c46d092018-04-07 15:32:37710 this._listItemNode.appendChild(this._leadingIconsElement);
Tim van der Lippe1d6e57a2019-09-30 11:55:34711 }
Tim van der Lippeffa78622019-09-16 12:07:12712 this._listItemNode.appendChild(this.titleElement);
Tim van der Lippe1d6e57a2019-09-30 11:55:34713 if (this._trailingIconsElement) {
Blink Reformat4c46d092018-04-07 15:32:37714 this._listItemNode.appendChild(this._trailingIconsElement);
Tim van der Lippe1d6e57a2019-09-30 11:55:34715 }
Blink Reformat4c46d092018-04-07 15:32:37716 this._ensureSelection();
717 }
718
719 /**
720 * @return {string}
721 */
722 titleAsText() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34723 if (!this._title) {
Blink Reformat4c46d092018-04-07 15:32:37724 return '';
Tim van der Lippe1d6e57a2019-09-30 11:55:34725 }
726 if (typeof this._title === 'string') {
Blink Reformat4c46d092018-04-07 15:32:37727 return this._title;
Tim van der Lippe1d6e57a2019-09-30 11:55:34728 }
Blink Reformat4c46d092018-04-07 15:32:37729 return this._title.textContent;
730 }
731
732 /**
733 * @param {!UI.InplaceEditor.Config} editingConfig
734 */
735 startEditingTitle(editingConfig) {
Tim van der Lippeffa78622019-09-16 12:07:12736 UI.InplaceEditor.startEditing(/** @type {!Element} */ (this.titleElement), editingConfig);
737 this.treeOutline._shadowRoot.getSelection().selectAllChildren(this.titleElement);
Blink Reformat4c46d092018-04-07 15:32:37738 }
739
740 /**
741 * @param {!Array<!UI.Icon>} icons
742 */
743 setLeadingIcons(icons) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34744 if (!this._leadingIconsElement && !icons.length) {
Blink Reformat4c46d092018-04-07 15:32:37745 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34746 }
Blink Reformat4c46d092018-04-07 15:32:37747 if (!this._leadingIconsElement) {
748 this._leadingIconsElement = createElementWithClass('div', 'leading-icons');
749 this._leadingIconsElement.classList.add('icons-container');
Tim van der Lippeffa78622019-09-16 12:07:12750 this._listItemNode.insertBefore(this._leadingIconsElement, this.titleElement);
Blink Reformat4c46d092018-04-07 15:32:37751 this._ensureSelection();
752 }
753 this._leadingIconsElement.removeChildren();
Tim van der Lippe1d6e57a2019-09-30 11:55:34754 for (const icon of icons) {
Blink Reformat4c46d092018-04-07 15:32:37755 this._leadingIconsElement.appendChild(icon);
Tim van der Lippe1d6e57a2019-09-30 11:55:34756 }
Blink Reformat4c46d092018-04-07 15:32:37757 }
758
759 /**
760 * @param {!Array<!UI.Icon>} icons
761 */
762 setTrailingIcons(icons) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34763 if (!this._trailingIconsElement && !icons.length) {
Blink Reformat4c46d092018-04-07 15:32:37764 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34765 }
Blink Reformat4c46d092018-04-07 15:32:37766 if (!this._trailingIconsElement) {
767 this._trailingIconsElement = createElementWithClass('div', 'trailing-icons');
768 this._trailingIconsElement.classList.add('icons-container');
769 this._listItemNode.appendChild(this._trailingIconsElement);
770 this._ensureSelection();
771 }
772 this._trailingIconsElement.removeChildren();
Tim van der Lippe1d6e57a2019-09-30 11:55:34773 for (const icon of icons) {
Blink Reformat4c46d092018-04-07 15:32:37774 this._trailingIconsElement.appendChild(icon);
Tim van der Lippe1d6e57a2019-09-30 11:55:34775 }
Blink Reformat4c46d092018-04-07 15:32:37776 }
777
778
779 /**
780 * @return {string}
781 */
782 get tooltip() {
783 return this._tooltip || '';
784 }
785
786 /**
787 * @param {string} x
788 */
789 set tooltip(x) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34790 if (this._tooltip === x) {
Blink Reformat4c46d092018-04-07 15:32:37791 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34792 }
Blink Reformat4c46d092018-04-07 15:32:37793 this._tooltip = x;
794 this._listItemNode.title = x;
795 }
796
797 /**
798 * @return {boolean}
799 */
800 isExpandable() {
801 return this._expandable;
802 }
803
804 /**
805 * @param {boolean} expandable
806 */
807 setExpandable(expandable) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34808 if (this._expandable === expandable) {
Blink Reformat4c46d092018-04-07 15:32:37809 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34810 }
Blink Reformat4c46d092018-04-07 15:32:37811
812 this._expandable = expandable;
813
814 this._listItemNode.classList.toggle('parent', expandable);
815 if (!expandable) {
816 this.collapse();
Erik Luoca738ae2019-08-15 02:51:20817 UI.ARIAUtils.unsetExpandable(this._listItemNode);
Blink Reformat4c46d092018-04-07 15:32:37818 } else {
819 UI.ARIAUtils.setExpanded(this._listItemNode, false);
820 }
821 }
822
823 /**
824 * @param {boolean} collapsible
825 */
826 setCollapsible(collapsible) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34827 if (this._collapsible === collapsible) {
Blink Reformat4c46d092018-04-07 15:32:37828 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34829 }
Blink Reformat4c46d092018-04-07 15:32:37830
831 this._collapsible = collapsible;
832
833 this._listItemNode.classList.toggle('always-parent', !collapsible);
Tim van der Lippe1d6e57a2019-09-30 11:55:34834 if (!collapsible) {
Blink Reformat4c46d092018-04-07 15:32:37835 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34836 }
Blink Reformat4c46d092018-04-07 15:32:37837 }
838
839 get hidden() {
840 return this._hidden;
841 }
842
843 set hidden(x) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34844 if (this._hidden === x) {
Blink Reformat4c46d092018-04-07 15:32:37845 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34846 }
Blink Reformat4c46d092018-04-07 15:32:37847
848 this._hidden = x;
849
850 this._listItemNode.classList.toggle('hidden', x);
851 this._childrenListNode.classList.toggle('hidden', x);
852 }
853
854 invalidateChildren() {
855 if (this._children) {
856 this.removeChildren();
857 this._children = null;
858 }
859 }
860
Blink Reformat4c46d092018-04-07 15:32:37861
862 _ensureSelection() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34863 if (!this.treeOutline || !this.treeOutline._renderSelection) {
Blink Reformat4c46d092018-04-07 15:32:37864 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34865 }
866 if (!this._selectionElement) {
Blink Reformat4c46d092018-04-07 15:32:37867 this._selectionElement = createElementWithClass('div', 'selection fill');
Tim van der Lippe1d6e57a2019-09-30 11:55:34868 }
Blink Reformat4c46d092018-04-07 15:32:37869 this._listItemNode.insertBefore(this._selectionElement, this.listItemElement.firstChild);
870 }
871
872 /**
873 * @param {!Event} event
874 */
875 _treeElementToggled(event) {
876 const element = event.currentTarget;
Tim van der Lippe1d6e57a2019-09-30 11:55:34877 if (element.treeElement !== this || element.hasSelection()) {
Blink Reformat4c46d092018-04-07 15:32:37878 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34879 }
Blink Reformat4c46d092018-04-07 15:32:37880
Erik Luod6bf97b2018-08-25 02:06:51881 console.assert(!!this.treeOutline);
882 const showSelectionOnKeyboardFocus = this.treeOutline ? this.treeOutline._showSelectionOnKeyboardFocus : false;
883 const toggleOnClick = this.toggleOnClick && (showSelectionOnKeyboardFocus || !this.selectable);
Blink Reformat4c46d092018-04-07 15:32:37884 const isInTriangle = this.isEventWithinDisclosureTriangle(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34885 if (!toggleOnClick && !isInTriangle) {
Blink Reformat4c46d092018-04-07 15:32:37886 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34887 }
Blink Reformat4c46d092018-04-07 15:32:37888
889 if (this.expanded) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34890 if (event.altKey) {
Blink Reformat4c46d092018-04-07 15:32:37891 this.collapseRecursively();
Tim van der Lippe1d6e57a2019-09-30 11:55:34892 } else {
Blink Reformat4c46d092018-04-07 15:32:37893 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34894 }
Blink Reformat4c46d092018-04-07 15:32:37895 } else {
Tim van der Lippe1d6e57a2019-09-30 11:55:34896 if (event.altKey) {
Blink Reformat4c46d092018-04-07 15:32:37897 this.expandRecursively();
Tim van der Lippe1d6e57a2019-09-30 11:55:34898 } else {
Blink Reformat4c46d092018-04-07 15:32:37899 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34900 }
Blink Reformat4c46d092018-04-07 15:32:37901 }
902 event.consume();
903 }
904
905 /**
906 * @param {!Event} event
907 */
908 _handleMouseDown(event) {
909 const element = event.currentTarget;
Tim van der Lippe1d6e57a2019-09-30 11:55:34910 if (!element) {
Blink Reformat4c46d092018-04-07 15:32:37911 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34912 }
913 if (!this.selectable) {
Blink Reformat4c46d092018-04-07 15:32:37914 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34915 }
916 if (element.treeElement !== this) {
Blink Reformat4c46d092018-04-07 15:32:37917 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34918 }
Blink Reformat4c46d092018-04-07 15:32:37919
Tim van der Lippe1d6e57a2019-09-30 11:55:34920 if (this.isEventWithinDisclosureTriangle(event)) {
Blink Reformat4c46d092018-04-07 15:32:37921 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34922 }
Blink Reformat4c46d092018-04-07 15:32:37923
924 this.selectOnMouseDown(event);
925 }
926
927 /**
928 * @param {!Event} event
929 */
930 _handleDoubleClick(event) {
931 const element = event.currentTarget;
Tim van der Lippe1d6e57a2019-09-30 11:55:34932 if (!element || element.treeElement !== this) {
Blink Reformat4c46d092018-04-07 15:32:37933 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34934 }
Blink Reformat4c46d092018-04-07 15:32:37935
936 const handled = this.ondblclick(event);
Tim van der Lippe1d6e57a2019-09-30 11:55:34937 if (handled) {
Blink Reformat4c46d092018-04-07 15:32:37938 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34939 }
940 if (this._expandable && !this.expanded) {
Blink Reformat4c46d092018-04-07 15:32:37941 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:34942 }
Blink Reformat4c46d092018-04-07 15:32:37943 }
944
945 _detach() {
946 this._listItemNode.remove();
947 this._childrenListNode.remove();
948 }
949
950 collapse() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34951 if (!this.expanded || !this._collapsible) {
Blink Reformat4c46d092018-04-07 15:32:37952 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34953 }
Blink Reformat4c46d092018-04-07 15:32:37954 this._listItemNode.classList.remove('expanded');
955 this._childrenListNode.classList.remove('expanded');
956 UI.ARIAUtils.setExpanded(this._listItemNode, false);
957 this.expanded = false;
958 this.oncollapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34959 if (this.treeOutline) {
Tim van der Lippe0830b3d2019-10-03 13:20:07960 this.treeOutline.dispatchEventToListeners(Events.ElementCollapsed, this);
Tim van der Lippe1d6e57a2019-09-30 11:55:34961 }
Blink Reformat4c46d092018-04-07 15:32:37962 }
963
964 collapseRecursively() {
965 let item = this;
966 while (item) {
Tim van der Lippe1d6e57a2019-09-30 11:55:34967 if (item.expanded) {
Blink Reformat4c46d092018-04-07 15:32:37968 item.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:34969 }
Blink Reformat4c46d092018-04-07 15:32:37970 item = item.traverseNextTreeElement(false, this, true);
971 }
972 }
973
974 collapseChildren() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34975 if (!this._children) {
Blink Reformat4c46d092018-04-07 15:32:37976 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34977 }
978 for (const child of this._children) {
Blink Reformat4c46d092018-04-07 15:32:37979 child.collapseRecursively();
Tim van der Lippe1d6e57a2019-09-30 11:55:34980 }
Blink Reformat4c46d092018-04-07 15:32:37981 }
982
983 expand() {
Tim van der Lippe1d6e57a2019-09-30 11:55:34984 if (!this._expandable || (this.expanded && this._children)) {
Blink Reformat4c46d092018-04-07 15:32:37985 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:34986 }
Blink Reformat4c46d092018-04-07 15:32:37987
988 // Set this before onpopulate. Since onpopulate can add elements, this makes
989 // sure the expanded flag is true before calling those functions. This prevents the possibility
990 // of an infinite loop if onpopulate were to call expand.
991
992 this.expanded = true;
993
994 this._populateIfNeeded();
995 this._listItemNode.classList.add('expanded');
996 this._childrenListNode.classList.add('expanded');
997 UI.ARIAUtils.setExpanded(this._listItemNode, true);
998
999 if (this.treeOutline) {
1000 this.onexpand();
Tim van der Lippe0830b3d2019-10-03 13:20:071001 this.treeOutline.dispatchEventToListeners(Events.ElementExpanded, this);
Blink Reformat4c46d092018-04-07 15:32:371002 }
1003 }
1004
1005 /**
1006 * @param {number=} maxDepth
Paul Lewisbfa62952019-06-26 12:44:001007 * @returns {!Promise}
Blink Reformat4c46d092018-04-07 15:32:371008 */
Paul Lewisbfa62952019-06-26 12:44:001009 async expandRecursively(maxDepth) {
Blink Reformat4c46d092018-04-07 15:32:371010 let item = this;
1011 const info = {};
1012 let depth = 0;
1013
1014 // The Inspector uses TreeOutlines to represents object properties, so recursive expansion
1015 // in some case can be infinite, since JavaScript objects can hold circular references.
1016 // So default to a recursion cap of 3 levels, since that gives fairly good results.
Tim van der Lippe1d6e57a2019-09-30 11:55:341017 if (isNaN(maxDepth)) {
Blink Reformat4c46d092018-04-07 15:32:371018 maxDepth = 3;
Tim van der Lippe1d6e57a2019-09-30 11:55:341019 }
Blink Reformat4c46d092018-04-07 15:32:371020
1021 while (item) {
Paul Lewisbfa62952019-06-26 12:44:001022 await item._populateIfNeeded();
1023
Tim van der Lippe1d6e57a2019-09-30 11:55:341024 if (depth < maxDepth) {
Blink Reformat4c46d092018-04-07 15:32:371025 item.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:341026 }
Paul Lewisbfa62952019-06-26 12:44:001027
Blink Reformat4c46d092018-04-07 15:32:371028 item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info);
1029 depth += info.depthChange;
1030 }
1031 }
1032
1033 /**
1034 * @param {boolean} altKey
1035 * @return {boolean}
1036 */
1037 collapseOrAscend(altKey) {
Erik Luo1617c3f2018-11-01 21:15:181038 if (this.expanded && this._collapsible) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341039 if (altKey) {
Blink Reformat4c46d092018-04-07 15:32:371040 this.collapseRecursively();
Tim van der Lippe1d6e57a2019-09-30 11:55:341041 } else {
Blink Reformat4c46d092018-04-07 15:32:371042 this.collapse();
Tim van der Lippe1d6e57a2019-09-30 11:55:341043 }
Blink Reformat4c46d092018-04-07 15:32:371044 return true;
1045 }
1046
Tim van der Lippe1d6e57a2019-09-30 11:55:341047 if (!this.parent || this.parent.root) {
Blink Reformat4c46d092018-04-07 15:32:371048 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341049 }
Blink Reformat4c46d092018-04-07 15:32:371050
1051 if (!this.parent.selectable) {
1052 this.parent.collapse();
1053 return true;
1054 }
1055
1056 let nextSelectedElement = this.parent;
Tim van der Lippe1d6e57a2019-09-30 11:55:341057 while (nextSelectedElement && !nextSelectedElement.selectable) {
Blink Reformat4c46d092018-04-07 15:32:371058 nextSelectedElement = nextSelectedElement.parent;
Tim van der Lippe1d6e57a2019-09-30 11:55:341059 }
Blink Reformat4c46d092018-04-07 15:32:371060
Tim van der Lippe1d6e57a2019-09-30 11:55:341061 if (!nextSelectedElement) {
Blink Reformat4c46d092018-04-07 15:32:371062 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341063 }
Blink Reformat4c46d092018-04-07 15:32:371064 nextSelectedElement.select(false, true);
1065 return true;
1066 }
1067
1068 /**
1069 * @param {boolean} altKey
1070 * @return {boolean}
1071 */
1072 descendOrExpand(altKey) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341073 if (!this._expandable) {
Blink Reformat4c46d092018-04-07 15:32:371074 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341075 }
Blink Reformat4c46d092018-04-07 15:32:371076
1077 if (!this.expanded) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341078 if (altKey) {
Blink Reformat4c46d092018-04-07 15:32:371079 this.expandRecursively();
Tim van der Lippe1d6e57a2019-09-30 11:55:341080 } else {
Blink Reformat4c46d092018-04-07 15:32:371081 this.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:341082 }
Blink Reformat4c46d092018-04-07 15:32:371083 return true;
1084 }
1085
1086 let nextSelectedElement = this.firstChild();
Tim van der Lippe1d6e57a2019-09-30 11:55:341087 while (nextSelectedElement && !nextSelectedElement.selectable) {
Blink Reformat4c46d092018-04-07 15:32:371088 nextSelectedElement = nextSelectedElement.nextSibling;
Tim van der Lippe1d6e57a2019-09-30 11:55:341089 }
Blink Reformat4c46d092018-04-07 15:32:371090
Tim van der Lippe1d6e57a2019-09-30 11:55:341091 if (!nextSelectedElement) {
Blink Reformat4c46d092018-04-07 15:32:371092 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341093 }
Blink Reformat4c46d092018-04-07 15:32:371094 nextSelectedElement.select(false, true);
1095 return true;
1096 }
1097
1098 /**
1099 * @param {boolean=} center
1100 */
1101 reveal(center) {
1102 let currentAncestor = this.parent;
1103 while (currentAncestor && !currentAncestor.root) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341104 if (!currentAncestor.expanded) {
Blink Reformat4c46d092018-04-07 15:32:371105 currentAncestor.expand();
Tim van der Lippe1d6e57a2019-09-30 11:55:341106 }
Blink Reformat4c46d092018-04-07 15:32:371107 currentAncestor = currentAncestor.parent;
1108 }
1109
1110 this.treeOutline._deferredScrollIntoView(this, !!center);
1111 }
1112
1113 /**
1114 * @return {boolean}
1115 */
1116 revealed() {
1117 let currentAncestor = this.parent;
1118 while (currentAncestor && !currentAncestor.root) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341119 if (!currentAncestor.expanded) {
Blink Reformat4c46d092018-04-07 15:32:371120 return false;
Tim van der Lippe1d6e57a2019-09-30 11:55:341121 }
Blink Reformat4c46d092018-04-07 15:32:371122 currentAncestor = currentAncestor.parent;
1123 }
1124
1125 return true;
1126 }
1127
1128 selectOnMouseDown(event) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341129 if (this.select(false, true)) {
Blink Reformat4c46d092018-04-07 15:32:371130 event.consume(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:341131 }
Joel Einbinderfb3e1df2018-05-30 00:11:271132
1133 if (this._listItemNode.draggable && this._selectionElement) {
1134 const marginLeft =
1135 this.treeOutline.element.getBoundingClientRect().left - this._listItemNode.getBoundingClientRect().left;
1136 // By default the left margin extends far off screen. This is not a problem except when dragging an element.
1137 // Setting the margin once here should be fine, because we believe the left margin should never change.
1138 this._selectionElement.style.setProperty('margin-left', marginLeft + 'px');
1139 }
Blink Reformat4c46d092018-04-07 15:32:371140 }
1141
1142 /**
1143 * @param {boolean=} omitFocus
1144 * @param {boolean=} selectedByUser
1145 * @return {boolean}
1146 */
1147 select(omitFocus, selectedByUser) {
Erik Luo1617c3f2018-11-01 21:15:181148 if (!this.treeOutline || !this.selectable || this.selected) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341149 if (!omitFocus) {
Erik Luo1617c3f2018-11-01 21:15:181150 this.listItemElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:341151 }
Blink Reformat4c46d092018-04-07 15:32:371152 return false;
Erik Luo1617c3f2018-11-01 21:15:181153 }
Blink Reformat4c46d092018-04-07 15:32:371154 // Wait to deselect this element so that focus only changes once
1155 const lastSelected = this.treeOutline.selectedTreeElement;
1156 this.treeOutline.selectedTreeElement = null;
1157
1158 if (this.treeOutline._rootElement === this) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341159 if (lastSelected) {
Blink Reformat4c46d092018-04-07 15:32:371160 lastSelected.deselect();
Tim van der Lippe1d6e57a2019-09-30 11:55:341161 }
1162 if (!omitFocus) {
Erik Luo1617c3f2018-11-01 21:15:181163 this.listItemElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:341164 }
Blink Reformat4c46d092018-04-07 15:32:371165 return false;
1166 }
1167
1168 this.selected = true;
1169
1170 this.treeOutline.selectedTreeElement = this;
Tim van der Lippe1d6e57a2019-09-30 11:55:341171 if (this.treeOutline._focusable) {
Blink Reformat4c46d092018-04-07 15:32:371172 this._setFocusable(true);
Tim van der Lippe1d6e57a2019-09-30 11:55:341173 }
1174 if (!omitFocus || this.treeOutline.contentElement.hasFocus()) {
Blink Reformat4c46d092018-04-07 15:32:371175 this.listItemElement.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:341176 }
Blink Reformat4c46d092018-04-07 15:32:371177
1178 this._listItemNode.classList.add('selected');
Tim van der Lippe0830b3d2019-10-03 13:20:071179 this.treeOutline.dispatchEventToListeners(Events.ElementSelected, this);
Tim van der Lippe1d6e57a2019-09-30 11:55:341180 if (lastSelected) {
Blink Reformat4c46d092018-04-07 15:32:371181 lastSelected.deselect();
Tim van der Lippe1d6e57a2019-09-30 11:55:341182 }
Blink Reformat4c46d092018-04-07 15:32:371183 return this.onselect(selectedByUser);
1184 }
1185
1186 /**
1187 * @param {boolean} focusable
1188 */
1189 _setFocusable(focusable) {
1190 if (focusable) {
Erik Luocc14b812018-11-03 01:33:091191 this._listItemNode.setAttribute('tabIndex', this.treeOutline && this.treeOutline._preventTabOrder ? -1 : 0);
Blink Reformat4c46d092018-04-07 15:32:371192 this._listItemNode.addEventListener('focus', this._boundOnFocus, false);
1193 this._listItemNode.addEventListener('blur', this._boundOnBlur, false);
1194 } else {
1195 this._listItemNode.removeAttribute('tabIndex');
1196 this._listItemNode.removeEventListener('focus', this._boundOnFocus, false);
1197 this._listItemNode.removeEventListener('blur', this._boundOnBlur, false);
1198 }
1199 }
1200
1201 _onFocus() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341202 if (this.treeOutline._useLightSelectionColor) {
Pavel Feldman7ad5b272019-01-08 03:01:001203 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341204 }
1205 if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred')) {
Erik Luod6bf97b2018-08-25 02:06:511206 this._listItemNode.classList.add('force-white-icons');
Tim van der Lippe1d6e57a2019-09-30 11:55:341207 }
Blink Reformat4c46d092018-04-07 15:32:371208 }
1209
1210 _onBlur() {
Tim van der Lippe1d6e57a2019-09-30 11:55:341211 if (this.treeOutline._useLightSelectionColor) {
Pavel Feldman7ad5b272019-01-08 03:01:001212 return;
Tim van der Lippe1d6e57a2019-09-30 11:55:341213 }
1214 if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred')) {
Erik Luod6bf97b2018-08-25 02:06:511215 this._listItemNode.classList.remove('force-white-icons');
Tim van der Lippe1d6e57a2019-09-30 11:55:341216 }
Blink Reformat4c46d092018-04-07 15:32:371217 }
1218
1219 /**
1220 * @param {boolean=} omitFocus
1221 */
1222 revealAndSelect(omitFocus) {
1223 this.reveal(true);
1224 this.select(omitFocus);
1225 }
1226
1227 deselect() {
1228 const hadFocus = this._listItemNode.hasFocus();
1229 this.selected = false;
1230 this._listItemNode.classList.remove('selected');
1231 this._setFocusable(false);
1232
1233 if (this.treeOutline && this.treeOutline.selectedTreeElement === this) {
1234 this.treeOutline.selectedTreeElement = null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341235 if (hadFocus) {
Blink Reformat4c46d092018-04-07 15:32:371236 this.treeOutline.focus();
Tim van der Lippe1d6e57a2019-09-30 11:55:341237 }
Blink Reformat4c46d092018-04-07 15:32:371238 }
1239 }
1240
Paul Lewisbfa62952019-06-26 12:44:001241 /**
1242 * @returns {!Promise}
1243 */
1244 async _populateIfNeeded() {
Blink Reformat4c46d092018-04-07 15:32:371245 if (this.treeOutline && this._expandable && !this._children) {
1246 this._children = [];
Paul Lewisbfa62952019-06-26 12:44:001247 await this.onpopulate();
Blink Reformat4c46d092018-04-07 15:32:371248 }
1249 }
1250
Paul Lewisbfa62952019-06-26 12:44:001251 /**
1252 * @return {!Promise}
1253 */
1254 async onpopulate() {
Blink Reformat4c46d092018-04-07 15:32:371255 // Overridden by subclasses.
1256 }
1257
1258 /**
1259 * @return {boolean}
1260 */
1261 onenter() {
1262 return false;
1263 }
1264
1265 /**
1266 * @return {boolean}
1267 */
1268 ondelete() {
1269 return false;
1270 }
1271
1272 /**
1273 * @return {boolean}
1274 */
1275 onspace() {
1276 return false;
1277 }
1278
1279 onbind() {
1280 }
1281
1282 onunbind() {
1283 }
1284
1285 onattach() {
1286 }
1287
1288 onexpand() {
1289 }
1290
1291 oncollapse() {
1292 }
1293
1294 /**
1295 * @param {!Event} e
1296 * @return {boolean}
1297 */
1298 ondblclick(e) {
1299 return false;
1300 }
1301
1302 /**
1303 * @param {boolean=} selectedByUser
1304 * @return {boolean}
1305 */
1306 onselect(selectedByUser) {
1307 return false;
1308 }
1309
1310 /**
1311 * @param {boolean} skipUnrevealed
Tim van der Lippe0830b3d2019-10-03 13:20:071312 * @param {?TreeElement=} stayWithin
Blink Reformat4c46d092018-04-07 15:32:371313 * @param {boolean=} dontPopulate
1314 * @param {!Object=} info
Tim van der Lippe0830b3d2019-10-03 13:20:071315 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:371316 */
1317 traverseNextTreeElement(skipUnrevealed, stayWithin, dontPopulate, info) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341318 if (!dontPopulate) {
Blink Reformat4c46d092018-04-07 15:32:371319 this._populateIfNeeded();
Tim van der Lippe1d6e57a2019-09-30 11:55:341320 }
Blink Reformat4c46d092018-04-07 15:32:371321
Tim van der Lippe1d6e57a2019-09-30 11:55:341322 if (info) {
Blink Reformat4c46d092018-04-07 15:32:371323 info.depthChange = 0;
Tim van der Lippe1d6e57a2019-09-30 11:55:341324 }
Blink Reformat4c46d092018-04-07 15:32:371325
1326 let element = skipUnrevealed ? (this.revealed() ? this.firstChild() : null) : this.firstChild();
1327 if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341328 if (info) {
Blink Reformat4c46d092018-04-07 15:32:371329 info.depthChange = 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341330 }
Blink Reformat4c46d092018-04-07 15:32:371331 return element;
1332 }
1333
Tim van der Lippe1d6e57a2019-09-30 11:55:341334 if (this === stayWithin) {
Blink Reformat4c46d092018-04-07 15:32:371335 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341336 }
Blink Reformat4c46d092018-04-07 15:32:371337
1338 element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling;
Tim van der Lippe1d6e57a2019-09-30 11:55:341339 if (element) {
Blink Reformat4c46d092018-04-07 15:32:371340 return element;
Tim van der Lippe1d6e57a2019-09-30 11:55:341341 }
Blink Reformat4c46d092018-04-07 15:32:371342
1343 element = this;
1344 while (element && !element.root &&
1345 !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) &&
1346 element.parent !== stayWithin) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341347 if (info) {
Blink Reformat4c46d092018-04-07 15:32:371348 info.depthChange -= 1;
Tim van der Lippe1d6e57a2019-09-30 11:55:341349 }
Blink Reformat4c46d092018-04-07 15:32:371350 element = element.parent;
1351 }
1352
Tim van der Lippe1d6e57a2019-09-30 11:55:341353 if (!element || element.root) {
Blink Reformat4c46d092018-04-07 15:32:371354 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341355 }
Blink Reformat4c46d092018-04-07 15:32:371356
1357 return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling);
1358 }
1359
1360 /**
1361 * @param {boolean} skipUnrevealed
1362 * @param {boolean=} dontPopulate
Tim van der Lippe0830b3d2019-10-03 13:20:071363 * @return {?TreeElement}
Blink Reformat4c46d092018-04-07 15:32:371364 */
1365 traversePreviousTreeElement(skipUnrevealed, dontPopulate) {
1366 let element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling;
Tim van der Lippe1d6e57a2019-09-30 11:55:341367 if (!dontPopulate && element) {
Blink Reformat4c46d092018-04-07 15:32:371368 element._populateIfNeeded();
Tim van der Lippe1d6e57a2019-09-30 11:55:341369 }
Blink Reformat4c46d092018-04-07 15:32:371370
Tim van der Lippe0830b3d2019-10-03 13:20:071371 while (element &&
1372 (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) :
1373 element.lastChild())) {
Tim van der Lippe1d6e57a2019-09-30 11:55:341374 if (!dontPopulate) {
Blink Reformat4c46d092018-04-07 15:32:371375 element._populateIfNeeded();
Tim van der Lippe1d6e57a2019-09-30 11:55:341376 }
Blink Reformat4c46d092018-04-07 15:32:371377 element =
1378 (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) :
1379 element.lastChild());
1380 }
1381
Tim van der Lippe1d6e57a2019-09-30 11:55:341382 if (element) {
Blink Reformat4c46d092018-04-07 15:32:371383 return element;
Tim van der Lippe1d6e57a2019-09-30 11:55:341384 }
Blink Reformat4c46d092018-04-07 15:32:371385
Tim van der Lippe1d6e57a2019-09-30 11:55:341386 if (!this.parent || this.parent.root) {
Blink Reformat4c46d092018-04-07 15:32:371387 return null;
Tim van der Lippe1d6e57a2019-09-30 11:55:341388 }
Blink Reformat4c46d092018-04-07 15:32:371389
1390 return this.parent;
1391 }
1392
1393 /**
1394 * @return {boolean}
1395 */
1396 isEventWithinDisclosureTriangle(event) {
1397 // FIXME: We should not use getComputedStyle(). For that we need to get rid of using ::before for disclosure triangle. (http://webk.it/74446)
1398 const paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLeft;
1399 console.assert(paddingLeftValue.endsWith('px'));
1400 const computedLeftPadding = parseFloat(paddingLeftValue);
1401 const left = this._listItemNode.totalOffsetLeft() + computedLeftPadding;
Tim van der Lippe0830b3d2019-10-03 13:20:071402 return event.pageX >= left && event.pageX <= left + TreeElement._ArrowToggleWidth && this._expandable;
Blink Reformat4c46d092018-04-07 15:32:371403 }
Tim van der Lippe0830b3d2019-10-03 13:20:071404}
Blink Reformat4c46d092018-04-07 15:32:371405
1406/** @const */
Tim van der Lippe0830b3d2019-10-03 13:20:071407TreeElement._ArrowToggleWidth = 10;
Blink Reformat4c46d092018-04-07 15:32:371408
1409(function() {
1410const img = new Image();
Joel Einbinderf6f86b62019-06-10 23:19:121411img.src = 'Images/treeoutlineTriangles.svg';
Tim van der Lippe0830b3d2019-10-03 13:20:071412TreeElement._imagePreload = img;
Blink Reformat4c46d092018-04-07 15:32:371413})();
Tim van der Lippe0830b3d2019-10-03 13:20:071414
1415/* Legacy exported object*/
1416self.UI = self.UI || {};
1417
1418/* Legacy exported object*/
1419UI = UI || {};
1420
1421/** @constructor */
1422UI.TreeOutline = TreeOutline;
1423
1424UI.TreeOutline.Events = Events;
1425
1426/** @constructor */
1427UI.TreeElement = TreeElement;
1428
1429/** @constructor */
1430UI.TreeOutlineInShadow = TreeOutlineInShadow;