Bug 683672 - Style Inspector is counting some unmatched rules incorrectly; r=msucan
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Mon, 05 Sep 2011 15:14:52 +0200
changeset 76657 05b61a98eb00ae415886936fb1fd84fa259c5ec8
parent 76656 ab1e3be27b4315cca736ec10486089786b2e3127
child 76658 d1c042be8802ee17c1d9e668ca162d0658185a3f
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersmsucan
bugs683672
milestone9.0a1
Bug 683672 - Style Inspector is counting some unmatched rules incorrectly; r=msucan
browser/devtools/styleinspector/CssHtmlTree.jsm
browser/devtools/styleinspector/CssLogic.jsm
browser/devtools/styleinspector/test/browser/Makefile.in
browser/devtools/styleinspector/test/browser/browser_bug683672.html
browser/devtools/styleinspector/test/browser/browser_bug683672.js
browser/locales/en-US/chrome/browser/styleinspector.properties
--- a/browser/devtools/styleinspector/CssHtmlTree.jsm
+++ b/browser/devtools/styleinspector/CssHtmlTree.jsm
@@ -42,17 +42,17 @@
 const Cu = Components.utils;
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/PluralForm.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 Cu.import("resource:///modules/devtools/CssLogic.jsm");
 Cu.import("resource:///modules/devtools/Templater.jsm");
 
-var EXPORTED_SYMBOLS = ["CssHtmlTree"];
+var EXPORTED_SYMBOLS = ["CssHtmlTree", "PropertyView"];
 
 /**
  * CssHtmlTree is a panel that manages the display of a table sorted by style.
  * There should be one instance of CssHtmlTree per style display (of which there
  * will generally only be one).
  *
  * @params {Document} aStyleWin The main XUL browser document
  * @params {CssLogic} aCssLogic How we dig into the CSS. See CssLogic.jsm
@@ -337,42 +337,42 @@ PropertyView.prototype = {
    */
   get propertyInfo()
   {
     return this.tree.cssLogic.getPropertyInfo(this.name);
   },
 
   /**
    * Compute the title of the property view. The title includes the number of
-   * rules that hold the current property.
+   * selectors that match the currently selected element.
    *
    * @param {nsIDOMElement} aElement reference to the DOM element where the rule
    * title needs to be displayed.
    * @return {string} The rule title.
    */
   ruleTitle: function PropertyView_ruleTitle(aElement)
   {
     let result = "";
-    let matchedRuleCount = this.propertyInfo.matchedRuleCount;
+    let matchedSelectorCount = this.propertyInfo.matchedSelectors.length;
 
-    if (matchedRuleCount > 0) {
+    if (matchedSelectorCount > 0) {
       aElement.classList.add("rule-count");
       aElement.firstElementChild.className = "expander";
 
-      let str = CssHtmlTree.l10n("property.numberOfRules");
-      result = PluralForm.get(matchedRuleCount, str)
-          .replace("#1", matchedRuleCount);
+      let str = CssHtmlTree.l10n("property.numberOfSelectors");
+      result = PluralForm.get(matchedSelectorCount, str)
+          .replace("#1", matchedSelectorCount);
     } else if (this.showUnmatchedLink) {
       aElement.classList.add("rule-unmatched");
       aElement.firstElementChild.className = "expander";
 
-      let unmatchedRuleCount = this.propertyInfo.unmatchedRuleCount;
-      let str = CssHtmlTree.l10n("property.numberOfUnmatchedRules");
-      result = PluralForm.get(unmatchedRuleCount, str)
-          .replace("#1", unmatchedRuleCount);
+      let unmatchedSelectorCount = this.propertyInfo.unmatchedSelectors.length;
+      let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
+      result = PluralForm.get(unmatchedSelectorCount, str)
+          .replace("#1", unmatchedSelectorCount);
     }
     return result;
   },
 
   /**
    * Close the property view.
    */
   close: function PropertyView_close()
@@ -424,18 +424,19 @@ PropertyView.prototype = {
 
   /**
    * The UI has a link to allow the user to display unmatched selectors.
    * This provides localized link text.
    */
   get showUnmatchedLinkText()
   {
     let smur = CssHtmlTree.l10n("rule.showUnmatchedLink");
-    let plural = PluralForm.get(this.propertyInfo.unmatchedRuleCount, smur);
-    return plural.replace("#1", this.propertyInfo.unmatchedRuleCount);
+    let unmatchedSelectorCount = this.propertyInfo.unmatchedSelectors.length;
+    let plural = PluralForm.get(unmatchedSelectorCount, smur);
+    return plural.replace("#1", unmatchedSelectorCount);
   },
 
   /**
    * The action when a user clicks the 'show unmatched' link.
    */
   showUnmatchedLinkClick: function PropertyView_showUnmatchedLinkClick(aEvent)
   {
     this.showUnmatched = true;
--- a/browser/devtools/styleinspector/CssLogic.jsm
+++ b/browser/devtools/styleinspector/CssLogic.jsm
@@ -736,16 +736,18 @@ function CssSheet(aCssLogic, aDomSheet, 
 
   // Cached CssRules from the given stylesheet.
   this._rules = {};
 
   this._ruleCount = -1;
 }
 
 CssSheet.prototype = {
+  _passId: null,
+
   /**
    * Get a source for a stylesheet, taking into account embedded stylesheets
    * for which we need to use document.defaultView.location.href rather than
    * sheet.href
    *
    * @return {string} the address of the stylesheet.
    */
   get href()
@@ -945,16 +947,18 @@ function CssRule(aCssSheet, aDomRule, aE
     this.source = CssLogic.l10n("rule.sourceElement");
     this.href = "#";
     this.systemRule = false;
     this.sourceElement = aElement;
   }
 }
 
 CssRule.prototype = {
+  _passId: null,
+
   /**
    * Check if the parent stylesheet is allowed by the CssLogic.sourceFilter.
    *
    * @return {boolean} true if the parent stylesheet is allowed by the current
    * sourceFilter, or false otherwise.
    */
   get sheetAllowed()
   {
@@ -1086,16 +1090,18 @@ function CssSelector(aCssRule, aSelector
 {
   this._cssRule = aCssRule;
   this.text = aSelector;
   this.elementStyle = this.text == "@element.style";
   this._specificity = null;
 }
 
 CssSelector.prototype = {
+  _matchId: null,
+
   /**
    * Retrieve the CssSelector source, which is the source of the CssSheet owning
    * the selector.
    *
    * @return {string} the selector source.
    */
   get source()
   {
--- a/browser/devtools/styleinspector/test/browser/Makefile.in
+++ b/browser/devtools/styleinspector/test/browser/Makefile.in
@@ -43,20 +43,22 @@ VPATH     = @srcdir@
 relativesrcdir  = browser/devtools/styleinspector/test/browser
 
 include $(DEPTH)/config/autoconf.mk
 include $(topsrcdir)/config/rules.mk
 
 _BROWSER_TEST_FILES = \
   browser_styleinspector.js \
   browser_styleinspector_webconsole.js \
+  browser_bug683672.js \
   head.js \
   $(NULL)
 
 _BROWSER_TEST_PAGES = \
   browser_styleinspector_webconsole.htm \
+  browser_bug683672.html \
   $(NULL)
 
 libs:: $(_BROWSER_TEST_FILES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
 
 libs:: $(_BROWSER_TEST_PAGES)
 	$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.html
@@ -0,0 +1,32 @@
+<!-- Any copyright is dedicated to the Public Domain.
+     http://creativecommons.org/publicdomain/zero/1.0/ -->
+<html>
+  <head>
+    <style>
+      .matched1, .matched2, .matched3, .matched4, .matched5 {
+        color: #000;
+      }
+
+      .unmatched1, .unmatched2, .unmatched3, .unmatched4, .unmatched5, .unmatched6, .unmatched7 {
+        color: #f00;
+      }
+
+      div {
+        position: absolute;
+        top: 40px;
+        left: 20px;
+        border: 1px solid #000;
+        color: #111;
+        width: 100px;
+        height: 50px;
+      }
+    </style>
+  </head>
+  <body>
+    inspectstyle($("test"));
+    <div id="test" class="matched1 matched2 matched3 matched4 matched5">Test div</div>
+    <div id="dummy">
+      <div></div>
+    </div>
+  </body>
+</html>
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/devtools/styleinspector/test/browser/browser_bug683672.js
@@ -0,0 +1,115 @@
+/* vim: set ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests that the style inspector works properly
+
+let doc;
+let stylePanel;
+
+const TEST_URI = "http://example.com/browser/browser/devtools/styleinspector/test/browser/browser_bug683672.html";
+
+Cu.import("resource:///modules/devtools/CssHtmlTree.jsm");
+
+function test()
+{
+  waitForExplicitFinish();
+  addTab(TEST_URI);
+  browser.addEventListener("load", tabLoaded, true);
+}
+
+function tabLoaded()
+{
+  ok(window.StyleInspector, "StyleInspector exists");
+  ok(StyleInspector.isEnabled, "style inspector preference is enabled");
+  stylePanel = StyleInspector.createPanel();
+  Services.obs.addObserver(runTests, "StyleInspector-opened", false);
+  stylePanel.openPopup();
+}
+
+function runTests()
+{
+  Services.obs.removeObserver(runTests, "StyleInspector-opened", false);
+
+  ok(stylePanel.isOpen(), "style inspector is open");
+
+  testMatchedSelectors();
+  testUnmatchedSelectors();
+
+  info("finishing up");
+  Services.obs.addObserver(finishUp, "StyleInspector-closed", false);
+  stylePanel.hidePopup();
+}
+
+function testMatchedSelectors()
+{
+  info("checking selector counts, matched rules and titles");
+  let div = content.document.getElementById("test");
+  ok(div, "captain, we have the div");
+
+  info("selecting the div");
+  stylePanel.selectNode(div);
+
+  let htmlTree = stylePanel.cssHtmlTree;
+
+  is(div, htmlTree.viewedElement,
+      "style inspector node matches the selected node");
+
+  let propertyView = new PropertyView(htmlTree, "color");
+  let numMatchedSelectors = propertyView.propertyInfo.matchedSelectors.length;
+
+  is(numMatchedSelectors, 6,
+      "CssLogic returns the correct number of matched selectors for div");
+
+  let dummy = content.document.getElementById("dummy");
+  let returnedRuleTitle = propertyView.ruleTitle(dummy);
+  let str = CssHtmlTree.l10n("property.numberOfSelectors");
+  let calculatedRuleTitle = PluralForm.get(numMatchedSelectors, str)
+                                      .replace("#1", numMatchedSelectors);
+
+  info("returnedRuleTitle: '" + returnedRuleTitle + "'");
+
+  is(returnedRuleTitle, calculatedRuleTitle,
+      "returned title for matched rules is correct");
+}
+
+function testUnmatchedSelectors()
+{
+  info("checking selector counts, unmatched rules and titles");
+  let body = content.document.body;
+  ok(body, "captain, we have a body");
+
+  info("selecting content.document.body");
+  stylePanel.selectNode(body);
+
+  let htmlTree = stylePanel.cssHtmlTree;
+
+  is(body, htmlTree.viewedElement,
+      "style inspector node matches the selected node");
+
+  let propertyView = new PropertyView(htmlTree, "color");
+  let numUnmatchedSelectors = propertyView.propertyInfo.unmatchedSelectors.length;
+
+  is(numUnmatchedSelectors, 13,
+      "CssLogic returns the correct number of unmatched selectors for body");
+
+  let dummy = content.document.getElementById("dummy");
+  let returnedRuleTitle = propertyView.ruleTitle(dummy);
+  let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
+  let calculatedRuleTitle = PluralForm.get(numUnmatchedSelectors, str)
+                                      .replace("#1", numUnmatchedSelectors);
+
+  info("returnedRuleTitle: '" + returnedRuleTitle + "'");
+
+  is(returnedRuleTitle, calculatedRuleTitle,
+      "returned title for unmatched rules is correct");
+}
+
+function finishUp()
+{
+  Services.obs.removeObserver(finishUp, "StyleInspector-closed", false);
+  ok(!stylePanel.isOpen(), "style inspector is closed");
+  doc = stylePanel = null;
+  gBrowser.removeCurrentTab();
+  finish();
+}
--- a/browser/locales/en-US/chrome/browser/styleinspector.properties
+++ b/browser/locales/en-US/chrome/browser/styleinspector.properties
@@ -1,26 +1,25 @@
 # LOCALIZATION NOTE These strings are used inside the Style Inspector.
 
 # LOCALIZATION NOTE (panelTitle): This is the panel title
 panelTitle=Style Inspector
 
-# LOCALIZATION NOTE (property.numberOfRules): For each style property the panel
-# shows the number of rules which hold that specific property, counted from all
-# of the stylesheets in the web page inspected.
+# LOCALIZATION NOTE (property.numberOfSelectors): For each style property the
+# panel shows the number of selectors which match the currently selected
+# element, counted from all stylesheets in the web page inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-property.numberOfRules=#1 rule;#1 rules
+property.numberOfSelectors=1 selector;#1 selectors
 
-# LOCALIZATION NOTE (property.numberOfUnmatchedRules): Each style property is
-# inside a rule. A rule is a selector that can match (or not) the highlighted
-# element in the web page. The property view shows no unmatched rules. If the
-# user wants to expand the property to view unmatched rules, he/she must click
-# this link displayed to the right of each property.
+# LOCALIZATION NOTE (property.numberOfUnmatchedSelectors): For each style
+# property the panel shows the number of selectors which do not match the
+# currently selected element, counted from all stylesheets in the web page
+# inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-property.numberOfUnmatchedRules=One unmatched rule;#1 unmatched rules
+property.numberOfUnmatchedSelectors=1 unmatched selector;#1 unmatched selectors
 
 # LOCALIZATION NOTE (rule.status): For each style property the panel shows
 # the rules which hold that specific property. For every rule, the rule status
 # is also displayed: a rule can be the best match, a match, a parent match, or a
 # rule did not match the element the user has highlighted.
 rule.status.BEST=Best Match
 rule.status.MATCHED=Matched
 rule.status.PARENT_MATCH=Parent Match
@@ -28,24 +27,22 @@ rule.status.UNMATCHED=Unmatched
 
 # LOCALIZATION NOTE (rule.sourceElement, rule.sourceInline): For each
 # style property the panel shows the rules which hold that specific property.
 # For every rule, the rule source is also displayed: a rule can come from a
 # file, from the same page (inline), or from the element itself (element).
 rule.sourceInline=inline
 rule.sourceElement=element
 
-# LOCALIZATION NOTE (rule.showUnmatchedLink): Each style property
-# is inside a rule. A rule is a selector that can match (or not) the highlighted
-# element in the web page. The property view shows only a few of the unmatched
-# rules. If the user wants to see all of the unmatched rules, he/she must click
-# the link displayed at the bottom of the rules table. That link shows how many
-# rules are not displayed. This is the string used when the link is generated.
+# LOCALIZATION NOTE (rule.showUnmatchedLink): For each style
+# property the panel shows the number of selectors which do not match the
+# currently selected element, counted from all stylesheets in the web page
+# inspected.
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
-rule.showUnmatchedLink=One unmatched rule...;#1 unmatched rules...
+rule.showUnmatchedLink=1 unmatched selector…;#1 unmatched selectors…
 
 # LOCALIZATION NOTE (group): Style properties are displayed in categories and
 # 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