зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1499049
- (Part 1) Log ancestor rule tree for changes to CSS declarations; r=pbro
⚠️ **To build locally, this change series depends on the [change series](https://phabricator.services.mozilla.com/D4399) which adds the ChangesActor**. 🏋️♂️ **To test hands-on, you can download a [custom macOS build](https://queue.taskcluster.net/v1/task/HIiZcwLXTuuSYYjfwEDmmA/runs/0/artifacts/public/build/target.dmg) (updated Wed, Oct 24) which includes both change series.** - Introduce ancestorRules getter to StyleRuleActor to get a flattened rule tree with the ancestors of the current rule; - Introduce CSSRuleTypeName to css-logic helpers to map between CSS rule type and human-readable name; - Log rule index position with each CSS declaration change to help differentiate between changes to rules with identical selectors at the same level of nesting. Differential Revision: https://phabricator.services.mozilla.com/D8718 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
11050d732a
Коммит
c9616064f5
|
@ -27,7 +27,10 @@ loader.lazyRequireGetter(this, "UPDATE_PRESERVING_RULES",
|
|||
"devtools/server/actors/stylesheets", true);
|
||||
loader.lazyRequireGetter(this, "UPDATE_GENERAL",
|
||||
"devtools/server/actors/stylesheets", true);
|
||||
loader.lazyRequireGetter(this, "findCssSelector", "devtools/shared/inspector/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "findCssSelector",
|
||||
"devtools/shared/inspector/css-logic", true);
|
||||
loader.lazyRequireGetter(this, "CSSRuleTypeName",
|
||||
"devtools/shared/inspector/css-logic", true);
|
||||
|
||||
loader.lazyGetter(this, "PSEUDO_ELEMENTS", () => {
|
||||
return InspectorUtils.getCSSPseudoElementNames();
|
||||
|
@ -986,13 +989,13 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
|||
if (CSSRule.isInstance(item)) {
|
||||
this.type = item.type;
|
||||
this.rawRule = item;
|
||||
this._computeRuleIndex();
|
||||
if ((this.type === CSSRule.STYLE_RULE ||
|
||||
this.type === CSSRule.KEYFRAME_RULE) &&
|
||||
this.rawRule.parentStyleSheet) {
|
||||
this.line = InspectorUtils.getRelativeRuleLine(this.rawRule);
|
||||
this.column = InspectorUtils.getRuleColumn(this.rawRule);
|
||||
this._parentSheet = this.rawRule.parentStyleSheet;
|
||||
this._computeRuleIndex();
|
||||
this.sheetActor = this.pageStyle._sheetRef(this._parentSheet);
|
||||
this.sheetActor.on("style-applied", this._onStyleApplied);
|
||||
}
|
||||
|
@ -1049,6 +1052,25 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
|||
this._parentSheet.href !== "about:PreferenceStyleSheet");
|
||||
},
|
||||
|
||||
/**
|
||||
* Return an array with StyleRuleActor instances for each of this rule's ancestor rules
|
||||
* (@media, @supports, @keyframes, etc) obtained by recursively reading rule.parentRule.
|
||||
* If the rule has no ancestors, return an empty array.
|
||||
*
|
||||
* @return {Array}
|
||||
*/
|
||||
get ancestorRules() {
|
||||
const ancestors = [];
|
||||
let rule = this.rawRule;
|
||||
|
||||
while (rule.parentRule) {
|
||||
ancestors.push(this.pageStyle._styleRef(rule.parentRule));
|
||||
rule = rule.parentRule;
|
||||
}
|
||||
|
||||
return ancestors;
|
||||
},
|
||||
|
||||
getDocument: function(sheet) {
|
||||
if (sheet.ownerNode) {
|
||||
return sheet.ownerNode.nodeType == sheet.ownerNode.DOCUMENT_NODE ?
|
||||
|
@ -1186,10 +1208,10 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
|||
const result = [];
|
||||
|
||||
while (rule) {
|
||||
let cssRules;
|
||||
let cssRules = [];
|
||||
if (rule.parentRule) {
|
||||
cssRules = rule.parentRule.cssRules;
|
||||
} else {
|
||||
} else if (rule.parentStyleSheet) {
|
||||
cssRules = rule.parentStyleSheet.cssRules;
|
||||
}
|
||||
|
||||
|
@ -1476,19 +1498,53 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
|||
|
||||
// Metadata about a change.
|
||||
const data = {};
|
||||
data.type = change.type;
|
||||
data.selector = this.rawRule.selectorText;
|
||||
// Collect information about the rule's ancestors (@media, @supports, @keyframes).
|
||||
// Used to show context for this change in the UI and to match the rule for undo/redo.
|
||||
data.ancestors = this.ancestorRules.map(rule => {
|
||||
return {
|
||||
// Rule type as number defined by CSSRule.type (ex: 4, 7, 12)
|
||||
// @see https://developer.mozilla.org/en-US/docs/Web/API/CSSRule
|
||||
type: rule.rawRule.type,
|
||||
// Rule type as human-readable string (ex: "@media", "@supports", "@keyframes")
|
||||
typeName: CSSRuleTypeName[rule.rawRule.type],
|
||||
// Conditions of @media and @supports rules (ex: "min-width: 1em")
|
||||
conditionText: rule.rawRule.conditionText,
|
||||
// Name of @keyframes rule; refrenced by the animation-name CSS property.
|
||||
name: rule.rawRule.name,
|
||||
// Selector of individual @keyframe rule within a @keyframes rule (ex: 0%, 100%).
|
||||
keyText: rule.rawRule.keyText,
|
||||
// Array with the indexes of this rule and its ancestors within the CSS rule tree.
|
||||
ruleIndex: rule._ruleIndex,
|
||||
};
|
||||
});
|
||||
|
||||
// For inline style changes, generate a unique selector and pass the node tag.
|
||||
// For changes in element style attributes, generate a unique selector.
|
||||
if (this.type === ELEMENT_STYLE) {
|
||||
data.tag = this.rawNode.tagName;
|
||||
data.href = "inline";
|
||||
// findCssSelector() fails on XUL documents. Catch and silently ignore that error.
|
||||
try {
|
||||
data.selector = findCssSelector(this.rawNode);
|
||||
} catch (err) {}
|
||||
|
||||
data.source = {
|
||||
type: "element",
|
||||
// Used to differentiate between elements which match the same generated selector
|
||||
// but live in different documents (ex: host document and iframe).
|
||||
href: this.rawNode.baseURI,
|
||||
// Element style attributes don't have a rule index; use the generated selector.
|
||||
index: data.selector,
|
||||
};
|
||||
data.ruleIndex = 0;
|
||||
} else {
|
||||
data.href = this._parentSheet.href || "inline stylesheet";
|
||||
data.selector = (this.type === CSSRule.KEYFRAME_RULE)
|
||||
? this.rawRule.keyText
|
||||
: this.rawRule.selectorText;
|
||||
data.source = {
|
||||
type: "stylesheet",
|
||||
href: this.sheetActor.href,
|
||||
index: this.sheetActor.styleSheetIndex,
|
||||
};
|
||||
// Used to differentiate between changes to rules with identical selectors.
|
||||
data.ruleIndex = this._ruleIndex;
|
||||
}
|
||||
|
||||
switch (change.type) {
|
||||
|
@ -1513,14 +1569,6 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
|||
break;
|
||||
}
|
||||
|
||||
// Do not track non-changes. This can occur when typing a value in the Rule view
|
||||
// inline editor, then committing it by pressing the Enter key.
|
||||
if (data.add && data.remove &&
|
||||
data.add.property === data.remove.property &&
|
||||
data.add.value === data.remove.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
TrackChangeEmitter.trackChange(data);
|
||||
},
|
||||
|
||||
|
|
|
@ -82,6 +82,26 @@ exports.STATUS = {
|
|||
UNKNOWN: -1,
|
||||
};
|
||||
|
||||
/**
|
||||
* Mapping of CSSRule type value to CSSRule type name.
|
||||
* @see https://developer.mozilla.org/en-US/docs/Web/API/CSSRule
|
||||
*/
|
||||
exports.CSSRuleTypeName = {
|
||||
1: "", // Regular CSS style rule has no name
|
||||
3: "@import",
|
||||
4: "@media",
|
||||
5: "@font-face",
|
||||
6: "@page",
|
||||
7: "@keyframes",
|
||||
8: "@keyframe",
|
||||
10: "@namespace",
|
||||
11: "@counter-style",
|
||||
12: "@supports",
|
||||
13: "@document",
|
||||
14: "@font-feature-values",
|
||||
15: "@viewport",
|
||||
};
|
||||
|
||||
/**
|
||||
* Lookup a l10n string in the shared styleinspector string bundle.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче