Bug 696180 - Add support for inherited properties to the rule view. r=robcee

This commit is contained in:
Dave Camp 2011-11-05 08:45:22 -07:00
parent d6fc06441d
commit 60392df231
4 changed files with 185 additions and 18 deletions

View File

@ -125,19 +125,29 @@ ElementStyle.prototype = {
{
this.rules = [];
let element = this.element;
do {
this._addElementRules(element);
} while ((element = element.parentNode) &&
element.nodeType === Ci.nsIDOMNode.ELEMENT_NODE);
// Mark overridden computed styles.
this.markOverridden();
},
_addElementRules: function ElementStyle_addElementRules(aElement)
{
let inherited = aElement !== this.element ? aElement : null;
// Include the element's style first.
this.rules.push(new Rule(this, {
style: this.element.style,
selectorText: CssLogic.l10n("rule.sourceElement")
}));
this._maybeAddRule({
style: aElement.style,
selectorText: CssLogic.l10n("rule.sourceElement"),
inherited: inherited
});
// Get the styles that apply to the element.
try {
var domRules = this.domUtils.getCSSStyleRules(this.element);
} catch (ex) {
Services.console.logStringMessage("ElementStyle_populate error: " + ex);
return;
}
var domRules = this.domUtils.getCSSStyleRules(aElement);
// getCSStyleRules returns ordered from least-specific to
// most-specific.
@ -150,14 +160,43 @@ ElementStyle.prototype = {
continue;
}
// XXX: non-style rules.
if (domRule.type === Ci.nsIDOMCSSRule.STYLE_RULE) {
this.rules.push(new Rule(this, { domRule: domRule }));
if (domRule.type !== Ci.nsIDOMCSSRule.STYLE_RULE) {
continue;
}
this._maybeAddRule({
domRule: domRule,
inherited: inherited
});
}
},
/**
* Add a rule if it's one we care about. Filters out duplicates and
* inherited styles with no inherited properties.
*
* @param {object} aOptions
* Options for creating the Rule, see the Rule constructor.
*
* @return true if we added the rule.
*/
_maybeAddRule: function ElementStyle_maybeAddRule(aOptions)
{
// If we've already included this domRule (for example, when a
// common selector is inherited), ignore it.
if (aOptions.domRule &&
this.rules.some(function(rule) rule.domRule === aOptions.domRule)) {
return false;
}
// Mark overridden computed styles.
this.markOverridden();
let rule = new Rule(this, aOptions);
// Ignore inherited rules with no properties.
if (aOptions.inherited && rule.textProps.length == 0) {
return false;
}
this.rules.push(rule);
},
/**
@ -178,7 +217,7 @@ ElementStyle.prototype = {
let computedProps = [];
for each (let textProp in textProps) {
computedProps = computedProps.concat(textProp.computed);
};
}
// Walk over the computed properties. As we see a property name
// for the first time, mark that property's name as taken by this
@ -273,6 +312,8 @@ ElementStyle.prototype = {
* the domRule's style will be used.
* selectorText: selector text to display. If omitted, the domRule's
* selectorText will be used.
* inherited: An element this rule was inherited from. If omitted,
* the rule applies directly to the current element.
* @constructor
*/
function Rule(aElementStyle, aOptions)
@ -281,7 +322,7 @@ function Rule(aElementStyle, aOptions)
this.domRule = aOptions.domRule || null;
this.style = aOptions.style || this.domRule.style;
this.selectorText = aOptions.selectorText || this.domRule.selectorText;
this.inherited = aOptions.inherited || null;
this._getTextProperties();
}
@ -297,6 +338,17 @@ Rule.prototype = {
let line = this.elementStyle.domUtils.getRuleLine(this.domRule);
this._title += ":" + line;
}
if (this.inherited) {
let eltText = this.inherited.tagName.toLowerCase();
if (this.inherited.id) {
eltText += "#" + this.inherited.id;
}
let args = [eltText, this._title];
this._title = CssLogic._strings.formatStringFromName("rule.inheritedSource",
args, args.length);
}
return this._title;
},
@ -416,7 +468,13 @@ Rule.prototype = {
if(!matches || !matches[2])
continue;
let prop = new TextProperty(this, matches[1], matches[2], matches[3] || "");
let name = matches[1];
if (this.inherited &&
!this.elementStyle.domUtils.isInheritedProperty(name)) {
continue;
}
let prop = new TextProperty(this, name, matches[2], matches[3] || "");
this.textProps.push(prop);
}
},

View File

@ -53,6 +53,7 @@ _BROWSER_TEST_FILES = \
browser_styleinspector_bug_672744_search_filter.js \
browser_bug_692400_element_style.js \
browser_ruleview_editor.js \
browser_ruleview_inherit.js \
browser_ruleview_manipulation.js \
browser_ruleview_override.js \
browser_ruleview_ui.js \

View File

@ -0,0 +1,101 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource:///modules/devtools/CssRuleView.jsm");
let doc;
function simpleInherit()
{
let style = '' +
'#test2 {' +
' background-color: green;' +
' color: purple;' +
'}';
let styleNode = addStyle(doc, style);
doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
is(elementStyle.rules.length, 2, "Should have 2 rules.");
let elementRule = elementStyle.rules[0];
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
let inheritRule = elementStyle.rules[1];
is(inheritRule.selectorText, "#test2", "Inherited rule should be the one that includes inheritable properties.");
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
let inheritProp = inheritRule.textProps[0];
is(inheritProp.name, "color", "color should have been inherited.");
styleNode.parentNode.removeChild(styleNode);
emptyInherit();
}
function emptyInherit()
{
// No inheritable styles, this rule shouldn't show up.
let style = '' +
'#test2 {' +
' background-color: green;' +
'}';
let styleNode = addStyle(doc, style);
doc.body.innerHTML = '<div id="test2"><div id="test1">Styled Node</div></div>';
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
is(elementStyle.rules.length, 1, "Should have 1 rule.");
let elementRule = elementStyle.rules[0];
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
styleNode.parentNode.removeChild(styleNode);
elementStyleInherit();
}
function elementStyleInherit()
{
doc.body.innerHTML = '<div id="test2" style="color: red"><div id="test1">Styled Node</div></div>';
let elementStyle = new _ElementStyle(doc.getElementById("test1"));
is(elementStyle.rules.length, 2, "Should have 2 rules.");
let elementRule = elementStyle.rules[0];
ok(!elementRule.inherited, "Element style attribute should not consider itself inherited.");
let inheritRule = elementStyle.rules[1];
ok(!inheritRule.domRule, "Inherited rule should be an element style, not a rule.");
ok(!!inheritRule.inherited, "Rule should consider itself inherited.");
is(inheritRule.textProps.length, 1, "Should only display one inherited style");
let inheritProp = inheritRule.textProps[0];
is(inheritProp.name, "color", "color should have been inherited.");
finishTest();
}
function finishTest()
{
doc = null;
gBrowser.removeCurrentTab();
finish();
}
function test()
{
waitForExplicitFinish();
gBrowser.selectedTab = gBrowser.addTab();
gBrowser.selectedBrowser.addEventListener("load", function(evt) {
gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true);
doc = content.document;
waitForFocus(simpleInherit, content);
}, true);
content.location = "data:text/html,basic style inspector tests";
}

View File

@ -19,6 +19,12 @@ rule.status.UNMATCHED=Unmatched
rule.sourceInline=inline
rule.sourceElement=element
# LOCALIZATION NOTE (rule.inheritedSource): Shown for CSS rules
# that were inherited from a parent node. Will be passed a node
# identifier and a source location.
# e.g "Inherited from body#bodyID (styles.css:20)"
rule.inheritedSource=Inherited from %S (%S)
# LOCALIZATION NOTE (group): Style properties are displayed in categories and
# these are the category names.
group.Text_Fonts_and_Color=Text, Fonts & Color
@ -34,3 +40,4 @@ group.Effects_and_Other=Effects and Other
style.highlighter.button.label1=Properties
style.highlighter.accesskey1=P
style.highlighter.button.tooltip=Inspect element styles