Source code

Revision control

Copy as Markdown

Other Tools

/* 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 XHTML_NS = "http://www.w3.org/1999/xhtml";
const OutputParser = require("resource://devtools/client/shared/output-parser.js");
loader.lazyGetter(this, "L10N", function () {
const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
return new LocalizationHelper(
"devtools/shared/locales/styleinspector.properties"
);
});
loader.lazyGetter(this, "L10N_EMPTY", function () {
return L10N.getStr("rule.variableEmpty");
});
loader.lazyGetter(this, "L10N_COMPUTED_VALUE", function () {
return L10N.getStr("rule.variableComputedValue");
});
/**
* Set the tooltip content of a provided HTMLTooltip instance to display a
* variable preview matching the provided text.
*
* @param {HTMLTooltip} tooltip
* The tooltip instance on which the text preview content should be set.
* @param {Document} doc
* A document element to create the HTML elements needed for the tooltip.
* @param {Object} params
* @param {String} params.computed
* The computed value for the variable.
* @param {Object} params.outputParserOptions
* Options to pass to the OutputParser. At the moment, this is the same object that
* we use in the Rules view, so we have the same output in the variable tooltip
* than in the Rules view.
* @param {Object} params.registeredProperty
* Contains the registered property data, if the variable was registered (@property or CSS.registerProperty)
* @param {String} params.registeredProperty.syntax
* The registered property `syntax` value
* @param {Boolean} params.registeredProperty.inherits
* The registered property `inherits` value
* @param {String} params.registeredProperty.initialValue
* The registered property `initial-value`
* @param {String} params.startingStyle
* The text for @starting-style value (e.g. `red`)
* @param {String} params.topSectionText
* Text to display in the top section of tooltip (e.g. "blue" or "--x is not defined").
* @param {String} params.variableName
* The name of the variable we're showing the tooltip for
*/
function setVariableTooltip(
tooltip,
doc,
{
computed,
cssProperties,
outputParserOptions,
registeredProperty,
startingStyle,
topSectionText,
variableName,
}
) {
// Create tooltip content
const div = doc.createElementNS(XHTML_NS, "div");
div.classList.add("devtools-monospace", "devtools-tooltip-css-variable");
const outputParser = new OutputParser(doc, cssProperties);
const parse = value =>
outputParser.parseCssProperty(variableName, value, {
...outputParserOptions,
colorSwatchReadOnly: true,
});
const valueEl = doc.createElementNS(XHTML_NS, "section");
valueEl.classList.add("variable-value");
const varData = outputParserOptions.getVariableData(variableName);
// If the variable is not defined, append the text as is so we don't get the additional
// class added by appendValue.
if (
typeof varData.value !== "string" &&
typeof registeredProperty?.initialValue !== "string"
) {
valueEl.append(doc.createTextNode(topSectionText));
} else {
appendValue(doc, valueEl, topSectionText, parse);
}
div.appendChild(valueEl);
if (typeof computed !== "undefined") {
const section = doc.createElementNS(XHTML_NS, "section");
section.classList.add("computed", "variable-tooltip-section");
const h2 = doc.createElementNS(XHTML_NS, "h2");
h2.append(doc.createTextNode(L10N_COMPUTED_VALUE));
const computedValueEl = doc.createElementNS(XHTML_NS, "div");
appendValue(doc, computedValueEl, computed, parse);
section.append(h2, computedValueEl);
div.appendChild(section);
}
if (typeof startingStyle !== "undefined") {
const section = doc.createElementNS(XHTML_NS, "section");
section.classList.add("starting-style", "variable-tooltip-section");
const h2 = doc.createElementNS(XHTML_NS, "h2");
h2.append(doc.createTextNode("@starting-style"));
const startingStyleValue = doc.createElementNS(XHTML_NS, "div");
appendValue(doc, startingStyleValue, startingStyle, parse);
section.append(h2, startingStyleValue);
div.appendChild(section);
}
// A registered property always have a non-falsy syntax
if (registeredProperty?.syntax) {
const section = doc.createElementNS(XHTML_NS, "section");
section.classList.add("registered-property", "variable-tooltip-section");
const h2 = doc.createElementNS(XHTML_NS, "h2");
h2.append(doc.createTextNode("@property"));
const dl = doc.createElementNS(XHTML_NS, "dl");
const addProperty = ({ label, value, parseValue, lineBreak }) => {
const dt = doc.createElementNS(XHTML_NS, "dt");
dt.append(doc.createTextNode(label));
const dd = doc.createElementNS(XHTML_NS, "dd");
appendValue(doc, dd, value, parseValue ? parse : null);
dl.append(dt, dd);
if (lineBreak) {
dl.append(doc.createElementNS(XHTML_NS, "br"));
}
};
const hasInitialValue = typeof registeredProperty.initialValue === "string";
addProperty({
label: "syntax:",
value: `"${registeredProperty.syntax}"`,
parseValue: false,
lineBreak: true,
});
addProperty({
label: "inherits:",
value: registeredProperty.inherits,
parseValue: false,
lineBreak: hasInitialValue,
});
if (hasInitialValue) {
addProperty({
label: "initial-value:",
value: registeredProperty.initialValue,
parseValue: true,
lineBreak: false,
});
}
section.append(h2, dl);
div.appendChild(section);
}
tooltip.panel.innerHTML = "";
tooltip.panel.appendChild(div);
tooltip.setContentSize({ width: "auto", height: "auto" });
}
/**
* Append a value into the passed element.
*
* @param {Document} doc: A document that will be used to create elements
* @param {Element} el: The element into which the rendered value will be appended
* @param {String} value: The value we want to append
* @param {Function} parse: An optional function that will be called with `value`, and whose
* result will be appended to `el`. If not passed, `value` will be appended
* as is in `el`, as a text node (if it's not empty).
*/
function appendValue(doc, el, value, parse) {
if (value !== "") {
const frag = parse && parse(value);
if (frag) {
el.append(frag);
} else {
el.append(doc.createTextNode(value));
}
el.classList.add("theme-fg-color1");
} else {
el.append(doc.createTextNode(`<${L10N_EMPTY}>`));
el.classList.add("empty-css-variable");
}
}
module.exports.setVariableTooltip = setVariableTooltip;