Bug 1422635: Implement CSS variable autocompletion. r=jdescottes
Initial support for CSS variable autocompletion in ruleview.
MozReview-Commit-ID: AlblDmyW4Iq
--- a/devtools/client/inspector/rules/views/text-property-editor.js
+++ b/devtools/client/inspector/rules/views/text-property-editor.js
@@ -311,16 +311,17 @@ TextPropertyEditor.prototype = {
advanceChars: advanceValidate,
contentType: InplaceEditor.CONTENT_TYPES.CSS_VALUE,
property: this.prop,
defaultIncrement: this.prop.name === "opacity" ? 0.1 : 1,
popup: this.popup,
multiline: true,
maxWidth: () => this.container.getBoundingClientRect().width,
cssProperties: this.cssProperties,
+ cssVariables: this.rule.elementStyle.variables,
});
this.ruleView.highlighters.on("hover-shape-point", this._onHoverShapePoint);
}
},
/**
* Get the path from which to resolve requests for this
--- a/devtools/client/shared/inplace-editor.js
+++ b/devtools/client/shared/inplace-editor.js
@@ -117,16 +117,17 @@ function isKeyIn(key, ...keys) {
* available if multiline is true. If a function is provided, it will be
* called when replacing the element by the inplace input.
* {Boolean} trimOutput: Should the returned string be trimmed?
* defaults to true
* {Boolean} preserveTextStyles: If true, do not copy text-related styles
* from `element` to the new input.
* defaults to false
* {Object} cssProperties: An instance of CSSProperties.
+ * {Object} cssVariables: A Map object containing all CSS variables.
* {Number} defaultIncrement: The value by which the input is incremented
* or decremented by default (0.1 for properties like opacity and 1 by default)
*/
function editableField(options) {
return editableItem(options, function (element, event) {
if (!options.element.inplaceEditor) {
new InplaceEditor(options, event);
}
@@ -219,16 +220,17 @@ function getInplaceEditorForSpan(span) {
exports.getInplaceEditorForSpan = getInplaceEditorForSpan;
function InplaceEditor(options, event) {
this.elt = options.element;
let doc = this.elt.ownerDocument;
this.doc = doc;
this.elt.inplaceEditor = this;
this.cssProperties = options.cssProperties;
+ this.cssVariables = options.cssVariables || new Map();
this.change = options.change;
this.done = options.done;
this.contextMenu = options.contextMenu;
this.defaultIncrement = options.defaultIncrement || 1;
this.destroy = options.destroy;
this.initial = options.initial ? options.initial : this.elt.textContent;
this.multiline = options.multiline || false;
this.maxWidth = options.maxWidth;
@@ -1328,18 +1330,26 @@ InplaceEditor.prototype = {
// Get the last query to be completed before the caret.
let match = /([^\s,.\/]+$)/.exec(query);
if (match) {
startCheckQuery = match[0];
} else {
startCheckQuery = "";
}
- list = ["!important",
- ...this._getCSSValuesForPropertyName(this.property.name)];
+ // Check if the query to be completed is a CSS variable.
+ let varMatch = /^var\(([^\s]+$)/.exec(startCheckQuery);
+
+ if (varMatch && varMatch.length == 2) {
+ startCheckQuery = varMatch[1];
+ list = this._getCSSVariableNames();
+ } else {
+ list = ["!important",
+ ...this._getCSSValuesForPropertyName(this.property.name)];
+ }
if (query == "") {
// Do not suggest '!important' without any manually typed character.
list.splice(0, 1);
}
} else if (this.contentType == CONTENT_TYPES.CSS_MIXED &&
/^\s*style\s*=/.test(query)) {
// Check if the style attribute is closed before the selection.
@@ -1485,16 +1495,25 @@ InplaceEditor.prototype = {
* mocked suggestion lists.
*
* @param {String} propertyName
* @return {Array} array of CSS property values (Strings)
*/
_getCSSValuesForPropertyName: function (propertyName) {
return this.cssProperties.getValues(propertyName);
},
+
+ /**
+ * Returns the list of all CSS variables to use for the autocompletion.
+ *
+ * @return {Array} array of CSS variable names (Strings)
+ */
+ _getCSSVariableNames: function () {
+ return Array.from(this.cssVariables.keys()).sort();
+ },
};
/**
* Copy text-related styles from one element to another.
*/
function copyTextStyles(from, to) {
let win = from.ownerDocument.defaultView;
let style = win.getComputedStyle(from);