Bug 663831 - Style inspector should be controllable from the highlighter; r=msucan,gavin
☠☠ backed out by c75401a8160a ☠ ☠
authorRob Campbell <rcampbell@mozilla.com>
Fri, 23 Sep 2011 13:50:33 -0300
changeset 78709 f1409901573ab504ffa35030198084679c0d8154
parent 78708 ce51db254f18be7172e30dfd9bd79ea199143862
child 78710 121518f3df44e8837ef64e7536717a8fdeb36006
child 78758 c75401a8160a4a92b38c8c9f79bf7be854779712
push id78
push userclegnitto@mozilla.com
push dateFri, 16 Dec 2011 17:32:24 +0000
treeherdermozilla-release@79d24e644fdd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmsucan, gavin
bugs663831
milestone9.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 663831 - Style inspector should be controllable from the highlighter; r=msucan,gavin
browser/devtools/highlighter/inspector.js
browser/devtools/styleinspector/CssHtmlTree.jsm
browser/devtools/styleinspector/StyleInspector.jsm
browser/devtools/styleinspector/test/browser/browser_styleinspector_webconsole.js
browser/devtools/webconsole/HUDService.jsm
browser/locales/en-US/chrome/browser/styleinspector.properties
--- a/browser/devtools/highlighter/inspector.js
+++ b/browser/devtools/highlighter/inspector.js
@@ -203,17 +203,16 @@ Highlighter.prototype = {
     closeButton.id = "highlighter-close-button";
     closeButton.appendChild(document.createElement("image"));
 
     closeButton.setAttribute("onclick", "InspectorUI.closeInspectorUI(false);");
 
     aParent.appendChild(closeButton);
   },
 
-
   /**
    * Destroy the nodes.
    */
   destroy: function Highlighter_destroy()
   {
     this.browser.removeEventListener("scroll", this, true);
     this.browser.removeEventListener("resize", this, true);
     this._highlightRect = null;
@@ -835,16 +834,36 @@ var InspectorUI = {
     gBrowser.addProgressListener(InspectorProgressListener);
   },
 
   /**
    * Register and initialize any included tools.
    */
   initTools: function IUI_initTools()
   {
+    // Style inspector
+    if (Services.prefs.getBoolPref("devtools.styleinspector.enabled") &&
+        !this.toolRegistered("styleinspector")) {
+      let stylePanel = this.StyleInspector.createPanel(true);
+      this.registerTool({
+        id: "styleinspector",
+        label: InspectorUI.StyleInspector.l10n("style.highlighter.button.label"),
+        tooltiptext: InspectorUI.StyleInspector.l10n("style.highlighter.button.tooltip"),
+        accesskey: InspectorUI.StyleInspector.l10n("style.highlighter.accesskey"),
+        context: stylePanel,
+        get isOpen() stylePanel.isOpen(),
+        onSelect: stylePanel.selectNode,
+        show: stylePanel.showTool,
+        hide: stylePanel.hideTool,
+        dim: stylePanel.dimTool,
+        panel: stylePanel,
+        unregister: stylePanel.destroy,
+      });
+      this.stylePanel = stylePanel;
+    }
   },
 
   /**
    * Initialize highlighter.
    */
   initializeHighlighter: function IUI_initializeHighlighter()
   {
     this.highlighter = new Highlighter(this.browser);
@@ -961,32 +980,34 @@ var InspectorUI = {
       this.removeEventListener("popuphidden", treePanelHidden, false);
 
       InspectorUI.closing = false;
       Services.obs.notifyObservers(null, INSPECTOR_NOTIFICATIONS.CLOSED, null);
     }, false);
 
     this.treePanel.hidePopup();
     delete this.treePanel;
+    delete this.stylePanel;
   },
 
   /**
    * Begin inspecting webpage, attach page event listeners, activate
    * highlighter event listeners.
    */
   startInspecting: function IUI_startInspecting()
   {
     // if currently editing an attribute value, starting
     // "live inspection" mode closes the editor
     if (this.editingContext)
       this.closeEditor();
 
     document.getElementById("inspector-inspect-toolbutton").checked = true;
     this.attachPageListeners();
     this.inspecting = true;
+    this.toolsDim(true);
     this.highlighter.veilContainer.removeAttribute("locked");
   },
 
   /**
    * Stop inspecting webpage, detach page listeners, disable highlighter
    * event listeners.
    * @param aPreventScroll
    *        Prevent scroll in the HTML tree?
@@ -995,16 +1016,17 @@ var InspectorUI = {
   {
     if (!this.inspecting) {
       return;
     }
 
     document.getElementById("inspector-inspect-toolbutton").checked = false;
     this.detachPageListeners();
     this.inspecting = false;
+    this.toolsDim(false);
     if (this.highlighter.node) {
       this.select(this.highlighter.node, true, true, !aPreventScroll);
     } else {
       this.select(null, true, true);
     }
     this.highlighter.veilContainer.setAttribute("locked", true);
   },
 
@@ -1154,20 +1176,22 @@ var InspectorUI = {
       node = this.getRepObject(aEvent.target);
     }
 
     if (node) {
       if (hitTwisty) {
         this.ioBox.toggleObject(node);
       } else {
         if (this.inspecting) {
+          this.toolsSelect();
           this.stopInspecting(true);
         } else {
           this.select(node, true, false);
           this.highlighter.highlightNode(node);
+          this.toolsSelect();
         }
       }
     }
   },
 
   /**
    * Handle double-click events in the html tree panel.
    * (double-clicking an attribute value allows it to be edited)
@@ -1626,16 +1650,17 @@ var InspectorUI = {
    *   label: "Button label",
    *   icon: "chrome://somepath.png",
    *   tooltiptext: "Button tooltip",
    *   accesskey: "S",
    *   isOpen: object.property, (getter) returning true if tool is open.
    *   onSelect: object.method,
    *   show: object.method, called to show the tool when button is pressed.
    *   hide: object.method, called to hide the tool when button is pressed.
+   *   dim: object.method, called to disable a tool during highlighting.
    *   unregister: object.method, called when tool should be destroyed.
    *   panel: myTool.panel
    * }
    *
    * @param aRegObj Object
    *        The Registration Object used to register this tool described
    *        above. The tool should cache this object for later deregistration.
    */
@@ -1789,16 +1814,29 @@ var InspectorUI = {
     this.toolsDo(function IUI_toolsOnSelect(aTool) {
       if (aTool.isOpen) {
         aTool.onSelect.call(aTool.context, InspectorUI.selection);
       }
     });
   },
 
   /**
+   * Dim or undim each tool in the tools collection
+   * @param aState true = dim, false = undim
+   */
+  toolsDim: function IUI_toolsDim(aState)
+  {
+    this.toolsDo(function IUI_toolsOnSelect(aTool) {
+      if (aTool.isOpen && "dim" in aTool) {
+        aTool.dim.call(aTool.context, aState);
+      }
+    });
+  },
+
+  /**
    * Loop through all registered tools and pass each into the provided function
    * @param aFunction The function to which each tool is to be passed
    */
   toolsDo: function IUI_toolsDo(aFunction)
   {
     for each (let tool in this.tools) {
       aFunction(tool);
     }
@@ -2055,8 +2093,14 @@ XPCOMUtils.defineLazyGetter(InspectorUI,
   return document.getElementById("Tools:Inspect");
 });
 
 XPCOMUtils.defineLazyGetter(InspectorUI, "strings", function () {
   return Services.strings.
          createBundle("chrome://browser/locale/inspector.properties");
 });
 
+XPCOMUtils.defineLazyGetter(InspectorUI, "StyleInspector", function () {
+  var obj = {};
+  Cu.import("resource:///modules/devtools/StyleInspector.jsm", obj);
+  return obj.StyleInspector;
+});
+
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -16,19 +16,20 @@
  * The Original Code is the Mozilla Inspector Module.
  *
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2010
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Joe Walker (jwalker@mozilla.com) (original author)
+ *   Joe Walker (jwalker@mozilla.com) (Original Author)
  *   Mihai Șucan <mihai.sucan@gmail.com>
  *   Michael Ratcliffe <mratcliffe@mozilla.com>
+ *   Rob Campbell <rcampbell@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
--- a/browser/devtools/styleinspector/StyleInspector.jsm
+++ b/browser/devtools/styleinspector/StyleInspector.jsm
@@ -16,17 +16,18 @@
  * The Original Code is the Mozilla Inspector Module.
  *
  * The Initial Developer of the Original Code is
  * The Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2011
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Mike Ratcliffe <mratcliffe@mozilla.com>
+ *   Mike Ratcliffe <mratcliffe@mozilla.com> (Original Author)
+ *   Rob Campbell <rcampbell@mozilla.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -104,31 +105,33 @@ var StyleInspector = {
     popupSet.appendChild(panel);
 
     /**
      * Iframe's onload event
      */
     let iframeReady = false;
     function SI_iframeOnload() {
       iframe.removeEventListener("load", SI_iframeOnload, true);
-      panel.cssLogic = new CssLogic();
-      panel.cssHtmlTree = new CssHtmlTree(iframe, panel.cssLogic, panel);
       iframeReady = true;
       if (panelReady) {
         SI_popupShown.call(panel);
       }
     }
 
     /**
      * Initialize the popup when it is first shown
      */
     let panelReady = false;
     function SI_popupShown() {
       panelReady = true;
       if (iframeReady) {
+        if (!this.cssLogic) {
+          this.cssLogic = new CssLogic();
+          this.cssHtmlTree = new CssHtmlTree(iframe, this.cssLogic, this);
+        }
         let selectedNode = this.selectedNode || null;
         this.cssLogic.highlight(selectedNode);
         this.cssHtmlTree.highlight(selectedNode);
         Services.obs.notifyObservers(null, "StyleInspector-opened", null);
       }
     }
 
     /**
@@ -157,39 +160,71 @@ var StyleInspector = {
     /**
      * Select a node to inspect in the Style Inspector panel
      *
      * @param aNode The node to inspect
      */
     panel.selectNode = function SI_selectNode(aNode)
     {
       this.selectedNode = aNode;
-      if (this.isOpen()) {
+      if (this.isOpen() && !this.hasAttribute("dimmed")) {
         this.cssLogic.highlight(aNode);
         this.cssHtmlTree.highlight(aNode);
-      } else {
-        let win = Services.wm.getMostRecentWindow("navigator:browser");
-        this.openPopup(win.gBrowser.selectedBrowser, "end_before", 0, 0, false, false);
       }
     };
 
     /**
      * Destroy the style panel, remove listeners etc.
      */
     panel.destroy = function SI_destroy()
     {
+      if (!this.cssLogic)
+        return;
+      if (this.isOpen())
+        this.hideTool();
       this.cssLogic = null;
       this.cssHtmlTree = null;
       this.removeEventListener("popupshown", SI_popupShown);
       this.removeEventListener("popuphidden", SI_popupHidden);
       this.parentNode.removeChild(this);
       Services.obs.notifyObservers(null, "StyleInspector-closed", null);
     };
 
     /**
+     * Dim or undim a panel by setting or removing a dimmed attribute.
+     *
+     * @param aState
+     *        true = dim, false = undim
+     */
+    panel.dimTool = function SI_dimTool(aState)
+    {
+      if (!this.isOpen())
+        return;
+
+      if (aState) {
+        this.setAttribute("dimmed", "true");
+      } else if (this.hasAttribute("dimmed")) {
+        this.removeAttribute("dimmed");
+      }
+    };
+
+    panel.showTool = function SI_showTool(aSelection)
+    {
+      this.selectNode(aSelection);
+      let win = Services.wm.getMostRecentWindow("navigator:browser");
+      this.openPopup(win.gBrowser.selectedBrowser, "end_before", 0, 0,
+        false, false);
+    };
+
+    panel.hideTool = function SI_hideTool()
+    {
+      this.hidePopup();
+    };
+
+    /**
      * Is the Style Inspector initialized?
      * @returns {Boolean} true or false
      */
     function isInitialized()
     {
       return panel.cssLogic && panel.cssHtmlTree;
     }
 
--- a/browser/devtools/styleinspector/test/browser/browser_styleinspector_webconsole.js
+++ b/browser/devtools/styleinspector/test/browser/browser_styleinspector_webconsole.js
@@ -169,31 +169,23 @@ function styleInspectorClosedByHide()
                            "StyleInspector-closed", false);
   closeConsole();
 }
 
 function styleInspectorClosedFromConsole1()
 {
   Services.obs.removeObserver(styleInspectorClosedFromConsole1,
                               "StyleInspector-closed", false);
-  info("Style Inspector 1 closed");
-  Services.obs.addObserver(styleInspectorClosedFromConsole2,
-                           "StyleInspector-closed", false);
-}
-
-function styleInspectorClosedFromConsole2()
-{
-  Services.obs.removeObserver(styleInspectorClosedFromConsole2,
-                              "StyleInspector-closed", false);
-  info("Style Inspector 2 closed");
+  info("Style Inspector 1 and 2 closed");
   executeSoon(cleanUp);
 }
 
 function cleanUp()
 {
-  let popupSet = document.getElementById("mainPopupSet");
-  ok(!popupSet.lastChild.hasAttribute("hudToolId"),
+  let panels = document.querySelector("panel[hudToolId]");
+  ok(!panels,
      "all style inspector panels are now detached and ready for garbage collection");
 
   info("cleaning up");
+
   doc = hudBox = stylePanels = jsterm = null;
   finishTest();
 }
--- a/browser/devtools/webconsole/HUDService.jsm
+++ b/browser/devtools/webconsole/HUDService.jsm
@@ -4433,17 +4433,17 @@ function JSTermHelper(aJSTerm)
       errstr = HUDService.getStr("inspectStyle.mustBeDomNode");
     } else if (!(aNode.style instanceof Ci.nsIDOMCSSStyleDeclaration)) {
       errstr = HUDService.getStr("inspectStyle.nodeHasNoStyleProps");
     }
 
     if (!errstr) {
       let stylePanel = StyleInspector.createPanel();
       stylePanel.setAttribute("hudToolId", aJSTerm.hudId);
-      stylePanel.selectNode(aNode);
+      stylePanel.showTool(aNode);
     } else {
       aJSTerm.writeOutput(errstr + "\n", CATEGORY_OUTPUT, SEVERITY_ERROR);
     }
   };
 
   /**
    * Prints aObject to the output.
    *
--- a/browser/locales/en-US/chrome/browser/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/styleinspector.properties
@@ -36,8 +36,14 @@ rule.sourceElement=element
 # these are the category names.
 group.Text_Fonts_and_Color=Text, Fonts & Color
 group.Background=Background
 group.Dimensions=Dimensions
 group.Positioning_and_Page_Flow=Positioning and Page Flow
 group.Borders=Borders
 group.Lists=Lists
 group.Effects_and_Other=Effects and Other
+
+# LOCALIZATION NOTE (style.highlighter.button): These strings are used inside
+# html tree of the highlighter for the style inspector button
+style.highlighter.button.label=Style
+style.highlighter.accesskey=S
+style.highlighter.button.tooltip=Inspect element styles