diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebInspectorUI/UserInterface/DOMTreeElement.js | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/DOMTreeElement.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/DOMTreeElement.js | 1319 |
1 files changed, 0 insertions, 1319 deletions
diff --git a/Source/WebInspectorUI/UserInterface/DOMTreeElement.js b/Source/WebInspectorUI/UserInterface/DOMTreeElement.js deleted file mode 100644 index 07bd89e31..000000000 --- a/Source/WebInspectorUI/UserInterface/DOMTreeElement.js +++ /dev/null @@ -1,1319 +0,0 @@ -/* - * Copyright (C) 2007, 2008, 2013 Apple Inc. All rights reserved. - * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com> - * Copyright (C) 2009 Joseph Pecoraro - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (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 {boolean=} elementCloseTag - */ -WebInspector.DOMTreeElement = function(node, elementCloseTag) -{ - this._elementCloseTag = elementCloseTag; - var hasChildrenOverride = !elementCloseTag && node.hasChildNodes() && !this._showInlineText(node); - - // The title will be updated in onattach. - TreeElement.call(this, "", node, hasChildrenOverride); - - if (this.representedObject.nodeType() == Node.ELEMENT_NODE && !elementCloseTag) - this._canAddAttributes = true; - this._searchQuery = null; - this._expandedChildrenLimit = WebInspector.DOMTreeElement.InitialChildrenLimit; -} - -WebInspector.DOMTreeElement.InitialChildrenLimit = 500; -WebInspector.DOMTreeElement.MaximumInlineTextChildLength = 80; - -// A union of HTML4 and HTML5-Draft elements that explicitly -// or implicitly (for HTML5) forbid the closing tag. -// FIXME: Revise once HTML5 Final is published. -WebInspector.DOMTreeElement.ForbiddenClosingTagElements = [ - "area", "base", "basefont", "br", "canvas", "col", "command", "embed", "frame", - "hr", "img", "input", "isindex", "keygen", "link", "meta", "param", "source" -].keySet(); - -// These tags we do not allow editing their tag name. -WebInspector.DOMTreeElement.EditTagBlacklist = [ - "html", "head", "body" -].keySet(); - -WebInspector.DOMTreeElement.prototype = { - isCloseTag: function() - { - return this._elementCloseTag; - }, - - highlightSearchResults: function(searchQuery) - { - if (this._searchQuery !== searchQuery) { - this._updateSearchHighlight(false); - delete this._highlightResult; // A new search query. - } - - this._searchQuery = searchQuery; - this._searchHighlightsVisible = true; - this.updateTitle(true); - }, - - hideSearchHighlights: function() - { - delete this._searchHighlightsVisible; - this._updateSearchHighlight(false); - }, - - _updateSearchHighlight: function(show) - { - if (!this._highlightResult) - return; - - function updateEntryShow(entry) - { - switch (entry.type) { - case "added": - entry.parent.insertBefore(entry.node, entry.nextSibling); - break; - case "changed": - entry.node.textContent = entry.newText; - break; - } - } - - function updateEntryHide(entry) - { - switch (entry.type) { - case "added": - if (entry.node.parentElement) - entry.node.parentElement.removeChild(entry.node); - break; - case "changed": - entry.node.textContent = entry.oldText; - break; - } - } - - var updater = show ? updateEntryShow : updateEntryHide; - - for (var i = 0, size = this._highlightResult.length; i < size; ++i) - updater(this._highlightResult[i]); - }, - - get hovered() - { - return this._hovered; - }, - - set hovered(x) - { - if (this._hovered === x) - return; - - this._hovered = x; - - if (this.listItemElement) { - if (x) { - this.updateSelection(); - this.listItemElement.classList.add("hovered"); - } else { - this.listItemElement.classList.remove("hovered"); - } - } - }, - - get expandedChildrenLimit() - { - return this._expandedChildrenLimit; - }, - - set expandedChildrenLimit(x) - { - if (this._expandedChildrenLimit === x) - return; - - this._expandedChildrenLimit = x; - if (this.treeOutline && !this._updateChildrenInProgress) - this._updateChildren(true); - }, - - get expandedChildCount() - { - var count = this.children.length; - if (count && this.children[count - 1]._elementCloseTag) - count--; - if (count && this.children[count - 1].expandAllButton) - count--; - return count; - }, - - showChild: function(index) - { - if (this._elementCloseTag) - return; - - if (index >= this.expandedChildrenLimit) { - this._expandedChildrenLimit = index + 1; - this._updateChildren(true); - } - - // Whether index-th child is visible in the children tree - return this.expandedChildCount > index; - }, - - _createTooltipForNode: function() - { - var node = /** @type {WebInspector.DOMNode} */ this.representedObject; - if (!node.nodeName() || node.nodeName().toLowerCase() !== "img") - return; - - function setTooltip(result) - { - if (!result || result.type !== "string") - return; - - try { - var properties = JSON.parse(result.description); - var offsetWidth = properties[0]; - var offsetHeight = properties[1]; - var naturalWidth = properties[2]; - var naturalHeight = properties[3]; - if (offsetHeight === naturalHeight && offsetWidth === naturalWidth) - this.tooltip = WebInspector.UIString("%d \xd7 %d pixels").format(offsetWidth, offsetHeight); - else - this.tooltip = WebInspector.UIString("%d \xd7 %d pixels (Natural: %d \xd7 %d pixels)").format(offsetWidth, offsetHeight, naturalWidth, naturalHeight); - } catch (e) { - console.error(e); - } - } - - function resolvedNode(object) - { - if (!object) - return; - - function dimensions() - { - return "[" + this.offsetWidth + "," + this.offsetHeight + "," + this.naturalWidth + "," + this.naturalHeight + "]"; - } - - object.callFunction(dimensions, undefined, setTooltip.bind(this)); - object.release(); - } - WebInspector.RemoteObject.resolveNode(node, "", resolvedNode.bind(this)); - }, - - updateSelection: function() - { - var listItemElement = this.listItemElement; - if (!listItemElement) - return; - - if (document.body.offsetWidth <= 0) { - // The stylesheet hasn't loaded yet or the window is closed, - // so we can't calculate what is need. Return early. - return; - } - - if (!this.selectionElement) { - this.selectionElement = document.createElement("div"); - this.selectionElement.className = "selection selected"; - listItemElement.insertBefore(this.selectionElement, listItemElement.firstChild); - } - - this.selectionElement.style.height = listItemElement.offsetHeight + "px"; - }, - - onattach: function() - { - if (this._hovered) { - this.updateSelection(); - this.listItemElement.classList.add("hovered"); - } - - this.updateTitle(); - this.listItemElement.draggable = true; - this.listItemElement.addEventListener("dragstart", this); - }, - - onpopulate: function() - { - if (this.children.length || this._showInlineText(this.representedObject) || this._elementCloseTag) - return; - - this.updateChildren(); - }, - - expandRecursively: function() - { - function callback() - { - TreeElement.prototype.expandRecursively.call(this, Number.MAX_VALUE); - } - - this.representedObject.getSubtree(-1, callback.bind(this)); - }, - - /** - * @param {boolean=} fullRefresh - */ - updateChildren: function(fullRefresh) - { - if (this._elementCloseTag) - return; - this.representedObject.getChildNodes(this._updateChildren.bind(this, fullRefresh)); - }, - - /** - * @param {boolean=} closingTag - */ - insertChildElement: function(child, index, closingTag) - { - var newElement = new WebInspector.DOMTreeElement(child, closingTag); - newElement.selectable = this.treeOutline._selectEnabled; - this.insertChild(newElement, index); - return newElement; - }, - - moveChild: function(child, targetIndex) - { - var wasSelected = child.selected; - this.removeChild(child); - this.insertChild(child, targetIndex); - if (wasSelected) - child.select(); - }, - - /** - * @param {boolean=} fullRefresh - */ - _updateChildren: function(fullRefresh) - { - if (this._updateChildrenInProgress || !this.treeOutline._visible) - return; - - this._updateChildrenInProgress = true; - var selectedNode = this.treeOutline.selectedDOMNode(); - var originalScrollTop = 0; - if (fullRefresh) { - var treeOutlineContainerElement = this.treeOutline.element.parentNode; - originalScrollTop = treeOutlineContainerElement.scrollTop; - var selectedTreeElement = this.treeOutline.selectedTreeElement; - if (selectedTreeElement && selectedTreeElement.hasAncestor(this)) - this.select(); - this.removeChildren(); - } - - var treeElement = this; - var treeChildIndex = 0; - var elementToSelect; - - function updateChildrenOfNode(node) - { - var treeOutline = treeElement.treeOutline; - var child = node.firstChild; - while (child) { - var currentTreeElement = treeElement.children[treeChildIndex]; - if (!currentTreeElement || currentTreeElement.representedObject !== child) { - // Find any existing element that is later in the children list. - var existingTreeElement = null; - for (var i = (treeChildIndex + 1), size = treeElement.expandedChildCount; i < size; ++i) { - if (treeElement.children[i].representedObject === child) { - existingTreeElement = treeElement.children[i]; - break; - } - } - - if (existingTreeElement && existingTreeElement.parent === treeElement) { - // If an existing element was found and it has the same parent, just move it. - treeElement.moveChild(existingTreeElement, treeChildIndex); - } else { - // No existing element found, insert a new element. - if (treeChildIndex < treeElement.expandedChildrenLimit) { - var newElement = treeElement.insertChildElement(child, treeChildIndex); - if (child === selectedNode) - elementToSelect = newElement; - if (treeElement.expandedChildCount > treeElement.expandedChildrenLimit) - treeElement.expandedChildrenLimit++; - } - } - } - - child = child.nextSibling; - ++treeChildIndex; - } - } - - // Remove any tree elements that no longer have this node (or this node's contentDocument) as their parent. - for (var i = (this.children.length - 1); i >= 0; --i) { - var currentChild = this.children[i]; - var currentNode = currentChild.representedObject; - var currentParentNode = currentNode.parentNode; - - if (currentParentNode === this.representedObject) - continue; - - var selectedTreeElement = this.treeOutline.selectedTreeElement; - if (selectedTreeElement && (selectedTreeElement === currentChild || selectedTreeElement.hasAncestor(currentChild))) - this.select(); - - this.removeChildAtIndex(i); - } - - updateChildrenOfNode(this.representedObject); - this.adjustCollapsedRange(); - - var lastChild = this.children.lastValue; - if (this.representedObject.nodeType() == Node.ELEMENT_NODE && (!lastChild || !lastChild._elementCloseTag)) - this.insertChildElement(this.representedObject, this.children.length, true); - - // We want to restore the original selection and tree scroll position after a full refresh, if possible. - if (fullRefresh && elementToSelect) { - elementToSelect.select(); - if (treeOutlineContainerElement && originalScrollTop <= treeOutlineContainerElement.scrollHeight) - treeOutlineContainerElement.scrollTop = originalScrollTop; - } - - delete this._updateChildrenInProgress; - }, - - adjustCollapsedRange: function() - { - // Ensure precondition: only the tree elements for node children are found in the tree - // (not the Expand All button or the closing tag). - if (this.expandAllButtonElement && this.expandAllButtonElement.__treeElement.parent) - this.removeChild(this.expandAllButtonElement.__treeElement); - - const node = this.representedObject; - if (!node.children) - return; - const childNodeCount = node.children.length; - - // In case some nodes from the expanded range were removed, pull some nodes from the collapsed range into the expanded range at the bottom. - for (var i = this.expandedChildCount, limit = Math.min(this.expandedChildrenLimit, childNodeCount); i < limit; ++i) - this.insertChildElement(node.children[i], i); - - const expandedChildCount = this.expandedChildCount; - if (childNodeCount > this.expandedChildCount) { - var targetButtonIndex = expandedChildCount; - if (!this.expandAllButtonElement) { - var button = document.createElement("button"); - button.className = "show-all-nodes"; - button.value = ""; - var item = new TreeElement(button, null, false); - item.selectable = false; - item.expandAllButton = true; - this.insertChild(item, targetButtonIndex); - this.expandAllButtonElement = item.listItemElement.firstChild; - this.expandAllButtonElement.__treeElement = item; - this.expandAllButtonElement.addEventListener("click", this.handleLoadAllChildren.bind(this), false); - } else if (!this.expandAllButtonElement.__treeElement.parent) - this.insertChild(this.expandAllButtonElement.__treeElement, targetButtonIndex); - this.expandAllButtonElement.textContent = WebInspector.UIString("Show All Nodes (%d More)").format(childNodeCount - expandedChildCount); - } else if (this.expandAllButtonElement) - delete this.expandAllButtonElement; - }, - - handleLoadAllChildren: function() - { - this.expandedChildrenLimit = Math.max(this.representedObject.childNodeCount, this.expandedChildrenLimit + WebInspector.DOMTreeElement.InitialChildrenLimit); - }, - - onexpand: function() - { - if (this._elementCloseTag) - return; - - this.updateTitle(); - this.treeOutline.updateSelection(); - }, - - oncollapse: function() - { - if (this._elementCloseTag) - return; - - this.updateTitle(); - this.treeOutline.updateSelection(); - }, - - onreveal: function() - { - if (this.listItemElement) { - var tagSpans = this.listItemElement.getElementsByClassName("html-tag-name"); - if (tagSpans.length) - tagSpans[0].scrollIntoViewIfNeeded(false); - else - this.listItemElement.scrollIntoViewIfNeeded(false); - } - }, - - onselect: function(treeElement, selectedByUser) - { - this.treeOutline.suppressRevealAndSelect = true; - this.treeOutline.selectDOMNode(this.representedObject, selectedByUser); - if (selectedByUser) - WebInspector.domTreeManager.highlightDOMNode(this.representedObject.id); - this.updateSelection(); - this.treeOutline.suppressRevealAndSelect = false; - }, - - ondeselect: function(treeElement) - { - this.treeOutline.selectDOMNode(null); - }, - - ondelete: function() - { - var startTagTreeElement = this.treeOutline.findTreeElement(this.representedObject); - startTagTreeElement ? startTagTreeElement.remove() : this.remove(); - return true; - }, - - onenter: function() - { - // On Enter or Return start editing the first attribute - // or create a new attribute on the selected element. - if (this.treeOutline.editing) - return false; - - this._startEditing(); - - // prevent a newline from being immediately inserted - return true; - }, - - selectOnMouseDown: function(event) - { - TreeElement.prototype.selectOnMouseDown.call(this, event); - - if (this._editing) - return; - - // Prevent selecting the nearest word on double click. - if (event.detail >= 2) - event.preventDefault(); - }, - - ondblclick: function(event) - { - if (this._editing || this._elementCloseTag) - return; - - if (this._startEditingTarget(event.target)) - return; - - if (this.hasChildren && !this.expanded) - this.expand(); - }, - - _insertInLastAttributePosition: function(tag, node) - { - if (tag.getElementsByClassName("html-attribute").length > 0) - tag.insertBefore(node, tag.lastChild); - else { - var nodeName = tag.textContent.match(/^<(.*?)>$/)[1]; - tag.textContent = ''; - tag.appendChild(document.createTextNode('<'+nodeName)); - tag.appendChild(node); - tag.appendChild(document.createTextNode('>')); - } - - this.updateSelection(); - }, - - _startEditingTarget: function(eventTarget) - { - if (this.treeOutline.selectedDOMNode() != this.representedObject) - return; - - if (this.representedObject.nodeType() != Node.ELEMENT_NODE && this.representedObject.nodeType() != Node.TEXT_NODE) - return false; - - var textNode = eventTarget.enclosingNodeOrSelfWithClass("html-text-node"); - if (textNode) - return this._startEditingTextNode(textNode); - - var attribute = eventTarget.enclosingNodeOrSelfWithClass("html-attribute"); - if (attribute) - return this._startEditingAttribute(attribute, eventTarget); - - var tagName = eventTarget.enclosingNodeOrSelfWithClass("html-tag-name"); - if (tagName) - return this._startEditingTagName(tagName); - - var newAttribute = eventTarget.enclosingNodeOrSelfWithClass("add-attribute"); - if (newAttribute) - return this._addNewAttribute(); - - return false; - }, - - _populateTagContextMenu: function(contextMenu, event) - { - var attribute = event.target.enclosingNodeOrSelfWithClass("html-attribute"); - var newAttribute = event.target.enclosingNodeOrSelfWithClass("add-attribute"); - - // Add attribute-related actions. - contextMenu.appendItem(WebInspector.UIString("Add Attribute"), this._addNewAttribute.bind(this)); - if (attribute && !newAttribute) - contextMenu.appendItem(WebInspector.UIString("Edit Attribute"), this._startEditingAttribute.bind(this, attribute, event.target)); - contextMenu.appendSeparator(); - - if (WebInspector.cssStyleManager.canForcePseudoClasses()) { - var pseudoSubMenu = contextMenu.appendSubMenuItem(WebInspector.UIString("Forced Pseudo-Classes")); - this._populateForcedPseudoStateItems(pseudoSubMenu); - contextMenu.appendSeparator(); - } - - this._populateNodeContextMenu(contextMenu); - this.treeOutline._populateContextMenu(contextMenu, this.representedObject); - }, - - _populateForcedPseudoStateItems: function(subMenu) - { - var node = this.representedObject; - var enabledPseudoClasses = node.enabledPseudoClasses; - // These strings don't need to be localized as they are CSS pseudo-classes. - WebInspector.CSSStyleManager.ForceablePseudoClasses.forEach(function(pseudoClass) { - var label = pseudoClass.capitalize(); - var enabled = enabledPseudoClasses.contains(pseudoClass); - subMenu.appendCheckboxItem(label, function() { - node.setPseudoClassEnabled(pseudoClass, !enabled); - }, enabled, false); - }); - }, - - _populateTextContextMenu: function(contextMenu, textNode) - { - contextMenu.appendItem(WebInspector.UIString("Edit Text"), this._startEditingTextNode.bind(this, textNode)); - this._populateNodeContextMenu(contextMenu); - }, - - _populateNodeContextMenu: function(contextMenu) - { - // Add free-form node-related actions. - contextMenu.appendItem(WebInspector.UIString("Edit as HTML"), this._editAsHTML.bind(this)); - contextMenu.appendItem(WebInspector.UIString("Copy as HTML"), this._copyHTML.bind(this)); - contextMenu.appendItem(WebInspector.UIString("Delete Node"), this.remove.bind(this)); - }, - - _startEditing: function() - { - if (this.treeOutline.selectedDOMNode() !== this.representedObject) - return; - - var listItem = this._listItemNode; - - if (this._canAddAttributes) { - var attribute = listItem.getElementsByClassName("html-attribute")[0]; - if (attribute) - return this._startEditingAttribute(attribute, attribute.getElementsByClassName("html-attribute-value")[0]); - - return this._addNewAttribute(); - } - - if (this.representedObject.nodeType() === Node.TEXT_NODE) { - var textNode = listItem.getElementsByClassName("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 = document.createElement("span"); - this._buildAttributeDOM(container, " ", ""); - var attr = container.firstChild; - attr.style.marginLeft = "2px"; // overrides the .editing margin rule - attr.style.marginRight = "2px"; // overrides the .editing margin rule - - var tag = this.listItemElement.getElementsByClassName("html-tag")[0]; - this._insertInLastAttributePosition(tag, attr); - return this._startEditingAttribute(attr, attr); - }, - - _triggerEditAttribute: function(attributeName) - { - var attributeElements = this.listItemElement.getElementsByClassName("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("html-attribute-value")) - return this._startEditingAttribute(elem.parentNode, elem); - } - } - } - }, - - _startEditingAttribute: function(attribute, elementForSelection) - { - if (WebInspector.isBeingEdited(attribute)) - return true; - - var attributeNameElement = attribute.getElementsByClassName("html-attribute-name")[0]; - if (!attributeNameElement) - return false; - - var attributeName = attributeNameElement.textContent; - - function removeZeroWidthSpaceRecursive(node) - { - if (node.nodeType === Node.TEXT_NODE) { - node.nodeValue = node.nodeValue.replace(/\u200B/g, ""); - return; - } - - if (node.nodeType !== Node.ELEMENT_NODE) - return; - - for (var child = node.firstChild; child; child = child.nextSibling) - removeZeroWidthSpaceRecursive(child); - } - - // Remove zero-width spaces that were added by nodeTitleInfo. - removeZeroWidthSpaceRecursive(attribute); - - var config = new WebInspector.EditingConfig(this._attributeEditingCommitted.bind(this), this._editingCancelled.bind(this), attributeName); - this._editing = WebInspector.startEditing(attribute, config); - - window.getSelection().setBaseAndExtent(elementForSelection, 0, elementForSelection, 1); - - return true; - }, - - _startEditingTextNode: function(textNode) - { - if (WebInspector.isBeingEdited(textNode)) - return true; - - var config = new WebInspector.EditingConfig(this._textNodeEditingCommitted.bind(this), this._editingCancelled.bind(this)); - config.spellcheck = true; - this._editing = WebInspector.startEditing(textNode, config); - window.getSelection().setBaseAndExtent(textNode, 0, textNode, 1); - - return true; - }, - - _startEditingTagName: function(tagNameElement) - { - if (!tagNameElement) { - tagNameElement = this.listItemElement.getElementsByClassName("html-tag-name")[0]; - if (!tagNameElement) - return false; - } - - var tagName = tagNameElement.textContent; - if (WebInspector.DOMTreeElement.EditTagBlacklist[tagName.toLowerCase()]) - return false; - - if (WebInspector.isBeingEdited(tagNameElement)) - return true; - - var closingTagElement = this._distinctClosingTagElement(); - - function keyupListener(event) - { - if (closingTagElement) - closingTagElement.textContent = "</" + tagNameElement.textContent + ">"; - } - - function editingComitted(element, newTagName) - { - tagNameElement.removeEventListener('keyup', keyupListener, false); - this._tagNameEditingCommitted.apply(this, arguments); - } - - function editingCancelled() - { - tagNameElement.removeEventListener('keyup', keyupListener, false); - this._editingCancelled.apply(this, arguments); - } - - tagNameElement.addEventListener('keyup', keyupListener, false); - - var config = new WebInspector.EditingConfig(editingComitted.bind(this), editingCancelled.bind(this), tagName); - this._editing = WebInspector.startEditing(tagNameElement, config); - window.getSelection().setBaseAndExtent(tagNameElement, 0, tagNameElement, 1); - return true; - }, - - _startEditingAsHTML: function(commitCallback, error, initialValue) - { - if (error) - return; - if (this._htmlEditElement && WebInspector.isBeingEdited(this._htmlEditElement)) - return; - - this._htmlEditElement = document.createElement("div"); - this._htmlEditElement.className = "source-code elements-tree-editor"; - this._htmlEditElement.textContent = initialValue; - - // 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.updateSelection(); - - function commit() - { - commitCallback(this._htmlEditElement.textContent); - dispose.call(this); - } - - function dispose() - { - this._editing = false; - - // 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.updateSelection(); - } - - var config = new WebInspector.EditingConfig(commit.bind(this), dispose.bind(this)); - config.setMultiline(true); - this._editing = WebInspector.startEditing(this._htmlEditElement, config); - }, - - _attributeEditingCommitted: function(element, newText, oldText, attributeName, moveDirection) - { - this._editing = false; - - var treeOutline = this.treeOutline; - function moveToNextAttributeIfNeeded(error) - { - if (error) - this._editingCancelled(element, attributeName); - - if (!moveDirection) - return; - - treeOutline._updateModifiedNodes(); - - // Search for the attribute's position, and then decide where to move to. - var attributes = this.representedObject.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) - this._triggerEditAttribute(attributes.lastValue.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 (!/^\s*$/.test(newText)) - this._addNewAttribute(); - else - this._startEditingTagName(); - } - } - - this.representedObject.setAttribute(attributeName, newText, moveToNextAttributeIfNeeded.bind(this)); - }, - - _tagNameEditingCommitted: function(element, newText, oldText, tagName, moveDirection) - { - this._editing = false; - var self = this; - - function cancel() - { - var closingTagElement = self._distinctClosingTagElement(); - if (closingTagElement) - closingTagElement.textContent = "</" + tagName + ">"; - - self._editingCancelled(element, tagName); - moveToNextAttributeIfNeeded.call(self); - } - - function moveToNextAttributeIfNeeded() - { - if (moveDirection !== "forward") { - this._addNewAttribute(); - return; - } - - var attributes = this.representedObject.attributes(); - if (attributes.length > 0) - this._triggerEditAttribute(attributes[0].name); - else - this._addNewAttribute(); - } - - newText = newText.trim(); - if (newText === oldText) { - cancel(); - return; - } - - var treeOutline = this.treeOutline; - var wasExpanded = this.expanded; - - function changeTagNameCallback(error, nodeId) - { - if (error || !nodeId) { - cancel(); - return; - } - - var node = WebInspector.domTreeManager.nodeForId(nodeId); - - // Select it and expand if necessary. We force tree update so that it processes dom events and is up to date. - treeOutline._updateModifiedNodes(); - treeOutline.selectDOMNode(node, true); - - var newTreeItem = treeOutline.findTreeElement(node); - if (wasExpanded) - newTreeItem.expand(); - - moveToNextAttributeIfNeeded.call(newTreeItem); - } - - this.representedObject.setNodeName(newText, changeTagNameCallback); - }, - - _textNodeEditingCommitted: function(element, newText) - { - this._editing = false; - - var textNode; - if (this.representedObject.nodeType() === Node.ELEMENT_NODE) { - // We only show text nodes inline in elements if the element only - // has a single child, and that child is a text node. - textNode = this.representedObject.firstChild; - } else if (this.representedObject.nodeType() == Node.TEXT_NODE) - textNode = this.representedObject; - - textNode.setNodeValue(newText, this.updateTitle.bind(this)); - }, - - _editingCancelled: function(element, context) - { - this._editing = false; - - // Need to restore attributes structure. - this.updateTitle(); - }, - - _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]; - } - - // 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("html-tag"); - return (tags.length === 1 ? null : tags[tags.length-1]); - }, - - /** - * @param {boolean=} onlySearchQueryChanged - */ - updateTitle: function(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) { - if (this._highlightResult) - this._updateSearchHighlight(false); - } else { - var highlightElement = document.createElement("span"); - highlightElement.className = "highlight"; - highlightElement.appendChild(this._nodeTitleInfo().titleDOM); - this.title = highlightElement; - delete this._highlightResult; - } - - delete this.selectionElement; - this.updateSelection(); - this._highlightSearchResults(); - }, - - /** - * @param {WebInspector.DOMNode=} node - */ - _buildAttributeDOM: function(parentElement, name, value, node) - { - var hasText = (value.length > 0); - var attrSpanElement = parentElement.createChild("span", "html-attribute"); - var attrNameElement = attrSpanElement.createChild("span", "html-attribute-name"); - attrNameElement.textContent = name; - - if (hasText) - attrSpanElement.appendChild(document.createTextNode("=\u200B\"")); - - if (name === "src" || name === "href") { - var baseURL = node.ownerDocument ? node.ownerDocument.documentURL : null; - var rewrittenURL = absoluteURL(value, baseURL); - - value = value.insertWordBreakCharacters(); - - if (!rewrittenURL) { - var attrValueElement = attrSpanElement.createChild("span", "html-attribute-value"); - attrValueElement.textContent = value; - } else { - if (value.startsWith("data:")) - value = value.trimMiddle(60); - - var linkElement = document.createElement("a"); - linkElement.href = rewrittenURL; - linkElement.textContent = value; - - attrSpanElement.appendChild(linkElement); - } - } else { - value = value.insertWordBreakCharacters(); - var attrValueElement = attrSpanElement.createChild("span", "html-attribute-value"); - attrValueElement.textContent = value; - } - - if (hasText) - attrSpanElement.appendChild(document.createTextNode("\"")); - }, - - _buildTagDOM: function(parentElement, tagName, isClosingTag, isDistinctTreeElement) - { - var node = /** @type WebInspector.DOMNode */ this.representedObject; - var classes = [ "html-tag" ]; - if (isClosingTag && isDistinctTreeElement) - classes.push("close"); - if (node.isInShadowTree()) - classes.push("shadow"); - var tagElement = parentElement.createChild("span", classes.join(" ")); - tagElement.appendChild(document.createTextNode("<")); - var tagNameElement = tagElement.createChild("span", isClosingTag ? "" : "html-tag-name"); - tagNameElement.textContent = (isClosingTag ? "/" : "") + tagName; - if (!isClosingTag && node.hasAttributes()) { - var attributes = node.attributes(); - for (var i = 0; i < attributes.length; ++i) { - var attr = attributes[i]; - tagElement.appendChild(document.createTextNode(" ")); - this._buildAttributeDOM(tagElement, attr.name, attr.value, node); - } - } - tagElement.appendChild(document.createTextNode(">")); - parentElement.appendChild(document.createTextNode("\u200B")); - }, - - _nodeTitleInfo: function() - { - var node = this.representedObject; - var info = {titleDOM: document.createDocumentFragment(), hasChildren: this.hasChildren}; - - switch (node.nodeType()) { - case Node.DOCUMENT_FRAGMENT_NODE: - var fragmentElement = info.titleDOM.createChild("span", "webkit-html-fragment"); - if (node.isInShadowTree()) { - fragmentElement.textContent = WebInspector.UIString("Shadow Content"); - fragmentElement.classList.add("shadow"); - } else - fragmentElement.textContent = WebInspector.UIString("Document Fragment"); - break; - - case Node.ATTRIBUTE_NODE: - var value = node.value || "\u200B"; // Zero width space to force showing an empty value. - this._buildAttributeDOM(info.titleDOM, node.name, value); - break; - - case Node.ELEMENT_NODE: - var tagName = node.nodeNameInCorrectCase(); - if (this._elementCloseTag) { - this._buildTagDOM(info.titleDOM, tagName, true, true); - info.hasChildren = false; - break; - } - - this._buildTagDOM(info.titleDOM, tagName, false, false); - - var textChild = this._singleTextChild(node); - var showInlineText = textChild && textChild.nodeValue().length < WebInspector.DOMTreeElement.MaximumInlineTextChildLength; - - if (!this.expanded && (!showInlineText && (this.treeOutline.isXMLMimeType || !WebInspector.DOMTreeElement.ForbiddenClosingTagElements[tagName]))) { - if (this.hasChildren) { - var textNodeElement = info.titleDOM.createChild("span", "html-text-node"); - textNodeElement.textContent = "\u2026"; - info.titleDOM.appendChild(document.createTextNode("\u200B")); - } - this._buildTagDOM(info.titleDOM, tagName, true, false); - } - - // If this element only has a single child that is a text node, - // just show that text and the closing tag inline rather than - // create a subtree for them - if (showInlineText) { - var textNodeElement = info.titleDOM.createChild("span", "html-text-node"); - var nodeNameLowerCase = node.nodeName().toLowerCase(); - - if (nodeNameLowerCase === "script") - textNodeElement.appendChild(WebInspector.syntaxHighlightStringAsDocumentFragment(textChild.nodeValue().trim(), "text/javascript")); - else if (nodeNameLowerCase === "style") - textNodeElement.appendChild(WebInspector.syntaxHighlightStringAsDocumentFragment(textChild.nodeValue().trim(), "text/css")); - else - textNodeElement.textContent = textChild.nodeValue(); - - info.titleDOM.appendChild(document.createTextNode("\u200B")); - - this._buildTagDOM(info.titleDOM, tagName, true, false); - info.hasChildren = false; - } - break; - - case Node.TEXT_NODE: - function trimedNodeValue() - { - // Trim empty lines from the beginning and extra space at the end since most style and script tags begin with a newline - // and end with a newline and indentation for the end tag. - return node.nodeValue().replace(/^[\n\r]*/, "").replace(/\s*$/, ""); - } - - if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "script") { - var newNode = info.titleDOM.createChild("span", "html-text-node large"); - newNode.appendChild(WebInspector.syntaxHighlightStringAsDocumentFragment(trimedNodeValue(), "text/javascript")); - } else if (node.parentNode && node.parentNode.nodeName().toLowerCase() === "style") { - var newNode = info.titleDOM.createChild("span", "html-text-node large"); - newNode.appendChild(WebInspector.syntaxHighlightStringAsDocumentFragment(trimedNodeValue(), "text/css")); - } else { - info.titleDOM.appendChild(document.createTextNode("\"")); - var textNodeElement = info.titleDOM.createChild("span", "html-text-node"); - textNodeElement.textContent = node.nodeValue(); - info.titleDOM.appendChild(document.createTextNode("\"")); - } - break; - - case Node.COMMENT_NODE: - var commentElement = info.titleDOM.createChild("span", "html-comment"); - commentElement.appendChild(document.createTextNode("<!--" + node.nodeValue() + "-->")); - break; - - case Node.DOCUMENT_TYPE_NODE: - var docTypeElement = info.titleDOM.createChild("span", "html-doctype"); - docTypeElement.appendChild(document.createTextNode("<!DOCTYPE " + node.nodeName())); - if (node.publicId) { - docTypeElement.appendChild(document.createTextNode(" PUBLIC \"" + node.publicId + "\"")); - if (node.systemId) - docTypeElement.appendChild(document.createTextNode(" \"" + node.systemId + "\"")); - } else if (node.systemId) - docTypeElement.appendChild(document.createTextNode(" SYSTEM \"" + node.systemId + "\"")); - - if (node.internalSubset) - docTypeElement.appendChild(document.createTextNode(" [" + node.internalSubset + "]")); - - docTypeElement.appendChild(document.createTextNode(">")); - break; - - case Node.CDATA_SECTION_NODE: - var cdataElement = info.titleDOM.createChild("span", "html-text-node"); - cdataElement.appendChild(document.createTextNode("<![CDATA[" + node.nodeValue() + "]]>")); - break; - default: - var defaultElement = info.titleDOM.appendChild(document.createTextNode(node.nodeNameInCorrectCase().collapseWhitespace())); - } - - return info; - }, - - _singleTextChild: function(node) - { - if (!node) - return null; - - var firstChild = node.firstChild; - if (!firstChild || firstChild.nodeType() !== Node.TEXT_NODE) - return null; - - if (node.hasShadowRoots()) - return null; - - var sibling = firstChild.nextSibling; - return sibling ? null : firstChild; - }, - - _showInlineText: function(node) - { - if (node.nodeType() === Node.ELEMENT_NODE) { - var textChild = this._singleTextChild(node); - if (textChild && textChild.nodeValue().length < WebInspector.DOMTreeElement.MaximumInlineTextChildLength) - return true; - } - return false; - }, - - remove: function() - { - var parentElement = this.parent; - if (!parentElement) - return; - - var self = this; - function removeNodeCallback(error, removedNodeId) - { - if (error) - return; - - if (!self.parent) - return; - - parentElement.removeChild(self); - parentElement.adjustCollapsedRange(); - } - - this.representedObject.removeNode(removeNodeCallback); - }, - - _editAsHTML: function() - { - var treeOutline = this.treeOutline; - var node = this.representedObject; - var parentNode = node.parentNode; - var index = node.index; - var wasExpanded = this.expanded; - - function selectNode(error, nodeId) - { - if (error) - return; - - // Select it and expand if necessary. We force tree update so that it processes dom events and is up to date. - treeOutline._updateModifiedNodes(); - - var newNode = parentNode ? parentNode.children[index] || parentNode : null; - if (!newNode) - return; - - treeOutline.selectDOMNode(newNode, true); - - if (wasExpanded) { - var newTreeItem = treeOutline.findTreeElement(newNode); - if (newTreeItem) - newTreeItem.expand(); - } - } - - function commitChange(value) - { - node.setOuterHTML(value, selectNode); - } - - node.getOuterHTML(this._startEditingAsHTML.bind(this, commitChange)); - }, - - _copyHTML: function() - { - this.representedObject.copyNode(); - }, - - _highlightSearchResults: function() - { - if (!this._searchQuery || !this._searchHighlightsVisible) - return; - if (this._highlightResult) { - this._updateSearchHighlight(true); - return; - } - - var text = this.listItemElement.textContent; - var regexObject = createPlainTextSearchRegex(this._searchQuery, "gi"); - - var offset = 0; - var match = regexObject.exec(text); - var matchRanges = []; - while (match) { - matchRanges.push({ offset: match.index, length: match[0].length }); - match = regexObject.exec(text); - } - - // Fall back for XPath, etc. matches. - if (!matchRanges.length) - matchRanges.push({ offset: 0, length: text.length }); - - this._highlightResult = []; - highlightSearchResults(this.listItemElement, matchRanges, this._highlightResult); - }, - - handleEvent: function(event) - { - if (event.type === "dragstart" && this._editing) - event.preventDefault(); - } -} - -WebInspector.DOMTreeElement.prototype.__proto__ = TreeElement.prototype; |