diff --git a/browser/devtools/shared/test/browser_outputparser.js b/browser/devtools/shared/test/browser_outputparser.js index 5cc0e0abdfac..ab34bf14d7dc 100644 --- a/browser/devtools/shared/test/browser_outputparser.js +++ b/browser/devtools/shared/test/browser_outputparser.js @@ -37,11 +37,23 @@ function testParseCssProperty() { target.appendChild(frag); is(target.innerHTML, - '1px solid #F00', + '1px solid #F00', "CSS property correctly parsed"); target.innerHTML = ""; + let frag = parser.parseCssProperty("background-image", "linear-gradient(to right, #F60 10%, rgba(0,0,0,1))", { + colorSwatchClass: "test-colorswatch", + colorClass: "test-color" + }); + target.appendChild(frag); + is(target.innerHTML, + 'linear-gradient(to right, #F60 10%, ' + + '#000)', + "Gradient CSS property correctly parsed"); + + target.innerHTML = ""; + testParseHTMLAttribute(); } @@ -49,14 +61,15 @@ function testParseHTMLAttribute() { let attrib = "color:red; font-size: 12px; background-image: " + "url(chrome://branding/content/about-logo.png)"; let frag = parser.parseHTMLAttribute(attrib, { - urlClass: "theme-link" + urlClass: "theme-link", + colorClass: "theme-color" }); let target = doc.querySelector("div"); ok(target, "captain, we have the div"); target.appendChild(frag); - let expected = 'color:#F00; font-size: 12px; ' + + let expected = 'color:#F00; font-size: 12px; ' + 'background-image: url(\'chrome://branding/content/about-logo.png\')'; diff --git a/browser/devtools/styleinspector/rule-view.js b/browser/devtools/styleinspector/rule-view.js index 09d677d2530d..01e4879c4ef1 100644 --- a/browser/devtools/styleinspector/rule-view.js +++ b/browser/devtools/styleinspector/rule-view.js @@ -2023,6 +2023,7 @@ TextPropertyEditor.prototype = { let outputParser = this.ruleEditor.ruleView._outputParser; let frag = outputParser.parseCssProperty(name, val, { colorSwatchClass: swatchClass, + colorClass: "ruleview-color", defaultColorType: !propDirty, urlClass: "theme-link", baseURI: this.sheetURI diff --git a/browser/devtools/styleinspector/test/browser.ini b/browser/devtools/styleinspector/test/browser.ini index 0ca9347280a9..d0e21683383c 100644 --- a/browser/devtools/styleinspector/test/browser.ini +++ b/browser/devtools/styleinspector/test/browser.ini @@ -53,3 +53,4 @@ support-files = browser_ruleview_pseudoelement.html [browser_bug913014_matched_expand.js] [browser_bug765105_background_image_tooltip.js] [browser_bug889638_rule_view_color_picker.js] +[browser_bug940500_rule_view_pick_gradient_color.js] diff --git a/browser/devtools/styleinspector/test/browser_bug940500_rule_view_pick_gradient_color.js b/browser/devtools/styleinspector/test/browser_bug940500_rule_view_pick_gradient_color.js new file mode 100644 index 000000000000..d52cae7090ac --- /dev/null +++ b/browser/devtools/styleinspector/test/browser_bug940500_rule_view_pick_gradient_color.js @@ -0,0 +1,135 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +// Test that changing a color in a gradient css declaration using the tooltip +// color picker works + +let {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); + +let contentDoc; +let contentWin; +let inspector; +let ruleView; + +const PAGE_CONTENT = [ + '', + 'Updating a gradient declaration with the color picker tooltip' +].join("\n"); + +function test() { + waitForExplicitFinish(); + + gBrowser.selectedTab = gBrowser.addTab(); + gBrowser.selectedBrowser.addEventListener("load", function(evt) { + gBrowser.selectedBrowser.removeEventListener(evt.type, arguments.callee, true); + contentDoc = content.document; + contentWin = contentDoc.defaultView; + waitForFocus(createDocument, content); + }, true); + + content.location = "data:text/html,rule view color picker tooltip test"; +} + +function createDocument() { + contentDoc.body.innerHTML = PAGE_CONTENT; + + openRuleView((aInspector, aRuleView) => { + inspector = aInspector; + ruleView = aRuleView; + startTests(); + }); +} + +function startTests() { + inspector.selection.setNode(contentDoc.body); + inspector.once("inspector-updated", testColorParsing); +} + +function endTests() { + executeSoon(function() { + gDevTools.once("toolbox-destroyed", () => { + contentDoc = contentWin = inspector = ruleView = null; + gBrowser.removeCurrentTab(); + finish(); + }); + inspector._toolbox.destroy(); + }); +} + +function testColorParsing() { + let ruleEl = getRuleViewProperty("background-image"); + ok(ruleEl, "The background-image gradient declaration was found"); + + let swatchEls = ruleEl.valueSpan.querySelectorAll(".ruleview-colorswatch"); + ok(swatchEls, "The color swatch elements were found"); + is(swatchEls.length, 3, "There are 3 color swatches"); + + let colorEls = ruleEl.valueSpan.querySelectorAll(".ruleview-color"); + ok(colorEls, "The color elements were found"); + is(colorEls.length, 3, "There are 3 color values"); + + let colors = ["#F06", "#333", "#000"]; + for (let i = 0; i < colors.length; i ++) { + is(colorEls[i].textContent, colors[i], "The right color value was found"); + } + + testPickingNewColor(); +} + +function testPickingNewColor() { + // Grab the first color swatch and color in the gradient + let ruleEl = getRuleViewProperty("background-image"); + let swatchEl = ruleEl.valueSpan.querySelector(".ruleview-colorswatch"); + let colorEl = ruleEl.valueSpan.querySelector(".ruleview-color"); + + // Get the color picker tooltip + let cPicker = ruleView.colorPicker; + + cPicker.tooltip.once("shown", () => { + simulateColorChange(cPicker, [1, 1, 1, 1]); + + executeSoon(() => { + is(swatchEl.style.backgroundColor, "rgb(1, 1, 1)", + "The color swatch's background was updated"); + is(colorEl.textContent, "rgba(1, 1, 1, 1)", + "The color text was updated"); + is(content.getComputedStyle(content.document.body).backgroundImage, + "linear-gradient(to left, rgb(255, 0, 102) 25%, rgb(51, 51, 51) 95%, rgb(0, 0, 0) 100%)", + "The gradient has been updated correctly"); + + cPicker.hide(); + endTests(); + }); + }); + swatchEl.click(); +} + +function simulateColorChange(colorPicker, newRgba) { + // Note that this test isn't concerned with simulating events to test how the + // spectrum color picker reacts, see browser_spectrum.js for this. + // This test only cares about the color swatch <-> color picker <-> rule view + // interactions. That's why there's no event simulations here + colorPicker.spectrum.then(spectrum => { + spectrum.rgb = newRgba; + spectrum.updateUI(); + spectrum.onChange(); + }); +} + +function getRuleViewProperty(name) { + let prop = null; + [].forEach.call(ruleView.doc.querySelectorAll(".ruleview-property"), property => { + let nameSpan = property.querySelector(".ruleview-propertyname"); + let valueSpan = property.querySelector(".ruleview-propertyvalue"); + + if (nameSpan.textContent === name) { + prop = {nameSpan: nameSpan, valueSpan: valueSpan}; + } + }); + return prop; +} diff --git a/toolkit/devtools/output-parser.js b/toolkit/devtools/output-parser.js index 036378b1bd4c..a17a419b1dc9 100644 --- a/toolkit/devtools/output-parser.js +++ b/toolkit/devtools/output-parser.js @@ -304,7 +304,9 @@ OutputParser.prototype = { if (options.defaultColorType) { color = colorObj.toString(); } - this._appendTextNode(color); + this._appendNode("span", { + class: options.colorClass + }, color); return true; } return false; @@ -362,7 +364,9 @@ OutputParser.prototype = { let attrs = Object.getOwnPropertyNames(attributes); for (let attr of attrs) { - node.setAttribute(attr, attributes[attr]); + if (attributes[attr]) { + node.setAttribute(attr, attributes[attr]); + } } if (value) { @@ -422,6 +426,8 @@ OutputParser.prototype = { * - defaultColorType: true // Convert colors to the default type * // selected in the options panel. * - colorSwatchClass: "" // The class to use for color swatches. + * - colorClass: "" // The class to use for the color value + * // that follows the swatch. * - isHTMLAttribute: false // This property indicates whether we * // are parsing an HTML attribute value. * // When the value is passed in from an @@ -439,6 +445,7 @@ OutputParser.prototype = { let defaults = { defaultColorType: true, colorSwatchClass: "", + colorClass: "", isHTMLAttribute: false, urlClass: "", baseURI: ""