blob: 3c7709328efe548db22914135b8d80f998821a94 [file] [log] [blame]
/*
* weinre is available under *either* the terms of the modified BSD license *or* the
* MIT License (2008). See http://opensource.org/licenses/alphabetical for full text.
*
* Copyright (c) 2010, 2011 IBM Corporation
*/
requireClass ../common/Weinre
requireClass ../common/IDGenerator
//-----------------------------------------------------------------------------
class NodeStore
this.__nodeMap = {}
this.__nodeDataMap = {}
this.inspectedNodes = []
document.addEventListener("DOMSubtreeModified", handleDOMSubtreeModified, false)
document.addEventListener("DOMNodeInserted", handleDOMNodeInserted, false)
document.addEventListener("DOMNodeRemoved", handleDOMNodeRemoved, false)
document.addEventListener("DOMAttrModified", handleDOMAttrModified, false)
document.addEventListener("DOMCharacterDataModified", handleDOMCharacterDataModified, false)
//-----------------------------------------------------------------------------
method addInspectedNode(nodeId)
this.inspectedNodes.unshift(nodeId)
if (this.inspectedNodes.length > 5) {
this.inspectedNodes = this.inspectedNodes.slice(0,5)
}
//-----------------------------------------------------------------------------
method getInspectedNode(index)
return this.inspectedNodes[index]
//-----------------------------------------------------------------------------
method getNode(nodeId)
return this.__nodeMap[nodeId]
//-----------------------------------------------------------------------------
method checkNodeId(node)
return node.__weinre_id
//-----------------------------------------------------------------------------
method getNodeId(node)
if (node.__weinre_id) {
return node.__weinre_id
}
node.__weinre_id = this.nextNodeId()
this.__nodeMap[node.__weinre_id] = node
return node.__weinre_id
//-----------------------------------------------------------------------------
method getNodeData(nodeId, depth)
return this.serializeNode(this.getNode(nodeId), depth)
//-----------------------------------------------------------------------------
method getPreviousSiblingId(node)
while (true) {
var sib = node.previousSibling
if (!sib) return 0
var id = this.checkNodeId(sib)
if (id) return id
node = sib
}
//-----------------------------------------------------------------------------
method nextNodeId()
return "" + IDGenerator.next()
//-----------------------------------------------------------------------------
method serializeNode(node, depth)
var nodeName = ""
var nodeValue = null
var localName = null
var id = this.getNodeId(node)
switch(node.nodeType) {
case Node.TEXT_NODE:
case Node.COMMENT_NODE:
case Node.CDATA_SECTION_NODE:
nodeValue = node.nodeValue
break
case Node.ATTRIBUTE_NODE:
localName = node.localName
break
case Node.DOCUMENT_FRAGMENT_NODE:
break
case Node.DOCUMENT_NODE:
case Node.ELEMENT_NODE:
default:
nodeName = node.nodeName
localName = node.localName
break
}
var nodeData = {
id: id,
nodeType: node.nodeType,
nodeName: nodeName,
localName: localName,
nodeValue: nodeValue
}
if (node.nodeType == Node.ELEMENT_NODE || node.nodeType == Node.DOCUMENT_NODE || node.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {
nodeData.childNodeCount = this.childNodeCount(node)
var children = this.serializeNodeChildren(node, depth)
if (children.length) {
nodeData.children = children
}
if (node.nodeType == Node.ELEMENT_NODE) {
nodeData.attributes = []
for (var i=0; i<node.attributes.length; i++) {
nodeData.attributes.push(node.attributes[i].nodeName)
nodeData.attributes.push(node.attributes[i].nodeValue)
}
}
else if (node.nodeType == Node.DOCUMENT_NODE) {
nodeData.documentURL = window.location.href
}
}
else if (node.nodeType == Node.DOCUMENT_TYPE_NODE) {
nodeData.publicId = node.publicId
nodeData.systemId = node.systemId
nodeData.internalSubset = node.internalSubset
}
else if (node.nodeType == Node.ATTRIBUTE_NODE) {
nodeData.name = node.nodeName
nodeData.value = node.nodeValue
}
return nodeData
//-----------------------------------------------------------------------------
method serializeNodeChildren(node, depth)
var result = []
var childIds = this.childNodeIds(node)
if (depth == 0) {
if (childIds.length == 1) {
var childNode = this.getNode(childIds[0])
if (childNode.nodeType == Node.TEXT_NODE) {
result.push(this.serializeNode(childNode))
}
}
return result
}
depth--;
for (var i=0; i<childIds.length; i++) {
result.push(this.serializeNode(this.getNode(childIds[i]), depth))
}
return result
//-----------------------------------------------------------------------------
method childNodeCount(node)
return this.childNodeIds(node).length
//-----------------------------------------------------------------------------
method childNodeIds(node)
var ids = []
for (var i=0; i<node.childNodes.length; i++) {
if (this.isToBeSkipped(node.childNodes[i])) continue
ids.push(this.getNodeId(node.childNodes[i]))
}
return ids
//-----------------------------------------------------------------------------
method isToBeSkipped(node)
if (!node) return true
if (node.__weinreHighlighter) return true
if (node.nodeType != Node.TEXT_NODE) return false
return !!node.nodeValue.match(/^\s*$/)
//-----------------------------------------------------------------------------
function handleDOMSubtreeModified(event)
if (!event.attrChange) return
NodeStore.handleDOMAttrModified(event)
//-----------------------------------------------------------------------------
function handleDOMNodeInserted(event)
var targetId = Weinre.nodeStore.checkNodeId(event.target)
var parentId = Weinre.nodeStore.checkNodeId(event.relatedNode)
if (!parentId) return
var child = Weinre.nodeStore.serializeNode(event.target, 0)
var previous = Weinre.nodeStore.getPreviousSiblingId(event.target)
Weinre.wi.DOMNotify.childNodeInserted(parentId, previous, child)
//-----------------------------------------------------------------------------
function handleDOMNodeRemoved(event)
var targetId = Weinre.nodeStore.checkNodeId(event.target)
var parentId = Weinre.nodeStore.checkNodeId(event.relatedNode)
if (!parentId) return
if (targetId) {
Weinre.wi.DOMNotify.childNodeRemoved(parentId, targetId)
}
else {
var childCount = Weinre.nodeStore.childNodeCount(event.relatedNode)
Weinre.wi.DOMNotify.childNodeCountUpdated(parentId, childCount)
}
//-----------------------------------------------------------------------------
// This event is not actually fired in WebKit, but DOMSubtreeModified may
// be fired for attribute changes. Doesn't seem to be at the moment.
function handleDOMAttrModified(event)
var targetId = Weinre.nodeStore.checkNodeId(event.target)
if (!targetId) return
attrs = []
for (var i=0; i<event.target.attributes.length; i++) {
attrs.push(event.target.attributes[i].name)
attrs.push(event.target.attributes[i].value)
}
Weinre.wi.DOMNotify.attributesUpdated(targetId, attrs)
//-----------------------------------------------------------------------------
function handleDOMCharacterDataModified(event)
var targetId = Weinre.nodeStore.checkNodeId(event.target)
if (!targetId) return
Weinre.wi.DOMNotify.characterDataModified(targetId, event.newValue)