browser/devtools/styleinspector/css-parsing-utils.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: javascript; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 "use strict";
michael@0 8
michael@0 9 const cssTokenizer = require("devtools/sourceeditor/css-tokenizer");
michael@0 10
michael@0 11 /**
michael@0 12 * Returns the string enclosed in quotes
michael@0 13 */
michael@0 14 function quoteString(string) {
michael@0 15 let hasDoubleQuotes = string.contains('"');
michael@0 16 let hasSingleQuotes = string.contains("'");
michael@0 17
michael@0 18 if (hasDoubleQuotes && !hasSingleQuotes) {
michael@0 19 // In this case, no escaping required, just enclose in single-quotes
michael@0 20 return "'" + string + "'";
michael@0 21 }
michael@0 22
michael@0 23 // In all other cases, enclose in double-quotes, and escape any double-quote
michael@0 24 // that may be in the string
michael@0 25 return '"' + string.replace(/"/g, '\"') + '"';
michael@0 26 }
michael@0 27
michael@0 28 /**
michael@0 29 * Returns an array of CSS declarations given an string.
michael@0 30 * For example, parseDeclarations("width: 1px; height: 1px") would return
michael@0 31 * [{name:"width", value: "1px"}, {name: "height", "value": "1px"}]
michael@0 32 *
michael@0 33 * The input string is assumed to only contain declarations so { and } characters
michael@0 34 * will be treated as part of either the property or value, depending where it's
michael@0 35 * found.
michael@0 36 *
michael@0 37 * @param {string} inputString
michael@0 38 * An input string of CSS
michael@0 39 * @return {Array} an array of objects with the following signature:
michael@0 40 * [{"name": string, "value": string, "priority": string}, ...]
michael@0 41 */
michael@0 42 function parseDeclarations(inputString) {
michael@0 43 let tokens = cssTokenizer(inputString);
michael@0 44
michael@0 45 let declarations = [{name: "", value: "", priority: ""}];
michael@0 46
michael@0 47 let current = "", hasBang = false, lastProp;
michael@0 48 for (let token of tokens) {
michael@0 49 lastProp = declarations[declarations.length - 1];
michael@0 50
michael@0 51 if (token.tokenType === ":") {
michael@0 52 if (!lastProp.name) {
michael@0 53 // Set the current declaration name if there's no name yet
michael@0 54 lastProp.name = current.trim();
michael@0 55 current = "";
michael@0 56 hasBang = false;
michael@0 57 } else {
michael@0 58 // Otherwise, just append ':' to the current value (declaration value
michael@0 59 // with colons)
michael@0 60 current += ":";
michael@0 61 }
michael@0 62 } else if (token.tokenType === ";") {
michael@0 63 lastProp.value = current.trim();
michael@0 64 current = "";
michael@0 65 hasBang = false;
michael@0 66 declarations.push({name: "", value: "", priority: ""});
michael@0 67 } else {
michael@0 68 switch(token.tokenType) {
michael@0 69 case "IDENT":
michael@0 70 if (token.value === "important" && hasBang) {
michael@0 71 lastProp.priority = "important";
michael@0 72 hasBang = false;
michael@0 73 } else {
michael@0 74 if (hasBang) {
michael@0 75 current += "!";
michael@0 76 }
michael@0 77 current += token.value;
michael@0 78 }
michael@0 79 break;
michael@0 80 case "WHITESPACE":
michael@0 81 current += " ";
michael@0 82 break;
michael@0 83 case "DIMENSION":
michael@0 84 current += token.repr;
michael@0 85 break;
michael@0 86 case "HASH":
michael@0 87 current += "#" + token.value;
michael@0 88 break;
michael@0 89 case "URL":
michael@0 90 current += "url(" + quoteString(token.value) + ")";
michael@0 91 break;
michael@0 92 case "FUNCTION":
michael@0 93 current += token.value + "(";
michael@0 94 break;
michael@0 95 case ")":
michael@0 96 current += token.tokenType;
michael@0 97 break;
michael@0 98 case "EOF":
michael@0 99 break;
michael@0 100 case "DELIM":
michael@0 101 if (token.value === "!") {
michael@0 102 hasBang = true;
michael@0 103 } else {
michael@0 104 current += token.value;
michael@0 105 }
michael@0 106 break;
michael@0 107 case "STRING":
michael@0 108 current += quoteString(token.value);
michael@0 109 break;
michael@0 110 case "{":
michael@0 111 case "}":
michael@0 112 current += token.tokenType;
michael@0 113 break;
michael@0 114 default:
michael@0 115 current += token.value;
michael@0 116 break;
michael@0 117 }
michael@0 118 }
michael@0 119 }
michael@0 120
michael@0 121 // Handle whatever trailing properties or values might still be there
michael@0 122 if (current) {
michael@0 123 if (!lastProp.name) {
michael@0 124 // Trailing property found, e.g. p1:v1;p2:v2;p3
michael@0 125 lastProp.name = current.trim();
michael@0 126 } else {
michael@0 127 // Trailing value found, i.e. value without an ending ;
michael@0 128 lastProp.value += current.trim();
michael@0 129 }
michael@0 130 }
michael@0 131
michael@0 132 // Remove declarations that have neither a name nor a value
michael@0 133 declarations = declarations.filter(prop => prop.name || prop.value);
michael@0 134
michael@0 135 return declarations;
michael@0 136 };
michael@0 137 exports.parseDeclarations = parseDeclarations;
michael@0 138
michael@0 139 /**
michael@0 140 * Expects a single CSS value to be passed as the input and parses the value
michael@0 141 * and priority.
michael@0 142 *
michael@0 143 * @param {string} value The value from the text editor.
michael@0 144 * @return {object} an object with 'value' and 'priority' properties.
michael@0 145 */
michael@0 146 function parseSingleValue(value) {
michael@0 147 let declaration = parseDeclarations("a: " + value + ";")[0];
michael@0 148 return {
michael@0 149 value: declaration ? declaration.value : "",
michael@0 150 priority: declaration ? declaration.priority : ""
michael@0 151 };
michael@0 152 };
michael@0 153 exports.parseSingleValue = parseSingleValue;

mercurial