Reviewed by Sam Weinig.
authorthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Oct 2007 00:08:06 +0000 (00:08 +0000)
committerthatcher <thatcher@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Oct 2007 00:08:06 +0000 (00:08 +0000)
        - Made seperate files for the various classes in ResourcePanel.js.
        - Broke up ResourcePanel.js and created seperate panel classes for different resource types.
        - Moved View code down to the Panel base-class.
        - Reduced code duplication in DatabasePanel.js by sub-classing from the new ResourcePanel.

        * page/inspector/DatabasePanel.js:
        * page/inspector/DocumentPanel.js: Added.
        * page/inspector/FontPanel.js: Added.
        * page/inspector/ImagePanel.js: Added.
        * page/inspector/Panel.js: Added.
        * page/inspector/PropertiesSection.js: Added.
        * page/inspector/Resource.js:
        * page/inspector/ResourcePanel.js:
        * page/inspector/SidebarPane.js: Added.
        * page/inspector/SourcePanel.js: Added.
        * page/inspector/inspector.css:
        * page/inspector/inspector.html:
        * page/inspector/inspector.js:

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

15 files changed:
WebCore/ChangeLog
WebCore/WebCore.xcodeproj/project.pbxproj
WebCore/page/inspector/DatabasePanel.js
WebCore/page/inspector/DocumentPanel.js [new file with mode: 0644]
WebCore/page/inspector/FontPanel.js [new file with mode: 0644]
WebCore/page/inspector/ImagePanel.js [new file with mode: 0644]
WebCore/page/inspector/Panel.js [new file with mode: 0644]
WebCore/page/inspector/PropertiesSection.js [new file with mode: 0644]
WebCore/page/inspector/Resource.js
WebCore/page/inspector/ResourcePanel.js
WebCore/page/inspector/SidebarPane.js [new file with mode: 0644]
WebCore/page/inspector/SourcePanel.js [new file with mode: 0644]
WebCore/page/inspector/inspector.css
WebCore/page/inspector/inspector.html
WebCore/page/inspector/inspector.js

index af4556a..c681f56 100644 (file)
@@ -1,3 +1,26 @@
+2007-10-23  Timothy Hatcher  <timothy@apple.com>
+
+        Reviewed by Sam Weinig.
+
+        - Made seperate files for the various classes in ResourcePanel.js.
+        - Broke up ResourcePanel.js and created seperate panel classes for different resource types.
+        - Moved View code down to the Panel base-class.
+        - Reduced code duplication in DatabasePanel.js by sub-classing from the new ResourcePanel.
+
+        * page/inspector/DatabasePanel.js:
+        * page/inspector/DocumentPanel.js: Added.
+        * page/inspector/FontPanel.js: Added.
+        * page/inspector/ImagePanel.js: Added.
+        * page/inspector/Panel.js: Added.
+        * page/inspector/PropertiesSection.js: Added.
+        * page/inspector/Resource.js:
+        * page/inspector/ResourcePanel.js:
+        * page/inspector/SidebarPane.js: Added.
+        * page/inspector/SourcePanel.js: Added.
+        * page/inspector/inspector.css:
+        * page/inspector/inspector.html:
+        * page/inspector/inspector.js:
+
 2007-10-23  Anders Carlsson  <andersca@apple.com>
 
         Correct the version #if check.
index f256685..b1ebeac 100644 (file)
                0867D690FE84028FC02AAC07 /* Project object */ = {
                        isa = PBXProject;
                        buildConfigurationList = 149C284308902B11008A9EFC /* Build configuration list for PBXProject "WebCore" */;
+                       compatibilityVersion = "Xcode 2.4";
                        hasScannedForEncodings = 1;
                        knownRegions = (
                                English,
index 0a92b45..d3cb2e7 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.DatabasePanel = function(database)
+WebInspector.DatabasePanel = function(database, views)
 {
-    WebInspector.Panel.call(this);
+    var allViews = [{ title: "Query" }, { title: "Browse" }];
+    if (views)
+        allViews = allViews.concat(views);
 
-    this.database = database;
+    WebInspector.ResourcePanel.call(this, database, allViews);
+
+    this.currentView = this.views.browse;
 
     this.queryPromptElement = document.createElement("textarea");
     this.queryPromptElement.className = "database-prompt";
@@ -42,80 +46,48 @@ WebInspector.DatabasePanel = function(database)
     this.queryPromptHistory = [];
     this.queryPromptHistoryOffset = 0;
 
-    var selectViewFunction = function(event)
-    {
-        WebInspector.navigateToView(event.currentTarget.view);
-    }
+    var queryView = this.views.query;
 
-    var views = [
-        { name: "query", title: "Query", selected: false },
-        { name: "browse", title: "Browse", selected: true }
-    ];
-
-    this.views = {};
-    this.viewButtons = [];
-    for (var i = 0; i < views.length; ++i) {
-        var buttonElement = document.createElement("button");
-        buttonElement.setAttribute("title", views[i].title);
-        buttonElement.addEventListener("click", selectViewFunction, "true");
-        buttonElement.appendChild(document.createElement("img"));
-
-        var contentElement = document.createElement("div");
-        contentElement.className = "content database-" + views[i].name;
-
-        var view = {};
-        view.panel = this;
-        view.buttonElement = buttonElement;
-        view.contentElement = contentElement;
-        view.buttonElement.view = view;
-
-        this.views[views[i].name] = view;
-        this.viewButtons.push(buttonElement);
-        this.element.appendChild(contentElement);
-    }
-
-    this.currentView = this.views.browse;
+    queryView.commandListElement = document.createElement("ol");
+    queryView.commandListElement.className = "database-command-list";
+    queryView.contentElement.appendChild(queryView.commandListElement);
 
-    var queryPanel = this.views.query;
-
-    queryPanel.commandListElement = document.createElement("ol");
-    queryPanel.commandListElement.className = "database-command-list";
-    queryPanel.contentElement.appendChild(queryPanel.commandListElement);
-
-    queryPanel.onshow = function()
+    queryView.show = function()
     {
         panel.queryPromptElement.focus();
         this.commandListElement.scrollTop = this.previousScrollTop;
     };
 
-    queryPanel.onhide = function()
+    queryView.hide = function()
     {
         this.previousScrollTop = this.commandListElement.scrollTop;
     };
 
-    var browsePanel = this.views.browse;
+    var browseView = this.views.browse;
 
-    browsePanel.reloadTableElement = document.createElement("button");
-    browsePanel.reloadTableElement.appendChild(document.createElement("img"));
-    browsePanel.reloadTableElement.className = "database-table-reload";
-    browsePanel.reloadTableElement.title = "Reload";
-    browsePanel.reloadTableElement.addEventListener("click", function() { panel.updateTableList(); panel.updateTableBrowser() }, false);
+    browseView.reloadTableElement = document.createElement("button");
+    browseView.reloadTableElement.appendChild(document.createElement("img"));
+    browseView.reloadTableElement.className = "database-table-reload";
+    browseView.reloadTableElement.title = "Reload";
+    browseView.reloadTableElement.addEventListener("click", function() { panel.updateTableList(); panel.updateTableBrowser() }, false);
 
-    browsePanel.onshow = function()
+    browseView.show = function()
     {
         panel.updateTableList();
         panel.queryPromptElement.focus();
 
         this.tableSelectElement.removeStyleClass("hidden");
-        document.getElementById("viewbuttons").appendChild(this.tableSelectElement);
+        if (!this.tableSelectElement.parentNode)
+            document.getElementById("toolbarButtons").appendChild(this.tableSelectElement);
 
         this.reloadTableElement.removeStyleClass("hidden");
-        document.getElementById("viewbuttons").appendChild(this.reloadTableElement);
+        if (!this.reloadTableElement.parentNode)
+            document.getElementById("toolbarButtons").appendChild(this.reloadTableElement);
 
         this.contentElement.scrollTop = this.previousScrollTop;
     };
 
-    browsePanel.onhide = function()
+    browseView.hide = function()
     {
         this.tableSelectElement.addStyleClass("hidden");
         this.reloadTableElement.addStyleClass("hidden");
@@ -130,47 +102,8 @@ var Math = window.Math;
 return {
     show: function()
     {
-        WebInspector.Panel.prototype.show.call(this);
+        WebInspector.ResourcePanel.prototype.show.call(this);
         this.queryPromptElement.focus();
-        if (this.currentView && "onshow" in this.currentView)
-            this.currentView.onshow.call(this.currentView);
-    },
-
-    hide: function()
-    {
-        if (this.currentView && "onhide" in this.currentView)
-            this.currentView.onhide();
-        WebInspector.Panel.prototype.hide.call(this);
-    },
-
-    get currentView()
-    {
-        return this._currentView;
-    },
-
-    set currentView(x)
-    {
-        if (this._currentView === x)
-            return;
-
-        if (this._currentView) {
-            if ("onhide" in this._currentView)
-                this._currentView.onhide.call(this._currentView);
-            this._currentView.buttonElement.removeStyleClass("selected");
-            this._currentView.contentElement.removeStyleClass("selected");
-        }
-
-        this._currentView = x;
-
-        if (x) {
-            x.buttonElement.addStyleClass("selected");
-            x.contentElement.addStyleClass("selected");
-            if ("onshow" in x)
-                x.onshow.call(x);
-
-            if (x.contentElement.parentNode !== this.element)
-                InspectorController.log("Tried to set currentView to a view " + x.title + " whose contentElement is a non-child");
-        }
     },
 
     get currentTable()
@@ -226,7 +159,7 @@ return {
         browseView.tableSelectElement.removeChildren();
 
         var selectedTableName = this.currentTable;
-        var tableNames = InspectorController.databaseTableNames(this.database.database).sort();
+        var tableNames = InspectorController.databaseTableNames(this.resource.database).sort();
 
         var length = tableNames.length;
         for (var i = 0; i < length; ++i) {
@@ -253,7 +186,7 @@ return {
         try {
             var panel = this;
             var query = "SELECT * FROM " + this.currentTable;
-            this.database.database.executeSql(query, [], function(result) { panel.browseQueryFinished(result) });
+            this.resource.database.executeSql(query, [], function(result) { panel.browseQueryFinished(result) });
         } catch(e) {
             // FIXME: handle this error a better way.
             this.views.browse.contentElement.removeChildren();
@@ -362,7 +295,7 @@ return {
 
         try {
             var panel = this;
-            this.database.database.executeSql(query, [], function(result) { panel.queryFinished(query, result) });
+            this.resource.database.executeSql(query, [], function(result) { panel.queryFinished(query, result) });
 
             this.queryPromptHistory.push(query);
             this.queryPromptHistoryOffset = 0;
@@ -512,4 +445,4 @@ return {
 }
 })();
 
-WebInspector.DatabasePanel.prototype.__proto__ = WebInspector.Panel.prototype;
+WebInspector.DatabasePanel.prototype.__proto__ = WebInspector.ResourcePanel.prototype;
diff --git a/WebCore/page/inspector/DocumentPanel.js b/WebCore/page/inspector/DocumentPanel.js
new file mode 100644 (file)
index 0000000..b626a95
--- /dev/null
@@ -0,0 +1,967 @@
+/*
+ * 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.DocumentPanel = function(resource, views)
+{
+    var allViews = [{ title: "DOM" }];
+    if (views)
+        allViews = allViews.concat(views);
+
+    WebInspector.SourcePanel.call(this, resource, allViews);
+
+    var domView = this.views.dom;
+    domView.show = function() { InspectorController.highlightDOMNode(panel.focusedDOMNode) };
+    domView.hide = function() { InspectorController.hideDOMNodeHighlight() };
+
+    domView.sideContentElement = document.createElement("div");
+    domView.sideContentElement.className = "content side";
+
+    domView.treeContentElement = document.createElement("div");
+    domView.treeContentElement.className = "content tree outline-disclosure";
+
+    domView.treeListElement = document.createElement("ol");
+    domView.treeOutline = new TreeOutline(domView.treeListElement);
+    domView.treeOutline.panel = this;
+
+    var panel = this;
+    window.addEventListener("resize", function() { panel.updateTreeSelection() }, false);
+
+    domView.crumbsElement = document.createElement("div");
+    domView.crumbsElement.className = "crumbs";
+
+    domView.innerCrumbsElement = document.createElement("div");
+    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");
+
+    var panel = this;
+    domView.sidebarPanes.styles.onexpand = function() { panel.updateStyles() };
+    domView.sidebarPanes.metrics.onexpand = function() { panel.updateMetrics() };
+    domView.sidebarPanes.properties.onexpand = function() { panel.updateProperties() };
+
+    domView.sidebarPanes.styles.expanded = true;
+
+    domView.sidebarElement = document.createElement("div");
+    domView.sidebarElement.className = "sidebar";
+
+    domView.sidebarElement.appendChild(domView.sidebarPanes.styles.element);
+    domView.sidebarElement.appendChild(domView.sidebarPanes.metrics.element);
+    domView.sidebarElement.appendChild(domView.sidebarPanes.properties.element);
+
+    domView.sideContentElement.appendChild(domView.treeContentElement);
+    domView.sideContentElement.appendChild(domView.crumbsElement);
+    domView.treeContentElement.appendChild(domView.treeListElement);
+
+    domView.sidebarResizeElement = document.createElement("div");
+    domView.sidebarResizeElement.className = "sidebar-resizer";
+    domView.sidebarResizeElement.addEventListener("mousedown", function(event) { panel.rightSidebarResizerDragStart(event) }, false);
+
+    domView.contentElement.appendChild(domView.sideContentElement);
+    domView.contentElement.appendChild(domView.sidebarElement);
+    domView.contentElement.appendChild(domView.sidebarResizeElement);
+
+    this.rootDOMNode = this.resource.documentNode;
+}
+
+WebInspector.DocumentPanel.prototype = {
+    updateTreeSelection: function()
+    {
+        if (!this.views.dom.treeOutline || !this.views.dom.treeOutline.selectedTreeElement)
+            return;
+        var element = this.views.dom.treeOutline.selectedTreeElement;
+        element.updateSelection(element);
+    },
+
+    get rootDOMNode()
+    {
+        return this._rootDOMNode;
+    },
+
+    set rootDOMNode(x)
+    {
+        if (this._rootDOMNode === x)
+            return;
+
+        this._rootDOMNode = x;
+
+        this.updateBreadcrumb();
+        this.updateTreeOutline();
+    },
+
+    get focusedDOMNode()
+    {
+        return this._focusedDOMNode;
+    },
+
+    set focusedDOMNode(x)
+    {
+        if (this.resource.category !== WebInspector.resourceCategories.documents) {
+            InspectorController.log("Called set focusedDOMNode on a non-document resource " + this.resource.displayName + " which is not a document");
+            return;
+        }
+
+        if (this._focusedDOMNode === x) {
+            var nodeItem = this.revealNode(x);
+            if (nodeItem)
+                nodeItem.select();
+            return;
+        }
+
+        this._focusedDOMNode = x;
+
+        this.updateBreadcrumb();
+
+        for (var pane in this.views.dom.sidebarPanes)
+            this.views.dom.sidebarPanes[pane].needsUpdate = true;
+
+        this.updateStyles();
+        this.updateMetrics();
+        this.updateProperties();
+
+        InspectorController.highlightDOMNode(x);
+
+        var nodeItem = this.revealNode(x);
+        if (nodeItem)
+            nodeItem.select();
+    },
+
+    revealNode: function(node)
+    {
+        var nodeItem = this.views.dom.treeOutline.findTreeElement(node, function(a, b) { return isAncestorNode.call(a, b); }, function(a) { return a.parentNode; });
+        if (!nodeItem)
+            return;
+
+        nodeItem.reveal();
+        return nodeItem;
+    },
+
+    updateTreeOutline: function()
+    {
+        this.views.dom.treeOutline.removeChildrenRecursive();
+
+        if (!this.rootDOMNode)
+            return;
+
+        // 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);
+            node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
+        }
+
+        this.updateTreeSelection();
+    },
+
+    updateBreadcrumb: function()
+    {
+        if (!this.views || !this.views.dom.contentElement)
+            return;
+        var crumbs = this.views.dom.innerCrumbsElement;
+        if (!crumbs)
+            return;
+
+        var handled = false;
+        var foundRoot = false;
+        var crumb = crumbs.firstChild;
+        while (crumb) {
+            if (crumb.representedObject === this.rootDOMNode)
+                foundRoot = true;
+
+            if (foundRoot)
+                crumb.addStyleClass("hidden");
+            else
+                crumb.removeStyleClass("hidden");
+
+            if (crumb.representedObject === this.focusedDOMNode) {
+                crumb.addStyleClass("selected");
+                handled = true;
+            } else {
+                crumb.removeStyleClass("selected");
+            }
+
+            crumb = crumb.nextSibling;
+        }
+
+        if (handled)
+            return;
+
+        crumbs.removeChildren();
+
+        var panel = this;
+        var selectCrumbFunction = function(event)
+        {
+            if (event.currentTarget.hasStyleClass("hidden"))
+                panel.rootDOMNode = event.currentTarget.representedObject.parentNode;
+            panel.focusedDOMNode = event.currentTarget.representedObject;
+            event.preventDefault();
+            event.stopPropagation();
+        }
+
+        var selectCrumbRootFunction = function(event)
+        {
+            panel.rootDOMNode = event.currentTarget.representedObject.parentNode;
+            panel.focusedDOMNode = event.currentTarget.representedObject;
+            event.preventDefault();
+            event.stopPropagation();
+        }
+
+        foundRoot = false;
+        var current = this.focusedDOMNode;
+        while (current) {
+            if (current.nodeType === Node.DOCUMENT_NODE)
+                break;
+
+            if (current === this.rootDOMNode)
+                foundRoot = true;
+
+            var crumb = document.createElement("span");
+            crumb.className = "crumb";
+            crumb.representedObject = current;
+            crumb.addEventListener("mousedown", selectCrumbFunction, false);
+            crumb.addEventListener("dblclick", selectCrumbRootFunction, false);
+
+            var crumbTitle;
+            switch (current.nodeType) {
+                case Node.ELEMENT_NODE:
+                    crumbTitle = current.nodeName.toLowerCase();
+    
+                    var value = current.getAttribute("id");
+                    if (value && value.length)
+                        crumbTitle += "#" + value;
+
+                    value = current.getAttribute("class");
+                    if (value && value.length) {
+                        var classes = value.split(/\s+/);
+                        var classesLength = classes.length;
+                        for (var i = 0; i < classesLength; ++i) {
+                            value = classes[i];
+                            if (value && value.length)
+                                crumbTitle += "." + value;
+                        }
+                    }
+
+                    break;
+
+                case Node.TEXT_NODE:
+                    if (isNodeWhitespace.call(current))
+                        crumbTitle = "(whitespace)";
+                    else
+                        crumbTitle = "(text)";
+                    break
+
+                case Node.COMMENT_NODE:
+                    crumbTitle = "<!-->";
+                    break;
+
+                default:
+                    crumbTitle = current.nodeName.toLowerCase();
+            }
+
+            crumb.textContent = crumbTitle;
+
+            if (foundRoot)
+                crumb.addStyleClass("hidden");
+            if (current === this.focusedDOMNode)
+                crumb.addStyleClass("selected");
+            if (!crumbs.childNodes.length)
+                crumb.addStyleClass("end");
+            if (current.parentNode.nodeType === Node.DOCUMENT_NODE)
+                crumb.addStyleClass("start");
+
+            crumbs.appendChild(crumb);
+            current = current.parentNode;
+        }
+    },
+
+    updateStyles: function()
+    {
+        if (!this.views.dom.sidebarPanes.styles.expanded)
+            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
+        }
+    },
+
+    updateMetrics: function()
+    {
+        if (!this.views.dom.sidebarPanes.metrics.expanded)
+            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);
+    },
+
+    updateProperties: function()
+    {
+        if (!this.views.dom.sidebarPanes.properties.expanded)
+            return;
+        if (!this.views.dom.sidebarPanes.properties.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);
+        }
+    },
+
+    handleKeyEvent: function(event)
+    {
+        if (this.views.dom.treeOutline && this.currentView && this.currentView === this.views.dom)
+            this.views.dom.treeOutline.handleKeyEvent(event);
+    },
+
+    rightSidebarResizerDragStart: function(event)
+    {
+        var panel = this; 
+        WebInspector.dividerDragStart(this.views.dom.sidebarElement, function(event) { panel.rightSidebarResizerDrag(event) }, function(event) { panel.rightSidebarResizerDragEnd(event) }, event, "col-resize");
+    },
+
+    rightSidebarResizerDragEnd: function(event)
+    {
+        var panel = this;
+        WebInspector.dividerDragEnd(this.views.dom.sidebarElement, function(event) { panel.rightSidebarResizerDrag(event) }, function(event) { panel.rightSidebarResizerDragEnd(event) }, event);
+    },
+
+    rightSidebarResizerDrag: function(event)
+    {
+        var rightSidebar = this.views.dom.sidebarElement;
+        if (rightSidebar.dragging == true) {
+            var x = event.clientX + window.scrollX;
+
+            var leftSidebarWidth = window.getComputedStyle(document.getElementById("sidebar")).getPropertyCSSValue("width").getFloatValue(CSSPrimitiveValue.CSS_PX);
+            var newWidth = Number.constrain(window.innerWidth - x, 100, window.innerWidth - leftSidebarWidth - 100);
+
+            if (x == newWidth)
+                rightSidebar.dragLastX = x;
+
+            rightSidebar.style.width = newWidth + "px";
+            this.views.dom.sideContentElement.style.right = newWidth + "px";
+            this.views.dom.sidebarResizeElement.style.right = (newWidth - 3) + "px";
+            event.preventDefault();
+        }
+    }
+}
+
+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;
+
+    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);
+    }
+}
+
+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.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 (!priority)
+        priority = prop.style.getPropertyPriority(prop.name);
+
+    var overloaded = (prop.unusedProperties[prop.name] || overloadCount === prop.subProperties.length);
+    var title = WebInspector.StylePropertyTreeElement.createTitle(prop.name, prop.style, overloaded, priority, computedStyle, usedProperties);
+
+    var item = new TreeElement(title, prop, (prop.subProperties && prop.subProperties.length > 1));
+    item.computedStyle = computedStyle;
+    item.onpopulate = WebInspector.StylePropertyTreeElement.populate;
+    return item;
+}
+
+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 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 (classes.length)
+        title += "</span>";
+
+    return title;
+}
+
+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);
+        }
+    }
+}
+
+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;
+        }
+    }
+
+    var representedObj = { object: object, name: name };
+    var item = new TreeElement(title, representedObj, hasChildren);
+    item.onpopulate = WebInspector.DOMPropertyTreeElement.populate;
+    return item;
+}
+
+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);
+    }
+}
diff --git a/WebCore/page/inspector/FontPanel.js b/WebCore/page/inspector/FontPanel.js
new file mode 100644 (file)
index 0000000..85e5fb5
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ * 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.FontPanel = function(resource)
+{
+    WebInspector.ResourcePanel.call(this, resource);
+
+    this.element.addStyleClass("font");
+
+    var uniqueFontName = "WebInspectorFontPreview" + this.resource.identifier;
+
+    this.fontPreviewElement = document.createElement("div");
+    this.fontPreviewElement.className = "preview";
+    this.element.appendChild(this.fontPreviewElement);
+
+    this.fontPreviewElement.style.setProperty("font-family", uniqueFontName, null);
+    this.fontPreviewElement.innerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890";
+
+    this.updateFontPreviewSize();
+
+    var panel = this;
+    var resizeListener = function() {
+        panel.updateFontPreviewSize();
+    };
+
+    window.addEventListener("resize", resizeListener, false);
+}
+
+WebInspector.FontPanel.prototype = {
+    show: function()
+    {
+        WebInspector.ResourcePanel.prototype.show.call(this);
+        this.updateFontPreviewSize();
+    },
+
+    updateFontPreviewSize: function ()
+    {
+        if (!this.fontPreviewElement || !this.visible)
+            return;
+
+        this.fontPreviewElement.removeStyleClass("preview");
+
+        var measureFontSize = 50;
+        this.fontPreviewElement.style.setProperty("position", "absolute", null);
+        this.fontPreviewElement.style.setProperty("font-size", measureFontSize + "px", null);
+        this.fontPreviewElement.style.removeProperty("height");
+
+        var height = this.fontPreviewElement.offsetHeight;
+        var width = this.fontPreviewElement.offsetWidth;
+
+        var containerHeight = this.element.offsetHeight;
+        var containerWidth = this.element.offsetWidth;
+
+        if (!height || !width || !containerHeight || !containerWidth) {
+            this.fontPreviewElement.style.removeProperty("font-size");
+            this.fontPreviewElement.style.removeProperty("position");
+            this.fontPreviewElement.addStyleClass("preview");
+            return;
+        }
+
+        var lineCount = this.fontPreviewElement.getElementsByTagName("br").length + 1;
+        var realLineHeight = Math.floor(height / lineCount);
+        var fontSizeLineRatio = measureFontSize / realLineHeight;
+        var widthRatio = containerWidth / width;
+        var heightRatio = containerHeight / height;
+
+        if (heightRatio < widthRatio)
+            var finalFontSize = Math.floor(realLineHeight * heightRatio * fontSizeLineRatio) - 1;
+        else
+            var finalFontSize = Math.floor(realLineHeight * widthRatio * fontSizeLineRatio) - 1;
+
+        this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null);
+        this.fontPreviewElement.style.setProperty("height", this.fontPreviewElement.offsetHeight + "px", null);
+        this.fontPreviewElement.style.removeProperty("position");
+
+        this.fontPreviewElement.addStyleClass("preview");
+    }
+}
+
+WebInspector.FontPanel.prototype.__proto__ = WebInspector.ResourcePanel.prototype;
diff --git a/WebCore/page/inspector/ImagePanel.js b/WebCore/page/inspector/ImagePanel.js
new file mode 100644 (file)
index 0000000..b6fde59
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.ImagePanel = function(resource)
+{
+    WebInspector.ResourcePanel.call(this, resource);
+
+    this.element.addStyleClass("image");
+
+    var container = document.createElement("div");
+    container.className = "image";
+    this.element.appendChild(container);
+
+    this.imagePreviewElement = document.createElement("img");
+    this.imagePreviewElement.setAttribute("src", this.resource.url);
+
+    container.appendChild(this.imagePreviewElement);
+
+    container = document.createElement("div");
+    container.className = "info";
+    this.element.appendChild(container);
+
+    var imageNameElement = document.createElement("h1");
+    imageNameElement.className = "title";
+    imageNameElement.textContent = this.resource.displayName;
+    container.appendChild(imageNameElement);
+
+    var infoListElement = document.createElement("dl");
+    infoListElement.className = "infoList";
+
+    var imageProperties = [
+        { name: "Dimensions", value: this.imagePreviewElement.naturalWidth + " \u00D7 " + this.imagePreviewElement.height },
+        { name: "File size", value: (this.resource.contentLength / 1024).toPrecision(2) + "KB" },
+        { name: "MIME type", value: this.resource.mimeType }
+    ];
+
+    var listHTML = '';
+    for (var i = 0; i < imageProperties.length; ++i)
+        listHTML += "<dt>" + imageProperties[i].name + "</dt><dd>" + imageProperties[i].value + "</dd>";
+
+    infoListElement.innerHTML = listHTML;
+    container.appendChild(infoListElement);
+}
+
+WebInspector.ImagePanel.prototype = {
+    
+}
+
+WebInspector.ImagePanel.prototype.__proto__ = WebInspector.ResourcePanel.prototype;
diff --git a/WebCore/page/inspector/Panel.js b/WebCore/page/inspector/Panel.js
new file mode 100644 (file)
index 0000000..b76b953
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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.Panel = function(views)
+{
+    this._visible = false;
+
+    this.element = document.createElement("div");
+    this.element.className = "panel";
+
+    this.views = {};
+    this.viewButtons = [];
+
+    if (views) {
+        var selectViewFunction = function(event)
+        {
+            var clickedView = event.currentTarget.view;
+            clickedView.panel.currentView = clickedView;
+        };
+
+        for (var i = 0; i < views.length; ++i) {
+            var view = views[i];
+            view.panel = this;
+
+            view.buttonElement = document.createElement("button");
+            view.buttonElement.setAttribute("title", view.title);
+            view.buttonElement.addEventListener("click", selectViewFunction, false);
+            view.buttonElement.appendChild(document.createElement("img"));
+            view.buttonElement.view = view;
+
+            view.contentElement = document.createElement("div");
+            view.contentElement.className = "content " + view.title.toLowerCase();
+
+            this.views[view.title.toLowerCase()] = view;
+            this.viewButtons.push(view.buttonElement);
+            this.element.appendChild(view.contentElement);
+        }
+    }
+}
+
+WebInspector.Panel.prototype = {
+    show: function()
+    {
+        this._visible = true;
+        if (!this.element.parentNode)
+            this.attach();
+        this.element.addStyleClass("selected");
+        this.updateToolbar();
+        if (this.currentView && this.currentView.show)
+            this.currentView.show();
+    },
+
+    hide: function()
+    {
+        if (this.currentView && this.currentView.hide)
+            this.currentView.hide();
+        document.getElementById("toolbarButtons").removeChildren();
+        this.element.removeStyleClass("selected");
+        this._visible = false;
+    },
+
+    updateToolbar: function()
+    {
+        var buttonContainer = document.getElementById("toolbarButtons");
+        buttonContainer.removeChildren();
+
+        var buttons = this.viewButtons;
+        if (buttons.length < 2)
+            return;
+
+        for (var i = 0; i < buttons.length; ++i) {
+            var button = buttons[i];
+
+            if (i === 0)
+                button.addStyleClass("first");
+            else if (i === (buttons.length - 1))
+                button.addStyleClass("last");
+
+            if (i) {
+                var divider = document.createElement("img");
+                divider.className = "split-button-divider";
+                buttonContainer.appendChild(divider);
+            }
+
+            button.addStyleClass("split-button");
+            button.addStyleClass("view-button-" + button.title.toLowerCase());
+
+            buttonContainer.appendChild(button);
+        }
+    },
+
+    attach: function()
+    {
+        document.getElementById("main").appendChild(this.element);
+    },
+
+    detach: function()
+    {
+        if (WebInspector.currentPanel === this)
+            WebInspector.currentPanel = null;
+        if (this.element && this.element.parentNode)
+            this.element.parentNode.removeChild(this.element);
+    },
+
+    get currentView()
+    {
+        return this._currentView;
+    },
+
+    set currentView(x)
+    {
+        InspectorController.log(x);
+        if (typeof x === "string" || x instanceof String)
+            x = this.views[x];
+
+        if (this._currentView === x)
+            return;
+
+        if (this._currentView) {
+            this._currentView.buttonElement.removeStyleClass("selected");
+            this._currentView.contentElement.removeStyleClass("selected");
+            if (this._currentView.hide)
+                this._currentView.hide();
+        }
+
+        this._currentView = x;
+
+        if (x) {
+            x.buttonElement.addStyleClass("selected");
+            x.contentElement.addStyleClass("selected");
+            if (x.show)
+                x.show();
+            if (x.panel !== this)
+                InspectorController.log("Set currentView to a view " + x.title + " whose panel is not this panel");
+        }
+    },
+
+    get visible()
+    {
+        return this._visible;
+    },
+
+    set visible(x)
+    {
+        if (this._visible === x)
+            return;
+
+        if (x)
+            this.show();
+        else
+            this.hide();
+    }
+}
diff --git a/WebCore/page/inspector/PropertiesSection.js b/WebCore/page/inspector/PropertiesSection.js
new file mode 100644 (file)
index 0000000..a56a852
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * 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.PropertiesSection = function(title, subtitle)
+{
+    this.element = document.createElement("div");
+    this.element.className = "section";
+
+    this.headerElement = document.createElement("div");
+    this.headerElement.className = "header";
+
+    this.titleElement = document.createElement("div");
+    this.titleElement.className = "title";
+
+    this.subtitleElement = document.createElement("div");
+    this.subtitleElement.className = "subtitle";
+
+    this.headerElement.appendChild(this.titleElement);
+    this.headerElement.appendChild(this.subtitleElement);
+
+    var section = this;
+    this.headerElement.addEventListener("click", function() { section.expanded = !section.expanded; }, false);
+
+    this.propertiesElement = document.createElement("ol");
+    this.propertiesElement.className = "properties";
+    this.propertiesTreeOutline = new TreeOutline(this.propertiesElement);
+
+    this.element.appendChild(this.headerElement);
+    this.element.appendChild(this.propertiesElement);
+
+    this.title = title;
+    this.subtitle = subtitle;
+    this.expanded = false;
+}
+
+WebInspector.PropertiesSection.prototype = {
+    get title()
+    {
+        return this._title;
+    },
+
+    set title(x)
+    {
+        if (this._title === x)
+            return;
+        this._title = x;
+        this.titleElement.textContent = x;
+    },
+
+    get subtitle()
+    {
+        return this._subtitle;
+    },
+
+    set subtitle(x)
+    {
+        if (this._subtitle === x)
+            return;
+        this._subtitle = x;
+        this.subtitleElement.innerHTML = x;
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    set expanded(x)
+    {
+        if (x)
+            this.expand();
+        else
+            this.collapse();
+    },
+
+    expand: function()
+    {
+        if (this._expanded)
+            return;
+        this._expanded = true;
+
+        if (!this._populated && this.onpopulate) {
+            this.onpopulate(this);
+            this._populated = true;
+        }
+        this.element.addStyleClass("expanded");
+    },
+
+    collapse: function()
+    {
+        if (!this._expanded)
+            return;
+        this._expanded = false;
+        this.element.removeStyleClass("expanded");
+    }
+}
index d68bee5..e365a14 100644 (file)
@@ -234,10 +234,6 @@ WebInspector.Resource.prototype = {
             return;
 
         this._finished = x;
-        this.updateTitleSoon();
-
-        if (this.panel)
-            this.panel.needsRefresh = true;
 
         if (x) {
             var canvas = document.getElementById("loadingIcon" + this.identifier);
@@ -247,6 +243,9 @@ WebInspector.Resource.prototype = {
             this._checkTips();
             this._checkWarnings();
         }
+
+        this.updateTitleSoon();
+        this.updatePanel();
     },
 
     get failed()
@@ -257,6 +256,9 @@ WebInspector.Resource.prototype = {
     set failed(x)
     {
         this._failed = x;
+
+        this.updateTitleSoon();
+        this.updatePanel();
     },
 
     get category()
@@ -279,8 +281,7 @@ WebInspector.Resource.prototype = {
         if (this._category)
             this._category.addResource(this);
 
-        if (this.panel)
-            this.panel.needsRefresh = true;
+        this.updatePanel();
     },
 
     get mimeType()
@@ -557,10 +558,44 @@ WebInspector.Resource.prototype = {
         this.listItem.tooltip = this.url;
     },
 
+    updatePanel: function()
+    {
+        if (this._panel) {
+            var current = (WebInspector.currentPanel === this._panel);
+
+            this._panel.detach();
+            delete this._panel;
+
+            if (current)
+                WebInspector.currentPanel = this.panel;
+        }
+    },
+
     get panel()
     {
-        if (!this._panel)
-            this._panel = new WebInspector.ResourcePanel(this);
+        if (!this._panel) {
+            if (this.finished && !this.failed) {
+                switch (this.category) {
+                case WebInspector.resourceCategories.documents:
+                    this._panel = new WebInspector.DocumentPanel(this);
+                    break;
+                case WebInspector.resourceCategories.stylesheets:
+                case WebInspector.resourceCategories.scripts:
+                    this._panel = new WebInspector.SourcePanel(this);
+                    break;
+                case WebInspector.resourceCategories.images:
+                    this._panel = new WebInspector.ImagePanel(this);
+                    break;
+                case WebInspector.resourceCategories.fonts:
+                    this._panel = new WebInspector.FontPanel(this);
+                    break;
+                }
+            }
+
+            if (!this._panel)
+                this._panel = new WebInspector.ResourcePanel(this);
+        }
+
         return this._panel;
     },
 
@@ -578,13 +613,14 @@ WebInspector.Resource.prototype = {
 
     attach: function()
     {
-        this.panel.attach();
+        if (this._panel)
+            this._panel.attach();
     },
 
     detach: function()
     {
         if (this._panel)
-            this.panel.detach();
+            this._panel.detach();
         if (this.fontStyleElement && this.fontStyleElement.parentNode)
             this.fontStyleElement.parentNode.removeChild(this.fontStyleElement);
     },
index 23a6277..b165c2b 100644 (file)
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.ResourcePanel = function(resource)
+WebInspector.ResourcePanel = function(resource, views)
 {
+    WebInspector.Panel.call(this, views);
     this.resource = resource;
-    this.messages = [];
-
-    WebInspector.Panel.call(this);
 }
 
 WebInspector.ResourcePanel.prototype = {
     show: function()
     {
         WebInspector.Panel.prototype.show.call(this);
-
-        this.resource.listItem.select(true);
+        this.resource.listItem.select(true); // passing true prevents a cycle
         this.resource.listItem.reveal();
-
-        if (this.currentView && "onshow" in this.currentView)
-            this.currentView.onshow();
     },
 
     hide: function()
     {
-        this.resource.listItem.deselect(true);
-        if (this.currentView && "onhide" in this.currentView)
-            this.currentView.onhide();
+        this.resource.listItem.deselect(true); // passing true prevents a cycle
         WebInspector.Panel.prototype.hide.call(this);
-    },
-
-    sourceRow: function(lineNumber)
-    {
-        this.refreshIfNeeded();
-        var doc = this.sourceFrame.contentDocument;
-        var rows = doc.getElementsByTagName("table")[0].rows;
-
-        // Line numbers are a 1-based index, but the rows collection is 0-based.
-        --lineNumber;
-        if (lineNumber >= rows.length)
-            lineNumber = rows.length - 1;
-
-        return rows[lineNumber];
-    },
-
-    showSourceLine: function(lineNumber)
-    {
-        var row = this.sourceRow(lineNumber);
-        if (!row)
-            return;
-        this.navigateToView("source");
-        row.scrollIntoView(true);
-    },
-
-    addMessageToSource: function(msg)
-    {
-        this.messages.push(msg);
-        if (this.sourceFrame)
-            this._addMessageToSource(msg);
-    },
-
-    _addMessageToSource: function(msg)
-    {
-        var row = this.sourceRow(msg.line);
-        if (!row)
-            return;
-        var cell = row.getElementsByTagName("td")[1];
-
-        var errorDiv = cell.lastChild;
-        if (!errorDiv || errorDiv.nodeName.toLowerCase() !== "div" || !errorDiv.hasStyleClass("webkit-html-message-bubble")) {
-            errorDiv = document.createElement("div");
-            errorDiv.className = "webkit-html-message-bubble";
-            cell.appendChild(errorDiv);
-        }
-        var imageURL;
-        switch (msg.level) {
-            case WebInspector.ConsoleMessage.MessageLevel.Error:
-                errorDiv.addStyleClass("webkit-html-error-message");
-                imageURL = "Images/errorIcon.png";
-                break;
-            case WebInspector.ConsoleMessage.MessageLevel.Warning:
-                errorDiv.addStyleClass("webkit-html-warning-message");
-                imageURL = "Images/warningIcon.png";
-                break;
-        }
-
-        var lineDiv = document.createElement("div");
-        lineDiv.className = "webkit-html-message-line";
-        errorDiv.appendChild(lineDiv);
-
-        var image = document.createElement("img");
-        image.src = imageURL;
-        image.className = "webkit-html-message-icon";
-        lineDiv.appendChild(image);
-
-        lineDiv.appendChild(document.createTextNode(msg.message));
-    },
-
-    _addMessagesToSource: function()
-    {
-        for (var i = 0; i < this.messages.length; ++i)
-            this._addMessageToSource(this.messages[i]);
-    },
-
-    navigateToView: function(view)
-    {
-        if (typeof view === "string" || view instanceof String) {
-            if (this.needsRefresh)
-                this.refresh();
-            view = this.views[view];
-        }
-
-        WebInspector.navigateToView(view);
-    },
-
-    createViews: function()
-    {
-        this.currentView = null;
-
-        var selectViewFunction = function(event)
-        {
-            WebInspector.navigateToView(event.currentTarget.view);
-        }
-
-        var views = [
-            {name: "source", title: "Source", selected: true},
-        ];
-
-        if (this.resource.category === WebInspector.resourceCategories.documents) {
-            var domView = {name: "dom", title: "DOM", selected: false};
-            var panel = this;
-            domView.onshow = function() { InspectorController.highlightDOMNode(panel.focusedDOMNode) };
-            domView.onhide = function() { InspectorController.hideDOMNodeHighlight() };
-            views.push(domView);
-        }
-
-        var oldViews = this.views || {};
-        this.views = {};
-        this.viewButtons = [];
-        for (var i = 0; i < views.length; ++i) {
-            var buttonElement = document.createElement("button");
-            buttonElement.setAttribute("title", views[i].title);
-            buttonElement.addEventListener("click", selectViewFunction, "true");
-            buttonElement.appendChild(document.createElement("img"));
-
-            var contentElement = document.createElement("div");
-            contentElement.className = "content " + views[i].name;
-
-            // We need to reuse the old view object if possible because it might
-            // already be in the backForwardList
-            var view = oldViews[views[i].name] || {};
-
-            view.buttonElement = buttonElement;
-            view.contentElement = contentElement;
-            view.panel = this;
-            view.buttonElement.view = view;
-            if ("onshow" in views[i])
-                view.onshow = views[i].onshow;
-            if ("onhide" in views[i])
-                view.onhide = views[i].onhide;
-
-            this.views[views[i].name] = view;
-            this.viewButtons.push(buttonElement);
-            this.element.appendChild(contentElement);
-        }
-
-        this.currentView = this.views.source;
-
-        if (WebInspector.currentPanel == this)
-            WebInspector.updateViewButtons();
-    },
-
-    _createSourceFrame: function()
-    {
-        this.sourceFrame = document.createElement("iframe");
-        this.sourceFrame.setAttribute("viewsource", "true");
-        this.sourceFrame.name = "sourceFrame" + WebInspector.ResourcePanel.sourceFrameCounter++;
-        this.views.source.contentElement.appendChild(this.sourceFrame);
-        InspectorController.addSourceToFrame(this.resource.identifier, this.sourceFrame);
-        WebInspector.addMainEventListeners(this.sourceFrame.contentDocument);
-        this._addMessagesToSource();
-    },
-
-    updateTreeSelection: function()
-    {
-        if (!this.domTreeOutline || !this.domTreeOutline.selectedTreeElement)
-            return;
-        var element = this.domTreeOutline.selectedTreeElement;
-        element.updateSelection(element);
-    },
-
-    refresh: function()
-    {
-        this.needsRefresh = false;
-
-        this.element.removeChildren();
-
-        this.createViews();
-
-        if (!this.resource.finished)
-            this.views.source.contentElement.addStyleClass("loading");
-        else if (this.resource.failed)
-            this.views.source.contentElement.removeStyleClass("failed");
-        else if (this.resource.category === WebInspector.resourceCategories.documents) {
-            this._createSourceFrame();
-
-            this.views.dom.contentElement.sideContentElement = document.createElement("div");
-            this.views.dom.contentElement.sideContentElement.className = "content side";
-
-            this.views.dom.contentElement.treeContentElement = document.createElement("div");
-            this.views.dom.contentElement.treeContentElement.className = "content tree outline-disclosure";
-
-            this.views.dom.contentElement.treeListElement = document.createElement("ol");
-            this.domTreeOutline = new TreeOutline(this.views.dom.contentElement.treeListElement);
-            this.domTreeOutline.panel = this;
-
-            var panel = this;
-            window.addEventListener("resize", function() { panel.updateTreeSelection() }, false);
-
-            this.views.dom.contentElement.crumbsElement = document.createElement("div");
-            this.views.dom.contentElement.crumbsElement.className = "crumbs";
-
-            this.views.dom.contentElement.innerCrumbsElement = document.createElement("div");
-            this.views.dom.contentElement.crumbsElement.appendChild(this.views.dom.contentElement.innerCrumbsElement);
-
-            this.views.dom.contentElement.sidebarPanes = {};
-            this.views.dom.contentElement.sidebarPanes.styles = new WebInspector.SidebarPane("Styles");
-            this.views.dom.contentElement.sidebarPanes.metrics = new WebInspector.SidebarPane("Metrics");
-            this.views.dom.contentElement.sidebarPanes.properties = new WebInspector.SidebarPane("Properties");
-
-            var panel = this;
-            this.views.dom.contentElement.sidebarPanes.styles.onexpand = function() { panel.updateStyles() };
-            this.views.dom.contentElement.sidebarPanes.metrics.onexpand = function() { panel.updateMetrics() };
-            this.views.dom.contentElement.sidebarPanes.properties.onexpand = function() { panel.updateProperties() };
-
-            this.views.dom.contentElement.sidebarPanes.styles.expanded = true;
-
-            this.views.dom.contentElement.sidebarElement = document.createElement("div");
-            this.views.dom.contentElement.sidebarElement.className = "sidebar";
-
-            this.views.dom.contentElement.sidebarElement.appendChild(this.views.dom.contentElement.sidebarPanes.styles.element);
-            this.views.dom.contentElement.sidebarElement.appendChild(this.views.dom.contentElement.sidebarPanes.metrics.element);
-            this.views.dom.contentElement.sidebarElement.appendChild(this.views.dom.contentElement.sidebarPanes.properties.element);
-
-            this.views.dom.contentElement.sideContentElement.appendChild(this.views.dom.contentElement.treeContentElement);
-            this.views.dom.contentElement.sideContentElement.appendChild(this.views.dom.contentElement.crumbsElement);
-            this.views.dom.contentElement.treeContentElement.appendChild(this.views.dom.contentElement.treeListElement);
-
-            this.views.dom.contentElement.resizeArea = document.createElement("div");
-            this.views.dom.contentElement.resizeArea.className = "sidebarResizeArea";
-            this.views.dom.contentElement.resizeArea.addEventListener("mousedown", function(event) { panel.rightSidebarResizerDragStart(event) }, false);
-
-            this.views.dom.contentElement.appendChild(this.views.dom.contentElement.sideContentElement);
-            this.views.dom.contentElement.appendChild(this.views.dom.contentElement.sidebarElement);
-            this.views.dom.contentElement.appendChild(this.views.dom.contentElement.resizeArea);
-
-            this.rootDOMNode = this.resource.documentNode;
-        } else if (this.resource.category === WebInspector.resourceCategories.images) {
-            this.views.source.contentElement.removeStyleClass("source");
-            this.views.source.contentElement.addStyleClass("image");
-
-            var container = document.createElement("div");
-            container.className = "image";
-            this.views.source.contentElement.appendChild(container);
-
-            this.imagePreviewElement = document.createElement("img");
-            this.imagePreviewElement.setAttribute("src", this.resource.url);
-
-            container.appendChild(this.imagePreviewElement);
-
-            container = document.createElement("div");
-            container.className = "info";
-            this.views.source.contentElement.appendChild(container);
-
-            var imageNameElement = document.createElement("h1");
-            imageNameElement.className = "title";
-            imageNameElement.textContent = this.resource.displayName;
-            container.appendChild(imageNameElement);
-
-            var infoListElement = document.createElement("dl");
-            infoListElement.className = "infoList";
-
-            var imageProperties = [
-                {name: "Dimensions", value: this.imagePreviewElement.naturalWidth + " \u00D7 " + this.imagePreviewElement.height},
-                {name: "File size", value: (this.resource.contentLength / 1024).toPrecision(2) + "KB"},
-                {name: "MIME type", value: this.resource.mimeType}
-            ];
-
-            var listHTML = '';
-            for (var i = 0; i < imageProperties.length; ++i)
-                listHTML += "<dt>" + imageProperties[i].name + "</dt><dd>" + imageProperties[i].value + "</dd>";
-
-            infoListElement.innerHTML = listHTML;
-            container.appendChild(infoListElement);
-        } else if (this.resource.category === WebInspector.resourceCategories.fonts) {
-            var panel = this;
-            var resizeListener = function() {
-                panel.updateFontPreviewSize();
-            };
-
-            this.views.source.onshow = function() {
-                this.panel.updateFontPreviewSize();
-                window.addEventListener("resize", resizeListener, false);
-            };
-
-            this.views.source.onhide = function() {
-                window.removeEventListener("resize", resizeListener, false);
-            };
-
-            window.addEventListener("resize", resizeListener, false);
-
-            this.views.source.contentElement.removeStyleClass("source");
-            this.views.source.contentElement.addStyleClass("font");
-
-            var uniqueFontName = "WebInspectorFontPreview" + this.resource.identifier;
-
-            this.fontPreviewElement = document.createElement("div");
-            this.fontPreviewElement.className = "preview";
-            this.views.source.contentElement.appendChild(this.fontPreviewElement);
-
-            this.fontPreviewElement.style.setProperty("font-family", uniqueFontName, null);
-            this.fontPreviewElement.innerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890";
-
-            this.updateFontPreviewSize();
-        } else if (this.resource.category === WebInspector.resourceCategories.stylesheets || this.resource.category === WebInspector.resourceCategories.scripts) {
-            this.views.source.contentElement.addStyleClass(this.resource.category.title.toLowerCase());
-            this._createSourceFrame();
-        } else {
-            if (this.resource.category)
-                this.views.source.contentElement.addStyleClass(this.resource.category.title.toLowerCase());
-        }
-    },
-
-    updateFontPreviewSize: function ()
-    {
-        if (!this.fontPreviewElement)
-            return;
-
-        this.fontPreviewElement.removeStyleClass("preview");
-
-        var measureFontSize = 50;
-        this.fontPreviewElement.style.setProperty("position", "absolute", null);
-        this.fontPreviewElement.style.setProperty("font-size", measureFontSize + "px", null);
-        this.fontPreviewElement.style.removeProperty("height");
-
-        var height = this.fontPreviewElement.offsetHeight;
-        var width = this.fontPreviewElement.offsetWidth;
-
-        var containerHeight = this.views.source.contentElement.offsetHeight;
-        var containerWidth = this.views.source.contentElement.offsetWidth;
-
-        if (!height || !width || !containerHeight || !containerWidth) {
-            this.fontPreviewElement.style.removeProperty("font-size");
-            this.fontPreviewElement.style.removeProperty("position");
-            this.fontPreviewElement.addStyleClass("preview");
-            return;
-        }
-
-        var lineCount = this.fontPreviewElement.getElementsByTagName("br").length + 1;
-        var realLineHeight = Math.floor(height / lineCount);
-        var fontSizeLineRatio = measureFontSize / realLineHeight;
-        var widthRatio = containerWidth / width;
-        var heightRatio = containerHeight / height;
-
-        if (heightRatio < widthRatio)
-            var finalFontSize = Math.floor(realLineHeight * heightRatio * fontSizeLineRatio) - 1;
-        else
-            var finalFontSize = Math.floor(realLineHeight * widthRatio * fontSizeLineRatio) - 1;
-
-        this.fontPreviewElement.style.setProperty("font-size", finalFontSize + "px", null);
-        this.fontPreviewElement.style.setProperty("height", this.fontPreviewElement.offsetHeight + "px", null);
-        this.fontPreviewElement.style.removeProperty("position");
-
-        this.fontPreviewElement.addStyleClass("preview");
-    },
-
-    get currentView()
-    {
-        return this._currentView;
-    },
-
-    set currentView(x)
-    {
-        if (this._currentView === x)
-            return;
-
-        if (this._currentView) {
-            this._currentView.buttonElement.removeStyleClass("selected");
-            this._currentView.contentElement.removeStyleClass("selected");
-            if ("onhide" in this._currentView)
-                this._currentView.onhide();
-        }
-
-        this._currentView = x;
-
-        if (x) {
-            x.buttonElement.addStyleClass("selected");
-            x.contentElement.addStyleClass("selected");
-            if ("onshow" in x)
-                x.onshow();
-
-            if (x.contentElement.parentNode !== this.element)
-                InspectorController.log("Tried to set currentView to a view " + x.title + " whose contentElement is a non-child");
-        }
-    },
-
-    get rootDOMNode()
-    {
-        return this._rootDOMNode;
-    },
-
-    set rootDOMNode(x)
-    {
-        if (this._rootDOMNode === x)
-            return;
-
-        this._rootDOMNode = x;
-
-        this.updateBreadcrumb();
-        this.updateTreeOutline();
-    },
-
-    get focusedDOMNode()
-    {
-        return this._focusedDOMNode;
-    },
-
-    set focusedDOMNode(x)
-    {
-        if (this.resource.category !== WebInspector.resourceCategories.documents) {
-            InspectorController.log("Called set focusedDOMNode on a non-document resource " + this.resource.displayName + " which is not a document");
-            return;
-        }
-
-        if (this._focusedDOMNode === x) {
-            var nodeItem = this.revealNode(x);
-            if (nodeItem)
-                nodeItem.select();
-            return;
-        }
-
-        this._focusedDOMNode = x;
-
-        this.updateBreadcrumb();
-
-        for (var pane in this.views.dom.contentElement.sidebarPanes)
-            this.views.dom.contentElement.sidebarPanes[pane].needsUpdate = true;
-
-        this.updateStyles();
-        this.updateMetrics();
-        this.updateProperties();
-
-        InspectorController.highlightDOMNode(x);
-
-        var nodeItem = this.revealNode(x);
-        if (nodeItem)
-            nodeItem.select();
-    },
-
-    revealNode: function(node)
-    {
-        var nodeItem = this.domTreeOutline.findTreeElement(node, function(a, b) { return isAncestorNode.call(a, b); }, function(a) { return a.parentNode; });
-        if (!nodeItem)
-            return;
-
-        nodeItem.reveal();
-        return nodeItem;
-    },
-
-    updateTreeOutline: function()
-    {
-        this.domTreeOutline.removeChildrenRecursive();
-
-        if (!this.rootDOMNode)
-            return;
-
-        // 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.domTreeOutline.appendChild(item);
-            node = Preferences.ignoreWhitespace ? nextSiblingSkippingWhitespace.call(node) : node.nextSibling;
-        }
-
-        this.updateTreeSelection();
-    },
-
-    updateBreadcrumb: function()
-    {
-        if (!this.views || !this.views.dom.contentElement)
-            return;
-        var crumbs = this.views.dom.contentElement.innerCrumbsElement;
-        if (!crumbs)
-            return;
-
-        var handled = false;
-        var foundRoot = false;
-        var crumb = crumbs.firstChild;
-        while (crumb) {
-            if (crumb.representedObject === this.rootDOMNode)
-                foundRoot = true;
-
-            if (foundRoot)
-                crumb.addStyleClass("hidden");
-            else
-                crumb.removeStyleClass("hidden");
-
-            if (crumb.representedObject === this.focusedDOMNode) {
-                crumb.addStyleClass("selected");
-                handled = true;
-            } else {
-                crumb.removeStyleClass("selected");
-            }
-
-            crumb = crumb.nextSibling;
-        }
-
-        if (handled)
-            return;
-
-        crumbs.removeChildren();
-
-        var panel = this;
-        var selectCrumbFunction = function(event)
-        {
-            if (event.currentTarget.hasStyleClass("hidden"))
-                panel.rootDOMNode = event.currentTarget.representedObject.parentNode;
-            panel.focusedDOMNode = event.currentTarget.representedObject;
-            event.preventDefault();
-            event.stopPropagation();
-        }
-
-        var selectCrumbRootFunction = function(event)
-        {
-            panel.rootDOMNode = event.currentTarget.representedObject.parentNode;
-            panel.focusedDOMNode = event.currentTarget.representedObject;
-            event.preventDefault();
-            event.stopPropagation();
-        }
-
-        foundRoot = false;
-        var current = this.focusedDOMNode;
-        while (current) {
-            if (current.nodeType === Node.DOCUMENT_NODE)
-                break;
-
-            if (current === this.rootDOMNode)
-                foundRoot = true;
-
-            var crumb = document.createElement("span");
-            crumb.className = "crumb";
-            crumb.representedObject = current;
-            crumb.addEventListener("mousedown", selectCrumbFunction, false);
-            crumb.addEventListener("dblclick", selectCrumbRootFunction, false);
-
-            var crumbTitle;
-            switch (current.nodeType) {
-                case Node.ELEMENT_NODE:
-                    crumbTitle = current.nodeName.toLowerCase();
-    
-                    var value = current.getAttribute("id");
-                    if (value && value.length)
-                        crumbTitle += "#" + value;
-
-                    value = current.getAttribute("class");
-                    if (value && value.length) {
-                        var classes = value.split(/\s+/);
-                        var classesLength = classes.length;
-                        for (var i = 0; i < classesLength; ++i) {
-                            value = classes[i];
-                            if (value && value.length)
-                                crumbTitle += "." + value;
-                        }
-                    }
-
-                    break;
-
-                case Node.TEXT_NODE:
-                    if (isNodeWhitespace.call(current))
-                        crumbTitle = "(whitespace)";
-                    else
-                        crumbTitle = "(text)";
-                    break
-
-                case Node.COMMENT_NODE:
-                    crumbTitle = "<!-->";
-                    break;
-
-                default:
-                    crumbTitle = current.nodeName.toLowerCase();
-            }
-
-            crumb.textContent = crumbTitle;
-
-            if (foundRoot)
-                crumb.addStyleClass("hidden");
-            if (current === this.focusedDOMNode)
-                crumb.addStyleClass("selected");
-            if (!crumbs.childNodes.length)
-                crumb.addStyleClass("end");
-            if (current.parentNode.nodeType === Node.DOCUMENT_NODE)
-                crumb.addStyleClass("start");
-
-            crumbs.appendChild(crumb);
-            current = current.parentNode;
-        }
-    },
-
-    updateStyles: function()
-    {
-        if (!this.views.dom.contentElement.sidebarPanes.styles.expanded)
-            return;
-        if (!this.views.dom.contentElement.sidebarPanes.styles.needsUpdate)
-            return;
-
-        this.views.dom.contentElement.sidebarPanes.styles.needsUpdate = false;
-
-        var stylesBody = this.views.dom.contentElement.sidebarPanes.styles.bodyElement;
-
-        stylesBody.removeChildren();
-        this.views.dom.contentElement.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.contentElement.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
-        }
-    },
-
-    updateMetrics: function()
-    {
-        if (!this.views.dom.contentElement.sidebarPanes.metrics.expanded)
-            return;
-        if (!this.views.dom.contentElement.sidebarPanes.metrics.needsUpdate)
-            return;
-
-        this.views.dom.contentElement.sidebarPanes.metrics.needsUpdate = false;
-
-        var metricsBody = this.views.dom.contentElement.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);
-    },
-
-    updateProperties: function()
-    {
-        if (!this.views.dom.contentElement.sidebarPanes.properties.expanded)
-            return;
-        if (!this.views.dom.contentElement.sidebarPanes.properties.needsUpdate)
-            return;
-
-        this.views.dom.contentElement.sidebarPanes.properties.needsUpdate = false;
-
-        var propertiesBody = this.views.dom.contentElement.sidebarPanes.properties.bodyElement;
-
-        propertiesBody.removeChildren();
-        this.views.dom.contentElement.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.contentElement.sidebarPanes.properties.sections.push(section);
-        }
-    },
-
-    handleKeyEvent: function(event)
-    {
-        if (this.domTreeOutline && this.currentView && this.currentView === this.views.dom)
-            this.domTreeOutline.handleKeyEvent(event);
-    },
-
-    rightSidebarResizerDragStart: function(event)
-    {
-        var panel = this; 
-        WebInspector.dividerDragStart(this.views.dom.contentElement.sidebarElement, function(event) { panel.rightSidebarResizerDrag(event) }, function(event) { panel.rightSidebarResizerDragEnd(event) }, event, "col-resize");
-    },
-
-    rightSidebarResizerDragEnd: function(event)
-    {
-        var panel = this;
-        WebInspector.dividerDragEnd(this.views.dom.contentElement.sidebarElement, function(event) { panel.rightSidebarResizerDrag(event) }, function(event) { panel.rightSidebarResizerDragEnd(event) }, event);
-    },
-
-    rightSidebarResizerDrag: function(event)
-    {
-        var rightSidebar = this.views.dom.contentElement.sidebarElement;
-        if (rightSidebar.dragging == true) {
-            var x = event.clientX + window.scrollX;
-
-            var leftSidebarWidth = document.defaultView.getComputedStyle(document.getElementById("sidebar")).getPropertyCSSValue("width").getFloatValue(CSSPrimitiveValue.CSS_PX);
-            var newWidth = Number.constrain(window.innerWidth - x, 100, window.innerWidth - leftSidebarWidth - 100);
-
-            if (x == newWidth)
-                rightSidebar.dragLastX = x;
-
-            rightSidebar.style.width = newWidth + "px";
-            this.views.dom.contentElement.sideContentElement.style.right = newWidth + "px";
-            this.views.dom.contentElement.resizeArea.style.right = (newWidth - 3) + "px";
-            event.preventDefault();
-        }
     }
 }
 
-WebInspector.ResourcePanel.sourceFrameCounter = 0;
-
 WebInspector.ResourcePanel.prototype.__proto__ = WebInspector.Panel.prototype;
-
-WebInspector.SidebarPane = function(title)
-{
-    this.element = document.createElement("div");
-    this.element.className = "pane";
-
-    this.titleElement = document.createElement("div");
-    this.titleElement.className = "title";
-
-    var pane = this;
-    this.titleElement.addEventListener("click", function() { pane.expanded = !pane.expanded; }, false);
-
-    this.bodyElement = document.createElement("div");
-    this.bodyElement.className = "body";
-
-    this.element.appendChild(this.titleElement);
-    this.element.appendChild(this.bodyElement);
-
-    this.title = title;
-    this.growbarVisible = false;
-    this.expanded = false;
-    this.onexpand = null;
-    this.oncollapse = null;
-}
-
-WebInspector.SidebarPane.prototype = {
-    get title()
-    {
-        return this._title;
-    },
-
-    set title(x)
-    {
-        if (this._title === x)
-            return;
-        this._title = x;
-        this.titleElement.textContent = x;
-    },
-
-    get growbarVisible()
-    {
-        return this._growbarVisible;
-    },
-
-    set growbarVisible(x)
-    {
-        if (this._growbarVisible === x)
-            return;
-
-        this._growbarVisible = x;
-
-        if (x && !this._growbarElement) {
-            this._growbarElement = document.createElement("div");
-            this._growbarElement.className = "growbar";
-            this.element.appendChild(this._growbarElement);
-        } else if (!x && this._growbarElement) {
-            if (this._growbarElement.parentNode)
-                this._growbarElement.parentNode(this._growbarElement);
-            delete this._growbarElement;
-        }
-    },
-
-    get expanded()
-    {
-        return this._expanded;
-    },
-
-    set expanded(x)
-    {
-        if (x)
-            this.expand();
-        else
-            this.collapse();
-    },
-
-    expand: function()
-    {
-        if (this._expanded)
-            return;
-        this._expanded = true;
-        this.element.addStyleClass("expanded");
-        if (this.onexpand)
-            this.onexpand(this);
-    },
-
-    collapse: function()
-    {
-        if (!this._expanded)
-            return;
-        this._expanded = false;
-        this.element.removeStyleClass("expanded");
-        if (this.oncollapse)
-            this.oncollapse(this);
-    }
-}
-
-WebInspector.PropertiesSection = function(title, subtitle)
-{
-    this.element = document.createElement("div");
-    this.element.className = "section";
-
-    this.headerElement = document.createElement("div");
-    this.headerElement.className = "header";
-
-    this.titleElement = document.createElement("div");
-    this.titleElement.className = "title";
-
-    this.subtitleElement = document.createElement("div");
-    this.subtitleElement.className = "subtitle";
-
-    this.headerElement.appendChild(this.titleElement);
-    this.headerElement.appendChild(this.subtitleElement);
-
-    var section = this;
-    this.headerElement.addEventListener("click", function() { section.expanded = !section.expanded; }, false);
-
-    this.propertiesElement = document.createElement("ol");
-    this.propertiesElement.className = "properties";
-    this.propertiesTreeOutline = new TreeOutline(this.propertiesElement);
-
-    this.element.appendChild(this.headerElement);
-    this.element.appendChild(this.propertiesElement);
-
-    this.title = title;
-    this.subtitle = subtitle;
-    this.expanded = false;
-}
-
-WebInspector.PropertiesSection.prototype = {
-    get title()
-    {
-        return this._title;
-    },
-
-    set title(x)
-    {
-        if (this._title === x)
-            return;
-        this._title = x;
-        this.titleElement.textContent = x;
-    },
-
-    get subtitle()
-    {
-        return this._subtitle;
-    },
-
-    set subtitle(x)
-    {
-        if (this._subtitle === x)
-            return;
-        this._subtitle = x;
-        this.subtitleElement.innerHTML = x;
-    },
-
-    get expanded()
-    {
-        return this._expanded;
-    },
-
-    set expanded(x)
-    {
-        if (x)
-            this.expand();
-        else
-            this.collapse();
-    },
-
-    expand: function()
-    {
-        if (this._expanded)
-            return;
-        this._expanded = true;
-
-        if (!this._populated && this.onpopulate) {
-            this.onpopulate(this);
-            this._populated = true;
-        }
-        this.element.addStyleClass("expanded");
-    },
-
-    collapse: function()
-    {
-        if (!this._expanded)
-            return;
-        this._expanded = false;
-        this.element.removeStyleClass("expanded");
-    }
-}
-
-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;
-
-    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);
-    }
-}
-
-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.contentElement.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.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 (!priority)
-        priority = prop.style.getPropertyPriority(prop.name);
-
-    var overloaded = (prop.unusedProperties[prop.name] || overloadCount === prop.subProperties.length);
-    var title = WebInspector.StylePropertyTreeElement.createTitle(prop.name, prop.style, overloaded, priority, computedStyle, usedProperties);
-
-    var item = new TreeElement(title, prop, (prop.subProperties && prop.subProperties.length > 1));
-    item.computedStyle = computedStyle;
-    item.onpopulate = WebInspector.StylePropertyTreeElement.populate;
-    return item;
-}
-
-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 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 (classes.length)
-        title += "</span>";
-
-    return title;
-}
-
-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);
-        }
-    }
-}
-
-WebInspector.RequestResponseTreeElement = function(name, object)
-{
-    var title = "<span class=\"name\">" + name.escapeHTML() + "</span>";
-
-    var hasChildren = object instanceof Object;
-    if (!hasChildren) {
-        var objectAsString = object.toString();
-        title += ": <span class=\"value\">" + objectAsString.escapeHTML() + "</span>";
-    }
-
-    var item = new TreeElement(title, object, hasChildren);
-    item.onpopulate = WebInspector.RequestResponseTreeElement.onpopulate;
-    return item;
-}
-
-WebInspector.RequestResponseTreeElement.onpopulate = function(element)
-{
-    if (element.children.length)
-        return;
-
-    for (var field in element.representedObject) {
-        var item = new WebInspector.RequestResponseTreeElement(field, element.representedObject[field]);
-        element.appendChild(item);
-    }
-}
-
-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;
-        }
-    }
-
-    var representedObj = { object: object, name: name };
-    var item = new TreeElement(title, representedObj, hasChildren);
-    item.onpopulate = WebInspector.DOMPropertyTreeElement.populate;
-    return item;
-}
-
-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);
-    }
-}
diff --git a/WebCore/page/inspector/SidebarPane.js b/WebCore/page/inspector/SidebarPane.js
new file mode 100644 (file)
index 0000000..6b55fde
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * 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.SidebarPane = function(title)
+{
+    this.element = document.createElement("div");
+    this.element.className = "pane";
+
+    this.titleElement = document.createElement("div");
+    this.titleElement.className = "title";
+
+    var pane = this;
+    this.titleElement.addEventListener("click", function() { pane.expanded = !pane.expanded; }, false);
+
+    this.bodyElement = document.createElement("div");
+    this.bodyElement.className = "body";
+
+    this.element.appendChild(this.titleElement);
+    this.element.appendChild(this.bodyElement);
+
+    this.title = title;
+    this.growbarVisible = false;
+    this.expanded = false;
+    this.onexpand = null;
+    this.oncollapse = null;
+}
+
+WebInspector.SidebarPane.prototype = {
+    get title()
+    {
+        return this._title;
+    },
+
+    set title(x)
+    {
+        if (this._title === x)
+            return;
+        this._title = x;
+        this.titleElement.textContent = x;
+    },
+
+    get growbarVisible()
+    {
+        return this._growbarVisible;
+    },
+
+    set growbarVisible(x)
+    {
+        if (this._growbarVisible === x)
+            return;
+
+        this._growbarVisible = x;
+
+        if (x && !this._growbarElement) {
+            this._growbarElement = document.createElement("div");
+            this._growbarElement.className = "growbar";
+            this.element.appendChild(this._growbarElement);
+        } else if (!x && this._growbarElement) {
+            if (this._growbarElement.parentNode)
+                this._growbarElement.parentNode(this._growbarElement);
+            delete this._growbarElement;
+        }
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    set expanded(x)
+    {
+        if (x)
+            this.expand();
+        else
+            this.collapse();
+    },
+
+    expand: function()
+    {
+        if (this._expanded)
+            return;
+        this._expanded = true;
+        this.element.addStyleClass("expanded");
+        if (this.onexpand)
+            this.onexpand(this);
+    },
+
+    collapse: function()
+    {
+        if (!this._expanded)
+            return;
+        this._expanded = false;
+        this.element.removeStyleClass("expanded");
+        if (this.oncollapse)
+            this.oncollapse(this);
+    }
+}
diff --git a/WebCore/page/inspector/SourcePanel.js b/WebCore/page/inspector/SourcePanel.js
new file mode 100644 (file)
index 0000000..7fba529
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * 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.SourcePanel = function(resource, views)
+{
+    var allViews = [{ title: "Source" }];
+    if (views)
+        allViews = allViews.concat(views);
+
+    WebInspector.ResourcePanel.call(this, resource, allViews);
+
+    this.currentView = this.views.source;
+
+    var sourceView = this.views.source;
+
+    sourceView.messages = [];
+    sourceView.frameNeedsSetup = true;
+
+    sourceView.frameElement = document.createElement("iframe");
+    sourceView.frameElement.setAttribute("viewsource", "true");
+    sourceView.contentElement.appendChild(sourceView.frameElement);
+}
+
+WebInspector.SourcePanel.prototype = {
+    show: function()
+    {
+        WebInspector.ResourcePanel.prototype.show.call(this);
+        this.setupSourceFrameIfNeeded();
+    },
+
+    setupSourceFrameIfNeeded: function()
+    {
+        if (this.views.source.frameNeedsSetup) {
+            this.attach();
+
+            InspectorController.addSourceToFrame(this.resource.identifier, this.views.source.frameElement);
+            WebInspector.addMainEventListeners(this.views.source.frameElement.contentDocument);
+
+            var length = this.views.source.messages;
+            for (var i = 0; i < length; ++i)
+                this._addMessageToSource(this.views.source.messages[i]);
+
+            delete this.views.source.frameNeedsSetup;
+        }
+    },
+
+    sourceRow: function(lineNumber)
+    {
+        var doc = this.views.source.frameElement.contentDocument;
+        var rows = doc.getElementsByTagName("table")[0].rows;
+
+        // Line numbers are a 1-based index, but the rows collection is 0-based.
+        --lineNumber;
+        if (lineNumber >= rows.length)
+            lineNumber = rows.length - 1;
+
+        return rows[lineNumber];
+    },
+
+    showSourceLine: function(lineNumber)
+    {
+        var row = this.sourceRow(lineNumber);
+        if (!row)
+            return;
+        this.currentView = this.views.source;
+        row.scrollIntoView(true);
+    },
+
+    addMessageToSource: function(msg)
+    {
+        this.views.source.messages.push(msg);
+        if (!this.views.source.frameNeedsSetup)
+            this._addMessageToSource(msg);
+    },
+
+    _addMessageToSource: function(msg)
+    {
+        var row = this.sourceRow(msg.line);
+        if (!row)
+            return;
+
+        var doc = this.views.source.frameElement.contentDocument;
+        var cell = row.getElementsByTagName("td")[1];
+
+        var errorDiv = cell.lastChild;
+        if (!errorDiv || errorDiv.nodeName.toLowerCase() !== "div" || !errorDiv.hasStyleClass("webkit-html-message-bubble")) {
+            errorDiv = doc.createElement("div");
+            errorDiv.className = "webkit-html-message-bubble";
+            cell.appendChild(errorDiv);
+        }
+
+        var imageURL;
+        switch (msg.level) {
+            case WebInspector.ConsoleMessage.MessageLevel.Error:
+                errorDiv.addStyleClass("webkit-html-error-message");
+                imageURL = "Images/errorIcon.png";
+                break;
+            case WebInspector.ConsoleMessage.MessageLevel.Warning:
+                errorDiv.addStyleClass("webkit-html-warning-message");
+                imageURL = "Images/warningIcon.png";
+                break;
+        }
+
+        var lineDiv = doc.createElement("div");
+        lineDiv.className = "webkit-html-message-line";
+        errorDiv.appendChild(lineDiv);
+
+        var image = doc.createElement("img");
+        image.src = imageURL;
+        image.className = "webkit-html-message-icon";
+        lineDiv.appendChild(image);
+
+        lineDiv.appendChild(doc.createTextNode(msg.message));
+    }
+}
+
+WebInspector.SourcePanel.prototype.__proto__ = WebInspector.ResourcePanel.prototype;
index 76b2fbe..ea75729 100644 (file)
@@ -220,16 +220,12 @@ body.inactive #toolbar .split-button-divider {
     opacity: 1;
 }
 
-#viewbuttons {
+#toolbarButtons {
     position: absolute;
     left: 200px;
     padding-left: 8px;
 }
 
-#viewbuttons .selected {
-    font-weight: bold;
-}
-
 #search {
     float: right;
     width: 200px;
@@ -689,17 +685,14 @@ body.inactive #sidebar li.selected {
     background-color: transparent !important;
 }
 
-.content.font {
-    position: relative;
-    width: 100%;
-    height: 100%;
+.panel.font {
     font-size: 60px;
     white-space: pre-wrap;
     word-wrap: break-word;
     text-align: center;
 }
 
-.content.font .preview {
+.panel.font .preview {
     position: absolute;
     margin-top: auto;
     margin-bottom: auto;
@@ -709,20 +702,20 @@ body.inactive #sidebar li.selected {
     bottom: 0;
 }
 
-.content.image {
+.panel.image {
     position: relative;
     width: 100%;
     height: 100%;
 }
 
-.content.image > .image {
+.panel.image > .image {
     position: relative;
     -webkit-box-sizing: border-box;
     height: 70%;
     padding: 20px;
 }
 
-.content.image > .info {
+.panel.image > .info {
     position: relative;
     -webkit-box-sizing: border-box;
     height: 30%;
@@ -731,7 +724,7 @@ body.inactive #sidebar li.selected {
     font-size: 11px;
 }
 
-.content.image img {
+.panel.image img {
     margin: auto;
     position: absolute;
     top: 0;
@@ -744,23 +737,23 @@ body.inactive #sidebar li.selected {
     -webkit-box-shadow: 0px 5px 10px rgba(0, 0, 0, 0.5);
 }
 
-.content.image .title {
+.panel.image .title {
     text-align: center;
     font-size: 13px;
 }
 
-.content.image .infoList {
+.panel.image .infoList {
     margin: 0;
 }
 
-.content.image .infoList dt {
+.panel.image .infoList dt {
     font-weight: bold;
     display: inline-block;
     width: 50%;
     text-align: right;
 }
 
-.content.image .infoList dd {
+.panel.image .infoList dd {
     -webkit-box-sizing: border-box;
     display: inline-block;
     padding-left: 10px;
@@ -769,7 +762,7 @@ body.inactive #sidebar li.selected {
     margin: 0;
 }
 
-.content.image .infoList dd::after {
+.panel.image .infoList dd::after {
     white-space: pre;
     content: "\A";
 }
@@ -1442,22 +1435,22 @@ body.inactive #sidebar li.selected {
     opacity: 0.7;
 }
 
-.database-query.content {
+.query.content {
     bottom: 21px;
 }
 
-.database-browse.content {
+.browse.content {
     font-size: 10px;
     overflow-y: auto;
     overflow-x: hidden;
     bottom: 21px;
 }
 
-.database-browse.content .database-result-table {
+.browse.content .database-result-table {
     border: none;
 }
 
-.database-browse.content .database-table-empty {
+.browse.content .database-table-empty {
     position: absolute;
     top: 0;
     bottom: 25%;
@@ -1474,7 +1467,7 @@ body.inactive #sidebar li.selected {
     padding: 10px;
 }
 
-.database-browse.content .database-table-error {
+.browse.content .database-table-error {
     position: absolute;
     top: 0;
     bottom: 25%;
@@ -1925,7 +1918,7 @@ body.inactive #sidebar li.selected {
     margin-bottom: -35px;
 }
 
-.sidebarResizeArea {
+.sidebar-resizer {
     position: absolute;
     top: 0;
     bottom: 0;
index 1cd8819..887f53c 100644 (file)
@@ -33,19 +33,26 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="utilities.js"></script>
     <script type="text/javascript" src="treeoutline.js"></script>
     <script type="text/javascript" src="inspector.js"></script>
-    <script type="text/javascript" src="ConsolePanel.js"></script>
+    <script type="text/javascript" src="Database.js"></script>
     <script type="text/javascript" src="Resource.js"></script>
     <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="Panel.js"></script>
     <script type="text/javascript" src="ResourcePanel.js"></script>
-    <script type="text/javascript" src="NetworkPanel.js"></script>
-    <script type="text/javascript" src="Database.js"></script>
+    <script type="text/javascript" src="SourcePanel.js"></script>
+    <script type="text/javascript" src="ConsolePanel.js"></script>
     <script type="text/javascript" src="DatabasePanel.js"></script>
+    <script type="text/javascript" src="DocumentPanel.js"></script>
+    <script type="text/javascript" src="FontPanel.js"></script>
+    <script type="text/javascript" src="ImagePanel.js"></script>
+    <script type="text/javascript" src="NetworkPanel.js"></script>
     <link rel="stylesheet" type="text/css" href="inspector.css" />
 </head>
 <body class="detached">
     <div id="toolbar">
         <button id="back" class="split-button first"><img></button><img class="split-button-divider"><button id="forward" class="split-button last"><img></button>
-        <span id="viewbuttons"></span>
+        <span id="toolbarButtons"></span>
         <input id="search" type="search" autosave="inspectorSearch" results="20" placeholder="Search" incremental="incremental" onsearch="WebInspector.performSearch(this.value)">
     </div>
     <div id="sidebar" class="focusable focused">
index 6bc1903..b9eed4d 100644 (file)
@@ -110,7 +110,6 @@ var WebInspector = {
             this._currentPanel.hide();
 
         this._currentPanel = x;
-        this.updateViewButtons();
 
         if (x)
             x.show();
@@ -450,7 +449,7 @@ WebInspector.sidebarResizerDrag = function(event)
     var sidebar = document.getElementById("sidebar");
     if (sidebar.dragging == true) {
         var main = document.getElementById("main");
-        var buttonContainer = document.getElementById("viewbuttons");
+        var buttonContainer = document.getElementById("toolbarButtons");
 
         var x = event.clientX + window.scrollX;
 
@@ -494,7 +493,7 @@ WebInspector.back = function()
         return;
     }
 
-    this.navigateToPanel(this.backForwardList[--this.currentBackForwardIndex], true);
+    this.navigateToPanel(this.backForwardList[--this.currentBackForwardIndex], null, true);
 }
 
 WebInspector.forward = function()
@@ -504,7 +503,7 @@ WebInspector.forward = function()
         return;
     }
 
-    this.navigateToPanel(this.backForwardList[++this.currentBackForwardIndex], true);
+    this.navigateToPanel(this.backForwardList[++this.currentBackForwardIndex], null, true);
 }
 
 WebInspector.updateBackForwardButtons = function()
@@ -515,39 +514,6 @@ WebInspector.updateBackForwardButtons = function()
     document.getElementById("forward").disabled = index >= this.backForwardList.length - 1;
 }
 
-WebInspector.updateViewButtons = function()
-{
-    var buttonContainer = document.getElementById("viewbuttons");
-    buttonContainer.removeChildren();
-
-    if (!this.currentPanel || !this.currentPanel.viewButtons)
-        return;
-
-    var buttons = this.currentPanel.viewButtons;
-    if (buttons.length < 2)
-        return;
-
-    for (var i = 0; i < buttons.length; ++i) {
-        var button = buttons[i];
-
-        if (i === 0)
-            button.addStyleClass("first");
-        else if (i === (buttons.length - 1))
-            button.addStyleClass("last");
-
-        if (i) {
-            var divider = document.createElement("img");
-            divider.className = "split-button-divider";
-            buttonContainer.appendChild(divider);
-        }
-
-        button.addStyleClass("split-button");
-        button.addStyleClass("view-button-" + button.title.toLowerCase());
-
-        buttonContainer.appendChild(button);
-    }
-}
-
 WebInspector.addResource = function(resource)
 {
     this.resources.push(resource);
@@ -668,7 +634,7 @@ WebInspector.updateFocusedNode = function(node)
         if (resource.documentNode !== node.ownerDocument)
             continue;
 
-        resource.panel.navigateToView("dom");
+        this.navigateToPanel(resource.panel, "dom");
         resource.panel.focusedDOMNode = node;
 
         this.currentFocusElement = document.getElementById("main");
@@ -714,17 +680,6 @@ WebInspector.addMainEventListeners = function(doc)
     doc.addEventListener("click", function(event) { WebInspector.documentClick(event) }, true);
 }
 
-WebInspector.navigateToView = function(view)
-{
-    if (!view) {
-        alert("Called navigateToView(null)");
-        return;
-    }
-
-    view.panel.currentView = view;
-    this.navigateToPanel(view.panel);
-}
-
 WebInspector.performSearch = function(query)
 {
     if (!query || !query.length) {
@@ -752,10 +707,9 @@ WebInspector.performSearch = function(query)
         var resource = resourcesToSearch[i];
 
         var sourceResults = [];
-        if (!isXPath) {
-            resource.panel.refreshIfNeeded();
-            if ("sourceFrame" in resource.panel)
-                sourceResults = InspectorController.search(resource.panel.sourceFrame.contentDocument, query);
+        if (!isXPath && "source" in resource.panel.views) {
+            resource.panel.setupSourceFrameIfNeeded();
+            sourceResults = InspectorController.search(resource.panel.views.source.frameElement.contentDocument, query);
         }
 
         var domResults = [];
@@ -792,14 +746,14 @@ WebInspector.performSearch = function(query)
         selection.removeAllRanges();
         selection.addRange(element.representedObject.range);
 
-        element.representedObject.panel.navigateToView("source");
+        WebInspector.navigateToPanel(element.representedObject.panel, "source");
         element.representedObject.line.scrollIntoView(true);
         resultsContainer.scrollToElement(element._listItemNode);
     }
 
     var domResultSelected = function(element)
     {
-        element.representedObject.panel.navigateToView("dom");
+        WebInspector.navigateToPanel(element.representedObject.panel, "dom");
         element.representedObject.panel.focusedDOMNode = element.representedObject.node;
         resultsContainer.scrollToElement(element._listItemNode);
     }
@@ -812,14 +766,14 @@ WebInspector.performSearch = function(query)
         fileItem.selectable = false;
         this.searchResultsTree.appendChild(fileItem);
 
-        if (file.sourceResults.length) {
+        if (file.sourceResults && file.sourceResults.length) {
             for (var j = 0; j < file.sourceResults.length; ++j) {
                 var range = file.sourceResults[j];
 
                 var line = range.startContainer;
                 while (line.parentNode && line.nodeName.toLowerCase() != "tr")
                     line = line.parentNode;
-                var lineRange = file.resource.panel.sourceFrame.contentDocument.createRange();
+                var lineRange = file.resource.panel.views.source.frameElement.contentDocument.createRange();
                 lineRange.selectNodeContents(line);
 
                 // Don't include any error bubbles in the search result
@@ -830,11 +784,11 @@ WebInspector.performSearch = function(query)
                     lineRange.setEndAfter(end);
                 }
 
-                var beforeRange = file.resource.panel.sourceFrame.contentDocument.createRange();
+                var beforeRange = file.resource.panel.views.source.frameElement.contentDocument.createRange();
                 beforeRange.setStart(lineRange.startContainer, lineRange.startOffset);
                 beforeRange.setEnd(range.startContainer, range.startOffset);
 
-                var afterRange = file.resource.panel.sourceFrame.contentDocument.createRange();
+                var afterRange = file.resource.panel.views.source.frameElement.contentDocument.createRange();
                 afterRange.setStart(range.endContainer, range.endOffset);
                 afterRange.setEnd(lineRange.endContainer, lineRange.endOffset);
 
@@ -881,10 +835,13 @@ WebInspector.navigateToResource = function(resource)
     this.navigateToPanel(resource.panel);
 }
 
-WebInspector.navigateToPanel = function(panel, fromBackForwardAction)
+WebInspector.navigateToPanel = function(panel, view, fromBackForwardAction)
 {
-    if (this.currentPanel == panel)
+    if (this.currentPanel === panel) {
+        if (panel && view)
+            panel.currentView = view;
         return;
+    }
 
     if (!fromBackForwardAction) {
         var oldIndex = this.currentBackForwardIndex;
@@ -895,85 +852,8 @@ WebInspector.navigateToPanel = function(panel, fromBackForwardAction)
     }
 
     this.currentPanel = panel;
-}
-
-WebInspector.Panel = function()
-{
-    this.element = document.createElement("div");
-    this.element.className = "panel";
-    this.attach();
-
-    this._needsRefresh = true;
-    this.refresh();
-}
-
-WebInspector.Panel.prototype = {
-    show: function()
-    {
-        this.visible = true;
-    },
-
-    hide: function()
-    {
-        this.visible = false;
-    },
-
-    attach: function()
-    {
-        document.getElementById("main").appendChild(this.element);
-    },
-
-    detach: function()
-    {
-        if (WebInspector.currentPanel === this)
-            WebInspector.currentPanel = null;
-        if (this.element && this.element.parentNode)
-            this.element.parentNode.removeChild(this.element);
-    },
-
-    refresh: function()
-    {
-    },
-
-    refreshIfNeeded: function()
-    {
-        if (this.needsRefresh)
-            this.refresh();
-    },
-
-    get visible()
-    {
-        return this._visible;
-    },
-
-    set visible(x)
-    {
-        if (this._visible === x)
-            return;
-
-        this._visible = x;
-
-        if (x) {
-            this.element.addStyleClass("selected");
-            this.refreshIfNeeded();
-        } else {
-            this.element.removeStyleClass("selected");
-        }
-    },
-
-    get needsRefresh()
-    {
-        return this._needsRefresh;
-    },
-
-    set needsRefresh(x)
-    {
-        if (this._needsRefresh === x)
-            return;
-        this._needsRefresh = x;
-        if (x && this.visible)
-            this.refresh();
-    }
+    if (panel && view)
+        panel.currentView = view;
 }
 
 WebInspector.StatusTreeElement = function(title)