Bug 1328016 - add parseNamedDeclarations and use in rule view; r=pbro

MozReview-Commit-ID: 25LvVRvbpIm

--HG--
extra : rebase_source : bc1d33cf183212863b5b9a1a138d8671aad995b3
This commit is contained in:
Tom Tromey 2017-01-03 13:14:08 -07:00
parent f15cf6b7a8
commit d0a35ae517
6 changed files with 64 additions and 22 deletions

View File

@ -12,7 +12,7 @@ const {ELEMENT_STYLE} = require("devtools/shared/specs/styles");
const {TextProperty} =
require("devtools/client/inspector/rules/models/text-property");
const {promiseWarn} = require("devtools/client/inspector/shared/utils");
const {parseDeclarations} = require("devtools/shared/css/parsing-utils");
const {parseNamedDeclarations} = require("devtools/shared/css/parsing-utils");
const Services = require("Services");
const STYLE_INSPECTOR_PROPERTIES = "devtools/shared/locales/styleinspector.properties";
@ -242,8 +242,8 @@ Rule.prototype = {
// Note that even though StyleRuleActors normally provide parsed
// declarations already, _applyPropertiesNoAuthored is only used when
// connected to older backend that do not provide them. So parse here.
for (let cssProp of parseDeclarations(this.cssProperties.isKnown,
this.style.authoredText)) {
for (let cssProp of parseNamedDeclarations(this.cssProperties.isKnown,
this.style.authoredText)) {
cssProps[cssProp.name] = cssProp;
}
@ -440,18 +440,15 @@ Rule.prototype = {
// Starting with FF49, StyleRuleActors provide parsed declarations.
let props = this.style.declarations;
if (!props.length) {
props = parseDeclarations(this.cssProperties.isKnown,
this.style.authoredText, true);
// If the authored text has an invalid property, it will show up
// as nameless. Skip these as we don't currently have a good
// way to display them.
props = parseNamedDeclarations(this.cssProperties.isKnown,
this.style.authoredText, true);
}
for (let prop of props) {
let name = prop.name;
// If the authored text has an invalid property, it will show up
// as nameless. Skip these as we don't currently have a good
// way to display them.
if (!name) {
continue;
}
// In an inherited rule, we only show inherited properties.
// However, we must keep all properties in order for rule
// rewriting to work properly. So, compute the "invisible"

View File

@ -17,7 +17,7 @@ const {
promiseWarn
} = require("devtools/client/inspector/shared/utils");
const {
parseDeclarations,
parseNamedDeclarations,
parsePseudoClassesAndAttributes,
SELECTOR_ATTRIBUTE,
SELECTOR_ELEMENT,
@ -473,8 +473,7 @@ RuleEditor.prototype = {
// case, we're creating a new declaration, it doesn't make sense to accept
// these entries
this.multipleAddedProperties =
parseDeclarations(this.rule.cssProperties.isKnown, value, true)
.filter(d => d.name);
parseNamedDeclarations(this.rule.cssProperties.isKnown, value, true);
// Blur the editor field now and deal with adding declarations later when
// the field gets destroyed (see _newPropertyDestroy)

View File

@ -6,7 +6,11 @@
"use strict";
const {require} = Components.utils.import("resource://devtools/shared/Loader.jsm", {});
const {parseDeclarations, _parseCommentDeclarations} = require("devtools/shared/css/parsing-utils");
const {
parseDeclarations,
_parseCommentDeclarations,
parseNamedDeclarations
} = require("devtools/shared/css/parsing-utils");
const {isCssPropertyKnown} = require("devtools/server/actors/css-properties");
const TEST_DATA = [
@ -366,6 +370,7 @@ const TEST_DATA = [
function run_test() {
run_basic_tests();
run_comment_tests();
run_named_tests();
}
// Test parseDeclarations.
@ -416,6 +421,28 @@ function run_comment_tests() {
}
}
const NAMED_DATA = [
{
input: "position:absolute;top50px;height:50px;",
expected: [
{name: "position", value: "absolute", priority: "", terminator: "",
offsets: [0, 18], colonOffsets: [8, 9]},
{name: "height", value: "50px", priority: "", terminator: "",
offsets: [26, 38], colonOffsets: [32, 33]}
],
},
];
// Test parseNamedDeclarations.
function run_named_tests() {
for (let test of NAMED_DATA) {
do_print("Test input string " + test.input);
let output = parseNamedDeclarations(isCssPropertyKnown, test.input, true);
do_print(JSON.stringify(output));
deepEqual(output, test.expected);
}
}
function assertOutput(actual, expected) {
if (actual.length === expected.length) {
for (let i = 0; i < expected.length; i++) {

View File

@ -473,6 +473,14 @@ const TEST_DATA = [
instruction: {type: "remove", name: "color", index: 1},
expected: "\n a:b;\n /* background-color: seagreen; */\n e:f;",
},
{
desc: "regression test for bug 1328016",
input: "position:absolute;top50px;height:50px;width:50px;",
instruction: {type: "set", name: "width", value: "60px", priority: "",
index: 2},
expected: "position:absolute;top50px;height:50px;width:60px;",
},
];
function rewriteDeclarations(inputString, instruction, defaultIndentation) {

View File

@ -9,7 +9,7 @@ const promise = require("promise");
const protocol = require("devtools/shared/protocol");
const {LongStringActor} = require("devtools/server/actors/string");
const {getDefinedGeometryProperties} = require("devtools/server/actors/highlighters/geometry-editor");
const {parseDeclarations} = require("devtools/shared/css/parsing-utils");
const {parseNamedDeclarations} = require("devtools/shared/css/parsing-utils");
const {isCssPropertyKnown} = require("devtools/server/actors/css-properties");
const {Task} = require("devtools/shared/task");
const events = require("sdk/event/core");
@ -1095,9 +1095,9 @@ var StyleRuleActor = protocol.ActorClassWithSpec(styleRuleSpec, {
// and so that we can safely determine if a declaration is valid rather than
// have the client guess it.
if (form.authoredText || form.cssText) {
let declarations = parseDeclarations(isCssPropertyKnown,
form.authoredText || form.cssText,
true);
let declarations = parseNamedDeclarations(isCssPropertyKnown,
form.authoredText || form.cssText,
true);
form.declarations = declarations.map(decl => {
decl.isValid = DOMUtils.cssPropertyIsValid(decl.name, decl.value);
return decl;

View File

@ -448,10 +448,20 @@ function parseDeclarations(isCssPropertyKnown, inputString,
parseComments, false, false);
}
/**
* Like @see parseDeclarations, but removes properties that do not
* have a name.
*/
function parseNamedDeclarations(isCssPropertyKnown, inputString,
parseComments = false) {
return parseDeclarations(isCssPropertyKnown, inputString, parseComments)
.filter(item => !!item.name);
}
/**
* Return an object that can be used to rewrite declarations in some
* source text. The source text and parsing are handled in the same
* way as @see parseDeclarations, with |parseComments| being true.
* way as @see parseNamedDeclarations, with |parseComments| being true.
* Rewriting is done by calling one of the modification functions like
* setPropertyEnabled. The returned object has the same interface
* as @see RuleModificationList.
@ -519,8 +529,8 @@ RuleRewriter.prototype = {
// Whether there are any newlines in the input text.
this.hasNewLine = /[\r\n]/.test(this.inputString);
// The declarations.
this.declarations = parseDeclarations(this.isCssPropertyKnown, this.inputString,
true);
this.declarations = parseNamedDeclarations(this.isCssPropertyKnown, this.inputString,
true);
this.decl = null;
this.result = null;
},
@ -1163,6 +1173,7 @@ exports.escapeCSSComment = escapeCSSComment;
// unescapeCSSComment is exported for testing.
exports._unescapeCSSComment = unescapeCSSComment;
exports.parseDeclarations = parseDeclarations;
exports.parseNamedDeclarations = parseNamedDeclarations;
// parseCommentDeclarations is exported for testing.
exports._parseCommentDeclarations = parseCommentDeclarations;
exports.RuleRewriter = RuleRewriter;