{
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;
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}} */
WebInspector.ElementsTreeOutline.prototype = {
/**
+ * @param {boolean} wrap
+ */
+ setWordWrap: function(wrap)
+ {
+ this._element.classList.toggle("nowrap", !wrap);
+ },
+
+ /**
* @param {!Event} event
*/
_onAnimationEnd: function(event)
setPickNodeMode: function(value)
{
this._pickNodeMode = value;
- this.element.classList.toggle("pick-node-mode", value);
+ this._element.classList.toggle("pick-node-mode", value);
},
/**
_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;
},
/**
return;
// Do not interfere with text editing.
- var currentFocusElement = WebInspector.currentFocusElement();
- if (currentFocusElement && WebInspector.isBeingEdited(currentFocusElement))
+ if (WebInspector.isEditing())
return;
var targetNode = this.selectedDOMNode();
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();
setVisible: function(visible)
{
this._visible = visible;
- if (!this._visible)
+ if (!this._visible) {
+ this._popoverHelper.hidePopover();
return;
+ }
this._updateModifiedNodes();
if (this._selectedDOMNode)
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);
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;
return false;
var treeElement = this._treeElementFromEvent(event);
- if (!treeElement)
- return false;
-
if (!this._isValidDragSourceOrTarget(treeElement))
return false;
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;
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");
/**
* @param {?string} pseudoType
+ * @suppressGlobalPropertiesCheck
* @suppressReceiverCheck
* @this {!Element}
*/
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);
style = document.createElement("style");
style.id = styleTagId;
style.type = "text/css";
- style.textContent = styleRules;
+ style.textContent = rule;
document.head.appendChild(style);
}
this._node = node;
this._elementCloseTag = elementCloseTag;
- this._updateHasChildren();
+ this._updateChildrenDisplayMode();
if (this._node.nodeType() == Node.ELEMENT_NODE && !elementCloseTag)
this._canAddAttributes = true;
"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) {
this._updateSearchHighlight(false);
},
+ /**
+ * @param {boolean} show
+ */
_updateSearchHighlight: function(show)
{
if (!this._highlightResult)
this._expandedChildrenLimit = x;
if (this.treeOutline && !this._updateChildrenInProgress)
- this._updateChildren(true);
+ this._updateChildren(true, this.children);
},
get expandedChildCount()
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
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,
}
if (!this.selectionElement) {
- this.selectionElement = document.createElement("div");
+ this.selectionElement = createElement("div");
this.selectionElement.className = "selection selected";
listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild);
}
onpopulate: function()
{
this.populated = true;
- if (this.children.length || !this.hasChildren)
+ if (this.children.length || !this._hasChildTreeElements())
return;
this.updateChildren();
*/
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));
},
/**
},
/**
- * @param {boolean=} fullRefresh
+ * @param {boolean} fullRefresh
+ * @param {?Array.<!WebInspector.DOMNode>} 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;
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.
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;
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;
},
*/
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);
},
return;
if (this.treeOutline._showInElementsPanelEnabled) {
- WebInspector.inspectorView.showPanel("elements");
+ var panel = WebInspector.ElementsPanel.instance();
+ WebInspector.inspectorView.setCurrentPanel(panel);
this.treeOutline.selectDOMNode(this._node, true);
}
if (this._startEditingTarget(/** @type {!Element} */(event.target)))
return false;
- if (this.hasChildren && !this.expanded)
+ if (this._hasChildTreeElements() && !this.expanded)
this.expand();
return false;
},
*/
hasEditableNode: function()
{
- return !this.representedObject.isShadowRoot() && !this.representedObject.ancestorUserAgentShadowRoot();
+ return !this._node.isShadowRoot() && !this._node.ancestorUserAgentShadowRoot();
},
_insertInLastAttributePosition: function(tag, node)
_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()
{
// 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
_startEditingAttribute: function(attribute, elementForSelection)
{
+ console.assert(this.listItemElement.isAncestor(attribute));
+
if (WebInspector.isBeingEdited(attribute))
return true;
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.
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.
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)
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;
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");
{
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")) {
_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:
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;
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())
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
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);
}
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)
}
if (hidePanelWhileUpdating) {
- this._treeOutline.element.classList.remove("hidden");
+ this._treeOutline._element.classList.remove("hidden");
if (originalScrollTop)
treeOutlineContainerElement.scrollTop = originalScrollTop;
this._treeOutline.updateSelection();
WebInspector.ElementsTreeOutline.Renderer.prototype = {
/**
* @param {!Object} object
- * @return {?Element}
+ * @return {!Promise.<!Element>}
*/
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);
+ }
+ }
}
}