Bug 1218996 - Fuse aboutNewTabService and RemoteNewTabLocation and return resource URLS r=marcosc

This commit is contained in:
Olivier Yiptong 2016-01-11 20:30:13 -05:00
parent f799e1c43a
commit b652513ab4
26 changed files with 514 additions and 471 deletions

View File

@ -53,7 +53,9 @@ XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
"@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
"resource://gre/modules/LightweightThemeManager.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "gAboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
return Services.strings.createBundle('chrome://browser/locale/browser.properties');
});
@ -2312,8 +2314,11 @@ function URLBarSetURI(aURI) {
} catch (e) {}
// Replace initial page URIs with an empty string
// only if there's no opener (bug 370555).
if (gInitialPages.indexOf(uri.spec) != -1)
// 1. only if there's no opener (bug 370555).
// 2. if remote newtab is enabled and it's the default remote newtab page
let defaultRemoteURL = gAboutNewTabService.remoteEnabled &&
uri.spec === gAboutNewTabService.newTabURL;
if (gInitialPages.includes(uri.spec) || defaultRemoteURL)
value = gBrowser.selectedBrowser.hasContentOpener ? uri.spec : "";
else
value = losslessDecodeURI(uri);

View File

@ -1,36 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* globals
waitForExplicitFinish, whenNewWindowLoaded, whenNewTabLoaded,
executeSoon, registerCleanupFunction, finish, is
*/
/* exported test */
// This test makes sure that opening a new tab in private browsing mode opens about:privatebrowsing
function test() {
// initialization
waitForExplicitFinish();
let aboutNewTabService = Components.classes["@mozilla.org/browser/aboutnewtab-service;1"]
.getService(Components.interfaces.nsIAboutNewTabService);
let windowsToClose = [];
let newTab;
let newTabURL;
let mode;
function doTest(aIsPrivateMode, aWindow, aCallback) {
whenNewTabLoaded(aWindow, function () {
whenNewTabLoaded(aWindow, function() {
if (aIsPrivateMode) {
mode = "per window private browsing";
newTabURL = "about:privatebrowsing";
} else {
mode = "normal";
newTabURL = aboutNewTabService.newTabURL;
newTabURL = "about:newtab";
}
is(aWindow.gBrowser.currentURI.spec, newTabURL,
"URL of NewTab should be " + newTabURL + " in " + mode + " mode");
aWindow.gBrowser.removeTab(aWindow.gBrowser.selectedTab);
aCallback()
aCallback();
});
};
}
function testOnWindow(aOptions, aCallback) {
whenNewWindowLoaded(aOptions, function(aWin) {
@ -40,9 +44,9 @@ function test() {
// call whenNewWindowLoaded() instead of testOnWindow() on your test.
executeSoon(() => aCallback(aWin));
});
};
}
// this function is called after calling finish() on the test.
// this function is called after calling finish() on the test.
registerCleanupFunction(function() {
windowsToClose.forEach(function(aWin) {
aWin.close();

View File

@ -1,24 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
/* globals waitForExplicitFinish, executeSoon, finish, whenNewWindowLoaded, ok */
/* globals is */
/* exported test */
function test() {
//initialization
waitForExplicitFinish();
let aboutNewTabService = Components.classes["@mozilla.org/browser/aboutnewtab-service;1"]
.getService(Components.interfaces.nsIAboutNewTabService);
let newTabURL;
let testURL = "http://example.com/";
let defaultURL = aboutNewTabService.newTabURL;
let mode;
function doTest(aIsPrivateMode, aWindow, aCallback) {
openNewTab(aWindow, function () {
openNewTab(aWindow, function() {
if (aIsPrivateMode) {
mode = "per window private browsing";
newTabURL = "about:privatebrowsing";
} else {
mode = "normal";
newTabURL = aboutNewTabService.newTabURL;
newTabURL = "about:newtab";
}
// Check the new tab opened while in normal/private mode
@ -29,18 +35,18 @@ function test() {
is(aboutNewTabService.newTabURL, testURL, "Custom newtab url is set");
// Open a newtab after setting the custom newtab url
openNewTab(aWindow, function () {
openNewTab(aWindow, function() {
is(aWindow.gBrowser.selectedBrowser.currentURI.spec, testURL,
"URL of NewTab should be the custom url");
// Clear the custom url.
aboutNewTabService.resetNewTabURL();
is(aboutNewTabService.newTabURL, "about:newtab", "No custom newtab url is set");
is(aboutNewTabService.newTabURL, defaultURL, "No custom newtab url is set");
aWindow.gBrowser.removeTab(aWindow.gBrowser.selectedTab);
aWindow.gBrowser.removeTab(aWindow.gBrowser.selectedTab);
aWindow.close();
aCallback()
aCallback();
});
});
}
@ -72,7 +78,7 @@ function openNewTab(aWindow, aCallback) {
aWindow.BrowserOpenTab();
let browser = aWindow.gBrowser.selectedBrowser;
if (browser.contentDocument.readyState == "complete") {
if (browser.contentDocument.readyState === "complete") {
executeSoon(aCallback);
return;
}

View File

@ -9,13 +9,19 @@
* as the nodePrincipal match the URL in the URL bar.
*/
const ABOUT_NEWTAB_URI = "about:newtab";
const PREF_URI = "http://example.com/browser/browser/base/content/test/newtab/external_newtab.html";
/* globals Cc, Ci, ok, is, content, TestRunner, addNewTabPageTab, gWindow, Services, info */
/* exported runTests */
"use strict";
var browser = null;
var aboutNewTabService = Cc["@mozilla.org/browser/aboutnewtab-service;1"]
.getService(Ci.nsIAboutNewTabService);
const ABOUT_NEWTAB_URI = "about:newtab";
const PREF_URI = "http://example.com/browser/browser/base/content/test/newtab/external_newtab.html";
const DEFAULT_URI = aboutNewTabService.newTabURL;
function testPref() {
// set the pref for about:newtab to point to an exteranl resource
aboutNewTabService.newTabURL = PREF_URI;
@ -34,7 +40,7 @@ function testPref() {
// reset to about:newtab and perform sanity check
aboutNewTabService.resetNewTabURL();
is(aboutNewTabService.newTabURL, ABOUT_NEWTAB_URI,
is(aboutNewTabService.newTabURL, DEFAULT_URI,
"sanity check: resetting the URL to about:newtab should return about:newtab");
// remove the tab and move on

View File

@ -46,5 +46,3 @@ component {d8903bf6-68d5-4e97-bcd1-e4d3012f721a} nsBrowserGlue.js
#ifndef MOZ_MULET
contract @mozilla.org/content-permission/prompt;1 {d8903bf6-68d5-4e97-bcd1-e4d3012f721a}
#endif
component {97eea4bb-db50-4ae0-9147-1e5ed55b4ed5} nsBrowserGlue.js
contract @mozilla.org/browser/aboutnewtab-service;1 {97eea4bb-db50-4ae0-9147-1e5ed55b4ed5}

View File

@ -51,7 +51,7 @@ add_task(function* () {
windowId: activeWindow,
active: true,
pinned: false,
url: "about:newtab",
url: "chrome://browser/content/newtab/newTab.xhtml",
};
let tests = [
@ -65,7 +65,7 @@ add_task(function* () {
},
{
create: {},
result: { url: "about:newtab" },
result: { url: "chrome://browser/content/newtab/newTab.xhtml" },
},
{
create: { active: false },

View File

@ -28,7 +28,6 @@ DIRS += [
DIRS += ['build']
XPIDL_SOURCES += [
'nsIAboutNewTabService.idl',
'nsIBrowserGlue.idl',
'nsIBrowserHandler.idl',
]

View File

@ -0,0 +1,2 @@
component {cef25b06-0ef6-4c50-a243-e69f943ef23d} aboutNewTabService.js
contract @mozilla.org/browser/aboutnewtab-service;1 {cef25b06-0ef6-4c50-a243-e69f943ef23d}

View File

@ -17,6 +17,7 @@ XPCOMUtils.defineLazyGetter(this, "EventEmitter", function() {
// Supported prefs and data type
const gPrefsMap = new Map([
["browser.newtabpage.remote", "bool"],
["browser.newtabpage.enabled", "bool"],
["browser.newtabpage.enhanced", "bool"],
["browser.newtabpage.pinned", "str"],

View File

@ -2,13 +2,14 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals XPCOMUtils, Deprecated, aboutNewTabService*/
/* exported NewTabURL */
"use strict";
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
const {utils: Cu} = Components;
this.EXPORTED_SYMBOLS = [ "NewTabURL" ];
this.EXPORTED_SYMBOLS = ["NewTabURL"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",

View File

@ -1,7 +1,7 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* globals Services, XPCOMUtils, RemotePages, RemoteNewTabLocation, RemoteNewTabUtils, Task */
/* globals Services, XPCOMUtils, RemotePages, RemoteNewTabUtils, Task, aboutNewTabService */
/* globals BackgroundPageThumbs, PageThumbs, DirectoryLinksProvider, PlacesProvider, NewTabPrefsProvider */
/* exported RemoteAboutNewTab */
@ -28,23 +28,25 @@ XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
"resource:///modules/DirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
"resource:///modules/RemoteNewTabLocation.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesProvider",
"resource:///modules/PlacesProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
"resource:///modules/NewTabPrefsProvider.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
let RemoteAboutNewTab = {
pageListener: null,
remoteURL: null,
/**
* Initialize the RemotePageManager and add all message listeners for this page
*/
init: function() {
RemoteNewTabLocation.init();
this.pageListener = new RemotePages("about:remote-newtab");
this.remoteURL = new URL(aboutNewTabService.generateRemoteURL());
this.pageListener = new RemotePages(this.remoteURL.href);
this.pageListener.addMessageListener("NewTab:InitializeGrid", this.initializeGrid.bind(this));
this.pageListener.addMessageListener("NewTab:UpdateGrid", this.updateGrid.bind(this));
this.pageListener.addMessageListener("NewTab:Customize", this.customize.bind(this));
@ -115,8 +117,8 @@ let RemoteAboutNewTab = {
*/
initContentFrame: function(message) {
message.target.sendAsyncMessage("NewTabFrame:Init", {
href: RemoteNewTabLocation.href,
origin: RemoteNewTabLocation.origin
href: this.remoteURL.href,
origin: this.remoteURL.origin
});
},
@ -293,7 +295,6 @@ let RemoteAboutNewTab = {
Ci.nsISupportsWeakReference]),
uninit: function() {
RemoteNewTabLocation.uninit();
this._removeObservers();
this.pageListener.destroy();
this.pageListener = null;

View File

@ -1,141 +0,0 @@
/* globals Services, UpdateUtils, XPCOMUtils, URL, NewTabPrefsProvider, Locale */
/* exported RemoteNewTabLocation */
"use strict";
this.EXPORTED_SYMBOLS = ["RemoteNewTabLocation"];
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.importGlobalProperties(["URL"]);
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
"resource:///modules/NewTabPrefsProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
"resource://gre/modules/Locale.jsm");
// The preference that tells whether to match the OS locale
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
// The preference that tells what locale the user selected
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const DEFAULT_PAGE_LOCATION = "https://newtab.cdn.mozilla.net/" +
"v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
const VALID_CHANNELS = new Set(["esr", "release", "beta", "aurora", "nightly"]);
const NEWTAB_VERSION = "0";
let RemoteNewTabLocation = {
/*
* Generate a default url based on locale and update channel
*/
_generateDefaultURL() {
let releaseName = this._releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
let uri = DEFAULT_PAGE_LOCATION
.replace("%VERSION%", this.version)
.replace("%LOCALE%", Locale.getLocale())
.replace("%CHANNEL%", releaseName);
return new URL(uri);
},
_url: null,
_overridden: false,
get href() {
return this._url.href;
},
get origin() {
return this._url.origin;
},
get overridden() {
return this._overridden;
},
get version() {
return NEWTAB_VERSION;
},
get channels() {
return VALID_CHANNELS;
},
/**
* Returns the release name from an Update Channel name
*
* @return {String} a release name based on the update channel. Defaults to nightly
*/
_releaseFromUpdateChannel(channel) {
let result = "nightly";
if (VALID_CHANNELS.has(channel)) {
result = channel;
}
return result;
},
/*
* Updates the location when the page is not overriden.
* Useful when there is a pref change
*/
_updateMaybe() {
if (!this.overridden) {
let url = this._generateDefaultURL();
if (url.href !== this._url.href) {
this._url = url;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
}
}
},
/*
* Override the Remote newtab page location.
*/
override(newURL) {
let url = new URL(newURL);
if (url.href !== this._url.href) {
this._overridden = true;
this._url = url;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
}
},
/*
* Reset the newtab page location to the default value
*/
reset() {
let url = this._generateDefaultURL();
if (url.href !== this._url.href) {
this._url = url;
this._overridden = false;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
}
},
init() {
NewTabPrefsProvider.prefs.on(
PREF_SELECTED_LOCALE,
this._updateMaybe.bind(this));
NewTabPrefsProvider.prefs.on(
PREF_MATCH_OS_LOCALE,
this._updateMaybe.bind(this));
this._url = this._generateDefaultURL();
},
uninit() {
this._url = null;
this._overridden = false;
NewTabPrefsProvider.prefs.off(PREF_SELECTED_LOCALE, this._updateMaybe);
NewTabPrefsProvider.prefs.off(PREF_MATCH_OS_LOCALE, this._updateMaybe);
}
};

View File

@ -0,0 +1,190 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
/* globals XPCOMUtils, NewTabPrefsProvider, Services,
Locale, UpdateUtils
*/
"use strict";
const {utils: Cu, interfaces: Ci} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
"resource:///modules/NewTabPrefsProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Locale",
"resource://gre/modules/Locale.jsm");
const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml";
const REMOTE_NEWTAB_URL = "https://newtab.cdn.mozilla.net/" +
"v%VERSION%/%CHANNEL%/%LOCALE%/index.html";
// Pref that tells if remote newtab is enabled
const PREF_REMOTE_ENABLED = "browser.newtabpage.remote";
// The preference that tells whether to match the OS locale
const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
// The preference that tells what locale the user selected
const PREF_SELECTED_LOCALE = "general.useragent.locale";
const VALID_CHANNELS = new Set(["esr", "release", "beta", "aurora", "nightly"]);
const REMOTE_NEWTAB_VERSION = "0";
function AboutNewTabService() {
NewTabPrefsProvider.prefs.on(PREF_REMOTE_ENABLED, this._handleToggleEvent.bind(this));
// trigger remote change if needed, according to pref
this.toggleRemote(Services.prefs.getBoolPref(PREF_REMOTE_ENABLED));
}
AboutNewTabService.prototype = {
_newTabURL: LOCAL_NEWTAB_URL,
_remoteEnabled: false,
_overridden: false,
classID: Components.ID("{cef25b06-0ef6-4c50-a243-e69f943ef23d}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutNewTabService]),
_xpcom_categories: [{
service: true
}],
_handleToggleEvent(prefName, stateEnabled, forceState) { //jshint unused:false
this.toggleRemote(stateEnabled, forceState);
},
/**
* React to changes to the remote newtab pref. Only act
* if there is a change of state and if not overridden.
*
* @returns {Boolean} Returns if there has been a state change
*
* @param {Boolean} stateEnabled remote state to set to
* @param {Boolean} forceState force state change
*/
toggleRemote(stateEnabled, forceState) {
if (!forceState && (this._overriden || stateEnabled === this._remoteEnabled)) {
// exit there is no change of state
return false;
}
if (stateEnabled) {
this._newTabURL = this.generateRemoteURL();
NewTabPrefsProvider.prefs.on(
PREF_SELECTED_LOCALE,
this._updateRemoteMaybe.bind(this));
NewTabPrefsProvider.prefs.on(
PREF_MATCH_OS_LOCALE,
this._updateRemoteMaybe.bind(this));
this._remoteEnabled = true;
} else {
this._newTabURL = LOCAL_NEWTAB_URL;
NewTabPrefsProvider.prefs.off(PREF_SELECTED_LOCALE, this._updateRemoteMaybe);
NewTabPrefsProvider.prefs.off(PREF_MATCH_OS_LOCALE, this._updateRemoteMaybe);
this._remoteEnabled = false;
}
return true;
},
/*
* Generate a default url based on locale and update channel
*/
generateRemoteURL() {
let releaseName = this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
let url = REMOTE_NEWTAB_URL
.replace("%VERSION%", REMOTE_NEWTAB_VERSION)
.replace("%LOCALE%", Locale.getLocale())
.replace("%CHANNEL%", releaseName);
return url;
},
/*
* Updates the remote location when the page is not overriden.
*
* Useful when there is a dependent pref change
*/
_updateRemoteMaybe() {
if (!this._remoteEnabled || this._overridden) {
return;
}
let url = this.generateRemoteURL();
if (url !== this._newTabURL) {
this._newTabURL = url;
Services.obs.notifyObservers(null, "newtab-url-changed",
this._newTabURL);
}
},
/**
* Returns the release name from an Update Channel name
*
* @return {String} a release name based on the update channel. Defaults to nightly
*/
releaseFromUpdateChannel(channelName) {
return VALID_CHANNELS.has(channelName) ? channelName : "nightly";
},
get newTabURL() {
return this._newTabURL;
},
get remoteVersion() {
return REMOTE_NEWTAB_VERSION;
},
get remoteReleaseName() {
return this.releaseFromUpdateChannel(UpdateUtils.UpdateChannel);
},
set newTabURL(aNewTabURL) {
if (aNewTabURL === "about:newtab") {
// avoid infinite redirects in case one sets the URL to about:newtab
this.resetNewTabURL();
return;
}
let remoteURL = this.generateRemoteURL();
let prefRemoteEnabled = Services.prefs.getBoolPref(PREF_REMOTE_ENABLED);
let isResetLocal = !prefRemoteEnabled && aNewTabURL === LOCAL_NEWTAB_URL;
let isResetRemote = prefRemoteEnabled && aNewTabURL === remoteURL;
if (isResetLocal || isResetRemote) {
if (this._overriden) {
// only trigger a reset if previously overridden
this.resetNewTabURL();
}
return;
}
// turn off remote state if needed
this.toggleRemote(false);
this._newTabURL = aNewTabURL;
this._overridden = true;
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
},
get overridden() {
return this._overridden;
},
get remoteEnabled() {
return this._remoteEnabled;
},
resetNewTabURL() {
this._overridden = false;
this.toggleRemote(Services.prefs.getBoolPref(PREF_REMOTE_ENABLED), true);
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
}
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AboutNewTabService]);

View File

@ -16,6 +16,16 @@ if not CONFIG['RELEASE_BUILD']:
'NewTabURL.jsm',
'PlacesProvider.jsm',
'RemoteAboutNewTab.jsm',
'RemoteNewTabLocation.jsm',
'RemoteNewTabUtils.jsm',
]
XPIDL_SOURCES += [
'nsIAboutNewTabService.idl',
]
XPIDL_MODULE = 'browser-newtab'
EXTRA_COMPONENTS += [
'aboutNewTabService.js',
'NewTabComponents.manifest',
]

View File

@ -0,0 +1,58 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* Allows to override about:newtab to point to a different location
* than the one specified within AboutRedirector.cpp
*/
[scriptable, uuid(cef25b06-0ef6-4c50-a243-e69f943ef23d)]
interface nsIAboutNewTabService : nsISupports
{
/**
* Returns the url of the resource for the newtab page if not overridden,
* otherwise a string represenation of the new URL.
*/
attribute ACString newTabURL;
/**
* Returns true if the default resource got overridden.
*/
readonly attribute bool overridden;
/**
* Returns true if the default resource is remotely hosted and isn't
* overridden
*/
readonly attribute bool remoteEnabled;
/**
* Returns the version of the remote newtab page expected
*/
readonly attribute ACString remoteVersion;
/**
* Returns the expected channel for the remote the newtab page
*/
readonly attribute ACString remoteReleaseName;
/**
* Generates and returns the remote newtab page url
*/
ACString generateRemoteURL();
/**
* Returns a remote new tab release name given an update channel name
*/
ACString releaseFromUpdateChannel(in ACString channelName);
/**
* Resets to the default resource and also resets the
* overridden attribute to false.
*/
void resetNewTabURL();
};

View File

@ -1,46 +1,57 @@
/* globals XPCOMUtils, Task, RemoteAboutNewTab, RemoteNewTabLocation, ok */
/* globals XPCOMUtils, aboutNewTabService, Services */
"use strict";
let Cu = Components.utils;
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
"resource:///modules/RemoteNewTabLocation.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteAboutNewTab",
"resource:///modules/RemoteAboutNewTab.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemotePageManager",
"resource://gre/modules/RemotePageManager.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
const TEST_URL = "https://example.com/browser/browser/components/newtab/tests/browser/dummy_page.html";
const NEWTAB_URL = "about:remote-newtab";
let tests = [];
/*
* Tests that:
* 1. overriding the RemoteNewTabPageLocation url causes a remote newtab page
* to load with the new url.
* 2. Messages pass between remote page <--> newTab.js <--> RemoteAboutNewTab.js
*/
tests.push(Task.spawn(function* testMessage() {
yield new Promise(resolve => {
RemoteAboutNewTab.pageListener.addMessageListener("NewTab:testMessage", () => {
ok(true, "message received");
resolve();
});
});
}));
add_task(function* open_newtab() {
RemoteNewTabLocation.override(TEST_URL);
ok(RemoteNewTabLocation.href === TEST_URL, "RemoteNewTabLocation has been overridden");
let notificationPromise = nextChangeNotificationPromise(TEST_URL, "newtab page now points to test url");
aboutNewTabService.newTabURL = TEST_URL;
yield notificationPromise;
Assert.ok(aboutNewTabService.overridden, "url has been overridden");
let tabOptions = {
gBrowser,
url: NEWTAB_URL,
url: "about:newtab",
};
for (let test of tests) {
yield BrowserTestUtils.withNewTab(tabOptions, function* (browser) { // jshint ignore:line
yield test;
}); // jshint ignore:line
}
yield BrowserTestUtils.withNewTab(tabOptions, function* (browser) {
Assert.equal(TEST_URL, browser.contentWindow.location, `New tab should open to ${TEST_URL}`);
});
});
add_task(function* emptyURL() {
let notificationPromise = nextChangeNotificationPromise("", "newtab service now points to empty url");
aboutNewTabService.newTabURL = "";
yield notificationPromise;
let tabOptions = {
gBrowser,
url: "about:newtab",
};
yield BrowserTestUtils.withNewTab(tabOptions, function* (browser) {
Assert.equal("about:blank", browser.contentWindow.location, `New tab should open to ${"about:blank"}`);
});
});
function nextChangeNotificationPromise(aNewURL, testMessage) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint unused:false
Services.obs.removeObserver(observer, aTopic);
Assert.equal(aData, aNewURL, testMessage);
resolve();
}, "newtab-url-changed", false);
});
}

View File

@ -6,17 +6,5 @@
</head>
<body>
<p>Dummy Page</p>
<script type="text/javascript;version=1.8">
document.addEventListener("NewTabCommandReady", function readyCmd() {
document.removeEventListener("NewTabCommandReady", readyCmd);
let event = new CustomEvent("NewTabCommand", {
detail: {
command: "NewTab:testMessage"
}
});
document.dispatchEvent(event);
});
</script>
</body>
</html>

View File

@ -1,38 +1,150 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* globals Services, XPCOMUtils, NewTabPrefsProvider, Preferences, aboutNewTabService */
"use strict";
Components.utils.import("resource://gre/modules/Services.jsm");
let aboutNewTabService = Components.classes["@mozilla.org/browser/aboutnewtab-service;1"]
.getService(Components.interfaces.nsIAboutNewTabService);
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
"resource:///modules/NewTabPrefsProvider.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
const DEFAULT_HREF = aboutNewTabService.generateRemoteURL();
/**
* Test the overriding of the default URL
*/
add_task(function* () {
Assert.equal(aboutNewTabService.newTabURL, "about:newtab", "Default newtab URL should be about:newtab");
NewTabPrefsProvider.prefs.init();
let notificationPromise;
Services.prefs.setBoolPref("browser.newtabpage.remote", false);
let localChromeURL = "chrome://browser/content/newtab/newTab.xhtml";
// tests default is the local newtab resource
Assert.equal(aboutNewTabService.newTabURL, localChromeURL,
`Default newtab URL should be ${localChromeURL}`);
// test the newtab service does not go in a circular redirect
aboutNewTabService.newTabURL = "about:newtab";
Assert.equal(aboutNewTabService.newTabURL, localChromeURL,
"Newtab URL avoids a circular redirect by setting to the default URL");
let url = "http://example.com/";
let notificationPromise = promiseNewtabURLNotification(url);
notificationPromise = nextChangeNotificationPromise(url);
aboutNewTabService.newTabURL = url;
yield notificationPromise;
Assert.ok(aboutNewTabService.overridden, "Newtab URL should be overridden");
Assert.ok(!aboutNewTabService.remoteEnabled, "Newtab remote should not be enabled");
Assert.equal(aboutNewTabService.newTabURL, url, "Newtab URL should be the custom URL");
notificationPromise = promiseNewtabURLNotification("about:newtab");
notificationPromise = nextChangeNotificationPromise("chrome://browser/content/newtab/newTab.xhtml");
aboutNewTabService.resetNewTabURL();
yield notificationPromise;
Assert.ok(!aboutNewTabService.overridden, "Newtab URL should not be overridden");
Assert.equal(aboutNewTabService.newTabURL, "about:newtab", "Newtab URL should be the about:newtab");
Assert.equal(aboutNewTabService.newTabURL, "chrome://browser/content/newtab/newTab.xhtml",
"Newtab URL should be the default");
// change newtab page to remote
Services.prefs.setBoolPref("browser.newtabpage.remote", true);
Assert.equal(aboutNewTabService.newTabURL, "about:remote-newtab", "Newtab URL should be the about:remote-newtab");
let remoteHref = aboutNewTabService.generateRemoteURL();
Assert.equal(aboutNewTabService.newTabURL, remoteHref, "Newtab URL should be the default remote URL");
Assert.ok(!aboutNewTabService.overridden, "Newtab URL should not be overridden");
Assert.ok(aboutNewTabService.remoteEnabled, "Newtab remote should be enabled");
NewTabPrefsProvider.prefs.uninit();
});
function promiseNewtabURLNotification(aNewURL) {
/**
* Tests reponse to updates to prefs
*/
add_task(function* test_updates() {
Preferences.set("browser.newtabpage.remote", true);
let notificationPromise;
let expectedHref = "https://newtab.cdn.mozilla.net" +
`/v${aboutNewTabService.remoteVersion}` +
`/${aboutNewTabService.remoteReleaseName}` +
"/en-GB" +
"/index.html";
Preferences.set("intl.locale.matchOS", true);
Preferences.set("general.useragent.locale", "en-GB");
NewTabPrefsProvider.prefs.init();
// test update checks for prefs
notificationPromise = nextChangeNotificationPromise(
expectedHref, "Remote href should be updated");
Preferences.set("intl.locale.matchOS", false);
yield notificationPromise;
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "Remote href changes back to default");
Preferences.set("general.useragent.locale", "en-US");
yield notificationPromise;
// test update fires on override and reset
let testURL = "https://example.com/";
notificationPromise = nextChangeNotificationPromise(
testURL, "a notification occurs on override");
aboutNewTabService.newTabURL = testURL;
yield notificationPromise;
// from overridden to default
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "a notification occurs on reset");
aboutNewTabService.resetNewTabURL();
Assert.ok(aboutNewTabService.remoteEnabled, "Newtab remote should be enabled");
yield notificationPromise;
// override to default URL from default URL
notificationPromise = nextChangeNotificationPromise(
testURL, "a notification only occurs for a change in overridden urls");
aboutNewTabService.newTabURL = aboutNewTabService.generateRemoteURL();
Assert.ok(aboutNewTabService.remoteEnabled, "Newtab remote should be enabled");
aboutNewTabService.newTabURL = testURL;
Assert.ok(!aboutNewTabService.remoteEnabled, "Newtab remote should not be enabled");
yield notificationPromise;
// reset twice, only one notification for default URL
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "reset occurs");
aboutNewTabService.resetNewTabURL();
yield notificationPromise;
NewTabPrefsProvider.prefs.uninit();
});
/**
* Verifies that releaseFromUpdateChannel
* Returns the correct release names
*/
add_task(function* test_release_names() {
let valid_channels = ["esr", "release", "beta", "aurora", "nightly"];
let invalid_channels = new Set(["default", "invalid"]);
for (let channel of valid_channels) {
Assert.equal(channel, aboutNewTabService.releaseFromUpdateChannel(channel),
"release == channel name when valid");
}
for (let channel of invalid_channels) {
Assert.equal("nightly", aboutNewTabService.releaseFromUpdateChannel(channel),
"release == nightly when invalid");
}
});
function nextChangeNotificationPromise(aNewURL, testMessage) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint unused:false
Services.obs.removeObserver(observer, aTopic);
Assert.equal(aData, aNewURL, "Data for newtab-url-changed notification should be new URL.");
Assert.equal(aData, aNewURL, testMessage);
resolve();
}, "newtab-url-changed", false);
});

View File

@ -1,13 +1,25 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/
*/
/* globals Services, NewTabURL, XPCOMUtils, aboutNewTabService */
"use strict";
Components.utils.import("resource:///modules/NewTabURL.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
const {utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource:///modules/NewTabURL.jsm");
Cu.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
"resource:///modules/NewTabPrefsProvider.jsm");
XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
"@mozilla.org/browser/aboutnewtab-service;1",
"nsIAboutNewTabService");
add_task(function* () {
Assert.equal(NewTabURL.get(), "about:newtab", "Default newtab URL should be about:newtab");
let defaultURL = aboutNewTabService.newTabURL;
Services.prefs.setBoolPref("browser.newtabpage.remote", false);
Assert.equal(NewTabURL.get(), defaultURL, `Default newtab URL should be ${defaultURL}`);
let url = "http://example.com/";
let notificationPromise = promiseNewtabURLNotification(url);
NewTabURL.override(url);
@ -15,21 +27,24 @@ add_task(function* () {
Assert.ok(NewTabURL.overridden, "Newtab URL should be overridden");
Assert.equal(NewTabURL.get(), url, "Newtab URL should be the custom URL");
notificationPromise = promiseNewtabURLNotification("about:newtab");
notificationPromise = promiseNewtabURLNotification(defaultURL);
NewTabURL.reset();
yield notificationPromise;
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
Assert.equal(NewTabURL.get(), "about:newtab", "Newtab URL should be the about:newtab");
Assert.equal(NewTabURL.get(), defaultURL, "Newtab URL should be the default");
// change newtab page to remote
NewTabPrefsProvider.prefs.init();
Services.prefs.setBoolPref("browser.newtabpage.remote", true);
Assert.equal(NewTabURL.get(), "about:remote-newtab", "Newtab URL should be the about:remote-newtab");
let remoteURL = aboutNewTabService.generateRemoteURL();
Assert.equal(NewTabURL.get(), remoteURL, `Newtab URL should be ${remoteURL}`);
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
NewTabPrefsProvider.prefs.uninit();
});
function promiseNewtabURLNotification(aNewURL) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint ignore:line
Services.obs.removeObserver(observer, aTopic);
Assert.equal(aData, aNewURL, "Data for newtab-url-changed notification should be new URL.");
resolve();

View File

@ -1,148 +0,0 @@
/* globals ok, equal, RemoteNewTabLocation, NewTabPrefsProvider, Services, Preferences, XPCOMUtils, UpdateUtils */
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
"use strict";
const {utils: Cu} = Components;
Cu.import("resource:///modules/RemoteNewTabLocation.jsm");
Cu.import("resource:///modules/NewTabPrefsProvider.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Preferences.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.importGlobalProperties(["URL"]);
XPCOMUtils.defineLazyModuleGetter(this, "UpdateUtils",
"resource://gre/modules/UpdateUtils.jsm");
RemoteNewTabLocation.init();
const DEFAULT_HREF = RemoteNewTabLocation.href;
RemoteNewTabLocation.uninit();
add_task(function* test_defaults() {
RemoteNewTabLocation.init();
ok(RemoteNewTabLocation.href, "Default location has an href");
ok(RemoteNewTabLocation.origin, "Default location has an origin");
ok(!RemoteNewTabLocation.overridden, "Default location is not overridden");
RemoteNewTabLocation.uninit();
});
/**
* Tests the overriding of the default URL
*/
add_task(function* test_overrides() {
RemoteNewTabLocation.init();
let testURL = new URL("https://example.com/");
let notificationPromise;
notificationPromise = nextChangeNotificationPromise(
testURL.href, "Remote Location should change");
RemoteNewTabLocation.override(testURL.href);
yield notificationPromise;
ok(RemoteNewTabLocation.overridden, "Remote location should be overridden");
equal(RemoteNewTabLocation.href, testURL.href,
"Remote href should be the custom URL");
equal(RemoteNewTabLocation.origin, testURL.origin,
"Remote origin should be the custom URL");
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "Remote href should be reset");
RemoteNewTabLocation.reset();
yield notificationPromise;
ok(!RemoteNewTabLocation.overridden, "Newtab URL should not be overridden");
RemoteNewTabLocation.uninit();
});
/**
* Tests how RemoteNewTabLocation responds to updates to prefs
*/
add_task(function* test_updates() {
RemoteNewTabLocation.init();
let notificationPromise;
let release = RemoteNewTabLocation._releaseFromUpdateChannel(
UpdateUtils.UpdateChannel);
let expectedHref = "https://newtab.cdn.mozilla.net" +
`/v${RemoteNewTabLocation.version}` +
`/${release}` +
"/en-GB" +
"/index.html";
Preferences.set("intl.locale.matchOS", true);
Preferences.set("general.useragent.locale", "en-GB");
NewTabPrefsProvider.prefs.init();
// test update checks for prefs
notificationPromise = nextChangeNotificationPromise(
expectedHref, "Remote href should be updated");
Preferences.set("intl.locale.matchOS", false);
yield notificationPromise;
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "Remote href changes back to default");
Preferences.set("general.useragent.locale", "en-US");
yield notificationPromise;
// test update fires on override and reset
let testURL = new URL("https://example.com/");
notificationPromise = nextChangeNotificationPromise(
testURL.href, "a notification occurs on override");
RemoteNewTabLocation.override(testURL.href);
yield notificationPromise;
// from overridden to default
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "a notification occurs on reset");
RemoteNewTabLocation.reset();
yield notificationPromise;
// override to default URL from default URL
notificationPromise = nextChangeNotificationPromise(
testURL.href, "a notification only occurs for a change in overridden urls");
RemoteNewTabLocation.override(DEFAULT_HREF);
RemoteNewTabLocation.override(testURL.href);
yield notificationPromise;
// reset twice, only one notification for default URL
notificationPromise = nextChangeNotificationPromise(
DEFAULT_HREF, "reset occurs");
RemoteNewTabLocation.reset();
yield notificationPromise;
notificationPromise = nextChangeNotificationPromise(
testURL.href, "a notification only occurs for a change in reset urls");
RemoteNewTabLocation.reset();
RemoteNewTabLocation.override(testURL.href);
yield notificationPromise;
NewTabPrefsProvider.prefs.uninit();
RemoteNewTabLocation.uninit();
});
/**
* Verifies that RemoteNewTabLocation's _releaseFromUpdateChannel
* Returns the correct release names
*/
add_task(function* test_release_names() {
RemoteNewTabLocation.init();
let valid_channels = RemoteNewTabLocation.channels;
let invalid_channels = new Set(["default", "invalid"]);
for (let channel of valid_channels) {
equal(channel, RemoteNewTabLocation._releaseFromUpdateChannel(channel),
"release == channel name when valid");
}
for (let channel of invalid_channels) {
equal("nightly", RemoteNewTabLocation._releaseFromUpdateChannel(channel),
"release == nightly when invalid");
}
RemoteNewTabLocation.uninit();
});
function nextChangeNotificationPromise(aNewURL, testMessage) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint ignore:line
Services.obs.removeObserver(observer, aTopic);
equal(aData, aNewURL, testMessage);
resolve();
}, "remote-new-tab-location-changed", false);
});
}

View File

@ -8,5 +8,4 @@ skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_NewTabPrefsProvider.js]
[test_NewTabURL.js]
[test_PlacesProvider.js]
[test_RemoteNewTabLocation.js]
[test_RemoteNewTabUtils.js]

View File

@ -194,8 +194,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
XPCOMUtils.defineLazyServiceGetter(this, "AlertsService",
"@mozilla.org/alerts-service;1", "nsIAlertsService");
const ABOUT_NEWTAB = "about:newtab";
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
@ -2474,50 +2472,6 @@ BrowserGlue.prototype = {
_xpcom_factory: BrowserGlueServiceFactory,
}
// ------------------------------------
// nsIAboutNewTabService implementation
//-------------------------------------
function AboutNewTabService()
{
this._newTabURL = ABOUT_NEWTAB;
this._overridden = false;
}
AboutNewTabService.prototype = {
classID: Components.ID("{97eea4bb-db50-4ae0-9147-1e5ed55b4ed5}"),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutNewTabService]),
get newTabURL() {
if (!AppConstants.RELEASE_BUILD && Services.prefs.getBoolPref("browser.newtabpage.remote")) {
return "about:remote-newtab";
}
return this._newTabURL;
},
set newTabURL(aNewTabURL) {
if (aNewTabURL === ABOUT_NEWTAB) {
this.resetNewTabURL();
return;
}
this._newTabURL = aNewTabURL;
this._overridden = true;
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
},
get overridden() {
return this._overridden;
},
resetNewTabURL: function() {
this._newTabURL = ABOUT_NEWTAB;
this._overridden = false;
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
}
};
function ContentPermissionPrompt() {}
ContentPermissionPrompt.prototype = {
@ -3332,7 +3286,7 @@ var E10SAccessibilityCheck = {
},
};
var components = [BrowserGlue, ContentPermissionPrompt, AboutNewTabService];
var components = [BrowserGlue, ContentPermissionPrompt];
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);

View File

@ -1,32 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsISupports.idl"
/**
* Allows to override about:newtab to point to a different location
* than the one specified within AboutRedirector.cpp
*/
[scriptable, uuid(6c66f022-beb1-46ea-8af6-c6c6dd937ea9)]
interface nsIAboutNewTabService : nsISupports
{
/**
* Returns "about:newtab" if not overridden, otherwise
* a string represenation of the new URL.
*/
attribute ACString newTabURL;
/**
* Returns true if the default of "about:newtab" got
* overridden.
*/
readonly attribute bool overridden;
/**
* Resets "about:newtab" to the default and also resets the
* overridden attribute to false.
*/
void resetNewTabURL();
};

View File

@ -387,6 +387,9 @@
@RESPATH@/browser/components/webideComponents.manifest
@RESPATH@/browser/components/Experiments.manifest
@RESPATH@/browser/components/ExperimentsService.js
@RESPATH@/browser/components/browser-newtab.xpt
@RESPATH@/browser/components/aboutNewTabService.js
@RESPATH@/browser/components/NewTabComponents.manifest
@RESPATH@/components/Downloads.manifest
@RESPATH@/components/DownloadLegacy.js
@RESPATH@/components/BrowserPageThumbs.manifest

View File

@ -116,6 +116,7 @@
@BINPATH@/components/browsercompsbase.xpt
@BINPATH@/components/browser-element.xpt
@BINPATH@/components/browser-feeds.xpt
@BINPATH@/components/browser-newtab.xpt
@BINPATH@/components/caps.xpt
@BINPATH@/components/chardet.xpt
@BINPATH@/components/chrome.xpt

View File

@ -526,7 +526,7 @@ Tart.prototype = {
],
newtabNoPreload: [
function(){aboutNewTabService.newTabURL = "about:newtab";
function(){aboutNewTabService.resetNewTabURL();
Services.prefs.setCharPref("layout.css.devPixelsPerPx", "-1");
Services.prefs.setBoolPref("browser.newtab.preload", false);
next();
@ -538,7 +538,7 @@ Tart.prototype = {
],
newtabYesPreload: [
function(){aboutNewTabService.newTabURL = "about:newtab";
function(){aboutNewTabService.resetNewTabURL();
Services.prefs.setCharPref("layout.css.devPixelsPerPx", "-1");
Services.prefs.setBoolPref("browser.newtab.preload", true);
next();