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

Impressum css-logic.js   Interaktion und
PortierbarkeitJAVA

 
/* 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 MAX_DATA_URL_LENGTH = 40;
/**
 * Provide access to the style information in a page.
 * CssLogic uses the standard DOM API, and the Gecko InspectorUtils API to
 * access styling information in the page, and present this to the user in a way
 * that helps them understand:
 * - why their expectations may not have been fulfilled
 * - how browsers process CSS
 * @constructor
 */


loader.lazyRequireGetter(
  this,
  "InspectorCSSParserWrapper",
  "resource://devtools/shared/css/lexer.js",
  true
);
loader.lazyRequireGetter(
  this,
  "getTabPrefs",
  "resource://devtools/shared/indentation.js",
  true
);
const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
const styleInspectorL10N = new LocalizationHelper(
  "devtools/shared/locales/styleinspector.properties"
);

/**
 * Special values for filter, in addition to an href these values can be used
 */

exports.FILTER = {
  // show properties for all user style sheets.
  USER: "user",
  // USER, plus user-agent (i.e. browser) style sheets
  UA: "ua",
};

/**
 * Each rule has a status, the bigger the number, the better placed it is to
 * provide styling information.
 *
 * These statuses are localized inside the styleinspector.properties
 * string bundle.
 * @see csshtmltree.js RuleView._cacheStatusNames()
 */

exports.STATUS = {
  BEST: 3,
  MATCHED: 2,
  PARENT_MATCH: 1,
  UNMATCHED: 0,
  UNKNOWN: -1,
};

/**
 * Mapping of CSS at-Rule className to CSSRule type name.
 */

exports.CSSAtRuleClassNameType = {
  CSSContainerRule: "container",
  CSSCounterStyleRule: "counter-style",
  CSSDocumentRule: "document",
  CSSFontFaceRule: "font-face",
  CSSFontFeatureValuesRule: "font-feature-values",
  CSSImportRule: "import",
  CSSKeyframeRule: "keyframe",
  CSSKeyframesRule: "keyframes",
  CSSLayerBlockRule: "layer",
  CSSMediaRule: "media",
  CSSNamespaceRule: "namespace",
  CSSPageRule: "page",
  CSSScopeRule: "scope",
  CSSStartingStyleRule: "starting-style",
  CSSSupportsRule: "supports",
};

/**
 * Get Rule type as human-readable string (ex: "@media", "@container", …)
 *
 * @param {CSSRule} cssRule
 * @returns {String}
 */

exports.getCSSAtRuleTypeName = function (cssRule) {
  const ruleClassName = ChromeUtils.getClassName(cssRule);
  const atRuleTypeName = exports.CSSAtRuleClassNameType[ruleClassName];
  if (atRuleTypeName) {
    return "@" + atRuleTypeName;
  }

  return "";
};

/**
 * Lookup a l10n string in the shared styleinspector string bundle.
 *
 * @param {String} name
 *        The key to lookup.
 * @returns {String} A localized version of the given key.
 */

exports.l10n = name => styleInspectorL10N.getStr(name);
exports.l10nFormatStr = (name, ...args) =>
  styleInspectorL10N.getFormatStr(name, ...args);

/**
 * Is the given property sheet an author stylesheet?
 *
 * @param {CSSStyleSheet} sheet a stylesheet
 * @return {boolean} true if the given stylesheet is an author stylesheet,
 * false otherwise.
 */

exports.isAuthorStylesheet = function (sheet) {
  return sheet.parsingMode === "author";
};

/**
 * Is the given property sheet a user stylesheet?
 *
 * @param {CSSStyleSheet} sheet a stylesheet
 * @return {boolean} true if the given stylesheet is a user stylesheet,
 * false otherwise.
 */

exports.isUserStylesheet = function (sheet) {
  return sheet.parsingMode === "user";
};

/**
 * Is the given property sheet a agent stylesheet?
 *
 * @param {CSSStyleSheet} sheet a stylesheet
 * @return {boolean} true if the given stylesheet is a agent stylesheet,
 * false otherwise.
 */

exports.isAgentStylesheet = function (sheet) {
  return sheet.parsingMode === "agent";
};

/**
 * Return a shortened version of a style sheet's source.
 *
 * @param {CSSStyleSheet} sheet the DOM object for the style sheet.
 */

exports.shortSource = function (sheet) {
  if (!sheet) {
    return exports.l10n("rule.sourceInline");
  }

  if (!sheet.href) {
    return exports.l10n(
      sheet.constructed ? "rule.sourceConstructed" : "rule.sourceInline"
    );
  }

  let name = sheet.href;

  // If the sheet is a data URL, return a trimmed version of it.
  const dataUrl = sheet.href.trim().match(/^data:.*?,((?:.|\r|\n)*)$/);
  if (dataUrl) {
    name =
      dataUrl[1].length > MAX_DATA_URL_LENGTH
        ? `${dataUrl[1].substr(0, MAX_DATA_URL_LENGTH - 1)}…`
        : dataUrl[1];
  } else {
    // We try, in turn, the filename, filePath, query string, whole thing
    let url = {};
    try {
      url = new URL(sheet.href);
    } catch (ex) {
      // Some UA-provided stylesheets are not valid URLs.
    }

    if (url.pathname) {
      const index = url.pathname.lastIndexOf("/");
      if (index !== -1 && index < url.pathname.length) {
        name = url.pathname.slice(index + 1);
      } else {
        name = url.pathname;
      }
    } else if (url.query) {
      name = url.query;
    }
  }

  try {
    name = decodeURIComponent(name);
  } catch (e) {
    // This may still fail if the URL contains invalid % numbers (for ex)
  }

  return name;
};

/**
 * Return the style sheet's source, handling element, inline and constructed stylesheets.
 *
 * @param {CSSStyleSheet} sheet the DOM object for the style sheet.
 */

exports.longSource = function (sheet) {
  if (!sheet) {
    return exports.l10n("rule.sourceInline");
  }

  if (!sheet.href) {
    return exports.l10n(
      sheet.constructed ? "rule.sourceConstructed" : "rule.sourceInline"
    );
  }

  return sheet.href;
};

const TAB_CHARS = "\t";
const SPACE_CHARS = " ";

function getLineCountInComments(text) {
  let count = 0;

  for (const comment of text.match(/\/\*(?:.|\n)*?\*\//gm) || []) {
    count += comment.split("\n").length + 1;
  }

  return count;
}

/**
 * Prettify minified CSS text.
 * This prettifies CSS code where there is no indentation in usual places while
 * keeping original indentation as-is elsewhere.
 *
 * Returns an object with the resulting prettified source and a list of mappings of
 * token positions between the original and the prettified source. Each single mapping
 * is an object that looks like this:
 *
 * {
 *  original: {line: {Number}, column: {Number}},
 *  generated: {line: {Number}, column: {Number}},
 * }
 *
 * @param  {String} text
 *         The CSS source to prettify.
 * @param  {Number} ruleCount
 *         The number of CSS rules expected in the CSS source.
 *         Set to null to force the text to be pretty-printed.
 *
 * @return {Object}
 *         Object with the prettified source and source mappings.
 *          {
 *            result: {String}  // Prettified source
 *            mappings: {Array} // List of objects with mappings for lines and columns
 *                              // between the original source and prettified source
 *          }
 */

// eslint-disable-next-line complexity
function prettifyCSS(text, ruleCount) {
  if (prettifyCSS.LINE_SEPARATOR == null) {
    const os = Services.appinfo.OS;
    prettifyCSS.LINE_SEPARATOR = os === "WINNT" ? "\r\n" : "\n";
  }

  // Stylesheets may start and end with HTML comment tags (possibly with whitespaces
  // before and after). Remove those first. Don't do anything there aren't any.
  const trimmed = text.trim();
  if (trimmed.startsWith("