зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1268568 - Decouple StyleRuleFront from StyleRuleActor;r=jryans
This commit is contained in:
Родитель
9c3cb25b76
Коммит
ef61ce0337
|
@ -3,14 +3,23 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
const { Cu } = require("chrome");
|
|
||||||
const {
|
const {
|
||||||
Front,
|
Front,
|
||||||
FrontClassWithSpec,
|
FrontClassWithSpec,
|
||||||
custom
|
custom,
|
||||||
|
preEvent
|
||||||
} = require("devtools/shared/protocol.js");
|
} = require("devtools/shared/protocol.js");
|
||||||
const { pageStyleSpec } = require("devtools/shared/specs/styles.js");
|
const {
|
||||||
|
pageStyleSpec,
|
||||||
|
styleRuleSpec
|
||||||
|
} = require("devtools/shared/specs/styles.js");
|
||||||
|
const promise = require("promise");
|
||||||
const { Task } = require("resource://gre/modules/Task.jsm");
|
const { Task } = require("resource://gre/modules/Task.jsm");
|
||||||
|
const { Class } = require("sdk/core/heritage");
|
||||||
|
|
||||||
|
loader.lazyGetter(this, "RuleRewriter", () => {
|
||||||
|
return require("devtools/client/shared/css-parsing-utils").RuleRewriter;
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PageStyleFront, the front object for the PageStyleActor
|
* PageStyleFront, the front object for the PageStyleActor
|
||||||
|
@ -79,3 +88,328 @@ const PageStyleFront = FrontClassWithSpec(pageStyleSpec, {
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.PageStyleFront = PageStyleFront;
|
exports.PageStyleFront = PageStyleFront;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StyleRuleFront, the front for the StyleRule actor.
|
||||||
|
*/
|
||||||
|
const StyleRuleFront = FrontClassWithSpec(styleRuleSpec, {
|
||||||
|
initialize: function (client, form, ctx, detail) {
|
||||||
|
Front.prototype.initialize.call(this, client, form, ctx, detail);
|
||||||
|
},
|
||||||
|
|
||||||
|
destroy: function () {
|
||||||
|
Front.prototype.destroy.call(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
form: function (form, detail) {
|
||||||
|
if (detail === "actorid") {
|
||||||
|
this.actorID = form;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.actorID = form.actor;
|
||||||
|
this._form = form;
|
||||||
|
if (this._mediaText) {
|
||||||
|
this._mediaText = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure _form is updated when location-changed is emitted.
|
||||||
|
*/
|
||||||
|
_locationChangedPre: preEvent("location-changed", function (line, column) {
|
||||||
|
this._clearOriginalLocation();
|
||||||
|
this._form.line = line;
|
||||||
|
this._form.column = column;
|
||||||
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a new RuleModificationList or RuleRewriter for this node.
|
||||||
|
* A RuleRewriter will be returned when the rule's canSetRuleText
|
||||||
|
* trait is true; otherwise a RuleModificationList will be
|
||||||
|
* returned.
|
||||||
|
*/
|
||||||
|
startModifyingProperties: function () {
|
||||||
|
if (this.canSetRuleText) {
|
||||||
|
return new RuleRewriter(this, this.authoredText);
|
||||||
|
}
|
||||||
|
return new RuleModificationList(this);
|
||||||
|
},
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return this._form.type;
|
||||||
|
},
|
||||||
|
get line() {
|
||||||
|
return this._form.line || -1;
|
||||||
|
},
|
||||||
|
get column() {
|
||||||
|
return this._form.column || -1;
|
||||||
|
},
|
||||||
|
get cssText() {
|
||||||
|
return this._form.cssText;
|
||||||
|
},
|
||||||
|
get authoredText() {
|
||||||
|
return this._form.authoredText || this._form.cssText;
|
||||||
|
},
|
||||||
|
get keyText() {
|
||||||
|
return this._form.keyText;
|
||||||
|
},
|
||||||
|
get name() {
|
||||||
|
return this._form.name;
|
||||||
|
},
|
||||||
|
get selectors() {
|
||||||
|
return this._form.selectors;
|
||||||
|
},
|
||||||
|
get media() {
|
||||||
|
return this._form.media;
|
||||||
|
},
|
||||||
|
get mediaText() {
|
||||||
|
if (!this._form.media) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (this._mediaText) {
|
||||||
|
return this._mediaText;
|
||||||
|
}
|
||||||
|
this._mediaText = this.media.join(", ");
|
||||||
|
return this._mediaText;
|
||||||
|
},
|
||||||
|
|
||||||
|
get parentRule() {
|
||||||
|
return this.conn.getActor(this._form.parentRule);
|
||||||
|
},
|
||||||
|
|
||||||
|
get parentStyleSheet() {
|
||||||
|
return this.conn.getActor(this._form.parentStyleSheet);
|
||||||
|
},
|
||||||
|
|
||||||
|
get element() {
|
||||||
|
return this.conn.getActor(this._form.element);
|
||||||
|
},
|
||||||
|
|
||||||
|
get href() {
|
||||||
|
if (this._form.href) {
|
||||||
|
return this._form.href;
|
||||||
|
}
|
||||||
|
let sheet = this.parentStyleSheet;
|
||||||
|
return sheet ? sheet.href : "";
|
||||||
|
},
|
||||||
|
|
||||||
|
get nodeHref() {
|
||||||
|
let sheet = this.parentStyleSheet;
|
||||||
|
return sheet ? sheet.nodeHref : "";
|
||||||
|
},
|
||||||
|
|
||||||
|
get supportsModifySelectorUnmatched() {
|
||||||
|
return this._form.traits && this._form.traits.modifySelectorUnmatched;
|
||||||
|
},
|
||||||
|
|
||||||
|
get canSetRuleText() {
|
||||||
|
return this._form.traits && this._form.traits.canSetRuleText;
|
||||||
|
},
|
||||||
|
|
||||||
|
get location() {
|
||||||
|
return {
|
||||||
|
source: this.parentStyleSheet,
|
||||||
|
href: this.href,
|
||||||
|
line: this.line,
|
||||||
|
column: this.column
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
_clearOriginalLocation: function () {
|
||||||
|
this._originalLocation = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getOriginalLocation: function () {
|
||||||
|
if (this._originalLocation) {
|
||||||
|
return promise.resolve(this._originalLocation);
|
||||||
|
}
|
||||||
|
let parentSheet = this.parentStyleSheet;
|
||||||
|
if (!parentSheet) {
|
||||||
|
// This rule doesn't belong to a stylesheet so it is an inline style.
|
||||||
|
// Inline styles do not have any mediaText so we can return early.
|
||||||
|
return promise.resolve(this.location);
|
||||||
|
}
|
||||||
|
return parentSheet.getOriginalLocation(this.line, this.column)
|
||||||
|
.then(({ fromSourceMap, source, line, column }) => {
|
||||||
|
let location = {
|
||||||
|
href: source,
|
||||||
|
line: line,
|
||||||
|
column: column,
|
||||||
|
mediaText: this.mediaText
|
||||||
|
};
|
||||||
|
if (fromSourceMap === false) {
|
||||||
|
location.source = this.parentStyleSheet;
|
||||||
|
}
|
||||||
|
if (!source) {
|
||||||
|
location.href = this.href;
|
||||||
|
}
|
||||||
|
this._originalLocation = location;
|
||||||
|
return location;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
modifySelector: custom(Task.async(function* (node, value) {
|
||||||
|
let response;
|
||||||
|
if (this.supportsModifySelectorUnmatched) {
|
||||||
|
// If the debugee supports adding unmatched rules (post FF41)
|
||||||
|
if (this.canSetRuleText) {
|
||||||
|
response = yield this.modifySelector2(node, value, true);
|
||||||
|
} else {
|
||||||
|
response = yield this.modifySelector2(node, value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response = yield this._modifySelector(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.ruleProps) {
|
||||||
|
response.ruleProps = response.ruleProps.entries[0];
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}), {
|
||||||
|
impl: "_modifySelector"
|
||||||
|
}),
|
||||||
|
|
||||||
|
setRuleText: custom(function (newText) {
|
||||||
|
this._form.authoredText = newText;
|
||||||
|
return this._setRuleText(newText);
|
||||||
|
}, {
|
||||||
|
impl: "_setRuleText"
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.StyleRuleFront = StyleRuleFront;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convenience API for building a list of attribute modifications
|
||||||
|
* for the `modifyProperties` request. A RuleModificationList holds a
|
||||||
|
* list of modifications that will be applied to a StyleRuleActor.
|
||||||
|
* The modifications are processed in the order in which they are
|
||||||
|
* added to the RuleModificationList.
|
||||||
|
*
|
||||||
|
* Objects of this type expose the same API as @see RuleRewriter.
|
||||||
|
* This lets the inspector use (mostly) the same code, regardless of
|
||||||
|
* whether the server implements setRuleText.
|
||||||
|
*/
|
||||||
|
var RuleModificationList = Class({
|
||||||
|
/**
|
||||||
|
* Initialize a RuleModificationList.
|
||||||
|
* @param {StyleRuleFront} rule the associated rule
|
||||||
|
*/
|
||||||
|
initialize: function (rule) {
|
||||||
|
this.rule = rule;
|
||||||
|
this.modifications = [];
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the modifications in this object to the associated rule.
|
||||||
|
*
|
||||||
|
* @return {Promise} A promise which will be resolved when the modifications
|
||||||
|
* are complete; @see StyleRuleActor.modifyProperties.
|
||||||
|
*/
|
||||||
|
apply: function () {
|
||||||
|
return this.rule.modifyProperties(this.modifications);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a "set" entry to the modification list.
|
||||||
|
*
|
||||||
|
* @param {Number} index index of the property in the rule.
|
||||||
|
* This can be -1 in the case where
|
||||||
|
* the rule does not support setRuleText;
|
||||||
|
* generally for setting properties
|
||||||
|
* on an element's style.
|
||||||
|
* @param {String} name the property's name
|
||||||
|
* @param {String} value the property's value
|
||||||
|
* @param {String} priority the property's priority, either the empty
|
||||||
|
* string or "important"
|
||||||
|
*/
|
||||||
|
setProperty: function (index, name, value, priority) {
|
||||||
|
this.modifications.push({
|
||||||
|
type: "set",
|
||||||
|
name: name,
|
||||||
|
value: value,
|
||||||
|
priority: priority
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a "remove" entry to the modification list.
|
||||||
|
*
|
||||||
|
* @param {Number} index index of the property in the rule.
|
||||||
|
* This can be -1 in the case where
|
||||||
|
* the rule does not support setRuleText;
|
||||||
|
* generally for setting properties
|
||||||
|
* on an element's style.
|
||||||
|
* @param {String} name the name of the property to remove
|
||||||
|
*/
|
||||||
|
removeProperty: function (index, name) {
|
||||||
|
this.modifications.push({
|
||||||
|
type: "remove",
|
||||||
|
name: name
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rename a property. This implementation acts like
|
||||||
|
* |removeProperty|, because |setRuleText| is not available.
|
||||||
|
*
|
||||||
|
* @param {Number} index index of the property in the rule.
|
||||||
|
* This can be -1 in the case where
|
||||||
|
* the rule does not support setRuleText;
|
||||||
|
* generally for setting properties
|
||||||
|
* on an element's style.
|
||||||
|
* @param {String} name current name of the property
|
||||||
|
*
|
||||||
|
* This parameter is also passed, but as it is not used in this
|
||||||
|
* implementation, it is omitted. It is documented here as this
|
||||||
|
* code also defined the interface implemented by @see RuleRewriter.
|
||||||
|
* @param {String} newName new name of the property
|
||||||
|
*/
|
||||||
|
renameProperty: function (index, name) {
|
||||||
|
this.removeProperty(index, name);
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable a property. This implementation acts like
|
||||||
|
* |removeProperty| when disabling, or a no-op when enabling,
|
||||||
|
* because |setRuleText| is not available.
|
||||||
|
*
|
||||||
|
* @param {Number} index index of the property in the rule.
|
||||||
|
* This can be -1 in the case where
|
||||||
|
* the rule does not support setRuleText;
|
||||||
|
* generally for setting properties
|
||||||
|
* on an element's style.
|
||||||
|
* @param {String} name current name of the property
|
||||||
|
* @param {Boolean} isEnabled true if the property should be enabled;
|
||||||
|
* false if it should be disabled
|
||||||
|
*/
|
||||||
|
setPropertyEnabled: function (index, name, isEnabled) {
|
||||||
|
if (!isEnabled) {
|
||||||
|
this.removeProperty(index, name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new property. This implementation does nothing, because
|
||||||
|
* |setRuleText| is not available.
|
||||||
|
*
|
||||||
|
* These parameter are passed, but as they are not used in this
|
||||||
|
* implementation, they are omitted. They are documented here as
|
||||||
|
* this code also defined the interface implemented by @see
|
||||||
|
* RuleRewriter.
|
||||||
|
*
|
||||||
|
* @param {Number} index index of the property in the rule.
|
||||||
|
* This can be -1 in the case where
|
||||||
|
* the rule does not support setRuleText;
|
||||||
|
* generally for setting properties
|
||||||
|
* on an element's style.
|
||||||
|
* @param {String} name name of the new property
|
||||||
|
* @param {String} value value of the new property
|
||||||
|
* @param {String} priority priority of the new property; either
|
||||||
|
* the empty string or "important"
|
||||||
|
*/
|
||||||
|
createProperty: function () {
|
||||||
|
// Nothing.
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ const protocol = require("devtools/shared/protocol");
|
||||||
const {Arg, Option, method, RetVal, types} = protocol;
|
const {Arg, Option, method, RetVal, types} = protocol;
|
||||||
const events = require("sdk/event/core");
|
const events = require("sdk/event/core");
|
||||||
const {Class} = require("sdk/core/heritage");
|
const {Class} = require("sdk/core/heritage");
|
||||||
const {PageStyleFront} = require("devtools/client/fronts/styles");
|
const {PageStyleFront, StyleRuleFront} = require("devtools/client/fronts/styles");
|
||||||
const {LongStringActor} = require("devtools/server/actors/string");
|
const {LongStringActor} = require("devtools/server/actors/string");
|
||||||
const {
|
const {
|
||||||
getDefinedGeometryProperties
|
getDefinedGeometryProperties
|
||||||
|
@ -19,7 +19,7 @@ const {
|
||||||
// This will also add the "stylesheet" actor type for protocol.js to recognize
|
// This will also add the "stylesheet" actor type for protocol.js to recognize
|
||||||
const {UPDATE_PRESERVING_RULES, UPDATE_GENERAL} =
|
const {UPDATE_PRESERVING_RULES, UPDATE_GENERAL} =
|
||||||
require("devtools/server/actors/stylesheets");
|
require("devtools/server/actors/stylesheets");
|
||||||
const {pageStyleSpec} = require("devtools/shared/specs/styles");
|
const {pageStyleSpec, styleRuleSpec} = require("devtools/shared/specs/styles");
|
||||||
|
|
||||||
loader.lazyRequireGetter(this, "CSS", "CSS");
|
loader.lazyRequireGetter(this, "CSS", "CSS");
|
||||||
|
|
||||||
|
@ -30,10 +30,6 @@ loader.lazyGetter(this, "DOMUtils", () => {
|
||||||
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
|
||||||
});
|
});
|
||||||
|
|
||||||
loader.lazyGetter(this, "RuleRewriter", () => {
|
|
||||||
return require("devtools/client/shared/css-parsing-utils").RuleRewriter;
|
|
||||||
});
|
|
||||||
|
|
||||||
// The PageStyle actor flattens the DOM CSS objects a little bit, merging
|
// The PageStyle actor flattens the DOM CSS objects a little bit, merging
|
||||||
// Rules and their Styles into one actor. For elements (which have a style
|
// Rules and their Styles into one actor. For elements (which have a style
|
||||||
// but no associated rule) we fake a rule with the following style id.
|
// but no associated rule) we fake a rule with the following style id.
|
||||||
|
@ -935,17 +931,7 @@ exports.PageStyleActor = PageStyleActor;
|
||||||
* (which have a CSSStyle but no CSSRule) we create a StyleRuleActor
|
* (which have a CSSStyle but no CSSRule) we create a StyleRuleActor
|
||||||
* with a special rule type (100).
|
* with a special rule type (100).
|
||||||
*/
|
*/
|
||||||
var StyleRuleActor = protocol.ActorClass({
|
var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
|
||||||
typeName: "domstylerule",
|
|
||||||
|
|
||||||
events: {
|
|
||||||
"location-changed": {
|
|
||||||
type: "locationChanged",
|
|
||||||
line: Arg(0, "number"),
|
|
||||||
column: Arg(1, "number")
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
initialize: function(pageStyle, item) {
|
initialize: function(pageStyle, item) {
|
||||||
protocol.Actor.prototype.initialize.call(this, null);
|
protocol.Actor.prototype.initialize.call(this, null);
|
||||||
this.pageStyle = pageStyle;
|
this.pageStyle = pageStyle;
|
||||||
|
@ -1252,7 +1238,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
* @param {String} newText the new text of the rule
|
* @param {String} newText the new text of the rule
|
||||||
* @returns the rule with updated properties
|
* @returns the rule with updated properties
|
||||||
*/
|
*/
|
||||||
setRuleText: method(Task.async(function* (newText) {
|
setRuleText: Task.async(function* (newText) {
|
||||||
if (!this.canSetRuleText ||
|
if (!this.canSetRuleText ||
|
||||||
(this.type !== Ci.nsIDOMCSSRule.STYLE_RULE &&
|
(this.type !== Ci.nsIDOMCSSRule.STYLE_RULE &&
|
||||||
this.type !== Ci.nsIDOMCSSRule.KEYFRAME_RULE)) {
|
this.type !== Ci.nsIDOMCSSRule.KEYFRAME_RULE)) {
|
||||||
|
@ -1270,9 +1256,6 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
yield parentStyleSheet.update(cssText, false, UPDATE_PRESERVING_RULES);
|
yield parentStyleSheet.update(cssText, false, UPDATE_PRESERVING_RULES);
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}), {
|
|
||||||
request: { modification: Arg(0, "string") },
|
|
||||||
response: { rule: RetVal("domstylerule") }
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1291,7 +1274,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
*
|
*
|
||||||
* @returns the rule with updated properties
|
* @returns the rule with updated properties
|
||||||
*/
|
*/
|
||||||
modifyProperties: method(function(modifications) {
|
modifyProperties: function(modifications) {
|
||||||
// Use a fresh element for each call to this function to prevent side
|
// Use a fresh element for each call to this function to prevent side
|
||||||
// effects that pop up based on property values that were already set on the
|
// effects that pop up based on property values that were already set on the
|
||||||
// element.
|
// element.
|
||||||
|
@ -1322,10 +1305,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}, {
|
},
|
||||||
request: { modifications: Arg(0, "array:json") },
|
|
||||||
response: { rule: RetVal("domstylerule") }
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for modifySelector and modifySelector2, inserts the new
|
* Helper function for modifySelector and modifySelector2, inserts the new
|
||||||
|
@ -1402,7 +1382,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
* Returns a boolean if the selector in the stylesheet was modified,
|
* Returns a boolean if the selector in the stylesheet was modified,
|
||||||
* and false otherwise
|
* and false otherwise
|
||||||
*/
|
*/
|
||||||
modifySelector: method(Task.async(function* (value) {
|
modifySelector: Task.async(function* (value) {
|
||||||
if (this.type === ELEMENT_STYLE) {
|
if (this.type === ELEMENT_STYLE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -1425,9 +1405,6 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}), {
|
|
||||||
request: { selector: Arg(0, "string") },
|
|
||||||
response: { isModified: RetVal("boolean") },
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1453,7 +1430,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
* new rule and a boolean indicating whether or not the new selector
|
* new rule and a boolean indicating whether or not the new selector
|
||||||
* matches the current selected element
|
* matches the current selected element
|
||||||
*/
|
*/
|
||||||
modifySelector2: method(function(node, value, editAuthored = false) {
|
modifySelector2: function(node, value, editAuthored = false) {
|
||||||
if (this.type === ELEMENT_STYLE ||
|
if (this.type === ELEMENT_STYLE ||
|
||||||
this.rawRule.selectorText === value) {
|
this.rawRule.selectorText === value) {
|
||||||
return { ruleProps: null, isMatching: true };
|
return { ruleProps: null, isMatching: true };
|
||||||
|
@ -1490,337 +1467,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||||
|
|
||||||
return { ruleProps, isMatching };
|
return { ruleProps, isMatching };
|
||||||
});
|
});
|
||||||
}, {
|
}
|
||||||
request: {
|
|
||||||
node: Arg(0, "domnode"),
|
|
||||||
value: Arg(1, "string"),
|
|
||||||
editAuthored: Arg(2, "boolean")
|
|
||||||
},
|
|
||||||
response: RetVal("modifiedStylesReturn")
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* StyleRuleFront, the front for the StyleRule actor.
|
|
||||||
*/
|
|
||||||
protocol.FrontClass(StyleRuleActor, {
|
|
||||||
initialize: function(client, form, ctx, detail) {
|
|
||||||
protocol.Front.prototype.initialize.call(this, client, form, ctx, detail);
|
|
||||||
},
|
|
||||||
|
|
||||||
destroy: function() {
|
|
||||||
protocol.Front.prototype.destroy.call(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
form: function(form, detail) {
|
|
||||||
if (detail === "actorid") {
|
|
||||||
this.actorID = form;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.actorID = form.actor;
|
|
||||||
this._form = form;
|
|
||||||
if (this._mediaText) {
|
|
||||||
this._mediaText = null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Ensure _form is updated when location-changed is emitted.
|
|
||||||
*/
|
|
||||||
_locationChangedPre: protocol.preEvent("location-changed", function(line,
|
|
||||||
column) {
|
|
||||||
this._clearOriginalLocation();
|
|
||||||
this._form.line = line;
|
|
||||||
this._form.column = column;
|
|
||||||
}),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a new RuleModificationList or RuleRewriter for this node.
|
|
||||||
* A RuleRewriter will be returned when the rule's canSetRuleText
|
|
||||||
* trait is true; otherwise a RuleModificationList will be
|
|
||||||
* returned.
|
|
||||||
*/
|
|
||||||
startModifyingProperties: function() {
|
|
||||||
if (this.canSetRuleText) {
|
|
||||||
return new RuleRewriter(this, this.authoredText);
|
|
||||||
}
|
|
||||||
return new RuleModificationList(this);
|
|
||||||
},
|
|
||||||
|
|
||||||
get type() {
|
|
||||||
return this._form.type;
|
|
||||||
},
|
|
||||||
get line() {
|
|
||||||
return this._form.line || -1;
|
|
||||||
},
|
|
||||||
get column() {
|
|
||||||
return this._form.column || -1;
|
|
||||||
},
|
|
||||||
get cssText() {
|
|
||||||
return this._form.cssText;
|
|
||||||
},
|
|
||||||
get authoredText() {
|
|
||||||
return this._form.authoredText || this._form.cssText;
|
|
||||||
},
|
|
||||||
get keyText() {
|
|
||||||
return this._form.keyText;
|
|
||||||
},
|
|
||||||
get name() {
|
|
||||||
return this._form.name;
|
|
||||||
},
|
|
||||||
get selectors() {
|
|
||||||
return this._form.selectors;
|
|
||||||
},
|
|
||||||
get media() {
|
|
||||||
return this._form.media;
|
|
||||||
},
|
|
||||||
get mediaText() {
|
|
||||||
if (!this._form.media) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
if (this._mediaText) {
|
|
||||||
return this._mediaText;
|
|
||||||
}
|
|
||||||
this._mediaText = this.media.join(", ");
|
|
||||||
return this._mediaText;
|
|
||||||
},
|
|
||||||
|
|
||||||
get parentRule() {
|
|
||||||
return this.conn.getActor(this._form.parentRule);
|
|
||||||
},
|
|
||||||
|
|
||||||
get parentStyleSheet() {
|
|
||||||
return this.conn.getActor(this._form.parentStyleSheet);
|
|
||||||
},
|
|
||||||
|
|
||||||
get element() {
|
|
||||||
return this.conn.getActor(this._form.element);
|
|
||||||
},
|
|
||||||
|
|
||||||
get href() {
|
|
||||||
if (this._form.href) {
|
|
||||||
return this._form.href;
|
|
||||||
}
|
|
||||||
let sheet = this.parentStyleSheet;
|
|
||||||
return sheet ? sheet.href : "";
|
|
||||||
},
|
|
||||||
|
|
||||||
get nodeHref() {
|
|
||||||
let sheet = this.parentStyleSheet;
|
|
||||||
return sheet ? sheet.nodeHref : "";
|
|
||||||
},
|
|
||||||
|
|
||||||
get supportsModifySelectorUnmatched() {
|
|
||||||
return this._form.traits && this._form.traits.modifySelectorUnmatched;
|
|
||||||
},
|
|
||||||
|
|
||||||
get canSetRuleText() {
|
|
||||||
return this._form.traits && this._form.traits.canSetRuleText;
|
|
||||||
},
|
|
||||||
|
|
||||||
get location() {
|
|
||||||
return {
|
|
||||||
source: this.parentStyleSheet,
|
|
||||||
href: this.href,
|
|
||||||
line: this.line,
|
|
||||||
column: this.column
|
|
||||||
};
|
|
||||||
},
|
|
||||||
|
|
||||||
_clearOriginalLocation: function() {
|
|
||||||
this._originalLocation = null;
|
|
||||||
},
|
|
||||||
|
|
||||||
getOriginalLocation: function() {
|
|
||||||
if (this._originalLocation) {
|
|
||||||
return promise.resolve(this._originalLocation);
|
|
||||||
}
|
|
||||||
let parentSheet = this.parentStyleSheet;
|
|
||||||
if (!parentSheet) {
|
|
||||||
// This rule doesn't belong to a stylesheet so it is an inline style.
|
|
||||||
// Inline styles do not have any mediaText so we can return early.
|
|
||||||
return promise.resolve(this.location);
|
|
||||||
}
|
|
||||||
return parentSheet.getOriginalLocation(this.line, this.column)
|
|
||||||
.then(({ fromSourceMap, source, line, column }) => {
|
|
||||||
let location = {
|
|
||||||
href: source,
|
|
||||||
line: line,
|
|
||||||
column: column,
|
|
||||||
mediaText: this.mediaText
|
|
||||||
};
|
|
||||||
if (fromSourceMap === false) {
|
|
||||||
location.source = this.parentStyleSheet;
|
|
||||||
}
|
|
||||||
if (!source) {
|
|
||||||
location.href = this.href;
|
|
||||||
}
|
|
||||||
this._originalLocation = location;
|
|
||||||
return location;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
modifySelector: protocol.custom(Task.async(function* (node, value) {
|
|
||||||
let response;
|
|
||||||
if (this.supportsModifySelectorUnmatched) {
|
|
||||||
// If the debugee supports adding unmatched rules (post FF41)
|
|
||||||
if (this.canSetRuleText) {
|
|
||||||
response = yield this.modifySelector2(node, value, true);
|
|
||||||
} else {
|
|
||||||
response = yield this.modifySelector2(node, value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
response = yield this._modifySelector(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.ruleProps) {
|
|
||||||
response.ruleProps = response.ruleProps.entries[0];
|
|
||||||
}
|
|
||||||
return response;
|
|
||||||
}), {
|
|
||||||
impl: "_modifySelector"
|
|
||||||
}),
|
|
||||||
|
|
||||||
setRuleText: protocol.custom(function(newText) {
|
|
||||||
this._form.authoredText = newText;
|
|
||||||
return this._setRuleText(newText);
|
|
||||||
}, {
|
|
||||||
impl: "_setRuleText"
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Convenience API for building a list of attribute modifications
|
|
||||||
* for the `modifyProperties` request. A RuleModificationList holds a
|
|
||||||
* list of modifications that will be applied to a StyleRuleActor.
|
|
||||||
* The modifications are processed in the order in which they are
|
|
||||||
* added to the RuleModificationList.
|
|
||||||
*
|
|
||||||
* Objects of this type expose the same API as @see RuleRewriter.
|
|
||||||
* This lets the inspector use (mostly) the same code, regardless of
|
|
||||||
* whether the server implements setRuleText.
|
|
||||||
*/
|
|
||||||
var RuleModificationList = Class({
|
|
||||||
/**
|
|
||||||
* Initialize a RuleModificationList.
|
|
||||||
* @param {StyleRuleFront} rule the associated rule
|
|
||||||
*/
|
|
||||||
initialize: function(rule) {
|
|
||||||
this.rule = rule;
|
|
||||||
this.modifications = [];
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Apply the modifications in this object to the associated rule.
|
|
||||||
*
|
|
||||||
* @return {Promise} A promise which will be resolved when the modifications
|
|
||||||
* are complete; @see StyleRuleActor.modifyProperties.
|
|
||||||
*/
|
|
||||||
apply: function() {
|
|
||||||
return this.rule.modifyProperties(this.modifications);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a "set" entry to the modification list.
|
|
||||||
*
|
|
||||||
* @param {Number} index index of the property in the rule.
|
|
||||||
* This can be -1 in the case where
|
|
||||||
* the rule does not support setRuleText;
|
|
||||||
* generally for setting properties
|
|
||||||
* on an element's style.
|
|
||||||
* @param {String} name the property's name
|
|
||||||
* @param {String} value the property's value
|
|
||||||
* @param {String} priority the property's priority, either the empty
|
|
||||||
* string or "important"
|
|
||||||
*/
|
|
||||||
setProperty: function(index, name, value, priority) {
|
|
||||||
this.modifications.push({
|
|
||||||
type: "set",
|
|
||||||
name: name,
|
|
||||||
value: value,
|
|
||||||
priority: priority
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a "remove" entry to the modification list.
|
|
||||||
*
|
|
||||||
* @param {Number} index index of the property in the rule.
|
|
||||||
* This can be -1 in the case where
|
|
||||||
* the rule does not support setRuleText;
|
|
||||||
* generally for setting properties
|
|
||||||
* on an element's style.
|
|
||||||
* @param {String} name the name of the property to remove
|
|
||||||
*/
|
|
||||||
removeProperty: function(index, name) {
|
|
||||||
this.modifications.push({
|
|
||||||
type: "remove",
|
|
||||||
name: name
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rename a property. This implementation acts like
|
|
||||||
* |removeProperty|, because |setRuleText| is not available.
|
|
||||||
*
|
|
||||||
* @param {Number} index index of the property in the rule.
|
|
||||||
* This can be -1 in the case where
|
|
||||||
* the rule does not support setRuleText;
|
|
||||||
* generally for setting properties
|
|
||||||
* on an element's style.
|
|
||||||
* @param {String} name current name of the property
|
|
||||||
*
|
|
||||||
* This parameter is also passed, but as it is not used in this
|
|
||||||
* implementation, it is omitted. It is documented here as this
|
|
||||||
* code also defined the interface implemented by @see RuleRewriter.
|
|
||||||
* @param {String} newName new name of the property
|
|
||||||
*/
|
|
||||||
renameProperty: function(index, name) {
|
|
||||||
this.removeProperty(index, name);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Enable or disable a property. This implementation acts like
|
|
||||||
* |removeProperty| when disabling, or a no-op when enabling,
|
|
||||||
* because |setRuleText| is not available.
|
|
||||||
*
|
|
||||||
* @param {Number} index index of the property in the rule.
|
|
||||||
* This can be -1 in the case where
|
|
||||||
* the rule does not support setRuleText;
|
|
||||||
* generally for setting properties
|
|
||||||
* on an element's style.
|
|
||||||
* @param {String} name current name of the property
|
|
||||||
* @param {Boolean} isEnabled true if the property should be enabled;
|
|
||||||
* false if it should be disabled
|
|
||||||
*/
|
|
||||||
setPropertyEnabled: function(index, name, isEnabled) {
|
|
||||||
if (!isEnabled) {
|
|
||||||
this.removeProperty(index, name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new property. This implementation does nothing, because
|
|
||||||
* |setRuleText| is not available.
|
|
||||||
*
|
|
||||||
* These parameter are passed, but as they are not used in this
|
|
||||||
* implementation, they are omitted. They are documented here as
|
|
||||||
* this code also defined the interface implemented by @see
|
|
||||||
* RuleRewriter.
|
|
||||||
*
|
|
||||||
* @param {Number} index index of the property in the rule.
|
|
||||||
* This can be -1 in the case where
|
|
||||||
* the rule does not support setRuleText;
|
|
||||||
* generally for setting properties
|
|
||||||
* on an element's style.
|
|
||||||
* @param {String} name name of the new property
|
|
||||||
* @param {String} value value of the new property
|
|
||||||
* @param {String} priority priority of the new property; either
|
|
||||||
* the empty string or "important"
|
|
||||||
*/
|
|
||||||
createProperty: function() {
|
|
||||||
// Nothing.
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -163,3 +163,40 @@ const pageStyleSpec = generateActorSpec({
|
||||||
});
|
});
|
||||||
|
|
||||||
exports.pageStyleSpec = pageStyleSpec;
|
exports.pageStyleSpec = pageStyleSpec;
|
||||||
|
|
||||||
|
const styleRuleSpec = generateActorSpec({
|
||||||
|
typeName: "domstylerule",
|
||||||
|
|
||||||
|
events: {
|
||||||
|
"location-changed": {
|
||||||
|
type: "locationChanged",
|
||||||
|
line: Arg(0, "number"),
|
||||||
|
column: Arg(1, "number")
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
setRuleText: {
|
||||||
|
request: { modification: Arg(0, "string") },
|
||||||
|
response: { rule: RetVal("domstylerule") }
|
||||||
|
},
|
||||||
|
modifyProperties: {
|
||||||
|
request: { modifications: Arg(0, "array:json") },
|
||||||
|
response: { rule: RetVal("domstylerule") }
|
||||||
|
},
|
||||||
|
modifySelector: {
|
||||||
|
request: { selector: Arg(0, "string") },
|
||||||
|
response: { isModified: RetVal("boolean") },
|
||||||
|
},
|
||||||
|
modifySelector2: {
|
||||||
|
request: {
|
||||||
|
node: Arg(0, "domnode"),
|
||||||
|
value: Arg(1, "string"),
|
||||||
|
editAuthored: Arg(2, "boolean")
|
||||||
|
},
|
||||||
|
response: RetVal("modifiedStylesReturn")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.styleRuleSpec = styleRuleSpec;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче