Backed out changeset 5f6375754b86 (bug 1210940) for xpcshell and m-e10s(bc4) bustage CLOSED TREE

This commit is contained in:
Wes Kocher 2015-10-09 16:42:50 -07:00
parent 189d3ff9bd
commit c3d6bae0b8
18 changed files with 16 additions and 4096 deletions

View File

@ -13,7 +13,6 @@ DIRS += [
'feeds',
'loop',
'migration',
'newtab',
'places',
'pocket',
'preferences',

View File

@ -1,233 +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/. */
/* globals Services, XPCOMUtils, RemotePages, RemoteNewTabLocation, RemoteNewTabUtils, Task */
/* globals BackgroundPageThumbs, PageThumbs, RemoteDirectoryLinksProvider */
/* exported RemoteAboutNewTab */
"use strict";
let Ci = Components.interfaces;
let Cu = Components.utils;
const XHTML_NAMESPACE = "http://www.w3.org/1999/xhtml";
this.EXPORTED_SYMBOLS = ["RemoteAboutNewTab"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.importGlobalProperties(["URL"]);
XPCOMUtils.defineLazyModuleGetter(this, "RemotePages",
"resource://gre/modules/RemotePageManager.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabUtils",
"resource:///modules/RemoteNewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BackgroundPageThumbs",
"resource://gre/modules/BackgroundPageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteDirectoryLinksProvider",
"resource:///modules/RemoteDirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
"resource:///modules/RemoteNewTabLocation.jsm");
let RemoteAboutNewTab = {
pageListener: null,
/**
* Initialize the RemotePageManager and add all message listeners for this page
*/
init: function() {
this.pageListener = new RemotePages("about:remote-newtab");
this.pageListener.addMessageListener("NewTab:InitializeGrid", this.initializeGrid.bind(this));
this.pageListener.addMessageListener("NewTab:UpdateGrid", this.updateGrid.bind(this));
this.pageListener.addMessageListener("NewTab:CaptureBackgroundPageThumbs",
this.captureBackgroundPageThumb.bind(this));
this.pageListener.addMessageListener("NewTab:PageThumbs", this.createPageThumb.bind(this));
this.pageListener.addMessageListener("NewTabFrame:GetInit", this.initContentFrame.bind(this));
this._addObservers();
},
/**
* Initializes the grid for the first time when the page loads.
* Fetch all the links and send them down to the child to populate
* the grid with.
*
* @param {Object} message
* A RemotePageManager message.
*/
initializeGrid: function(message) {
RemoteNewTabUtils.links.populateCache(() => {
message.target.sendAsyncMessage("NewTab:InitializeLinks", {
links: RemoteNewTabUtils.links.getLinks(),
enhancedLinks: this.getEnhancedLinks(),
});
});
},
/**
* Inits the content iframe with the newtab location
*/
initContentFrame: function(message) {
message.target.sendAsyncMessage("NewTabFrame:Init", {
href: RemoteNewTabLocation.href,
origin: RemoteNewTabLocation.origin
});
},
/**
* Updates the grid by getting a new set of links.
*
* @param {Object} message
* A RemotePageManager message.
*/
updateGrid: function(message) {
message.target.sendAsyncMessage("NewTab:UpdateLinks", {
links: RemoteNewTabUtils.links.getLinks(),
enhancedLinks: this.getEnhancedLinks(),
});
},
/**
* Captures the site's thumbnail in the background, then attemps to show the thumbnail.
*
* @param {Object} message
* A RemotePageManager message with the following data:
*
* link (Object):
* A link object that contains:
*
* baseDomain (String)
* blockState (Boolean)
* frecency (Integer)
* lastVisiteDate (Integer)
* pinState (Boolean)
* title (String)
* type (String)
* url (String)
*/
captureBackgroundPageThumb: Task.async(function* (message) {
try {
yield BackgroundPageThumbs.captureIfMissing(message.data.link.url);
this.createPageThumb(message);
} catch (err) {
Cu.reportError("error: " + err);
}
}),
/**
* Creates the thumbnail to display for each site based on the unique URL
* of the site and it's type (regular or enhanced). If the thumbnail is of
* type "regular", we create a blob and send that down to the child. If the
* thumbnail is of type "enhanced", get the file path for the URL and create
* and enhanced URI that will be sent down to the child.
*
* @param {Object} message
* A RemotePageManager message with the following data:
*
* link (Object):
* A link object that contains:
*
* baseDomain (String)
* blockState (Boolean)
* frecency (Integer)
* lastVisiteDate (Integer)
* pinState (Boolean)
* title (String)
* type (String)
* url (String)
*/
createPageThumb: function(message) {
let imgSrc = PageThumbs.getThumbnailURL(message.data.link.url);
let doc = Services.appShell.hiddenDOMWindow.document;
let img = doc.createElementNS(XHTML_NAMESPACE, "img");
let canvas = doc.createElementNS(XHTML_NAMESPACE, "canvas");
let enhanced = Services.prefs.getBoolPref("browser.newtabpage.enhanced");
img.onload = function(e) { // jshint ignore:line
canvas.width = img.naturalWidth;
canvas.height = img.naturalHeight;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, this.naturalWidth, this.naturalHeight);
canvas.toBlob(function(blob) {
let host = new URL(message.data.link.url).host;
RemoteAboutNewTab.pageListener.sendAsyncMessage("NewTab:RegularThumbnailURI", {
thumbPath: "/pagethumbs/" + host,
enhanced,
url: message.data.link.url,
blob,
});
});
};
img.src = imgSrc;
},
/**
* Get the set of enhanced links (if any) from the Directory Links Provider.
*/
getEnhancedLinks: function() {
let enhancedLinks = [];
for (let link of RemoteNewTabUtils.links.getLinks()) {
if (link) {
enhancedLinks.push(RemoteDirectoryLinksProvider.getEnhancedLink(link));
}
}
return enhancedLinks;
},
/**
* Listens for a preference change or session purge for all pages and sends
* a message to update the pages that are open. If a session purge occured,
* also clear the links cache and update the set of links to display, as they
* may have changed, then proceed with the page update.
*/
observe: function(aSubject, aTopic, aData) { // jshint ignore:line
let extraData;
let refreshPage = false;
if (aTopic === "browser:purge-session-history") {
RemoteNewTabUtils.links.resetCache();
RemoteNewTabUtils.links.populateCache(() => {
this.pageListener.sendAsyncMessage("NewTab:UpdateLinks", {
links: RemoteNewTabUtils.links.getLinks(),
enhancedLinks: this.getEnhancedLinks(),
});
});
}
if (extraData !== undefined || aTopic === "page-thumbnail:create") {
if (aTopic !== "page-thumbnail:create") {
// Change the topic for enhanced and enabled observers.
aTopic = aData;
}
this.pageListener.sendAsyncMessage("NewTab:Observe", {topic: aTopic, data: extraData});
}
},
/**
* Add all observers that about:newtab page must listen for.
*/
_addObservers: function() {
Services.obs.addObserver(this, "page-thumbnail:create", true);
Services.obs.addObserver(this, "browser:purge-session-history", true);
},
/**
* Remove all observers on the page.
*/
_removeObservers: function() {
Services.obs.removeObserver(this, "page-thumbnail:create");
Services.obs.removeObserver(this, "browser:purge-session-history");
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
Ci.nsISupportsWeakReference]),
uninit: function() {
this._removeObservers();
this.pageListener.destroy();
this.pageListener = null;
},
};

File diff suppressed because it is too large Load Diff

View File

@ -1,42 +0,0 @@
/* globals Services */
"use strict";
this.EXPORTED_SYMBOLS = ["RemoteNewTabLocation"];
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.importGlobalProperties(["URL"]);
// TODO: will get dynamically set in bug 1210478
const DEFAULT_PAGE_LOCATION = "https://newtab.cdn.mozilla.net/v0/nightly/en-US/index.html";
this.RemoteNewTabLocation = {
_url: new URL(DEFAULT_PAGE_LOCATION),
_overridden: false,
get href() {
return this._url.href;
},
get origin() {
return this._url.origin;
},
get overridden() {
return this._overridden;
},
override: function(newURL) {
this._url = new URL(newURL);
this._overridden = true;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
},
reset: function() {
this._url = new URL(DEFAULT_PAGE_LOCATION);
this._overridden = false;
Services.obs.notifyObservers(null, "remote-new-tab-location-changed",
this._url.href);
}
};

View File

@ -1,766 +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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["RemoteNewTabUtils"];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Task.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "BinarySearch",
"resource://gre/modules/BinarySearch.jsm");
XPCOMUtils.defineLazyGetter(this, "gPrincipal", function () {
let uri = Services.io.newURI("about:newtab", null, null);
return Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
});
// The maximum number of results PlacesProvider retrieves from history.
const HISTORY_RESULTS_LIMIT = 100;
// The maximum number of links Links.getLinks will return.
const LINKS_GET_LINKS_LIMIT = 100;
/**
* Singleton that serves as the default link provider for the grid. It queries
* the history to retrieve the most frequently visited sites.
*/
let PlacesProvider = {
/**
* A count of how many batch updates are under way (batches may be nested, so
* we keep a counter instead of a simple bool).
**/
_batchProcessingDepth: 0,
/**
* A flag that tracks whether onFrecencyChanged was notified while a batch
* operation was in progress, to tell us whether to take special action after
* the batch operation completes.
**/
_batchCalledFrecencyChanged: false,
/**
* Set this to change the maximum number of links the provider will provide.
*/
maxNumLinks: HISTORY_RESULTS_LIMIT,
/**
* Must be called before the provider is used.
*/
init: function PlacesProvider_init() {
PlacesUtils.history.addObserver(this, true);
},
/**
* Gets the current set of links delivered by this provider.
* @param aCallback The function that the array of links is passed to.
*/
getLinks: function PlacesProvider_getLinks(aCallback) {
let options = PlacesUtils.history.getNewQueryOptions();
options.maxResults = this.maxNumLinks;
// Sort by frecency, descending.
options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_FRECENCY_DESCENDING
let links = [];
let callback = {
handleResult: function (aResultSet) {
let row;
while ((row = aResultSet.getNextRow())) {
let url = row.getResultByIndex(1);
if (LinkChecker.checkLoadURI(url)) {
let title = row.getResultByIndex(2);
let frecency = row.getResultByIndex(12);
let lastVisitDate = row.getResultByIndex(5);
links.push({
url: url,
title: title,
frecency: frecency,
lastVisitDate: lastVisitDate,
type: "history",
});
}
}
},
handleError: function (aError) {
// Should we somehow handle this error?
aCallback([]);
},
handleCompletion: function (aReason) {
// The Places query breaks ties in frecency by place ID descending, but
// that's different from how Links.compareLinks breaks ties, because
// compareLinks doesn't have access to place IDs. It's very important
// that the initial list of links is sorted in the same order imposed by
// compareLinks, because Links uses compareLinks to perform binary
// searches on the list. So, ensure the list is so ordered.
let i = 1;
let outOfOrder = [];
while (i < links.length) {
if (Links.compareLinks(links[i - 1], links[i]) > 0)
outOfOrder.push(links.splice(i, 1)[0]);
else
i++;
}
for (let link of outOfOrder) {
i = BinarySearch.insertionIndexOf(Links.compareLinks, links, link);
links.splice(i, 0, link);
}
aCallback(links);
}
};
// Execute the query.
let query = PlacesUtils.history.getNewQuery();
let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase);
db.asyncExecuteLegacyQueries([query], 1, options, callback);
},
/**
* Registers an object that will be notified when the provider's links change.
* @param aObserver An object with the following optional properties:
* * onLinkChanged: A function that's called when a single link
* changes. It's passed the provider and the link object. Only the
* link's `url` property is guaranteed to be present. If its `title`
* property is present, then its title has changed, and the
* property's value is the new title. If any sort properties are
* present, then its position within the provider's list of links may
* have changed, and the properties' values are the new sort-related
* values. Note that this link may not necessarily have been present
* in the lists returned from any previous calls to getLinks.
* * onManyLinksChanged: A function that's called when many links
* change at once. It's passed the provider. You should call
* getLinks to get the provider's new list of links.
*/
addObserver: function PlacesProvider_addObserver(aObserver) {
this._observers.push(aObserver);
},
_observers: [],
/**
* Called by the history service.
*/
onBeginUpdateBatch: function() {
this._batchProcessingDepth += 1;
},
onEndUpdateBatch: function() {
this._batchProcessingDepth -= 1;
if (this._batchProcessingDepth == 0 && this._batchCalledFrecencyChanged) {
this.onManyFrecenciesChanged();
this._batchCalledFrecencyChanged = false;
}
},
onDeleteURI: function PlacesProvider_onDeleteURI(aURI, aGUID, aReason) {
// let observers remove sensetive data associated with deleted visit
this._callObservers("onDeleteURI", {
url: aURI.spec,
});
},
onClearHistory: function() {
this._callObservers("onClearHistory")
},
/**
* Called by the history service.
*/
onFrecencyChanged: function PlacesProvider_onFrecencyChanged(aURI, aNewFrecency, aGUID, aHidden, aLastVisitDate) {
// If something is doing a batch update of history entries we don't want
// to do lots of work for each record. So we just track the fact we need
// to call onManyFrecenciesChanged() once the batch is complete.
if (this._batchProcessingDepth > 0) {
this._batchCalledFrecencyChanged = true;
return;
}
// The implementation of the query in getLinks excludes hidden and
// unvisited pages, so it's important to exclude them here, too.
if (!aHidden && aLastVisitDate) {
this._callObservers("onLinkChanged", {
url: aURI.spec,
frecency: aNewFrecency,
lastVisitDate: aLastVisitDate,
type: "history",
});
}
},
/**
* Called by the history service.
*/
onManyFrecenciesChanged: function PlacesProvider_onManyFrecenciesChanged() {
this._callObservers("onManyLinksChanged");
},
/**
* Called by the history service.
*/
onTitleChanged: function PlacesProvider_onTitleChanged(aURI, aNewTitle, aGUID) {
this._callObservers("onLinkChanged", {
url: aURI.spec,
title: aNewTitle
});
},
_callObservers: function PlacesProvider__callObservers(aMethodName, aArg) {
for (let obs of this._observers) {
if (obs[aMethodName]) {
try {
obs[aMethodName](this, aArg);
} catch (err) {
Cu.reportError(err);
}
}
}
},
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavHistoryObserver,
Ci.nsISupportsWeakReference]),
};
/**
* Singleton that provides access to all links contained in the grid (including
* the ones that don't fit on the grid). A link is a plain object that looks
* like this:
*
* {
* url: "http://www.mozilla.org/",
* title: "Mozilla",
* frecency: 1337,
* lastVisitDate: 1394678824766431,
* }
*/
let Links = {
/**
* The maximum number of links returned by getLinks.
*/
maxNumLinks: LINKS_GET_LINKS_LIMIT,
/**
* A mapping from each provider to an object { sortedLinks, siteMap, linkMap }.
* sortedLinks is the cached, sorted array of links for the provider.
* siteMap is a mapping from base domains to URL count associated with the domain.
* siteMap is used to look up a user's top sites that can be targeted
* with a suggested tile.
* linkMap is a Map from link URLs to link objects.
*/
_providers: new Map(),
/**
* The properties of link objects used to sort them.
*/
_sortProperties: [
"frecency",
"lastVisitDate",
"url",
],
/**
* List of callbacks waiting for the cache to be populated.
*/
_populateCallbacks: [],
/**
* A list of objects that are observing links updates.
*/
_observers: [],
/**
* Registers an object that will be notified when links updates.
*/
addObserver: function (aObserver) {
this._observers.push(aObserver);
},
/**
* Adds a link provider.
* @param aProvider The link provider.
*/
addProvider: function Links_addProvider(aProvider) {
this._providers.set(aProvider, null);
aProvider.addObserver(this);
},
/**
* Removes a link provider.
* @param aProvider The link provider.
*/
removeProvider: function Links_removeProvider(aProvider) {
if (!this._providers.delete(aProvider))
throw new Error("Unknown provider");
},
/**
* Populates the cache with fresh links from the providers.
* @param aCallback The callback to call when finished (optional).
* @param aForce When true, populates the cache even when it's already filled.
*/
populateCache: function Links_populateCache(aCallback, aForce) {
let callbacks = this._populateCallbacks;
// Enqueue the current callback.
callbacks.push(aCallback);
// There was a callback waiting already, thus the cache has not yet been
// populated.
if (callbacks.length > 1)
return;
function executeCallbacks() {
while (callbacks.length) {
let callback = callbacks.shift();
if (callback) {
try {
callback();
} catch (e) {
// We want to proceed even if a callback fails.
}
}
}
}
let numProvidersRemaining = this._providers.size;
for (let [provider, links] of this._providers) {
this._populateProviderCache(provider, () => {
if (--numProvidersRemaining == 0)
executeCallbacks();
}, aForce);
}
},
/**
* Gets the current set of links contained in the grid.
* @return The links in the grid.
*/
getLinks: function Links_getLinks() {
let links = this._getMergedProviderLinks();
let sites = new Set();
// Filter duplicate base domains.
links = links.filter(function (link) {
let site = RemoteNewTabUtils.extractSite(link.url);
link.baseDomain = site;
if (site == null || sites.has(site))
return false;
sites.add(site);
return true;
});
return links;
},
/**
* Resets the links cache.
*/
resetCache: function Links_resetCache() {
for (let provider of this._providers.keys()) {
this._providers.set(provider, null);
}
},
/**
* Compares two links.
* @param aLink1 The first link.
* @param aLink2 The second link.
* @return A negative number if aLink1 is ordered before aLink2, zero if
* aLink1 and aLink2 have the same ordering, or a positive number if
* aLink1 is ordered after aLink2.
*
* @note compareLinks's this object is bound to Links below.
*/
compareLinks: function Links_compareLinks(aLink1, aLink2) {
for (let prop of this._sortProperties) {
if (!(prop in aLink1) || !(prop in aLink2))
throw new Error("Comparable link missing required property: " + prop);
}
return aLink2.frecency - aLink1.frecency ||
aLink2.lastVisitDate - aLink1.lastVisitDate ||
aLink1.url.localeCompare(aLink2.url);
},
_incrementSiteMap: function(map, link) {
let site = RemoteNewTabUtils.extractSite(link.url);
map.set(site, (map.get(site) || 0) + 1);
},
_decrementSiteMap: function(map, link) {
let site = RemoteNewTabUtils.extractSite(link.url);
let previousURLCount = map.get(site);
if (previousURLCount === 1) {
map.delete(site);
} else {
map.set(site, previousURLCount - 1);
}
},
/**
* Update the siteMap cache based on the link given and whether we need
* to increment or decrement it. We do this by iterating over all stored providers
* to find which provider this link already exists in. For providers that
* have this link, we will adjust siteMap for them accordingly.
*
* @param aLink The link that will affect siteMap
* @param increment A boolean for whether to increment or decrement siteMap
*/
_adjustSiteMapAndNotify: function(aLink, increment=true) {
for (let [provider, cache] of this._providers) {
// We only update siteMap if aLink is already stored in linkMap.
if (cache.linkMap.get(aLink.url)) {
if (increment) {
this._incrementSiteMap(cache.siteMap, aLink);
continue;
}
this._decrementSiteMap(cache.siteMap, aLink);
}
}
this._callObservers("onLinkChanged", aLink);
},
populateProviderCache: function(provider, callback) {
if (!this._providers.has(provider)) {
throw new Error("Can only populate provider cache for existing provider.");
}
return this._populateProviderCache(provider, callback, false);
},
/**
* Calls getLinks on the given provider and populates our cache for it.
* @param aProvider The provider whose cache will be populated.
* @param aCallback The callback to call when finished.
* @param aForce When true, populates the provider's cache even when it's
* already filled.
*/
_populateProviderCache: function (aProvider, aCallback, aForce) {
let cache = this._providers.get(aProvider);
let createCache = !cache;
if (createCache) {
cache = {
// Start with a resolved promise.
populatePromise: new Promise(resolve => resolve()),
};
this._providers.set(aProvider, cache);
}
// Chain the populatePromise so that calls are effectively queued.
cache.populatePromise = cache.populatePromise.then(() => {
return new Promise(resolve => {
if (!createCache && !aForce) {
aCallback();
resolve();
return;
}
aProvider.getLinks(links => {
// Filter out null and undefined links so we don't have to deal with
// them in getLinks when merging links from providers.
links = links.filter((link) => !!link);
cache.sortedLinks = links;
cache.siteMap = links.reduce((map, link) => {
this._incrementSiteMap(map, link);
return map;
}, new Map());
cache.linkMap = links.reduce((map, link) => {
map.set(link.url, link);
return map;
}, new Map());
aCallback();
resolve();
});
});
});
},
/**
* Merges the cached lists of links from all providers whose lists are cached.
* @return The merged list.
*/
_getMergedProviderLinks: function Links__getMergedProviderLinks() {
// Build a list containing a copy of each provider's sortedLinks list.
let linkLists = [];
for (let provider of this._providers.keys()) {
let links = this._providers.get(provider);
if (links && links.sortedLinks) {
linkLists.push(links.sortedLinks.slice());
}
}
function getNextLink() {
let minLinks = null;
for (let links of linkLists) {
if (links.length &&
(!minLinks || Links.compareLinks(links[0], minLinks[0]) < 0))
minLinks = links;
}
return minLinks ? minLinks.shift() : null;
}
let finalLinks = [];
for (let nextLink = getNextLink();
nextLink && finalLinks.length < this.maxNumLinks;
nextLink = getNextLink()) {
finalLinks.push(nextLink);
}
return finalLinks;
},
/**
* Called by a provider to notify us when a single link changes.
* @param aProvider The provider whose link changed.
* @param aLink The link that changed. If the link is new, it must have all
* of the _sortProperties. Otherwise, it may have as few or as
* many as is convenient.
* @param aIndex The current index of the changed link in the sortedLinks
cache in _providers. Defaults to -1 if the provider doesn't know the index
* @param aDeleted Boolean indicating if the provider has deleted the link.
*/
onLinkChanged: function Links_onLinkChanged(aProvider, aLink, aIndex=-1, aDeleted=false) {
if (!("url" in aLink))
throw new Error("Changed links must have a url property");
let links = this._providers.get(aProvider);
if (!links)
// This is not an error, it just means that between the time the provider
// was added and the future time we call getLinks on it, it notified us of
// a change.
return;
let { sortedLinks, siteMap, linkMap } = links;
let existingLink = linkMap.get(aLink.url);
let insertionLink = null;
if (existingLink) {
// Update our copy's position in O(lg n) by first removing it from its
// list. It's important to do this before modifying its properties.
if (this._sortProperties.some(prop => prop in aLink)) {
let idx = aIndex;
if (idx < 0) {
idx = this._indexOf(sortedLinks, existingLink);
} else if (this.compareLinks(aLink, sortedLinks[idx]) != 0) {
throw new Error("aLink should be the same as sortedLinks[idx]");
}
if (idx < 0) {
throw new Error("Link should be in _sortedLinks if in _linkMap");
}
sortedLinks.splice(idx, 1);
if (aDeleted) {
linkMap.delete(existingLink.url);
this._decrementSiteMap(siteMap, existingLink);
} else {
// Update our copy's properties.
Object.assign(existingLink, aLink);
// Finally, reinsert our copy below.
insertionLink = existingLink;
}
}
// Update our copy's title in O(1).
if ("title" in aLink && aLink.title != existingLink.title) {
existingLink.title = aLink.title;
}
}
else if (this._sortProperties.every(prop => prop in aLink)) {
// Before doing the O(lg n) insertion below, do an O(1) check for the
// common case where the new link is too low-ranked to be in the list.
if (sortedLinks.length && sortedLinks.length == aProvider.maxNumLinks) {
let lastLink = sortedLinks[sortedLinks.length - 1];
if (this.compareLinks(lastLink, aLink) < 0) {
return;
}
}
// Copy the link object so that changes later made to it by the caller
// don't affect our copy.
insertionLink = {};
for (let prop in aLink) {
insertionLink[prop] = aLink[prop];
}
linkMap.set(aLink.url, insertionLink);
this._incrementSiteMap(siteMap, aLink);
}
if (insertionLink) {
let idx = this._insertionIndexOf(sortedLinks, insertionLink);
sortedLinks.splice(idx, 0, insertionLink);
if (sortedLinks.length > aProvider.maxNumLinks) {
let lastLink = sortedLinks.pop();
linkMap.delete(lastLink.url);
this._decrementSiteMap(siteMap, lastLink);
}
}
},
/**
* Called by a provider to notify us when many links change.
*/
onManyLinksChanged: function Links_onManyLinksChanged(aProvider) {
this._populateProviderCache(aProvider, () => {}, true);
},
_indexOf: function Links__indexOf(aArray, aLink) {
return this._binsearch(aArray, aLink, "indexOf");
},
_insertionIndexOf: function Links__insertionIndexOf(aArray, aLink) {
return this._binsearch(aArray, aLink, "insertionIndexOf");
},
_binsearch: function Links__binsearch(aArray, aLink, aMethod) {
return BinarySearch[aMethod](this.compareLinks, aArray, aLink);
},
_callObservers(methodName, ...args) {
for (let obs of this._observers) {
if (typeof(obs[methodName]) == "function") {
try {
obs[methodName](this, ...args);
} catch (err) {
Cu.reportError(err);
}
}
}
},
};
Links.compareLinks = Links.compareLinks.bind(Links);
/**
* Singleton that checks if a given link should be displayed on about:newtab
* or if we should rather not do it for security reasons. URIs that inherit
* their caller's principal will be filtered.
*/
let LinkChecker = {
_cache: {},
get flags() {
return Ci.nsIScriptSecurityManager.DISALLOW_INHERIT_PRINCIPAL |
Ci.nsIScriptSecurityManager.DONT_REPORT_ERRORS;
},
checkLoadURI: function LinkChecker_checkLoadURI(aURI) {
if (!(aURI in this._cache))
this._cache[aURI] = this._doCheckLoadURI(aURI);
return this._cache[aURI];
},
_doCheckLoadURI: function Links_doCheckLoadURI(aURI) {
try {
Services.scriptSecurityManager.
checkLoadURIStrWithPrincipal(gPrincipal, aURI, this.flags);
return true;
} catch (e) {
// We got a weird URI or one that would inherit the caller's principal.
return false;
}
}
};
let ExpirationFilter = {
init: function ExpirationFilter_init() {
PageThumbs.addExpirationFilter(this);
},
filterForThumbnailExpiration:
function ExpirationFilter_filterForThumbnailExpiration(aCallback) {
Links.populateCache(function () {
let urls = [];
// Add all URLs to the list that we want to keep thumbnails for.
for (let link of Links.getLinks().slice(0, 25)) {
if (link && link.url)
urls.push(link.url);
}
aCallback(urls);
});
}
};
/**
* Singleton that provides the public API of this JSM.
*/
this.RemoteNewTabUtils = {
_initialized: false,
/**
* Extract a "site" from a url in a way that multiple urls of a "site" returns
* the same "site."
* @param aUrl Url spec string
* @return The "site" string or null
*/
extractSite: function Links_extractSite(url) {
let host;
try {
// Note that nsIURI.asciiHost throws NS_ERROR_FAILURE for some types of
// URIs, including jar and moz-icon URIs.
host = Services.io.newURI(url, null, null).asciiHost;
} catch (ex) {
return null;
}
// Strip off common subdomains of the same site (e.g., www, load balancer)
return host.replace(/^(m|mobile|www\d*)\./, "");
},
init: function RemoteNewTabUtils_init() {
if (this.initWithoutProviders()) {
PlacesProvider.init();
Links.addProvider(PlacesProvider);
}
},
initWithoutProviders: function RemoteNewTabUtils_initWithoutProviders() {
if (!this._initialized) {
this._initialized = true;
ExpirationFilter.init();
return true;
}
return false;
},
getProviderLinks: function(aProvider) {
let cache = Links._providers.get(aProvider);
if (cache && cache.sortedLinks) {
return cache.sortedLinks;
}
return [];
},
isTopSiteGivenProvider: function(aSite, aProvider) {
let cache = Links._providers.get(aProvider);
if (cache && cache.siteMap) {
return cache.siteMap.has(aSite);
}
return false;
},
isTopPlacesSite: function(aSite) {
return this.isTopSiteGivenProvider(aSite, PlacesProvider);
},
links: Links,
linkChecker: LinkChecker,
placesProvider: PlacesProvider
};

View File

@ -1,19 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']
XPCSHELL_TESTS_MANIFESTS += [
'tests/xpcshell/xpcshell.ini',
]
EXTRA_JS_MODULES += [
'NewTabURL.jsm',
'RemoteAboutNewTab.jsm',
'RemoteDirectoryLinksProvider.jsm',
'RemoteNewTabLocation.jsm',
'RemoteNewTabUtils.jsm',
]

View File

@ -1,5 +0,0 @@
[DEFAULT]
support-files =
dummy_page.html
[browser_remotenewtab_pageloads.js]

View File

@ -1,47 +0,0 @@
/* globals XPCOMUtils, Task, RemoteAboutNewTab, RemoteNewTabLocation, ok */
"use strict";
let Cu = Components.utils;
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabLocation",
"resource:///modules/RemoteNewTabLocation.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteAboutNewTab",
"resource:///modules/RemoteAboutNewTab.jsm");
const TEST_URL = "https://example.com/browser/browser/components/newtab/tests/browser/dummy_page.html";
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);
let tabOptions = {
gBrowser,
url: "about:remote-newtab"
};
function* testLoader() {
yield Promise.all(tests);
}
yield BrowserTestUtils.withNewTab(
tabOptions,
browser => testLoader // jshint ignore:line
);
});

View File

@ -1,22 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</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,40 +0,0 @@
/* globals ok, equal, RemoteNewTabLocation, Services */
"use strict";
Components.utils.import("resource:///modules/RemoteNewTabLocation.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
Components.utils.importGlobalProperties(["URL"]);
add_task(function* () {
var notificationPromise;
let defaultHref = RemoteNewTabLocation.href;
ok(RemoteNewTabLocation.href, "Default location has an href");
ok(RemoteNewTabLocation.origin, "Default location has an origin");
ok(!RemoteNewTabLocation.overridden, "Default location is not overridden");
let testURL = new URL("https://example.com/");
notificationPromise = changeNotificationPromise(testURL.href);
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 = changeNotificationPromise(defaultHref);
RemoteNewTabLocation.reset();
yield notificationPromise;
ok(!RemoteNewTabLocation.overridden, "Newtab URL should not be overridden");
equal(RemoteNewTabLocation.href, defaultHref, "Remote href should be reset");
});
function changeNotificationPromise(aNewURL) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint ignore:line
Services.obs.removeObserver(observer, aTopic);
equal(aData, aNewURL, "remote-new-tab-location-changed data should be new URL.");
resolve();
}, "remote-new-tab-location-changed", false);
});
}

View File

@ -1,375 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// See also browser/base/content/test/newtab/.
const { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components;
Cu.import("resource:///modules/RemoteNewTabUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function run_test() {
run_next_test();
}
add_task(function validCacheMidPopulation() {
let expectedLinks = makeLinks(0, 3, 1);
let provider = new TestProvider(done => done(expectedLinks));
provider.maxNumLinks = expectedLinks.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
let promise = new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
// isTopSiteGivenProvider() and getProviderLinks() should still return results
// even when cache is empty or being populated.
do_check_false(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider));
do_check_links(RemoteNewTabUtils.getProviderLinks(provider), []);
yield promise;
// Once the cache is populated, we get the expected results
do_check_true(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider));
do_check_links(RemoteNewTabUtils.getProviderLinks(provider), expectedLinks);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function notifyLinkDelete() {
let expectedLinks = makeLinks(0, 3, 1);
let provider = new TestProvider(done => done(expectedLinks));
provider.maxNumLinks = expectedLinks.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Remove a link.
let removedLink = expectedLinks[2];
provider.notifyLinkChanged(removedLink, 2, true);
let links = RemoteNewTabUtils.links._providers.get(provider);
// Check that sortedLinks is correctly updated.
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks.slice(0, 2));
// Check that linkMap is accurately updated.
do_check_eq(links.linkMap.size, 2);
do_check_true(links.linkMap.get(expectedLinks[0].url));
do_check_true(links.linkMap.get(expectedLinks[1].url));
do_check_false(links.linkMap.get(removedLink.url));
// Check that siteMap is correctly updated.
do_check_eq(links.siteMap.size, 2);
do_check_true(links.siteMap.has(RemoteNewTabUtils.extractSite(expectedLinks[0].url)));
do_check_true(links.siteMap.has(RemoteNewTabUtils.extractSite(expectedLinks[1].url)));
do_check_false(links.siteMap.has(RemoteNewTabUtils.extractSite(removedLink.url)));
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function populatePromise() {
let count = 0;
let expectedLinks = makeLinks(0, 10, 2);
let getLinksFcn = Task.async(function* (callback) {
//Should not be calling getLinksFcn twice
count++;
do_check_eq(count, 1);
yield Promise.resolve();
callback(expectedLinks);
});
let provider = new TestProvider(getLinksFcn);
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
RemoteNewTabUtils.links.populateProviderCache(provider, () => {});
RemoteNewTabUtils.links.populateProviderCache(provider, () => {
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
RemoteNewTabUtils.links.removeProvider(provider);
});
});
add_task(function isTopSiteGivenProvider() {
let expectedLinks = makeLinks(0, 10, 2);
// The lowest 2 frecencies have the same base domain.
expectedLinks[expectedLinks.length - 2].url = expectedLinks[expectedLinks.length - 1].url + "Test";
let provider = new TestProvider(done => done(expectedLinks));
provider.maxNumLinks = expectedLinks.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example1.com", provider), false);
// Push out frecency 2 because the maxNumLinks is reached when adding frecency 3
let newLink = makeLink(3);
provider.notifyLinkChanged(newLink);
// There is still a frecent url with example2 domain, so it's still frecent.
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example3.com", provider), true);
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), true);
// Push out frecency 3
newLink = makeLink(5);
provider.notifyLinkChanged(newLink);
// Push out frecency 4
newLink = makeLink(9);
provider.notifyLinkChanged(newLink);
// Our count reached 0 for the example2.com domain so it's no longer a frecent site.
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example5.com", provider), true);
do_check_eq(RemoteNewTabUtils.isTopSiteGivenProvider("example2.com", provider), false);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function multipleProviders() {
// Make each provider generate RemoteNewTabUtils.links.maxNumLinks links to check
// that no more than maxNumLinks are actually returned in the merged list.
let evenLinks = makeLinks(0, 2 * RemoteNewTabUtils.links.maxNumLinks, 2);
let evenProvider = new TestProvider(done => done(evenLinks));
let oddLinks = makeLinks(0, 2 * RemoteNewTabUtils.links.maxNumLinks - 1, 2);
let oddProvider = new TestProvider(done => done(oddLinks));
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(evenProvider);
RemoteNewTabUtils.links.addProvider(oddProvider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
let links = RemoteNewTabUtils.links.getLinks();
let expectedLinks = makeLinks(RemoteNewTabUtils.links.maxNumLinks,
2 * RemoteNewTabUtils.links.maxNumLinks,
1);
do_check_eq(links.length, RemoteNewTabUtils.links.maxNumLinks);
do_check_links(links, expectedLinks);
RemoteNewTabUtils.links.removeProvider(evenProvider);
RemoteNewTabUtils.links.removeProvider(oddProvider);
});
add_task(function changeLinks() {
let expectedLinks = makeLinks(0, 20, 2);
let provider = new TestProvider(done => done(expectedLinks));
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a new link.
let newLink = makeLink(19);
expectedLinks.splice(1, 0, newLink);
provider.notifyLinkChanged(newLink);
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a link that's changed sort criteria.
newLink.frecency = 17;
expectedLinks.splice(1, 1);
expectedLinks.splice(2, 0, newLink);
provider.notifyLinkChanged({
url: newLink.url,
frecency: 17,
});
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a link that's changed title.
newLink.title = "My frecency is now 17";
provider.notifyLinkChanged({
url: newLink.url,
title: newLink.title,
});
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of a new link again, but this time make it overflow maxNumLinks.
provider.maxNumLinks = expectedLinks.length;
newLink = makeLink(21);
expectedLinks.unshift(newLink);
expectedLinks.pop();
do_check_eq(expectedLinks.length, provider.maxNumLinks); // Sanity check.
provider.notifyLinkChanged(newLink);
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
// Notify of many links changed.
expectedLinks = makeLinks(0, 3, 1);
provider.notifyManyLinksChanged();
// Since _populateProviderCache() is async, we must wait until the provider's
// populate promise has been resolved.
yield RemoteNewTabUtils.links._providers.get(provider).populatePromise;
// RemoteNewTabUtils.links will now repopulate its cache
do_check_links(RemoteNewTabUtils.links.getLinks(), expectedLinks);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function oneProviderAlreadyCached() {
let links1 = makeLinks(0, 10, 1);
let provider1 = new TestProvider(done => done(links1));
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider1);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), links1);
let links2 = makeLinks(10, 20, 1);
let provider2 = new TestProvider(done => done(links2));
RemoteNewTabUtils.links.addProvider(provider2);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), links2.concat(links1));
RemoteNewTabUtils.links.removeProvider(provider1);
RemoteNewTabUtils.links.removeProvider(provider2);
});
add_task(function newLowRankedLink() {
// Init a provider with 10 links and make its maximum number also 10.
let links = makeLinks(0, 10, 1);
let provider = new TestProvider(done => done(links));
provider.maxNumLinks = links.length;
RemoteNewTabUtils.initWithoutProviders();
RemoteNewTabUtils.links.addProvider(provider);
yield new Promise(resolve => RemoteNewTabUtils.links.populateCache(resolve));
do_check_links(RemoteNewTabUtils.links.getLinks(), links);
// Notify of a new link that's low-ranked enough not to make the list.
let newLink = makeLink(0);
provider.notifyLinkChanged(newLink);
do_check_links(RemoteNewTabUtils.links.getLinks(), links);
// Notify about the new link's title change.
provider.notifyLinkChanged({
url: newLink.url,
title: "a new title",
});
do_check_links(RemoteNewTabUtils.links.getLinks(), links);
RemoteNewTabUtils.links.removeProvider(provider);
});
add_task(function extractSite() {
// All these should extract to the same site
[ "mozilla.org",
"m.mozilla.org",
"mobile.mozilla.org",
"www.mozilla.org",
"www3.mozilla.org",
].forEach(host => {
let url = "http://" + host;
do_check_eq(RemoteNewTabUtils.extractSite(url), "mozilla.org", "extracted same " + host);
});
// All these should extract to the same subdomain
[ "bugzilla.mozilla.org",
"www.bugzilla.mozilla.org",
].forEach(host => {
let url = "http://" + host;
do_check_eq(RemoteNewTabUtils.extractSite(url), "bugzilla.mozilla.org", "extracted eTLD+2 " + host);
});
// All these should not extract to the same site
[ "bugzilla.mozilla.org",
"bug123.bugzilla.mozilla.org",
"too.many.levels.bugzilla.mozilla.org",
"m2.mozilla.org",
"mobile30.mozilla.org",
"ww.mozilla.org",
"ww2.mozilla.org",
"wwwww.mozilla.org",
"wwwww50.mozilla.org",
"wwws.mozilla.org",
"secure.mozilla.org",
"secure10.mozilla.org",
"many.levels.deep.mozilla.org",
"just.check.in",
"192.168.0.1",
"localhost",
].forEach(host => {
let url = "http://" + host;
do_check_neq(RemoteNewTabUtils.extractSite(url), "mozilla.org", "extracted diff " + host);
});
// All these should not extract to the same site
[ "about:blank",
"file:///Users/user/file",
"chrome://browser/something",
"ftp://ftp.mozilla.org/",
].forEach(url => {
do_check_neq(RemoteNewTabUtils.extractSite(url), "mozilla.org", "extracted diff url " + url);
});
});
function TestProvider(getLinksFn) {
this.getLinks = getLinksFn;
this._observers = new Set();
}
TestProvider.prototype = {
addObserver: function (observer) {
this._observers.add(observer);
},
notifyLinkChanged: function (link, index=-1, deleted=false) {
this._notifyObservers("onLinkChanged", link, index, deleted);
},
notifyManyLinksChanged: function () {
this._notifyObservers("onManyLinksChanged");
},
_notifyObservers: function () {
let observerMethodName = arguments[0];
let args = Array.prototype.slice.call(arguments, 1);
args.unshift(this);
for (let obs of this._observers) {
if (obs[observerMethodName])
obs[observerMethodName].apply(RemoteNewTabUtils.links, args);
}
},
};
function do_check_links(actualLinks, expectedLinks) {
do_check_true(Array.isArray(actualLinks));
do_check_eq(actualLinks.length, expectedLinks.length);
for (let i = 0; i < expectedLinks.length; i++) {
let expected = expectedLinks[i];
let actual = actualLinks[i];
do_check_eq(actual.url, expected.url);
do_check_eq(actual.title, expected.title);
do_check_eq(actual.frecency, expected.frecency);
do_check_eq(actual.lastVisitDate, expected.lastVisitDate);
}
}
function makeLinks(frecRangeStart, frecRangeEnd, step) {
let links = [];
// Remember, links are ordered by frecency descending.
for (let i = frecRangeEnd; i > frecRangeStart; i -= step) {
links.push(makeLink(i));
}
return links;
}
function makeLink(frecency) {
return {
url: "http://example" + frecency + ".com/",
title: "My frecency is " + frecency,
frecency: frecency,
lastVisitDate: 0,
};
}

View File

@ -1,10 +0,0 @@
[DEFAULT]
head =
tail =
firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_NewTabURL.js]
[test_RemoteDirectoryLinksProvider.js]
[test_RemoteNewTabLocation.js]
[test_RemoteNewTabUtils.js]

View File

@ -20,21 +20,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "AboutHome",
XPCOMUtils.defineLazyModuleGetter(this, "AboutNewTab",
"resource:///modules/AboutNewTab.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
"resource:///modules/DirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteAboutNewTab",
"resource:///modules/RemoteAboutNewTab.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteDirectoryLinksProvider",
"resource:///modules/RemoteDirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RemoteNewTabUtils",
"resource:///modules/RemoteNewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "UITour",
"resource:///modules/UITour.jsm");
@ -44,6 +29,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "AddonManager",
XPCOMUtils.defineLazyModuleGetter(this, "ContentClick",
"resource:///modules/ContentClick.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "DirectoryLinksProvider",
"resource:///modules/DirectoryLinksProvider.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
"resource://gre/modules/NetUtil.jsm");
@ -65,6 +53,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebappManager",
XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs",
"resource://gre/modules/PageThumbs.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils",
"resource://gre/modules/NewTabUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizationTabPreloader",
"resource:///modules/CustomizationTabPreloader.jsm");
@ -600,7 +591,7 @@ BrowserGlue.prototype = {
}
},
// initialization (called on application startup)
// initialization (called on application startup)
_init: function BG__init() {
let os = Services.obs;
os.addObserver(this, "notifications-open-settings", false);
@ -820,7 +811,7 @@ BrowserGlue.prototype = {
this._sanitizer.onStartup();
// check if we're in safe mode
if (Services.appinfo.inSafeMode) {
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
Services.ww.openWindow(null, "chrome://browser/content/safeMode.xul",
"_blank", "chrome,centerscreen,modal,resizable=no", null);
}
@ -835,6 +826,9 @@ BrowserGlue.prototype = {
WebappManager.init();
PageThumbs.init();
NewTabUtils.init();
DirectoryLinksProvider.init();
NewTabUtils.links.addProvider(DirectoryLinksProvider);
#ifdef NIGHTLY_BUILD
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
SignInToWebsiteUX.init();
@ -842,17 +836,7 @@ BrowserGlue.prototype = {
#endif
webrtcUI.init();
AboutHome.init();
RemoteDirectoryLinksProvider.init();
RemoteNewTabUtils.init();
RemoteNewTabUtils.links.addProvider(RemoteDirectoryLinksProvider);
RemoteAboutNewTab.init();
DirectoryLinksProvider.init();
NewTabUtils.init();
NewTabUtils.links.addProvider(DirectoryLinksProvider);
AboutNewTab.init();
SessionStore.init();
BrowserUITelemetry.init();
ContentSearch.init();
@ -1177,8 +1161,6 @@ BrowserGlue.prototype = {
CustomizationTabPreloader.uninit();
WebappManager.uninit();
RemoteAboutNewTab.uninit();
AboutNewTab.uninit();
#ifdef NIGHTLY_BUILD
if (Services.prefs.getBoolPref("dom.identity.enabled")) {
@ -2061,7 +2043,7 @@ BrowserGlue.prototype = {
}
if (currentUIVersion < 19) {
let detector = null;
let detector = null;
try {
detector = Services.prefs.getComplexValue("intl.charset.detector",
Ci.nsIPrefLocalizedString).data;
@ -2223,7 +2205,7 @@ BrowserGlue.prototype = {
Services.prefs.clearUserPref("browser.devedition.showCustomizeButton");
}
if (currentUIVersion < 31) {
xulStore.removeValue(BROWSER_DOCURL, "bookmarks-menu-button", "class");
xulStore.removeValue(BROWSER_DOCURL, "home-button", "class");

View File

@ -14,15 +14,10 @@ Components.utils.import("resource://gre/modules/Services.jsm");
this.NewTabURL = {
_url: "about:newtab",
_remoteUrl: "about:remote-newtab",
_overridden: false,
get: function() {
let output = this._url;
if (Services.prefs.getBoolPref("browser.newtabpage.remote")) {
output = this._remoteUrl;
}
return output;
return this._url;
},
get overridden() {

View File

@ -30,6 +30,7 @@ EXTRA_JS_MODULES += [
'FormValidationHandler.jsm',
'HiddenFrame.jsm',
'NetworkPrioritizer.jsm',
'NewTabURL.jsm',
'offlineAppCache.jsm',
'PanelFrame.jsm',
'PluginContent.jsm',

View File

@ -20,11 +20,6 @@ add_task(function* () {
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");
// change newtab page to remote
Services.prefs.setBoolPref("browser.newtabpage.remote", true);
Assert.equal(NewTabURL.get(), "about:remote-newtab", "Newtab URL should be the about:remote-newtab");
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
});
function promiseNewtabURLNotification(aNewURL) {

View File

@ -5,4 +5,5 @@ firefox-appdir = browser
skip-if = toolkit == 'android' || toolkit == 'gonk'
[test_DirectoryLinksProvider.js]
[test_NewTabURL.js]
[test_SitePermissions.js]