Bug 1395154 - If Send Page to Device pageAction is Pinned, it should dismiss when a user sends a tab. r?jaws
MozReview-Commit-ID: HkuzOOp8PDP
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -216,16 +216,21 @@ var BrowserPageActions = {
panelNode.setAttribute("actionID", action.id);
panelNode.setAttribute("role", "group");
panelNode.setAttribute("type", "arrow");
panelNode.setAttribute("flip", "slide");
panelNode.setAttribute("noautofocus", "true");
panelNode.setAttribute("tabspecific", "true");
panelNode.setAttribute("photon", "true");
+ // For tests.
+ if (this._disableActivatedActionPanelAnimation) {
+ panelNode.setAttribute("animate", "false");
+ }
+
let panelViewNode = null;
let iframeNode = null;
if (action.subview) {
let multiViewNode = document.createElement("photonpanelmultiview");
panelViewNode = this._makePanelViewNodeForAction(action, true);
multiViewNode.appendChild(panelViewNode);
panelNode.appendChild(multiViewNode);
@@ -801,30 +806,34 @@ BrowserPageActions.sendToDevice = {
},
onShowingSubview(panelViewNode) {
let browser = gBrowser.selectedBrowser;
let url = browser.currentURI.spec;
let title = browser.contentTitle;
let bodyNode = panelViewNode.firstChild;
+ let panelNode = panelViewNode.closest("panel");
// This is on top because it also clears the device list between state
// changes.
gSync.populateSendTabToDevicesMenu(bodyNode, url, title, (clientId, name, clientType) => {
if (!name) {
return document.createElement("toolbarseparator");
}
let item = document.createElement("toolbarbutton");
item.classList.add("pageAction-sendToDevice-device", "subviewbutton");
if (clientId) {
item.classList.add("subviewbutton-iconic");
}
item.setAttribute("tooltiptext", name);
item.addEventListener("command", event => {
+ if (panelNode) {
+ panelNode.hidePopup();
+ }
// There are items in the subview that don't represent devices: "Sign
// in", "Learn about Sync", etc. Device items will be .sendtab-target.
if (event.target.classList.contains("sendtab-target")) {
BrowserPageActionFeedback.show("sendToDevice", event);
}
});
return item;
});
--- a/browser/base/content/browser-sync.js
+++ b/browser/base/content/browser-sync.js
@@ -335,17 +335,16 @@ var gSync = {
_appendSendTabDeviceList(fragment, createDeviceNodeFn, url, title) {
const onTargetDeviceCommand = (event) => {
let clients = event.target.getAttribute("clientId") ?
[event.target.getAttribute("clientId")] :
this.remoteClients.map(client => client.id);
clients.forEach(clientId => this.sendTabToDevice(url, clientId, title));
- BrowserPageActions.panelNode.hidePopup();
}
function addTargetDevice(clientId, name, clientType) {
const targetDevice = createDeviceNodeFn(clientId, name, clientType);
targetDevice.addEventListener("command", onTargetDeviceCommand, true);
targetDevice.classList.add("sync-menuitem", "sendtab-target");
targetDevice.setAttribute("clientId", clientId);
targetDevice.setAttribute("clientType", clientType);
@@ -368,49 +367,45 @@ var gSync = {
}
},
_appendSendTabSingleDevice(fragment, createDeviceNodeFn) {
const noDevices = this.fxaStrings.GetStringFromName("sendTabToDevice.singledevice.status");
const learnMore = this.fxaStrings.GetStringFromName("sendTabToDevice.singledevice");
this._appendSendTabInfoItems(fragment, createDeviceNodeFn, noDevices, learnMore, () => {
this.openSendToDevicePromo();
- BrowserPageActions.panelNode.hidePopup();
});
},
_appendSendTabVerify(fragment, createDeviceNodeFn) {
const notVerified = this.fxaStrings.GetStringFromName("sendTabToDevice.verify.status");
const verifyAccount = this.fxaStrings.GetStringFromName("sendTabToDevice.verify");
this._appendSendTabInfoItems(fragment, createDeviceNodeFn, notVerified, verifyAccount, () => {
this.openPrefs("sendtab");
- BrowserPageActions.panelNode.hidePopup();
});
},
_appendSendTabUnconfigured(fragment, createDeviceNodeFn) {
const notConnected = this.fxaStrings.GetStringFromName("sendTabToDevice.unconfigured.status");
const learnMore = this.fxaStrings.GetStringFromName("sendTabToDevice.unconfigured");
this._appendSendTabInfoItems(fragment, createDeviceNodeFn, notConnected, learnMore, () => {
this.openSendToDevicePromo();
- BrowserPageActions.panelNode.hidePopup();
});
// Now add a 'sign in to sync' item above the 'learn more' item.
const signInToSync = this.fxaStrings.GetStringFromName("sendTabToDevice.signintosync");
let signInItem = createDeviceNodeFn(null, signInToSync, null);
signInItem.classList.add("sync-menuitem");
signInItem.setAttribute("label", signInToSync);
// Show an icon if opened in the page action panel:
if (signInItem.classList.contains("subviewbutton")) {
signInItem.classList.add("subviewbutton-iconic", "signintosync");
}
signInItem.addEventListener("command", () => {
this.openPrefs("sendtab");
- BrowserPageActions.panelNode.hidePopup();
});
fragment.insertBefore(signInItem, fragment.lastChild);
},
_appendSendTabInfoItems(fragment, createDeviceNodeFn, statusLabel, actionLabel, actionCommand) {
const status = createDeviceNodeFn(null, statusLabel, null);
status.setAttribute("label", statusLabel);
status.setAttribute("disabled", true);
--- a/browser/base/content/test/urlbar/browser_page_action_menu.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu.js
@@ -457,16 +457,116 @@ add_task(async function sendToDevice_dev
let hiddenPromise = promisePageActionPanelHidden();
BrowserPageActions.panelNode.hidePopup();
await hiddenPromise;
cleanUp();
});
});
+add_task(async function sendToDevice_inUrlbar() {
+ // Open a tab that's sendable.
+ await BrowserTestUtils.withNewTab("http://example.com/", async () => {
+ await promiseSyncReady();
+ const sandbox = sinon.sandbox.create();
+ sandbox.stub(gSync, "syncReady").get(() => true);
+ sandbox.stub(Weave.Service.clientsEngine, "lastSync").get(() => Date.now());
+ sandbox.stub(UIState, "get").returns({ status: UIState.STATUS_SIGNED_IN });
+ sandbox.stub(gSync, "isSendableURI").returns(true);
+ sandbox.stub(gSync, "remoteClients").get(() => mockRemoteClients);
+
+ let cleanUp = () => {
+ sandbox.restore();
+ };
+ registerCleanupFunction(cleanUp);
+
+ // Disable the activated-action panel animation when it opens. Otherwise
+ // it's necessary to wait a moment before trying to click the device menu
+ // item below.
+ BrowserPageActions._disableActivatedActionPanelAnimation = true;
+
+ // Add Send to Device to the urlbar.
+ let action = PageActions.actionForID("sendToDevice");
+ action.shownInUrlbar = true;
+
+ // Click it to open its panel.
+ let urlbarButton = document.getElementById(
+ BrowserPageActions._urlbarButtonNodeIDForActionID(action.id)
+ );
+ Assert.ok(!urlbarButton.disabled);
+ let panelPromise =
+ promisePanelShown(BrowserPageActions._activatedActionPanelID);
+ EventUtils.synthesizeMouseAtCenter(urlbarButton, {});
+ await panelPromise;
+
+ // The devices should be shown in the subview.
+ let expectedItems = [
+ {
+ id: "pageAction-urlbar-sendToDevice-notReady",
+ display: "none",
+ disabled: true,
+ },
+ ];
+ for (let client of mockRemoteClients) {
+ expectedItems.push({
+ attrs: {
+ clientId: client.id,
+ label: client.name,
+ clientType: client.type,
+ },
+ });
+ }
+ expectedItems.push(
+ null,
+ {
+ attrs: {
+ label: "Send to All Devices"
+ }
+ }
+ );
+ checkSendToDeviceItems(expectedItems, true);
+
+ // Get the first device menu item in the panel.
+ let bodyID =
+ BrowserPageActions._panelViewNodeIDForActionID("sendToDevice", true) +
+ "-body";
+ let body = document.getElementById(bodyID);
+ let deviceMenuItem = body.querySelector(".sendtab-target");
+ Assert.notEqual(deviceMenuItem, null);
+
+ // For good measure, wait until it's visible.
+ let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor)
+ .getInterface(Ci.nsIDOMWindowUtils);
+ await BrowserTestUtils.waitForCondition(() => {
+ let bounds = dwu.getBoundsWithoutFlushing(deviceMenuItem);
+ return bounds.height > 0 && bounds.width > 0;
+ }, "Waiting for first device menu item to appear");
+
+ // Click it, which should cause the panel to close.
+ let hiddenPromise =
+ promisePanelHidden(BrowserPageActions._activatedActionPanelID);
+ EventUtils.synthesizeMouseAtCenter(deviceMenuItem, {});
+ info("Waiting for Send to Device panel to close after clicking a device");
+ await hiddenPromise;
+
+ // And then the "Sent!" notification panel should open and close by itself
+ // after a moment.
+ info("Waiting for the Sent! notification panel to open");
+ await promisePanelShown(BrowserPageActionFeedback.panelNode.id);
+ info("Waiting for the Sent! notification panel to close");
+ await promisePanelHidden(BrowserPageActionFeedback.panelNode.id);
+
+ // Remove Send to Device from the urlbar.
+ action.shownInUrlbar = false;
+ BrowserPageActions._disableActivatedActionPanelAnimation = false;
+
+ cleanUp();
+ });
+});
+
add_task(async function contextMenu() {
// Open an actionable page so that the main page action button appears.
let url = "http://example.com/";
await BrowserTestUtils.withNewTab(url, async () => {
// Open the panel and then open the context menu on the bookmark button.
await promisePageActionPanelOpen();
let bookmarkButton = document.getElementById("pageAction-panel-bookmark");
let contextMenuPromise = promisePanelShown("pageActionPanelContextMenu");
@@ -572,19 +672,21 @@ function promiseSyncReady() {
.getService(Components.interfaces.nsISupports)
.wrappedJSObject;
return service.whenLoaded().then(() => {
UIState.isReady();
return UIState.refresh();
});
}
-function checkSendToDeviceItems(expectedItems) {
- let body =
- document.getElementById("pageAction-panel-sendToDevice-subview-body");
+function checkSendToDeviceItems(expectedItems, forUrlbar = false) {
+ let bodyID =
+ BrowserPageActions._panelViewNodeIDForActionID("sendToDevice", forUrlbar) +
+ "-body";
+ let body = document.getElementById(bodyID);
Assert.equal(body.childNodes.length, expectedItems.length);
for (let i = 0; i < expectedItems.length; i++) {
let expected = expectedItems[i];
let actual = body.childNodes[i];
if (!expected) {
Assert.equal(actual.localName, "toolbarseparator");
continue;
}