mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to central, a=merge
This commit is contained in:
commit
638c2a9058
@ -330,6 +330,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||||||
|
|
||||||
var errorString;
|
var errorString;
|
||||||
switch (this.props.failureReason) {
|
switch (this.props.failureReason) {
|
||||||
|
case FAILURE_DETAILS.NO_MEDIA:
|
||||||
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
||||||
errorString = mozL10n.get("no_media_failure_message");
|
errorString = mozL10n.get("no_media_failure_message");
|
||||||
break;
|
break;
|
||||||
|
@ -330,6 +330,7 @@ loop.conversationViews = (function(mozL10n) {
|
|||||||
|
|
||||||
var errorString;
|
var errorString;
|
||||||
switch (this.props.failureReason) {
|
switch (this.props.failureReason) {
|
||||||
|
case FAILURE_DETAILS.NO_MEDIA:
|
||||||
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
case FAILURE_DETAILS.UNABLE_TO_PUBLISH_MEDIA:
|
||||||
errorString = mozL10n.get("no_media_failure_message");
|
errorString = mozL10n.get("no_media_failure_message");
|
||||||
break;
|
break;
|
||||||
|
@ -978,7 +978,7 @@ loop.OTSdkDriver = (function() {
|
|||||||
|
|
||||||
var bucket = this.mozLoop.SHARING_STATE_CHANGE[type.toUpperCase() + "_" +
|
var bucket = this.mozLoop.SHARING_STATE_CHANGE[type.toUpperCase() + "_" +
|
||||||
(enabled ? "ENABLED" : "DISABLED")];
|
(enabled ? "ENABLED" : "DISABLED")];
|
||||||
if (!bucket) {
|
if (typeof bucket === "undefined") {
|
||||||
console.error("No sharing state bucket found for '" + type + "'");
|
console.error("No sharing state bucket found for '" + type + "'");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ let LoopRoomsInternal = {
|
|||||||
* @param {String} roomToken The token for the room that needs encrypting.
|
* @param {String} roomToken The token for the room that needs encrypting.
|
||||||
*/
|
*/
|
||||||
queueForEncryption: function(roomToken) {
|
queueForEncryption: function(roomToken) {
|
||||||
if (!this.encryptionQueue.queue.includes(roomToken)) {
|
if (this.encryptionQueue.queue.indexOf(roomToken) == -1) {
|
||||||
this.encryptionQueue.queue.push(roomToken);
|
this.encryptionQueue.queue.push(roomToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -939,6 +939,15 @@ describe("loop.conversationViews", function () {
|
|||||||
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should show 'no media' for FAILURE_DETAILS.NO_MEDIA reason", function() {
|
||||||
|
view = mountTestComponent({
|
||||||
|
cancelCall: function() {},
|
||||||
|
failureReason: FAILURE_DETAILS.NO_MEDIA
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(view.getDOMNode().querySelector("h2").textContent).eql("no_media_failure_message");
|
||||||
|
});
|
||||||
|
|
||||||
it("should show 'generic_failure_title' when no reason is specified", function() {
|
it("should show 'generic_failure_title' when no reason is specified", function() {
|
||||||
view = mountTestComponent({cancelCall: function() {}});
|
view = mountTestComponent({cancelCall: function() {}});
|
||||||
|
|
||||||
|
@ -78,16 +78,16 @@ describe("loop.OTSdkDriver", function () {
|
|||||||
mozLoop = {
|
mozLoop = {
|
||||||
telemetryAddValue: sinon.stub(),
|
telemetryAddValue: sinon.stub(),
|
||||||
TWO_WAY_MEDIA_CONN_LENGTH: {
|
TWO_WAY_MEDIA_CONN_LENGTH: {
|
||||||
SHORTER_THAN_10S: "SHORTER_THAN_10S",
|
SHORTER_THAN_10S: 0,
|
||||||
BETWEEN_10S_AND_30S: "BETWEEN_10S_AND_30S",
|
BETWEEN_10S_AND_30S: 1,
|
||||||
BETWEEN_30S_AND_5M: "BETWEEN_30S_AND_5M",
|
BETWEEN_30S_AND_5M: 2,
|
||||||
MORE_THAN_5M: "MORE_THAN_5M"
|
MORE_THAN_5M: 3
|
||||||
},
|
},
|
||||||
SHARING_STATE_CHANGE: {
|
SHARING_STATE_CHANGE: {
|
||||||
WINDOW_ENABLED: "WINDOW_ENABLED",
|
WINDOW_ENABLED: 0,
|
||||||
WINDOW_DISABLED: "WINDOW_DISABLED",
|
WINDOW_DISABLED: 1,
|
||||||
BROWSER_ENABLED: "BROWSER_ENABLED",
|
BROWSER_ENABLED: 2,
|
||||||
BROWSER_DISABLED: "BROWSER_DISABLED"
|
BROWSER_DISABLED: 3
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -190,8 +190,8 @@ EventEmitter.decorate(this);
|
|||||||
/**
|
/**
|
||||||
* DOM query helpers.
|
* DOM query helpers.
|
||||||
*/
|
*/
|
||||||
function $(selector, target = document) target.querySelector(selector);
|
let $ = (selector, target = document) => target.querySelector(selector);
|
||||||
function $all(selector, target = document) target.querySelectorAll(selector);
|
let $all = (selector, target = document) => target.querySelectorAll(selector);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper for getting an nsIURL instance out of a string.
|
* Helper for getting an nsIURL instance out of a string.
|
||||||
|
@ -57,7 +57,9 @@ CanvasDebuggerPanel.prototype = {
|
|||||||
|
|
||||||
// DevToolPanel API
|
// DevToolPanel API
|
||||||
|
|
||||||
get target() this._toolbox.target,
|
get target() {
|
||||||
|
return this._toolbox.target;
|
||||||
|
},
|
||||||
|
|
||||||
destroy: function() {
|
destroy: function() {
|
||||||
// Make sure this panel is not already destroyed.
|
// Make sure this panel is not already destroyed.
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* You can also use this initialization format as a template for other tests.
|
* You can also use this initialization format as a template for other tests.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
||||||
|
|
||||||
ok(target, "Should have a target available.");
|
ok(target, "Should have a target available.");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* and that their stack is successfully retrieved.
|
* and that their stack is successfully retrieved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
let { target, front } = yield initCallWatcherBackend(SIMPLE_CANVAS_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* for a canvas context.
|
* for a canvas context.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* the correct thumbnails.
|
* the correct thumbnails.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* the correct "end result" screenshot.
|
* the correct "end result" screenshot.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if screenshots for arbitrary draw calls are generated properly.
|
* Tests if screenshots for arbitrary draw calls are generated properly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_TRANSPARENT_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_TRANSPARENT_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* by deferring the the most recent previous draw-call.
|
* by deferring the the most recent previous draw-call.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_CANVAS_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* forms if the method's signature does not expect an enum. Bug 999687.
|
* forms if the method's signature does not expect an enum. Bug 999687.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_BITMASKS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SIMPLE_BITMASKS_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* forms if the method's signature does not expect an enum. Bug 999687.
|
* forms if the method's signature does not expect an enum. Bug 999687.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_ENUM_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_ENUM_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* after generating screenshots using the actor.
|
* after generating screenshots using the actor.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_BINDINGS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(WEBGL_BINDINGS_URL);
|
||||||
loadFrameScripts();
|
loadFrameScripts();
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* for a canvas context, and that the generated screenshots are correct.
|
* for a canvas context, and that the generated screenshots are correct.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(SET_TIMEOUT_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(SET_TIMEOUT_URL);
|
||||||
|
|
||||||
let navigated = once(target, "navigate");
|
let navigated = once(target, "navigate");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* in the event no rAF loop is found.
|
* in the event no rAF loop is found.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, front } = yield initCanvasDebuggerBackend(NO_CANVAS_URL);
|
let { target, front } = yield initCanvasDebuggerBackend(NO_CANVAS_URL);
|
||||||
loadFrameScripts();
|
loadFrameScripts();
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if certain function calls are properly highlighted in the UI.
|
* Tests if certain function calls are properly highlighted in the UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* are properly displayed in the UI.
|
* are properly displayed in the UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if filtering the items in the call list works properly.
|
* Tests if filtering the items in the call list works properly.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
let searchbox = $("#calls-searchbox");
|
let searchbox = $("#calls-searchbox");
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if the a function call's stack is properly displayed in the UI.
|
* Tests if the a function call's stack is properly displayed in the UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* and jumping to source in the debugger for the topmost call item works.
|
* and jumping to source in the debugger for the topmost call item works.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* on a function call item.
|
* on a function call item.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_DEEP_STACK_URL);
|
||||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if clearing the snapshots list works as expected.
|
* Tests if clearing the snapshots list works as expected.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, EVENTS, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if screenshots are properly displayed in the UI.
|
* Tests if screenshots are properly displayed in the UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if thumbnails are properly displayed in the UI.
|
* Tests if thumbnails are properly displayed in the UI.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, $all, EVENTS, SnapshotsListView } = panel.panelWin;
|
let { window, $, $all, EVENTS, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* function call items and their respective screenshots.
|
* function call items and their respective screenshots.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests that the frontend UI is properly configured when opening the tool.
|
* Tests that the frontend UI is properly configured when opening the tool.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { $ } = panel.panelWin;
|
let { $ } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests whether the frontend behaves correctly while reording a snapshot.
|
* Tests whether the frontend behaves correctly while reording a snapshot.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests whether the frontend displays a placeholder snapshot while recording.
|
* Tests whether the frontend displays a placeholder snapshot while recording.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, EVENTS, L10N, $, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, L10N, $, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* after finishing recording.
|
* after finishing recording.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* of its loop, when the recording starts before the rAFs start.
|
* of its loop, when the recording starts before the rAFs start.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_BEGIN_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_BEGIN_URL);
|
||||||
let { window, EVENTS, gFront, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, gFront, SnapshotsListView } = panel.panelWin;
|
||||||
loadFrameScripts();
|
loadFrameScripts();
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests that the frontend UI is properly reconfigured after reloading.
|
* Tests that the frontend UI is properly reconfigured after reloading.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS } = panel.panelWin;
|
let { window, $, EVENTS } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests that the frontend UI is properly reconfigured after reloading.
|
* Tests that the frontend UI is properly reconfigured after reloading.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, $all, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if the slider in the calls list view works as advertised.
|
* Tests if the slider in the calls list view works as advertised.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if the slider in the calls list view works as advertised.
|
* Tests if the slider in the calls list view works as advertised.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, gFront, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, gFront, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* respective to their recorded animation frame.
|
* respective to their recorded animation frame.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* respective to their recorded animation frame.
|
* respective to their recorded animation frame.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests if the stepping buttons in the call list toolbar work as advertised.
|
* Tests if the stepping buttons in the call list toolbar work as advertised.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(SIMPLE_CANVAS_URL);
|
||||||
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
let { window, $, EVENTS, SnapshotsListView, CallsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests that you can stop a recording that does not have a rAF cycle.
|
* Tests that you can stop a recording that does not have a rAF cycle.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
||||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
* Tests that a recording that does not have a rAF cycle fails after timeout.
|
* Tests that a recording that does not have a rAF cycle fails after timeout.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(NO_CANVAS_URL);
|
||||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
* after timeout.
|
* after timeout.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function ifTestingSupported() {
|
function* ifTestingSupported() {
|
||||||
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_NO_CANVAS_URL);
|
let { target, panel } = yield initCanvasDebuggerFrontend(RAF_NO_CANVAS_URL);
|
||||||
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
let { window, EVENTS, $, SnapshotsListView } = panel.panelWin;
|
||||||
|
|
||||||
|
@ -66,6 +66,7 @@ support-files =
|
|||||||
[browser_graphs-09f.js]
|
[browser_graphs-09f.js]
|
||||||
[browser_graphs-10a.js]
|
[browser_graphs-10a.js]
|
||||||
[browser_graphs-10b.js]
|
[browser_graphs-10b.js]
|
||||||
|
[browser_graphs-10c.js]
|
||||||
[browser_graphs-11a.js]
|
[browser_graphs-11a.js]
|
||||||
[browser_graphs-11b.js]
|
[browser_graphs-11b.js]
|
||||||
[browser_graphs-12.js]
|
[browser_graphs-12.js]
|
||||||
|
86
browser/devtools/shared/test/browser_graphs-10c.js
Normal file
86
browser/devtools/shared/test/browser_graphs-10c.js
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
|
||||||
|
// Tests that graphs properly handle resizing.
|
||||||
|
|
||||||
|
const TEST_DATA = [{ delta: 112, value: 48 }, { delta: 213, value: 59 }, { delta: 313, value: 60 }, { delta: 413, value: 59 }, { delta: 530, value: 59 }, { delta: 646, value: 58 }, { delta: 747, value: 60 }, { delta: 863, value: 48 }, { delta: 980, value: 37 }, { delta: 1097, value: 30 }, { delta: 1213, value: 29 }, { delta: 1330, value: 23 }, { delta: 1430, value: 10 }, { delta: 1534, value: 17 }, { delta: 1645, value: 20 }, { delta: 1746, value: 22 }, { delta: 1846, value: 39 }, { delta: 1963, value: 26 }, { delta: 2080, value: 27 }, { delta: 2197, value: 35 }, { delta: 2312, value: 47 }, { delta: 2412, value: 53 }, { delta: 2514, value: 60 }, { delta: 2630, value: 37 }, { delta: 2730, value: 36 }, { delta: 2830, value: 37 }, { delta: 2946, value: 36 }, { delta: 3046, value: 40 }, { delta: 3163, value: 47 }, { delta: 3280, value: 41 }, { delta: 3380, value: 35 }, { delta: 3480, value: 27 }, { delta: 3580, value: 39 }, { delta: 3680, value: 42 }, { delta: 3780, value: 49 }, { delta: 3880, value: 55 }, { delta: 3980, value: 60 }, { delta: 4080, value: 60 }, { delta: 4180, value: 60 }];
|
||||||
|
let {LineGraphWidget} = Cu.import("resource:///modules/devtools/Graphs.jsm", {});
|
||||||
|
let {Promise} = devtools.require("resource://gre/modules/Promise.jsm");
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
yield promiseTab("about:blank");
|
||||||
|
yield performTest();
|
||||||
|
gBrowser.removeCurrentTab();
|
||||||
|
});
|
||||||
|
|
||||||
|
function* performTest() {
|
||||||
|
let [host, win, doc] = yield createHost("window");
|
||||||
|
doc.body.setAttribute("style", "position: fixed; width: 100%; height: 100%; margin: 0;");
|
||||||
|
|
||||||
|
let graph = new LineGraphWidget(doc.body, "fps");
|
||||||
|
yield graph.once("ready");
|
||||||
|
|
||||||
|
let refreshCount = 0;
|
||||||
|
graph.on("refresh", () => refreshCount++);
|
||||||
|
|
||||||
|
yield testGraph(host, graph);
|
||||||
|
|
||||||
|
is(refreshCount, 2, "The graph should've been refreshed 2 times.");
|
||||||
|
|
||||||
|
yield graph.destroy();
|
||||||
|
host.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
function* testGraph(host, graph) {
|
||||||
|
graph.setData(TEST_DATA);
|
||||||
|
|
||||||
|
host._window.resizeTo(500, 500);
|
||||||
|
yield graph.once("refresh");
|
||||||
|
let oldBounds = host.frame.getBoundingClientRect();
|
||||||
|
|
||||||
|
is (graph._width, oldBounds.width * window.devicePixelRatio,
|
||||||
|
"The window was properly resized (1).");
|
||||||
|
is (graph._height, oldBounds.height * window.devicePixelRatio,
|
||||||
|
"The window was properly resized (1).");
|
||||||
|
|
||||||
|
dragStart(graph, 100);
|
||||||
|
dragStop(graph, 400);
|
||||||
|
|
||||||
|
is(graph.getSelection().start, 100,
|
||||||
|
"The current selection start value is correct (1).");
|
||||||
|
is(graph.getSelection().end, 400,
|
||||||
|
"The current selection end value is correct (1).");
|
||||||
|
|
||||||
|
info("Making sure the selection updates when the window is resized");
|
||||||
|
|
||||||
|
host._window.resizeTo(250, 250);
|
||||||
|
yield graph.once("refresh");
|
||||||
|
let newBounds = host.frame.getBoundingClientRect();
|
||||||
|
|
||||||
|
is (graph._width, newBounds.width * window.devicePixelRatio,
|
||||||
|
"The window was properly resized (2).");
|
||||||
|
is (graph._height, newBounds.height * window.devicePixelRatio,
|
||||||
|
"The window was properly resized (2).");
|
||||||
|
|
||||||
|
let ratio = oldBounds.width / newBounds.width;
|
||||||
|
info("The window resize ratio is: " + ratio);
|
||||||
|
|
||||||
|
is(graph.getSelection().start, Math.round(100 / ratio),
|
||||||
|
"The current selection start value is correct (2).");
|
||||||
|
is(graph.getSelection().end, Math.round(400 / ratio),
|
||||||
|
"The current selection end value is correct (2).");
|
||||||
|
}
|
||||||
|
|
||||||
|
// EventUtils just doesn't work!
|
||||||
|
|
||||||
|
function dragStart(graph, x, y = 1) {
|
||||||
|
x /= window.devicePixelRatio;
|
||||||
|
y /= window.devicePixelRatio;
|
||||||
|
graph._onMouseMove({ testX: x, testY: y });
|
||||||
|
graph._onMouseDown({ testX: x, testY: y });
|
||||||
|
}
|
||||||
|
|
||||||
|
function dragStop(graph, x, y = 1) {
|
||||||
|
x /= window.devicePixelRatio;
|
||||||
|
y /= window.devicePixelRatio;
|
||||||
|
graph._onMouseMove({ testX: x, testY: y });
|
||||||
|
graph._onMouseUp({ testX: x, testY: y });
|
||||||
|
}
|
@ -684,6 +684,13 @@ AbstractCanvasGraph.prototype = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle a changed size by mapping the old selection to the new width
|
||||||
|
if (this._width && newWidth && this.hasSelection()) {
|
||||||
|
let ratio = this._width / (newWidth * this._pixelRatio);
|
||||||
|
this._selection.start = Math.round(this._selection.start / ratio);
|
||||||
|
this._selection.end = Math.round(this._selection.end / ratio);
|
||||||
|
}
|
||||||
|
|
||||||
bounds.width = newWidth;
|
bounds.width = newWidth;
|
||||||
bounds.height = newHeight;
|
bounds.height = newHeight;
|
||||||
this._iframe.setAttribute("width", bounds.width);
|
this._iframe.setAttribute("width", bounds.width);
|
||||||
|
@ -151,6 +151,7 @@ function CssHtmlTree(aStyleInspector, aPageStyle)
|
|||||||
this._onClick = this._onClick.bind(this);
|
this._onClick = this._onClick.bind(this);
|
||||||
this._onCopy = this._onCopy.bind(this);
|
this._onCopy = this._onCopy.bind(this);
|
||||||
this._onCopyColor = this._onCopyColor.bind(this);
|
this._onCopyColor = this._onCopyColor.bind(this);
|
||||||
|
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||||
this._onFilterStyles = this._onFilterStyles.bind(this);
|
this._onFilterStyles = this._onFilterStyles.bind(this);
|
||||||
this._onFilterKeyPress = this._onFilterKeyPress.bind(this);
|
this._onFilterKeyPress = this._onFilterKeyPress.bind(this);
|
||||||
this._onClearSearch = this._onClearSearch.bind(this);
|
this._onClearSearch = this._onClearSearch.bind(this);
|
||||||
@ -328,7 +329,7 @@ CssHtmlTree.prototype = {
|
|||||||
* - type {String} One of the VIEW_NODE_XXX_TYPE const in
|
* - type {String} One of the VIEW_NODE_XXX_TYPE const in
|
||||||
* style-inspector-overlays
|
* style-inspector-overlays
|
||||||
* - value {Object} Depends on the type of the node
|
* - value {Object} Depends on the type of the node
|
||||||
* returns null of the node isn't anything we care about
|
* returns null if the node isn't anything we care about
|
||||||
*/
|
*/
|
||||||
getNodeInfo: function(node) {
|
getNodeInfo: function(node) {
|
||||||
if (!node) {
|
if (!node) {
|
||||||
@ -351,7 +352,7 @@ CssHtmlTree.prototype = {
|
|||||||
return {
|
return {
|
||||||
type: overlays.VIEW_NODE_SELECTOR_TYPE,
|
type: overlays.VIEW_NODE_SELECTOR_TYPE,
|
||||||
value: selectorText.trim()
|
value: selectorText.trim()
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Walk up the nodes to find out where node is
|
// Walk up the nodes to find out where node is
|
||||||
@ -715,6 +716,13 @@ CssHtmlTree.prototype = {
|
|||||||
command: this._onCopyColor
|
command: this._onCopyColor
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Copy data URI
|
||||||
|
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
|
||||||
|
label: "styleinspector.contextmenu.copyImageDataUrl",
|
||||||
|
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
|
||||||
|
command: this._onCopyImageDataUrl
|
||||||
|
});
|
||||||
|
|
||||||
// Show Original Sources
|
// Show Original Sources
|
||||||
this.menuitemSources= createMenuItem(this._contextmenu, {
|
this.menuitemSources= createMenuItem(this._contextmenu, {
|
||||||
label: "ruleView.contextmenu.showOrigSources",
|
label: "ruleView.contextmenu.showOrigSources",
|
||||||
@ -745,6 +753,7 @@ CssHtmlTree.prototype = {
|
|||||||
this.menuitemSources.setAttribute("checked", showOrig);
|
this.menuitemSources.setAttribute("checked", showOrig);
|
||||||
|
|
||||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||||
|
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -757,14 +766,12 @@ CssHtmlTree.prototype = {
|
|||||||
_isColorPopup: function () {
|
_isColorPopup: function () {
|
||||||
this._colorToCopy = "";
|
this._colorToCopy = "";
|
||||||
|
|
||||||
let trigger = this.popupNode;
|
|
||||||
if (!trigger) {
|
let container = this._getPopupNodeContainer();
|
||||||
|
if (!container) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
|
|
||||||
trigger.parentElement : trigger;
|
|
||||||
|
|
||||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||||
|
|
||||||
while (!isColorNode(container)) {
|
while (!isColorNode(container)) {
|
||||||
@ -778,6 +785,52 @@ CssHtmlTree.prototype = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the context menu popup was opened with a click on an image link
|
||||||
|
* If true, save the image url to this._imageUrlToCopy
|
||||||
|
*/
|
||||||
|
_isImageUrlPopup: function () {
|
||||||
|
this._imageUrlToCopy = "";
|
||||||
|
|
||||||
|
let container = this._getPopupNodeContainer();
|
||||||
|
let isImageUrlNode = this._isImageUrlNode(container);
|
||||||
|
if (isImageUrlNode) {
|
||||||
|
this._imageUrlToCopy = container.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isImageUrlNode;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node is an image url
|
||||||
|
* @param {DOMNode} node The node which we want information about
|
||||||
|
* @return {Boolean} true if the node is an image url
|
||||||
|
*/
|
||||||
|
_isImageUrlNode: function (node) {
|
||||||
|
let nodeInfo = this.getNodeInfo(node);
|
||||||
|
if (!nodeInfo) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the DOM Node container for the current popupNode.
|
||||||
|
* If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
|
||||||
|
* @return {DOMNode}
|
||||||
|
*/
|
||||||
|
_getPopupNodeContainer: function () {
|
||||||
|
let container = null;
|
||||||
|
let node = this.popupNode;
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||||
|
container = isTextNode ? node.parentElement : node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context menu handler.
|
* Context menu handler.
|
||||||
*/
|
*/
|
||||||
@ -821,6 +874,22 @@ CssHtmlTree.prototype = {
|
|||||||
clipboardHelper.copyString(this._colorToCopy);
|
clipboardHelper.copyString(this._colorToCopy);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the image data for the selected image url and copy it to the clipboard
|
||||||
|
*/
|
||||||
|
_onCopyImageDataUrl: Task.async(function*() {
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
let inspectorFront = this.inspector.inspector;
|
||||||
|
let data = yield inspectorFront.getImageDataFromURL(this._imageUrlToCopy);
|
||||||
|
message = yield data.data.string();
|
||||||
|
} catch (e) {
|
||||||
|
message = CssHtmlTree.l10n("styleinspector.copyImageDataUrlError");
|
||||||
|
}
|
||||||
|
|
||||||
|
clipboardHelper.copyString(message);
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy selected text.
|
* Copy selected text.
|
||||||
*
|
*
|
||||||
@ -910,6 +979,10 @@ CssHtmlTree.prototype = {
|
|||||||
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
||||||
this.menuitemCopyColor = null;
|
this.menuitemCopyColor = null;
|
||||||
|
|
||||||
|
// Destroy Copy Data URI menuitem.
|
||||||
|
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
|
||||||
|
this.menuitemCopyImageDataUrl = null;
|
||||||
|
|
||||||
// Destroy the context menu.
|
// Destroy the context menu.
|
||||||
this._contextmenu.removeEventListener("popupshowing", this._contextMenuUpdate);
|
this._contextmenu.removeEventListener("popupshowing", this._contextMenuUpdate);
|
||||||
this._contextmenu.parentNode.removeChild(this._contextmenu);
|
this._contextmenu.parentNode.removeChild(this._contextmenu);
|
||||||
|
@ -1123,6 +1123,7 @@ function CssRuleView(aInspector, aDoc, aStore, aPageStyle) {
|
|||||||
this._onSelectAll = this._onSelectAll.bind(this);
|
this._onSelectAll = this._onSelectAll.bind(this);
|
||||||
this._onCopy = this._onCopy.bind(this);
|
this._onCopy = this._onCopy.bind(this);
|
||||||
this._onCopyColor = this._onCopyColor.bind(this);
|
this._onCopyColor = this._onCopyColor.bind(this);
|
||||||
|
this._onCopyImageDataUrl = this._onCopyImageDataUrl.bind(this);
|
||||||
this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
|
this._onToggleOrigSources = this._onToggleOrigSources.bind(this);
|
||||||
this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
|
this._onShowMdnDocs = this._onShowMdnDocs.bind(this);
|
||||||
this._onFilterStyles = this._onFilterStyles.bind(this);
|
this._onFilterStyles = this._onFilterStyles.bind(this);
|
||||||
@ -1214,6 +1215,11 @@ CssRuleView.prototype = {
|
|||||||
accesskey: "ruleView.contextmenu.copyColor.accessKey",
|
accesskey: "ruleView.contextmenu.copyColor.accessKey",
|
||||||
command: this._onCopyColor
|
command: this._onCopyColor
|
||||||
});
|
});
|
||||||
|
this.menuitemCopyImageDataUrl = createMenuItem(this._contextmenu, {
|
||||||
|
label: "styleinspector.contextmenu.copyImageDataUrl",
|
||||||
|
accesskey: "styleinspector.contextmenu.copyImageDataUrl.accessKey",
|
||||||
|
command: this._onCopyImageDataUrl
|
||||||
|
});
|
||||||
this.menuitemSources = createMenuItem(this._contextmenu, {
|
this.menuitemSources = createMenuItem(this._contextmenu, {
|
||||||
label: "ruleView.contextmenu.showOrigSources",
|
label: "ruleView.contextmenu.showOrigSources",
|
||||||
accesskey: "ruleView.contextmenu.showOrigSources.accessKey",
|
accesskey: "ruleView.contextmenu.showOrigSources.accessKey",
|
||||||
@ -1348,6 +1354,7 @@ CssRuleView.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
this.menuitemCopyColor.hidden = !this._isColorPopup();
|
||||||
|
this.menuitemCopyImageDataUrl.hidden = !this._isImageUrlPopup();
|
||||||
this.menuitemCopy.disabled = !copy;
|
this.menuitemCopy.disabled = !copy;
|
||||||
|
|
||||||
var showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
var showOrig = Services.prefs.getBoolPref(PREF_ORIG_SOURCES);
|
||||||
@ -1398,7 +1405,7 @@ CssRuleView.prototype = {
|
|||||||
pseudoElement: prop.rule.pseudoElement,
|
pseudoElement: prop.rule.pseudoElement,
|
||||||
sheetHref: prop.rule.domRule.href
|
sheetHref: prop.rule.domRule.href
|
||||||
};
|
};
|
||||||
} else if (classes.contains("theme-link") && prop) {
|
} else if (classes.contains("theme-link") && !classes.contains("ruleview-rule-source") && prop) {
|
||||||
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
type = overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||||
value = {
|
value = {
|
||||||
property: getPropertyNameAndValue(node).name,
|
property: getPropertyNameAndValue(node).name,
|
||||||
@ -1430,14 +1437,11 @@ CssRuleView.prototype = {
|
|||||||
_isColorPopup: function () {
|
_isColorPopup: function () {
|
||||||
this._colorToCopy = "";
|
this._colorToCopy = "";
|
||||||
|
|
||||||
let trigger = this.doc.popupNode;
|
let container = this._getPopupNodeContainer();
|
||||||
if (!trigger) {
|
if (!container) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let container = (trigger.nodeType == trigger.TEXT_NODE) ?
|
|
||||||
trigger.parentElement : trigger;
|
|
||||||
|
|
||||||
let isColorNode = el => el.dataset && "color" in el.dataset;
|
let isColorNode = el => el.dataset && "color" in el.dataset;
|
||||||
|
|
||||||
while (!isColorNode(container)) {
|
while (!isColorNode(container)) {
|
||||||
@ -1451,6 +1455,52 @@ CssRuleView.prototype = {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the context menu popup was opened with a click on an image link
|
||||||
|
* If true, save the image url to this._imageUrlToCopy
|
||||||
|
*/
|
||||||
|
_isImageUrlPopup: function () {
|
||||||
|
this._imageUrlToCopy = "";
|
||||||
|
|
||||||
|
let container = this._getPopupNodeContainer();
|
||||||
|
let isImageUrlNode = this._isImageUrlNode(container);
|
||||||
|
if (isImageUrlNode) {
|
||||||
|
this._imageUrlToCopy = container.href;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isImageUrlNode;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a node is an image url
|
||||||
|
* @param {DOMNode} node The node which we want information about
|
||||||
|
* @return {Boolean} true if the node is an image url
|
||||||
|
*/
|
||||||
|
_isImageUrlNode: function (node) {
|
||||||
|
let nodeInfo = this.getNodeInfo(node);
|
||||||
|
if (!nodeInfo) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return nodeInfo.type == overlays.VIEW_NODE_IMAGE_URL_TYPE;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the DOM Node container for the current popupNode.
|
||||||
|
* If popupNode is a textNode, return the parent node, otherwise return popupNode itself.
|
||||||
|
* @return {DOMNode}
|
||||||
|
*/
|
||||||
|
_getPopupNodeContainer: function () {
|
||||||
|
let container = null;
|
||||||
|
let node = this.doc.popupNode;
|
||||||
|
|
||||||
|
if (node) {
|
||||||
|
let isTextNode = node.nodeType == node.TEXT_NODE;
|
||||||
|
container = isTextNode ? node.parentElement : node;
|
||||||
|
}
|
||||||
|
|
||||||
|
return container;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Context menu handler.
|
* Context menu handler.
|
||||||
*/
|
*/
|
||||||
@ -1525,6 +1575,22 @@ CssRuleView.prototype = {
|
|||||||
clipboardHelper.copyString(this._colorToCopy);
|
clipboardHelper.copyString(this._colorToCopy);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the image data for the selected image url and copy it to the clipboard
|
||||||
|
*/
|
||||||
|
_onCopyImageDataUrl: Task.async(function*() {
|
||||||
|
let message;
|
||||||
|
try {
|
||||||
|
let inspectorFront = this.inspector.inspector;
|
||||||
|
let data = yield inspectorFront.getImageDataFromURL(this._imageUrlToCopy);
|
||||||
|
message = yield data.data.string();
|
||||||
|
} catch (e) {
|
||||||
|
message = _strings.GetStringFromName("styleinspector.copyImageDataUrlError");
|
||||||
|
}
|
||||||
|
|
||||||
|
clipboardHelper.copyString(message);
|
||||||
|
}),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle the original sources pref.
|
* Toggle the original sources pref.
|
||||||
*/
|
*/
|
||||||
@ -1729,6 +1795,10 @@ CssRuleView.prototype = {
|
|||||||
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
this.menuitemCopyColor.removeEventListener("command", this._onCopyColor);
|
||||||
this.menuitemCopyColor = null;
|
this.menuitemCopyColor = null;
|
||||||
|
|
||||||
|
// Destroy Copy Data URI menuitem.
|
||||||
|
this.menuitemCopyImageDataUrl.removeEventListener("command", this._onCopyImageDataUrl);
|
||||||
|
this.menuitemCopyImageDataUrl = null;
|
||||||
|
|
||||||
this.menuitemSources.removeEventListener("command", this._onToggleOrigSources);
|
this.menuitemSources.removeEventListener("command", this._onToggleOrigSources);
|
||||||
this.menuitemSources = null;
|
this.menuitemSources = null;
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ const {
|
|||||||
SwatchFilterTooltip
|
SwatchFilterTooltip
|
||||||
} = require("devtools/shared/widgets/Tooltip");
|
} = require("devtools/shared/widgets/Tooltip");
|
||||||
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||||
|
const EventEmitter = require("devtools/toolkit/event-emitter");
|
||||||
const {Promise:promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
const {Promise:promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
|
||||||
Cu.import("resource://gre/modules/Task.jsm");
|
Cu.import("resource://gre/modules/Task.jsm");
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
@ -59,6 +60,8 @@ function HighlightersOverlay(view) {
|
|||||||
// Only initialize the overlay if at least one of the highlighter types is
|
// Only initialize the overlay if at least one of the highlighter types is
|
||||||
// supported
|
// supported
|
||||||
this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
|
this.supportsHighlighters = this.highlighterUtils.supportsCustomHighlighters();
|
||||||
|
|
||||||
|
EventEmitter.decorate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.HighlightersOverlay = HighlightersOverlay;
|
exports.HighlightersOverlay = HighlightersOverlay;
|
||||||
@ -124,8 +127,12 @@ HighlightersOverlay.prototype = {
|
|||||||
if (type) {
|
if (type) {
|
||||||
this.highlighterShown = type;
|
this.highlighterShown = type;
|
||||||
let node = this.view.inspector.selection.nodeFront;
|
let node = this.view.inspector.selection.nodeFront;
|
||||||
this._getHighlighter(type).then(highlighter => {
|
this._getHighlighter(type)
|
||||||
highlighter.show(node);
|
.then(highlighter => highlighter.show(node))
|
||||||
|
.then(shown => {
|
||||||
|
if (shown) {
|
||||||
|
this.emit("highlighter-shown");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -176,6 +183,7 @@ HighlightersOverlay.prototype = {
|
|||||||
promise.then(null, Cu.reportError);
|
promise.then(null, Cu.reportError);
|
||||||
}
|
}
|
||||||
this.highlighterShown = null;
|
this.highlighterShown = null;
|
||||||
|
this.emit("highlighter-hidden");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -151,6 +151,7 @@ skip-if = e10s # bug 1040670 Cannot open inline styles in viewSourceUtils
|
|||||||
[browser_ruleview_user-property-reset.js]
|
[browser_ruleview_user-property-reset.js]
|
||||||
[browser_styleinspector_context-menu-copy-color_01.js]
|
[browser_styleinspector_context-menu-copy-color_01.js]
|
||||||
[browser_styleinspector_context-menu-copy-color_02.js]
|
[browser_styleinspector_context-menu-copy-color_02.js]
|
||||||
|
[browser_styleinspector_context-menu-copy-data-uri.js]
|
||||||
[browser_styleinspector_csslogic-content-stylesheets.js]
|
[browser_styleinspector_csslogic-content-stylesheets.js]
|
||||||
[browser_styleinspector_output-parser.js]
|
[browser_styleinspector_output-parser.js]
|
||||||
[browser_styleinspector_refresh_when_active.js]
|
[browser_styleinspector_refresh_when_active.js]
|
||||||
|
@ -0,0 +1,99 @@
|
|||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
const PROPERTIES_URL = "chrome://global/locale/devtools/styleinspector.properties";
|
||||||
|
const TEST_DATA_URI = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACwAAAAAAQABAAACAkQBADs=";
|
||||||
|
|
||||||
|
// invalid URL still needs to be reachable otherwise getImageDataUrl will timeout.
|
||||||
|
// Reusing the properties bundle URL as a workaround
|
||||||
|
const INVALID_IMAGE_URI = PROPERTIES_URL;
|
||||||
|
|
||||||
|
const ERROR_MESSAGE = Services.strings
|
||||||
|
.createBundle(PROPERTIES_URL)
|
||||||
|
.GetStringFromName("styleinspector.copyImageDataUrlError");
|
||||||
|
|
||||||
|
add_task(function*() {
|
||||||
|
const PAGE_CONTENT = [
|
||||||
|
"<style type=\"text/css\">",
|
||||||
|
" .valid-background {",
|
||||||
|
" background-image: url(" + TEST_DATA_URI + ");",
|
||||||
|
" }",
|
||||||
|
" .invalid-background {",
|
||||||
|
" background-image: url(" + INVALID_IMAGE_URI + ");",
|
||||||
|
" }",
|
||||||
|
"</style>",
|
||||||
|
"<div class=\"valid-background\">Valid background image</div>",
|
||||||
|
"<div class=\"invalid-background\">Invalid background image</div>"
|
||||||
|
].join("\n");
|
||||||
|
|
||||||
|
yield addTab("data:text/html;charset=utf8," + encodeURIComponent(PAGE_CONTENT));
|
||||||
|
|
||||||
|
yield startTest();
|
||||||
|
});
|
||||||
|
|
||||||
|
function* startTest() {
|
||||||
|
info("Opening rule view");
|
||||||
|
let ruleViewData = yield openRuleView();
|
||||||
|
|
||||||
|
info("Test valid background image URL in rule view");
|
||||||
|
yield testCopyImageDataUrlToClipboard(ruleViewData, ".valid-background", TEST_DATA_URI);
|
||||||
|
info("Test invalid background image URL in rue view");
|
||||||
|
yield testCopyImageDataUrlToClipboard(ruleViewData, ".invalid-background", ERROR_MESSAGE);
|
||||||
|
|
||||||
|
info("Opening computed view");
|
||||||
|
let computedViewData = yield openComputedView();
|
||||||
|
|
||||||
|
info("Test valid background image URL in computed view");
|
||||||
|
yield testCopyImageDataUrlToClipboard(computedViewData, ".valid-background", TEST_DATA_URI);
|
||||||
|
info("Test invalid background image URL in computed view");
|
||||||
|
yield testCopyImageDataUrlToClipboard(computedViewData, ".invalid-background", ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function* testCopyImageDataUrlToClipboard({view, inspector}, selector, expected) {
|
||||||
|
info("Select node in inspector panel");
|
||||||
|
yield selectNode(selector, inspector);
|
||||||
|
|
||||||
|
info("Retrieve background-image link for selected node in current styleinspector view");
|
||||||
|
let property = getBackgroundImageProperty(view, selector);
|
||||||
|
let imageLink = property.valueSpan.querySelector(".theme-link");
|
||||||
|
ok(imageLink, "Background-image link element found");
|
||||||
|
|
||||||
|
info("Simulate right click on the background-image URL");
|
||||||
|
let popup = once(view._contextmenu, "popupshown");
|
||||||
|
|
||||||
|
// Cannot rely on synthesizeMouseAtCenter here. The image URL can be displayed on several lines.
|
||||||
|
// A click simulated at the exact center may click between the lines and miss the target
|
||||||
|
// Instead, using the top-left corner of first client rect, with an offset of 2 pixels.
|
||||||
|
let rect = imageLink.getClientRects()[0];
|
||||||
|
let x = rect.left + 2;
|
||||||
|
let y = rect.top + 2;
|
||||||
|
|
||||||
|
EventUtils.synthesizeMouseAtPoint(x, y, {button: 2, type: "contextmenu"}, getViewWindow(view));
|
||||||
|
yield popup;
|
||||||
|
|
||||||
|
info("Context menu is displayed");
|
||||||
|
ok(!view.menuitemCopyImageDataUrl.hidden, "\"Copy Image Data-URL\" menu entry is displayed");
|
||||||
|
|
||||||
|
info("Click Copy Data URI and wait for clipboard");
|
||||||
|
yield waitForClipboard(() => view.menuitemCopyImageDataUrl.click(), expected);
|
||||||
|
|
||||||
|
info("Hide context menu");
|
||||||
|
view._contextmenu.hidePopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getBackgroundImageProperty(view, selector) {
|
||||||
|
let isRuleView = view instanceof CssRuleView;
|
||||||
|
if (isRuleView) {
|
||||||
|
return getRuleViewProperty(view, selector, "background-image");
|
||||||
|
} else {
|
||||||
|
return getComputedViewProperty(view, "background-image");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function that returns the window for a given view.
|
||||||
|
*/
|
||||||
|
function getViewWindow(view) {
|
||||||
|
let viewDocument = view.styleDocument ? view.styleDocument : view.doc;
|
||||||
|
return viewDocument.defaultView;
|
||||||
|
}
|
@ -36,7 +36,9 @@ add_task(function*() {
|
|||||||
|
|
||||||
info("Faking a mousemove on a transform property");
|
info("Faking a mousemove on a transform property");
|
||||||
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
||||||
|
let onHighlighterShown = hs.once("highlighter-shown");
|
||||||
hs._onMouseMove({target: valueSpan});
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
||||||
let h = yield hs.promises[TYPE];
|
let h = yield hs.promises[TYPE];
|
||||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||||
@ -57,7 +59,9 @@ add_task(function*() {
|
|||||||
|
|
||||||
info("Faking a mousemove on a transform property");
|
info("Faking a mousemove on a transform property");
|
||||||
({valueSpan} = getComputedViewProperty(cView, "transform"));
|
({valueSpan} = getComputedViewProperty(cView, "transform"));
|
||||||
|
onHighlighterShown = hs.once("highlighter-shown");
|
||||||
hs._onMouseMove({target: valueSpan});
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
ok(hs.promises[TYPE], "The highlighter is being initialized");
|
||||||
h = yield hs.promises[TYPE];
|
h = yield hs.promises[TYPE];
|
||||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||||
|
@ -39,53 +39,64 @@ add_task(function*() {
|
|||||||
this.nodeFront = nodeFront;
|
this.nodeFront = nodeFront;
|
||||||
this.isShown = true;
|
this.isShown = true;
|
||||||
this.nbOfTimesShown ++;
|
this.nbOfTimesShown ++;
|
||||||
|
return promise.resolve(true);
|
||||||
},
|
},
|
||||||
hide: function() {
|
hide: function() {
|
||||||
this.nodeFront = null;
|
this.nodeFront = null;
|
||||||
this.isShown = false;
|
this.isShown = false;
|
||||||
|
return promise.resolve();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Inject the mock highlighter in the rule-view
|
// Inject the mock highlighter in the rule-view
|
||||||
rView.highlighters.promises[TYPE] = {
|
let hs = rView.highlighters;
|
||||||
then: function(cb) {
|
hs.promises[TYPE] = promise.resolve(HighlighterFront);
|
||||||
cb(HighlighterFront);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let {valueSpan} = getRuleViewProperty(rView, "body", "transform");
|
let {valueSpan} = getRuleViewProperty(rView, "body", "transform");
|
||||||
|
|
||||||
info("Checking that the HighlighterFront's show/hide methods are called");
|
info("Checking that the HighlighterFront's show/hide methods are called");
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
let onHighlighterShown = hs.once("highlighter-shown");
|
||||||
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
ok(HighlighterFront.isShown, "The highlighter is shown");
|
ok(HighlighterFront.isShown, "The highlighter is shown");
|
||||||
rView.highlighters._onMouseLeave();
|
let onHighlighterHidden = hs.once("highlighter-hidden");
|
||||||
|
hs._onMouseLeave();
|
||||||
|
yield onHighlighterHidden;
|
||||||
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
||||||
|
|
||||||
info("Checking that hovering several times over the same property doesn't" +
|
info("Checking that hovering several times over the same property doesn't" +
|
||||||
" show the highlighter several times");
|
" show the highlighter several times");
|
||||||
let nb = HighlighterFront.nbOfTimesShown;
|
let nb = HighlighterFront.nbOfTimesShown;
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
onHighlighterShown = hs.once("highlighter-shown");
|
||||||
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
is(HighlighterFront.nbOfTimesShown, nb + 1, "The highlighter was shown once");
|
is(HighlighterFront.nbOfTimesShown, nb + 1, "The highlighter was shown once");
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
hs._onMouseMove({target: valueSpan});
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
hs._onMouseMove({target: valueSpan});
|
||||||
is(HighlighterFront.nbOfTimesShown, nb + 1,
|
is(HighlighterFront.nbOfTimesShown, nb + 1,
|
||||||
"The highlighter was shown once, after several mousemove");
|
"The highlighter was shown once, after several mousemove");
|
||||||
|
|
||||||
info("Checking that the right NodeFront reference is passed");
|
info("Checking that the right NodeFront reference is passed");
|
||||||
yield selectNode("html", inspector);
|
yield selectNode("html", inspector);
|
||||||
({valueSpan} = getRuleViewProperty(rView, "html", "transform"));
|
({valueSpan} = getRuleViewProperty(rView, "html", "transform"));
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
onHighlighterShown = hs.once("highlighter-shown");
|
||||||
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
is(HighlighterFront.nodeFront.tagName, "HTML",
|
is(HighlighterFront.nodeFront.tagName, "HTML",
|
||||||
"The right NodeFront is passed to the highlighter (1)");
|
"The right NodeFront is passed to the highlighter (1)");
|
||||||
|
|
||||||
yield selectNode("body", inspector);
|
yield selectNode("body", inspector);
|
||||||
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
({valueSpan} = getRuleViewProperty(rView, "body", "transform"));
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
onHighlighterShown = hs.once("highlighter-shown");
|
||||||
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
is(HighlighterFront.nodeFront.tagName, "BODY",
|
is(HighlighterFront.nodeFront.tagName, "BODY",
|
||||||
"The right NodeFront is passed to the highlighter (2)");
|
"The right NodeFront is passed to the highlighter (2)");
|
||||||
|
|
||||||
info("Checking that the highlighter gets hidden when hovering a non-transform property");
|
info("Checking that the highlighter gets hidden when hovering a non-transform property");
|
||||||
({valueSpan} = getRuleViewProperty(rView, "body", "color"));
|
({valueSpan} = getRuleViewProperty(rView, "body", "color"));
|
||||||
rView.highlighters._onMouseMove({target: valueSpan});
|
onHighlighterHidden = hs.once("highlighter-hidden");
|
||||||
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterHidden;
|
||||||
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
ok(!HighlighterFront.isShown, "The highlighter is hidden");
|
||||||
});
|
});
|
||||||
|
@ -55,7 +55,9 @@ add_task(function*() {
|
|||||||
|
|
||||||
info("Faking a mousemove on the now unoverriden property");
|
info("Faking a mousemove on the now unoverriden property");
|
||||||
({valueSpan} = getRuleViewProperty(rView, "div", "transform"));
|
({valueSpan} = getRuleViewProperty(rView, "div", "transform"));
|
||||||
|
let onHighlighterShown = hs.once("highlighter-shown");
|
||||||
hs._onMouseMove({target: valueSpan});
|
hs._onMouseMove({target: valueSpan});
|
||||||
|
yield onHighlighterShown;
|
||||||
ok(hs.promises[TYPE], "The highlighter is being initialized now");
|
ok(hs.promises[TYPE], "The highlighter is being initialized now");
|
||||||
let h = yield hs.promises[TYPE];
|
let h = yield hs.promises[TYPE];
|
||||||
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
is(h, hs.highlighters[TYPE], "The initialized highlighter is the right one");
|
||||||
|
@ -431,7 +431,7 @@ if test -z "$RUSTC" -a -n "$MOZ_RUST"; then
|
|||||||
To compile rust language sources, you must have 'rustc' in your path.
|
To compile rust language sources, you must have 'rustc' in your path.
|
||||||
See http://www.rust-lang.org/ for more information.])
|
See http://www.rust-lang.org/ for more information.])
|
||||||
fi
|
fi
|
||||||
if test -n "$MOZ_RUST" -a -z "$_RUSTC_MAJOR_VERSION" -o \
|
if test -n "$MOZ_RUST" && test -z "$_RUSTC_MAJOR_VERSION" -o \
|
||||||
"$_RUSTC_MAJOR_VERSION" -lt 1; then
|
"$_RUSTC_MAJOR_VERSION" -lt 1; then
|
||||||
AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old.
|
AC_MSG_ERROR([Rust compiler ${RUSTC_VERSION} is too old.
|
||||||
To compile rust language sources please install at least
|
To compile rust language sources please install at least
|
||||||
|
@ -548,6 +548,8 @@ public class BrowserApp extends GeckoApp
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showBookmarkAddedToast() {
|
private void showBookmarkAddedToast() {
|
||||||
|
// This flow is from the option menu which has check to see if a bookmark was already added.
|
||||||
|
// So, it is safe here to show the toast that bookmark_added without any checks.
|
||||||
getButtonToast().show(false,
|
getButtonToast().show(false,
|
||||||
getResources().getString(R.string.bookmark_added),
|
getResources().getString(R.string.bookmark_added),
|
||||||
ButtonToast.LENGTH_SHORT,
|
ButtonToast.LENGTH_SHORT,
|
||||||
|
@ -559,11 +559,12 @@ public abstract class GeckoApp
|
|||||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
db.addBookmark(getContentResolver(), title, url);
|
final boolean bookmarkAdded = db.addBookmark(getContentResolver(), title, url);
|
||||||
|
final int resId = bookmarkAdded ? R.string.bookmark_added : R.string.bookmark_already_added;
|
||||||
ThreadUtils.postToUiThread(new Runnable() {
|
ThreadUtils.postToUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
Toast.makeText(context, R.string.bookmark_added, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, resId, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ public interface BrowserDB {
|
|||||||
public abstract String getUrlForKeyword(ContentResolver cr, String keyword);
|
public abstract String getUrlForKeyword(ContentResolver cr, String keyword);
|
||||||
|
|
||||||
public abstract boolean isBookmark(ContentResolver cr, String uri);
|
public abstract boolean isBookmark(ContentResolver cr, String uri);
|
||||||
public abstract void addBookmark(ContentResolver cr, String title, String uri);
|
public abstract boolean addBookmark(ContentResolver cr, String title, String uri);
|
||||||
public abstract Cursor getBookmarkForUrl(ContentResolver cr, String url);
|
public abstract Cursor getBookmarkForUrl(ContentResolver cr, String url);
|
||||||
public abstract void removeBookmarksWithURL(ContentResolver cr, String uri);
|
public abstract void removeBookmarksWithURL(ContentResolver cr, String uri);
|
||||||
public abstract void registerBookmarkObserver(ContentResolver cr, ContentObserver observer);
|
public abstract void registerBookmarkObserver(ContentResolver cr, ContentObserver observer);
|
||||||
|
@ -939,9 +939,34 @@ public class LocalBrowserDB implements BrowserDB {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@RobocopTarget
|
@RobocopTarget
|
||||||
public void addBookmark(ContentResolver cr, String title, String uri) {
|
public boolean addBookmark(ContentResolver cr, String title, String uri) {
|
||||||
long folderId = getFolderIdFromGuid(cr, Bookmarks.MOBILE_FOLDER_GUID);
|
long folderId = getFolderIdFromGuid(cr, Bookmarks.MOBILE_FOLDER_GUID);
|
||||||
|
if (isBookmarkForUrlInFolder(cr, uri, folderId)) {
|
||||||
|
// Bookmark added already.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add a new bookmark.
|
||||||
addBookmarkItem(cr, title, uri, folderId);
|
addBookmarkItem(cr, title, uri, folderId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isBookmarkForUrlInFolder(ContentResolver cr, String uri, long folderId) {
|
||||||
|
final Cursor c = cr.query(bookmarksUriWithLimit(1),
|
||||||
|
new String[] { Bookmarks._ID },
|
||||||
|
Bookmarks.URL + " = ? AND " + Bookmarks.PARENT + " = ? AND " + Bookmarks.IS_DELETED + " == 0",
|
||||||
|
new String[] { uri, String.valueOf(folderId) },
|
||||||
|
Bookmarks.URL);
|
||||||
|
|
||||||
|
if (c == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return c.getCount() > 0;
|
||||||
|
} finally {
|
||||||
|
c.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -250,7 +250,8 @@ public class StubBrowserDB implements BrowserDB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RobocopTarget
|
@RobocopTarget
|
||||||
public void addBookmark(ContentResolver cr, String title, String uri) {
|
public boolean addBookmark(ContentResolver cr, String title, String uri) {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RobocopTarget
|
@RobocopTarget
|
||||||
|
@ -44,6 +44,10 @@
|
|||||||
<!ENTITY bookmark "Bookmark">
|
<!ENTITY bookmark "Bookmark">
|
||||||
<!ENTITY bookmark_remove "Remove bookmark">
|
<!ENTITY bookmark_remove "Remove bookmark">
|
||||||
<!ENTITY bookmark_added "Bookmark added">
|
<!ENTITY bookmark_added "Bookmark added">
|
||||||
|
<!-- Localization note (bookmark_already_added) : This string is
|
||||||
|
used as a label in a toast. It is the verb "to bookmark", not
|
||||||
|
the noun "a bookmark". -->
|
||||||
|
<!ENTITY bookmark_already_added "Already bookmarked">
|
||||||
<!ENTITY bookmark_removed "Bookmark removed">
|
<!ENTITY bookmark_removed "Bookmark removed">
|
||||||
<!ENTITY bookmark_updated "Bookmark updated">
|
<!ENTITY bookmark_updated "Bookmark updated">
|
||||||
<!ENTITY bookmark_options "Options">
|
<!ENTITY bookmark_options "Options">
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
<string name="bookmark">&bookmark;</string>
|
<string name="bookmark">&bookmark;</string>
|
||||||
<string name="bookmark_remove">&bookmark_remove;</string>
|
<string name="bookmark_remove">&bookmark_remove;</string>
|
||||||
<string name="bookmark_added">&bookmark_added;</string>
|
<string name="bookmark_added">&bookmark_added;</string>
|
||||||
|
<string name="bookmark_already_added">&bookmark_already_added;</string>
|
||||||
<string name="bookmark_removed">&bookmark_removed;</string>
|
<string name="bookmark_removed">&bookmark_removed;</string>
|
||||||
<string name="bookmark_updated">&bookmark_updated;</string>
|
<string name="bookmark_updated">&bookmark_updated;</string>
|
||||||
<string name="bookmark_options">&bookmark_options;</string>
|
<string name="bookmark_options">&bookmark_options;</string>
|
||||||
|
@ -50,14 +50,12 @@ class DatabaseHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a bookmark, or updates the bookmark title if the url already exists.
|
* Adds a bookmark.
|
||||||
*
|
|
||||||
* The LocalBrowserDB.addBookmark implementation handles updating existing bookmarks.
|
|
||||||
*/
|
*/
|
||||||
protected void addOrUpdateMobileBookmark(String title, String url) {
|
protected void addMobileBookmark(String title, String url) {
|
||||||
final ContentResolver resolver = mActivity.getContentResolver();
|
final ContentResolver resolver = mActivity.getContentResolver();
|
||||||
getProfileDB().addBookmark(resolver, title, url);
|
getProfileDB().addBookmark(resolver, title, url);
|
||||||
mAsserter.ok(true, "Inserting/updating a new bookmark", "Inserting/updating the bookmark with the title = " + title + " and the url = " + url);
|
mAsserter.ok(true, "Inserting a new bookmark", "Inserting the bookmark with the title = " + title + " and the url = " + url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +31,7 @@ public class testBookmark extends AboutHomeTest {
|
|||||||
mAsserter.ok(mDatabaseHelper.isBookmark(url), "Checking that " + url + " is bookmarked by default", url + " is bookmarked");
|
mAsserter.ok(mDatabaseHelper.isBookmark(url), "Checking that " + url + " is bookmarked by default", url + " is bookmarked");
|
||||||
}
|
}
|
||||||
|
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
|
mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
|
||||||
waitForBookmarked(true);
|
waitForBookmarked(true);
|
||||||
|
|
||||||
isBookmarkDisplayed(BOOKMARK_URL);
|
isBookmarkDisplayed(BOOKMARK_URL);
|
||||||
|
@ -13,7 +13,7 @@ public class testBookmarkKeyword extends AboutHomeTest {
|
|||||||
final String keyword = "testkeyword";
|
final String keyword = "testkeyword";
|
||||||
|
|
||||||
// Add a bookmark, and update it to have a keyword.
|
// Add a bookmark, and update it to have a keyword.
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, url);
|
mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, url);
|
||||||
mDatabaseHelper.updateBookmark(url, mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, keyword);
|
mDatabaseHelper.updateBookmark(url, mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, keyword);
|
||||||
|
|
||||||
// Enter the keyword in the urlbar.
|
// Enter the keyword in the urlbar.
|
||||||
|
@ -40,7 +40,7 @@ public class testBookmarklets extends AboutHomeTest {
|
|||||||
|
|
||||||
// add the bookmarklet to the database. there's currently no way to
|
// add the bookmarklet to the database. there's currently no way to
|
||||||
// add this using the UI, so we go through the content provider.
|
// add this using the UI, so we go through the content provider.
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark(title, js);
|
mDatabaseHelper.addMobileBookmark(title, js);
|
||||||
|
|
||||||
// Open about:home in the Bookmarks page
|
// Open about:home in the Bookmarks page
|
||||||
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
||||||
|
@ -21,7 +21,7 @@ public class testBookmarksPanel extends AboutHomeTest {
|
|||||||
initializeProfile();
|
initializeProfile();
|
||||||
|
|
||||||
// Add a mobile bookmark.
|
// Add a mobile bookmark.
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
|
mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_01_TITLE, BOOKMARK_URL);
|
||||||
|
|
||||||
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
openAboutHomeTab(AboutHomeTabs.BOOKMARKS);
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ public class testClearPrivateData extends PixelTest {
|
|||||||
|
|
||||||
loadUrlAndWait(blank1);
|
loadUrlAndWait(blank1);
|
||||||
verifyUrlBarTitle(blank1);
|
verifyUrlBarTitle(blank1);
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2);
|
mDatabaseHelper.addMobileBookmark(mStringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2);
|
||||||
|
|
||||||
// Checking that the history list is not empty
|
// Checking that the history list is not empty
|
||||||
verifyHistoryCount(1);
|
verifyHistoryCount(1);
|
||||||
|
@ -113,7 +113,7 @@ public class testImportFromAndroid extends AboutHomeTest {
|
|||||||
for (String url:androidBookmarks) {
|
for (String url:androidBookmarks) {
|
||||||
// Add every 3rd bookmark to Firefox Mobile
|
// Add every 3rd bookmark to Firefox Mobile
|
||||||
if ((androidBookmarks.indexOf(url) % 3) == 0) {
|
if ((androidBookmarks.indexOf(url) % 3) == 0) {
|
||||||
mDatabaseHelper.addOrUpdateMobileBookmark("Bookmark Number" + String.valueOf(androidBookmarks.indexOf(url)), url);
|
mDatabaseHelper.addMobileBookmark("Bookmark Number" + String.valueOf(androidBookmarks.indexOf(url)), url);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,57 @@ const MEASURES = [
|
|||||||
{key: "ticks", percentOfDeltaT: false, label: "Activations"},
|
{key: "ticks", percentOfDeltaT: false, label: "Activations"},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to control the live updates in the performance page.
|
||||||
|
*/
|
||||||
|
let AutoUpdate = {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timer that is created when setInterval is called.
|
||||||
|
*/
|
||||||
|
_timerId: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dropdown DOM element.
|
||||||
|
*/
|
||||||
|
_intervalDropdown: null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts updating the performance data if the updates are paused.
|
||||||
|
*/
|
||||||
|
start: function () {
|
||||||
|
if (AutoUpdate._intervalDropdown == null){
|
||||||
|
AutoUpdate._intervalDropdown = document.getElementById("intervalDropdown");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (AutoUpdate._timerId == null) {
|
||||||
|
let dropdownIndex = AutoUpdate._intervalDropdown.selectedIndex;
|
||||||
|
let dropdownValue = AutoUpdate._intervalDropdown.options[dropdownIndex].value;
|
||||||
|
AutoUpdate._timerId = window.setInterval(update, dropdownValue);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the updates if the data is updating.
|
||||||
|
*/
|
||||||
|
stop: function () {
|
||||||
|
if (AutoUpdate._timerId == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
clearInterval(AutoUpdate._timerId);
|
||||||
|
AutoUpdate._timerId = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the refresh interval when the dropdown selection is changed.
|
||||||
|
*/
|
||||||
|
updateRefreshRate: function () {
|
||||||
|
AutoUpdate.stop();
|
||||||
|
AutoUpdate.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
let State = {
|
let State = {
|
||||||
/**
|
/**
|
||||||
* @type{PerformanceData}
|
* @type{PerformanceData}
|
||||||
@ -237,9 +288,11 @@ function updateLiveData() {
|
|||||||
function go() {
|
function go() {
|
||||||
// Compute initial state immediately, then wait a little
|
// Compute initial state immediately, then wait a little
|
||||||
// before we start computing diffs and refreshing.
|
// before we start computing diffs and refreshing.
|
||||||
State.update();
|
document.getElementById("playButton").addEventListener("click", () => AutoUpdate.start());
|
||||||
|
document.getElementById("pauseButton").addEventListener("click", () => AutoUpdate.stop());
|
||||||
|
|
||||||
window.setTimeout(() => {
|
document.getElementById("intervalDropdown").addEventListener("change", () => AutoUpdate.updateRefreshRate());
|
||||||
window.setInterval(update, 10000);
|
|
||||||
}, 1000);
|
State.update();
|
||||||
|
setTimeout(update, 1000);
|
||||||
}
|
}
|
@ -87,6 +87,16 @@
|
|||||||
<body onload="go()">
|
<body onload="go()">
|
||||||
|
|
||||||
<h1>Performance monitor</h1>
|
<h1>Performance monitor</h1>
|
||||||
|
|
||||||
|
<input type="button" id="playButton" value="Play" />
|
||||||
|
<input type="button" id="pauseButton" value="Pause" />
|
||||||
|
<select id="intervalDropdown">
|
||||||
|
<option value="500">0.5 seconds</option>
|
||||||
|
<option value="1000">1 second</option>
|
||||||
|
<option value="2000">2 seconds</option>
|
||||||
|
<option value="5000" selected="selected">5 seconds</option>
|
||||||
|
<option value="10000">10 seconds</option>
|
||||||
|
</select>
|
||||||
<table id="liveData">
|
<table id="liveData">
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ exports.zip = function zip(a, b) {
|
|||||||
*/
|
*/
|
||||||
exports.executeSoon = function executeSoon(aFn) {
|
exports.executeSoon = function executeSoon(aFn) {
|
||||||
if (isWorker) {
|
if (isWorker) {
|
||||||
require("Timer").setTimeout(aFn, 0);
|
setImmediate(aFn);
|
||||||
} else {
|
} else {
|
||||||
Services.tm.mainThread.dispatch({
|
Services.tm.mainThread.dispatch({
|
||||||
run: exports.makeInfallible(aFn)
|
run: exports.makeInfallible(aFn)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
const {Cu, Cc, Ci} = require("chrome");
|
const {Cu, Cc, Ci} = require("chrome");
|
||||||
const Services = require("Services");
|
const Services = require("Services");
|
||||||
const protocol = require("devtools/server/protocol");
|
const protocol = require("devtools/server/protocol");
|
||||||
const {Arg, Option, method} = protocol;
|
const {Arg, Option, method, RetVal} = protocol;
|
||||||
const events = require("sdk/event/core");
|
const events = require("sdk/event/core");
|
||||||
const Heritage = require("sdk/core/heritage");
|
const Heritage = require("sdk/core/heritage");
|
||||||
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
const {CssLogic} = require("devtools/styleinspector/css-logic");
|
||||||
@ -455,17 +455,21 @@ let CustomHighlighterActor = exports.CustomHighlighterActor = protocol.ActorClas
|
|||||||
*
|
*
|
||||||
* @param NodeActor The node to be highlighted
|
* @param NodeActor The node to be highlighted
|
||||||
* @param Object Options for the custom highlighter
|
* @param Object Options for the custom highlighter
|
||||||
|
* @return Boolean True, if the highlighter has been successfully shown (FF41+)
|
||||||
*/
|
*/
|
||||||
show: method(function(node, options) {
|
show: method(function(node, options) {
|
||||||
if (!node || !isNodeValid(node.rawNode) || !this._highlighter) {
|
if (!node || !isNodeValid(node.rawNode) || !this._highlighter) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._highlighter.show(node.rawNode, options);
|
return this._highlighter.show(node.rawNode, options);
|
||||||
}, {
|
}, {
|
||||||
request: {
|
request: {
|
||||||
node: Arg(0, "domnode"),
|
node: Arg(0, "domnode"),
|
||||||
options: Arg(1, "nullable:json")
|
options: Arg(1, "nullable:json")
|
||||||
|
},
|
||||||
|
response: {
|
||||||
|
value: RetVal("nullable:boolean")
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
@ -849,7 +853,7 @@ AutoRefreshHighlighter.prototype = {
|
|||||||
let isSameOptions = this._isSameOptions(options);
|
let isSameOptions = this._isSameOptions(options);
|
||||||
|
|
||||||
if (!isNodeValid(node) || (isSameNode && isSameOptions)) {
|
if (!isNodeValid(node) || (isSameNode && isSameOptions)) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.options = options;
|
this.options = options;
|
||||||
@ -858,9 +862,12 @@ AutoRefreshHighlighter.prototype = {
|
|||||||
this.currentNode = node;
|
this.currentNode = node;
|
||||||
this._updateAdjustedQuads();
|
this._updateAdjustedQuads();
|
||||||
this._startRefreshLoop();
|
this._startRefreshLoop();
|
||||||
this._show();
|
|
||||||
|
|
||||||
|
let shown = this._show();
|
||||||
|
if (shown) {
|
||||||
this.emit("shown");
|
this.emit("shown");
|
||||||
|
}
|
||||||
|
return shown;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -942,6 +949,7 @@ AutoRefreshHighlighter.prototype = {
|
|||||||
// To be implemented by sub classes
|
// To be implemented by sub classes
|
||||||
// When called, sub classes should actually show the highlighter for
|
// When called, sub classes should actually show the highlighter for
|
||||||
// this.currentNode, potentially using options in this.options
|
// this.currentNode, potentially using options in this.options
|
||||||
|
throw new Error("Custom highlighter class had to implement _show method");
|
||||||
},
|
},
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
@ -949,11 +957,13 @@ AutoRefreshHighlighter.prototype = {
|
|||||||
// When called, sub classes should update the highlighter shown for
|
// When called, sub classes should update the highlighter shown for
|
||||||
// this.currentNode
|
// this.currentNode
|
||||||
// This is called as a result of a page scroll, zoom or repaint
|
// This is called as a result of a page scroll, zoom or repaint
|
||||||
|
throw new Error("Custom highlighter class had to implement _update method");
|
||||||
},
|
},
|
||||||
|
|
||||||
_hide: function() {
|
_hide: function() {
|
||||||
// To be implemented by sub classes
|
// To be implemented by sub classes
|
||||||
// When called, sub classes should actually hide the highlighter
|
// When called, sub classes should actually hide the highlighter
|
||||||
|
throw new Error("Custom highlighter class had to implement _hide method");
|
||||||
},
|
},
|
||||||
|
|
||||||
_startRefreshLoop: function() {
|
_startRefreshLoop: function() {
|
||||||
@ -1229,9 +1239,10 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
|||||||
this.options.region = "content";
|
this.options.region = "content";
|
||||||
}
|
}
|
||||||
|
|
||||||
this._update();
|
let shown = this._update();
|
||||||
this._trackMutations();
|
this._trackMutations();
|
||||||
this.emit("ready");
|
this.emit("ready");
|
||||||
|
return shown;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1259,6 +1270,7 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
|||||||
* Should be called whenever node size or attributes change
|
* Should be called whenever node size or attributes change
|
||||||
*/
|
*/
|
||||||
_update: function() {
|
_update: function() {
|
||||||
|
let shown = false;
|
||||||
setIgnoreLayoutChanges(true);
|
setIgnoreLayoutChanges(true);
|
||||||
|
|
||||||
if (this._updateBoxModel()) {
|
if (this._updateBoxModel()) {
|
||||||
@ -1268,12 +1280,15 @@ BoxModelHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.prototype
|
|||||||
this._hideInfobar();
|
this._hideInfobar();
|
||||||
}
|
}
|
||||||
this._showBoxModel();
|
this._showBoxModel();
|
||||||
|
shown = true;
|
||||||
} else {
|
} else {
|
||||||
// Nothing to highlight (0px rectangle like a <script> tag for instance)
|
// Nothing to highlight (0px rectangle like a <script> tag for instance)
|
||||||
this._hide();
|
this._hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
||||||
|
|
||||||
|
return shown;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1775,15 +1790,14 @@ CssTransformHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.proto
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Show the highlighter on a given node
|
* Show the highlighter on a given node
|
||||||
* @param {DOMNode} node
|
|
||||||
*/
|
*/
|
||||||
_show: function() {
|
_show: function() {
|
||||||
if (!this._isTransformed(this.currentNode)) {
|
if (!this._isTransformed(this.currentNode)) {
|
||||||
this.hide();
|
this.hide();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._update();
|
return this._update();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1830,7 +1844,7 @@ CssTransformHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.proto
|
|||||||
if (!quads.length ||
|
if (!quads.length ||
|
||||||
quads[0].bounds.width <= 0 || quads[0].bounds.height <= 0) {
|
quads[0].bounds.width <= 0 || quads[0].bounds.height <= 0) {
|
||||||
this._hideShapes();
|
this._hideShapes();
|
||||||
return null;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let [quad] = quads;
|
let [quad] = quads;
|
||||||
@ -1850,6 +1864,7 @@ CssTransformHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.proto
|
|||||||
this._showShapes();
|
this._showShapes();
|
||||||
|
|
||||||
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
setIgnoreLayoutChanges(false, this.currentNode.ownerDocument.documentElement);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1898,7 +1913,7 @@ SelectorHighlighter.prototype = {
|
|||||||
this.hide();
|
this.hide();
|
||||||
|
|
||||||
if (!isNodeValid(node) || !options.selector) {
|
if (!isNodeValid(node) || !options.selector) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let nodes = [];
|
let nodes = [];
|
||||||
@ -1922,6 +1937,8 @@ SelectorHighlighter.prototype = {
|
|||||||
this._highlighters.push(highlighter);
|
this._highlighters.push(highlighter);
|
||||||
i ++;
|
i ++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
@ -1998,7 +2015,7 @@ RectHighlighter.prototype = {
|
|||||||
show: function(node, options) {
|
show: function(node, options) {
|
||||||
if (!this._hasValidOptions(options) || !node || !node.ownerDocument) {
|
if (!this._hasValidOptions(options) || !node || !node.ownerDocument) {
|
||||||
this.hide();
|
this.hide();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let contextNode = node.ownerDocument.documentElement;
|
let contextNode = node.ownerDocument.documentElement;
|
||||||
@ -2007,7 +2024,7 @@ RectHighlighter.prototype = {
|
|||||||
let quads = this.layoutHelpers.getAdjustedQuads(contextNode);
|
let quads = this.layoutHelpers.getAdjustedQuads(contextNode);
|
||||||
if (!quads.length) {
|
if (!quads.length) {
|
||||||
this.hide();
|
this.hide();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {bounds} = quads[0];
|
let {bounds} = quads[0];
|
||||||
@ -2025,6 +2042,8 @@ RectHighlighter.prototype = {
|
|||||||
let rect = this.getElement("highlighted-rect");
|
let rect = this.getElement("highlighted-rect");
|
||||||
rect.setAttribute("style", style);
|
rect.setAttribute("style", style);
|
||||||
rect.removeAttribute("hidden");
|
rect.removeAttribute("hidden");
|
||||||
|
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
@ -2366,13 +2385,15 @@ GeometryEditorHighlighter.prototype = Heritage.extend(AutoRefreshHighlighter.pro
|
|||||||
// XXX: sticky positioning is ignored for now. To be implemented next.
|
// XXX: sticky positioning is ignored for now. To be implemented next.
|
||||||
if (pos === "sticky") {
|
if (pos === "sticky") {
|
||||||
this.hide();
|
this.hide();
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hasUpdated = this._update();
|
let hasUpdated = this._update();
|
||||||
if (!hasUpdated) {
|
if (!hasUpdated) {
|
||||||
this.hide();
|
this.hide();
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
_update: function() {
|
_update: function() {
|
||||||
@ -2832,6 +2853,7 @@ RulersHighlighter.prototype = {
|
|||||||
show: function() {
|
show: function() {
|
||||||
this.markup.removeAttributeForElement(this.ID_CLASS_PREFIX + "elements",
|
this.markup.removeAttributeForElement(this.ID_CLASS_PREFIX + "elements",
|
||||||
"hidden");
|
"hidden");
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
hide: function() {
|
hide: function() {
|
||||||
@ -2874,6 +2896,7 @@ SimpleOutlineHighlighter.prototype = {
|
|||||||
installHelperSheet(getWindow(node), SIMPLE_OUTLINE_SHEET);
|
installHelperSheet(getWindow(node), SIMPLE_OUTLINE_SHEET);
|
||||||
DOMUtils.addPseudoClassLock(node, HIGHLIGHTED_PSEUDO_CLASS);
|
DOMUtils.addPseudoClassLock(node, HIGHLIGHTED_PSEUDO_CLASS);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
// interchangable on the main thread, making them easier to test.
|
// interchangable on the main thread, making them easier to test.
|
||||||
//
|
//
|
||||||
// On the worker thread, some of these modules, in particular those that rely on
|
// On the worker thread, some of these modules, in particular those that rely on
|
||||||
// the use of Components and for which the worker debugger doesn't provide an
|
// the use of Components, and for which the worker debugger doesn't provide an
|
||||||
// alternative API, will be replaced by vacuous objects. Consequently, they can
|
// alternative API, will be replaced by vacuous objects. Consequently, they can
|
||||||
// still be required, but any attempts to use them will lead to an exception.
|
// still be required, but any attempts to use them will lead to an exception.
|
||||||
|
|
||||||
@ -22,18 +22,37 @@ this.EXPORTED_SYMBOLS = ["WorkerDebuggerLoader", "worker"];
|
|||||||
// Some notes on module ids and URLs:
|
// Some notes on module ids and URLs:
|
||||||
//
|
//
|
||||||
// An id is either a relative id or an absolute id. An id is relative if and
|
// An id is either a relative id or an absolute id. An id is relative if and
|
||||||
// only if it starts with a dot. An absolute id is a normalized id if and only if
|
// only if it starts with a dot. An absolute id is a normalized id if and only
|
||||||
// it contains no redundant components. Every normalized id is a URL.
|
// if it contains no redundant components.
|
||||||
//
|
//
|
||||||
// A URL is either an absolute URL or a relative URL. A URL is absolute if and
|
// Every normalized id is a URL. A URL is either an absolute URL or a relative
|
||||||
// only if it starts with a scheme name followed by a colon and 2 slashes.
|
// URL. A URL is absolute if and only if it starts with a scheme name followed
|
||||||
|
// by a colon and 2 or 3 slashes.
|
||||||
|
|
||||||
// Resolve the given relative id to an absolute id.
|
/**
|
||||||
|
* Convert the given relative id to an absolute id.
|
||||||
|
*
|
||||||
|
* @param String id
|
||||||
|
* The relative id to be resolved.
|
||||||
|
* @param String baseId
|
||||||
|
* The absolute base id to resolve the relative id against.
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
* An absolute id
|
||||||
|
*/
|
||||||
function resolveId(id, baseId) {
|
function resolveId(id, baseId) {
|
||||||
return baseId + "/../" + id;
|
return baseId + "/../" + id;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert the given absolute id to a normalized id.
|
/**
|
||||||
|
* Convert the given absolute id to a normalized id.
|
||||||
|
*
|
||||||
|
* @param String id
|
||||||
|
* The absolute id to be normalized.
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
* A normalized id.
|
||||||
|
*/
|
||||||
function normalizeId(id) {
|
function normalizeId(id) {
|
||||||
// An id consists of an optional root and a path. A root consists of either
|
// An id consists of an optional root and a path. A root consists of either
|
||||||
// a scheme name followed by 2 or 3 slashes, or a single slash. Slashes in the
|
// a scheme name followed by 2 or 3 slashes, or a single slash. Slashes in the
|
||||||
@ -49,8 +68,7 @@ function normalizeId(id) {
|
|||||||
case "..":
|
case "..":
|
||||||
if (stack.length === 0) {
|
if (stack.length === 0) {
|
||||||
if (root !== undefined) {
|
if (root !== undefined) {
|
||||||
throw new Error("can't convert absolute id " + id + " to " +
|
throw new Error("Can't normalize absolute id '" + id + "'!");
|
||||||
"normalized id because it's going past root!");
|
|
||||||
} else {
|
} else {
|
||||||
stack.push("..");
|
stack.push("..");
|
||||||
}
|
}
|
||||||
@ -71,7 +89,15 @@ function normalizeId(id) {
|
|||||||
return (root ? root : "") + stack.join("/");
|
return (root ? root : "") + stack.join("/");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a module object with the given id.
|
/**
|
||||||
|
* Create a module object with the given normalized id.
|
||||||
|
*
|
||||||
|
* @param String
|
||||||
|
* The normalized id of the module to be created.
|
||||||
|
*
|
||||||
|
* @return Object
|
||||||
|
* A module with the given id.
|
||||||
|
*/
|
||||||
function createModule(id) {
|
function createModule(id) {
|
||||||
return Object.create(null, {
|
return Object.create(null, {
|
||||||
// CommonJS specifies the id property to be non-configurable and
|
// CommonJS specifies the id property to be non-configurable and
|
||||||
@ -94,31 +120,42 @@ function createModule(id) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a CommonJS loader with the following options:
|
/**
|
||||||
// - createSandbox:
|
* Create a CommonJS loader with the following options:
|
||||||
// A function that will be used to create sandboxes. It takes the name and
|
* - createSandbox:
|
||||||
// prototype of the sandbox to be created, and should return the newly
|
* A function that will be used to create sandboxes. It should take the name
|
||||||
// created sandbox as result. This option is mandatory.
|
* and prototype of the sandbox to be created, and return the newly created
|
||||||
// - globals:
|
* sandbox as result. This option is required.
|
||||||
// A map of built-in globals that will be exposed to every module. Defaults
|
* - globals:
|
||||||
// to the empty map.
|
* A map of names to built-in globals that will be exposed to every module.
|
||||||
// - loadInSandbox:
|
* Defaults to the empty map.
|
||||||
// A function that will be used to load scripts in sandboxes. It takes the
|
* - loadSubScript:
|
||||||
// URL from which and the sandbox in which the script is to be loaded, and
|
* A function that will be used to load scripts in sandboxes. It should take
|
||||||
// should not return a result. This option is mandatory.
|
* the URL from and the sandbox in which the script is to be loaded, and not
|
||||||
// - modules:
|
* return a result. This option is required.
|
||||||
// A map of built-in modules that will be added to the module cache.
|
* - modules:
|
||||||
// Defaults to the empty map.
|
* A map from normalized ids to built-in modules that will be added to the
|
||||||
// - paths:
|
* module cache. Defaults to the empty map.
|
||||||
// A map of paths to base URLs that will be used to resolve relative URLs to
|
* - paths:
|
||||||
// absolute URLS. Defaults to the empty map.
|
* A map of paths to base URLs that will be used to resolve relative URLs to
|
||||||
// - resolve:
|
* absolute URLS. Defaults to the empty map.
|
||||||
// A function that will be used to resolve relative ids to absolute ids. It
|
* - resolve:
|
||||||
// takes the relative id of the module to be required and the normalized id
|
* A function that will be used to resolve relative ids to absolute ids. It
|
||||||
// of the requiring module as arguments, and should return the absolute id
|
* should take the relative id of a module to be required and the absolute
|
||||||
// of the module to be required as result. Defaults to resolveId above.
|
* id of the requiring module as arguments, and return the absolute id of
|
||||||
|
* the module to be required as result. Defaults to resolveId above.
|
||||||
|
*/
|
||||||
function WorkerDebuggerLoader(options) {
|
function WorkerDebuggerLoader(options) {
|
||||||
// Resolve the given relative URL to an absolute URL.
|
/**
|
||||||
|
* Convert the given relative URL to an absolute URL, using the map of paths
|
||||||
|
* given below.
|
||||||
|
*
|
||||||
|
* @param String url
|
||||||
|
* The relative URL to be resolved.
|
||||||
|
*
|
||||||
|
* @return String
|
||||||
|
* An absolute URL.
|
||||||
|
*/
|
||||||
function resolveURL(url) {
|
function resolveURL(url) {
|
||||||
let found = false;
|
let found = false;
|
||||||
for (let [path, baseURL] of paths) {
|
for (let [path, baseURL] of paths) {
|
||||||
@ -129,19 +166,25 @@ function WorkerDebuggerLoader(options) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
throw new Error("can't resolve relative URL " + url + " to absolute " +
|
throw new Error("Can't resolve relative URL '" + url + "'!");
|
||||||
"URL!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the url has no extension, use ".js" by default.
|
// If the url has no extension, use ".js" by default.
|
||||||
return url.endsWith(".js") ? url : url + ".js";
|
return url.endsWith(".js") ? url : url + ".js";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load the given module with the given url.
|
/**
|
||||||
|
* Load the given module with the given url.
|
||||||
|
*
|
||||||
|
* @param Object module
|
||||||
|
* The module object to be loaded.
|
||||||
|
* @param String url
|
||||||
|
* The URL to load the module from.
|
||||||
|
*/
|
||||||
function loadModule(module, url) {
|
function loadModule(module, url) {
|
||||||
// CommonJS specifies 3 free variables named require, exports, and module,
|
// CommonJS specifies 3 free variables: require, exports, and module. These
|
||||||
// that must be exposed to every module, so define these as properties on
|
// must be exposed to every module, so define these as properties on the
|
||||||
// the sandbox prototype. Additional built-in globals are exposed by making
|
// sandbox prototype. Additional built-in globals are exposed by making
|
||||||
// the map of built-in globals the prototype of the sandbox prototype.
|
// the map of built-in globals the prototype of the sandbox prototype.
|
||||||
let prototype = Object.create(globals);
|
let prototype = Object.create(globals);
|
||||||
prototype.Components = {};
|
prototype.Components = {};
|
||||||
@ -151,29 +194,37 @@ function WorkerDebuggerLoader(options) {
|
|||||||
|
|
||||||
let sandbox = createSandbox(url, prototype);
|
let sandbox = createSandbox(url, prototype);
|
||||||
try {
|
try {
|
||||||
loadInSandbox(url, sandbox);
|
loadSubScript(url, sandbox);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (/^Error opening input stream/.test(String(error))) {
|
if (/^Error opening input stream/.test(String(error))) {
|
||||||
throw new Error("can't load module " + module.id + " with url " + url +
|
throw new Error("Can't load module '" + module.id + "' with url '" +
|
||||||
"!");
|
url + "'!");
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The value of exports may have been changed by the module script, so only
|
// The value of exports may have been changed by the module script, so
|
||||||
// freeze it if it is still an object.
|
// freeze it if and only if it is still an object.
|
||||||
if (typeof module.exports === "object" && module.exports !== null) {
|
if (typeof module.exports === "object" && module.exports !== null) {
|
||||||
Object.freeze(module.exports);
|
Object.freeze(module.exports);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create a require function for the given requirer. If no requirer is given,
|
/**
|
||||||
// create a require function for top-level modules instead.
|
* Create a require function for the given module. If no module is given,
|
||||||
|
* create a require function for the top-level module instead.
|
||||||
|
*
|
||||||
|
* @param Object requirer
|
||||||
|
* The module for which the require function is to be created.
|
||||||
|
*
|
||||||
|
* @return Function
|
||||||
|
* A require function for the given module.
|
||||||
|
*/
|
||||||
function createRequire(requirer) {
|
function createRequire(requirer) {
|
||||||
return function require(id) {
|
return function require(id) {
|
||||||
// Make sure an id was passed.
|
// Make sure an id was passed.
|
||||||
if (id === undefined) {
|
if (id === undefined) {
|
||||||
throw new Error("can't require module without id!");
|
throw new Error("Can't require module without id!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Built-in modules are cached by id rather than URL, so try to find the
|
// Built-in modules are cached by id rather than URL, so try to find the
|
||||||
@ -183,11 +234,11 @@ function WorkerDebuggerLoader(options) {
|
|||||||
// Failed to find the module to be required by id, so convert the id to
|
// Failed to find the module to be required by id, so convert the id to
|
||||||
// a URL and try again.
|
// a URL and try again.
|
||||||
|
|
||||||
// If the id is relative, resolve it to an absolute id.
|
// If the id is relative, convert it to an absolute id.
|
||||||
if (id.startsWith(".")) {
|
if (id.startsWith(".")) {
|
||||||
if (requirer === undefined) {
|
if (requirer === undefined) {
|
||||||
throw new Error("can't require top-level module with relative id " +
|
throw new Error("Can't require top-level module with relative id " +
|
||||||
id + "!");
|
"'" + id + "'!");
|
||||||
}
|
}
|
||||||
id = resolve(id, requirer.id);
|
id = resolve(id, requirer.id);
|
||||||
}
|
}
|
||||||
@ -207,7 +258,7 @@ function WorkerDebuggerLoader(options) {
|
|||||||
module = modules[url];
|
module = modules[url];
|
||||||
if (module === undefined) {
|
if (module === undefined) {
|
||||||
// Failed to find the module to be required in the cache, so create
|
// Failed to find the module to be required in the cache, so create
|
||||||
// a new module, load it with the given URL, and add it to the cache.
|
// a new module, load it from the given URL, and add it to the cache.
|
||||||
|
|
||||||
// Add modules to the cache early so that any recursive calls to
|
// Add modules to the cache early so that any recursive calls to
|
||||||
// require for the same module will return the partially-loaded module
|
// require for the same module will return the partially-loaded module
|
||||||
@ -219,7 +270,7 @@ function WorkerDebuggerLoader(options) {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
// If the module failed to load, remove it from the cache so that
|
// If the module failed to load, remove it from the cache so that
|
||||||
// subsequent calls to require for the same module will trigger a
|
// subsequent calls to require for the same module will trigger a
|
||||||
// new load instead of returning a partially-loaded module from
|
// new load, instead of returning a partially-loaded module from
|
||||||
// the cache.
|
// the cache.
|
||||||
delete modules[url];
|
delete modules[url];
|
||||||
throw error;
|
throw error;
|
||||||
@ -235,11 +286,11 @@ function WorkerDebuggerLoader(options) {
|
|||||||
|
|
||||||
let createSandbox = options.createSandbox;
|
let createSandbox = options.createSandbox;
|
||||||
let globals = options.globals || Object.create(null);
|
let globals = options.globals || Object.create(null);
|
||||||
let loadInSandbox = options.loadInSandbox;
|
let loadSubScript = options.loadSubScript;
|
||||||
|
|
||||||
// Create the module cache by converting each entry in the map of built-in
|
// Create the module cache, by converting each entry in the map from
|
||||||
// modules to a module object with its exports property set to a frozen
|
// normalized ids to built-in modules to a module object, with the exports
|
||||||
// version of the original entry.
|
// property of each module set to a frozen version of the original entry.
|
||||||
let modules = options.modules || {};
|
let modules = options.modules || {};
|
||||||
for (let id in modules) {
|
for (let id in modules) {
|
||||||
let module = createModule(id);
|
let module = createModule(id);
|
||||||
@ -248,9 +299,9 @@ function WorkerDebuggerLoader(options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert the map of paths to base URLs into an array for use by resolveURL.
|
// Convert the map of paths to base URLs into an array for use by resolveURL.
|
||||||
// The array is sorted from longest to shortest path so the longest path will
|
// The array is sorted from longest to shortest path to ensure that the
|
||||||
// always be the first to be found.
|
// longest path is always the first to be found.
|
||||||
let paths = options.paths || {};
|
let paths = options.paths || Object.create(null);
|
||||||
paths = Object.keys(paths)
|
paths = Object.keys(paths)
|
||||||
.sort((a, b) => b.length - a.length)
|
.sort((a, b) => b.length - a.length)
|
||||||
.map(path => [path, paths[path]]);
|
.map(path => [path, paths[path]]);
|
||||||
@ -262,20 +313,89 @@ function WorkerDebuggerLoader(options) {
|
|||||||
|
|
||||||
this.WorkerDebuggerLoader = WorkerDebuggerLoader;
|
this.WorkerDebuggerLoader = WorkerDebuggerLoader;
|
||||||
|
|
||||||
const chrome = { CC: undefined, Cc: undefined, ChromeWorker: undefined,
|
// The following APIs rely on the use of Components, and the worker debugger
|
||||||
Cm: undefined, Ci: undefined, Cu: undefined,
|
// does not provide alternative definitions for them. Consequently, they are
|
||||||
Cr: undefined, components: undefined };
|
// stubbed out both on the main thread and worker threads.
|
||||||
|
|
||||||
// The default instance of the worker debugger loader is defined differently
|
let PromiseDebugging = {
|
||||||
// depending on whether it is loaded from the main thread or a worker thread.
|
getState: function () {
|
||||||
if (typeof Components === "object") {
|
throw new Error("PromiseDebugging is not available in workers!");
|
||||||
const { Constructor: CC, classes: Cc, manager: Cm, interfaces: Ci,
|
}
|
||||||
results: Cr, utils: Cu } = Components;
|
};
|
||||||
|
|
||||||
const principal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
|
let chrome = {
|
||||||
|
CC: undefined,
|
||||||
|
Cc: undefined,
|
||||||
|
ChromeWorker: undefined,
|
||||||
|
Cm: undefined,
|
||||||
|
Ci: undefined,
|
||||||
|
Cu: undefined,
|
||||||
|
Cr: undefined,
|
||||||
|
components: undefined
|
||||||
|
};
|
||||||
|
|
||||||
// Create a sandbox with the given name and prototype.
|
let loader = {
|
||||||
const createSandbox = function (name, prototype) {
|
lazyGetter: function (object, name, lambda) {
|
||||||
|
Object.defineProperty(object, name, {
|
||||||
|
get: function () {
|
||||||
|
delete object[name];
|
||||||
|
return object[name] = lambda.apply(object);
|
||||||
|
},
|
||||||
|
configurable: true,
|
||||||
|
enumerable: true
|
||||||
|
});
|
||||||
|
},
|
||||||
|
lazyImporter: function () {
|
||||||
|
throw new Error("Can't import JSM from worker thread!");
|
||||||
|
},
|
||||||
|
lazyServiceGetter: function () {
|
||||||
|
throw new Error("Can't import XPCOM service from worker thread!");
|
||||||
|
},
|
||||||
|
lazyRequireGetter: function (obj, property, module, destructure) {
|
||||||
|
Object.defineProperty(obj, property, {
|
||||||
|
get: () => destructure ? worker.require(module)[property]
|
||||||
|
: worker.require(module || property)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following APIs are defined differently depending on whether we are on the
|
||||||
|
// main thread or a worker thread. On the main thread, we use the Components
|
||||||
|
// object to implement them. On worker threads, we use the APIs provided by
|
||||||
|
// the worker debugger.
|
||||||
|
|
||||||
|
let {
|
||||||
|
Debugger,
|
||||||
|
createSandbox,
|
||||||
|
dump,
|
||||||
|
loadSubScript,
|
||||||
|
reportError,
|
||||||
|
setImmediate,
|
||||||
|
xpcInspector
|
||||||
|
} = (function () {
|
||||||
|
if (typeof Components === "object") { // Main thread
|
||||||
|
let {
|
||||||
|
Constructor: CC,
|
||||||
|
classes: Cc,
|
||||||
|
manager: Cm,
|
||||||
|
interfaces: Ci,
|
||||||
|
results: Cr,
|
||||||
|
utils: Cu
|
||||||
|
} = Components;
|
||||||
|
|
||||||
|
let principal = CC('@mozilla.org/systemprincipal;1', 'nsIPrincipal')();
|
||||||
|
|
||||||
|
// To ensure that the this passed to addDebuggerToGlobal is a global, the
|
||||||
|
// Debugger object needs to be defined in a sandbox.
|
||||||
|
let sandbox = Cu.Sandbox(principal, {});
|
||||||
|
Cu.evalInSandbox(
|
||||||
|
"Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
|
||||||
|
"addDebuggerToGlobal(this);",
|
||||||
|
sandbox
|
||||||
|
);
|
||||||
|
let Debugger = sandbox.Debugger;
|
||||||
|
|
||||||
|
let createSandbox = function(name, prototype) {
|
||||||
return Cu.Sandbox(principal, {
|
return Cu.Sandbox(principal, {
|
||||||
invisibleToDebugger: true,
|
invisibleToDebugger: true,
|
||||||
sandboxName: name,
|
sandboxName: name,
|
||||||
@ -285,72 +405,65 @@ if (typeof Components === "object") {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadSubScript = Cc['@mozilla.org/moz/jssubscript-loader;1'].
|
let subScriptLoader = Cc['@mozilla.org/moz/jssubscript-loader;1'].
|
||||||
getService(Ci.mozIJSSubScriptLoader).loadSubScript;
|
getService(Ci.mozIJSSubScriptLoader);
|
||||||
|
|
||||||
// Load a script from the given URL in the given sandbox.
|
let loadSubScript = function (url, sandbox) {
|
||||||
const loadInSandbox = function (url, sandbox) {
|
subScriptLoader.loadSubScript(url, sandbox, "UTF-8");
|
||||||
loadSubScript(url, sandbox, "UTF-8");
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Define the Debugger object in a sandbox to ensure that the this passed to
|
let reportError = Cu.reportError;
|
||||||
// addDebuggerToGlobal is a global.
|
|
||||||
let sandbox = Cu.Sandbox(principal, {});
|
|
||||||
Cu.evalInSandbox(
|
|
||||||
"Components.utils.import('resource://gre/modules/jsdebugger.jsm');" +
|
|
||||||
"addDebuggerToGlobal(this);",
|
|
||||||
sandbox
|
|
||||||
);
|
|
||||||
const Debugger = sandbox.Debugger;
|
|
||||||
|
|
||||||
const Timer = Cu.import("resource://gre/modules/Timer.jsm", {});
|
let Timer = Cu.import("resource://gre/modules/Timer.jsm", {});
|
||||||
const xpcInspector = Cc["@mozilla.org/jsinspector;1"].
|
|
||||||
|
let setImmediate = function (callback) {
|
||||||
|
Timer.setTimeout(callback, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
let xpcInspector = Cc["@mozilla.org/jsinspector;1"].
|
||||||
getService(Ci.nsIJSInspector);
|
getService(Ci.nsIJSInspector);
|
||||||
|
|
||||||
let worker = this.worker = new WorkerDebuggerLoader({
|
return {
|
||||||
|
Debugger,
|
||||||
|
createSandbox,
|
||||||
|
dump,
|
||||||
|
loadSubScript,
|
||||||
|
reportError,
|
||||||
|
setImmediate,
|
||||||
|
xpcInspector
|
||||||
|
};
|
||||||
|
} else { // Worker thread
|
||||||
|
throw new Error("Not yet implemented!");
|
||||||
|
}
|
||||||
|
}).call(this);
|
||||||
|
|
||||||
|
// Create the default instance of the worker loader, using the APIs we defined
|
||||||
|
// above.
|
||||||
|
|
||||||
|
this.worker = new WorkerDebuggerLoader({
|
||||||
createSandbox: createSandbox,
|
createSandbox: createSandbox,
|
||||||
globals: {
|
globals: {
|
||||||
"isWorker": true,
|
"isWorker": true,
|
||||||
"reportError": Cu.reportError,
|
"dump": dump,
|
||||||
"loader": {
|
"loader": loader,
|
||||||
lazyGetter: function (aObject, aName, aLambda) {
|
"reportError": reportError,
|
||||||
Object.defineProperty(aObject, aName, {
|
"setImmediate": setImmediate
|
||||||
get: function () {
|
|
||||||
delete aObject[aName];
|
|
||||||
return aObject[aName] = aLambda.apply(aObject);
|
|
||||||
},
|
},
|
||||||
configurable: true,
|
loadSubScript: loadSubScript,
|
||||||
enumerable: true
|
|
||||||
});
|
|
||||||
},
|
|
||||||
lazyImporter: function () { throw new Error("Can't import JSM from worker debugger server") },
|
|
||||||
lazyServiceGetter: function () { throw new Error("Can't import XPCOM from worker debugger server") },
|
|
||||||
lazyRequireGetter: function (obj, property, module, destructure) {
|
|
||||||
Object.defineProperty(obj, property, {
|
|
||||||
get: () => destructure
|
|
||||||
? worker.require(module)[property]
|
|
||||||
: worker.require(module || property)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
loadInSandbox: loadInSandbox,
|
|
||||||
modules: {
|
modules: {
|
||||||
"Services": {},
|
|
||||||
"chrome": chrome,
|
|
||||||
"promise": Promise,
|
|
||||||
"Debugger": Debugger,
|
"Debugger": Debugger,
|
||||||
"xpcInspector": xpcInspector,
|
"PromiseDebugging": PromiseDebugging,
|
||||||
"Timer": Object.create(Timer),
|
"Services": Object.create(null),
|
||||||
"PromiseDebugging": PromiseDebugging
|
"chrome": chrome,
|
||||||
|
"xpcInspector": xpcInspector
|
||||||
},
|
},
|
||||||
paths: {
|
paths: {
|
||||||
"": "resource://gre/modules/commonjs/",
|
"": "resource://gre/modules/commonjs/",
|
||||||
"devtools": "resource:///modules/devtools",
|
"devtools": "resource:///modules/devtools",
|
||||||
"devtools/server": "resource://gre/modules/devtools/server",
|
"devtools/server": "resource://gre/modules/devtools/server",
|
||||||
"devtools/toolkit": "resource://gre/modules/devtools",
|
"devtools/toolkit": "resource://gre/modules/devtools",
|
||||||
|
"promise": "resource://gre/modules/Promise-backend.js",
|
||||||
"source-map": "resource://gre/modules/devtools/source-map",
|
"source-map": "resource://gre/modules/devtools/source-map",
|
||||||
"xpcshell-test": "resource://test",
|
"xpcshell-test": "resource://test"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
@ -85,7 +85,7 @@ ruleView.contextmenu.selectAll.accessKey=A
|
|||||||
ruleView.contextmenu.copy=Copy
|
ruleView.contextmenu.copy=Copy
|
||||||
|
|
||||||
# LOCALIZATION NOTE (ruleView.contextmenu.copy.accessKey): Access key for
|
# LOCALIZATION NOTE (ruleView.contextmenu.copy.accessKey): Access key for
|
||||||
# the rule view context menu "Select all" entry.
|
# the rule view context menu "Copy" entry.
|
||||||
ruleView.contextmenu.copy.accessKey=C
|
ruleView.contextmenu.copy.accessKey=C
|
||||||
|
|
||||||
# LOCALIZATION NOTE (ruleView.contextmenu.copyColor): Text displayed in the rule
|
# LOCALIZATION NOTE (ruleView.contextmenu.copyColor): Text displayed in the rule
|
||||||
@ -96,6 +96,20 @@ ruleView.contextmenu.copyColor=Copy Color
|
|||||||
# the rule and computed view context menu "Copy Color" entry.
|
# the rule and computed view context menu "Copy Color" entry.
|
||||||
ruleView.contextmenu.copyColor.accessKey=L
|
ruleView.contextmenu.copyColor.accessKey=L
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (styleinspector.contextmenu.copyImageDataUrl): In rule and computed view :
|
||||||
|
# text displayed in the context menu for an image URL.
|
||||||
|
# Clicking it copies the image as Data-URL to the clipboard of the user.
|
||||||
|
styleinspector.contextmenu.copyImageDataUrl=Copy Image Data-URL
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (styleinspector.contextmenu.copyDataUri.accessKey): Access key for
|
||||||
|
# the rule and computed view context menu "Copy Image Data-URL" entry.
|
||||||
|
styleinspector.contextmenu.copyImageDataUrl.accessKey=U
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (styleinspector.copyDataUriError): Text set in the clipboard
|
||||||
|
# if an error occurs when using the copyImageDataUrl context menu action
|
||||||
|
# (invalid image link, timeout, etc...)
|
||||||
|
styleinspector.copyImageDataUrlError=Failed to copy image Data-URL
|
||||||
|
|
||||||
# LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources): Text displayed in the rule view
|
# LOCALIZATION NOTE (ruleView.contextmenu.showOrigSources): Text displayed in the rule view
|
||||||
# context menu.
|
# context menu.
|
||||||
ruleView.contextmenu.showOrigSources=Show original sources
|
ruleView.contextmenu.showOrigSources=Show original sources
|
||||||
@ -134,5 +148,5 @@ computedView.contextmenu.selectAll.accessKey=A
|
|||||||
computedView.contextmenu.copy=Copy
|
computedView.contextmenu.copy=Copy
|
||||||
|
|
||||||
# LOCALIZATION NOTE (computedView.contextmenu.copy.accessKey): Access key for
|
# LOCALIZATION NOTE (computedView.contextmenu.copy.accessKey): Access key for
|
||||||
# the computed view context menu "Select all" entry.
|
# the computed view context menu "Copy" entry.
|
||||||
computedView.contextmenu.copy.accessKey=C
|
computedView.contextmenu.copy.accessKey=C
|
||||||
|
@ -22,9 +22,17 @@
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// Globals
|
//// Globals
|
||||||
|
|
||||||
|
// Do not load the FinalizationWitnessService is we are being required as a
|
||||||
|
// CommonJS module, because the Components object is not available in workers.
|
||||||
|
if (!isWorker) {
|
||||||
Cu.import("resource://gre/modules/Services.jsm");
|
Cu.import("resource://gre/modules/Services.jsm");
|
||||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(this, "FinalizationWitnessService",
|
||||||
|
"@mozilla.org/toolkit/finalizationwitness;1",
|
||||||
|
"nsIFinalizationWitnessService");
|
||||||
|
}
|
||||||
|
|
||||||
const STATUS_PENDING = 0;
|
const STATUS_PENDING = 0;
|
||||||
const STATUS_RESOLVED = 1;
|
const STATUS_RESOLVED = 1;
|
||||||
const STATUS_REJECTED = 2;
|
const STATUS_REJECTED = 2;
|
||||||
@ -38,7 +46,7 @@ const salt = Math.floor(Math.random() * 100);
|
|||||||
const N_INTERNALS = "{private:internals:" + salt + "}";
|
const N_INTERNALS = "{private:internals:" + salt + "}";
|
||||||
|
|
||||||
// We use DOM Promise for scheduling the walker loop.
|
// We use DOM Promise for scheduling the walker loop.
|
||||||
const DOMPromise = Promise;
|
const DOMPromise = isWorker ? null : Promise;
|
||||||
|
|
||||||
/////// Warn-upon-finalization mechanism
|
/////// Warn-upon-finalization mechanism
|
||||||
//
|
//
|
||||||
@ -71,10 +79,6 @@ const DOMPromise = Promise;
|
|||||||
// In this snippet, the error is reported both by p1 and by p2.
|
// In this snippet, the error is reported both by p1 and by p2.
|
||||||
//
|
//
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetter(this, "FinalizationWitnessService",
|
|
||||||
"@mozilla.org/toolkit/finalizationwitness;1",
|
|
||||||
"nsIFinalizationWitnessService");
|
|
||||||
|
|
||||||
let PendingErrors = {
|
let PendingErrors = {
|
||||||
// An internal counter, used to generate unique id.
|
// An internal counter, used to generate unique id.
|
||||||
_counter: 0,
|
_counter: 0,
|
||||||
@ -247,7 +251,13 @@ let PendingErrors = {
|
|||||||
this._observers.clear();
|
this._observers.clear();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Do not initialize the warn-on-finalization mechanism if we are being required
|
||||||
|
// as a CommonJS module by the worker loader, because the Components object (and
|
||||||
|
// therefore the FinalizationWitnessService) is not available.
|
||||||
|
if (!isWorker) {
|
||||||
PendingErrors.init();
|
PendingErrors.init();
|
||||||
|
}
|
||||||
|
|
||||||
// Default mechanism for displaying errors
|
// Default mechanism for displaying errors
|
||||||
PendingErrors.addObserver(function(details) {
|
PendingErrors.addObserver(function(details) {
|
||||||
@ -618,6 +628,12 @@ Object.freeze(Promise.Debugging);
|
|||||||
|
|
||||||
Object.freeze(Promise);
|
Object.freeze(Promise);
|
||||||
|
|
||||||
|
// Make sure to export the Promise object if we are being required as a CommonJS
|
||||||
|
// module by the worker loader.
|
||||||
|
if (isWorker) {
|
||||||
|
module.exports = Promise;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
//// PromiseWalker
|
//// PromiseWalker
|
||||||
|
|
||||||
@ -669,7 +685,7 @@ this.PromiseWalker = {
|
|||||||
aPromise[N_INTERNALS].value = aValue;
|
aPromise[N_INTERNALS].value = aValue;
|
||||||
if (aPromise[N_INTERNALS].handlers.length > 0) {
|
if (aPromise[N_INTERNALS].handlers.length > 0) {
|
||||||
this.schedulePromise(aPromise);
|
this.schedulePromise(aPromise);
|
||||||
} else if (aStatus == STATUS_REJECTED) {
|
} else if (!isWorker && aStatus == STATUS_REJECTED) {
|
||||||
// This is a rejection and the promise is the last in the chain.
|
// This is a rejection and the promise is the last in the chain.
|
||||||
// For the time being we therefore have an uncaught error.
|
// For the time being we therefore have an uncaught error.
|
||||||
let id = PendingErrors.register(aValue);
|
let id = PendingErrors.register(aValue);
|
||||||
@ -685,7 +701,11 @@ this.PromiseWalker = {
|
|||||||
scheduleWalkerLoop: function()
|
scheduleWalkerLoop: function()
|
||||||
{
|
{
|
||||||
this.walkerLoopScheduled = true;
|
this.walkerLoopScheduled = true;
|
||||||
|
if (isWorker) {
|
||||||
|
setImmediate(this.walkerLoop);
|
||||||
|
} else {
|
||||||
DOMPromise.resolve().then(() => this.walkerLoop());
|
DOMPromise.resolve().then(() => this.walkerLoop());
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,6 +96,17 @@ this.Ci = Components.interfaces;
|
|||||||
this.Cu = Components.utils;
|
this.Cu = Components.utils;
|
||||||
this.Cr = Components.results;
|
this.Cr = Components.results;
|
||||||
|
|
||||||
|
// Promise-backend.js can either be loaded as a subscript by this file, or
|
||||||
|
// required as a CommonJS module by the worker loader. Because certain APIS (in
|
||||||
|
// particular, Components) are not available in workers, Promise-backend.js
|
||||||
|
// behaves slightly different in the latter case.
|
||||||
|
//
|
||||||
|
// To distinguish between these two cases, the worker loader defines a global
|
||||||
|
// variable isWorker, and sets it to true. When loading Promise-backend.js as
|
||||||
|
// a subscript, we need to make sure this variable is defined as well, and set
|
||||||
|
// it to false.
|
||||||
|
this.isWorker = false;
|
||||||
|
|
||||||
this.Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
this.Cc["@mozilla.org/moz/jssubscript-loader;1"]
|
||||||
.getService(this.Ci.mozIJSSubScriptLoader)
|
.getService(this.Ci.mozIJSSubScriptLoader)
|
||||||
.loadSubScript("resource://gre/modules/Promise-backend.js", this);
|
.loadSubScript("resource://gre/modules/Promise-backend.js", this);
|
||||||
|
Loading…
Reference in New Issue
Block a user