diff options
Diffstat (limited to '')
-rw-r--r-- | devtools/client/inspector/rules/views/registered-property-editor.js | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/devtools/client/inspector/rules/views/registered-property-editor.js b/devtools/client/inspector/rules/views/registered-property-editor.js new file mode 100644 index 0000000000..d89c0fe89d --- /dev/null +++ b/devtools/client/inspector/rules/views/registered-property-editor.js @@ -0,0 +1,182 @@ +/* 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 EventEmitter = require("resource://devtools/shared/event-emitter.js"); +const { + appendText, + createChild, +} = require("resource://devtools/client/inspector/shared/utils.js"); + +const INDENT_SIZE = 2; +const INDENT_STR = " ".repeat(INDENT_SIZE); + +/** + * RegisteredPropertyEditor creates a list of TextPropertyEditors for a given + * CSS registered property propertyDefinition that can be rendered in the Rules view. + * + * @param {CssRuleView} ruleView + * The CssRuleView containg the document holding this rule editor. + * @param {Rule} rule + * The Rule object we're editing. + */ +class RegisteredPropertyEditor extends EventEmitter { + /** + * @param {CssRuleView} ruleView + * The CssRuleView containing the document holding this rule editor. + * @param {Object} propertyDefinition + * The property definition data as returned by PageStyleActor's getRegisteredProperties + */ + constructor(ruleView, propertyDefinition) { + super(); + + this.#doc = ruleView.styleDocument; + this.#propertyDefinition = propertyDefinition; + this.#createElement(); + } + + #doc; + #propertyDefinition; + // The HTMLElement that will represent the registered property. Populated in #createElement. + element = null; + + #createElement() { + this.element = this.#doc.createElement("div"); + this.element.className = "ruleview-rule devtools-monospace"; + this.element.setAttribute("uneditable", true); + this.element.setAttribute("unmatched", false); + this.element.setAttribute("data-name", this.#propertyDefinition.name); + + // Give a relative position for the inplace editor's measurement + // span to be placed absolutely against. + this.element.style.position = "relative"; + + const code = createChild(this.element, "code", { + class: "ruleview-code", + }); + + const header = createChild(code, "header", {}); + + this.propertyName = createChild(header, "span", { + class: "ruleview-registered-property-name", + textContent: this.#propertyDefinition.name, + }); + + this.openBrace = createChild(header, "span", { + class: "ruleview-ruleopen", + textContent: " {", + }); + + // We can't use a proper "ol" as it will mess with selection copy text, + // adding spaces on list item instead of the one we craft (.ruleview-rule-indent) + this.propertyList = createChild(code, "div", { + class: "ruleview-propertylist", + role: "list", + }); + + this.#populateProperties(); + + this.closeBrace = createChild(code, "div", { + class: "ruleview-ruleclose", + textContent: "}", + }); + } + + /** + * Sets the content of this.#propertyList with the contents of the registered property . + */ + #populateProperties() { + const properties = [ + { + name: "syntax", + value: `"${this.#propertyDefinition.syntax}"`, + }, + { + name: "inherits", + value: this.#propertyDefinition.inherits, + }, + ]; + + // The initial value may not be set, when syntax is "*", so let's only display + // it when it is actually set. + if (this.#propertyDefinition.initialValue !== null) { + // For JS-defined properties, we want to display them in the same syntax that + // was used in CSS.registerProperty (so we'll show `initialValue` and not `initial-value`). + properties.push({ + name: this.#propertyDefinition.fromJS + ? "initialValue" + : "initial-value", + value: this.#propertyDefinition.fromJS + ? `"${this.#propertyDefinition.initialValue}"` + : this.#propertyDefinition.initialValue, + }); + } + + // When the property is registered with CSS.registerProperty, we want to match the + // object shape of the parameter, so include the "name" property. + if (this.#propertyDefinition.fromJS) { + properties.unshift({ + name: "name", + value: `"${this.#propertyDefinition.name}"`, + }); + } + + for (const { name, value } of properties) { + // XXX: We could use the TextPropertyEditor here. + // Pros: + // - we'd get the similar markup, so styling would be easier + // - the value would be properly parsed so our various swatches and popups would work + // out of the box + // - rule view filtering would also work out of the box + // Cons: + // - it is quite tied with the Rules view regular rule, which mean we'd have + // to modify it to accept registered properties. + + const element = createChild(this.propertyList, "div", { + role: "listitem", + }); + const container = createChild(element, "div", { + class: "ruleview-propertycontainer", + }); + + createChild(container, "span", { + class: "ruleview-rule-indent clipboard-only", + textContent: INDENT_STR, + }); + + const nameContainer = createChild(container, "span", { + class: "ruleview-namecontainer", + }); + + createChild(nameContainer, "span", { + class: "ruleview-propertyname theme-fg-color3", + textContent: name, + }); + + appendText(nameContainer, ": "); + + // Create a span that will hold the property and semicolon. + // Use this span to create a slightly larger click target + // for the value. + const valueContainer = createChild(container, "span", { + class: "ruleview-propertyvaluecontainer", + }); + + // Property value, editable when focused. Changes to the + // property value are applied as they are typed, and reverted + // if the user presses escape. + createChild(valueContainer, "span", { + class: "ruleview-propertyvalue theme-fg-color1", + textContent: value, + }); + + appendText(valueContainer, this.#propertyDefinition.fromJS ? "," : ";"); + + this.propertyList.appendChild(element); + } + } +} + +module.exports = RegisteredPropertyEditor; |