gecko/browser/base/content/test/newtab/head.js
Marco Bonardo 90a5f7a6cb Bug 791447 - Move about:newTab data to preferences. r=gavin
Gecko 18 doesn't store anymore about: pages DOMStorage into chromeappsstore.sqlite, so any previous data would be lost on upgrade to it.
Moreover, we want to move off DOMStorage due to high startup costs.
Thus here we migrate old about:newTab chromeappsstore.sqlite data to complex prefs.
2012-12-03 20:19:17 +01:00

375 lines
9.6 KiB
JavaScript

/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const PREF_NEWTAB_ENABLED = "browser.newtabpage.enabled";
Services.prefs.setBoolPref(PREF_NEWTAB_ENABLED, true);
let tmp = {};
Cu.import("resource:///modules/NewTabUtils.jsm", tmp);
Cc["@mozilla.org/moz/jssubscript-loader;1"]
.getService(Ci.mozIJSSubScriptLoader)
.loadSubScript("chrome://browser/content/sanitize.js", tmp);
let {NewTabUtils, Sanitizer} = tmp;
let uri = Services.io.newURI("about:newtab", null, null);
let principal = Services.scriptSecurityManager.getNoAppCodebasePrincipal(uri);
let gWindow = window;
registerCleanupFunction(function () {
while (gWindow.gBrowser.tabs.length > 1)
gWindow.gBrowser.removeTab(gWindow.gBrowser.tabs[1]);
Services.prefs.clearUserPref(PREF_NEWTAB_ENABLED);
});
/**
* Provide the default test function to start our test runner.
*/
function test() {
TestRunner.run();
}
/**
* The test runner that controls the execution flow of our tests.
*/
let TestRunner = {
/**
* Starts the test runner.
*/
run: function () {
waitForExplicitFinish();
this._iter = runTests();
this.next();
},
/**
* Runs the next available test or finishes if there's no test left.
*/
next: function () {
try {
TestRunner._iter.next();
} catch (e if e instanceof StopIteration) {
TestRunner.finish();
}
},
/**
* Finishes all tests and cleans up.
*/
finish: function () {
function cleanupAndFinish() {
clearHistory();
whenPagesUpdated(finish);
NewTabUtils.restore();
}
let callbacks = NewTabUtils.links._populateCallbacks;
let numCallbacks = callbacks.length;
if (numCallbacks)
callbacks.splice(0, numCallbacks, cleanupAndFinish);
else
cleanupAndFinish();
}
};
/**
* Returns the selected tab's content window.
* @return The content window.
*/
function getContentWindow() {
return gWindow.gBrowser.selectedBrowser.contentWindow;
}
/**
* Returns the selected tab's content document.
* @return The content document.
*/
function getContentDocument() {
return gWindow.gBrowser.selectedBrowser.contentDocument;
}
/**
* Returns the newtab grid of the selected tab.
* @return The newtab grid.
*/
function getGrid() {
return getContentWindow().gGrid;
}
/**
* Returns the cell at the given index of the selected tab's newtab grid.
* @param aIndex The cell index.
* @return The newtab cell.
*/
function getCell(aIndex) {
return getGrid().cells[aIndex];
}
/**
* Allows to provide a list of links that is used to construct the grid.
* @param aLinksPattern the pattern (see below)
*
* Example: setLinks("1,2,3")
* Result: [{url: "http://example.com/#1", title: "site#1"},
* {url: "http://example.com/#2", title: "site#2"}
* {url: "http://example.com/#3", title: "site#3"}]
*/
function setLinks(aLinks) {
let links = aLinks;
if (typeof links == "string") {
links = aLinks.split(/\s*,\s*/).map(function (id) {
return {url: "http://example.com/#" + id, title: "site#" + id};
});
}
clearHistory();
fillHistory(links, function () {
NewTabUtils.links.populateCache(function () {
NewTabUtils.allPages.update();
TestRunner.next();
}, true);
});
}
function clearHistory() {
PlacesUtils.history.removeAllPages();
}
function fillHistory(aLinks, aCallback) {
let numLinks = aLinks.length;
let transitionLink = Ci.nsINavHistoryService.TRANSITION_LINK;
for (let link of aLinks.reverse()) {
let place = {
uri: makeURI(link.url),
title: link.title,
visits: [{visitDate: Date.now() * 1000, transitionType: transitionLink}]
};
PlacesUtils.asyncHistory.updatePlaces(place, {
handleError: function () ok(false, "couldn't add visit to history"),
handleResult: function () {},
handleCompletion: function () {
if (--numLinks == 0)
aCallback();
}
});
}
}
/**
* Allows to specify the list of pinned links (that have a fixed position in
* the grid.
* @param aLinksPattern the pattern (see below)
*
* Example: setPinnedLinks("3,,1")
* Result: 'http://example.com/#3' is pinned in the first cell. 'http://example.com/#1' is
* pinned in the third cell.
*/
function setPinnedLinks(aLinks) {
let links = aLinks;
if (typeof links == "string") {
links = aLinks.split(/\s*,\s*/).map(function (id) {
if (id)
return {url: "http://example.com/#" + id, title: "site#" + id};
});
}
let string = Cc["@mozilla.org/supports-string;1"]
.createInstance(Ci.nsISupportsString);
string.data = JSON.stringify(links);
Services.prefs.setComplexValue("browser.newtabpage.pinned",
Ci.nsISupportsString, string);
NewTabUtils.pinnedLinks.resetCache();
NewTabUtils.allPages.update();
}
/**
* Restore the grid state.
*/
function restore() {
whenPagesUpdated();
NewTabUtils.restore();
}
/**
* Creates a new tab containing 'about:newtab'.
*/
function addNewTabPageTab() {
let tab = gWindow.gBrowser.selectedTab = gWindow.gBrowser.addTab("about:newtab");
let browser = tab.linkedBrowser;
function whenNewTabLoaded() {
if (NewTabUtils.allPages.enabled) {
// Continue when the link cache has been populated.
NewTabUtils.links.populateCache(function () {
executeSoon(TestRunner.next);
});
} else {
TestRunner.next();
}
}
// The new tab page might have been preloaded in the background.
if (browser.contentDocument.readyState == "complete") {
whenNewTabLoaded();
return;
}
// Wait for the new tab page to be loaded.
browser.addEventListener("load", function onLoad() {
browser.removeEventListener("load", onLoad, true);
whenNewTabLoaded();
}, true);
}
/**
* Compares the current grid arrangement with the given pattern.
* @param the pattern (see below)
* @param the array of sites to compare with (optional)
*
* Example: checkGrid("3p,2,,1p")
* Result: We expect the first cell to contain the pinned site 'http://example.com/#3'.
* The second cell contains 'http://example.com/#2'. The third cell is empty.
* The fourth cell contains the pinned site 'http://example.com/#4'.
*/
function checkGrid(aSitesPattern, aSites) {
let length = aSitesPattern.split(",").length;
let sites = (aSites || getGrid().sites).slice(0, length);
let current = sites.map(function (aSite) {
if (!aSite)
return "";
let pinned = aSite.isPinned();
let pinButton = aSite.node.querySelector(".newtab-control-pin");
let hasPinnedAttr = pinButton.hasAttribute("pinned");
if (pinned != hasPinnedAttr)
ok(false, "invalid state (site.isPinned() != site[pinned])");
return aSite.url.replace(/^http:\/\/example\.com\/#(\d+)$/, "$1") + (pinned ? "p" : "");
});
is(current, aSitesPattern, "grid status = " + aSitesPattern);
}
/**
* Blocks a site from the grid.
* @param aIndex The cell index.
*/
function blockCell(aIndex) {
whenPagesUpdated();
getCell(aIndex).site.block();
}
/**
* Pins a site on a given position.
* @param aIndex The cell index.
* @param aPinIndex The index the defines where the site should be pinned.
*/
function pinCell(aIndex, aPinIndex) {
getCell(aIndex).site.pin(aPinIndex);
}
/**
* Unpins the given cell's site.
* @param aIndex The cell index.
*/
function unpinCell(aIndex) {
whenPagesUpdated();
getCell(aIndex).site.unpin();
}
/**
* Simulates a drop and drop operation.
* @param aDropIndex The cell index of the drop target.
* @param aDragIndex The cell index containing the dragged site (optional).
*/
function simulateDrop(aDropIndex, aDragIndex) {
let draggedSite;
let {gDrag: drag, gDrop: drop} = getContentWindow();
let event = createDragEvent("drop", "http://example.com/#99\nblank");
if (typeof aDragIndex != "undefined")
draggedSite = getCell(aDragIndex).site;
if (draggedSite)
drag.start(draggedSite, event);
whenPagesUpdated();
drop.drop(getCell(aDropIndex), event);
if (draggedSite)
drag.end(draggedSite);
}
/**
* Sends a custom drag event to a given DOM element.
* @param aEventType The drag event's type.
* @param aTarget The DOM element that the event is dispatched to.
* @param aData The event's drag data (optional).
*/
function sendDragEvent(aEventType, aTarget, aData) {
let event = createDragEvent(aEventType, aData);
let ifaceReq = getContentWindow().QueryInterface(Ci.nsIInterfaceRequestor);
let windowUtils = ifaceReq.getInterface(Ci.nsIDOMWindowUtils);
windowUtils.dispatchDOMEventViaPresShell(aTarget, event, true);
}
/**
* Creates a custom drag event.
* @param aEventType The drag event's type.
* @param aData The event's drag data (optional).
* @return The drag event.
*/
function createDragEvent(aEventType, aData) {
let dataTransfer = {
mozUserCancelled: false,
setData: function () null,
setDragImage: function () null,
getData: function () aData,
types: {
contains: function (aType) aType == "text/x-moz-url"
},
mozGetDataAt: function (aType, aIndex) {
if (aIndex || aType != "text/x-moz-url")
return null;
return aData;
}
};
let event = getContentDocument().createEvent("DragEvents");
event.initDragEvent(aEventType, true, true, getContentWindow(), 0, 0, 0, 0, 0,
false, false, false, false, 0, null, dataTransfer);
return event;
}
/**
* Resumes testing when all pages have been updated.
*/
function whenPagesUpdated(aCallback) {
let page = {
update: function () {
NewTabUtils.allPages.unregister(this);
executeSoon(aCallback || TestRunner.next);
}
};
NewTabUtils.allPages.register(page);
registerCleanupFunction(function () {
NewTabUtils.allPages.unregister(page);
});
}