blob: 3062852e523320d872dba0cf17f5edd3e233071f [file] [log] [blame]
/*
* 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.svg", "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;