Bug 1471877 - Add link to share menu to configuration. r=gijs, r=mstange
MozReview-Commit-ID: CCTO9SJJMY6
--- a/browser/base/content/browser-pageActions.js
+++ b/browser/base/content/browser-pageActions.js
@@ -1225,36 +1225,44 @@ BrowserPageActions.shareURL = {
}
let sharingService = this._sharingService;
let url = gBrowser.selectedBrowser.currentURI;
let currentURI = gURLBar.makeURIReadable(url).displaySpec;
let shareProviders = sharingService.getSharingProviders(currentURI);
let fragment = document.createDocumentFragment();
+ let onCommand = event => {
+ let shareName = event.target.getAttribute("share-name");
+ if (shareName) {
+ sharingService.shareUrl(shareName,
+ currentURI,
+ gBrowser.selectedBrowser.contentTitle);
+ } else if (event.target.classList.contains("share-more-button")) {
+ sharingService.openSharingPreferences();
+ }
+ PanelMultiView.hidePopup(BrowserPageActions.panelNode);
+ };
+
shareProviders.forEach(function(share) {
let item = document.createElement("toolbarbutton");
item.setAttribute("label", share.menuItemTitle);
item.setAttribute("share-name", share.name);
item.setAttribute("image", share.image);
item.classList.add("subviewbutton", "subviewbutton-iconic");
-
- item.addEventListener("command", event => {
- let shareName = event.target.getAttribute("share-name");
- if (shareName) {
- sharingService.shareUrl(shareName,
- currentURI,
- gBrowser.selectedBrowser.contentTitle);
- }
- PanelMultiView.hidePopup(BrowserPageActions.panelNode);
- });
-
+ item.addEventListener("command", onCommand);
fragment.appendChild(item);
});
+ let item = document.createElement("toolbarbutton");
+ item.setAttribute("label", BrowserPageActions.panelNode.getAttribute("shareMore-label"));
+ item.classList.add("subviewbutton", "subviewbutton-iconic", "share-more-button");
+ item.addEventListener("command", onCommand);
+ fragment.appendChild(item);
+
while (bodyNode.firstChild) {
bodyNode.firstChild.remove();
}
bodyNode.appendChild(fragment);
this._cached = true;
}
};
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -469,17 +469,18 @@
photon="true"
position="bottomcenter topright"
tabspecific="true"
noautofocus="true"
copyURL-title="&pageAction.copyLink.label;"
emailLink-title="&emailPageCmd.label;"
sendToDevice-title="&pageAction.sendTabToDevice.label;"
sendToDevice-notReadyTitle="&sendToDevice.syncNotReady.label;"
- shareURL-title="&pageAction.shareUrl.label;">
+ shareURL-title="&pageAction.shareUrl.label;"
+ shareMore-label="&pageAction.shareMore.label;">
<panelmultiview id="pageActionPanelMultiView"
mainViewId="pageActionPanelMainView"
viewCacheId="appMenu-viewCache">
<panelview id="pageActionPanelMainView"
context="pageActionContextMenu"
class="PanelUI-subView">
<vbox class="panel-subview-body"/>
</panelview>
--- a/browser/base/content/test/urlbar/browser_page_action_menu_share_mac.js
+++ b/browser/base/content/test/urlbar/browser_page_action_menu_share_mac.js
@@ -5,19 +5,18 @@
"use strict";
/* global sinon */
Services.scriptloader.loadSubScript("resource://testing-common/sinon-2.3.2.js");
const URL = "http://example.org/";
// Keep track of title of service we chose to share with
-let serviceName;
-let sharedUrl;
-let sharedTitle;
+let serviceName, sharedUrl, sharedTitle;
+let sharingPreferencesCalled = false;
let mockShareData = [{
name: "NSA",
menuItemTitle: "National Security Agency",
image: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEA" +
"LAAAAAABAAEAAAICTAEAOw=="
}];
@@ -25,16 +24,19 @@ let stub = sinon.stub(BrowserPageActions
return {
getSharingProviders(url) {
return mockShareData;
},
shareUrl(name, url, title) {
serviceName = name;
sharedUrl = url;
sharedTitle = title;
+ },
+ openSharingPreferences() {
+ sharingPreferencesCalled = true;
}
};
});
registerCleanupFunction(async function() {
stub.restore();
delete window.sinon;
await EventUtils.synthesizeNativeMouseMove(document.documentElement, 0, 0);
@@ -49,17 +51,18 @@ add_task(async function shareURL() {
// Click Share URL.
let shareURLButton = document.getElementById("pageAction-panel-shareURL");
let viewPromise = promisePageActionViewShown();
EventUtils.synthesizeMouseAtCenter(shareURLButton, {});
let view = await viewPromise;
let body = document.getElementById(view.id + "-body");
- Assert.equal(body.childNodes.length, 1, "Has correct share receivers");
+ // We should see 1 receiver and one extra node for the "More..." button
+ Assert.equal(body.childNodes.length, 2, "Has correct share receivers");
let shareButton = body.childNodes[0];
Assert.equal(shareButton.label, mockShareData[0].menuItemTitle);
let hiddenPromise = promisePageActionPanelHidden();
// Click on share, panel should hide and sharingService should be
// given the title of service to share with
EventUtils.synthesizeMouseAtCenter(shareButton, {});
await hiddenPromise;
@@ -102,17 +105,18 @@ add_task(async function shareURLAddressB
// Press the Share button
let shareButton = document.getElementById("pageAction-urlbar-shareURL");
let viewPromise = promisePageActionPanelShown();
EventUtils.synthesizeMouseAtCenter(shareButton, {});
await viewPromise;
// Ensure we have share providers
let panel = document.getElementById("pageAction-urlbar-shareURL-subview-body");
- Assert.equal(panel.childNodes.length, 1, "Has correct share receivers");
+ // We should see 1 receiver and one extra node for the "More..." button
+ Assert.equal(panel.childNodes.length, 2, "Has correct share receivers");
// Remove the Share URL button from the Address bar so we dont interfere
// with future tests
contextMenuPromise = promisePanelShown("pageActionContextMenu");
EventUtils.synthesizeMouseAtCenter(shareButton, {
type: "contextmenu",
button: 2,
});
@@ -120,8 +124,35 @@ add_task(async function shareURLAddressB
contextMenuPromise = promisePanelHidden("pageActionContextMenu");
ctxMenuButton = document.querySelector("#pageActionContextMenu " +
".pageActionContextMenuItem");
EventUtils.synthesizeMouseAtCenter(ctxMenuButton, {});
await contextMenuPromise;
});
});
+
+add_task(async function openSharingPreferences() {
+ await BrowserTestUtils.withNewTab(URL, async () => {
+ // Open the panel.
+ await promisePageActionPanelOpen();
+
+ // Click Share URL.
+ let shareURLButton = document.getElementById("pageAction-panel-shareURL");
+ let viewPromise = promisePageActionViewShown();
+ EventUtils.synthesizeMouseAtCenter(shareURLButton, {});
+
+ let view = await viewPromise;
+ let body = document.getElementById(view.id + "-body");
+
+ // We should see 1 receiver and one extra node for the "More..." button
+ Assert.equal(body.childNodes.length, 2, "Has correct share receivers");
+ let moreButton = body.childNodes[1];
+ let hiddenPromise = promisePageActionPanelHidden();
+ // Click on the "more" button, panel should hide and we should call
+ // the sharingService function to open preferences
+ EventUtils.synthesizeMouseAtCenter(moreButton, {});
+ await hiddenPromise;
+
+ Assert.equal(sharingPreferencesCalled, true,
+ "We called openSharingPreferences");
+ });
+});
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -1026,16 +1026,17 @@ you can use these alternative items. Oth
<!ENTITY pageAction.allowInUrlbar.label "Show in Address Bar">
<!ENTITY pageAction.disallowInUrlbar.label "Don’t Show in Address Bar">
<!ENTITY pageAction.manageExtension.label "Manage Extension…">
<!ENTITY pageAction.sendTabToDevice.label "Send Tab to Device">
<!ENTITY sendToDevice.syncNotReady.label "Syncing Devices…">
<!ENTITY pageAction.shareUrl.label "Share">
+<!ENTITY pageAction.shareMore.label "More…">
<!ENTITY libraryButton.tooltip "View history, saved bookmarks, and more">
<!-- LOCALIZATION NOTE: (accessibilityIndicator.tooltip): This is used to
display a tooltip for accessibility indicator in toolbar/tabbar. It is also
used as a textual label for the indicator used by assistive technology
users. -->
<!ENTITY accessibilityIndicator.tooltip "Accessibility Features Enabled">
--- a/browser/themes/shared/urlbar-searchbar.inc.css
+++ b/browser/themes/shared/urlbar-searchbar.inc.css
@@ -293,17 +293,17 @@
#urlbar[switchingtabs] > .urlbar-textbox-container > .urlbar-history-dropmarker {
transition: none;
}
#nav-bar:not([customizing="true"]) > #nav-bar-customization-target > #urlbar-container:not(:hover) > #urlbar:not([focused]) > .urlbar-textbox-container > .urlbar-history-dropmarker {
opacity: 0;
}
-#pageActionButton {
+#pageActionButton, .share-more-button {
list-style-image: url("chrome://browser/skin/page-action.svg");
}
@keyframes bookmark-animation {
from {
transform: translateX(0);
}
to {
--- a/widget/cocoa/nsMacSharingService.mm
+++ b/widget/cocoa/nsMacSharingService.mm
@@ -17,16 +17,26 @@ NS_IMPL_ISUPPORTS(nsMacSharingService, n
NSArray *filteredProviderNames = @[
@"com.apple.share.System.add-to-safari-reading-list",
@"com.apple.share.Mail.compose"
];
NSString* const remindersServiceName =
@"com.apple.reminders.RemindersShareExtension";
+// These are some undocumented constants also used by Safari
+// to let us open the preferences window
+NSString* const extensionPrefPanePath =
+ @"/System/Library/PreferencePanes/Extensions.prefPane";
+const UInt32 openSharingSubpaneDescriptorType = 'ptru';
+NSString* const openSharingSubpaneActionKey = @"action";
+NSString* const openSharingSubpaneActionValue = @"revealExtensionPoint";
+NSString* const openSharingSubpaneProtocolKey = @"protocol";
+NSString* const openSharingSubpaneProtocolValue = @"com.apple.share-services";
+
// Expose the id so we can pass reference through to JS and back
@interface NSSharingService (ExposeName)
- (id)name;
@end
// Clean up the activity once the share is complete
@interface SharingServiceDelegate : NSObject <NSSharingServiceDelegate>
{
@@ -124,16 +134,50 @@ nsMacSharingService::GetSharingProviders
aResult.setObject(*array);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
+nsMacSharingService::OpenSharingPreferences()
+{
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
+
+ NSURL* prefPaneURL =
+ [NSURL fileURLWithPath:extensionPrefPanePath isDirectory:YES];
+ NSDictionary* args = @{
+ openSharingSubpaneActionKey: openSharingSubpaneActionValue,
+ openSharingSubpaneProtocolKey: openSharingSubpaneProtocolValue
+ };
+ NSData* data =
+ [NSPropertyListSerialization
+ dataWithPropertyList:args
+ format:NSPropertyListXMLFormat_v1_0
+ options:0
+ error:nil];
+ NSAppleEventDescriptor* descriptor =
+ [[NSAppleEventDescriptor alloc]
+ initWithDescriptorType:openSharingSubpaneDescriptorType
+ data:data];
+
+ [[NSWorkspace sharedWorkspace] openURLs:@[ prefPaneURL ]
+ withAppBundleIdentifier:nil
+ options:NSWorkspaceLaunchAsync
+ additionalEventParamDescriptor:descriptor
+ launchIdentifiers:NULL];
+
+ [descriptor release];
+
+ return NS_OK;
+ NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
+}
+
+NS_IMETHODIMP
nsMacSharingService::ShareUrl(const nsAString& aServiceName,
const nsAString& aPageUrl,
const nsAString& aPageTitle)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NSString* serviceName = nsCocoaUtils::ToNSString(aServiceName);
NSURL* pageUrl = [NSURL URLWithString:nsCocoaUtils::ToNSString(aPageUrl)];
--- a/widget/nsIMacSharingService.idl
+++ b/widget/nsIMacSharingService.idl
@@ -17,9 +17,14 @@ interface nsIMacSharingService : nsISupp
[implicit_jscontext] jsval getSharingProviders(in AString pageUrl);
/**
* Launch service with shareTitle with given url
*/
void shareUrl(in AString serviceName,
in AString pageUrl,
in AString pageTitle);
+
+ /**
+ * Open the MacOS preferences window to the sharing panel
+ */
+ void openSharingPreferences();
};