зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1136257 - Shift-click to switch between color unit format in place r=bgrins
This commit is contained in:
Родитель
c90ba68148
Коммит
40cecd0bac
|
@ -1,7 +1,6 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
const COLOR_UNIT_PREF = "devtools.defaultColorUnit";
|
||||
const TEST_URI = "data:text/html;charset=utf-8,browser_css_color.js";
|
||||
let {colorUtils} = devtools.require("devtools/css-color");
|
||||
let origColorUnit;
|
||||
|
@ -9,7 +8,6 @@ let origColorUnit;
|
|||
add_task(function*() {
|
||||
yield promiseTab("about:blank");
|
||||
let [host, win, doc] = yield createHost("bottom", TEST_URI);
|
||||
origColorUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF);
|
||||
|
||||
info("Creating a test canvas element to test colors");
|
||||
let canvas = createTestCanvas(doc);
|
||||
|
@ -49,23 +47,19 @@ function testColorUtils(canvas) {
|
|||
}
|
||||
|
||||
function testToString(color, name, hex, hsl, rgb) {
|
||||
switchColorUnit(colorUtils.CssColor.COLORUNIT.name);
|
||||
color.colorUnit = colorUtils.CssColor.COLORUNIT.name;
|
||||
is(color.toString(), name, "toString() with authored type");
|
||||
|
||||
switchColorUnit(colorUtils.CssColor.COLORUNIT.hex);
|
||||
color.colorUnit = colorUtils.CssColor.COLORUNIT.hex;
|
||||
is(color.toString(), hex, "toString() with hex type");
|
||||
|
||||
switchColorUnit(colorUtils.CssColor.COLORUNIT.hsl);
|
||||
color.colorUnit = colorUtils.CssColor.COLORUNIT.hsl;
|
||||
is(color.toString(), hsl, "toString() with hsl type");
|
||||
|
||||
switchColorUnit(colorUtils.CssColor.COLORUNIT.rgb);
|
||||
color.colorUnit = colorUtils.CssColor.COLORUNIT.rgb;
|
||||
is(color.toString(), rgb, "toString() with rgb type");
|
||||
}
|
||||
|
||||
function switchColorUnit(unit) {
|
||||
Services.prefs.setCharPref(COLOR_UNIT_PREF, unit);
|
||||
}
|
||||
|
||||
function testColorMatch(name, hex, hsl, rgb, rgba, canvas) {
|
||||
let target;
|
||||
let ctx = canvas.getContext("2d");
|
||||
|
@ -110,7 +104,6 @@ function testColorMatch(name, hex, hsl, rgb, rgba, canvas) {
|
|||
test(hex, "hex");
|
||||
test(hsl, "hsl");
|
||||
test(rgb, "rgb");
|
||||
switchColorUnit(origColorUnit);
|
||||
}
|
||||
|
||||
function testProcessCSSString() {
|
||||
|
|
|
@ -1020,6 +1020,11 @@ SwatchBasedEditorTooltip.prototype = {
|
|||
|
||||
_onSwatchClick: function(event) {
|
||||
let swatch = this.swatches.get(event.target);
|
||||
|
||||
if (event.shiftKey) {
|
||||
event.stopPropagation();
|
||||
return;
|
||||
}
|
||||
if (swatch) {
|
||||
this.activeSwatch = event.target;
|
||||
this.show();
|
||||
|
|
|
@ -980,7 +980,6 @@ function PropertyView(aTree, aName)
|
|||
|
||||
this.link = "https://developer.mozilla.org/CSS/" + aName;
|
||||
|
||||
this.templateMatchedSelectors = aTree.styleDocument.getElementById("templateMatchedSelectors");
|
||||
this._propertyInfo = new PropertyInfo(aTree, aName);
|
||||
}
|
||||
|
||||
|
@ -1192,6 +1191,7 @@ PropertyView.prototype = {
|
|||
this.propertyInfo.value,
|
||||
{
|
||||
colorSwatchClass: "computedview-colorswatch",
|
||||
colorClass: "computedview-color",
|
||||
urlClass: "theme-link"
|
||||
// No need to use baseURI here as computed URIs are never relative.
|
||||
});
|
||||
|
@ -1222,9 +1222,10 @@ PropertyView.prototype = {
|
|||
}
|
||||
|
||||
this._matchedSelectorResponse = matched;
|
||||
CssHtmlTree.processTemplate(this.templateMatchedSelectors,
|
||||
this.matchedSelectorsContainer, this);
|
||||
|
||||
this._buildMatchedSelectors();
|
||||
this.matchedExpander.setAttribute("open", "");
|
||||
|
||||
this.tree.inspector.emit("computed-view-property-expanded");
|
||||
}).then(null, console.error);
|
||||
} else {
|
||||
|
@ -1240,6 +1241,40 @@ PropertyView.prototype = {
|
|||
return this._matchedSelectorResponse;
|
||||
},
|
||||
|
||||
_buildMatchedSelectors: function() {
|
||||
let frag = this.element.ownerDocument.createDocumentFragment();
|
||||
|
||||
for (let selector of this.matchedSelectorViews) {
|
||||
let p = createChild(frag, "p");
|
||||
let span = createChild(p, "span", {
|
||||
class: "rule-link"
|
||||
});
|
||||
let link = createChild(span, "a", {
|
||||
target: "_blank",
|
||||
class: "link theme-link",
|
||||
title: selector.href,
|
||||
sourcelocation: selector.source,
|
||||
tabindex: "0",
|
||||
textContent: selector.source
|
||||
});
|
||||
link.addEventListener("click", selector.openStyleEditor, false);
|
||||
link.addEventListener("keydown", selector.maybeOpenStyleEditor, false);
|
||||
|
||||
let status = createChild(p, "span", {
|
||||
dir: "ltr",
|
||||
class: "rule-text theme-fg-color3 " + selector.statusClass,
|
||||
title: selector.statusText,
|
||||
textContent: selector.sourceText
|
||||
});
|
||||
let valueSpan = createChild(status, "span", {
|
||||
class: "other-property-value theme-fg-color1"
|
||||
});
|
||||
valueSpan.appendChild(selector.outputFragment);
|
||||
}
|
||||
|
||||
this.matchedSelectorsContainer.appendChild(frag);
|
||||
},
|
||||
|
||||
/**
|
||||
* Provide access to the matched SelectorViews that we are currently
|
||||
* displaying.
|
||||
|
@ -1279,6 +1314,9 @@ PropertyView.prototype = {
|
|||
*/
|
||||
onMatchedToggle: function PropertyView_onMatchedToggle(aEvent)
|
||||
{
|
||||
if (aEvent.shiftKey) {
|
||||
return;
|
||||
}
|
||||
this.matchedExpanded = !this.matchedExpanded;
|
||||
this.refreshMatchedSelectors();
|
||||
aEvent.preventDefault();
|
||||
|
@ -1328,6 +1366,9 @@ function SelectorView(aTree, aSelectorInfo)
|
|||
this.selectorInfo = aSelectorInfo;
|
||||
this._cacheStatusNames();
|
||||
|
||||
this.openStyleEditor = this.openStyleEditor.bind(this);
|
||||
this.maybeOpenStyleEditor = this.maybeOpenStyleEditor.bind(this);
|
||||
|
||||
this.updateSourceLink();
|
||||
}
|
||||
|
||||
|
@ -1418,6 +1459,7 @@ SelectorView.prototype = {
|
|||
this.selectorInfo.name,
|
||||
this.selectorInfo.value, {
|
||||
colorSwatchClass: "computedview-colorswatch",
|
||||
colorClass: "computedview-color",
|
||||
urlClass: "theme-link",
|
||||
baseURI: this.selectorInfo.rule.href
|
||||
});
|
||||
|
@ -1540,5 +1582,32 @@ SelectorView.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a child element with a set of attributes.
|
||||
*
|
||||
* @param {Element} aParent
|
||||
* The parent node.
|
||||
* @param {string} aTag
|
||||
* The tag name.
|
||||
* @param {object} aAttributes
|
||||
* A set of attributes to set on the node.
|
||||
*/
|
||||
function createChild(aParent, aTag, aAttributes={}) {
|
||||
let elt = aParent.ownerDocument.createElementNS(HTML_NS, aTag);
|
||||
for (let attr in aAttributes) {
|
||||
if (aAttributes.hasOwnProperty(attr)) {
|
||||
if (attr === "textContent") {
|
||||
elt.textContent = aAttributes[attr];
|
||||
} else if(attr === "child") {
|
||||
elt.appendChild(aAttributes[attr]);
|
||||
} else {
|
||||
elt.setAttribute(attr, aAttributes[attr]);
|
||||
}
|
||||
}
|
||||
}
|
||||
aParent.appendChild(elt);
|
||||
return elt;
|
||||
}
|
||||
|
||||
exports.CssHtmlTree = CssHtmlTree;
|
||||
exports.PropertyView = PropertyView;
|
||||
|
|
|
@ -72,38 +72,5 @@
|
|||
&noPropertiesFound;
|
||||
</div>
|
||||
|
||||
<!--
|
||||
To visually debug the templates without running firefox, alter the display:none
|
||||
-->
|
||||
<div style="display:none;">
|
||||
<!--
|
||||
A templateMatchedSelectors sits inside each templateProperties showing the
|
||||
list of selectors that affect that property. Each needs data like this:
|
||||
{
|
||||
matchedSelectorViews: ..., // from cssHtmlTree.propertyViews[name].matchedSelectorViews
|
||||
}
|
||||
This is a template so the parent does not need to be a table, except that
|
||||
using a div as the parent causes the DOM to muck with the tr elements
|
||||
-->
|
||||
<div id="templateMatchedSelectors">
|
||||
<loop foreach="selector in ${matchedSelectorViews}">
|
||||
<p>
|
||||
<span class="rule-link">
|
||||
<a target="_blank" class="link theme-link"
|
||||
onclick="${selector.openStyleEditor}"
|
||||
onkeydown="${selector.maybeOpenStyleEditor}"
|
||||
title="${selector.href}"
|
||||
sourcelocation="${selector.source}"
|
||||
tabindex="0">${selector.source}</a>
|
||||
</span>
|
||||
<span dir="ltr" class="rule-text ${selector.statusClass} theme-fg-color3" title="${selector.statusText}">
|
||||
${selector.sourceText}
|
||||
<span class="other-property-value theme-fg-color1">${selector.outputFragment}</span>
|
||||
</span>
|
||||
</p>
|
||||
</loop>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -27,6 +27,7 @@ support-files =
|
|||
head.js
|
||||
|
||||
[browser_computedview_browser-styles.js]
|
||||
[browser_computedview_cycle_color.js]
|
||||
[browser_computedview_getNodeInfo.js]
|
||||
[browser_computedview_keybindings_01.js]
|
||||
[browser_computedview_keybindings_02.js]
|
||||
|
@ -99,6 +100,7 @@ skip-if = (os == "win" && debug) || e10s # bug 963492: win. bug 1040653: e10s.
|
|||
[browser_ruleview_multiple_properties_01.js]
|
||||
[browser_ruleview_multiple_properties_02.js]
|
||||
[browser_ruleview_original-source-link.js]
|
||||
[browser_ruleview_cycle-color.js]
|
||||
[browser_ruleview_override.js]
|
||||
[browser_ruleview_pseudo-element_01.js]
|
||||
[browser_ruleview_pseudo-element_02.js]
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Computed view color cycling test.
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
"<style type=\"text/css\">",
|
||||
".matches {color: #F00;}</style>",
|
||||
"<span id=\"matches\" class=\"matches\">Some styled text</span>",
|
||||
"</div>"
|
||||
].join("\n");
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8," +
|
||||
"Computed view color cycling test.");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
info("Opening the computed view");
|
||||
let {toolbox, inspector, view} = yield openComputedView();
|
||||
|
||||
info("Selecting the test node");
|
||||
yield selectNode("#matches", inspector);
|
||||
|
||||
info("Checking the property itself");
|
||||
let container = getComputedViewPropertyView(view, "color").valueNode;
|
||||
checkColorCycling(container, inspector);
|
||||
|
||||
info("Checking matched selectors");
|
||||
container = yield getComputedViewMatchedRules(view, "color");
|
||||
checkColorCycling(container, inspector);
|
||||
});
|
||||
|
||||
function checkColorCycling(container, inspector) {
|
||||
let swatch = container.querySelector(".computedview-colorswatch");
|
||||
let valueNode = container.querySelector(".computedview-color");
|
||||
let win = inspector.sidebar.getWindowForTab("computedview");
|
||||
|
||||
// Hex (default)
|
||||
is(valueNode.textContent, "#F00", "Color displayed as a hex value.");
|
||||
|
||||
// HSL
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "hsl(0, 100%, 50%)",
|
||||
"Color displayed as an HSL value.");
|
||||
|
||||
// RGB
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "rgb(255, 0, 0)",
|
||||
"Color displayed as an RGB value.");
|
||||
|
||||
// Color name
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "red",
|
||||
"Color displayed as a color name.");
|
||||
|
||||
// "Authored" (currently the computed value)
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "rgb(255, 0, 0)",
|
||||
"Color displayed as an RGB value.");
|
||||
|
||||
// Back to hex
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "#F00",
|
||||
"Color displayed as hex again.");
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test cycling color types in the rule view.
|
||||
|
||||
const PAGE_CONTENT = [
|
||||
"<style type=\"text/css\">",
|
||||
" body {",
|
||||
" color: #F00;",
|
||||
" }",
|
||||
"</style>",
|
||||
"Test cycling color types in the rule view!"
|
||||
].join("\n");
|
||||
|
||||
add_task(function*() {
|
||||
yield addTab("data:text/html;charset=utf-8,Test cycling color types in the " +
|
||||
"rule view.");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
let container = getRuleViewProperty(view, "body", "color").valueSpan;
|
||||
checkColorCycling(container, inspector);
|
||||
});
|
||||
|
||||
function checkColorCycling(container, inspector) {
|
||||
let swatch = container.querySelector(".ruleview-colorswatch");
|
||||
let valueNode = container.querySelector(".ruleview-color");
|
||||
let win = inspector.sidebar.getWindowForTab("ruleview");
|
||||
|
||||
// Hex (default)
|
||||
is(valueNode.textContent, "#F00", "Color displayed as a hex value.");
|
||||
|
||||
// HSL
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "hsl(0, 100%, 50%)",
|
||||
"Color displayed as an HSL value.");
|
||||
|
||||
// RGB
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "rgb(255, 0, 0)",
|
||||
"Color displayed as an RGB value.");
|
||||
|
||||
// Color name
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "red",
|
||||
"Color displayed as a color name.");
|
||||
|
||||
// "Authored" (currently the computed value)
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "rgb(255, 0, 0)",
|
||||
"Color displayed as an RGB value.");
|
||||
|
||||
// Back to hex
|
||||
EventUtils.synthesizeMouseAtCenter(swatch, {type: "mousedown", shiftKey: true}, win);
|
||||
is(valueNode.textContent, "#F00",
|
||||
"Color displayed as hex again.");
|
||||
}
|
|
@ -95,8 +95,22 @@ CssColor.COLORUNIT = {
|
|||
};
|
||||
|
||||
CssColor.prototype = {
|
||||
_colorUnit: null,
|
||||
|
||||
authored: null,
|
||||
|
||||
get colorUnit() {
|
||||
if (this._colorUnit === null) {
|
||||
let defaultUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF);
|
||||
this._colorUnit = CssColor.COLORUNIT[defaultUnit];
|
||||
}
|
||||
return this._colorUnit;
|
||||
},
|
||||
|
||||
set colorUnit(unit) {
|
||||
this._colorUnit = unit;
|
||||
},
|
||||
|
||||
get hasAlpha() {
|
||||
if (!this.valid) {
|
||||
return false;
|
||||
|
@ -269,15 +283,31 @@ CssColor.prototype = {
|
|||
return this;
|
||||
},
|
||||
|
||||
nextColorUnit: function() {
|
||||
// Reorder the formats array to have the current format at the
|
||||
// front so we can cycle through.
|
||||
let formats = ["authored", "hex", "hsl", "rgb", "name"];
|
||||
let putOnEnd = formats.splice(0, formats.indexOf(this.colorUnit));
|
||||
formats = formats.concat(putOnEnd);
|
||||
let currentDisplayedColor = this[formats[0]];
|
||||
|
||||
for (let format of formats) {
|
||||
if (this[format].toLowerCase() !== currentDisplayedColor.toLowerCase()) {
|
||||
this.colorUnit = CssColor.COLORUNIT[format];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.toString();
|
||||
},
|
||||
|
||||
/**
|
||||
* Return a string representing a color of type defined in COLOR_UNIT_PREF.
|
||||
*/
|
||||
toString: function() {
|
||||
let color;
|
||||
let defaultUnit = Services.prefs.getCharPref(COLOR_UNIT_PREF);
|
||||
let unit = CssColor.COLORUNIT[defaultUnit];
|
||||
|
||||
switch(unit) {
|
||||
switch(this.colorUnit) {
|
||||
case CssColor.COLORUNIT.authored:
|
||||
color = this.authored;
|
||||
break;
|
||||
|
|
|
@ -77,6 +77,8 @@ loader.lazyGetter(this, "REGEX_ALL_CSS_PROPERTIES", function () {
|
|||
*/
|
||||
function OutputParser() {
|
||||
this.parsed = [];
|
||||
this.colorSwatches = new WeakMap();
|
||||
this._onSwatchMouseDown = this._onSwatchMouseDown.bind(this);
|
||||
}
|
||||
|
||||
exports.OutputParser = OutputParser;
|
||||
|
@ -396,12 +398,14 @@ OutputParser.prototype = {
|
|||
class: options.colorSwatchClass,
|
||||
style: "background-color:" + color
|
||||
});
|
||||
this.colorSwatches.set(swatch, colorObj);
|
||||
swatch.addEventListener("mousedown", this._onSwatchMouseDown, false);
|
||||
container.appendChild(swatch);
|
||||
}
|
||||
|
||||
if (options.defaultColorType) {
|
||||
color = colorObj.toString();
|
||||
container.dataset["color"] = color;
|
||||
container.dataset.color = color;
|
||||
}
|
||||
|
||||
let value = this._createNode("span", {
|
||||
|
@ -435,6 +439,21 @@ OutputParser.prototype = {
|
|||
this.parsed.push(container);
|
||||
},
|
||||
|
||||
_onSwatchMouseDown: function(event) {
|
||||
// Prevent text selection in the case of shift-click or double-click.
|
||||
event.preventDefault();
|
||||
|
||||
if (!event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
|
||||
let swatch = event.target;
|
||||
let color = this.colorSwatches.get(swatch);
|
||||
let val = color.nextColorUnit();
|
||||
|
||||
swatch.nextElementSibling.textContent = val;
|
||||
},
|
||||
|
||||
/**
|
||||
* Append a URL to the output.
|
||||
*
|
||||
|
|
Загрузка…
Ссылка в новой задаче