tor-browser

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

VariableTooltipHelper.js (7108B)


      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 XHTML_NS = "http://www.w3.org/1999/xhtml";
      8 
      9 const OutputParser = require("resource://devtools/client/shared/output-parser.js");
     10 loader.lazyGetter(this, "L10N", function () {
     11  const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
     12  return new LocalizationHelper(
     13    "devtools/shared/locales/styleinspector.properties"
     14  );
     15 });
     16 loader.lazyGetter(this, "L10N_EMPTY", function () {
     17  return L10N.getStr("rule.variableEmpty");
     18 });
     19 loader.lazyGetter(this, "L10N_COMPUTED_VALUE", function () {
     20  return L10N.getStr("rule.variableComputedValue");
     21 });
     22 
     23 /**
     24 * Set the tooltip content of a provided HTMLTooltip instance to display a
     25 * variable preview matching the provided text.
     26 *
     27 * @param  {HTMLTooltip} tooltip
     28 *         The tooltip instance on which the text preview content should be set.
     29 * @param  {Document} doc
     30 *         A document element to create the HTML elements needed for the tooltip.
     31 * @param  {object} params
     32 * @param  {string} params.computed
     33 *         The computed value for the variable.
     34 * @param  {object} params.outputParserOptions
     35 *         Options to pass to the OutputParser. At the moment, this is the same object that
     36 *         we use in the Rules view, so we have the same output in the variable tooltip
     37 *         than in the Rules view.
     38 * @param  {object} params.registeredProperty
     39 *         Contains the registered property data, if the variable was registered (@property or CSS.registerProperty)
     40 * @param  {string} params.registeredProperty.syntax
     41 *         The registered property `syntax` value
     42 * @param  {boolean} params.registeredProperty.inherits
     43 *         The registered property `inherits` value
     44 * @param  {string} params.registeredProperty.initialValue
     45 *         The registered property `initial-value`
     46 * @param  {string} params.startingStyle
     47 *         The text for @starting-style value (e.g. `red`)
     48 * @param  {string} params.topSectionText
     49 *         Text to display in the top section of tooltip (e.g. "blue" or "--x is not defined").
     50 * @param  {string} params.variableName
     51 *         The name of the variable we're showing the tooltip for
     52 */
     53 function setVariableTooltip(
     54  tooltip,
     55  doc,
     56  {
     57    computed,
     58    cssProperties,
     59    outputParserOptions,
     60    registeredProperty,
     61    startingStyle,
     62    topSectionText,
     63    variableName,
     64  }
     65 ) {
     66  // Create tooltip content
     67  const div = doc.createElementNS(XHTML_NS, "div");
     68  div.classList.add("devtools-monospace", "devtools-tooltip-css-variable");
     69 
     70  const outputParser = new OutputParser(doc, cssProperties);
     71  const parse = value =>
     72    outputParser.parseCssProperty(variableName, value, {
     73      ...outputParserOptions,
     74      colorSwatchReadOnly: true,
     75      // At the moment, we can't hover the tooltip, so the button couldn't be clicked/activated
     76      showJumpToVariableButton: false,
     77    });
     78 
     79  const valueEl = doc.createElementNS(XHTML_NS, "section");
     80  valueEl.classList.add("variable-value");
     81  const varData = outputParserOptions.getVariableData(variableName);
     82  // If the variable is not defined, append the text as is so we don't get the additional
     83  // class added by appendValue.
     84  if (
     85    typeof varData.value !== "string" &&
     86    typeof registeredProperty?.initialValue !== "string"
     87  ) {
     88    valueEl.append(doc.createTextNode(topSectionText));
     89  } else {
     90    appendValue(doc, valueEl, topSectionText, parse);
     91  }
     92  div.appendChild(valueEl);
     93 
     94  if (typeof computed !== "undefined") {
     95    const section = doc.createElementNS(XHTML_NS, "section");
     96    section.classList.add("computed", "variable-tooltip-section");
     97 
     98    const h2 = doc.createElementNS(XHTML_NS, "h2");
     99    h2.append(doc.createTextNode(L10N_COMPUTED_VALUE));
    100    const computedValueEl = doc.createElementNS(XHTML_NS, "div");
    101    appendValue(doc, computedValueEl, computed, parse);
    102    section.append(h2, computedValueEl);
    103 
    104    div.appendChild(section);
    105  }
    106 
    107  if (typeof startingStyle !== "undefined") {
    108    const section = doc.createElementNS(XHTML_NS, "section");
    109    section.classList.add("starting-style", "variable-tooltip-section");
    110 
    111    const h2 = doc.createElementNS(XHTML_NS, "h2");
    112    h2.append(doc.createTextNode("@starting-style"));
    113    const startingStyleValue = doc.createElementNS(XHTML_NS, "div");
    114    appendValue(doc, startingStyleValue, startingStyle, parse);
    115    section.append(h2, startingStyleValue);
    116 
    117    div.appendChild(section);
    118  }
    119 
    120  // A registered property always have a non-falsy syntax
    121  if (registeredProperty?.syntax) {
    122    const section = doc.createElementNS(XHTML_NS, "section");
    123    section.classList.add("registered-property", "variable-tooltip-section");
    124 
    125    const h2 = doc.createElementNS(XHTML_NS, "h2");
    126    h2.append(doc.createTextNode("@property"));
    127 
    128    const dl = doc.createElementNS(XHTML_NS, "dl");
    129    const addProperty = ({ label, value, parseValue, lineBreak }) => {
    130      const dt = doc.createElementNS(XHTML_NS, "dt");
    131      dt.append(doc.createTextNode(label));
    132      const dd = doc.createElementNS(XHTML_NS, "dd");
    133      appendValue(doc, dd, value, parseValue ? parse : null);
    134      dl.append(dt, dd);
    135      if (lineBreak) {
    136        dl.append(doc.createElementNS(XHTML_NS, "br"));
    137      }
    138    };
    139 
    140    const hasInitialValue = typeof registeredProperty.initialValue === "string";
    141 
    142    addProperty({
    143      label: "syntax:",
    144      value: `"${registeredProperty.syntax}"`,
    145      parseValue: false,
    146      lineBreak: true,
    147    });
    148    addProperty({
    149      label: "inherits:",
    150      value: registeredProperty.inherits,
    151      parseValue: false,
    152      lineBreak: hasInitialValue,
    153    });
    154    if (hasInitialValue) {
    155      addProperty({
    156        label: "initial-value:",
    157        value: registeredProperty.initialValue,
    158        parseValue: true,
    159        lineBreak: false,
    160      });
    161    }
    162 
    163    section.append(h2, dl);
    164    div.appendChild(section);
    165  }
    166 
    167  tooltip.panel.innerHTML = "";
    168  tooltip.panel.appendChild(div);
    169  tooltip.setContentSize({ width: "auto", height: "auto" });
    170 }
    171 
    172 /**
    173 * Append a value into the passed element.
    174 *
    175 * @param {Document} doc: A document that will be used to create elements
    176 * @param {Element} el: The element into which the rendered value will be appended
    177 * @param {string} value: The value we want to append
    178 * @param {Function} parse: An optional function that will be called with `value`, and whose
    179 *                   result will be appended to `el`. If not passed, `value` will be appended
    180 *                   as is in `el`, as a text node (if it's not empty).
    181 */
    182 function appendValue(doc, el, value, parse) {
    183  if (value !== "") {
    184    const frag = parse && parse(value);
    185    if (frag) {
    186      el.append(frag);
    187    } else {
    188      el.append(doc.createTextNode(value));
    189    }
    190    el.classList.add("theme-fg-color1");
    191  } else {
    192    el.append(doc.createTextNode(`<${L10N_EMPTY}>`));
    193    el.classList.add("empty-css-variable");
    194  }
    195 }
    196 
    197 module.exports.setVariableTooltip = setVariableTooltip;