Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(190)

Unified Diff: third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js

Issue 2466123002: DevTools: reformat front-end code to match chromium style. (Closed)
Patch Set: all done Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
index c9b8db58f336663eac6a27ead6351cd660066c8a..57ec8c27bb9ff8095c8df75ada2db1a1891868a9 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
+++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsTreeElement.js
@@ -27,1618 +27,1554 @@
* (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 {TreeElement}
- * @param {!WebInspector.DOMNode} node
- * @param {boolean=} elementCloseTag
+ * @unrestricted
*/
-WebInspector.ElementsTreeElement = function(node, elementCloseTag)
-{
+WebInspector.ElementsTreeElement = class extends TreeElement {
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @param {boolean=} elementCloseTag
+ */
+ constructor(node, elementCloseTag) {
// The title will be updated in onattach.
- TreeElement.call(this);
+ super();
this._node = node;
- this._gutterContainer = this.listItemElement.createChild("div", "gutter-container");
- this._gutterContainer.addEventListener("click", this._showContextMenu.bind(this));
- this._decorationsElement = this._gutterContainer.createChild("div", "hidden");
+ this._gutterContainer = this.listItemElement.createChild('div', 'gutter-container');
+ this._gutterContainer.addEventListener('click', this._showContextMenu.bind(this));
+ this._decorationsElement = this._gutterContainer.createChild('div', 'hidden');
this._elementCloseTag = elementCloseTag;
if (this._node.nodeType() === Node.ELEMENT_NODE && !elementCloseTag)
- this._canAddAttributes = true;
+ this._canAddAttributes = true;
this._searchQuery = null;
this._expandedChildrenLimit = WebInspector.ElementsTreeElement.InitialChildrenLimit;
-};
-
-WebInspector.ElementsTreeElement.InitialChildrenLimit = 500;
-
-// A union of HTML4 and HTML5-Draft elements that explicitly
-// or implicitly (for HTML5) forbid the closing tag.
-WebInspector.ElementsTreeElement.ForbiddenClosingTagElements = new Set([
- "area", "base", "basefont", "br", "canvas", "col", "command", "embed", "frame",
- "hr", "img", "input", "keygen", "link", "menuitem", "meta", "param", "source", "track", "wbr"
-]);
-
-// These tags we do not allow editing their tag name.
-WebInspector.ElementsTreeElement.EditTagBlacklist = new Set([
- "html", "head", "body"
-]);
-
-/**
- * @param {!WebInspector.ElementsTreeElement} treeElement
- */
-WebInspector.ElementsTreeElement.animateOnDOMUpdate = function(treeElement)
-{
- var tagName = treeElement.listItemElement.querySelector(".webkit-html-tag-name");
- WebInspector.runCSSAnimationOnce(tagName || treeElement.listItemElement, "dom-update-highlight");
-};
-
-/**
- * @param {!WebInspector.DOMNode} node
- * @return {!Array<!WebInspector.DOMNode>}
- */
-WebInspector.ElementsTreeElement.visibleShadowRoots = function(node)
-{
+ }
+
+ /**
+ * @param {!WebInspector.ElementsTreeElement} treeElement
+ */
+ static animateOnDOMUpdate(treeElement) {
+ var tagName = treeElement.listItemElement.querySelector('.webkit-html-tag-name');
+ WebInspector.runCSSAnimationOnce(tagName || treeElement.listItemElement, 'dom-update-highlight');
+ }
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @return {!Array<!WebInspector.DOMNode>}
+ */
+ static visibleShadowRoots(node) {
var roots = node.shadowRoots();
- if (roots.length && !WebInspector.moduleSetting("showUAShadowDOM").get())
- roots = roots.filter(filter);
+ if (roots.length && !WebInspector.moduleSetting('showUAShadowDOM').get())
+ roots = roots.filter(filter);
/**
* @param {!WebInspector.DOMNode} root
*/
- function filter(root)
- {
- return root.shadowRootType() !== WebInspector.DOMNode.ShadowRootTypes.UserAgent;
+ function filter(root) {
+ return root.shadowRootType() !== WebInspector.DOMNode.ShadowRootTypes.UserAgent;
}
return roots;
-};
-
-/**
- * @param {!WebInspector.DOMNode} node
- * @return {boolean}
- */
-WebInspector.ElementsTreeElement.canShowInlineText = function(node)
-{
- if (node.importedDocument() || node.templateContent() || WebInspector.ElementsTreeElement.visibleShadowRoots(node).length || node.hasPseudoElements())
- return false;
+ }
+
+ /**
+ * @param {!WebInspector.DOMNode} node
+ * @return {boolean}
+ */
+ static canShowInlineText(node) {
+ if (node.importedDocument() || node.templateContent() ||
+ WebInspector.ElementsTreeElement.visibleShadowRoots(node).length || node.hasPseudoElements())
+ return false;
if (node.nodeType() !== Node.ELEMENT_NODE)
- return false;
+ return false;
if (!node.firstChild || node.firstChild !== node.lastChild || node.firstChild.nodeType() !== Node.TEXT_NODE)
- return false;
+ return false;
var textChild = node.firstChild;
var maxInlineTextChildLength = 80;
if (textChild.nodeValue().length < maxInlineTextChildLength)
- return true;
+ return true;
return false;
-};
-
-/**
- * @param {!WebInspector.ContextSubMenuItem} subMenu
- * @param {!WebInspector.DOMNode} node
- */
-WebInspector.ElementsTreeElement.populateForcedPseudoStateItems = function(subMenu, node)
-{
- const pseudoClasses = ["active", "hover", "focus", "visited"];
+ }
+
+ /**
+ * @param {!WebInspector.ContextSubMenuItem} subMenu
+ * @param {!WebInspector.DOMNode} node
+ */
+ static populateForcedPseudoStateItems(subMenu, node) {
+ const pseudoClasses = ['active', 'hover', 'focus', 'visited'];
var forcedPseudoState = WebInspector.CSSModel.fromNode(node).pseudoState(node);
for (var i = 0; i < pseudoClasses.length; ++i) {
- var pseudoClassForced = forcedPseudoState.indexOf(pseudoClasses[i]) >= 0;
- subMenu.appendCheckboxItem(":" + pseudoClasses[i], setPseudoStateCallback.bind(null, pseudoClasses[i], !pseudoClassForced), pseudoClassForced, false);
+ var pseudoClassForced = forcedPseudoState.indexOf(pseudoClasses[i]) >= 0;
+ subMenu.appendCheckboxItem(
+ ':' + pseudoClasses[i], setPseudoStateCallback.bind(null, pseudoClasses[i], !pseudoClassForced),
+ pseudoClassForced, false);
}
/**
* @param {string} pseudoState
* @param {boolean} enabled
*/
- function setPseudoStateCallback(pseudoState, enabled)
- {
- WebInspector.CSSModel.fromNode(node).forcePseudoState(node, pseudoState, enabled);
+ function setPseudoStateCallback(pseudoState, enabled) {
+ WebInspector.CSSModel.fromNode(node).forcePseudoState(node, pseudoState, enabled);
+ }
+ }
+
+ /**
+ * @return {boolean}
+ */
+ isClosingTag() {
+ return !!this._elementCloseTag;
+ }
+
+ /**
+ * @return {!WebInspector.DOMNode}
+ */
+ node() {
+ return this._node;
+ }
+
+ /**
+ * @return {boolean}
+ */
+ isEditing() {
+ return !!this._editing;
+ }
+
+ /**
+ * @param {string} searchQuery
+ */
+ highlightSearchResults(searchQuery) {
+ if (this._searchQuery !== searchQuery)
+ this._hideSearchHighlight();
+
+ this._searchQuery = searchQuery;
+ this._searchHighlightsVisible = true;
+ this.updateTitle(null, true);
+ }
+
+ hideSearchHighlights() {
+ delete this._searchHighlightsVisible;
+ this._hideSearchHighlight();
+ }
+
+ _hideSearchHighlight() {
+ if (!this._highlightResult)
+ return;
+
+ function updateEntryHide(entry) {
+ switch (entry.type) {
+ case 'added':
+ entry.node.remove();
+ break;
+ case 'changed':
+ entry.node.textContent = entry.oldText;
+ break;
+ }
}
-};
-WebInspector.ElementsTreeElement.prototype = {
- /**
- * @return {boolean}
- */
- isClosingTag: function()
- {
- return !!this._elementCloseTag;
- },
+ for (var i = (this._highlightResult.length - 1); i >= 0; --i)
+ updateEntryHide(this._highlightResult[i]);
- /**
- * @return {!WebInspector.DOMNode}
- */
- node: function()
- {
- return this._node;
- },
+ delete this._highlightResult;
+ }
- /**
- * @return {boolean}
- */
- isEditing: function()
- {
- return !!this._editing;
- },
+ /**
+ * @param {boolean} inClipboard
+ */
+ setInClipboard(inClipboard) {
+ if (this._inClipboard === inClipboard)
+ return;
+ this._inClipboard = inClipboard;
+ this.listItemElement.classList.toggle('in-clipboard', inClipboard);
+ }
- /**
- * @param {string} searchQuery
- */
- highlightSearchResults: function(searchQuery)
- {
- if (this._searchQuery !== searchQuery)
- this._hideSearchHighlight();
-
- this._searchQuery = searchQuery;
- this._searchHighlightsVisible = true;
- this.updateTitle(null, true);
- },
-
- hideSearchHighlights: function()
- {
- delete this._searchHighlightsVisible;
- this._hideSearchHighlight();
- },
-
- _hideSearchHighlight: function()
- {
- if (!this._highlightResult)
- return;
-
- function updateEntryHide(entry)
- {
- switch (entry.type) {
- case "added":
- entry.node.remove();
- break;
- case "changed":
- entry.node.textContent = entry.oldText;
- break;
- }
- }
+ get hovered() {
+ return this._hovered;
+ }
- for (var i = (this._highlightResult.length - 1); i >= 0; --i)
- updateEntryHide(this._highlightResult[i]);
+ set hovered(x) {
+ if (this._hovered === x)
+ return;
- delete this._highlightResult;
- },
+ this._hovered = x;
- /**
- * @param {boolean} inClipboard
- */
- setInClipboard: function(inClipboard)
- {
- if (this._inClipboard === inClipboard)
- return;
- this._inClipboard = inClipboard;
- this.listItemElement.classList.toggle("in-clipboard", inClipboard);
- },
-
- get hovered()
- {
- return this._hovered;
- },
-
- set hovered(x)
- {
- if (this._hovered === x)
- return;
-
- this._hovered = x;
-
- if (this.listItemElement) {
- if (x) {
- this._createSelection();
- this.listItemElement.classList.add("hovered");
- } else {
- this.listItemElement.classList.remove("hovered");
- }
- }
- },
+ if (this.listItemElement) {
+ if (x) {
+ this._createSelection();
+ this.listItemElement.classList.add('hovered');
+ } else {
+ this.listItemElement.classList.remove('hovered');
+ }
+ }
+ }
+
+ /**
+ * @return {number}
+ */
+ expandedChildrenLimit() {
+ return this._expandedChildrenLimit;
+ }
+
+ /**
+ * @param {number} expandedChildrenLimit
+ */
+ setExpandedChildrenLimit(expandedChildrenLimit) {
+ this._expandedChildrenLimit = expandedChildrenLimit;
+ }
+
+ _createSelection() {
+ var listItemElement = this.listItemElement;
+ if (!listItemElement)
+ return;
+
+ if (!this.selectionElement) {
+ this.selectionElement = createElement('div');
+ this.selectionElement.className = 'selection fill';
+ this.selectionElement.style.setProperty('margin-left', (-this._computeLeftIndent()) + 'px');
+ listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild);
+ }
+ }
+
+ /**
+ * @override
+ */
+ onbind() {
+ if (!this._elementCloseTag)
+ this._node[this.treeOutline.treeElementSymbol()] = this;
+ }
+
+ /**
+ * @override
+ */
+ onunbind() {
+ if (this._node[this.treeOutline.treeElementSymbol()] === this)
+ this._node[this.treeOutline.treeElementSymbol()] = null;
+ }
+
+ /**
+ * @override
+ */
+ onattach() {
+ if (this._hovered) {
+ this._createSelection();
+ this.listItemElement.classList.add('hovered');
+ }
- /**
- * @return {number}
- */
- expandedChildrenLimit: function()
- {
- return this._expandedChildrenLimit;
- },
+ this.updateTitle();
+ this._preventFollowingLinksOnDoubleClick();
+ this.listItemElement.draggable = true;
+ }
+
+ _preventFollowingLinksOnDoubleClick() {
+ var links = this.listItemElement.querySelectorAll(
+ 'li .webkit-html-tag > .webkit-html-attribute > .webkit-html-external-link, li .webkit-html-tag > .webkit-html-attribute > .webkit-html-resource-link');
+ if (!links)
+ return;
+
+ for (var i = 0; i < links.length; ++i)
+ links[i].preventFollowOnDoubleClick = true;
+ }
+
+ /**
+ * @override
+ */
+ onpopulate() {
+ this.populated = true;
+ this.treeOutline.populateTreeElement(this);
+ }
+
+ /**
+ * @override
+ */
+ expandRecursively() {
+ this._node.getSubtree(-1, TreeElement.prototype.expandRecursively.bind(this, Number.MAX_VALUE));
+ }
+
+ /**
+ * @override
+ */
+ onexpand() {
+ if (this._elementCloseTag)
+ return;
+
+ this.updateTitle();
+ }
+
+ /**
+ * @override
+ */
+ oncollapse() {
+ if (this._elementCloseTag)
+ return;
+
+ this.updateTitle();
+ }
+
+ /**
+ * @override
+ * @param {boolean=} omitFocus
+ * @param {boolean=} selectedByUser
+ * @return {boolean}
+ */
+ select(omitFocus, selectedByUser) {
+ if (this._editing)
+ return false;
+ return super.select(omitFocus, selectedByUser);
+ }
+
+ /**
+ * @override
+ * @param {boolean=} selectedByUser
+ * @return {boolean}
+ */
+ onselect(selectedByUser) {
+ this.treeOutline.suppressRevealAndSelect = true;
+ this.treeOutline.selectDOMNode(this._node, selectedByUser);
+ if (selectedByUser)
+ this._node.highlight();
+ this._createSelection();
+ this.treeOutline.suppressRevealAndSelect = false;
+ return true;
+ }
+
+ /**
+ * @override
+ * @return {boolean}
+ */
+ ondelete() {
+ var startTagTreeElement = this.treeOutline.findTreeElement(this._node);
+ startTagTreeElement ? startTagTreeElement.remove() : this.remove();
+ return true;
+ }
+
+ /**
+ * @override
+ * @return {boolean}
+ */
+ onenter() {
+ // On Enter or Return start editing the first attribute
+ // or create a new attribute on the selected element.
+ if (this._editing)
+ return false;
+
+ this._startEditing();
+
+ // prevent a newline from being immediately inserted
+ return true;
+ }
+
+ /**
+ * @override
+ */
+ selectOnMouseDown(event) {
+ super.selectOnMouseDown(event);
+
+ if (this._editing)
+ return;
+
+ // Prevent selecting the nearest word on double click.
+ if (event.detail >= 2)
+ event.preventDefault();
+ }
+
+ /**
+ * @override
+ * @return {boolean}
+ */
+ ondblclick(event) {
+ if (this._editing || this._elementCloseTag)
+ return false;
+
+ if (this._startEditingTarget(/** @type {!Element} */ (event.target)))
+ return false;
+
+ if (this.isExpandable() && !this.expanded)
+ this.expand();
+ return false;
+ }
+
+ /**
+ * @return {boolean}
+ */
+ hasEditableNode() {
+ return !this._node.isShadowRoot() && !this._node.ancestorUserAgentShadowRoot();
+ }
+
+ _insertInLastAttributePosition(tag, node) {
+ if (tag.getElementsByClassName('webkit-html-attribute').length > 0)
+ tag.insertBefore(node, tag.lastChild);
+ else {
+ var nodeName = tag.textContent.match(/^<(.*?)>$/)[1];
+ tag.textContent = '';
+ tag.createTextChild('<' + nodeName);
+ tag.appendChild(node);
+ tag.createTextChild('>');
+ }
+ }
- /**
- * @param {number} expandedChildrenLimit
- */
- setExpandedChildrenLimit: function(expandedChildrenLimit)
- {
- this._expandedChildrenLimit = expandedChildrenLimit;
- },
-
- _createSelection: function()
- {
- var listItemElement = this.listItemElement;
- if (!listItemElement)
- return;
-
- if (!this.selectionElement) {
- this.selectionElement = createElement("div");
- this.selectionElement.className = "selection fill";
- this.selectionElement.style.setProperty("margin-left", (-this._computeLeftIndent()) + "px");
- listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild);
- }
- },
+ /**
+ * @param {!Element} eventTarget
+ * @return {boolean}
+ */
+ _startEditingTarget(eventTarget) {
+ if (this.treeOutline.selectedDOMNode() !== this._node)
+ return false;
- /**
- * @override
- */
- onbind: function()
- {
- if (!this._elementCloseTag)
- this._node[this.treeOutline.treeElementSymbol()] = this;
- },
+ if (this._node.nodeType() !== Node.ELEMENT_NODE && this._node.nodeType() !== Node.TEXT_NODE)
+ return false;
- /**
- * @override
- */
- onunbind: function()
- {
- if (this._node[this.treeOutline.treeElementSymbol()] === this)
- this._node[this.treeOutline.treeElementSymbol()] = null;
- },
+ var textNode = eventTarget.enclosingNodeOrSelfWithClass('webkit-html-text-node');
+ if (textNode)
+ return this._startEditingTextNode(textNode);
- /**
- * @override
- */
- onattach: function()
- {
- if (this._hovered) {
- this._createSelection();
- this.listItemElement.classList.add("hovered");
- }
+ var attribute = eventTarget.enclosingNodeOrSelfWithClass('webkit-html-attribute');
+ if (attribute)
+ return this._startEditingAttribute(attribute, eventTarget);
- this.updateTitle();
- this._preventFollowingLinksOnDoubleClick();
- this.listItemElement.draggable = true;
- },
-
- _preventFollowingLinksOnDoubleClick: function()
- {
- var links = this.listItemElement.querySelectorAll("li .webkit-html-tag > .webkit-html-attribute > .webkit-html-external-link, li .webkit-html-tag > .webkit-html-attribute > .webkit-html-resource-link");
- if (!links)
- return;
-
- for (var i = 0; i < links.length; ++i)
- links[i].preventFollowOnDoubleClick = true;
- },
-
- onpopulate: function()
- {
- this.populated = true;
- this.treeOutline.populateTreeElement(this);
- },
-
- expandRecursively: function()
- {
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function callback()
- {
- TreeElement.prototype.expandRecursively.call(this, Number.MAX_VALUE);
- }
+ var tagName = eventTarget.enclosingNodeOrSelfWithClass('webkit-html-tag-name');
+ if (tagName)
+ return this._startEditingTagName(tagName);
- this._node.getSubtree(-1, callback.bind(this));
- },
+ var newAttribute = eventTarget.enclosingNodeOrSelfWithClass('add-attribute');
+ if (newAttribute)
+ return this._addNewAttribute();
- /**
- * @override
- */
- onexpand: function()
- {
- if (this._elementCloseTag)
- return;
+ return false;
+ }
+
+ /**
+ * @param {!Event} event
+ */
+ _showContextMenu(event) {
+ this.treeOutline.showContextMenu(this, event);
+ }
+
+ /**
+ * @param {!WebInspector.ContextMenu} contextMenu
+ * @param {!Event} event
+ */
+ populateTagContextMenu(contextMenu, event) {
+ // Add attribute-related actions.
+ var treeElement = this._elementCloseTag ? this.treeOutline.findTreeElement(this._node) : this;
+ contextMenu.appendItem(
+ WebInspector.UIString.capitalize('Add ^attribute'), treeElement._addNewAttribute.bind(treeElement));
+
+ var attribute = event.target.enclosingNodeOrSelfWithClass('webkit-html-attribute');
+ var newAttribute = event.target.enclosingNodeOrSelfWithClass('add-attribute');
+ if (attribute && !newAttribute)
+ contextMenu.appendItem(
+ WebInspector.UIString.capitalize('Edit ^attribute'),
+ this._startEditingAttribute.bind(this, attribute, event.target));
+ this.populateNodeContextMenu(contextMenu);
+ WebInspector.ElementsTreeElement.populateForcedPseudoStateItems(contextMenu, treeElement.node());
+ contextMenu.appendSeparator();
+ this.populateScrollIntoView(contextMenu);
+ }
+
+ /**
+ * @param {!WebInspector.ContextMenu} contextMenu
+ */
+ populateScrollIntoView(contextMenu) {
+ contextMenu.appendItem(WebInspector.UIString.capitalize('Scroll into ^view'), this._scrollIntoView.bind(this));
+ }
+
+ populateTextContextMenu(contextMenu, textNode) {
+ if (!this._editing)
+ contextMenu.appendItem(
+ WebInspector.UIString.capitalize('Edit ^text'), this._startEditingTextNode.bind(this, textNode));
+ this.populateNodeContextMenu(contextMenu);
+ }
+
+ populateNodeContextMenu(contextMenu) {
+ // Add free-form node-related actions.
+ var openTagElement = this._node[this.treeOutline.treeElementSymbol()] || this;
+ var isEditable = this.hasEditableNode();
+ if (isEditable && !this._editing)
+ contextMenu.appendItem(WebInspector.UIString('Edit as HTML'), this._editAsHTML.bind(this));
+ var isShadowRoot = this._node.isShadowRoot();
+
+ // Place it here so that all "Copy"-ing items stick together.
+ var copyMenu = contextMenu.appendSubMenuItem(WebInspector.UIString('Copy'));
+ var createShortcut = WebInspector.KeyboardShortcut.shortcutToString;
+ var modifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
+ var treeOutline = this.treeOutline;
+ var menuItem;
+ if (!isShadowRoot) {
+ menuItem = copyMenu.appendItem(
+ WebInspector.UIString('Copy outerHTML'), treeOutline.performCopyOrCut.bind(treeOutline, false, this._node));
+ menuItem.setShortcut(createShortcut('V', modifier));
+ }
+ if (this._node.nodeType() === Node.ELEMENT_NODE)
+ copyMenu.appendItem(WebInspector.UIString.capitalize('Copy selector'), this._copyCSSPath.bind(this));
+ if (!isShadowRoot)
+ copyMenu.appendItem(WebInspector.UIString('Copy XPath'), this._copyXPath.bind(this));
+ if (!isShadowRoot) {
+ menuItem = copyMenu.appendItem(
+ WebInspector.UIString('Cut element'), treeOutline.performCopyOrCut.bind(treeOutline, true, this._node),
+ !this.hasEditableNode());
+ menuItem.setShortcut(createShortcut('X', modifier));
+ menuItem = copyMenu.appendItem(
+ WebInspector.UIString('Copy element'), treeOutline.performCopyOrCut.bind(treeOutline, false, this._node));
+ menuItem.setShortcut(createShortcut('C', modifier));
+ menuItem = copyMenu.appendItem(
+ WebInspector.UIString('Paste element'), treeOutline.pasteNode.bind(treeOutline, this._node),
+ !treeOutline.canPaste(this._node));
+ menuItem.setShortcut(createShortcut('V', modifier));
+ }
- this.updateTitle();
- },
+ contextMenu.appendSeparator();
+ menuItem = contextMenu.appendCheckboxItem(
+ WebInspector.UIString('Hide element'), treeOutline.toggleHideElement.bind(treeOutline, this._node),
+ treeOutline.isToggledToHidden(this._node));
+ menuItem.setShortcut(WebInspector.shortcutRegistry.shortcutTitleForAction('elements.hide-element'));
- oncollapse: function()
- {
- if (this._elementCloseTag)
- return;
+ if (isEditable)
+ contextMenu.appendItem(WebInspector.UIString('Delete element'), this.remove.bind(this));
+ contextMenu.appendSeparator();
- this.updateTitle();
- },
+ contextMenu.appendItem(WebInspector.UIString('Expand all'), this.expandRecursively.bind(this));
+ contextMenu.appendItem(WebInspector.UIString('Collapse all'), this.collapseRecursively.bind(this));
+ contextMenu.appendSeparator();
+ }
- /**
- * @override
- * @param {boolean=} omitFocus
- * @param {boolean=} selectedByUser
- * @return {boolean}
- */
- select: function(omitFocus, selectedByUser)
- {
- if (this._editing)
- return false;
- return TreeElement.prototype.select.call(this, omitFocus, selectedByUser);
- },
+ _startEditing() {
+ if (this.treeOutline.selectedDOMNode() !== this._node)
+ return;
- /**
- * @override
- * @param {boolean=} selectedByUser
- * @return {boolean}
- */
- onselect: function(selectedByUser)
- {
- this.treeOutline.suppressRevealAndSelect = true;
- this.treeOutline.selectDOMNode(this._node, selectedByUser);
- if (selectedByUser)
- this._node.highlight();
- this._createSelection();
- this.treeOutline.suppressRevealAndSelect = false;
- return true;
- },
+ var listItem = this._listItemNode;
- /**
- * @override
- * @return {boolean}
- */
- ondelete: function()
- {
- var startTagTreeElement = this.treeOutline.findTreeElement(this._node);
- startTagTreeElement ? startTagTreeElement.remove() : this.remove();
- return true;
- },
+ if (this._canAddAttributes) {
+ var attribute = listItem.getElementsByClassName('webkit-html-attribute')[0];
+ if (attribute)
+ return this._startEditingAttribute(
+ attribute, attribute.getElementsByClassName('webkit-html-attribute-value')[0]);
- /**
- * @override
- * @return {boolean}
- */
- onenter: function()
- {
- // On Enter or Return start editing the first attribute
- // or create a new attribute on the selected element.
- if (this._editing)
- return false;
+ return this._addNewAttribute();
+ }
- this._startEditing();
+ if (this._node.nodeType() === Node.TEXT_NODE) {
+ var textNode = listItem.getElementsByClassName('webkit-html-text-node')[0];
+ if (textNode)
+ return this._startEditingTextNode(textNode);
+ return;
+ }
+ }
+
+ _addNewAttribute() {
+ // Cannot just convert the textual html into an element without
+ // a parent node. Use a temporary span container for the HTML.
+ var container = createElement('span');
+ this._buildAttributeDOM(container, ' ', '', null);
+ var attr = container.firstElementChild;
+ attr.style.marginLeft = '2px'; // overrides the .editing margin rule
+ attr.style.marginRight = '2px'; // overrides the .editing margin rule
+
+ var tag = this.listItemElement.getElementsByClassName('webkit-html-tag')[0];
+ this._insertInLastAttributePosition(tag, attr);
+ attr.scrollIntoViewIfNeeded(true);
+ return this._startEditingAttribute(attr, attr);
+ }
+
+ _triggerEditAttribute(attributeName) {
+ var attributeElements = this.listItemElement.getElementsByClassName('webkit-html-attribute-name');
+ for (var i = 0, len = attributeElements.length; i < len; ++i) {
+ if (attributeElements[i].textContent === attributeName) {
+ for (var elem = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) {
+ if (elem.nodeType !== Node.ELEMENT_NODE)
+ continue;
+
+ if (elem.classList.contains('webkit-html-attribute-value'))
+ return this._startEditingAttribute(elem.parentNode, elem);
+ }
+ }
+ }
+ }
- // prevent a newline from being immediately inserted
- return true;
- },
+ _startEditingAttribute(attribute, elementForSelection) {
+ console.assert(this.listItemElement.isAncestor(attribute));
- selectOnMouseDown: function(event)
- {
- TreeElement.prototype.selectOnMouseDown.call(this, event);
+ if (WebInspector.isBeingEdited(attribute))
+ return true;
- if (this._editing)
- return;
+ var attributeNameElement = attribute.getElementsByClassName('webkit-html-attribute-name')[0];
+ if (!attributeNameElement)
+ return false;
- // Prevent selecting the nearest word on double click.
- if (event.detail >= 2)
- event.preventDefault();
- },
+ var attributeName = attributeNameElement.textContent;
+ var attributeValueElement = attribute.getElementsByClassName('webkit-html-attribute-value')[0];
- /**
- * @override
- * @return {boolean}
- */
- ondblclick: function(event)
- {
- if (this._editing || this._elementCloseTag)
- return false;
+ // Make sure elementForSelection is not a child of attributeValueElement.
+ elementForSelection =
+ attributeValueElement.isAncestor(elementForSelection) ? attributeValueElement : elementForSelection;
- if (this._startEditingTarget(/** @type {!Element} */(event.target)))
- return false;
+ function removeZeroWidthSpaceRecursive(node) {
+ if (node.nodeType === Node.TEXT_NODE) {
+ node.nodeValue = node.nodeValue.replace(/\u200B/g, '');
+ return;
+ }
- if (this.isExpandable() && !this.expanded)
- this.expand();
- return false;
- },
+ if (node.nodeType !== Node.ELEMENT_NODE)
+ return;
- /**
- * @return {boolean}
- */
- hasEditableNode: function()
- {
- return !this._node.isShadowRoot() && !this._node.ancestorUserAgentShadowRoot();
- },
-
- _insertInLastAttributePosition: function(tag, node)
- {
- if (tag.getElementsByClassName("webkit-html-attribute").length > 0)
- tag.insertBefore(node, tag.lastChild);
- else {
- var nodeName = tag.textContent.match(/^<(.*?)>$/)[1];
- tag.textContent = "";
- tag.createTextChild("<" + nodeName);
- tag.appendChild(node);
- tag.createTextChild(">");
- }
- },
+ for (var child = node.firstChild; child; child = child.nextSibling)
+ removeZeroWidthSpaceRecursive(child);
+ }
- /**
- * @param {!Element} eventTarget
- * @return {boolean}
- */
- _startEditingTarget: function(eventTarget)
- {
- if (this.treeOutline.selectedDOMNode() !== this._node)
- return false;
+ var attributeValue = attributeName && attributeValueElement ? this._node.getAttribute(attributeName) : undefined;
+ if (attributeValue !== undefined)
+ attributeValueElement.setTextContentTruncatedIfNeeded(
+ attributeValue, WebInspector.UIString('<value is too large to edit>'));
- if (this._node.nodeType() !== Node.ELEMENT_NODE && this._node.nodeType() !== Node.TEXT_NODE)
- return false;
+ // Remove zero-width spaces that were added by nodeTitleInfo.
+ removeZeroWidthSpaceRecursive(attribute);
- var textNode = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-text-node");
- if (textNode)
- return this._startEditingTextNode(textNode);
+ var config = new WebInspector.InplaceEditor.Config(
+ this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName);
- var attribute = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-attribute");
- if (attribute)
- return this._startEditingAttribute(attribute, eventTarget);
+ /**
+ * @param {!Event} event
+ * @return {string}
+ */
+ function postKeyDownFinishHandler(event) {
+ WebInspector.handleElementValueModifications(event, attribute);
+ return '';
+ }
- var tagName = eventTarget.enclosingNodeOrSelfWithClass("webkit-html-tag-name");
- if (tagName)
- return this._startEditingTagName(tagName);
+ if (!attributeValueElement.textContent.asParsedURL())
+ config.setPostKeydownFinishHandler(postKeyDownFinishHandler);
+
+ this._editing = WebInspector.InplaceEditor.startEditing(attribute, config);
+
+ this.listItemElement.getComponentSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1);
+
+ return true;
+ }
+
+ /**
+ * @param {!Element} textNodeElement
+ */
+ _startEditingTextNode(textNodeElement) {
+ if (WebInspector.isBeingEdited(textNodeElement))
+ return true;
+
+ var textNode = this._node;
+ // We only show text nodes inline in elements if the element only
+ // has a single child, and that child is a text node.
+ if (textNode.nodeType() === Node.ELEMENT_NODE && textNode.firstChild)
+ textNode = textNode.firstChild;
+
+ var container = textNodeElement.enclosingNodeOrSelfWithClass('webkit-html-text-node');
+ if (container)
+ container.textContent = textNode.nodeValue(); // Strip the CSS or JS highlighting if present.
+ var config = new WebInspector.InplaceEditor.Config(
+ this._textNodeEditingCommitted.bind(this, textNode), this._editingCancelled.bind(this));
+ this._editing = WebInspector.InplaceEditor.startEditing(textNodeElement, config);
+ this.listItemElement.getComponentSelection().setBaseAndExtent(textNodeElement, 0, textNodeElement, 1);
+
+ return true;
+ }
+
+ /**
+ * @param {!Element=} tagNameElement
+ */
+ _startEditingTagName(tagNameElement) {
+ if (!tagNameElement) {
+ tagNameElement = this.listItemElement.getElementsByClassName('webkit-html-tag-name')[0];
+ if (!tagNameElement)
+ return false;
+ }
- var newAttribute = eventTarget.enclosingNodeOrSelfWithClass("add-attribute");
- if (newAttribute)
- return this._addNewAttribute();
+ var tagName = tagNameElement.textContent;
+ if (WebInspector.ElementsTreeElement.EditTagBlacklist.has(tagName.toLowerCase()))
+ return false;
- return false;
- },
+ if (WebInspector.isBeingEdited(tagNameElement))
+ return true;
+
+ var closingTagElement = this._distinctClosingTagElement();
/**
* @param {!Event} event
*/
- _showContextMenu: function(event)
- {
- this.treeOutline.showContextMenu(this, event);
- },
+ function keyupListener(event) {
+ if (closingTagElement)
+ closingTagElement.textContent = '</' + tagNameElement.textContent + '>';
+ }
/**
- * @param {!WebInspector.ContextMenu} contextMenu
- * @param {!Event} event
+ * @param {!Element} element
+ * @param {string} newTagName
+ * @this {WebInspector.ElementsTreeElement}
*/
- populateTagContextMenu: function(contextMenu, event)
- {
- // Add attribute-related actions.
- var treeElement = this._elementCloseTag ? this.treeOutline.findTreeElement(this._node) : this;
- contextMenu.appendItem(WebInspector.UIString.capitalize("Add ^attribute"), treeElement._addNewAttribute.bind(treeElement));
-
- var attribute = event.target.enclosingNodeOrSelfWithClass("webkit-html-attribute");
- var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute");
- if (attribute && !newAttribute)
- contextMenu.appendItem(WebInspector.UIString.capitalize("Edit ^attribute"), this._startEditingAttribute.bind(this, attribute, event.target));
- this.populateNodeContextMenu(contextMenu);
- WebInspector.ElementsTreeElement.populateForcedPseudoStateItems(contextMenu, treeElement.node());
- contextMenu.appendSeparator();
- this.populateScrollIntoView(contextMenu);
- },
+ function editingComitted(element, newTagName) {
+ tagNameElement.removeEventListener('keyup', keyupListener, false);
+ this._tagNameEditingCommitted.apply(this, arguments);
+ }
/**
- * @param {!WebInspector.ContextMenu} contextMenu
+ * @this {WebInspector.ElementsTreeElement}
*/
- populateScrollIntoView: function(contextMenu)
- {
- contextMenu.appendItem(WebInspector.UIString.capitalize("Scroll into ^view"), this._scrollIntoView.bind(this));
- },
-
- populateTextContextMenu: function(contextMenu, textNode)
- {
- if (!this._editing)
- contextMenu.appendItem(WebInspector.UIString.capitalize("Edit ^text"), this._startEditingTextNode.bind(this, textNode));
- this.populateNodeContextMenu(contextMenu);
- },
-
- populateNodeContextMenu: function(contextMenu)
- {
- // Add free-form node-related actions.
- var openTagElement = this._node[this.treeOutline.treeElementSymbol()] || this;
- var isEditable = this.hasEditableNode();
- if (isEditable && !this._editing)
- contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), this._editAsHTML.bind(this));
- var isShadowRoot = this._node.isShadowRoot();
-
- // Place it here so that all "Copy"-ing items stick together.
- var copyMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Copy"));
- var createShortcut = WebInspector.KeyboardShortcut.shortcutToString;
- var modifier = WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta;
- var treeOutline = this.treeOutline;
- var menuItem;
- if (!isShadowRoot) {
- menuItem = copyMenu.appendItem(WebInspector.UIString("Copy outerHTML"), treeOutline.performCopyOrCut.bind(treeOutline, false, this._node));
- menuItem.setShortcut(createShortcut("V", modifier));
- }
- if (this._node.nodeType() === Node.ELEMENT_NODE)
- copyMenu.appendItem(WebInspector.UIString.capitalize("Copy selector"), this._copyCSSPath.bind(this));
- if (!isShadowRoot)
- copyMenu.appendItem(WebInspector.UIString("Copy XPath"), this._copyXPath.bind(this));
- if (!isShadowRoot) {
- menuItem = copyMenu.appendItem(WebInspector.UIString("Cut element"), treeOutline.performCopyOrCut.bind(treeOutline, true, this._node), !this.hasEditableNode());
- menuItem.setShortcut(createShortcut("X", modifier));
- menuItem = copyMenu.appendItem(WebInspector.UIString("Copy element"), treeOutline.performCopyOrCut.bind(treeOutline, false, this._node));
- menuItem.setShortcut(createShortcut("C", modifier));
- menuItem = copyMenu.appendItem(WebInspector.UIString("Paste element"), treeOutline.pasteNode.bind(treeOutline, this._node), !treeOutline.canPaste(this._node));
- menuItem.setShortcut(createShortcut("V", modifier));
- }
-
- contextMenu.appendSeparator();
- menuItem = contextMenu.appendCheckboxItem(WebInspector.UIString("Hide element"), treeOutline.toggleHideElement.bind(treeOutline, this._node), treeOutline.isToggledToHidden(this._node));
- menuItem.setShortcut(WebInspector.shortcutRegistry.shortcutTitleForAction("elements.hide-element"));
-
-
- if (isEditable)
- contextMenu.appendItem(WebInspector.UIString("Delete element"), this.remove.bind(this));
- contextMenu.appendSeparator();
-
- contextMenu.appendItem(WebInspector.UIString("Expand all"), this.expandRecursively.bind(this));
- contextMenu.appendItem(WebInspector.UIString("Collapse all"), this.collapseRecursively.bind(this));
- contextMenu.appendSeparator();
- },
-
- _startEditing: function()
- {
- if (this.treeOutline.selectedDOMNode() !== this._node)
- return;
-
- var listItem = this._listItemNode;
+ function editingCancelled() {
+ tagNameElement.removeEventListener('keyup', keyupListener, false);
+ this._editingCancelled.apply(this, arguments);
+ }
- if (this._canAddAttributes) {
- var attribute = listItem.getElementsByClassName("webkit-html-attribute")[0];
- if (attribute)
- return this._startEditingAttribute(attribute, attribute.getElementsByClassName("webkit-html-attribute-value")[0]);
+ tagNameElement.addEventListener('keyup', keyupListener, false);
+
+ var config =
+ new WebInspector.InplaceEditor.Config(editingComitted.bind(this), editingCancelled.bind(this), tagName);
+ this._editing = WebInspector.InplaceEditor.startEditing(tagNameElement, config);
+ this.listItemElement.getComponentSelection().setBaseAndExtent(tagNameElement, 0, tagNameElement, 1);
+ return true;
+ }
+
+ /**
+ * @param {function(string, string)} commitCallback
+ * @param {function()} disposeCallback
+ * @param {?Protocol.Error} error
+ * @param {string} initialValue
+ */
+ _startEditingAsHTML(commitCallback, disposeCallback, error, initialValue) {
+ if (error)
+ return;
+ if (this._editing)
+ return;
+
+ function consume(event) {
+ if (event.eventPhase === Event.AT_TARGET)
+ event.consume(true);
+ }
- return this._addNewAttribute();
- }
+ initialValue = this._convertWhitespaceToEntities(initialValue).text;
- if (this._node.nodeType() === Node.TEXT_NODE) {
- var textNode = listItem.getElementsByClassName("webkit-html-text-node")[0];
- if (textNode)
- return this._startEditingTextNode(textNode);
- return;
- }
- },
-
- _addNewAttribute: function()
- {
- // Cannot just convert the textual html into an element without
- // a parent node. Use a temporary span container for the HTML.
- var container = createElement("span");
- this._buildAttributeDOM(container, " ", "", null);
- var attr = container.firstElementChild;
- attr.style.marginLeft = "2px"; // overrides the .editing margin rule
- attr.style.marginRight = "2px"; // overrides the .editing margin rule
-
- var tag = this.listItemElement.getElementsByClassName("webkit-html-tag")[0];
- this._insertInLastAttributePosition(tag, attr);
- attr.scrollIntoViewIfNeeded(true);
- return this._startEditingAttribute(attr, attr);
- },
-
- _triggerEditAttribute: function(attributeName)
- {
- var attributeElements = this.listItemElement.getElementsByClassName("webkit-html-attribute-name");
- for (var i = 0, len = attributeElements.length; i < len; ++i) {
- if (attributeElements[i].textContent === attributeName) {
- for (var elem = attributeElements[i].nextSibling; elem; elem = elem.nextSibling) {
- if (elem.nodeType !== Node.ELEMENT_NODE)
- continue;
-
- if (elem.classList.contains("webkit-html-attribute-value"))
- return this._startEditingAttribute(elem.parentNode, elem);
- }
- }
- }
- },
+ this._htmlEditElement = createElement('div');
+ this._htmlEditElement.className = 'source-code elements-tree-editor';
- _startEditingAttribute: function(attribute, elementForSelection)
- {
- console.assert(this.listItemElement.isAncestor(attribute));
+ // Hide header items.
+ var child = this.listItemElement.firstChild;
+ while (child) {
+ child.style.display = 'none';
+ child = child.nextSibling;
+ }
+ // Hide children item.
+ if (this._childrenListNode)
+ this._childrenListNode.style.display = 'none';
+ // Append editor.
+ this.listItemElement.appendChild(this._htmlEditElement);
+ this.listItemElement.classList.add('editing-as-html');
+ this.treeOutline.element.addEventListener('mousedown', consume, false);
- if (WebInspector.isBeingEdited(attribute))
- return true;
+ /**
+ * @param {!Element} element
+ * @param {string} newValue
+ * @this {WebInspector.ElementsTreeElement}
+ */
+ function commit(element, newValue) {
+ commitCallback(initialValue, newValue);
+ dispose.call(this);
+ }
- var attributeNameElement = attribute.getElementsByClassName("webkit-html-attribute-name")[0];
- if (!attributeNameElement)
- return false;
+ /**
+ * @this {WebInspector.ElementsTreeElement}
+ */
+ function dispose() {
+ disposeCallback();
+ delete this._editing;
+ this.treeOutline.setMultilineEditing(null);
+
+ this.listItemElement.classList.remove('editing-as-html');
+ // Remove editor.
+ this.listItemElement.removeChild(this._htmlEditElement);
+ delete this._htmlEditElement;
+ // Unhide children item.
+ if (this._childrenListNode)
+ this._childrenListNode.style.removeProperty('display');
+ // Unhide header items.
+ var child = this.listItemElement.firstChild;
+ while (child) {
+ child.style.removeProperty('display');
+ child = child.nextSibling;
+ }
+
+ this.treeOutline.element.removeEventListener('mousedown', consume, false);
+ this.treeOutline.focus();
+ }
- var attributeName = attributeNameElement.textContent;
- var attributeValueElement = attribute.getElementsByClassName("webkit-html-attribute-value")[0];
+ var config = new WebInspector.InplaceEditor.Config(commit.bind(this), dispose.bind(this));
+ config.setMultilineOptions(
+ initialValue, {name: 'xml', htmlMode: true}, 'web-inspector-html',
+ WebInspector.moduleSetting('domWordWrap').get(), true);
+ WebInspector.InplaceEditor.startMultilineEditing(this._htmlEditElement, config).then(markAsBeingEdited.bind(this));
- // Make sure elementForSelection is not a child of attributeValueElement.
- elementForSelection = attributeValueElement.isAncestor(elementForSelection) ? attributeValueElement : elementForSelection;
+ /**
+ * @param {!Object} controller
+ * @this {WebInspector.ElementsTreeElement}
+ */
+ function markAsBeingEdited(controller) {
+ this._editing = /** @type {!WebInspector.InplaceEditor.Controller} */ (controller);
+ this._editing.setWidth(this.treeOutline.visibleWidth() - this._computeLeftIndent());
+ this.treeOutline.setMultilineEditing(this._editing);
+ }
+ }
- function removeZeroWidthSpaceRecursive(node)
- {
- if (node.nodeType === Node.TEXT_NODE) {
- node.nodeValue = node.nodeValue.replace(/\u200B/g, "");
- return;
- }
+ _attributeEditingCommitted(element, newText, oldText, attributeName, moveDirection) {
+ delete this._editing;
- if (node.nodeType !== Node.ELEMENT_NODE)
- return;
+ var treeOutline = this.treeOutline;
- for (var child = node.firstChild; child; child = child.nextSibling)
- removeZeroWidthSpaceRecursive(child);
+ /**
+ * @param {?Protocol.Error=} error
+ * @this {WebInspector.ElementsTreeElement}
+ */
+ function moveToNextAttributeIfNeeded(error) {
+ if (error)
+ this._editingCancelled(element, attributeName);
+
+ if (!moveDirection)
+ return;
+
+ treeOutline.runPendingUpdates();
+
+ // Search for the attribute's position, and then decide where to move to.
+ var attributes = this._node.attributes();
+ for (var i = 0; i < attributes.length; ++i) {
+ if (attributes[i].name !== attributeName)
+ continue;
+
+ if (moveDirection === 'backward') {
+ if (i === 0)
+ this._startEditingTagName();
+ else
+ this._triggerEditAttribute(attributes[i - 1].name);
+ } else {
+ if (i === attributes.length - 1)
+ this._addNewAttribute();
+ else
+ this._triggerEditAttribute(attributes[i + 1].name);
}
-
- var attributeValue = attributeName && attributeValueElement ? this._node.getAttribute(attributeName) : undefined;
- if (attributeValue !== undefined)
- attributeValueElement.setTextContentTruncatedIfNeeded(attributeValue, WebInspector.UIString("<value is too large to edit>"));
-
- // Remove zero-width spaces that were added by nodeTitleInfo.
- removeZeroWidthSpaceRecursive(attribute);
-
- var config = new WebInspector.InplaceEditor.Config(this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName);
-
- /**
- * @param {!Event} event
- * @return {string}
- */
- function postKeyDownFinishHandler(event)
- {
- WebInspector.handleElementValueModifications(event, attribute);
- return "";
+ return;
+ }
+
+ // Moving From the "New Attribute" position.
+ if (moveDirection === 'backward') {
+ if (newText === ' ') {
+ // Moving from "New Attribute" that was not edited
+ if (attributes.length > 0)
+ this._triggerEditAttribute(attributes[attributes.length - 1].name);
+ } else {
+ // Moving from "New Attribute" that holds new value
+ if (attributes.length > 1)
+ this._triggerEditAttribute(attributes[attributes.length - 2].name);
}
+ } else if (moveDirection === 'forward') {
+ if (!newText.isWhitespace())
+ this._addNewAttribute();
+ else
+ this._startEditingTagName();
+ }
+ }
- if (!attributeValueElement.textContent.asParsedURL())
- config.setPostKeydownFinishHandler(postKeyDownFinishHandler);
+ if ((attributeName.trim() || newText.trim()) && oldText !== newText) {
+ this._node.setAttribute(attributeName, newText, moveToNextAttributeIfNeeded.bind(this));
+ return;
+ }
- this._editing = WebInspector.InplaceEditor.startEditing(attribute, config);
+ this.updateTitle();
+ moveToNextAttributeIfNeeded.call(this);
+ }
- this.listItemElement.getComponentSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1);
+ _tagNameEditingCommitted(element, newText, oldText, tagName, moveDirection) {
+ delete this._editing;
+ var self = this;
- return true;
- },
+ function cancel() {
+ var closingTagElement = self._distinctClosingTagElement();
+ if (closingTagElement)
+ closingTagElement.textContent = '</' + tagName + '>';
- /**
- * @param {!Element} textNodeElement
- */
- _startEditingTextNode: function(textNodeElement)
- {
- if (WebInspector.isBeingEdited(textNodeElement))
- return true;
-
- var textNode = this._node;
- // We only show text nodes inline in elements if the element only
- // has a single child, and that child is a text node.
- if (textNode.nodeType() === Node.ELEMENT_NODE && textNode.firstChild)
- textNode = textNode.firstChild;
-
- var container = textNodeElement.enclosingNodeOrSelfWithClass("webkit-html-text-node");
- if (container)
- container.textContent = textNode.nodeValue(); // Strip the CSS or JS highlighting if present.
- var config = new WebInspector.InplaceEditor.Config(this._textNodeEditingCommitted.bind(this, textNode), this._editingCancelled.bind(this));
- this._editing = WebInspector.InplaceEditor.startEditing(textNodeElement, config);
- this.listItemElement.getComponentSelection().setBaseAndExtent(textNodeElement, 0, textNodeElement, 1);
-
- return true;
- },
+ self._editingCancelled(element, tagName);
+ moveToNextAttributeIfNeeded.call(self);
+ }
/**
- * @param {!Element=} tagNameElement
+ * @this {WebInspector.ElementsTreeElement}
*/
- _startEditingTagName: function(tagNameElement)
- {
- if (!tagNameElement) {
- tagNameElement = this.listItemElement.getElementsByClassName("webkit-html-tag-name")[0];
- if (!tagNameElement)
- return false;
- }
-
- var tagName = tagNameElement.textContent;
- if (WebInspector.ElementsTreeElement.EditTagBlacklist.has(tagName.toLowerCase()))
- return false;
-
- if (WebInspector.isBeingEdited(tagNameElement))
- return true;
-
- var closingTagElement = this._distinctClosingTagElement();
+ function moveToNextAttributeIfNeeded() {
+ if (moveDirection !== 'forward') {
+ this._addNewAttribute();
+ return;
+ }
+
+ var attributes = this._node.attributes();
+ if (attributes.length > 0)
+ this._triggerEditAttribute(attributes[0].name);
+ else
+ this._addNewAttribute();
+ }
- /**
- * @param {!Event} event
- */
- function keyupListener(event)
- {
- if (closingTagElement)
- closingTagElement.textContent = "</" + tagNameElement.textContent + ">";
- }
+ newText = newText.trim();
+ if (newText === oldText) {
+ cancel();
+ return;
+ }
- /**
- * @param {!Element} element
- * @param {string} newTagName
- * @this {WebInspector.ElementsTreeElement}
- */
- function editingComitted(element, newTagName)
- {
- tagNameElement.removeEventListener("keyup", keyupListener, false);
- this._tagNameEditingCommitted.apply(this, arguments);
- }
+ var treeOutline = this.treeOutline;
+ var wasExpanded = this.expanded;
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function editingCancelled()
- {
- tagNameElement.removeEventListener("keyup", keyupListener, false);
- this._editingCancelled.apply(this, arguments);
- }
-
- tagNameElement.addEventListener("keyup", keyupListener, false);
+ function changeTagNameCallback(error, nodeId) {
+ if (error || !nodeId) {
+ cancel();
+ return;
+ }
+ var newTreeItem = treeOutline.selectNodeAfterEdit(wasExpanded, error, nodeId);
+ moveToNextAttributeIfNeeded.call(newTreeItem);
+ }
+ this._node.setNodeName(newText, changeTagNameCallback);
+ }
- var config = new WebInspector.InplaceEditor.Config(editingComitted.bind(this), editingCancelled.bind(this), tagName);
- this._editing = WebInspector.InplaceEditor.startEditing(tagNameElement, config);
- this.listItemElement.getComponentSelection().setBaseAndExtent(tagNameElement, 0, tagNameElement, 1);
- return true;
- },
+ /**
+ * @param {!WebInspector.DOMNode} textNode
+ * @param {!Element} element
+ * @param {string} newText
+ */
+ _textNodeEditingCommitted(textNode, element, newText) {
+ delete this._editing;
/**
- * @param {function(string, string)} commitCallback
- * @param {function()} disposeCallback
- * @param {?Protocol.Error} error
- * @param {string} initialValue
+ * @this {WebInspector.ElementsTreeElement}
*/
- _startEditingAsHTML: function(commitCallback, disposeCallback, error, initialValue)
- {
- if (error)
- return;
- if (this._editing)
- return;
-
- function consume(event)
- {
- if (event.eventPhase === Event.AT_TARGET)
- event.consume(true);
- }
+ function callback() {
+ this.updateTitle();
+ }
+ textNode.setNodeValue(newText, callback.bind(this));
+ }
+
+ /**
+ * @param {!Element} element
+ * @param {*} context
+ */
+ _editingCancelled(element, context) {
+ delete this._editing;
+
+ // Need to restore attributes structure.
+ this.updateTitle();
+ }
+
+ /**
+ * @return {!Element}
+ */
+ _distinctClosingTagElement() {
+ // FIXME: Improve the Tree Element / Outline Abstraction to prevent crawling the DOM
+
+ // For an expanded element, it will be the last element with class "close"
+ // in the child element list.
+ if (this.expanded) {
+ var closers = this._childrenListNode.querySelectorAll('.close');
+ return closers[closers.length - 1];
+ }
- initialValue = this._convertWhitespaceToEntities(initialValue).text;
+ // Remaining cases are single line non-expanded elements with a closing
+ // tag, or HTML elements without a closing tag (such as <br>). Return
+ // null in the case where there isn't a closing tag.
+ var tags = this.listItemElement.getElementsByClassName('webkit-html-tag');
+ return (tags.length === 1 ? null : tags[tags.length - 1]);
+ }
+
+ /**
+ * @param {?WebInspector.ElementsTreeOutline.UpdateRecord=} updateRecord
+ * @param {boolean=} onlySearchQueryChanged
+ */
+ updateTitle(updateRecord, onlySearchQueryChanged) {
+ // If we are editing, return early to prevent canceling the edit.
+ // After editing is committed updateTitle will be called.
+ if (this._editing)
+ return;
+
+ if (onlySearchQueryChanged) {
+ this._hideSearchHighlight();
+ } else {
+ var nodeInfo = this._nodeTitleInfo(updateRecord || null);
+ if (this._node.nodeType() === Node.DOCUMENT_FRAGMENT_NODE && this._node.isInShadowTree() &&
+ this._node.shadowRootType()) {
+ this.childrenListElement.classList.add('shadow-root');
+ var depth = 4;
+ for (var node = this._node; depth && node; node = node.parentNode) {
+ if (node.nodeType() === Node.DOCUMENT_FRAGMENT_NODE)
+ depth--;
+ }
+ if (!depth)
+ this.childrenListElement.classList.add('shadow-root-deep');
+ else
+ this.childrenListElement.classList.add('shadow-root-depth-' + depth);
+ }
+ var highlightElement = createElement('span');
+ highlightElement.className = 'highlight';
+ highlightElement.appendChild(nodeInfo);
+ this.title = highlightElement;
+ this.updateDecorations();
+ this.listItemElement.insertBefore(this._gutterContainer, this.listItemElement.firstChild);
+ delete this._highlightResult;
+ }
- this._htmlEditElement = createElement("div");
- this._htmlEditElement.className = "source-code elements-tree-editor";
+ delete this.selectionElement;
+ if (this.selected)
+ this._createSelection();
+ this._preventFollowingLinksOnDoubleClick();
+ this._highlightSearchResults();
+ }
+
+ /**
+ * @return {number}
+ */
+ _computeLeftIndent() {
+ var treeElement = this.parent;
+ var depth = 0;
+ while (treeElement !== null) {
+ depth++;
+ treeElement = treeElement.parent;
+ }
- // Hide header items.
- var child = this.listItemElement.firstChild;
- while (child) {
- child.style.display = "none";
- child = child.nextSibling;
- }
- // Hide children item.
- if (this._childrenListNode)
- this._childrenListNode.style.display = "none";
- // Append editor.
- this.listItemElement.appendChild(this._htmlEditElement);
- this.listItemElement.classList.add("editing-as-html");
- this.treeOutline.element.addEventListener("mousedown", consume, false);
-
- /**
- * @param {!Element} element
- * @param {string} newValue
- * @this {WebInspector.ElementsTreeElement}
- */
- function commit(element, newValue)
- {
- commitCallback(initialValue, newValue);
- dispose.call(this);
- }
+ /** Keep it in sync with elementsTreeOutline.css **/
+ return 12 * (depth - 2) + (this.isExpandable() ? 1 : 12);
+ }
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function dispose()
- {
- disposeCallback();
- delete this._editing;
- this.treeOutline.setMultilineEditing(null);
-
- this.listItemElement.classList.remove("editing-as-html");
- // Remove editor.
- this.listItemElement.removeChild(this._htmlEditElement);
- delete this._htmlEditElement;
- // Unhide children item.
- if (this._childrenListNode)
- this._childrenListNode.style.removeProperty("display");
- // Unhide header items.
- var child = this.listItemElement.firstChild;
- while (child) {
- child.style.removeProperty("display");
- child = child.nextSibling;
- }
-
- this.treeOutline.element.removeEventListener("mousedown", consume, false);
- this.treeOutline.focus();
- }
+ updateDecorations() {
+ this._gutterContainer.style.left = (-this._computeLeftIndent()) + 'px';
- var config = new WebInspector.InplaceEditor.Config(commit.bind(this), dispose.bind(this));
- config.setMultilineOptions(initialValue, { name: "xml", htmlMode: true }, "web-inspector-html", WebInspector.moduleSetting("domWordWrap").get(), true);
- WebInspector.InplaceEditor.startMultilineEditing(this._htmlEditElement, config).then(markAsBeingEdited.bind(this));
-
- /**
- * @param {!Object} controller
- * @this {WebInspector.ElementsTreeElement}
- */
- function markAsBeingEdited(controller)
- {
- this._editing = /** @type {!WebInspector.InplaceEditor.Controller} */ (controller);
- this._editing.setWidth(this.treeOutline.visibleWidth() - this._computeLeftIndent());
- this.treeOutline.setMultilineEditing(this._editing);
- }
- },
-
- _attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection)
- {
- delete this._editing;
-
- var treeOutline = this.treeOutline;
-
- /**
- * @param {?Protocol.Error=} error
- * @this {WebInspector.ElementsTreeElement}
- */
- function moveToNextAttributeIfNeeded(error)
- {
- if (error)
- this._editingCancelled(element, attributeName);
-
- if (!moveDirection)
- return;
-
- treeOutline.runPendingUpdates();
-
- // Search for the attribute's position, and then decide where to move to.
- var attributes = this._node.attributes();
- for (var i = 0; i < attributes.length; ++i) {
- if (attributes[i].name !== attributeName)
- continue;
-
- if (moveDirection === "backward") {
- if (i === 0)
- this._startEditingTagName();
- else
- this._triggerEditAttribute(attributes[i - 1].name);
- } else {
- if (i === attributes.length - 1)
- this._addNewAttribute();
- else
- this._triggerEditAttribute(attributes[i + 1].name);
- }
- return;
- }
-
- // Moving From the "New Attribute" position.
- if (moveDirection === "backward") {
- if (newText === " ") {
- // Moving from "New Attribute" that was not edited
- if (attributes.length > 0)
- this._triggerEditAttribute(attributes[attributes.length - 1].name);
- } else {
- // Moving from "New Attribute" that holds new value
- if (attributes.length > 1)
- this._triggerEditAttribute(attributes[attributes.length - 2].name);
- }
- } else if (moveDirection === "forward") {
- if (!newText.isWhitespace())
- this._addNewAttribute();
- else
- this._startEditingTagName();
- }
- }
+ if (this.isClosingTag())
+ return;
+ var node = this._node;
+ if (node.nodeType() !== Node.ELEMENT_NODE)
+ return;
- if ((attributeName.trim() || newText.trim()) && oldText !== newText) {
- this._node.setAttribute(attributeName, newText, moveToNextAttributeIfNeeded.bind(this));
- return;
- }
+ if (!this.treeOutline._decoratorExtensions)
+ /** @type {!Array.<!Runtime.Extension>} */
+ this.treeOutline._decoratorExtensions = runtime.extensions(WebInspector.DOMPresentationUtils.MarkerDecorator);
- this.updateTitle();
- moveToNextAttributeIfNeeded.call(this);
- },
+ var markerToExtension = new Map();
+ for (var i = 0; i < this.treeOutline._decoratorExtensions.length; ++i)
+ markerToExtension.set(
+ this.treeOutline._decoratorExtensions[i].descriptor()['marker'], this.treeOutline._decoratorExtensions[i]);
- _tagNameEditingCommitted: function(element, newText, oldText, tagName, moveDirection)
- {
- delete this._editing;
- var self = this;
+ var promises = [];
+ var decorations = [];
+ var descendantDecorations = [];
+ node.traverseMarkers(visitor);
- function cancel()
- {
- var closingTagElement = self._distinctClosingTagElement();
- if (closingTagElement)
- closingTagElement.textContent = "</" + tagName + ">";
+ /**
+ * @param {!WebInspector.DOMNode} n
+ * @param {string} marker
+ */
+ function visitor(n, marker) {
+ var extension = markerToExtension.get(marker);
+ if (!extension)
+ return;
+ promises.push(extension.instance().then(collectDecoration.bind(null, n)));
+ }
- self._editingCancelled(element, tagName);
- moveToNextAttributeIfNeeded.call(self);
- }
+ /**
+ * @param {!WebInspector.DOMNode} n
+ * @param {!WebInspector.DOMPresentationUtils.MarkerDecorator} decorator
+ */
+ function collectDecoration(n, decorator) {
+ var decoration = decorator.decorate(n);
+ if (!decoration)
+ return;
+ (n === node ? decorations : descendantDecorations).push(decoration);
+ }
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function moveToNextAttributeIfNeeded()
- {
- if (moveDirection !== "forward") {
- this._addNewAttribute();
- return;
- }
-
- var attributes = this._node.attributes();
- if (attributes.length > 0)
- this._triggerEditAttribute(attributes[0].name);
- else
- this._addNewAttribute();
- }
+ Promise.all(promises).then(updateDecorationsUI.bind(this));
- newText = newText.trim();
- if (newText === oldText) {
- cancel();
- return;
+ /**
+ * @this {WebInspector.ElementsTreeElement}
+ */
+ function updateDecorationsUI() {
+ this._decorationsElement.removeChildren();
+ this._decorationsElement.classList.add('hidden');
+ this._gutterContainer.classList.toggle('has-decorations', decorations.length || descendantDecorations.length);
+
+ if (!decorations.length && !descendantDecorations.length)
+ return;
+
+ var colors = new Set();
+ var titles = createElement('div');
+
+ for (var decoration of decorations) {
+ var titleElement = titles.createChild('div');
+ titleElement.textContent = decoration.title;
+ colors.add(decoration.color);
+ }
+ if (this.expanded && !decorations.length)
+ return;
+
+ var descendantColors = new Set();
+ if (descendantDecorations.length) {
+ var element = titles.createChild('div');
+ element.textContent = WebInspector.UIString('Children:');
+ for (var decoration of descendantDecorations) {
+ element = titles.createChild('div');
+ element.style.marginLeft = '15px';
+ element.textContent = decoration.title;
+ descendantColors.add(decoration.color);
}
-
- var treeOutline = this.treeOutline;
- var wasExpanded = this.expanded;
-
- function changeTagNameCallback(error, nodeId)
- {
- if (error || !nodeId) {
- cancel();
- return;
- }
- var newTreeItem = treeOutline.selectNodeAfterEdit(wasExpanded, error, nodeId);
- moveToNextAttributeIfNeeded.call(newTreeItem);
+ }
+
+ var offset = 0;
+ processColors.call(this, colors, 'elements-gutter-decoration');
+ if (!this.expanded)
+ processColors.call(this, descendantColors, 'elements-gutter-decoration elements-has-decorated-children');
+ WebInspector.Tooltip.install(this._decorationsElement, titles);
+
+ /**
+ * @param {!Set<string>} colors
+ * @param {string} className
+ * @this {WebInspector.ElementsTreeElement}
+ */
+ function processColors(colors, className) {
+ for (var color of colors) {
+ var child = this._decorationsElement.createChild('div', className);
+ this._decorationsElement.classList.remove('hidden');
+ child.style.backgroundColor = color;
+ child.style.borderColor = color;
+ if (offset)
+ child.style.marginLeft = offset + 'px';
+ offset += 3;
}
- this._node.setNodeName(newText, changeTagNameCallback);
- },
+ }
+ }
+ }
+
+ /**
+ * @param {!Node} parentElement
+ * @param {string} name
+ * @param {string} value
+ * @param {?WebInspector.ElementsTreeOutline.UpdateRecord} updateRecord
+ * @param {boolean=} forceValue
+ * @param {!WebInspector.DOMNode=} node
+ */
+ _buildAttributeDOM(parentElement, name, value, updateRecord, forceValue, node) {
+ var closingPunctuationRegex = /[\/;:\)\]\}]/g;
+ var highlightIndex = 0;
+ var highlightCount;
+ var additionalHighlightOffset = 0;
+ var result;
/**
- * @param {!WebInspector.DOMNode} textNode
- * @param {!Element} element
- * @param {string} newText
+ * @param {string} match
+ * @param {number} replaceOffset
+ * @return {string}
*/
- _textNodeEditingCommitted: function(textNode, element, newText)
- {
- delete this._editing;
-
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function callback()
- {
- this.updateTitle();
- }
- textNode.setNodeValue(newText, callback.bind(this));
- },
+ function replacer(match, replaceOffset) {
+ while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
+ result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
+ ++highlightIndex;
+ }
+ additionalHighlightOffset += 1;
+ return match + '\u200B';
+ }
/**
* @param {!Element} element
- * @param {*} context
+ * @param {string} value
+ * @this {WebInspector.ElementsTreeElement}
*/
- _editingCancelled: function(element, context)
- {
- delete this._editing;
+ function setValueWithEntities(element, value) {
+ result = this._convertWhitespaceToEntities(value);
+ highlightCount = result.entityRanges.length;
+ value = result.text.replace(closingPunctuationRegex, replacer);
+ while (highlightIndex < highlightCount) {
+ result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
+ ++highlightIndex;
+ }
+ element.setTextContentTruncatedIfNeeded(value);
+ WebInspector.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
+ }
- // Need to restore attributes structure.
- this.updateTitle();
- },
+ var hasText = (forceValue || value.length > 0);
+ var attrSpanElement = parentElement.createChild('span', 'webkit-html-attribute');
+ var attrNameElement = attrSpanElement.createChild('span', 'webkit-html-attribute-name');
+ attrNameElement.textContent = name;
- /**
- * @return {!Element}
- */
- _distinctClosingTagElement: function()
- {
- // FIXME: Improve the Tree Element / Outline Abstraction to prevent crawling the DOM
-
- // For an expanded element, it will be the last element with class "close"
- // in the child element list.
- if (this.expanded) {
- var closers = this._childrenListNode.querySelectorAll(".close");
- return closers[closers.length - 1];
- }
+ if (hasText)
+ attrSpanElement.createTextChild('=\u200B"');
+
+ var attrValueElement = attrSpanElement.createChild('span', 'webkit-html-attribute-value');
- // Remaining cases are single line non-expanded elements with a closing
- // tag, or HTML elements without a closing tag (such as <br>). Return
- // null in the case where there isn't a closing tag.
- var tags = this.listItemElement.getElementsByClassName("webkit-html-tag");
- return (tags.length === 1 ? null : tags[tags.length - 1]);
- },
+ if (updateRecord && updateRecord.isAttributeModified(name))
+ WebInspector.runCSSAnimationOnce(hasText ? attrValueElement : attrNameElement, 'dom-update-highlight');
/**
- * @param {?WebInspector.ElementsTreeOutline.UpdateRecord=} updateRecord
- * @param {boolean=} onlySearchQueryChanged
+ * @this {WebInspector.ElementsTreeElement}
+ * @param {string} value
+ * @return {!Element}
*/
- updateTitle: function(updateRecord, onlySearchQueryChanged)
- {
- // If we are editing, return early to prevent canceling the edit.
- // After editing is committed updateTitle will be called.
- if (this._editing)
- return;
-
- if (onlySearchQueryChanged) {
- this._hideSearchHighlight();
+ function linkifyValue(value) {
+ var rewrittenHref = node.resolveURL(value);
+ if (rewrittenHref === null) {
+ var span = createElement('span');
+ setValueWithEntities.call(this, span, value);
+ return span;
+ }
+ value = value.replace(closingPunctuationRegex, '$&\u200B');
+ if (value.startsWith('data:'))
+ value = value.trimMiddle(60);
+ var anchor = WebInspector.linkifyURLAsNode(rewrittenHref, value, '', node.nodeName().toLowerCase() === 'a');
+ anchor.preventFollow = true;
+ return anchor;
+ }
+
+ if (node && (name === 'src' || name === 'href')) {
+ attrValueElement.appendChild(linkifyValue.call(this, value));
+ } else if (
+ node && (node.nodeName().toLowerCase() === 'img' || node.nodeName().toLowerCase() === 'source') &&
+ name === 'srcset') {
+ var sources = value.split(',');
+ for (var i = 0; i < sources.length; ++i) {
+ if (i > 0)
+ attrValueElement.createTextChild(', ');
+ var source = sources[i].trim();
+ var indexOfSpace = source.indexOf(' ');
+ var url, tail;
+
+ if (indexOfSpace === -1) {
+ url = source;
} else {
- var nodeInfo = this._nodeTitleInfo(updateRecord || null);
- if (this._node.nodeType() === Node.DOCUMENT_FRAGMENT_NODE && this._node.isInShadowTree() && this._node.shadowRootType()) {
- this.childrenListElement.classList.add("shadow-root");
- var depth = 4;
- for (var node = this._node; depth && node; node = node.parentNode) {
- if (node.nodeType() === Node.DOCUMENT_FRAGMENT_NODE)
- depth--;
- }
- if (!depth)
- this.childrenListElement.classList.add("shadow-root-deep");
- else
- this.childrenListElement.classList.add("shadow-root-depth-" + depth);
- }
- var highlightElement = createElement("span");
- highlightElement.className = "highlight";
- highlightElement.appendChild(nodeInfo);
- this.title = highlightElement;
- this.updateDecorations();
- this.listItemElement.insertBefore(this._gutterContainer, this.listItemElement.firstChild);
- delete this._highlightResult;
+ url = source.substring(0, indexOfSpace);
+ tail = source.substring(indexOfSpace);
}
- delete this.selectionElement;
- if (this.selected)
- this._createSelection();
- this._preventFollowingLinksOnDoubleClick();
- this._highlightSearchResults();
- },
+ attrValueElement.appendChild(linkifyValue.call(this, url));
- /**
- * @return {number}
- */
- _computeLeftIndent: function()
- {
- var treeElement = this.parent;
- var depth = 0;
- while (treeElement !== null) {
- depth++;
- treeElement = treeElement.parent;
- }
+ if (tail)
+ attrValueElement.createTextChild(tail);
+ }
+ } else {
+ setValueWithEntities.call(this, attrValueElement, value);
+ }
- /** Keep it in sync with elementsTreeOutline.css **/
- return 12 * (depth - 2) + (this.isExpandable() ? 1 : 12);
- },
-
- updateDecorations: function()
- {
- this._gutterContainer.style.left = (-this._computeLeftIndent()) + "px";
-
- if (this.isClosingTag())
- return;
-
- var node = this._node;
- if (node.nodeType() !== Node.ELEMENT_NODE)
- return;
-
- if (!this.treeOutline._decoratorExtensions)
- /** @type {!Array.<!Runtime.Extension>} */
- this.treeOutline._decoratorExtensions = runtime.extensions(WebInspector.DOMPresentationUtils.MarkerDecorator);
-
- var markerToExtension = new Map();
- for (var i = 0; i < this.treeOutline._decoratorExtensions.length; ++i)
- markerToExtension.set(this.treeOutline._decoratorExtensions[i].descriptor()["marker"], this.treeOutline._decoratorExtensions[i]);
-
- var promises = [];
- var decorations = [];
- var descendantDecorations = [];
- node.traverseMarkers(visitor);
-
- /**
- * @param {!WebInspector.DOMNode} n
- * @param {string} marker
- */
- function visitor(n, marker)
- {
- var extension = markerToExtension.get(marker);
- if (!extension)
- return;
- promises.push(extension.instance().then(collectDecoration.bind(null, n)));
+ if (hasText)
+ attrSpanElement.createTextChild('"');
+ }
+
+ /**
+ * @param {!Node} parentElement
+ * @param {string} pseudoElementName
+ */
+ _buildPseudoElementDOM(parentElement, pseudoElementName) {
+ var pseudoElement = parentElement.createChild('span', 'webkit-html-pseudo-element');
+ pseudoElement.textContent = '::' + pseudoElementName;
+ parentElement.createTextChild('\u200B');
+ }
+
+ /**
+ * @param {!Node} parentElement
+ * @param {string} tagName
+ * @param {boolean} isClosingTag
+ * @param {boolean} isDistinctTreeElement
+ * @param {?WebInspector.ElementsTreeOutline.UpdateRecord} updateRecord
+ */
+ _buildTagDOM(parentElement, tagName, isClosingTag, isDistinctTreeElement, updateRecord) {
+ var node = this._node;
+ var classes = ['webkit-html-tag'];
+ if (isClosingTag && isDistinctTreeElement)
+ classes.push('close');
+ var tagElement = parentElement.createChild('span', classes.join(' '));
+ tagElement.createTextChild('<');
+ var tagNameElement =
+ tagElement.createChild('span', isClosingTag ? 'webkit-html-close-tag-name' : 'webkit-html-tag-name');
+ tagNameElement.textContent = (isClosingTag ? '/' : '') + tagName;
+ if (!isClosingTag) {
+ if (node.hasAttributes()) {
+ var attributes = node.attributes();
+ for (var i = 0; i < attributes.length; ++i) {
+ var attr = attributes[i];
+ tagElement.createTextChild(' ');
+ this._buildAttributeDOM(tagElement, attr.name, attr.value, updateRecord, false, node);
}
+ }
+ if (updateRecord) {
+ var hasUpdates = updateRecord.hasRemovedAttributes() || updateRecord.hasRemovedChildren();
+ hasUpdates |= !this.expanded && updateRecord.hasChangedChildren();
+ if (hasUpdates)
+ WebInspector.runCSSAnimationOnce(tagNameElement, 'dom-update-highlight');
+ }
+ }
- /**
- * @param {!WebInspector.DOMNode} n
- * @param {!WebInspector.DOMPresentationUtils.MarkerDecorator} decorator
- */
- function collectDecoration(n, decorator)
- {
- var decoration = decorator.decorate(n);
- if (!decoration)
- return;
- (n === node ? decorations : descendantDecorations).push(decoration);
+ tagElement.createTextChild('>');
+ parentElement.createTextChild('\u200B');
+ }
+
+ /**
+ * @param {string} text
+ * @return {!{text: string, entityRanges: !Array.<!WebInspector.SourceRange>}}
+ */
+ _convertWhitespaceToEntities(text) {
+ var result = '';
+ var lastIndexAfterEntity = 0;
+ var entityRanges = [];
+ var charToEntity = WebInspector.ElementsTreeOutline.MappedCharToEntity;
+ for (var i = 0, size = text.length; i < size; ++i) {
+ var char = text.charAt(i);
+ if (charToEntity[char]) {
+ result += text.substring(lastIndexAfterEntity, i);
+ var entityValue = '&' + charToEntity[char] + ';';
+ entityRanges.push({offset: result.length, length: entityValue.length});
+ result += entityValue;
+ lastIndexAfterEntity = i + 1;
+ }
+ }
+ if (result)
+ result += text.substring(lastIndexAfterEntity);
+ return {text: result || text, entityRanges: entityRanges};
+ }
+
+ /**
+ * @param {?WebInspector.ElementsTreeOutline.UpdateRecord} updateRecord
+ * @return {!DocumentFragment} result
+ */
+ _nodeTitleInfo(updateRecord) {
+ var node = this._node;
+ var titleDOM = createDocumentFragment();
+
+ switch (node.nodeType()) {
+ case Node.ATTRIBUTE_NODE:
+ this._buildAttributeDOM(
+ titleDOM, /** @type {string} */ (node.name), /** @type {string} */ (node.value), updateRecord, true);
+ break;
+
+ case Node.ELEMENT_NODE:
+ var pseudoType = node.pseudoType();
+ if (pseudoType) {
+ this._buildPseudoElementDOM(titleDOM, pseudoType);
+ break;
}
- Promise.all(promises).then(updateDecorationsUI.bind(this));
-
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function updateDecorationsUI()
- {
- this._decorationsElement.removeChildren();
- this._decorationsElement.classList.add("hidden");
- this._gutterContainer.classList.toggle("has-decorations", decorations.length || descendantDecorations.length);
-
- if (!decorations.length && !descendantDecorations.length)
- return;
-
- var colors = new Set();
- var titles = createElement("div");
-
- for (var decoration of decorations) {
- var titleElement = titles.createChild("div");
- titleElement.textContent = decoration.title;
- colors.add(decoration.color);
- }
- if (this.expanded && !decorations.length)
- return;
-
- var descendantColors = new Set();
- if (descendantDecorations.length) {
- var element = titles.createChild("div");
- element.textContent = WebInspector.UIString("Children:");
- for (var decoration of descendantDecorations) {
- element = titles.createChild("div");
- element.style.marginLeft = "15px";
- element.textContent = decoration.title;
- descendantColors.add(decoration.color);
- }
- }
-
- var offset = 0;
- processColors.call(this, colors, "elements-gutter-decoration");
- if (!this.expanded)
- processColors.call(this, descendantColors, "elements-gutter-decoration elements-has-decorated-children");
- WebInspector.Tooltip.install(this._decorationsElement, titles);
-
- /**
- * @param {!Set<string>} colors
- * @param {string} className
- * @this {WebInspector.ElementsTreeElement}
- */
- function processColors(colors, className)
- {
- for (var color of colors) {
- var child = this._decorationsElement.createChild("div", className);
- this._decorationsElement.classList.remove("hidden");
- child.style.backgroundColor = color;
- child.style.borderColor = color;
- if (offset)
- child.style.marginLeft = offset + "px";
- offset += 3;
- }
- }
+ var tagName = node.nodeNameInCorrectCase();
+ if (this._elementCloseTag) {
+ this._buildTagDOM(titleDOM, tagName, true, true, updateRecord);
+ break;
}
- },
- /**
- * @param {!Node} parentElement
- * @param {string} name
- * @param {string} value
- * @param {?WebInspector.ElementsTreeOutline.UpdateRecord} updateRecord
- * @param {boolean=} forceValue
- * @param {!WebInspector.DOMNode=} node
- */
- _buildAttributeDOM: function(parentElement, name, value, updateRecord, forceValue, node)
- {
- var closingPunctuationRegex = /[\/;:\)\]\}]/g;
- var highlightIndex = 0;
- var highlightCount;
- var additionalHighlightOffset = 0;
- var result;
-
- /**
- * @param {string} match
- * @param {number} replaceOffset
- * @return {string}
- */
- function replacer(match, replaceOffset) {
- while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
- result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
- ++highlightIndex;
- }
- additionalHighlightOffset += 1;
- return match + "\u200B";
- }
+ this._buildTagDOM(titleDOM, tagName, false, false, updateRecord);
- /**
- * @param {!Element} element
- * @param {string} value
- * @this {WebInspector.ElementsTreeElement}
- */
- function setValueWithEntities(element, value)
- {
- result = this._convertWhitespaceToEntities(value);
- highlightCount = result.entityRanges.length;
- value = result.text.replace(closingPunctuationRegex, replacer);
- while (highlightIndex < highlightCount) {
- result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
- ++highlightIndex;
- }
- element.setTextContentTruncatedIfNeeded(value);
- WebInspector.highlightRangesWithStyleClass(element, result.entityRanges, "webkit-html-entity-value");
+ if (this.isExpandable()) {
+ if (!this.expanded) {
+ var textNodeElement = titleDOM.createChild('span', 'webkit-html-text-node bogus');
+ textNodeElement.textContent = '\u2026';
+ titleDOM.createTextChild('\u200B');
+ this._buildTagDOM(titleDOM, tagName, true, false, updateRecord);
+ }
+ break;
}
- var hasText = (forceValue || value.length > 0);
- var attrSpanElement = parentElement.createChild("span", "webkit-html-attribute");
- var attrNameElement = attrSpanElement.createChild("span", "webkit-html-attribute-name");
- attrNameElement.textContent = name;
-
- if (hasText)
- attrSpanElement.createTextChild("=\u200B\"");
-
- var attrValueElement = attrSpanElement.createChild("span", "webkit-html-attribute-value");
-
- if (updateRecord && updateRecord.isAttributeModified(name))
- WebInspector.runCSSAnimationOnce(hasText ? attrValueElement : attrNameElement, "dom-update-highlight");
-
- /**
- * @this {WebInspector.ElementsTreeElement}
- * @param {string} value
- * @return {!Element}
- */
- function linkifyValue(value)
- {
- var rewrittenHref = node.resolveURL(value);
- if (rewrittenHref === null) {
- var span = createElement("span");
- setValueWithEntities.call(this, span, value);
- return span;
- }
- value = value.replace(closingPunctuationRegex, "$&\u200B");
- if (value.startsWith("data:"))
- value = value.trimMiddle(60);
- var anchor = WebInspector.linkifyURLAsNode(rewrittenHref, value, "", node.nodeName().toLowerCase() === "a");
- anchor.preventFollow = true;
- return anchor;
+ if (WebInspector.ElementsTreeElement.canShowInlineText(node)) {
+ var textNodeElement = 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');
+ titleDOM.createTextChild('\u200B');
+ this._buildTagDOM(titleDOM, tagName, true, false, updateRecord);
+ if (updateRecord && updateRecord.hasChangedChildren())
+ WebInspector.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');
+ if (updateRecord && updateRecord.isCharDataModified())
+ WebInspector.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');
+ break;
}
- if (node && (name === "src" || name === "href")) {
- attrValueElement.appendChild(linkifyValue.call(this, value));
- } else if (node && (node.nodeName().toLowerCase() === "img" || node.nodeName().toLowerCase() === "source") && name === "srcset") {
- var sources = value.split(",");
- for (var i = 0; i < sources.length; ++i) {
- if (i > 0)
- attrValueElement.createTextChild(", ");
- var source = sources[i].trim();
- var indexOfSpace = source.indexOf(" ");
- var url, tail;
-
- if (indexOfSpace === -1) {
- url = source;
- } else {
- url = source.substring(0, indexOfSpace);
- tail = source.substring(indexOfSpace);
- }
-
- attrValueElement.appendChild(linkifyValue.call(this, url));
-
- if (tail)
- attrValueElement.createTextChild(tail);
- }
+ if (this.treeOutline.isXMLMimeType ||
+ !WebInspector.ElementsTreeElement.ForbiddenClosingTagElements.has(tagName))
+ this._buildTagDOM(titleDOM, tagName, true, false, updateRecord);
+ break;
+
+ case Node.TEXT_NODE:
+ if (node.parentNode && node.parentNode.nodeName().toLowerCase() === 'script') {
+ var newNode = titleDOM.createChild('span', 'webkit-html-text-node webkit-html-js-node');
+ var text = node.nodeValue();
+ newNode.textContent = text.startsWith('\n') ? text.substring(1) : text;
+
+ var javascriptSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter('text/javascript', true);
+ javascriptSyntaxHighlighter.syntaxHighlightNode(newNode).then(updateSearchHighlight.bind(this));
+ } else if (node.parentNode && node.parentNode.nodeName().toLowerCase() === 'style') {
+ var newNode = titleDOM.createChild('span', 'webkit-html-text-node webkit-html-css-node');
+ var text = node.nodeValue();
+ newNode.textContent = text.startsWith('\n') ? text.substring(1) : text;
+
+ var cssSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter('text/css', true);
+ cssSyntaxHighlighter.syntaxHighlightNode(newNode).then(updateSearchHighlight.bind(this));
} else {
- setValueWithEntities.call(this, attrValueElement, value);
+ titleDOM.createTextChild('"');
+ var textNodeElement = titleDOM.createChild('span', 'webkit-html-text-node');
+ var result = this._convertWhitespaceToEntities(node.nodeValue());
+ textNodeElement.textContent = result.text;
+ WebInspector.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
+ titleDOM.createTextChild('"');
+ if (updateRecord && updateRecord.isCharDataModified())
+ WebInspector.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');
}
-
- if (hasText)
- attrSpanElement.createTextChild("\"");
- },
+ break;
+
+ case Node.COMMENT_NODE:
+ var commentElement = titleDOM.createChild('span', 'webkit-html-comment');
+ commentElement.createTextChild('<!--' + node.nodeValue() + '-->');
+ break;
+
+ case Node.DOCUMENT_TYPE_NODE:
+ var docTypeElement = titleDOM.createChild('span', 'webkit-html-doctype');
+ docTypeElement.createTextChild('<!DOCTYPE ' + node.nodeName());
+ if (node.publicId) {
+ docTypeElement.createTextChild(' PUBLIC "' + node.publicId + '"');
+ if (node.systemId)
+ docTypeElement.createTextChild(' "' + node.systemId + '"');
+ } else if (node.systemId)
+ docTypeElement.createTextChild(' SYSTEM "' + node.systemId + '"');
+
+ if (node.internalSubset)
+ docTypeElement.createTextChild(' [' + node.internalSubset + ']');
+
+ docTypeElement.createTextChild('>');
+ break;
+
+ case Node.CDATA_SECTION_NODE:
+ var cdataElement = titleDOM.createChild('span', 'webkit-html-text-node');
+ cdataElement.createTextChild('<![CDATA[' + node.nodeValue() + ']]>');
+ break;
+
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ var fragmentElement = titleDOM.createChild('span', 'webkit-html-fragment');
+ fragmentElement.textContent = node.nodeNameInCorrectCase().collapseWhitespace();
+ break;
+ default:
+ titleDOM.createTextChild(node.nodeNameInCorrectCase().collapseWhitespace());
+ }
/**
- * @param {!Node} parentElement
- * @param {string} pseudoElementName
+ * @this {WebInspector.ElementsTreeElement}
*/
- _buildPseudoElementDOM: function(parentElement, pseudoElementName)
- {
- var pseudoElement = parentElement.createChild("span", "webkit-html-pseudo-element");
- pseudoElement.textContent = "::" + pseudoElementName;
- parentElement.createTextChild("\u200B");
- },
+ function updateSearchHighlight() {
+ delete this._highlightResult;
+ this._highlightSearchResults();
+ }
- /**
- * @param {!Node} parentElement
- * @param {string} tagName
- * @param {boolean} isClosingTag
- * @param {boolean} isDistinctTreeElement
- * @param {?WebInspector.ElementsTreeOutline.UpdateRecord} updateRecord
- */
- _buildTagDOM: function(parentElement, tagName, isClosingTag, isDistinctTreeElement, updateRecord)
- {
- var node = this._node;
- var classes = [ "webkit-html-tag" ];
- if (isClosingTag && isDistinctTreeElement)
- classes.push("close");
- var tagElement = parentElement.createChild("span", classes.join(" "));
- tagElement.createTextChild("<");
- var tagNameElement = tagElement.createChild("span", isClosingTag ? "webkit-html-close-tag-name" : "webkit-html-tag-name");
- tagNameElement.textContent = (isClosingTag ? "/" : "") + tagName;
- if (!isClosingTag) {
- if (node.hasAttributes()) {
- var attributes = node.attributes();
- for (var i = 0; i < attributes.length; ++i) {
- var attr = attributes[i];
- tagElement.createTextChild(" ");
- this._buildAttributeDOM(tagElement, attr.name, attr.value, updateRecord, false, node);
- }
- }
- if (updateRecord) {
- var hasUpdates = updateRecord.hasRemovedAttributes() || updateRecord.hasRemovedChildren();
- hasUpdates |= !this.expanded && updateRecord.hasChangedChildren();
- if (hasUpdates)
- WebInspector.runCSSAnimationOnce(tagNameElement, "dom-update-highlight");
- }
- }
+ return titleDOM;
+ }
+
+ remove() {
+ if (this._node.pseudoType())
+ return;
+ var parentElement = this.parent;
+ if (!parentElement)
+ return;
+
+ if (!this._node.parentNode || this._node.parentNode.nodeType() === Node.DOCUMENT_NODE)
+ return;
+ this._node.removeNode();
+ }
+
+ /**
+ * @param {function(boolean)=} callback
+ * @param {boolean=} startEditing
+ */
+ toggleEditAsHTML(callback, startEditing) {
+ if (this._editing && this._htmlEditElement && WebInspector.isBeingEdited(this._htmlEditElement)) {
+ this._editing.commit();
+ return;
+ }
- tagElement.createTextChild(">");
- parentElement.createTextChild("\u200B");
- },
+ if (startEditing === false)
+ return;
/**
- * @param {string} text
- * @return {!{text: string, entityRanges: !Array.<!WebInspector.SourceRange>}}
+ * @param {?Protocol.Error} error
*/
- _convertWhitespaceToEntities: function(text)
- {
- var result = "";
- var lastIndexAfterEntity = 0;
- var entityRanges = [];
- var charToEntity = WebInspector.ElementsTreeOutline.MappedCharToEntity;
- for (var i = 0, size = text.length; i < size; ++i) {
- var char = text.charAt(i);
- if (charToEntity[char]) {
- result += text.substring(lastIndexAfterEntity, i);
- var entityValue = "&" + charToEntity[char] + ";";
- entityRanges.push({offset: result.length, length: entityValue.length});
- result += entityValue;
- lastIndexAfterEntity = i + 1;
- }
- }
- if (result)
- result += text.substring(lastIndexAfterEntity);
- return {text: result || text, entityRanges: entityRanges};
- },
+ function selectNode(error) {
+ if (callback)
+ callback(!error);
+ }
/**
- * @param {?WebInspector.ElementsTreeOutline.UpdateRecord} updateRecord
- * @return {!DocumentFragment} result
+ * @param {string} initialValue
+ * @param {string} value
*/
- _nodeTitleInfo: function(updateRecord)
- {
- var node = this._node;
- var titleDOM = createDocumentFragment();
-
- switch (node.nodeType()) {
- case Node.ATTRIBUTE_NODE:
- this._buildAttributeDOM(titleDOM, /** @type {string} */ (node.name), /** @type {string} */ (node.value), updateRecord, true);
- break;
-
- case Node.ELEMENT_NODE:
- var pseudoType = node.pseudoType();
- if (pseudoType) {
- this._buildPseudoElementDOM(titleDOM, pseudoType);
- break;
- }
-
- var tagName = node.nodeNameInCorrectCase();
- if (this._elementCloseTag) {
- this._buildTagDOM(titleDOM, tagName, true, true, updateRecord);
- break;
- }
-
- this._buildTagDOM(titleDOM, tagName, false, false, updateRecord);
-
- if (this.isExpandable()) {
- if (!this.expanded) {
- var textNodeElement = titleDOM.createChild("span", "webkit-html-text-node bogus");
- textNodeElement.textContent = "\u2026";
- titleDOM.createTextChild("\u200B");
- this._buildTagDOM(titleDOM, tagName, true, false, updateRecord);
- }
- break;
- }
-
- if (WebInspector.ElementsTreeElement.canShowInlineText(node)) {
- var textNodeElement = 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");
- titleDOM.createTextChild("\u200B");
- this._buildTagDOM(titleDOM, tagName, true, false, updateRecord);
- if (updateRecord && updateRecord.hasChangedChildren())
- WebInspector.runCSSAnimationOnce(textNodeElement, "dom-update-highlight");
- if (updateRecord && updateRecord.isCharDataModified())
- WebInspector.runCSSAnimationOnce(textNodeElement, "dom-update-highlight");
- break;
- }
-
- if (this.treeOutline.isXMLMimeType || !WebInspector.ElementsTreeElement.ForbiddenClosingTagElements.has(tagName))
- this._buildTagDOM(titleDOM, tagName, true, false, updateRecord);
- break;
-
- case Node.TEXT_NODE:
- if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "script") {
- var newNode = titleDOM.createChild("span", "webkit-html-text-node webkit-html-js-node");
- var text = node.nodeValue();
- newNode.textContent = text.startsWith("\n") ? text.substring(1) : text;
-
- var javascriptSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/javascript", true);
- javascriptSyntaxHighlighter.syntaxHighlightNode(newNode).then(updateSearchHighlight.bind(this));
- } else if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "style") {
- var newNode = titleDOM.createChild("span", "webkit-html-text-node webkit-html-css-node");
- var text = node.nodeValue();
- newNode.textContent = text.startsWith("\n") ? text.substring(1) : text;
-
- var cssSyntaxHighlighter = new WebInspector.DOMSyntaxHighlighter("text/css", true);
- cssSyntaxHighlighter.syntaxHighlightNode(newNode).then(updateSearchHighlight.bind(this));
- } else {
- titleDOM.createTextChild("\"");
- var textNodeElement = titleDOM.createChild("span", "webkit-html-text-node");
- var result = this._convertWhitespaceToEntities(node.nodeValue());
- textNodeElement.textContent = result.text;
- WebInspector.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, "webkit-html-entity-value");
- titleDOM.createTextChild("\"");
- if (updateRecord && updateRecord.isCharDataModified())
- WebInspector.runCSSAnimationOnce(textNodeElement, "dom-update-highlight");
- }
- break;
-
- case Node.COMMENT_NODE:
- var commentElement = titleDOM.createChild("span", "webkit-html-comment");
- commentElement.createTextChild("<!--" + node.nodeValue() + "-->");
- break;
-
- case Node.DOCUMENT_TYPE_NODE:
- var docTypeElement = titleDOM.createChild("span", "webkit-html-doctype");
- docTypeElement.createTextChild("<!DOCTYPE " + node.nodeName());
- if (node.publicId) {
- docTypeElement.createTextChild(" PUBLIC \"" + node.publicId + "\"");
- if (node.systemId)
- docTypeElement.createTextChild(" \"" + node.systemId + "\"");
- } else if (node.systemId)
- docTypeElement.createTextChild(" SYSTEM \"" + node.systemId + "\"");
-
- if (node.internalSubset)
- docTypeElement.createTextChild(" [" + node.internalSubset + "]");
-
- docTypeElement.createTextChild(">");
- break;
-
- case Node.CDATA_SECTION_NODE:
- var cdataElement = titleDOM.createChild("span", "webkit-html-text-node");
- cdataElement.createTextChild("<![CDATA[" + node.nodeValue() + "]]>");
- break;
-
- case Node.DOCUMENT_FRAGMENT_NODE:
- var fragmentElement = titleDOM.createChild("span", "webkit-html-fragment");
- fragmentElement.textContent = node.nodeNameInCorrectCase().collapseWhitespace();
- break;
- default:
- titleDOM.createTextChild(node.nodeNameInCorrectCase().collapseWhitespace());
- }
+ function commitChange(initialValue, value) {
+ if (initialValue !== value)
+ node.setOuterHTML(value, selectNode);
+ }
- /**
- * @this {WebInspector.ElementsTreeElement}
- */
- function updateSearchHighlight()
- {
- delete this._highlightResult;
- this._highlightSearchResults();
- }
+ function disposeCallback() {
+ if (callback)
+ callback(false);
+ }
- return titleDOM;
- },
+ var node = this._node;
+ node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange, disposeCallback));
+ }
- remove: function()
- {
- if (this._node.pseudoType())
- return;
- var parentElement = this.parent;
- if (!parentElement)
- return;
+ _copyCSSPath() {
+ InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath(this._node, true));
+ }
- if (!this._node.parentNode || this._node.parentNode.nodeType() === Node.DOCUMENT_NODE)
- return;
- this._node.removeNode();
- },
+ _copyXPath() {
+ InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.xPath(this._node, true));
+ }
- /**
- * @param {function(boolean)=} callback
- * @param {boolean=} startEditing
- */
- toggleEditAsHTML: function(callback, startEditing)
- {
- if (this._editing && this._htmlEditElement && WebInspector.isBeingEdited(this._htmlEditElement)) {
- this._editing.commit();
- return;
- }
+ _highlightSearchResults() {
+ if (!this._searchQuery || !this._searchHighlightsVisible)
+ return;
+ this._hideSearchHighlight();
- if (startEditing === false)
- return;
+ var text = this.listItemElement.textContent;
+ var regexObject = createPlainTextSearchRegex(this._searchQuery, 'gi');
- /**
- * @param {?Protocol.Error} error
- */
- function selectNode(error)
- {
- if (callback)
- callback(!error);
- }
+ var match = regexObject.exec(text);
+ var matchRanges = [];
+ while (match) {
+ matchRanges.push(new WebInspector.SourceRange(match.index, match[0].length));
+ match = regexObject.exec(text);
+ }
- /**
- * @param {string} initialValue
- * @param {string} value
- */
- function commitChange(initialValue, value)
- {
- if (initialValue !== value)
- node.setOuterHTML(value, selectNode);
- }
+ // Fall back for XPath, etc. matches.
+ if (!matchRanges.length)
+ matchRanges.push(new WebInspector.SourceRange(0, text.length));
+
+ this._highlightResult = [];
+ WebInspector.highlightSearchResults(this.listItemElement, matchRanges, this._highlightResult);
+ }
+
+ _scrollIntoView() {
+ function scrollIntoViewCallback(object) {
+ /**
+ * @suppressReceiverCheck
+ * @this {!Element}
+ */
+ function scrollIntoView() {
+ this.scrollIntoViewIfNeeded(true);
+ }
+
+ if (object)
+ object.callFunction(scrollIntoView);
+ }
- function disposeCallback()
- {
- if (callback)
- callback(false);
- }
+ this._node.resolveToObject('', scrollIntoViewCallback);
+ }
- var node = this._node;
- node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange, disposeCallback));
- },
-
- _copyCSSPath: function()
- {
- InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.cssPath(this._node, true));
- },
-
- _copyXPath: function()
- {
- InspectorFrontendHost.copyText(WebInspector.DOMPresentationUtils.xPath(this._node, true));
- },
-
- _highlightSearchResults: function()
- {
- if (!this._searchQuery || !this._searchHighlightsVisible)
- return;
- this._hideSearchHighlight();
-
- var text = this.listItemElement.textContent;
- var regexObject = createPlainTextSearchRegex(this._searchQuery, "gi");
-
- var match = regexObject.exec(text);
- var matchRanges = [];
- while (match) {
- matchRanges.push(new WebInspector.SourceRange(match.index, match[0].length));
- match = regexObject.exec(text);
- }
+ _editAsHTML() {
+ var promise = WebInspector.Revealer.revealPromise(this.node());
+ promise.then(() => WebInspector.actionRegistry.action('elements.edit-as-html').execute());
+ }
+};
- // Fall back for XPath, etc. matches.
- if (!matchRanges.length)
- matchRanges.push(new WebInspector.SourceRange(0, text.length));
-
- this._highlightResult = [];
- WebInspector.highlightSearchResults(this.listItemElement, matchRanges, this._highlightResult);
- },
-
- _scrollIntoView: function()
- {
- function scrollIntoViewCallback(object)
- {
- /**
- * @suppressReceiverCheck
- * @this {!Element}
- */
- function scrollIntoView()
- {
- this.scrollIntoViewIfNeeded(true);
- }
-
- if (object)
- object.callFunction(scrollIntoView);
- }
+WebInspector.ElementsTreeElement.InitialChildrenLimit = 500;
- this._node.resolveToObject("", scrollIntoViewCallback);
- },
+// A union of HTML4 and HTML5-Draft elements that explicitly
+// or implicitly (for HTML5) forbid the closing tag.
+WebInspector.ElementsTreeElement.ForbiddenClosingTagElements = new Set([
+ 'area', 'base', 'basefont', 'br', 'canvas', 'col', 'command', 'embed', 'frame', 'hr',
+ 'img', 'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'track', 'wbr'
+]);
+
+// These tags we do not allow editing their tag name.
+WebInspector.ElementsTreeElement.EditTagBlacklist = new Set(['html', 'head', 'body']);
- _editAsHTML: function()
- {
- var promise = WebInspector.Revealer.revealPromise(this.node());
- promise.then(() => WebInspector.actionRegistry.action("elements.edit-as-html").execute());
- },
- __proto__: TreeElement.prototype
-};

Powered by Google App Engine
This is Rietveld 408576698