Bug 1234150 - Support overriding "about:newtab" using chrome_url_overrides. r=aswan,mixedpuppy
authorMatthew Wein <mwein@mozilla.com>
Tue, 10 Jan 2017 14:24:50 -0500
changeset 330741 485014423bd9
parent 330740 0723b0ecb8b9
child 330742 96d0d062d978
push id36398
push userryanvm@gmail.com
push date2017-01-24 03:27 +0000
treeherderautoland@485014423bd9 [default view] [failures only]
reviewersaswan, mixedpuppy
bugs1234150
milestone54.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1234150 - Support overriding "about:newtab" using chrome_url_overrides. r=aswan,mixedpuppy MozReview-Commit-ID: 4psqXfT1w2p
browser/components/extensions/ext-url-overrides.js
browser/components/extensions/extensions-browser.manifest
browser/components/extensions/jar.mn
browser/components/extensions/schemas/jar.mn
browser/components/extensions/schemas/url_overrides.json
browser/components/extensions/test/browser/browser-common.ini
browser/components/extensions/test/browser/browser_ext_url_overrides.js
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/ext-url-overrides.js
@@ -0,0 +1,49 @@
+/* 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";
+
+Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
+                                   "@mozilla.org/browser/aboutnewtab-service;1",
+                                   "nsIAboutNewTabService");
+
+// Bug 1320736 tracks creating a generic precedence manager for handling
+// multiple addons modifying the same properties, and bug 1330494 has been filed
+// to track utilizing this manager for chrome_url_overrides. Until those land,
+// the edge cases surrounding multiple addons using chrome_url_overrides will
+// be ignored and precedence will be first come, first serve.
+let overrides = {
+  // A queue of extensions in line to override the newtab page (sorted oldest to newest).
+  newtab: [],
+};
+
+/* eslint-disable mozilla/balanced-listeners */
+extensions.on("manifest_chrome_url_overrides", (type, directive, extension, manifest) => {
+  if (manifest.chrome_url_overrides.newtab) {
+    let newtab = manifest.chrome_url_overrides.newtab;
+    let url = extension.baseURI.resolve(newtab);
+
+    // Only set the newtab URL if no other extension is overriding it.
+    if (!overrides.newtab.length) {
+      aboutNewTabService.newTabURL = url;
+    }
+
+    overrides.newtab.push({extension, url});
+  }
+});
+
+extensions.on("shutdown", (type, extension) => {
+  let i = overrides.newtab.findIndex(o => o.extension === extension);
+  if (i !== -1) {
+    overrides.newtab.splice(i, 1);
+
+    if (overrides.newtab.length) {
+      aboutNewTabService.newTabURL = overrides.newtab[0].url;
+    } else {
+      aboutNewTabService.resetNewTabURL();
+    }
+  }
+});
+/* eslint-enable mozilla/balanced-listeners */
--- a/browser/components/extensions/extensions-browser.manifest
+++ b/browser/components/extensions/extensions-browser.manifest
@@ -7,16 +7,17 @@ category webextension-scripts contextMen
 category webextension-scripts desktop-runtime chrome://browser/content/ext-desktop-runtime.js
 category webextension-scripts devtools chrome://browser/content/ext-devtools.js
 category webextension-scripts history chrome://browser/content/ext-history.js
 category webextension-scripts omnibox chrome://browser/content/ext-omnibox.js
 category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
 category webextension-scripts sessions chrome://browser/content/ext-sessions.js
 category webextension-scripts tabs chrome://browser/content/ext-tabs.js
 category webextension-scripts theme chrome://browser/content/ext-theme.js
+category webextension-scripts url-overrides chrome://browser/content/ext-url-overrides.js
 category webextension-scripts utils chrome://browser/content/ext-utils.js
 category webextension-scripts windows chrome://browser/content/ext-windows.js
 
 # scripts specific for devtools extension contexts.
 category webextension-scripts-devtools devtools-inspectedWindow chrome://browser/content/ext-c-devtools-inspectedWindow.js
 
 # scripts that must run in the same process as addon code.
 category webextension-scripts-addon contextMenus chrome://browser/content/ext-c-contextMenus.js
@@ -33,9 +34,10 @@ category webextension-schemas context_me
 category webextension-schemas devtools chrome://browser/content/schemas/devtools.json
 category webextension-schemas devtools_inspected_window chrome://browser/content/schemas/devtools_inspected_window.json
 category webextension-schemas history chrome://browser/content/schemas/history.json
 category webextension-schemas omnibox chrome://browser/content/schemas/omnibox.json
 category webextension-schemas page_action chrome://browser/content/schemas/page_action.json
 category webextension-schemas sessions chrome://browser/content/schemas/sessions.json
 category webextension-schemas tabs chrome://browser/content/schemas/tabs.json
 category webextension-schemas theme chrome://browser/content/schemas/theme.json
+category webextension-schemas url_overrides chrome://browser/content/schemas/url_overrides.json
 category webextension-schemas windows chrome://browser/content/schemas/windows.json
--- a/browser/components/extensions/jar.mn
+++ b/browser/components/extensions/jar.mn
@@ -20,14 +20,15 @@ browser.jar:
     content/browser/ext-desktop-runtime.js
     content/browser/ext-devtools.js
     content/browser/ext-history.js
     content/browser/ext-omnibox.js
     content/browser/ext-pageAction.js
     content/browser/ext-sessions.js
     content/browser/ext-tabs.js
     content/browser/ext-theme.js
+    content/browser/ext-url-overrides.js
     content/browser/ext-utils.js
     content/browser/ext-windows.js
     content/browser/ext-c-contextMenus.js
     content/browser/ext-c-devtools-inspectedWindow.js
     content/browser/ext-c-omnibox.js
     content/browser/ext-c-tabs.js
--- a/browser/components/extensions/schemas/jar.mn
+++ b/browser/components/extensions/schemas/jar.mn
@@ -12,9 +12,10 @@ browser.jar:
     content/browser/schemas/devtools.json
     content/browser/schemas/devtools_inspected_window.json
     content/browser/schemas/history.json
     content/browser/schemas/omnibox.json
     content/browser/schemas/page_action.json
     content/browser/schemas/sessions.json
     content/browser/schemas/tabs.json
     content/browser/schemas/theme.json
+    content/browser/schemas/url_overrides.json
     content/browser/schemas/windows.json
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/schemas/url_overrides.json
@@ -0,0 +1,35 @@
+[
+  {
+    "namespace": "manifest",
+    "types": [
+      {
+        "$extend": "WebExtensionManifest",
+        "properties": {
+          "chrome_url_overrides": {
+            "type": "object",
+            "optional": true,
+            "properties": {
+              "newtab": {
+                "$ref": "ExtensionURL",
+                "optional": true,
+                "preprocess": "localize"
+              },
+              "bookmarks": {
+                "unsupported": true,
+                "$ref": "ExtensionURL",
+                "optional": true,
+                "preprocess": "localize"
+              },
+              "history": {
+                "unsupported": true,
+                "$ref": "ExtensionURL",
+                "optional": true,
+                "preprocess": "localize"
+              }
+            }
+          }
+        }
+      }
+    ]
+  }
+]
\ No newline at end of file
--- a/browser/components/extensions/test/browser/browser-common.ini
+++ b/browser/components/extensions/test/browser/browser-common.ini
@@ -102,23 +102,24 @@ support-files =
 [browser_ext_tabs_reload_bypass_cache.js]
 [browser_ext_tabs_sendMessage.js]
 [browser_ext_tabs_cookieStoreId.js]
 [browser_ext_tabs_update.js]
 [browser_ext_tabs_zoom.js]
 [browser_ext_tabs_update_url.js]
 [browser_ext_themes.js]
 [browser_ext_topwindowid.js]
+[browser_ext_url_overrides.js]
 [browser_ext_webRequest.js]
 [browser_ext_webNavigation_frameId0.js]
 [browser_ext_webNavigation_getFrames.js]
 [browser_ext_webNavigation_urlbar_transitions.js]
 [browser_ext_windows.js]
 [browser_ext_windows_create.js]
 tags = fullscreen
 [browser_ext_windows_create_params.js]
 [browser_ext_windows_create_tabId.js]
 [browser_ext_windows_create_url.js]
 [browser_ext_windows_events.js]
 [browser_ext_windows_size.js]
 skip-if = os == 'mac' # Fails when windows are randomly opened in fullscreen mode
 [browser_ext_windows_update.js]
-tags = fullscreen
+tags = fullscreen
\ No newline at end of file
new file mode 100644
--- /dev/null
+++ b/browser/components/extensions/test/browser/browser_ext_url_overrides.js
@@ -0,0 +1,110 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+
+"use strict";
+
+XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
+                                   "@mozilla.org/browser/aboutnewtab-service;1",
+                                   "nsIAboutNewTabService");
+
+const NEWTAB_URI_1 = "webext-newtab-1.html";
+const NEWTAB_URI_2 = "webext-newtab-2.html";
+const NEWTAB_URI_3 = "webext-newtab-3.html";
+
+add_task(function* test_multiple_extensions_overriding_newtab_page() {
+  is(aboutNewTabService.newTabURL, "about:newtab",
+     "Default newtab url should be about:newtab");
+
+  let ext1 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {}},
+  });
+
+  let ext2 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI_1}},
+  });
+
+  let ext3 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI_2}},
+  });
+
+  let ext4 = ExtensionTestUtils.loadExtension({
+    manifest: {"chrome_url_overrides": {newtab: NEWTAB_URI_3}},
+  });
+
+  yield ext1.startup();
+
+  is(aboutNewTabService.newTabURL, "about:newtab",
+       "Default newtab url should still be about:newtab");
+
+  yield ext2.startup();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
+     "Newtab url should be overriden by the second extension.");
+
+  yield ext1.unload();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
+     "Newtab url should still be overriden by the second extension.");
+
+  yield ext3.startup();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_1),
+     "Newtab url should still be overriden by the second extension.");
+
+  yield ext2.unload();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
+     "Newtab url should be overriden by the third extension.");
+
+  yield ext4.startup();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
+     "Newtab url should be overriden by the third extension.");
+
+  yield ext4.unload();
+
+  ok(aboutNewTabService.newTabURL.endsWith(NEWTAB_URI_2),
+     "Newtab url should be overriden by the third extension.");
+
+  yield ext3.unload();
+
+  is(aboutNewTabService.newTabURL, "about:newtab",
+     "Newtab url should be reset to about:newtab");
+});
+
+add_task(function* test_sending_message_from_newtab_page() {
+  let extension = ExtensionTestUtils.loadExtension({
+    manifest: {
+      "chrome_url_overrides": {
+        newtab: NEWTAB_URI_2,
+      },
+    },
+    files: {
+      [NEWTAB_URI_2]: `
+        <!DOCTYPE html>
+        <head>
+          <meta charset="utf-8"/></head>
+        <html>
+          <body>
+            <script src="newtab.js"></script>
+          </body>
+        </html>
+      `,
+
+      "newtab.js": function() {
+        window.onload = () => {
+          browser.test.sendMessage("from-newtab-page");
+        };
+      },
+    },
+  });
+
+  yield extension.startup();
+
+  // Simulate opening the newtab open as a user would.
+  BrowserOpenTab();
+
+  yield extension.awaitMessage("from-newtab-page");
+  yield BrowserTestUtils.removeTab(gBrowser.selectedTab);
+  yield extension.unload();
+});