Bug 1262439 - 2 - Add a new pickColor inspector method to use the new eye-dropper highlighter; r=bgrins

The inspector actor now has a new method that can be used to pick a
color from the page. This method just instantiates the eye-dropper
highlighter and shows it on the page.
The method doesn't return the color because this requires user interaction.
Instead, it returns immediately and an event is sent later, when the user
has selected a color or escaped.

MozReview-Commit-ID: cjadLyNXQd

--HG--
extra : rebase_source : 392a3cbfce7b81518cd7e4c90a44bae17d96e8de
This commit is contained in:
Patrick Brosset 2016-07-20 16:07:04 +02:00
parent d2cc90ec24
commit 968dc79025
5 changed files with 207 additions and 0 deletions

View File

@ -66,7 +66,9 @@ const {
HighlighterActor,
CustomHighlighterActor,
isTypeRegistered,
HighlighterEnvironment
} = require("devtools/server/actors/highlighters");
const {EyeDropper} = require("devtools/server/actors/highlighters/eye-dropper");
const {
isAnonymous,
isNativeAnonymous,
@ -2584,11 +2586,17 @@ var InspectorActor = exports.InspectorActor = protocol.ActorClassWithSpec(inspec
initialize: function (conn, tabActor) {
protocol.Actor.prototype.initialize.call(this, conn);
this.tabActor = tabActor;
this._onColorPicked = this._onColorPicked.bind(this);
this._onColorPickCanceled = this._onColorPickCanceled.bind(this);
this.destroyEyeDropper = this.destroyEyeDropper.bind(this);
},
destroy: function () {
protocol.Actor.prototype.destroy.call(this);
this.destroyEyeDropper();
this._highlighterPromise = null;
this._pageStylePromise = null;
this._walkerPromise = null;
@ -2736,6 +2744,66 @@ var InspectorActor = exports.InspectorActor = protocol.ActorClassWithSpec(inspec
let baseURI = Services.io.newURI(document.location.href, null, null);
return Services.io.newURI(url, null, baseURI).spec;
},
/**
* Create an instance of the eye-dropper highlighter and store it on this._eyeDropper.
* Note that for now, a new instance is created every time to deal with page navigation.
*/
createEyeDropper: function () {
this.destroyEyeDropper();
this._highlighterEnv = new HighlighterEnvironment();
this._highlighterEnv.initFromTabActor(this.tabActor);
this._eyeDropper = new EyeDropper(this._highlighterEnv);
},
/**
* Destroy the current eye-dropper highlighter instance.
*/
destroyEyeDropper: function () {
if (this._eyeDropper) {
this.cancelPickColorFromPage();
this._eyeDropper.destroy();
this._eyeDropper = null;
this._highlighterEnv.destroy();
this._highlighterEnv = null;
}
},
/**
* Pick a color from the page using the eye-dropper. This method doesn't return anything
* but will cause events to be sent to the front when a color is picked or when the user
* cancels the picker.
* @param {Object} options
*/
pickColorFromPage: function (options) {
this.createEyeDropper();
this._eyeDropper.show(this.window.document.documentElement, options);
this._eyeDropper.once("selected", this._onColorPicked);
this._eyeDropper.once("canceled", this._onColorPickCanceled);
events.once(this.tabActor, "will-navigate", this.destroyEyeDropper);
},
/**
* After the pickColorFromPage method is called, the only way to dismiss the eye-dropper
* highlighter is for the user to click in the page and select a color. If you need to
* dismiss the eye-dropper programatically instead, use this method.
*/
cancelPickColorFromPage: function () {
if (this._eyeDropper) {
this._eyeDropper.hide();
this._eyeDropper.off("selected", this._onColorPicked);
this._eyeDropper.off("canceled", this._onColorPickCanceled);
events.off(this.tabActor, "will-navigate", this.destroyEyeDropper);
}
},
_onColorPicked: function (e, color) {
events.emit(this, "color-picked", color);
},
_onColorPickCanceled: function () {
events.emit(this, "color-pick-canceled");
}
});

View File

@ -11,6 +11,7 @@ support-files =
inspector_css-properties.html
inspector_getImageData.html
inspector-delay-image-response.sjs
inspector-eyedropper.html
inspector-helpers.js
inspector-search-data.html
inspector-styles-data.css
@ -75,6 +76,7 @@ skip-if = buildapp == 'mulet'
[test_inspector-mutations-childlist.html]
[test_inspector-mutations-frameload.html]
[test_inspector-mutations-value.html]
[test_inspector-pick-color.html]
[test_inspector-pseudoclass-lock.html]
[test_inspector-release.html]
[test_inspector-reload.html]

View File

@ -0,0 +1,18 @@
<html>
<head>
<meta charset="UTF-8">
<title>Inspector Eyedropper tests</title>
<style>
html {
background: black;
}
</style>
<script type="text/javascript">
window.onload = function() {
window.opener.postMessage('ready', '*');
};
</script>
</head>
</body>
</body>
</html>

View File

@ -0,0 +1,101 @@
<!DOCTYPE HTML>
<html>
<!--
Test that the inspector actor has the pickColorFromPage and cancelPickColorFromPage
methods and that when a color is picked the color-picked event is emitted and that when
the eyedropper is dimissed, the color-pick-canceled event is emitted.
https://bugzilla.mozilla.org/show_bug.cgi?id=1262439
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1262439</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
<script type="application/javascript;version=1.8" src="inspector-helpers.js"></script>
<script type="application/javascript;version=1.8">
window.onload = function() {
const Cu = Components.utils;
Cu.import("resource://devtools/shared/Loader.jsm");
const {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
const {InspectorFront} = devtools.require("devtools/shared/fronts/inspector");
const {console} = Cu.import("resource://gre/modules/Console.jsm", {});
SimpleTest.waitForExplicitFinish();
let win = null;
let inspector = null;
addAsyncTest(function*() {
info("Setting up inspector actor");
let url = document.getElementById("inspectorContent").href;
yield new Promise(resolve => {
attachURL(url, function(err, client, tab, doc) {
win = doc.defaultView;
inspector = InspectorFront(client, tab);
resolve();
});
});
runNextTest();
});
addAsyncTest(function*() {
info("Start picking a color from the page");
yield inspector.pickColorFromPage();
info("Click in the page and make sure a color-picked event is received");
let onColorPicked = waitForEvent("color-picked");
win.document.body.click();
let color = yield onColorPicked;
is(color, "#000000", "The color-picked event was received with the right color");
runNextTest();
});
addAsyncTest(function*() {
info("Start picking a color from the page");
yield inspector.pickColorFromPage();
info("Use the escape key to dismiss the eyedropper");
let onPickCanceled = waitForEvent("color-pick-canceled");
let keyboardEvent = win.document.createEvent("KeyboardEvent");
keyboardEvent.initKeyEvent("keydown", true, true, win, false, false,
false, false, 27, 0);
win.document.dispatchEvent(keyboardEvent);
yield onPickCanceled;
ok(true, "The color-pick-canceled event was received");
runNextTest();
});
addAsyncTest(function*() {
info("Start picking a color from the page");
yield inspector.pickColorFromPage();
info("And cancel the color picking");
yield inspector.cancelPickColorFromPage();
runNextTest();
});
function waitForEvent(name) {
return new Promise(resolve => inspector.once(name, resolve));
}
runNextTest();
};
</script>
</head>
<body>
<a id="inspectorContent" target="_blank" href="inspector-eyedropper.html">Test Document</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -371,6 +371,16 @@ exports.walkerSpec = walkerSpec;
const inspectorSpec = generateActorSpec({
typeName: "inspector",
events: {
"color-picked": {
type: "colorPicked",
color: Arg(0, "string")
},
"color-pick-canceled": {
type: "colorPickCanceled"
}
},
methods: {
getWalker: {
request: {
@ -409,6 +419,14 @@ const inspectorSpec = generateActorSpec({
resolveRelativeURL: {
request: {url: Arg(0, "string"), node: Arg(1, "nullable:domnode")},
response: {value: RetVal("string")}
},
pickColorFromPage: {
request: {options: Arg(0, "nullable:json")},
response: {}
},
cancelPickColorFromPage: {
request: {},
response: {}
}
}
});