Bug 802435. Unload social sidebar after some timeout. r=gavin
authorJared Wein <jwein@mozilla.com>
Tue, 23 Oct 2012 17:09:59 -0700
changeset 111339 047148d2783ebac91352e900e1e37c55c162a999
parent 111338 332a8a91de0a4f09bd9c594c8ebe8b0da14dd7c8
child 111340 2fe58d68cf8c1f445eb846b23a729d75e4806ece
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersgavin
bugs802435
milestone19.0a1
Bug 802435. Unload social sidebar after some timeout. r=gavin Includes workaround by Felipe to force document to be released from memory. r=gavin
browser/app/profile/firefox.js
browser/base/content/browser-social.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1172,12 +1172,13 @@ pref("pdfjs.previousHandler.alwaysAskBef
 pref("image.mem.max_decoded_image_kb", 256000);
 
 // Example social provider
 pref("social.manifest.facebook", "{\"origin\":\"https://www.facebook.com\",\"name\":\"Facebook Messenger\",\"workerURL\":\"https://www.facebook.com/desktop/fbdesktop2/socialfox/fbworker.js.php\",\"iconURL\":\"data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8%2F9hAAAAX0lEQVQ4jWP4%2F%2F8%2FAyUYTFhHzjgDxP9JxGeQDSBVMxgTbUBCxer%2Fr999%2BQ8DJBuArJksA9A10s8AXIBoA0B%2BR%2FY%2FjD%2BEwoBoA1yT5v3PbdmCE8MAshhID%2FUMoDgzUYIBj0Cgi7ar4coAAAAASUVORK5CYII%3D\",\"sidebarURL\":\"https://www.facebook.com/desktop/fbdesktop2/?socialfox=true\"}");
 // Comma-separated list of nsIURI::prePaths that are allowed to activate
 // built-in social functionality.
 pref("social.activation.whitelist", "https://www.facebook.com");
 pref("social.sidebar.open", true);
+pref("social.sidebar.unload_timeout_ms", 10000);
 pref("social.active", false);
 pref("social.toast-notifications.enabled", true);
 
 pref("dom.identity.enabled", false);
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -877,22 +877,16 @@ 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");
-    // 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);
     this.updateSidebar();
   },
 
   // Whether the sidebar can be shown for this window.
   get canShow() {
     return Social.uiVisible && Social.provider.sidebarURL && !this.chromeless;
   },
 
@@ -912,54 +906,85 @@ var SocialSidebar = {
   dispatchEvent: function(aType, aDetail) {
     let sbrowser = document.getElementById("social-sidebar-browser");
     let evt = sbrowser.contentDocument.createEvent("CustomEvent");
     evt.initCustomEvent(aType, true, true, aDetail ? aDetail : {});
     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");
 
     // 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");
-      // If we're disabled, unload the sidebar content
+      // 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) {
-        sbrowser.removeAttribute("origin");
-        sbrowser.setAttribute("src", "about:blank");
+        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);
           // let load finish, then fire our event
           setTimeout(function () {
             SocialSidebar.dispatchEvent("socialFrameShow");
           }, 0);
         });
       } else {
         this.dispatchEvent("socialFrameShow");
       }
     }
   },
 
+  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");
+    container.appendChild(sbrowser);
+
+    SocialFlyout.unload();
+  },
+
+  _unloadTimeoutId: 0,
+
   setSidebarErrorMessage: function() {
     let sbrowser = document.getElementById("social-sidebar-browser");
     let url = encodeURIComponent(Social.provider.sidebarURL);
     sbrowser.loadURI("about:socialerror?mode=tryAgain&url=" + url, null, null);
   }
 }
 
 // Error handling class used to listen for network errors in the social frames