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 |
Jack Franklin | 71519f8 | 2020-11-03 12:08:59 | [diff] [blame^] | 427 | * @param {!{enableLegacyPatching:boolean}} options |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 428 | */ |
Jack Franklin | 71519f8 | 2020-11-03 12:08:59 | [diff] [blame^] | 429 | registerRequiredCSS(cssFile, options) { |
| 430 | appendStyle(this._shadowRoot, cssFile, options); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 431 | } |
| 432 | |
| 433 | hideOverflow() { |
| 434 | this._disclosureElement.classList.add('tree-outline-disclosure-hide-overflow'); |
| 435 | } |
| 436 | |
| 437 | makeDense() { |
| 438 | this.contentElement.classList.add('tree-outline-dense'); |
| 439 | } |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 440 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 441 | |
| 442 | /** |
| 443 | * @unrestricted |
| 444 | */ |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 445 | export class TreeElement { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 446 | /** |
| 447 | * @param {(string|!Node)=} title |
| 448 | * @param {boolean=} expandable |
| 449 | */ |
| 450 | constructor(title, expandable) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 451 | /** @type {?TreeOutline} */ |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 452 | this.treeOutline = null; |
| 453 | this.parent = null; |
| 454 | this.previousSibling = null; |
| 455 | this.nextSibling = null; |
| 456 | this._boundOnFocus = this._onFocus.bind(this); |
| 457 | this._boundOnBlur = this._onBlur.bind(this); |
| 458 | |
Changhao Han | c1817b2 | 2020-09-07 09:04:18 | [diff] [blame] | 459 | this._listItemNode = /** @type {!HTMLLIElement} */ (createElement('li')); |
Simon Zünd | 7334f5c | 2020-10-07 08:06:54 | [diff] [blame] | 460 | |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 461 | this.titleElement = this._listItemNode.createChild('span', 'tree-element-title'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 462 | this._listItemNode.treeElement = this; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 463 | if (title) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 464 | this.title = title; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 465 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 466 | this._listItemNode.addEventListener('mousedown', this._handleMouseDown.bind(this), false); |
| 467 | this._listItemNode.addEventListener('click', this._treeElementToggled.bind(this), false); |
| 468 | this._listItemNode.addEventListener('dblclick', this._handleDoubleClick.bind(this), false); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 469 | ARIAUtils.markAsTreeitem(this._listItemNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 470 | |
| 471 | this._childrenListNode = createElement('ol'); |
| 472 | this._childrenListNode.parentTreeElement = this; |
| 473 | this._childrenListNode.classList.add('children'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 474 | ARIAUtils.markAsGroup(this._childrenListNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 475 | |
| 476 | this._hidden = false; |
| 477 | this._selectable = true; |
| 478 | this.expanded = false; |
| 479 | this.selected = false; |
| 480 | this.setExpandable(expandable || false); |
| 481 | this._collapsible = true; |
Changhao Han | bb4af12 | 2020-09-10 13:45:25 | [diff] [blame] | 482 | this.toggleOnClick = false; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 483 | } |
| 484 | |
| 485 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 486 | * @param {?TreeElement} ancestor |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 487 | * @return {boolean} |
| 488 | */ |
| 489 | hasAncestor(ancestor) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 490 | if (!ancestor) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 491 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 492 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 493 | |
| 494 | let currentNode = this.parent; |
| 495 | while (currentNode) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 496 | if (ancestor === currentNode) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 497 | return true; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 498 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 499 | currentNode = currentNode.parent; |
| 500 | } |
| 501 | |
| 502 | return false; |
| 503 | } |
| 504 | |
| 505 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 506 | * @param {?TreeElement} ancestor |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 507 | * @return {boolean} |
| 508 | */ |
| 509 | hasAncestorOrSelf(ancestor) { |
| 510 | return this === ancestor || this.hasAncestor(ancestor); |
| 511 | } |
| 512 | |
| 513 | /** |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 514 | * @return {boolean} |
| 515 | */ |
| 516 | isHidden() { |
| 517 | if (this.hidden) { |
| 518 | return true; |
| 519 | } |
| 520 | |
| 521 | let currentNode = this.parent; |
| 522 | while (currentNode) { |
| 523 | if (currentNode.hidden) { |
| 524 | return true; |
| 525 | } |
| 526 | currentNode = currentNode.parent; |
| 527 | } |
| 528 | |
| 529 | return false; |
| 530 | } |
| 531 | |
| 532 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 533 | * @return {!Array.<!TreeElement>} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 534 | */ |
| 535 | children() { |
| 536 | return this._children || []; |
| 537 | } |
| 538 | |
| 539 | /** |
| 540 | * @return {number} |
| 541 | */ |
| 542 | childCount() { |
| 543 | return this._children ? this._children.length : 0; |
| 544 | } |
| 545 | |
| 546 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 547 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 548 | */ |
| 549 | firstChild() { |
| 550 | return this._children ? this._children[0] : null; |
| 551 | } |
| 552 | |
| 553 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 554 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 555 | */ |
| 556 | lastChild() { |
| 557 | return this._children ? this._children[this._children.length - 1] : null; |
| 558 | } |
| 559 | |
| 560 | /** |
| 561 | * @param {number} index |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 562 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 563 | */ |
| 564 | childAt(index) { |
| 565 | return this._children ? this._children[index] : null; |
| 566 | } |
| 567 | |
| 568 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 569 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 570 | * @return {number} |
| 571 | */ |
| 572 | indexOfChild(child) { |
| 573 | return this._children ? this._children.indexOf(child) : -1; |
| 574 | } |
| 575 | |
| 576 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 577 | * @param {!TreeElement} child |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 578 | * @param {(function(!TreeElement, !TreeElement):number)=} comparator |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 579 | */ |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 580 | appendChild(child, comparator) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 581 | if (!this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 582 | this._children = []; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 583 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 584 | |
| 585 | let insertionIndex; |
Sigurd Schneider | dc2aa0d | 2020-07-09 10:20:09 | [diff] [blame] | 586 | if (comparator) { |
| 587 | insertionIndex = this._children.lowerBound(child, comparator); |
| 588 | } else if (this.treeOutline && this.treeOutline._comparator) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 589 | insertionIndex = this._children.lowerBound(child, this.treeOutline._comparator); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 590 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 591 | insertionIndex = this._children.length; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 592 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 593 | this.insertChild(child, insertionIndex); |
| 594 | } |
| 595 | |
| 596 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 597 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 598 | * @param {number} index |
| 599 | */ |
| 600 | insertChild(child, index) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 601 | if (!this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 602 | this._children = []; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 603 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 604 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 605 | if (!child) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 606 | throw 'child can\'t be undefined or null'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 607 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 608 | |
| 609 | console.assert( |
| 610 | !child.parent, 'Attempting to insert a child that is already in the tree, reparenting is not supported.'); |
| 611 | |
| 612 | const previousChild = (index > 0 ? this._children[index - 1] : null); |
| 613 | if (previousChild) { |
| 614 | previousChild.nextSibling = child; |
| 615 | child.previousSibling = previousChild; |
| 616 | } else { |
| 617 | child.previousSibling = null; |
| 618 | } |
| 619 | |
| 620 | const nextChild = this._children[index]; |
| 621 | if (nextChild) { |
| 622 | nextChild.previousSibling = child; |
| 623 | child.nextSibling = nextChild; |
| 624 | } else { |
| 625 | child.nextSibling = null; |
| 626 | } |
| 627 | |
| 628 | this._children.splice(index, 0, child); |
| 629 | |
| 630 | this.setExpandable(true); |
| 631 | child.parent = this; |
| 632 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 633 | if (this.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 634 | this.treeOutline._bindTreeElement(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 635 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 636 | for (let current = child.firstChild(); this.treeOutline && current; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 637 | current = current.traverseNextTreeElement(false, child, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 638 | this.treeOutline._bindTreeElement(current); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 639 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 640 | child.onattach(); |
| 641 | child._ensureSelection(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 642 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 643 | this.treeOutline.dispatchEventToListeners(Events.ElementAttached, child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 644 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 645 | const nextSibling = child.nextSibling ? child.nextSibling._listItemNode : null; |
| 646 | this._childrenListNode.insertBefore(child._listItemNode, nextSibling); |
| 647 | this._childrenListNode.insertBefore(child._childrenListNode, nextSibling); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 648 | if (child.selected) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 649 | child.select(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 650 | } |
| 651 | if (child.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 652 | child.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 653 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 654 | } |
| 655 | |
| 656 | /** |
| 657 | * @param {number} childIndex |
| 658 | */ |
| 659 | removeChildAtIndex(childIndex) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 660 | if (childIndex < 0 || childIndex >= this._children.length) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 661 | throw 'childIndex out of range'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 662 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 663 | |
| 664 | const child = this._children[childIndex]; |
| 665 | this._children.splice(childIndex, 1); |
| 666 | |
| 667 | const parent = child.parent; |
| 668 | if (this.treeOutline && this.treeOutline.selectedTreeElement && |
| 669 | this.treeOutline.selectedTreeElement.hasAncestorOrSelf(child)) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 670 | if (child.nextSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 671 | child.nextSibling.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 672 | } else if (child.previousSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 673 | child.previousSibling.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 674 | } else if (parent) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 675 | parent.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 676 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 677 | } |
| 678 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 679 | if (child.previousSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 680 | child.previousSibling.nextSibling = child.nextSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 681 | } |
| 682 | if (child.nextSibling) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 683 | child.nextSibling.previousSibling = child.previousSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 684 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 685 | child.parent = null; |
| 686 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 687 | if (this.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 688 | this.treeOutline._unbindTreeElement(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 689 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 690 | for (let current = child.firstChild(); this.treeOutline && current; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 691 | current = current.traverseNextTreeElement(false, child, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 692 | this.treeOutline._unbindTreeElement(current); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 693 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 694 | |
| 695 | child._detach(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 696 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 697 | this.treeOutline.dispatchEventToListeners(Events.ElementsDetached); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 698 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 699 | } |
| 700 | |
| 701 | /** |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 702 | * @param {!TreeElement} child |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 703 | */ |
| 704 | removeChild(child) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 705 | if (!child) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 706 | throw 'child can\'t be undefined or null'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 707 | } |
| 708 | if (child.parent !== this) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 709 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 710 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 711 | |
| 712 | const childIndex = this._children.indexOf(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 713 | if (childIndex === -1) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 714 | throw 'child not found in this node\'s children'; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 715 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 716 | |
| 717 | this.removeChildAtIndex(childIndex); |
| 718 | } |
| 719 | |
| 720 | removeChildren() { |
| 721 | if (!this.root && this.treeOutline && this.treeOutline.selectedTreeElement && |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 722 | this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 723 | this.select(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 724 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 725 | |
| 726 | for (let i = 0; this._children && i < this._children.length; ++i) { |
| 727 | const child = this._children[i]; |
| 728 | child.previousSibling = null; |
| 729 | child.nextSibling = null; |
| 730 | child.parent = null; |
| 731 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 732 | if (this.treeOutline) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 733 | this.treeOutline._unbindTreeElement(child); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 734 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 735 | for (let current = child.firstChild(); this.treeOutline && current; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 736 | current = current.traverseNextTreeElement(false, child, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 737 | this.treeOutline._unbindTreeElement(current); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 738 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 739 | child._detach(); |
| 740 | } |
| 741 | this._children = []; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 742 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 743 | this.treeOutline.dispatchEventToListeners(Events.ElementsDetached); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 744 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 745 | } |
| 746 | |
| 747 | get selectable() { |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 748 | if (this.isHidden()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 749 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 750 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 751 | return this._selectable; |
| 752 | } |
| 753 | |
| 754 | set selectable(x) { |
| 755 | this._selectable = x; |
| 756 | } |
| 757 | |
| 758 | get listItemElement() { |
| 759 | return this._listItemNode; |
| 760 | } |
| 761 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 762 | get childrenListElement() { |
| 763 | return this._childrenListNode; |
| 764 | } |
| 765 | |
| 766 | /** |
| 767 | * @return {string|!Node} |
| 768 | */ |
| 769 | get title() { |
| 770 | return this._title; |
| 771 | } |
| 772 | |
| 773 | /** |
| 774 | * @param {string|!Node} x |
| 775 | */ |
| 776 | set title(x) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 777 | if (this._title === x) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 778 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 779 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 780 | this._title = x; |
| 781 | |
| 782 | if (typeof x === 'string') { |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 783 | this.titleElement.textContent = x; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 784 | this.tooltip = x; |
| 785 | } else { |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 786 | this.titleElement = x; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 787 | this.tooltip = ''; |
| 788 | } |
| 789 | |
| 790 | this._listItemNode.removeChildren(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 791 | if (this._leadingIconsElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 792 | this._listItemNode.appendChild(this._leadingIconsElement); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 793 | } |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 794 | this._listItemNode.appendChild(this.titleElement); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 795 | if (this._trailingIconsElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 796 | this._listItemNode.appendChild(this._trailingIconsElement); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 797 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 798 | this._ensureSelection(); |
| 799 | } |
| 800 | |
| 801 | /** |
| 802 | * @return {string} |
| 803 | */ |
| 804 | titleAsText() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 805 | if (!this._title) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 806 | return ''; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 807 | } |
| 808 | if (typeof this._title === 'string') { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 809 | return this._title; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 810 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 811 | return this._title.textContent; |
| 812 | } |
| 813 | |
| 814 | /** |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 815 | * @param {!Config<*>} editingConfig |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 816 | */ |
| 817 | startEditingTitle(editingConfig) { |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 818 | InplaceEditor.startEditing(/** @type {!Element} */ (this.titleElement), editingConfig); |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 819 | this.treeOutline._shadowRoot.getSelection().selectAllChildren(this.titleElement); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 820 | } |
| 821 | |
| 822 | /** |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 823 | * @param {!Array<!Icon>} icons |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 824 | */ |
| 825 | setLeadingIcons(icons) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 826 | if (!this._leadingIconsElement && !icons.length) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 827 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 828 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 829 | if (!this._leadingIconsElement) { |
Tim van der Lippe | f49e232 | 2020-05-01 15:03:09 | [diff] [blame] | 830 | this._leadingIconsElement = document.createElement('div'); |
| 831 | this._leadingIconsElement.classList.add('leading-icons'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 832 | this._leadingIconsElement.classList.add('icons-container'); |
Tim van der Lippe | ffa7862 | 2019-09-16 12:07:12 | [diff] [blame] | 833 | this._listItemNode.insertBefore(this._leadingIconsElement, this.titleElement); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 834 | this._ensureSelection(); |
| 835 | } |
| 836 | this._leadingIconsElement.removeChildren(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 837 | for (const icon of icons) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 838 | this._leadingIconsElement.appendChild(icon); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 839 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 840 | } |
| 841 | |
| 842 | /** |
Paul Lewis | 9950e18 | 2019-12-16 16:06:07 | [diff] [blame] | 843 | * @param {!Array<!Icon>} icons |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 844 | */ |
| 845 | setTrailingIcons(icons) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 846 | if (!this._trailingIconsElement && !icons.length) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 847 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 848 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 849 | if (!this._trailingIconsElement) { |
Tim van der Lippe | f49e232 | 2020-05-01 15:03:09 | [diff] [blame] | 850 | this._trailingIconsElement = document.createElement('div'); |
| 851 | this._trailingIconsElement.classList.add('trailing-icons'); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 852 | this._trailingIconsElement.classList.add('icons-container'); |
| 853 | this._listItemNode.appendChild(this._trailingIconsElement); |
| 854 | this._ensureSelection(); |
| 855 | } |
| 856 | this._trailingIconsElement.removeChildren(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 857 | for (const icon of icons) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 858 | this._trailingIconsElement.appendChild(icon); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 859 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 860 | } |
| 861 | |
| 862 | |
| 863 | /** |
| 864 | * @return {string} |
| 865 | */ |
| 866 | get tooltip() { |
| 867 | return this._tooltip || ''; |
| 868 | } |
| 869 | |
| 870 | /** |
| 871 | * @param {string} x |
| 872 | */ |
| 873 | set tooltip(x) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 874 | if (this._tooltip === x) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 875 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 876 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 877 | this._tooltip = x; |
| 878 | this._listItemNode.title = x; |
| 879 | } |
| 880 | |
| 881 | /** |
| 882 | * @return {boolean} |
| 883 | */ |
| 884 | isExpandable() { |
| 885 | return this._expandable; |
| 886 | } |
| 887 | |
| 888 | /** |
| 889 | * @param {boolean} expandable |
| 890 | */ |
| 891 | setExpandable(expandable) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 892 | if (this._expandable === expandable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 893 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 894 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 895 | |
| 896 | this._expandable = expandable; |
| 897 | |
| 898 | this._listItemNode.classList.toggle('parent', expandable); |
| 899 | if (!expandable) { |
| 900 | this.collapse(); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 901 | ARIAUtils.unsetExpandable(this._listItemNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 902 | } else { |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 903 | ARIAUtils.setExpanded(this._listItemNode, false); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 904 | } |
| 905 | } |
| 906 | |
| 907 | /** |
| 908 | * @param {boolean} collapsible |
| 909 | */ |
| 910 | setCollapsible(collapsible) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 911 | if (this._collapsible === collapsible) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 912 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 913 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 914 | |
| 915 | this._collapsible = collapsible; |
| 916 | |
| 917 | this._listItemNode.classList.toggle('always-parent', !collapsible); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 918 | if (!collapsible) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 919 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 920 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 921 | } |
| 922 | |
| 923 | get hidden() { |
| 924 | return this._hidden; |
| 925 | } |
| 926 | |
| 927 | set hidden(x) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 928 | if (this._hidden === x) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 929 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 930 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 931 | |
| 932 | this._hidden = x; |
| 933 | |
| 934 | this._listItemNode.classList.toggle('hidden', x); |
| 935 | this._childrenListNode.classList.toggle('hidden', x); |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 936 | |
| 937 | if (x && this.treeOutline && this.treeOutline.selectedTreeElement && |
| 938 | this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) { |
| 939 | const hadFocus = this.treeOutline.selectedTreeElement.listItemElement.hasFocus(); |
| 940 | this.treeOutline.forceSelect(!hadFocus, /* selectedByUser */ false); |
| 941 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 942 | } |
| 943 | |
| 944 | invalidateChildren() { |
| 945 | if (this._children) { |
| 946 | this.removeChildren(); |
| 947 | this._children = null; |
| 948 | } |
| 949 | } |
| 950 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 951 | |
| 952 | _ensureSelection() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 953 | if (!this.treeOutline || !this.treeOutline._renderSelection) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 954 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 955 | } |
| 956 | if (!this._selectionElement) { |
Tim van der Lippe | e7f2705 | 2020-05-01 15:15:28 | [diff] [blame] | 957 | this._selectionElement = document.createElement('div'); |
| 958 | this._selectionElement.classList.add('selection'); |
| 959 | this._selectionElement.classList.add('fill'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 960 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 961 | this._listItemNode.insertBefore(this._selectionElement, this.listItemElement.firstChild); |
| 962 | } |
| 963 | |
| 964 | /** |
| 965 | * @param {!Event} event |
| 966 | */ |
| 967 | _treeElementToggled(event) { |
| 968 | const element = event.currentTarget; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 969 | if (element.treeElement !== this || element.hasSelection()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 970 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 971 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 972 | |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 973 | console.assert(!!this.treeOutline); |
| 974 | const showSelectionOnKeyboardFocus = this.treeOutline ? this.treeOutline._showSelectionOnKeyboardFocus : false; |
| 975 | const toggleOnClick = this.toggleOnClick && (showSelectionOnKeyboardFocus || !this.selectable); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 976 | const isInTriangle = this.isEventWithinDisclosureTriangle(event); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 977 | if (!toggleOnClick && !isInTriangle) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 978 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 979 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 980 | |
| 981 | if (this.expanded) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 982 | if (event.altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 983 | this.collapseRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 984 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 985 | this.collapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 986 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 987 | } else { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 988 | if (event.altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 989 | this.expandRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 990 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 991 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 992 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 993 | } |
| 994 | event.consume(); |
| 995 | } |
| 996 | |
| 997 | /** |
| 998 | * @param {!Event} event |
| 999 | */ |
| 1000 | _handleMouseDown(event) { |
| 1001 | const element = event.currentTarget; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1002 | if (!element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1003 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1004 | } |
| 1005 | if (!this.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1006 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1007 | } |
| 1008 | if (element.treeElement !== this) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1009 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1010 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1011 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1012 | if (this.isEventWithinDisclosureTriangle(event)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1013 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1014 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1015 | |
| 1016 | this.selectOnMouseDown(event); |
| 1017 | } |
| 1018 | |
| 1019 | /** |
| 1020 | * @param {!Event} event |
| 1021 | */ |
| 1022 | _handleDoubleClick(event) { |
| 1023 | const element = event.currentTarget; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1024 | if (!element || element.treeElement !== this) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1025 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1026 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1027 | |
| 1028 | const handled = this.ondblclick(event); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1029 | if (handled) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1030 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1031 | } |
| 1032 | if (this._expandable && !this.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1033 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1034 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1035 | } |
| 1036 | |
| 1037 | _detach() { |
| 1038 | this._listItemNode.remove(); |
| 1039 | this._childrenListNode.remove(); |
| 1040 | } |
| 1041 | |
| 1042 | collapse() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1043 | if (!this.expanded || !this._collapsible) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1044 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1045 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1046 | this._listItemNode.classList.remove('expanded'); |
| 1047 | this._childrenListNode.classList.remove('expanded'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1048 | ARIAUtils.setExpanded(this._listItemNode, false); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1049 | this.expanded = false; |
| 1050 | this.oncollapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1051 | if (this.treeOutline) { |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1052 | this.treeOutline.dispatchEventToListeners(Events.ElementCollapsed, this); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1053 | } |
Amanda Baker | 98c26ea | 2019-10-24 01:40:52 | [diff] [blame] | 1054 | |
| 1055 | const selectedTreeElement = this.treeOutline.selectedTreeElement; |
| 1056 | if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) { |
| 1057 | this.select(/* omitFocus */ true, /* selectedByUser */ true); |
| 1058 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1059 | } |
| 1060 | |
| 1061 | collapseRecursively() { |
| 1062 | let item = this; |
| 1063 | while (item) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1064 | if (item.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1065 | item.collapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1066 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1067 | item = item.traverseNextTreeElement(false, this, true); |
| 1068 | } |
| 1069 | } |
| 1070 | |
| 1071 | collapseChildren() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1072 | if (!this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1073 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1074 | } |
| 1075 | for (const child of this._children) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1076 | child.collapseRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1077 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1078 | } |
| 1079 | |
| 1080 | expand() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1081 | if (!this._expandable || (this.expanded && this._children)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1082 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1083 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1084 | |
| 1085 | // Set this before onpopulate. Since onpopulate can add elements, this makes |
| 1086 | // sure the expanded flag is true before calling those functions. This prevents the possibility |
| 1087 | // of an infinite loop if onpopulate were to call expand. |
| 1088 | |
| 1089 | this.expanded = true; |
| 1090 | |
| 1091 | this._populateIfNeeded(); |
| 1092 | this._listItemNode.classList.add('expanded'); |
| 1093 | this._childrenListNode.classList.add('expanded'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1094 | ARIAUtils.setExpanded(this._listItemNode, true); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1095 | |
| 1096 | if (this.treeOutline) { |
| 1097 | this.onexpand(); |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1098 | this.treeOutline.dispatchEventToListeners(Events.ElementExpanded, this); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1099 | } |
| 1100 | } |
| 1101 | |
| 1102 | /** |
| 1103 | * @param {number=} maxDepth |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 1104 | * @returns {!Promise<void>} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1105 | */ |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1106 | async expandRecursively(maxDepth) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1107 | let item = this; |
| 1108 | const info = {}; |
| 1109 | let depth = 0; |
| 1110 | |
| 1111 | // The Inspector uses TreeOutlines to represents object properties, so recursive expansion |
| 1112 | // in some case can be infinite, since JavaScript objects can hold circular references. |
| 1113 | // 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] | 1114 | if (isNaN(maxDepth)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1115 | maxDepth = 3; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1116 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1117 | |
| 1118 | while (item) { |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1119 | await item._populateIfNeeded(); |
| 1120 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1121 | if (depth < maxDepth) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1122 | item.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1123 | } |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1124 | |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1125 | item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info); |
| 1126 | depth += info.depthChange; |
| 1127 | } |
| 1128 | } |
| 1129 | |
| 1130 | /** |
| 1131 | * @param {boolean} altKey |
| 1132 | * @return {boolean} |
| 1133 | */ |
| 1134 | collapseOrAscend(altKey) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1135 | if (this.expanded && this._collapsible) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1136 | if (altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1137 | this.collapseRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1138 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1139 | this.collapse(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1140 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1141 | return true; |
| 1142 | } |
| 1143 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1144 | if (!this.parent || this.parent.root) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1145 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1146 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1147 | |
| 1148 | if (!this.parent.selectable) { |
| 1149 | this.parent.collapse(); |
| 1150 | return true; |
| 1151 | } |
| 1152 | |
| 1153 | let nextSelectedElement = this.parent; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1154 | while (nextSelectedElement && !nextSelectedElement.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1155 | nextSelectedElement = nextSelectedElement.parent; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1156 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1157 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1158 | if (!nextSelectedElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1159 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1160 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1161 | nextSelectedElement.select(false, true); |
| 1162 | return true; |
| 1163 | } |
| 1164 | |
| 1165 | /** |
| 1166 | * @param {boolean} altKey |
| 1167 | * @return {boolean} |
| 1168 | */ |
| 1169 | descendOrExpand(altKey) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1170 | if (!this._expandable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1171 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1172 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1173 | |
| 1174 | if (!this.expanded) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1175 | if (altKey) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1176 | this.expandRecursively(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1177 | } else { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1178 | this.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1179 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1180 | return true; |
| 1181 | } |
| 1182 | |
| 1183 | let nextSelectedElement = this.firstChild(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1184 | while (nextSelectedElement && !nextSelectedElement.selectable) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1185 | nextSelectedElement = nextSelectedElement.nextSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1186 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1187 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1188 | if (!nextSelectedElement) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1189 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1190 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1191 | nextSelectedElement.select(false, true); |
| 1192 | return true; |
| 1193 | } |
| 1194 | |
| 1195 | /** |
| 1196 | * @param {boolean=} center |
| 1197 | */ |
| 1198 | reveal(center) { |
| 1199 | let currentAncestor = this.parent; |
| 1200 | while (currentAncestor && !currentAncestor.root) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1201 | if (!currentAncestor.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1202 | currentAncestor.expand(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1203 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1204 | currentAncestor = currentAncestor.parent; |
| 1205 | } |
| 1206 | |
| 1207 | this.treeOutline._deferredScrollIntoView(this, !!center); |
| 1208 | } |
| 1209 | |
| 1210 | /** |
| 1211 | * @return {boolean} |
| 1212 | */ |
| 1213 | revealed() { |
| 1214 | let currentAncestor = this.parent; |
| 1215 | while (currentAncestor && !currentAncestor.root) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1216 | if (!currentAncestor.expanded) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1217 | return false; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1218 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1219 | currentAncestor = currentAncestor.parent; |
| 1220 | } |
| 1221 | |
| 1222 | return true; |
| 1223 | } |
| 1224 | |
| 1225 | selectOnMouseDown(event) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1226 | if (this.select(false, true)) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1227 | event.consume(true); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1228 | } |
Joel Einbinder | fb3e1df | 2018-05-30 00:11:27 | [diff] [blame] | 1229 | |
| 1230 | if (this._listItemNode.draggable && this._selectionElement) { |
| 1231 | const marginLeft = |
| 1232 | this.treeOutline.element.getBoundingClientRect().left - this._listItemNode.getBoundingClientRect().left; |
| 1233 | // By default the left margin extends far off screen. This is not a problem except when dragging an element. |
| 1234 | // Setting the margin once here should be fine, because we believe the left margin should never change. |
| 1235 | this._selectionElement.style.setProperty('margin-left', marginLeft + 'px'); |
| 1236 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1237 | } |
| 1238 | |
| 1239 | /** |
| 1240 | * @param {boolean=} omitFocus |
| 1241 | * @param {boolean=} selectedByUser |
| 1242 | * @return {boolean} |
| 1243 | */ |
| 1244 | select(omitFocus, selectedByUser) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1245 | if (!this.treeOutline || !this.selectable || this.selected) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1246 | if (!omitFocus) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1247 | this.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1248 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1249 | return false; |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1250 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1251 | // Wait to deselect this element so that focus only changes once |
| 1252 | const lastSelected = this.treeOutline.selectedTreeElement; |
| 1253 | this.treeOutline.selectedTreeElement = null; |
| 1254 | |
| 1255 | if (this.treeOutline._rootElement === this) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1256 | if (lastSelected) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1257 | lastSelected.deselect(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1258 | } |
| 1259 | if (!omitFocus) { |
Erik Luo | 1617c3f | 2018-11-01 21:15:18 | [diff] [blame] | 1260 | this.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1261 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1262 | return false; |
| 1263 | } |
| 1264 | |
| 1265 | this.selected = true; |
| 1266 | |
| 1267 | this.treeOutline.selectedTreeElement = this; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 1268 | this.treeOutline.updateFocusable(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1269 | if (!omitFocus || this.treeOutline.contentElement.hasFocus()) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1270 | this.listItemElement.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1271 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1272 | |
| 1273 | this._listItemNode.classList.add('selected'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1274 | ARIAUtils.setSelected(this._listItemNode, true); |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1275 | this.treeOutline.dispatchEventToListeners(Events.ElementSelected, this); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1276 | if (lastSelected) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1277 | lastSelected.deselect(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1278 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1279 | return this.onselect(selectedByUser); |
| 1280 | } |
| 1281 | |
| 1282 | /** |
| 1283 | * @param {boolean} focusable |
| 1284 | */ |
| 1285 | _setFocusable(focusable) { |
| 1286 | if (focusable) { |
Erik Luo | cc14b81 | 2018-11-03 01:33:09 | [diff] [blame] | 1287 | this._listItemNode.setAttribute('tabIndex', this.treeOutline && this.treeOutline._preventTabOrder ? -1 : 0); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1288 | this._listItemNode.addEventListener('focus', this._boundOnFocus, false); |
| 1289 | this._listItemNode.addEventListener('blur', this._boundOnBlur, false); |
| 1290 | } else { |
| 1291 | this._listItemNode.removeAttribute('tabIndex'); |
| 1292 | this._listItemNode.removeEventListener('focus', this._boundOnFocus, false); |
| 1293 | this._listItemNode.removeEventListener('blur', this._boundOnBlur, false); |
| 1294 | } |
| 1295 | } |
| 1296 | |
| 1297 | _onFocus() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1298 | if (this.treeOutline._useLightSelectionColor) { |
Pavel Feldman | 7ad5b27 | 2019-01-08 03:01:00 | [diff] [blame] | 1299 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1300 | } |
| 1301 | if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred')) { |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 1302 | this._listItemNode.classList.add('force-white-icons'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1303 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1304 | } |
| 1305 | |
| 1306 | _onBlur() { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1307 | if (this.treeOutline._useLightSelectionColor) { |
Pavel Feldman | 7ad5b27 | 2019-01-08 03:01:00 | [diff] [blame] | 1308 | return; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1309 | } |
| 1310 | if (!this.treeOutline.contentElement.classList.contains('hide-selection-when-blurred')) { |
Erik Luo | d6bf97b | 2018-08-25 02:06:51 | [diff] [blame] | 1311 | this._listItemNode.classList.remove('force-white-icons'); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1312 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1313 | } |
| 1314 | |
| 1315 | /** |
| 1316 | * @param {boolean=} omitFocus |
| 1317 | */ |
| 1318 | revealAndSelect(omitFocus) { |
| 1319 | this.reveal(true); |
| 1320 | this.select(omitFocus); |
| 1321 | } |
| 1322 | |
| 1323 | deselect() { |
| 1324 | const hadFocus = this._listItemNode.hasFocus(); |
| 1325 | this.selected = false; |
| 1326 | this._listItemNode.classList.remove('selected'); |
Tim van der Lippe | aa76aa2 | 2020-02-14 14:38:24 | [diff] [blame] | 1327 | ARIAUtils.clearSelected(this._listItemNode); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1328 | this._setFocusable(false); |
| 1329 | |
| 1330 | if (this.treeOutline && this.treeOutline.selectedTreeElement === this) { |
| 1331 | this.treeOutline.selectedTreeElement = null; |
Amanda Baker | 05d6a23 | 2019-10-24 01:23:35 | [diff] [blame] | 1332 | this.treeOutline.updateFocusable(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1333 | if (hadFocus) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1334 | this.treeOutline.focus(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1335 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1336 | } |
| 1337 | } |
| 1338 | |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1339 | /** |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 1340 | * @returns {!Promise<void>} |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1341 | */ |
| 1342 | async _populateIfNeeded() { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1343 | if (this.treeOutline && this._expandable && !this._children) { |
| 1344 | this._children = []; |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1345 | await this.onpopulate(); |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1346 | } |
| 1347 | } |
| 1348 | |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1349 | /** |
Tim van der Lippe | ee6e3e9 | 2020-05-13 13:01:37 | [diff] [blame] | 1350 | * @return {!Promise<void>} |
Paul Lewis | bfa6295 | 2019-06-26 12:44:00 | [diff] [blame] | 1351 | */ |
| 1352 | async onpopulate() { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1353 | // Overridden by subclasses. |
| 1354 | } |
| 1355 | |
| 1356 | /** |
| 1357 | * @return {boolean} |
| 1358 | */ |
| 1359 | onenter() { |
| 1360 | return false; |
| 1361 | } |
| 1362 | |
| 1363 | /** |
| 1364 | * @return {boolean} |
| 1365 | */ |
| 1366 | ondelete() { |
| 1367 | return false; |
| 1368 | } |
| 1369 | |
| 1370 | /** |
| 1371 | * @return {boolean} |
| 1372 | */ |
| 1373 | onspace() { |
| 1374 | return false; |
| 1375 | } |
| 1376 | |
| 1377 | onbind() { |
| 1378 | } |
| 1379 | |
| 1380 | onunbind() { |
| 1381 | } |
| 1382 | |
| 1383 | onattach() { |
| 1384 | } |
| 1385 | |
| 1386 | onexpand() { |
| 1387 | } |
| 1388 | |
| 1389 | oncollapse() { |
| 1390 | } |
| 1391 | |
| 1392 | /** |
| 1393 | * @param {!Event} e |
| 1394 | * @return {boolean} |
| 1395 | */ |
| 1396 | ondblclick(e) { |
| 1397 | return false; |
| 1398 | } |
| 1399 | |
| 1400 | /** |
| 1401 | * @param {boolean=} selectedByUser |
| 1402 | * @return {boolean} |
| 1403 | */ |
| 1404 | onselect(selectedByUser) { |
| 1405 | return false; |
| 1406 | } |
| 1407 | |
| 1408 | /** |
| 1409 | * @param {boolean} skipUnrevealed |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1410 | * @param {?TreeElement=} stayWithin |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1411 | * @param {boolean=} dontPopulate |
| 1412 | * @param {!Object=} info |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1413 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1414 | */ |
| 1415 | traverseNextTreeElement(skipUnrevealed, stayWithin, dontPopulate, info) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1416 | if (!dontPopulate) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1417 | this._populateIfNeeded(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1418 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1419 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1420 | if (info) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1421 | info.depthChange = 0; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1422 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1423 | |
| 1424 | let element = skipUnrevealed ? (this.revealed() ? this.firstChild() : null) : this.firstChild(); |
| 1425 | if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1426 | if (info) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1427 | info.depthChange = 1; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1428 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1429 | return element; |
| 1430 | } |
| 1431 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1432 | if (this === stayWithin) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1433 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1434 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1435 | |
| 1436 | element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1437 | if (element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1438 | return element; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1439 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1440 | |
| 1441 | element = this; |
| 1442 | while (element && !element.root && |
| 1443 | !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && |
| 1444 | element.parent !== stayWithin) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1445 | if (info) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1446 | info.depthChange -= 1; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1447 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1448 | element = element.parent; |
| 1449 | } |
| 1450 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1451 | if (!element || element.root) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1452 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1453 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1454 | |
| 1455 | return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling); |
| 1456 | } |
| 1457 | |
| 1458 | /** |
| 1459 | * @param {boolean} skipUnrevealed |
| 1460 | * @param {boolean=} dontPopulate |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1461 | * @return {?TreeElement} |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1462 | */ |
| 1463 | traversePreviousTreeElement(skipUnrevealed, dontPopulate) { |
| 1464 | let element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1465 | if (!dontPopulate && element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1466 | element._populateIfNeeded(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1467 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1468 | |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1469 | while (element && |
| 1470 | (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : |
| 1471 | element.lastChild())) { |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1472 | if (!dontPopulate) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1473 | element._populateIfNeeded(); |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1474 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1475 | element = |
| 1476 | (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : |
| 1477 | element.lastChild()); |
| 1478 | } |
| 1479 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1480 | if (element) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1481 | return element; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1482 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1483 | |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1484 | if (!this.parent || this.parent.root) { |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1485 | return null; |
Tim van der Lippe | 1d6e57a | 2019-09-30 11:55:34 | [diff] [blame] | 1486 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1487 | |
| 1488 | return this.parent; |
| 1489 | } |
| 1490 | |
| 1491 | /** |
| 1492 | * @return {boolean} |
| 1493 | */ |
| 1494 | isEventWithinDisclosureTriangle(event) { |
| 1495 | // FIXME: We should not use getComputedStyle(). For that we need to get rid of using ::before for disclosure triangle. (http://webk.it/74446) |
| 1496 | const paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLeft; |
| 1497 | console.assert(paddingLeftValue.endsWith('px')); |
| 1498 | const computedLeftPadding = parseFloat(paddingLeftValue); |
| 1499 | const left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1500 | return event.pageX >= left && event.pageX <= left + TreeElement._ArrowToggleWidth && this._expandable; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1501 | } |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1502 | } |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1503 | |
| 1504 | /** @const */ |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1505 | TreeElement._ArrowToggleWidth = 10; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1506 | |
| 1507 | (function() { |
| 1508 | const img = new Image(); |
Joel Einbinder | f6f86b6 | 2019-06-10 23:19:12 | [diff] [blame] | 1509 | img.src = 'Images/treeoutlineTriangles.svg'; |
Tim van der Lippe | 0830b3d | 2019-10-03 13:20:07 | [diff] [blame] | 1510 | TreeElement._imagePreload = img; |
Blink Reformat | 4c46d09 | 2018-04-07 15:32:37 | [diff] [blame] | 1511 | })(); |