Reviewed by Adam.
authortimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Nov 2007 00:09:54 +0000 (00:09 +0000)
committertimothy@apple.com <timothy@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 5 Nov 2007 00:09:54 +0000 (00:09 +0000)
        Bug 15834: There are many subtle bugs in the Styles pane of the Web Inspector
        http://bugs.webkit.org/show_bug.cgi?id=15834

        - Broke up DocumentPanel and added three SidebarPane sub-classes.
        - Fixed many Style pane bugs, including:
          * Poor handling of duplicate properties in the same rule. Some of this can't be
            fixed since we can't only get the "winning" value for duplicate properties.
            So we should only show one entry per unique property name.
          * Computed style does not show font shorthand sub-properties if 'font' was used.
          * Property priority was broken, the wrong properties were crossed out.
          * The 'border' shorthand shows null for the shorthand value.
          * Shorthands didn't show their priority (e.g. !important).
          * HSL and HTML hex colors didn't have preview swatch blocks.
          * Code refactoring, making it easier to reuse for console.log later.

        * page/inspector/DocumentPanel.js: Move sidebar pane code to three seperate
          classes in new files.
        * page/inspector/MetricsSidebarPane.js: Added.
        * page/inspector/Panel.js: Remove an InspectorController.log() call.
        * page/inspector/PropertiesSection.js: Add the section to the TreeOutline.
          So TreeElements can access properties on their section.
        * page/inspector/PropertiesSidebarPane.js: Added.
        * page/inspector/SidebarPane.js: Remove the explicit asignment of the
          onexpand and oncollapse to null. These were hiding prototypes.
        * page/inspector/StylesSidebarPane.js: Added.
        * page/inspector/inspector.html: Include the new script files.
        * page/inspector/treeoutline.js: If a null representedObject is passed
          in just use a empty object.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@27431 268f45cc-cd09-0410-ab3c-d52691b4dbfc

WebCore/ChangeLog
WebCore/page/inspector/DocumentPanel.js
WebCore/page/inspector/MetricsSidebarPane.js [new file with mode: 0644]
WebCore/page/inspector/Panel.js
WebCore/page/inspector/PropertiesSection.js
WebCore/page/inspector/PropertiesSidebarPane.js [new file with mode: 0644]
WebCore/page/inspector/SidebarPane.js
WebCore/page/inspector/StylesSidebarPane.js [new file with mode: 0644]
WebCore/page/inspector/inspector.html
WebCore/page/inspector/treeoutline.js

index 8bced1a..5b2bb46 100644 (file)
@@ -1,3 +1,36 @@
+2007-11-04  Timothy Hatcher  <timothy@apple.com>
+
+        Reviewed by Adam.
+
+        Bug 15834: There are many subtle bugs in the Styles pane of the Web Inspector
+        http://bugs.webkit.org/show_bug.cgi?id=15834
+
+        - Broke up DocumentPanel and added three SidebarPane sub-classes.
+        - Fixed many Style pane bugs, including:
+          * Poor handling of duplicate properties in the same rule. Some of this can't be
+            fixed since we can't only get the "winning" value for duplicate properties.
+            So we should only show one entry per unique property name.
+          * Computed style does not show font shorthand sub-properties if 'font' was used.
+          * Property priority was broken, the wrong properties were crossed out.
+          * The 'border' shorthand shows null for the shorthand value.
+          * Shorthands didn't show their priority (e.g. !important).
+          * HSL and HTML hex colors didn't have preview swatch blocks.
+          * Code refactoring, making it easier to reuse for console.log later.
+
+        * page/inspector/DocumentPanel.js: Move sidebar pane code to three seperate
+          classes in new files.
+        * page/inspector/MetricsSidebarPane.js: Added.
+        * page/inspector/Panel.js: Remove an InspectorController.log() call.
+        * page/inspector/PropertiesSection.js: Add the section to the TreeOutline.
+          So TreeElements can access properties on their section.
+        * page/inspector/PropertiesSidebarPane.js: Added.
+        * page/inspector/SidebarPane.js: Remove the explicit asignment of the
+          onexpand and oncollapse to null. These were hiding prototypes.
+        * page/inspector/StylesSidebarPane.js: Added.
+        * page/inspector/inspector.html: Include the new script files.
+        * page/inspector/treeoutline.js: If a null representedObject is passed
+          in just use a empty object.
+
 2007-11-04  David D. Kilzer  <ddkilzer@webkit.org>
 
         Fix build when spaces appear in the WebKit source path.
index 54efd2c..f80168f 100644 (file)
@@ -55,9 +55,9 @@ WebInspector.DocumentPanel = function(resource, views)
     domView.crumbsElement.appendChild(domView.innerCrumbsElement);
 
     domView.sidebarPanes = {};
-    domView.sidebarPanes.styles = new WebInspector.SidebarPane("Styles");
-    domView.sidebarPanes.metrics = new WebInspector.SidebarPane("Metrics");
-    domView.sidebarPanes.properties = new WebInspector.SidebarPane("Properties");
+    domView.sidebarPanes.styles = new WebInspector.StylesSidebarPane();
+    domView.sidebarPanes.metrics = new WebInspector.MetricsSidebarPane();
+    domView.sidebarPanes.properties = new WebInspector.PropertiesSidebarPane();
 
     var panel = this;
     domView.sidebarPanes.styles.onexpand = function() { panel.updateStyles() };
@@ -105,7 +105,7 @@ WebInspector.DocumentPanel.prototype = {
         if (!this.views.dom.treeOutline || !this.views.dom.treeOutline.selectedTreeElement)
             return;
         var element = this.views.dom.treeOutline.selectedTreeElement;
-        element.updateSelection(element);
+        element.updateSelection();
     },
 
     get rootDOMNode()
@@ -181,8 +181,7 @@ WebInspector.DocumentPanel.prototype = {
         // FIXME: this could use findTreeElement to reuse a tree element if it already exists
         var node = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(this.rootDOMNode) : this.rootDOMNode.firstChild);
         while (node) {
-            var item = new WebInspector.DOMNodeTreeElement(node);
-            this.views.dom.treeOutline.appendChild(item);
+            this.views.dom.treeOutline.appendChild(new WebInspector.DOMNodeTreeElement(node));
             node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
         }
 
@@ -312,370 +311,32 @@ WebInspector.DocumentPanel.prototype = {
 
     updateStyles: function()
     {
-        if (!this.views.dom.sidebarPanes.styles.expanded)
+        var stylesSidebarPane = this.views.dom.sidebarPanes.styles;
+        if (!stylesSidebarPane.expanded || !stylesSidebarPane.needsUpdate)
             return;
-        if (!this.views.dom.sidebarPanes.styles.needsUpdate)
-            return;
-
-        this.views.dom.sidebarPanes.styles.needsUpdate = false;
-
-        var stylesBody = this.views.dom.sidebarPanes.styles.bodyElement;
-
-        stylesBody.removeChildren();
-        this.views.dom.sidebarPanes.styles.sections = [];
-
-        if (!this.focusedDOMNode)
-            return;
-
-        var styleNode = this.focusedDOMNode;
-        if (styleNode.nodeType === Node.TEXT_NODE && styleNode.parentNode)
-            styleNode = styleNode.parentNode;
-
-        var styleRules = [];
-        var styleProperties = [];
-
-        if (styleNode.nodeType === Node.ELEMENT_NODE) {
-            var propertyCount = [];
-
-            var computedStyle = styleNode.ownerDocument.defaultView.getComputedStyle(styleNode);
-            if (computedStyle && computedStyle.length)
-                styleRules.push({ isComputedStyle: true, selectorText: "Computed Style", style: computedStyle });
-
-            var styleNodeName = styleNode.nodeName.toLowerCase();
-            for (var i = 0; i < styleNode.attributes.length; ++i) {
-                var attr = styleNode.attributes[i];
-                if (attr.style) {
-                    var attrStyle = { attrName: attr.name, style: attr.style };
-                    attrStyle.subtitle = "element\u2019s \u201C" + attr.name + "\u201D attribute";
-                    attrStyle.selectorText = styleNodeName + "[" + attr.name;
-                    if (attr.value.length)
-                        attrStyle.selectorText += "=" + attr.value;
-                    attrStyle.selectorText += "]";
-                    styleRules.push(attrStyle);
-                }
-            }
-
-            if (styleNode.style && styleNode.style.length) {
-                var inlineStyle = { selectorText: "Inline Style Attribute", style: styleNode.style };
-                inlineStyle.subtitle = "element\u2019s \u201Cstyle\u201D attribute";
-                styleRules.push(inlineStyle);
-            }
-
-            var matchedStyleRules = styleNode.ownerDocument.defaultView.getMatchedCSSRules(styleNode, "", !Preferences.showUserAgentStyles);
-            if (matchedStyleRules) {
-                for (var i = matchedStyleRules.length - 1; i >= 0; --i)
-                    styleRules.push(matchedStyleRules[i]);
-            }
-
-            var priorityUsed = false;
-            var usedProperties = {};
-            var shorthandProperties = {};
-            for (var i = 0; i < styleRules.length; ++i) {
-                styleProperties[i] = [];
-
-                var style = styleRules[i].style;
-                var styleShorthandLookup = [];
-                for (var j = 0; j < style.length; ++j) {
-                    var prop = null;
-                    var name = style[j];
-                    var shorthand = style.getPropertyShorthand(name);
-                    if (!shorthand && styleRules[i].isComputedStyle)
-                        shorthand = shorthandProperties[name];
-
-                    if (shorthand) {
-                        prop = styleShorthandLookup[shorthand];
-                        shorthandProperties[name] = shorthand;
-                    }
-
-                    if (!priorityUsed && style.getPropertyPriority(name).length)
-                        priorityUsed = true;
-
-                    if (prop) {
-                        prop.subProperties.push(name);
-                    } else {
-                        prop = { style: style, subProperties: [name], unusedProperties: [], name: (shorthand ? shorthand : name) };
-                        styleProperties[i].push(prop);
-
-                        if (shorthand) {
-                            styleShorthandLookup[shorthand] = prop;
-                            if (!styleRules[i].isComputedStyle) {
-                                if (!propertyCount[shorthand]) {
-                                    propertyCount[shorthand] = 1;
-                                } else {
-                                    prop.unusedProperties[shorthand] = true;
-                                    propertyCount[shorthand]++;
-                                }
-                            }
-                        }
-                    }
-
-                    if (styleRules[i].isComputedStyle)
-                        continue;
 
-                    usedProperties[name] = true;
-                    if (shorthand)
-                        usedProperties[shorthand] = true;
-
-                    if (!propertyCount[name]) {
-                        propertyCount[name] = 1;
-                    } else {
-                        prop.unusedProperties[name] = true;
-                        propertyCount[name]++;
-                    }
-                }
-            }
-
-            if (priorityUsed) {
-                // walk the properties again and account for !important
-                var priorityCount = [];
-                for (var i = 0; i < styleRules.length; ++i) {
-                    if (styleRules[i].isComputedStyle)
-                        continue;
-                    var style = styleRules[i].style;
-                    for (var j = 0; j < styleProperties[i].length; ++j) {
-                        var prop = styleProperties[i][j];
-                        for (var k = 0; k < prop.subProperties.length; ++k) {
-                            var name = prop.subProperties[k];
-                            if (style.getPropertyPriority(name).length) {
-                                if (!priorityCount[name]) {
-                                    if (prop.unusedProperties[name])
-                                        prop.unusedProperties[name] = false;
-                                    priorityCount[name] = 1;
-                                } else {
-                                    priorityCount[name]++;
-                                }
-                            } else if (priorityCount[name]) {
-                                prop.unusedProperties[name] = true;
-                            }
-                        }
-                    }
-                }
-            }
-
-            var styleRulesLength = styleRules.length;
-            for (var i = 0; i < styleRulesLength; ++i) {
-                var selectorText = styleRules[i].selectorText;
-
-                var section = new WebInspector.PropertiesSection(selectorText);
-                section.expanded = true;
-
-                if (styleRules[i].isComputedStyle) {
-                    if (Preferences.showInheritedComputedStyleProperties)
-                        section.element.addStyleClass("show-inherited");
-
-                    var showInheritedLabel = document.createElement("label");
-                    var showInheritedInput = document.createElement("input");
-                    showInheritedInput.type = "checkbox";
-                    showInheritedInput.checked = Preferences.showInheritedComputedStyleProperties;
-
-                    var computedStyleSection = section;
-                    var showInheritedToggleFunction = function(event) {
-                        Preferences.showInheritedComputedStyleProperties = showInheritedInput.checked;
-                        if (Preferences.showInheritedComputedStyleProperties)
-                            computedStyleSection.element.addStyleClass("show-inherited");
-                        else
-                            computedStyleSection.element.removeStyleClass("show-inherited");
-                        event.stopPropagation();
-                    };
-
-                    showInheritedLabel.addEventListener("click", showInheritedToggleFunction, false);
-
-                    showInheritedLabel.appendChild(showInheritedInput);
-                    showInheritedLabel.appendChild(document.createTextNode("Show implicit properties"));
-                    section.subtitleElement.appendChild(showInheritedLabel);
-                } else {
-                    var sheet;
-                    var file = false;
-                    if (styleRules[i].subtitle)
-                        sheet = styleRules[i].subtitle;
-                    else if (styleRules[i].parentStyleSheet && styleRules[i].parentStyleSheet.href) {
-                        var url = styleRules[i].parentStyleSheet.href;
-                        sheet = WebInspector.linkifyURL(url, url.trimURL(WebInspector.mainResource.domain).escapeHTML());
-                        file = true;
-                    } else if (styleRules[i].parentStyleSheet && !styleRules[i].parentStyleSheet.ownerNode)
-                        sheet = "user agent stylesheet";
-                    else
-                        sheet = "inline stylesheet";
-
-                    if (file)
-                        section.subtitleElement.addStyleClass("file");
-
-                    section.subtitle = sheet;
-                }
-
-                stylesBody.appendChild(section.element);
-                this.views.dom.sidebarPanes.styles.sections.push(section);
-
-                var properties = styleProperties[i];
-                var isComputedStyle = styleRules[i].isComputedStyle;
-
-                for (var j = 0; j < properties.length; ++j) {
-                    var prop = properties[j];
-
-                    var propTreeElement = new WebInspector.StylePropertyTreeElement(prop, isComputedStyle, usedProperties);
-                    section.propertiesTreeOutline.appendChild(propTreeElement);
-                }
-            }
-        } else {
-            // can't style this node
-        }
+        stylesSidebarPane.update(this.focusedDOMNode);
+        stylesSidebarPane.needsUpdate = false;
     },
 
     updateMetrics: function()
     {
-        if (!this.views.dom.sidebarPanes.metrics.expanded)
+        var metricsSidebarPane = this.views.dom.sidebarPanes.metrics;
+        if (!metricsSidebarPane.expanded || !metricsSidebarPane.needsUpdate)
             return;
-        if (!this.views.dom.sidebarPanes.metrics.needsUpdate)
-            return;
-
-        this.views.dom.sidebarPanes.metrics.needsUpdate = false;
-
-        var metricsBody = this.views.dom.sidebarPanes.metrics.bodyElement;
-
-        metricsBody.removeChildren();
-
-        if (!this.focusedDOMNode)
-            return;
-
-        var style;
-        if (this.focusedDOMNode.nodeType === Node.ELEMENT_NODE)
-            style = this.focusedDOMNode.ownerDocument.defaultView.getComputedStyle(this.focusedDOMNode);
-        if (!style)
-            return;
-
-        var metricsElement = document.createElement("div");
-        metricsElement.className = "metrics";
 
-        function boxPartValue(style, name, suffix)
-        {
-            var value = style.getPropertyValue(name + suffix);
-            if (value === "" || value === "0px")
-                value = "\u2012";
-            return value.replace(/px$/, "");
-        }
-
-        // Display types for which margin is ignored.
-        var noMarginDisplayType = {
-            "table-cell": true,
-            "table-column": true,
-            "table-column-group": true,
-            "table-footer-group": true,
-            "table-header-group": true,
-            "table-row": true,
-            "table-row-group": true
-        };
-
-        // Display types for which padding is ignored.
-        var noPaddingDisplayType = {
-            "table-column": true,
-            "table-column-group": true,
-            "table-footer-group": true,
-            "table-header-group": true,
-            "table-row": true,
-            "table-row-group": true
-        };
-
-        var boxes = ["content", "padding", "border", "margin"];
-        var previousBox;
-        for (var i = 0; i < boxes.length; ++i) {
-            var name = boxes[i];
-
-            if (name === "margin" && noMarginDisplayType[style.display])
-                continue;
-            if (name === "padding" && noPaddingDisplayType[style.display])
-                continue;
-
-            var boxElement = document.createElement("div");
-            boxElement.className = name;
-
-            if (boxes[i] === "content") {
-                var width = style.width.replace(/px$/, "");
-                var height = style.height.replace(/px$/, "");
-                boxElement.textContent = width + " \u00D7 " + height;
-            } else {
-                var suffix = boxes[i] === "border" ? "-width" : "";
-
-                var labelElement = document.createElement("div");
-                labelElement.className = "label";
-                labelElement.textContent = name;
-                boxElement.appendChild(labelElement);
-
-                var topElement = document.createElement("div");
-                topElement.className = "top";
-                topElement.textContent = boxPartValue(style, name + "-top", suffix);
-                boxElement.appendChild(topElement);
-
-                var leftElement = document.createElement("div");
-                leftElement.className = "left";
-                leftElement.textContent = boxPartValue(style, name + "-left", suffix);
-                boxElement.appendChild(leftElement);
-
-                if (previousBox)
-                    boxElement.appendChild(previousBox);
-
-                var rightElement = document.createElement("div");
-                rightElement.className = "right";
-                rightElement.textContent = boxPartValue(style, name + "-right", suffix);
-                boxElement.appendChild(rightElement);
-
-                var bottomElement = document.createElement("div");
-                bottomElement.className = "bottom";
-                bottomElement.textContent = boxPartValue(style, name + "-bottom", suffix);
-                boxElement.appendChild(bottomElement);
-            }
-
-            previousBox = boxElement;
-        }
-
-        metricsElement.appendChild(previousBox);
-        metricsBody.appendChild(metricsElement);
+        metricsSidebarPane.update(this.focusedDOMNode);
+        metricsSidebarPane.needsUpdate = false;
     },
 
     updateProperties: function()
     {
-        if (!this.views.dom.sidebarPanes.properties.expanded)
-            return;
-        if (!this.views.dom.sidebarPanes.properties.needsUpdate)
+        var propertiesSidebarPane = this.views.dom.sidebarPanes.properties;
+        if (!propertiesSidebarPane.expanded || !propertiesSidebarPane.needsUpdate)
             return;
 
-        this.views.dom.sidebarPanes.properties.needsUpdate = false;
-
-        var propertiesBody = this.views.dom.sidebarPanes.properties.bodyElement;
-
-        propertiesBody.removeChildren();
-        this.views.dom.sidebarPanes.properties.sections = [];
-
-        if (!this.focusedDOMNode)
-            return;
-
-        for (var prototype = this.focusedDOMNode; prototype; prototype = prototype.__proto__) {
-            var hasChildren = false;
-            for (var prop in prototype) {
-                if (prop === "__treeElementIdentifier")
-                    continue;
-                if (!prototype.hasOwnProperty(prop))
-                    continue;
-
-                hasChildren = true;
-                break;
-            }
-
-            if (!hasChildren)
-                continue;
-
-            var title = Object.describe(prototype);
-            var subtitle;
-            if (title.match(/Prototype$/)) {
-                title = title.replace(/Prototype$/, "");
-                subtitle = "Prototype";
-            }
-
-            var section = new WebInspector.PropertiesSection(title, subtitle);
-            section.onpopulate = WebInspector.DOMPropertiesSection.onpopulate(prototype);
-
-            propertiesBody.appendChild(section.element);
-            this.views.dom.sidebarPanes.properties.sections.push(section);
-        }
+        propertiesSidebarPane.update(this.focusedDOMNode);
+        propertiesSidebarPane.needsUpdate = false;
     },
 
     handleKeyEvent: function(event)
@@ -721,258 +382,90 @@ WebInspector.DocumentPanel.prototype = {
 
 WebInspector.DocumentPanel.prototype.__proto__ = WebInspector.SourcePanel.prototype;
 
-WebInspector.DOMPropertiesSection = function()
-{
-    // FIXME: Perhaps this should be a real subclass someday
-}
-
-WebInspector.DOMPropertiesSection.onpopulate = function(prototype)
-{
-    return function(section) {
-        var properties = Object.sortedProperties(prototype);
-        for (var i = 0; i < properties.length; ++i) {
-            var name = properties[i];
-            if (!prototype.hasOwnProperty(name))
-                continue;
-            if (name === "__treeElementIdentifier")
-                continue;
-            var item = new WebInspector.DOMPropertyTreeElement(name, prototype);
-            section.propertiesTreeOutline.appendChild(item);
-        }
-    }
-}
-
 WebInspector.DOMNodeTreeElement = function(node)
 {
     var hasChildren = (Preferences.ignoreWhitespace ? (firstChildSkippingWhitespace.call(node) ? true : false) : node.hasChildNodes());
-
     var titleInfo = nodeTitleInfo.call(node, hasChildren, WebInspector.linkifyURL);
-    var title = titleInfo.title;
-    hasChildren = titleInfo.hasChildren;
-
-    var item = new TreeElement(title, node, hasChildren);
-    item.updateSelection = WebInspector.DOMNodeTreeElement.updateSelection;
-    item.onpopulate = WebInspector.DOMNodeTreeElement.populate;
-    item.onexpand = WebInspector.DOMNodeTreeElement.expanded;
-    item.oncollapse = WebInspector.DOMNodeTreeElement.collapsed;
-    item.onselect = WebInspector.DOMNodeTreeElement.selected;
-    item.onreveal = WebInspector.DOMNodeTreeElement.revealed;
-    item.ondblclick = WebInspector.DOMNodeTreeElement.doubleClicked;
-    if (hasChildren) 
-        item.whitespaceIgnored = Preferences.ignoreWhitespace;
-    return item;
-}
-
-WebInspector.DOMNodeTreeElement.updateSelection = function(element)
-{
-    if (!element || !element._listItemNode)
-        return;
 
-    if (!element.selectionElement) {
-        element.selectionElement = document.createElement("div");
-        element.selectionElement.className = "selection selected";
-        element._listItemNode.insertBefore(element.selectionElement, element._listItemNode.firstChild);
-    }
-
-    element.selectionElement.style.height = element._listItemNode.offsetHeight + "px";
-}
-
-WebInspector.DOMNodeTreeElement.populate = function(element)
-{
-    if (element.children.length || element.whitespaceIgnored !== Preferences.ignoreWhitespace)
-        return;
+    if (titleInfo.hasChildren) 
+        this.whitespaceIgnored = Preferences.ignoreWhitespace;
 
-    element.removeChildren();
-    element.whitespaceIgnored = Preferences.ignoreWhitespace;
-
-    var node = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(element.representedObject) : element.representedObject.firstChild);
-    while (node) {
-        var item = new WebInspector.DOMNodeTreeElement(node);
-        element.appendChild(item);
-        node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
-    }
-
-    if (element.representedObject.nodeType == Node.ELEMENT_NODE) {
-        var title = "<span class=\"webkit-html-tag close\">&lt;/" + element.representedObject.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
-        var item = new TreeElement(title, element.representedObject, false);
-        item.selectable = false;
-        element.appendChild(item);
-    }
+    TreeElement.call(this, titleInfo.title, node, titleInfo.hasChildren);
 }
 
-WebInspector.DOMNodeTreeElement.expanded = function(element)
-{
-    element.treeOutline.panel.updateTreeSelection();
-}
-
-WebInspector.DOMNodeTreeElement.collapsed = function(element)
-{
-    element.treeOutline.panel.updateTreeSelection();
-}
-
-WebInspector.DOMNodeTreeElement.revealed = function(element)
-{
-    if (!element._listItemNode || !element.treeOutline || !element.treeOutline._childrenListNode)
-        return;
-    var parent = element.treeOutline.panel.views.dom.treeContentElement;
-    parent.scrollToElement(element._listItemNode);
-}
-
-WebInspector.DOMNodeTreeElement.selected = function(element)
-{
-    var panel = element.treeOutline.panel;
-    panel.focusedDOMNode = element.representedObject;
-
-    // Call updateSelection twice to make sure the height is correct,
-    // the first time might have a bad height because we are in a weird tree state
-    element.updateSelection(element);
-    setTimeout(function() { element.updateSelection(element) }, 0);
-}
-
-WebInspector.DOMNodeTreeElement.doubleClicked = function(element)
-{
-    var panel = element.treeOutline.panel;
-    panel.rootDOMNode = element.representedObject.parentNode;
-    panel.focusedDOMNode = element.representedObject;
-}
+WebInspector.DOMNodeTreeElement.prototype = {
+    updateSelection: function()
+    {
+        if (!this._listItemNode)
+            return;
 
-WebInspector.StylePropertyTreeElement = function(prop, computedStyle, usedProperties)
-{
-    var overloadCount = 0;
-    var priority;
-    if (prop.subProperties && prop.subProperties.length > 1) {
-        for (var i = 0; i < prop.subProperties.length; ++i) {
-            var name = prop.subProperties[i];
-            if (!priority)
-                priority = prop.style.getPropertyPriority(name);
-            if (prop.unusedProperties[name])
-                overloadCount++;
+        if (!this.selectionElement) {
+            this.selectionElement = document.createElement("div");
+            this.selectionElement.className = "selection selected";
+            this._listItemNode.insertBefore(this.selectionElement, this._listItemNode.firstChild);
         }
-    }
 
-    if (!priority)
-        priority = prop.style.getPropertyPriority(prop.name);
+        this.selectionElement.style.height = this._listItemNode.offsetHeight + "px";
+    },
 
-    var overloaded = (prop.unusedProperties[prop.name] || overloadCount === prop.subProperties.length);
-    var title = WebInspector.StylePropertyTreeElement.createTitle(prop.name, prop.style, overloaded, priority, computedStyle, usedProperties);
+    onpopulate: function()
+    {
+        if (this.children.length || this.whitespaceIgnored !== Preferences.ignoreWhitespace)
+            return;
 
-    var item = new TreeElement(title, prop, (prop.subProperties && prop.subProperties.length > 1));
-    item.computedStyle = computedStyle;
-    item.onpopulate = WebInspector.StylePropertyTreeElement.populate;
-    return item;
-}
+        this.removeChildren();
+        this.whitespaceIgnored = Preferences.ignoreWhitespace;
 
-WebInspector.StylePropertyTreeElement.createTitle = function(name, style, overloaded, priority, computed, usedProperties)
-{
-    // "Nicknames" for some common values that are easier to read.
-    var valueNickname = {
-        "rgb(0, 0, 0)": "black",
-        "rgb(255, 255, 255)": "white",
-        "rgba(0, 0, 0, 0)": "transparent"
-    };
-
-    var alwaysShowComputedProperties = { "display": true, "height": true, "width": true };
-
-    var value = style.getPropertyValue(name);
-
-    var textValue = value;
-    if (value) {
-        var urls = value.match(/url\([^)]+\)/);
-        if (urls) {
-            for (var i = 0; i < urls.length; ++i) {
-                var url = urls[i].substring(4, urls[i].length - 1);
-                textValue = textValue.replace(urls[i], "url(" + WebInspector.linkifyURL(url) + ")");
-            }
-        } else {
-            if (value in valueNickname)
-                textValue = valueNickname[value];
-            textValue = textValue.escapeHTML();
+        var node = (Preferences.ignoreWhitespace ? firstChildSkippingWhitespace.call(this.representedObject) : this.representedObject.firstChild);
+        while (node) {
+            this.appendChild(new WebInspector.DOMNodeTreeElement(node));
+            node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
         }
-    }
 
-    var classes = [];
-    if (!computed && (style.isPropertyImplicit(name) || value == "initial"))
-        classes.push("implicit");
-    if (computed && !usedProperties[name] && !alwaysShowComputedProperties[name])
-        classes.push("inherited");
-    if (overloaded)
-        classes.push("overloaded");
-
-    var title = "";
-    if (classes.length)
-        title += "<span class=\"" + classes.join(" ") + "\">";
-
-    title += "<span class=\"name\">" + name.escapeHTML() + "</span>: ";
-    title += "<span class=\"value\">" + textValue;
-    if (priority && priority.length)
-        title += " !" + priority;
-    title += "</span>;";
-
-    if (value) {
-        // FIXME: this dosen't catch keyword based colors like black and white
-        var colors = value.match(/(rgb\([0-9]+,\s?[0-9]+,\s?[0-9]+\))|(rgba\([0-9]+,\s?[0-9]+,\s?[0-9]+,\s?[0-9]+\))/g);
-        if (colors) {
-            var colorsLength = colors.length;
-            for (var i = 0; i < colorsLength; ++i)
-                title += "<span class=\"swatch\" style=\"background-color: " + colors[i] + "\"></span>";
+        if (this.representedObject.nodeType == Node.ELEMENT_NODE) {
+            var title = "<span class=\"webkit-html-tag close\">&lt;/" + this.representedObject.nodeName.toLowerCase().escapeHTML() + "&gt;</span>";
+            var item = new TreeElement(title, this.representedObject, false);
+            item.selectable = false;
+            this.appendChild(item);
         }
-    }
+    },
 
-    if (classes.length)
-        title += "</span>";
+    onexpand: function()
+    {
+        this.treeOutline.panel.updateTreeSelection();
+    },
 
-    return title;
-}
+    oncollapse: function()
+    {
+        this.treeOutline.panel.updateTreeSelection();
+    },
 
-WebInspector.StylePropertyTreeElement.populate = function(element)
-{
-    if (element.children.length)
-        return;
-
-    var prop = element.representedObject;
-    if (prop.subProperties && prop.subProperties.length > 1) {
-        for (var i = 0; i < prop.subProperties.length; ++i) {
-            var name = prop.subProperties[i];
-            var overloaded = (prop.unusedProperties[prop.name] || prop.unusedProperties[name]);
-            var priority = prop.style.getPropertyPriority(name);
-            var title = WebInspector.StylePropertyTreeElement.createTitle(name, prop.style, overloaded, priority, element.computedStyle);
-            var subitem = new TreeElement(title, {}, false);
-            element.appendChild(subitem);
-        }
-    }
-}
+    onreveal: function()
+    {
+        if (!this._listItemNode || !this.treeOutline || !this.treeOutline._childrenListNode)
+            return;
+        var parent = this.treeOutline.panel.views.dom.treeContentElement;
+        parent.scrollToElement(this._listItemNode);
+    },
 
-WebInspector.DOMPropertyTreeElement = function(name, object)
-{
-    var title = "<span class=\"name\">" + name.escapeHTML() + "</span>: ";
-    title += "<span class=\"value\">" + Object.describe(object[name], true).escapeHTML() + "</span>";
-
-    var hasChildren = false;
-    var type = typeof object[name];
-    if (object[name] && (type === "object" || type === "function")) {
-        for (value in object[name]) {
-            hasChildren = true;
-            break;
-        }
-    }
+    onselect: function()
+    {
+        this.treeOutline.panel.focusedDOMNode = this.representedObject;
 
-    var representedObj = { object: object, name: name };
-    var item = new TreeElement(title, representedObj, hasChildren);
-    item.onpopulate = WebInspector.DOMPropertyTreeElement.populate;
-    return item;
-}
+        // Call updateSelection twice to make sure the height is correct,
+        // the first time might have a bad height because we are in a weird tree state
+        this.updateSelection();
 
-WebInspector.DOMPropertyTreeElement.populate = function(element)
-{
-    if (element.children.length)
-        return;
-
-    var parent = element.representedObject.object[element.representedObject.name];
-    var properties = Object.sortedProperties(parent);
-    for (var i = 0; i < properties.length; ++i) {
-        if (properties[i] === "__treeElementIdentifier")
-            continue;
-        var item = new WebInspector.DOMPropertyTreeElement(properties[i], parent);
-        element.appendChild(item);
+        var element = this;
+        setTimeout(function() { element.updateSelection() }, 0);
+    },
+
+    ondblclick: function()
+    {
+        var panel = this.treeOutline.panel;
+        panel.rootDOMNode = this.representedObject.parentNode;
+        panel.focusedDOMNode = this.representedObject;
     }
 }
+
+WebInspector.DOMNodeTreeElement.prototype.__proto__ = TreeElement.prototype;
diff --git a/WebCore/page/inspector/MetricsSidebarPane.js b/WebCore/page/inspector/MetricsSidebarPane.js
new file mode 100644 (file)
index 0000000..cb52e3f
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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.MetricsSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, "Metrics");
+}
+
+WebInspector.MetricsSidebarPane.prototype = {
+    update: function(node)
+    {
+        var body = this.bodyElement;
+
+        body.removeChildren();
+
+        if (!node)
+            return;
+
+        var style;
+        if (node.nodeType === Node.ELEMENT_NODE)
+            style = node.ownerDocument.defaultView.getComputedStyle(node);
+        if (!style)
+            return;
+
+        var metricsElement = document.createElement("div");
+        metricsElement.className = "metrics";
+
+        function boxPartValue(style, name, suffix)
+        {
+            var value = style.getPropertyValue(name + suffix);
+            if (value === "" || value === "0px")
+                value = "\u2012";
+            return value.replace(/px$/, "");
+        }
+
+        // Display types for which margin is ignored.
+        var noMarginDisplayType = {
+            "table-cell": true,
+            "table-column": true,
+            "table-column-group": true,
+            "table-footer-group": true,
+            "table-header-group": true,
+            "table-row": true,
+            "table-row-group": true
+        };
+
+        // Display types for which padding is ignored.
+        var noPaddingDisplayType = {
+            "table-column": true,
+            "table-column-group": true,
+            "table-footer-group": true,
+            "table-header-group": true,
+            "table-row": true,
+            "table-row-group": true
+        };
+
+        var boxes = ["content", "padding", "border", "margin"];
+        var previousBox;
+        for (var i = 0; i < boxes.length; ++i) {
+            var name = boxes[i];
+
+            if (name === "margin" && noMarginDisplayType[style.display])
+                continue;
+            if (name === "padding" && noPaddingDisplayType[style.display])
+                continue;
+
+            var boxElement = document.createElement("div");
+            boxElement.className = name;
+
+            if (name === "content") {
+                var width = style.width.replace(/px$/, "");
+                var height = style.height.replace(/px$/, "");
+                boxElement.textContent = width + " \u00D7 " + height;
+            } else {
+                var suffix = (name === "border" ? "-width" : "");
+
+                var labelElement = document.createElement("div");
+                labelElement.className = "label";
+                labelElement.textContent = name;
+                boxElement.appendChild(labelElement);
+
+                var topElement = document.createElement("div");
+                topElement.className = "top";
+                topElement.textContent = boxPartValue(style, name + "-top", suffix);
+                boxElement.appendChild(topElement);
+
+                var leftElement = document.createElement("div");
+                leftElement.className = "left";
+                leftElement.textContent = boxPartValue(style, name + "-left", suffix);
+                boxElement.appendChild(leftElement);
+
+                if (previousBox)
+                    boxElement.appendChild(previousBox);
+
+                var rightElement = document.createElement("div");
+                rightElement.className = "right";
+                rightElement.textContent = boxPartValue(style, name + "-right", suffix);
+                boxElement.appendChild(rightElement);
+
+                var bottomElement = document.createElement("div");
+                bottomElement.className = "bottom";
+                bottomElement.textContent = boxPartValue(style, name + "-bottom", suffix);
+                boxElement.appendChild(bottomElement);
+            }
+
+            previousBox = boxElement;
+        }
+
+        metricsElement.appendChild(previousBox);
+        body.appendChild(metricsElement);
+    }
+}
+
+WebInspector.MetricsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
index b76b953..0090021 100644 (file)
@@ -134,7 +134,6 @@ WebInspector.Panel.prototype = {
 
     set currentView(x)
     {
-        InspectorController.log(x);
         if (typeof x === "string" || x instanceof String)
             x = this.views[x];
 
index a56a852..bed9167 100644 (file)
@@ -49,6 +49,7 @@ WebInspector.PropertiesSection = function(title, subtitle)
     this.propertiesElement = document.createElement("ol");
     this.propertiesElement.className = "properties";
     this.propertiesTreeOutline = new TreeOutline(this.propertiesElement);
+    this.propertiesTreeOutline.section = this;
 
     this.element.appendChild(this.headerElement);
     this.element.appendChild(this.propertiesElement);
diff --git a/WebCore/page/inspector/PropertiesSidebarPane.js b/WebCore/page/inspector/PropertiesSidebarPane.js
new file mode 100644 (file)
index 0000000..b3448e1
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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.PropertiesSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, "Properties");
+}
+
+WebInspector.PropertiesSidebarPane.prototype = {
+    update: function(object)
+    {
+        var body = this.bodyElement;
+
+        body.removeChildren();
+
+        this.sections = [];
+
+        if (!object)
+            return;
+
+        for (var prototype = object; prototype; prototype = prototype.__proto__) {
+            var section = new WebInspector.ObjectPropertiesSection(prototype);
+            this.sections.push(section);
+            body.appendChild(section.element);
+        }
+    }
+}
+
+WebInspector.PropertiesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
+
+WebInspector.ObjectPropertiesSection = function(object)
+{
+    var title = Object.describe(object);
+    var subtitle;
+    if (title.match(/Prototype$/)) {
+        title = title.replace(/Prototype$/, "");
+        subtitle = "Prototype";
+    }
+
+    this.object = object;
+
+    WebInspector.PropertiesSection.call(this, title, subtitle);
+}
+
+WebInspector.ObjectPropertiesSection.prototype = {
+    onpopulate: function()
+    {
+        var properties = Object.sortedProperties(this.object);
+        for (var i = 0; i < properties.length; ++i) {
+            var propertyName = properties[i];
+            if (!this.object.hasOwnProperty(propertyName) || propertyName === "__treeElementIdentifier")
+                continue;
+            this.propertiesTreeOutline.appendChild(new WebInspector.ObjectPropertyTreeElement(this.object, propertyName));
+        }
+    }
+}
+
+WebInspector.ObjectPropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
+
+WebInspector.ObjectPropertyTreeElement = function(object, propertyName)
+{
+    var title = "<span class=\"name\">" + propertyName.escapeHTML() + "</span>: ";
+    title += "<span class=\"value\">" + Object.describe(object[propertyName], true).escapeHTML() + "</span>";
+
+    var hasSubProperties = false;
+    var type = typeof object[propertyName];
+    if (object[propertyName] && (type === "object" || type === "function")) {
+        for (subPropertyName in object[propertyName]) {
+            if (subPropertyName === "__treeElementIdentifier")
+                continue;
+            hasSubProperties = true;
+            break;
+        }
+    }
+
+    this.object = object;
+    this.propertyName = propertyName;
+
+    TreeElement.call(this, title, null, hasSubProperties);
+}
+
+WebInspector.ObjectPropertyTreeElement.prototype = {
+    onpopulate: function()
+    {
+        if (this.children.length)
+            return;
+
+        var object = this.object[this.propertyName];
+        var properties = Object.sortedProperties(object);
+        for (var i = 0; i < properties.length; ++i) {
+            var propertyName = properties[i];
+            if (propertyName === "__treeElementIdentifier")
+                continue;
+            this.appendChild(new WebInspector.ObjectPropertyTreeElement(object, propertyName));
+        }
+    }
+}
+
+WebInspector.ObjectPropertyTreeElement.prototype.__proto__ = TreeElement.prototype;
index 6b55fde..fda27b6 100644 (file)
@@ -46,8 +46,6 @@ WebInspector.SidebarPane = function(title)
     this.title = title;
     this.growbarVisible = false;
     this.expanded = false;
-    this.onexpand = null;
-    this.oncollapse = null;
 }
 
 WebInspector.SidebarPane.prototype = {
diff --git a/WebCore/page/inspector/StylesSidebarPane.js b/WebCore/page/inspector/StylesSidebarPane.js
new file mode 100644 (file)
index 0000000..afcedb7
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2007 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.
+ * 3.  Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE 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 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.StylesSidebarPane = function()
+{
+    WebInspector.SidebarPane.call(this, "Styles");
+}
+
+WebInspector.StylesSidebarPane.prototype = {
+    update: function(node)
+    {
+        var body = this.bodyElement;
+
+        body.removeChildren();
+
+        this.sections = [];
+
+        if (!node)
+            return;
+
+        if (node.nodeType === Node.TEXT_NODE && node.parentNode)
+            node = node.parentNode;
+
+        var styleRules = [];
+        var styleProperties = [];
+
+        if (node.nodeType === Node.ELEMENT_NODE) {
+            var propertyCount = [];
+
+            var computedStyle = node.ownerDocument.defaultView.getComputedStyle(node);
+            if (computedStyle && computedStyle.length)
+                styleRules.push({ computedStyle: true, selectorText: "Computed Style", style: computedStyle });
+
+            var nodeName = node.nodeName.toLowerCase();
+            for (var i = 0; i < node.attributes.length; ++i) {
+                var attr = node.attributes[i];
+                if (attr.style) {
+                    var attrStyle = { style: attr.style };
+                    attrStyle.subtitle = "element\u2019s \u201C" + attr.name + "\u201D attribute";
+                    attrStyle.selectorText = nodeName + "[" + attr.name;
+                    if (attr.value.length)
+                        attrStyle.selectorText += "=" + attr.value;
+                    attrStyle.selectorText += "]";
+                    styleRules.push(attrStyle);
+                }
+            }
+
+            if (node.style && node.style.length) {
+                var inlineStyle = { selectorText: "Inline Style Attribute", style: node.style };
+                inlineStyle.subtitle = "element\u2019s \u201Cstyle\u201D attribute";
+                styleRules.push(inlineStyle);
+            }
+
+            var matchedStyleRules = node.ownerDocument.defaultView.getMatchedCSSRules(node, "", !Preferences.showUserAgentStyles);
+            if (matchedStyleRules) {
+                // Add rules in reverse order to match the cascade order.
+                for (var i = (matchedStyleRules.length - 1); i >= 0; --i)
+                    styleRules.push(matchedStyleRules[i]);
+            }
+
+            var usedProperties = {};
+            var priorityUsed = false;
+
+            // Walk the style rules and make a list of all used and overloaded properties.
+            for (var i = 0; i < styleRules.length; ++i) {
+                if (styleRules[i].computedStyle)
+                    continue;
+
+                styleRules[i].overloadedProperties = {};
+
+                var foundProperties = {};
+
+                var style = styleRules[i].style;
+                for (var j = 0; j < style.length; ++j) {
+                    var name = style[j];
+                    var shorthand = style.getPropertyShorthand(name);
+                    var overloaded = (name in usedProperties);
+
+                    if (!priorityUsed && style.getPropertyPriority(name).length)
+                        priorityUsed = true;
+
+                    if (overloaded)
+                        styleRules[i].overloadedProperties[name] = true;
+
+                    foundProperties[name] = true;
+                    if (shorthand)
+                        foundProperties[shorthand] = true;
+
+                    if (name === "font") {
+                        // The font property is not reported as a shorthand. Report finding the individual
+                        // properties so they are visible in computed style.
+                        // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15598 is fixed.
+                        foundProperties["font-family"] = true;
+                        foundProperties["font-size"] = true;
+                        foundProperties["font-style"] = true;
+                        foundProperties["font-variant"] = true;
+                        foundProperties["font-weight"] = true;
+                        foundProperties["line-height"] = true;
+                    }
+                }
+
+                // Add all the properties found in this style to the used properties list.
+                // Do this here so only future rules are affect by properties used in this rule.
+                for (var name in foundProperties)
+                    usedProperties[name] = true;
+            }
+
+            if (priorityUsed) {
+                // Walk the properties again and account for !important.
+                var foundPriorityProperties = [];
+
+                // Walk in reverse to match the order !important overrides.
+                for (var i = (styleRules.length - 1); i >= 0; --i) {
+                    if (styleRules[i].computedStyle)
+                        continue;
+
+                    var foundProperties = {};
+                    var style = styleRules[i].style;
+                    for (var j = 0; j < style.length; ++j) {
+                        var name = style[j];
+
+                        // Skip duplicate properties in the same rule.
+                        if (name in foundProperties)
+                            continue;
+
+                        foundProperties[name] = true;
+
+                        if (style.getPropertyPriority(name).length) {
+                            if (!(name in foundPriorityProperties))
+                                delete styleRules[i].overloadedProperties[name];
+                            else
+                                styleRules[i].overloadedProperties[name] = true;
+                            foundPriorityProperties[name] = true;
+                        } else if (name in foundPriorityProperties)
+                            styleRules[i].overloadedProperties[name] = true;
+                    }
+                }
+            }
+
+            // Make a property section for each style rule.
+            var styleRulesLength = styleRules.length;
+            for (var i = 0; i < styleRulesLength; ++i) {
+                var styleRule = styleRules[i];
+                var subtitle = styleRule.subtitle;
+                delete styleRule.subtitle;
+
+                var computedStyle = styleRule.computedStyle;
+                delete styleRule.computedStyle;
+
+                var overloadedProperties = styleRule.overloadedProperties;
+                delete styleRule.overloadedProperties;
+
+                var section = new WebInspector.StylePropertiesSection(styleRule, subtitle, computedStyle, (overloadedProperties || usedProperties));
+                section.expanded = true;
+
+                body.appendChild(section.element);
+                this.sections.push(section);
+            }
+        } else {
+            // can't style this node
+        }
+    }
+}
+
+WebInspector.StylesSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype;
+
+WebInspector.StylePropertiesSection = function(styleRule, subtitle, computedStyle, overloadedOrUsedProperties)
+{
+    WebInspector.PropertiesSection.call(this, styleRule.selectorText);
+
+    this.styleRule = styleRule;
+    this.computedStyle = computedStyle;
+
+    if (computedStyle)
+        this.usedProperties = overloadedOrUsedProperties;
+    else
+        this.overloadedProperties = overloadedOrUsedProperties || {};
+
+    if (computedStyle) {
+        if (Preferences.showInheritedComputedStyleProperties)
+            this.element.addStyleClass("show-inherited");
+
+        var showInheritedLabel = document.createElement("label");
+        var showInheritedInput = document.createElement("input");
+        showInheritedInput.type = "checkbox";
+        showInheritedInput.checked = Preferences.showInheritedComputedStyleProperties;
+
+        var computedStyleSection = this;
+        var showInheritedToggleFunction = function(event) {
+            Preferences.showInheritedComputedStyleProperties = showInheritedInput.checked;
+            if (Preferences.showInheritedComputedStyleProperties)
+                computedStyleSection.element.addStyleClass("show-inherited");
+            else
+                computedStyleSection.element.removeStyleClass("show-inherited");
+            event.stopPropagation();
+        };
+
+        showInheritedLabel.addEventListener("click", showInheritedToggleFunction, false);
+
+        showInheritedLabel.appendChild(showInheritedInput);
+        showInheritedLabel.appendChild(document.createTextNode("Show inherited properties"));
+        this.subtitleElement.appendChild(showInheritedLabel);
+    } else {
+        if (!subtitle) {
+            if (this.styleRule.parentStyleSheet && this.styleRule.parentStyleSheet.href) {
+                var url = this.styleRule.parentStyleSheet.href;
+                subtitle = WebInspector.linkifyURL(url, url.trimURL(WebInspector.mainResource.domain).escapeHTML());
+                this.subtitleElement.addStyleClass("file");
+            } else if (this.styleRule.parentStyleSheet && !this.styleRule.parentStyleSheet.ownerNode)
+                subtitle = "user agent stylesheet";
+            else
+                subtitle = "inline stylesheet";
+        }
+
+        this.subtitle = subtitle;
+    }
+}
+
+WebInspector.StylePropertiesSection.prototype = {
+    onpopulate: function()
+    {
+        var style = this.styleRule.style;
+        if (!style.length)
+            return;
+
+        var foundProperties = {};
+
+        // Add properties in reverse order to better match how the style
+        // system picks the winning value for duplicate properties.
+        for (var i = (style.length - 1); i >= 0; --i) {
+            var name = style[i];
+            var shorthand = style.getPropertyShorthand(name);
+
+            if (name in foundProperties || (shorthand && shorthand in foundProperties))
+                continue;
+
+            foundProperties[name] = true;
+            if (shorthand)
+                foundProperties[shorthand] = true;
+
+            if (this.computedStyle)
+                var inherited = (this.usedProperties && !((shorthand || name) in this.usedProperties));
+            else {
+                var overloaded = ((shorthand || name) in this.overloadedProperties);
+
+                if (shorthand && !overloaded) {
+                    // Find out if all the individual properties of a shorthand
+                    // are overloaded and mark the shorthand as overloaded too.
+
+                    var count = 0;
+                    var overloadCount = 0;
+                    for (var j = 0; j < style.length; ++j) {
+                        var individualProperty = style[j];
+                        if (style.getPropertyShorthand(individualProperty) !== shorthand)
+                            continue;
+                        ++count;
+                        if (individualProperty in this.overloadedProperties)
+                            ++overloadCount;
+                    }
+
+                    overloaded = (overloadCount >= count);
+                }
+            }
+
+            var item = new WebInspector.StylePropertyTreeElement(style, (shorthand || name), this.computedStyle, (shorthand ? true : false), (overloaded || inherited));
+            this.propertiesTreeOutline.insertChild(item, 0);
+        }
+    }
+}
+
+WebInspector.StylePropertiesSection.prototype.__proto__ = WebInspector.PropertiesSection.prototype;
+
+WebInspector.StylePropertyTreeElement = function(style, name, computedStyle, shorthand, overloadedOrInherited)
+{
+    // These properties should always show for Computed Style
+    var alwaysShowComputedProperties = { "display": true, "height": true, "width": true };
+
+    // "Nicknames" for some common values that are easier to read.
+    var valueNicknames = {
+        "rgb(0, 0, 0)": "black",
+        "#000": "black",
+        "#000000": "black",
+        "rgb(255, 255, 255)": "white",
+        "#fff": "white",
+        "#ffffff": "white",
+        "#FFF": "white",
+        "#FFFFFF": "white",
+        "rgba(0, 0, 0, 0)": "transparent",
+        "rgb(255, 0, 0)": "red",
+        "rgb(0, 255, 0)": "lime",
+        "rgb(0, 0, 255)": "blue",
+        "rgb(255, 255, 0)": "yellow",
+        "rgb(255, 0, 255)": "magenta",
+        "rgb(0, 255, 255)": "cyan"
+    };
+
+    this.style = style;
+    this.name = name;
+    this.computedStyle = computedStyle;
+    this.shorthand = shorthand;
+    this.overloaded = (!computedStyle && overloadedOrInherited);
+    this.inherited = (computedStyle && overloadedOrInherited && !(name in alwaysShowComputedProperties));
+
+    var priority = style.getPropertyPriority(name);
+    var value = style.getPropertyValue(name);
+    var htmlValue = value;
+
+    if (priority && !priority.length)
+        delete priority;
+
+    if (!priority && shorthand) {
+        // Priority is not returned for shorthands, find the priority from an individual property.
+        for (var i = 0; i < style.length; ++i) {
+            var individualProperty = style[i];
+            if (style.getPropertyShorthand(individualProperty) !== name)
+                continue;
+            priority = style.getPropertyPriority(individualProperty);
+            break;
+        }
+    }
+
+    if (value) {
+        var urls = value.match(/url\([^)]+\)/);
+        if (urls) {
+            for (var i = 0; i < urls.length; ++i) {
+                var url = urls[i].substring(4, urls[i].length - 1);
+                htmlValue = htmlValue.replace(urls[i], "url(" + WebInspector.linkifyURL(url) + ")");
+            }
+        } else {
+            if (value in valueNicknames)
+                htmlValue = valueNicknames[value];
+            htmlValue = htmlValue.escapeHTML();
+        }
+    } else if (shorthand) {
+        // Some shorthands (like border) return a null value, so compute a shorthand value.
+        // FIXME: remove this when http://bugs.webkit.org/show_bug.cgi?id=15823 is fixed.
+
+        value = "";
+
+        var foundProperties = {};
+        for (var i = 0; i < style.length; ++i) {
+            var individualProperty = style[i];
+            if (style.getPropertyShorthand(individualProperty) !== name || individualProperty in foundProperties)
+                continue;
+
+            var individualValue = style.getPropertyValue(individualProperty);
+            if (style.isPropertyImplicit(individualProperty) || individualValue === "initial")
+                continue;
+
+            foundProperties[individualProperty] = true;
+
+            if (value.length)
+                value += " ";
+            value += individualValue;
+        }
+
+        htmlValue = value.escapeHTML();
+    } else
+        htmlValue = value = "";
+
+    var classes = [];
+    if (!computedStyle && (style.isPropertyImplicit(name) || value === "initial"))
+        classes.push("implicit");
+    if (this.inherited)
+        classes.push("inherited");
+    if (this.overloaded)
+        classes.push("overloaded");
+
+    var title = "";
+    if (classes.length)
+        title += "<span class=\"" + classes.join(" ") + "\">";
+
+    title += "<span class=\"name\">" + name.escapeHTML() + "</span>: ";
+    title += "<span class=\"value\">" + htmlValue;
+    if (priority)
+        title += " !" + priority;
+    title += "</span>;";
+
+    if (value) {
+        // FIXME: this dosen't catch keyword based colors like black and white
+        var colors = value.match(/((rgb|hsl)a?\([^)]+\))|(#[0-9a-fA-F]{6})|(#[0-9a-fA-F]{3})/g);
+        if (colors) {
+            var colorsLength = colors.length;
+            for (var i = 0; i < colorsLength; ++i)
+                title += "<span class=\"swatch\" style=\"background-color: " + colors[i] + "\"></span>";
+        }
+    }
+
+    if (classes.length)
+        title += "</span>";
+
+    TreeElement.call(this, title, null, shorthand);
+
+    this.tooltip = name + ": " + (valueNicknames[value] || value) + (priority ? " !" + priority : "");
+}
+
+WebInspector.StylePropertyTreeElement.prototype = {
+    onpopulate: function()
+    {
+        // Only populate once and if this property is a shorthand.
+        if (this.children.length || !this.shorthand)
+            return;
+
+        var foundProperties = {};
+
+        // Add properties in reverse order to better match how the style
+        // system picks the winning value for duplicate properties.
+        for (var i = (this.style.length - 1); i >= 0; --i) {
+            var name = this.style[i];
+            var shorthand = this.style.getPropertyShorthand(name);
+
+            if (shorthand !== this.name || name in foundProperties)
+                continue;
+
+            foundProperties[name] = true;
+
+            if (this.computedStyle)
+                var inherited = (this.treeOutline.section.usedProperties && !(name in this.treeOutline.section.usedProperties));
+            else
+                var overloaded = (name in this.treeOutline.section.overloadedProperties);
+
+            var item = new WebInspector.StylePropertyTreeElement(this.style, name, this.computedStyle, false, (inherited || overloaded));
+            this.insertChild(item, 0);
+        }
+    }
+}
+
+WebInspector.StylePropertyTreeElement.prototype.__proto__ = TreeElement.prototype;
index ca0d007..cf80ad9 100644 (file)
@@ -38,6 +38,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="ResourceCategory.js"></script>
     <script type="text/javascript" src="SidebarPane.js"></script>
     <script type="text/javascript" src="PropertiesSection.js"></script>
+    <script type="text/javascript" src="MetricsSidebarPane.js"></script>
+    <script type="text/javascript" src="PropertiesSidebarPane.js"></script>
+    <script type="text/javascript" src="StylesSidebarPane.js"></script>
     <script type="text/javascript" src="Panel.js"></script>
     <script type="text/javascript" src="ResourcePanel.js"></script>
     <script type="text/javascript" src="SourcePanel.js"></script>
index b9bdc75..ecb85aa 100644 (file)
@@ -278,8 +278,8 @@ TreeOutline.prototype.findTreeElement = function(representedObject, isAncestor,
     }
 
     for (var i = 0; i < ancestors.length; ++i) {
-        item = this.findTreeElement(ancestors[i]);
-        if (ancestors[i] !== representedObject && item.onpopulate)
+        item = this.findTreeElement(ancestors[i], isAncestor, getParent);
+        if (ancestors[i] !== representedObject && item && item.onpopulate)
             item.onpopulate(item);
     }
 
@@ -378,7 +378,7 @@ TreeOutline.prototype.removeChildrenRecursive = TreeOutline._removeChildrenRecur
 function TreeElement(title, representedObject, hasChildren)
 {
     this._title = title;
-    this.representedObject = representedObject;
+    this.representedObject = (representedObject || {});
 
     if (this.representedObject.__treeElementIdentifier)
         this.identifier = this.representedObject.__treeElementIdentifier;
@@ -393,13 +393,6 @@ function TreeElement(title, representedObject, hasChildren)
     this.selectable = true;
     this.hasChildren = hasChildren;
     this.children = [];
-    this.onpopulate = null;
-    this.onexpand = null;
-    this.oncollapse = null;
-    this.onreveal = null;
-    this.onselect = null;
-    this.ondeselect = null;
-    this.ondblclick = null;
     this.treeOutline = null;
     this.parent = null;
     this.previousSibling = null;