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