summaryrefslogtreecommitdiffstats
path: root/devtools/client/fronts/style-rule.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 00:47:55 +0000
commit26a029d407be480d791972afb5975cf62c9360a6 (patch)
treef435a8308119effd964b339f76abb83a57c29483 /devtools/client/fronts/style-rule.js
parentInitial commit. (diff)
downloadfirefox-26a029d407be480d791972afb5975cf62c9360a6.tar.xz
firefox-26a029d407be480d791972afb5975cf62c9360a6.zip
Adding upstream version 124.0.1.upstream/124.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'devtools/client/fronts/style-rule.js')
-rw-r--r--devtools/client/fronts/style-rule.js310
1 files changed, 310 insertions, 0 deletions
diff --git a/devtools/client/fronts/style-rule.js b/devtools/client/fronts/style-rule.js
new file mode 100644
index 0000000000..c690e9e9e0
--- /dev/null
+++ b/devtools/client/fronts/style-rule.js
@@ -0,0 +1,310 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const {
+ FrontClassWithSpec,
+ registerFront,
+} = require("resource://devtools/shared/protocol.js");
+const {
+ styleRuleSpec,
+} = require("resource://devtools/shared/specs/style-rule.js");
+
+loader.lazyRequireGetter(
+ this,
+ "RuleRewriter",
+ "resource://devtools/client/fronts/inspector/rule-rewriter.js"
+);
+
+/**
+ * StyleRuleFront, the front for the StyleRule actor.
+ */
+class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
+ constructor(client, targetFront, parentFront) {
+ super(client, targetFront, parentFront);
+
+ this.before("location-changed", this._locationChangedPre.bind(this));
+ }
+
+ form(form) {
+ this.actorID = form.actor;
+ this._form = form;
+ this.traits = form.traits || {};
+ }
+
+ /**
+ * Ensure _form is updated when location-changed is emitted.
+ */
+ _locationChangedPre(line, column) {
+ 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.
+ *
+ * @param {CssPropertiesFront} cssProperties
+ * This is needed by the RuleRewriter.
+ * @return {RuleModificationList}
+ */
+ startModifyingProperties(cssProperties) {
+ if (this.canSetRuleText) {
+ return new RuleRewriter(cssProperties.isKnown, 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 typeof this._form.authoredText === "string"
+ ? this._form.authoredText
+ : this._form.cssText;
+ }
+ get declarations() {
+ return this._form.declarations || [];
+ }
+ get keyText() {
+ return this._form.keyText;
+ }
+ get name() {
+ return this._form.name;
+ }
+ get selectors() {
+ return this._form.selectors;
+ }
+
+ /**
+ * When a rule is nested in another non-at-rule (aka CSS Nesting), this will return
+ * the "full" selectors, which includes ancestor rules selectors.
+ * To compute it, the parent selector (&) is recursively replaced by the parent
+ * rule selector wrapped in `:is()`.
+ * For example, with the following nested rule: `body { & > main {} }`,
+ * the desugared selectors will be [`:is(body) > main`],
+ * while the "regular" selectors will only be [`main`].
+ *
+ * See https://www.w3.org/TR/css-nesting-1/#nest-selector for more information.
+ *
+ * @returns {Array<String>} An array of the desugared selectors for this rule.
+ * This falls back to the regular list of selectors
+ * when desugared selectors are not sent by the server.
+ */
+ get desugaredSelectors() {
+ // We don't send the desugaredSelectors for top-level selectors, so fall back to
+ // the regular selectors in that case.
+ return this._form.desugaredSelectors || this._form.selectors;
+ }
+
+ get selectorWarnings() {
+ return this._form.selectorWarnings;
+ }
+
+ get parentStyleSheet() {
+ const resourceCommand = this.targetFront.commands.resourceCommand;
+ return resourceCommand.getResourceById(
+ resourceCommand.TYPES.STYLESHEET,
+ this._form.parentStyleSheet
+ );
+ }
+
+ get element() {
+ return this.conn.getFrontByID(this._form.element);
+ }
+
+ get href() {
+ if (this._form.href) {
+ return this._form.href;
+ }
+ const sheet = this.parentStyleSheet;
+ return sheet ? sheet.href : "";
+ }
+
+ get nodeHref() {
+ const sheet = this.parentStyleSheet;
+ return sheet ? sheet.nodeHref : "";
+ }
+
+ 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,
+ };
+ }
+
+ get ancestorData() {
+ return this._form.ancestorData;
+ }
+
+ get userAdded() {
+ return this._form.userAdded;
+ }
+
+ async modifySelector(node, value) {
+ const response = await super.modifySelector(
+ node,
+ value,
+ this.canSetRuleText
+ );
+
+ if (response.ruleProps) {
+ response.ruleProps = response.ruleProps.entries[0];
+ }
+ return response;
+ }
+
+ setRuleText(newText, modifications) {
+ this._form.authoredText = newText;
+ return super.setRuleText(newText, modifications);
+ }
+}
+
+exports.StyleRuleFront = StyleRuleFront;
+registerFront(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.
+ */
+class RuleModificationList {
+ /**
+ * Initialize a RuleModificationList.
+ * @param {StyleRuleFront} rule the associated rule
+ */
+ constructor(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() {
+ 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(index, name, value, priority) {
+ this.modifications.push({ type: "set", index, name, value, 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(index, name) {
+ this.modifications.push({ type: "remove", index, 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(index, name) {
+ this.removeProperty(index, name);
+ }
+
+ /**
+ * Enable or disable a property. This implementation acts like
+ * 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(index, name, isEnabled) {
+ if (!isEnabled) {
+ this.modifications.push({ type: "disable", index, name });
+ }
+ }
+
+ /**
+ * Create a new property. This implementation does nothing, because
+ * |setRuleText| is not available.
+ *
+ * These parameters 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"
+ * @param {Boolean} enabled True if the new property should be
+ * enabled, false if disabled
+ */
+ createProperty() {
+ // Nothing.
+ }
+}