diff --git a/.lock b/.lock
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js
index f0605a5ab0c5..24845987daf6 100644
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1588,6 +1588,15 @@ pref("services.push.serverURL", "wss://push.services.mozilla.com/");
pref("social.sidebar.unload_timeout_ms", 10000);
+// activation from inside of share panel is possible if activationPanelEnabled
+// is true. Pref'd off for release while usage testing is done through beta.
+#ifdef RELEASE_BUILD
+pref("social.share.activationPanelEnabled", false);
+#else
+pref("social.share.activationPanelEnabled", true);
+#endif
+pref("social.shareDirectory", "https://activations.cdn.mozilla.net/en-US/sharePanel.html");
+
pref("dom.identity.enabled", false);
// Block insecure active content on https pages
diff --git a/browser/base/content/aboutSocialError.xhtml b/browser/base/content/aboutSocialError.xhtml
index eba803a915c8..5cb78accca6a 100644
--- a/browser/base/content/aboutSocialError.xhtml
+++ b/browser/base/content/aboutSocialError.xhtml
@@ -43,12 +43,17 @@
function parseQueryString() {
let url = document.documentURI;
- let queryString = url.replace(/^about:socialerror\??/, "");
+ var searchParams = new URLSearchParams(url);
- let modeMatch = queryString.match(/mode=([^&]+)/);
- let mode = modeMatch && modeMatch[1] ? modeMatch[1] : "";
- let originMatch = queryString.match(/origin=([^&]+)/);
- config.origin = originMatch && originMatch[1] ? decodeURIComponent(originMatch[1]) : "";
+ let mode = searchParams.get("mode");
+ config.directory = searchParams.get("directory");
+ config.origin = searchParams.get("origin");
+ let encodedURL = searchParams.get("url");
+ let url = decodeURIComponent(encodedURL);
+ if (config.directory) {
+ let URI = Services.io.newURI(url, null, null);
+ config.origin = Services.scriptSecurityManager.getNoAppCodebasePrincipal(URI).origin;
+ }
switch (mode) {
case "compactInfo":
@@ -59,10 +64,6 @@
document.getElementById("btnCloseSidebar").style.display = 'none';
//intentional fall-through
case "tryAgain":
- let urlMatch = queryString.match(/url=([^&]+)/);
- let encodedURL = urlMatch && urlMatch[1] ? urlMatch[1] : "";
- let url = decodeURIComponent(encodedURL);
-
config.tryAgainCallback = loadQueryURL;
config.queryURL = url;
break;
@@ -80,7 +81,7 @@
let productName = brandBundle.GetStringFromName("brandShortName");
let provider = Social._getProviderFromOrigin(config.origin);
- let providerName = provider && provider.name;
+ let providerName = provider ? provider.name : config.origin;
// Sets up the error message
let msg = browserBundle.formatStringFromName("social.error.message", [productName, providerName], 2);
diff --git a/browser/base/content/aboutneterror/netError.css b/browser/base/content/aboutneterror/netError.css
index 51fc83cdfb44..e4c6d6c7041a 100644
--- a/browser/base/content/aboutneterror/netError.css
+++ b/browser/base/content/aboutneterror/netError.css
@@ -45,6 +45,7 @@ ul {
#errorTryAgain {
margin-top: 1.2em;
+ min-width: 150px
}
#errorContainer {
diff --git a/browser/base/content/browser-sets.inc b/browser/base/content/browser-sets.inc
index b9afa3ab09f3..1cf108785da7 100644
--- a/browser/base/content/browser-sets.inc
+++ b/browser/base/content/browser-sets.inc
@@ -119,7 +119,7 @@
#endif
-
+
diff --git a/browser/base/content/browser-social.js b/browser/base/content/browser-social.js
index 638ed3275d9c..9ca5456617cd 100644
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -183,7 +183,7 @@ SocialUI = {
// about:home or the share panel, we bypass the enable prompt. Any website
// activation, such as from the activations directory or a providers website
// will still get the prompt.
- _activationEventHandler: function SocialUI_activationHandler(e, aBypassUserEnable=false) {
+ _activationEventHandler: function SocialUI_activationHandler(e, options={}) {
let targetDoc;
let node;
if (e.target instanceof HTMLDocument) {
@@ -197,7 +197,9 @@ SocialUI = {
if (!(targetDoc instanceof HTMLDocument))
return;
- if (!aBypassUserEnable && targetDoc.defaultView != content)
+ // The share panel iframe will not match "content" so it passes a bypass
+ // flag
+ if (!options.bypassContentCheck && targetDoc.defaultView != content)
return;
// If we are in PB mode, we silently do nothing (bug 829404 exists to
@@ -233,11 +235,25 @@ SocialUI = {
if (provider.sidebarURL) {
SocialSidebar.show(provider.origin);
}
+ if (provider.shareURL) {
+ // make this new provider the selected provider. If the panel hasn't
+ // been opened, we need to make the frame first.
+ SocialShare._createFrame();
+ SocialShare.iframe.setAttribute('src', 'data:text/plain;charset=utf8,');
+ SocialShare.iframe.setAttribute('origin', provider.origin);
+ // get the right button selected
+ SocialShare.populateProviderMenu();
+ if (SocialShare.panel.state == "open") {
+ SocialShare.sharePage(provider.origin);
+ }
+ }
if (provider.postActivationURL) {
- openUILinkIn(provider.postActivationURL, "tab");
+ // if activated from an open share panel, we load the landing page in
+ // a background tab
+ gBrowser.loadOneTab(provider.postActivationURL, {inBackground: SocialShare.panel.state == "open"});
}
});
- }, aBypassUserEnable);
+ }, options);
},
showLearnMore: function() {
@@ -290,10 +306,10 @@ SocialUI = {
// called on tab/urlbar/location changes and after customization. Update
// anything that is tab specific.
updateState: function() {
+ SocialShare.update();
if (!SocialUI.enabled)
return;
SocialMarks.update();
- SocialShare.update();
}
}
@@ -434,6 +450,12 @@ SocialFlyout = {
}
SocialShare = {
+ get _dynamicResizer() {
+ delete this._dynamicResizer;
+ this._dynamicResizer = new DynamicResizeWatcher();
+ return this._dynamicResizer;
+ },
+
// Share panel may be attached to the overflow or menu button depending on
// customization, we need to manage open state of the anchor.
get anchor() {
@@ -452,15 +474,27 @@ SocialShare = {
return this.panel.lastChild;
},
+ get activationPanelEnabled () {
+ // ability to pref off for release
+ return Services.prefs.getBoolPref("social.share.activationPanelEnabled");
+ },
+
+ _activationHandler: function(event) {
+ if (!SocialShare.activationPanelEnabled)
+ return;
+ SocialUI._activationEventHandler(event, { bypassContentCheck: true, bypassInstallPanel: true });
+ },
+
uninit: function () {
if (this.iframe) {
+ this.iframe.removeEventListener("ActivateSocialFeature", this._activationHandler, true, true);
this.iframe.remove();
}
},
_createFrame: function() {
let panel = this.panel;
- if (!SocialUI.enabled || this.iframe)
+ if (this.iframe)
return;
this.panel.hidden = false;
// create and initialize the panel for this window
@@ -472,6 +506,7 @@ SocialShare = {
iframe.setAttribute("disableglobalhistory", "true");
iframe.setAttribute("flex", "1");
panel.appendChild(iframe);
+ this.iframe.addEventListener("ActivateSocialFeature", this._activationHandler, true, true);
this.populateProviderMenu();
},
@@ -481,11 +516,19 @@ SocialShare = {
if (lastProviderOrigin) {
provider = Social._getProviderFromOrigin(lastProviderOrigin);
}
+ // if we are able to activate a provider we don't need to do anything fancy
+ // here, the user will land on the activation panel if no previously
+ // selected provider is available.
+ if (this.activationPanelEnabled)
+ return provider;
+
// if they have a provider selected in the sidebar use that for the initial
// default in share
if (!provider)
provider = SocialSidebar.provider;
- // if our provider has no shareURL, select the first one that does
+ // if our provider has no shareURL, select the first one that does. If we
+ // have no selected provider and activation is available, default to that
+ // panel.
if (!provider || !provider.shareURL) {
let providers = [p for (p of Social.providers) if (p.shareURL)];
provider = providers.length > 0 && providers[0];
@@ -498,17 +541,12 @@ SocialShare = {
return;
let providers = [p for (p of Social.providers) if (p.shareURL)];
let hbox = document.getElementById("social-share-provider-buttons");
- // selectable providers are inserted before the provider-menu seperator,
- // remove any menuitems in that area
- while (hbox.firstChild) {
+ // remove everything before the add-share-provider button (which should also
+ // be lastChild if any share providers were added)
+ let addButton = document.getElementById("add-share-provider");
+ while (hbox.firstChild != addButton) {
hbox.removeChild(hbox.firstChild);
}
- // reset our share toolbar
- // only show a selection if there is more than one
- if (!SocialUI.enabled || providers.length < 2) {
- this.panel.firstChild.hidden = true;
- return;
- }
let selectedProvider = this.getSelectedProvider();
for (let provider of providers) {
let button = document.createElement("toolbarbutton");
@@ -518,17 +556,16 @@ SocialShare = {
button.setAttribute("image", provider.iconURL);
button.setAttribute("tooltiptext", provider.name);
button.setAttribute("origin", provider.origin);
- button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin')); this.checked=true;");
+ button.setAttribute("oncommand", "SocialShare.sharePage(this.getAttribute('origin'));");
if (provider == selectedProvider) {
this.defaultButton = button;
}
- hbox.appendChild(button);
+ hbox.insertBefore(button, addButton);
}
if (!this.defaultButton) {
- this.defaultButton = hbox.firstChild
+ this.defaultButton = this.activationPanelEnabled ? addButton : hbox.firstChild;
}
this.defaultButton.setAttribute("checked", "true");
- this.panel.firstChild.hidden = false;
},
get shareButton() {
@@ -560,8 +597,8 @@ SocialShare = {
let shareButton = widget.forWindow(window).node;
// hidden state is based on available share providers and location of
// button. It's always visible and disabled in the customization palette.
- shareButton.hidden = !SocialUI.enabled || (widget.areaType &&
- [p for (p of Social.providers) if (p.shareURL)].length == 0);
+ shareButton.hidden = !this.activationPanelEnabled && (!SocialUI.enabled || (widget.areaType &&
+ [p for (p of Social.providers) if (p.shareURL)].length == 0));
let disabled = !widget.areaType || shareButton.hidden || !this.canSharePage(gBrowser.currentURI);
// 1. update the relevent command's disabled state so the keyboard
@@ -577,6 +614,9 @@ SocialShare = {
cmd.removeAttribute("disabled");
shareButton.removeAttribute("disabled");
}
+
+ // enable or disable the activation panel
+ document.getElementById("add-share-provider").hidden = !this.activationPanelEnabled;
},
_onclick: function() {
@@ -608,10 +648,15 @@ SocialShare = {
if (!iframe)
return;
- iframe.removeAttribute("src");
- iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
- encodeURIComponent(iframe.getAttribute("origin")),
- null, null, null, null);
+ let url;
+ let origin = iframe.getAttribute("origin");
+ if (!origin && this.activationPanelEnabled) {
+ // directory site is down
+ url = "about:socialerror?mode=tryAgainOnly&directory=1&url=" + encodeURIComponent(iframe.getAttribute("src"));
+ } else {
+ url = "about:socialerror?mode=compactInfo&origin=" + encodeURIComponent(origin);
+ }
+ iframe.webNavigation.loadURI(url, null, null, null, null);
sizeSocialPanelToContent(this.panel, iframe);
},
@@ -621,13 +666,6 @@ SocialShare = {
// will call sharePage with an origin for us to switch to.
this._createFrame();
let iframe = this.iframe;
- let provider;
- if (providerOrigin)
- provider = Social._getProviderFromOrigin(providerOrigin);
- else
- provider = this.getSelectedProvider();
- if (!provider || !provider.shareURL)
- return;
// graphData is an optional param that either defines the full set of data
// to be shared, or partial data about the current page. It is set by a call
@@ -659,20 +697,25 @@ SocialShare = {
}
this.currentShare = pageData;
+ let provider;
+ if (providerOrigin)
+ provider = Social._getProviderFromOrigin(providerOrigin);
+ else
+ provider = this.getSelectedProvider();
+ if (!provider || !provider.shareURL) {
+ this.showDirectory();
+ return;
+ }
+ // check the menu button
+ let hbox = document.getElementById("social-share-provider-buttons");
+ let btn = hbox.querySelector("[origin='" + provider.origin + "']");
+ btn.checked = true;
+
let shareEndpoint = OpenGraphBuilder.generateEndpointURL(provider.shareURL, pageData);
let size = provider.getPageSize("share");
if (size) {
- if (this._dynamicResizer) {
- this._dynamicResizer.stop();
- this._dynamicResizer = null;
- }
- let {width, height} = size;
- width += this.panel.boxObject.width - iframe.boxObject.width;
- height += this.panel.boxObject.height - iframe.boxObject.height;
- this.panel.sizeTo(width, height);
- } else {
- this._dynamicResizer = new DynamicResizeWatcher();
+ this._dynamicResizer.stop();
}
// if we've already loaded this provider/page share endpoint, we don't want
@@ -684,7 +727,7 @@ SocialShare = {
reload = shareEndpoint != iframe.contentDocument.location.spec;
}
if (!reload) {
- if (this._dynamicResizer)
+ if (!size)
this._dynamicResizer.start(this.panel, iframe);
iframe.docShell.isActive = true;
iframe.docShell.isAppTab = true;
@@ -702,7 +745,13 @@ SocialShare = {
// should close the window when done.
iframe.contentWindow.opener = iframe.contentWindow;
setTimeout(function() {
- if (SocialShare._dynamicResizer) { // may go null if hidden quickly
+ if (size) {
+ let panel = SocialShare.panel;
+ let {width, height} = size;
+ width += panel.boxObject.width - iframe.boxObject.width;
+ height += panel.boxObject.height - iframe.boxObject.height;
+ panel.sizeTo(width, height);
+ } else {
SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
}
}, 0);
@@ -723,10 +772,32 @@ SocialShare = {
let uri = Services.io.newURI(shareEndpoint, null, null);
iframe.setAttribute("origin", provider.origin);
iframe.setAttribute("src", shareEndpoint);
+ this._openPanel();
+ },
+ showDirectory: function() {
+ let url = Services.prefs.getCharPref("social.shareDirectory");
+ this._createFrame();
+ let iframe = this.iframe;
+ iframe.removeAttribute("origin");
+ iframe.setAttribute("src", url);
+ iframe.addEventListener("load", function panelBrowserOnload(e) {
+ iframe.removeEventListener("load", panelBrowserOnload, true);
+ SocialShare._dynamicResizer.start(iframe.parentNode, iframe);
+
+ iframe.addEventListener("unload", function panelBrowserOnload(e) {
+ iframe.removeEventListener("unload", panelBrowserOnload, true);
+ SocialShare._dynamicResizer.stop();
+ }, true);
+
+ }, true);
+ this._openPanel();
+ },
+
+ _openPanel: function() {
let anchor = document.getAnonymousElementByAttribute(this.anchor, "class", "toolbarbutton-icon");
this.panel.openPopup(anchor, "bottomcenter topright", 0, 0, false, false);
- Social.setErrorListener(iframe, this.setErrorMessage.bind(this));
+ Social.setErrorListener(this.iframe, this.setErrorMessage.bind(this));
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
}
};
diff --git a/browser/base/content/browser.css b/browser/base/content/browser.css
index 8e18e90c2f24..56cf111d783e 100644
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -320,6 +320,14 @@ toolbar:not(#TabsToolbar) > #personal-bookmarks {
min-width: 25ch;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .searchbar-engine-image,
+ .searchbar-engine-menuitem > .menu-iconic-left > .menu-iconic-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
#urlbar,
.searchbar-textbox {
/* Setting a width and min-width to let the location & search bars maintain
@@ -472,6 +480,20 @@ toolbarbutton.bookmark-item {
max-width: 13em;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .alltabs-popup > .menuitem-iconic > .menu-iconic-left > .menu-iconic-icon,
+ .menuitem-with-favicon > .menu-iconic-left > .menu-iconic-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+
+ .bookmark-item > .toolbarbutton-icon,
+ .bookmark-item > .menu-iconic-left > .menu-iconic-icon,
+ #personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
#editBMPanel_tagsSelector {
/* override default listbox width from xul.css */
width: auto;
@@ -629,6 +651,13 @@ window[chromehidden~="toolbar"] toolbar:not(.toolbar-primary):not(.chromeclass-m
height: 16px;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .ctrlTab-favicon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
.ctrlTab-preview {
-moz-binding: url("chrome://browser/content/browser-tabPreviews.xml#ctrlTab-preview");
}
@@ -832,6 +861,15 @@ chatbar {
max-height: 0;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ #social-sidebar-favico,
+ .social-status-button,
+ .chat-status-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
/** See bug 872317 for why the following rule is necessary. */
#downloads-button {
@@ -1000,6 +1038,15 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
list-style-image: none;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ #PanelUI-recentlyClosedWindows > toolbarbutton > .toolbarbutton-icon,
+ #PanelUI-recentlyClosedTabs > toolbarbutton > .toolbarbutton-icon,
+ #PanelUI-historyItems > toolbarbutton > .toolbarbutton-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
#customization-panelHolder {
overflow-y: hidden;
}
diff --git a/browser/base/content/browser.xul b/browser/base/content/browser.xul
index 353a7cbb71f5..11198db1f6c6 100644
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -246,7 +246,11 @@
onpopuphidden="SocialShare.onHidden()"
hidden="true">
-
+
+
+
diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js
index eb89cdfdbc17..b5abc90d5627 100644
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -334,7 +334,7 @@ nsContextMenu.prototype = {
let shareEnabled = shareButton && !shareButton.disabled && !this.onSocial;
let pageShare = shareEnabled && !(this.isContentSelected ||
this.onTextInput || this.onLink || this.onImage ||
- this.onVideo || this.onAudio);
+ 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);
diff --git a/browser/base/content/tabbrowser.css b/browser/base/content/tabbrowser.css
index d5d9ee608ccf..bc5860e7114a 100644
--- a/browser/base/content/tabbrowser.css
+++ b/browser/base/content/tabbrowser.css
@@ -44,6 +44,13 @@ tabpanels {
z-index: 2;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .tab-icon-image {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
.tab-icon-image:not([src]):not([pinned]),
.tab-throbber:not([busy]),
.tab-throbber[busy] + .tab-icon-image {
diff --git a/browser/base/content/test/general/test_contextmenu.html b/browser/base/content/test/general/test_contextmenu.html
index d90f21c3e600..3c1b7895dc8c 100644
--- a/browser/base/content/test/general/test_contextmenu.html
+++ b/browser/base/content/test/general/test_contextmenu.html
@@ -89,6 +89,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for text");
// Context menu for plain text
plainTextItems = ["context-navigation", null,
["context-back", false,
@@ -96,6 +97,7 @@ function runTest(testNum) {
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -110,6 +112,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for text link");
// Context menu for text link
if (perWindowPrivateBrowsing) {
checkContextMenu(["context-openlinkintab", true,
@@ -117,6 +120,7 @@ function runTest(testNum) {
"context-openlinkprivate", true,
"---", null,
"context-bookmarklink", true,
+ "context-sharelink", true,
"context-savelink", true,
"context-copylink", true,
"context-searchselect", true
@@ -126,6 +130,7 @@ function runTest(testNum) {
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
+ "context-sharelink", true,
"context-savelink", true,
"context-copylink", true,
"context-searchselect", true
@@ -136,6 +141,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for mailto link");
// Context menu for text mailto-link
checkContextMenu(["context-copyemail", true,
"context-searchselect", true
@@ -145,12 +151,14 @@ function runTest(testNum) {
},
function () {
+ info("context menu for image");
// Context menu for an image
checkContextMenu(["context-viewimage", true,
"context-copyimage-contents", true,
"context-copyimage", true,
"---", null,
"context-saveimage", true,
+ "context-shareimage", true,
"context-sendimage", true,
"context-setDesktopBackground", true,
"context-viewimageinfo", true
@@ -160,6 +168,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for canvas");
// Context menu for a canvas
checkContextMenu(["context-viewimage", true,
"context-saveimage", true,
@@ -170,6 +179,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for video_ok");
// Context menu for a video (with a VALID media source)
checkContextMenu(["context-media-play", true,
"context-media-mute", true,
@@ -186,6 +196,7 @@ function runTest(testNum) {
"context-copyvideourl", true,
"---", null,
"context-savevideo", true,
+ "context-sharevideo", true,
"context-video-saveimage", true,
"context-sendvideo", true
].concat(inspectItems));
@@ -194,6 +205,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for audio_in_video");
// Context menu for a video (with an audio-only file)
checkContextMenu(["context-media-play", true,
"context-media-mute", true,
@@ -214,6 +226,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for video_bad");
// Context menu for a video (with an INVALID media source)
checkContextMenu(["context-media-play", false,
"context-media-mute", false,
@@ -230,6 +243,7 @@ function runTest(testNum) {
"context-copyvideourl", true,
"---", null,
"context-savevideo", true,
+ "context-sharevideo", true,
"context-video-saveimage", false,
"context-sendvideo", true
].concat(inspectItems));
@@ -238,6 +252,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for video_bad2");
// Context menu for a video (with an INVALID media source)
checkContextMenu(["context-media-play", false,
"context-media-mute", false,
@@ -254,6 +269,7 @@ function runTest(testNum) {
"context-copyvideourl", false,
"---", null,
"context-savevideo", false,
+ "context-sharevideo", false,
"context-video-saveimage", false,
"context-sendvideo", false
].concat(inspectItems));
@@ -262,6 +278,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for iframe");
// Context menu for an iframe
checkContextMenu(["context-navigation", null,
["context-back", false,
@@ -269,6 +286,7 @@ function runTest(testNum) {
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -296,6 +314,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for video_in_iframe");
// Context menu for a video in an iframe
checkContextMenu(["context-media-play", true,
"context-media-mute", true,
@@ -312,6 +331,7 @@ function runTest(testNum) {
"context-copyvideourl", true,
"---", null,
"context-savevideo", true,
+ "context-sharevideo", true,
"context-video-saveimage", true,
"context-sendvideo", true,
"frame", null,
@@ -332,12 +352,14 @@ function runTest(testNum) {
},
function () {
+ info("context menu for image_in_iframe");
// Context menu for an image in an iframe
checkContextMenu(["context-viewimage", true,
"context-copyimage-contents", true,
"context-copyimage", true,
"---", null,
"context-saveimage", true,
+ "context-shareimage", true,
"context-sendimage", true,
"context-setDesktopBackground", true,
"context-viewimageinfo", true,
@@ -359,6 +381,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for textarea");
// Context menu for textarea before spell check initialization finishes
checkContextMenu(["context-undo", false,
"---", null,
@@ -376,6 +399,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for textarea, wait for spell check");
// Context menu for textarea after spell check initialization finishes
checkContextMenu(["*chubbiness", true, // spelling suggestion
"spell-add-to-dictionary", true,
@@ -401,6 +425,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for text");
// Re-check context menu for plain text to make sure it hasn't changed
checkContextMenu(plainTextItems);
closeContextMenu();
@@ -408,6 +433,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for textarea after word added");
// Context menu for textarea after a word has been added
// to the dictionary
checkContextMenu(["spell-undo-add-to-dictionary", true,
@@ -433,6 +459,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for contenteditable");
// Context menu for contenteditable
checkContextMenu(["spell-no-suggestions", false,
"spell-add-to-dictionary", true,
@@ -458,12 +485,14 @@ function runTest(testNum) {
},
function () {
+ info("context menu for link");
executeCopyCommand("cmd_copyLink", "http://mozilla.com/");
closeContextMenu();
openContextMenuFor(pagemenu); // Invoke context menu for next test.
},
function () {
+ info("context menu for pagemenu");
// Context menu for element with assigned content context menu
checkContextMenu(["context-navigation", null,
["context-back", false,
@@ -491,6 +520,7 @@ function runTest(testNum) {
"---", null,
"+Checkbox", {type: "checkbox", icon: "", checked: false, disabled: false}], null,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -516,6 +546,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for fullscreen mode");
// Context menu for DOM Fullscreen mode (NOTE: this is *NOT* on an img)
checkContextMenu(["context-navigation", null,
["context-back", false,
@@ -525,6 +556,7 @@ function runTest(testNum) {
"---", null,
"context-leave-dom-fullscreen", true,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -546,6 +578,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for element with assigned content context menu");
// Context menu for element with assigned content context menu
// The shift key should bypass content context menu processing
checkContextMenu(["context-navigation", null,
@@ -554,6 +587,7 @@ function runTest(testNum) {
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -568,6 +602,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for text selection");
// Context menu for selected text
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
@@ -575,6 +610,7 @@ function runTest(testNum) {
"context-selectall", true,
"---", null,
"context-searchselect", true,
+ "context-shareselect", true,
"context-viewpartialsource-selection", true
].concat(inspectItems));
}
@@ -584,6 +620,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for text selection with url pattern");
// Context menu for selected text which matches valid URL pattern
if (SpecialPowers.Services.appinfo.OS == "Darwin") {
// This test is only enabled on Mac due to bug 736399.
@@ -594,11 +631,13 @@ function runTest(testNum) {
"context-openlinkprivate", true,
"---", null,
"context-bookmarklink", true,
+ "context-sharelink", true,
"context-savelink", true,
"context-copy", true,
"context-selectall", true,
"---", null,
"context-searchselect", true,
+ "context-shareselect", true,
"context-viewpartialsource-selection", true
].concat(inspectItems));
} else {
@@ -607,11 +646,13 @@ function runTest(testNum) {
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
+ "context-sharelink", true,
"context-savelink", true,
"context-copy", true,
"context-selectall", true,
"---", null,
"context-searchselect", true,
+ "context-shareselect", true,
"context-viewpartialsource-selection", true
].concat(inspectItems));
}
@@ -624,6 +665,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for imagelink");
// Context menu for image link
if (perWindowPrivateBrowsing) {
checkContextMenu(["context-openlinkintab", true,
@@ -631,6 +673,7 @@ function runTest(testNum) {
"context-openlinkprivate", true,
"---", null,
"context-bookmarklink", true,
+ "context-sharelink", true,
"context-savelink", true,
"context-copylink", true,
"---", null,
@@ -639,6 +682,7 @@ function runTest(testNum) {
"context-copyimage", true,
"---", null,
"context-saveimage", true,
+ "context-shareimage", true,
"context-sendimage", true,
"context-setDesktopBackground", true,
"context-viewimageinfo", true
@@ -648,6 +692,7 @@ function runTest(testNum) {
"context-openlink", true,
"---", null,
"context-bookmarklink", true,
+ "context-sharelink", true,
"context-savelink", true,
"context-copylink", true,
"---", null,
@@ -656,6 +701,7 @@ function runTest(testNum) {
"context-copyimage", true,
"---", null,
"context-saveimage", true,
+ "context-shareimage", true,
"context-sendimage", true,
"context-setDesktopBackground", true,
"context-viewimageinfo", true
@@ -667,6 +713,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for select_inputtext");
// Context menu for selected text in input
checkContextMenu(["context-undo", false,
"---", null,
@@ -686,6 +733,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for selected text in input[type='password']");
// Context menu for selected text in input[type="password"]
checkContextMenu(["context-undo", false,
"---", null,
@@ -709,6 +757,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for click-to-play blocked plugin");
// Context menu for click-to-play blocked plugin
checkContextMenu(["context-navigation", null,
["context-back", false,
@@ -719,6 +768,7 @@ function runTest(testNum) {
"context-ctp-play", true,
"context-ctp-hide", true,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -734,12 +784,14 @@ function runTest(testNum) {
},
function () {
+ info("context menu for image with longdesc");
// Context menu for an image with longdesc
checkContextMenu(["context-viewimage", true,
"context-copyimage-contents", true,
"context-copyimage", true,
"---", null,
"context-saveimage", true,
+ "context-shareimage", true,
"context-sendimage", true,
"context-setDesktopBackground", true,
"context-viewimageinfo", true,
@@ -750,6 +802,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for iframe with srcdoc attribute set");
// Context menu for an iframe with srcdoc attribute set
checkContextMenu(["context-navigation", null,
["context-back", false,
@@ -757,6 +810,7 @@ function runTest(testNum) {
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
@@ -779,6 +833,7 @@ function runTest(testNum) {
},
function () {
+ info("context menu for text input field with spellcheck=false");
// Context menu for text input field with spellcheck=false
checkContextMenu(["context-undo", false,
"---", null,
diff --git a/browser/base/content/test/general/test_contextmenu_input.html b/browser/base/content/test/general/test_contextmenu_input.html
index 004d88512742..82164b2535e0 100644
--- a/browser/base/content/test/general/test_contextmenu_input.html
+++ b/browser/base/content/test/general/test_contextmenu_input.html
@@ -198,6 +198,7 @@ function runTest(testNum) {
"context-reload", true,
"context-bookmarkpage", true], null,
"---", null,
+ "context-sharepage", true,
"context-savepage", true,
"---", null,
"context-viewbgimage", false,
diff --git a/browser/base/content/test/social/browser.ini b/browser/base/content/test/social/browser.ini
index f6e2a7d8135e..57729df7e9c5 100644
--- a/browser/base/content/test/social/browser.ini
+++ b/browser/base/content/test/social/browser.ini
@@ -11,6 +11,7 @@ support-files =
opengraph/shorturl_linkrel.html
microdata.html
share.html
+ share_activate.html
social_activate.html
social_activate_iframe.html
social_chat.html
diff --git a/browser/base/content/test/social/browser_share.js b/browser/base/content/test/social/browser_share.js
index 09a6837ee428..bd616bb4abb8 100644
--- a/browser/base/content/test/social/browser_share.js
+++ b/browser/base/content/test/social/browser_share.js
@@ -10,10 +10,46 @@ let manifest = { // normal provider
iconURL: "https://example.com/browser/browser/base/content/test/general/moz.png",
shareURL: "https://example.com/browser/browser/base/content/test/social/share.html"
};
+let activationPage = "https://example.com/browser/browser/base/content/test/social/share_activate.html";
+
+function waitForProviderEnabled(cb) {
+ Services.obs.addObserver(function providerSet(subject, topic, data) {
+ Services.obs.removeObserver(providerSet, "social:provider-enabled");
+ info("social:provider-enabled observer was notified");
+ cb();
+ }, "social:provider-enabled", false);
+}
+
+function sendActivationEvent(callback) {
+ // hack Social.lastEventReceived so we don't hit the "too many events" check.
+ Social.lastEventReceived = 0;
+ let doc = SocialShare.iframe.contentDocument;
+ // if our test has a frame, use it
+ let button = doc.getElementById("activation");
+ ok(!!button, "got the activation button");
+ EventUtils.synthesizeMouseAtCenter(button, {}, doc.defaultView);
+ if (callback)
+ executeSoon(callback);
+}
+
+function waitForEvent(iframe, eventName, callback) {
+ iframe.addEventListener(eventName, function load() {
+ info("page load is "+iframe.contentDocument.location.href);
+ if (iframe.contentDocument.location.href != "data:text/plain;charset=utf8,") {
+ iframe.removeEventListener(eventName, load, true);
+ executeSoon(callback);
+ }
+ }, true);
+}
function test() {
waitForExplicitFinish();
-
+ Services.prefs.setCharPref("social.shareDirectory", activationPage);
+ registerCleanupFunction(function () {
+ Services.prefs.clearUserPref("social.directories");
+ Services.prefs.clearUserPref("social.shareDirectory");
+ Services.prefs.clearUserPref("social.share.activationPanelEnabled");
+ });
runSocialTests(tests);
}
@@ -75,11 +111,10 @@ let corpus = [
function loadURLInTab(url, callback) {
info("Loading tab with "+url);
let tab = gBrowser.selectedTab = gBrowser.addTab(url);
- tab.linkedBrowser.addEventListener("load", function listener() {
+ waitForEvent(tab.linkedBrowser, "load", () => {
is(tab.linkedBrowser.currentURI.spec, url, "tab loaded")
- tab.linkedBrowser.removeEventListener("load", listener, true);
- executeSoon(function() { callback(tab) });
- }, true);
+ callback(tab)
+ });
}
function hasoptions(testOptions, options) {
@@ -110,7 +145,6 @@ var tests = {
checkSocialUI();
// share should not be enabled since we only have about:blank page
let shareButton = SocialShare.shareButton;
- is(shareButton.disabled, true, "share button is disabled");
// verify the attribute for proper css
is(shareButton.getAttribute("disabled"), "true", "share button attribute is disabled");
// button should be visible
@@ -128,7 +162,6 @@ var tests = {
checkSocialUI();
// share should not be enabled since we only have about:blank page
let shareButton = SocialShare.shareButton;
- is(shareButton.disabled, false, "share button is enabled");
// verify the attribute for proper css
ok(!shareButton.hasAttribute("disabled"), "share button is enabled");
// button should be visible
@@ -149,7 +182,7 @@ var tests = {
function runOneTest() {
loadURLInTab(testData.url, function(tab) {
testTab = tab;
- SocialShare.sharePage();
+ SocialShare.sharePage(manifest.origin);
});
}
@@ -241,5 +274,46 @@ var tests = {
SocialShare.sharePage(manifest.origin, null, target);
});
});
+ },
+ testSharePanelActivation: function(next) {
+ let testTab;
+ // cleared in the cleanup function
+ Services.prefs.setCharPref("social.directories", "https://example.com");
+ Services.prefs.setBoolPref("social.share.activationPanelEnabled", true);
+ // make the iframe so we can wait on the load
+ SocialShare._createFrame();
+ let iframe = SocialShare.iframe;
+
+ waitForEvent(iframe, "load", () => {
+ waitForCondition(() => {
+ // sometimes the iframe is ready before the panel is open, we need to
+ // wait for both conditions
+ return SocialShare.panel.state == "open";
+ }, () => {
+ is(iframe.contentDocument.location.href, activationPage, "activation page loaded");
+ waitForProviderEnabled(() => {
+ let provider = Social._getProviderFromOrigin(manifest.origin);
+ let port = provider.getWorkerPort();
+ ok(!!port, "got port");
+ port.onmessage = function (e) {
+ let topic = e.data.topic;
+ info("got topic "+topic+"\n");
+ switch (topic) {
+ case "got-share-data-message":
+ ok(true, "share completed");
+ gBrowser.removeTab(testTab);
+ SocialService.uninstallProvider(manifest.origin, next);
+ break;
+ }
+ }
+ port.postMessage({topic: "test-init"});
+ });
+ sendActivationEvent();
+ }, "share panel did not open and load share page");
+ });
+ loadURLInTab(activationPage, function(tab) {
+ testTab = tab;
+ SocialShare.sharePage();
+ });
}
}
diff --git a/browser/base/content/test/social/share_activate.html b/browser/base/content/test/social/share_activate.html
new file mode 100644
index 000000000000..f53da0b288c0
--- /dev/null
+++ b/browser/base/content/test/social/share_activate.html
@@ -0,0 +1,36 @@
+
+
+
+ Activation test
+
+
+
+
+nothing to see here
+
+
+
+
+
diff --git a/browser/components/customizableui/CustomizableUI.jsm b/browser/components/customizableui/CustomizableUI.jsm
index 582d2ff9ad1b..4a026f706f8e 100644
--- a/browser/components/customizableui/CustomizableUI.jsm
+++ b/browser/components/customizableui/CustomizableUI.jsm
@@ -166,6 +166,7 @@ let CustomizableUIInternal = {
"preferences-button",
"add-ons-button",
"developer-button",
+ "social-share-button",
];
if (gPalette.has("switch-to-metro-button")) {
@@ -207,7 +208,6 @@ let CustomizableUIInternal = {
"downloads-button",
"home-button",
"loop-call-button",
- "social-share-button",
],
defaultCollapsed: false,
}, true);
diff --git a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
index 6458db7360a2..cdc401c064e5 100644
--- a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
+++ b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js
@@ -27,7 +27,7 @@ add_task(function testWrapUnwrap() {
// Creating and destroying a widget should correctly deal with panel placeholders
add_task(function testPanelPlaceholders() {
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
- is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 1 : 2, "The number of placeholders should be correct.");
+ is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 3 : 1, "The number of placeholders should be correct.");
CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL});
let elem = document.getElementById(kTestWidget2);
let wrapper = document.getElementById("wrapper-" + kTestWidget2);
@@ -35,7 +35,7 @@ add_task(function testPanelPlaceholders() {
ok(wrapper, "There should be a wrapper");
is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget");
is(wrapper.parentNode, panel, "Wrapper should be in panel");
- is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 3 : 1, "The number of placeholders should be correct.");
+ is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 2 : 3, "The number of placeholders should be correct.");
CustomizableUI.destroyWidget(kTestWidget2);
wrapper = document.getElementById("wrapper-" + kTestWidget2);
ok(!wrapper, "There should be a wrapper");
diff --git a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
index b001e48dc5ae..8b1d0ac029e1 100644
--- a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
+++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js
@@ -22,7 +22,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(zoomControls, printButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -48,7 +49,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(zoomControls, savePageButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -72,7 +74,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(zoomControls, newWindowButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -95,7 +98,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(zoomControls, historyPanelMenu);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -122,7 +126,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(zoomControls, preferencesButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -149,7 +154,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterInsert);
simulateItemDrag(openFileButton, zoomControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
@@ -188,7 +194,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterInsert);
simulateItemDrag(openFileButton, editControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert);
@@ -224,7 +231,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(editControls, zoomControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -248,7 +256,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(editControls, newWindowButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -275,7 +284,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(editControls, privateBrowsingButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -302,7 +312,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(editControls, savePageButton);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -328,7 +339,8 @@ add_task(function() {
"preferences-button",
"add-ons-button",
"edit-controls",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(editControls, panel);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -353,7 +365,8 @@ add_task(function() {
"find-button",
"preferences-button",
"add-ons-button",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
let paletteChildElementCount = palette.childElementCount;
simulateItemDrag(editControls, palette);
@@ -377,7 +390,8 @@ add_task(function() {
yield startCustomizing();
let editControls = document.getElementById("edit-controls");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
- let numPlaceholders = isInWin8() ? 1 : 2;
+ let numPlaceholders = isInWin8() ? 3 : 1;
+ is(numPlaceholders, panel.getElementsByClassName("panel-customization-placeholder").length, "correct number of placeholders");
for (let i = 0; i < numPlaceholders; i++) {
// NB: We can't just iterate over all of the placeholders
// because each drag-drop action recreates them.
@@ -393,7 +407,8 @@ add_task(function() {
"preferences-button",
"add-ons-button",
"edit-controls",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
simulateItemDrag(editControls, placeholder);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
@@ -423,6 +438,8 @@ add_task(function() {
yield startCustomizing();
let editControls = document.getElementById("edit-controls");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+ let numPlaceholders = isInWin8() ? 3 : 1;
+ is(panel.getElementsByClassName("panel-customization-placeholder").length, numPlaceholders, "correct number of placeholders");
let target = panel.getElementsByClassName("panel-customization-placeholder")[0];
let placementsAfterMove = ["zoom-controls",
"new-window-button",
@@ -435,18 +452,22 @@ add_task(function() {
"preferences-button",
"add-ons-button",
"edit-controls",
- "developer-button"];
+ "developer-button",
+ "social-share-button"];
addSwitchToMetroButtonInWindows8(placementsAfterMove);
+ if (isInWin8()) {
+ placementsAfterMove.splice(10, 1);
+ placementsAfterMove.push("edit-controls");
+ }
simulateItemDrag(editControls, target);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
let itemToDrag = "sync-button";
let button = document.getElementById(itemToDrag);
- placementsAfterMove.splice(11, 0, itemToDrag);
if (isInWin8()) {
- placementsAfterMove[10] = placementsAfterMove[11];
- placementsAfterMove[11] = placementsAfterMove[12];
- placementsAfterMove[12] = placementsAfterMove[13];
- placementsAfterMove[13] = "edit-controls";
+ placementsAfterMove.push(itemToDrag);
+ } else {
+ placementsAfterMove.splice(10, 1, itemToDrag);
+ placementsAfterMove.push("edit-controls");
}
simulateItemDrag(button, editControls);
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove);
diff --git a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
index bddcb50dc19c..f96f70b590e4 100644
--- a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
+++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js
@@ -11,15 +11,13 @@ add_task(function() {
yield startCustomizing();
let btn = document.getElementById("open-file-button");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
- let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+ CustomizableUI.removeWidgetFromArea("social-share-button");
if (isInWin8()) {
CustomizableUI.removeWidgetFromArea("switch-to-metro-button");
- placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
- ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
- } else {
- ok(CustomizableUI.inDefaultState, "Should be in default state.");
}
+ let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
+ ok(!CustomizableUI.inDefaultState, "Should no longer be in default state.");
assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting");
@@ -28,6 +26,7 @@ add_task(function() {
yield startCustomizing();
is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering");
+ CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_PANEL);
if (isInWin8()) {
CustomizableUI.addWidgetToArea("switch-to-metro-button", CustomizableUI.AREA_PANEL);
}
@@ -39,6 +38,7 @@ add_task(function() {
yield startCustomizing();
let btn = document.getElementById("open-file-button");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
+ CustomizableUI.removeWidgetFromArea("social-share-button");
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
let placementsAfterAppend = placements;
@@ -49,7 +49,7 @@ add_task(function() {
}
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
- is(CustomizableUI.inDefaultState, isInWin8(), "Should only be in default state if on Win8");
+ ok(!CustomizableUI.inDefaultState, "Should not be in default state");
is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder before exiting");
yield endCustomizing();
@@ -63,26 +63,24 @@ add_task(function() {
btn = document.getElementById("open-file-button");
simulateItemDrag(btn, palette);
}
+ CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});
// Two orphaned items should have one placeholder next to them (case 2).
add_task(function() {
yield startCustomizing();
- let btn = document.getElementById("add-ons-button");
- let btn2 = document.getElementById("developer-button");
- let btn3 = document.getElementById("switch-to-metro-button");
+ let buttonsToMove = ["add-ons-button", "developer-button", "social-share-button"];
+ if (isInWin8()) {
+ buttonsToMove.push("switch-to-metro-button");
+ }
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
let palette = document.getElementById("customization-palette");
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
- let placementsAfterAppend = placements.filter(p => p != btn.id && p != btn2.id);
- simulateItemDrag(btn, palette);
- simulateItemDrag(btn2, palette);
-
- if (isInWin8()) {
- placementsAfterAppend = placementsAfterAppend.filter(p => p != btn3.id);
- simulateItemDrag(btn3, palette);
+ let placementsAfterAppend = placements.filter(p => buttonsToMove.indexOf(p) < 0);
+ for (let i in buttonsToMove) {
+ CustomizableUI.removeWidgetFromArea(buttonsToMove[i]);
}
assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend);
@@ -93,11 +91,8 @@ add_task(function() {
yield startCustomizing();
is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholder after re-entering");
- simulateItemDrag(btn, panel);
- simulateItemDrag(btn2, panel);
-
- if (isInWin8()) {
- simulateItemDrag(btn3, panel);
+ for (let i in buttonsToMove) {
+ CustomizableUI.addWidgetToArea(buttonsToMove[i], CustomizableUI.AREA_PANEL);
}
assertAreaPlacements(CustomizableUI.AREA_PANEL, placements);
@@ -112,6 +107,7 @@ add_task(function() {
let metroBtn = document.getElementById("switch-to-metro-button");
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
let palette = document.getElementById("customization-palette");
+ CustomizableUI.removeWidgetFromArea("social-share-button");
let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL);
placements.pop();
@@ -133,6 +129,7 @@ add_task(function() {
is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering");
simulateItemDrag(developerButton, panel);
+ CustomizableUI.addWidgetToArea("social-share-button", CustomizableUI.AREA_PANEL);
if (isInWin8()) {
simulateItemDrag(metroBtn, panel);
}
@@ -141,10 +138,10 @@ add_task(function() {
ok(CustomizableUI.inDefaultState, "Should be in default state again.");
});
-// The default placements should have two placeholders at the bottom (or 1 in win8).
+// The default placements should have one placeholder at the bottom (or 3 in metro-enabled win8).
add_task(function() {
yield startCustomizing();
- let numPlaceholders = isInWin8() ? 1 : 2;
+ let numPlaceholders = isInWin8() ? 3 : 1;
let panel = document.getElementById(CustomizableUI.AREA_PANEL);
ok(CustomizableUI.inDefaultState, "Should be in default state.");
is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting");
diff --git a/browser/components/places/content/places.css b/browser/components/places/content/places.css
index 5151cca8254b..de3cc91d84ff 100644
--- a/browser/components/places/content/places.css
+++ b/browser/components/places/content/places.css
@@ -14,3 +14,12 @@ tree[type="places"] {
menupopup[placespopup="true"] {
-moz-binding: url("chrome://browser/content/places/menu.xml#places-popup-base");
}
+
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ #bookmarksChildren,
+ .sidebar-placesTreechildren,
+ .placesTree > treechildren {
+ image-rendering: -moz-crisp-edges;
+ }
+}
diff --git a/browser/components/preferences/handlers.css b/browser/components/preferences/handlers.css
index abac7d575e9f..d5f100831e68 100644
--- a/browser/components/preferences/handlers.css
+++ b/browser/components/preferences/handlers.css
@@ -23,3 +23,11 @@
listitem.offlineapp {
-moz-binding: url("chrome://browser/content/preferences/handlers.xml#offlineapp");
}
+
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ #handlersView > richlistitem,
+ .actionsMenu > menupopup > menuitem > .menu-iconic-left {
+ image-rendering: -moz-crisp-edges;
+ }
+}
diff --git a/browser/components/tabview/tabview.css b/browser/components/tabview/tabview.css
index 8ab4b6c2466c..8f3ff20279f8 100644
--- a/browser/components/tabview/tabview.css
+++ b/browser/components/tabview/tabview.css
@@ -65,6 +65,13 @@ body {
position: absolute;
}
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .favicon > img {
+ image-rendering: -moz-crisp-edges;
+ }
+}
+
.close {
position: absolute;
cursor: pointer;
diff --git a/browser/devtools/markupview/markup-view.js b/browser/devtools/markupview/markup-view.js
index 22bef8fc7a04..3f059677be08 100644
--- a/browser/devtools/markupview/markup-view.js
+++ b/browser/devtools/markupview/markup-view.js
@@ -13,7 +13,6 @@ const DEFAULT_MAX_CHILDREN = 100;
const COLLAPSE_ATTRIBUTE_LENGTH = 120;
const COLLAPSE_DATA_URL_REGEX = /^data.+base64/;
const COLLAPSE_DATA_URL_LENGTH = 60;
-const CONTAINER_FLASHING_DURATION = 500;
const NEW_SELECTION_HIGHLIGHTER_TIMER = 1000;
const {UndoStack} = require("devtools/shared/undo");
@@ -112,6 +111,11 @@ function MarkupView(aInspector, aFrame, aControllerWindow) {
exports.MarkupView = MarkupView;
MarkupView.prototype = {
+ /**
+ * How long does a node flash when it mutates (in ms).
+ */
+ CONTAINER_FLASHING_DURATION: 500,
+
_selectedContainer: null,
_initTooltips: function() {
@@ -1578,7 +1582,7 @@ MarkupContainer.prototype = {
}
this._flashMutationTimer = contentWin.setTimeout(() => {
this.flashed = false;
- }, CONTAINER_FLASHING_DURATION);
+ }, this.markup.CONTAINER_FLASHING_DURATION);
}
},
diff --git a/browser/devtools/markupview/test/browser_markupview_mutation_02.js b/browser/devtools/markupview/test/browser_markupview_mutation_02.js
index 7aae473747d8..c7a12d3bd203 100644
--- a/browser/devtools/markupview/test/browser_markupview_mutation_02.js
+++ b/browser/devtools/markupview/test/browser_markupview_mutation_02.js
@@ -55,6 +55,10 @@ const TEST_DATA = [{
let test = asyncTest(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
+ // Make sure mutated nodes flash for a very long time so we can more easily
+ // assert they do
+ inspector.markup.CONTAINER_FLASHING_DURATION = 1000 * 60 * 60;
+
info("Getting the root node to test mutations on");
let rootNode = getNode(".list");
let rootNodeFront = yield getNodeFront(".list", inspector);
@@ -88,4 +92,9 @@ function* assertNodeFlashing(nodeFront, inspector) {
ok(container, "Markup container for node found");
ok(container.tagState.classList.contains("theme-bg-contrast"),
"Markup container for node is flashing");
+
+ // Clear the mutation flashing timeout now that we checked the node was flashing
+ let markup = inspector.markup;
+ markup._frame.contentWindow.clearTimeout(container._flashMutationTimer);
+ container._flashMutationTimer = null;
}
diff --git a/browser/locales/en-US/chrome/browser/browser.dtd b/browser/locales/en-US/chrome/browser/browser.dtd
index e18c817d2aa4..e6fc718b90ca 100644
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -140,17 +140,18 @@ These should match what Safari and other Apple applications use on OS X Lion. --
+
-
+
-
+
-
+
-
+
diff --git a/browser/modules/Social.jsm b/browser/modules/Social.jsm
index 54f03eefced1..6301d2a6ec1e 100644
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -363,7 +363,8 @@ SocialErrorListener.prototype = {
if (failure && aStatus != Components.results.NS_BINDING_ABORTED) {
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
let provider = Social._getProviderFromOrigin(this.iframe.getAttribute("origin"));
- provider.errorState = "content-error";
+ if (provider && !provider.errorState)
+ provider.errorState = "content-error";
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
.chromeEventHandler);
}
@@ -373,7 +374,7 @@ SocialErrorListener.prototype = {
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
aRequest.cancel(Components.results.NS_BINDING_ABORTED);
let provider = Social._getProviderFromOrigin(this.iframe.getAttribute("origin"));
- if (!provider.errorState)
+ if (provider && !provider.errorState)
provider.errorState = "content-error";
schedule(function() {
this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
diff --git a/browser/themes/osx/browser.css b/browser/themes/osx/browser.css
index 112adcd82654..519d13cc64e4 100644
--- a/browser/themes/osx/browser.css
+++ b/browser/themes/osx/browser.css
@@ -387,14 +387,6 @@ toolbarbutton.bookmark-item > menupopup {
opacity: 0.7;
}
-@media (min-resolution: 2dppx) {
- .bookmark-item > .toolbarbutton-icon,
- .bookmark-item > .menu-iconic-left > .menu-iconic-icon,
- #personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
- image-rendering: -moz-crisp-edges;
- }
-}
-
#bookmarks-toolbar-placeholder {
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.png") !important;
}
@@ -1321,6 +1313,11 @@ toolbar .toolbarbutton-1 > .toolbarbutton-menubutton-dropmarker > .dropmarker-ic
width: 16px;
}
+ #add-share-provider {
+ list-style-image: url(chrome://browser/skin/menuPanel-small@2x.png);
+ -moz-image-region: rect(0px, 192px, 32px, 160px);
+ }
+
#loop-call-button > .toolbarbutton-badge-container {
list-style-image: url("chrome://browser/skin/loop/toolbar@2x.png");
-moz-image-region: rect(0, 36px, 36px, 0);
@@ -2798,7 +2795,6 @@ toolbarbutton.chevron > .toolbarbutton-menu-dropmarker {
.tab-icon-image {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
- image-rendering: -moz-crisp-edges;
}
.tab-throbber[busy] {
diff --git a/browser/themes/osx/searchbar.css b/browser/themes/osx/searchbar.css
index 93023fee176a..0a45f7510b04 100644
--- a/browser/themes/osx/searchbar.css
+++ b/browser/themes/osx/searchbar.css
@@ -47,11 +47,6 @@
}
@media (min-resolution: 2dppx) {
- .searchbar-engine-image,
- .searchbar-engine-menuitem > .menu-iconic-left > .menu-iconic-icon {
- image-rendering: -moz-crisp-edges;
- }
-
.searchbar-engine-image {
list-style-image: url("chrome://mozapps/skin/places/defaultFavicon@2x.png");
}
diff --git a/browser/themes/shared/incontentprefs/preferences.css b/browser/themes/shared/incontentprefs/preferences.css
index 83434349b26f..93576c6d9422 100644
--- a/browser/themes/shared/incontentprefs/preferences.css
+++ b/browser/themes/shared/incontentprefs/preferences.css
@@ -167,7 +167,7 @@ prefpane {
#typeColumn > .treecol-sortdirection[sortDirection=descending],
#actionColumn > .treecol-sortdirection[sortDirection=descending] {
-moz-appearance: none;
- list-style-image: url("chrome://browser/skin/preferences/in-content/sorter.png");
+ list-style-image: url("chrome://browser/skin/in-content/sorter.png");
}
#typeColumn > .treecol-sortdirection[sortDirection=descending],
@@ -182,7 +182,7 @@ prefpane {
#actionColumn > .treecol-sortdirection[sortDirection=descending] {
width: 12px;
height: 8px;
- list-style-image: url("chrome://browser/skin/preferences/in-content/sorter@2x.png");
+ list-style-image: url("chrome://browser/skin/in-content/sorter@2x.png");
}
}
diff --git a/browser/themes/shared/menupanel.inc.css b/browser/themes/shared/menupanel.inc.css
index 436a00faede9..dfb1ce39bcc7 100644
--- a/browser/themes/shared/menupanel.inc.css
+++ b/browser/themes/shared/menupanel.inc.css
@@ -218,3 +218,8 @@ toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-out-button {
toolbarpaletteitem[place="palette"] > #zoom-controls > #zoom-in-button {
-moz-image-region: rect(0px, 96px, 16px, 80px);
}
+
+#add-share-provider {
+ list-style-image: url(chrome://browser/skin/menuPanel-small.png);
+ -moz-image-region: rect(0px, 96px, 16px, 80px);
+}
\ No newline at end of file
diff --git a/browser/themes/shared/newtab/controls.svg b/browser/themes/shared/newtab/controls.svg
index a37a3a7a42a3..3985f331c3b8 100644
--- a/browser/themes/shared/newtab/controls.svg
+++ b/browser/themes/shared/newtab/controls.svg
@@ -19,16 +19,11 @@
}
.glyphShape-style-hover-gear {
- fill: url(#gradient-linear-hover-gear);
- }
- .glyphShape-style-hover-gear-dropshadow {
- fill: #000;
- fill-opacity: .5;
- filter: url(#filter-shadow-drop);
+ fill: #4a90e2;
}
.glyphShape-style-hover-pin {
- fill: #0092e5;
+ fill: #4a90e2;
}
.glyphShape-style-hover-delete {
@@ -57,14 +52,6 @@
-
-
-
-
-
@@ -79,7 +66,6 @@
-
diff --git a/mobile/android/base/toolbar/TabCounter.java b/mobile/android/base/toolbar/TabCounter.java
index b991ac46dc9a..770edc373ff5 100644
--- a/mobile/android/base/toolbar/TabCounter.java
+++ b/mobile/android/base/toolbar/TabCounter.java
@@ -133,7 +133,7 @@ public class TabCounter extends ThemedTextSwitcher
@Override
public View makeView() {
- return mInflater.inflate(mLayoutId, this, false);
+ return mInflater.inflate(mLayoutId, null);
}
}
diff --git a/toolkit/components/search/SearchSuggestionController.jsm b/toolkit/components/search/SearchSuggestionController.jsm
index 74f4413916f8..64aeb5a41e52 100644
--- a/toolkit/components/search/SearchSuggestionController.jsm
+++ b/toolkit/components/search/SearchSuggestionController.jsm
@@ -17,6 +17,16 @@ const SEARCH_RESPONSE_SUGGESTION_JSON = "application/x-suggestions+json";
const DEFAULT_FORM_HISTORY_PARAM = "searchbar-history";
const HTTP_OK = 200;
const REMOTE_TIMEOUT = 500; // maximum time (ms) to wait before giving up on a remote suggestions
+const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled";
+
+/**
+ * Remote search suggestions will be shown if gRemoteSuggestionsEnabled
+ * is true. Global because only one pref observer is needed for all instances.
+ */
+let gRemoteSuggestionsEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
+Services.prefs.addObserver(BROWSER_SUGGEST_PREF, function(aSubject, aTopic, aData) {
+ gRemoteSuggestionsEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
+}, false);
/**
* SearchSuggestionController.jsm exists as a helper module to allow multiple consumers to request and display
@@ -124,7 +134,7 @@ this.SearchSuggestionController.prototype = {
this._searchString = searchTerm;
// Remote results
- if (searchTerm && this.maxRemoteResults &&
+ if (searchTerm && gRemoteSuggestionsEnabled && this.maxRemoteResults &&
engine.supportsResponseType(SEARCH_RESPONSE_SUGGESTION_JSON)) {
this._deferredRemoteResult = this._fetchRemote(searchTerm, engine, privateMode);
promises.push(this._deferredRemoteResult.promise);
diff --git a/toolkit/components/search/nsSearchSuggestions.js b/toolkit/components/search/nsSearchSuggestions.js
index cbe7e5e64110..8e232bf651fc 100644
--- a/toolkit/components/search/nsSearchSuggestions.js
+++ b/toolkit/components/search/nsSearchSuggestions.js
@@ -2,10 +2,6 @@
* 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/. */
-const BROWSER_SUGGEST_PREF = "browser.search.suggest.enabled";
-const XPCOM_SHUTDOWN_TOPIC = "xpcom-shutdown";
-const NS_PREFBRANCH_PREFCHANGE_TOPIC_ID = "nsPref:changed";
-
const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
@@ -28,8 +24,6 @@ function SuggestAutoComplete() {
SuggestAutoComplete.prototype = {
_init: function() {
- this._addObservers();
- this._suggestEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
this._suggestionController = new SearchSuggestionController(obj => this.onResultsReturned(obj));
},
@@ -39,11 +33,6 @@ SuggestAutoComplete.prototype = {
return this._suggestionLabel = bundle.GetStringFromName("suggestion_label");
},
- /**
- * Search suggestions will be shown if this._suggestEnabled is true.
- */
- _suggestEnabled: null,
-
/**
* The object implementing nsIAutoCompleteObserver that we notify when
* we have found results
@@ -178,32 +167,6 @@ SuggestAutoComplete.prototype = {
this._suggestionController.stop();
},
- /**
- * nsIObserver
- */
- observe: function SAC_observe(aSubject, aTopic, aData) {
- switch (aTopic) {
- case NS_PREFBRANCH_PREFCHANGE_TOPIC_ID:
- this._suggestEnabled = Services.prefs.getBoolPref(BROWSER_SUGGEST_PREF);
- break;
- case XPCOM_SHUTDOWN_TOPIC:
- this._removeObservers();
- break;
- }
- },
-
- _addObservers: function SAC_addObservers() {
- Services.prefs.addObserver(BROWSER_SUGGEST_PREF, this, false);
-
- Services.obs.addObserver(this, XPCOM_SHUTDOWN_TOPIC, false);
- },
-
- _removeObservers: function SAC_removeObservers() {
- Services.prefs.removeObserver(BROWSER_SUGGEST_PREF, this);
-
- Services.obs.removeObserver(this, XPCOM_SHUTDOWN_TOPIC);
- },
-
// nsISupports
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAutoCompleteSearch,
Ci.nsIAutoCompleteObserver])
diff --git a/toolkit/components/search/tests/xpcshell/test_searchSuggest.js b/toolkit/components/search/tests/xpcshell/test_searchSuggest.js
index 36ea60dc9302..b80bebf8621c 100644
--- a/toolkit/components/search/tests/xpcshell/test_searchSuggest.js
+++ b/toolkit/components/search/tests/xpcshell/test_searchSuggest.js
@@ -278,6 +278,49 @@ add_task(function* one_of_each() {
do_check_eq(result.remote[0], "letter B");
});
+add_task(function* local_result_returned_remote_result_disabled() {
+ Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
+ let controller = new SearchSuggestionController();
+ controller.maxLocalResults = 1;
+ controller.maxRemoteResults = 1;
+ let result = yield controller.fetch("letter ", false, getEngine);
+ do_check_eq(result.term, "letter ");
+ do_check_eq(result.local.length, 1);
+ do_check_eq(result.local[0], "letter A");
+ do_check_eq(result.remote.length, 0);
+ Services.prefs.clearUserPref("browser.search.suggest.enabled");
+});
+
+add_task(function* local_result_returned_remote_result_disabled_after_creation_of_controller() {
+ let controller = new SearchSuggestionController();
+ controller.maxLocalResults = 1;
+ controller.maxRemoteResults = 1;
+ Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
+ let result = yield controller.fetch("letter ", false, getEngine);
+ do_check_eq(result.term, "letter ");
+ do_check_eq(result.local.length, 1);
+ do_check_eq(result.local[0], "letter A");
+ do_check_eq(result.remote.length, 0);
+});
+
+add_task(function* one_of_each_disabled_before_creation_enabled_after_creation_of_controller() {
+ Services.prefs.setBoolPref("browser.search.suggest.enabled", false);
+ let controller = new SearchSuggestionController();
+ controller.maxLocalResults = 1;
+ controller.maxRemoteResults = 1;
+ Services.prefs.setBoolPref("browser.search.suggest.enabled", true);
+ let result = yield controller.fetch("letter ", false, getEngine);
+ do_check_eq(result.term, "letter ");
+ do_check_eq(result.local.length, 1);
+ do_check_eq(result.local[0], "letter A");
+ do_check_eq(result.remote.length, 1);
+ do_check_eq(result.remote[0], "letter B");
+});
+
+add_task(function* clear_suggestions_pref() {
+ Services.prefs.clearUserPref("browser.search.suggest.enabled");
+});
+
add_task(function* one_local_zero_remote() {
let controller = new SearchSuggestionController();
controller.maxLocalResults = 1;
diff --git a/toolkit/components/social/SocialService.jsm b/toolkit/components/social/SocialService.jsm
index 9dc6c623ee02..b98151f6c554 100644
--- a/toolkit/components/social/SocialService.jsm
+++ b/toolkit/components/social/SocialService.jsm
@@ -585,26 +585,24 @@ this.SocialService = {
action, [], options);
},
- installProvider: function(aDOMDocument, data, installCallback, aBypassUserEnable=false) {
+ installProvider: function(aDOMDocument, data, installCallback, options={}) {
let manifest;
let installOrigin = aDOMDocument.nodePrincipal.origin;
- if (data) {
- let installType = getOriginActivationType(installOrigin);
- // if we get data, we MUST have a valid manifest generated from the data
- manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
- if (!manifest)
- throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
+ let installType = getOriginActivationType(installOrigin);
+ // if we get data, we MUST have a valid manifest generated from the data
+ manifest = this._manifestFromData(installType, data, aDOMDocument.nodePrincipal);
+ if (!manifest)
+ throw new Error("SocialService.installProvider: service configuration is invalid from " + aDOMDocument.location.href);
- let addon = new AddonWrapper(manifest);
- if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
- throw new Error("installProvider: provider with origin [" +
- installOrigin + "] is blocklisted");
- // manifestFromData call above will enforce correct origin. To support
- // activation from about: uris, we need to be sure to use the updated
- // origin on the manifest.
- installOrigin = manifest.origin;
- }
+ let addon = new AddonWrapper(manifest);
+ if (addon && addon.blocklistState == Ci.nsIBlocklistService.STATE_BLOCKED)
+ throw new Error("installProvider: provider with origin [" +
+ installOrigin + "] is blocklisted");
+ // manifestFromData call above will enforce correct origin. To support
+ // activation from about: uris, we need to be sure to use the updated
+ // origin on the manifest.
+ installOrigin = manifest.origin;
let id = getAddonIDFromOrigin(installOrigin);
AddonManager.getAddonByID(id, function(aAddon) {
@@ -613,7 +611,7 @@ this.SocialService = {
aAddon.userDisabled = false;
}
schedule(function () {
- this._installProvider(aDOMDocument, manifest, aBypassUserEnable, aManifest => {
+ this._installProvider(aDOMDocument, manifest, options, aManifest => {
this._notifyProviderListeners("provider-installed", aManifest.origin);
installCallback(aManifest);
});
@@ -621,43 +619,21 @@ this.SocialService = {
}.bind(this));
},
- _installProvider: function(aDOMDocument, manifest, aBypassUserEnable, installCallback) {
- let sourceURI = aDOMDocument.location.href;
- let installOrigin = aDOMDocument.nodePrincipal.origin;
+ _installProvider: function(aDOMDocument, manifest, options, installCallback) {
+ if (!manifest)
+ throw new Error("Cannot install provider without manifest data");
- let installType = getOriginActivationType(installOrigin);
- let installer;
- switch(installType) {
- case "foreign":
- if (!Services.prefs.getBoolPref("social.remote-install.enabled"))
- throw new Error("Remote install of services is disabled");
- if (!manifest)
- throw new Error("Cannot install provider without manifest data");
+ let installType = getOriginActivationType(aDOMDocument.nodePrincipal.origin);
+ if (installType == "foreign" && !Services.prefs.getBoolPref("social.remote-install.enabled"))
+ throw new Error("Remote install of services is disabled");
- installer = new AddonInstaller(sourceURI, manifest, installCallback);
- this._showInstallNotification(aDOMDocument, installer);
- break;
- case "internal":
- // double check here since "builtin" falls through this as well.
- aBypassUserEnable = installType == "internal" && manifest.oneclick;
- case "directory":
- // a manifest is requried, and will have been vetted by reviewers. We
- // also handle in-product installations without the verification step.
- if (aBypassUserEnable) {
- installer = new AddonInstaller(sourceURI, manifest, installCallback);
- installer.install();
- return;
- }
- // a manifest is required, we'll catch a missing manifest below.
- if (!manifest)
- throw new Error("Cannot install provider without manifest data");
- installer = new AddonInstaller(sourceURI, manifest, installCallback);
- this._showInstallNotification(aDOMDocument, installer);
- break;
- default:
- throw new Error("SocialService.installProvider: Invalid install type "+installType+"\n");
- break;
- }
+ let installer = new AddonInstaller(aDOMDocument.location.href, manifest, installCallback);
+ let bypassPanel = options.bypassInstallPanel ||
+ (installType == "internal" && manifest.oneclick);
+ if (bypassPanel)
+ installer.install();
+ else
+ this._showInstallNotification(aDOMDocument, installer);
},
createWrapper: function(manifest) {
diff --git a/toolkit/content/autocomplete.css b/toolkit/content/autocomplete.css
new file mode 100644
index 000000000000..249c7ebf9c10
--- /dev/null
+++ b/toolkit/content/autocomplete.css
@@ -0,0 +1,13 @@
+/* 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/. */
+
+@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
+@namespace html url("http://www.w3.org/1999/xhtml");
+
+/* Apply crisp rendering for favicons at exactly 2dppx resolution */
+@media (resolution: 2dppx) {
+ .ac-site-icon {
+ image-rendering: -moz-crisp-edges;
+ }
+}
diff --git a/toolkit/content/jar.mn b/toolkit/content/jar.mn
index 60000211d24d..54ad0d66e551 100644
--- a/toolkit/content/jar.mn
+++ b/toolkit/content/jar.mn
@@ -11,6 +11,7 @@ toolkit.jar:
* content/global/xul.css (xul.css)
content/global/textbox.css (textbox.css)
content/global/menulist.css (menulist.css)
+ content/global/autocomplete.css (autocomplete.css)
content/global/about.js (about.js)
content/global/about.xhtml (about.xhtml)
content/global/aboutAbout.js (aboutAbout.js)
diff --git a/toolkit/content/widgets/autocomplete.xml b/toolkit/content/widgets/autocomplete.xml
index 58dc9af6f4dc..cb83860817cb 100644
--- a/toolkit/content/widgets/autocomplete.xml
+++ b/toolkit/content/widgets/autocomplete.xml
@@ -19,6 +19,7 @@
+
@@ -598,6 +599,7 @@