diff options
Diffstat (limited to 'Source/WebInspectorUI/UserInterface/DOMNodeDetailsSidebarPanel.js')
-rw-r--r-- | Source/WebInspectorUI/UserInterface/DOMNodeDetailsSidebarPanel.js | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/Source/WebInspectorUI/UserInterface/DOMNodeDetailsSidebarPanel.js b/Source/WebInspectorUI/UserInterface/DOMNodeDetailsSidebarPanel.js new file mode 100644 index 000000000..b7a8a970d --- /dev/null +++ b/Source/WebInspectorUI/UserInterface/DOMNodeDetailsSidebarPanel.js @@ -0,0 +1,281 @@ +/* + * 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: + * 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. + */ + +WebInspector.DOMNodeDetailsSidebarPanel = function() { + WebInspector.DOMDetailsSidebarPanel.call(this, "dom-node-details", WebInspector.UIString("Node"), WebInspector.UIString("Node"), "Images/NavigationItemAngleBrackets.pdf", "2"); + + WebInspector.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.AttributeModified, this._attributesChanged, this); + WebInspector.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.AttributeRemoved, this._attributesChanged, this); + + this.element.classList.add(WebInspector.DOMNodeDetailsSidebarPanel.StyleClassName); + + this._identityNodeTypeRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Type")); + this._identityNodeNameRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Name")); + this._identityNodeValueRow = new WebInspector.DetailsSectionSimpleRow(WebInspector.UIString("Value")); + + var identityGroup = new WebInspector.DetailsSectionGroup([this._identityNodeTypeRow, this._identityNodeNameRow, this._identityNodeValueRow]); + var identitySection = new WebInspector.DetailsSection("dom-node-identity", WebInspector.UIString("Identity"), [identityGroup]); + + this._attributesDataGridRow = new WebInspector.DetailsSectionDataGridRow(null, WebInspector.UIString("No Attributes")); + + var attributesGroup = new WebInspector.DetailsSectionGroup([this._attributesDataGridRow]); + var attributesSection = new WebInspector.DetailsSection("dom-node-attributes", WebInspector.UIString("Attributes"), [attributesGroup]); + + this._propertiesRow = new WebInspector.DetailsSectionRow; + + var propertiesGroup = new WebInspector.DetailsSectionGroup([this._propertiesRow]); + var propertiesSection = new WebInspector.DetailsSection("dom-node-properties", WebInspector.UIString("Properties"), [propertiesGroup]); + + this._eventListenersSectionGroup = new WebInspector.DetailsSectionGroup; + var eventListenersSection = new WebInspector.DetailsSection("dom-node-event-listeners", WebInspector.UIString("Event Listeners"), [this._eventListenersSectionGroup]); + + this.element.appendChild(identitySection.element); + this.element.appendChild(attributesSection.element); + this.element.appendChild(propertiesSection.element); + this.element.appendChild(eventListenersSection.element); +}; + +WebInspector.DOMNodeDetailsSidebarPanel.StyleClassName = "dom-node"; +WebInspector.DOMNodeDetailsSidebarPanel.PropertiesObjectGroupName = "dom-node-details-sidebar-properties-object-group"; + +WebInspector.DOMNodeDetailsSidebarPanel.prototype = { + constructor: WebInspector.DOMNodeDetailsSidebarPanel, + + // Public + + refresh: function() + { + var domNode = this.domNode; + if (!domNode) + return; + + this._identityNodeTypeRow.value = this._nodeTypeDisplayName(); + this._identityNodeNameRow.value = domNode.nodeNameInCorrectCase(); + this._identityNodeValueRow.value = domNode.nodeValue(); + + this._refreshAttributes(); + this._refreshProperties(); + this._refreshEventListeners(); + }, + + // Private + + _refreshAttributes: function() + { + this._attributesDataGridRow.dataGrid = this._createAttributesDataGrid(); + }, + + _refreshProperties: function() + { + var domNode = this.domNode; + if (!domNode) + return; + + RuntimeAgent.releaseObjectGroup(WebInspector.DOMNodeDetailsSidebarPanel.PropertiesObjectGroupName); + WebInspector.RemoteObject.resolveNode(domNode, WebInspector.DOMNodeDetailsSidebarPanel.PropertiesObjectGroupName, nodeResolved.bind(this)); + + function nodeResolved(object) + { + if (!object) + return; + + // Bail if the DOM node changed while we were waiting for the async response. + if (this.domNode !== domNode) + return; + + function collectPrototypes() + { + // This builds an object with numeric properties. This is easier than dealing with arrays + // with the way RemoteObject works. Start at 1 since we use parseInt later and parseInt + // returns 0 for non-numeric strings make it ambiguous. + var prototype = this; + var result = []; + var counter = 1; + + while (prototype) { + result[counter++] = prototype; + prototype = prototype.__proto__; + } + + return result; + } + + object.callFunction(collectPrototypes, undefined, nodePrototypesReady.bind(this)); + object.release(); + } + + function nodePrototypesReady(object) + { + if (!object) + return; + + // Bail if the DOM node changed while we were waiting for the async response. + if (this.domNode !== domNode) + return; + + object.getOwnProperties(fillSection.bind(this)); + } + + function fillSection(prototypes) + { + if (!prototypes) + return; + + // Bail if the DOM node changed while we were waiting for the async response. + if (this.domNode !== domNode) + return; + + var element = this._propertiesRow.element; + element.removeChildren(); + + // Get array of prototype user-friendly names. + for (var i = 0; i < prototypes.length; ++i) { + // The only values we care about are numeric, as assigned in collectPrototypes. + if (!parseInt(prototypes[i].name, 10)) + continue; + + var prototype = prototypes[i].value; + var title = prototype.description; + if (title.match(/Prototype$/)) + title = title.replace(/Prototype$/, WebInspector.UIString(" (Prototype)")); + else if (title === "Object") + title = title + WebInspector.UIString(" (Prototype)"); + + var propertiesSection = new WebInspector.ObjectPropertiesSection(prototype); + + var detailsSection = new WebInspector.DetailsSection(prototype.description.hash + "-prototype-properties", title, null, null, true); + detailsSection.groups[0].rows = [new WebInspector.DetailsSectionPropertiesRow(propertiesSection)]; + + element.appendChild(detailsSection.element); + } + } + }, + + _refreshEventListeners: function() + { + var domNode = this.domNode; + if (!domNode) + return; + + domNode.eventListeners(eventListenersCallback.bind(this)); + + function eventListenersCallback(error, eventListeners) + { + if (error) + return; + + // Bail if the DOM node changed while we were waiting for the async response. + if (this.domNode !== domNode) + return; + + var eventListenerTypes = []; + var eventListenerSections = {}; + for (var i = 0; i < eventListeners.length; ++i) { + var eventListener = eventListeners[i]; + eventListener.node = WebInspector.domTreeManager.nodeForId(eventListener.nodeId); + + var type = eventListener.type; + var section = eventListenerSections[type]; + if (!section) { + section = new WebInspector.EventListenerSection(type, domNode.id); + eventListenerSections[type] = section; + eventListenerTypes.push(type); + } + + section.addListener(eventListener); + } + + if (!eventListenerTypes.length) { + var emptyRow = new WebInspector.DetailsSectionRow(WebInspector.UIString("No Event Listeners")); + emptyRow.showEmptyMessage(); + this._eventListenersSectionGroup.rows = [emptyRow]; + return; + } + + eventListenerTypes.sort(); + + var rows = []; + for (var i = 0; i < eventListenerTypes.length; ++i) + rows.push(eventListenerSections[eventListenerTypes[i]]); + this._eventListenersSectionGroup.rows = rows; + } + }, + + _attributesChanged: function(event) + { + if (event.data.node !== this.domNode) + return; + this._refreshAttributes(); + }, + + _nodeTypeDisplayName: function() + { + switch (this.domNode.nodeType()) { + case Node.ELEMENT_NODE: + return WebInspector.UIString("Element"); + case Node.TEXT_NODE: + return WebInspector.UIString("Text Node"); + case Node.COMMENT_NODE: + return WebInspector.UIString("Comment"); + case Node.DOCUMENT_NODE: + return WebInspector.UIString("Document"); + case Node.DOCUMENT_TYPE_NODE: + return WebInspector.UIString("Document Type"); + case Node.DOCUMENT_FRAGMENT_NODE: + return WebInspector.UIString("Document Fragment"); + case Node.CDATA_SECTION_NODE: + return WebInspector.UIString("Character Data"); + case Node.PROCESSING_INSTRUCTION_NODE: + return WebInspector.UIString("Processing Instruction"); + default: + console.error("Unknown DOM node type: ", this.domNode.nodeType()); + return this.domNode.nodeType(); + } + }, + + _createAttributesDataGrid: function() + { + var domNode = this.domNode; + if (!domNode || !domNode.hasAttributes()) + return null; + + var columns = {name: {title: WebInspector.UIString("Name"), width: "30%"}, value: {title: WebInspector.UIString("Value")}}; + var dataGrid = new WebInspector.DataGrid(columns); + + var attributes = domNode.attributes(); + for (var i = 0; i < attributes.length; ++i) { + var attribute = attributes[i]; + + var node = new WebInspector.DataGridNode({name: attribute.name, value: attribute.value || ""}, false); + node.selectable = true; + + dataGrid.appendChild(node); + } + + return dataGrid; + } +}; + +WebInspector.DOMNodeDetailsSidebarPanel.prototype.__proto__ = WebInspector.DOMDetailsSidebarPanel.prototype; |