Index: third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
index fbfb9d23d7b0dab1751bd8c0bf949f6746f1ac01..4e8bf1ed589b8b165fee20f935365d82d95565b9 100644 |
--- a/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
+++ b/third_party/WebKit/Source/devtools/front_end/ui/treeoutline.js |
@@ -25,14 +25,15 @@ |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
*/ |
- |
/** |
- * @constructor |
- * @extends {WebInspector.Object} |
- * @param {boolean=} nonFocusable |
+ * @unrestricted |
*/ |
-function TreeOutline(nonFocusable) |
-{ |
+var TreeOutline = class extends WebInspector.Object { |
+ /** |
+ * @param {boolean=} nonFocusable |
+ */ |
+ constructor(nonFocusable) { |
+ super(); |
this._createRootElement(); |
this.selectedTreeElement = null; |
@@ -41,339 +42,312 @@ function TreeOutline(nonFocusable) |
this._comparator = null; |
this.contentElement = this._rootElement._childrenListNode; |
- this.contentElement.addEventListener("keydown", this._treeKeyDown.bind(this), true); |
+ this.contentElement.addEventListener('keydown', this._treeKeyDown.bind(this), true); |
this.setFocusable(!nonFocusable); |
this.element = this.contentElement; |
-} |
- |
-/** @enum {symbol} */ |
-TreeOutline.Events = { |
- ElementAttached: Symbol("ElementAttached"), |
- ElementExpanded: Symbol("ElementExpanded"), |
- ElementCollapsed: Symbol("ElementCollapsed"), |
- ElementSelected: Symbol("ElementSelected") |
-}; |
- |
-TreeOutline.prototype = { |
- _createRootElement: function() |
- { |
- this._rootElement = new TreeElement(); |
- this._rootElement.treeOutline = this; |
- this._rootElement.root = true; |
- this._rootElement.selectable = false; |
- this._rootElement.expanded = true; |
- this._rootElement._childrenListNode.classList.remove("children"); |
- }, |
- |
- /** |
- * @return {!TreeElement} |
- */ |
- rootElement: function() |
- { |
- return this._rootElement; |
- }, |
- |
- /** |
- * @return {?TreeElement} |
- */ |
- firstChild: function() |
- { |
- return this._rootElement.firstChild(); |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- */ |
- appendChild: function(child) |
- { |
- this._rootElement.appendChild(child); |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- * @param {number} index |
- */ |
- insertChild: function(child, index) |
- { |
- this._rootElement.insertChild(child, index); |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- */ |
- removeChild: function(child) |
- { |
- this._rootElement.removeChild(child); |
- }, |
- |
- removeChildren: function() |
- { |
- this._rootElement.removeChildren(); |
- }, |
- |
- /** |
- * @param {number} x |
- * @param {number} y |
- * @return {?TreeElement} |
- */ |
- treeElementFromPoint: function(x, y) |
- { |
- var node = this.contentElement.ownerDocument.deepElementFromPoint(x, y); |
- if (!node) |
- return null; |
- |
- var listNode = node.enclosingNodeOrSelfWithNodeNameInArray(["ol", "li"]); |
- if (listNode) |
- return listNode.parentTreeElement || listNode.treeElement; |
- return null; |
- }, |
- |
- /** |
- * @param {?Event} event |
- * @return {?TreeElement} |
- */ |
- treeElementFromEvent: function(event) |
- { |
- return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; |
- }, |
- |
- /** |
- * @param {?function(!TreeElement, !TreeElement):number} comparator |
- */ |
- setComparator: function(comparator) |
- { |
- this._comparator = comparator; |
- }, |
- |
- /** |
- * @param {boolean} focusable |
- */ |
- setFocusable: function(focusable) |
- { |
- if (focusable) |
- this.contentElement.setAttribute("tabIndex", 0); |
+ } |
+ |
+ _createRootElement() { |
+ this._rootElement = new TreeElement(); |
+ this._rootElement.treeOutline = this; |
+ this._rootElement.root = true; |
+ this._rootElement.selectable = false; |
+ this._rootElement.expanded = true; |
+ this._rootElement._childrenListNode.classList.remove('children'); |
+ } |
+ |
+ /** |
+ * @return {!TreeElement} |
+ */ |
+ rootElement() { |
+ return this._rootElement; |
+ } |
+ |
+ /** |
+ * @return {?TreeElement} |
+ */ |
+ firstChild() { |
+ return this._rootElement.firstChild(); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ */ |
+ appendChild(child) { |
+ this._rootElement.appendChild(child); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ * @param {number} index |
+ */ |
+ insertChild(child, index) { |
+ this._rootElement.insertChild(child, index); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ */ |
+ removeChild(child) { |
+ this._rootElement.removeChild(child); |
+ } |
+ |
+ removeChildren() { |
+ this._rootElement.removeChildren(); |
+ } |
+ |
+ /** |
+ * @param {number} x |
+ * @param {number} y |
+ * @return {?TreeElement} |
+ */ |
+ treeElementFromPoint(x, y) { |
+ var node = this.contentElement.ownerDocument.deepElementFromPoint(x, y); |
+ if (!node) |
+ return null; |
+ |
+ var listNode = node.enclosingNodeOrSelfWithNodeNameInArray(['ol', 'li']); |
+ if (listNode) |
+ return listNode.parentTreeElement || listNode.treeElement; |
+ return null; |
+ } |
+ |
+ /** |
+ * @param {?Event} event |
+ * @return {?TreeElement} |
+ */ |
+ treeElementFromEvent(event) { |
+ return event ? this.treeElementFromPoint(event.pageX, event.pageY) : null; |
+ } |
+ |
+ /** |
+ * @param {?function(!TreeElement, !TreeElement):number} comparator |
+ */ |
+ setComparator(comparator) { |
+ this._comparator = comparator; |
+ } |
+ |
+ /** |
+ * @param {boolean} focusable |
+ */ |
+ setFocusable(focusable) { |
+ if (focusable) |
+ this.contentElement.setAttribute('tabIndex', 0); |
+ else |
+ this.contentElement.removeAttribute('tabIndex'); |
+ } |
+ |
+ focus() { |
+ this.contentElement.focus(); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} element |
+ */ |
+ _bindTreeElement(element) { |
+ if (element.treeOutline) |
+ console.error('Binding element for the second time: ' + new Error().stack); |
+ element.treeOutline = this; |
+ element.onbind(); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} element |
+ */ |
+ _unbindTreeElement(element) { |
+ if (!element.treeOutline) |
+ console.error('Unbinding element that was not bound: ' + new Error().stack); |
+ |
+ element.deselect(); |
+ element.onunbind(); |
+ element.treeOutline = null; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ selectPrevious() { |
+ var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true); |
+ while (nextSelectedElement && !nextSelectedElement.selectable) |
+ nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing); |
+ if (nextSelectedElement) { |
+ nextSelectedElement.reveal(); |
+ nextSelectedElement.select(false, true); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ selectNext() { |
+ var nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true); |
+ while (nextSelectedElement && !nextSelectedElement.selectable) |
+ nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing); |
+ if (nextSelectedElement) { |
+ nextSelectedElement.reveal(); |
+ nextSelectedElement.select(false, true); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _treeKeyDown(event) { |
+ if (event.target !== this.contentElement) |
+ return; |
+ |
+ if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey) |
+ return; |
+ |
+ var handled = false; |
+ var nextSelectedElement; |
+ if (event.key === 'ArrowUp' && !event.altKey) { |
+ handled = this.selectPrevious(); |
+ } else if (event.key === 'ArrowDown' && !event.altKey) { |
+ handled = this.selectNext(); |
+ } else if (event.key === 'ArrowLeft') { |
+ if (this.selectedTreeElement.expanded) { |
+ if (event.altKey) |
+ this.selectedTreeElement.collapseRecursively(); |
else |
- this.contentElement.removeAttribute("tabIndex"); |
- }, |
- |
- focus: function() |
- { |
- this.contentElement.focus(); |
- }, |
- |
- /** |
- * @param {!TreeElement} element |
- */ |
- _bindTreeElement: function(element) |
- { |
- if (element.treeOutline) |
- console.error("Binding element for the second time: " + new Error().stack); |
- element.treeOutline = this; |
- element.onbind(); |
- }, |
- |
- /** |
- * @param {!TreeElement} element |
- */ |
- _unbindTreeElement: function(element) |
- { |
- if (!element.treeOutline) |
- console.error("Unbinding element that was not bound: " + new Error().stack); |
- |
- element.deselect(); |
- element.onunbind(); |
- element.treeOutline = null; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- selectPrevious: function() |
- { |
- var nextSelectedElement = this.selectedTreeElement.traversePreviousTreeElement(true); |
- while (nextSelectedElement && !nextSelectedElement.selectable) |
- nextSelectedElement = nextSelectedElement.traversePreviousTreeElement(!this.expandTreeElementsWhenArrowing); |
- if (nextSelectedElement) { |
- nextSelectedElement.reveal(); |
- nextSelectedElement.select(false, true); |
- return true; |
- } |
- return false; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- selectNext: function() |
- { |
- var nextSelectedElement = this.selectedTreeElement.traverseNextTreeElement(true); |
- while (nextSelectedElement && !nextSelectedElement.selectable) |
- nextSelectedElement = nextSelectedElement.traverseNextTreeElement(!this.expandTreeElementsWhenArrowing); |
- if (nextSelectedElement) { |
- nextSelectedElement.reveal(); |
- nextSelectedElement.select(false, true); |
- return true; |
- } |
- return false; |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _treeKeyDown: function(event) |
- { |
- if (event.target !== this.contentElement) |
- return; |
- |
- if (!this.selectedTreeElement || event.shiftKey || event.metaKey || event.ctrlKey) |
- return; |
- |
- var handled = false; |
- var nextSelectedElement; |
- if (event.key === "ArrowUp" && !event.altKey) { |
- handled = this.selectPrevious(); |
- } else if (event.key === "ArrowDown" && !event.altKey) { |
- handled = this.selectNext(); |
- } else if (event.key === "ArrowLeft") { |
- if (this.selectedTreeElement.expanded) { |
- if (event.altKey) |
- this.selectedTreeElement.collapseRecursively(); |
- else |
- this.selectedTreeElement.collapse(); |
- handled = true; |
- } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { |
- handled = true; |
- if (this.selectedTreeElement.parent.selectable) { |
- nextSelectedElement = this.selectedTreeElement.parent; |
- while (nextSelectedElement && !nextSelectedElement.selectable) |
- nextSelectedElement = nextSelectedElement.parent; |
- handled = nextSelectedElement ? true : false; |
- } else if (this.selectedTreeElement.parent) |
- this.selectedTreeElement.parent.collapse(); |
- } |
- } else if (event.key === "ArrowRight") { |
- if (!this.selectedTreeElement.revealed()) { |
- this.selectedTreeElement.reveal(); |
- handled = true; |
- } else if (this.selectedTreeElement._expandable) { |
- handled = true; |
- if (this.selectedTreeElement.expanded) { |
- nextSelectedElement = this.selectedTreeElement.firstChild(); |
- while (nextSelectedElement && !nextSelectedElement.selectable) |
- nextSelectedElement = nextSelectedElement.nextSibling; |
- handled = nextSelectedElement ? true : false; |
- } else { |
- if (event.altKey) |
- this.selectedTreeElement.expandRecursively(); |
- else |
- this.selectedTreeElement.expand(); |
- } |
- } |
- } else if (event.keyCode === 8 /* Backspace */ || event.keyCode === 46 /* Delete */) |
- handled = this.selectedTreeElement.ondelete(); |
- else if (isEnterKey(event)) |
- handled = this.selectedTreeElement.onenter(); |
- else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code) |
- handled = this.selectedTreeElement.onspace(); |
- |
- if (nextSelectedElement) { |
- nextSelectedElement.reveal(); |
- nextSelectedElement.select(false, true); |
+ this.selectedTreeElement.collapse(); |
+ handled = true; |
+ } else if (this.selectedTreeElement.parent && !this.selectedTreeElement.parent.root) { |
+ handled = true; |
+ if (this.selectedTreeElement.parent.selectable) { |
+ nextSelectedElement = this.selectedTreeElement.parent; |
+ while (nextSelectedElement && !nextSelectedElement.selectable) |
+ nextSelectedElement = nextSelectedElement.parent; |
+ handled = nextSelectedElement ? true : false; |
+ } else if (this.selectedTreeElement.parent) |
+ this.selectedTreeElement.parent.collapse(); |
+ } |
+ } else if (event.key === 'ArrowRight') { |
+ if (!this.selectedTreeElement.revealed()) { |
+ this.selectedTreeElement.reveal(); |
+ handled = true; |
+ } else if (this.selectedTreeElement._expandable) { |
+ handled = true; |
+ if (this.selectedTreeElement.expanded) { |
+ nextSelectedElement = this.selectedTreeElement.firstChild(); |
+ while (nextSelectedElement && !nextSelectedElement.selectable) |
+ nextSelectedElement = nextSelectedElement.nextSibling; |
+ handled = nextSelectedElement ? true : false; |
+ } else { |
+ if (event.altKey) |
+ this.selectedTreeElement.expandRecursively(); |
+ else |
+ this.selectedTreeElement.expand(); |
} |
+ } |
+ } else if (event.keyCode === 8 /* Backspace */ || event.keyCode === 46 /* Delete */) |
+ handled = this.selectedTreeElement.ondelete(); |
+ else if (isEnterKey(event)) |
+ handled = this.selectedTreeElement.onenter(); |
+ else if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Space.code) |
+ handled = this.selectedTreeElement.onspace(); |
+ |
+ if (nextSelectedElement) { |
+ nextSelectedElement.reveal(); |
+ nextSelectedElement.select(false, true); |
+ } |
- if (handled) |
- event.consume(true); |
- }, |
- |
+ if (handled) |
+ event.consume(true); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} treeElement |
+ * @param {boolean} center |
+ */ |
+ _deferredScrollIntoView(treeElement, center) { |
+ if (!this._treeElementToScrollIntoView) |
+ this.element.window().requestAnimationFrame(deferredScrollIntoView.bind(this)); |
+ this._treeElementToScrollIntoView = treeElement; |
+ this._centerUponScrollIntoView = center; |
/** |
- * @param {!TreeElement} treeElement |
- * @param {boolean} center |
+ * @this {TreeOutline} |
*/ |
- _deferredScrollIntoView: function(treeElement, center) |
- { |
- if (!this._treeElementToScrollIntoView) |
- this.element.window().requestAnimationFrame(deferredScrollIntoView.bind(this)); |
- this._treeElementToScrollIntoView = treeElement; |
- this._centerUponScrollIntoView = center; |
- /** |
- * @this {TreeOutline} |
- */ |
- function deferredScrollIntoView() |
- { |
- this._treeElementToScrollIntoView.listItemElement.scrollIntoViewIfNeeded(this._centerUponScrollIntoView); |
- delete this._treeElementToScrollIntoView; |
- delete this._centerUponScrollIntoView; |
- } |
- }, |
+ function deferredScrollIntoView() { |
+ this._treeElementToScrollIntoView.listItemElement.scrollIntoViewIfNeeded(this._centerUponScrollIntoView); |
+ delete this._treeElementToScrollIntoView; |
+ delete this._centerUponScrollIntoView; |
+ } |
+ } |
+}; |
- __proto__: WebInspector.Object.prototype |
+/** @enum {symbol} */ |
+TreeOutline.Events = { |
+ ElementAttached: Symbol('ElementAttached'), |
+ ElementExpanded: Symbol('ElementExpanded'), |
+ ElementCollapsed: Symbol('ElementCollapsed'), |
+ ElementSelected: Symbol('ElementSelected') |
}; |
/** |
- * @constructor |
- * @extends {TreeOutline} |
+ * @unrestricted |
*/ |
-function TreeOutlineInShadow() |
-{ |
- TreeOutline.call(this); |
- this.contentElement.classList.add("tree-outline"); |
+var TreeOutlineInShadow = class extends TreeOutline { |
+ constructor() { |
+ super(); |
+ this.contentElement.classList.add('tree-outline'); |
// Redefine element to the external one. |
- this.element = createElement("div"); |
- this._shadowRoot = WebInspector.createShadowRootWithCoreStyles(this.element, "ui/treeoutline.css"); |
- this._disclosureElement = this._shadowRoot.createChild("div", "tree-outline-disclosure"); |
+ this.element = createElement('div'); |
+ this._shadowRoot = WebInspector.createShadowRootWithCoreStyles(this.element, 'ui/treeoutline.css'); |
+ this._disclosureElement = this._shadowRoot.createChild('div', 'tree-outline-disclosure'); |
this._disclosureElement.appendChild(this.contentElement); |
this._renderSelection = true; |
-} |
- |
-TreeOutlineInShadow.prototype = { |
- /** |
- * @param {string} cssFile |
- */ |
- registerRequiredCSS: function(cssFile) |
- { |
- WebInspector.appendStyle(this._shadowRoot, cssFile); |
- }, |
- |
- hideOverflow: function() |
- { |
- this._disclosureElement.classList.add("tree-outline-disclosure-hide-overflow"); |
- }, |
- |
- makeDense: function() |
- { |
- this.contentElement.classList.add("tree-outline-dense"); |
- }, |
- |
- __proto__: TreeOutline.prototype |
+ } |
+ |
+ /** |
+ * @param {string} cssFile |
+ */ |
+ registerRequiredCSS(cssFile) { |
+ WebInspector.appendStyle(this._shadowRoot, cssFile); |
+ } |
+ |
+ hideOverflow() { |
+ this._disclosureElement.classList.add('tree-outline-disclosure-hide-overflow'); |
+ } |
+ |
+ makeDense() { |
+ this.contentElement.classList.add('tree-outline-dense'); |
+ } |
}; |
/** |
- * @constructor |
- * @param {(string|!Node)=} title |
- * @param {boolean=} expandable |
+ * @unrestricted |
*/ |
-function TreeElement(title, expandable) |
-{ |
+var TreeElement = class { |
+ /** |
+ * @param {(string|!Node)=} title |
+ * @param {boolean=} expandable |
+ */ |
+ constructor(title, expandable) { |
/** @type {?TreeOutline} */ |
this.treeOutline = null; |
this.parent = null; |
this.previousSibling = null; |
this.nextSibling = null; |
- this._listItemNode = createElement("li"); |
+ this._listItemNode = createElement('li'); |
this._listItemNode.treeElement = this; |
if (title) |
- this.title = title; |
- this._listItemNode.addEventListener("mousedown", this._handleMouseDown.bind(this), false); |
- this._listItemNode.addEventListener("click", this._treeElementToggled.bind(this), false); |
- this._listItemNode.addEventListener("dblclick", this._handleDoubleClick.bind(this), false); |
+ this.title = title; |
+ this._listItemNode.addEventListener('mousedown', this._handleMouseDown.bind(this), false); |
+ this._listItemNode.addEventListener('click', this._treeElementToggled.bind(this), false); |
+ this._listItemNode.addEventListener('dblclick', this._handleDoubleClick.bind(this), false); |
- this._childrenListNode = createElement("ol"); |
+ this._childrenListNode = createElement('ol'); |
this._childrenListNode.parentTreeElement = this; |
- this._childrenListNode.classList.add("children"); |
+ this._childrenListNode.classList.add('children'); |
this._hidden = false; |
this._selectable = true; |
@@ -381,780 +355,736 @@ function TreeElement(title, expandable) |
this.selected = false; |
this.setExpandable(expandable || false); |
this._collapsible = true; |
-} |
- |
-/** @const */ |
-TreeElement._ArrowToggleWidth = 10; |
- |
-TreeElement.prototype = { |
- /** |
- * @param {?TreeElement} ancestor |
- * @return {boolean} |
- */ |
- hasAncestor: function(ancestor) |
- { |
- if (!ancestor) |
- return false; |
- |
- var currentNode = this.parent; |
- while (currentNode) { |
- if (ancestor === currentNode) |
- return true; |
- currentNode = currentNode.parent; |
- } |
- |
- return false; |
- }, |
- |
- /** |
- * @param {?TreeElement} ancestor |
- * @return {boolean} |
- */ |
- hasAncestorOrSelf: function(ancestor) |
- { |
- return this === ancestor || this.hasAncestor(ancestor); |
- }, |
- |
- /** |
- * @return {!Array.<!TreeElement>} |
- */ |
- children: function() |
- { |
- return this._children || []; |
- }, |
- |
- /** |
- * @return {number} |
- */ |
- childCount: function() |
- { |
- return this._children ? this._children.length : 0; |
- }, |
- |
- /** |
- * @return {?TreeElement} |
- */ |
- firstChild: function() |
- { |
- return this._children ? this._children[0] : null; |
- }, |
- |
- /** |
- * @return {?TreeElement} |
- */ |
- lastChild: function() |
- { |
- return this._children ? this._children[this._children.length - 1] : null; |
- }, |
- |
- /** |
- * @param {number} index |
- * @return {?TreeElement} |
- */ |
- childAt: function(index) |
- { |
- return this._children ? this._children[index] : null; |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- * @return {number} |
- */ |
- indexOfChild: function(child) |
- { |
- return this._children ? this._children.indexOf(child) : -1; |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- */ |
- appendChild: function(child) |
- { |
- if (!this._children) |
- this._children = []; |
- |
- var insertionIndex; |
- if (this.treeOutline && this.treeOutline._comparator) |
- insertionIndex = this._children.lowerBound(child, this.treeOutline._comparator); |
- else |
- insertionIndex = this._children.length; |
- this.insertChild(child, insertionIndex); |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- * @param {number} index |
- */ |
- insertChild: function(child, index) |
- { |
- if (!this._children) |
- this._children = []; |
- |
- if (!child) |
- throw "child can't be undefined or null"; |
- |
- console.assert(!child.parent, "Attempting to insert a child that is already in the tree, reparenting is not supported."); |
- |
- var previousChild = (index > 0 ? this._children[index - 1] : null); |
- if (previousChild) { |
- previousChild.nextSibling = child; |
- child.previousSibling = previousChild; |
- } else { |
- child.previousSibling = null; |
- } |
- |
- var nextChild = this._children[index]; |
- if (nextChild) { |
- nextChild.previousSibling = child; |
- child.nextSibling = nextChild; |
- } else { |
- child.nextSibling = null; |
- } |
- |
- this._children.splice(index, 0, child); |
- |
- this.setExpandable(true); |
- child.parent = this; |
- |
- if (this.treeOutline) |
- this.treeOutline._bindTreeElement(child); |
- for (var current = child.firstChild(); this.treeOutline && current; current = current.traverseNextTreeElement(false, child, true)) |
- this.treeOutline._bindTreeElement(current); |
- child.onattach(); |
- child._ensureSelection(); |
- if (this.treeOutline) |
- this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementAttached, child); |
- var nextSibling = child.nextSibling ? child.nextSibling._listItemNode : null; |
- this._childrenListNode.insertBefore(child._listItemNode, nextSibling); |
- this._childrenListNode.insertBefore(child._childrenListNode, nextSibling); |
- if (child.selected) |
- child.select(); |
- if (child.expanded) |
- child.expand(); |
- }, |
- |
- /** |
- * @param {number} childIndex |
- */ |
- removeChildAtIndex: function(childIndex) |
- { |
- if (childIndex < 0 || childIndex >= this._children.length) |
- throw "childIndex out of range"; |
- |
- var child = this._children[childIndex]; |
- this._children.splice(childIndex, 1); |
- |
- var parent = child.parent; |
- if (this.treeOutline && this.treeOutline.selectedTreeElement && this.treeOutline.selectedTreeElement.hasAncestorOrSelf(child)) { |
- if (child.nextSibling) |
- child.nextSibling.select(true); |
- else if (child.previousSibling) |
- child.previousSibling.select(true); |
- else if (parent) |
- parent.select(true); |
- } |
- |
- if (child.previousSibling) |
- child.previousSibling.nextSibling = child.nextSibling; |
- if (child.nextSibling) |
- child.nextSibling.previousSibling = child.previousSibling; |
- child.parent = null; |
- |
- if (this.treeOutline) |
- this.treeOutline._unbindTreeElement(child); |
- for (var current = child.firstChild(); this.treeOutline && current; current = current.traverseNextTreeElement(false, child, true)) |
- this.treeOutline._unbindTreeElement(current); |
- |
- child._detach(); |
- }, |
- |
- /** |
- * @param {!TreeElement} child |
- */ |
- removeChild: function(child) |
- { |
- if (!child) |
- throw "child can't be undefined or null"; |
- if (child.parent !== this) |
- return; |
- |
- var childIndex = this._children.indexOf(child); |
- if (childIndex === -1) |
- throw "child not found in this node's children"; |
- |
- this.removeChildAtIndex(childIndex); |
- }, |
- |
- removeChildren: function() |
- { |
- if (!this.root && this.treeOutline && this.treeOutline.selectedTreeElement && this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) |
- this.select(true); |
- |
- for (var i = 0; this._children && i < this._children.length; ++i) { |
- var child = this._children[i]; |
- child.previousSibling = null; |
- child.nextSibling = null; |
- child.parent = null; |
- |
- if (this.treeOutline) |
- this.treeOutline._unbindTreeElement(child); |
- for (var current = child.firstChild(); this.treeOutline && current; current = current.traverseNextTreeElement(false, child, true)) |
- this.treeOutline._unbindTreeElement(current); |
- child._detach(); |
- } |
- this._children = []; |
- }, |
- |
- get selectable() |
- { |
- if (this._hidden) |
- return false; |
- return this._selectable; |
- }, |
- |
- set selectable(x) |
- { |
- this._selectable = x; |
- }, |
- |
- get listItemElement() |
- { |
- return this._listItemNode; |
- }, |
- |
- get childrenListElement() |
- { |
- return this._childrenListNode; |
- }, |
- |
- get title() |
- { |
- return this._title; |
- }, |
- |
- /** |
- * @param {string|!Node} x |
- */ |
- set title(x) |
- { |
- if (this._title === x) |
- return; |
- this._title = x; |
- |
- if (typeof x === "string") { |
- this._titleElement = createElementWithClass("span", "tree-element-title"); |
- this._titleElement.textContent = x; |
- this.tooltip = x; |
- } else { |
- this._titleElement = x; |
- this.tooltip = ""; |
- } |
- |
- this._listItemNode.removeChildren(); |
- if (this._iconElement) |
- this._listItemNode.appendChild(this._iconElement); |
- |
- this._listItemNode.appendChild(this._titleElement); |
- this._ensureSelection(); |
- }, |
- |
- /** |
- * @return {string} |
- */ |
- titleAsText: function() |
- { |
- if (!this._title) |
- return ""; |
- if (typeof this._title === "string") |
- return this._title; |
- return this._title.textContent; |
- }, |
- |
- /** |
- * @param {!WebInspector.InplaceEditor.Config} editingConfig |
- */ |
- startEditingTitle: function(editingConfig) |
- { |
- WebInspector.InplaceEditor.startEditing(this._titleElement, editingConfig); |
- this.treeOutline._shadowRoot.getSelection().setBaseAndExtent(this._titleElement, 0, this._titleElement, 1); |
- }, |
- |
- createIcon() |
- { |
- if (!this._iconElement) { |
- this._iconElement = createElementWithClass("div", "icon"); |
- this._listItemNode.insertBefore(this._iconElement, this._listItemNode.firstChild); |
- this._ensureSelection(); |
- } |
- }, |
- |
- get tooltip() |
- { |
- return this._tooltip || ""; |
- }, |
- |
- /** |
- * @param {string} x |
- */ |
- set tooltip(x) |
- { |
- if (this._tooltip === x) |
- return; |
- this._tooltip = x; |
- this._listItemNode.title = x; |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- isExpandable: function() |
- { |
- return this._expandable; |
- }, |
- |
- /** |
- * @param {boolean} expandable |
- */ |
- setExpandable: function(expandable) |
- { |
- if (this._expandable === expandable) |
- return; |
- |
- this._expandable = expandable; |
- |
- this._listItemNode.classList.toggle("parent", expandable); |
- if (!expandable) |
- this.collapse(); |
- }, |
- |
- /** |
- * @param {boolean} collapsible |
- */ |
- setCollapsible: function(collapsible) |
- { |
- if (this._collapsible === collapsible) |
- return; |
- |
- this._collapsible = collapsible; |
- |
- this._listItemNode.classList.toggle("always-parent", !collapsible); |
- if (!collapsible) |
- this.expand(); |
- }, |
- |
- get hidden() |
- { |
- return this._hidden; |
- }, |
- |
- set hidden(x) |
- { |
- if (this._hidden === x) |
- return; |
- |
- this._hidden = x; |
- |
- this._listItemNode.classList.toggle("hidden", x); |
- this._childrenListNode.classList.toggle("hidden", x); |
- }, |
- |
- invalidateChildren: function() |
- { |
- if (this._children) { |
- this.removeChildren(); |
- this._children = null; |
- } |
- }, |
- |
- _ensureSelection: function() |
- { |
- if (!this.treeOutline || !this.treeOutline._renderSelection) |
- return; |
- if (!this._selectionElement) |
- this._selectionElement = createElementWithClass("div", "selection fill"); |
- this._listItemNode.insertBefore(this._selectionElement, this.listItemElement.firstChild); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _treeElementToggled: function(event) |
- { |
- var element = event.currentTarget; |
- if (element.treeElement !== this || element.hasSelection()) |
- return; |
- |
- var toggleOnClick = this.toggleOnClick && !this.selectable; |
- var isInTriangle = this.isEventWithinDisclosureTriangle(event); |
- if (!toggleOnClick && !isInTriangle) |
- return; |
- |
- if (event.target && event.target.enclosingNodeOrSelfWithNodeName("a")) |
- return; |
- |
- if (this.expanded) { |
- if (event.altKey) |
- this.collapseRecursively(); |
- else |
- this.collapse(); |
- } else { |
- if (event.altKey) |
- this.expandRecursively(); |
- else |
- this.expand(); |
- } |
- event.consume(); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _handleMouseDown: function(event) |
- { |
- var element = event.currentTarget; |
- if (!element) |
- return; |
- if (!this.selectable) |
- return; |
- if (element.treeElement !== this) |
- return; |
- |
- if (this.isEventWithinDisclosureTriangle(event)) |
- return; |
- |
- this.selectOnMouseDown(event); |
- }, |
- |
- /** |
- * @param {!Event} event |
- */ |
- _handleDoubleClick: function(event) |
- { |
- var element = event.currentTarget; |
- if (!element || element.treeElement !== this) |
- return; |
- |
- var handled = this.ondblclick(event); |
- if (handled) |
- return; |
- if (this._expandable && !this.expanded) |
- this.expand(); |
- }, |
- |
- _detach: function() |
- { |
- this._listItemNode.remove(); |
- this._childrenListNode.remove(); |
- }, |
- |
- collapse: function() |
- { |
- if (!this.expanded || !this._collapsible) |
- return; |
- this._listItemNode.classList.remove("expanded"); |
- this._childrenListNode.classList.remove("expanded"); |
- this.expanded = false; |
- this.oncollapse(); |
- if (this.treeOutline) |
- this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementCollapsed, this); |
- }, |
- |
- collapseRecursively: function() |
- { |
- var item = this; |
- while (item) { |
- if (item.expanded) |
- item.collapse(); |
- item = item.traverseNextTreeElement(false, this, true); |
- } |
- }, |
- |
- expand: function() |
- { |
- if (!this._expandable || (this.expanded && this._children)) |
- return; |
- |
- // Set this before onpopulate. Since onpopulate can add elements, this makes |
- // sure the expanded flag is true before calling those functions. This prevents the possibility |
- // of an infinite loop if onpopulate were to call expand. |
- |
- this.expanded = true; |
- |
- this._populateIfNeeded(); |
- this._listItemNode.classList.add("expanded"); |
- this._childrenListNode.classList.add("expanded"); |
- |
- if (this.treeOutline) { |
- this.onexpand(); |
- this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementExpanded, this); |
- } |
- }, |
- |
- /** |
- * @param {number=} maxDepth |
- */ |
- expandRecursively: function(maxDepth) |
- { |
- var item = this; |
- var info = {}; |
- var depth = 0; |
- |
- // The Inspector uses TreeOutlines to represents object properties, so recursive expansion |
- // in some case can be infinite, since JavaScript objects can hold circular references. |
- // So default to a recursion cap of 3 levels, since that gives fairly good results. |
- if (isNaN(maxDepth)) |
- maxDepth = 3; |
- |
- while (item) { |
- if (depth < maxDepth) |
- item.expand(); |
- item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info); |
- depth += info.depthChange; |
- } |
- }, |
- |
- /** |
- * @param {boolean=} center |
- */ |
- reveal: function(center) |
- { |
- var currentAncestor = this.parent; |
- while (currentAncestor && !currentAncestor.root) { |
- if (!currentAncestor.expanded) |
- currentAncestor.expand(); |
- currentAncestor = currentAncestor.parent; |
- } |
- |
- this.treeOutline._deferredScrollIntoView(this, !!center); |
- }, |
- |
- /** |
- * @return {boolean} |
- */ |
- revealed: function() |
- { |
- var currentAncestor = this.parent; |
- while (currentAncestor && !currentAncestor.root) { |
- if (!currentAncestor.expanded) |
- return false; |
- currentAncestor = currentAncestor.parent; |
- } |
- |
+ } |
+ |
+ /** |
+ * @param {?TreeElement} ancestor |
+ * @return {boolean} |
+ */ |
+ hasAncestor(ancestor) { |
+ if (!ancestor) |
+ return false; |
+ |
+ var currentNode = this.parent; |
+ while (currentNode) { |
+ if (ancestor === currentNode) |
return true; |
- }, |
- |
- selectOnMouseDown: function(event) |
- { |
- if (this.select(false, true)) |
- event.consume(true); |
- }, |
- |
- /** |
- * @param {boolean=} omitFocus |
- * @param {boolean=} selectedByUser |
- * @return {boolean} |
- */ |
- select: function(omitFocus, selectedByUser) |
- { |
- if (!this.treeOutline || !this.selectable || this.selected) |
- return false; |
- |
- if (this.treeOutline.selectedTreeElement) |
- this.treeOutline.selectedTreeElement.deselect(); |
- this.treeOutline.selectedTreeElement = null; |
- |
- if (this.treeOutline._rootElement === this) |
- return false; |
- |
- this.selected = true; |
- |
- if (!omitFocus) |
- this.treeOutline.focus(); |
- |
- // Focusing on another node may detach "this" from tree. |
- if (!this.treeOutline) |
- return false; |
- this.treeOutline.selectedTreeElement = this; |
- this._listItemNode.classList.add("selected"); |
- this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementSelected, this); |
- return this.onselect(selectedByUser); |
- }, |
- |
- /** |
- * @param {boolean=} omitFocus |
- */ |
- revealAndSelect: function(omitFocus) |
- { |
- this.reveal(true); |
- this.select(omitFocus); |
- }, |
+ currentNode = currentNode.parent; |
+ } |
- /** |
- * @param {boolean=} supressOnDeselect |
- */ |
- deselect: function(supressOnDeselect) |
- { |
- if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !this.selected) |
- return; |
- |
- this.selected = false; |
- this.treeOutline.selectedTreeElement = null; |
- this._listItemNode.classList.remove("selected"); |
- }, |
- |
- _populateIfNeeded: function() |
- { |
- if (this.treeOutline && this._expandable && !this._children) { |
- this._children = []; |
- this.onpopulate(); |
- } |
- }, |
+ return false; |
+ } |
+ |
+ /** |
+ * @param {?TreeElement} ancestor |
+ * @return {boolean} |
+ */ |
+ hasAncestorOrSelf(ancestor) { |
+ return this === ancestor || this.hasAncestor(ancestor); |
+ } |
+ |
+ /** |
+ * @return {!Array.<!TreeElement>} |
+ */ |
+ children() { |
+ return this._children || []; |
+ } |
+ |
+ /** |
+ * @return {number} |
+ */ |
+ childCount() { |
+ return this._children ? this._children.length : 0; |
+ } |
+ |
+ /** |
+ * @return {?TreeElement} |
+ */ |
+ firstChild() { |
+ return this._children ? this._children[0] : null; |
+ } |
+ |
+ /** |
+ * @return {?TreeElement} |
+ */ |
+ lastChild() { |
+ return this._children ? this._children[this._children.length - 1] : null; |
+ } |
+ |
+ /** |
+ * @param {number} index |
+ * @return {?TreeElement} |
+ */ |
+ childAt(index) { |
+ return this._children ? this._children[index] : null; |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ * @return {number} |
+ */ |
+ indexOfChild(child) { |
+ return this._children ? this._children.indexOf(child) : -1; |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ */ |
+ appendChild(child) { |
+ if (!this._children) |
+ this._children = []; |
+ |
+ var insertionIndex; |
+ if (this.treeOutline && this.treeOutline._comparator) |
+ insertionIndex = this._children.lowerBound(child, this.treeOutline._comparator); |
+ else |
+ insertionIndex = this._children.length; |
+ this.insertChild(child, insertionIndex); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ * @param {number} index |
+ */ |
+ insertChild(child, index) { |
+ if (!this._children) |
+ this._children = []; |
+ |
+ if (!child) |
+ throw 'child can\'t be undefined or null'; |
+ |
+ console.assert( |
+ !child.parent, 'Attempting to insert a child that is already in the tree, reparenting is not supported.'); |
+ |
+ var previousChild = (index > 0 ? this._children[index - 1] : null); |
+ if (previousChild) { |
+ previousChild.nextSibling = child; |
+ child.previousSibling = previousChild; |
+ } else { |
+ child.previousSibling = null; |
+ } |
- onpopulate: function() |
- { |
- // Overridden by subclasses. |
- }, |
+ var nextChild = this._children[index]; |
+ if (nextChild) { |
+ nextChild.previousSibling = child; |
+ child.nextSibling = nextChild; |
+ } else { |
+ child.nextSibling = null; |
+ } |
- /** |
- * @return {boolean} |
- */ |
- onenter: function() |
- { |
- return false; |
- }, |
+ this._children.splice(index, 0, child); |
+ |
+ this.setExpandable(true); |
+ child.parent = this; |
+ |
+ if (this.treeOutline) |
+ this.treeOutline._bindTreeElement(child); |
+ for (var current = child.firstChild(); this.treeOutline && current; |
+ current = current.traverseNextTreeElement(false, child, true)) |
+ this.treeOutline._bindTreeElement(current); |
+ child.onattach(); |
+ child._ensureSelection(); |
+ if (this.treeOutline) |
+ this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementAttached, child); |
+ var nextSibling = child.nextSibling ? child.nextSibling._listItemNode : null; |
+ this._childrenListNode.insertBefore(child._listItemNode, nextSibling); |
+ this._childrenListNode.insertBefore(child._childrenListNode, nextSibling); |
+ if (child.selected) |
+ child.select(); |
+ if (child.expanded) |
+ child.expand(); |
+ } |
+ |
+ /** |
+ * @param {number} childIndex |
+ */ |
+ removeChildAtIndex(childIndex) { |
+ if (childIndex < 0 || childIndex >= this._children.length) |
+ throw 'childIndex out of range'; |
+ |
+ var child = this._children[childIndex]; |
+ this._children.splice(childIndex, 1); |
+ |
+ var parent = child.parent; |
+ if (this.treeOutline && this.treeOutline.selectedTreeElement && |
+ this.treeOutline.selectedTreeElement.hasAncestorOrSelf(child)) { |
+ if (child.nextSibling) |
+ child.nextSibling.select(true); |
+ else if (child.previousSibling) |
+ child.previousSibling.select(true); |
+ else if (parent) |
+ parent.select(true); |
+ } |
- /** |
- * @return {boolean} |
- */ |
- ondelete: function() |
- { |
- return false; |
- }, |
+ if (child.previousSibling) |
+ child.previousSibling.nextSibling = child.nextSibling; |
+ if (child.nextSibling) |
+ child.nextSibling.previousSibling = child.previousSibling; |
+ child.parent = null; |
+ |
+ if (this.treeOutline) |
+ this.treeOutline._unbindTreeElement(child); |
+ for (var current = child.firstChild(); this.treeOutline && current; |
+ current = current.traverseNextTreeElement(false, child, true)) |
+ this.treeOutline._unbindTreeElement(current); |
+ |
+ child._detach(); |
+ } |
+ |
+ /** |
+ * @param {!TreeElement} child |
+ */ |
+ removeChild(child) { |
+ if (!child) |
+ throw 'child can\'t be undefined or null'; |
+ if (child.parent !== this) |
+ return; |
+ |
+ var childIndex = this._children.indexOf(child); |
+ if (childIndex === -1) |
+ throw 'child not found in this node\'s children'; |
+ |
+ this.removeChildAtIndex(childIndex); |
+ } |
+ |
+ removeChildren() { |
+ if (!this.root && this.treeOutline && this.treeOutline.selectedTreeElement && |
+ this.treeOutline.selectedTreeElement.hasAncestorOrSelf(this)) |
+ this.select(true); |
+ |
+ for (var i = 0; this._children && i < this._children.length; ++i) { |
+ var child = this._children[i]; |
+ child.previousSibling = null; |
+ child.nextSibling = null; |
+ child.parent = null; |
+ |
+ if (this.treeOutline) |
+ this.treeOutline._unbindTreeElement(child); |
+ for (var current = child.firstChild(); this.treeOutline && current; |
+ current = current.traverseNextTreeElement(false, child, true)) |
+ this.treeOutline._unbindTreeElement(current); |
+ child._detach(); |
+ } |
+ this._children = []; |
+ } |
+ |
+ get selectable() { |
+ if (this._hidden) |
+ return false; |
+ return this._selectable; |
+ } |
+ |
+ set selectable(x) { |
+ this._selectable = x; |
+ } |
+ |
+ get listItemElement() { |
+ return this._listItemNode; |
+ } |
+ |
+ get childrenListElement() { |
+ return this._childrenListNode; |
+ } |
+ |
+ /** |
+ * @return {string|!Node} |
+ */ |
+ get title() { |
+ return this._title; |
+ } |
+ |
+ /** |
+ * @param {string|!Node} x |
+ */ |
+ set title(x) { |
+ if (this._title === x) |
+ return; |
+ this._title = x; |
+ |
+ if (typeof x === 'string') { |
+ this._titleElement = createElementWithClass('span', 'tree-element-title'); |
+ this._titleElement.textContent = x; |
+ this.tooltip = x; |
+ } else { |
+ this._titleElement = x; |
+ this.tooltip = ''; |
+ } |
- /** |
- * @return {boolean} |
- */ |
- onspace: function() |
- { |
- return false; |
- }, |
+ this._listItemNode.removeChildren(); |
+ if (this._iconElement) |
+ this._listItemNode.appendChild(this._iconElement); |
+ |
+ this._listItemNode.appendChild(this._titleElement); |
+ this._ensureSelection(); |
+ } |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ titleAsText() { |
+ if (!this._title) |
+ return ''; |
+ if (typeof this._title === 'string') |
+ return this._title; |
+ return this._title.textContent; |
+ } |
+ |
+ /** |
+ * @param {!WebInspector.InplaceEditor.Config} editingConfig |
+ */ |
+ startEditingTitle(editingConfig) { |
+ WebInspector.InplaceEditor.startEditing(this._titleElement, editingConfig); |
+ this.treeOutline._shadowRoot.getSelection().setBaseAndExtent(this._titleElement, 0, this._titleElement, 1); |
+ } |
+ |
+ createIcon() { |
+ if (!this._iconElement) { |
+ this._iconElement = createElementWithClass('div', 'icon'); |
+ this._listItemNode.insertBefore(this._iconElement, this._listItemNode.firstChild); |
+ this._ensureSelection(); |
+ } |
+ } |
+ |
+ /** |
+ * @return {string} |
+ */ |
+ get tooltip() { |
+ return this._tooltip || ''; |
+ } |
+ |
+ /** |
+ * @param {string} x |
+ */ |
+ set tooltip(x) { |
+ if (this._tooltip === x) |
+ return; |
+ this._tooltip = x; |
+ this._listItemNode.title = x; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ isExpandable() { |
+ return this._expandable; |
+ } |
+ |
+ /** |
+ * @param {boolean} expandable |
+ */ |
+ setExpandable(expandable) { |
+ if (this._expandable === expandable) |
+ return; |
+ |
+ this._expandable = expandable; |
+ |
+ this._listItemNode.classList.toggle('parent', expandable); |
+ if (!expandable) |
+ this.collapse(); |
+ } |
+ |
+ /** |
+ * @param {boolean} collapsible |
+ */ |
+ setCollapsible(collapsible) { |
+ if (this._collapsible === collapsible) |
+ return; |
+ |
+ this._collapsible = collapsible; |
+ |
+ this._listItemNode.classList.toggle('always-parent', !collapsible); |
+ if (!collapsible) |
+ this.expand(); |
+ } |
+ |
+ get hidden() { |
+ return this._hidden; |
+ } |
+ |
+ set hidden(x) { |
+ if (this._hidden === x) |
+ return; |
+ |
+ this._hidden = x; |
+ |
+ this._listItemNode.classList.toggle('hidden', x); |
+ this._childrenListNode.classList.toggle('hidden', x); |
+ } |
+ |
+ invalidateChildren() { |
+ if (this._children) { |
+ this.removeChildren(); |
+ this._children = null; |
+ } |
+ } |
+ |
+ _ensureSelection() { |
+ if (!this.treeOutline || !this.treeOutline._renderSelection) |
+ return; |
+ if (!this._selectionElement) |
+ this._selectionElement = createElementWithClass('div', 'selection fill'); |
+ this._listItemNode.insertBefore(this._selectionElement, this.listItemElement.firstChild); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _treeElementToggled(event) { |
+ var element = event.currentTarget; |
+ if (element.treeElement !== this || element.hasSelection()) |
+ return; |
+ |
+ var toggleOnClick = this.toggleOnClick && !this.selectable; |
+ var isInTriangle = this.isEventWithinDisclosureTriangle(event); |
+ if (!toggleOnClick && !isInTriangle) |
+ return; |
+ |
+ if (event.target && event.target.enclosingNodeOrSelfWithNodeName('a')) |
+ return; |
+ |
+ if (this.expanded) { |
+ if (event.altKey) |
+ this.collapseRecursively(); |
+ else |
+ this.collapse(); |
+ } else { |
+ if (event.altKey) |
+ this.expandRecursively(); |
+ else |
+ this.expand(); |
+ } |
+ event.consume(); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _handleMouseDown(event) { |
+ var element = event.currentTarget; |
+ if (!element) |
+ return; |
+ if (!this.selectable) |
+ return; |
+ if (element.treeElement !== this) |
+ return; |
+ |
+ if (this.isEventWithinDisclosureTriangle(event)) |
+ return; |
+ |
+ this.selectOnMouseDown(event); |
+ } |
+ |
+ /** |
+ * @param {!Event} event |
+ */ |
+ _handleDoubleClick(event) { |
+ var element = event.currentTarget; |
+ if (!element || element.treeElement !== this) |
+ return; |
+ |
+ var handled = this.ondblclick(event); |
+ if (handled) |
+ return; |
+ if (this._expandable && !this.expanded) |
+ this.expand(); |
+ } |
+ |
+ _detach() { |
+ this._listItemNode.remove(); |
+ this._childrenListNode.remove(); |
+ } |
+ |
+ collapse() { |
+ if (!this.expanded || !this._collapsible) |
+ return; |
+ this._listItemNode.classList.remove('expanded'); |
+ this._childrenListNode.classList.remove('expanded'); |
+ this.expanded = false; |
+ this.oncollapse(); |
+ if (this.treeOutline) |
+ this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementCollapsed, this); |
+ } |
+ |
+ collapseRecursively() { |
+ var item = this; |
+ while (item) { |
+ if (item.expanded) |
+ item.collapse(); |
+ item = item.traverseNextTreeElement(false, this, true); |
+ } |
+ } |
- onbind: function() |
- { |
- }, |
+ expand() { |
+ if (!this._expandable || (this.expanded && this._children)) |
+ return; |
- onunbind: function() |
- { |
- }, |
+ // Set this before onpopulate. Since onpopulate can add elements, this makes |
+ // sure the expanded flag is true before calling those functions. This prevents the possibility |
+ // of an infinite loop if onpopulate were to call expand. |
- onattach: function() |
- { |
- }, |
+ this.expanded = true; |
- onexpand: function() |
- { |
- }, |
+ this._populateIfNeeded(); |
+ this._listItemNode.classList.add('expanded'); |
+ this._childrenListNode.classList.add('expanded'); |
- oncollapse: function() |
- { |
- }, |
+ if (this.treeOutline) { |
+ this.onexpand(); |
+ this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementExpanded, this); |
+ } |
+ } |
+ |
+ /** |
+ * @param {number=} maxDepth |
+ */ |
+ expandRecursively(maxDepth) { |
+ var item = this; |
+ var info = {}; |
+ var depth = 0; |
+ |
+ // The Inspector uses TreeOutlines to represents object properties, so recursive expansion |
+ // in some case can be infinite, since JavaScript objects can hold circular references. |
+ // So default to a recursion cap of 3 levels, since that gives fairly good results. |
+ if (isNaN(maxDepth)) |
+ maxDepth = 3; |
+ |
+ while (item) { |
+ if (depth < maxDepth) |
+ item.expand(); |
+ item = item.traverseNextTreeElement(false, this, (depth >= maxDepth), info); |
+ depth += info.depthChange; |
+ } |
+ } |
+ |
+ /** |
+ * @param {boolean=} center |
+ */ |
+ reveal(center) { |
+ var currentAncestor = this.parent; |
+ while (currentAncestor && !currentAncestor.root) { |
+ if (!currentAncestor.expanded) |
+ currentAncestor.expand(); |
+ currentAncestor = currentAncestor.parent; |
+ } |
- /** |
- * @param {!Event} e |
- * @return {boolean} |
- */ |
- ondblclick: function(e) |
- { |
- return false; |
- }, |
+ this.treeOutline._deferredScrollIntoView(this, !!center); |
+ } |
- /** |
- * @param {boolean=} selectedByUser |
- * @return {boolean} |
- */ |
- onselect: function(selectedByUser) |
- { |
+ /** |
+ * @return {boolean} |
+ */ |
+ revealed() { |
+ var currentAncestor = this.parent; |
+ while (currentAncestor && !currentAncestor.root) { |
+ if (!currentAncestor.expanded) |
return false; |
- }, |
- |
- /** |
- * @param {boolean} skipUnrevealed |
- * @param {?TreeElement=} stayWithin |
- * @param {boolean=} dontPopulate |
- * @param {!Object=} info |
- * @return {?TreeElement} |
- */ |
- traverseNextTreeElement: function(skipUnrevealed, stayWithin, dontPopulate, info) |
- { |
- if (!dontPopulate) |
- this._populateIfNeeded(); |
- |
- if (info) |
- info.depthChange = 0; |
- |
- var element = skipUnrevealed ? (this.revealed() ? this.firstChild() : null) : this.firstChild(); |
- if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { |
- if (info) |
- info.depthChange = 1; |
- return element; |
- } |
- |
- if (this === stayWithin) |
- return null; |
- |
- element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling; |
- if (element) |
- return element; |
- |
- element = this; |
- while (element && !element.root && !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && element.parent !== stayWithin) { |
- if (info) |
- info.depthChange -= 1; |
- element = element.parent; |
- } |
- |
- if (!element || element.root) |
- return null; |
+ currentAncestor = currentAncestor.parent; |
+ } |
- return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling); |
- }, |
+ return true; |
+ } |
+ |
+ selectOnMouseDown(event) { |
+ if (this.select(false, true)) |
+ event.consume(true); |
+ } |
+ |
+ /** |
+ * @param {boolean=} omitFocus |
+ * @param {boolean=} selectedByUser |
+ * @return {boolean} |
+ */ |
+ select(omitFocus, selectedByUser) { |
+ if (!this.treeOutline || !this.selectable || this.selected) |
+ return false; |
+ |
+ if (this.treeOutline.selectedTreeElement) |
+ this.treeOutline.selectedTreeElement.deselect(); |
+ this.treeOutline.selectedTreeElement = null; |
+ |
+ if (this.treeOutline._rootElement === this) |
+ return false; |
+ |
+ this.selected = true; |
+ |
+ if (!omitFocus) |
+ this.treeOutline.focus(); |
+ |
+ // Focusing on another node may detach "this" from tree. |
+ if (!this.treeOutline) |
+ return false; |
+ this.treeOutline.selectedTreeElement = this; |
+ this._listItemNode.classList.add('selected'); |
+ this.treeOutline.dispatchEventToListeners(TreeOutline.Events.ElementSelected, this); |
+ return this.onselect(selectedByUser); |
+ } |
+ |
+ /** |
+ * @param {boolean=} omitFocus |
+ */ |
+ revealAndSelect(omitFocus) { |
+ this.reveal(true); |
+ this.select(omitFocus); |
+ } |
+ |
+ /** |
+ * @param {boolean=} supressOnDeselect |
+ */ |
+ deselect(supressOnDeselect) { |
+ if (!this.treeOutline || this.treeOutline.selectedTreeElement !== this || !this.selected) |
+ return; |
- /** |
- * @param {boolean} skipUnrevealed |
- * @param {boolean=} dontPopulate |
- * @return {?TreeElement} |
- */ |
- traversePreviousTreeElement: function(skipUnrevealed, dontPopulate) |
- { |
- var element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling; |
- if (!dontPopulate && element) |
- element._populateIfNeeded(); |
- |
- while (element && (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : element.lastChild())) { |
- if (!dontPopulate) |
- element._populateIfNeeded(); |
- element = (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : element.lastChild()); |
- } |
+ this.selected = false; |
+ this.treeOutline.selectedTreeElement = null; |
+ this._listItemNode.classList.remove('selected'); |
+ } |
+ |
+ _populateIfNeeded() { |
+ if (this.treeOutline && this._expandable && !this._children) { |
+ this._children = []; |
+ this.onpopulate(); |
+ } |
+ } |
+ |
+ onpopulate() { |
+ // Overridden by subclasses. |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ onenter() { |
+ return false; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ ondelete() { |
+ return false; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ onspace() { |
+ return false; |
+ } |
+ |
+ onbind() { |
+ } |
+ |
+ onunbind() { |
+ } |
+ |
+ onattach() { |
+ } |
+ |
+ onexpand() { |
+ } |
+ |
+ oncollapse() { |
+ } |
+ |
+ /** |
+ * @param {!Event} e |
+ * @return {boolean} |
+ */ |
+ ondblclick(e) { |
+ return false; |
+ } |
+ |
+ /** |
+ * @param {boolean=} selectedByUser |
+ * @return {boolean} |
+ */ |
+ onselect(selectedByUser) { |
+ return false; |
+ } |
+ |
+ /** |
+ * @param {boolean} skipUnrevealed |
+ * @param {?TreeElement=} stayWithin |
+ * @param {boolean=} dontPopulate |
+ * @param {!Object=} info |
+ * @return {?TreeElement} |
+ */ |
+ traverseNextTreeElement(skipUnrevealed, stayWithin, dontPopulate, info) { |
+ if (!dontPopulate) |
+ this._populateIfNeeded(); |
+ |
+ if (info) |
+ info.depthChange = 0; |
+ |
+ var element = skipUnrevealed ? (this.revealed() ? this.firstChild() : null) : this.firstChild(); |
+ if (element && (!skipUnrevealed || (skipUnrevealed && this.expanded))) { |
+ if (info) |
+ info.depthChange = 1; |
+ return element; |
+ } |
- if (element) |
- return element; |
+ if (this === stayWithin) |
+ return null; |
- if (!this.parent || this.parent.root) |
- return null; |
+ element = skipUnrevealed ? (this.revealed() ? this.nextSibling : null) : this.nextSibling; |
+ if (element) |
+ return element; |
- return this.parent; |
- }, |
+ element = this; |
+ while (element && !element.root && |
+ !(skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling) && |
+ element.parent !== stayWithin) { |
+ if (info) |
+ info.depthChange -= 1; |
+ element = element.parent; |
+ } |
- /** |
- * @return {boolean} |
- */ |
- isEventWithinDisclosureTriangle: function(event) |
- { |
- // FIXME: We should not use getComputedStyle(). For that we need to get rid of using ::before for disclosure triangle. (http://webk.it/74446) |
- var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLeft; |
- console.assert(paddingLeftValue.endsWith("px")); |
- var computedLeftPadding = parseFloat(paddingLeftValue); |
- var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
- return event.pageX >= left && event.pageX <= left + TreeElement._ArrowToggleWidth && this._expandable; |
+ if (!element || element.root) |
+ return null; |
+ |
+ return (skipUnrevealed ? (element.revealed() ? element.nextSibling : null) : element.nextSibling); |
+ } |
+ |
+ /** |
+ * @param {boolean} skipUnrevealed |
+ * @param {boolean=} dontPopulate |
+ * @return {?TreeElement} |
+ */ |
+ traversePreviousTreeElement(skipUnrevealed, dontPopulate) { |
+ var element = skipUnrevealed ? (this.revealed() ? this.previousSibling : null) : this.previousSibling; |
+ if (!dontPopulate && element) |
+ element._populateIfNeeded(); |
+ |
+ while (element && (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : |
+ element.lastChild())) { |
+ if (!dontPopulate) |
+ element._populateIfNeeded(); |
+ element = |
+ (skipUnrevealed ? (element.revealed() && element.expanded ? element.lastChild() : null) : |
+ element.lastChild()); |
} |
+ |
+ if (element) |
+ return element; |
+ |
+ if (!this.parent || this.parent.root) |
+ return null; |
+ |
+ return this.parent; |
+ } |
+ |
+ /** |
+ * @return {boolean} |
+ */ |
+ isEventWithinDisclosureTriangle(event) { |
+ // FIXME: We should not use getComputedStyle(). For that we need to get rid of using ::before for disclosure triangle. (http://webk.it/74446) |
+ var paddingLeftValue = window.getComputedStyle(this._listItemNode).paddingLeft; |
+ console.assert(paddingLeftValue.endsWith('px')); |
+ var computedLeftPadding = parseFloat(paddingLeftValue); |
+ var left = this._listItemNode.totalOffsetLeft() + computedLeftPadding; |
+ return event.pageX >= left && event.pageX <= left + TreeElement._ArrowToggleWidth && this._expandable; |
+ } |
}; |
+ |
+/** @const */ |
+TreeElement._ArrowToggleWidth = 10; |