Bug 939040 - Add eyedropper tool and include it in the color picker tooltip; r=pbrosset

This commit is contained in:
Heather Arthur 2014-03-31 15:26:53 -07:00
Родитель 735bae1fa6
Коммит e5bfce063b
34 изменённых файлов: 1344 добавлений и 113 удалений

Просмотреть файл

@ -1274,6 +1274,9 @@ pref("devtools.hud.loglimit.cssparser", 200);
pref("devtools.hud.loglimit.exception", 200);
pref("devtools.hud.loglimit.console", 200);
// By how many times eyedropper will magnify pixels
pref("devtools.eyedropper.zoom", 6);
// The developer tools editor configuration:
// - tabsize: how many spaces to use when a Tab character is displayed.
// - expandtab: expand Tab characters to spaces.

Просмотреть файл

@ -504,6 +504,9 @@
<menuitem id="menu_responsiveUI"
observes="devtoolsMenuBroadcaster_ResponsiveUI"
accesskey="&responsiveDesignTool.accesskey;"/>
<menuitem id="menu_eyedropper"
observes="devtoolsMenuBroadcaster_Eyedropper"
accesskey="&eyedropper.accesskey;"/>
<menuitem id="menu_scratchpad"
observes="devtoolsMenuBroadcaster_Scratchpad"
accesskey="&scratchpad.accesskey;"/>

Просмотреть файл

@ -102,6 +102,7 @@
<command id="Tools:BrowserConsole" oncommand="HUDService.toggleBrowserConsole();"/>
<command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/>
<command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/>
<command id="Tools:Eyedropper" oncommand="openEyedropper();"/>
<command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/>
<command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/>
<command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/>
@ -211,6 +212,10 @@
type="checkbox" autocheck="false"
command="Tools:ResponsiveUI"
key="key_responsiveUI"/>
<broadcaster id="devtoolsMenuBroadcaster_Eyedropper"
label="&eyedropper.label;"
type="checkbox" autocheck="false"
command="Tools:Eyedropper"/>
<broadcaster id="devtoolsMenuBroadcaster_PageSource"
label="&pageSourceCmd.label;"
key="key_viewSource"

Просмотреть файл

@ -7122,6 +7122,20 @@ XPCOMUtils.defineLazyGetter(ResponsiveUI, "ResponsiveUIManager", function() {
return tmp.ResponsiveUIManager;
});
function openEyedropper() {
var eyedropper = new this.Eyedropper(this);
eyedropper.open();
}
Object.defineProperty(this, "Eyedropper", {
get: function() {
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
return devtools.require("devtools/eyedropper/eyedropper").Eyedropper;
},
configurable: true,
enumerable: true
});
XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () {
#ifdef XP_WIN
// Only show resizers on Windows 2000 and XP

Просмотреть файл

@ -0,0 +1,3 @@
* {
cursor: crosshair !important;
}

Просмотреть файл

@ -0,0 +1,671 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const {Cc, Ci, Cu} = require("chrome");
const {rgbToHsl} = require("devtools/css-color").colorUtils;
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js");
Cu.import("resource://gre/modules/Services.jsm");
loader.lazyGetter(this, "clipboardHelper", function() {
return Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper);
});
loader.lazyGetter(this, "ssService", function() {
return Cc["@mozilla.org/content/style-sheet-service;1"]
.getService(Ci.nsIStyleSheetService);
});
loader.lazyGetter(this, "ioService", function() {
return Cc["@mozilla.org/network/io-service;1"]
.getService(Ci.nsIIOService);
});
loader.lazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
});
loader.lazyGetter(this, "XULRuntime", function() {
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime);
});
loader.lazyGetter(this, "l10n", () => Services.strings
.createBundle("chrome://browser/locale/devtools/eyedropper.properties"));
const EYEDROPPER_URL = "chrome://browser/content/devtools/eyedropper.xul";
const CROSSHAIRS_URL = "chrome://browser/content/devtools/eyedropper/crosshairs.css";
const NOCURSOR_URL = "chrome://browser/content/devtools/eyedropper/nocursor.css";
const ZOOM_PREF = "devtools.eyedropper.zoom";
const FORMAT_PREF = "devtools.defaultColorUnit";
const CANVAS_WIDTH = 96;
const CANVAS_OFFSET = 3; // equals the border width of the canvas.
const CLOSE_DELAY = 750;
const HEX_BOX_WIDTH = CANVAS_WIDTH + CANVAS_OFFSET * 2;
const HSL_BOX_WIDTH = 158;
/**
* Eyedropper widget. Once opened, shows zoomed area above current pixel and
* displays the color value of the center pixel. Clicking on the window will
* close the widget and fire a 'select' event. If 'copyOnSelect' is true, the color
* will also be copied to the clipboard.
*
* let eyedropper = new Eyedropper(window);
* eyedropper.open();
*
* eyedropper.once("select", (ev, color) => {
* console.log(color); // "rgb(20, 50, 230)"
* })
*
* @param {DOMWindow} chromeWindow
* window to inspect
* @param {object} opts
* optional options object, with 'copyOnSelect'
*/
function Eyedropper(chromeWindow, opts = { copyOnSelect: true }) {
this.copyOnSelect = opts.copyOnSelect;
this._onFirstMouseMove = this._onFirstMouseMove.bind(this);
this._onMouseMove = this._onMouseMove.bind(this);
this._onMouseDown = this._onMouseDown.bind(this);
this._onKeyDown = this._onKeyDown.bind(this);
this._onFrameLoaded = this._onFrameLoaded.bind(this);
this._chromeWindow = chromeWindow;
this._chromeDocument = chromeWindow.document;
this._dragging = true;
this.loaded = false;
this.format = Services.prefs.getCharPref(FORMAT_PREF); // color value format
this.zoom = Services.prefs.getIntPref(ZOOM_PREF); // zoom level - integer
this._zoomArea = {
x: 0, // the left coordinate of the center of the inspected region
y: 0, // the top coordinate of the center of the inspected region
width: CANVAS_WIDTH, // width of canvas to draw zoomed area onto
height: CANVAS_WIDTH // height of canvas
};
EventEmitter.decorate(this);
}
exports.Eyedropper = Eyedropper;
Eyedropper.prototype = {
/**
* Get the number of cells (blown-up pixels) per direction in the grid.
*/
get cellsWide() {
// Canvas will render whole "pixels" (cells) only, and an even
// number at that. Round up to the nearest even number of pixels.
let cellsWide = Math.ceil(this._zoomArea.width / this.zoom);
cellsWide += cellsWide % 2;
return cellsWide;
},
/**
* Get the size of each cell (blown-up pixel) in the grid.
*/
get cellSize() {
return this._zoomArea.width / this.cellsWide;
},
/**
* Get index of cell in the center of the grid.
*/
get centerCell() {
return Math.floor(this.cellsWide / 2);
},
/**
* Get color of center cell in the grid.
*/
get centerColor() {
let x = y = (this.centerCell * this.cellSize) + (this.cellSize / 2);
let rgb = this._ctx.getImageData(x, y, 1, 1).data;
return rgb;
},
/**
* Start the eyedropper. Add listeners for a mouse move in the window to
* show the eyedropper.
*/
open: function() {
if (this.isOpen) {
// the eyedropper is aready open, don't create another panel.
return;
}
this.isOpen = true;
this._OS = XULRuntime.OS;
this._chromeDocument.addEventListener("mousemove", this._onFirstMouseMove);
this._showCrosshairs();
},
/**
* Called on the first mouse move over the window. Opens the eyedropper
* panel where the mouse is.
*/
_onFirstMouseMove: function(event) {
this._chromeDocument.removeEventListener("mousemove", this._onFirstMouseMove);
this._panel = this._buildPanel();
let popupSet = this._chromeDocument.querySelector("#mainPopupSet");
popupSet.appendChild(this._panel);
let { panelX, panelY } = this._getPanelCoordinates(event);
this._panel.openPopupAtScreen(panelX, panelY);
this._setCoordinates(event);
this._addListeners();
// hide cursor as we'll be showing the panel over the mouse instead.
this._hideCrosshairs();
this._hideCursor();
},
/**
* Set the current coordinates to inspect from where a mousemove originated.
*
* @param {MouseEvent} event
* Event for the mouse move.
*/
_setCoordinates: function(event) {
let win = this._chromeWindow;
let x, y;
if (this._OS == "Linux") {
// event.clientX is off on Linux, so calculate it by hand
let windowX = win.screenX + (win.outerWidth - win.innerWidth);
x = event.screenX - windowX;
let windowY = win.screenY + (win.outerHeight - win.innerHeight);
y = event.screenY - windowY;
}
else {
x = event.clientX;
y = event.clientY;
}
// don't let it inspect outside the browser window
x = Math.max(0, Math.min(x, win.outerWidth - 1));
y = Math.max(0, Math.min(y, win.outerHeight - 1));
this._zoomArea.x = x;
this._zoomArea.y = y;
},
/**
* Build and add a new eyedropper panel to the window.
*
* @return {Panel}
* The XUL panel holding the eyedropper UI.
*/
_buildPanel: function() {
let panel = this._chromeDocument.createElement("panel");
panel.setAttribute("noautofocus", true);
panel.setAttribute("noautohide", true);
panel.setAttribute("level", "floating");
panel.setAttribute("class", "devtools-eyedropper-panel");
let iframe = this._iframe = this._chromeDocument.createElement("iframe");
iframe.addEventListener("load", this._onFrameLoaded, true);
iframe.setAttribute("flex", "1");
iframe.setAttribute("transparent", "transparent");
iframe.setAttribute("allowTransparency", true);
iframe.setAttribute("class", "devtools-eyedropper-iframe");
iframe.setAttribute("src", EYEDROPPER_URL);
iframe.setAttribute("width", CANVAS_WIDTH);
iframe.setAttribute("height", CANVAS_WIDTH);
panel.appendChild(iframe);
return panel;
},
/**
* Event handler for the panel's iframe's load event. Emits
* a "load" event from this eyedropper object.
*/
_onFrameLoaded: function() {
this._iframe.removeEventListener("load", this._onFrameLoaded, true);
this._iframeDocument = this._iframe.contentDocument;
this._colorPreview = this._iframeDocument.querySelector("#color-preview");
this._colorValue = this._iframeDocument.querySelector("#color-value");
// value box will be too long for hex values and too short for hsl
let valueBox = this._iframeDocument.querySelector("#color-value-box");
if (this.format == "hex") {
valueBox.style.width = HEX_BOX_WIDTH + "px";
}
else if (this.format == "hsl") {
valueBox.style.width = HSL_BOX_WIDTH + "px";
}
this._canvas = this._iframeDocument.querySelector("#canvas");
this._ctx = this._canvas.getContext("2d");
// so we preserve the clear pixel boundaries
this._ctx.mozImageSmoothingEnabled = false;
this._drawWindow();
this._addPanelListeners();
this._iframe.focus();
this.loaded = true;
this.emit("load");
},
/**
* Add key listeners to the panel.
*/
_addPanelListeners: function() {
this._iframeDocument.addEventListener("keydown", this._onKeyDown);
let closeCmd = this._iframeDocument.getElementById("eyedropper-cmd-close");
closeCmd.addEventListener("command", this.destroy.bind(this), true);
let copyCmd = this._iframeDocument.getElementById("eyedropper-cmd-copy");
copyCmd.addEventListener("command", this.selectColor.bind(this), true);
},
/**
* Remove listeners from the panel.
*/
_removePanelListeners: function() {
this._iframeDocument.removeEventListener("keydown", this._onKeyDown);
},
/**
* Add mouse event listeners to the document we're inspecting.
*/
_addListeners: function() {
this._chromeDocument.addEventListener("mousemove", this._onMouseMove);
this._chromeDocument.addEventListener("mousedown", this._onMouseDown);
},
/**
* Remove mouse event listeners from the document we're inspecting.
*/
_removeListeners: function() {
this._chromeDocument.removeEventListener("mousemove", this._onFirstMouseMove);
this._chromeDocument.removeEventListener("mousemove", this._onMouseMove);
this._chromeDocument.removeEventListener("mousedown", this._onMouseDown);
},
/**
* Hide the cursor.
*/
_hideCursor: function() {
registerStyleSheet(NOCURSOR_URL);
},
/**
* Reset the cursor back to default.
*/
_resetCursor: function() {
unregisterStyleSheet(NOCURSOR_URL);
},
/**
* Show a crosshairs as the mouse cursor
*/
_showCrosshairs: function() {
registerStyleSheet(CROSSHAIRS_URL);
},
/**
* Reset cursor.
*/
_hideCrosshairs: function() {
unregisterStyleSheet(CROSSHAIRS_URL);
},
/**
* Event handler for a mouse move over the page we're inspecting.
* Preview the area under the cursor, and move panel to be under the cursor.
*
* @param {DOMEvent} event
* MouseEvent for the mouse moving
*/
_onMouseMove: function(event) {
if (!this._dragging || !this._panel || !this._canvas) {
return;
}
this._setCoordinates(event);
this._drawWindow();
let { panelX, panelY } = this._getPanelCoordinates(event);
this._movePanel(panelX, panelY);
},
/**
* Get coordinates of where the eyedropper panel should go based on
* the current coordinates of the mouse cursor.
*
* @param {MouseEvent} event
* object with properties 'screenX' and 'screenY'
*
* @return {object}
* object with properties 'panelX', 'panelY'
*/
_getPanelCoordinates: function({screenX, screenY}) {
let win = this._chromeWindow;
let offset = CANVAS_WIDTH / 2 + CANVAS_OFFSET;
let panelX = screenX - offset;
let windowX = win.screenX + (win.outerWidth - win.innerWidth);
let maxX = win.screenX + win.outerWidth - offset - 1;
let panelY = screenY - offset;
let windowY = win.screenY + (win.outerHeight - win.innerHeight);
let maxY = win.screenY + win.outerHeight - offset - 1;
// don't let the panel move outside the browser window
panelX = Math.max(windowX - offset, Math.min(panelX, maxX));
panelY = Math.max(windowY - offset, Math.min(panelY, maxY));
return { panelX: panelX, panelY: panelY };
},
/**
* Move the eyedropper panel to the given coordinates.
*
* @param {number} screenX
* left coordinate on the screen
* @param {number} screenY
* top coordinate
*/
_movePanel: function(screenX, screenY) {
this._panelX = screenX;
this._panelY = screenY;
this._panel.moveTo(screenX, screenY);
},
/**
* Handler for the mouse down event on the inspected page. This means a
* click, so we'll select the color that's currently hovered.
*
* @param {Event} event
* DOM MouseEvent object
*/
_onMouseDown: function(event) {
event.preventDefault();
event.stopPropagation();
this.selectColor();
},
/**
* Select the current color that's being previewed. Fire a
* "select" event with the color as an rgb string.
*/
selectColor: function() {
if (this._isSelecting) {
return;
}
this._isSelecting = true;
this._dragging = false;
this.emit("select", this._colorValue.value);
if (this.copyOnSelect) {
this.copyColor(this.destroy.bind(this));
}
else {
this.destroy();
}
},
/**
* Copy the currently inspected color to the clipboard.
*
* @param {Function} callback
* Callback to be called when the color is in the clipboard.
*/
copyColor: function(callback) {
Services.appShell.hiddenDOMWindow.clearTimeout(this._copyTimeout);
let color = this._colorValue.value;
clipboardHelper.copyString(color);
this._colorValue.classList.add("highlight");
this._colorValue.value = "✓ " + l10n.GetStringFromName("colorValue.copied");
this._copyTimeout = Services.appShell.hiddenDOMWindow.setTimeout(() => {
this._colorValue.classList.remove("highlight");
this._colorValue.value = color;
if (callback) {
callback();
}
}, CLOSE_DELAY);
},
/**
* Handler for the keydown event on the panel. Either copy the color
* or move the panel in a direction depending on the key pressed.
*
* @param {Event} event
* DOM KeyboardEvent object
*/
_onKeyDown: function(event) {
if (event.metaKey && event.keyCode === event.DOM_VK_C) {
this.copyColor();
return;
}
let offsetX = 0;
let offsetY = 0;
let modifier = 1;
if (event.keyCode === event.DOM_VK_LEFT) {
offsetX = -1;
}
if (event.keyCode === event.DOM_VK_RIGHT) {
offsetX = 1;
}
if (event.keyCode === event.DOM_VK_UP) {
offsetY = -1;
}
if (event.keyCode === event.DOM_VK_DOWN) {
offsetY = 1;
}
if (event.shiftKey) {
modifier = 10;
}
offsetY *= modifier;
offsetX *= modifier;
if (offsetX !== 0 || offsetY !== 0) {
this._zoomArea.x += offsetX;
this._zoomArea.y += offsetY;
this._drawWindow();
this._movePanel(this._panelX + offsetX, this._panelY + offsetY);
event.preventDefault();
}
},
/**
* Draw the inspected area onto the canvas using the zoom level.
*/
_drawWindow: function() {
let { width, height, x, y } = this._zoomArea;
let zoomedWidth = width / this.zoom;
let zoomedHeight = height / this.zoom;
let drawX = x - (zoomedWidth / 2);
let drawY = y - (zoomedHeight / 2);
// draw the portion of the window we're inspecting
this._ctx.drawWindow(this._chromeWindow, drawX, drawY, zoomedWidth,
zoomedHeight, "white");
// now scale it
let sx = 0;
let sy = 0;
let sw = zoomedWidth;
let sh = zoomedHeight;
let dx = 0;
let dy = 0;
let dw = width;
let dh = height;
this._ctx.drawImage(this._canvas, sx, sy, sw, sh, dx, dy, dw, dh);
let rgb = this.centerColor;
this._colorPreview.style.backgroundColor = toColorString(rgb, "rgb");
this._colorValue.value = toColorString(rgb, this.format);
if (this.zoom > 2) {
// grid at 2x is too busy
this._drawGrid();
}
this._drawCrosshair();
},
/**
* Draw a grid on the canvas representing pixel boundaries.
*/
_drawGrid: function() {
let { width, height } = this._zoomArea;
this._ctx.lineWidth = 1;
this._ctx.strokeStyle = "rgba(143, 143, 143, 0.2)";
for (let i = 0; i < width; i += this.cellSize) {
this._ctx.beginPath();
this._ctx.moveTo(i - .5, 0);
this._ctx.lineTo(i - .5, height);
this._ctx.stroke();
this._ctx.beginPath();
this._ctx.moveTo(0, i - .5);
this._ctx.lineTo(width, i - .5);
this._ctx.stroke();
}
},
/**
* Draw a box on the canvas to highlight the center cell.
*/
_drawCrosshair: function() {
let x = y = this.centerCell * this.cellSize;
this._ctx.lineWidth = 1;
this._ctx.lineJoin = 'miter';
this._ctx.strokeStyle = "rgba(0, 0, 0, 1)";
this._ctx.strokeRect(x - 1.5, y - 1.5, this.cellSize + 2, this.cellSize + 2);
this._ctx.strokeStyle = "rgba(255, 255, 255, 1)";
this._ctx.strokeRect(x - 0.5, y - 0.5, this.cellSize, this.cellSize);
},
/**
* Destroy the eyedropper and clean up. Emits a "destroy" event.
*/
destroy: function() {
this._resetCursor();
this._hideCrosshairs();
if (this._panel) {
this._panel.hidePopup();
this._panel.remove();
this._panel = null;
}
this._removePanelListeners();
this._removeListeners();
this.isOpen = false;
this._isSelecting = false;
this.emit("destroy");
}
}
/**
* Add a user style sheet that applies to all documents.
*/
function registerStyleSheet(url) {
var uri = ioService.newURI(url, null, null);
if (!ssService.sheetRegistered(uri, ssService.AGENT_SHEET)) {
ssService.loadAndRegisterSheet(uri, ssService.AGENT_SHEET);
}
}
/**
* Remove a user style sheet.
*/
function unregisterStyleSheet(url) {
var uri = ioService.newURI(url, null, null);
if (ssService.sheetRegistered(uri, ssService.AGENT_SHEET)) {
ssService.unregisterSheet(uri, ssService.AGENT_SHEET);
}
}
/**
* Get a formatted CSS color string from a color value.
*
* @param {array} rgb
* Rgb values of a color to format
* @param {string} format
* Format of string. One of "hex", "rgb", "hsl", "name"
*
* @return {string}
* Formatted color value, e.g. "#FFF" or "hsl(20, 10%, 10%)"
*/
function toColorString(rgb, format) {
let [r,g,b] = rgb;
switch(format) {
case "hex":
return hexString(rgb);
case "rgb":
return "rgb(" + r + ", " + g + ", " + b + ")";
case "hsl":
let [h,s,l] = rgbToHsl(rgb);
return "hsl(" + h + ", " + s + "%, " + l + "%)";
case "name":
let str;
try {
str = DOMUtils.rgbToColorName(r, g, b);
} catch(e) {
str = hexString(rgb);
}
return str;
default:
return hexString(rgb);
}
}
/**
* Produce a hex-formatted color string from rgb values.
*
* @param {array} rgb
* Rgb values of color to stringify
*
* @return {string}
* Hex formatted string for color, e.g. "#FFEE00"
*/
function hexString([r,g,b]) {
let val = (1 << 24) + (r << 16) + (g << 8) + (b << 0);
return "#" + val.toString(16).substr(-6).toUpperCase();
}

Просмотреть файл

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<!DOCTYPE window []>
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/eyedropper.css" type="text/css"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<commandset id="eyedropper-commandset">
<command id="eyedropper-cmd-close"
oncommand="void(0);"/>
<command id="eyedropper-cmd-copy"
oncommand="void(0);"/>
</commandset>
<keyset id="eyedropper-keyset">
<key id="eyedropper-key-escape"
keycode="VK_ESCAPE"
command="eyedropper-cmd-close"/>
<key id="eyedropper-key-enter"
keycode="VK_RETURN"
command="eyedropper-cmd-copy"/>
</keyset>
<box id="canvas-overflow">
<canvas id="canvas" xmlns="http://www.w3.org/1999/xhtml" width="96" height="96">
</canvas>
</box>
<hbox id="color-value-container">
<hbox id="color-value-box">
<box id="color-preview">
</box>
<label id="color-value" class="devtools-monospace">
</label>
</hbox>
</hbox>
</window>

Просмотреть файл

@ -0,0 +1,13 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_DIRS += ['test']
JS_MODULES_PATH = 'modules/devtools/eyedropper'
EXTRA_JS_MODULES += [
'eyedropper.js'
]

Просмотреть файл

@ -0,0 +1,3 @@
* {
cursor: none !important;
}

Просмотреть файл

@ -0,0 +1,8 @@
[DEFAULT]
skip-if = e10s # Bug ?????? - devtools tests disabled with e10s
support-files =
color-block.html
head.js
[browser_eyedropper_basic.js]
skip-if = os == "win" && debug # bug 963492

Просмотреть файл

@ -0,0 +1,75 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TESTCASE_URI = TEST_BASE + "color-block.html";
const DIV_COLOR = "#0000FF";
/**
* Test basic eyedropper widget functionality:
* - Opening eyedropper and pressing ESC closes the eyedropper
* - Opening eyedropper and clicking copies the center color
*/
function test() {
addTab(TESTCASE_URI).then(testEscape);
}
function testEscape() {
let dropper = new Eyedropper(window);
dropper.once("destroy", (event) => {
ok(true, "escape closed the eyedropper");
// now test selecting a color
testSelect();
});
inspectPage(dropper, false).then(pressESC);
}
function testSelect() {
let dropper = new Eyedropper(window);
dropper.once("select", (event, color) => {
is(color, DIV_COLOR, "correct color selected");
});
// wait for DIV_COLOR to be copied to the clipboard then finish the test.
waitForClipboard(DIV_COLOR, () => {
inspectPage(dropper); // setup: inspect the page
}, finish, finish);
}
/* Helpers */
function inspectPage(dropper, click=true) {
dropper.open();
let target = content.document.getElementById("test");
let win = content.window;
EventUtils.synthesizeMouse(target, 20, 20, { type: "mousemove" }, win);
return dropperLoaded(dropper).then(() => {
EventUtils.synthesizeMouse(target, 30, 30, { type: "mousemove" }, win);
if (click) {
EventUtils.synthesizeMouse(target, 30, 30, {}, win);
}
});
}
function pressESC() {
EventUtils.synthesizeKey("VK_ESCAPE", { });
}
function dropperLoaded(dropper) {
if (dropper.loaded) {
return promise.resolve();
}
let deferred = promise.defer();
dropper.once("load", deferred.resolve);
return deferred.promise;
}

Просмотреть файл

@ -0,0 +1,22 @@
<!doctype html>
<html>
<head>
<title>basic eyedropper test case</title>
<style type="text/css">
body {
background: #f99;
}
#test {
margin: 100px;
background-color: blue;
width: 200px;
height: 200px;
}
</style>
</head>
<body>
<div id="test">
</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const TEST_BASE = "chrome://mochitests/content/browser/browser/devtools/eyedropper/test/";
const TEST_HOST = 'mochi.test:8888';
const promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise;
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
const { Eyedropper } = require("devtools/eyedropper/eyedropper");
waitForExplicitFinish();
function cleanup()
{
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
}
registerCleanupFunction(cleanup);
function addTab(uri) {
let deferred = promise.defer();
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
gBrowser.selectedBrowser.addEventListener("load", function onLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onLoad, true);
deferred.resolve(tab);
}, true);
content.location = uri;
return deferred.promise;
}

Просмотреть файл

@ -0,0 +1,6 @@
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']

Просмотреть файл

@ -108,3 +108,7 @@ browser.jar:
content/browser/devtools/app-manager/manifest-editor.js (app-manager/content/manifest-editor.js)
content/browser/devtools/spectrum-frame.xhtml (shared/widgets/spectrum-frame.xhtml)
content/browser/devtools/spectrum.css (shared/widgets/spectrum.css)
content/browser/devtools/eyedropper.xul (eyedropper/eyedropper.xul)
content/browser/devtools/eyedropper/crosshairs.css (eyedropper/crosshairs.css)
content/browser/devtools/eyedropper/nocursor.css (eyedropper/nocursor.css)

Просмотреть файл

@ -9,6 +9,7 @@ DIRS += [
'canvasdebugger',
'commandline',
'debugger',
'eyedropper',
'fontinspector',
'framework',
'inspector',

Просмотреть файл

@ -147,158 +147,158 @@ function finishUp() {
function getTestData() {
return [
{authored: "aliceblue", name: "aliceblue", hex: "#F0F8FF", hsl: "hsl(208, 100%, 97%)", rgb: "rgb(240, 248, 255)"},
{authored: "antiquewhite", name: "antiquewhite", hex: "#FAEBD7", hsl: "hsl(34.286, 78%, 91%)", rgb: "rgb(250, 235, 215)"},
{authored: "antiquewhite", name: "antiquewhite", hex: "#FAEBD7", hsl: "hsl(34, 78%, 91%)", rgb: "rgb(250, 235, 215)"},
{authored: "aqua", name: "aqua", hex: "#0FF", hsl: "hsl(180, 100%, 50%)", rgb: "rgb(0, 255, 255)"},
{authored: "aquamarine", name: "aquamarine", hex: "#7FFFD4", hsl: "hsl(159.844, 100%, 75%)", rgb: "rgb(127, 255, 212)"},
{authored: "aquamarine", name: "aquamarine", hex: "#7FFFD4", hsl: "hsl(160, 100%, 75%)", rgb: "rgb(127, 255, 212)"},
{authored: "azure", name: "azure", hex: "#F0FFFF", hsl: "hsl(180, 100%, 97%)", rgb: "rgb(240, 255, 255)"},
{authored: "beige", name: "beige", hex: "#F5F5DC", hsl: "hsl(60, 56%, 91%)", rgb: "rgb(245, 245, 220)"},
{authored: "bisque", name: "bisque", hex: "#FFE4C4", hsl: "hsl(32.542, 100%, 88%)", rgb: "rgb(255, 228, 196)"},
{authored: "bisque", name: "bisque", hex: "#FFE4C4", hsl: "hsl(33, 100%, 88%)", rgb: "rgb(255, 228, 196)"},
{authored: "black", name: "black", hex: "#000", hsl: "hsl(0, 0%, 0%)", rgb: "rgb(0, 0, 0)"},
{authored: "blanchedalmond", name: "blanchedalmond", hex: "#FFEBCD", hsl: "hsl(36, 100%, 90%)", rgb: "rgb(255, 235, 205)"},
{authored: "blue", name: "blue", hex: "#00F", hsl: "hsl(240, 100%, 50%)", rgb: "rgb(0, 0, 255)"},
{authored: "blueviolet", name: "blueviolet", hex: "#8A2BE2", hsl: "hsl(271.148, 76%, 53%)", rgb: "rgb(138, 43, 226)"},
{authored: "blueviolet", name: "blueviolet", hex: "#8A2BE2", hsl: "hsl(271, 76%, 53%)", rgb: "rgb(138, 43, 226)"},
{authored: "brown", name: "brown", hex: "#A52A2A", hsl: "hsl(0, 59%, 41%)", rgb: "rgb(165, 42, 42)"},
{authored: "burlywood", name: "burlywood", hex: "#DEB887", hsl: "hsl(33.793, 57%, 70%)", rgb: "rgb(222, 184, 135)"},
{authored: "cadetblue", name: "cadetblue", hex: "#5F9EA0", hsl: "hsl(181.846, 25%, 50%)", rgb: "rgb(95, 158, 160)"},
{authored: "chartreuse", name: "chartreuse", hex: "#7FFF00", hsl: "hsl(90.118, 100%, 50%)", rgb: "rgb(127, 255, 0)"},
{authored: "burlywood", name: "burlywood", hex: "#DEB887", hsl: "hsl(34, 57%, 70%)", rgb: "rgb(222, 184, 135)"},
{authored: "cadetblue", name: "cadetblue", hex: "#5F9EA0", hsl: "hsl(182, 25%, 50%)", rgb: "rgb(95, 158, 160)"},
{authored: "chartreuse", name: "chartreuse", hex: "#7FFF00", hsl: "hsl(90, 100%, 50%)", rgb: "rgb(127, 255, 0)"},
{authored: "chocolate", name: "chocolate", hex: "#D2691E", hsl: "hsl(25, 75%, 47%)", rgb: "rgb(210, 105, 30)"},
{authored: "coral", name: "coral", hex: "#FF7F50", hsl: "hsl(16.114, 100%, 66%)", rgb: "rgb(255, 127, 80)"},
{authored: "cornflowerblue", name: "cornflowerblue", hex: "#6495ED", hsl: "hsl(218.54, 79%, 66%)", rgb: "rgb(100, 149, 237)"},
{authored: "coral", name: "coral", hex: "#FF7F50", hsl: "hsl(16, 100%, 66%)", rgb: "rgb(255, 127, 80)"},
{authored: "cornflowerblue", name: "cornflowerblue", hex: "#6495ED", hsl: "hsl(219, 79%, 66%)", rgb: "rgb(100, 149, 237)"},
{authored: "cornsilk", name: "cornsilk", hex: "#FFF8DC", hsl: "hsl(48, 100%, 93%)", rgb: "rgb(255, 248, 220)"},
{authored: "crimson", name: "crimson", hex: "#DC143C", hsl: "hsl(348, 83%, 47%)", rgb: "rgb(220, 20, 60)"},
{authored: "cyan", name: "aqua", hex: "#0FF", hsl: "hsl(180, 100%, 50%)", rgb: "rgb(0, 255, 255)"},
{authored: "darkblue", name: "darkblue", hex: "#00008B", hsl: "hsl(240, 100%, 27%)", rgb: "rgb(0, 0, 139)"},
{authored: "darkcyan", name: "darkcyan", hex: "#008B8B", hsl: "hsl(180, 100%, 27%)", rgb: "rgb(0, 139, 139)"},
{authored: "darkgoldenrod", name: "darkgoldenrod", hex: "#B8860B", hsl: "hsl(42.659, 89%, 38%)", rgb: "rgb(184, 134, 11)"},
{authored: "darkgoldenrod", name: "darkgoldenrod", hex: "#B8860B", hsl: "hsl(43, 89%, 38%)", rgb: "rgb(184, 134, 11)"},
{authored: "darkgray", name: "darkgray", hex: "#A9A9A9", hsl: "hsl(0, 0%, 66%)", rgb: "rgb(169, 169, 169)"},
{authored: "darkgreen", name: "darkgreen", hex: "#006400", hsl: "hsl(120, 100%, 20%)", rgb: "rgb(0, 100, 0)"},
{authored: "darkgrey", name: "darkgray", hex: "#A9A9A9", hsl: "hsl(0, 0%, 66%)", rgb: "rgb(169, 169, 169)"},
{authored: "darkkhaki", name: "darkkhaki", hex: "#BDB76B", hsl: "hsl(55.61, 38%, 58%)", rgb: "rgb(189, 183, 107)"},
{authored: "darkkhaki", name: "darkkhaki", hex: "#BDB76B", hsl: "hsl(56, 38%, 58%)", rgb: "rgb(189, 183, 107)"},
{authored: "darkmagenta", name: "darkmagenta", hex: "#8B008B", hsl: "hsl(300, 100%, 27%)", rgb: "rgb(139, 0, 139)"},
{authored: "darkolivegreen", name: "darkolivegreen", hex: "#556B2F", hsl: "hsl(82, 39%, 30%)", rgb: "rgb(85, 107, 47)"},
{authored: "darkorange", name: "darkorange", hex: "#FF8C00", hsl: "hsl(32.941, 100%, 50%)", rgb: "rgb(255, 140, 0)"},
{authored: "darkorchid", name: "darkorchid", hex: "#9932CC", hsl: "hsl(280.13, 61%, 50%)", rgb: "rgb(153, 50, 204)"},
{authored: "darkorange", name: "darkorange", hex: "#FF8C00", hsl: "hsl(33, 100%, 50%)", rgb: "rgb(255, 140, 0)"},
{authored: "darkorchid", name: "darkorchid", hex: "#9932CC", hsl: "hsl(280, 61%, 50%)", rgb: "rgb(153, 50, 204)"},
{authored: "darkred", name: "darkred", hex: "#8B0000", hsl: "hsl(0, 100%, 27%)", rgb: "rgb(139, 0, 0)"},
{authored: "darksalmon", name: "darksalmon", hex: "#E9967A", hsl: "hsl(15.135, 72%, 70%)", rgb: "rgb(233, 150, 122)"},
{authored: "darksalmon", name: "darksalmon", hex: "#E9967A", hsl: "hsl(15, 72%, 70%)", rgb: "rgb(233, 150, 122)"},
{authored: "darkseagreen", name: "darkseagreen", hex: "#8FBC8F", hsl: "hsl(120, 25%, 65%)", rgb: "rgb(143, 188, 143)"},
{authored: "darkslateblue", name: "darkslateblue", hex: "#483D8B", hsl: "hsl(248.462, 39%, 39%)", rgb: "rgb(72, 61, 139)"},
{authored: "darkslateblue", name: "darkslateblue", hex: "#483D8B", hsl: "hsl(248, 39%, 39%)", rgb: "rgb(72, 61, 139)"},
{authored: "darkslategray", name: "darkslategray", hex: "#2F4F4F", hsl: "hsl(180, 25%, 25%)", rgb: "rgb(47, 79, 79)"},
{authored: "darkslategrey", name: "darkslategray", hex: "#2F4F4F", hsl: "hsl(180, 25%, 25%)", rgb: "rgb(47, 79, 79)"},
{authored: "darkturquoise", name: "darkturquoise", hex: "#00CED1", hsl: "hsl(180.861, 100%, 41%)", rgb: "rgb(0, 206, 209)"},
{authored: "darkviolet", name: "darkviolet", hex: "#9400D3", hsl: "hsl(282.085, 100%, 41%)", rgb: "rgb(148, 0, 211)"},
{authored: "deeppink", name: "deeppink", hex: "#FF1493", hsl: "hsl(327.574, 100%, 54%)", rgb: "rgb(255, 20, 147)"},
{authored: "deepskyblue", name: "deepskyblue", hex: "#00BFFF", hsl: "hsl(195.059, 100%, 50%)", rgb: "rgb(0, 191, 255)"},
{authored: "darkturquoise", name: "darkturquoise", hex: "#00CED1", hsl: "hsl(181, 100%, 41%)", rgb: "rgb(0, 206, 209)"},
{authored: "darkviolet", name: "darkviolet", hex: "#9400D3", hsl: "hsl(282, 100%, 41%)", rgb: "rgb(148, 0, 211)"},
{authored: "deeppink", name: "deeppink", hex: "#FF1493", hsl: "hsl(328, 100%, 54%)", rgb: "rgb(255, 20, 147)"},
{authored: "deepskyblue", name: "deepskyblue", hex: "#00BFFF", hsl: "hsl(195, 100%, 50%)", rgb: "rgb(0, 191, 255)"},
{authored: "dimgray", name: "dimgray", hex: "#696969", hsl: "hsl(0, 0%, 41%)", rgb: "rgb(105, 105, 105)"},
{authored: "dodgerblue", name: "dodgerblue", hex: "#1E90FF", hsl: "hsl(209.6, 100%, 56%)", rgb: "rgb(30, 144, 255)"},
{authored: "dodgerblue", name: "dodgerblue", hex: "#1E90FF", hsl: "hsl(210, 100%, 56%)", rgb: "rgb(30, 144, 255)"},
{authored: "firebrick", name: "firebrick", hex: "#B22222", hsl: "hsl(0, 68%, 42%)", rgb: "rgb(178, 34, 34)"},
{authored: "floralwhite", name: "floralwhite", hex: "#FFFAF0", hsl: "hsl(40, 100%, 97%)", rgb: "rgb(255, 250, 240)"},
{authored: "forestgreen", name: "forestgreen", hex: "#228B22", hsl: "hsl(120, 61%, 34%)", rgb: "rgb(34, 139, 34)"},
{authored: "fuchsia", name: "fuchsia", hex: "#F0F", hsl: "hsl(300, 100%, 50%)", rgb: "rgb(255, 0, 255)"},
{authored: "gainsboro", name: "gainsboro", hex: "#DCDCDC", hsl: "hsl(0, 0%, 86%)", rgb: "rgb(220, 220, 220)"},
{authored: "ghostwhite", name: "ghostwhite", hex: "#F8F8FF", hsl: "hsl(240, 100%, 99%)", rgb: "rgb(248, 248, 255)"},
{authored: "gold", name: "gold", hex: "#FFD700", hsl: "hsl(50.588, 100%, 50%)", rgb: "rgb(255, 215, 0)"},
{authored: "goldenrod", name: "goldenrod", hex: "#DAA520", hsl: "hsl(42.903, 74%, 49%)", rgb: "rgb(218, 165, 32)"},
{authored: "gold", name: "gold", hex: "#FFD700", hsl: "hsl(51, 100%, 50%)", rgb: "rgb(255, 215, 0)"},
{authored: "goldenrod", name: "goldenrod", hex: "#DAA520", hsl: "hsl(43, 74%, 49%)", rgb: "rgb(218, 165, 32)"},
{authored: "gray", name: "gray", hex: "#808080", hsl: "hsl(0, 0%, 50%)", rgb: "rgb(128, 128, 128)"},
{authored: "green", name: "green", hex: "#008000", hsl: "hsl(120, 100%, 25%)", rgb: "rgb(0, 128, 0)"},
{authored: "greenyellow", name: "greenyellow", hex: "#ADFF2F", hsl: "hsl(83.654, 100%, 59%)", rgb: "rgb(173, 255, 47)"},
{authored: "greenyellow", name: "greenyellow", hex: "#ADFF2F", hsl: "hsl(84, 100%, 59%)", rgb: "rgb(173, 255, 47)"},
{authored: "grey", name: "gray", hex: "#808080", hsl: "hsl(0, 0%, 50%)", rgb: "rgb(128, 128, 128)"},
{authored: "honeydew", name: "honeydew", hex: "#F0FFF0", hsl: "hsl(120, 100%, 97%)", rgb: "rgb(240, 255, 240)"},
{authored: "hotpink", name: "hotpink", hex: "#FF69B4", hsl: "hsl(330, 100%, 71%)", rgb: "rgb(255, 105, 180)"},
{authored: "indianred", name: "indianred", hex: "#CD5C5C", hsl: "hsl(0, 53%, 58%)", rgb: "rgb(205, 92, 92)"},
{authored: "indigo", name: "indigo", hex: "#4B0082", hsl: "hsl(274.615, 100%, 25%)", rgb: "rgb(75, 0, 130)"},
{authored: "indigo", name: "indigo", hex: "#4B0082", hsl: "hsl(275, 100%, 25%)", rgb: "rgb(75, 0, 130)"},
{authored: "ivory", name: "ivory", hex: "#FFFFF0", hsl: "hsl(60, 100%, 97%)", rgb: "rgb(255, 255, 240)"},
{authored: "khaki", name: "khaki", hex: "#F0E68C", hsl: "hsl(54, 77%, 75%)", rgb: "rgb(240, 230, 140)"},
{authored: "lavender", name: "lavender", hex: "#E6E6FA", hsl: "hsl(240, 67%, 94%)", rgb: "rgb(230, 230, 250)"},
{authored: "lavenderblush", name: "lavenderblush", hex: "#FFF0F5", hsl: "hsl(340, 100%, 97%)", rgb: "rgb(255, 240, 245)"},
{authored: "lawngreen", name: "lawngreen", hex: "#7CFC00", hsl: "hsl(90.476, 100%, 49%)", rgb: "rgb(124, 252, 0)"},
{authored: "lawngreen", name: "lawngreen", hex: "#7CFC00", hsl: "hsl(90, 100%, 49%)", rgb: "rgb(124, 252, 0)"},
{authored: "lemonchiffon", name: "lemonchiffon", hex: "#FFFACD", hsl: "hsl(54, 100%, 90%)", rgb: "rgb(255, 250, 205)"},
{authored: "lightblue", name: "lightblue", hex: "#ADD8E6", hsl: "hsl(194.737, 53%, 79%)", rgb: "rgb(173, 216, 230)"},
{authored: "lightblue", name: "lightblue", hex: "#ADD8E6", hsl: "hsl(195, 53%, 79%)", rgb: "rgb(173, 216, 230)"},
{authored: "lightcoral", name: "lightcoral", hex: "#F08080", hsl: "hsl(0, 79%, 72%)", rgb: "rgb(240, 128, 128)"},
{authored: "lightcyan", name: "lightcyan", hex: "#E0FFFF", hsl: "hsl(180, 100%, 94%)", rgb: "rgb(224, 255, 255)"},
{authored: "lightgoldenrodyellow", name: "lightgoldenrodyellow", hex: "#FAFAD2", hsl: "hsl(60, 80%, 90%)", rgb: "rgb(250, 250, 210)"},
{authored: "lightgray", name: "lightgray", hex: "#D3D3D3", hsl: "hsl(0, 0%, 83%)", rgb: "rgb(211, 211, 211)"},
{authored: "lightgreen", name: "lightgreen", hex: "#90EE90", hsl: "hsl(120, 73%, 75%)", rgb: "rgb(144, 238, 144)"},
{authored: "lightgrey", name: "lightgray", hex: "#D3D3D3", hsl: "hsl(0, 0%, 83%)", rgb: "rgb(211, 211, 211)"},
{authored: "lightpink", name: "lightpink", hex: "#FFB6C1", hsl: "hsl(350.959, 100%, 86%)", rgb: "rgb(255, 182, 193)"},
{authored: "lightsalmon", name: "lightsalmon", hex: "#FFA07A", hsl: "hsl(17.143, 100%, 74%)", rgb: "rgb(255, 160, 122)"},
{authored: "lightseagreen", name: "lightseagreen", hex: "#20B2AA", hsl: "hsl(176.712, 70%, 41%)", rgb: "rgb(32, 178, 170)"},
{authored: "lightskyblue", name: "lightskyblue", hex: "#87CEFA", hsl: "hsl(202.957, 92%, 75%)", rgb: "rgb(135, 206, 250)"},
{authored: "lightpink", name: "lightpink", hex: "#FFB6C1", hsl: "hsl(351, 100%, 86%)", rgb: "rgb(255, 182, 193)"},
{authored: "lightsalmon", name: "lightsalmon", hex: "#FFA07A", hsl: "hsl(17, 100%, 74%)", rgb: "rgb(255, 160, 122)"},
{authored: "lightseagreen", name: "lightseagreen", hex: "#20B2AA", hsl: "hsl(177, 70%, 41%)", rgb: "rgb(32, 178, 170)"},
{authored: "lightskyblue", name: "lightskyblue", hex: "#87CEFA", hsl: "hsl(203, 92%, 75%)", rgb: "rgb(135, 206, 250)"},
{authored: "lightslategray", name: "lightslategray", hex: "#789", hsl: "hsl(210, 14%, 53%)", rgb: "rgb(119, 136, 153)"},
{authored: "lightslategrey", name: "lightslategray", hex: "#789", hsl: "hsl(210, 14%, 53%)", rgb: "rgb(119, 136, 153)"},
{authored: "lightsteelblue", name: "lightsteelblue", hex: "#B0C4DE", hsl: "hsl(213.913, 41%, 78%)", rgb: "rgb(176, 196, 222)"},
{authored: "lightsteelblue", name: "lightsteelblue", hex: "#B0C4DE", hsl: "hsl(214, 41%, 78%)", rgb: "rgb(176, 196, 222)"},
{authored: "lightyellow", name: "lightyellow", hex: "#FFFFE0", hsl: "hsl(60, 100%, 94%)", rgb: "rgb(255, 255, 224)"},
{authored: "lime", name: "lime", hex: "#0F0", hsl: "hsl(120, 100%, 50%)", rgb: "rgb(0, 255, 0)"},
{authored: "limegreen", name: "limegreen", hex: "#32CD32", hsl: "hsl(120, 61%, 50%)", rgb: "rgb(50, 205, 50)"},
{authored: "linen", name: "linen", hex: "#FAF0E6", hsl: "hsl(30, 67%, 94%)", rgb: "rgb(250, 240, 230)"},
{authored: "magenta", name: "fuchsia", hex: "#F0F", hsl: "hsl(300, 100%, 50%)", rgb: "rgb(255, 0, 255)"},
{authored: "maroon", name: "maroon", hex: "#800000", hsl: "hsl(0, 100%, 25%)", rgb: "rgb(128, 0, 0)"},
{authored: "mediumaquamarine", name: "mediumaquamarine", hex: "#66CDAA", hsl: "hsl(159.612, 51%, 60%)", rgb: "rgb(102, 205, 170)"},
{authored: "mediumaquamarine", name: "mediumaquamarine", hex: "#66CDAA", hsl: "hsl(160, 51%, 60%)", rgb: "rgb(102, 205, 170)"},
{authored: "mediumblue", name: "mediumblue", hex: "#0000CD", hsl: "hsl(240, 100%, 40%)", rgb: "rgb(0, 0, 205)"},
{authored: "mediumorchid", name: "mediumorchid", hex: "#BA55D3", hsl: "hsl(288.095, 59%, 58%)", rgb: "rgb(186, 85, 211)"},
{authored: "mediumpurple", name: "mediumpurple", hex: "#9370DB", hsl: "hsl(259.626, 60%, 65%)", rgb: "rgb(147, 112, 219)"},
{authored: "mediumseagreen", name: "mediumseagreen", hex: "#3CB371", hsl: "hsl(146.723, 50%, 47%)", rgb: "rgb(60, 179, 113)"},
{authored: "mediumslateblue", name: "mediumslateblue", hex: "#7B68EE", hsl: "hsl(248.507, 80%, 67%)", rgb: "rgb(123, 104, 238)"},
{authored: "mediumspringgreen", name: "mediumspringgreen", hex: "#00FA9A", hsl: "hsl(156.96, 100%, 49%)", rgb: "rgb(0, 250, 154)"},
{authored: "mediumturquoise", name: "mediumturquoise", hex: "#48D1CC", hsl: "hsl(177.81, 60%, 55%)", rgb: "rgb(72, 209, 204)"},
{authored: "mediumvioletred", name: "mediumvioletred", hex: "#C71585", hsl: "hsl(322.247, 81%, 43%)", rgb: "rgb(199, 21, 133)"},
{authored: "mediumorchid", name: "mediumorchid", hex: "#BA55D3", hsl: "hsl(288, 59%, 58%)", rgb: "rgb(186, 85, 211)"},
{authored: "mediumpurple", name: "mediumpurple", hex: "#9370DB", hsl: "hsl(260, 60%, 65%)", rgb: "rgb(147, 112, 219)"},
{authored: "mediumseagreen", name: "mediumseagreen", hex: "#3CB371", hsl: "hsl(147, 50%, 47%)", rgb: "rgb(60, 179, 113)"},
{authored: "mediumslateblue", name: "mediumslateblue", hex: "#7B68EE", hsl: "hsl(249, 80%, 67%)", rgb: "rgb(123, 104, 238)"},
{authored: "mediumspringgreen", name: "mediumspringgreen", hex: "#00FA9A", hsl: "hsl(157, 100%, 49%)", rgb: "rgb(0, 250, 154)"},
{authored: "mediumturquoise", name: "mediumturquoise", hex: "#48D1CC", hsl: "hsl(178, 60%, 55%)", rgb: "rgb(72, 209, 204)"},
{authored: "mediumvioletred", name: "mediumvioletred", hex: "#C71585", hsl: "hsl(322, 81%, 43%)", rgb: "rgb(199, 21, 133)"},
{authored: "midnightblue", name: "midnightblue", hex: "#191970", hsl: "hsl(240, 64%, 27%)", rgb: "rgb(25, 25, 112)"},
{authored: "mintcream", name: "mintcream", hex: "#F5FFFA", hsl: "hsl(150, 100%, 98%)", rgb: "rgb(245, 255, 250)"},
{authored: "mistyrose", name: "mistyrose", hex: "#FFE4E1", hsl: "hsl(6, 100%, 94%)", rgb: "rgb(255, 228, 225)"},
{authored: "moccasin", name: "moccasin", hex: "#FFE4B5", hsl: "hsl(38.108, 100%, 85%)", rgb: "rgb(255, 228, 181)"},
{authored: "navajowhite", name: "navajowhite", hex: "#FFDEAD", hsl: "hsl(35.854, 100%, 84%)", rgb: "rgb(255, 222, 173)"},
{authored: "moccasin", name: "moccasin", hex: "#FFE4B5", hsl: "hsl(38, 100%, 85%)", rgb: "rgb(255, 228, 181)"},
{authored: "navajowhite", name: "navajowhite", hex: "#FFDEAD", hsl: "hsl(36, 100%, 84%)", rgb: "rgb(255, 222, 173)"},
{authored: "navy", name: "navy", hex: "#000080", hsl: "hsl(240, 100%, 25%)", rgb: "rgb(0, 0, 128)"},
{authored: "oldlace", name: "oldlace", hex: "#FDF5E6", hsl: "hsl(39.13, 85%, 95%)", rgb: "rgb(253, 245, 230)"},
{authored: "oldlace", name: "oldlace", hex: "#FDF5E6", hsl: "hsl(39, 85%, 95%)", rgb: "rgb(253, 245, 230)"},
{authored: "olive", name: "olive", hex: "#808000", hsl: "hsl(60, 100%, 25%)", rgb: "rgb(128, 128, 0)"},
{authored: "olivedrab", name: "olivedrab", hex: "#6B8E23", hsl: "hsl(79.626, 60%, 35%)", rgb: "rgb(107, 142, 35)"},
{authored: "orange", name: "orange", hex: "#FFA500", hsl: "hsl(38.824, 100%, 50%)", rgb: "rgb(255, 165, 0)"},
{authored: "orangered", name: "orangered", hex: "#FF4500", hsl: "hsl(16.235, 100%, 50%)", rgb: "rgb(255, 69, 0)"},
{authored: "orchid", name: "orchid", hex: "#DA70D6", hsl: "hsl(302.264, 59%, 65%)", rgb: "rgb(218, 112, 214)"},
{authored: "palegoldenrod", name: "palegoldenrod", hex: "#EEE8AA", hsl: "hsl(54.706, 67%, 80%)", rgb: "rgb(238, 232, 170)"},
{authored: "olivedrab", name: "olivedrab", hex: "#6B8E23", hsl: "hsl(80, 60%, 35%)", rgb: "rgb(107, 142, 35)"},
{authored: "orange", name: "orange", hex: "#FFA500", hsl: "hsl(39, 100%, 50%)", rgb: "rgb(255, 165, 0)"},
{authored: "orangered", name: "orangered", hex: "#FF4500", hsl: "hsl(16, 100%, 50%)", rgb: "rgb(255, 69, 0)"},
{authored: "orchid", name: "orchid", hex: "#DA70D6", hsl: "hsl(302, 59%, 65%)", rgb: "rgb(218, 112, 214)"},
{authored: "palegoldenrod", name: "palegoldenrod", hex: "#EEE8AA", hsl: "hsl(55, 67%, 80%)", rgb: "rgb(238, 232, 170)"},
{authored: "palegreen", name: "palegreen", hex: "#98FB98", hsl: "hsl(120, 93%, 79%)", rgb: "rgb(152, 251, 152)"},
{authored: "paleturquoise", name: "paleturquoise", hex: "#AFEEEE", hsl: "hsl(180, 65%, 81%)", rgb: "rgb(175, 238, 238)"},
{authored: "palevioletred", name: "palevioletred", hex: "#DB7093", hsl: "hsl(340.374, 60%, 65%)", rgb: "rgb(219, 112, 147)"},
{authored: "papayawhip", name: "papayawhip", hex: "#FFEFD5", hsl: "hsl(37.143, 100%, 92%)", rgb: "rgb(255, 239, 213)"},
{authored: "peachpuff", name: "peachpuff", hex: "#FFDAB9", hsl: "hsl(28.286, 100%, 86%)", rgb: "rgb(255, 218, 185)"},
{authored: "peru", name: "peru", hex: "#CD853F", hsl: "hsl(29.577, 59%, 53%)", rgb: "rgb(205, 133, 63)"},
{authored: "pink", name: "pink", hex: "#FFC0CB", hsl: "hsl(349.524, 100%, 88%)", rgb: "rgb(255, 192, 203)"},
{authored: "palevioletred", name: "palevioletred", hex: "#DB7093", hsl: "hsl(340, 60%, 65%)", rgb: "rgb(219, 112, 147)"},
{authored: "papayawhip", name: "papayawhip", hex: "#FFEFD5", hsl: "hsl(37, 100%, 92%)", rgb: "rgb(255, 239, 213)"},
{authored: "peachpuff", name: "peachpuff", hex: "#FFDAB9", hsl: "hsl(28, 100%, 86%)", rgb: "rgb(255, 218, 185)"},
{authored: "peru", name: "peru", hex: "#CD853F", hsl: "hsl(30, 59%, 53%)", rgb: "rgb(205, 133, 63)"},
{authored: "pink", name: "pink", hex: "#FFC0CB", hsl: "hsl(350, 100%, 88%)", rgb: "rgb(255, 192, 203)"},
{authored: "plum", name: "plum", hex: "#DDA0DD", hsl: "hsl(300, 47%, 75%)", rgb: "rgb(221, 160, 221)"},
{authored: "powderblue", name: "powderblue", hex: "#B0E0E6", hsl: "hsl(186.667, 52%, 80%)", rgb: "rgb(176, 224, 230)"},
{authored: "powderblue", name: "powderblue", hex: "#B0E0E6", hsl: "hsl(187, 52%, 80%)", rgb: "rgb(176, 224, 230)"},
{authored: "purple", name: "purple", hex: "#800080", hsl: "hsl(300, 100%, 25%)", rgb: "rgb(128, 0, 128)"},
{authored: "red", name: "red", hex: "#F00", hsl: "hsl(0, 100%, 50%)", rgb: "rgb(255, 0, 0)"},
{authored: "rosybrown", name: "rosybrown", hex: "#BC8F8F", hsl: "hsl(0, 25%, 65%)", rgb: "rgb(188, 143, 143)"},
{authored: "royalblue", name: "royalblue", hex: "#4169E1", hsl: "hsl(225, 73%, 57%)", rgb: "rgb(65, 105, 225)"},
{authored: "saddlebrown", name: "saddlebrown", hex: "#8B4513", hsl: "hsl(25, 76%, 31%)", rgb: "rgb(139, 69, 19)"},
{authored: "salmon", name: "salmon", hex: "#FA8072", hsl: "hsl(6.176, 93%, 71%)", rgb: "rgb(250, 128, 114)"},
{authored: "sandybrown", name: "sandybrown", hex: "#F4A460", hsl: "hsl(27.568, 87%, 67%)", rgb: "rgb(244, 164, 96)"},
{authored: "seagreen", name: "seagreen", hex: "#2E8B57", hsl: "hsl(146.452, 50%, 36%)", rgb: "rgb(46, 139, 87)"},
{authored: "seashell", name: "seashell", hex: "#FFF5EE", hsl: "hsl(24.706, 100%, 97%)", rgb: "rgb(255, 245, 238)"},
{authored: "sienna", name: "sienna", hex: "#A0522D", hsl: "hsl(19.304, 56%, 40%)", rgb: "rgb(160, 82, 45)"},
{authored: "salmon", name: "salmon", hex: "#FA8072", hsl: "hsl(6, 93%, 71%)", rgb: "rgb(250, 128, 114)"},
{authored: "sandybrown", name: "sandybrown", hex: "#F4A460", hsl: "hsl(28, 87%, 67%)", rgb: "rgb(244, 164, 96)"},
{authored: "seagreen", name: "seagreen", hex: "#2E8B57", hsl: "hsl(146, 50%, 36%)", rgb: "rgb(46, 139, 87)"},
{authored: "seashell", name: "seashell", hex: "#FFF5EE", hsl: "hsl(25, 100%, 97%)", rgb: "rgb(255, 245, 238)"},
{authored: "sienna", name: "sienna", hex: "#A0522D", hsl: "hsl(19, 56%, 40%)", rgb: "rgb(160, 82, 45)"},
{authored: "silver", name: "silver", hex: "#C0C0C0", hsl: "hsl(0, 0%, 75%)", rgb: "rgb(192, 192, 192)"},
{authored: "skyblue", name: "skyblue", hex: "#87CEEB", hsl: "hsl(197.4, 71%, 73%)", rgb: "rgb(135, 206, 235)"},
{authored: "slateblue", name: "slateblue", hex: "#6A5ACD", hsl: "hsl(248.348, 53%, 58%)", rgb: "rgb(106, 90, 205)"},
{authored: "skyblue", name: "skyblue", hex: "#87CEEB", hsl: "hsl(197, 71%, 73%)", rgb: "rgb(135, 206, 235)"},
{authored: "slateblue", name: "slateblue", hex: "#6A5ACD", hsl: "hsl(248, 53%, 58%)", rgb: "rgb(106, 90, 205)"},
{authored: "slategray", name: "slategray", hex: "#708090", hsl: "hsl(210, 13%, 50%)", rgb: "rgb(112, 128, 144)"},
{authored: "slategrey", name: "slategray", hex: "#708090", hsl: "hsl(210, 13%, 50%)", rgb: "rgb(112, 128, 144)"},
{authored: "snow", name: "snow", hex: "#FFFAFA", hsl: "hsl(0, 100%, 99%)", rgb: "rgb(255, 250, 250)"},
{authored: "springgreen", name: "springgreen", hex: "#00FF7F", hsl: "hsl(149.882, 100%, 50%)", rgb: "rgb(0, 255, 127)"},
{authored: "steelblue", name: "steelblue", hex: "#4682B4", hsl: "hsl(207.273, 44%, 49%)", rgb: "rgb(70, 130, 180)"},
{authored: "tan", name: "tan", hex: "#D2B48C", hsl: "hsl(34.286, 44%, 69%)", rgb: "rgb(210, 180, 140)"},
{authored: "springgreen", name: "springgreen", hex: "#00FF7F", hsl: "hsl(150, 100%, 50%)", rgb: "rgb(0, 255, 127)"},
{authored: "steelblue", name: "steelblue", hex: "#4682B4", hsl: "hsl(207, 44%, 49%)", rgb: "rgb(70, 130, 180)"},
{authored: "tan", name: "tan", hex: "#D2B48C", hsl: "hsl(34, 44%, 69%)", rgb: "rgb(210, 180, 140)"},
{authored: "teal", name: "teal", hex: "#008080", hsl: "hsl(180, 100%, 25%)", rgb: "rgb(0, 128, 128)"},
{authored: "thistle", name: "thistle", hex: "#D8BFD8", hsl: "hsl(300, 24%, 80%)", rgb: "rgb(216, 191, 216)"},
{authored: "tomato", name: "tomato", hex: "#FF6347", hsl: "hsl(9.13, 100%, 64%)", rgb: "rgb(255, 99, 71)"},
{authored: "tomato", name: "tomato", hex: "#FF6347", hsl: "hsl(9, 100%, 64%)", rgb: "rgb(255, 99, 71)"},
{authored: "turquoise", name: "turquoise", hex: "#40E0D0", hsl: "hsl(174, 72%, 56%)", rgb: "rgb(64, 224, 208)"},
{authored: "violet", name: "violet", hex: "#EE82EE", hsl: "hsl(300, 76%, 72%)", rgb: "rgb(238, 130, 238)"},
{authored: "wheat", name: "wheat", hex: "#F5DEB3", hsl: "hsl(39.091, 77%, 83%)", rgb: "rgb(245, 222, 179)"},
{authored: "wheat", name: "wheat", hex: "#F5DEB3", hsl: "hsl(39, 77%, 83%)", rgb: "rgb(245, 222, 179)"},
{authored: "white", name: "white", hex: "#FFF", hsl: "hsl(0, 0%, 100%)", rgb: "rgb(255, 255, 255)"},
{authored: "whitesmoke", name: "whitesmoke", hex: "#F5F5F5", hsl: "hsl(0, 0%, 96%)", rgb: "rgb(245, 245, 245)"},
{authored: "yellow", name: "yellow", hex: "#FF0", hsl: "hsl(60, 100%, 50%)", rgb: "rgb(255, 255, 0)"},
{authored: "yellowgreen", name: "yellowgreen", hex: "#9ACD32", hsl: "hsl(79.742, 61%, 50%)", rgb: "rgb(154, 205, 50)"},
{authored: "yellowgreen", name: "yellowgreen", hex: "#9ACD32", hsl: "hsl(80, 61%, 50%)", rgb: "rgb(154, 205, 50)"},
{authored: "rgba(0, 0, 0, 0)", name: "rgba(0, 0, 0, 0)", hex: "rgba(0, 0, 0, 0)", hsl: "hsla(0, 0%, 0%, 0)", rgb: "rgba(0, 0, 0, 0)"},
{authored: "hsla(0, 0%, 0%, 0)", name: "rgba(0, 0, 0, 0)", hex: "rgba(0, 0, 0, 0)", hsl: "hsla(0, 0%, 0%, 0)", rgb: "rgba(0, 0, 0, 0)"},
{authored: "rgba(50, 60, 70, 0.5)", name: "rgba(50, 60, 70, 0.5)", hex: "rgba(50, 60, 70, 0.5)", hsl: "hsla(210, 17%, 24%, 0.5)", rgb: "rgba(50, 60, 70, 0.5)"},
{authored: "rgba(0, 0, 0, 0.3)", name: "rgba(0, 0, 0, 0.3)", hex: "rgba(0, 0, 0, 0.3)", hsl: "hsla(0, 0%, 0%, 0.3)", rgb: "rgba(0, 0, 0, 0.3)"},
{authored: "rgba(255, 255, 255, 0.6)", name: "rgba(255, 255, 255, 0.6)", hex: "rgba(255, 255, 255, 0.6)", hsl: "hsla(0, 0%, 100%, 0.6)", rgb: "rgba(255, 255, 255, 0.6)"},
{authored: "rgba(127, 89, 45, 1)", name: "#7F592D", hex: "#7F592D", hsl: "hsl(32.195, 48%, 34%)", rgb: "rgb(127, 89, 45)"},
{authored: "hsla(19.304, 56%, 40%, 1)", name: "#9F512C", hex: "#9F512C", hsl: "hsl(19.304, 57%, 40%)", rgb: "rgb(159, 81, 44)"},
{authored: "rgba(127, 89, 45, 1)", name: "#7F592D", hex: "#7F592D", hsl: "hsl(32, 48%, 34%)", rgb: "rgb(127, 89, 45)"},
{authored: "hsla(19.304, 56%, 40%, 1)", name: "#9F512C", hex: "#9F512C", hsl: "hsl(19, 57%, 40%)", rgb: "rgb(159, 81, 44)"},
{authored: "currentcolor", name: "currentcolor", hex: "currentcolor", hsl: "currentcolor", rgb: "currentcolor"},
{authored: "inherit", name: "inherit", hex: "inherit", hsl: "inherit", rgb: "inherit"},
{authored: "initial", name: "initial", hex: "initial", hsl: "initial", rgb: "initial"},

Просмотреть файл

@ -13,6 +13,7 @@ const EventEmitter = require("devtools/toolkit/event-emitter");
const {colorUtils} = require("devtools/css-color");
const Heritage = require("sdk/core/heritage");
const {CSSTransformPreviewer} = require("devtools/shared/widgets/CSSTransformPreviewer");
const {Eyedropper} = require("devtools/eyedropper/eyedropper");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@ -692,7 +693,7 @@ Tooltip.prototype = {
let iframe = this.doc.createElementNS(XHTML_NS, "iframe");
iframe.setAttribute("transparent", true);
iframe.setAttribute("width", "210");
iframe.setAttribute("height", "195");
iframe.setAttribute("height", "220");
iframe.setAttribute("flex", "1");
iframe.setAttribute("class", "devtools-tooltip-iframe");
@ -707,12 +708,21 @@ Tooltip.prototype = {
let container = win.document.getElementById("spectrum");
let spectrum = new Spectrum(container, color);
// Finalize spectrum's init when the tooltip becomes visible
panel.addEventListener("popupshown", function shown() {
panel.removeEventListener("popupshown", shown, true);
function finalizeSpectrum() {
spectrum.show();
def.resolve(spectrum);
}, true);
}
// Finalize spectrum's init when the tooltip becomes visible
if (panel.state == "open") {
finalizeSpectrum();
}
else {
panel.addEventListener("popupshown", function shown() {
panel.removeEventListener("popupshown", shown, true);
finalizeSpectrum();
}, true);
}
}
iframe.addEventListener("load", onLoad, true);
iframe.setAttribute("src", SPECTRUM_FRAME);
@ -832,7 +842,11 @@ SwatchBasedEditorTooltip.prototype = {
show: function() {
if (this.activeSwatch) {
this.tooltip.show(this.activeSwatch, "topcenter bottomleft");
this.tooltip.once("hidden", () => this.activeSwatch = null);
this.tooltip.once("hidden", () => {
if (!this.eyedropperOpen) {
this.activeSwatch = null;
}
});
}
},
@ -951,6 +965,7 @@ function SwatchColorPickerTooltip(doc) {
// resolves to the spectrum instance
this.spectrum = this.tooltip.setColorPickerContent([0, 0, 0, 1]);
this._onSpectrumColorChange = this._onSpectrumColorChange.bind(this);
this._openEyeDropper = this._openEyeDropper.bind(this);
}
module.exports.SwatchColorPickerTooltip = SwatchColorPickerTooltip;
@ -975,16 +990,59 @@ SwatchColorPickerTooltip.prototype = Heritage.extend(SwatchBasedEditorTooltip.pr
spectrum.updateUI();
});
}
let tooltipDoc = this.tooltip.content.contentDocument;
let eyeButton = tooltipDoc.querySelector("#eyedropper-button");
eyeButton.addEventListener("click", this._openEyeDropper);
},
_onSpectrumColorChange: function(event, rgba, cssColor) {
this._selectColor(cssColor);
},
_selectColor: function(color) {
if (this.activeSwatch) {
this.activeSwatch.style.backgroundColor = cssColor;
this.currentSwatchColor.textContent = cssColor;
this.preview(cssColor);
this.activeSwatch.style.backgroundColor = color;
this.currentSwatchColor.textContent = color;
this.preview(color);
}
},
_openEyeDropper: function() {
let chromeWindow = this.tooltip.doc.defaultView.top;
let windowType = chromeWindow.document.documentElement
.getAttribute("windowtype");
let toolboxWindow;
if (windowType != "navigator:browser") {
// this means the toolbox is in a seperate window. We need to make
// sure we'll be inspecting the browser window instead
toolboxWindow = chromeWindow;
chromeWindow = Services.wm.getMostRecentWindow("navigator:browser");
chromeWindow.focus();
}
let dropper = new Eyedropper(chromeWindow, { copyOnSelect: false });
dropper.once("select", (event, color) => {
if (toolboxWindow) {
toolboxWindow.focus();
}
this._selectColor(color);
});
dropper.once("destroy", () => {
this.eyedropperOpen = false;
this.activeSwatch = null;
})
dropper.open();
this.eyedropperOpen = true;
// close the colorpicker tooltip so that only the eyedropper is open.
this.hide();
this.tooltip.emit("eyedropper-opened", dropper);
},
_colorToRgba: function(color) {
color = new colorUtils.CssColor(color);
let rgba = color._getRGBATuple();

Просмотреть файл

@ -19,5 +19,6 @@
</head>
<body role="application">
<div id="spectrum"></div>
<button id="eyedropper-button"></button>
</body>
</html>

Просмотреть файл

@ -2,6 +2,20 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#eyedropper-button {
background: url("chrome://browser/skin/devtools/eyedropper-black.png") no-repeat center;
width: 20px;
height: 20px;
-moz-margin-start: 6px;
border: 1px solid #ccc;
border-radius: 2px;
cursor: pointer;
}
.theme-dark #eyedropper-button {
filter: url(chrome://browser/skin/devtools/filters.svg#colorpicker-invert);
}
/* Mix-in classes */
.spectrum-checker {

Просмотреть файл

@ -1997,7 +1997,8 @@ TextPropertyEditor.prototype = {
*/
get editing() {
return !!(this.nameSpan.inplaceEditor || this.valueSpan.inplaceEditor ||
this.ruleEditor.ruleView.colorPicker.tooltip.isShown());
this.ruleEditor.ruleView.colorPicker.tooltip.isShown() ||
this.ruleEditor.ruleView.colorPicker.eyedropperOpen);
},
/**

Просмотреть файл

@ -60,6 +60,8 @@ support-files =
[browser_ruleview_edit-property-order.js]
[browser_ruleview_edit-property_01.js]
[browser_ruleview_edit-property_02.js]
[browser_ruleview_eyedropper.js]
skip-if = os == "win" && debug # bug 963492
[browser_ruleview_inherit.js]
[browser_ruleview_keybindings.js]
[browser_ruleview_livepreview.js]

Просмотреть файл

@ -0,0 +1,141 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const PAGE_CONTENT = [
'<style type="text/css">',
' body {',
' background-color: #ff5;',
' padding: 50px',
' }',
' div {',
' width: 100px;',
' height: 100px;',
' background-color: #f09;',
' }',
'</style>',
'<body><div></div></body>'
].join("\n");
const ORIGINAL_COLOR = "rgb(255, 0, 153)"; // #f09
const EXPECTED_COLOR = "rgb(255, 255, 85)"; // #ff5
// Test opening the eyedropper from the color picker. Pressing escape
// to close it, and clicking the page to select a color.
let test = asyncTest(function*() {
yield addTab("data:text/html,rule view eyedropper test");
content.document.body.innerHTML = PAGE_CONTENT;
let {toolbox, inspector, view} = yield openRuleView();
let element = content.document.querySelector("div");
inspector.selection.setNode(element, "test");
yield inspector.once("inspector-updated");
let property = getRuleViewProperty(view, "div", "background-color");
let swatch = property.valueSpan.querySelector(".ruleview-colorswatch");
ok(swatch, "Color swatch is displayed for the bg-color property");
let dropper = yield openEyedropper(view, swatch);
let tooltip = view.colorPicker.tooltip;
ok(tooltip.isHidden(),
"color picker tooltip is closed after opening eyedropper");
yield testESC(swatch, dropper);
dropper = yield openEyedropper(view, swatch);
ok(dropper, "dropper opened");
yield testSelect(swatch, dropper);
});
function testESC(swatch, dropper) {
let deferred = promise.defer();
dropper.once("destroy", () => {
let color = swatch.style.backgroundColor;
is(color, ORIGINAL_COLOR, "swatch didn't change after pressing ESC");
deferred.resolve();
});
inspectPage(dropper, false).then(pressESC);
return deferred.promise;
}
function testSelect(swatch, dropper) {
let deferred = promise.defer();
dropper.once("destroy", () => {
let color = swatch.style.backgroundColor;
is(color, EXPECTED_COLOR, "swatch changed colors");
// the change to the content is done async after rule view change
executeSoon(() => {
let element = content.document.querySelector("div");
is(content.window.getComputedStyle(element).backgroundColor,
EXPECTED_COLOR,
"div's color set to body color after dropper");
deferred.resolve();
});
});
inspectPage(dropper);
return deferred.promise;
}
/* Helpers */
function openEyedropper(view, swatch) {
let deferred = promise.defer();
let tooltip = view.colorPicker.tooltip;
tooltip.once("shown", () => {
let tooltipDoc = tooltip.content.contentDocument;
let dropperButton = tooltipDoc.querySelector("#eyedropper-button");
tooltip.once("eyedropper-opened", (event, dropper) => {
deferred.resolve(dropper)
});
dropperButton.click();
});
swatch.click();
return deferred.promise;
}
function inspectPage(dropper, click=true) {
let target = content.document.body;
let win = content.window;
EventUtils.synthesizeMouse(target, 10, 10, { type: "mousemove" }, win);
return dropperLoaded(dropper).then(() => {
EventUtils.synthesizeMouse(target, 20, 20, { type: "mousemove" }, win);
if (click) {
EventUtils.synthesizeMouse(target, 20, 20, {}, win);
}
});
}
function dropperLoaded(dropper) {
if (dropper.loaded) {
return promise.resolve();
}
return dropper.once("load");
}
function pressESC() {
EventUtils.synthesizeKey("VK_ESCAPE", { });
}

Просмотреть файл

@ -232,6 +232,9 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY responsiveDesignTool.accesskey "R">
<!ENTITY responsiveDesignTool.commandkey "M">
<!ENTITY eyedropper.label "Eyedropper">
<!ENTITY eyedropper.accesskey "Y">
<!-- LOCALIZATION NOTE (scratchpad.label): This menu item label appears
- in the Tools menu. See bug 653093.
- The Scratchpad is intended to provide a simple text editor for creating

Просмотреть файл

@ -0,0 +1,14 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# LOCALIZATION NOTE These strings are used in the Eyedropper color tool.
# LOCALIZATION NOTE The correct localization of this file might be to keep it
# in English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best documentation
# on web development on the web.
# LOCALIZATION NOTE (colorValue.copied): This text is displayed when the user selects a
# color with the eyedropper and it's copied to the clipboard.
colorValue.copied=copied

Просмотреть файл

@ -55,6 +55,7 @@
locale/browser/devtools/toolbox.dtd (%chrome/browser/devtools/toolbox.dtd)
locale/browser/devtools/toolbox.properties (%chrome/browser/devtools/toolbox.properties)
locale/browser/devtools/inspector.dtd (%chrome/browser/devtools/inspector.dtd)
locale/browser/devtools/eyedropper.properties (%chrome/browser/devtools/eyedropper.properties)
locale/browser/devtools/connection-screen.dtd (%chrome/browser/devtools/connection-screen.dtd)
locale/browser/devtools/connection-screen.properties (%chrome/browser/devtools/connection-screen.properties)
locale/browser/devtools/font-inspector.dtd (%chrome/browser/devtools/font-inspector.dtd)

Просмотреть файл

@ -221,6 +221,7 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
@ -296,6 +297,7 @@ browser.jar:
skin/classic/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
skin/classic/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-16.png
skin/classic/browser/sync-32.png

Просмотреть файл

@ -340,6 +340,7 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
@ -415,6 +416,8 @@ browser.jar:
skin/classic/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
skin/classic/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-16.png
skin/classic/browser/sync-32.png

Просмотреть файл

@ -215,3 +215,14 @@
border: none;
background: transparent;
}
/* Eyedropper Widget */
.devtools-eyedropper-panel {
pointer-events: none;
-moz-appearance: none;
width: 156px;
height: 120px;
background-color: transparent;
border: none;
}

Просмотреть файл

@ -0,0 +1,45 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#canvas {
image-rendering: -moz-crisp-edges;
cursor: none;
border: 3px solid #E0E0E0;
border-radius: 50%;
}
#canvas-overflow {
overflow: hidden;
width: 96px;
height: 96px;
}
#color-preview {
width: 16px;
height: 16px;
box-shadow: 0px 0px 0px black;
border: solid 1px #fff;
margin: 3px;
}
#color-value-box {
background-color: #E0E0E0;
border-radius: 1px;
width: 150px;
}
#color-value {
padding: 0.3em;
text-shadow: 1px 1px 1px #fff;
}
#color-value.highlight {
font-family: inherit;
}
window {
/* inexplicably, otherwise background shows up on Linux */
border: 1px solid transparent;
background-color: transparent;
}

Просмотреть файл

@ -6,4 +6,11 @@
<feFuncB type="table" tableValues=".1 0"/>
</feComponentTransfer>
</filter>
<filter id="colorpicker-invert" x="0%" y="0%" width="100%" height="100%" >
<feComponentTransfer>
<feFuncR type="table" tableValues=".6 0"/>
<feFuncG type="table" tableValues=".6 0"/>
<feFuncB type="table" tableValues=".6 0"/>
</feComponentTransfer>
</filter>
</svg>

До

Ширина:  |  Высота:  |  Размер: 321 B

После

Ширина:  |  Высота:  |  Размер: 596 B

Двоичные данные
browser/themes/shared/devtools/images/eyedropper-black.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.7 KiB

Просмотреть файл

@ -252,6 +252,7 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
@ -326,6 +327,8 @@ browser.jar:
skin/classic/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
skin/classic/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
skin/classic/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
skin/classic/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/browser/sync-16.png
skin/classic/browser/sync-32.png
@ -606,6 +609,7 @@ browser.jar:
* skin/classic/aero/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/aero/browser/devtools/netmonitor.css (devtools/netmonitor.css)
* skin/classic/aero/browser/devtools/scratchpad.css (devtools/scratchpad.css)
skin/classic/aero/browser/devtools/eyedropper.css (../shared/devtools/eyedropper.css)
skin/classic/aero/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/aero/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
skin/classic/aero/browser/devtools/magnifying-glass-light.png (../shared/devtools/images/magnifying-glass-light.png)
@ -680,6 +684,7 @@ browser.jar:
skin/classic/aero/browser/devtools/app-manager/rocket.svg (../shared/devtools/app-manager/images/rocket.svg)
skin/classic/aero/browser/devtools/app-manager/noise.png (../shared/devtools/app-manager/images/noise.png)
skin/classic/aero/browser/devtools/app-manager/default-app-icon.png (../shared/devtools/app-manager/images/default-app-icon.png)
skin/classic/aero/browser/devtools/eyedropper-black.png (../shared/devtools/images/eyedropper-black.png)
#ifdef MOZ_SERVICES_SYNC
skin/classic/aero/browser/sync-16.png

Просмотреть файл

@ -80,7 +80,8 @@ function CssColor(colorValue) {
module.exports.colorUtils = {
CssColor: CssColor,
processCSSString: processCSSString
processCSSString: processCSSString,
rgbToHsl: rgbToHsl
};
/**
@ -330,41 +331,9 @@ CssColor.prototype = {
return "hsl(" + h + ", " + s + ", " + l + ")";
}
r = r / 255;
g = g / 255;
b = b / 255;
let [h,s,l] = rgbToHsl([r,g,b]);
let max = Math.max(r, g, b);
let min = Math.min(r, g, b);
let h;
let s;
let l = (max + min) / 2;
if(max == min){
h = s = 0;
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r:
h = ((g - b) / d) % 6;
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h *= 60;
if (h < 0) {
h += 360;
}
}
return "hsl(" + (Math.round(h * 1000)) / 1000 +
", " + Math.round(s * 100) +
"%, " + Math.round(l * 100) + "%)";
return "hsl(" + h + ", " + s + "%, " + l + "%)";
},
/**
@ -427,6 +396,51 @@ function processCSSString(value) {
return value;
}
/**
* Convert rgb value to hsl
*
* @param {array} rgb
* Array of rgb values
* @return {array}
* Array of hsl values.
*/
function rgbToHsl([r,g,b]) {
r = r / 255;
g = g / 255;
b = b / 255;
let max = Math.max(r, g, b);
let min = Math.min(r, g, b);
let h;
let s;
let l = (max + min) / 2;
if(max == min){
h = s = 0;
} else {
let d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r:
h = ((g - b) / d) % 6;
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h *= 60;
if (h < 0) {
h += 360;
}
}
return [Math.round(h), Math.round(s * 100), Math.round(l * 100)];
}
loader.lazyGetter(this, "DOMUtils", function () {
return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
});