Bug 806038. Sidebar docShell is not defined after sidebar has been unloaded. r=gavin
authorFelipe Gomes <felipc@gmail.com>
Mon, 29 Oct 2012 20:52:56 -0700
changeset 111866 215b45694fffdf0aa0beaca528f7c5f4ee3ea16b
parent 111865 dd6b5dcd73c35a6e0e79dafcee3c391544206a4b
child 111867 dd59fc450c806991f402f37b822c921fe0b90dec
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersgavin
bugs806038
milestone19.0a1
Bug 806038. Sidebar docShell is not defined after sidebar has been unloaded. r=gavin
browser/base/content/browser-social.js
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -897,19 +897,31 @@ var SocialToolbar = {
                                              encodeURIComponent(src), null, null, null, null);
     sizeSocialPanelToContent(aNotificationFrame);
   }
 }
 
 var SocialSidebar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialSidebar_init() {
+    let sbrowser = document.getElementById("social-sidebar-browser");
+    this.errorListener = new SocialErrorListener("sidebar");
+    this.configureSidebarDocShell(sbrowser.docShell);
     this.updateSidebar();
   },
 
+  configureSidebarDocShell: function SocialSidebar_configureDocShell(aDocShell) {
+    // setting isAppTab causes clicks on untargeted links to open new tabs
+    aDocShell.isAppTab = true;
+    aDocShell.QueryInterface(Ci.nsIWebProgress)
+             .addProgressListener(SocialSidebar.errorListener,
+                                  Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
+                                  Ci.nsIWebProgress.NOTIFY_LOCATION);
+  },
+
   // Whether the sidebar can be shown for this window.
   get canShow() {
     return Social.uiVisible && Social.provider.sidebarURL && !this.chromeless;
   },
 
   // Whether this is a "chromeless window" (e.g. popup window). We don't show
   // the sidebar in these windows.
   get chromeless() {
@@ -918,20 +930,21 @@ var SocialSidebar = {
            docElem.getAttribute('chromehidden').contains("toolbar");
   },
 
   // Whether the user has toggled the sidebar on (for windows where it can appear)
   get opened() {
     return Services.prefs.getBoolPref("social.sidebar.open") && !document.mozFullScreen;
   },
 
-  dispatchEvent: function(aType, aDetail) {
+  setSidebarVisibilityState: function(aEnabled) {
     let sbrowser = document.getElementById("social-sidebar-browser");
+    sbrowser.docShell.isActive = aEnabled;
     let evt = sbrowser.contentDocument.createEvent("CustomEvent");
-    evt.initCustomEvent(aType, true, true, aDetail ? aDetail : {});
+    evt.initCustomEvent(aEnabled ? "socialFrameShow" : "socialFrameHide", true, true, {});
     sbrowser.contentDocument.documentElement.dispatchEvent(evt);
   },
 
   updateSidebar: function SocialSidebar_updateSidebar() {
     clearTimeout(this._unloadTimeoutId);
     // Hide the toggle menu item if the sidebar cannot appear
     let command = document.getElementById("Social:ToggleSidebar");
     command.setAttribute("hidden", this.canShow ? "false" : "true");
@@ -939,65 +952,71 @@ var SocialSidebar = {
     // Hide the sidebar if it cannot appear, or has been toggled off.
     // Also set the command "checked" state accordingly.
     let hideSidebar = !this.canShow || !this.opened;
     let broadcaster = document.getElementById("socialSidebarBroadcaster");
     broadcaster.hidden = hideSidebar;
     command.setAttribute("checked", !hideSidebar);
 
     let sbrowser = document.getElementById("social-sidebar-browser");
-    sbrowser.docShell.isActive = !hideSidebar;
     if (hideSidebar) {
-      this.dispatchEvent("socialFrameHide");
+      this.setSidebarVisibilityState(false);
       // If we've been disabled, unload the sidebar content immediately;
       // if the sidebar was just toggled to invisible, wait a timeout
       // before unloading.
       if (!this.canShow) {
         this.unloadSidebar();
       } else {
         this._unloadTimeoutId = setTimeout(
           this.unloadSidebar,
           Services.prefs.getIntPref("social.sidebar.unload_timeout_ms")
         );
       }
     } else {
       // Make sure the right sidebar URL is loaded
       if (sbrowser.getAttribute("origin") != Social.provider.origin) {
         sbrowser.setAttribute("origin", Social.provider.origin);
-        // setting isAppTab causes clicks on untargeted links to open new tabs
-        sbrowser.docShell.isAppTab = true;
-        sbrowser.webProgress.addProgressListener(new SocialErrorListener("sidebar"),
-                                                 Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
-                                                 Ci.nsIWebProgress.NOTIFY_LOCATION);
         sbrowser.setAttribute("src", Social.provider.sidebarURL);
         sbrowser.addEventListener("load", function sidebarOnShow() {
-          sbrowser.removeEventListener("load", sidebarOnShow);
+          sbrowser.removeEventListener("load", sidebarOnShow, true);
           // let load finish, then fire our event
           setTimeout(function () {
-            SocialSidebar.dispatchEvent("socialFrameShow");
+            SocialSidebar.setSidebarVisibilityState(true);
           }, 0);
-        });
+        }, true);
       } else {
-        this.dispatchEvent("socialFrameShow");
+        this.setSidebarVisibilityState(true);
       }
     }
   },
 
   unloadSidebar: function SocialSidebar_unloadSidebar() {
     let sbrowser = document.getElementById("social-sidebar-browser");
     if (!sbrowser.hasAttribute("origin"))
       return;
 
     // Bug 803255 - If we don't remove the sidebar browser from the DOM,
     // the previous document leaks because it's only released when the
     // sidebar is made visible again.
     let container = sbrowser.parentNode;
     container.removeChild(sbrowser);
     sbrowser.removeAttribute("origin");
     sbrowser.removeAttribute("src");
+
+    function resetDocShell(docshellSupports) {
+      let docshell = docshellSupports.QueryInterface(Ci.nsIDocShell);
+      if (docshell.chromeEventHandler != sbrowser)
+        return;
+
+      SocialSidebar.configureSidebarDocShell(docshell);
+
+      Services.obs.removeObserver(resetDocShell, "webnavigation-create");
+    }
+    Services.obs.addObserver(resetDocShell, "webnavigation-create", false);
+
     container.appendChild(sbrowser);
 
     SocialFlyout.unload();
   },
 
   _unloadTimeoutId: 0,
 
   setSidebarErrorMessage: function() {