summaryrefslogtreecommitdiffstats
path: root/browser/modules
diff options
context:
space:
mode:
Diffstat (limited to 'browser/modules')
-rw-r--r--browser/modules/BrowserUITelemetry.jsm11
-rw-r--r--browser/modules/Social.jsm272
-rw-r--r--browser/modules/SocialService.jsm1097
-rw-r--r--browser/modules/moz.build2
4 files changed, 5 insertions, 1377 deletions
diff --git a/browser/modules/BrowserUITelemetry.jsm b/browser/modules/BrowserUITelemetry.jsm
index 392462b45..2ad319f1a 100644
--- a/browser/modules/BrowserUITelemetry.jsm
+++ b/browser/modules/BrowserUITelemetry.jsm
@@ -53,7 +53,6 @@ XPCOMUtils.defineLazyGetter(this, "DEFAULT_AREA_PLACEMENTS", function() {
"pocket-button",
"downloads-button",
"home-button",
- "social-share-button",
],
// It's true that toolbar-menubar is not visible
// on OS X, but the XUL node is definitely present
@@ -694,7 +693,7 @@ this.BrowserUITelemetry = {
"spell-undo-add-to-dictionary", "openlinkincurrent", "openlinkintab",
"openlink",
// "openlinkprivate" intentionally omitted for privacy reasons. See bug 1176391.
- "bookmarklink", "sharelink", "savelink",
+ "bookmarklink", "savelink",
"marklinkMenu", "copyemail", "copylink", "media-play", "media-pause",
"media-mute", "media-unmute", "media-playbackrate",
"media-playbackrate-050x", "media-playbackrate-100x",
@@ -702,12 +701,12 @@ this.BrowserUITelemetry = {
"media-showcontrols", "media-hidecontrols",
"video-fullscreen", "leave-dom-fullscreen",
"reloadimage", "viewimage", "viewvideo", "copyimage-contents", "copyimage",
- "copyvideourl", "copyaudiourl", "saveimage", "shareimage", "sendimage",
+ "copyvideourl", "copyaudiourl", "saveimage", "sendimage",
"setDesktopBackground", "viewimageinfo", "viewimagedesc", "savevideo",
- "sharevideo", "saveaudio", "video-saveimage", "sendvideo", "sendaudio",
- "ctp-play", "ctp-hide", "sharepage", "savepage", "pocket", "markpageMenu",
+ "saveaudio", "video-saveimage", "sendvideo", "sendaudio",
+ "ctp-play", "ctp-hide", "savepage", "pocket", "markpageMenu",
"viewbgimage", "undo", "cut", "copy", "paste", "delete", "selectall",
- "keywordfield", "searchselect", "shareselect", "frame", "showonlythisframe",
+ "keywordfield", "searchselect", "frame", "showonlythisframe",
"openframeintab", "openframe", "reloadframe", "bookmarkframe", "saveframe",
"printframe", "viewframesource", "viewframeinfo",
"viewpartialsource-selection", "viewpartialsource-mathml",
diff --git a/browser/modules/Social.jsm b/browser/modules/Social.jsm
deleted file mode 100644
index 1569e0122..000000000
--- a/browser/modules/Social.jsm
+++ /dev/null
@@ -1,272 +0,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/. */
-
-"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;
- },
-};
diff --git a/browser/modules/SocialService.jsm b/browser/modules/SocialService.jsm
deleted file mode 100644
index 95f5e0259..000000000
--- a/browser/modules/SocialService.jsm
+++ /dev/null
@@ -1,1097 +0,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/. */
-
-this.EXPORTED_SYMBOLS = ["SocialService"];
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/AddonManager.jsm");
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
-
-const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
-const ADDON_TYPE_SERVICE = "service";
-const ID_SUFFIX = "@services.mozilla.org";
-const STRING_TYPE_NAME = "type.%ID%.name";
-
-XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", "resource://gre/modules/DeferredTask.jsm");
-
-XPCOMUtils.defineLazyServiceGetter(this, "etld",
- "@mozilla.org/network/effective-tld-service;1",
- "nsIEffectiveTLDService");
-
-/**
- * The SocialService is the public API to social providers - it tracks which
- * providers are installed and enabled, and is the entry-point for access to
- * the provider itself.
- */
-
-// Internal helper methods and state
-var SocialServiceInternal = {
- get enabled() {
- return this.providerArray.length > 0;
- },
-
- get providerArray() {
- return Object.keys(this.providers).map(origin => this.providers[origin]);
- },
- *manifestsGenerator() {
- // Retrieve the manifests of installed providers from prefs
- let MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
- let prefs = MANIFEST_PREFS.getChildList("", []);
- for (let pref of prefs) {
- // we only consider manifests in user level prefs to be *installed*
- if (!MANIFEST_PREFS.prefHasUserValue(pref))
- continue;
- try {
- var manifest = JSON.parse(MANIFEST_PREFS.getComplexValue(pref, Ci.nsISupportsString).data);
- if (manifest && typeof(manifest) == "object" && manifest.origin)
- yield manifest;
- } catch (err) {
- Cu.reportError("SocialService: failed to load manifest: " + pref +
- ", exception: " + err);
- }
- }
- },
- get manifests() {
- return this.manifestsGenerator();
- },
- getManifestPrefname: function(origin) {
- // Retrieve the prefname for a given origin/manifest.
- // If no existing pref, return a generated prefname.
- let MANIFEST_PREFS = Services.prefs.getBranch("social.manifest.");
- let prefs = MANIFEST_PREFS.getChildList("", []);
- for (let pref of prefs) {
- try {
- var manifest = JSON.parse(MANIFEST_PREFS.getComplexValue(pref, Ci.nsISupportsString).data);
- if (manifest.origin == origin) {
- return pref;
- }
- } catch (err) {
- Cu.reportError("SocialService: failed to load manifest: " + pref +
- ", exception: " + err);
- }
- }
- let originUri = Services.io.newURI(origin, null, null);
- return originUri.hostPort.replace('.', '-');
- },
- orderedProviders: function(aCallback) {
- if (SocialServiceInternal.providerArray.length < 2) {
- schedule(function () {
- aCallback(SocialServiceInternal.providerArray);
- });
- return;
- }
- // query moz_hosts for frecency. since some providers may not have a
- // frecency entry, we need to later sort on our own. We use the providers
- // object below as an easy way to later record the frecency on the provider
- // object from the query results.
- let hosts = [];
- let providers = {};
-
- for (let p of SocialServiceInternal.providerArray) {
- p.frecency = 0;
- providers[p.domain] = p;
- hosts.push(p.domain);
- }
-
- // cannot bind an array to stmt.params so we have to build the string
- let stmt = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
- .DBConnection.createAsyncStatement(
- "SELECT host, frecency FROM moz_hosts WHERE host IN (" +
- hosts.map(host => '"' + host + '"').join(",") + ") "
- );
-
- try {
- stmt.executeAsync({
- handleResult: function(aResultSet) {
- let row;
- while ((row = aResultSet.getNextRow())) {
- let rh = row.getResultByName("host");
- let frecency = row.getResultByName("frecency");
- providers[rh].frecency = parseInt(frecency) || 0;
- }
- },
- handleError: function(aError) {
- Cu.reportError(aError.message + " (Result = " + aError.result + ")");
- },
- handleCompletion: function(aReason) {
- // the query may not have returned all our providers, so we have
- // stamped the frecency on the provider and sort here. This makes sure
- // all enabled providers get sorted even with frecency zero.
- let providerList = SocialServiceInternal.providerArray;
- // reverse sort
- aCallback(providerList.sort((a, b) => b.frecency - a.frecency));
- }
- });
- } finally {
- stmt.finalize();
- }
- }
-};
-
-XPCOMUtils.defineLazyGetter(SocialServiceInternal, "providers", function () {
- initService();
- let providers = {};
- for (let manifest of this.manifests) {
- try {
- if (ActiveProviders.has(manifest.origin)) {
- // enable the api when a provider is enabled
- let provider = new SocialProvider(manifest);
- providers[provider.origin] = provider;
- }
- } catch (err) {
- Cu.reportError("SocialService: failed to load provider: " + manifest.origin +
- ", exception: " + err);
- }
- }
- return providers;
-});
-
-function getOriginActivationType(origin) {
- // if this is an about uri, treat it as a directory
- let URI = Services.io.newURI(origin, null, null);
- let principal = Services.scriptSecurityManager.createCodebasePrincipal(URI, {});
- if (Services.scriptSecurityManager.isSystemPrincipal(principal) || origin == "moz-safe-about:home") {
- return "internal";
- }
-
- let directories = Services.prefs.getCharPref("social.directories").split(',');
- if (directories.indexOf(origin) >= 0)
- return "directory";
-
- return "foreign";
-}
-
-var ActiveProviders = {
- get _providers() {
- delete this._providers;
- this._providers = {};
- try {
- let pref = Services.prefs.getComplexValue("social.activeProviders",
- Ci.nsISupportsString);
- this._providers = JSON.parse(pref);
- } catch (ex) {}
- return this._providers;
- },
-
- has: function (origin) {
- return (origin in this._providers);
- },
-
- add: function (origin) {
- this._providers[origin] = 1;
- this._deferredTask.arm();
- },
-
- delete: function (origin) {
- delete this._providers[origin];
- this._deferredTask.arm();
- },
-
- flush: function () {
- this._deferredTask.disarm();
- this._persist();
- },
-
- get _deferredTask() {
- delete this._deferredTask;
- return this._deferredTask = new DeferredTask(this._persist.bind(this), 0);
- },
-
- _persist: function () {
- let string = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- string.data = JSON.stringify(this._providers);
- Services.prefs.setComplexValue("social.activeProviders",
- Ci.nsISupportsString, string);
- }
-};
-
-function migrateSettings() {
- let activeProviders, enabled;
- try {
- activeProviders = Services.prefs.getCharPref("social.activeProviders");
- } catch (e) {
- // not set, we'll check if we need to migrate older prefs
- }
- if (Services.prefs.prefHasUserValue("social.enabled")) {
- enabled = Services.prefs.getBoolPref("social.enabled");
- }
- if (activeProviders) {
- // migration from fx21 to fx22 or later
- // ensure any *builtin* provider in activeproviders is in user level prefs
- for (let origin in ActiveProviders._providers) {
- let prefname;
- let manifest;
- let defaultManifest;
- try {
- prefname = getPrefnameFromOrigin(origin);
- manifest = JSON.parse(Services.prefs.getComplexValue(prefname, Ci.nsISupportsString).data);
- } catch (e) {
- // Our preference is missing or bad, remove from ActiveProviders and
- // continue. This is primarily an error-case and should only be
- // reached by either messing with preferences or hitting the one or
- // two days of nightly that ran into it, so we'll flush right away.
- ActiveProviders.delete(origin);
- ActiveProviders.flush();
- continue;
- }
- let needsUpdate = !manifest.updateDate;
- // fx23 may have built-ins with shareURL
- try {
- defaultManifest = Services.prefs.getDefaultBranch(null)
- .getComplexValue(prefname, Ci.nsISupportsString).data;
- defaultManifest = JSON.parse(defaultManifest);
- } catch (e) {
- // not a built-in, continue
- }
- if (defaultManifest) {
- if (defaultManifest.shareURL && !manifest.shareURL) {
- manifest.shareURL = defaultManifest.shareURL;
- needsUpdate = true;
- }
- if (defaultManifest.version && (!manifest.version || defaultManifest.version > manifest.version)) {
- manifest = defaultManifest;
- needsUpdate = true;
- }
- }
- if (needsUpdate) {
- // the provider was installed with an older build, so we will update the
- // timestamp and ensure the manifest is in user prefs
- delete manifest.builtin;
- // we're potentially updating for share, so always mark the updateDate
- manifest.updateDate = Date.now();
- if (!manifest.installDate)
- manifest.installDate = 0; // we don't know when it was installed
-
- let string = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- string.data = JSON.stringify(manifest);
- Services.prefs.setComplexValue(prefname, Ci.nsISupportsString, string);
- }
- // as of fx 29, we no longer rely on social.enabled. migration from prior
- // versions should disable all service addons if social.enabled=false
- if (enabled === false) {
- ActiveProviders.delete(origin);
- }
- }
- ActiveProviders.flush();
- Services.prefs.clearUserPref("social.enabled");
- return;
- }
-
- // primary migration from pre-fx21
- let active;
- try {
- active = Services.prefs.getBoolPref("social.active");
- } catch (e) {}
- if (!active)
- return;
-
- // primary difference from SocialServiceInternal.manifests is that we
- // only read the default branch here.
- let manifestPrefs = Services.prefs.getDefaultBranch("social.manifest.");
- let prefs = manifestPrefs.getChildList("", []);
- for (let pref of prefs) {
- try {
- let manifest;
- try {
- manifest = JSON.parse(manifestPrefs.getComplexValue(pref, Ci.nsISupportsString).data);
- } catch (e) {
- // bad or missing preference, we wont update this one.
- continue;
- }
- if (manifest && typeof(manifest) == "object" && manifest.origin) {
- // our default manifests have been updated with the builtin flags as of
- // fx22, delete it so we can set the user-pref
- delete manifest.builtin;
- if (!manifest.updateDate) {
- manifest.updateDate = Date.now();
- manifest.installDate = 0; // we don't know when it was installed
- }
-
- let string = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
- string.data = JSON.stringify(manifest);
- // pref here is just the branch name, set the full pref name
- Services.prefs.setComplexValue("social.manifest." + pref, Ci.nsISupportsString, string);
- ActiveProviders.add(manifest.origin);
- ActiveProviders.flush();
- // social.active was used at a time that there was only one
- // builtin, we'll assume that is still the case
- return;
- }
- } catch (err) {
- Cu.reportError("SocialService: failed to load manifest: " + pref + ", exception: " + err);
- }
- }
-}
-
-function initService() {
- Services.obs.addObserver(function xpcomShutdown() {
- ActiveProviders.flush();
- SocialService._providerListeners = null;
- Services.obs.removeObserver(xpcomShutdown, "xpcom-shutdown");
- }, "xpcom-shutdown", false);
-
- try {
- migrateSettings();
- } catch (e) {
- // no matter what, if migration fails we do not want to render social
- // unusable. Worst case scenario is that, when upgrading Firefox, previously
- // enabled providers are not migrated.
- Cu.reportError("Error migrating social settings: " + e);
- }
-}
-
-function schedule(callback) {
- Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
-}
-
-// Public API
-this.SocialService = {
- get hasEnabledProviders() {
- // used as an optimization during startup, can be used to check if further
- // initialization should be done (e.g. creating the instances of
- // SocialProvider and turning on UI). ActiveProviders may have changed and
- // not yet flushed so we check the active providers array
- for (let p in ActiveProviders._providers) {
- return true;
- }
- return false;
- },
- get enabled() {
- return SocialServiceInternal.enabled;
- },
- set enabled(val) {
- throw new Error("not allowed to set SocialService.enabled");
- },
-
- // Enables a provider, the manifest must already exist in prefs. The provider
- // may or may not have previously been added. onDone is always called
- // - with null if no such provider exists, or the activated provider on
- // success.
- enableProvider: function enableProvider(origin, onDone) {
- if (SocialServiceInternal.providers[origin]) {
- schedule(function() {
- onDone(SocialServiceInternal.providers[origin]);
- });
- return;
- }
- let manifest = SocialService.getManifestByOrigin(origin);
- if (manifest) {
- let addon = new AddonWrapper(manifest);
- AddonManagerPrivate.callAddonListeners("onEnabling", addon, false);
- addon.pendingOperations |= AddonManager.PENDING_ENABLE;
- this.addProvider(manifest, onDone);
- addon.pendingOperations -= AddonManager.PENDING_ENABLE;
- AddonManagerPrivate.callAddonListeners("onEnabled", addon);
- return;
- }
- schedule(function() {
- onDone(null);
- });
- },
-
- // Adds a provider given a manifest, and returns the added provider.
- addProvider: function addProvider(manifest, onDone) {
- if (SocialServiceInternal.providers[manifest.origin])
- throw new Error("SocialService.addProvider: provider with this origin already exists");
-
- // enable the api when a provider is enabled
- let provider = new SocialProvider(manifest);
- SocialServiceInternal.providers[provider.origin] = provider;
- ActiveProviders.add(provider.origin);
-
- this.getOrderedProviderList(function (providers) {
- this._notifyProviderListeners("provider-enabled", provider.origin, providers);
- if (onDone)
- onDone(provider);
- }.bind(this));
- },
-
- // Removes a provider with the given origin, and notifies when the removal is
- // complete.
- disableProvider: function disableProvider(origin, onDone) {
- if (!(origin in SocialServiceInternal.providers))
- throw new Error("SocialService.disableProvider: no provider with origin " + origin + " exists!");
-
- let provider = SocialServiceInternal.providers[origin];
- let manifest = SocialService.getManifestByOrigin(origin);
- let addon = manifest && new AddonWrapper(manifest);
- if (addon) {
- AddonManagerPrivate.callAddonListeners("onDisabling", addon, false);
- addon.pendingOperations |= AddonManager.PENDING_DISABLE;
- }
- provider.enabled = false;
-
- ActiveProviders.delete(provider.origin);
-
- delete SocialServiceInternal.providers[origin];
-
- if (addon) {
- // we have to do this now so the addon manager ui will update an uninstall
- // correctly.
- addon.pendingOperations -= AddonManager.PENDING_DISABLE;
- AddonManagerPrivate.callAddonListeners("onDisabled", addon);
- }
-
- this.getOrderedProviderList(function (providers) {
- this._notifyProviderListeners("provider-disabled", origin, providers);
- if (onDone)
- onDone();
- }.bind(this));
- },
-
- // Returns a single provider object with the specified origin. The provider
- // must be "installed" (ie, in ActiveProviders)
- getProvider: function getProvider(origin, onDone) {
- schedule((function () {
- onDone(SocialServiceInternal.providers[origin] || null);
- }).bind(this));
- },
-
- // Returns an unordered array of installed providers
- getProviderList: function(onDone) {
- schedule(function () {
- onDone(SocialServiceInternal.providerArray);
- });
- },
-
- getManifestByOrigin: function(origin) {
- for (let manifest of SocialServiceInternal.manifests) {
- if (origin == manifest.origin) {
- return manifest;
- }
- }
- return null;
- },
-
- // Returns an array of installed providers, sorted by frecency
- getOrderedProviderList: function(onDone) {
- SocialServiceInternal.orderedProviders(onDone);
- },
-
- getOriginActivationType: function (origin) {
- return getOriginActivationType(origin);
- },
-
- _providerListeners: new Map(),
- registerProviderListener: function registerProviderListener(listener) {
- this._providerListeners.set(listener, 1);
- },
- unregisterProviderListener: function unregisterProviderListener(listener) {
- this._providerListeners.delete(listener);
- },
-
- _notifyProviderListeners: function (topic, origin, providers) {
- for (let [listener, ] of this._providerListeners) {
- try {
- listener(topic, origin, providers);
- } catch (ex) {
- Components.utils.reportError("SocialService: provider listener threw an exception: " + ex);
- }
- }
- },
-
- _manifestFromData: function(type, data, installOrigin) {
- let featureURLs = ['shareURL'];
- let resolveURLs = featureURLs.concat(['postActivationURL']);
-
- if (type == 'directory' || type == 'internal') {
- // directory provided manifests must have origin in manifest, use that
- if (!data['origin']) {
- Cu.reportError("SocialService.manifestFromData directory service provided manifest without origin.");
- return null;
- }
- installOrigin = data.origin;
- }
- // force/fixup origin
- let URI = Services.io.newURI(installOrigin, null, null);
- let principal = Services.scriptSecurityManager.createCodebasePrincipal(URI, {});
- data.origin = principal.origin;
-
- // iconURL and name are required
- let providerHasFeatures = featureURLs.some(url => data[url]);
- if (!providerHasFeatures) {
- Cu.reportError("SocialService.manifestFromData manifest missing required urls.");
- return null;
- }
- if (!data['name'] || !data['iconURL']) {
- Cu.reportError("SocialService.manifestFromData manifest missing name or iconURL.");
- return null;
- }
- for (let url of resolveURLs) {
- if (data[url]) {
- try {
- let resolved = Services.io.newURI(principal.URI.resolve(data[url]), null, null);
- if (!(resolved.schemeIs("http") || resolved.schemeIs("https"))) {
- Cu.reportError("SocialService.manifestFromData unsupported scheme '" + resolved.scheme + "' for " + principal.origin);
- return null;
- }
- data[url] = resolved.spec;
- } catch (e) {
- Cu.reportError("SocialService.manifestFromData unable to resolve '" + url + "' for " + principal.origin);
- return null;
- }
- }
- }
- return data;
- },
-
- _showInstallNotification: function(data, aAddonInstaller) {
- let brandBundle = Services.strings.createBundle("chrome://branding/locale/brand.properties");
- let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
-
- // internal/directory activations need to use the manifest origin, any other
- // use the domain activation is occurring on
- let url = data.url;
- if (data.installType == "internal" || data.installType == "directory") {
- url = data.manifest.origin;
- }
- let requestingURI = Services.io.newURI(url, null, null);
- let productName = brandBundle.GetStringFromName("brandShortName");
-
- let message = browserBundle.formatStringFromName("service.install.description",
- [requestingURI.host, productName], 2);
-
- let action = {
- label: browserBundle.GetStringFromName("service.install.ok.label"),
- accessKey: browserBundle.GetStringFromName("service.install.ok.accesskey"),
- callback: function() {
- aAddonInstaller.install();
- },
- };
-
- let options = {
- learnMoreURL: Services.urlFormatter.formatURLPref("app.support.baseURL") + "social-api",
- };
- let anchor = "servicesInstall-notification-icon";
- let notificationid = "servicesInstall";
- data.window.PopupNotifications.show(data.window.gBrowser.selectedBrowser,
- notificationid, message, anchor,
- action, [], options);
- },
-
- installProvider: function(data, installCallback, options={}) {
- data.installType = getOriginActivationType(data.origin);
- // if we get data, we MUST have a valid manifest generated from the data
- let manifest = this._manifestFromData(data.installType, data.manifest, data.origin);
- if (!manifest)
- throw new Error("SocialService.installProvider: service configuration is invalid from " + data.url);
-
- let addon = new AddonWrapper(manifest);
- if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
- throw new Error("installProvider: provider with origin [" +
- data.origin + "] 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.
- data.manifest = manifest;
- let id = getAddonIDFromOrigin(manifest.origin);
- AddonManager.getAddonByID(id, function(aAddon) {
- if (aAddon && aAddon.userDisabled) {
- aAddon.cancelUninstall();
- aAddon.userDisabled = false;
- }
- schedule(function () {
- try {
- this._installProvider(data, options, aManifest => {
- this._notifyProviderListeners("provider-installed", aManifest.origin);
- installCallback(aManifest);
- });
- } catch (e) {
- Cu.reportError("Activation failed: " + e);
- installCallback(null);
- }
- }.bind(this));
- }.bind(this));
- },
-
- _installProvider: function(data, options, installCallback) {
- if (!data.manifest)
- throw new Error("Cannot install provider without manifest data");
-
- if (data.installType == "foreign" && !Services.prefs.getBoolPref("social.remote-install.enabled"))
- throw new Error("Remote install of services is disabled");
-
- // if installing from any website, the install must happen over https.
- // "internal" are installs from about:home or similar
- if (data.installType != "internal" && !Services.io.newURI(data.origin, null, null).schemeIs("https")) {
- throw new Error("attempt to activate provider over unsecured channel: " + data.origin);
- }
-
- let installer = new AddonInstaller(data.url, data.manifest, installCallback);
- let bypassPanel = options.bypassInstallPanel ||
- (data.installType == "internal" && data.manifest.oneclick);
- if (bypassPanel)
- installer.install();
- else
- this._showInstallNotification(data, installer);
- },
-
- createWrapper: function(manifest) {
- return new AddonWrapper(manifest);
- },
-
- /**
- * updateProvider is used from the worker to self-update. Since we do not
- * have knowledge of the currently selected provider here, we will notify
- * the front end to deal with any reload.
- */
- updateProvider: function(aUpdateOrigin, aManifest) {
- let installType = this.getOriginActivationType(aUpdateOrigin);
- // if we get data, we MUST have a valid manifest generated from the data
- let manifest = this._manifestFromData(installType, aManifest, aUpdateOrigin);
- if (!manifest)
- throw new Error("SocialService.installProvider: service configuration is invalid from " + aUpdateOrigin);
-
- // overwrite the preference
- let string = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- string.data = JSON.stringify(manifest);
- Services.prefs.setComplexValue(getPrefnameFromOrigin(manifest.origin), Ci.nsISupportsString, string);
-
- // overwrite the existing provider then notify the front end so it can
- // handle any reload that might be necessary.
- if (ActiveProviders.has(manifest.origin)) {
- let provider = SocialServiceInternal.providers[manifest.origin];
- provider.enabled = false;
- provider = new SocialProvider(manifest);
- SocialServiceInternal.providers[provider.origin] = provider;
- // update the cache and ui, reload provider if necessary
- this.getOrderedProviderList(providers => {
- this._notifyProviderListeners("provider-update", provider.origin, providers);
- });
- }
-
- },
-
- uninstallProvider: function(origin, aCallback) {
- let manifest = SocialService.getManifestByOrigin(origin);
- let addon = new AddonWrapper(manifest);
- addon.uninstall(aCallback);
- }
-};
-
-/**
- * The SocialProvider object represents a social provider.
- *
- * @constructor
- * @param {jsobj} object representing the manifest file describing this provider
- * @param {bool} boolean indicating whether this provider is "built in"
- */
-function SocialProvider(input) {
- if (!input.name)
- throw new Error("SocialProvider must be passed a name");
- if (!input.origin)
- throw new Error("SocialProvider must be passed an origin");
-
- let addon = new AddonWrapper(input);
- if (addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
- throw new Error("SocialProvider: provider with origin [" +
- input.origin + "] is blocklisted");
-
- this.name = input.name;
- this.iconURL = input.iconURL;
- this.icon32URL = input.icon32URL;
- this.icon64URL = input.icon64URL;
- this.shareURL = input.shareURL;
- this.postActivationURL = input.postActivationURL;
- this.origin = input.origin;
- let originUri = Services.io.newURI(input.origin, null, null);
- this.principal = Services.scriptSecurityManager.createCodebasePrincipal(originUri, {});
- this.ambientNotificationIcons = {};
- this.errorState = null;
- this.frecency = 0;
-
- try {
- this.domain = etld.getBaseDomainFromHost(originUri.host);
- } catch (e) {
- this.domain = originUri.host;
- }
-}
-
-SocialProvider.prototype = {
- reload: function() {
- // calling terminate/activate does not set the enabled state whereas setting
- // enabled will call terminate/activate
- this.enabled = false;
- this.enabled = true;
- Services.obs.notifyObservers(null, "social:provider-reload", this.origin);
- },
-
- // Provider enabled/disabled state.
- _enabled: false,
- get enabled() {
- return this._enabled;
- },
- set enabled(val) {
- let enable = !!val;
- if (enable == this._enabled)
- return;
-
- this._enabled = enable;
-
- if (enable) {
- this._activate();
- } else {
- this._terminate();
- }
- },
-
- get manifest() {
- return SocialService.getManifestByOrigin(this.origin);
- },
-
- getPageSize: function(name) {
- let manifest = this.manifest;
- if (manifest && manifest.pageSize)
- return manifest.pageSize[name];
- return undefined;
- },
-
- // Internal helper methods
- _activate: function _activate() {
- },
-
- _terminate: function _terminate() {
- this.errorState = null;
- },
-
- /**
- * Checks if a given URI is of the same origin as the provider.
- *
- * Returns true or false.
- *
- * @param {URI or string} uri
- */
- isSameOrigin: function isSameOrigin(uri, allowIfInheritsPrincipal) {
- if (!uri)
- return false;
- if (typeof uri == "string") {
- try {
- uri = Services.io.newURI(uri, null, null);
- } catch (ex) {
- // an invalid URL can't be loaded!
- return false;
- }
- }
- try {
- this.principal.checkMayLoad(
- uri, // the thing to check.
- false, // reportError - we do our own reporting when necessary.
- allowIfInheritsPrincipal
- );
- return true;
- } catch (ex) {
- return false;
- }
- },
-
- /**
- * Resolve partial URLs for a provider.
- *
- * Returns nsIURI object or null on failure
- *
- * @param {string} url
- */
- resolveUri: function resolveUri(url) {
- try {
- let fullURL = this.principal.URI.resolve(url);
- return Services.io.newURI(fullURL, null, null);
- } catch (ex) {
- Cu.reportError("mozSocial: failed to resolve window URL: " + url + "; " + ex);
- return null;
- }
- }
-};
-
-function getAddonIDFromOrigin(origin) {
- let originUri = Services.io.newURI(origin, null, null);
- return originUri.host + ID_SUFFIX;
-}
-
-function getPrefnameFromOrigin(origin) {
- return "social.manifest." + SocialServiceInternal.getManifestPrefname(origin);
-}
-
-function AddonInstaller(sourceURI, aManifest, installCallback) {
- aManifest.updateDate = Date.now();
- // get the existing manifest for installDate
- let manifest = SocialService.getManifestByOrigin(aManifest.origin);
- let isNewInstall = !manifest;
- if (manifest && manifest.installDate)
- aManifest.installDate = manifest.installDate;
- else
- aManifest.installDate = aManifest.updateDate;
-
- this.sourceURI = sourceURI;
- this.install = function() {
- let addon = this.addon;
- if (isNewInstall) {
- AddonManagerPrivate.callInstallListeners("onExternalInstall", null, addon, null, false);
- AddonManagerPrivate.callAddonListeners("onInstalling", addon, false);
- }
-
- let string = Cc["@mozilla.org/supports-string;1"].
- createInstance(Ci.nsISupportsString);
- string.data = JSON.stringify(aManifest);
- Services.prefs.setComplexValue(getPrefnameFromOrigin(aManifest.origin), Ci.nsISupportsString, string);
-
- if (isNewInstall) {
- AddonManagerPrivate.callAddonListeners("onInstalled", addon);
- }
- installCallback(aManifest);
- };
- this.cancel = function() {
- Services.prefs.clearUserPref(getPrefnameFromOrigin(aManifest.origin));
- };
- this.addon = new AddonWrapper(aManifest);
-}
-
-var SocialAddonProvider = {
- startup: function() {},
-
- shutdown: function() {},
-
- updateAddonAppDisabledStates: function() {
- // we wont bother with "enabling" services that are released from blocklist
- for (let manifest of SocialServiceInternal.manifests) {
- try {
- if (ActiveProviders.has(manifest.origin)) {
- let addon = new AddonWrapper(manifest);
- if (addon.blocklistState != Ci.nsIBlocklistService.STATE_NOT_BLOCKED) {
- SocialService.disableProvider(manifest.origin);
- }
- }
- } catch (e) {
- Cu.reportError(e);
- }
- }
- },
-
- getAddonByID: function(aId, aCallback) {
- for (let manifest of SocialServiceInternal.manifests) {
- if (aId == getAddonIDFromOrigin(manifest.origin)) {
- aCallback(new AddonWrapper(manifest));
- return;
- }
- }
- aCallback(null);
- },
-
- getAddonsByTypes: function(aTypes, aCallback) {
- if (aTypes && aTypes.indexOf(ADDON_TYPE_SERVICE) == -1) {
- aCallback([]);
- return;
- }
- aCallback([...SocialServiceInternal.manifests].map(a => new AddonWrapper(a)));
- },
-
- removeAddon: function(aAddon, aCallback) {
- AddonManagerPrivate.callAddonListeners("onUninstalling", aAddon, false);
- aAddon.pendingOperations |= AddonManager.PENDING_UNINSTALL;
- Services.prefs.clearUserPref(getPrefnameFromOrigin(aAddon.manifest.origin));
- aAddon.pendingOperations -= AddonManager.PENDING_UNINSTALL;
- AddonManagerPrivate.callAddonListeners("onUninstalled", aAddon);
- SocialService._notifyProviderListeners("provider-uninstalled", aAddon.manifest.origin);
- if (aCallback)
- schedule(aCallback);
- }
-};
-
-
-function AddonWrapper(aManifest) {
- this.manifest = aManifest;
- this.id = getAddonIDFromOrigin(this.manifest.origin);
- this._pending = AddonManager.PENDING_NONE;
-}
-AddonWrapper.prototype = {
- get type() {
- return ADDON_TYPE_SERVICE;
- },
-
- get appDisabled() {
- return this.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED;
- },
-
- set softDisabled(val) {
- this.userDisabled = val;
- },
-
- get softDisabled() {
- return this.userDisabled;
- },
-
- get isCompatible() {
- return true;
- },
-
- get isPlatformCompatible() {
- return true;
- },
-
- get scope() {
- return AddonManager.SCOPE_PROFILE;
- },
-
- get foreignInstall() {
- return false;
- },
-
- isCompatibleWith: function(appVersion, platformVersion) {
- return true;
- },
-
- get providesUpdatesSecurely() {
- return true;
- },
-
- get blocklistState() {
- return Services.blocklist.getAddonBlocklistState(this);
- },
-
- get blocklistURL() {
- return Services.blocklist.getAddonBlocklistURL(this);
- },
-
- get screenshots() {
- return [];
- },
-
- get pendingOperations() {
- return this._pending || AddonManager.PENDING_NONE;
- },
- set pendingOperations(val) {
- this._pending = val;
- },
-
- get operationsRequiringRestart() {
- return AddonManager.OP_NEEDS_RESTART_NONE;
- },
-
- get size() {
- return null;
- },
-
- get permissions() {
- let permissions = 0;
- // any "user defined" manifest can be removed
- if (Services.prefs.prefHasUserValue(getPrefnameFromOrigin(this.manifest.origin)))
- permissions = AddonManager.PERM_CAN_UNINSTALL;
- if (!this.appDisabled) {
- if (this.userDisabled) {
- permissions |= AddonManager.PERM_CAN_ENABLE;
- } else {
- permissions |= AddonManager.PERM_CAN_DISABLE;
- }
- }
- return permissions;
- },
-
- findUpdates: function(listener, reason, appVersion, platformVersion) {
- if ("onNoCompatibilityUpdateAvailable" in listener)
- listener.onNoCompatibilityUpdateAvailable(this);
- if ("onNoUpdateAvailable" in listener)
- listener.onNoUpdateAvailable(this);
- if ("onUpdateFinished" in listener)
- listener.onUpdateFinished(this);
- },
-
- get isActive() {
- return ActiveProviders.has(this.manifest.origin);
- },
-
- get name() {
- return this.manifest.name;
- },
- get version() {
- return this.manifest.version ? this.manifest.version.toString() : "";
- },
-
- get iconURL() {
- return this.manifest.icon32URL ? this.manifest.icon32URL : this.manifest.iconURL;
- },
- get icon64URL() {
- return this.manifest.icon64URL;
- },
- get icons() {
- let icons = {
- 16: this.manifest.iconURL
- };
- if (this.manifest.icon32URL)
- icons[32] = this.manifest.icon32URL;
- if (this.manifest.icon64URL)
- icons[64] = this.manifest.icon64URL;
- return icons;
- },
-
- get description() {
- return this.manifest.description;
- },
- get homepageURL() {
- return this.manifest.homepageURL;
- },
- get defaultLocale() {
- return this.manifest.defaultLocale;
- },
- get selectedLocale() {
- return this.manifest.selectedLocale;
- },
-
- get installDate() {
- return this.manifest.installDate ? new Date(this.manifest.installDate) : null;
- },
- get updateDate() {
- return this.manifest.updateDate ? new Date(this.manifest.updateDate) : null;
- },
-
- get creator() {
- return new AddonManagerPrivate.AddonAuthor(this.manifest.author);
- },
-
- get userDisabled() {
- return this.appDisabled || !ActiveProviders.has(this.manifest.origin);
- },
-
- set userDisabled(val) {
- if (val == this.userDisabled)
- return val;
- if (val) {
- SocialService.disableProvider(this.manifest.origin);
- } else if (!this.appDisabled) {
- SocialService.enableProvider(this.manifest.origin);
- }
- return val;
- },
-
- uninstall: function(aCallback) {
- let prefName = getPrefnameFromOrigin(this.manifest.origin);
- if (Services.prefs.prefHasUserValue(prefName)) {
- if (ActiveProviders.has(this.manifest.origin)) {
- SocialService.disableProvider(this.manifest.origin, function() {
- SocialAddonProvider.removeAddon(this, aCallback);
- }.bind(this));
- } else {
- SocialAddonProvider.removeAddon(this, aCallback);
- }
- } else {
- schedule(aCallback);
- }
- },
-
- cancelUninstall: function() {
- this._pending -= AddonManager.PENDING_UNINSTALL;
- AddonManagerPrivate.callAddonListeners("onOperationCancelled", this);
- }
-};
-
-
-AddonManagerPrivate.registerProvider(SocialAddonProvider, [
- new AddonManagerPrivate.AddonType(ADDON_TYPE_SERVICE, URI_EXTENSION_STRINGS,
- STRING_TYPE_NAME,
- AddonManager.VIEW_TYPE_LIST, 10000)
-]);
diff --git a/browser/modules/moz.build b/browser/modules/moz.build
index 852a4c911..a7bbbc258 100644
--- a/browser/modules/moz.build
+++ b/browser/modules/moz.build
@@ -35,8 +35,6 @@ EXTRA_JS_MODULES += [
'Sanitizer.jsm',
'SelfSupportBackend.jsm',
'SitePermissions.jsm',
- 'Social.jsm',
- 'SocialService.jsm',
'TransientPrefs.jsm',
'URLBarZoom.jsm',
'webrtcUI.jsm',