tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

style-rule.js (10117B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  FrontClassWithSpec,
      9  registerFront,
     10 } = require("resource://devtools/shared/protocol.js");
     11 const {
     12  styleRuleSpec,
     13 } = require("resource://devtools/shared/specs/style-rule.js");
     14 
     15 loader.lazyRequireGetter(
     16  this,
     17  "RuleRewriter",
     18  "resource://devtools/client/fronts/inspector/rule-rewriter.js"
     19 );
     20 
     21 /**
     22 * StyleRuleFront, the front for the StyleRule actor.
     23 */
     24 class StyleRuleFront extends FrontClassWithSpec(styleRuleSpec) {
     25  constructor(client, targetFront, parentFront) {
     26    super(client, targetFront, parentFront);
     27 
     28    this.before("location-changed", this._locationChangedPre.bind(this));
     29  }
     30 
     31  form(form) {
     32    this.actorID = form.actor;
     33    this._form = form;
     34    this.traits = form.traits || {};
     35  }
     36 
     37  /**
     38   * Ensure _form is updated when location-changed is emitted.
     39   */
     40  _locationChangedPre(line, column) {
     41    this._form.line = line;
     42    this._form.column = column;
     43  }
     44 
     45  /**
     46   * Return a new RuleModificationList or RuleRewriter for this node.
     47   * A RuleRewriter will be returned when the rule's canSetRuleText
     48   * trait is true; otherwise a RuleModificationList will be
     49   * returned.
     50   *
     51   * @param {Window} win
     52   *                 This is needed by the RuleRewriter.
     53   * @param {CssPropertiesFront} cssProperties
     54   *                             This is needed by the RuleRewriter.
     55   * @return {RuleModificationList}
     56   */
     57  startModifyingProperties(win, cssProperties) {
     58    if (this.canSetRuleText) {
     59      return new RuleRewriter(
     60        win,
     61        cssProperties.isKnown,
     62        this,
     63        this.authoredText
     64      );
     65    }
     66    return new RuleModificationList(this);
     67  }
     68 
     69  get type() {
     70    return this._form.type;
     71  }
     72  get className() {
     73    return this._form.className;
     74  }
     75  get line() {
     76    return this._form.line || -1;
     77  }
     78  get column() {
     79    return this._form.column || -1;
     80  }
     81  get cssText() {
     82    return this._form.cssText;
     83  }
     84  get isNestedDeclarations() {
     85    return !!this._form.isNestedDeclarations;
     86  }
     87  get authoredText() {
     88    return typeof this._form.authoredText === "string"
     89      ? this._form.authoredText
     90      : this._form.cssText;
     91  }
     92  get declarations() {
     93    return this._form.declarations || [];
     94  }
     95  get keyText() {
     96    return this._form.keyText;
     97  }
     98  get name() {
     99    return this._form.name;
    100  }
    101  get selectors() {
    102    return this._form.selectors;
    103  }
    104  get selectorsSpecificity() {
    105    return this._form.selectorsSpecificity;
    106  }
    107 
    108  /**
    109   * Returns a concatenation of the rule's selector and all its ancestor "selectors".
    110   * This is different from a "desugared" selector as what's returned is not an
    111   * actual selector, but some kind of key that represent the rule selectors.
    112   * This is used for the selector highlighter, where we need to know what's
    113   * being highlighted.
    114   *
    115   * @returns {string}
    116   */
    117  get computedSelector() {
    118    let selector = "";
    119    for (const ancestor of this.ancestorData) {
    120      let ancestorSelector;
    121      if (ancestor.selectors) {
    122        ancestorSelector = ancestor.selectors.join(",");
    123      } else if (ancestor.type === "container") {
    124        ancestorSelector =
    125          ancestor.containerName + " " + ancestor.containerQuery;
    126      } else if (ancestor.type === "supports") {
    127        ancestorSelector = ancestor.conditionText;
    128      } else if (ancestor.value) {
    129        ancestorSelector = ancestor.value;
    130      }
    131      selector +=
    132        "/" + (ancestor.type ? ancestor.type + " " : "") + ancestorSelector;
    133    }
    134 
    135    return (selector ? selector + "/" : "") + this._form.selectors.join(",");
    136  }
    137 
    138  get selectorWarnings() {
    139    return this._form.selectorWarnings;
    140  }
    141 
    142  get parentStyleSheet() {
    143    const resourceCommand = this.targetFront.commands.resourceCommand;
    144    return resourceCommand.getResourceById(
    145      resourceCommand.TYPES.STYLESHEET,
    146      this._form.parentStyleSheet
    147    );
    148  }
    149 
    150  get element() {
    151    return this.conn.getFrontByID(this._form.element);
    152  }
    153 
    154  get href() {
    155    if (this._form.href) {
    156      return this._form.href;
    157    }
    158    const sheet = this.parentStyleSheet;
    159    return sheet ? sheet.href : "";
    160  }
    161 
    162  get nodeHref() {
    163    const sheet = this.parentStyleSheet;
    164    return sheet ? sheet.nodeHref : "";
    165  }
    166 
    167  get canSetRuleText() {
    168    return this._form.traits && this._form.traits.canSetRuleText;
    169  }
    170 
    171  get location() {
    172    return {
    173      source: this.parentStyleSheet,
    174      href: this.href,
    175      line: this.line,
    176      column: this.column,
    177    };
    178  }
    179 
    180  get ancestorData() {
    181    return this._form.ancestorData;
    182  }
    183 
    184  get userAdded() {
    185    return this._form.userAdded;
    186  }
    187 
    188  async modifySelector(node, value) {
    189    const response = await super.modifySelector(
    190      node,
    191      value,
    192      this.canSetRuleText
    193    );
    194 
    195    if (response.ruleProps) {
    196      response.ruleProps = response.ruleProps.entries[0];
    197    }
    198    return response;
    199  }
    200 
    201  setRuleText(newText, modifications) {
    202    this._form.authoredText = newText;
    203    return super.setRuleText(newText, modifications);
    204  }
    205 }
    206 
    207 registerFront(StyleRuleFront);
    208 
    209 /**
    210 * Convenience API for building a list of attribute modifications
    211 * for the `modifyProperties` request.  A RuleModificationList holds a
    212 * list of modifications that will be applied to a StyleRuleActor.
    213 * The modifications are processed in the order in which they are
    214 * added to the RuleModificationList.
    215 *
    216 * Objects of this type expose the same API as @see RuleRewriter.
    217 * This lets the inspector use (mostly) the same code, regardless of
    218 * whether the server implements setRuleText.
    219 */
    220 class RuleModificationList {
    221  /**
    222   * Initialize a RuleModificationList.
    223   *
    224   * @param {StyleRuleFront} rule the associated rule
    225   */
    226  constructor(rule) {
    227    this.rule = rule;
    228    this.modifications = [];
    229  }
    230 
    231  /**
    232   * Apply the modifications in this object to the associated rule.
    233   *
    234   * @return {Promise} A promise which will be resolved when the modifications
    235   *         are complete; @see StyleRuleActor.modifyProperties.
    236   */
    237  apply() {
    238    return this.rule.modifyProperties(this.modifications);
    239  }
    240 
    241  /**
    242   * Add a "set" entry to the modification list.
    243   *
    244   * @param {number} index index of the property in the rule.
    245   *                       This can be -1 in the case where
    246   *                       the rule does not support setRuleText;
    247   *                       generally for setting properties
    248   *                       on an element's style.
    249   * @param {string} name the property's name
    250   * @param {string} value the property's value
    251   * @param {string} priority the property's priority, either the empty
    252   *                          string or "important"
    253   */
    254  setProperty(index, name, value, priority) {
    255    this.modifications.push({ type: "set", index, name, value, priority });
    256  }
    257 
    258  /**
    259   * Add a "remove" entry to the modification list.
    260   *
    261   * @param {number} index index of the property in the rule.
    262   *                       This can be -1 in the case where
    263   *                       the rule does not support setRuleText;
    264   *                       generally for setting properties
    265   *                       on an element's style.
    266   * @param {string} name the name of the property to remove
    267   */
    268  removeProperty(index, name) {
    269    this.modifications.push({ type: "remove", index, name });
    270  }
    271 
    272  /**
    273   * Rename a property.  This implementation acts like
    274   * |removeProperty|, because |setRuleText| is not available.
    275   *
    276   * @param {number} index index of the property in the rule.
    277   *                       This can be -1 in the case where
    278   *                       the rule does not support setRuleText;
    279   *                       generally for setting properties
    280   *                       on an element's style.
    281   * @param {string} name current name of the property
    282   *
    283   * This parameter is also passed, but as it is not used in this
    284   * implementation, it is omitted.  It is documented here as this
    285   * code also defined the interface implemented by @see RuleRewriter.
    286   * @param {string} newName new name of the property
    287   */
    288  renameProperty(index, name) {
    289    this.removeProperty(index, name);
    290  }
    291 
    292  /**
    293   * Enable or disable a property.  This implementation acts like
    294   * a no-op when enabling, because |setRuleText| is not available.
    295   *
    296   * @param {number} index index of the property in the rule.
    297   *                       This can be -1 in the case where
    298   *                       the rule does not support setRuleText;
    299   *                       generally for setting properties
    300   *                       on an element's style.
    301   * @param {string} name current name of the property
    302   * @param {boolean} isEnabled true if the property should be enabled;
    303   *                        false if it should be disabled
    304   */
    305  setPropertyEnabled(index, name, isEnabled) {
    306    if (!isEnabled) {
    307      this.modifications.push({ type: "disable", index, name });
    308    }
    309  }
    310 
    311  /**
    312   * Create a new property.  This implementation does nothing, because
    313   * |setRuleText| is not available.
    314   *
    315   * These parameters are passed, but as they are not used in this
    316   * implementation, they are omitted.  They are documented here as
    317   * this code also defined the interface implemented by @see
    318   * RuleRewriter.
    319   *
    320   * @param {number} index index of the property in the rule.
    321   *                       This can be -1 in the case where
    322   *                       the rule does not support setRuleText;
    323   *                       generally for setting properties
    324   *                       on an element's style.
    325   * @param {string} name name of the new property
    326   * @param {string} value value of the new property
    327   * @param {string} priority priority of the new property; either
    328   *                          the empty string or "important"
    329   * @param {boolean} enabled True if the new property should be
    330   *                          enabled, false if disabled
    331   */
    332  createProperty() {
    333    // Nothing.
    334  }
    335 }