--- a/browser/base/content/aboutSocialError.xhtml
+++ b/browser/base/content/aboutSocialError.xhtml
@@ -41,23 +41,24 @@
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource:///modules/Social.jsm");
let config = {
tryAgainCallback: reloadProvider
}
function parseQueryString() {
- let searchParams = new URLSearchParams(location.href.split("?")[1]);
+ let searchParams = new URLSearchParams(document.documentURI.split("?")[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) {
+ // directory does not have origin set, in that case use the url origin for
+ // the error message.
+ if (!config.origin) {
let URI = Services.io.newURI(url, null, null);
config.origin = Services.scriptSecurityManager.getNoAppCodebasePrincipal(URI).origin;
}
switch (mode) {
case "compactInfo":
document.getElementById("btnTryAgain").style.display = 'none';
break;
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -55,16 +55,19 @@ XPCOMUtils.defineLazyGetter(this, "hookW
SocialUI = {
_initialized: false,
// Called on delayed startup to initialize the UI
init: function SocialUI_init() {
if (this._initialized) {
return;
}
+ let mm = window.getGroupMessageManager("social");
+ mm.loadFrameScript("chrome://browser/content/content.js", true);
+ mm.loadFrameScript("chrome://browser/content/social-content.js", true);
Services.obs.addObserver(this, "social:ambient-notification-changed", false);
Services.obs.addObserver(this, "social:profile-changed", false);
Services.obs.addObserver(this, "social:frameworker-error", false);
Services.obs.addObserver(this, "social:providers-changed", false);
Services.obs.addObserver(this, "social:provider-reload", false);
Services.obs.addObserver(this, "social:provider-enabled", false);
Services.obs.addObserver(this, "social:provider-disabled", false);
@@ -149,17 +152,17 @@ SocialUI = {
case "social:profile-changed":
// make sure anything that happens here only affects the provider for
// which the profile is changing, and that anything we call actually
// needs to change based on profile data.
SocialStatus.updateButton(data);
break;
case "social:frameworker-error":
if (this.enabled && SocialSidebar.provider && SocialSidebar.provider.origin == data) {
- SocialSidebar.setSidebarErrorMessage();
+ SocialSidebar.loadFrameworkerFailure();
}
break;
case "nsPref:changed":
if (data == "social.toast-notifications.enabled") {
SocialSidebar.updateToggleNotifications();
}
break;
}
@@ -346,41 +349,39 @@ SocialFlyout = {
doc.documentElement.dispatchEvent(evt);
},
_createFrame: function() {
let panel = this.panel;
if (!SocialUI.enabled || panel.firstChild)
return;
// create and initialize the panel for this window
- let iframe = document.createElement("iframe");
+ let iframe = document.createElement("browser");
iframe.setAttribute("type", "content");
iframe.setAttribute("class", "social-panel-frame");
iframe.setAttribute("flex", "1");
+ iframe.setAttribute("message", "true");
+ iframe.setAttribute("messagemanagergroup", "social");
iframe.setAttribute("tooltip", "aHTMLTooltip");
+ iframe.setAttribute("context", "contentAreaContextMenu");
iframe.setAttribute("origin", SocialSidebar.provider.origin);
panel.appendChild(iframe);
- },
-
- setFlyoutErrorMessage: function SF_setFlyoutErrorMessage() {
- this.iframe.removeAttribute("src");
- this.iframe.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
- encodeURIComponent(this.iframe.getAttribute("origin")),
- null, null, null, null);
- sizeSocialPanelToContent(this.panel, this.iframe);
+ // the xbl bindings for the iframe probably don't exist yet, so we can't
+ // access iframe.messageManager directly - but can get at it with this dance.
+ let mm = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
+ mm.sendAsyncMessage("Social:SetErrorURL", null,
+ { template: "about:socialerror?mode=compactInfo&origin=%{origin}" });
},
unload: function() {
let panel = this.panel;
panel.hidePopup();
if (!panel.firstChild)
return
let iframe = panel.firstChild;
- if (iframe.socialErrorListener)
- iframe.socialErrorListener.remove();
panel.removeChild(iframe);
},
onShown: function(aEvent) {
let panel = this.panel;
let iframe = this.iframe;
this._dynamicResizer = new DynamicResizeWatcher();
iframe.docShell.isActive = true;
@@ -418,17 +419,16 @@ SocialFlyout = {
// same url with only ref difference does not cause a new load, so we
// want to go right to the callback
let src = iframe.contentDocument && iframe.contentDocument.documentURIObject;
if (!src || !src.equalsExceptRef(Services.io.newURI(aURL, null, null))) {
iframe.addEventListener("load", function documentLoaded() {
iframe.removeEventListener("load", documentLoaded, true);
cb();
}, true);
- Social.setErrorListener(iframe, SocialFlyout.setFlyoutErrorMessage.bind(SocialFlyout))
iframe.setAttribute("src", aURL);
} else {
// we still need to set the src to trigger the contents hashchange event
// for ref changes
iframe.setAttribute("src", aURL);
cb();
}
},
@@ -498,21 +498,23 @@ SocialShare = {
// create and initialize the panel for this window
let iframe = document.createElement("browser");
iframe.setAttribute("type", "content");
iframe.setAttribute("class", "social-share-frame");
iframe.setAttribute("context", "contentAreaContextMenu");
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.setAttribute("disableglobalhistory", "true");
iframe.setAttribute("flex", "1");
+ iframe.setAttribute("message", "true");
+ iframe.setAttribute("messagemanagergroup", "social");
panel.lastChild.appendChild(iframe);
- iframe.addEventListener("load", function _firstload() {
- iframe.removeEventListener("load", _firstload, true);
- iframe.messageManager.loadFrameScript("chrome://browser/content/content.js", true);
- }, true);
+ let mm = iframe.QueryInterface(Components.interfaces.nsIFrameLoaderOwner).frameLoader.messageManager;
+ mm.sendAsyncMessage("Social:SetErrorURL", null,
+ { template: "about:socialerror?mode=compactInfo&origin=%{origin}&url=%{url}" });
+
this.populateProviderMenu();
},
getSelectedProvider: function() {
let provider;
let lastProviderOrigin = this.iframe && this.iframe.getAttribute("origin");
if (lastProviderOrigin) {
provider = Social._getProviderFromOrigin(lastProviderOrigin);
@@ -591,33 +593,16 @@ SocialShare = {
// share panel use is over, purge any history
if (this.iframe.sessionHistory) {
let purge = this.iframe.sessionHistory.count;
if (purge > 0)
this.iframe.sessionHistory.PurgeHistory(purge);
}
},
- setErrorMessage: function() {
- let iframe = this.iframe;
- if (!iframe)
- return;
-
- let url;
- let origin = iframe.getAttribute("origin");
- if (!origin) {
- // 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);
- },
-
sharePage: function(providerOrigin, graphData, target) {
// if providerOrigin is undefined, we use the last-used provider, or the
// current/default provider. The provider selection in the share panel
// will call sharePage with an origin for us to switch to.
this._createFrame();
let iframe = this.iframe;
// graphData is an optional param that either defines the full set of data
@@ -759,17 +744,16 @@ SocialShare = {
}, true);
iframe.setAttribute("src", "about:providerdirectory");
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(this.iframe, this.setErrorMessage.bind(this));
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(0);
}
};
SocialSidebar = {
_openStartTime: 0,
// Whether the sidebar can be shown for this window.
@@ -913,27 +897,22 @@ SocialSidebar = {
} else {
this._unloadTimeoutId = setTimeout(
this.unloadSidebar,
Services.prefs.getIntPref("social.sidebar.unload_timeout_ms")
);
}
} else {
sbrowser.setAttribute("origin", this.provider.origin);
- if (this.provider.errorState == "frameworker-error") {
- SocialSidebar.setSidebarErrorMessage();
- return;
- }
// Make sure the right sidebar URL is loaded
if (sbrowser.getAttribute("src") != this.provider.sidebarURL) {
// we check readyState right after setting src, we need a new content
// viewer to ensure we are checking against the correct document.
sbrowser.docShell.createAboutBlankContentViewer(null);
- Social.setErrorListener(sbrowser, this.setSidebarErrorMessage.bind(this));
// setting isAppTab causes clicks on untargeted links to open new tabs
sbrowser.docShell.isAppTab = true;
sbrowser.setAttribute("src", this.provider.sidebarURL);
PopupNotifications.locationChange(sbrowser);
}
// if the document has not loaded, delay until it is
if (sbrowser.contentDocument.readyState != "complete") {
@@ -971,28 +950,23 @@ SocialSidebar = {
// doesn't get destroyed until about:blank has loaded (which does not happen
// as long as the element is hidden).
sbrowser.docShell.createAboutBlankContentViewer(null);
SocialFlyout.unload();
},
_unloadTimeoutId: 0,
- setSidebarErrorMessage: function() {
- let sbrowser = document.getElementById("social-sidebar-browser");
- // a frameworker error "trumps" a sidebar error.
- let origin = sbrowser.getAttribute("origin");
- if (origin) {
- origin = "&origin=" + encodeURIComponent(origin);
- }
- if (this.provider.errorState == "frameworker-error") {
- sbrowser.setAttribute("src", "about:socialerror?mode=workerFailure" + origin);
- } else {
- let url = encodeURIComponent(this.provider.sidebarURL);
- sbrowser.loadURI("about:socialerror?mode=tryAgain&url=" + url + origin, null, null);
+ loadFrameworkerFailure: function() {
+ if (this.provider && this.provider.errorState == "frameworker-error") {
+ // we have to explicitly load this error page since it is not being
+ // handled via the normal error page paths.
+ let sbrowser = document.getElementById("social-sidebar-browser");
+ sbrowser.setAttribute("src", "about:socialerror?mode=workerFailure&origin=" +
+ encodeURIComponent(this.provider.origin));
}
},
_provider: null,
ensureProvider: function() {
if (this._provider)
return;
// origin for sidebar is persisted, so get the previously selected sidebar
@@ -1293,57 +1267,54 @@ SocialStatus = {
[ariaLabel, badge]);
button.setAttribute("aria-label", ariaLabel);
}
},
_onclose: function(frame) {
frame.removeEventListener("close", this._onclose, true);
frame.removeEventListener("click", this._onclick, true);
- if (frame.socialErrorListener)
- frame.socialErrorListener.remove();
},
_onclick: function() {
Services.telemetry.getHistogramById("SOCIAL_PANEL_CLICKS").add(1);
},
showPopup: function(aToolbarButton) {
// attach our notification panel if necessary
let origin = aToolbarButton.getAttribute("origin");
let provider = Social._getProviderFromOrigin(origin);
PanelFrame.showPopup(window, aToolbarButton, "social", origin,
provider.statusURL, provider.getPageSize("status"),
(frame) => {
frame.addEventListener("close", () => { SocialStatus._onclose(frame) }, true);
frame.addEventListener("click", this._onclick, true);
- Social.setErrorListener(frame, this.setPanelErrorMessage.bind(this));
});
Services.telemetry.getHistogramById("SOCIAL_TOOLBAR_BUTTONS").add(1);
- },
-
- setPanelErrorMessage: function(aNotificationFrame) {
- if (!aNotificationFrame)
- return;
-
- let src = aNotificationFrame.getAttribute("src");
- aNotificationFrame.removeAttribute("src");
- let origin = aNotificationFrame.getAttribute("origin");
- aNotificationFrame.webNavigation.loadURI("about:socialerror?mode=tryAgainOnly&url=" +
- encodeURIComponent(src) + "&origin=" +
- encodeURIComponent(origin),
- null, null, null, null);
- let panel = aNotificationFrame.parentNode;
- sizeSocialPanelToContent(panel, aNotificationFrame);
- },
-
+ }
};
+let SocialMarksWidgetListener = {
+ onWidgetAdded: function(aWidgetId, aArea, aPosition) {
+ let node = document.getElementById(aWidgetId);
+ if (!node || !node.classList.contains("social-mark-button"))
+ return;
+ node._receiveMessage = node.receiveMessage.bind(node);
+ messageManager.addMessageListener("Social:ErrorPageNotify", node._receiveMessage);
+ },
+ onWidgetBeforeDOMChange: function(aNode, aNextNode, aContainer, isRemoval) {
+ if (!isRemoval || !aNode || !aNode.classList.contains("social-mark-button"))
+ return;
+ messageManager.removeMessageListener("Social:ErrorPageNotify", aNode._receiveMessage);
+ delete aNode._receiveMessage;
+ }
+}
+
/**
* SocialMarks
*
* Handles updates to toolbox and signals all buttons to update when necessary.
*/
SocialMarks = {
get nodes() {
let providers = [p for (p of Social.providers) if (p.markURL)];
@@ -1437,17 +1408,19 @@ SocialMarks = {
},
removeProvider: function(origin) {
this._toolbarHelper.removeProviderButton(origin);
},
get _toolbarHelper() {
delete this._toolbarHelper;
- this._toolbarHelper = new ToolbarHelper("social-mark-button", CreateSocialMarkWidget);
+ this._toolbarHelper = new ToolbarHelper("social-mark-button",
+ CreateSocialMarkWidget,
+ SocialMarksWidgetListener);
return this._toolbarHelper;
},
markLink: function(aOrigin, aUrl, aTarget) {
// find the button for this provider, and open it
let id = this._toolbarHelper.idFromOrigin(aOrigin);
document.getElementById(id).markLink(aUrl, aTarget);
}
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -1218,16 +1218,18 @@
oncommand="SocialUI.showLearnMore();"/>
</menupopup>
</toolbarbutton>
</sidebarheader>
<browser id="social-sidebar-browser"
type="content"
context="contentAreaContextMenu"
+ message="true"
+ messagemanagergroup="social"
disableglobalhistory="true"
tooltip="aHTMLTooltip"
popupnotificationanchor="social-sidebar-favico"
flex="1"
style="min-width: 14em; width: 18em; max-width: 36em;"/>
</vbox>
<vbox id="browser-border-end" hidden="true" layer="true"/>
</hbox>
new file mode 100644
--- /dev/null
+++ b/browser/base/content/social-content.js
@@ -0,0 +1,105 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* This content script should work in any browser or iframe and should not
+ * depend on the frame being contained in tabbrowser. */
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+// social frames are always treated as app tabs
+docShell.isAppTab = true;
+
+// Error handling class used to listen for network errors in the social frames
+// and replace them with a social-specific error page
+SocialErrorListener = {
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
+ Ci.nsISupportsWeakReference,
+ Ci.nsISupports]),
+
+ defaultTemplate: "about:socialerror?mode=tryAgainOnly&url=%{url}&origin=%{origin}",
+ urlTemplate: null,
+
+ init() {
+ addMessageListener("Social:SetErrorURL", this);
+ let webProgress = docShell.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
+ .getInterface(Components.interfaces.nsIWebProgress);
+ webProgress.addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
+ Ci.nsIWebProgress.NOTIFY_LOCATION);
+ },
+ receiveMessage(message) {
+ switch(message.name) {
+ case "Social:SetErrorURL": {
+ // either a url or null to reset to default template
+ this.urlTemplate = message.objects.template;
+ }
+ }
+ },
+
+ setErrorPage() {
+ // if this is about:providerdirectory, use the directory iframe
+ let frame = docShell.chromeEventHandler;
+ let origin = frame.getAttribute("origin");
+ let src = frame.getAttribute("src");
+ if (src == "about:providerdirectory") {
+ frame = content.document.getElementById("activation-frame");
+ src = frame.getAttribute("src");
+ }
+
+ let url = this.urlTemplate || this.defaultTemplate;
+ url = url.replace("%{url}", encodeURIComponent(src));
+ url = url.replace("%{origin}", encodeURIComponent(origin));
+ if (frame != docShell.chromeEventHandler) {
+ // Unable to access frame.docShell here. This is our own frame and doesn't
+ // provide reload, so we'll just set the src.
+ frame.setAttribute("src", url);
+ } else {
+ let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
+ webNav.loadURI(url, null, null, null, null);
+ }
+ sendAsyncMessage("Social:ErrorPageNotify", {
+ origin: origin,
+ url: src
+ });
+ },
+
+ onStateChange(aWebProgress, aRequest, aState, aStatus) {
+ let failure = false;
+ if ((aState & Ci.nsIWebProgressListener.STATE_STOP)) {
+ if (aRequest instanceof Ci.nsIHttpChannel) {
+ try {
+ // Change the frame to an error page on 4xx (client errors)
+ // and 5xx (server errors). responseStatus throws if it is not set.
+ failure = aRequest.responseStatus >= 400 &&
+ aRequest.responseStatus < 600;
+ } catch (e) {
+ failure = aStatus != Components.results.NS_OK;
+ }
+ }
+ }
+
+ // Calling cancel() will raise some OnStateChange notifications by itself,
+ // so avoid doing that more than once
+ if (failure && aStatus != Components.results.NS_BINDING_ABORTED) {
+ aRequest.cancel(Components.results.NS_BINDING_ABORTED);
+ this.setErrorPage();
+ }
+ },
+
+ onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
+ if (aRequest && aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
+ aRequest.cancel(Components.results.NS_BINDING_ABORTED);
+ this.setErrorPage();
+ }
+ },
+
+ onProgressChange() {},
+ onStatusChange() {},
+ onSecurityChange() {},
+};
+
+SocialErrorListener.init();
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -25,16 +25,18 @@
<xul:toolbarbutton anonid="swap" class="chat-swap-button chat-toolbarbutton"
oncommand="document.getBindingParent(this).swapWindows();"/>
<xul:toolbarbutton anonid="close" class="chat-close-button chat-toolbarbutton"
oncommand="document.getBindingParent(this).close();"/>
</xul:hbox>
<xul:browser anonid="content" class="chat-frame" flex="1"
context="contentAreaContextMenu"
disableglobalhistory="true"
+ message="true"
+ messagemanagergroup="social"
tooltip="aHTMLTooltip"
xbl:inherits="src,origin" type="content"/>
</content>
<implementation implements="nsIDOMEventListener">
<constructor><![CDATA[
const kAnchorMap = new Map([
["", "notification-"],
@@ -67,23 +69,16 @@
this.addEventListener("DOMContentLoaded", function DOMContentLoaded(event) {
if (event.target != this.contentDocument)
return;
this.removeEventListener("DOMContentLoaded", DOMContentLoaded, true);
this.isActive = !this.minimized;
this._deferredChatLoaded.resolve(this);
}, true);
- // load content.js to support webrtc, fullscreen, etc.
- this.addEventListener("load", function loaded(event) {
- this.removeEventListener("load", loaded, true);
- let mm = this.content.messageManager;
- mm.loadFrameScript("chrome://browser/content/content.js", true);
- }, true);
-
if (this.src)
this.setAttribute("src", this.src);
]]></constructor>
<field name="_deferredChatLoaded" readonly="true">
Promise.defer();
</field>
--- a/browser/base/content/socialmarks.xml
+++ b/browser/base/content/socialmarks.xml
@@ -49,16 +49,18 @@
let provider = Social._getProviderFromOrigin(this.getAttribute("origin"));
let size = provider.getPageSize("marks");
let {width, height} = size ? size : {width: 330, height: 100};
let iframe = this._frame = document.createElement("iframe");
iframe.setAttribute("type", "content");
iframe.setAttribute("class", "social-panel-frame");
iframe.setAttribute("flex", "1");
+ iframe.setAttribute("message", "true");
+ iframe.setAttribute("messagemanagergroup", "social");
iframe.setAttribute("tooltip", "aHTMLTooltip");
iframe.setAttribute("context", "contentAreaContextMenu");
iframe.setAttribute("origin", provider.origin);
iframe.setAttribute("style", "width: " + width + "px; height: " + height + "px;");
this.panel.appendChild(iframe);
this._frame.addEventListener("DOMLinkAdded", this);
return this._frame;
@@ -129,16 +131,25 @@
// that we can hide
if (panel.hidePopup) {
panel.hidePopup();
}
this.pageData = null;
]]></body>
</method>
+ <method name="receiveMessage">
+ <parameter name="message"/>
+ <body><![CDATA[
+ if (message.name != "Social:ErrorPageNotify" || message.target != this.content)
+ return;
+ this.openPanel();
+ ]]></body>
+ </method>
+
<method name="loadPanel">
<parameter name="pageData"/>
<parameter name="target"/>
<body><![CDATA[
let provider = this.provider;
let panel = this.panel;
panel.hidden = false;
@@ -201,47 +212,26 @@
Social.unmarkURI(provider.origin, gBrowser.currentURI, () => {
this.update();
});
}
}.bind(this);
let unload = () => {
contentWindow.removeEventListener("unload", unload);
contentWindow.removeEventListener("socialMarkUpdate", markUpdate);
- if (this.content.socialErrorListener)
- this.content.socialErrorListener.remove();
}
contentWindow.addEventListener("socialMarkUpdate", markUpdate);
contentWindow.addEventListener("unload", unload);
}
this.content.addEventListener("DOMContentLoaded", DOMContentLoaded, true);
- Social.setErrorListener(this.content, this.setErrorMessage.bind(this));
this._loading = true;
this.content.setAttribute("src", endpoint);
]]></body>
</method>
- <method name="setErrorMessage">
- <parameter name="aNotificationFrame"/>
- <body><![CDATA[
- if (!aNotificationFrame)
- return;
-
- let src = aNotificationFrame.getAttribute("src");
- aNotificationFrame.removeAttribute("src");
- let origin = aNotificationFrame.getAttribute("origin");
- aNotificationFrame.webNavigation.loadURI("about:socialerror?mode=tryAgainOnly&url=" +
- encodeURIComponent(src) + "&origin=" +
- encodeURIComponent(origin),
- null, null, null, null);
- // ensure the panel is open if error occurs on first click
- this.openPanel();
- ]]></body>
- </method>
-
<method name="openPanel">
<parameter name="aResetOnClose"/>
<body><![CDATA[
let panel = this.panel;
let anchor = document.getAnonymousElementByAttribute(this._anchor, "class", "toolbarbutton-icon");
// Bug 849216 - open the popup in a setTimeout so we avoid the auto-rollup
// handling from preventing it being opened in some cases.
setTimeout(() => {
--- a/browser/base/content/test/social/browser_social_errorPage.js
+++ b/browser/base/content/test/social/browser_social_errorPage.js
@@ -57,27 +57,27 @@ function test() {
runSocialTests(tests, undefined, function(next) { goOnline().then(next) }, finishcb);
});
}
var tests = {
testSidebar: function(next) {
let sbrowser = document.getElementById("social-sidebar-browser");
onSidebarLoad(function() {
- ok(sbrowser.contentDocument.location.href.indexOf("about:socialerror?")==0, "sidebar is on social error page");
+ ok(sbrowser.contentDocument.documentURI.indexOf("about:socialerror?mode=tryAgainOnly")==0, "sidebar is on social error page");
gc();
// Add a new load listener, then find and click the "try again" button.
onSidebarLoad(function() {
// should still be on the error page.
- ok(sbrowser.contentDocument.location.href.indexOf("about:socialerror?")==0, "sidebar is still on social error page");
+ ok(sbrowser.contentDocument.documentURI.indexOf("about:socialerror?mode=tryAgainOnly")==0, "sidebar is still on social error page");
// go online and try again - this should work.
goOnline().then(function () {
onSidebarLoad(function() {
// should now be on the correct page.
- is(sbrowser.contentDocument.location.href, manifest.sidebarURL, "sidebar is now on social sidebar page");
+ is(sbrowser.contentDocument.documentURI, manifest.sidebarURL, "sidebar is now on social sidebar page");
next();
});
sbrowser.contentDocument.getElementById("btnTryAgain").click();
});
});
sbrowser.contentDocument.getElementById("btnTryAgain").click();
});
// go offline then attempt to load the sidebar - it should fail.
@@ -92,30 +92,30 @@ var tests = {
goOffline().then(function() {
openPanel(
manifest.sidebarURL, /* empty html page */
function() { // the panel api callback
panelCallbackCount++;
},
function() { // the "load" callback.
todo_is(panelCallbackCount, 0, "Bug 833207 - should be no callback when error page loads.");
- let href = panel.firstChild.contentDocument.location.href;
- ok(href.indexOf("about:socialerror?")==0, "flyout is on social error page");
+ let href = panel.firstChild.contentDocument.documentURI;
+ ok(href.indexOf("about:socialerror?mode=compactInfo")==0, "flyout is on social error page");
// Bug 832943 - the listeners previously stopped working after a GC, so
// force a GC now and try again.
gc();
openPanel(
manifest.sidebarURL, /* empty html page */
function() { // the panel api callback
panelCallbackCount++;
},
function() { // the "load" callback.
todo_is(panelCallbackCount, 0, "Bug 833207 - should be no callback when error page loads.");
- let href = panel.firstChild.contentDocument.location.href;
- ok(href.indexOf("about:socialerror?")==0, "flyout is on social error page");
+ let href = panel.firstChild.contentDocument.documentURI;
+ ok(href.indexOf("about:socialerror?mode=compactInfo")==0, "flyout is on social error page");
gc();
SocialFlyout.unload();
next();
}
);
}
);
});
@@ -129,17 +129,17 @@ var tests = {
openChat(
manifest.sidebarURL, /* empty html page */
function() { // the panel api callback
panelCallbackCount++;
},
function() { // the "load" callback.
todo_is(panelCallbackCount, 0, "Bug 833207 - should be no callback when error page loads.");
let chat = getChatBar().selectedChat;
- waitForCondition(function() chat.content != null && chat.contentDocument.location.href.indexOf("about:socialerror?")==0,
+ waitForCondition(function() chat.content != null && chat.contentDocument.documentURI.indexOf("about:socialerror?mode=tryAgainOnly")==0,
function() {
chat.close();
next();
},
"error page didn't appear");
}
);
});
@@ -152,29 +152,29 @@ var tests = {
// chatwindow tests throw errors, which muddy test output, if the worker
// doesn't get test-init
// open a chat while we are still online.
openChat(
url,
null,
function() { // the "load" callback.
let chat = getChatBar().selectedChat;
- is(chat.contentDocument.location.href, url, "correct url loaded");
+ is(chat.contentDocument.documentURI, url, "correct url loaded");
// toggle to a detached window.
chat.swapWindows().then(
chat => {
ok(!!chat.content, "we have chat content 1");
waitForCondition(function() chat.content != null && chat.contentDocument.readyState == "complete",
function() {
// now go offline and reload the chat - about:socialerror should be loaded.
goOffline().then(function() {
ok(!!chat.content, "we have chat content 2");
chat.contentDocument.location.reload();
info("chat reload called");
- waitForCondition(function() chat.contentDocument.location.href.indexOf("about:socialerror?")==0,
+ waitForCondition(function() chat.contentDocument.documentURI.indexOf("about:socialerror?mode=tryAgainOnly")==0,
function() {
chat.close();
next();
},
"error page didn't appear");
});
}, "swapped window loaded");
}
--- a/browser/base/content/test/social/browser_social_marks.js
+++ b/browser/base/content/test/social/browser_social_marks.js
@@ -233,17 +233,17 @@ var tests = {
addTab(activationURL, function(tab) {
ok(!btn.disabled, "button is enabled");
goOffline().then(function() {
info("testing offline error page");
// wait for popupshown
ensureEventFired(btn.panel, "popupshown").then(() => {
info("marks panel is open");
ensureFrameLoaded(btn.content).then(() => {
- is(btn.contentDocument.location.href.indexOf("about:socialerror?"), 0, "social error page is showing");
+ is(btn.contentDocument.documentURI.indexOf("about:socialerror?mode=tryAgainOnly"), 0, "social error page is showing "+btn.contentDocument.documentURI);
// cleanup after the page has been unmarked
ensureBrowserTabClosed(tab).then(() => {
ok(btn.disabled, "button is disabled");
goOnline().then(next);
});
});
});
btn.markCurrentPage();
--- a/browser/base/content/test/social/browser_social_status.js
+++ b/browser/base/content/test/social/browser_social_status.js
@@ -178,17 +178,17 @@ var tests = {
port.postMessage({topic: "test-init"});
goOffline().then(function() {
info("testing offline error page");
// wait for popupshown
let panel = document.getElementById("social-notification-panel");
ensureEventFired(panel, "popupshown").then(() => {
ensureFrameLoaded(frame).then(() => {
- is(frame.contentDocument.location.href.indexOf("about:socialerror?"), 0, "social error page is showing "+frame.contentDocument.location.href);
+ is(frame.contentDocument.documentURI.indexOf("about:socialerror?mode=tryAgainOnly"), 0, "social error page is showing "+frame.contentDocument.documentURI);
panel.hidePopup();
goOnline().then(next);
});
});
// reload after going offline, wait for unload to open panel
ensureEventFired(frame, "unload").then(() => {
btn.click();
});
--- a/browser/base/content/test/social/browser_social_workercrash.js
+++ b/browser/base/content/test/social/browser_social_workercrash.js
@@ -58,17 +58,17 @@ var tests = {
mm.loadFrameScript(TEST_CONTENT_HELPER, false);
// add an observer for the crash - after it sees the crash we attempt
// a reload.
let observer = new crashObserver(function() {
info("Saw the process crash.")
Services.obs.removeObserver(observer, 'ipc:content-shutdown');
// Add another sidebar load listener - it should be the error page.
onSidebarLoad(function() {
- ok(sbrowser.contentDocument.location.href.indexOf("about:socialerror?")==0, "is on social error page");
+ ok(sbrowser.contentDocument.location.href.indexOf("about:socialerror?mode=workerFailure")==0, "is on social error page");
// after reloading, the sidebar should reload
onSidebarLoad(function() {
// now ping both workers - they should both be alive.
ensureWorkerLoaded(gProviders[0], function() {
ensureWorkerLoaded(gProviders[1], function() {
// and we are done!
next();
});
--- a/browser/base/jar.mn
+++ b/browser/base/jar.mn
@@ -80,16 +80,17 @@ browser.jar:
content/browser/browser-pocket-de.properties (content/browser-pocket-de.properties)
content/browser/browser-pocket-es-ES.properties (content/browser-pocket-es-ES.properties)
content/browser/browser-pocket-ja.properties (content/browser-pocket-ja.properties)
content/browser/browser-pocket-ru.properties (content/browser-pocket-ru.properties)
* content/browser/browser-tabPreviews.xml (content/browser-tabPreviews.xml)
* content/browser/chatWindow.xul (content/chatWindow.xul)
content/browser/tab-content.js (content/tab-content.js)
content/browser/content.js (content/content.js)
+ content/browser/social-content.js (content/social-content.js)
content/browser/defaultthemes/1.footer.jpg (content/defaultthemes/1.footer.jpg)
content/browser/defaultthemes/1.header.jpg (content/defaultthemes/1.header.jpg)
content/browser/defaultthemes/1.icon.jpg (content/defaultthemes/1.icon.jpg)
content/browser/defaultthemes/1.preview.jpg (content/defaultthemes/1.preview.jpg)
content/browser/defaultthemes/2.footer.jpg (content/defaultthemes/2.footer.jpg)
content/browser/defaultthemes/2.header.jpg (content/defaultthemes/2.header.jpg)
content/browser/defaultthemes/2.icon.jpg (content/defaultthemes/2.icon.jpg)
content/browser/defaultthemes/2.preview.jpg (content/defaultthemes/2.preview.jpg)
--- a/browser/modules/PanelFrame.jsm
+++ b/browser/modules/PanelFrame.jsm
@@ -72,16 +72,20 @@ let PanelFrameInternal = {
// work around bug 793057 - by making the panel roughly the final size
// we are more likely to have the anchor in the correct position.
"style": "width: " + width + "px; height: " + height + "px;",
"dynamicresizer": !aSize,
"origin": aOrigin,
"src": aSrc
};
+ if (aType == "social") {
+ attrs["message"] = "true";
+ attrs["messagemanagergroup"] = aType;
+ }
for (let [k, v] of Iterator(attrs)) {
frame.setAttribute(k, v);
}
aParent.appendChild(frame);
} else {
frame.setAttribute("origin", aOrigin);
frame.setAttribute("src", aSrc);
}
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -235,22 +235,16 @@ this.Social = {
// remove the annotation
providerList.splice(providerList.indexOf(origin), 1);
promiseSetAnnotation(aURI, providerList).then(function() {
if (aCallback)
schedule(function() { aCallback(false); } );
}).then(null, Cu.reportError);
}
}).then(null, Cu.reportError);
- },
-
- setErrorListener: function(iframe, errorHandler) {
- if (iframe.socialErrorListener)
- return iframe.socialErrorListener;
- return new SocialErrorListener(iframe, errorHandler);
}
};
function schedule(callback) {
Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
}
function CreateSocialStatusWidget(aId, aProvider) {
@@ -317,94 +311,16 @@ function CreateSocialMarkWidget(aId, aPr
node.setAttribute("tooltiptext", menuLabel);
node.setAttribute("observes", "Social:PageShareOrMark");
return node;
}
});
};
-// Error handling class used to listen for network errors in the social frames
-// and replace them with a social-specific error page
-function SocialErrorListener(iframe, errorHandler) {
- this.setErrorMessage = errorHandler;
- this.iframe = iframe;
- iframe.socialErrorListener = this;
- // Force a layout flush by calling .clientTop so that the docShell of this
- // frame is created for the error listener
- iframe.clientTop;
- iframe.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebProgress)
- .addProgressListener(this,
- Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
- Ci.nsIWebProgress.NOTIFY_LOCATION);
-}
-
-SocialErrorListener.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
- Ci.nsISupportsWeakReference,
- Ci.nsISupports]),
-
- remove: function() {
- this.iframe.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebProgress)
- .removeProgressListener(this);
- delete this.iframe.socialErrorListener;
- },
-
- onStateChange: function SPL_onStateChange(aWebProgress, aRequest, aState, aStatus) {
- let failure = false;
- if ((aState & Ci.nsIWebProgressListener.STATE_STOP)) {
- if (aRequest instanceof Ci.nsIHttpChannel) {
- try {
- // Change the frame to an error page on 4xx (client errors)
- // and 5xx (server errors). responseStatus throws if it is not set.
- failure = aRequest.responseStatus >= 400 &&
- aRequest.responseStatus < 600;
- } catch (e) {
- failure = aStatus == Components.results.NS_ERROR_CONNECTION_REFUSED;
- }
- }
- }
-
- // Calling cancel() will raise some OnStateChange notifications by itself,
- // so avoid doing that more than once
- if (failure && aStatus != Components.results.NS_BINDING_ABORTED) {
- aRequest.cancel(Components.results.NS_BINDING_ABORTED);
- let origin = this.iframe.getAttribute("origin");
- if (origin) {
- let provider = Social._getProviderFromOrigin(origin);
- provider.errorState = "content-error";
- }
- this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler);
- }
- },
-
- onLocationChange: function SPL_onLocationChange(aWebProgress, aRequest, aLocation, aFlags) {
- if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
- aRequest.cancel(Components.results.NS_BINDING_ABORTED);
- let origin = this.iframe.getAttribute("origin");
- if (origin) {
- let provider = Social._getProviderFromOrigin(origin);
- if (!provider.errorState)
- provider.errorState = "content-error";
- }
- schedule(function() {
- this.setErrorMessage(aWebProgress.QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler);
- }.bind(this));
- }
- },
-
- onProgressChange: function SPL_onProgressChange() {},
- onStatusChange: function SPL_onStatusChange() {},
- onSecurityChange: function SPL_onSecurityChange() {},
-};
-
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.
--- a/toolkit/components/social/MozSocialAPI.jsm
+++ b/toolkit/components/social/MozSocialAPI.jsm
@@ -293,26 +293,18 @@ function getChromeWindow(contentWin) {
this.openChatWindow =
function openChatWindow(contentWindow, provider, url, callback, mode) {
let fullURI = provider.resolveUri(url);
if (!provider.isSameOrigin(fullURI)) {
Cu.reportError("Failed to open a social chat window - the requested URL is not the same origin as the provider.");
return;
}
- let thisCallback = function(chatbox) {
- // All social chat windows get a special error listener.
- Social.setErrorListener(chatbox.content, function(aBrowser) {
- aBrowser.webNavigation.loadURI("about:socialerror?mode=compactInfo&origin=" +
- encodeURIComponent(aBrowser.getAttribute("origin")),
- null, null, null, null);
- });
- }
let chatbox = Chat.open(contentWindow, provider.origin, provider.name,
- fullURI.spec, mode, undefined, thisCallback);
+ fullURI.spec, mode);
if (callback) {
chatbox.promiseChatLoaded.then(() => {
callback(chatbox.contentWindow);
});
}
}
this.closeAllChatWindows = function closeAllChatWindows(provider) {