X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fthird_party%2FWebKit%2FSource%2Fdevtools%2Ffront_end%2Felements%2FElementsTreeOutline.js;h=b88807cf6312acf53b5cf20a46b72dda86104c65;hb=1afa4dd80ef85af7c90efaea6959db1d92330844;hp=0a4be13134291204b92d106da50177524b65cc87;hpb=90762837333c13ccf56f2ad88e4481fc71e8d281;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js b/src/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js index 0a4be13..b88807c 100644 --- a/src/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js +++ b/src/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeOutline.js @@ -40,21 +40,28 @@ WebInspector.ElementsTreeOutline = function(target, omitRootDOMNode, selectEnabl { this._target = target; this._domModel = target.domModel; - this.element = document.createElement("ol"); - this.element.className = "elements-tree-outline"; - this.element.addEventListener("mousedown", this._onmousedown.bind(this), false); - this.element.addEventListener("mousemove", this._onmousemove.bind(this), false); - this.element.addEventListener("mouseout", this._onmouseout.bind(this), false); - this.element.addEventListener("dragstart", this._ondragstart.bind(this), false); - this.element.addEventListener("dragover", this._ondragover.bind(this), false); - this.element.addEventListener("dragleave", this._ondragleave.bind(this), false); - this.element.addEventListener("drop", this._ondrop.bind(this), false); - this.element.addEventListener("dragend", this._ondragend.bind(this), false); - this.element.addEventListener("keydown", this._onkeydown.bind(this), false); - this.element.addEventListener("webkitAnimationEnd", this._onAnimationEnd.bind(this), false); - this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), false); - - TreeOutline.call(this, this.element); + var element = createElement("div"); + + this._shadowRoot = element.createShadowRoot(); + this._shadowRoot.appendChild(WebInspector.View.createStyleElement("elements/elementsTreeOutline.css")); + + var outlineDisclosureElement = this._shadowRoot.createChild("div", "outline-disclosure"); + WebInspector.installComponentRootStyles(outlineDisclosureElement); + this._element = outlineDisclosureElement.createChild("ol", "elements-tree-outline source-code"); + this._element.addEventListener("mousedown", this._onmousedown.bind(this), false); + this._element.addEventListener("mousemove", this._onmousemove.bind(this), false); + this._element.addEventListener("mouseleave", this._onmouseleave.bind(this), false); + this._element.addEventListener("dragstart", this._ondragstart.bind(this), false); + this._element.addEventListener("dragover", this._ondragover.bind(this), false); + this._element.addEventListener("dragleave", this._ondragleave.bind(this), false); + this._element.addEventListener("drop", this._ondrop.bind(this), false); + this._element.addEventListener("dragend", this._ondragend.bind(this), false); + this._element.addEventListener("keydown", this._onkeydown.bind(this), false); + this._element.addEventListener("webkitAnimationEnd", this._onAnimationEnd.bind(this), false); + this._element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), false); + + TreeOutline.call(this, this._element); + this.element = element; this._includeRootDOMNode = !omitRootDOMNode; this._selectEnabled = selectEnabled; @@ -69,6 +76,9 @@ WebInspector.ElementsTreeOutline = function(target, omitRootDOMNode, selectEnabl this._setPseudoClassCallback = setPseudoClassCallback; this._createNodeDecorators(); + + this._popoverHelper = new WebInspector.PopoverHelper(this._element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this)); + this._popoverHelper.setTimeout(0); } /** @typedef {{node: !WebInspector.DOMNode, isCut: boolean}} */ @@ -107,6 +117,14 @@ WebInspector.ElementsTreeOutline.MappedCharToEntity = { WebInspector.ElementsTreeOutline.prototype = { /** + * @param {boolean} wrap + */ + setWordWrap: function(wrap) + { + this._element.classList.toggle("nowrap", !wrap); + }, + + /** * @param {!Event} event */ _onAnimationEnd: function(event) @@ -121,7 +139,7 @@ WebInspector.ElementsTreeOutline.prototype = { setPickNodeMode: function(value) { this._pickNodeMode = value; - this.element.classList.toggle("pick-node-mode", value); + this._element.classList.toggle("pick-node-mode", value); }, /** @@ -131,14 +149,14 @@ WebInspector.ElementsTreeOutline.prototype = { _handlePickNode: function(element, node) { if (!this._pickNodeMode) - return true; + return false; this._eventSupport.dispatchEventToListeners(WebInspector.ElementsTreeOutline.Events.NodePicked, node); var hasRunningAnimation = element.classList.contains("elements-tree-element-pick-node-1") || element.classList.contains("elements-tree-element-pick-node-2"); element.classList.toggle("elements-tree-element-pick-node-1"); if (hasRunningAnimation) element.classList.toggle("elements-tree-element-pick-node-2"); - return false; + return true; }, /** @@ -226,8 +244,7 @@ WebInspector.ElementsTreeOutline.prototype = { return; // Do not interfere with text editing. - var currentFocusElement = WebInspector.currentFocusElement(); - if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement)) + if (WebInspector.isEditing()) return; var targetNode = this.selectedDOMNode(); @@ -289,8 +306,7 @@ WebInspector.ElementsTreeOutline.prototype = { handlePasteKeyboardEvent: function(event) { // Do not interfere with text editing. - var currentFocusElement = WebInspector.currentFocusElement(); - if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement)) + if (WebInspector.isEditing()) return; var targetNode = this.selectedDOMNode(); @@ -335,8 +351,10 @@ WebInspector.ElementsTreeOutline.prototype = { setVisible: function(visible) { this._visible = visible; - if (!this._visible) + if (!this._visible) { + this._popoverHelper.hidePopover(); return; + } this._updateModifiedNodes(); if (this._selectedDOMNode) @@ -575,6 +593,77 @@ WebInspector.ElementsTreeOutline.prototype = { return element; }, + /** + * @param {!Element} element + * @param {!Event} event + * @return {!Element|!AnchorBox|undefined} + */ + _getPopoverAnchor: function(element, event) + { + var anchor = element.enclosingNodeOrSelfWithClass("webkit-html-resource-link"); + if (!anchor || !anchor.href) + return; + + return anchor; + }, + + /** + * @param {!WebInspector.DOMNode} node + * @param {function()} callback + */ + _loadDimensionsForNode: function(node, callback) + { + if (!node.nodeName() || node.nodeName().toLowerCase() !== "img") { + callback(); + return; + } + + node.resolveToObject("", resolvedNode); + + function resolvedNode(object) + { + if (!object) { + callback(); + return; + } + + object.callFunctionJSON(dimensions, undefined, callback); + object.release(); + + /** + * @return {!{offsetWidth: number, offsetHeight: number, naturalWidth: number, naturalHeight: number}} + * @suppressReceiverCheck + * @this {!Element} + */ + function dimensions() + { + return { offsetWidth: this.offsetWidth, offsetHeight: this.offsetHeight, naturalWidth: this.naturalWidth, naturalHeight: this.naturalHeight }; + } + } + }, + + /** + * @param {!Element} anchor + * @param {!WebInspector.Popover} popover + */ + _showPopover: function(anchor, popover) + { + var listItem = anchor.enclosingNodeOrSelfWithNodeName("li"); + var node = /** @type {!WebInspector.ElementsTreeElement} */ (listItem.treeElement).node(); + this._loadDimensionsForNode(node, WebInspector.DOMPresentationUtils.buildImagePreviewContents.bind(WebInspector.DOMPresentationUtils, node.target(), anchor.href, true, showPopover)); + + /** + * @param {!Element=} contents + */ + function showPopover(contents) + { + if (!contents) + return; + popover.setCanShrink(false); + popover.show(contents, anchor); + } + }, + _onmousedown: function(event) { var element = this._treeElementFromEvent(event); @@ -607,12 +696,8 @@ WebInspector.ElementsTreeOutline.prototype = { this._domModel.hideDOMNodeHighlight(); }, - _onmouseout: function(event) + _onmouseleave: function(event) { - var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); - if (nodeUnderMouse && nodeUnderMouse.isDescendant(this.element)) - return; - if (this._previousHoveredElement) { this._previousHoveredElement.hovered = false; delete this._previousHoveredElement; @@ -629,9 +714,6 @@ WebInspector.ElementsTreeOutline.prototype = { return false; var treeElement = this._treeElementFromEvent(event); - if (!treeElement) - return false; - if (!this._isValidDragSourceOrTarget(treeElement)) return false; @@ -687,10 +769,11 @@ WebInspector.ElementsTreeOutline.prototype = { if (!treeElement) return false; - var node = treeElement.representedObject; - if (!(node instanceof WebInspector.DOMNode)) + if (!(treeElement instanceof WebInspector.ElementsTreeElement)) return false; + var elementsTreeElement = /** @type {!WebInspector.ElementsTreeElement} */ (treeElement); + var node = elementsTreeElement._node; if (!node.parentNode || node.parentNode.nodeType() !== Node.ELEMENT_NODE) return false; @@ -773,7 +856,6 @@ WebInspector.ElementsTreeOutline.prototype = { return; var contextMenu = new WebInspector.ContextMenu(event); - var isPseudoElement = !!treeElement._node.pseudoType(); var isTag = treeElement._node.nodeType() === Node.ELEMENT_NODE && !isPseudoElement; var textNode = event.target.enclosingNodeOrSelfWithClass("webkit-html-text-node"); @@ -896,6 +978,7 @@ WebInspector.ElementsTreeOutline.prototype = { /** * @param {?string} pseudoType + * @suppressGlobalPropertiesCheck * @suppressReceiverCheck * @this {!Element} */ @@ -904,7 +987,14 @@ WebInspector.ElementsTreeOutline.prototype = { const classNamePrefix = "__web-inspector-hide"; const classNameSuffix = "-shortcut__"; const styleTagId = "__web-inspector-hide-shortcut-style__"; - const styleRules = ".__web-inspector-hide-shortcut__, .__web-inspector-hide-shortcut__ * { visibility: hidden !important; } .__web-inspector-hidebefore-shortcut__::before { visibility: hidden !important; } .__web-inspector-hideafter-shortcut__::after { visibility: hidden !important; }"; + var selectors = []; + selectors.push("html /deep/ .__web-inspector-hide-shortcut__"); + selectors.push("html /deep/ .__web-inspector-hide-shortcut__ /deep/ *"); + selectors.push("html /deep/ .__web-inspector-hidebefore-shortcut__::before"); + selectors.push("html /deep/ .__web-inspector-hideafter-shortcut__::after"); + var selector = selectors.join(", "); + var ruleBody = " visibility: hidden !important;"; + var rule = "\n" + selector + "\n{\n" + ruleBody + "\n}\n"; var className = classNamePrefix + (pseudoType || "") + classNameSuffix; this.classList.toggle(className); @@ -916,7 +1006,7 @@ WebInspector.ElementsTreeOutline.prototype = { style = document.createElement("style"); style.id = styleTagId; style.type = "text/css"; - style.textContent = styleRules; + style.textContent = rule; document.head.appendChild(style); } @@ -1010,7 +1100,7 @@ WebInspector.ElementsTreeElement = function(node, elementCloseTag) this._node = node; this._elementCloseTag = elementCloseTag; - this._updateHasChildren(); + this._updateChildrenDisplayMode(); if (this._node.nodeType() == Node.ELEMENT_NODE && !elementCloseTag) this._canAddAttributes = true; @@ -1032,7 +1122,25 @@ WebInspector.ElementsTreeElement.EditTagBlacklist = [ "html", "head", "body" ].keySet(); +/** @enum {number} */ +WebInspector.ElementsTreeElement.ChildrenDisplayMode = { + NoChildren: 0, + InlineText: 1, + HasChildren: 2 +} + WebInspector.ElementsTreeElement.prototype = { + /** + * @return {!WebInspector.DOMNode} + */ + node: function() + { + return this._node; + }, + + /** + * @param {string} searchQuery + */ highlightSearchResults: function(searchQuery) { if (this._searchQuery !== searchQuery) { @@ -1051,6 +1159,9 @@ WebInspector.ElementsTreeElement.prototype = { this._updateSearchHighlight(false); }, + /** + * @param {boolean} show + */ _updateSearchHighlight: function(show) { if (!this._highlightResult) @@ -1135,7 +1246,7 @@ WebInspector.ElementsTreeElement.prototype = { this._expandedChildrenLimit = x; if (this.treeOutline && !this._updateChildrenInProgress) - this._updateChildren(true); + this._updateChildren(true, this.children); }, get expandedChildCount() @@ -1163,7 +1274,7 @@ WebInspector.ElementsTreeElement.prototype = { if (index >= this.expandedChildrenLimit) { this._expandedChildrenLimit = index + 1; - this._updateChildren(true); + this._updateChildren(true, this.children); } // Whether index-th child is visible in the children tree @@ -1177,7 +1288,7 @@ WebInspector.ElementsTreeElement.prototype = { return; if (!this._readyToUpdateSelection) { - if (document.body.offsetWidth > 0) + if (listItemElement.ownerDocument.body.offsetWidth > 0) this._readyToUpdateSelection = true; else { // The stylesheet hasn't loaded yet or the window is closed, @@ -1187,7 +1298,7 @@ WebInspector.ElementsTreeElement.prototype = { } if (!this.selectionElement) { - this.selectionElement = document.createElement("div"); + this.selectionElement = createElement("div"); this.selectionElement.className = "selection selected"; listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild); } @@ -1220,7 +1331,7 @@ WebInspector.ElementsTreeElement.prototype = { onpopulate: function() { this.populated = true; - if (this.children.length || !this.hasChildren) + if (this.children.length || !this._hasChildTreeElements()) return; this.updateChildren(); @@ -1231,10 +1342,10 @@ WebInspector.ElementsTreeElement.prototype = { */ updateChildren: function(fullRefresh) { - if (!this.hasChildren) + if (!this._hasChildTreeElements()) return; console.assert(!this._elementCloseTag); - this._node.getChildNodes(this._updateChildren.bind(this, fullRefresh)); + this._node.getChildNodes(this._updateChildren.bind(this, fullRefresh || false)); }, /** @@ -1261,11 +1372,12 @@ WebInspector.ElementsTreeElement.prototype = { }, /** - * @param {boolean=} fullRefresh + * @param {boolean} fullRefresh + * @param {?Array.} children */ - _updateChildren: function(fullRefresh) + _updateChildren: function(fullRefresh, children) { - if (this._updateChildrenInProgress || !this.treeOutline._visible) + if (!children || this._updateChildrenInProgress || !this.treeOutline._visible) return; this._updateChildrenInProgress = true; @@ -1280,74 +1392,50 @@ WebInspector.ElementsTreeElement.prototype = { this.removeChildren(); } - /** - * @this {WebInspector.ElementsTreeElement} - * @return {?WebInspector.ElementsTreeElement} - */ - function updateChildrenOfNode() - { - var treeOutline = this.treeOutline; - var visibleChildren = this._visibleChildren(); - var treeChildIndex = 0; - var elementToSelect = null; - - for (var i = 0; i < visibleChildren.length; ++i) { - var child = visibleChildren[i]; - var currentTreeElement = this.children[treeChildIndex]; - if (!currentTreeElement || currentTreeElement._node !== child) { - // Find any existing element that is later in the children list. - var existingTreeElement = null; - for (var j = (treeChildIndex + 1), size = this.expandedChildCount; j < size; ++j) { - if (this.children[j]._node === child) { - existingTreeElement = this.children[j]; - break; - } - } - - if (existingTreeElement && existingTreeElement.parent === this) { - // If an existing element was found and it has the same parent, just move it. - this.moveChild(existingTreeElement, treeChildIndex); - } else { - // No existing element found, insert a new element. - if (treeChildIndex < this.expandedChildrenLimit) { - var newElement = this.insertChildElement(child, treeChildIndex); - if (child === selectedNode) - elementToSelect = newElement; - if (this.expandedChildCount > this.expandedChildrenLimit) - this.expandedChildrenLimit++; - } - } - } - - ++treeChildIndex; - } - return elementToSelect; - } - - // Remove any tree elements that no longer have this node (or this node's contentDocument) as their parent. - for (var i = (this.children.length - 1); i >= 0; --i) { - var currentChild = this.children[i]; - var currentNode = currentChild._node; - if (!currentNode) + // Remove any tree elements that no longer have this node as their parent and save + // all existing elements that could be reused. This also removes closing tag element. + var existingTreeElements = new Map(); + for (var i = this.children.length - 1; i >= 0; --i) { + var existingTreeElement = this.children[i]; + var existingNode = existingTreeElement._node; + // Skip expand all button. + if (!existingNode) continue; - var currentParentNode = currentNode.parentNode; - if (currentParentNode === this._node) + if (existingNode.parentNode === this._node) { + existingTreeElements.set(existingNode, existingTreeElement); continue; + } var selectedTreeElement = this.treeOutline.selectedTreeElement; - if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild))) + if (selectedTreeElement && (selectedTreeElement === existingTreeElement || selectedTreeElement.hasAncestor(existingTreeElement))) this.select(); this.removeChildAtIndex(i); } - var elementToSelect = updateChildrenOfNode.call(this); + var elementToSelect; + var visibleChildren = this._visibleChildren(); + for (var i = 0; i < visibleChildren.length && i < this.expandedChildrenLimit; ++i) { + var child = visibleChildren[i]; + if (existingTreeElements.has(child)) { + // If an existing element was found, just move it. + this.moveChild(existingTreeElements.get(child), i); + } else { + // No existing element found, insert a new element. + var newElement = this.insertChildElement(child, i); + if (child === selectedNode) + elementToSelect = newElement; + // If a node was inserted in the middle of existing list dynamically we might need to increase the limit. + if (this.expandedChildCount > this.expandedChildrenLimit) + this.expandedChildrenLimit++; + } + } + this.updateTitle(); this._adjustCollapsedRange(); - var lastChild = this.children[this.children.length - 1]; - if (this._node.nodeType() === Node.ELEMENT_NODE && this.hasChildren) + if (this._node.nodeType() === Node.ELEMENT_NODE && this._hasChildTreeElements()) this.insertChildElement(this._node, this.children.length, true); // We want to restore the original selection and tree scroll position after a full refresh, if possible. @@ -1365,8 +1453,8 @@ WebInspector.ElementsTreeElement.prototype = { var visibleChildren = this._visibleChildren(); // Ensure precondition: only the tree elements for node children are found in the tree // (not the Expand All button or the closing tag). - if (this.expandAllButtonElement && this.expandAllButtonElement.__treeElement.parent) - this.removeChild(this.expandAllButtonElement.__treeElement); + if (this.expandAllButtonElement && this.expandAllButtonElement.parent) + this.removeChild(this.expandAllButtonElement); const childNodeCount = visibleChildren.length; @@ -1378,19 +1466,18 @@ WebInspector.ElementsTreeElement.prototype = { if (childNodeCount > this.expandedChildCount) { var targetButtonIndex = expandedChildCount; if (!this.expandAllButtonElement) { - var button = document.createElement("button"); + var button = createElement("button"); button.className = "text-button"; button.value = ""; - var item = new TreeElement(button, null, false); - item.selectable = false; - item.expandAllButton = true; - this.insertChild(item, targetButtonIndex); - this.expandAllButtonElement = item.listItemElement.firstChild; - this.expandAllButtonElement.__treeElement = item; - this.expandAllButtonElement.addEventListener("click", this.handleLoadAllChildren.bind(this), false); - } else if (!this.expandAllButtonElement.__treeElement.parent) - this.insertChild(this.expandAllButtonElement.__treeElement, targetButtonIndex); - this.expandAllButtonElement.textContent = WebInspector.UIString("Show All Nodes (%d More)", childNodeCount - expandedChildCount); + button.addEventListener("click", this.handleLoadAllChildren.bind(this), false); + this.expandAllButtonElement = new TreeElement(button, null, false); + this.expandAllButtonElement.selectable = false; + this.expandAllButtonElement.expandAllButton = true; + this.expandAllButtonElement._button = button; + this.insertChild(this.expandAllButtonElement, targetButtonIndex); + } else if (!this.expandAllButtonElement.parent) + this.insertChild(this.expandAllButtonElement, targetButtonIndex); + this.expandAllButtonElement._button.textContent = WebInspector.UIString("Show All Nodes (%d More)", childNodeCount - expandedChildCount); } else if (this.expandAllButtonElement) delete this.expandAllButtonElement; }, @@ -1455,8 +1542,10 @@ WebInspector.ElementsTreeElement.prototype = { */ select: function(omitFocus, selectedByUser) { - if (!this.treeOutline._handlePickNode(this.title, this._node)) + if (this._editing) return false; + if (this.treeOutline._handlePickNode(this.title, this._node)) + return true; return TreeElement.prototype.select.call(this, omitFocus, selectedByUser); }, @@ -1512,7 +1601,8 @@ WebInspector.ElementsTreeElement.prototype = { return; if (this.treeOutline._showInElementsPanelEnabled) { - WebInspector.inspectorView.showPanel("elements"); + var panel = WebInspector.ElementsPanel.instance(); + WebInspector.inspectorView.setCurrentPanel(panel); this.treeOutline.selectDOMNode(this._node, true); } @@ -1533,7 +1623,7 @@ WebInspector.ElementsTreeElement.prototype = { if (this._startEditingTarget(/** @type {!Element} */(event.target))) return false; - if (this.hasChildren && !this.expanded) + if (this._hasChildTreeElements() && !this.expanded) this.expand(); return false; }, @@ -1543,7 +1633,7 @@ WebInspector.ElementsTreeElement.prototype = { */ hasEditableNode: function() { - return !this.representedObject.isShadowRoot() && !this.representedObject.ancestorUserAgentShadowRoot(); + return !this._node.isShadowRoot() && !this._node.ancestorUserAgentShadowRoot(); }, _insertInLastAttributePosition: function(tag, node) @@ -1649,26 +1739,28 @@ WebInspector.ElementsTreeElement.prototype = { _populateNodeContextMenu: function(contextMenu) { // Add free-form node-related actions. - var openTagElement = this.treeOutline.getCachedTreeElement(this.representedObject) || this; + var openTagElement = this.treeOutline.getCachedTreeElement(this._node) || this; var isEditable = this.hasEditableNode(); if (isEditable && !this._editing) contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), openTagElement._editAsHTML.bind(openTagElement)); - var isShadowRoot = this.representedObject.isShadowRoot(); + var isShadowRoot = this._node.isShadowRoot(); // Place it here so that all "Copy"-ing items stick together. - if (this.representedObject.nodeType() === Node.ELEMENT_NODE) + if (this._node.nodeType() === Node.ELEMENT_NODE) contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Copy CSS path" : "Copy CSS Path"), this._copyCSSPath.bind(this)); if (!isShadowRoot) contextMenu.appendItem(WebInspector.UIString("Copy XPath"), this._copyXPath.bind(this)); if (!isShadowRoot) { var treeOutline = this.treeOutline; - contextMenu.appendItem(WebInspector.UIString("Copy"), treeOutline._performCopyOrCut.bind(treeOutline, false, this.representedObject)); - contextMenu.appendItem(WebInspector.UIString("Cut"), treeOutline._performCopyOrCut.bind(treeOutline, true, this.representedObject), !this.hasEditableNode()); - contextMenu.appendItem(WebInspector.UIString("Paste"), treeOutline._pasteNode.bind(treeOutline, this.representedObject), !treeOutline._canPaste(this.representedObject)); + contextMenu.appendSeparator(); + contextMenu.appendItem(WebInspector.UIString("Cut"), treeOutline._performCopyOrCut.bind(treeOutline, true, this._node), !this.hasEditableNode()); + contextMenu.appendItem(WebInspector.UIString("Copy"), treeOutline._performCopyOrCut.bind(treeOutline, false, this._node)); + contextMenu.appendItem(WebInspector.UIString("Paste"), treeOutline._pasteNode.bind(treeOutline, this._node), !treeOutline._canPaste(this._node)); } if (isEditable) - contextMenu.appendItem(WebInspector.UIString(WebInspector.useLowerCaseMenuTitles() ? "Delete node" : "Delete Node"), this.remove.bind(this)); + contextMenu.appendItem(WebInspector.UIString("Delete"), this.remove.bind(this)); + contextMenu.appendSeparator(); }, _startEditing: function() @@ -1698,7 +1790,7 @@ WebInspector.ElementsTreeElement.prototype = { { // Cannot just convert the textual html into an element without // a parent node. Use a temporary span container for the HTML. - var container = document.createElement("span"); + var container = createElement("span"); this._buildAttributeDOM(container, " ", ""); var attr = container.firstElementChild; attr.style.marginLeft = "2px"; // overrides the .editing margin rule @@ -1728,6 +1820,8 @@ WebInspector.ElementsTreeElement.prototype = { _startEditingAttribute: function(attribute, elementForSelection) { + console.assert(this.listItemElement.isAncestor(attribute)); + if (WebInspector.isBeingEdited(attribute)) return true; @@ -1752,12 +1846,8 @@ WebInspector.ElementsTreeElement.prototype = { removeZeroWidthSpaceRecursive(child); } - var domNode; - var listItemElement = attribute.enclosingNodeOrSelfWithNodeName("li"); - if (attributeName && attributeValueElement && listItemElement && listItemElement.treeElement) - domNode = listItemElement.treeElement.representedObject; - var attributeValue = domNode ? domNode.getAttribute(attributeName) : undefined; - if (typeof attributeValue !== "undefined") + var attributeValue = attributeName && attributeValueElement ? this._node.getAttribute(attributeName) : undefined; + if (attributeValue !== undefined) attributeValueElement.textContent = attributeValue; // Remove zero-width spaces that were added by nodeTitleInfo. @@ -1892,7 +1982,7 @@ WebInspector.ElementsTreeElement.prototype = { initialValue = this._convertWhitespaceToEntities(initialValue).text; - this._htmlEditElement = document.createElement("div"); + this._htmlEditElement = createElement("div"); this._htmlEditElement.className = "source-code elements-tree-editor"; // Hide header items. @@ -1944,14 +2034,23 @@ WebInspector.ElementsTreeElement.prototype = { this.treeOutline.childrenListElement.parentElement.removeEventListener("mousedown", consume, false); this.updateSelection(); - this.treeOutline.element.focus(); + this.treeOutline._element.focus(); } var config = new WebInspector.InplaceEditor.Config(commit.bind(this), dispose.bind(this)); config.setMultilineOptions(initialValue, { name: "xml", htmlMode: true }, "web-inspector-html", WebInspector.settings.domWordWrap.get(), true); - this._editing = WebInspector.InplaceEditor.startEditing(this._htmlEditElement, config); - this._editing.setWidth(this.treeOutline._visibleWidth); - this.treeOutline._multilineEditing = this._editing; + WebInspector.InplaceEditor.startMultilineEditing(this._htmlEditElement, config).then(markAsBeingEdited.bind(this)).done(); + + /** + * @param {!Object} controller + * @this {WebInspector.ElementsTreeElement} + */ + function markAsBeingEdited(controller) + { + this._editing = /** @type {!WebInspector.InplaceEditor.Controller} */ (controller); + this._editing.setWidth(this.treeOutline._visibleWidth); + this.treeOutline._multilineEditing = this._editing; + } }, _attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection) @@ -2146,7 +2245,7 @@ WebInspector.ElementsTreeElement.prototype = { var nodeInfo = this._nodeTitleInfo(WebInspector.linkifyURLAsNode); if (nodeInfo.shadowRoot) this.listItemElement.classList.add("shadow-root"); - var highlightElement = document.createElement("span"); + var highlightElement = createElement("span"); highlightElement.className = "highlight"; highlightElement.appendChild(nodeInfo.titleDOM); this.title = highlightElement; @@ -2187,7 +2286,7 @@ WebInspector.ElementsTreeElement.prototype = { if (!decoratorMessages.length && !parentDecoratorMessages.length) return null; - var decoratorElement = document.createElement("div"); + var decoratorElement = createElement("div"); decoratorElement.classList.add("elements-gutter-decoration"); if (!decoratorMessages.length) decoratorElement.classList.add("elements-has-decorated-children"); @@ -2271,14 +2370,16 @@ WebInspector.ElementsTreeElement.prototype = { { var rewrittenHref = node.resolveURL(value); if (rewrittenHref === null) { - var span = document.createElement("span"); + var span = createElement("span"); setValueWithEntities.call(this, span, value); return span; } value = value.replace(closingPunctuationRegex, "$&\u200B"); if (value.startsWith("data:")) value = value.trimMiddle(60); - return linkify(rewrittenHref, value, "", node.nodeName().toLowerCase() === "a"); + var anchor = linkify(rewrittenHref, value, "", node.nodeName().toLowerCase() === "a"); + anchor.preventFollow = true; + return anchor; } if (linkify && (name === "src" || name === "href")) { @@ -2375,7 +2476,7 @@ WebInspector.ElementsTreeElement.prototype = { _nodeTitleInfo: function(linkify) { var node = this._node; - var info = {titleDOM: document.createDocumentFragment(), hasChildren: this.hasChildren}; + var info = {titleDOM: createDocumentFragment(), hasChildren: this._hasChildTreeElements()}; switch (node.nodeType()) { case Node.ATTRIBUTE_NODE: @@ -2399,28 +2500,30 @@ WebInspector.ElementsTreeElement.prototype = { this._buildTagDOM(info.titleDOM, tagName, false, false, linkify); - var showInlineText = this._showInlineText() && !this.hasChildren; - if (!this.expanded && !showInlineText && (this.treeOutline.isXMLMimeType || !WebInspector.ElementsTreeElement.ForbiddenClosingTagElements[tagName])) { - if (this.hasChildren) { + switch (this._childrenDisplayMode) { + case WebInspector.ElementsTreeElement.ChildrenDisplayMode.HasChildren: + if (!this.expanded) { var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node bogus"); textNodeElement.textContent = "\u2026"; info.titleDOM.createTextChild("\u200B"); + this._buildTagDOM(info.titleDOM, tagName, true, false); } - this._buildTagDOM(info.titleDOM, tagName, true, false); - } + break; - // If this element only has a single child that is a text node, - // just show that text and the closing tag inline rather than - // create a subtree for them - if (showInlineText) { - console.assert(!this.hasChildren); + case WebInspector.ElementsTreeElement.ChildrenDisplayMode.InlineText: var textNodeElement = info.titleDOM.createChild("span", "webkit-html-text-node"); var result = this._convertWhitespaceToEntities(node.firstChild.nodeValue()); textNodeElement.textContent = result.text; WebInspector.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, "webkit-html-entity-value"); info.titleDOM.createTextChild("\u200B"); - this._buildTagDOM(info.titleDOM, tagName, true, false); info.hasChildren = false; + this._buildTagDOM(info.titleDOM, tagName, true, false); + break; + + case WebInspector.ElementsTreeElement.ChildrenDisplayMode.NoChildren: + if (this.treeOutline.isXMLMimeType || !WebInspector.ElementsTreeElement.ForbiddenClosingTagElements[tagName]) + this._buildTagDOM(info.titleDOM, tagName, true, false); + break; } break; @@ -2489,24 +2592,6 @@ WebInspector.ElementsTreeElement.prototype = { return info; }, - /** - * @return {boolean} - */ - _showInlineText: function() - { - if (this._node.importedDocument() || this._node.templateContent() || this._visibleShadowRoots().length > 0 || this._node.hasPseudoElements()) - return false; - if (this._node.nodeType() !== Node.ELEMENT_NODE) - return false; - if (!this._node.firstChild || this._node.firstChild !== this._node.lastChild || this._node.firstChild.nodeType() !== Node.TEXT_NODE) - return false; - var textChild = this._node.firstChild; - var maxInlineTextChildLength = 80; - if (textChild.nodeValue().length < maxInlineTextChildLength) - return true; - return false; - }, - remove: function() { if (this._node.pseudoType()) @@ -2685,9 +2770,45 @@ WebInspector.ElementsTreeElement.prototype = { return childCount; }, - _updateHasChildren: function() + /** + * @return {boolean} + */ + _hasChildTreeElements: function() + { + return this._childrenDisplayMode === WebInspector.ElementsTreeElement.ChildrenDisplayMode.HasChildren; + }, + + /** + * @return {boolean} + */ + _canShowInlineText: function() + { + if (this._node.importedDocument() || this._node.templateContent() || this._visibleShadowRoots().length > 0 || this._node.hasPseudoElements()) + return false; + if (this._node.nodeType() !== Node.ELEMENT_NODE) + return false; + if (!this._node.firstChild || this._node.firstChild !== this._node.lastChild || this._node.firstChild.nodeType() !== Node.TEXT_NODE) + return false; + var textChild = this._node.firstChild; + var maxInlineTextChildLength = 80; + if (textChild.nodeValue().length < maxInlineTextChildLength) + return true; + return false; + }, + + _updateChildrenDisplayMode: function() { - this.hasChildren = !this._elementCloseTag && !this._showInlineText() && this._visibleChildCount() > 0; + var showInlineText = this._canShowInlineText(); + var hasChildren = !this._elementCloseTag && this._visibleChildCount() > 0; + + if (showInlineText) + this._childrenDisplayMode = WebInspector.ElementsTreeElement.ChildrenDisplayMode.InlineText; + else if (hasChildren) + this._childrenDisplayMode = WebInspector.ElementsTreeElement.ChildrenDisplayMode.HasChildren; + else + this._childrenDisplayMode = WebInspector.ElementsTreeElement.ChildrenDisplayMode.NoChildren; + + this.setHasChildren(this._childrenDisplayMode === WebInspector.ElementsTreeElement.ChildrenDisplayMode.HasChildren); }, __proto__: TreeElement.prototype @@ -2739,10 +2860,9 @@ WebInspector.ElementsTreeUpdater.prototype = { var treeElement = this._treeOutline.findTreeElement(parentNode); if (treeElement) { - var oldHasChildren = treeElement.hasChildren; - var oldShowInlineText = treeElement._showInlineText(); - treeElement._updateHasChildren(); - if (treeElement.hasChildren !== oldHasChildren || oldShowInlineText || treeElement._showInlineText()) + var oldDisplayMode = treeElement._childrenDisplayMode; + treeElement._updateChildrenDisplayMode(); + if (treeElement._childrenDisplayMode !== oldDisplayMode) this._nodeModified(parentNode); } @@ -2837,26 +2957,26 @@ WebInspector.ElementsTreeUpdater.prototype = { delete this._updateModifiedNodesTimeout; } - var updatedNodes = this._recentlyModifiedNodes.values().concat(this._recentlyModifiedParentNodes.values()); + var updatedNodes = this._recentlyModifiedNodes.valuesArray().concat(this._recentlyModifiedParentNodes.valuesArray()); var hidePanelWhileUpdating = updatedNodes.length > 10; if (hidePanelWhileUpdating) { var treeOutlineContainerElement = this._treeOutline.element.parentNode; var originalScrollTop = treeOutlineContainerElement ? treeOutlineContainerElement.scrollTop : 0; - this._treeOutline.element.classList.add("hidden"); + this._treeOutline._element.classList.add("hidden"); } - if (this._treeOutline._rootDOMNode && this._recentlyModifiedParentNodes.contains(this._treeOutline._rootDOMNode)) { + if (this._treeOutline._rootDOMNode && this._recentlyModifiedParentNodes.has(this._treeOutline._rootDOMNode)) { // Document's children have changed, perform total update. this._treeOutline.update(); } else { - var nodes = this._recentlyModifiedNodes.values(); + var nodes = this._recentlyModifiedNodes.valuesArray(); for (var i = 0, size = nodes.length; i < size; ++i) { var nodeItem = this._treeOutline.findTreeElement(nodes[i]); if (nodeItem) nodeItem.updateTitle(); } - var parentNodes = this._recentlyModifiedParentNodes.values(); + var parentNodes = this._recentlyModifiedParentNodes.valuesArray(); for (var i = 0, size = parentNodes.length; i < size; ++i) { var parentNodeItem = this._treeOutline.findTreeElement(parentNodes[i]); if (parentNodeItem && parentNodeItem.populated) @@ -2865,7 +2985,7 @@ WebInspector.ElementsTreeUpdater.prototype = { } if (hidePanelWhileUpdating) { - this._treeOutline.element.classList.remove("hidden"); + this._treeOutline._element.classList.remove("hidden"); if (originalScrollTop) treeOutlineContainerElement.scrollTop = originalScrollTop; this._treeOutline.updateSelection(); @@ -2897,20 +3017,44 @@ WebInspector.ElementsTreeOutline.Renderer = function() WebInspector.ElementsTreeOutline.Renderer.prototype = { /** * @param {!Object} object - * @return {?Element} + * @return {!Promise.} */ render: function(object) { - if (!(object instanceof WebInspector.DOMNode)) - return null; - var node = /** @type {!WebInspector.DOMNode} */ (object); - var treeOutline = new WebInspector.ElementsTreeOutline(node.target(), false, false); - treeOutline.rootDOMNode = node; - treeOutline.element.classList.add("outline-disclosure"); - if (!treeOutline.children[0].hasChildren) - treeOutline.element.classList.add("single-node"); - treeOutline.setVisible(true); - treeOutline.element.treeElementForTest = treeOutline.children[0]; - return treeOutline.element; + return new Promise(renderPromise); + + /** + * @param {function(!Element)} resolve + * @param {function(!Error)} reject + */ + function renderPromise(resolve, reject) + { + if (object instanceof WebInspector.DOMNode) + onNodeResolved(/** @type {!WebInspector.DOMNode} */ (object)); + else if (object instanceof WebInspector.DeferredDOMNode) + (/** @type {!WebInspector.DeferredDOMNode} */ (object)).resolve(onNodeResolved); + else if (object instanceof WebInspector.RemoteObject) + (/** @type {!WebInspector.RemoteObject} */ (object)).pushNodeToFrontend(onNodeResolved); + else + reject(new Error("Can't reveal not a node.")); + + /** + * @param {?WebInspector.DOMNode} node + */ + function onNodeResolved(node) + { + if (!node) { + reject(new Error("Could not resolve node.")); + return; + } + var treeOutline = new WebInspector.ElementsTreeOutline(node.target(), false, false); + treeOutline.rootDOMNode = node; + if (!treeOutline.children[0].hasChildren) + treeOutline._element.classList.add("single-node"); + treeOutline.setVisible(true); + treeOutline.element.treeElementForTest = treeOutline.children[0]; + resolve(treeOutline.element); + } + } } }