зеркало из 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.remote.mode", "str"],
|
||||||
["browser.newtabpage.enabled", "bool"],
|
["browser.newtabpage.enabled", "bool"],
|
||||||
["browser.newtabpage.enhanced", "bool"],
|
["browser.newtabpage.enhanced", "bool"],
|
||||||
|
["browser.newtabpage.introShown", "bool"],
|
||||||
|
["browser.newtabpage.updateIntroShown", "bool"],
|
||||||
["browser.newtabpage.pinned", "str"],
|
["browser.newtabpage.pinned", "str"],
|
||||||
|
["browser.newtabpage.blocked", "str"],
|
||||||
["intl.locale.matchOS", "bool"],
|
["intl.locale.matchOS", "bool"],
|
||||||
["general.useragent.locale", "localized"],
|
["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() {
|
let PrefsProvider = function PrefsProvider() {
|
||||||
EventEmitter.decorate(this);
|
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() {
|
get prefsMap() {
|
||||||
return gPrefsMap;
|
return gPrefsMap;
|
||||||
},
|
},
|
||||||
|
@ -83,4 +107,5 @@ const gPrefs = new PrefsProvider();
|
||||||
|
|
||||||
let NewTabPrefsProvider = {
|
let NewTabPrefsProvider = {
|
||||||
prefs: gPrefs,
|
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 += [
|
EXTRA_JS_MODULES += [
|
||||||
|
'NewTabMessages.jsm',
|
||||||
'NewTabPrefsProvider.jsm',
|
'NewTabPrefsProvider.jsm',
|
||||||
'NewTabRemoteResources.jsm',
|
'NewTabRemoteResources.jsm',
|
||||||
'NewTabURL.jsm',
|
'NewTabURL.jsm',
|
||||||
|
'NewTabWebChannel.jsm',
|
||||||
'PlacesProvider.jsm'
|
'PlacesProvider.jsm'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
[DEFAULT]
|
[DEFAULT]
|
||||||
support-files =
|
support-files =
|
||||||
dummy_page.html
|
dummy_page.html
|
||||||
|
newtabwebchannel_basic.html
|
||||||
|
newtabmessages_prefs.html
|
||||||
|
|
||||||
[browser_remotenewtab_pageloads.js]
|
[browser_remotenewtab_pageloads.js]
|
||||||
[browser_newtab_overrides.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",
|
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
|
||||||
"resource:///modules/NewTabPrefsProvider.jsm");
|
"resource:///modules/NewTabPrefsProvider.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "NewTabWebChannel",
|
||||||
|
"resource:///modules/NewTabWebChannel.jsm");
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyModuleGetter(this, "NewTabMessages",
|
||||||
|
"resource:///modules/NewTabMessages.jsm");
|
||||||
|
|
||||||
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
|
||||||
"resource:///modules/UITour.jsm");
|
"resource:///modules/UITour.jsm");
|
||||||
|
|
||||||
|
@ -749,6 +755,8 @@ BrowserGlue.prototype = {
|
||||||
AboutNewTab.init();
|
AboutNewTab.init();
|
||||||
|
|
||||||
NewTabPrefsProvider.prefs.init();
|
NewTabPrefsProvider.prefs.init();
|
||||||
|
NewTabWebChannel.init();
|
||||||
|
NewTabMessages.init();
|
||||||
|
|
||||||
SessionStore.init();
|
SessionStore.init();
|
||||||
BrowserUITelemetry.init();
|
BrowserUITelemetry.init();
|
||||||
|
@ -1054,6 +1062,9 @@ BrowserGlue.prototype = {
|
||||||
|
|
||||||
SelfSupportBackend.uninit();
|
SelfSupportBackend.uninit();
|
||||||
NewTabPrefsProvider.prefs.uninit();
|
NewTabPrefsProvider.prefs.uninit();
|
||||||
|
NewTabWebChannel.uninit();
|
||||||
|
NewTabMessages.uninit();
|
||||||
|
|
||||||
AboutNewTab.uninit();
|
AboutNewTab.uninit();
|
||||||
webrtcUI.uninit();
|
webrtcUI.uninit();
|
||||||
FormValidationHandler.uninit();
|
FormValidationHandler.uninit();
|
||||||
|
|
Загрузка…
Ссылка в новой задаче