Bug 777176 - Preload SocialAPI panels. r=felipe
authorJared Wein <jwein@mozilla.com>
Thu, 16 Aug 2012 18:02:23 -0700
changeset 102593 cd7025e07686ef571e334dddd92233db6a30ef75
parent 102592 96131c46e845084a300bd71fe64115c5d1543244
child 102594 112f7d84d94b88b391c1feee06addeae3a4049d2
push id13541
push userjwein@mozilla.com
push dateFri, 17 Aug 2012 01:02:50 +0000
treeherdermozilla-inbound@cd7025e07686 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfelipe
bugs777176
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 777176 - Preload SocialAPI panels. r=felipe
browser/base/content/browser-social.js
browser/base/content/browser.xul
browser/base/content/test/Makefile.in
browser/base/content/test/browser_social_mozSocial_API.js
browser/base/content/test/browser_social_toolbar.js
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -248,19 +248,16 @@ let SocialShareButton = {
   }
 };
 
 var SocialToolbar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialToolbar_init() {
     document.getElementById("social-provider-image").setAttribute("image", Social.provider.iconURL);
 
-    let notifBrowser = document.getElementById("social-notification-browser");
-    notifBrowser.docShell.isAppTab = true;
-
     let removeItem = document.getElementById("social-remove-menuitem");
     let brandShortName = document.getElementById("bundle_brand").getString("brandShortName");
     let label = gNavigatorBundle.getFormattedString("social.remove.label",
                                                     [brandShortName]);
     let accesskey = gNavigatorBundle.getString("social.remove.accesskey");
     removeItem.setAttribute("label", label);
     removeItem.setAttribute("accesskey", accesskey);
 
@@ -277,16 +274,24 @@ var SocialToolbar = {
   },
 
   get button() {
     return document.getElementById("social-toolbar-button");
   },
 
   updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() {
     this.button.hidden = !Social.uiVisible;
+    if (!Social.provider.profile || !Social.provider.profile.userName) {
+      ["social-notification-box",
+       "social-status-iconbox"].forEach(function removeChildren(parentId) {
+        let parent = document.getElementById(parentId);
+        while(parent.hasChildNodes())
+          parent.removeChild(parent.firstChild);
+      });
+    }
   },
 
   updateProfile: function SocialToolbar_updateProfile() {
     // Profile may not have been initialized yet, since it depends on a worker
     // response. In that case we'll be called again when it's available, via
     // social:profile-changed
     let profile = Social.provider.profile || {};
     let userPortrait = profile.portrait || "chrome://browser/skin/social/social.png";
@@ -301,83 +306,120 @@ var SocialToolbar = {
     } else {
       notLoggedInLabel.hidden = false;
       userNameBtn.hidden = true;
     }
   },
 
   updateButton: function SocialToolbar_updateButton() {
     this.updateButtonHiddenState();
-
     let provider = Social.provider;
-    // if there are no ambient icons, we collapse them in the following loop
     let iconNames = Object.keys(provider.ambientNotificationIcons);
     let iconBox = document.getElementById("social-status-iconbox");
-    for (var i = 0; i < iconBox.childNodes.length; i++) {
-      let iconContainer = iconBox.childNodes[i];
-      if (i > iconNames.length - 1) {
-        iconContainer.collapsed = true;
-        continue;
+    let notifBox = document.getElementById("social-notification-box");
+    let notifBrowsers = document.createDocumentFragment();
+    let iconContainers = document.createDocumentFragment();
+
+    for each(let name in iconNames) {
+      let icon = provider.ambientNotificationIcons[name];
+
+      let notifBrowserId = "social-status-" + icon.name;
+      let notifBrowser = document.getElementById(notifBrowserId);
+      if (!notifBrowser) {
+        notifBrowser = document.createElement("iframe");
+        notifBrowser.setAttribute("type", "content");
+        notifBrowser.setAttribute("id", notifBrowserId);
+        notifBrowsers.appendChild(notifBrowser);
       }
-
-      iconContainer.collapsed = false;
-      let icon = provider.ambientNotificationIcons[iconNames[i]];
-      let iconImage = iconContainer.firstChild;
-      let iconCounter = iconImage.nextSibling;
+      notifBrowser.setAttribute("origin", provider.origin);
+      if (notifBrowser.getAttribute("src") != icon.contentPanel)
+        notifBrowser.setAttribute("src", icon.contentPanel);
 
-      iconImage.setAttribute("contentPanel", icon.contentPanel);
-      iconImage.setAttribute("src", icon.iconURL);
+      let iconId = "social-notification-icon-" + icon.name;
+      let iconContainer = document.getElementById(iconId);
+      let iconImage, iconCounter;
+      if (iconContainer) {
+        iconImage = iconContainer.getElementsByClassName("social-notification-icon-image")[0];
+        iconCounter = iconContainer.getElementsByClassName("social-notification-icon-counter")[0];
+      } else {
+        iconContainer = document.createElement("box");
+        iconContainer.setAttribute("id", iconId);
+        iconContainer.classList.add("social-notification-icon-container");
+        iconContainer.addEventListener("click", function (e) { SocialToolbar.showAmbientPopup(iconContainer); }, false);
 
-      if (iconCounter.firstChild)
-        iconCounter.removeChild(iconCounter.firstChild);
+        iconImage = document.createElement("image");
+        iconImage.classList.add("social-notification-icon-image");
+        iconImage = iconContainer.appendChild(iconImage);
 
-      if (icon.counter) {
-        iconCounter.appendChild(document.createTextNode(icon.counter));
-        iconCounter.collapsed = false;
-      } else {
-        iconCounter.collapsed = true;
+        iconCounter = document.createElement("box");
+        iconCounter.classList.add("social-notification-icon-counter");
+        iconCounter.appendChild(document.createTextNode(""));
+        iconCounter = iconContainer.appendChild(iconCounter);
+
+        iconContainers.appendChild(iconContainer);
       }
+      if (iconImage.getAttribute("src") != icon.iconURL)
+        iconImage.setAttribute("src", icon.iconURL);
+      iconImage.setAttribute("notifBrowserId", notifBrowserId);
+
+      iconCounter.collapsed = !icon.counter;
+      iconCounter.firstChild.textContent = icon.counter || "";
+    }
+    notifBox.appendChild(notifBrowsers);
+    iconBox.appendChild(iconContainers);
+
+    let browserIter = notifBox.firstElementChild;
+    while (browserIter) {
+      browserIter.docShell.isAppTab = true;
+      browserIter = browserIter.nextElementSibling;
     }
   },
 
   showAmbientPopup: function SocialToolbar_showAmbientPopup(iconContainer) {
     let iconImage = iconContainer.firstChild;
     let panel = document.getElementById("social-notification-panel");
-    let notifBrowser = document.getElementById("social-notification-browser");
+    let notifBox = document.getElementById("social-notification-box");
+    let notifBrowser = document.getElementById(iconImage.getAttribute("notifBrowserId"));
 
     panel.hidden = false;
 
     function sizePanelToContent() {
       // FIXME: bug 764787: Maybe we can use nsIDOMWindowUtils.getRootBounds() here?
       // Need to handle dynamic sizing
       let doc = notifBrowser.contentDocument;
+      if (!doc) {
+        return;
+      }
       // "notif" is an implementation detail that we should get rid of
       // eventually
-      let body = doc.getElementById("notif") || (doc.body && doc.body.firstChild);
-      if (!body)
+      let body = doc.getElementById("notif") || doc.body;
+      if (!body || !body.firstChild) {
         return;
-      let h = body.scrollHeight > 0 ? body.scrollHeight : 300;
-      notifBrowser.style.width = body.scrollWidth + "px";
-      notifBrowser.style.height = h + "px";
+      }
+
+      // Clear dimensions on all browsers so the panel size will
+      // only use the selected browser.
+      let browserIter = notifBox.firstElementChild;
+      while (browserIter) {
+        browserIter.hidden = (browserIter != notifBrowser);
+        browserIter = browserIter.nextElementSibling;
+      }
+
+      let [height, width] = [body.firstChild.offsetHeight || 300, 330];
+      notifBrowser.style.width = width + "px";
+      notifBrowser.style.height = height + "px";
     }
 
-    notifBrowser.addEventListener("DOMContentLoaded", function onload() {
-      notifBrowser.removeEventListener("DOMContentLoaded", onload);
-      sizePanelToContent();
-    });
+    sizePanelToContent();
 
     panel.addEventListener("popuphiding", function onpopuphiding() {
       panel.removeEventListener("popuphiding", onpopuphiding);
-      // unload the panel
       SocialToolbar.button.removeAttribute("open");
-      notifBrowser.setAttribute("src", "about:blank");
     });
 
-    notifBrowser.setAttribute("origin", Social.provider.origin);
-    notifBrowser.setAttribute("src", iconImage.getAttribute("contentPanel"));
     this.button.setAttribute("open", "true");
     panel.openPopup(iconImage, "bottomcenter topleft", 0, 0, false, false);
   }
 }
 
 var SocialSidebar = {
   // Called once, after window load, when the Social.provider object is initialized
   init: function SocialSidebar_init() {
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -264,17 +264,17 @@
                 label="&social.sharePopup.undo.label;"
                 accesskey="&social.sharePopup.undo.accesskey;"
                 command="Social:UnsharePage"/>
 #endif
       </hbox>
     </panel>
 
     <panel id="social-notification-panel" type="arrow" hidden="true" noautofocus="true">
-      <browser id="social-notification-browser" type="content" flex="1"/>
+      <box id="social-notification-box" flex="1"></box>
     </panel>
 
     <menupopup id="inspector-node-popup">
       <menuitem id="inspectorHTMLCopyInner"
                 label="&inspectorHTMLCopyInner.label;"
                 accesskey="&inspectorHTMLCopyInner.accesskey;"
                 command="Inspector:CopyInner"/>
       <menuitem id="inspectorHTMLCopyOuter"
@@ -680,31 +680,16 @@
                         type="checkbox"
                         autocheck="false"
                         command="Social:ToggleSidebar"
                         label="&social.toggleSidebar.label;"
                         accesskey="&social.toggleSidebar.accesskey;"/>
             </menupopup>
           </button>
           <hbox id="social-status-iconbox" flex="1">
-            <box class="social-notification-icon-container" collapsed="true"
-                     onclick="SocialToolbar.showAmbientPopup(this);">
-              <image class="social-notification-icon-image"/>
-              <box class="social-notification-icon-counter" collapsed="true"/>
-            </box>
-            <box class="social-notification-icon-container" collapsed="true"
-                     onclick="SocialToolbar.showAmbientPopup(this);">
-              <image class="social-notification-icon-image"/>
-              <box class="social-notification-icon-counter" collapsed="true"/>
-            </box>
-            <box class="social-notification-icon-container" collapsed="true"
-                     onclick="SocialToolbar.showAmbientPopup(this);">
-              <image class="social-notification-icon-image"/>
-              <box class="social-notification-icon-counter" collapsed="true"/>
-            </box>
           </hbox>
         </hbox>
       </toolbaritem>
 
       <toolbaritem id="bookmarks-menu-button-container"
                    class="chromeclass-toolbar-additional"
                    removable="true"
                    title="&bookmarksMenuButton.label;">
--- a/browser/base/content/test/Makefile.in
+++ b/browser/base/content/test/Makefile.in
@@ -59,16 +59,19 @@ endif
 # 480169)
 
 # browser_drag.js is disabled, as it needs to be updated for the new behavior from bug 320638.
 
 # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
 
 # browser_pageInfo.js + feed_tab.html is disabled for leaking (bug 767896)
 
+# browser_social_shareButton.js is disabled for not properly
+#   tearing down the social providers (bug 780010).
+
 _BROWSER_FILES = \
                  head.js \
                  browser_typeAheadFind.js \
                  browser_keywordSearch.js \
                  browser_allTabsPanel.js \
                  browser_alltabslistener.js \
                  browser_bug304198.js \
                  title_test.svg \
@@ -151,17 +154,16 @@ endif
                  browser_bug710878.js \
                  browser_bug719271.js \
                  browser_bug724239.js \
                  browser_bug735471.js \
                  browser_bug743421.js \
                  browser_bug749738.js \
                  browser_bug763468.js \
                  browser_bug767836.js \
-                 browser_social_shareButton.js \
                  browser_canonizeURL.js \
                  browser_customize.js \
                  browser_findbarClose.js \
                  browser_homeDrop.js \
                  browser_keywordBookmarklets.js \
                  browser_contextSearchTabPosition.js \
                  browser_ctrlTab.js \
                  browser_customize_popupNotification.js \
--- a/browser/base/content/test/browser_social_mozSocial_API.js
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -24,17 +24,17 @@ var tests = {
 
     function checkNext() {
       if (iconsReady && gotSidebarMessage)
         triggerIconPanel();
     }
 
     function triggerIconPanel() {
       let statusIcons = document.getElementById("social-status-iconbox");
-      ok(!statusIcons.firstChild.collapsed, "status icon is visible");
+      ok(!statusIcons.firstChild.hidden, "status icon is visible");
       // Click the button to trigger its contentPanel
       let panel = document.getElementById("social-notification-panel");
       EventUtils.synthesizeMouseAtCenter(statusIcons.firstChild, {});
     }
 
     let port = Social.provider.port;
     ok(port, "provider has a port");
     port.postMessage({topic: "test-init"});
--- a/browser/base/content/test/browser_social_toolbar.js
+++ b/browser/base/content/test/browser_social_toolbar.js
@@ -57,16 +57,16 @@ var tests = {
     Social.provider.updateUserProfile({});
     // check dom values
     let portrait = document.getElementById("social-statusarea-user-portrait").getAttribute("src");
     is(portrait, "chrome://browser/skin/social/social.png", "portrait is generic");
     let userButton = document.getElementById("social-statusarea-username");
     ok(userButton.hidden, "username is not visible");
     let ambience = document.getElementById("social-status-iconbox").firstChild;
     while (ambience) {
-      ok(ambience.collapsed, "ambient icon is collapsed");
+      ok(ambience.collapsed, "ambient icon (" + ambience.id + ") is collapsed");
       ambience = ambience.nextSibling;
     }
     
     next();
   }
 }