Shane Clifford | ec98d52 | 2020-05-01 17:24:53 | [diff] [blame] | 1 | // Copyright 2020 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 5 | /* |
| 6 | * Copyright (C) 2007 Apple Inc. All rights reserved. |
| 7 | * |
| 8 | * Redistribution and use in source and binary forms, with or without |
| 9 | * modification, are permitted provided that the following conditions |
| 10 | * are met: |
| 11 | * |
| 12 | * 1. Redistributions of source code must retain the above copyright |
| 13 | * notice, this list of conditions and the following disclaimer. |
| 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| 15 | * notice, this list of conditions and the following disclaimer in the |
| 16 | * documentation and/or other materials provided with the distribution. |
| 17 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
| 18 | * its contributors may be used to endorse or promote products derived |
| 19 | * from this software without specific prior written permission. |
| 20 | * |
| 21 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| 22 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| 23 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| 24 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| 25 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| 26 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| 27 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| 28 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 29 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| 30 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 31 | */ |
| 32 | |
Tim van der Lippe | ee97fa3 | 2020-04-23 15:20:56 | [diff] [blame] | 33 | // @ts-nocheck |
| 34 | // TODO(crbug.com/1011811): Enable TypeScript compiler checks |
| 35 | |
Paul Lewis | 17e384e | 2020-01-08 15:46:51 | [diff] [blame] | 36 | import * as Common from '../common/common.js'; |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 37 | |
| 38 | import * as ARIAUtils from './ARIAUtils.js'; |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 39 | import {Icon} from './Icon.js'; // eslint-disable-line no-unused-vars |
| 40 | import {Config, InplaceEditor} from './InplaceEditor.js'; // eslint-disable-line no-unused-vars |
| 41 | import {Keys} from './KeyboardShortcut.js'; |
| 42 | import {isEditing} from './UIUtils.js'; |
| 43 | import {appendStyle} from './utils/append-style.js'; |
| 44 | import {createShadowRootWithCoreStyles} from './utils/create-shadow-root-with-core-styles.js'; |
| 45 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 46 | /** |
| 47 | * @unrestricted |
| 48 | */ |
Paul Lewis | 17e384e | 2020-01-08 15:46:51 | [diff] [blame] | 49 | export class TreeOutline extends Common.ObjectWrapper.ObjectWrapper { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 50 | constructor() { |
| 51 | super(); |
| 52 | this._createRootElement(); |
| 53 | |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 54 | /** @type {?TreeElement} */ |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 55 | this.selectedTreeElement = null; |
| 56 | this.expandTreeElementsWhenArrowing = false; |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 57 | /** @type {?function(!TreeElement, !TreeElement):number} */ |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 58 | this._comparator = null; |
| 59 | |
| 60 | this.contentElement = this._rootElement._childrenListNode; |
Erik Luo | ea8f509 | 2018-09-19 22:37:13 | [diff] [blame] | 61 | this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this), false); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 62 | |
Erik Luo | cc14b81 | 2018-11-03 01:33:09 | [diff] [blame] | 63 | this._preventTabOrder = false; |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 64 | this._showSelectionOnKeyboardFocus = false; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 65 | this.setFocusable(true); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 66 | this.element = this.contentElement; |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 67 | ARIAUtils.markAsTree(this.element); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 68 | } |
| 69 | |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 70 | /** |
| 71 | * @param {boolean} show |
Erik Luo | cc14b81 | 2018-11-03 01:33:09 | [diff] [blame] | 72 | * @param {boolean=} preventTabOrder |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 73 | */ |
Erik Luo | cc14b81 | 2018-11-03 01:33:09 | [diff] [blame] | 74 | setShowSelectionOnKeyboardFocus(show, preventTabOrder) { |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 75 | this.contentElement.classList.toggle('hide-selection-when-blurred', show); |
Erik Luo | cc14b81 | 2018-11-03 01:33:09 | [diff] [blame] | 76 | this._preventTabOrder = !!preventTabOrder; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 77 | if (this._focusable) { |
| 78 | this.contentElement.tabIndex = !!preventTabOrder ? -1 : 0; |
| 79 | } |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 80 | this._showSelectionOnKeyboardFocus = show; |
| 81 | } |
| 82 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 83 | _createRootElement() { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 84 | this._rootElement = new TreeElement(); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 85 | this._rootElement.treeOutline = this; |
| 86 | this._rootElement.root = true; |
| 87 | this._rootElement.selectable = false; |
| 88 | this._rootElement.expanded = true; |
| 89 | this._rootElement._childrenListNode.classList.remove('children'); |
| 90 | } |
| 91 | |
| 92 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 93 | * @return {!TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 94 | */ |
| 95 | rootElement() { |
| 96 | return this._rootElement; |
| 97 | } |
| 98 | |
| 99 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 100 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 101 | */ |
| 102 | firstChild() { |
| 103 | return this._rootElement.firstChild(); |
| 104 | } |
| 105 | |
| 106 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 107 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 108 | */ |
| 109 | _lastDescendent() { |
| 110 | let last = this._rootElement.lastChild(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 111 | while (last.expanded && last.childCount()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 112 | last = last.lastChild(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 113 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 114 | return last; |
| 115 | } |
| 116 | |
| 117 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 118 | * @param {!TreeElement} child |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 119 | * @param {(function(!TreeElement, !TreeElement):number)=} comparator |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 120 | */ |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 121 | appendChild(child, comparator) { |
| 122 | this._rootElement.appendChild(child, comparator); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 123 | } |
| 124 | |
| 125 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 126 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 127 | * @param {number} index |
| 128 | */ |
| 129 | insertChild(child, index) { |
| 130 | this._rootElement.insertChild(child, index); |
| 131 | } |
| 132 | |
| 133 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 134 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 135 | */ |
| 136 | removeChild(child) { |
| 137 | this._rootElement.removeChild(child); |
| 138 | } |
| 139 | |
| 140 | removeChildren() { |
| 141 | this._rootElement.removeChildren(); |
| 142 | } |
| 143 | |
| 144 | /** |
| 145 | * @param {number} x |
| 146 | * @param {number} y |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 147 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 148 | */ |
| 149 | treeElementFromPoint(x, y) { |
| 150 | const node = this.contentElement.ownerDocument.deepElementFromPoint(x, y); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 151 | if (!node) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 152 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 153 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 154 | |
| 155 | const listNode = node.enclosingNodeOrSelfWithNodeNameInArray(['ol', 'li']); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 156 | if (listNode) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 157 | return listNode.parentTreeElement || listNode.treeElement; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 158 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 159 | return null; |
| 160 | } |
| 161 | |
| 162 | /** |
| 163 | * @param {?Event} event |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 164 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 165 | */ |
| 166 | treeElementFromEvent(event) { |
| 167 | return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; |
| 168 | } |
| 169 | |
| 170 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 171 | * @param {?function(!TreeElement, !TreeElement):number} comparator |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 172 | */ |
| 173 | setComparator(comparator) { |
| 174 | this._comparator = comparator; |
| 175 | } |
| 176 | |
| 177 | /** |
| 178 | * @param {boolean} focusable |
| 179 | */ |
| 180 | setFocusable(focusable) { |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 181 | this._focusable = focusable; |
| 182 | this.updateFocusable(); |
| 183 | } |
| 184 | |
| 185 | updateFocusable() { |
| 186 | if (this._focusable) { |
| 187 | this.contentElement.tabIndex = (this._preventTabOrder || !!this.selectedTreeElement) ? -1 : 0; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 188 | if (this.selectedTreeElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 189 | this.selectedTreeElement._setFocusable(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 190 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 191 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 192 | this.contentElement.removeAttribute('tabIndex'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 193 | if (this.selectedTreeElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 194 | this.selectedTreeElement._setFocusable(false); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 195 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 196 | } |
| 197 | } |
| 198 | |
| 199 | focus() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 200 | if (this.selectedTreeElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 201 | this.selectedTreeElement.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 202 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 203 | this.contentElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 204 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 205 | } |
| 206 | |
Pavel Feldman | 7ad5b27 | 2019-01-08 03:01:00 | [diff] [blame] | 207 | useLightSelectionColor() { |
| 208 | this._useLightSelectionColor = true; |
| 209 | } |
| 210 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 211 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 212 | * @param {!TreeElement} element |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 213 | */ |
| 214 | _bindTreeElement(element) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 215 | if (element.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 216 | console.error('Binding element for the second time: ' + new Error().stack); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 217 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 218 | element.treeOutline = this; |
| 219 | element.onbind(); |
| 220 | } |
| 221 | |
| 222 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 223 | * @param {!TreeElement} element |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 224 | */ |
| 225 | _unbindTreeElement(element) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 226 | if (!element.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 227 | console.error('Unbinding element that was not bound: ' + new Error().stack); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 228 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 229 | |
| 230 | element.deselect(); |
| 231 | element.onunbind(); |
| 232 | element.treeOutline = null; |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | * @return {boolean} |
| 237 | */ |
| 238 | selectPrevious() { |
| 239 | let nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 240 | while (nextSelectedElement && !nextSelectedElement.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 241 | nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 242 | } |
| 243 | if (!nextSelectedElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 244 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 245 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 246 | nextSelectedElement.select(false, true); |
| 247 | return true; |
| 248 | } |
| 249 | |
| 250 | /** |
| 251 | * @return {boolean} |
| 252 | */ |
| 253 | selectNext() { |
| 254 | let nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 255 | while (nextSelectedElement && !nextSelectedElement.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 256 | nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 257 | } |
| 258 | if (!nextSelectedElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 259 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 260 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 261 | nextSelectedElement.select(false, true); |
| 262 | return true; |
| 263 | } |
| 264 | |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 265 | /** |
| 266 | * @param {boolean=} omitFocus |
| 267 | * @param {boolean=} selectedByUser |
| 268 | */ |
| 269 | forceSelect(omitFocus = false, selectedByUser = true) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 270 | if (this.selectedTreeElement) { |
Erik Luo | 31c21f6 | 2018-12-13 03:39:39 | [diff] [blame] | 271 | this.selectedTreeElement.deselect(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 272 | } |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 273 | this._selectFirst(omitFocus, selectedByUser); |
Erik Luo | 31c21f6 | 2018-12-13 03:39:39 | [diff] [blame] | 274 | } |
| 275 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 276 | /** |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 277 | * @param {boolean=} omitFocus |
| 278 | * @param {boolean=} selectedByUser |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 279 | * @return {boolean} |
| 280 | */ |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 281 | _selectFirst(omitFocus = false, selectedByUser = true) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 282 | let first = this.firstChild(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 283 | while (first && !first.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 284 | first = first.traverseNextTreeElement(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 285 | } |
| 286 | if (!first) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 287 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 288 | } |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 289 | first.select(omitFocus, selectedByUser); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 290 | return true; |
| 291 | } |
| 292 | |
| 293 | /** |
| 294 | * @return {boolean} |
| 295 | */ |
| 296 | _selectLast() { |
| 297 | let last = this._lastDescendent(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 298 | while (last && !last.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 299 | last = last.traversePreviousTreeElement(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 300 | } |
| 301 | if (!last) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 302 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 303 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 304 | last.select(false, true); |
| 305 | return true; |
| 306 | } |
| 307 | |
| 308 | /** |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 309 | * @param {!Event} event |
| 310 | */ |
| 311 | _treeKeyDown(event) { |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 312 | if (event.shiftKey || event.metaKey || event.ctrlKey || isEditing()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 313 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 314 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 315 | |
| 316 | let handled = false; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 317 | if (!this.selectedTreeElement) { |
| 318 | if (event.key === 'ArrowUp' && !event.altKey) { |
| 319 | handled = this._selectLast(); |
| 320 | } else if (event.key === 'ArrowDown' && !event.altKey) { |
| 321 | handled = this._selectFirst(); |
| 322 | } |
| 323 | } else if (event.key === 'ArrowUp' && !event.altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 324 | handled = this.selectPrevious(); |
| 325 | } else if (event.key === 'ArrowDown' && !event.altKey) { |
| 326 | handled = this.selectNext(); |
| 327 | } else if (event.key === 'ArrowLeft') { |
| 328 | handled = this.selectedTreeElement.collapseOrAscend(event.altKey); |
| 329 | } else if (event.key === 'ArrowRight') { |
| 330 | if (!this.selectedTreeElement.revealed()) { |
| 331 | this.selectedTreeElement.reveal(); |
| 332 | handled = true; |
| 333 | } else { |
| 334 | handled = this.selectedTreeElement.descendOrExpand(event.altKey); |
| 335 | } |
| 336 | } else if (event.keyCode === 8 /* Backspace */ || event.keyCode === 46 /* Delete */) { |
| 337 | handled = this.selectedTreeElement.ondelete(); |
| 338 | } else if (isEnterKey(event)) { |
| 339 | handled = this.selectedTreeElement.onenter(); |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 340 | } else if (event.keyCode === Keys.Space.code) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 341 | handled = this.selectedTreeElement.onspace(); |
| 342 | } else if (event.key === 'Home') { |
Erik Luo | 31c21f6 | 2018-12-13 03:39:39 | [diff] [blame] | 343 | handled = this._selectFirst(); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 344 | } else if (event.key === 'End') { |
| 345 | handled = this._selectLast(); |
| 346 | } |
| 347 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 348 | if (handled) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 349 | event.consume(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 350 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 351 | } |
| 352 | |
| 353 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 354 | * @param {!TreeElement} treeElement |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 355 | * @param {boolean} center |
| 356 | */ |
| 357 | _deferredScrollIntoView(treeElement, center) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 358 | if (!this._treeElementToScrollIntoView) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 359 | this.element.window().requestAnimationFrame(deferredScrollIntoView.bind(this)); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 360 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 361 | this._treeElementToScrollIntoView = treeElement; |
| 362 | this._centerUponScrollIntoView = center; |
| 363 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 364 | * @this {TreeOutline} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 365 | */ |
| 366 | function deferredScrollIntoView() { |
Shane Clifford | ec98d52 | 2020-05-01 17:24:53 | [diff] [blame] | 367 | // This function no longer uses scrollIntoViewIfNeeded because users were bothered |
| 368 | // by the fact that it always scrolls in both direction even if only one is necessary |
| 369 | // to bring the item into view. |
| 370 | |
| 371 | const itemRect = this._treeElementToScrollIntoView.listItemElement.getBoundingClientRect(); |
| 372 | const treeRect = this.contentElement.getBoundingClientRect(); |
| 373 | const viewRect = this.element.getBoundingClientRect(); |
| 374 | |
| 375 | const currentScrollX = viewRect.left - treeRect.left; |
| 376 | const currentScrollY = viewRect.top - treeRect.top; |
| 377 | |
| 378 | // Only scroll into view on each axis if the item is not visible at all |
| 379 | // but if we do scroll and _centerUponScrollIntoView is true |
| 380 | // then we center the top left corner of the item in view. |
| 381 | let deltaLeft = itemRect.left - treeRect.left; |
| 382 | if (deltaLeft > currentScrollX && deltaLeft < currentScrollX + viewRect.width) { |
| 383 | deltaLeft = currentScrollX; |
| 384 | } else if (this._centerUponScrollIntoView) { |
| 385 | deltaLeft = deltaLeft - viewRect.width / 2; |
| 386 | } |
| 387 | let deltaTop = itemRect.top - treeRect.top; |
| 388 | if (deltaTop > currentScrollY && deltaTop < currentScrollY + viewRect.height) { |
| 389 | deltaTop = currentScrollY; |
| 390 | } else if (this._centerUponScrollIntoView) { |
| 391 | deltaTop = deltaTop - viewRect.height / 2; |
| 392 | } |
| 393 | this.element.scrollTo(deltaLeft, deltaTop); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 394 | delete this._treeElementToScrollIntoView; |
| 395 | delete this._centerUponScrollIntoView; |
| 396 | } |
| 397 | } |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 398 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 399 | |
| 400 | /** @enum {symbol} */ |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 401 | export const Events = { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 402 | ElementAttached: Symbol('ElementAttached'), |
Erik Luo | 96fee7b | 2019-06-21 04:30:29 | [diff] [blame] | 403 | ElementsDetached: Symbol('ElementsDetached'), |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 404 | ElementExpanded: Symbol('ElementExpanded'), |
| 405 | ElementCollapsed: Symbol('ElementCollapsed'), |
| 406 | ElementSelected: Symbol('ElementSelected') |
| 407 | }; |
| 408 | |
| 409 | /** |
| 410 | * @unrestricted |
| 411 | */ |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 412 | export class TreeOutlineInShadow extends TreeOutline { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 413 | constructor() { |
| 414 | super(); |
| 415 | this.contentElement.classList.add('tree-outline'); |
| 416 | |
| 417 | // Redefine element to the external one. |
| 418 | this.element = createElement('div'); |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 419 | this._shadowRoot = createShadowRootWithCoreStyles(this.element, 'ui/treeoutline.css'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 420 | this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline-disclosure'); |
| 421 | this._disclosureElement.appendChild(this.contentElement); |
| 422 | this._renderSelection = true; |
| 423 | } |
| 424 | |
| 425 | /** |
| 426 | * @param {string} cssFile |
| 427 | */ |
| 428 | registerRequiredCSS(cssFile) { |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 429 | appendStyle(this._shadowRoot, cssFile); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 430 | } |
| 431 | |
| 432 | hideOverflow() { |
| 433 | this._disclosureElement.classList.add('tree-outline-disclosure-hide-overflow'); |
| 434 | } |
| 435 | |
| 436 | makeDense() { |
| 437 | this.contentElement.classList.add('tree-outline-dense'); |
| 438 | } |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 439 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 440 | |
| 441 | /** |
| 442 | * @unrestricted |
| 443 | */ |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 444 | export class TreeElement { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 445 | /** |
| 446 | * @param {(string|!Node)=} title |
| 447 | * @param {boolean=} expandable |
| 448 | */ |
| 449 | constructor(title, expandable) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 450 | /** @type {?TreeOutline} */ |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 451 | this.treeOutline = null; |
| 452 | this.parent = null; |
| 453 | this.previousSibling = null; |
| 454 | this.nextSibling = null; |
| 455 | this._boundOnFocus = this._onFocus.bind(this); |
| 456 | this._boundOnBlur = this._onBlur.bind(this); |
| 457 | |
Changhao Han | c1817b2 | 2020-09-07 09:04:18 | [diff] [blame^] | 458 | this._listItemNode = /** @type {!HTMLLIElement} */ (createElement('li')); |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 459 | /** @protected */ |
| 460 | this.titleElement = this._listItemNode.createChild('span', 'tree-element-title'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 461 | this._listItemNode.treeElement = this; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 462 | if (title) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 463 | this.title = title; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 464 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 465 | this._listItemNode.addEventListener('mousedown', this._handleMouseDown.bind(this), false); |
| 466 | this._listItemNode.addEventListener('click', this._treeElementToggled.bind(this), false); |
| 467 | this._listItemNode.addEventListener('dblclick', this._handleDoubleClick.bind(this), false); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 468 | ARIAUtils.markAsTreeitem(this._listItemNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 469 | |
| 470 | this._childrenListNode = createElement('ol'); |
| 471 | this._childrenListNode.parentTreeElement = this; |
| 472 | this._childrenListNode.classList.add('children'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 473 | ARIAUtils.markAsGroup(this._childrenListNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 474 | |
| 475 | this._hidden = false; |
| 476 | this._selectable = true; |
| 477 | this.expanded = false; |
| 478 | this.selected = false; |
| 479 | this.setExpandable(expandable || false); |
| 480 | this._collapsible = true; |
| 481 | } |
| 482 | |
| 483 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 484 | * @param {?TreeElement} ancestor |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 485 | * @return {boolean} |
| 486 | */ |
| 487 | hasAncestor(ancestor) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 488 | if (!ancestor) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 489 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 490 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 491 | |
| 492 | let currentNode = this.parent; |
| 493 | while (currentNode) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 494 | if (ancestor === currentNode) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 495 | return true; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 496 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 497 | currentNode = currentNode.parent; |
| 498 | } |
| 499 | |
| 500 | return false; |
| 501 | } |
| 502 | |
| 503 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 504 | * @param {?TreeElement} ancestor |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 505 | * @return {boolean} |
| 506 | */ |
| 507 | hasAncestorOrSelf(ancestor) { |
| 508 | return this === ancestor || this.hasAncestor(ancestor); |
| 509 | } |
| 510 | |
| 511 | /** |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 512 | * @return {boolean} |
| 513 | */ |
| 514 | isHidden() { |
| 515 | if (this.hidden) { |
| 516 | return true; |
| 517 | } |
| 518 | |
| 519 | let currentNode = this.parent; |
| 520 | while (currentNode) { |
| 521 | if (currentNode.hidden) { |
| 522 | return true; |
| 523 | } |
| 524 | currentNode = currentNode.parent; |
| 525 | } |
| 526 | |
| 527 | return false; |
| 528 | } |
| 529 | |
| 530 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 531 | * @return {!Array.<!TreeElement>} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 532 | */ |
| 533 | children() { |
| 534 | return this._children || []; |
| 535 | } |
| 536 | |
| 537 | /** |
| 538 | * @return {number} |
| 539 | */ |
| 540 | childCount() { |
| 541 | return this._children ? this._children.length : 0; |
| 542 | } |
| 543 | |
| 544 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 545 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 546 | */ |
| 547 | firstChild() { |
| 548 | return this._children ? this._children[0] : null; |
| 549 | } |
| 550 | |
| 551 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 552 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 553 | */ |
| 554 | lastChild() { |
| 555 | return this._children ? this._children[this._children.length - 1] : null; |
| 556 | } |
| 557 | |
| 558 | /** |
| 559 | * @param {number} index |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 560 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 561 | */ |
| 562 | childAt(index) { |
| 563 | return this._children ? this._children[index] : null; |
| 564 | } |
| 565 | |
| 566 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 567 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 568 | * @return {number} |
| 569 | */ |
| 570 | indexOfChild(child) { |
| 571 | return this._children ? this._children.indexOf(child) : -1; |
| 572 | } |
| 573 | |
| 574 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 575 | * @param {!TreeElement} child |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 576 | * @param {(function(!TreeElement, !TreeElement):number)=} comparator |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 577 | */ |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 578 | appendChild(child, comparator) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 579 | if (!this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 580 | this._children = []; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 581 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 582 | |
| 583 | let insertionIndex; |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 584 | if (comparator) { |
| 585 | insertionIndex = this._children.lowerBound(child, comparator); |
| 586 | } else if (this.treeOutline && this.treeOutline._comparator) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 587 | insertionIndex = this._children.lowerBound(child, this.treeOutline._comparator); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 588 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 589 | insertionIndex = this._children.length; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 590 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 591 | this.insertChild(child, insertionIndex); |
| 592 | } |
| 593 | |
| 594 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 595 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 596 | * @param {number} index |
| 597 | */ |
| 598 | insertChild(child, index) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 599 | if (!this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 600 | this._children = []; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 601 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 602 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 603 | if (!child) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 604 | throw 'child can\'t be undefined or null'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 605 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 606 | |
| 607 | console.assert( |
| 608 | !child.parent, 'Attempting to insert a child that is already in the tree, reparenting is not supported.'); |
| 609 | |
| 610 | const previousChild = (index > 0 ? this._children[index - 1] : null); |
| 611 | if (previousChild) { |
| 612 | previousChild.nextSibling = child; |
| 613 | child.previousSibling = previousChild; |
| 614 | } else { |
| 615 | child.previousSibling = null; |
| 616 | } |
| 617 | |
| 618 | const nextChild = this._children[index]; |
| 619 | if (nextChild) { |
| 620 | nextChild.previousSibling = child; |
| 621 | child.nextSibling = nextChild; |
| 622 | } else { |
| 623 | child.nextSibling = null; |
| 624 | } |
| 625 | |
| 626 | this._children.splice(index, 0, child); |
| 627 | |
| 628 | this.setExpandable(true); |
| 629 | child.parent = this; |
| 630 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 631 | if (this.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 632 | this.treeOutline._bindTreeElement(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 633 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 634 | for (let current = child.firstChild(); this.treeOutline && current; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 635 | current = current.traverseNextTreeElement(false, child, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 636 | this.treeOutline._bindTreeElement(current); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 637 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 638 | child.onattach(); |
| 639 | child._ensureSelection(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 640 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 641 | this.treeOutline.dispatchEventToListeners(Events.ElementAttached, child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 642 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 643 | const nextSibling = child.nextSibling ? child.nextSibling._listItemNode : null; |
| 644 | this._childrenListNode.insertBefore(child._listItemNode, nextSibling); |
| 645 | this._childrenListNode.insertBefore(child._childrenListNode, nextSibling); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 646 | if (child.selected) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 647 | child.select(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 648 | } |
| 649 | if (child.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 650 | child.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 651 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 652 | } |
| 653 | |
| 654 | /** |
| 655 | * @param {number} childIndex |
| 656 | */ |
| 657 | removeChildAtIndex(childIndex) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 658 | if (childIndex < 0 || childIndex >= this._children.length) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 659 | throw 'childIndex out of range'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 660 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 661 | |
| 662 | const child = this._children[childIndex]; |
| 663 | this._children.splice(childIndex, 1); |
| 664 | |
| 665 | const parent = child.parent; |
| 666 | if (this.treeOutline && this.treeOutline.selectedTreeElement && |
| 667 | this.treeOutline.selectedTreeElement.hasAncestorOrSelf(child)) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 668 | if (child.nextSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 669 | child.nextSibling.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 670 | } else if (child.previousSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 671 | child.previousSibling.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 672 | } else if (parent) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 673 | parent.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 674 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 675 | } |
| 676 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 677 | if (child.previousSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 678 | child.previousSibling.nextSibling = child.nextSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 679 | } |
| 680 | if (child.nextSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 681 | child.nextSibling.previousSibling = child.previousSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 682 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 683 | child.parent = null; |
| 684 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 685 | if (this.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 686 | this.treeOutline._unbindTreeElement(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 687 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 688 | for (let current = child.firstChild(); this.treeOutline && current; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 689 | current = current.traverseNextTreeElement(false, child, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 690 | this.treeOutline._unbindTreeElement(current); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 691 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 692 | |
| 693 | child._detach(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 694 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 695 | this.treeOutline.dispatchEventToListeners(Events.ElementsDetached); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 696 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 697 | } |
| 698 | |
| 699 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 700 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 701 | */ |
| 702 | removeChild(child) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 703 | if (!child) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 704 | throw 'child can\'t be undefined or null'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 705 | } |
| 706 | if (child.parent !== this) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 707 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 708 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 709 | |
| 710 | const childIndex = this._children.indexOf(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 711 | if (childIndex === -1) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 712 | throw 'child not found in this node\'s children'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 713 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 714 | |
| 715 | this.removeChildAtIndex(childIndex); |
| 716 | } |
| 717 | |
| 718 | removeChildren() { |
| 719 | if (!this.root && this.treeOutline && this.treeOutline.selectedTreeElement && |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 720 | this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 721 | this.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 722 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 723 | |
| 724 | for (let i = 0; this._children && i < this._children.length; ++i) { |
| 725 | const child = this._children[i]; |
| 726 | child.previousSibling = null; |
| 727 | child.nextSibling = null; |
| 728 | child.parent = null; |
| 729 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 730 | if (this.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 731 | this.treeOutline._unbindTreeElement(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 732 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 733 | for (let current = child.firstChild(); this.treeOutline && current; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 734 | current = current.traverseNextTreeElement(false, child, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 735 | this.treeOutline._unbindTreeElement(current); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 736 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 737 | child._detach(); |
| 738 | } |
| 739 | this._children = []; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 740 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 741 | this.treeOutline.dispatchEventToListeners(Events.ElementsDetached); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 742 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 743 | } |
| 744 | |
| 745 | get selectable() { |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 746 | if (this.isHidden()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 747 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 748 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 749 | return this._selectable; |
| 750 | } |
| 751 | |
| 752 | set selectable(x) { |
| 753 | this._selectable = x; |
| 754 | } |
| 755 | |
| 756 | get listItemElement() { |
| 757 | return this._listItemNode; |
| 758 | } |
| 759 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 760 | get childrenListElement() { |
| 761 | return this._childrenListNode; |
| 762 | } |
| 763 | |
| 764 | /** |
| 765 | * @return {string|!Node} |
| 766 | */ |
| 767 | get title() { |
| 768 | return this._title; |
| 769 | } |
| 770 | |
| 771 | /** |
| 772 | * @param {string|!Node} x |
| 773 | */ |
| 774 | set title(x) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 775 | if (this._title === x) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 776 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 777 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 778 | this._title = x; |
| 779 | |
| 780 | if (typeof x === 'string') { |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 781 | this.titleElement.textContent = x; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 782 | this.tooltip = x; |
| 783 | } else { |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 784 | this.titleElement = x; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 785 | this.tooltip = ''; |
| 786 | } |
| 787 | |
| 788 | this._listItemNode.removeChildren(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 789 | if (this._leadingIconsElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 790 | this._listItemNode.appendChild(this._leadingIconsElement); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 791 | } |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 792 | this._listItemNode.appendChild(this.titleElement); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 793 | if (this._trailingIconsElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 794 | this._listItemNode.appendChild(this._trailingIconsElement); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 795 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 796 | this._ensureSelection(); |
| 797 | } |
| 798 | |
| 799 | /** |
| 800 | * @return {string} |
| 801 | */ |
| 802 | titleAsText() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 803 | if (!this._title) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 804 | return ''; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 805 | } |
| 806 | if (typeof this._title === 'string') { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 807 | return this._title; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 808 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 809 | return this._title.textContent; |
| 810 | } |
| 811 | |
| 812 | /** |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 813 | * @param {!Config<*>} editingConfig |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 814 | */ |
| 815 | startEditingTitle(editingConfig) { |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 816 | InplaceEditor.startEditing(/** @type {!Element} */ (this.titleElement), editingConfig); |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 817 | this.treeOutline._shadowRoot.getSelection().selectAllChildren(this.titleElement); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 818 | } |
| 819 | |
| 820 | /** |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 821 | * @param {!Array<!Icon>} icons |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 822 | */ |
| 823 | setLeadingIcons(icons) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 824 | if (!this._leadingIconsElement && !icons.length) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 825 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 826 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 827 | if (!this._leadingIconsElement) { |
Tim van der Lippe | f49e232 | 2020-05-01 15:03:09 | [diff] [blame] | 828 | this._leadingIconsElement = document.createElement('div'); |
| 829 | this._leadingIconsElement.classList.add('leading-icons'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 830 | this._leadingIconsElement.classList.add('icons-container'); |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 831 | this._listItemNode.insertBefore(this._leadingIconsElement, this.titleElement); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 832 | this._ensureSelection(); |
| 833 | } |
| 834 | this._leadingIconsElement.removeChildren(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 835 | for (const icon of icons) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 836 | this._leadingIconsElement.appendChild(icon); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 837 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 838 | } |
| 839 | |
| 840 | /** |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 841 | * @param {!Array<!Icon>} icons |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 842 | */ |
| 843 | setTrailingIcons(icons) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 844 | if (!this._trailingIconsElement && !icons.length) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 845 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 846 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 847 | if (!this._trailingIconsElement) { |
Tim van der Lippe | f49e232 | 2020-05-01 15:03:09 | [diff] [blame] | 848 | this._trailingIconsElement = document.createElement('div'); |
| 849 | this._trailingIconsElement.classList.add('trailing-icons'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 850 | this._trailingIconsElement.classList.add('icons-container'); |
| 851 | this._listItemNode.appendChild(this._trailingIconsElement); |
| 852 | this._ensureSelection(); |
| 853 | } |
| 854 | this._trailingIconsElement.removeChildren(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 855 | for (const icon of icons) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 856 | this._trailingIconsElement.appendChild(icon); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 857 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 858 | } |
| 859 | |
| 860 | |
| 861 | /** |
| 862 | * @return {string} |
| 863 | */ |
| 864 | get tooltip() { |
| 865 | return this._tooltip || ''; |
| 866 | } |
| 867 | |
| 868 | /** |
| 869 | * @param {string} x |
| 870 | */ |
| 871 | set tooltip(x) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 872 | if (this._tooltip === x) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 873 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 874 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 875 | this._tooltip = x; |
| 876 | this._listItemNode.title = x; |
| 877 | } |
| 878 | |
| 879 | /** |
| 880 | * @return {boolean} |
| 881 | */ |
| 882 | isExpandable() { |
| 883 | return this._expandable; |
| 884 | } |
| 885 | |
| 886 | /** |
| 887 | * @param {boolean} expandable |
| 888 | */ |
| 889 | setExpandable(expandable) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 890 | if (this._expandable === expandable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 891 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 892 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 893 | |
| 894 | this._expandable = expandable; |
| 895 | |
| 896 | this._listItemNode.classList.toggle('parent', expandable); |
| 897 | if (!expandable) { |
| 898 | this.collapse(); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 899 | ARIAUtils.unsetExpandable(this._listItemNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 900 | } else { |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 901 | ARIAUtils.setExpanded(this._listItemNode, false); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 902 | } |
| 903 | } |
| 904 | |
| 905 | /** |
| 906 | * @param {boolean} collapsible |
| 907 | */ |
| 908 | setCollapsible(collapsible) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 909 | if (this._collapsible === collapsible) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 910 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 911 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 912 | |
| 913 | this._collapsible = collapsible; |
| 914 | |
| 915 | this._listItemNode.classList.toggle('always-parent', !collapsible); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 916 | if (!collapsible) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 917 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 918 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 919 | } |
| 920 | |
| 921 | get hidden() { |
| 922 | return this._hidden; |
| 923 | } |
| 924 | |
| 925 | set hidden(x) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 926 | if (this._hidden === x) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 927 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 928 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 929 | |
| 930 | this._hidden = x; |
| 931 | |
| 932 | this._listItemNode.classList.toggle('hidden', x); |
| 933 | this._childrenListNode.classList.toggle('hidden', x); |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 934 | |
| 935 | if (x && this.treeOutline && this.treeOutline.selectedTreeElement && |
| 936 | this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) { |
| 937 | const hadFocus = this.treeOutline.selectedTreeElement.listItemElement.hasFocus(); |
| 938 | this.treeOutline.forceSelect(!hadFocus, /* selectedByUser */ false); |
| 939 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 940 | } |
| 941 | |
| 942 | invalidateChildren() { |
| 943 | if (this._children) { |
| 944 | this.removeChildren(); |
| 945 | this._children = null; |
| 946 | } |
| 947 | } |
| 948 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 949 | |
| 950 | _ensureSelection() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 951 | if (!this.treeOutline || !this.treeOutline._renderSelection) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 952 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 953 | } |
| 954 | if (!this._selectionElement) { |
Tim van der Lippe | e7f2705 | 2020-05-01 15:15:28 | [diff] [blame] | 955 | this._selectionElement = document.createElement('div'); |
| 956 | this._selectionElement.classList.add('selection'); |
| 957 | this._selectionElement.classList.add('fill'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 958 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 959 | this._listItemNode.insertBefore(this._selectionElement, this.listItemElement.firstChild); |
| 960 | } |
| 961 | |
| 962 | /** |
| 963 | * @param {!Event} event |
| 964 | */ |
| 965 | _treeElementToggled(event) { |
| 966 | const element = event.currentTarget; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 967 | if (element.treeElement !== this || element.hasSelection()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 968 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 969 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 970 | |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 971 | console.assert(!!this.treeOutline); |
| 972 | const showSelectionOnKeyboardFocus = this.treeOutline ? this.treeOutline._showSelectionOnKeyboardFocus : false; |
| 973 | const toggleOnClick = this.toggleOnClick && (showSelectionOnKeyboardFocus || !this.selectable); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 974 | const isInTriangle = this.isEventWithinDisclosureTriangle(event); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 975 | if (!toggleOnClick && !isInTriangle) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 976 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 977 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 978 | |
| 979 | if (this.expanded) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 980 | if (event.altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 981 | this.collapseRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 982 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 983 | this.collapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 984 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 985 | } else { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 986 | if (event.altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 987 | this.expandRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 988 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 989 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 990 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 991 | } |
| 992 | event.consume(); |
| 993 | } |
| 994 | |
| 995 | /** |
| 996 | * @param {!Event} event |
| 997 | */ |
| 998 | _handleMouseDown(event) { |
| 999 | const element = event.currentTarget; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1000 | if (!element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1001 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1002 | } |
| 1003 | if (!this.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1004 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1005 | } |
| 1006 | if (element.treeElement !== this) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1007 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1008 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1009 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1010 | if (this.isEventWithinDisclosureTriangle(event)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1011 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1012 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1013 | |
| 1014 | this.selectOnMouseDown(event); |
| 1015 | } |
| 1016 | |
| 1017 | /** |
| 1018 | * @param {!Event} event |
| 1019 | */ |
| 1020 | _handleDoubleClick(event) { |
| 1021 | const element = event.currentTarget; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1022 | if (!element || element.treeElement !== this) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1023 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1024 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1025 | |
| 1026 | const handled = this.ondblclick(event); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1027 | if (handled) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1028 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1029 | } |
| 1030 | if (this._expandable && !this.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1031 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1032 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1033 | } |
| 1034 | |
| 1035 | _detach() { |
| 1036 | this._listItemNode.remove(); |
| 1037 | this._childrenListNode.remove(); |
| 1038 | } |
| 1039 | |
| 1040 | collapse() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1041 | if (!this.expanded || !this._collapsible) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1042 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1043 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1044 | this._listItemNode.classList.remove('expanded'); |
| 1045 | this._childrenListNode.classList.remove('expanded'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1046 | ARIAUtils.setExpanded(this._listItemNode, false); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1047 | this.expanded = false; |
| 1048 | this.oncollapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1049 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1050 | this.treeOutline.dispatchEventToListeners(Events.ElementCollapsed, this); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1051 | } |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 1052 | |
| 1053 | const selectedTreeElement = this.treeOutline.selectedTreeElement; |
| 1054 | if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) { |
| 1055 | this.select(/* omitFocus */ true, /* selectedByUser */ true); |
| 1056 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1057 | } |
| 1058 | |
| 1059 | collapseRecursively() { |
| 1060 | let item = this; |
| 1061 | while (item) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1062 | if (item.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1063 | item.collapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1064 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1065 | item = item.traverseNextTreeElement(false, this, true); |
| 1066 | } |
| 1067 | } |
| 1068 | |
| 1069 | collapseChildren() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1070 | if (!this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1071 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1072 | } |
| 1073 | for (const child of this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1074 | child.collapseRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1075 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1076 | } |
| 1077 | |
| 1078 | expand() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1079 | if (!this._expandable || (this.expanded && this._children)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1080 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1081 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1082 | |
| 1083 | // Set this before onpopulate. Since onpopulate can add elements, this makes |
| 1084 | // sure the expanded flag is true before calling those functions. This prevents the possibility |
| 1085 | // of an infinite loop if onpopulate were to call expand. |
| 1086 | |
| 1087 | this.expanded = true; |
| 1088 | |
| 1089 | this._populateIfNeeded(); |
| 1090 | this._listItemNode.classList.add('expanded'); |
| 1091 | this._childrenListNode.classList.add('expanded'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1092 | ARIAUtils.setExpanded(this._listItemNode, true); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1093 | |
| 1094 | if (this.treeOutline) { |
| 1095 | this.onexpand(); |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1096 | this.treeOutline.dispatchEventToListeners(Events.ElementExpanded, this); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1097 | } |
| 1098 | } |
| 1099 | |
| 1100 | /** |
| 1101 | * @param {number=} maxDepth |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 1102 | * @returns {!Promise<void>} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1103 | */ |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1104 | async expandRecursively(maxDepth) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1105 | let item = this; |
| 1106 | const info = {}; |
| 1107 | let depth = 0; |
| 1108 | |
| 1109 | // The Inspector uses TreeOutlines to represents object properties, so recursive expansion |
| 1110 | // in some case can be infinite, since JavaScript objects can hold circular references. |
| 1111 | // So default to a recursion cap of 3 levels, since that gives fairly good results. |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1112 | if (isNaN(maxDepth)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1113 | maxDepth = 3; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1114 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1115 | |
| 1116 | while (item) { |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1117 | await item._populateIfNeeded(); |
| 1118 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1119 | if (depth < maxDepth) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1120 | item.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1121 | } |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1122 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1123 | item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info); |
| 1124 | depth += info.depthChange; |
| 1125 | } |
| 1126 | } |
| 1127 | |
| 1128 | /** |
| 1129 | * @param {boolean} altKey |
| 1130 | * @return {boolean} |
| 1131 | */ |
| 1132 | collapseOrAscend(altKey) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1133 | if (this.expanded && this._collapsible) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1134 | if (altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1135 | this.collapseRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1136 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1137 | this.collapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1138 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1139 | return true; |
| 1140 | } |
| 1141 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1142 | if (!this.parent || this.parent.root) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1143 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1144 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1145 | |
| 1146 | if (!this.parent.selectable) { |
| 1147 | this.parent.collapse(); |
| 1148 | return true; |
| 1149 | } |
| 1150 | |
| 1151 | let nextSelectedElement = this.parent; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1152 | while (nextSelectedElement && !nextSelectedElement.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1153 | nextSelectedElement = nextSelectedElement.parent; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1154 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1155 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1156 | if (!nextSelectedElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1157 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1158 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1159 | nextSelectedElement.select(false, true); |
| 1160 | return true; |
| 1161 | } |
| 1162 | |
| 1163 | /** |
| 1164 | * @param {boolean} altKey |
| 1165 | * @return {boolean} |
| 1166 | */ |
| 1167 | descendOrExpand(altKey) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1168 | if (!this._expandable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1169 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1170 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1171 | |
| 1172 | if (!this.expanded) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1173 | if (altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1174 | this.expandRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1175 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1176 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1177 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1178 | return true; |
| 1179 | } |
| 1180 | |
| 1181 | let nextSelectedElement = this.firstChild(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1182 | while (nextSelectedElement && !nextSelectedElement.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1183 | nextSelectedElement = nextSelectedElement.nextSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1184 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1185 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1186 | if (!nextSelectedElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1187 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1188 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1189 | nextSelectedElement.select(false, true); |
| 1190 | return true; |
| 1191 | } |
| 1192 | |
| 1193 | /** |
| 1194 | * @param {boolean=} center |
| 1195 | */ |
| 1196 | reveal(center) { |
| 1197 | let currentAncestor = this.parent; |
| 1198 | while (currentAncestor && !currentAncestor.root) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1199 | if (!currentAncestor.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1200 | currentAncestor.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1201 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1202 | currentAncestor = currentAncestor.parent; |
| 1203 | } |
| 1204 | |
| 1205 | this.treeOutline._deferredScrollIntoView(this, !!center); |
| 1206 | } |
| 1207 | |
| 1208 | /** |
| 1209 | * @return {boolean} |
| 1210 | */ |
| 1211 | revealed() { |
| 1212 | let currentAncestor = this.parent; |
| 1213 | while (currentAncestor && !currentAncestor.root) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1214 | if (!currentAncestor.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1215 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1216 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1217 | currentAncestor = currentAncestor.parent; |
| 1218 | } |
| 1219 | |
| 1220 | return true; |
| 1221 | } |
| 1222 | |
| 1223 | selectOnMouseDown(event) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1224 | if (this.select(false, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1225 | event.consume(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1226 | } |
Joel Einbinder | fb3e1df | 2018-05-30 00:11:27 | [diff] [blame] | 1227 | |
| 1228 | if (this._listItemNode.draggable && this._selectionElement) { |
| 1229 | const marginLeft = |
| 1230 | this.treeOutline.element.getBoundingClientRect().left - this._listItemNode.getBoundingClientRect().left; |
| 1231 | // By default the left margin extends far off screen. This is not a problem except when dragging an element. |
| 1232 | // Setting the margin once here should be fine, because we believe the left margin should never change. |
| 1233 | this._selectionElement.style.setProperty('margin-left', marginLeft + 'px'); |
| 1234 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1235 | } |
| 1236 | |
| 1237 | /** |
| 1238 | * @param {boolean=} omitFocus |
| 1239 | * @param {boolean=} selectedByUser |
| 1240 | * @return {boolean} |
| 1241 | */ |
| 1242 | select(omitFocus, selectedByUser) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1243 | if (!this.treeOutline || !this.selectable || this.selected) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1244 | if (!omitFocus) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1245 | this.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1246 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1247 | return false; |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1248 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1249 | // Wait to deselect this element so that focus only changes once |
| 1250 | const lastSelected = this.treeOutline.selectedTreeElement; |
| 1251 | this.treeOutline.selectedTreeElement = null; |
| 1252 | |
| 1253 | if (this.treeOutline._rootElement === this) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1254 | if (lastSelected) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1255 | lastSelected.deselect(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1256 | } |
| 1257 | if (!omitFocus) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1258 | this.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1259 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1260 | return false; |
| 1261 | } |
| 1262 | |
| 1263 | this.selected = true; |
| 1264 | |
| 1265 | this.treeOutline.selectedTreeElement = this; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 1266 | this.treeOutline.updateFocusable(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1267 | if (!omitFocus || this.treeOutline.contentElement.hasFocus()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1268 | this.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1269 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1270 | |
| 1271 | this._listItemNode.classList.add('selected'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1272 | ARIAUtils.setSelected(this._listItemNode, true); |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1273 | this.treeOutline.dispatchEventToListeners(Events.ElementSelected, this); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1274 | if (lastSelected) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1275 | lastSelected.deselect(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1276 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1277 | return this.onselect(selectedByUser); |
| 1278 | } |
| 1279 | |
| 1280 | /** |
| 1281 | * @param {boolean} focusable |
| 1282 | */ |
| 1283 | _setFocusable(focusable) { |
| 1284 | if (focusable) { |
Erik Luo | cc14b81 | 2018-11-03 01:33:09 | [diff] [blame] | 1285 | this._listItemNode.setAttribute('tabIndex', this.treeOutline && this.treeOutline._preventTabOrder ? -1 : 0); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1286 | this._listItemNode.addEventListener('focus', this._boundOnFocus, false); |
| 1287 | this._listItemNode.addEventListener('blur', this._boundOnBlur, false); |
| 1288 | } else { |
| 1289 | this._listItemNode.removeAttribute('tabIndex'); |
| 1290 | this._listItemNode.removeEventListener('focus', this._boundOnFocus, false); |
| 1291 | this._listItemNode.removeEventListener('blur', this._boundOnBlur, false); |
| 1292 | } |
| 1293 | } |
| 1294 | |
| 1295 | _onFocus() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1296 | if (this.treeOutline._useLightSelectionColor) { |
Pavel Feldman | 7ad5b27 | 2019-01-08 03:01:00 | [diff] [blame] | 1297 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1298 | } |
| 1299 | if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred')) { |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 1300 | this._listItemNode.classList.add('force-white-icons'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1301 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1302 | } |
| 1303 | |
| 1304 | _onBlur() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1305 | if (this.treeOutline._useLightSelectionColor) { |
Pavel Feldman | 7ad5b27 | 2019-01-08 03:01:00 | [diff] [blame] | 1306 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1307 | } |
| 1308 | if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred')) { |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 1309 | this._listItemNode.classList.remove('force-white-icons'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1310 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1311 | } |
| 1312 | |
| 1313 | /** |
| 1314 | * @param {boolean=} omitFocus |
| 1315 | */ |
| 1316 | revealAndSelect(omitFocus) { |
| 1317 | this.reveal(true); |
| 1318 | this.select(omitFocus); |
| 1319 | } |
| 1320 | |
| 1321 | deselect() { |
| 1322 | const hadFocus = this._listItemNode.hasFocus(); |
| 1323 | this.selected = false; |
| 1324 | this._listItemNode.classList.remove('selected'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1325 | ARIAUtils.clearSelected(this._listItemNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1326 | this._setFocusable(false); |
| 1327 | |
| 1328 | if (this.treeOutline && this.treeOutline.selectedTreeElement === this) { |
| 1329 | this.treeOutline.selectedTreeElement = null; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 1330 | this.treeOutline.updateFocusable(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1331 | if (hadFocus) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1332 | this.treeOutline.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1333 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1334 | } |
| 1335 | } |
| 1336 | |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1337 | /** |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 1338 | * @returns {!Promise<void>} |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1339 | */ |
| 1340 | async _populateIfNeeded() { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1341 | if (this.treeOutline && this._expandable && !this._children) { |
| 1342 | this._children = []; |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1343 | await this.onpopulate(); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1344 | } |
| 1345 | } |
| 1346 | |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1347 | /** |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 1348 | * @return {!Promise<void>} |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1349 | */ |
| 1350 | async onpopulate() { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1351 | // Overridden by subclasses. |
| 1352 | } |
| 1353 | |
| 1354 | /** |
| 1355 | * @return {boolean} |
| 1356 | */ |
| 1357 | onenter() { |
| 1358 | return false; |
| 1359 | } |
| 1360 | |
| 1361 | /** |
| 1362 | * @return {boolean} |
| 1363 | */ |
| 1364 | ondelete() { |
| 1365 | return false; |
| 1366 | } |
| 1367 | |
| 1368 | /** |
| 1369 | * @return {boolean} |
| 1370 | */ |
| 1371 | onspace() { |
| 1372 | return false; |
| 1373 | } |
| 1374 | |
| 1375 | onbind() { |
| 1376 | } |
| 1377 | |
| 1378 | onunbind() { |
| 1379 | } |
| 1380 | |
| 1381 | onattach() { |
| 1382 | } |
| 1383 | |
| 1384 | onexpand() { |
| 1385 | } |
| 1386 | |
| 1387 | oncollapse() { |
| 1388 | } |
| 1389 | |
| 1390 | /** |
| 1391 | * @param {!Event} e |
| 1392 | * @return {boolean} |
| 1393 | */ |
| 1394 | ondblclick(e) { |
| 1395 | return false; |
| 1396 | } |
| 1397 | |
| 1398 | /** |
| 1399 | * @param {boolean=} selectedByUser |
| 1400 | * @return {boolean} |
| 1401 | */ |
| 1402 | onselect(selectedByUser) { |
| 1403 | return false; |
| 1404 | } |
| 1405 | |
| 1406 | /** |
| 1407 | * @param {boolean} skipUnrevealed |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1408 | * @param {?TreeElement=} stayWithin |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1409 | * @param {boolean=} dontPopulate |
| 1410 | * @param {!Object=} info |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1411 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1412 | */ |
| 1413 | traverseNextTreeElement(skipUnrevealed, stayWithin, dontPopulate, info) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1414 | if (!dontPopulate) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1415 | this._populateIfNeeded(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1416 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1417 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1418 | if (info) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1419 | info.depthChange = 0; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1420 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1421 | |
| 1422 | let element = skipUnrevealed ? (this.revealed() ? this.firstChild() : null) : this.firstChild(); |
| 1423 | if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1424 | if (info) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1425 | info.depthChange = 1; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1426 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1427 | return element; |
| 1428 | } |
| 1429 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1430 | if (this === stayWithin) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1431 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1432 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1433 | |
| 1434 | element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1435 | if (element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1436 | return element; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1437 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1438 | |
| 1439 | element = this; |
| 1440 | while (element && !element.root && |
| 1441 | !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && |
| 1442 | element.parent !== stayWithin) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1443 | if (info) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1444 | info.depthChange -= 1; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1445 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1446 | element = element.parent; |
| 1447 | } |
| 1448 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1449 | if (!element || element.root) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1450 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1451 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1452 | |
| 1453 | return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling); |
| 1454 | } |
| 1455 | |
| 1456 | /** |
| 1457 | * @param {boolean} skipUnrevealed |
| 1458 | * @param {boolean=} dontPopulate |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1459 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1460 | */ |
| 1461 | traversePreviousTreeElement(skipUnrevealed, dontPopulate) { |
| 1462 | let element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1463 | if (!dontPopulate && element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1464 | element._populateIfNeeded(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1465 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1466 | |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1467 | while (element && |
| 1468 | (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : |
| 1469 | element.lastChild())) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1470 | if (!dontPopulate) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1471 | element._populateIfNeeded(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1472 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1473 | element = |
| 1474 | (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : |
| 1475 | element.lastChild()); |
| 1476 | } |
| 1477 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1478 | if (element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1479 | return element; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1480 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1481 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1482 | if (!this.parent || this.parent.root) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1483 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1484 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1485 | |
| 1486 | return this.parent; |
| 1487 | } |
| 1488 | |
| 1489 | /** |
| 1490 | * @return {boolean} |
| 1491 | */ |
| 1492 | isEventWithinDisclosureTriangle(event) { |
| 1493 | // FIXME: We should not use getComputedStyle(). For that we need to get rid of using ::before for disclosure triangle. (http://webk.it/74446) |
| 1494 | const paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLeft; |
| 1495 | console.assert(paddingLeftValue.endsWith('px')); |
| 1496 | const computedLeftPadding = parseFloat(paddingLeftValue); |
| 1497 | const left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1498 | return event.pageX >= left && event.pageX <= left + TreeElement._ArrowToggleWidth && this._expandable; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1499 | } |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1500 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1501 | |
| 1502 | /** @const */ |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1503 | TreeElement._ArrowToggleWidth = 10; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1504 | |
| 1505 | (function() { |
| 1506 | const img = new Image(); |
Joel Einbinder | f6f86b6 | 2019-06-10 23:19:12 | [diff] [blame] | 1507 | img.src = 'Images/treeoutlineTriangles.svg'; |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1508 | TreeElement._imagePreload = img; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1509 | })(); |