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