summaryrefslogtreecommitdiff
path: root/Source/WebInspectorUI/UserInterface/DOMNode.js
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2013-09-13 12:51:20 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-09-19 20:50:05 +0200
commitd441d6f39bb846989d95bcf5caf387b42414718d (patch)
treee367e64a75991c554930278175d403c072de6bb8 /Source/WebInspectorUI/UserInterface/DOMNode.js
parent0060b2994c07842f4c59de64b5e3e430525c4b90 (diff)
downloadqtwebkit-d441d6f39bb846989d95bcf5caf387b42414718d.tar.gz
Import Qt5x2 branch of QtWebkit for Qt 5.2
Importing a new snapshot of webkit. Change-Id: I2d01ad12cdc8af8cb015387641120a9d7ea5f10c Reviewed-by: Allan Sandfeld Jensen <allan.jensen@digia.com>
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/DOMNode.js')
-rw-r--r--Source/WebInspectorUI/UserInterface/DOMNode.js690
1 files changed, 690 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/DOMNode.js b/Source/WebInspectorUI/UserInterface/DOMNode.js
new file mode 100644
index 000000000..ee002783c
--- /dev/null
+++ b/Source/WebInspectorUI/UserInterface/DOMNode.js
@@ -0,0 +1,690 @@
+/*
+ * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Joseph Pecoraro
+ * Copyright (C) 2013 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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
+ * @param {WebInspector.DOMAgent} domAgent
+ * @param {?WebInspector.DOMNode} doc
+ * @param {boolean} isInShadowTree
+ * @param {DOMAgent.Node} payload
+ */
+WebInspector.DOMNode = function(domAgent, doc, isInShadowTree, payload) {
+ WebInspector.Object.call(this);
+
+ this._domAgent = domAgent;
+ this._isInShadowTree = isInShadowTree;
+
+ this.id = payload.nodeId;
+ domAgent._idToDOMNode[this.id] = this;
+
+ this._nodeType = payload.nodeType;
+ this._nodeName = payload.nodeName;
+ this._localName = payload.localName;
+ this._nodeValue = payload.nodeValue;
+
+ if (this._nodeType === Node.DOCUMENT_NODE)
+ this.ownerDocument = this;
+ else
+ this.ownerDocument = doc;
+
+ this._attributes = [];
+ this._attributesMap = {};
+ if (payload.attributes)
+ this._setAttributesPayload(payload.attributes);
+
+ this._childNodeCount = payload.childNodeCount;
+ this._children = null;
+ this._filteredChildren = null;
+ this._filteredChildrenNeedsUpdating = true;
+
+ this._nextSibling = null;
+ this._previousSibling = null;
+ this.parentNode = null;
+
+ this._enabledPseudoClasses = [];
+
+ this._shadowRoots = [];
+ if (payload.shadowRoots) {
+ for (var i = 0; i < payload.shadowRoots.length; ++i) {
+ var root = payload.shadowRoots[i];
+ var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, true, root);
+ this._shadowRoots.push(node);
+ }
+ }
+
+ if (payload.children)
+ this._setChildrenPayload(payload.children);
+
+ if (payload.contentDocument) {
+ this._contentDocument = new WebInspector.DOMNode(domAgent, null, false, payload.contentDocument);
+ this._children = [this._contentDocument];
+ this._renumber();
+ }
+
+ if (this._nodeType === Node.ELEMENT_NODE) {
+ // HTML and BODY from internal iframes should not overwrite top-level ones.
+ if (this.ownerDocument && !this.ownerDocument.documentElement && this._nodeName === "HTML")
+ this.ownerDocument.documentElement = this;
+ if (this.ownerDocument && !this.ownerDocument.body && this._nodeName === "BODY")
+ this.ownerDocument.body = this;
+ if (payload.documentURL)
+ this.documentURL = payload.documentURL;
+ } else if (this._nodeType === Node.DOCUMENT_TYPE_NODE) {
+ this.publicId = payload.publicId;
+ this.systemId = payload.systemId;
+ this.internalSubset = payload.internalSubset;
+ } else if (this._nodeType === Node.DOCUMENT_NODE) {
+ this.documentURL = payload.documentURL;
+ this.xmlVersion = payload.xmlVersion;
+ } else if (this._nodeType === Node.ATTRIBUTE_NODE) {
+ this.name = payload.name;
+ this.value = payload.value;
+ }
+}
+
+WebInspector.Object.addConstructorFunctions(WebInspector.DOMNode);
+
+WebInspector.DOMNode.Event = {
+ EnabledPseudoClassesChanged: "dom-node-enabled-pseudo-classes-did-change",
+ AttributeModified: "dom-node-attribute-modified",
+ AttributeRemoved: "dom-node-attribute-removed"
+};
+
+WebInspector.DOMNode.prototype = {
+ constructor: WebInspector.DOMNode,
+
+ get children()
+ {
+ if (!this._children)
+ return null;
+
+ if (WebInspector.showShadowDOMSetting.value)
+ return this._children;
+
+ if (this._filteredChildrenNeedsUpdating) {
+ this._filteredChildrenNeedsUpdating = false;
+ this._filteredChildren = this._children.filter(function(node) {
+ return !node._isInShadowTree;
+ });
+ }
+
+ return this._filteredChildren;
+ },
+
+ get firstChild()
+ {
+ var children = this.children;
+
+ if (children && children.length > 0)
+ return children[0];
+
+ return null;
+ },
+
+ get lastChild()
+ {
+ var children = this.children;
+
+ if (children && children.length > 0)
+ return children.lastValue;
+
+ return null;
+ },
+
+ get nextSibling()
+ {
+ if (WebInspector.showShadowDOMSetting.value)
+ return this._nextSibling;
+
+ var node = this._nextSibling;
+ while (node) {
+ if (!node._isInShadowTree)
+ return node;
+ node = node._nextSibling;
+ }
+ return null;
+ },
+
+ get previousSibling()
+ {
+ if (WebInspector.showShadowDOMSetting.value)
+ return this._previousSibling;
+
+ var node = this._previousSibling;
+ while (node) {
+ if (!node._isInShadowTree)
+ return node;
+ node = node._previousSibling;
+ }
+ return null;
+ },
+
+ get childNodeCount()
+ {
+ var children = this.children;
+ if (children)
+ return children.length;
+
+ if (WebInspector.showShadowDOMSetting.value)
+ return this._childNodeCount + this._shadowRoots.length;
+
+ return this._childNodeCount;
+ },
+
+ set childNodeCount(count)
+ {
+ this._childNodeCount = count;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasAttributes: function()
+ {
+ return this._attributes.length > 0;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasChildNodes: function()
+ {
+ return this.childNodeCount > 0;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ hasShadowRoots: function()
+ {
+ return !!this._shadowRoots.length;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isInShadowTree: function()
+ {
+ return this._isInShadowTree;
+ },
+
+ /**
+ * @return {number}
+ */
+ nodeType: function()
+ {
+ return this._nodeType;
+ },
+
+ /**
+ * @return {string}
+ */
+ nodeName: function()
+ {
+ return this._nodeName;
+ },
+
+ /**
+ * @return {string}
+ */
+ nodeNameInCorrectCase: function()
+ {
+ return this.isXMLNode() ? this.nodeName() : this.nodeName().toLowerCase();
+ },
+
+ /**
+ * @param {string} name
+ * @param {function()=} callback
+ */
+ setNodeName: function(name, callback)
+ {
+ DOMAgent.setNodeName(this.id, name, this._makeUndoableCallback(callback));
+ },
+
+ /**
+ * @return {string}
+ */
+ localName: function()
+ {
+ return this._localName;
+ },
+
+ /**
+ * @return {string}
+ */
+ nodeValue: function()
+ {
+ return this._nodeValue;
+ },
+
+ /**
+ * @param {string} value
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setNodeValue: function(value, callback)
+ {
+ DOMAgent.setNodeValue(this.id, value, this._makeUndoableCallback(callback));
+ },
+
+ /**
+ * @param {string} name
+ * @return {string}
+ */
+ getAttribute: function(name)
+ {
+ var attr = this._attributesMap[name];
+ return attr ? attr.value : undefined;
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} text
+ * @param {function()=} callback
+ */
+ setAttribute: function(name, text, callback)
+ {
+ DOMAgent.setAttributesAsText(this.id, text, name, this._makeUndoableCallback(callback));
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ * @param {function()=} callback
+ */
+ setAttributeValue: function(name, value, callback)
+ {
+ DOMAgent.setAttributeValue(this.id, name, value, this._makeUndoableCallback(callback));
+ },
+
+ /**
+ * @return {Object}
+ */
+ attributes: function()
+ {
+ return this._attributes;
+ },
+
+ /**
+ * @param {string} name
+ * @param {function()=} callback
+ */
+ removeAttribute: function(name, callback)
+ {
+ function mycallback(error, success)
+ {
+ if (!error) {
+ delete this._attributesMap[name];
+ for (var i = 0; i < this._attributes.length; ++i) {
+ if (this._attributes[i].name === name) {
+ this._attributes.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ this._makeUndoableCallback(callback)(error);
+ }
+ DOMAgent.removeAttribute(this.id, name, mycallback.bind(this));
+ },
+
+ /**
+ * @param {function(Array.<WebInspector.DOMNode>)=} callback
+ */
+ getChildNodes: function(callback)
+ {
+ if (this.children) {
+ if (callback)
+ callback(this.children);
+ return;
+ }
+
+ /**
+ * @this {WebInspector.DOMNode}
+ * @param {?Protocol.Error} error
+ */
+ function mycallback(error) {
+ if (!error && callback)
+ callback(this.children);
+ }
+
+ DOMAgent.requestChildNodes(this.id, mycallback.bind(this));
+ },
+
+ /**
+ * @param {number} depth
+ * @param {function(Array.<WebInspector.DOMNode>)=} callback
+ */
+ getSubtree: function(depth, callback)
+ {
+ /**
+ * @this {WebInspector.DOMNode}
+ * @param {?Protocol.Error} error
+ */
+ function mycallback(error)
+ {
+ if (callback)
+ callback(error ? null : this.children);
+ }
+
+ DOMAgent.requestChildNodes(this.id, depth, mycallback.bind(this));
+ },
+
+ /**
+ * @param {function(?Protocol.Error)=} callback
+ */
+ getOuterHTML: function(callback)
+ {
+ DOMAgent.getOuterHTML(this.id, callback);
+ },
+
+ /**
+ * @param {string} html
+ * @param {function(?Protocol.Error)=} callback
+ */
+ setOuterHTML: function(html, callback)
+ {
+ DOMAgent.setOuterHTML(this.id, html, this._makeUndoableCallback(callback));
+ },
+
+ /**
+ * @param {function(?Protocol.Error)=} callback
+ */
+ removeNode: function(callback)
+ {
+ DOMAgent.removeNode(this.id, this._makeUndoableCallback(callback));
+ },
+
+ copyNode: function()
+ {
+ function copy(error, text)
+ {
+ if (!error)
+ InspectorFrontendHost.copyText(text);
+ }
+ DOMAgent.getOuterHTML(this.id, copy);
+ },
+
+ /**
+ * @param {function(?Protocol.Error)=} callback
+ */
+ eventListeners: function(callback)
+ {
+ DOMAgent.getEventListenersForNode(this.id, callback);
+ },
+
+ /**
+ * @return {string}
+ */
+ path: function()
+ {
+ var path = [];
+ var node = this;
+ while (node && "index" in node && node._nodeName.length) {
+ path.push([node.index, node._nodeName]);
+ node = node.parentNode;
+ }
+ path.reverse();
+ return path.join(",");
+ },
+
+ /**
+ * @param {boolean} justSelector
+ * @return {string}
+ */
+ appropriateSelectorFor: function(justSelector)
+ {
+ var lowerCaseName = this.localName() || this.nodeName().toLowerCase();
+
+ var id = this.getAttribute("id");
+ if (id) {
+ if (/[\s'"]/.test(id)) {
+ id = id.replace(/\\/g, "\\\\").replace(/\"/g, "\\\"");
+ selector = lowerCaseName + "[id=\"" + id + "\"]";
+ } else
+ selector = "#" + id;
+ return (justSelector ? selector : lowerCaseName + selector);
+ }
+
+ var className = this.getAttribute("class");
+ if (className) {
+ var selector = "." + className.trim().replace(/\s+/, ".");
+ return (justSelector ? selector : lowerCaseName + selector);
+ }
+
+ if (lowerCaseName === "input" && this.getAttribute("type"))
+ return lowerCaseName + "[type=\"" + this.getAttribute("type") + "\"]";
+
+ return lowerCaseName;
+ },
+
+ /**
+ * @param {WebInspector.DOMNode} node
+ * @return {boolean}
+ */
+ isAncestor: function(node)
+ {
+ if (!node)
+ return false;
+
+ var currentNode = node.parentNode;
+ while (currentNode) {
+ if (this === currentNode)
+ return true;
+ currentNode = currentNode.parentNode;
+ }
+ return false;
+ },
+
+ /**
+ * @param {WebInspector.DOMNode} descendant
+ * @return {boolean}
+ */
+ isDescendant: function(descendant)
+ {
+ return descendant !== null && descendant.isAncestor(this);
+ },
+
+ /**
+ * @param {Array.<string>} attrs
+ */
+ _setAttributesPayload: function(attrs)
+ {
+ this._attributes = [];
+ this._attributesMap = {};
+ for (var i = 0; i < attrs.length; i += 2)
+ this._addAttribute(attrs[i], attrs[i + 1]);
+ },
+
+ /**
+ * @param {WebInspector.DOMNode} prev
+ * @param {DOMAgent.Node} payload
+ * @return {WebInspector.DOMNode}
+ */
+ _insertChild: function(prev, payload)
+ {
+ var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payload);
+ if (!prev) {
+ if (!this._children) {
+ // First node
+ this._children = this._shadowRoots.concat([node]);
+ } else
+ this._children.unshift(node);
+ } else
+ this._children.splice(this._children.indexOf(prev) + 1, 0, node);
+ this._renumber();
+ return node;
+ },
+
+ /**
+ * @param {WebInspector.DOMNode} node
+ */
+ _removeChild: function(node)
+ {
+ this._children.splice(this._children.indexOf(node), 1);
+ node.parentNode = null;
+ this._renumber();
+ },
+
+ /**
+ * @param {Array.<DOMAgent.Node>} payloads
+ */
+ _setChildrenPayload: function(payloads)
+ {
+ // We set children in the constructor.
+ if (this._contentDocument)
+ return;
+
+ this._children = this._shadowRoots.slice();
+ for (var i = 0; i < payloads.length; ++i) {
+ var payload = payloads[i];
+ var node = new WebInspector.DOMNode(this._domAgent, this.ownerDocument, this._isInShadowTree, payload);
+ this._children.push(node);
+ }
+ this._renumber();
+ },
+
+ _renumber: function()
+ {
+ this._filteredChildrenNeedsUpdating = true;
+
+ var childNodeCount = this._children.length;
+ if (childNodeCount === 0)
+ return;
+
+ for (var i = 0; i < childNodeCount; ++i) {
+ var child = this._children[i];
+ child.index = i;
+ child._nextSibling = i + 1 < childNodeCount ? this._children[i + 1] : null;
+ child._previousSibling = i - 1 >= 0 ? this._children[i - 1] : null;
+ child.parentNode = this;
+ }
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ _addAttribute: function(name, value)
+ {
+ var attr = {
+ name: name,
+ value: value,
+ _node: this
+ };
+ this._attributesMap[name] = attr;
+ this._attributes.push(attr);
+ },
+
+ /**
+ * @param {string} name
+ * @param {string} value
+ */
+ _setAttribute: function(name, value)
+ {
+ var attr = this._attributesMap[name];
+ if (attr)
+ attr.value = value;
+ else
+ this._addAttribute(name, value);
+ },
+
+ /**
+ * @param {string} name
+ */
+ _removeAttribute: function(name)
+ {
+ var attr = this._attributesMap[name];
+ if (attr) {
+ this._attributes.remove(attr);
+ delete this._attributesMap[name];
+ }
+ },
+
+ /**
+ * @param {WebInspector.DOMNode} targetNode
+ * @param {?WebInspector.DOMNode} anchorNode
+ * @param {function(?Protocol.Error)=} callback
+ */
+ moveTo: function(targetNode, anchorNode, callback)
+ {
+ DOMAgent.moveTo(this.id, targetNode.id, anchorNode ? anchorNode.id : undefined, this._makeUndoableCallback(callback));
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isXMLNode: function()
+ {
+ return !!this.ownerDocument && !!this.ownerDocument.xmlVersion;
+ },
+
+ get enabledPseudoClasses()
+ {
+ return this._enabledPseudoClasses;
+ },
+
+ setPseudoClassEnabled: function(pseudoClass, enabled)
+ {
+ var pseudoClasses = this._enabledPseudoClasses;
+ if (enabled) {
+ if (pseudoClasses.contains(pseudoClass))
+ return;
+ pseudoClasses.push(pseudoClass);
+ } else {
+ if (!pseudoClasses.contains(pseudoClass))
+ return;
+ pseudoClasses.remove(pseudoClass);
+ }
+
+ function changed(error)
+ {
+ if (!error)
+ this.dispatchEventToListeners(WebInspector.DOMNode.Event.EnabledPseudoClassesChanged);
+ }
+
+ CSSAgent.forcePseudoState(this.id, pseudoClasses, changed.bind(this));
+ },
+
+ _makeUndoableCallback: function(callback)
+ {
+ return function(error)
+ {
+ if (!error)
+ DOMAgent.markUndoableState();
+
+ if (callback)
+ callback.apply(null, arguments);
+ };
+ }
+}
+
+WebInspector.DOMNode.prototype.__proto__ = WebInspector.Object.prototype;