зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1239118 - Send prefs to Remote Newtab page using WebChannel r=ursula
MozReview-Commit-ID: CQQQmgrXSDt --HG-- extra : rebase_source : fafebd3deaaff3a6afb1b211c58bd5fed023efc5
This commit is contained in:
Родитель
9f92cc4921
Коммит
fb47188c38
|
@ -0,0 +1,95 @@
|
|||
/*global
|
||||
NewTabWebChannel,
|
||||
NewTabPrefsProvider,
|
||||
Preferences,
|
||||
XPCOMUtils
|
||||
*/
|
||||
|
||||
/* exported NewTabMessages */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
"resource:///modules/NewTabWebChannel.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["NewTabMessages"];
|
||||
|
||||
const PREF_ENABLED = "browser.newtabpage.remote";
|
||||
|
||||
// Action names are from the content's perspective. in from chrome == out from content
|
||||
// Maybe replace the ACTION objects by a bi-directional Map a bit later?
|
||||
const ACTIONS = {
|
||||
prefs: {
|
||||
inPrefs: "REQUEST_PREFS",
|
||||
outPrefs: "RECEIVE_PREFS",
|
||||
action_types: new Set(["REQUEST_PREFS", "RECEIVE_PREFS"]),
|
||||
}
|
||||
};
|
||||
|
||||
let NewTabMessages = {
|
||||
|
||||
_prefs: {},
|
||||
|
||||
/** NEWTAB EVENT HANDLERS **/
|
||||
|
||||
/*
|
||||
* Return to the originator all newtabpage prefs. A point-to-point request.
|
||||
*/
|
||||
handlePrefRequest(actionName, {target}) {
|
||||
if (ACTIONS.prefs.action_types.has(actionName)) {
|
||||
let results = NewTabPrefsProvider.prefs.newtabPagePrefs;
|
||||
NewTabWebChannel.send(ACTIONS.prefs.outPrefs, results, target);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Broadcast preference changes to all open newtab pages
|
||||
*/
|
||||
handlePrefChange(actionName, value) {
|
||||
let prefChange = {};
|
||||
prefChange[actionName] = value;
|
||||
NewTabWebChannel.broadcast(ACTIONS.prefs.outPrefs, prefChange);
|
||||
},
|
||||
|
||||
_handleEnabledChange(prefName, value) {
|
||||
if (prefName === PREF_ENABLED) {
|
||||
if (this._prefs.enabled && !value) {
|
||||
this.uninit();
|
||||
} else if (!this._prefs.enabled && value) {
|
||||
this.init();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
init() {
|
||||
this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
|
||||
|
||||
if (this._prefs.enabled) {
|
||||
NewTabWebChannel.on(ACTIONS.prefs.inPrefs, this.handlePrefRequest.bind(this));
|
||||
NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handleEnabledChange.bind(this));
|
||||
|
||||
for (let pref of NewTabPrefsProvider.newtabPagePrefSet) {
|
||||
NewTabPrefsProvider.prefs.on(pref, this.handlePrefChange.bind(this));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
uninit() {
|
||||
this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
|
||||
|
||||
if (this._prefs.enabled) {
|
||||
NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handleEnabledChange);
|
||||
|
||||
NewTabWebChannel.off(ACTIONS.prefs.inPrefs, this.handlePrefRequest);
|
||||
for (let pref of NewTabPrefsProvider.newtabPagePrefSet) {
|
||||
NewTabPrefsProvider.prefs.off(pref, this.handlePrefChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
|
@ -21,11 +21,24 @@ const gPrefsMap = new Map([
|
|||
["browser.newtabpage.remote.mode", "str"],
|
||||
["browser.newtabpage.enabled", "bool"],
|
||||
["browser.newtabpage.enhanced", "bool"],
|
||||
["browser.newtabpage.introShown", "bool"],
|
||||
["browser.newtabpage.updateIntroShown", "bool"],
|
||||
["browser.newtabpage.pinned", "str"],
|
||||
["browser.newtabpage.blocked", "str"],
|
||||
["intl.locale.matchOS", "bool"],
|
||||
["general.useragent.locale", "localized"],
|
||||
]);
|
||||
|
||||
// prefs that are important for the newtab page
|
||||
const gNewtabPagePrefs = new Set([
|
||||
"browser.newtabpage.enabled",
|
||||
"browser.newtabpage.enhanced",
|
||||
"browser.newtabpage.pinned",
|
||||
"browser.newtabpage.blocked",
|
||||
"browser.newtabpage.introShown",
|
||||
"browser.newtabpage.updateIntroShown"
|
||||
]);
|
||||
|
||||
let PrefsProvider = function PrefsProvider() {
|
||||
EventEmitter.decorate(this);
|
||||
};
|
||||
|
@ -59,6 +72,17 @@ PrefsProvider.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Return the preferences that are important to the newtab page
|
||||
*/
|
||||
get newtabPagePrefs() {
|
||||
let results = {};
|
||||
for (let pref of gNewtabPagePrefs) {
|
||||
results[pref] = Preferences.get(pref, null);
|
||||
}
|
||||
return results;
|
||||
},
|
||||
|
||||
get prefsMap() {
|
||||
return gPrefsMap;
|
||||
},
|
||||
|
@ -83,4 +107,5 @@ const gPrefs = new PrefsProvider();
|
|||
|
||||
let NewTabPrefsProvider = {
|
||||
prefs: gPrefs,
|
||||
newtabPagePrefSet: gNewtabPagePrefs,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
/* global
|
||||
NewTabPrefsProvider,
|
||||
Services,
|
||||
EventEmitter,
|
||||
Preferences,
|
||||
XPCOMUtils,
|
||||
WebChannel,
|
||||
NewTabRemoteResources
|
||||
*/
|
||||
/* exported NewTabWebChannel */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["NewTabWebChannel"];
|
||||
|
||||
const {utils: Cu} = Components;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabRemoteResources",
|
||||
"resource:///modules/NewTabRemoteResources.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
|
||||
"resource://gre/modules/WebChannel.jsm");
|
||||
XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
|
||||
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
|
||||
return EventEmitter;
|
||||
});
|
||||
|
||||
const CHAN_ID = "newtab";
|
||||
const PREF_ENABLED = "browser.newtabpage.remote";
|
||||
const PREF_MODE = "browser.newtabpage.remote.mode";
|
||||
|
||||
/**
|
||||
* NewTabWebChannel is the conduit for all communication with unprivileged newtab instances.
|
||||
*
|
||||
* It allows for the ability to broadcast to all newtab browsers.
|
||||
* If the browser.newtab.remote pref is false, the object will be in an uninitialized state.
|
||||
*
|
||||
* Mode choices:
|
||||
* 'production': pages from our production CDN
|
||||
* 'staging': pages from our staging CDN
|
||||
* 'test': intended for tests
|
||||
* 'test2': intended for tests
|
||||
* 'dev': intended for development
|
||||
*
|
||||
* An unknown mode will result in 'production' mode, which is the default
|
||||
*
|
||||
* Incoming messages are expected to be JSON-serialized and in the format:
|
||||
*
|
||||
* {
|
||||
* type: "REQUEST_SCREENSHOT",
|
||||
* data: {
|
||||
* url: "https://example.com"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* Or:
|
||||
*
|
||||
* {
|
||||
* type: "REQUEST_SCREENSHOT",
|
||||
* }
|
||||
*
|
||||
* Outgoing messages are expected to be objects serializable by structured cloning, in a similar format:
|
||||
* {
|
||||
* type: "RECEIVE_SCREENSHOT",
|
||||
* data: {
|
||||
* "url": "https://example.com",
|
||||
* "image": "dataURi:....."
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
let NewTabWebChannelImpl = function NewTabWebChannelImpl() {
|
||||
EventEmitter.decorate(this);
|
||||
this._handlePrefChange = this._handlePrefChange.bind(this);
|
||||
this._incomingMessage = this._incomingMessage.bind(this);
|
||||
};
|
||||
|
||||
NewTabWebChannelImpl.prototype = {
|
||||
_prefs: {},
|
||||
_channel: null,
|
||||
|
||||
// a WeakMap containing browsers as keys and a weak ref to their principal
|
||||
// as value
|
||||
_principals: null,
|
||||
|
||||
// a Set containing weak refs to browsers
|
||||
_browsers: null,
|
||||
|
||||
/*
|
||||
* Returns current channel's ID
|
||||
*/
|
||||
get chanId() {
|
||||
return CHAN_ID;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns the number of browsers currently tracking
|
||||
*/
|
||||
get numBrowsers() {
|
||||
return this._getBrowserRefs().length;
|
||||
},
|
||||
|
||||
/*
|
||||
* Returns current channel's origin
|
||||
*/
|
||||
get origin() {
|
||||
if (!(this._prefs.mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
|
||||
this._prefs.mode = "production";
|
||||
}
|
||||
return NewTabRemoteResources.MODE_CHANNEL_MAP[this._prefs.mode].origin;
|
||||
},
|
||||
|
||||
/*
|
||||
* Unloads all browsers and principals
|
||||
*/
|
||||
_unloadAll() {
|
||||
if (this._principals != null) {
|
||||
this._principals = new WeakMap();
|
||||
}
|
||||
this._browsers = new Set();
|
||||
this.emit("targetUnloadAll");
|
||||
},
|
||||
|
||||
/*
|
||||
* Checks if a browser is known
|
||||
*
|
||||
* This will cause an iteration through all known browsers.
|
||||
* That's ok, we don't expect a lot of browsers
|
||||
*/
|
||||
_isBrowserKnown(browser) {
|
||||
for (let bRef of this._getBrowserRefs()) {
|
||||
let b = bRef.get();
|
||||
if (b && b.permanentKey === browser.permanentKey) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/*
|
||||
* Obtains all known browser refs
|
||||
*/
|
||||
_getBrowserRefs() {
|
||||
let refs = [];
|
||||
for (let bRef of this._browsers) {
|
||||
/*
|
||||
* even though we hold a weak ref to browser, it seems that browser
|
||||
* objects aren't gc'd immediately after a tab closes. They stick around
|
||||
* in memory, but thankfully they don't have a documentURI in that case
|
||||
*/
|
||||
let browser = bRef.get();
|
||||
if (browser && browser.documentURI) {
|
||||
refs.push(bRef);
|
||||
} else {
|
||||
// need to clean up principals because the browser object is not gc'ed
|
||||
// immediately
|
||||
this._principals.delete(browser);
|
||||
this._browsers.delete(bRef);
|
||||
this.emit("targetUnload");
|
||||
}
|
||||
}
|
||||
return refs;
|
||||
},
|
||||
|
||||
/*
|
||||
* Receives a message from content.
|
||||
*
|
||||
* Keeps track of browsers for broadcast, relays messages to listeners.
|
||||
*/
|
||||
_incomingMessage(id, message, target) {
|
||||
if (this.chanId !== id) {
|
||||
Cu.reportError(new Error("NewTabWebChannel unexpected message destination"));
|
||||
}
|
||||
|
||||
/*
|
||||
* need to differentiate by browser, because event targets are created each
|
||||
* time a message is sent.
|
||||
*/
|
||||
if (!this._isBrowserKnown(target.browser)) {
|
||||
this._browsers.add(Cu.getWeakReference(target.browser));
|
||||
this._principals.set(target.browser, Cu.getWeakReference(target.principal));
|
||||
this.emit("targetAdd");
|
||||
}
|
||||
|
||||
try {
|
||||
let msg = JSON.parse(message);
|
||||
this.emit(msg.type, {data: msg.data, target: target});
|
||||
} catch (err) {
|
||||
Cu.reportError(err);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sends a message to all known browsers
|
||||
*/
|
||||
broadcast(actionType, message) {
|
||||
for (let bRef of this._getBrowserRefs()) {
|
||||
let browser = bRef.get();
|
||||
try {
|
||||
let principal = this._principals.get(browser).get();
|
||||
if (principal && browser && browser.documentURI) {
|
||||
this._channel.send({type: actionType, data: message}, {browser, principal});
|
||||
}
|
||||
} catch (e) {
|
||||
Cu.reportError(new Error("NewTabWebChannel WeakRef is dead"));
|
||||
this._principals.delete(browser);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sends a message to a specific target
|
||||
*/
|
||||
send(actionType, message, target) {
|
||||
try {
|
||||
this._channel.send({type: actionType, data: message}, target);
|
||||
} catch (e) {
|
||||
// Web Channel might be dead
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Pref change observer callback
|
||||
*/
|
||||
_handlePrefChange(prefName, newState, forceState) { // eslint-disable-line no-unused-vars
|
||||
switch (prefName) {
|
||||
case PREF_ENABLED:
|
||||
if (!this._prefs.enabled && newState) {
|
||||
// changing state from disabled to enabled
|
||||
this.setupState();
|
||||
} else if (this._prefs.enabled && !newState) {
|
||||
// changing state from enabled to disabled
|
||||
this.tearDownState();
|
||||
}
|
||||
break;
|
||||
case PREF_MODE:
|
||||
if (this._prefs.mode !== newState) {
|
||||
// changing modes
|
||||
this.tearDownState();
|
||||
this.setupState();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Sets up the internal state
|
||||
*/
|
||||
setupState() {
|
||||
this._prefs.enabled = Preferences.get(PREF_ENABLED, false);
|
||||
|
||||
let mode = Preferences.get(PREF_MODE, "production");
|
||||
if (!(mode in NewTabRemoteResources.MODE_CHANNEL_MAP)) {
|
||||
mode = "production";
|
||||
}
|
||||
this._prefs.mode = mode;
|
||||
this._principals = new WeakMap();
|
||||
this._browsers = new Set();
|
||||
|
||||
if (this._prefs.enabled) {
|
||||
this._channel = new WebChannel(this.chanId, Services.io.newURI(this.origin, null, null));
|
||||
this._channel.listen(this._incomingMessage);
|
||||
}
|
||||
},
|
||||
|
||||
tearDownState() {
|
||||
if (this._channel) {
|
||||
this._channel.stopListening();
|
||||
}
|
||||
this._prefs = {};
|
||||
this._unloadAll();
|
||||
this._channel = null;
|
||||
this._principals = null;
|
||||
this._browsers = null;
|
||||
},
|
||||
|
||||
init() {
|
||||
this.setupState();
|
||||
NewTabPrefsProvider.prefs.on(PREF_ENABLED, this._handlePrefChange);
|
||||
NewTabPrefsProvider.prefs.on(PREF_MODE, this._handlePrefChange);
|
||||
},
|
||||
|
||||
uninit() {
|
||||
this.tearDownState();
|
||||
NewTabPrefsProvider.prefs.off(PREF_ENABLED, this._handlePrefChange);
|
||||
NewTabPrefsProvider.prefs.off(PREF_MODE, this._handlePrefChange);
|
||||
}
|
||||
};
|
||||
|
||||
let NewTabWebChannel = new NewTabWebChannelImpl();
|
|
@ -11,9 +11,11 @@ XPCSHELL_TESTS_MANIFESTS += [
|
|||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'NewTabMessages.jsm',
|
||||
'NewTabPrefsProvider.jsm',
|
||||
'NewTabRemoteResources.jsm',
|
||||
'NewTabURL.jsm',
|
||||
'NewTabWebChannel.jsm',
|
||||
'PlacesProvider.jsm'
|
||||
]
|
||||
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
dummy_page.html
|
||||
newtabwebchannel_basic.html
|
||||
newtabmessages_prefs.html
|
||||
|
||||
[browser_remotenewtab_pageloads.js]
|
||||
[browser_newtab_overrides.js]
|
||||
[browser_newtabmessages.js]
|
||||
[browser_newtabwebchannel.js]
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/* globals Cu, XPCOMUtils, Preferences, is, registerCleanupFunction, NewTabWebChannel */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
"resource:///modules/NewTabWebChannel.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabMessages",
|
||||
"resource:///modules/NewTabMessages.jsm");
|
||||
|
||||
function setup() {
|
||||
Preferences.set("browser.newtabpage.enhanced", true);
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
NewTabMessages.init();
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
NewTabMessages.uninit();
|
||||
NewTabWebChannel.tearDownState();
|
||||
Preferences.set("browser.newtabpage.remote", false);
|
||||
Preferences.set("browser.newtabpage.remote.mode", "production");
|
||||
}
|
||||
registerCleanupFunction(cleanup);
|
||||
|
||||
/*
|
||||
* Sanity tests for pref messages
|
||||
*/
|
||||
add_task(function* prefMessages_request() {
|
||||
setup();
|
||||
let testURL = "https://example.com/browser/browser/components/newtab/tests/browser/newtabmessages_prefs.html";
|
||||
|
||||
let tabOptions = {
|
||||
gBrowser,
|
||||
url: testURL
|
||||
};
|
||||
|
||||
let prefResponseAck = new Promise(resolve => {
|
||||
NewTabWebChannel.once("responseAck", () => {
|
||||
ok(true, "a request response has been received");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
yield BrowserTestUtils.withNewTab(tabOptions, function*() {
|
||||
yield prefResponseAck;
|
||||
let prefChangeAck = new Promise(resolve => {
|
||||
NewTabWebChannel.once("responseAck", () => {
|
||||
ok(true, "a change response has been received");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
Preferences.set("browser.newtabpage.enhanced", false);
|
||||
yield prefChangeAck;
|
||||
});
|
||||
cleanup();
|
||||
});
|
|
@ -0,0 +1,232 @@
|
|||
/* globals XPCOMUtils, Cu, Preferences, NewTabWebChannel, is, registerCleanupFunction */
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Preferences.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
"resource:///modules/NewTabWebChannel.jsm");
|
||||
|
||||
const TEST_URL = "https://example.com/browser/browser/components/newtab/tests/browser/newtabwebchannel_basic.html";
|
||||
const TEST_URL_2 = "http://mochi.test:8888/browser/browser/components/newtab/tests/browser/newtabwebchannel_basic.html";
|
||||
|
||||
function cleanup() {
|
||||
NewTabWebChannel.tearDownState();
|
||||
Preferences.set("browser.newtabpage.remote", false);
|
||||
Preferences.set("browser.newtabpage.remote.mode", "production");
|
||||
}
|
||||
registerCleanupFunction(cleanup);
|
||||
|
||||
/*
|
||||
* Tests flow of messages from newtab to chrome and chrome to newtab
|
||||
*/
|
||||
add_task(function* open_webchannel_basic() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
|
||||
let tabOptions = {
|
||||
gBrowser,
|
||||
url: TEST_URL
|
||||
};
|
||||
|
||||
let messagePromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("foo", function(name, msg) {
|
||||
is(name, "foo", "Correct message type sent: foo");
|
||||
is(msg.data, "bar", "Correct data sent: bar");
|
||||
resolve(msg.target);
|
||||
});
|
||||
});
|
||||
|
||||
let replyPromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("reply", function(name, msg) {
|
||||
is(name, "reply", "Correct message type sent: reply");
|
||||
is(msg.data, "quuz", "Correct data sent: quuz");
|
||||
resolve(msg.target);
|
||||
});
|
||||
});
|
||||
|
||||
let unloadPromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("targetUnload", function(name) {
|
||||
is(name, "targetUnload", "Correct message type sent: targetUnload");
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
yield BrowserTestUtils.withNewTab(tabOptions, function*(browser) {
|
||||
let target = yield messagePromise;
|
||||
is(NewTabWebChannel.numBrowsers, 1, "One target expected");
|
||||
is(target.browser, browser, "Same browser");
|
||||
NewTabWebChannel.send("respond", null, target);
|
||||
yield replyPromise;
|
||||
});
|
||||
|
||||
Cu.forceGC();
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
yield unloadPromise;
|
||||
cleanup();
|
||||
});
|
||||
|
||||
/*
|
||||
* Tests message broadcast reaches all open newtab pages
|
||||
*/
|
||||
add_task(function* webchannel_broadcast() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
|
||||
let countingMessagePromise = new Promise(resolve => {
|
||||
let count = 0;
|
||||
NewTabWebChannel.on("foo", function test_message(name, msg) {
|
||||
count += 1;
|
||||
if (count === 2) {
|
||||
NewTabWebChannel.off("foo", test_message);
|
||||
resolve(msg.target);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
let countingReplyPromise = new Promise(resolve => {
|
||||
let count = 0;
|
||||
NewTabWebChannel.on("reply", function test_message(name, msg) {
|
||||
count += 1;
|
||||
if (count === 2) {
|
||||
NewTabWebChannel.off("reply", test_message);
|
||||
resolve(msg.target);
|
||||
}
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
let countingUnloadPromise = new Promise(resolve => {
|
||||
let count = 0;
|
||||
NewTabWebChannel.on("targetUnload", function test_message() {
|
||||
count += 1;
|
||||
if (count === 2) {
|
||||
NewTabWebChannel.off("targetUnload", test_message);
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
let tabs = [];
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
tabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL));
|
||||
tabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL));
|
||||
|
||||
yield countingMessagePromise;
|
||||
is(NewTabWebChannel.numBrowsers, 2, "Two targets expected");
|
||||
|
||||
NewTabWebChannel.broadcast("respond", null);
|
||||
yield countingReplyPromise;
|
||||
|
||||
for (let tab of tabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
Cu.forceGC();
|
||||
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
yield countingUnloadPromise;
|
||||
cleanup();
|
||||
});
|
||||
|
||||
/*
|
||||
* Tests switching modes
|
||||
*/
|
||||
add_task(function* webchannel_switch() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
|
||||
function newMessagePromise() {
|
||||
return new Promise(resolve => {
|
||||
NewTabWebChannel.once("foo", function(name, msg) {
|
||||
resolve(msg.target);
|
||||
}.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
let replyCount = 0;
|
||||
let replyPromise = new Promise(resolve => {
|
||||
NewTabWebChannel.on("reply", function() {
|
||||
replyCount += 1;
|
||||
resolve();
|
||||
}.bind(this));
|
||||
});
|
||||
|
||||
let unloadPromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("targetUnload", function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let unloadAllPromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("targetUnloadAll", function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
let tabs = [];
|
||||
let messagePromise;
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
|
||||
messagePromise = newMessagePromise();
|
||||
tabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL));
|
||||
yield messagePromise;
|
||||
is(NewTabWebChannel.numBrowsers, 1, "Correct number of targets");
|
||||
|
||||
messagePromise = newMessagePromise();
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test2");
|
||||
tabs.push(yield BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URL_2));
|
||||
yield unloadAllPromise;
|
||||
yield messagePromise;
|
||||
is(NewTabWebChannel.numBrowsers, 1, "Correct number of targets");
|
||||
|
||||
NewTabWebChannel.broadcast("respond", null);
|
||||
yield replyPromise;
|
||||
is(replyCount, 1, "only current channel is listened to for replies");
|
||||
|
||||
for (let tab of tabs) {
|
||||
yield BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
|
||||
Cu.forceGC();
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
yield unloadPromise;
|
||||
cleanup();
|
||||
});
|
||||
|
||||
add_task(function* open_webchannel_reload() {
|
||||
Preferences.set("browser.newtabpage.remote.mode", "test");
|
||||
Preferences.set("browser.newtabpage.remote", true);
|
||||
|
||||
let tabOptions = {
|
||||
gBrowser,
|
||||
url: TEST_URL
|
||||
};
|
||||
|
||||
let messagePromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("foo", function(name, msg) {
|
||||
is(name, "foo", "Correct message type sent: foo");
|
||||
is(msg.data, "bar", "Correct data sent: bar");
|
||||
resolve(msg.target);
|
||||
});
|
||||
});
|
||||
let unloadPromise = new Promise(resolve => {
|
||||
NewTabWebChannel.once("targetUnload", function() {
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
yield BrowserTestUtils.withNewTab(tabOptions, function*(browser) {
|
||||
let target = yield messagePromise;
|
||||
is(NewTabWebChannel.numBrowsers, 1, "One target expected");
|
||||
is(target.browser, browser, "Same browser");
|
||||
|
||||
browser.contentWindow.location.reload();
|
||||
});
|
||||
|
||||
Cu.forceGC();
|
||||
is(NewTabWebChannel.numBrowsers, 0, "Sanity check");
|
||||
yield unloadPromise;
|
||||
cleanup();
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Newtab WebChannel test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
window.addEventListener("WebChannelMessageToContent", function(e) {
|
||||
if (e.detail.message && e.detail.message.type === "RECEIVE_PREFS") {
|
||||
let reply = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||
detail: {
|
||||
id: "newtab",
|
||||
message: JSON.stringify({type: "responseAck"}),
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(reply);
|
||||
}
|
||||
}, true);
|
||||
|
||||
document.onreadystatechange = function () {
|
||||
let msg = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||
detail: {
|
||||
id: "newtab",
|
||||
message: JSON.stringify({type: "REQUEST_PREFS"}),
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(msg);
|
||||
};
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,32 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf8">
|
||||
<title>Newtab WebChannel test</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
document.onreadystatechange = function () {
|
||||
let msg = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||
detail: {
|
||||
id: "newtab",
|
||||
message: JSON.stringify({type: "foo", data: "bar"}),
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(msg);
|
||||
};
|
||||
|
||||
window.addEventListener("WebChannelMessageToContent", function(e) {
|
||||
if (e.detail.message && e.detail.message.type === "respond") {
|
||||
let reply = new window.CustomEvent("WebChannelMessageToChrome", {
|
||||
detail: {
|
||||
id: "newtab",
|
||||
message: JSON.stringify({type: "reply", data: "quuz"}),
|
||||
}
|
||||
});
|
||||
window.dispatchEvent(reply);
|
||||
}
|
||||
}, true);
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -28,6 +28,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
|
|||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||
"resource:///modules/NewTabWebChannel.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "NewTabMessages",
|
||||
"resource:///modules/NewTabMessages.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||
"resource:///modules/UITour.jsm");
|
||||
|
||||
|
@ -749,6 +755,8 @@ BrowserGlue.prototype = {
|
|||
AboutNewTab.init();
|
||||
|
||||
NewTabPrefsProvider.prefs.init();
|
||||
NewTabWebChannel.init();
|
||||
NewTabMessages.init();
|
||||
|
||||
SessionStore.init();
|
||||
BrowserUITelemetry.init();
|
||||
|
@ -1054,6 +1062,9 @@ BrowserGlue.prototype = {
|
|||
|
||||
SelfSupportBackend.uninit();
|
||||
NewTabPrefsProvider.prefs.uninit();
|
||||
NewTabWebChannel.uninit();
|
||||
NewTabMessages.uninit();
|
||||
|
||||
AboutNewTab.uninit();
|
||||
webrtcUI.uninit();
|
||||
FormValidationHandler.uninit();
|
||||
|
|
Загрузка…
Ссылка в новой задаче