Bug 1026444 - Fix error pages in social panels. r=markh, a=lsblakk
authorShane Caraveo <scaraveo@mozilla.com>
Fri, 19 Dec 2014 12:41:09 -0800
changeset 234494 1e3eeb02017caba8544c0b268198cd20af1ce24d
parent 234493 1facdf833813c50b9c0db986eea67924f3093ccd
child 234495 52b319921de39783361913463ebd84f2cbbfbd18
push id7402
push userryanvm@gmail.com
push dateTue, 23 Dec 2014 17:46:27 +0000
treeherdermozilla-aurora@52b319921de3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmarkh, lsblakk
bugs1026444
milestone36.0a2
Bug 1026444 - Fix error pages in social panels. r=markh, a=lsblakk
browser/base/content/browser-social.js
browser/base/content/socialmarks.xml
browser/base/content/test/social/browser_social_errorPage.js
browser/base/content/test/social/browser_social_marks.js
browser/base/content/test/social/browser_social_status.js
browser/base/content/test/social/head.js
browser/modules/Social.jsm
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -418,19 +418,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);
-      // Force a layout flush by calling .clientTop so
-      // that the docShell of this frame is created
-      iframe.clientTop;
       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();
     }
@@ -1294,37 +1291,38 @@ SocialStatus = {
       // if there is a badge value, we must use a localizable string to insert it.
       if (badge)
         ariaLabel = gNavigatorBundle.getFormattedString("social.aria.toolbarButtonBadgeText",
                                                         [ariaLabel, badge]);
       button.setAttribute("aria-label", ariaLabel);
     }
   },
 
-  _onclose: function() {
-    let notificationFrameId = "social-status-" + origin;
-    let frame = document.getElementById(notificationFrameId);
+  _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", this._onclose, true);
+                          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;
 
--- a/browser/base/content/socialmarks.xml
+++ b/browser/base/content/socialmarks.xml
@@ -199,28 +199,50 @@
             if (this.isMarked) {
               Social.markURI(provider.origin, gBrowser.currentURI);
             } else {
               Social.unmarkURI(provider.origin, gBrowser.currentURI, () => {
                 this.update();
               });
             }
           }.bind(this);
-          contentWindow.addEventListener("socialMarkUpdate", markUpdate);
-          contentWindow.addEventListener("unload", function unload() {
+          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
@@ -6,57 +6,16 @@ function gc() {
   Cu.forceGC();
   let wu =  window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
                   .getInterface(Components.interfaces.nsIDOMWindowUtils);
   wu.garbageCollect();
 }
 
 let openChatWindow = Cu.import("resource://gre/modules/MozSocialAPI.jsm", {}).openChatWindow;
 
-// Support for going on and offline.
-// (via browser/base/content/test/browser_bookmark_titles.js)
-let origProxyType = Services.prefs.getIntPref('network.proxy.type');
-
-function toggleOfflineStatus(goOffline) {
-  // Bug 968887 fix.  when going on/offline, wait for notification before continuing
-  let deferred = Promise.defer();
-  if (!goOffline) {
-    Services.prefs.setIntPref('network.proxy.type', origProxyType);
-  }
-  if (goOffline != Services.io.offline) {
-    info("initial offline state " + Services.io.offline);
-    let expect = !Services.io.offline;
-    Services.obs.addObserver(function offlineChange(subject, topic, data) {
-      Services.obs.removeObserver(offlineChange, "network:offline-status-changed");
-      info("offline state changed to " + Services.io.offline);
-      is(expect, Services.io.offline, "network:offline-status-changed successful toggle");
-      deferred.resolve();
-    }, "network:offline-status-changed", false);
-    BrowserOffline.toggleOfflineStatus();
-  } else {
-    deferred.resolve();
-  }
-  if (goOffline) {
-    Services.prefs.setIntPref('network.proxy.type', 0);
-    // LOAD_FLAGS_BYPASS_CACHE isn't good enough. So clear the cache.
-    Services.cache2.clear();
-  }
-  return deferred.promise;
-}
-
-function goOffline() {
-  // Simulate a network outage with offline mode. (Localhost is still
-  // accessible in offline mode, so disable the test proxy as well.)
-  return toggleOfflineStatus(true);
-}
-
-function goOnline(callback) {
-  return toggleOfflineStatus(false);
-}
-
 function openPanel(url, panelCallback, loadCallback) {
   // open a flyout
   SocialFlyout.open(url, 0, panelCallback);
   // wait for both open and loaded before callback. Since the test doesn't close
   // the panel between opens, we cannot rely on events here. We need to ensure
   // popupshown happens before we finish out the tests.
   waitForCondition(function() {
                     return SocialFlyout.panel.state == "open" &&
--- a/browser/base/content/test/social/browser_social_marks.js
+++ b/browser/base/content/test/social/browser_social_marks.js
@@ -82,18 +82,17 @@ var tests = {
       checkSocialUI(window);
       SocialService.disableProvider(manifest2.origin, next);
     });
   },
   testNoButtonOnEnable: function(next) {
     // we expect the addon install dialog to appear, we need to accept the
     // install from the dialog.
     let panel = document.getElementById("servicesInstall-notification");
-    PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
-      PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
+    ensureEventFired(PopupNotifications.panel, "popupshown").then(() => {
       info("servicesInstall-notification panel opened");
       panel.button.click();
     });
 
     let activationURL = manifest3.origin + "/browser/browser/base/content/test/social/social_activate.html"
     addTab(activationURL, function(tab) {
       let doc = tab.linkedBrowser.contentDocument;
       let data = {
@@ -116,18 +115,17 @@ var tests = {
           });
         });
       });
     });
   },
 
   testButtonOnEnable: function(next) {
     let panel = document.getElementById("servicesInstall-notification");
-    PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
-      PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
+    ensureEventFired(PopupNotifications.panel, "popupshown").then(() => {
       info("servicesInstall-notification panel opened");
       panel.button.click();
     });
 
     // enable the provider now
     let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
     addTab(activationURL, function(tab) {
       let doc = tab.linkedBrowser.contentDocument;
@@ -182,51 +180,82 @@ var tests = {
         switch (topic) {
           case "test-init-done":
             ok(true, "test-init-done received");
             ok(provider.profile.userName, "profile was set by test worker");
             // first click marks the page, second click opens the page. We have to
             // synthesize so the command event happens
             EventUtils.synthesizeMouseAtCenter(btn, {});
             // wait for the button to be marked, click to open panel
+            is(btn.panel.state, "closed", "panel should not be visible yet");
             waitForCondition(function() btn.isMarked, function() {
-              is(btn.panel.state, "closed", "panel should not be visible yet");
               EventUtils.synthesizeMouseAtCenter(btn, {});
             }, "button is marked");
             break;
           case "got-social-panel-visibility":
             ok(true, "got the panel message " + e.data.result);
             if (e.data.result == "shown") {
               // unmark the page via the button in the page
-              let doc = btn.contentDocument;
-              let unmarkBtn = doc.getElementById("unmark");
-              ok(unmarkBtn, "got the panel unmark button");
-              EventUtils.sendMouseEvent({type: "click"}, unmarkBtn, btn.contentWindow);
+              ensureFrameLoaded(btn.content).then(() => {
+                let doc = btn.contentDocument;
+                let unmarkBtn = doc.getElementById("unmark");
+                ok(unmarkBtn, "testMarkPanel - got the panel unmark button");
+                EventUtils.sendMouseEvent({type: "click"}, unmarkBtn, btn.contentWindow);
+              });
             } else {
               // page should no longer be marked
               port.close();
               waitForCondition(function() !btn.isMarked, function() {
                 // cleanup after the page has been unmarked
-                gBrowser.tabContainer.addEventListener("TabClose", function onTabClose() {
-                  gBrowser.tabContainer.removeEventListener("TabClose", onTabClose);
-                    executeSoon(function () {
-                      ok(btn.disabled, "button is disabled");
-                      next();
-                    });
+                ensureBrowserTabClosed(tab).then(() => {
+                  ok(btn.disabled, "button is disabled");
+                  next();
                 });
-                gBrowser.removeTab(tab);
               }, "button unmarked");
             }
             break;
         }
       };
       port.postMessage({topic: "test-init"});
     });
   },
 
+  testMarkPanelOffline: function(next) {
+    // click on panel to open and wait for visibility
+    let provider = Social._getProviderFromOrigin(manifest2.origin);
+    ok(provider.enabled, "provider is enabled");
+    let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
+    let widget = CustomizableUI.getWidget(id);
+    let btn = widget.forWindow(window).node;
+    ok(btn, "got a mark button");
+
+    // verify markbutton is disabled when there is no browser url
+    ok(btn.disabled, "button is disabled");
+    let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
+    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");
+            // cleanup after the page has been unmarked
+            ensureBrowserTabClosed(tab).then(() => {
+              ok(btn.disabled, "button is disabled");
+              goOnline().then(next);
+            });
+          });
+        });
+        btn.markCurrentPage();
+      });
+    });
+  },
+
   testMarkPanelLoggedOut: function(next) {
     // click on panel to open and wait for visibility
     let provider = Social._getProviderFromOrigin(manifest2.origin);
     ok(provider.enabled, "provider is enabled");
     let id = SocialMarks._toolbarHelper.idFromOrigin(manifest2.origin);
     let widget = CustomizableUI.getWidget(id);
     let btn = widget.forWindow(window).node;
     ok(btn, "got a mark button");
@@ -254,33 +283,31 @@ var tests = {
                 "profile was unset by test worker");
             break;
           case "got-social-panel-visibility":
             ok(true, "got the panel message " + e.data.result);
             if (e.data.result == "shown") {
               // our test marks the page during the load event (see
               // social_mark.html) regardless of login state, unmark the page
               // via the button in the page
-              let doc = btn.contentDocument;
-              let unmarkBtn = doc.getElementById("unmark");
-              ok(unmarkBtn, "got the panel unmark button");
-              EventUtils.sendMouseEvent({type: "click"}, unmarkBtn, btn.contentWindow);
+              ensureFrameLoaded(btn.content).then(() => {
+                let doc = btn.contentDocument;
+                let unmarkBtn = doc.getElementById("unmark");
+                ok(unmarkBtn, "testMarkPanelLoggedOut - got the panel unmark button");
+                EventUtils.sendMouseEvent({type: "click"}, unmarkBtn, btn.contentWindow);
+              });
             } else {
               // page should no longer be marked
               port.close();
               waitForCondition(function() !btn.isMarked, function() {
                 // cleanup after the page has been unmarked
-                gBrowser.tabContainer.addEventListener("TabClose", function onTabClose() {
-                  gBrowser.tabContainer.removeEventListener("TabClose", onTabClose);
-                    executeSoon(function () {
-                      ok(btn.disabled, "button is disabled");
-                      next();
-                    });
+                ensureBrowserTabClosed(tab).then(() => {
+                  ok(btn.disabled, "button is disabled");
+                  next();
                 });
-                gBrowser.removeTab(tab);
               }, "button unmarked");
             }
             break;
         }
       };
       port.postMessage({topic: "test-init"});
     });
   },
@@ -318,21 +345,20 @@ var tests = {
       let manifest = manifests.pop();
       if (!manifest) {
         info("INSTALLATION FINISHED");
         executeSoon(callback);
         return;
       }
       info("INSTALLING " + manifest.origin);
       let panel = document.getElementById("servicesInstall-notification");
-      PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
-        PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
+      ensureEventFired(PopupNotifications.panel, "popupshown").then(() => {
         info("servicesInstall-notification panel opened");
         panel.button.click();
-      })
+      });
 
       let activationURL = manifest.origin + "/browser/browser/base/content/test/social/social_activate.html"
       let id = SocialMarks._toolbarHelper.idFromOrigin(manifest.origin);
       let toolbar = document.getElementById("nav-bar");
       addTab(activationURL, function(tab) {
         let doc = tab.linkedBrowser.contentDocument;
         let data = {
           origin: doc.nodePrincipal.origin,
--- a/browser/base/content/test/social/browser_social_status.js
+++ b/browser/base/content/test/social/browser_social_status.js
@@ -52,18 +52,17 @@ function test() {
   });
 }
 
 var tests = {
   testNoButtonOnEnable: function(next) {
     // we expect the addon install dialog to appear, we need to accept the
     // install from the dialog.
     let panel = document.getElementById("servicesInstall-notification");
-    PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
-      PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
+    ensureEventFired(PopupNotifications.panel, "popupshown").then(() => {
       info("servicesInstall-notification panel opened");
       panel.button.click();
     })
 
     let activationURL = manifest3.origin + "/browser/browser/base/content/test/social/social_activate.html"
     addTab(activationURL, function(tab) {
       let doc = tab.linkedBrowser.contentDocument;
       let data = {
@@ -84,18 +83,17 @@ var tests = {
             next();
           });
         });
       });
     });
   },
   testButtonOnEnable: function(next) {
     let panel = document.getElementById("servicesInstall-notification");
-    PopupNotifications.panel.addEventListener("popupshown", function onpopupshown() {
-      PopupNotifications.panel.removeEventListener("popupshown", onpopupshown);
+    ensureEventFired(PopupNotifications.panel, "popupshown").then(() => {
       info("servicesInstall-notification panel opened");
       panel.button.click();
     });
 
     // enable the provider now
     let activationURL = manifest2.origin + "/browser/browser/base/content/test/social/social_activate.html"
     addTab(activationURL, function(tab) {
       let doc = tab.linkedBrowser.contentDocument;
@@ -160,16 +158,49 @@ var tests = {
                          next();
                        }, "button updated by notification");
           }
           break;
       }
     };
     port.postMessage({topic: "test-init"});
   },
+
+  testPanelOffline: function(next) {
+    // click on panel to open and wait for visibility
+    let provider = Social._getProviderFromOrigin(manifest2.origin);
+    ok(provider.enabled, "provider is enabled");
+    let id = SocialStatus._toolbarHelper.idFromOrigin(manifest2.origin);
+    let widget = CustomizableUI.getWidget(id);
+    let btn = widget.forWindow(window).node;
+    ok(btn, "got a status button");
+    let frameId = btn.getAttribute("notificationFrameId");
+    let frame = document.getElementById(frameId);
+    let port = provider.getWorkerPort();
+    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);
+          panel.hidePopup();
+          goOnline().then(next);
+        });
+      });
+      // reload after going offline, wait for unload to open panel
+      ensureEventFired(frame, "unload").then(() => {
+        btn.click();
+      });
+      frame.contentDocument.location.reload();
+    });
+  },
+
   testButtonOnDisable: function(next) {
     // enable the provider now
     let provider = Social._getProviderFromOrigin(manifest2.origin);
     ok(provider, "provider is installed");
     SocialService.disableProvider(manifest2.origin, function() {
       let id = SocialStatus._toolbarHelper.idFromOrigin(manifest2.origin);
       waitForCondition(function() { return !document.getElementById(id) },
                        function() {
--- a/browser/base/content/test/social/head.js
+++ b/browser/base/content/test/social/head.js
@@ -390,24 +390,51 @@ function selectBrowserTab(tab, callback)
   gBrowser.tabContainer.addEventListener("TabSelect", function onTabSelect() {
     gBrowser.tabContainer.removeEventListener("TabSelect", onTabSelect, false);
     is(gBrowser.selectedTab, tab, "browser tab is selected");
     executeSoon(function() {callback(tab)});
   });
   gBrowser.selectedTab = tab;
 }
 
+function ensureEventFired(elem, event) {
+  let deferred = Promise.defer();
+  elem.addEventListener(event, function handler() {
+    elem.removeEventListener(event, handler, true);
+    deferred.resolve()
+  }, true);
+  return deferred.promise;
+}
+
 function loadIntoTab(tab, url, callback) {
   tab.linkedBrowser.addEventListener("load", function tabLoad(event) {
     tab.linkedBrowser.removeEventListener("load", tabLoad, true);
     executeSoon(function() {callback(tab)});
   }, true);
   tab.linkedBrowser.loadURI(url);
 }
 
+function ensureBrowserTabClosed(tab) {
+  let promise = ensureEventFired(gBrowser.tabContainer, "TabClose");
+  gBrowser.removeTab(tab);
+  return promise;
+}
+
+function ensureFrameLoaded(frame) {
+  let deferred = Promise.defer();
+  if (frame.contentDocument && frame.contentDocument.readyState == "complete") {
+    deferred.resolve();
+  } else {
+    frame.addEventListener("load", function handler() {
+      frame.removeEventListener("load", handler, true);
+      deferred.resolve()
+    }, true);
+  }
+  return deferred.promise;
+}
 
 // chat test help functions
 
 // And lots of helpers for the resize tests.
 function get3ChatsForCollapsing(mode, cb) {
   // We make one chat, then measure its size.  We then resize the browser to
   // ensure a second can be created fully visible but a third can not - then
   // create the other 2.  first will will be collapsed, second fully visible
@@ -588,8 +615,50 @@ function getPopupWidth() {
 }
 
 function closeAllChats() {
   let chatbar = getChatBar();
   while (chatbar.selectedChat) {
     chatbar.selectedChat.close();
   }
 }
+
+
+// Support for going on and offline.
+// (via browser/base/content/test/browser_bookmark_titles.js)
+let origProxyType = Services.prefs.getIntPref('network.proxy.type');
+
+function toggleOfflineStatus(goOffline) {
+  // Bug 968887 fix.  when going on/offline, wait for notification before continuing
+  let deferred = Promise.defer();
+  if (!goOffline) {
+    Services.prefs.setIntPref('network.proxy.type', origProxyType);
+  }
+  if (goOffline != Services.io.offline) {
+    info("initial offline state " + Services.io.offline);
+    let expect = !Services.io.offline;
+    Services.obs.addObserver(function offlineChange(subject, topic, data) {
+      Services.obs.removeObserver(offlineChange, "network:offline-status-changed");
+      info("offline state changed to " + Services.io.offline);
+      is(expect, Services.io.offline, "network:offline-status-changed successful toggle");
+      deferred.resolve();
+    }, "network:offline-status-changed", false);
+    BrowserOffline.toggleOfflineStatus();
+  } else {
+    deferred.resolve();
+  }
+  if (goOffline) {
+    Services.prefs.setIntPref('network.proxy.type', 0);
+    // LOAD_FLAGS_BYPASS_CACHE isn't good enough. So clear the cache.
+    Services.cache2.clear();
+  }
+  return deferred.promise;
+}
+
+function goOffline() {
+  // Simulate a network outage with offline mode. (Localhost is still
+  // accessible in offline mode, so disable the test proxy as well.)
+  return toggleOfflineStatus(true);
+}
+
+function goOnline(callback) {
+  return toggleOfflineStatus(false);
+}
--- a/browser/modules/Social.jsm
+++ b/browser/modules/Social.jsm
@@ -322,16 +322,19 @@ function CreateSocialMarkWidget(aId, aPr
 };
 
 // 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 = {