Index: sky/framework/inspector/dom-agent.sky |
diff --git a/sky/framework/inspector/dom-agent.sky b/sky/framework/inspector/dom-agent.sky |
new file mode 100644 |
index 0000000000000000000000000000000000000000..6e6048fda614c2a62a912f3ff7e9ac33bf03f026 |
--- /dev/null |
+++ b/sky/framework/inspector/dom-agent.sky |
@@ -0,0 +1,169 @@ |
+<script> |
+function DOMAgent(delegate) { |
+ this.enabled = false; |
+ this.delegate_ = delegate; |
+ this.nextNodeId_ = 1; |
+ this.nodeToId_ = new Map(); |
+ this.idToNode_ = new Map(); |
+} |
+ |
+DOMAgent.prototype.getIdForNode_ = function(node) { |
+ if (this.nodeToId_.has(node)) |
+ return this.nodeToId_.get(node); |
+ var id = this.nextNodeId_++; |
+ this.nodeToId_.set(node, id); |
+ this.idToNode_.set(id, node); |
+ return id; |
+}; |
+ |
+DOMAgent.prototype.serializeChildren_ = function(node) { |
+ var children = []; |
+ for (var child = node.firstChild; child; child = child.nextSibling) { |
+ var record = this.serializeNode_(child); |
+ if (record) |
+ children.push(record); |
+ } |
+ return children; |
+}; |
+ |
+DOMAgent.prototype.serializeAttributes_ = function(element) { |
+ var attributes = []; |
+ var attrs = element.attributes; |
+ for (var i = 0; i < attrs.length; ++i) { |
+ var attr = attrs[i]; |
+ attributes.push(attr.name); |
+ attributes.push(attr.value); |
+ } |
+ return attributes; |
+}; |
+ |
+DOMAgent.prototype.serializeNode_ = function(node) { |
+ var id = this.getIdForNode_(node); |
+ |
+ var record = { |
+ nodeId: id, |
+ }; |
+ |
+ var isContainer = false; |
+ |
+ if (node instanceof Element) { |
+ isContainer = true; |
+ record.nodeType = 1; |
+ record.nodeName = node.tagName; |
+ record.localName = node.tagName; |
+ record.nodeValue = ""; |
+ record.attributes = this.serializeAttributes_(node); |
+ } else if (node instanceof Text) { |
+ record.nodeType = 3; |
+ record.nodeName = "#text"; |
+ var nodeValue = node.data; |
+ if (!nodeValue.trim()) |
+ return null; |
+ record.nodeValue = nodeValue; |
+ } else if (node instanceof Comment) { |
+ record.nodeType = 8; |
+ record.nodeName = "#comment"; |
+ record.nodeValue = node.data; |
+ } else if (node instanceof Document) { |
+ isContainer = true; |
+ record.nodeType = 9; |
+ record.nodeName = "#document"; |
+ record.localName = ""; |
+ record.nodeValue = ""; |
+ record.documentURL = node.URL; |
+ record.baseURL = node.baseURI; |
+ } else if (node instanceof DocumentFragment) { |
+ isContainer = true; |
+ record.nodeType = 11; |
+ record.nodeName = "#document-fragment"; |
+ record.localName = ""; |
+ record.nodeValue = ""; |
+ } else { |
+ console.log("Unknown node type"); |
+ return null; |
+ } |
+ |
+ if (isContainer) { |
+ var children = this.serializeChildren_(node); |
+ if (children.length) { |
+ record.childNodeCount = children.length; |
+ record.children = children; |
+ } |
+ } |
+ |
+ return record; |
+}; |
+ |
+DOMAgent.prototype.enable = function() { |
+ this.enabled = true; |
+ this.observer_ = new MutationObserver(this.mutationCallback_.bind(this)); |
+ this.observer_.observe(document, { |
+ childList: true, |
+ attributes: true, |
+ characterData: true, |
+ subtree : true, |
+ }); |
+}; |
+ |
+DOMAgent.prototype.getDocument = function() { |
+ return { |
+ root: this.serializeNode_(document), |
+ }; |
+}; |
+ |
+DOMAgent.prototype.hideHighlight = function() { |
+}; |
+ |
+DOMAgent.prototype.highlightNode = function() { |
+}; |
+ |
+DOMAgent.prototype.mutationCallback_ = function(mutationRecords) { |
+ for (var i = 0; i < mutationRecords.length; ++i) { |
+ var record = mutationRecords[i]; |
+ var type = record.type; |
+ var target = record.target; |
+ var nodeId = this.getIdForNode_(target); |
+ if (type == "attributes") { |
+ var attributeName = record.attributeName; |
+ if (target.hasAttribute(attributeName)) { |
+ this.delegate_.sendMessage("DOM.attributeModified", { |
+ nodeId: nodeId, |
+ name: attributeName, |
+ value: target.getAttribute(attributeName), |
+ }); |
+ } else { |
+ this.delegate_.sendMessage("DOM.attributeRemoved", { |
+ nodeId: nodeId, |
+ name: attributeName, |
+ }); |
+ } |
+ } else if (type == "characterData") { |
+ this.delegate_.sendMessage("DOM.characterDataModified", { |
+ nodeId: nodeId, |
+ characterData: target.data, |
+ }); |
+ } else if (type == "childList") { |
+ // FIXME: If this subtree isn't expanded, we only need to send across the |
+ // {"method":"DOM.childNodeCountUpdated","params":"nodeId":648,"childNodeCount":2} |
+ |
+ Array.prototype.forEach.call(record.removedNodes, function(node) { |
+ this.delegate_.sendMessage("DOM.childNodeRemoved", { |
+ parentNodeId: nodeId, |
+ nodeId: this.getIdForNode_(node), |
+ }); |
+ }.bind(this)); |
+ |
+ Array.prototype.forEach.call(record.addedNodes, function(node) { |
+ var previousNodeId = node.previousSibling ? this.getIdForNode_(node.previousSibling) : 0; |
+ this.delegate_.sendMessage("DOM.childNodeInserted", { |
+ parentNodeId: nodeId, |
+ previousNodeId: previousNodeId, |
+ node: this.serializeNode_(node), |
+ }); |
+ }.bind(this)); |
+ } |
+ } |
+}; |
+ |
+this.exports = DOMAgent; |
+</script> |