diff --git a/browser/base/content/browser-pageActions.js b/browser/base/content/browser-pageActions.js index f3b76832a743..1d9d468c31d0 100644 --- a/browser/base/content/browser-pageActions.js +++ b/browser/base/content/browser-pageActions.js @@ -2,6 +2,12 @@ * 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/. */ +ChromeUtils.defineModuleGetter( + this, + "SiteSpecificBrowserService", + "resource:///modules/SiteSpecificBrowserService.jsm" +); + var BrowserPageActions = { /** * The main page action button in the urlbar (DOM node) @@ -1098,20 +1104,7 @@ BrowserPageActions.launchSSB = { return; } - let sa = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); - let uri = Cc["@mozilla.org/supports-string;1"].createInstance( - Ci.nsISupportsString - ); - uri.data = gBrowser.currentURI.spec; - sa.appendElement(uri); - Services.ww.openWindow( - null, - "chrome://browser/content/ssb/ssb.html", - "_blank", - "chrome,dialog=no,all", - sa - ); - + SiteSpecificBrowserService.launchFromURI(gBrowser.currentURI); gBrowser.removeTab(gBrowser.selectedTab, { closeWindowWithLastTab: false }); }, }; diff --git a/browser/components/ssb/SiteSpecificBrowserService.jsm b/browser/components/ssb/SiteSpecificBrowserService.jsm new file mode 100644 index 000000000000..9935b9a187a8 --- /dev/null +++ b/browser/components/ssb/SiteSpecificBrowserService.jsm @@ -0,0 +1,95 @@ +/* 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/. */ + +var EXPORTED_SYMBOLS = ["SiteSpecificBrowserService", "SSBCommandLineHandler"]; + +const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); +const { XPCOMUtils } = ChromeUtils.import( + "resource://gre/modules/XPCOMUtils.jsm" +); + +const SiteSpecificBrowserService = { + /** + * Given a URI launches the SSB UI to display it. + * + * @param {nsIURI} uri the URI to display. + */ + launchFromURI(uri) { + if (!this.isEnabled) { + throw new Error("Site specific browsing is disabled."); + } + + if (!uri.schemeIs("https")) { + throw new Error( + "Site specific browsers can only be opened for secure sites." + ); + } + + let sa = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray); + let uristr = Cc["@mozilla.org/supports-string;1"].createInstance( + Ci.nsISupportsString + ); + uristr.data = uri.spec; + sa.appendElement(uristr); + Services.ww.openWindow( + null, + "chrome://browser/content/ssb/ssb.html", + "_blank", + "chrome,dialog=no,all", + sa + ); + }, +}; + +XPCOMUtils.defineLazyPreferenceGetter( + SiteSpecificBrowserService, + "isEnabled", + "browser.ssb.enabled", + false +); + +class SSBCommandLineHandler { + /* nsICommandLineHandler */ + handle(cmdLine) { + if (!SiteSpecificBrowserService.isEnabled) { + return; + } + + let site = cmdLine.handleFlagWithParam("ssb", false); + if (site) { + cmdLine.preventDefault = true; + + try { + let fixupInfo = Services.uriFixup.getFixupURIInfo( + site, + Services.uriFixup.FIXUP_FLAG_FIX_SCHEME_TYPOS + ); + + let uri = fixupInfo.preferredURI; + if (!uri) { + dump(`Unable to parse '${site}' as a URI.\n`); + return; + } + + if (fixupInfo.fixupChangedProtocol && uri.schemeIs("http")) { + uri = uri + .mutate() + .setScheme("https") + .finalize(); + } + SiteSpecificBrowserService.launchFromURI(uri); + } catch (e) { + dump(`Unable to parse '${site}' as a URI: ${e}\n`); + } + } + } + + get helpInfo() { + return " --ssb Open a site specific browser for .\n"; + } +} + +SSBCommandLineHandler.prototype.QueryInterface = ChromeUtils.generateQI([ + Ci.nsICommandLineHandler, +]); diff --git a/browser/components/ssb/components.conf b/browser/components/ssb/components.conf new file mode 100644 index 000000000000..c58fe7eda0a0 --- /dev/null +++ b/browser/components/ssb/components.conf @@ -0,0 +1,19 @@ +# -*- Mode: python; 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/. + +Classes = [ + { + 'cid': '{6344f783-c893-4db8-91ec-7d43a46bd6f4}', + 'contract_ids': [ + '@mozilla.org/browser/ssb/clh;1', + ], + 'jsm': 'resource:///modules/SiteSpecificBrowserService.jsm', + 'constructor': 'SSBCommandLineHandler', + 'categories': { + 'command-line-handler': 'e-ssb', + }, + }, +] diff --git a/browser/components/ssb/moz.build b/browser/components/ssb/moz.build index 240a6da16494..9514edda9675 100644 --- a/browser/components/ssb/moz.build +++ b/browser/components/ssb/moz.build @@ -6,3 +6,11 @@ JAR_MANIFESTS += ['content/jar.mn'] BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini'] + +XPCOM_MANIFESTS += [ + 'components.conf', +] + +EXTRA_JS_MODULES += [ + 'SiteSpecificBrowserService.jsm', +] diff --git a/browser/components/ssb/tests/browser/browser_ssb_lasttab.js b/browser/components/ssb/tests/browser/browser_ssb_lasttab.js index 795d14a29d62..4c4d514da593 100644 --- a/browser/components/ssb/tests/browser/browser_ssb_lasttab.js +++ b/browser/components/ssb/tests/browser/browser_ssb_lasttab.js @@ -13,20 +13,23 @@ add_task(async () => { Assert.equal(win.gBrowser.tabs.length, 1, "Should be only one tab."); let tab = win.gBrowser.selectedTab; - let loaded = BrowserTestUtils.browserLoaded( - win.gBrowser.selectedBrowser, - false, - gHttpsTestRoot + "test_page.html" - ); BrowserTestUtils.loadURI( win.gBrowser.selectedBrowser, gHttpsTestRoot + "test_page.html" ); - await loaded; + await BrowserTestUtils.browserLoaded( + win.gBrowser.selectedBrowser, + true, + gHttpsTestRoot + "test_page.html" + ); let ssb = await openSSBFromBrowserWindow(win); Assert.equal(win.gBrowser.tabs.length, 1, "Should still be only one tab."); Assert.notEqual(tab, win.gBrowser.selectedTab, "Should be a new tab."); + Assert.equal( + getBrowser(ssb).currentURI.spec, + gHttpsTestRoot + "test_page.html" + ); Assert.ok(!windowClosed, "Should not have seen the window close."); await BrowserTestUtils.closeWindow(ssb); diff --git a/browser/components/ssb/tests/browser/head.js b/browser/components/ssb/tests/browser/head.js index b466121e637a..54d062681280 100644 --- a/browser/components/ssb/tests/browser/head.js +++ b/browser/components/ssb/tests/browser/head.js @@ -27,6 +27,8 @@ async function openSSBFromBrowserWindow(win = window) { EventUtils.synthesizeMouseAtCenter(pageActionButton, {}, win); await popupShown; + let expectedUri = win.gBrowser.selectedBrowser.currentURI; + let openItem = doc.getElementById("pageAction-panel-launchSSB"); Assert.ok(!openItem.disabled, "Open menu item should not be disabled"); Assert.ok(!openItem.hidden, "Open menu item should not be hidden"); @@ -39,7 +41,7 @@ async function openSSBFromBrowserWindow(win = window) { EventUtils.synthesizeMouseAtCenter(openItem, {}, win); let ssbwin = await openPromise; let browser = ssbwin.document.getElementById("browser"); - await BrowserTestUtils.browserLoaded(browser, true); + await BrowserTestUtils.browserLoaded(browser, true, expectedUri.spec); return ssbwin; } diff --git a/browser/modules/PageActions.jsm b/browser/modules/PageActions.jsm index 300752eb7b81..c06118e6cade 100644 --- a/browser/modules/PageActions.jsm +++ b/browser/modules/PageActions.jsm @@ -36,6 +36,11 @@ ChromeUtils.defineModuleGetter( "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm" ); +ChromeUtils.defineModuleGetter( + this, + "SiteSpecificBrowserService", + "resource:///modules/SiteSpecificBrowserService.jsm" +); const ACTION_ID_BOOKMARK = "bookmark"; const ACTION_ID_PIN_TAB = "pinTab"; @@ -1280,7 +1285,7 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) { }); } -if (Services.prefs.getBoolPref("browser.ssb.enabled", false)) { +if (SiteSpecificBrowserService.isEnabled) { gBuiltInActions.push({ id: "launchSSB", // Hardcoded for now. Localization tracked in bug 1602528.