Bug 794640 - Clicking a link in social content panels should close the panel. r=gavin
authorShane Caraveo <scaraveo@mozilla.com>
Mon, 15 Oct 2012 23:58:13 -0700
changeset 110623 6c1d11cdda0addcef124c9cdcea2ded667d249a1
parent 110622 0fb868c93955e29ccbfa5df29fba4ebdf21d5bf9
child 110624 4f8830d30f623af5b0f3d10ab6ca7d9b44204759
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersgavin
bugs794640
milestone19.0a1
Bug 794640 - Clicking a link in social content panels should close the panel. r=gavin
browser/base/content/browser-social.js
browser/base/content/browser.js
browser/base/content/browser.xul
browser/base/content/test/browser_social_flyout.js
browser/base/content/test/social_flyout.html
browser/themes/pinstripe/browser.css
browser/themes/winstripe/browser.css
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -173,16 +173,34 @@ let SocialUI = {
 
   undoActivation: function SocialUI_undoActivation() {
     Social.active = false;
     this.notificationPanel.hidePopup();
   },
 
   haveLoggedInUser: function SocialUI_haveLoggedInUser() {
     return !!(Social.provider && Social.provider.profile && Social.provider.profile.userName);
+  },
+
+  closeSocialPanelForLinkTraversal: function (target, linkNode) {
+    // No need to close the panel if this traversal was not retargeted
+    if (target == "" || target == "_self")
+      return;
+
+    // Check to see whether this link traversal was in a social panel
+    let win = linkNode.ownerDocument.defaultView;
+    let container = win.QueryInterface(Ci.nsIInterfaceRequestor)
+                                  .getInterface(Ci.nsIWebNavigation)
+                                  .QueryInterface(Ci.nsIDocShell)
+                                  .chromeEventHandler;
+    let containerParent = container.parentNode;
+    if (containerParent.classList.contains("social-panel") &&
+        containerParent instanceof Ci.nsIDOMXULPopupElement) {
+      containerParent.hidePopup();
+    }
   }
 }
 
 let SocialChatBar = {
   get chatbar() {
     return document.getElementById("pinnedchats");
   },
   // Whether the chats can be shown for this window.
@@ -622,17 +640,17 @@ var SocialToolbar = {
   get button() {
     return document.getElementById("social-provider-button");
   },
 
   updateButtonHiddenState: function SocialToolbar_updateButtonHiddenState() {
     let tbi = document.getElementById("social-toolbar-item");
     tbi.hidden = !Social.uiVisible;
     if (!SocialUI.haveLoggedInUser()) {
-      let parent = document.getElementById("social-notification-box");
+      let parent = document.getElementById("social-notification-panel");
       while (parent.hasChildNodes())
         parent.removeChild(parent.firstChild);
 
       while (tbi.lastChild != tbi.firstChild)
         tbi.removeChild(tbi.lastChild);
     }
   },
 
@@ -657,17 +675,16 @@ var SocialToolbar = {
   },
 
   updateButton: function SocialToolbar_updateButton() {
     this.updateButtonHiddenState();
     let provider = Social.provider;
     let icons = provider.ambientNotificationIcons;
     let iconNames = Object.keys(icons);
     let iconBox = document.getElementById("social-toolbar-item");
-    let notifBox = document.getElementById("social-notification-box");
     let panel = document.getElementById("social-notification-panel");
     panel.hidden = false;
 
     let command = document.getElementById("Social:ToggleNotifications");
     command.setAttribute("checked", Services.prefs.getBoolPref("social.toast-notifications.enabled"));
 
     const CACHE_PREF_NAME = "social.cached.notificationIcons";
     // provider.profile == undefined means no response yet from the provider
@@ -775,40 +792,39 @@ var SocialToolbar = {
       let labelValue = icon.counter || "";
       // Only update the value attribute if it has changed to reduce layout changes.
       if (!label.hasAttribute("value") || label.getAttribute("value") != labelValue)
         label.setAttribute("value", labelValue);
 
       if (image.getAttribute("src") != icon.iconURL)
         image.setAttribute("src", icon.iconURL);
     }
-    notifBox.appendChild(notificationFrames);
+    panel.appendChild(notificationFrames);
     iconBox.appendChild(iconContainers);
 
     for (let frame of createdFrames) {
       if (frame.docShell) {
         frame.docShell.isActive = false;
         frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
                       .getInterface(Ci.nsIWebProgress)
                       .addProgressListener(new SocialErrorListener("notification-panel"),
                                            Ci.nsIWebProgress.NOTIFY_STATE_REQUEST |
                                            Ci.nsIWebProgress.NOTIFY_LOCATION);
       }
     }
   },
 
   showAmbientPopup: function SocialToolbar_showAmbientPopup(aToolbarButtonBox) {
     let panel = document.getElementById("social-notification-panel");
-    let notifBox = document.getElementById("social-notification-box");
     let notificationFrameId = aToolbarButtonBox.getAttribute("notificationFrameId");
     let notificationFrame = document.getElementById(notificationFrameId);
 
     // Clear dimensions on all browsers so the panel size will
     // only use the selected browser.
-    let frameIter = notifBox.firstElementChild;
+    let frameIter = panel.firstElementChild;
     while (frameIter) {
       frameIter.collapsed = (frameIter != notificationFrame);
       frameIter = frameIter.nextElementSibling;
     }
 
     function dispatchPanelEvent(name) {
       let evt = notificationFrame.contentDocument.createEvent("CustomEvent");
       evt.initCustomEvent(name, true, true, {});
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -3906,16 +3906,22 @@ var XULBrowserWindow = {
       field.label = text;
       field.setAttribute("crop", type == "overLink" ? "center" : "end");
       this.statusText = text;
     }
   },
 
   // Called before links are navigated to to allow us to retarget them if needed.
   onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
+    let target = this._onBeforeLinkTraversal(originalTarget, linkURI, linkNode, isAppTab);
+    SocialUI.closeSocialPanelForLinkTraversal(target, linkNode);
+    return target;
+  },
+
+  _onBeforeLinkTraversal: function(originalTarget, linkURI, linkNode, isAppTab) {
     // Don't modify non-default targets or targets that aren't in top-level app
     // tab docshells (isAppTab will be false for app tab subframes).
     if (originalTarget != "" || !isAppTab)
       return originalTarget;
 
     // External links from within app tabs should always open in new tabs
     // instead of replacing the app tab's page (Bug 575561)
     let linkHost;
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -262,19 +262,17 @@
       </hbox>
     </panel>
 
     <panel id="social-notification-panel"
            class="social-panel"
            type="arrow"
            hidden="true"
            consumeoutsideclicks="true"
-           noautofocus="true">
-      <box id="social-notification-box" flex="1"></box>
-    </panel>
+           noautofocus="true"/>
     <panel id="social-flyout-panel"
            class="social-panel"
            onpopupshown="SocialFlyout.onShown()"
            onpopuphidden="SocialFlyout.onHidden()"
            side="right"
            type="arrow"
            hidden="true"
            noautofocus="true"
--- a/browser/base/content/test/browser_social_flyout.js
+++ b/browser/base/content/test/browser_social_flyout.js
@@ -106,10 +106,45 @@ var tests = {
           }, false);
           is(panel.state, "open", "flyout should be open");
           port.close(); // so we don't get the -visibility message as it hides...
           SocialFlyout.dispatchPanelEvent("socialTest-CloseSelf");
           break;
       }
     }
     port.postMessage({topic: "test-init"});
+  },
+
+  testCloseOnLinkTraversal: function(next) {
+
+    function onTabOpen(event) {
+      gBrowser.tabContainer.removeEventListener("TabOpen", onTabOpen, true);
+      is(panel.state, "closed", "flyout should be closed");
+      ok(true, "Link should open a new tab");
+      executeSoon(function(){
+        gBrowser.removeTab(event.target);
+        next();
+      });
+    }
+
+    let panel = document.getElementById("social-flyout-panel");
+    let port = Social.provider.getWorkerPort();
+    ok(port, "provider has a port");
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "test-init-done":
+          port.postMessage({topic: "test-flyout-open"});
+          break;
+        case "got-flyout-visibility":
+          if (e.data.result == "shown") {
+            // click on our test link
+            is(panel.state, "open", "flyout should be open");
+            gBrowser.tabContainer.addEventListener("TabOpen", onTabOpen, true); 
+            let iframe = panel.firstChild;
+            iframe.contentDocument.getElementById('traversal').click();
+          }
+          break;
+      }
+    }
+    port.postMessage({topic: "test-init"});
   }
 }
--- a/browser/base/content/test/social_flyout.html
+++ b/browser/base/content/test/social_flyout.html
@@ -26,10 +26,12 @@
         var evt = document.createEvent("CustomEvent");
         evt.initCustomEvent("SocialTest-DoneCloseSelf", true, true, {});
         document.documentElement.dispatchEvent(evt);
       }, false);
     </script>
   </head>
   <body style="max-width: 250px;" onload="pingWorker();">
     <p>This is a test social flyout panel.</p>
+    <a id="traversal" href="http://mochi.test">test link</a>
   </body>
 </html>
+
--- a/browser/themes/pinstripe/browser.css
+++ b/browser/themes/pinstripe/browser.css
@@ -4106,17 +4106,16 @@ html|*#gcli-output-frame {
   margin: 4px;
   -moz-margin-start: 0;
 }
 
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
-#social-notification-box,
 .social-panel-frame {
   border-radius: inherit;
 }
 
 /* === end of social toolbar provider menu === */
 
 .chat-status-icon {
   max-height: 16px;
--- a/browser/themes/winstripe/browser.css
+++ b/browser/themes/winstripe/browser.css
@@ -3390,17 +3390,16 @@ html|*#gcli-output-frame {
 #social-statusarea-user[_moz-menuactive] > vbox > #social-statusarea-username {
   text-decoration: underline;
 }
 
 .social-panel > .panel-arrowcontainer > .panel-arrowcontent {
   padding: 0;
 }
 
-#social-notification-box,
 .social-panel-frame {
   border-radius: inherit;
 }
 
 .chat-status-icon {
   max-height: 16px;
   max-width: 16px;
   padding: 0;