Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/client/inspector/changes/selectors/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 8 kB image not shown  

Quelle  changes.js   Sprache: JAVA

 
/* 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";

loader.lazyRequireGetter(
  this,
  "getTabPrefs",
  "resource://devtools/shared/indentation.js",
  true
);

const {
  getSourceForDisplay,
} = require("resource://devtools/client/inspector/changes/utils/changes-utils.js");

/**
 * In the Redux state, changed CSS rules are grouped by source (stylesheet) and stored in
 * a single level array, regardless of nesting.
 * This method returns a nested tree structure of the changed CSS rules so the React
 * consumer components can traverse it easier when rendering the nested CSS rules view.
 * Keeping this interface updated allows the Redux state structure to change without
 * affecting the consumer components.
 *
 * @param {Object} state
 *        Redux slice for tracked changes.
 * @param {Object} filter
 *        Object with optional filters to use. Has the following properties:
 *        - sourceIds: {Array}
 *          Use only subtrees of sources matching source ids from this array.
 *        - ruleIds: {Array}
 *          Use only rules matching rule ids from this array. If the array includes ids
 *          of ancestor rules (@media, @supports), their nested rules will be included.
 * @return {Object}
 */

function getChangesTree(state, filter = {}) {
  // Use or assign defaults of sourceId and ruleId arrays by which to filter the tree.
  const { sourceIds: sourceIdsFilter = [], ruleIds: rulesIdsFilter = [] } =
    filter;
  /**
   * Recursively replace a rule's array of child rule ids with the referenced child rules.
   * Mark visited rules so as not to handle them (and their children) again.
   *
   * Returns the rule object with expanded children or null if previously visited.
   *
   * @param  {String} ruleId
   * @param  {Object} rule
   * @param  {Array} rules
   * @param  {Set} visitedRules
   * @return {Object|null}
   */

  function expandRuleChildren(ruleId, rule, rules, visitedRules) {
    if (visitedRules.has(ruleId)) {
      return null;
    }

    visitedRules.add(ruleId);

    return {
      ...rule,
      children: rule.children.map(childRuleId =>
        expandRuleChildren(childRuleId, rules[childRuleId], rules, visitedRules)
      ),
    };
  }

  return Object.entries(state)
    .filter(([sourceId]) => {
      // Use only matching sources if an array to filter by was provided.
      if (sourceIdsFilter.length) {
        return sourceIdsFilter.includes(sourceId);
      }

      return true;
    })
    .reduce((sourcesObj, [sourceId, source]) => {
      const { rules } = source;
      // Log of visited rules in this source. Helps avoid duplication when traversing the
      // descendant rule tree. This Set is unique per source. It will be passed down to
      // be populated with ids of rules once visited. This ensures that only visited rules
      // unique to this source will be skipped and prevents skipping identical rules from
      // other sources (ex: rules with the same selector and the same index).
      const visitedRules = new Set();

      // Build a new collection of sources keyed by source id.
      sourcesObj[sourceId] = {
        ...source,
        // Build a new collection of rules keyed by rule id.
        rules: Object.entries(rules)
          .filter(([ruleId]) => {
            // Use only matching rules if an array to filter by was provided.
            if (rulesIdsFilter.length) {
              return rulesIdsFilter.includes(ruleId);
            }

            return true;
          })
          .reduce((rulesObj, [ruleId, rule]) => {
            // Expand the rule's array of child rule ids with the referenced child rules.
            // Skip exposing null values which mean the rule was previously visited
            // as part of an ancestor descendant tree.
            const expandedRule = expandRuleChildren(
              ruleId,
              rule,
              rules,
              visitedRules
            );
            if (expandedRule !== null) {
              rulesObj[ruleId] = expandedRule;
            }

            return rulesObj;
          }, {}),
      };

      return sourcesObj;
    }, {});
}

/**
 * Build the CSS text of a stylesheet with the changes aggregated in the Redux state.
 * If filters for rule id or source id are provided, restrict the changes to the matching
 * sources and rules.
 *
 * Code comments with the source origin are put above of the CSS rule (or group of
 * rules). Removed CSS declarations are written commented out. Added CSS declarations are
 * written as-is.
 *
 * @param  {Object} state
 *         Redux slice for tracked changes.
 * @param  {Object} filter
 *         Object with optional source and rule filters. See getChangesTree()
 * @return {String}
 *         CSS stylesheet text.
 */


// For stylesheet sources, the stylesheet filename and full path are used:
//
// /* styles.css | https://example.com/styles.css */
//
// .selector {
//  /* property: oldvalue; */
//  property: value;
// }

// For inline stylesheet sources, the stylesheet index and host document URL are used:
//
// /* Inline #1 | https://example.com */
//
// .selector {
//  /* property: oldvalue; */
//  property: value;
// }

// For element style attribute sources, the unique selector generated for the element
// and the host document URL are used:
//
// /* Element (div) | https://example.com */
//
// div:nth-child(1) {
//  /* property: oldvalue; */
//  property: value;
// }
function getChangesStylesheet(state, filter) {
  const changeTree = getChangesTree(state, filter);
  // Get user prefs about indentation style.
  const { indentUnit, indentWithTabs } = getTabPrefs();
  const indentChar = indentWithTabs
    ? "\t".repeat(indentUnit)
    : " ".repeat(indentUnit);

  /**
   * If the rule has just one item in its array of selector versions, return it as-is.
   * If it has more than one, build a string using the first selector commented-out
   * and the last selector as-is. This indicates that a rule's selector has changed.
   *
   * @param  {Array} selectors
   *         History of selector versions if changed over time.
   *         Array with a single item (the original selector) if never changed.
   * @param  {Number} level
   *         Level of nesting within a CSS rule tree.
   * @return {String}
   */

  function writeSelector(selectors = [], level) {
    const indent = indentChar.repeat(level);
    let selectorText;
    switch (selectors.length) {
      case 0:
        selectorText = "";
        break;
      case 1:
        selectorText = `${indent}${selectors[0]}`;
        break;
      default:
        selectorText =
          `${indent}/* ${selectors[0]} { */\n` +
          `${indent}${selectors[selectors.length - 1]}`;
    }

    return selectorText;
  }

  function writeRule(ruleId, rule, level) {
    // Write nested rules, if any.
    let ruleBody = rule.children.reduce((str, childRule) => {
      str += writeRule(childRule.ruleId, childRule, level + 1);
      return str;
    }, "");

    // Write changed CSS declarations.
    ruleBody += writeDeclarations(rule.remove, rule.add, level + 1);

    const indent = indentChar.repeat(level);
    const selectorText = writeSelector(rule.selectors, level);
    return `\n${selectorText} {${ruleBody}\n${indent}}`;
  }

  function writeDeclarations(remove = [], add = [], level) {
    const indent = indentChar.repeat(level);
    const removals = remove
      // Sort declarations in the order in which they exist in the original CSS rule.
      .sort((a, b) => a.index > b.index)
      .reduce((str, { property, value }) => {
        str += `\n${indent}/* ${property}: ${value}; */`;
        return str;
      }, "");

    const additions = add
      // Sort declarations in the order in which they exist in the original CSS rule.
      .sort((a, b) => a.index > b.index)
      .reduce((str, { property, value }) => {
        str += `\n${indent}${property}: ${value};`;
        return str;
      }, "");

    return removals + additions;
  }

  // Iterate through all sources in the change tree and build a CSS stylesheet string.
  return Object.values(changeTree).reduce((stylesheetText, source) => {
    const { href, rules } = source;
    // Write code comment with source origin
    stylesheetText += `\n/* ${getSourceForDisplay(source)} | ${href} */\n`;
    // Write CSS rules
    stylesheetText += Object.entries(rules).reduce((str, [ruleId, rule]) => {
      // Add a new like only after top-level rules (level == 0)
      str += writeRule(ruleId, rule, 0) + "\n";
      return str;
    }, "");

    return stylesheetText;
  }, "");
}

module.exports = {
  getChangesTree,
  getChangesStylesheet,
};

Messung V0.5
C=90 H=97 G=93

¤ Dauer der Verarbeitung: 0.7 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.