mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 685902 - Improve csshtmltree speeds by adding a has[Un]matchedSelectors() method. r=msucan
This commit is contained in:
parent
4db0dfb0b8
commit
962e2bb0fe
@ -284,7 +284,6 @@ CssHtmlTree.prototype = {
|
||||
this.cssLogic.sourceFilter = this.showOnlyUserStyles ?
|
||||
CssLogic.FILTER.ALL :
|
||||
CssLogic.FILTER.UA;
|
||||
|
||||
this.refreshPanel();
|
||||
},
|
||||
|
||||
@ -443,12 +442,28 @@ PropertyView.prototype = {
|
||||
return this.tree.cssLogic.getPropertyInfo(this.name);
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the property have any matched selectors?
|
||||
*/
|
||||
get hasMatchedSelectors()
|
||||
{
|
||||
return this.propertyInfo.hasMatchedSelectors();
|
||||
},
|
||||
|
||||
/**
|
||||
* Does the property have any unmatched selectors?
|
||||
*/
|
||||
get hasUnmatchedSelectors()
|
||||
{
|
||||
return this.propertyInfo.hasUnmatchedSelectors();
|
||||
},
|
||||
|
||||
/**
|
||||
* Should this property be visible?
|
||||
*/
|
||||
get visible()
|
||||
{
|
||||
if (this.tree.showOnlyUserStyles && this.matchedSelectorCount == 0) {
|
||||
if (this.tree.showOnlyUserStyles && !this.hasMatchedSelectors) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -469,22 +484,6 @@ PropertyView.prototype = {
|
||||
return this.visible ? "property-view" : "property-view-hidden";
|
||||
},
|
||||
|
||||
/**
|
||||
* The number of matched selectors.
|
||||
*/
|
||||
get matchedSelectorCount()
|
||||
{
|
||||
return this.propertyInfo.matchedSelectors.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* The number of unmatched selectors.
|
||||
*/
|
||||
get unmatchedSelectorCount()
|
||||
{
|
||||
return this.propertyInfo.unmatchedSelectors.length;
|
||||
},
|
||||
|
||||
/**
|
||||
* Refresh the panel's CSS property value.
|
||||
*/
|
||||
@ -520,10 +519,10 @@ PropertyView.prototype = {
|
||||
*/
|
||||
refreshMatchedSelectors: function PropertyView_refreshMatchedSelectors()
|
||||
{
|
||||
this.matchedSelectorsTitleNode.innerHTML = this.matchedSelectorTitle();
|
||||
this.matchedSelectorsContainer.hidden = this.matchedSelectorCount == 0;
|
||||
let hasMatchedSelectors = this.hasMatchedSelectors;
|
||||
this.matchedSelectorsContainer.hidden = !hasMatchedSelectors;
|
||||
|
||||
if (this.matchedExpanded && this.matchedSelectorCount > 0) {
|
||||
if (this.matchedExpanded && hasMatchedSelectors) {
|
||||
CssHtmlTree.processTemplate(this.templateMatchedSelectors,
|
||||
this.matchedSelectorTable, this);
|
||||
this.matchedExpander.setAttribute("open", "");
|
||||
@ -536,11 +535,12 @@ PropertyView.prototype = {
|
||||
/**
|
||||
* Refresh the panel unmatched rules.
|
||||
*/
|
||||
refreshUnmatchedSelectors: function PropertyView_refreshUnmatchedSelectors() {
|
||||
this.unmatchedSelectorsTitleNode.innerHTML = this.unmatchedSelectorTitle();
|
||||
this.unmatchedSelectorsContainer.hidden = this.unmatchedSelectorCount == 0;
|
||||
refreshUnmatchedSelectors: function PropertyView_refreshUnmatchedSelectors()
|
||||
{
|
||||
let hasUnmatchedSelectors = this.hasUnmatchedSelectors;
|
||||
this.unmatchedSelectorsContainer.hidden = !hasUnmatchedSelectors;
|
||||
|
||||
if (this.unmatchedExpanded && this.unmatchedSelectorCount > 0) {
|
||||
if (this.unmatchedExpanded && hasUnmatchedSelectors) {
|
||||
CssHtmlTree.processTemplate(this.templateUnmatchedSelectors,
|
||||
this.unmatchedSelectorTable, this);
|
||||
this.unmatchedExpander.setAttribute("open", "");
|
||||
@ -550,42 +550,6 @@ PropertyView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute the title of the matched selector expander. The title includes the
|
||||
* number of selectors that match the currently selected element.
|
||||
*
|
||||
* @return {string} The rule title.
|
||||
*/
|
||||
matchedSelectorTitle: function PropertyView_matchedSelectorTitle()
|
||||
{
|
||||
let result = "";
|
||||
|
||||
if (this.matchedSelectorCount > 0) {
|
||||
let str = CssHtmlTree.l10n("property.numberOfMatchedSelectors");
|
||||
result = PluralForm.get(this.matchedSelectorCount, str)
|
||||
.replace("#1", this.matchedSelectorCount);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Compute the title of the unmatched selector expander. The title includes
|
||||
* the number of selectors that match the currently selected element.
|
||||
*
|
||||
* @return {string} The rule title.
|
||||
*/
|
||||
unmatchedSelectorTitle: function PropertyView_unmatchedSelectorTitle()
|
||||
{
|
||||
let result = "";
|
||||
|
||||
if (this.unmatchedSelectorCount > 0) {
|
||||
let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
|
||||
result = PluralForm.get(this.unmatchedSelectorCount, str)
|
||||
.replace("#1", this.unmatchedSelectorCount);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
|
||||
/**
|
||||
* Provide access to the matched SelectorViews that we are currently
|
||||
* displaying.
|
||||
|
@ -216,7 +216,8 @@ CssLogic.prototype = {
|
||||
|
||||
/**
|
||||
* Source filter. Only display properties coming from the given source (web
|
||||
* address).
|
||||
* address). Note that in order to avoid information overload we DO NOT show
|
||||
* unmatched system rules.
|
||||
* @see CssLogic.FILTER.*
|
||||
*/
|
||||
set sourceFilter(aValue) {
|
||||
@ -415,6 +416,27 @@ CssLogic.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Process *some* cached stylesheets in the document using your callback. The
|
||||
* callback function should return true in order to halt processing.
|
||||
*
|
||||
* @param {function} aCallback the function you want executed for some of the
|
||||
* CssSheet objects cached.
|
||||
* @param {object} aScope the scope you want for the callback function. aScope
|
||||
* will be the this object when aCallback executes.
|
||||
* @return {Boolean} true if aCallback returns true during any iteration,
|
||||
* otherwise false is returned.
|
||||
*/
|
||||
forSomeSheets: function CssLogic_forSomeSheets(aCallback, aScope)
|
||||
{
|
||||
for each (let sheets in this._sheets) {
|
||||
if (sheets.some(aCallback, aScope)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the number nsIDOMCSSRule objects in the document, counted from all of
|
||||
* the stylesheets. System sheets are excluded. If a filter is active, this
|
||||
@ -554,7 +576,6 @@ CssLogic.prototype = {
|
||||
if (!this._matchedSelectors) {
|
||||
this.processMatchedSelectors();
|
||||
}
|
||||
|
||||
if (this._unmatchedSelectors) {
|
||||
if (aCallback) {
|
||||
this._unmatchedSelectors.forEach(aCallback, aScope);
|
||||
@ -565,6 +586,7 @@ CssLogic.prototype = {
|
||||
this._unmatchedSelectors = [];
|
||||
|
||||
this.forEachSheet(function (aSheet) {
|
||||
// We do not show unmatched selectors from system stylesheets
|
||||
if (aSheet.systemSheet) {
|
||||
return;
|
||||
}
|
||||
@ -581,6 +603,79 @@ CssLogic.prototype = {
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the highlighted element or it's parents have matched selectors.
|
||||
* If aCallback is provided then the domRules for the element are passed to
|
||||
* the callback function.
|
||||
*
|
||||
* @param {function} [aCallback] Simple callback method
|
||||
* @return {Boolean} true if the current element or it's parents have
|
||||
* matching CssSelector objects, false otherwise
|
||||
*/
|
||||
hasMatchedSelectors: function CL_hasMatchedSelectors(aCallback)
|
||||
{
|
||||
let domRules;
|
||||
let element = this.viewedElement;
|
||||
let matched = false;
|
||||
|
||||
do {
|
||||
try {
|
||||
domRules = this.domUtils.getCSSStyleRules(element);
|
||||
} catch (ex) {
|
||||
Services.console.
|
||||
logStringMessage("CssLogic_hasMatchedSelectors error: " + ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (domRules.Count() && (!aCallback || aCallback(domRules))) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} while ((element = element.parentNode) &&
|
||||
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
|
||||
|
||||
return matched;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the highlighted element or it's parents have unmatched selectors.
|
||||
*
|
||||
* @param {String} aProperty The CSS property to check against
|
||||
* @return {Boolean} true if the current element or it's parents have
|
||||
* unmatched CssSelector objects, false otherwise
|
||||
*/
|
||||
hasUnmatchedSelectors: function CL_hasUnmatchedSelectors(aProperty)
|
||||
{
|
||||
return this.forSomeSheets(function (aSheet) {
|
||||
// We do not show unmatched selectors from system stylesheets
|
||||
if (aSheet.systemSheet) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return aSheet.forSomeRules(function (aRule) {
|
||||
if (aRule.getPropertyValue(aProperty)) {
|
||||
let element = this.viewedElement;
|
||||
let selectorText = aRule._domRule.selectorText;
|
||||
let matches = false;
|
||||
|
||||
do {
|
||||
if (element.mozMatchesSelector(selectorText)) {
|
||||
matches = true;
|
||||
break;
|
||||
}
|
||||
} while ((element = element.parentNode) &&
|
||||
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
|
||||
|
||||
if (!matches) {
|
||||
// Now we know that there are rules but none match.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}, this);
|
||||
}, this);
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
@ -914,6 +1009,36 @@ CssSheet.prototype = {
|
||||
this._ruleCount = ruleCount;
|
||||
},
|
||||
|
||||
/**
|
||||
* Process *some* rules in this stylesheet using your callback function. Your
|
||||
* function receives one argument: the CssRule object for each CSSStyleRule
|
||||
* inside the stylesheet. In order to stop processing the callback function
|
||||
* needs to return a value.
|
||||
*
|
||||
* Note that this method also iterates through @media rules inside the
|
||||
* stylesheet.
|
||||
*
|
||||
* @param {function} aCallback the function you want to execute for each of
|
||||
* the style rules.
|
||||
* @param {object} aScope the scope you want for the callback function. aScope
|
||||
* will be the this object when aCallback executes.
|
||||
* @return {Boolean} true if aCallback returns true during any iteration,
|
||||
* otherwise false is returned.
|
||||
*/
|
||||
forSomeRules: function CssSheet_forSomeRules(aCallback, aScope)
|
||||
{
|
||||
let domRules = this.domSheet.cssRules;
|
||||
function _iterator(aDomRule) {
|
||||
if (aDomRule.type == Ci.nsIDOMCSSRule.STYLE_RULE) {
|
||||
return aCallback.call(aScope, this.getRule(aDomRule));
|
||||
} else if (aDomRule.type == Ci.nsIDOMCSSRule.MEDIA_RULE &&
|
||||
aDomRule.cssRules && CssLogic.sheetMediaAllowed(aDomRule)) {
|
||||
return Array.prototype.some.call(aDomRule.cssRules, _iterator, this);
|
||||
}
|
||||
}
|
||||
return Array.prototype.some.call(domRules, _iterator, this);
|
||||
},
|
||||
|
||||
toString: function CssSheet_toString()
|
||||
{
|
||||
return "CssSheet[" + this.shortSource + "]";
|
||||
@ -1264,6 +1389,9 @@ function CssPropertyInfo(aCssLogic, aProperty)
|
||||
// counted. This includes rules that come from filtered stylesheets (those
|
||||
// that have sheetAllowed = false).
|
||||
this._matchedSelectors = null;
|
||||
this._unmatchedSelectors = null;
|
||||
this._hasMatchedSelectors = null;
|
||||
this._hasUnmatchedSelectors = null;
|
||||
}
|
||||
|
||||
CssPropertyInfo.prototype = {
|
||||
@ -1361,6 +1489,55 @@ CssPropertyInfo.prototype = {
|
||||
return this._unmatchedSelectors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the property has any matched selectors.
|
||||
*
|
||||
* @return {Boolean} true if the current element or it's parents have
|
||||
* matching CssSelector objects, false otherwise
|
||||
*/
|
||||
hasMatchedSelectors: function CssPropertyInfo_hasMatchedSelectors()
|
||||
{
|
||||
if (this._hasMatchedSelectors === null) {
|
||||
this._hasMatchedSelectors = this._cssLogic.hasMatchedSelectors(function(aDomRules) {
|
||||
for (let i = 0; i < aDomRules.Count(); i++) {
|
||||
let domRule = aDomRules.GetElementAt(i);
|
||||
|
||||
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let domSheet = domRule.parentStyleSheet;
|
||||
let systemSheet = CssLogic.isSystemStyleSheet(domSheet);
|
||||
let filter = this._cssLogic.sourceFilter;
|
||||
if (filter !== CssLogic.FILTER.UA && systemSheet) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (domRule.style.getPropertyValue(this.property)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
return this._hasMatchedSelectors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the property has any matched selectors.
|
||||
*
|
||||
* @return {Boolean} true if the current element or it's parents have
|
||||
* unmatched CssSelector objects, false otherwise
|
||||
*/
|
||||
hasUnmatchedSelectors: function CssPropertyInfo_hasUnmatchedSelectors()
|
||||
{
|
||||
if (this._hasUnmatchedSelectors === null) {
|
||||
this._hasUnmatchedSelectors = this._cssLogic.hasUnmatchedSelectors(this.property);
|
||||
}
|
||||
return this._hasUnmatchedSelectors;
|
||||
},
|
||||
|
||||
/**
|
||||
* Find the selectors that match the highlighted element and its parents.
|
||||
* Uses CssLogic.processMatchedSelectors() to find the matched selectors,
|
||||
@ -1437,7 +1614,8 @@ CssPropertyInfo.prototype = {
|
||||
},
|
||||
|
||||
/**
|
||||
* Process an unmatched CssSelector object.
|
||||
* Process an unmatched CssSelector object. Note that in order to avoid
|
||||
* information overload we DO NOT show unmatched system rules.
|
||||
*
|
||||
* @private
|
||||
* @param {CssSelector} aSelector the unmatched CssSelector object.
|
||||
|
@ -130,9 +130,7 @@ To visually debug the templates without running firefox, alter the display:none
|
||||
<div save="${matchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
|
||||
<div onclick="${matchedSelectorsClick}" class="rule-matched">
|
||||
<div save="${matchedExpander}" class="expander"></div>
|
||||
<div save="${matchedSelectorsTitleNode}">
|
||||
${matchedSelectorTitle(__element)}
|
||||
</div>
|
||||
<div save="${matchedSelectorsTitleNode}">&matchedSelectors;</div>
|
||||
</div>
|
||||
<table save="${matchedSelectorTable}" dir="${getRTLAttr}"></table>
|
||||
</div>
|
||||
@ -140,9 +138,7 @@ To visually debug the templates without running firefox, alter the display:none
|
||||
<div save="${unmatchedSelectorsContainer}" class="rulelink" dir="${getRTLAttr}">
|
||||
<div onclick="${unmatchedSelectorsClick}" class="rule-unmatched">
|
||||
<div save="${unmatchedExpander}" class="expander"></div>
|
||||
<div save="${unmatchedSelectorsTitleNode}">
|
||||
${unmatchedSelectorTitle(__element)}
|
||||
</div>
|
||||
<div save="${unmatchedSelectorsTitleNode}">&unmatchedSelectors;</div>
|
||||
</div>
|
||||
<table save="${unmatchedSelectorTable}" dir="${getRTLAttr}"></table>
|
||||
</div>
|
||||
|
@ -62,15 +62,8 @@ function testMatchedSelectors()
|
||||
is(numMatchedSelectors, 6,
|
||||
"CssLogic returns the correct number of matched selectors for div");
|
||||
|
||||
let returnedSelectorTitle = propertyView.matchedSelectorTitle();
|
||||
let str = CssHtmlTree.l10n("property.numberOfMatchedSelectors");
|
||||
let calculatedSelectorTitle = PluralForm.get(numMatchedSelectors, str)
|
||||
.replace("#1", numMatchedSelectors);
|
||||
|
||||
info("returnedSelectorTitle: '" + returnedSelectorTitle + "'");
|
||||
|
||||
is(returnedSelectorTitle, calculatedSelectorTitle,
|
||||
"returned title for matched selectors is correct");
|
||||
is(propertyView.propertyInfo.hasMatchedSelectors(), true,
|
||||
"hasMatchedSelectors returns true");
|
||||
}
|
||||
|
||||
function testUnmatchedSelectors()
|
||||
@ -93,15 +86,8 @@ function testUnmatchedSelectors()
|
||||
is(numUnmatchedSelectors, 13,
|
||||
"CssLogic returns the correct number of unmatched selectors for body");
|
||||
|
||||
let returnedSelectorTitle = propertyView.unmatchedSelectorTitle();
|
||||
let str = CssHtmlTree.l10n("property.numberOfUnmatchedSelectors");
|
||||
let calculatedSelectorTitle = PluralForm.get(numUnmatchedSelectors, str)
|
||||
.replace("#1", numUnmatchedSelectors);
|
||||
|
||||
info("returnedSelectorTitle: '" + returnedSelectorTitle + "'");
|
||||
|
||||
is(returnedSelectorTitle, calculatedSelectorTitle,
|
||||
"returned title for unmatched selectors is correct");
|
||||
is(propertyView.propertyInfo.hasUnmatchedSelectors(), true,
|
||||
"hasUnmatchedSelectors returns true");
|
||||
}
|
||||
|
||||
function finishUp()
|
||||
|
@ -13,3 +13,13 @@
|
||||
- quickly jump to the documentation from the Mozilla Developer Network site.
|
||||
- This is the link title shown in the hover tooltip. -->
|
||||
<!ENTITY helpLinkTitle "Read the documentation for this property">
|
||||
|
||||
<!-- LOCALIZATION NOTE (matchedSelectors): For each style property the
|
||||
- panel shows whether there are any selectors that match the currently
|
||||
- selected element. -->
|
||||
<!ENTITY matchedSelectors "Matched selectors">
|
||||
|
||||
<!-- LOCALIZATION NOTE (unmatchedSelectors): For each style property
|
||||
- the panel shows whether there are any selectors that do not match the
|
||||
- currently selected element. -->
|
||||
<!ENTITY unmatchedSelectors "Unmatched selectors">
|
||||
|
@ -3,19 +3,6 @@
|
||||
# LOCALIZATION NOTE (panelTitle): This is the panel title
|
||||
panelTitle=Style Inspector
|
||||
|
||||
# LOCALIZATION NOTE (property.numberOfMatchedSelectors): 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.numberOfMatchedSelectors=1 matched selector;#1 matched selectors
|
||||
|
||||
# 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.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
|
||||
|
Loading…
Reference in New Issue
Block a user