Bug 1602123: Add a page action to open the current tab into a standalone window. r=Gijs

The action should open the SSB UI to show the page. No other custom behaviour
is expecgterd at this point.

Differential Revision: https://phabricator.services.mozilla.com/D56283

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dave Townsend 2019-12-12 20:22:50 +00:00
Родитель 0ae5a64d9b
Коммит c696551b78
16 изменённых файлов: 278 добавлений и 1 удалений

Просмотреть файл

@ -1085,6 +1085,37 @@ BrowserPageActions.pinTab = {
},
};
// SiteSpecificBrowser
BrowserPageActions.launchSSB = {
updateState() {
let action = PageActions.actionForID("launchSSB");
let browser = gBrowser.selectedBrowser;
action.setDisabled(!browser.currentURI.schemeIs("https"), window);
},
onCommand(event, buttonNode) {
if (!gBrowser.currentURI.schemeIs("https")) {
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
);
gBrowser.removeTab(gBrowser.selectedTab, { closeWindowWithLastTab: false });
},
};
// copy URL
BrowserPageActions.copyURL = {
onBeforePlacedInWindow(browserWindow) {

Просмотреть файл

@ -3153,7 +3153,10 @@
this.removeTab(this.selectedTab, aParams);
},
removeTab(aTab, { animate, byMouse, skipPermitUnload } = {}) {
removeTab(
aTab,
{ animate, byMouse, skipPermitUnload, closeWindowWithLastTab } = {}
) {
// Telemetry stopwatches may already be running if removeTab gets
// called again for an already closing tab.
if (
@ -3185,6 +3188,7 @@
!this._beginRemoveTab(aTab, {
closeWindowFastpath: true,
skipPermitUnload,
closeWindowWithLastTab,
})
) {
TelemetryStopwatch.cancel("FX_TAB_CLOSE_TIME_ANIM_MS", aTab);

Просмотреть файл

@ -52,6 +52,7 @@ DIRS += [
'search',
'sessionstore',
'shell',
'ssb',
'syncedtabs',
'uitour',
'urlbar',

Просмотреть файл

@ -0,0 +1,8 @@
# 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.jar:
content/browser/ssb/ssb.html
content/browser/ssb/ssb.js
content/browser/ssb/ssb.css

Просмотреть файл

@ -0,0 +1,14 @@
/* 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/. */
html,
body,
#browser-container,
#browser {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}

Просмотреть файл

@ -0,0 +1,16 @@
<!-- 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/. -->
<!DOCTYPE html>
<html width="800" height="600">
<head>
<link rel="stylesheet" href="chrome://global/skin/">
<link rel="stylesheet" href="ssb.css">
</head>
<body>
<div id="browser-container"></div>
<script type="text/javascript" src="ssb.js"></script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,16 @@
/* 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/. */
let gSSBBrowser = null;
function init() {
gSSBBrowser = document.createXULElement("browser");
gSSBBrowser.setAttribute("id", "browser");
gSSBBrowser.setAttribute("type", "content");
gSSBBrowser.setAttribute("remote", "true");
document.getElementById("browser-container").appendChild(gSSBBrowser);
gSSBBrowser.src = window.arguments[0];
}
window.addEventListener("load", init, true);

Просмотреть файл

@ -0,0 +1,8 @@
# -*- 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/.
JAR_MANIFESTS += ['content/jar.mn']
BROWSER_CHROME_MANIFESTS += ['tests/browser/browser.ini']

Просмотреть файл

@ -0,0 +1,10 @@
[DEFAULT]
support-files =
head.js
test_page.html
prefs =
browser.ssb.enabled=true
[browser_ssb_lasttab.js]
[browser_ssb_menu.js]
[browser_ssb_open.js]

Просмотреть файл

@ -0,0 +1,34 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Opening from the last browser tab should not close the window.
add_task(async () => {
let win = await BrowserTestUtils.openNewBrowserWindow();
let windowClosed = false;
BrowserTestUtils.windowClosed(win).then(() => {
windowClosed = true;
});
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;
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.ok(!windowClosed, "Should not have seen the window close.");
await BrowserTestUtils.closeWindow(ssb);
await BrowserTestUtils.closeWindow(win);
});

Просмотреть файл

@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Check that it is correctly enabled/disabled based on the displaying page.
add_task(async () => {
let tab = await BrowserTestUtils.openNewForegroundTab({
gBrowser,
url: gHttpTestRoot + "test_page.html",
});
// Must open the panel before the item gets added.
let pageActionButton = document.getElementById("pageActionButton");
let panel = document.getElementById("pageActionPanel");
let popupShown = BrowserTestUtils.waitForEvent(panel, "popupshown");
EventUtils.synthesizeMouseAtCenter(pageActionButton, {}, window);
await popupShown;
let popupHidden = BrowserTestUtils.waitForEvent(panel, "popuphidden");
panel.hidePopup();
await popupHidden;
Assert.ok(
document.getElementById("pageAction-panel-launchSSB").disabled,
"Menu should be disabled for a http: page."
);
let uri = gHttpsTestRoot + "test_page.html";
BrowserTestUtils.loadURI(tab.linkedBrowser, uri);
await BrowserTestUtils.browserLoaded(tab.linkedBrowser, true, uri);
Assert.ok(
!document.getElementById("pageAction-panel-launchSSB").disabled,
"Menu should not be disabled for a https: page."
);
BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -0,0 +1,19 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Verify that clicking the menu button opens an ssb.
add_task(async () => {
let tab = await BrowserTestUtils.openNewForegroundTab({
gBrowser,
url: gHttpsTestRoot + "test_page.html",
});
let ssb = await openSSBFromBrowserWindow();
Assert.equal(
getBrowser(ssb).currentURI.spec,
gHttpsTestRoot + "test_page.html"
);
Assert.equal(tab.parentNode, null, "The tab should have been closed");
await BrowserTestUtils.closeWindow(ssb);
});

Просмотреть файл

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
</body>
</html>

Просмотреть файл

@ -0,0 +1,49 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// An insecure site to use. SSBs cannot be insecure.
const gHttpTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"http://example.com/"
);
// A secure site to use.
const gHttpsTestRoot = getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
"https://example.com/"
);
// The chrome url for the SSB UI.
const SSB_WINDOW = "chrome://browser/content/ssb/ssb.html";
// Simulates opening a SSB from the main browser window. Resolves to the SSB
// DOM window after the SSB content has loaded.
async function openSSBFromBrowserWindow(win = window) {
let doc = win.document;
let pageActionButton = doc.getElementById("pageActionButton");
let panel = doc.getElementById("pageActionPanel");
let popupShown = BrowserTestUtils.waitForEvent(panel, "popupshown");
EventUtils.synthesizeMouseAtCenter(pageActionButton, {}, win);
await popupShown;
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");
let openPromise = BrowserTestUtils.domWindowOpened(null, async domwin => {
await BrowserTestUtils.waitForEvent(domwin, "load");
return domwin.location.toString() == SSB_WINDOW;
});
EventUtils.synthesizeMouseAtCenter(openItem, {}, win);
let ssbwin = await openPromise;
let browser = ssbwin.document.getElementById("browser");
await BrowserTestUtils.browserLoaded(browser, true);
return ssbwin;
}
// Given the SSB UI DOM window gets the browser element showing the content.
function getBrowser(ssbwin) {
return ssbwin.document.getElementById("browser");
}

Просмотреть файл

@ -0,0 +1,6 @@
<!DOCTYPE html>
<html>
<body>
</body>
</html>

Просмотреть файл

@ -1280,6 +1280,20 @@ if (Services.prefs.getBoolPref("identity.fxaccounts.enabled")) {
});
}
if (Services.prefs.getBoolPref("browser.ssb.enabled", false)) {
gBuiltInActions.push({
id: "launchSSB",
// Hardcoded for now. Localization tracked in bug 1602528.
title: "Launch Site Specific Browser",
onLocationChange(browserWindow) {
browserPageActions(browserWindow).launchSSB.updateState();
},
onCommand(event, buttonNode) {
browserPageActions(buttonNode).launchSSB.onCommand(event, buttonNode);
},
});
}
// share URL
if (AppConstants.platform == "macosx") {
gBuiltInActions.push({