css-properties.js (6006B)
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 { 8 FrontClassWithSpec, 9 registerFront, 10 } = require("resource://devtools/shared/protocol.js"); 11 const { 12 cssPropertiesSpec, 13 } = require("resource://devtools/shared/specs/css-properties.js"); 14 15 loader.lazyRequireGetter( 16 this, 17 "cssColors", 18 "resource://devtools/shared/css/color-db.js", 19 true 20 ); 21 loader.lazyRequireGetter( 22 this, 23 "CSS_TYPES", 24 "resource://devtools/shared/css/constants.js", 25 true 26 ); 27 loader.lazyRequireGetter( 28 this, 29 "isCssVariable", 30 "resource://devtools/shared/inspector/css-logic.js", 31 true 32 ); 33 34 /** 35 * The CssProperties front provides a mechanism to have a one-time asynchronous 36 * load of a CSS properties database. This is then fed into the CssProperties 37 * interface that provides synchronous methods for finding out what CSS 38 * properties the current server supports. 39 */ 40 class CssPropertiesFront extends FrontClassWithSpec(cssPropertiesSpec) { 41 constructor(client, targetFront) { 42 super(client, targetFront); 43 44 // Attribute name from which to retrieve the actorID out of the target actor's form 45 this.formAttributeName = "cssPropertiesActor"; 46 } 47 48 async initialize() { 49 const db = await super.getCSSDatabase(); 50 this.cssProperties = new CssProperties(normalizeCssData(db)); 51 } 52 53 destroy() { 54 this.cssProperties = null; 55 super.destroy(); 56 } 57 } 58 59 /** 60 * Ask questions to a CSS database. This class does not care how the database 61 * gets loaded in, only the questions that you can ask to it. 62 * Prototype functions are bound to 'this' so they can be passed around as helper 63 * functions. 64 * 65 */ 66 class CssProperties { 67 /** 68 * @param {object} db 69 * A database of CSS properties 70 * @param {object} inheritedList 71 * The key is the property name, the value is whether or not 72 * that property is inherited. 73 */ 74 constructor(db) { 75 this.properties = db.properties; 76 77 this.isKnown = this.isKnown.bind(this); 78 this.isInherited = this.isInherited.bind(this); 79 this.supportsType = this.supportsType.bind(this); 80 } 81 /** 82 * Checks to see if the property is known by the browser. This function has 83 * `this` already bound so that it can be passed around by reference. 84 * 85 * @param {string} property The property name to be checked. 86 * @return {boolean} 87 */ 88 isKnown(property) { 89 // Custom Property Names (aka CSS Variables) are case-sensitive; do not lowercase. 90 property = property.startsWith("--") ? property : property.toLowerCase(); 91 return !!this.properties[property] || isCssVariable(property); 92 } 93 94 /** 95 * Checks to see if the property is an inherited one. 96 * 97 * @param {string} property The property name to be checked. 98 * @return {boolean} 99 */ 100 isInherited(property) { 101 return this.properties[property]?.isInherited; 102 } 103 104 /** 105 * Checks if the property supports the given CSS type. 106 * 107 * @param {string} property The property to be checked. 108 * @param {string} type One of the values from InspectorPropertyType. 109 * @return {boolean} 110 */ 111 supportsType(property, type) { 112 const id = CSS_TYPES[type]; 113 return ( 114 this.properties[property] && 115 (this.properties[property].supports.includes(type) || 116 this.properties[property].supports.includes(id)) 117 ); 118 } 119 120 /** 121 * Gets the CSS values for a given property name. 122 * 123 * @param {string} property The property to use. 124 * @return {Array} An array of strings. 125 */ 126 getValues(property) { 127 return this.properties[property] ? this.properties[property].values : []; 128 } 129 130 /** 131 * Gets the CSS property names. 132 * 133 * @return {Array} An array of strings. 134 */ 135 getNames() { 136 return Object.keys(this.properties); 137 } 138 139 /** 140 * Return a list of subproperties for the given property. If |name| 141 * does not name a valid property, an empty array is returned. If 142 * the property is not a shorthand property, then array containing 143 * just the property itself is returned. 144 * 145 * @param {string} name The property to query 146 * @return {Array} An array of subproperty names. 147 */ 148 getSubproperties(name) { 149 // Custom Property Names (aka CSS Variables) are case-sensitive; do not lowercase. 150 name = name.startsWith("--") ? name : name.toLowerCase(); 151 if (this.isKnown(name)) { 152 if (this.properties[name] && this.properties[name].subproperties) { 153 return this.properties[name].subproperties; 154 } 155 return [name]; 156 } 157 return []; 158 } 159 } 160 161 /** 162 * Even if the target has the cssProperties actor, the returned data may not be in the 163 * same shape or have all of the data we need. This normalizes the data and fills in 164 * any missing information like color values. 165 * 166 * @return {object} The normalized CSS database. 167 */ 168 function normalizeCssData(db) { 169 // If there is a `from` attributes, it means that it comes from RDP 170 // and it is not the client `generateCssProperties()` object passed by tests. 171 if (typeof db.from == "string") { 172 // This is where to put backward compat tweaks here to support old runtimes. 173 } 174 175 reattachCssColorValues(db); 176 177 return db; 178 } 179 180 /** 181 * Color values are omitted to save on space. Add them back here. 182 * 183 * @param {object} The CSS database. 184 */ 185 function reattachCssColorValues(db) { 186 if (db.properties.color.values[0] === "COLOR") { 187 const colors = Object.keys(cssColors); 188 189 for (const name in db.properties) { 190 const property = db.properties[name]; 191 // "values" can be undefined if {name} was not found in CSS_PROPERTIES_DB. 192 if (property.values && property.values[0] === "COLOR") { 193 property.values.shift(); 194 property.values = property.values.concat(colors).sort(); 195 } 196 } 197 } 198 } 199 200 module.exports = { 201 CssPropertiesFront, 202 CssProperties, 203 normalizeCssData, 204 }; 205 registerFront(CssPropertiesFront);