1
0
mirror of https://github.com/roytam1/UXP.git synced 2026-05-26 22:13:05 +00:00

Revert "Remove the Social API"

This commit is contained in:
Moonchild
2018-05-25 20:45:48 +00:00
committed by Roy Tam
parent d7e628ffa5
commit aa52f6bd53
52 changed files with 2895 additions and 16 deletions
+7
View File
@@ -1118,6 +1118,13 @@ pref("pdfjs.previousHandler.alwaysAskBeforeHandling", false);
// (This is intentionally on the high side; see bug 746055.)
pref("image.mem.max_decoded_image_kb", 256000);
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.
pref("social.share.activationPanelEnabled", true);
pref("social.shareDirectory", "https://activations.cdn.mozilla.net/sharePanel.html");
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd" >
%brandDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&social.directory.label;</title>
<link rel="stylesheet" type="text/css" media="all"
href="chrome://browser/skin/aboutProviderDirectory.css"/>
</head>
<body>
<div id="activation-link" hidden="true">
<div id="message-box">
<p>&social.directory.text;</p>
</div>
<div id="button-box">
<button onclick="openDirectory()">&social.directory.button;</button>
</div>
</div>
<div id="activation" hidden="true">
<p>&social.directory.introText;</p>
<div><iframe id="activation-frame"/></div>
<p><a class="link" onclick="openDirectory()">&social.directory.viewmore.text;</a></p>
</div>
</body>
<script type="text/javascript;version=1.8"><![CDATA[
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
function openDirectory() {
let url = Services.prefs.getCharPref("social.directories").split(',')[0];
window.open(url);
window.close();
}
if (Services.prefs.getBoolPref("social.share.activationPanelEnabled")) {
let url = Services.prefs.getCharPref("social.shareDirectory");
document.getElementById("activation-frame").setAttribute("src", url);
document.getElementById("activation").removeAttribute("hidden");
} else {
document.getElementById("activation-link").removeAttribute("hidden");
}
]]></script>
</html>
+111
View File
@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="UTF-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/. -->
<!DOCTYPE html [
<!ENTITY % htmlDTD
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"DTD/xhtml1-strict.dtd">
%htmlDTD;
<!ENTITY % netErrorDTD SYSTEM "chrome://global/locale/netError.dtd">
%netErrorDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>&loadError.label;</title>
<link rel="stylesheet" href="chrome://browser/skin/aboutNetError.css" type="text/css" media="all" />
<link rel="stylesheet" type="text/css" media="all" href="chrome://browser/skin/aboutSocialError.css"/>
<link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/warning-16.png"/>
</head>
<body>
<div id="errorPageContainer">
<!-- Error Title -->
<div id="errorTitle">
<p id="errorShortDescText" >foo</p>
</div>
<div id="button-box">
<button id="btnTryAgain" onclick="tryAgainButton()"/>
</div>
</div>
</body>
<script type="text/javascript;version=1.8"><![CDATA[
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/Social.jsm");
let config = {
tryAgainCallback: reloadProvider
}
function parseQueryString() {
let searchParams = new URLSearchParams(document.documentURI.split("?")[1]);
let mode = searchParams.get("mode");
config.origin = searchParams.get("origin");
let encodedURL = searchParams.get("url");
let url = decodeURIComponent(encodedURL);
// directory does not have origin set, in that case use the url origin for
// the error message.
if (!config.origin) {
let URI = Services.io.newURI(url, null, null);
config.origin =
Services.scriptSecurityManager.createCodebasePrincipal(URI, {}).origin;
}
switch (mode) {
case "compactInfo":
document.getElementById("btnTryAgain").style.display = 'none';
break;
case "tryAgainOnly":
//intentional fall-through
case "tryAgain":
config.tryAgainCallback = loadQueryURL;
config.queryURL = url;
break;
default:
break;
}
}
function setUpStrings() {
let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
let productName = brandBundle.GetStringFromName("brandShortName");
let provider = Social._getProviderFromOrigin(config.origin);
let providerName = provider ? provider.name : config.origin;
// Sets up the error message
let msg = browserBundle.formatStringFromName("social.error.message", [productName, providerName], 2);
document.getElementById("errorShortDescText").textContent = msg;
// Sets up the buttons' labels and accesskeys
let btnTryAgain = document.getElementById("btnTryAgain");
btnTryAgain.textContent = browserBundle.GetStringFromName("social.error.tryAgain.label");
btnTryAgain.accessKey = browserBundle.GetStringFromName("social.error.tryAgain.accesskey");
}
function tryAgainButton() {
config.tryAgainCallback();
}
function loadQueryURL() {
window.location.href = config.queryURL;
}
function reloadProvider() {
let provider = Social._getProviderFromOrigin(config.origin);
provider.reload();
}
parseQueryString();
setUpStrings();
]]></script>
</html>
+20
View File
@@ -85,6 +85,10 @@
label="&bookmarkThisLinkCmd.label;"
accesskey="&bookmarkThisLinkCmd.accesskey;"
oncommand="gContextMenu.bookmarkLink();"/>
<menuitem id="context-sharelink"
label="&shareLink.label;"
accesskey="&shareLink.accesskey;"
oncommand="gContextMenu.shareLink();"/>
<menuitem id="context-savelink"
label="&saveLinkCmd.label;"
accesskey="&saveLinkCmd.accesskey;"
@@ -208,6 +212,10 @@
label="&saveImageCmd.label;"
accesskey="&saveImageCmd.accesskey;"
oncommand="gContextMenu.saveMedia();"/>
<menuitem id="context-shareimage"
label="&shareImage.label;"
accesskey="&shareImage.accesskey;"
oncommand="gContextMenu.shareImage();"/>
<menuitem id="context-sendimage"
label="&emailImageCmd.label;"
accesskey="&emailImageCmd.accesskey;"
@@ -229,6 +237,10 @@
label="&saveVideoCmd.label;"
accesskey="&saveVideoCmd.accesskey;"
oncommand="gContextMenu.saveMedia();"/>
<menuitem id="context-sharevideo"
label="&shareVideo.label;"
accesskey="&shareVideo.accesskey;"
oncommand="gContextMenu.shareVideo();"/>
<menuitem id="context-saveaudio"
label="&saveAudioCmd.label;"
accesskey="&saveAudioCmd.accesskey;"
@@ -259,6 +271,10 @@
accesskey="&hidePluginCmd.accesskey;"
oncommand="gContextMenu.hidePlugin();"/>
<menuseparator id="context-sep-ctp"/>
<menuitem id="context-sharepage"
label="&sharePageCmd.label;"
accesskey="&sharePageCmd.accesskey;"
oncommand="SocialShare.sharePage();"/>
<menuitem id="context-savepage"
label="&savePageCmd.label;"
accesskey="&savePageCmd.accesskey2;"
@@ -318,6 +334,10 @@
<menupopup id="context-sendlinktodevice-popup"
onpopupshowing="gFxAccounts.populateSendTabToDevicesMenu(event.target, gContextMenu.linkURL, gContextMenu.linkTextStr);"/>
</menu>
<menuitem id="context-shareselect"
label="&shareSelect.label;"
accesskey="&shareSelect.accesskey;"
oncommand="gContextMenu.shareSelect();"/>
<menuseparator id="frame-sep"/>
<menu id="frame" label="&thisFrameMenu.label;" accesskey="&thisFrameMenu.accesskey;">
<menupopup>
+3
View File
@@ -105,6 +105,8 @@
oncommand="OpenBrowserWindow({private: true});" reserved="true"/>
<command id="History:UndoCloseTab" oncommand="undoCloseTab();"/>
<command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/>
<command id="Social:SharePage" oncommand="SocialShare.sharePage();"/>
<command id="Social:Addons" oncommand="BrowserOpenAddonsMgr('addons://list/service');"/>
</commandset>
<commandset id="placesCommands">
@@ -115,6 +117,7 @@
</commandset>
<broadcasterset id="mainBroadcasterSet">
<broadcaster id="Social:PageShareable" disabled="true"/>
<broadcaster id="viewBookmarksSidebar" autoCheck="false" label="&bookmarksButton.label;"
type="checkbox" group="sidebar" sidebarurl="chrome://browser/content/bookmarks/bookmarksPanel.xul"
oncommand="SidebarUI.toggle('viewBookmarksSidebar');"/>
+503
View File
@@ -0,0 +1,503 @@
/* 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/. */
// the "exported" symbols
var SocialUI,
SocialShare,
SocialActivationListener;
(function() {
XPCOMUtils.defineLazyGetter(this, "OpenGraphBuilder", function() {
let tmp = {};
Cu.import("resource:///modules/Social.jsm", tmp);
return tmp.OpenGraphBuilder;
});
XPCOMUtils.defineLazyGetter(this, "DynamicResizeWatcher", function() {
let tmp = {};
Cu.import("resource:///modules/Social.jsm", tmp);
return tmp.DynamicResizeWatcher;
});
SocialUI = {
_initialized: false,
// Called on delayed startup to initialize the UI
init: function SocialUI_init() {
if (this._initialized) {
return;
}
let mm = window.getGroupMessageManager("social");
mm.loadFrameScript("chrome://browser/content/content.js", true);
mm.loadFrameScript("chrome://browser/content/social-content.js", true);
Services.obs.addObserver(this, "social:providers-changed", false);
CustomizableUI.addListener(this);
SocialActivationListener.init();
Social.init().then((update) => {
if (update)
this._providersChanged();
});
this._initialized = true;
},
// Called on window unload
uninit: function SocialUI_uninit() {
if (!this._initialized) {
return;
}
Services.obs.removeObserver(this, "social:providers-changed");
CustomizableUI.removeListener(this);
SocialActivationListener.uninit();
this._initialized = false;
},
observe: function SocialUI_observe(subject, topic, data) {
switch (topic) {
case "social:providers-changed":
this._providersChanged();
break;
}
},
_providersChanged: function() {
SocialShare.populateProviderMenu();
},
showLearnMore: function() {
let url = Services.urlFormatter.formatURLPref("app.support.baseURL") + "social-api";
openUILinkIn(url, "tab");
},
closeSocialPanelForLinkTraversal: function (target, linkNode) {
// No need to close the panel if this traversal was not retargeted
if (target == "" || target == "_self")
return;
// Check to see whether this link traversal was in a social panel
let win = linkNode.ownerGlobal;
let container = win.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler;
let containerParent = container.parentNode;
if (containerParent.classList.contains("social-panel") &&
containerParent instanceof Ci.nsIDOMXULPopupElement) {
// allow the link traversal to finish before closing the panel
setTimeout(() => {
containerParent.hidePopup();
}, 0);
}
},
get _chromeless() {
// Is this a popup window that doesn't want chrome shown?
let docElem = document.documentElement;
// extrachrome is not restored during session restore, so we need
// to check for the toolbar as well.
let chromeless = docElem.getAttribute("chromehidden").includes("extrachrome") ||
docElem.getAttribute('chromehidden').includes("toolbar");
// This property is "fixed" for a window, so avoid doing the check above
// multiple times...
delete this._chromeless;
this._chromeless = chromeless;
return chromeless;
},
get enabled() {
// Returns whether social is enabled *for this window*.
if (this._chromeless)
return false;
return Social.providers.length > 0;
},
canSharePage: function(aURI) {
return (aURI && (aURI.schemeIs('http') || aURI.schemeIs('https')));
},
onCustomizeEnd: function(aWindow) {
if (aWindow != window)
return;
// customization mode gets buttons out of sync with command updating, fix
// the disabled state
let canShare = this.canSharePage(gBrowser.currentURI);
let shareButton = SocialShare.shareButton;
if (shareButton) {
if (canShare) {
shareButton.removeAttribute("disabled")
} else {
shareButton.setAttribute("disabled", "true")
}
}
},
// called on tab/urlbar/location changes and after customization. Update
// anything that is tab specific.
updateState: function() {
goSetCommandEnabled("Social:PageShareable", this.canSharePage(gBrowser.currentURI));
}
}
// message manager handlers
SocialActivationListener = {
init: function() {
messageManager.addMessageListener("Social:Activation", this);
},
uninit: function() {
messageManager.removeMessageListener("Social:Activation", this);
},
receiveMessage: function(aMessage) {
let data = aMessage.json;
let browser = aMessage.target;
data.window = window;
// if the source if the message is the share panel, we do a one-click
// installation. The source of activations is controlled by the
// social.directories preference
let options;
if (browser == SocialShare.iframe && Services.prefs.getBoolPref("social.share.activationPanelEnabled")) {
options = { bypassContentCheck: true, bypassInstallPanel: true };
}
Social.installProvider(data, function(manifest) {
Social.activateFromOrigin(manifest.origin, function(provider) {
if (provider.shareURL) {
// Ensure that the share button is somewhere usable.
// SocialShare.shareButton may return null if it is in the menu-panel
// and has never been visible, so we check the widget directly. If
// there is no area for the widget we move it into the toolbar.
let widget = CustomizableUI.getWidget("social-share-button");
// If the panel is already open, we can be sure that the provider can
// already be accessed, possibly anchored to another toolbar button.
// In that case we don't move the widget.
if (!widget.areaType && SocialShare.panel.state != "open") {
CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_NAVBAR);
// Ensure correct state.
SocialUI.onCustomizeEnd(window);
}
// 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) {
// 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"});
}
});
}, options);
}
}
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() {
let widget = CustomizableUI.getWidget("social-share-button");
return widget.forWindow(window).anchor;
},
// Holds the anchor node in use whilst the panel is open, because it may vary.
_currentAnchor: null,
get panel() {
return document.getElementById("social-share-panel");
},
get iframe() {
// panel.firstChild is our toolbar hbox, panel.lastChild is the iframe
// container hbox used for an interstitial "loading" graphic
return this.panel.lastChild.firstChild;
},
uninit: function () {
if (this.iframe) {
let mm = this.messageManager;
mm.removeMessageListener("PageVisibility:Show", this);
mm.removeMessageListener("PageVisibility:Hide", this);
mm.removeMessageListener("Social:DOMWindowClose", this);
this.iframe.removeEventListener("load", this);
this.iframe.remove();
}
},
_createFrame: function() {
let panel = this.panel;
if (this.iframe)
return;
this.panel.hidden = false;
// create and initialize the panel for this window
let iframe = document.createElement("browser");
iframe.setAttribute("type", "content");
iframe.setAttribute("class", "social-share-frame");
iframe.setAttribute("context", "contentAreaContextMenu");
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.setAttribute("disableglobalhistory", "true");
iframe.setAttribute("flex", "1");
iframe.setAttribute("message", "true");
iframe.setAttribute("messagemanagergroup", "social");
panel.lastChild.appendChild(iframe);
let mm = this.messageManager;
mm.addMessageListener("PageVisibility:Show", this);
mm.addMessageListener("PageVisibility:Hide", this);
mm.sendAsyncMessage("Social:SetErrorURL",
{ template: "about:socialerror?mode=compactInfo&origin=%{origin}&url=%{url}" });
iframe.addEventListener("load", this, true);
mm.addMessageListener("Social:DOMWindowClose", this);
this.populateProviderMenu();
},
get messageManager() {
// The xbl bindings for the iframe may not exist yet, so we can't
// access iframe.messageManager directly - but can get at it with this dance.
return this.iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
},
receiveMessage: function(aMessage) {
let iframe = this.iframe;
switch(aMessage.name) {
case "PageVisibility:Show":
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
break;
case "PageVisibility:Hide":
SocialShare._dynamicResizer.stop();
break;
case "Social:DOMWindowClose":
this.panel.hidePopup();
break;
}
},
handleEvent: function(event) {
switch (event.type) {
case "load": {
this.iframe.parentNode.removeAttribute("loading");
if (this.currentShare)
SocialShare.messageManager.sendAsyncMessage("Social:OpenGraphData", this.currentShare);
}
}
},
getSelectedProvider: function() {
let provider;
let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin");
if (lastProviderOrigin) {
provider = Social._getProviderFromOrigin(lastProviderOrigin);
}
return provider;
},
createTooltip: function(event) {
let tt = event.target;
let provider = Social._getProviderFromOrigin(tt.triggerNode.getAttribute("origin"));
tt.firstChild.setAttribute("value", provider.name);
tt.lastChild.setAttribute("value", provider.origin);
},
populateProviderMenu: function() {
if (!this.iframe)
return;
let providers = Social.providers.filter(p => p.shareURL);
let hbox = document.getElementById("social-share-provider-buttons");
// 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.lastChild != addButton) {
hbox.removeChild(hbox.lastChild);
}
let selectedProvider = this.getSelectedProvider();
for (let provider of providers) {
let button = document.createElement("toolbarbutton");
button.setAttribute("class", "toolbarbutton-1 share-provider-button");
button.setAttribute("type", "radio");
button.setAttribute("group", "share-providers");
button.setAttribute("image", provider.iconURL);
button.setAttribute("tooltip", "share-button-tooltip");
button.setAttribute("origin", provider.origin);
button.setAttribute("label", provider.name);
button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin'));");
if (provider == selectedProvider) {
this.defaultButton = button;
}
hbox.appendChild(button);
}
if (!this.defaultButton) {
this.defaultButton = addButton;
}
this.defaultButton.setAttribute("checked", "true");
},
get shareButton() {
// web-panels (bookmark/sidebar) don't include customizableui, so
// nsContextMenu fails when accessing shareButton, breaking
// browser_bug409481.js.
if (!window.CustomizableUI)
return null;
let widget = CustomizableUI.getWidget("social-share-button");
if (!widget || !widget.areaType)
return null;
return widget.forWindow(window).node;
},
_onclick: function() {
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(0);
},
onShowing: function() {
(this._currentAnchor || this.anchor).setAttribute("open", "true");
this.iframe.addEventListener("click", this._onclick, true);
},
onHidden: function() {
(this._currentAnchor || this.anchor).removeAttribute("open");
this._currentAnchor = null;
this.iframe.docShellIsActive = false;
this.iframe.removeEventListener("click", this._onclick, true);
this.iframe.setAttribute("src", "data:text/plain;charset=utf8,");
// make sure that the frame is unloaded after it is hidden
this.messageManager.sendAsyncMessage("Social:ClearFrame");
this.currentShare = null;
// share panel use is over, purge any history
this.iframe.purgeSessionHistory();
},
sharePage: function(providerOrigin, graphData, target, anchor) {
// if providerOrigin is undefined, we use the last-used provider, or the
// current/default provider. The provider selection in the share panel
// will call sharePage with an origin for us to switch to.
this._createFrame();
let iframe = this.iframe;
// 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
// in mozSocial API, or via nsContentMenu calls. If it is present, it MUST
// define at least url. If it is undefined, we're sharing the current url in
// the browser tab.
let pageData = graphData ? graphData : this.currentShare;
let sharedURI = pageData ? Services.io.newURI(pageData.url, null, null) :
gBrowser.currentURI;
if (!SocialUI.canSharePage(sharedURI))
return;
let browserMM = gBrowser.selectedBrowser.messageManager;
// the point of this action type is that we can use existing share
// endpoints (e.g. oexchange) that do not support additional
// socialapi functionality. One tweak is that we shoot an event
// containing the open graph data.
let _dataFn;
if (!pageData || sharedURI == gBrowser.currentURI) {
browserMM.addMessageListener("PageMetadata:PageDataResult", _dataFn = (msg) => {
browserMM.removeMessageListener("PageMetadata:PageDataResult", _dataFn);
let pageData = msg.json;
if (graphData) {
// overwrite data retreived from page with data given to us as a param
for (let p in graphData) {
pageData[p] = graphData[p];
}
}
this.sharePage(providerOrigin, pageData, target, anchor);
});
browserMM.sendAsyncMessage("PageMetadata:GetPageData", null, { target });
return;
}
// if this is a share of a selected item, get any microformats
if (!pageData.microformats && target) {
browserMM.addMessageListener("PageMetadata:MicroformatsResult", _dataFn = (msg) => {
browserMM.removeMessageListener("PageMetadata:MicroformatsResult", _dataFn);
pageData.microformats = msg.data;
this.sharePage(providerOrigin, pageData, target, anchor);
});
browserMM.sendAsyncMessage("PageMetadata:GetMicroformats", null, { target });
return;
}
this.currentShare = pageData;
let provider;
if (providerOrigin)
provider = Social._getProviderFromOrigin(providerOrigin);
else
provider = this.getSelectedProvider();
if (!provider || !provider.shareURL) {
this.showDirectory(anchor);
return;
}
// check the menu button
let hbox = document.getElementById("social-share-provider-buttons");
let btn = hbox.querySelector("[origin='" + provider.origin + "']");
if (btn)
btn.checked = true;
let shareEndpoint = OpenGraphBuilder.generateEndpointURL(provider.shareURL, pageData);
this._dynamicResizer.stop();
let size = provider.getPageSize("share");
if (size) {
// let the css on the share panel define width, but height
// calculations dont work on all sites, so we allow that to be
// defined.
delete size.width;
}
// if we've already loaded this provider/page share endpoint, we don't want
// to add another load event listener.
let endpointMatch = shareEndpoint == iframe.getAttribute("src");
if (endpointMatch) {
this._dynamicResizer.start(iframe.parentNode, iframe, size);
iframe.docShellIsActive = true;
SocialShare.messageManager.sendAsyncMessage("Social:OpenGraphData", this.currentShare);
} else {
iframe.parentNode.setAttribute("loading", "true");
}
// if the user switched between share providers we do not want that history
// available.
iframe.purgeSessionHistory();
// always ensure that origin belongs to the endpoint
let uri = Services.io.newURI(shareEndpoint, null, null);
iframe.setAttribute("origin", provider.origin);
iframe.setAttribute("src", shareEndpoint);
this._openPanel(anchor);
},
showDirectory: function(anchor) {
this._createFrame();
let iframe = this.iframe;
if (iframe.getAttribute("src") == "about:providerdirectory")
return;
iframe.removeAttribute("origin");
iframe.parentNode.setAttribute("loading", "true");
iframe.setAttribute("src", "about:providerdirectory");
this._openPanel(anchor);
},
_openPanel: function(anchor) {
this._currentAnchor = anchor || this.anchor;
anchor = document.getAnonymousElementByAttribute(this._currentAnchor, "class", "toolbarbutton-icon");
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
}
};
})();
+5
View File
@@ -933,6 +933,11 @@ html|*#gcli-output-frame,
transition: none;
}
panelview > .social-panel-frame {
width: auto;
height: auto;
}
/* Translation */
notification[value="translation"] {
-moz-binding: url("chrome://browser/content/translation-infobar.xml#translationbar");
+9 -1
View File
@@ -44,6 +44,7 @@ Cu.import("resource://gre/modules/NotificationDB.jsm");
["ShortcutUtils", "resource://gre/modules/ShortcutUtils.jsm"],
["SimpleServiceDiscovery", "resource://gre/modules/SimpleServiceDiscovery.jsm"],
["SitePermissions", "resource:///modules/SitePermissions.jsm"],
["Social", "resource:///modules/Social.jsm"],
["TabCrashHandler", "resource:///modules/ContentCrashHandlers.jsm"],
["Task", "resource://gre/modules/Task.jsm"],
["TelemetryStopwatch", "resource://gre/modules/TelemetryStopwatch.jsm"],
@@ -1409,6 +1410,8 @@ var gBrowserInit = {
// Enable the Restore Last Session command if needed
RestoreLastSessionObserver.init();
SocialUI.init();
// Start monitoring slow add-ons
AddonWatcher.init();
@@ -1539,6 +1542,7 @@ var gBrowserInit = {
gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
ctrlTab.uninit();
SocialUI.uninit();
gBrowserThumbnails.uninit();
FullZoom.destroy();
@@ -4300,7 +4304,9 @@ var XULBrowserWindow = {
// Called before links are navigated to to allow us to retarget them if needed.
onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
return BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
let target = BrowserUtils.onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
SocialUI.closeSocialPanelForLinkTraversal(target, linkNode);
return target;
},
// Check whether this URI should load in the current process
@@ -4481,6 +4487,8 @@ var XULBrowserWindow = {
gIdentityHandler.onLocationChange();
SocialUI.updateState();
UITour.onLocationChange(location);
gTabletModePageCounter.inc();
+26
View File
@@ -268,6 +268,27 @@
<box id="UITourHighlight"></box>
</panel>
<panel id="social-share-panel"
class="social-panel"
type="arrow"
orient="vertical"
onpopupshowing="SocialShare.onShowing()"
onpopuphidden="SocialShare.onHidden()"
hidden="true">
<hbox class="social-share-toolbar">
<toolbarbutton id="manage-share-providers" class="share-provider-button"
tooltiptext="&social.addons.label;"
oncommand="BrowserOpenAddonsMgr('addons://list/service');
this.parentNode.parentNode.hidePopup();"/>
<arrowscrollbox id="social-share-provider-buttons" orient="horizontal" flex="1" pack="end">
<toolbarbutton id="add-share-provider" class="share-provider-button" type="radio"
group="share-providers" tooltiptext="&findShareServices.label;"
oncommand="SocialShare.showDirectory()"/>
</arrowscrollbox>
</hbox>
<hbox id="share-container" flex="1"/>
</panel>
<menupopup id="toolbar-context-menu"
onpopupshowing="onViewToolbarsPopupShowing(event, document.getElementById('viewToolbarsMenuSeparator'));">
<menuitem oncommand="gCustomizeMode.addToPanel(document.popupNode)"
@@ -405,6 +426,11 @@
#endif
</tooltip>
<tooltip id="share-button-tooltip" onpopupshowing="SocialShare.createTooltip(event);">
<label class="tooltip-label"/>
<label class="tooltip-label"/>
</tooltip>
#include popup-notifications.inc
#include ../../components/customizableui/content/panelUI.inc.xul
+31
View File
@@ -698,6 +698,37 @@ var PageMetadataMessenger = {
}
PageMetadataMessenger.init();
addEventListener("ActivateSocialFeature", function (aEvent) {
let document = content.document;
let dwu = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
if (!dwu.isHandlingUserInput) {
Cu.reportError("attempt to activate provider without user input from " + document.nodePrincipal.origin);
return;
}
let node = aEvent.target;
let ownerDocument = node.ownerDocument;
let data = node.getAttribute("data-service");
if (data) {
try {
data = JSON.parse(data);
} catch (e) {
Cu.reportError("Social Service manifest parse error: " + e);
return;
}
} else {
Cu.reportError("Social Service manifest not available");
return;
}
sendAsyncMessage("Social:Activation", {
url: ownerDocument.location.href,
origin: ownerDocument.nodePrincipal.origin,
manifest: data
});
}, true, true);
addMessageListener("ContextMenu:SaveVideoFrameAsImage", (message) => {
let video = message.objects.target;
let canvas = content.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
+39 -8
View File
@@ -174,15 +174,15 @@ nsContextMenu.prototype = {
initNavigationItems: function CM_initNavigationItems() {
var shouldShow = !(this.isContentSelected || this.onLink || this.onImage ||
this.onCanvas || this.onVideo || this.onAudio ||
this.onTextInput);
this.onTextInput || this.onSocial);
this.showItem("context-navigation", shouldShow);
this.showItem("context-sep-navigation", shouldShow);
let stopped = XULBrowserWindow.stopCommand.getAttribute("disabled") == "true";
let stopReloadItem = "";
if (shouldShow) {
stopReloadItem = (stopped) ? "reload" : "stop";
if (shouldShow || this.onSocial) {
stopReloadItem = (stopped || this.onSocial) ? "reload" : "stop";
}
this.showItem("context-reload", stopReloadItem == "reload");
@@ -249,7 +249,7 @@ nsContextMenu.prototype = {
this.onImage || this.onCanvas ||
this.onVideo || this.onAudio ||
this.onLink || this.onTextInput);
var showInspect = gPrefService.getBoolPref("devtools.inspector.enabled");
var showInspect = !this.onSocial && gPrefService.getBoolPref("devtools.inspector.enabled");
this.showItem("context-viewsource", shouldShow);
this.showItem("context-viewinfo", shouldShow);
this.showItem("inspect-separator", showInspect);
@@ -306,11 +306,12 @@ nsContextMenu.prototype = {
let bookmarkPage = document.getElementById("context-bookmarkpage");
this.showItem(bookmarkPage,
!(this.isContentSelected || this.onTextInput || this.onLink ||
this.onImage || this.onVideo || this.onAudio || this.onCanvas));
this.onImage || this.onVideo || this.onAudio || this.onSocial ||
this.onCanvas));
bookmarkPage.setAttribute("tooltiptext", bookmarkPage.getAttribute("buttontooltiptext"));
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink) ||
this.onPlainTextLink);
this.showItem("context-bookmarklink", (this.onLink && !this.onMailtoLink &&
!this.onSocial) || this.onPlainTextLink);
this.showItem("context-keywordfield",
this.onTextInput && this.onKeywordField);
this.showItem("frame", this.inFrame);
@@ -348,6 +349,19 @@ nsContextMenu.prototype = {
this.onTextInput && !this.onNumeric && top.gBidiUI);
this.showItem("context-bidi-page-direction-toggle",
!this.onTextInput && top.gBidiUI);
// SocialShare
let shareButton = SocialShare.shareButton;
let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial;
let pageShare = shareEnabled && !(this.isContentSelected ||
this.onTextInput || this.onLink || this.onImage ||
this.onVideo || this.onAudio || this.onCanvas);
this.showItem("context-sharepage", pageShare);
this.showItem("context-shareselect", shareEnabled && this.isContentSelected);
this.showItem("context-sharelink", shareEnabled && (this.onLink || this.onPlainTextLink) && !this.onMailtoLink);
this.showItem("context-shareimage", shareEnabled && this.onImage);
this.showItem("context-sharevideo", shareEnabled && this.onVideo);
this.setItemAttr("context-sharevideo", "disabled", !this.mediaURL || this.mediaURL.startsWith("blob:"));
},
initSpellingItems: function() {
@@ -667,6 +681,7 @@ nsContextMenu.prototype = {
.getInterface(Ci.nsIDOMWindowUtils)
.outerWindowID;
}
this.onSocial = !!this.browser.getAttribute("origin");
// Check if we are in a synthetic document (stand alone image, video, etc.).
this.inSyntheticDoc = ownerDoc.mozSyntheticDocument;
@@ -1711,6 +1726,22 @@ nsContextMenu.prototype = {
mm.sendAsyncMessage("ContextMenu:BookmarkFrame", null, { target: this.target });
},
shareLink: function CM_shareLink() {
SocialShare.sharePage(null, { url: this.linkURI.spec }, this.target);
},
shareImage: function CM_shareImage() {
SocialShare.sharePage(null, { url: this.imageURL, previews: [ this.mediaURL ] }, this.target);
},
shareVideo: function CM_shareVideo() {
SocialShare.sharePage(null, { url: this.mediaURL, source: this.mediaURL }, this.target);
},
shareSelect: function CM_shareSelect() {
SocialShare.sharePage(null, { url: this.browser.currentURI.spec, text: this.textSelected }, this.target);
},
savePageAs: function CM_savePageAs() {
saveBrowser(this.browser);
},
@@ -1825,7 +1856,7 @@ nsContextMenu.prototype = {
_getTelemetryPageContextInfo: function() {
let rv = [];
for (let k of ["isContentSelected", "onLink", "onImage", "onCanvas", "onVideo", "onAudio",
"onTextInput"]) {
"onTextInput", "onSocial"]) {
if (this[k]) {
rv.push(k.replace(/^(?:is|on)(.)/, (match, firstLetter) => firstLetter.toLowerCase()));
}
+172
View File
@@ -0,0 +1,172 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* 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/. */
/* This content script is intended for use by iframes in the share panel. */
var {interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
// social frames are always treated as app tabs
docShell.isAppTab = true;
addEventListener("DOMContentLoaded", function(event) {
if (event.target != content.document)
return;
// Some share panels (e.g. twitter and facebook) check content.opener, and if
// it doesn't exist they act like they are in a browser tab. We want them to
// act like they are in a dialog (which is the typical case).
if (content && !content.opener) {
content.opener = content;
}
hookWindowClose();
disableDialogs();
});
addMessageListener("Social:OpenGraphData", (message) => {
let ev = new content.CustomEvent("OpenGraphData", { detail: JSON.stringify(message.data) });
content.dispatchEvent(ev);
});
addMessageListener("Social:ClearFrame", () => {
docShell.createAboutBlankContentViewer(null);
});
addEventListener("DOMWindowClose", (evt) => {
// preventDefault stops the default window.close() function being called,
// which doesn't actually close anything but causes things to get into
// a bad state (an internal 'closed' flag is set and debug builds start
// asserting as the window is used.).
// None of the windows we inject this API into are suitable for this
// default close behaviour, so even if we took no action above, we avoid
// the default close from doing anything.
evt.preventDefault();
// Tells the SocialShare class to close the panel
sendAsyncMessage("Social:DOMWindowClose");
});
function hookWindowClose() {
// Allow scripts to close the "window". Because we are in a panel and not
// in a full dialog, the DOMWindowClose listener above will only receive the
// event if we do this.
let dwu = content.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindowUtils);
dwu.allowScriptsToClose();
}
function disableDialogs() {
let windowUtils = content.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils);
windowUtils.disableDialogs();
}
// Error handling class used to listen for network errors in the social frames
// and replace them with a social-specific error page
const SocialErrorListener = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMEventListener,
Ci.nsIWebProgressListener,
Ci.nsISupportsWeakReference,
Ci.nsISupports]),
defaultTemplate: "about:socialerror?mode=tryAgainOnly&url=%{url}&origin=%{origin}",
urlTemplate: null,
init() {
addMessageListener("Social:SetErrorURL", this);
let webProgress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebProgress);
webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
Ci.nsIWebProgress.NOTIFY_LOCATION);
},
receiveMessage(message) {
switch (message.name) {
case "Social:SetErrorURL":
// Either a url or null to reset to default template.
this.urlTemplate = message.data.template;
break;
}
},
setErrorPage() {
// if this is about:providerdirectory, use the directory iframe
let frame = docShell.chromeEventHandler;
let origin = frame.getAttribute("origin");
let src = frame.getAttribute("src");
if (src == "about:providerdirectory") {
frame = content.document.getElementById("activation-frame");
src = frame.getAttribute("src");
}
let url = this.urlTemplate || this.defaultTemplate;
url = url.replace("%{url}", encodeURIComponent(src));
url = url.replace("%{origin}", encodeURIComponent(origin));
if (frame != docShell.chromeEventHandler) {
// Unable to access frame.docShell here. This is our own frame and doesn't
// provide reload, so we'll just set the src.
frame.setAttribute("src", url);
} else {
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
webNav.loadURI(url, null, null, null, null);
}
sendAsyncMessage("Social:ErrorPageNotify", {
origin: origin,
url: src
});
},
onStateChange(aWebProgress, aRequest, aState, aStatus) {
let failure = false;
if ((aState & Ci.nsIWebProgressListener.STATE_IS_REQUEST))
return;
if ((aState & Ci.nsIWebProgressListener.STATE_STOP)) {
if (aRequest instanceof Ci.nsIHttpChannel) {
try {
// Change the frame to an error page on 4xx (client errors)
// and 5xx (server errors). responseStatus throws if it is not set.
failure = aRequest.responseStatus >= 400 &&
aRequest.responseStatus < 600;
} catch (e) {
failure = aStatus != Components.results.NS_OK;
}
}
}
// Calling cancel() will raise some OnStateChange notifications by itself,
// so avoid doing that more than once
if (failure && aStatus != Components.results.NS_BINDING_ABORTED) {
// if tp is enabled and we get a failure, ignore failures (ie. STATE_STOP)
// on child resources since they *may* have been blocked. We don't have an
// easy way to know if a particular url is blocked by TP, only that
// something was.
if (docShell.hasTrackingContentBlocked) {
let frame = docShell.chromeEventHandler;
let src = frame.getAttribute("src");
if (aRequest && aRequest.name != src) {
Cu.reportError("SocialErrorListener ignoring blocked content error for " + aRequest.name);
return;
}
}
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
this.setErrorPage();
}
},
onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
if (aRequest && aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
this.setErrorPage();
}
},
onProgressChange() {},
onStatusChange() {},
onSecurityChange() {},
};
SocialErrorListener.init();
+4
View File
@@ -64,6 +64,8 @@ browser.jar:
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
content/browser/aboutProviderDirectory.xhtml (content/aboutProviderDirectory.xhtml)
content/browser/aboutTabCrashed.css (content/aboutTabCrashed.css)
content/browser/aboutTabCrashed.js (content/aboutTabCrashed.js)
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
@@ -89,6 +91,7 @@ browser.jar:
content/browser/browser-safebrowsing.js (content/browser-safebrowsing.js)
#endif
content/browser/browser-sidebar.js (content/browser-sidebar.js)
content/browser/browser-social.js (content/browser-social.js)
* content/browser/browser-syncui.js (content/browser-syncui.js)
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
#ifdef CAN_DRAW_IN_TITLEBAR
@@ -100,6 +103,7 @@ browser.jar:
content/browser/browser-trackingprotection.js (content/browser-trackingprotection.js)
* content/browser/tab-content.js (content/tab-content.js)
content/browser/content.js (content/content.js)
content/browser/social-content.js (content/social-content.js)
content/browser/defaultthemes/1.footer.jpg (content/defaultthemes/1.footer.jpg)
content/browser/defaultthemes/1.header.jpg (content/defaultthemes/1.header.jpg)
content/browser/defaultthemes/1.icon.jpg (content/defaultthemes/1.icon.jpg)
@@ -56,6 +56,16 @@ static RedirEntry kRedirMap[] = {
nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT
},
{
"socialerror", "chrome://browser/content/aboutSocialError.xhtml",
nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT
},
{
"providerdirectory", "chrome://browser/content/aboutProviderDirectory.xhtml",
nsIAboutModule::ALLOW_SCRIPT |
nsIAboutModule::HIDE_FROM_ABOUTABOUT
},
{
"tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml",
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
+2
View File
@@ -90,6 +90,8 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "blocked", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
#endif
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "socialerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "providerdirectory", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "tabcrashed", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
@@ -556,6 +556,47 @@ const CustomizableWidgets = [
clearSubview(sidebarItems);
fillSubviewFromMenuItems([...menu.children], sidebarItems);
}
}, {
id: "social-share-button",
// custom build our button so we can attach to the share command
type: "custom",
onBuild: function(aDocument) {
let node = aDocument.createElementNS(kNSXUL, "toolbarbutton");
node.setAttribute("id", this.id);
node.classList.add("toolbarbutton-1");
node.classList.add("chromeclass-toolbar-additional");
node.setAttribute("label", CustomizableUI.getLocalizedProperty(this, "label"));
node.setAttribute("tooltiptext", CustomizableUI.getLocalizedProperty(this, "tooltiptext"));
node.setAttribute("removable", "true");
node.setAttribute("observes", "Social:PageShareable");
node.setAttribute("command", "Social:SharePage");
let listener = {
onWidgetAdded: (aWidgetId) => {
if (aWidgetId != this.id)
return;
Services.obs.notifyObservers(null, "social:" + this.id + "-added", null);
},
onWidgetRemoved: aWidgetId => {
if (aWidgetId != this.id)
return;
Services.obs.notifyObservers(null, "social:" + this.id + "-removed", null);
},
onWidgetInstanceRemoved: (aWidgetId, aDoc) => {
if (aWidgetId != this.id || aDoc != aDocument)
return;
CustomizableUI.removeListener(listener);
}
};
CustomizableUI.addListener(listener);
return node;
}
}, {
id: "add-ons-button",
shortcutId: "key_openAddons",
@@ -240,6 +240,8 @@
onclick="PanelUI.hide();"/>
</panelview>
<panelview id="PanelUI-socialapi" flex="1"/>
<panelview id="PanelUI-feeds" flex="1" oncommand="FeedHandler.subscribeToFeed(null, event);">
<label value="&feedsMenu2.label;" class="panel-subview-header"/>
</panelview>
+1
View File
@@ -128,6 +128,7 @@ divide the following different context menu situations:
- ``canvas`` if the user opened the context menu on a canvas (that isn't a link);
- ``media`` if the user opened the context menu on an HTML video or audio element;
- ``input`` if the user opened the context menu on a text input element;
- ``social`` if the user opened the context menu inside a social frame;
- ``other`` for all other openings of the content menu;
Each of these objects (if they exist) then gets a "withcustom" and/or a "withoutcustom" property
@@ -163,7 +163,22 @@ These should match what Safari and other Apple applications use on OS X Lion. --
<!ENTITY bookmarkThisPageCmd.label "Bookmark This Page">
<!ENTITY editThisBookmarkCmd.label "Edit This Bookmark">
<!ENTITY bookmarkThisPageCmd.commandkey "d">
<!-- LOCALIZATION NOTE (findShareServices.label):
- Use the unicode ellipsis char, \u2026,
- or use "..." if \u2026 doesn't suit traditions in your locale. -->
<!ENTITY findShareServices.label "Find more Share services…">
<!ENTITY sharePageCmd.label "Share This Page">
<!ENTITY sharePageCmd.commandkey "S">
<!ENTITY sharePageCmd.accesskey "s">
<!-- LOCALIZATION NOTE (shareLink.accesskey): must be different than the following share access keys -->
<!ENTITY shareLink.label "Share This Link">
<!ENTITY shareLink.accesskey "h">
<!ENTITY shareImage.label "Share This Image">
<!ENTITY shareImage.accesskey "r">
<!ENTITY shareSelect.label "Share Selection">
<!ENTITY shareSelect.accesskey "r">
<!ENTITY shareVideo.label "Share This Video">
<!ENTITY shareVideo.accesskey "r">
<!ENTITY feedsMenu2.label "Subscribe to This Page">
<!ENTITY subscribeToPageMenupopup.label "Subscribe to This Page">
<!ENTITY subscribeToPageMenuitem.label "Subscribe to This Page…">
@@ -765,6 +780,14 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY syncReAuthItem.accesskey "R">
<!ENTITY syncToolbarButton.label "Sync">
<!ENTITY social.addons.label "Manage Services…">
<!ENTITY social.directory.label "Activations Directory">
<!ENTITY social.directory.text "You can activate Share services from the directory.">
<!ENTITY social.directory.button "Take me there!">
<!ENTITY social.directory.introText "Click on a service to add it to &brandShortName;.">
<!ENTITY social.directory.viewmore.text "View More">
<!ENTITY customizeMode.menuAndToolbars.header2 "Additional Tools and Features">
<!ENTITY customizeMode.menuAndToolbars.empty "Want more tools?">
<!ENTITY customizeMode.menuAndToolbars.emptyLink "Choose from thousands of add-ons">
@@ -453,6 +453,29 @@ processHang.button_debug.accessKey = D
# LOCALIZATION NOTE (fullscreenButton.tooltip): %S is the keyboard shortcut for full screen
fullscreenButton.tooltip=Display the window in full screen (%S)
service.toolbarbutton.label=Services
service.toolbarbutton.tooltiptext=Services
# LOCALIZATION NOTE (social.install.description): %1$S is the hostname of the social provider, %2$S is brandShortName (e.g. Firefox)
service.install.description=Would you like to enable services from %1$S to display in your %2$S toolbar and sidebar?
service.install.ok.label=Enable Services
service.install.ok.accesskey=E
# LOCALIZATION NOTE (social.markpageMenu.label): %S is the name of the social provider
social.markpageMenu.label=Save Page to %S
# LOCALIZATION NOTE (social.marklinkMenu.label): %S is the name of the social provider
social.marklinkMenu.label=Save Link to %S
# LOCALIZATION NOTE (social.error.message): %1$S is brandShortName (e.g. Firefox), %2$S is the name of the social provider
social.error.message=%1$S is unable to connect with %2$S right now.
social.error.tryAgain.label=Try Again
social.error.tryAgain.accesskey=T
social.error.closeSidebar.label=Close This Sidebar
social.error.closeSidebar.accesskey=C
# LOCALIZATION NOTE: %1$S is the label for the toolbar button, %2$S is the associated badge numbering that the social provider may provide.
social.aria.toolbarButtonBadgeText=%1$S (%2$S)
# LOCALIZATION NOTE (getUserMedia.shareCamera.message, getUserMedia.shareMicrophone.message,
# getUserMedia.shareScreen.message, getUserMedia.shareCameraAndMicrophone.message,
# getUserMedia.shareScreenAndMicrophone.message, getUserMedia.shareCameraAndAudioCapture.message,
@@ -95,6 +95,9 @@ quit-button.tooltiptext.linux2 = Quit %1$S (%2$S)
# %2$S is the keyboard shortcut
quit-button.tooltiptext.mac = Quit %1$S (%2$S)
social-share-button.label = Share This Page
social-share-button.tooltiptext = Share this page
panic-button.label = Forget
panic-button.tooltiptext = Forget about some browsing history
+5 -5
View File
@@ -694,7 +694,7 @@ this.BrowserUITelemetry = {
"spell-undo-add-to-dictionary", "openlinkincurrent", "openlinkintab",
"openlink",
// "openlinkprivate" intentionally omitted for privacy reasons. See bug 1176391.
"bookmarklink", "savelink",
"bookmarklink", "sharelink", "savelink",
"marklinkMenu", "copyemail", "copylink", "media-play", "media-pause",
"media-mute", "media-unmute", "media-playbackrate",
"media-playbackrate-050x", "media-playbackrate-100x",
@@ -702,12 +702,12 @@ this.BrowserUITelemetry = {
"media-showcontrols", "media-hidecontrols",
"video-fullscreen", "leave-dom-fullscreen",
"reloadimage", "viewimage", "viewvideo", "copyimage-contents", "copyimage",
"copyvideourl", "copyaudiourl", "saveimage", "sendimage",
"copyvideourl", "copyaudiourl", "saveimage", "shareimage", "sendimage",
"setDesktopBackground", "viewimageinfo", "viewimagedesc", "savevideo",
"saveaudio", "video-saveimage", "sendvideo", "sendaudio",
"ctp-play", "ctp-hide", "savepage", "pocket", "markpageMenu",
"sharevideo", "saveaudio", "video-saveimage", "sendvideo", "sendaudio",
"ctp-play", "ctp-hide", "sharepage", "savepage", "pocket", "markpageMenu",
"viewbgimage", "undo", "cut", "copy", "paste", "delete", "selectall",
"keywordfield", "searchselect", "frame", "showonlythisframe",
"keywordfield", "searchselect", "shareselect", "frame", "showonlythisframe",
"openframeintab", "openframe", "reloadframe", "bookmarkframe", "saveframe",
"printframe", "viewframesource", "viewframeinfo",
"viewpartialsource-selection", "viewpartialsource-mathml",
+272
View File
@@ -0,0 +1,272 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Social", "OpenGraphBuilder",
"DynamicResizeWatcher", "sizeSocialPanelToContent"];
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cu = Components.utils;
// The minimum sizes for the auto-resize panel code, minimum size necessary to
// properly show the error page in the panel.
const PANEL_MIN_HEIGHT = 190;
const PANEL_MIN_WIDTH = 330;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI",
"resource:///modules/CustomizableUI.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SocialService",
"resource:///modules/SocialService.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PageMetadata",
"resource://gre/modules/PageMetadata.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
"resource://gre/modules/PlacesUtils.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
this.Social = {
initialized: false,
lastEventReceived: 0,
providers: [],
_disabledForSafeMode: false,
init: function Social_init() {
this._disabledForSafeMode = Services.appinfo.inSafeMode && this.enabled;
let deferred = Promise.defer();
if (this.initialized) {
deferred.resolve(true);
return deferred.promise;
}
this.initialized = true;
// if SocialService.hasEnabledProviders, retreive the providers so the
// front-end can generate UI
if (SocialService.hasEnabledProviders) {
// Retrieve the current set of providers, and set the current provider.
SocialService.getOrderedProviderList(function (providers) {
Social._updateProviderCache(providers);
Social._updateEnabledState(SocialService.enabled);
deferred.resolve(false);
});
} else {
deferred.resolve(false);
}
// Register an observer for changes to the provider list
SocialService.registerProviderListener(function providerListener(topic, origin, providers) {
// An engine change caused by adding/removing a provider should notify.
// any providers we receive are enabled in the AddonsManager
if (topic == "provider-installed" || topic == "provider-uninstalled") {
// installed/uninstalled do not send the providers param
Services.obs.notifyObservers(null, "social:" + topic, origin);
return;
}
if (topic == "provider-enabled") {
Social._updateProviderCache(providers);
Social._updateEnabledState(true);
Services.obs.notifyObservers(null, "social:" + topic, origin);
return;
}
if (topic == "provider-disabled") {
// a provider was removed from the list of providers, update states
Social._updateProviderCache(providers);
Social._updateEnabledState(providers.length > 0);
Services.obs.notifyObservers(null, "social:" + topic, origin);
return;
}
if (topic == "provider-update") {
// a provider has self-updated its manifest, we need to update our cache
// and reload the provider.
Social._updateProviderCache(providers);
let provider = Social._getProviderFromOrigin(origin);
provider.reload();
}
});
return deferred.promise;
},
_updateEnabledState: function(enable) {
for (let p of Social.providers) {
p.enabled = enable;
}
},
// Called to update our cache of providers and set the current provider
_updateProviderCache: function (providers) {
this.providers = providers;
Services.obs.notifyObservers(null, "social:providers-changed", null);
},
get enabled() {
return !this._disabledForSafeMode && this.providers.length > 0;
},
_getProviderFromOrigin: function (origin) {
for (let p of this.providers) {
if (p.origin == origin) {
return p;
}
}
return null;
},
getManifestByOrigin: function(origin) {
return SocialService.getManifestByOrigin(origin);
},
installProvider: function(data, installCallback, options={}) {
SocialService.installProvider(data, installCallback, options);
},
uninstallProvider: function(origin, aCallback) {
SocialService.uninstallProvider(origin, aCallback);
},
// Activation functionality
activateFromOrigin: function (origin, callback) {
// It's OK if the provider has already been activated - we still get called
// back with it.
SocialService.enableProvider(origin, callback);
}
};
function sizeSocialPanelToContent(panel, iframe, requestedSize) {
let doc = iframe.contentDocument;
if (!doc || !doc.body) {
return;
}
// We need an element to use for sizing our panel. See if the body defines
// an id for that element, otherwise use the body itself.
let body = doc.body;
let docEl = doc.documentElement;
let bodyId = body.getAttribute("contentid");
if (bodyId) {
body = doc.getElementById(bodyId) || doc.body;
}
// offsetHeight/Width don't include margins, so account for that.
let cs = doc.defaultView.getComputedStyle(body);
let width = Math.max(PANEL_MIN_WIDTH, docEl.offsetWidth);
let height = Math.max(PANEL_MIN_HEIGHT, docEl.offsetHeight);
// if the panel is preloaded prior to being shown, cs will be null. in that
// case use the minimum size for the panel until it is shown.
if (cs) {
let computedHeight = parseInt(cs.marginTop) + body.offsetHeight + parseInt(cs.marginBottom);
height = Math.max(computedHeight, height);
let computedWidth = parseInt(cs.marginLeft) + body.offsetWidth + parseInt(cs.marginRight);
width = Math.max(computedWidth, width);
}
// if our scrollHeight is still larger than the iframe, the css calculations
// above did not work for this site, increase the height. This can happen if
// the site increases its height for additional UI.
if (docEl.scrollHeight > iframe.boxObject.height)
height = docEl.scrollHeight;
// if a size was defined in the manifest use it as a minimum
if (requestedSize) {
if (requestedSize.height)
height = Math.max(height, requestedSize.height);
if (requestedSize.width)
width = Math.max(width, requestedSize.width);
}
// add the extra space used by the panel (toolbar, borders, etc) if the iframe
// has been loaded
if (iframe.boxObject.width && iframe.boxObject.height) {
// add extra space the panel needs if any
width += panel.boxObject.width - iframe.boxObject.width;
height += panel.boxObject.height - iframe.boxObject.height;
}
// using panel.sizeTo will ignore css transitions, set size via style
if (Math.abs(panel.boxObject.width - width) >= 2)
panel.style.width = width + "px";
if (Math.abs(panel.boxObject.height - height) >= 2)
panel.style.height = height + "px";
}
function DynamicResizeWatcher() {
this._mutationObserver = null;
}
DynamicResizeWatcher.prototype = {
start: function DynamicResizeWatcher_start(panel, iframe, requestedSize) {
this.stop(); // just in case...
let doc = iframe.contentDocument;
this._mutationObserver = new iframe.contentWindow.MutationObserver((mutations) => {
sizeSocialPanelToContent(panel, iframe, requestedSize);
});
// Observe anything that causes the size to change.
let config = {attributes: true, characterData: true, childList: true, subtree: true};
this._mutationObserver.observe(doc, config);
// and since this may be setup after the load event has fired we do an
// initial resize now.
sizeSocialPanelToContent(panel, iframe, requestedSize);
},
stop: function DynamicResizeWatcher_stop() {
if (this._mutationObserver) {
try {
this._mutationObserver.disconnect();
} catch (ex) {
// may get "TypeError: can't access dead object" which seems strange,
// but doesn't seem to indicate a real problem, so ignore it...
}
this._mutationObserver = null;
}
}
}
this.OpenGraphBuilder = {
generateEndpointURL: function(URLTemplate, pageData) {
// support for existing oexchange style endpoints by supporting their
// querystring arguments. parse the query string template and do
// replacements where necessary the query names may be different than ours,
// so we could see u=%{url} or url=%{url}
let [endpointURL, queryString] = URLTemplate.split("?");
let query = {};
if (queryString) {
queryString.split('&').forEach(function (val) {
let [name, value] = val.split('=');
let p = /%\{(.+)\}/.exec(value);
if (!p) {
// preserve non-template query vars
query[name] = value;
} else if (pageData[p[1]]) {
if (p[1] == "previews")
query[name] = pageData[p[1]][0];
else
query[name] = pageData[p[1]];
} else if (p[1] == "body") {
// build a body for emailers
let body = "";
if (pageData.title)
body += pageData.title + "\n\n";
if (pageData.description)
body += pageData.description + "\n\n";
if (pageData.text)
body += pageData.text + "\n\n";
body += pageData.url;
query["body"] = body;
}
});
// if the url template doesn't have title and no text was provided, add the title as the text.
if (!query.text && !query.title && pageData.title) {
query.text = pageData.title;
}
}
var str = [];
for (let p in query)
str.push(p + "=" + encodeURIComponent(query[p]));
if (str.length)
endpointURL = endpointURL + "?" + str.join("&");
return endpointURL;
},
};
File diff suppressed because it is too large Load Diff
+2
View File
@@ -35,6 +35,8 @@ EXTRA_JS_MODULES += [
'Sanitizer.jsm',
'SelfSupportBackend.jsm',
'SitePermissions.jsm',
'Social.jsm',
'SocialService.jsm',
'TransientPrefs.jsm',
'URLBarZoom.jsm',
'webrtcUI.jsm',
+50
View File
@@ -1172,6 +1172,56 @@ html|span.ac-emphasize-text-url {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
/* social share panel */
%include ../shared/social/social.inc.css
.social-share-frame {
border-top: 1px solid #f8f8f8;
width: 756px;
height: 150px;
}
#share-container {
min-width: 756px;
background-color: white;
background-repeat: no-repeat;
background-position: center center;
}
#share-container[loading] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
}
#share-container > browser {
transition: opacity 150ms ease-in-out;
opacity: 1;
}
#share-container[loading] > browser {
opacity: 0;
}
.social-share-toolbar {
border-bottom: 1px solid #dedede;
padding: 2px;
}
#social-share-provider-buttons {
padding: 0;
margin: 0;
}
.share-provider-button {
padding: 5px;
margin: 2px;
}
.share-provider-button > .toolbarbutton-text {
display: none;
}
.share-provider-button > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;
}
/* bookmarks menu-button */
#bookmarks-menu-button[cui-areatype="toolbar"] > .toolbarbutton-menubutton-dropmarker {
@@ -49,6 +49,14 @@
padding-inline-start: 0;
}
/* subviewbutton entries for social sidebars have images that come from external
/* sources, and are not guaranteed to be the size we want, so force the size on
/* those icons. */
toolbarbutton.social-provider-menuitem > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
.subviewbutton:-moz-any([image],[targetURI],.cui-withicon, .restoreallitem, .bookmark-item)[checked="true"] > .toolbarbutton-icon {
visibility: hidden;
}
+4
View File
@@ -81,6 +81,10 @@ browser.jar:
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/social/services-16.png (social/services-16.png)
skin/classic/browser/social/services-64.png (social/services-64.png)
skin/classic/browser/social/share-button.png (social/share-button.png)
skin/classic/browser/social/share-button-active.png (social/share-button-active.png)
skin/classic/browser/tabbrowser/alltabs.png (tabbrowser/alltabs.png)
skin/classic/browser/tabbrowser/alltabs-inverted.png (tabbrowser/alltabs-inverted.png)
skin/classic/browser/tabbrowser/newtab.svg (tabbrowser/newtab.svg)
+88
View File
@@ -808,6 +808,10 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
-moz-image-region: rect(18px, 288px, 36px, 270px);
}
#social-share-button@toolbarButtonPressed@ {
-moz-image-region: rect(18px, 306px, 36px, 288px);
}
#characterencoding-button@toolbarButtonPressed@ {
-moz-image-region: rect(18px, 324px, 36px, 306px);
}
@@ -963,6 +967,10 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
-moz-image-region: rect(36px, 576px, 72px, 540px);
}
#social-share-button@toolbarButtonPressed@ {
-moz-image-region: rect(36px, 612px, 72px, 576px);
}
#characterencoding-button@toolbarButtonPressed@ {
-moz-image-region: rect(36px, 648px, 72px, 612px);
}
@@ -2021,6 +2029,59 @@ html|span.ac-emphasize-text-url {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
/* social share panel */
.social-share-frame {
border-top: 1px solid #f8f8f8;
min-width: 756px;
height: 150px;
/* we resize our panels dynamically, make it look nice */
}
#share-container {
min-width: 756px;
background-repeat: no-repeat;
background-position: center center;
}
#share-container[loading] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
}
#share-container > browser {
transition: opacity 150ms ease-in-out;
opacity: 1;
}
#share-container[loading] > browser {
opacity: 0;
}
#manage-share-providers {
-moz-image-region: rect(18px, 468px, 36px, 450px);
}
.social-share-toolbar {
border-bottom: 1px solid #dedede;
padding: 2px;
}
#social-share-provider-buttons {
padding: 0;
margin: 0;
}
.share-provider-button {
padding: 5px;
margin: 2px;
}
.share-provider-button > .toolbarbutton-text {
display: none;
}
.share-provider-button > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;
}
/* BOOKMARKING PANEL */
#editBookmarkPanelStarIcon {
list-style-image: url("chrome://browser/skin/places/starred48.png");
@@ -3121,6 +3182,33 @@ menulist.translate-infobar-element > .menulist-dropmarker {
border-radius: 1px;
}
/* Share */
%include ../shared/social/social.inc.css
#social-share-panel {
min-height: 100px;
min-width: 300px;
transition: height .3s ease-in-out, width .3s ease-in-out;
}
#share-container,
.social-share-frame {
border-top-left-radius: 0;
border-bottom-left-radius: inherit;
border-top-right-radius: 0;
border-bottom-right-radius: inherit;
}
#social-share-panel > .social-share-toolbar {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}
#social-share-provider-buttons {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}
/* Customization mode */
%include ../shared/customizableui/customizeMode.inc.css
+4
View File
@@ -124,6 +124,10 @@ browser.jar:
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/social/services-16.png (social/services-16.png)
skin/classic/browser/social/services-16@2x.png (social/services-16@2x.png)
skin/classic/browser/social/services-64.png (social/services-64.png)
skin/classic/browser/social/services-64@2x.png (social/services-64@2x.png)
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon.png (tabbrowser/alltabs-box-bkgnd-icon.png)
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted.png (tabbrowser/alltabs-box-bkgnd-icon-inverted.png)
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png (tabbrowser/alltabs-box-bkgnd-icon-inverted@2x.png)
@@ -0,0 +1,30 @@
%include aboutSocialError.css
body {
width: 310px;
margin: 1em auto;
}
#message-box {
margin-top: 2em;
background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
padding-inline-start: 30px;
}
#activation-frame {
border: none;
margin: 0;
width: 310px;
height: 200px;
}
#activation > p {
width: 100%;
text-align: center;
margin: 0;
line-height: 2em;
}
.link {
text-decoration: none;
color: -moz-nativehyperlinktext;
cursor: pointer;
}
+1 -1
View File
@@ -2,7 +2,7 @@
% Note that zoom-reset-button is a bit different since it doesn't use an image and thus has the image with display: none.
%define nestedButtons #zoom-out-button, #zoom-reset-button, #zoom-in-button, #cut-button, #copy-button, #paste-button
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #webide-button, #containers-panelmenu
%define primaryToolbarButtons #back-button, #forward-button, #home-button, #print-button, #downloads-button, #bookmarks-menu-button, #new-tab-button, #new-window-button, #fullscreen-button, #sync-button, #feed-button, #social-share-button, #open-file-button, #find-button, #developer-button, #preferences-button, #privatebrowsing-button, #save-page-button, #add-ons-button, #history-panelmenu, #nav-bar-overflow-button, #PanelUI-menu-button, #characterencoding-button, #email-link-button, #sidebar-button, @nestedButtons@, #e10s-button, #panic-button, #webide-button, #containers-panelmenu
%ifdef XP_MACOSX
% Prior to 10.7 there wasn't a native fullscreen button so we use #restore-button to exit fullscreen
@@ -951,6 +951,7 @@ panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.panelUI-grid .toolbarbutton-1 > .toolbarbutton-menubutton-button,
.share-provider-button,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton {
-moz-appearance: none;
padding: 0 6px;
@@ -963,6 +964,7 @@ panelview .toolbarbutton-1,
panelview .toolbarbutton-1,
.subviewbutton,
.widget-overflow-list .toolbarbutton-1,
.share-provider-button,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton {
border-width: 1px;
}
@@ -1036,6 +1038,7 @@ panelview .toolbarbutton-1@buttonStateHover@,
toolbarbutton.subviewbutton@buttonStateHover@,
menu.subviewbutton@menuStateHover@,
menuitem.subviewbutton@menuStateHover@,
.share-provider-button@buttonStateHover@:not([checked="true"]),
.widget-overflow-list .toolbarbutton-1@buttonStateHover@,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton@buttonStateHover@ {
background-color: var(--arrowpanel-dimmed);
@@ -1050,6 +1053,7 @@ panelview .toolbarbutton-1:-moz-any(@buttonStateActive@,[checked=true]),
toolbarbutton.subviewbutton@buttonStateActive@,
menu.subviewbutton@menuStateActive@,
menuitem.subviewbutton@menuStateActive@,
.share-provider-button:-moz-any(@buttonStateActive@,[checked=true]),
.widget-overflow-list .toolbarbutton-1@buttonStateActive@,
.toolbaritem-combined-buttons@inAnyPanel@ > toolbarbutton@buttonStateActive@ {
background-color: var(--arrowpanel-dimmed-further);
+5
View File
@@ -10,7 +10,9 @@
skin/classic/browser/aboutNetError.css (../shared/aboutNetError.css)
skin/classic/browser/blockedSite.css (../shared/blockedSite.css)
skin/classic/browser/error-pages.css (../shared/error-pages.css)
* skin/classic/browser/aboutProviderDirectory.css (../shared/aboutProviderDirectory.css)
* skin/classic/browser/aboutSessionRestore.css (../shared/aboutSessionRestore.css)
skin/classic/browser/aboutSocialError.css (../shared/aboutSocialError.css)
skin/classic/browser/aboutTabCrashed.css (../shared/aboutTabCrashed.css)
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
skin/classic/browser/content-contextmenu.svg (../shared/content-contextmenu.svg)
@@ -63,6 +65,7 @@
* skin/classic/browser/identity-icon.svg (../shared/identity-block/identity-icon.svg)
skin/classic/browser/info.svg (../shared/info.svg)
* skin/classic/browser/menuPanel.svg (../shared/menuPanel.svg)
* skin/classic/browser/menuPanel-small.svg (../shared/menuPanel-small.svg)
* skin/classic/browser/notification-icons.svg (../shared/notification-icons.svg)
* skin/classic/browser/tracking-protection-16.svg (../shared/identity-block/tracking-protection-16.svg)
skin/classic/browser/newtab/close.png (../shared/newtab/close.png)
@@ -97,6 +100,8 @@
skin/classic/browser/search-indicator-magnifying-glass.svg (../shared/search/search-indicator-magnifying-glass.svg)
skin/classic/browser/search-arrow-go.svg (../shared/search/search-arrow-go.svg)
skin/classic/browser/gear.svg (../shared/search/gear.svg)
skin/classic/browser/social/gear_default.png (../shared/social/gear_default.png)
skin/classic/browser/social/gear_clicked.png (../shared/social/gear_clicked.png)
skin/classic/browser/tabbrowser/connecting.png (../shared/tabbrowser/connecting.png)
skin/classic/browser/tabbrowser/connecting@2x.png (../shared/tabbrowser/connecting@2x.png)
skin/classic/browser/tabbrowser/crashed.svg (../shared/tabbrowser/crashed.svg)
+16
View File
@@ -0,0 +1,16 @@
<?xml version="1.0"?>
<!-- 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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="96" height="16" viewBox="0 0 96 16"
class="fieldtext">
#include icon-colors.inc.svg
<path id="placeholder" d="M8,16a8,8,0,1,1,8-8A8,8,0,0,1,8,16ZM12,4H4v8h8V4ZM5,9.939V6.061L6.939,8ZM9.939,11H6.061L8,9.061ZM11,11h0Zm0-4.939V9.939L9.061,8ZM11,5h0ZM6.061,5H9.939L8,6.939Z"/>
<path id="cut" d="M29.63,15a2.426,2.426,0,0,1-2.282-1.277c-0.761-1.109-1.694-2.488-1.694-2.488S25,10.329,24.549,9.623a1.05,1.05,0,0,0-1.106-.538S20.6,4.437,20.124,3.706C19.465,2.689,20.7,1,20.7,1l4.4,7.044a19.333,19.333,0,0,0,1.867,2.286c0.519,0.4,1.382-.373,2.8.908C31.7,12.984,31.048,15,29.63,15ZM29.423,12.11c-0.933-1.042-1.728-.908-1.936-0.639a2.093,2.093,0,0,0,.38,1.748,1.612,1.612,0,0,0,1.383.74C29.838,13.959,30.356,13.153,29.423,12.11ZM25.582,7.372L24.4,5.6,27.276,1s1.233,1.69.575,2.708C27.568,4.142,26.445,5.967,25.582,7.372Zm-4.576,2.956A12.482,12.482,0,0,0,22.43,8.645l0.826,1.239c-0.428.65-.937,1.352-0.937,1.352s-0.933,1.378-1.694,2.488A2.426,2.426,0,0,1,18.344,15c-1.417,0-2.074-2.017-.138-3.765C19.624,9.956,20.487,10.732,21.006,10.329ZM18.551,12.11c-0.933,1.042-.415,1.849.173,1.849a1.612,1.612,0,0,0,1.383-.74,2.093,2.093,0,0,0,.38-1.748C20.28,11.2,19.485,11.068,18.551,12.11Z"/>
<path id="copy" d="M46,15H40a1,1,0,0,1-1-1V6a1,1,0,0,1,1-1h4.953C45,5,47,6.984,47,7.047V14A1,1,0,0,1,46,15ZM44,6V8h2ZM38,4.886V11H34a1,1,0,0,1-1-1V2a1,1,0,0,1,1-1h4.953C39,1,41,2.985,41,3.047v1.34H38.5A0.5,0.5,0,0,0,38,4.886ZM38,2V4h2Z"/>
<path id="paste" d="M59.5,15h-7A1.5,1.5,0,0,1,51,13.5v-9A1.5,1.5,0,0,1,52.5,3H54a2,2,0,1,1,4,0h1.5A1.5,1.5,0,0,1,61,4.5v9A1.5,1.5,0,0,1,59.5,15ZM58.682,4L57.61,3.5a1.613,1.613,0,0,0-3.219,0L53.318,4,52.781,5h6.437ZM58.82,5.688H54.074L51.059,7.428l2.849,4.935,6.574-3.8Z"/>
<rect id="zoomOut" x="67" y="7" width="10" height="2"/>
<path id="zoomIn" d="M93,9H89v4H87V9H83V7h4V3h2V7h4V9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+10
View File
@@ -63,6 +63,11 @@ toolbarpaletteitem[place="palette"] > #feed-button {
-moz-image-region: rect(0px, 416px, 32px, 384px);
}
#social-share-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #social-share-button {
-moz-image-region: rect(0px, 448px, 32px, 416px);
}
#characterencoding-button[cui-areatype="menu-panel"],
toolbarpaletteitem[place="palette"] > #characterencoding-button {
-moz-image-region: rect(0px, 480px, 32px, 448px);
@@ -171,3 +176,8 @@ 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.svg);
-moz-image-region: rect(0px, 96px, 16px, 80px);
}
@@ -271,6 +271,28 @@ html|*#webRTC-previewVideo {
}
}
/* SOCIAL API */
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64.png);
}
.service-icon {
list-style-image: url(chrome://browser/skin/social/services-16.png);
}
%ifdef XP_MACOSX
@media (min-resolution: 1.1dppx) {
.popup-notification-icon[popupid="servicesInstall"] {
list-style-image: url(chrome://browser/skin/social/services-64@2x.png);
}
.service-icon {
list-style-image: url(chrome://browser/skin/social/services-16@2x.png);
}
}
%endif
/* TRANSLATION */
.translation-icon {
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,23 @@
%if 0
/* 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/. */
%endif
#manage-share-providers {
list-style-image: url("chrome://browser/skin/Toolbar.png");
-moz-image-region: rect(0, 468px, 18px, 450px);
}
#manage-share-providers > .toolbarbutton-icon {
min-height: 18px;
min-width: 18px;
}
.social-panel > .panel-arrowcontainer > .panel-arrowcontent {
padding: 0;
}
/* fixup corners for share panel */
.social-panel > .social-panel-frame {
border-radius: inherit;
}
@@ -64,6 +64,10 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke
-moz-image-region: rect(0, 288px, 18px, 270px);
}
#social-share-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0px, 306px, 18px, 288px);
}
#characterencoding-button[cui-areatype="toolbar"]{
-moz-image-region: rect(0, 324px, 18px, 306px);
}
@@ -238,6 +242,10 @@ toolbar[brighttext] #bookmarks-menu-button > .toolbarbutton-menubutton-dropmarke
-moz-image-region: rect(0, 576px, 36px, 540px);
}
#social-share-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 612px, 36px, 576px);
}
#characterencoding-button[cui-areatype="toolbar"] {
-moz-image-region: rect(0, 648px, 36px, 612px);
}
+75
View File
@@ -1874,6 +1874,81 @@ html|span.ac-emphasize-text-url {
-moz-image-region: rect(0, 48px, 16px, 32px);
}
/* social share panel */
%include ../shared/social/social.inc.css
.social-panel-frame {
border-radius: inherit;
}
.social-share-frame {
min-width: 756px;
height: 150px;
}
#share-container {
min-width: 756px;
background-color: white;
background-repeat: no-repeat;
background-position: center center;
}
#share-container[loading] {
background-image: url(chrome://browser/skin/tabbrowser/pendingpaint.png);
}
#share-container > browser {
transition: opacity 150ms ease-in-out;
opacity: 1;
}
#share-container[loading] > browser {
opacity: 0;
}
.social-share-toolbar {
border-bottom: 1px solid #e2e5e8;
padding: 2px;
}
#social-share-provider-buttons {
padding: 0;
margin: 0;
}
.share-provider-button {
padding: 5px;
margin: 2px;
}
.share-provider-button > .toolbarbutton-text {
display: none;
}
.share-provider-button > .toolbarbutton-icon {
width: 16px;
min-height: 16px;
max-height: 16px;
}
#social-share-panel {
min-height: 100px;
min-width: 766px;
}
#share-container,
.social-share-frame {
border-top-left-radius: 0;
border-bottom-left-radius: inherit;
border-top-right-radius: 0;
border-bottom-right-radius: inherit;
}
#social-share-panel > .social-share-toolbar {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}
#social-share-provider-buttons {
border-top-left-radius: inherit;
border-top-right-radius: inherit;
}
/* bookmarks menu-button */
#nav-bar #bookmarks-menu-button[cui-areatype="toolbar"]:not([overflowedItem=true]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
@@ -97,6 +97,14 @@ menuitem[type="checkbox"].subviewbutton {
padding-inline-start: 0;
}
/* subviewbutton entries for social sidebars have images that come from external
/* sources, and are not guaranteed to be the size we want, so force the size on
/* those icons. */
toolbarbutton.social-provider-menuitem > .toolbarbutton-icon {
width: 16px;
height: 16px;
}
.subviewbutton:-moz-any([image],[targetURI],.cui-withicon, .restoreallitem, .bookmark-item)[checked="true"] > .toolbarbutton-icon {
visibility: hidden;
}
+2
View File
@@ -133,6 +133,8 @@ browser.jar:
* skin/classic/browser/preferences/in-content/preferences.css (preferences/in-content/preferences.css)
* skin/classic/browser/preferences/in-content/dialog.css (preferences/in-content/dialog.css)
skin/classic/browser/preferences/applications.css (preferences/applications.css)
skin/classic/browser/social/services-16.png (social/services-16.png)
skin/classic/browser/social/services-64.png (social/services-64.png)
skin/classic/browser/tabbrowser/newtab.svg (tabbrowser/newtab.svg)
skin/classic/browser/tabbrowser/newtab-XPVista7.svg (tabbrowser/newtab-XPVista7.svg)
skin/classic/browser/tabbrowser/newtab-inverted.svg (tabbrowser/newtab-inverted.svg)
@@ -407,6 +407,8 @@ MessageManagerTunnel.prototype = {
"PageInfo:",
// Messages sent from printUtils.js
"Printing:",
// Messages sent from browser-social.js
"Social:",
"PageMetadata:",
// Messages sent from viewSourceUtils.js
"ViewSource:",
@@ -425,6 +427,8 @@ MessageManagerTunnel.prototype = {
"PageInfo:",
// Messages sent to printUtils.js
"Printing:",
// Messages sent to browser-social.js
"Social:",
"PageMetadata:",
// Messages sent to viewSourceUtils.js
"ViewSource:",
+1
View File
@@ -62,6 +62,7 @@ option(env='MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER',
set_config('MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER',
depends_if('MOZ_ANDROID_PACKAGE_INSTALL_BOUNCER')(lambda _: True))
imply_option('MOZ_SOCIAL', False)
imply_option('MOZ_SERVICES_HEALTHREPORT', True)
imply_option('MOZ_ANDROID_HISTORY', True)
+12
View File
@@ -4861,6 +4861,18 @@ pref("memory.dump_reports_on_oom", false);
// Number of stack frames to capture in createObjectURL for about:memory.
pref("memory.blob_report.stack_frames", 0);
// comma separated list of domain origins (e.g. https://domain.com) that still
// need localStorage in the frameworker
pref("social.whitelist", "https://mozsocial.cliqz.com");
// comma separated list of domain origins (e.g. https://domain.com) for
// directory websites (e.g. AMO) that can install providers for other sites
pref("social.directories", "https://activations.cdn.mozilla.net");
// remote-install allows any website to activate a provider, with extended UI
// notifying user of installation. we can later pref off remote install if
// necessary. This does not affect whitelisted and directory installs.
pref("social.remote-install.enabled", true);
pref("social.toast-notifications.enabled", true);
// Disable idle observer fuzz, because only privileged content can access idle
// observers (bug 780507).
pref("dom.idle-observers-api.fuzz_time.disabled", true);
+7
View File
@@ -2250,6 +2250,7 @@ MOZ_JETPACK=1
MOZ_DEVTOOLS_SERVER=1
MOZ_DEVTOOLS=
MOZ_PLACES=1
MOZ_SOCIAL=1
MOZ_SERVICES_HEALTHREPORT=1
MOZ_SERVICES_SYNC=1
MOZ_SERVICES_CLOUDSYNC=1
@@ -5115,6 +5116,12 @@ if test "$MOZ_PLACES"; then
AC_DEFINE(MOZ_PLACES)
fi
dnl Build SocialAPI if required
AC_SUBST(MOZ_SOCIAL)
if test "$MOZ_SOCIAL"; then
AC_DEFINE(MOZ_SOCIAL)
fi
dnl Build Firefox Health Reporter Service
AC_SUBST(MOZ_SERVICES_HEALTHREPORT)
if test -n "$MOZ_SERVICES_HEALTHREPORT"; then
+1
View File
@@ -588,6 +588,7 @@ Tester.prototype = {
sidebar.setAttribute("src", "about:blank");
SelfSupportBackend.uninit();
SocialShare.uninit();
}
// Destroy BackgroundPageThumbs resources.
@@ -6677,6 +6677,11 @@
"kind": "boolean",
"description": "If we are on Windows and neither the Windows countryCode nor the geoip countryCode indicates we are in the US, set to false if they both agree on the value or true otherwise"
},
"SOCIAL_ENABLED_ON_SESSION": {
"expires_in_version": "never",
"kind": "flag",
"description": "Social has been enabled at least once on the current session"
},
"ENABLE_PRIVILEGE_EVER_CALLED": {
"expires_in_version": "never",
"kind": "flag",
@@ -8963,6 +8968,30 @@
"description": "Scaling percentage for the display where the first window is opened (Linux only)",
"cpp_guard": "XP_LINUX"
},
"SOCIAL_SIDEBAR_STATE": {
"expires_in_version": "never",
"kind": "boolean",
"description": "Social Sidebar state 0: closed, 1: opened. Toggling between providers will result in a higher opened rate."
},
"SOCIAL_TOOLBAR_BUTTONS": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 3,
"description": "Social toolbar button has been used (0:share, 1:status, 2:bookmark)"
},
"SOCIAL_PANEL_CLICKS": {
"expires_in_version": "never",
"kind": "enumerated",
"n_values": 4,
"description": "Social content has been interacted with (0:share, 1:status, 2:bookmark, 3: sidebar)"
},
"SOCIAL_SIDEBAR_OPEN_DURATION": {
"expires_in_version": "never",
"kind": "exponential",
"high": 10000000,
"n_buckets": 10,
"description": "Sidebar showing: seconds that the sidebar has been opened"
},
"SHUTDOWN_PHASE_DURATION_TICKS_QUIT_APPLICATION": {
"expires_in_version": "never",
"kind": "exponential",
@@ -610,6 +610,11 @@
"SHUTDOWN_PHASE_DURATION_TICKS_XPCOM_WILL_SHUTDOWN",
"SLOW_ADDON_WARNING_RESPONSE_TIME",
"SLOW_ADDON_WARNING_STATES",
"SOCIAL_ENABLED_ON_SESSION",
"SOCIAL_PANEL_CLICKS",
"SOCIAL_SIDEBAR_OPEN_DURATION",
"SOCIAL_SIDEBAR_STATE",
"SOCIAL_TOOLBAR_BUTTONS",
"SPDY_CHUNK_RECVD",
"SPDY_GOAWAY_LOCAL",
"SPDY_GOAWAY_PEER",
@@ -1496,6 +1501,11 @@
"SLOW_ADDON_WARNING_RESPONSE_TIME",
"SLOW_ADDON_WARNING_STATES",
"SLOW_SCRIPT_NOTICE_COUNT",
"SOCIAL_ENABLED_ON_SESSION",
"SOCIAL_PANEL_CLICKS",
"SOCIAL_SIDEBAR_OPEN_DURATION",
"SOCIAL_SIDEBAR_STATE",
"SOCIAL_TOOLBAR_BUTTONS",
"SPDY_CHUNK_RECVD",
"SPDY_GOAWAY_LOCAL",
"SPDY_GOAWAY_PEER",
+1
View File
@@ -83,6 +83,7 @@ const PREFS_WHITELIST = [
"services.sync.lastSync",
"services.sync.numClients",
"services.sync.engine.",
"social.enabled",
"storage.vacuum.last.",
"svg.",
"toolkit.startup.recent_crashes",