mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Bug 1014332 enable share button by default with default selection of share providers, r=jaws
This commit is contained in:
parent
e47af3ba07
commit
4bc6b9c1be
@ -1588,6 +1588,15 @@ pref("services.push.serverURL", "wss://push.services.mozilla.com/");
|
||||
|
||||
pref("social.sidebar.unload_timeout_ms", 10000);
|
||||
|
||||
// activation from inside of share panel is possible if activationPanelEnabled
|
||||
// is true. Pref'd off for release while usage testing is done through beta.
|
||||
#ifdef RELEASE_BUILD
|
||||
pref("social.share.activationPanelEnabled", false);
|
||||
#else
|
||||
pref("social.share.activationPanelEnabled", true);
|
||||
#endif
|
||||
pref("social.shareDirectory", "https://activations.cdn.mozilla.net/en-US/sharePanel.html");
|
||||
|
||||
pref("dom.identity.enabled", false);
|
||||
|
||||
// Block insecure active content on https pages
|
||||
|
@ -43,12 +43,17 @@
|
||||
|
||||
function parseQueryString() {
|
||||
let url = document.documentURI;
|
||||
let queryString = url.replace(/^about:socialerror\??/, "");
|
||||
var searchParams = new URLSearchParams(url);
|
||||
|
||||
let modeMatch = queryString.match(/mode=([^&]+)/);
|
||||
let mode = modeMatch && modeMatch[1] ? modeMatch[1] : "";
|
||||
let originMatch = queryString.match(/origin=([^&]+)/);
|
||||
config.origin = originMatch && originMatch[1] ? decodeURIComponent(originMatch[1]) : "";
|
||||
let mode = searchParams.get("mode");
|
||||
config.directory = searchParams.get("directory");
|
||||
config.origin = searchParams.get("origin");
|
||||
let encodedURL = searchParams.get("url");
|
||||
let url = decodeURIComponent(encodedURL);
|
||||
if (config.directory) {
|
||||
let URI = Services.io.newURI(url, null, null);
|
||||
config.origin = Services.scriptSecurityManager.getNoAppCodebasePrincipal(URI).origin;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case "compactInfo":
|
||||
@ -59,10 +64,6 @@
|
||||
document.getElementById("btnCloseSidebar").style.display = 'none';
|
||||
//intentional fall-through
|
||||
case "tryAgain":
|
||||
let urlMatch = queryString.match(/url=([^&]+)/);
|
||||
let encodedURL = urlMatch && urlMatch[1] ? urlMatch[1] : "";
|
||||
let url = decodeURIComponent(encodedURL);
|
||||
|
||||
config.tryAgainCallback = loadQueryURL;
|
||||
config.queryURL = url;
|
||||
break;
|
||||
@ -80,7 +81,7 @@
|
||||
|
||||
let productName = brandBundle.GetStringFromName("brandShortName");
|
||||
let provider = Social._getProviderFromOrigin(config.origin);
|
||||
let providerName = provider && provider.name;
|
||||
let providerName = provider ? provider.name : config.origin;
|
||||
|
||||
// Sets up the error message
|
||||
let msg = browserBundle.formatStringFromName("social.error.message", [productName, providerName], 2);
|
||||
|
@ -119,7 +119,7 @@
|
||||
#endif
|
||||
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
|
||||
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
|
||||
<command id="Social:SharePage" oncommand="SocialShare.sharePage();" disabled="true"/>
|
||||
<command id="Social:SharePage" oncommand="SocialShare.sharePage();"/>
|
||||
<command id="Social:ToggleSidebar" oncommand="SocialSidebar.toggleSidebar();" hidden="true"/>
|
||||
<command id="Social:ToggleNotifications" oncommand="Social.toggleNotifications();" hidden="true"/>
|
||||
<command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
|
||||
|
@ -183,7 +183,7 @@ SocialUI = {
|
||||
// about:home or the share panel, we bypass the enable prompt. Any website
|
||||
// activation, such as from the activations directory or a providers website
|
||||
// will still get the prompt.
|
||||
_activationEventHandler: function SocialUI_activationHandler(e, aBypassUserEnable=false) {
|
||||
_activationEventHandler: function SocialUI_activationHandler(e, options={}) {
|
||||
let targetDoc;
|
||||
let node;
|
||||
if (e.target instanceof HTMLDocument) {
|
||||
@ -197,7 +197,9 @@ SocialUI = {
|
||||
if (!(targetDoc instanceof HTMLDocument))
|
||||
return;
|
||||
|
||||
if (!aBypassUserEnable && targetDoc.defaultView != content)
|
||||
// The share panel iframe will not match "content" so it passes a bypass
|
||||
// flag
|
||||
if (!options.bypassContentCheck && targetDoc.defaultView != content)
|
||||
return;
|
||||
|
||||
// If we are in PB mode, we silently do nothing (bug 829404 exists to
|
||||
@ -233,11 +235,25 @@ SocialUI = {
|
||||
if (provider.sidebarURL) {
|
||||
SocialSidebar.show(provider.origin);
|
||||
}
|
||||
if (provider.shareURL) {
|
||||
// make this new provider the selected provider. If the panel hasn't
|
||||
// been opened, we need to make the frame first.
|
||||
SocialShare._createFrame();
|
||||
SocialShare.iframe.setAttribute('src', 'data:text/plain;charset=utf8,');
|
||||
SocialShare.iframe.setAttribute('origin', provider.origin);
|
||||
// get the right button selected
|
||||
SocialShare.populateProviderMenu();
|
||||
if (SocialShare.panel.state == "open") {
|
||||
SocialShare.sharePage(provider.origin);
|
||||
}
|
||||
}
|
||||
if (provider.postActivationURL) {
|
||||
openUILinkIn(provider.postActivationURL, "tab");
|
||||
// if activated from an open share panel, we load the landing page in
|
||||
// a background tab
|
||||
gBrowser.loadOneTab(provider.postActivationURL, {inBackground: SocialShare.panel.state == "open"});
|
||||
}
|
||||
});
|
||||
}, aBypassUserEnable);
|
||||
}, options);
|
||||
},
|
||||
|
||||
showLearnMore: function() {
|
||||
@ -290,10 +306,10 @@ SocialUI = {
|
||||
// called on tab/urlbar/location changes and after customization. Update
|
||||
// anything that is tab specific.
|
||||
updateState: function() {
|
||||
SocialShare.update();
|
||||
if (!SocialUI.enabled)
|
||||
return;
|
||||
SocialMarks.update();
|
||||
SocialShare.update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -434,6 +450,12 @@ SocialFlyout = {
|
||||
}
|
||||
|
||||
SocialShare = {
|
||||
get _dynamicResizer() {
|
||||
delete this._dynamicResizer;
|
||||
this._dynamicResizer = new DynamicResizeWatcher();
|
||||
return this._dynamicResizer;
|
||||
},
|
||||
|
||||
// Share panel may be attached to the overflow or menu button depending on
|
||||
// customization, we need to manage open state of the anchor.
|
||||
get anchor() {
|
||||
@ -452,15 +474,27 @@ SocialShare = {
|
||||
return this.panel.lastChild;
|
||||
},
|
||||
|
||||
get activationPanelEnabled () {
|
||||
// ability to pref off for release
|
||||
return Services.prefs.getBoolPref("social.share.activationPanelEnabled");
|
||||
},
|
||||
|
||||
_activationHandler: function(event) {
|
||||
if (!SocialShare.activationPanelEnabled)
|
||||
return;
|
||||
SocialUI._activationEventHandler(event, { bypassContentCheck: true, bypassInstallPanel: true });
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
if (this.iframe) {
|
||||
this.iframe.removeEventListener("ActivateSocialFeature", this._activationHandler, true, true);
|
||||
this.iframe.remove();
|
||||
}
|
||||
},
|
||||
|
||||
_createFrame: function() {
|
||||
let panel = this.panel;
|
||||
if (!SocialUI.enabled || this.iframe)
|
||||
if (this.iframe)
|
||||
return;
|
||||
this.panel.hidden = false;
|
||||
// create and initialize the panel for this window
|
||||
@ -472,6 +506,7 @@ SocialShare = {
|
||||
iframe.setAttribute("disableglobalhistory", "true");
|
||||
iframe.setAttribute("flex", "1");
|
||||
panel.appendChild(iframe);
|
||||
this.iframe.addEventListener("ActivateSocialFeature", this._activationHandler, true, true);
|
||||
this.populateProviderMenu();
|
||||
},
|
||||
|
||||
@ -481,11 +516,19 @@ SocialShare = {
|
||||
if (lastProviderOrigin) {
|
||||
provider = Social._getProviderFromOrigin(lastProviderOrigin);
|
||||
}
|
||||
// if we are able to activate a provider we don't need to do anything fancy
|
||||
// here, the user will land on the activation panel if no previously
|
||||
// selected provider is available.
|
||||
if (this.activationPanelEnabled)
|
||||
return provider;
|
||||
|
||||
// if they have a provider selected in the sidebar use that for the initial
|
||||
// default in share
|
||||
if (!provider)
|
||||
provider = SocialSidebar.provider;
|
||||
// if our provider has no shareURL, select the first one that does
|
||||
// if our provider has no shareURL, select the first one that does. If we
|
||||
// have no selected provider and activation is available, default to that
|
||||
// panel.
|
||||
if (!provider || !provider.shareURL) {
|
||||
let providers = [p for (p of Social.providers) if (p.shareURL)];
|
||||
provider = providers.length > 0 && providers[0];
|
||||
@ -498,17 +541,12 @@ SocialShare = {
|
||||
return;
|
||||
let providers = [p for (p of Social.providers) if (p.shareURL)];
|
||||
let hbox = document.getElementById("social-share-provider-buttons");
|
||||
// selectable providers are inserted before the provider-menu seperator,
|
||||
// remove any menuitems in that area
|
||||
while (hbox.firstChild) {
|
||||
// remove everything before the add-share-provider button (which should also
|
||||
// be lastChild if any share providers were added)
|
||||
let addButton = document.getElementById("add-share-provider");
|
||||
while (hbox.firstChild != addButton) {
|
||||
hbox.removeChild(hbox.firstChild);
|
||||
}
|
||||
// reset our share toolbar
|
||||
// only show a selection if there is more than one
|
||||
if (!SocialUI.enabled || providers.length < 2) {
|
||||
this.panel.firstChild.hidden = true;
|
||||
return;
|
||||
}
|
||||
let selectedProvider = this.getSelectedProvider();
|
||||
for (let provider of providers) {
|
||||
let button = document.createElement("toolbarbutton");
|
||||
@ -518,17 +556,16 @@ SocialShare = {
|
||||
button.setAttribute("image", provider.iconURL);
|
||||
button.setAttribute("tooltiptext", provider.name);
|
||||
button.setAttribute("origin", provider.origin);
|
||||
button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin')); this.checked=true;");
|
||||
button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin'));");
|
||||
if (provider == selectedProvider) {
|
||||
this.defaultButton = button;
|
||||
}
|
||||
hbox.appendChild(button);
|
||||
hbox.insertBefore(button, addButton);
|
||||
}
|
||||
if (!this.defaultButton) {
|
||||
this.defaultButton = hbox.firstChild
|
||||
this.defaultButton = this.activationPanelEnabled ? addButton : hbox.firstChild;
|
||||
}
|
||||
this.defaultButton.setAttribute("checked", "true");
|
||||
this.panel.firstChild.hidden = false;
|
||||
},
|
||||
|
||||
get shareButton() {
|
||||
@ -560,8 +597,8 @@ SocialShare = {
|
||||
let shareButton = widget.forWindow(window).node;
|
||||
// hidden state is based on available share providers and location of
|
||||
// button. It's always visible and disabled in the customization palette.
|
||||
shareButton.hidden = !SocialUI.enabled || (widget.areaType &&
|
||||
[p for (p of Social.providers) if (p.shareURL)].length == 0);
|
||||
shareButton.hidden = !this.activationPanelEnabled && (!SocialUI.enabled || (widget.areaType &&
|
||||
[p for (p of Social.providers) if (p.shareURL)].length == 0));
|
||||
let disabled = !widget.areaType || shareButton.hidden || !this.canSharePage(gBrowser.currentURI);
|
||||
|
||||
// 1. update the relevent command's disabled state so the keyboard
|
||||
@ -577,6 +614,9 @@ SocialShare = {
|
||||
cmd.removeAttribute("disabled");
|
||||
shareButton.removeAttribute("disabled");
|
||||
}
|
||||
|
||||
// enable or disable the activation panel
|
||||
document.getElementById("add-share-provider").hidden = !this.activationPanelEnabled;
|
||||
},
|
||||
|
||||
_onclick: function() {
|
||||
@ -608,10 +648,15 @@ SocialShare = {
|
||||
if (!iframe)
|
||||
return;
|
||||
|
||||
iframe.removeAttribute("src");
|
||||
iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
|
||||
encodeURIComponent(iframe.getAttribute("origin")),
|
||||
null, null, null, null);
|
||||
let url;
|
||||
let origin = iframe.getAttribute("origin");
|
||||
if (!origin && this.activationPanelEnabled) {
|
||||
// directory site is down
|
||||
url = "about:socialerror?mode=tryAgainOnly&directory=1&url=" + encodeURIComponent(iframe.getAttribute("src"));
|
||||
} else {
|
||||
url = "about:socialerror?mode=compactInfo&origin=" + encodeURIComponent(origin);
|
||||
}
|
||||
iframe.webNavigation.loadURI(url, null, null, null, null);
|
||||
sizeSocialPanelToContent(this.panel, iframe);
|
||||
},
|
||||
|
||||
@ -621,13 +666,6 @@ SocialShare = {
|
||||
// will call sharePage with an origin for us to switch to.
|
||||
this._createFrame();
|
||||
let iframe = this.iframe;
|
||||
let provider;
|
||||
if (providerOrigin)
|
||||
provider = Social._getProviderFromOrigin(providerOrigin);
|
||||
else
|
||||
provider = this.getSelectedProvider();
|
||||
if (!provider || !provider.shareURL)
|
||||
return;
|
||||
|
||||
// graphData is an optional param that either defines the full set of data
|
||||
// to be shared, or partial data about the current page. It is set by a call
|
||||
@ -659,20 +697,25 @@ SocialShare = {
|
||||
}
|
||||
this.currentShare = pageData;
|
||||
|
||||
let provider;
|
||||
if (providerOrigin)
|
||||
provider = Social._getProviderFromOrigin(providerOrigin);
|
||||
else
|
||||
provider = this.getSelectedProvider();
|
||||
if (!provider || !provider.shareURL) {
|
||||
this.showDirectory();
|
||||
return;
|
||||
}
|
||||
// check the menu button
|
||||
let hbox = document.getElementById("social-share-provider-buttons");
|
||||
let btn = hbox.querySelector("[origin='" + provider.origin + "']");
|
||||
btn.checked = true;
|
||||
|
||||
let shareEndpoint = OpenGraphBuilder.generateEndpointURL(provider.shareURL, pageData);
|
||||
|
||||
let size = provider.getPageSize("share");
|
||||
if (size) {
|
||||
if (this._dynamicResizer) {
|
||||
this._dynamicResizer.stop();
|
||||
this._dynamicResizer = null;
|
||||
}
|
||||
let {width, height} = size;
|
||||
width += this.panel.boxObject.width - iframe.boxObject.width;
|
||||
height += this.panel.boxObject.height - iframe.boxObject.height;
|
||||
this.panel.sizeTo(width, height);
|
||||
} else {
|
||||
this._dynamicResizer = new DynamicResizeWatcher();
|
||||
this._dynamicResizer.stop();
|
||||
}
|
||||
|
||||
// if we've already loaded this provider/page share endpoint, we don't want
|
||||
@ -684,7 +727,7 @@ SocialShare = {
|
||||
reload = shareEndpoint != iframe.contentDocument.location.spec;
|
||||
}
|
||||
if (!reload) {
|
||||
if (this._dynamicResizer)
|
||||
if (!size)
|
||||
this._dynamicResizer.start(this.panel, iframe);
|
||||
iframe.docShell.isActive = true;
|
||||
iframe.docShell.isAppTab = true;
|
||||
@ -702,7 +745,13 @@ SocialShare = {
|
||||
// should close the window when done.
|
||||
iframe.contentWindow.opener = iframe.contentWindow;
|
||||
setTimeout(function() {
|
||||
if (SocialShare._dynamicResizer) { // may go null if hidden quickly
|
||||
if (size) {
|
||||
let panel = SocialShare.panel;
|
||||
let {width, height} = size;
|
||||
width += panel.boxObject.width - iframe.boxObject.width;
|
||||
height += panel.boxObject.height - iframe.boxObject.height;
|
||||
panel.sizeTo(width, height);
|
||||
} else {
|
||||
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
|
||||
}
|
||||
}, 0);
|
||||
@ -723,10 +772,32 @@ SocialShare = {
|
||||
let uri = Services.io.newURI(shareEndpoint, null, null);
|
||||
iframe.setAttribute("origin", provider.origin);
|
||||
iframe.setAttribute("src", shareEndpoint);
|
||||
this._openPanel();
|
||||
},
|
||||
|
||||
showDirectory: function() {
|
||||
let url = Services.prefs.getCharPref("social.shareDirectory");
|
||||
this._createFrame();
|
||||
let iframe = this.iframe;
|
||||
iframe.removeAttribute("origin");
|
||||
iframe.setAttribute("src", url);
|
||||
iframe.addEventListener("load", function panelBrowserOnload(e) {
|
||||
iframe.removeEventListener("load", panelBrowserOnload, true);
|
||||
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
|
||||
|
||||
iframe.addEventListener("unload", function panelBrowserOnload(e) {
|
||||
iframe.removeEventListener("unload", panelBrowserOnload, true);
|
||||
SocialShare._dynamicResizer.stop();
|
||||
}, true);
|
||||
|
||||
}, true);
|
||||
this._openPanel();
|
||||
},
|
||||
|
||||
_openPanel: function() {
|
||||
let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
|
||||
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
|
||||
Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
|
||||
Social.setErrorListener(this.iframe, this.setErrorMessage.bind(this));
|
||||
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
|
||||
}
|
||||
};
|
||||
|
@ -246,7 +246,11 @@
|
||||
onpopuphidden="SocialShare.onHidden()"
|
||||
hidden="true">
|
||||
<vbox class="social-share-toolbar">
|
||||
<arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1"/>
|
||||
<arrowscrollbox id="social-share-provider-buttons" orient="vertical" flex="1">
|
||||
<toolbarbutton id="add-share-provider" class="toolbarbutton share-provider-button" type="radio"
|
||||
group="share-providers" tooltiptext="&findShareServices.label;"
|
||||
oncommand="SocialShare.showDirectory()"/>
|
||||
</arrowscrollbox>
|
||||
</vbox>
|
||||
</panel>
|
||||
|
||||
|
@ -11,6 +11,7 @@ support-files =
|
||||
opengraph/shorturl_linkrel.html
|
||||
microdata.html
|
||||
share.html
|
||||
share_activate.html
|
||||
social_activate.html
|
||||
social_activate_iframe.html
|
||||
social_chat.html
|
||||
|
@ -10,10 +10,46 @@ let manifest = { // normal provider
|
||||
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
|
||||
shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
|
||||
};
|
||||
let activationPage = "https://example.com/browser/browser/base/content/test/social/share_activate.html";
|
||||
|
||||
function waitForProviderEnabled(cb) {
|
||||
Services.obs.addObserver(function providerSet(subject, topic, data) {
|
||||
Services.obs.removeObserver(providerSet, "social:provider-enabled");
|
||||
info("social:provider-enabled observer was notified");
|
||||
cb();
|
||||
}, "social:provider-enabled", false);
|
||||
}
|
||||
|
||||
function sendActivationEvent(callback) {
|
||||
// hack Social.lastEventReceived so we don't hit the "too many events" check.
|
||||
Social.lastEventReceived = 0;
|
||||
let doc = SocialShare.iframe.contentDocument;
|
||||
// if our test has a frame, use it
|
||||
let button = doc.getElementById("activation");
|
||||
ok(!!button, "got the activation button");
|
||||
EventUtils.synthesizeMouseAtCenter(button, {}, doc.defaultView);
|
||||
if (callback)
|
||||
executeSoon(callback);
|
||||
}
|
||||
|
||||
function waitForEvent(iframe, eventName, callback) {
|
||||
iframe.addEventListener(eventName, function load() {
|
||||
info("page load is "+iframe.contentDocument.location.href);
|
||||
if (iframe.contentDocument.location.href != "data:text/plain;charset=utf8,") {
|
||||
iframe.removeEventListener(eventName, load, true);
|
||||
executeSoon(callback);
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function test() {
|
||||
waitForExplicitFinish();
|
||||
|
||||
Services.prefs.setCharPref("social.shareDirectory", activationPage);
|
||||
registerCleanupFunction(function () {
|
||||
Services.prefs.clearUserPref("social.directories");
|
||||
Services.prefs.clearUserPref("social.shareDirectory");
|
||||
Services.prefs.clearUserPref("social.share.activationPanelEnabled");
|
||||
});
|
||||
runSocialTests(tests);
|
||||
}
|
||||
|
||||
@ -75,11 +111,10 @@ let corpus = [
|
||||
function loadURLInTab(url, callback) {
|
||||
info("Loading tab with "+url);
|
||||
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
|
||||
tab.linkedBrowser.addEventListener("load", function listener() {
|
||||
waitForEvent(tab.linkedBrowser, "load", () => {
|
||||
is(tab.linkedBrowser.currentURI.spec, url, "tab loaded")
|
||||
tab.linkedBrowser.removeEventListener("load", listener, true);
|
||||
executeSoon(function() { callback(tab) });
|
||||
}, true);
|
||||
callback(tab)
|
||||
});
|
||||
}
|
||||
|
||||
function hasoptions(testOptions, options) {
|
||||
@ -110,7 +145,6 @@ var tests = {
|
||||
checkSocialUI();
|
||||
// share should not be enabled since we only have about:blank page
|
||||
let shareButton = SocialShare.shareButton;
|
||||
is(shareButton.disabled, true, "share button is disabled");
|
||||
// verify the attribute for proper css
|
||||
is(shareButton.getAttribute("disabled"), "true", "share button attribute is disabled");
|
||||
// button should be visible
|
||||
@ -128,7 +162,6 @@ var tests = {
|
||||
checkSocialUI();
|
||||
// share should not be enabled since we only have about:blank page
|
||||
let shareButton = SocialShare.shareButton;
|
||||
is(shareButton.disabled, false, "share button is enabled");
|
||||
// verify the attribute for proper css
|
||||
ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
|
||||
// button should be visible
|
||||
@ -149,7 +182,7 @@ var tests = {
|
||||
function runOneTest() {
|
||||
loadURLInTab(testData.url, function(tab) {
|
||||
testTab = tab;
|
||||
SocialShare.sharePage();
|
||||
SocialShare.sharePage(manifest.origin);
|
||||
});
|
||||
}
|
||||
|
||||
@ -241,5 +274,46 @@ var tests = {
|
||||
SocialShare.sharePage(manifest.origin, null, target);
|
||||
});
|
||||
});
|
||||
},
|
||||
testSharePanelActivation: function(next) {
|
||||
let testTab;
|
||||
// cleared in the cleanup function
|
||||
Services.prefs.setCharPref("social.directories", "https://example.com");
|
||||
Services.prefs.setBoolPref("social.share.activationPanelEnabled", true);
|
||||
// make the iframe so we can wait on the load
|
||||
SocialShare._createFrame();
|
||||
let iframe = SocialShare.iframe;
|
||||
|
||||
waitForEvent(iframe, "load", () => {
|
||||
waitForCondition(() => {
|
||||
// sometimes the iframe is ready before the panel is open, we need to
|
||||
// wait for both conditions
|
||||
return SocialShare.panel.state == "open";
|
||||
}, () => {
|
||||
is(iframe.contentDocument.location.href, activationPage, "activation page loaded");
|
||||
waitForProviderEnabled(() => {
|
||||
let provider = Social._getProviderFromOrigin(manifest.origin);
|
||||
let port = provider.getWorkerPort();
|
||||
ok(!!port, "got port");
|
||||
port.onmessage = function (e) {
|
||||
let topic = e.data.topic;
|
||||
info("got topic "+topic+"\n");
|
||||
switch (topic) {
|
||||
case "got-share-data-message":
|
||||
ok(true, "share completed");
|
||||
gBrowser.removeTab(testTab);
|
||||
SocialService.uninstallProvider(manifest.origin, next);
|
||||
break;
|
||||
}
|
||||
}
|
||||
port.postMessage({topic: "test-init"});
|
||||
});
|
||||
sendActivationEvent();
|
||||
}, "share panel did not open and load share page");
|
||||
});
|
||||
loadURLInTab(activationPage, function(tab) {
|
||||
testTab = tab;
|
||||
SocialShare.sharePage();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
36
browser/base/content/test/social/share_activate.html
Normal file
36
browser/base/content/test/social/share_activate.html
Normal file
@ -0,0 +1,36 @@
|
||||
<html>
|
||||
<!-- 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/. -->
|
||||
<head>
|
||||
<title>Activation test</title>
|
||||
</head>
|
||||
<script>
|
||||
|
||||
var data = {
|
||||
// currently required
|
||||
"name": "Demo Social Service",
|
||||
// browser_share.js serves this page from "https://example.com"
|
||||
"origin": "https://example.com",
|
||||
"iconURL": "chrome://branding/content/icon16.png",
|
||||
"icon32URL": "chrome://branding/content/favicon32.png",
|
||||
"icon64URL": "chrome://branding/content/icon64.png",
|
||||
"workerURL": "/browser/browser/base/content/test/social/social_worker.js",
|
||||
"shareURL": "/browser/browser/base/content/test/social/share.html"
|
||||
}
|
||||
|
||||
function activate(node) {
|
||||
node.setAttribute("data-service", JSON.stringify(data));
|
||||
var event = new CustomEvent("ActivateSocialFeature");
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
|
||||
</script>
|
||||
<body>
|
||||
|
||||
nothing to see here
|
||||
|
||||
<button id="activation" onclick="activate(this, true)">Activate the share provider</button>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -140,6 +140,7 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
<!ENTITY editThisBookmarkCmd.label "Edit This Bookmark">
|
||||
<!ENTITY bookmarkThisPageCmd.commandkey "d">
|
||||
<!ENTITY markPageCmd.commandkey "l">
|
||||
<!ENTITY findShareServices.label "Find more Share services…">
|
||||
<!ENTITY sharePageCmd.label "Share This Page">
|
||||
<!ENTITY sharePageCmd.commandkey "S">
|
||||
<!ENTITY sharePageCmd.accesskey "s">
|
||||
|
@ -363,7 +363,8 @@ SocialErrorListener.prototype = {
|
||||
if (failure && aStatus != Components.results.NS_BINDING_ABORTED) {
|
||||
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
|
||||
let provider = Social._getProviderFromOrigin(this.iframe.getAttribute("origin"));
|
||||
provider.errorState = "content-error";
|
||||
if (provider && !provider.errorState)
|
||||
provider.errorState = "content-error";
|
||||
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
|
||||
.chromeEventHandler);
|
||||
}
|
||||
@ -373,7 +374,7 @@ SocialErrorListener.prototype = {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
|
||||
let provider = Social._getProviderFromOrigin(this.iframe.getAttribute("origin"));
|
||||
if (!provider.errorState)
|
||||
if (provider && !provider.errorState)
|
||||
provider.errorState = "content-error";
|
||||
schedule(function() {
|
||||
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
|
||||
|
@ -1313,6 +1313,11 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
#add-share-provider {
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
|
||||
-moz-image-region: rect(0px, 192px, 32px, 160px);
|
||||
}
|
||||
|
||||
#loop-call-button > .toolbarbutton-badge-container {
|
||||
list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
|
||||
-moz-image-region: rect(0, 36px, 36px, 0);
|
||||
|
@ -218,3 +218,8 @@ toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
|
||||
toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
||||
|
||||
#add-share-provider {
|
||||
list-style-image: url(chrome://browser/skin/menuPanel-small.png);
|
||||
-moz-image-region: rect(0px, 96px, 16px, 80px);
|
||||
}
|
@ -585,26 +585,24 @@ this.SocialService = {
|
||||
action, [], options);
|
||||
},
|
||||
|
||||
installProvider: function(aDOMDocument, data, installCallback, aBypassUserEnable=false) {
|
||||
installProvider: function(aDOMDocument, data, installCallback, options={}) {
|
||||
let manifest;
|
||||
let installOrigin = aDOMDocument.nodePrincipal.origin;
|
||||
|
||||
if (data) {
|
||||
let installType = getOriginActivationType(installOrigin);
|
||||
// if we get data, we MUST have a valid manifest generated from the data
|
||||
manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
|
||||
if (!manifest)
|
||||
throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
|
||||
let installType = getOriginActivationType(installOrigin);
|
||||
// if we get data, we MUST have a valid manifest generated from the data
|
||||
manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
|
||||
if (!manifest)
|
||||
throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
|
||||
|
||||
let addon = new AddonWrapper(manifest);
|
||||
if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
|
||||
throw new Error("installProvider: provider with origin [" +
|
||||
installOrigin + "] is blocklisted");
|
||||
// manifestFromData call above will enforce correct origin. To support
|
||||
// activation from about: uris, we need to be sure to use the updated
|
||||
// origin on the manifest.
|
||||
installOrigin = manifest.origin;
|
||||
}
|
||||
let addon = new AddonWrapper(manifest);
|
||||
if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
|
||||
throw new Error("installProvider: provider with origin [" +
|
||||
installOrigin + "] is blocklisted");
|
||||
// manifestFromData call above will enforce correct origin. To support
|
||||
// activation from about: uris, we need to be sure to use the updated
|
||||
// origin on the manifest.
|
||||
installOrigin = manifest.origin;
|
||||
|
||||
let id = getAddonIDFromOrigin(installOrigin);
|
||||
AddonManager.getAddonByID(id, function(aAddon) {
|
||||
@ -613,7 +611,7 @@ this.SocialService = {
|
||||
aAddon.userDisabled = false;
|
||||
}
|
||||
schedule(function () {
|
||||
this._installProvider(aDOMDocument, manifest, aBypassUserEnable, aManifest => {
|
||||
this._installProvider(aDOMDocument, manifest, options, aManifest => {
|
||||
this._notifyProviderListeners("provider-installed", aManifest.origin);
|
||||
installCallback(aManifest);
|
||||
});
|
||||
@ -621,43 +619,21 @@ this.SocialService = {
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
_installProvider: function(aDOMDocument, manifest, aBypassUserEnable, installCallback) {
|
||||
let sourceURI = aDOMDocument.location.href;
|
||||
let installOrigin = aDOMDocument.nodePrincipal.origin;
|
||||
_installProvider: function(aDOMDocument, manifest, options, installCallback) {
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
|
||||
let installType = getOriginActivationType(installOrigin);
|
||||
let installer;
|
||||
switch(installType) {
|
||||
case "foreign":
|
||||
if (!Services.prefs.getBoolPref("social.remote-install.enabled"))
|
||||
throw new Error("Remote install of services is disabled");
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
let installType = getOriginActivationType(aDOMDocument.nodePrincipal.origin);
|
||||
if (installType == "foreign" && !Services.prefs.getBoolPref("social.remote-install.enabled"))
|
||||
throw new Error("Remote install of services is disabled");
|
||||
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
break;
|
||||
case "internal":
|
||||
// double check here since "builtin" falls through this as well.
|
||||
aBypassUserEnable = installType == "internal" && manifest.oneclick;
|
||||
case "directory":
|
||||
// a manifest is requried, and will have been vetted by reviewers. We
|
||||
// also handle in-product installations without the verification step.
|
||||
if (aBypassUserEnable) {
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
installer.install();
|
||||
return;
|
||||
}
|
||||
// a manifest is required, we'll catch a missing manifest below.
|
||||
if (!manifest)
|
||||
throw new Error("Cannot install provider without manifest data");
|
||||
installer = new AddonInstaller(sourceURI, manifest, installCallback);
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
break;
|
||||
default:
|
||||
throw new Error("SocialService.installProvider: Invalid install type "+installType+"\n");
|
||||
break;
|
||||
}
|
||||
let installer = new AddonInstaller(aDOMDocument.location.href, manifest, installCallback);
|
||||
let bypassPanel = options.bypassInstallPanel ||
|
||||
(installType == "internal" && manifest.oneclick);
|
||||
if (bypassPanel)
|
||||
installer.install();
|
||||
else
|
||||
this._showInstallNotification(aDOMDocument, installer);
|
||||
},
|
||||
|
||||
createWrapper: function(manifest) {
|
||||
|
Loading…
Reference in New Issue
Block a user