Bug 795518 - window.close() in social windows should close social panel. r=jaws, a=gavin
authorMark Hammond <mhammond@skippinet.com.au>
Tue, 02 Oct 2012 17:57:20 +1000
changeset 107035 94b299dc86b093007ecf5c629fba99d555be33fb
parent 107034 8b04789c536f790c85fcc1f4552fd834504840e8
child 107036 8971aa08c2fef967869467c58c208bbabd773dc6
push id2196
push usergsharp@mozilla.com
push dateWed, 03 Oct 2012 01:19:02 +0000
treeherdermozilla-aurora@94b299dc86b0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws, gavin
bugs795518
milestone17.0a2
Bug 795518 - window.close() in social windows should close social panel. r=jaws, a=gavin
browser/base/content/test/browser_social_chatwindow.js
browser/base/content/test/browser_social_flyout.js
browser/base/content/test/social_chat.html
browser/base/content/test/social_flyout.html
toolkit/components/social/MozSocialAPI.jsm
--- a/browser/base/content/test/browser_social_chatwindow.js
+++ b/browser/base/content/test/browser_social_chatwindow.js
@@ -111,16 +111,43 @@ var tests = {
           port.close();
           ensureSocialUrlNotRemembered(chatUrl);
           next();
           break;
       }
     }
     port.postMessage({topic: "test-worker-chat", data: chatUrl});
   },
+  testCloseSelf: function(next) {
+    let chats = document.getElementById("pinnedchats");
+    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-chatbox-open"});
+          break;
+        case "got-chatbox-visibility":
+          is(e.data.result, "shown", "chatbox shown");
+          port.close(); // don't want any more visibility messages.
+          let chat = chats.selectedChat;
+          ok(chat.parentNode, "chat has a parent node before it is closed");
+          // ask it to close itself.
+          let doc = chat.iframe.contentDocument;
+          let evt = doc.createEvent("CustomEvent");
+          evt.initCustomEvent("socialTest-CloseSelf", true, true, {});
+          doc.documentElement.dispatchEvent(evt);
+          ok(!chat.parentNode, "chat is now closed");
+          next();
+          break;
+      }
+    }
+    port.postMessage({topic: "test-init", data: { id: 1 }});
+  },
   testCloseOnLogout: function(next) {
     const chatUrl = "https://example.com/browser/browser/base/content/test/social_chat.html";
     let port = Social.provider.getWorkerPort();
     ok(port, "provider has a port");
     port.postMessage({topic: "test-init"});
     port.onmessage = function (e) {
       let topic = e.data.topic;
       switch (topic) {
--- a/browser/base/content/test/browser_social_flyout.js
+++ b/browser/base/content/test/browser_social_flyout.js
@@ -62,18 +62,44 @@ var tests = {
           let iframe = panel.firstChild;
           let cs = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body);
           is(cs.width, "250px", "should be 250px wide");
           iframe.contentDocument.addEventListener("SocialTest-DoneMakeWider", function _doneHandler() {
             iframe.contentDocument.removeEventListener("SocialTest-DoneMakeWider", _doneHandler, false);
             cs = iframe.contentWindow.getComputedStyle(iframe.contentDocument.body);
             is(cs.width, "500px", "should now be 500px wide");
             panel.hidePopup();
+            port.close();
             next();
           }, false);
           SocialFlyout.dispatchPanelEvent("socialTest-MakeWider");
           break;
       }
     }
     port.postMessage({topic: "test-init"});
+  },
+
+  testCloseSelf: function(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":
+          let iframe = panel.firstChild;
+          iframe.contentDocument.addEventListener("SocialTest-DoneCloseSelf", function _doneHandler() {
+            iframe.contentDocument.removeEventListener("SocialTest-DoneCloseSelf", _doneHandler, false);
+            is(panel.state, "closed", "flyout should have closed itself");
+            next();
+          }, 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"});
   }
 }
-
--- a/browser/base/content/test/social_chat.html
+++ b/browser/base/content/test/social_chat.html
@@ -9,14 +9,17 @@
       window.addEventListener("socialFrameShow", function(e) {
         var port = navigator.mozSocial.getWorker().port;
         port.postMessage({topic: "chatbox-visibility", result: "shown"});
       }, false);
       window.addEventListener("socialFrameHide", function(e) {
         var port = navigator.mozSocial.getWorker().port;
         port.postMessage({topic: "chatbox-visibility", result: "hidden"});
       }, false);
+      window.addEventListener("socialTest-CloseSelf", function(e) {
+        window.close();
+      }, false);
     </script>
   </head>
   <body onload="pingWorker();">
     <p>This is a test social chat window.</p>
   </body>
 </html>
--- a/browser/base/content/test/social_flyout.html
+++ b/browser/base/content/test/social_flyout.html
@@ -16,14 +16,20 @@
       }, false);
       window.addEventListener("socialTest-MakeWider", function(e) {
         document.body.setAttribute("style", "width: 500px;");
         document.body.offsetWidth; // force a layout flush
         var evt = document.createEvent("CustomEvent");
         evt.initCustomEvent("SocialTest-DoneMakeWider", true, true, {});
         document.documentElement.dispatchEvent(evt);
       }, false);
+      window.addEventListener("socialTest-CloseSelf", function(e) {
+        window.close();
+        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>
   </body>
 </html>
--- a/toolkit/components/social/MozSocialAPI.jsm
+++ b/toolkit/components/social/MozSocialAPI.jsm
@@ -169,16 +169,40 @@ function attachToWindow(provider, target
   });
 
   targetWindow.addEventListener("unload", function () {
     // We want to close the port, but also want the target window to be
     // able to use the port during an unload event they setup - so we
     // set a timer which will fire after the unload events have all fired.
     schedule(function () { port.close(); });
   });
+  targetWindow.addEventListener("DOMWindowClose", function _mozSocialDOMWindowClose(evt) {
+    let elt = targetWindow.QueryInterface(Ci.nsIInterfaceRequestor)
+                .getInterface(Ci.nsIWebNavigation)
+                .QueryInterface(Ci.nsIDocShell)
+                .chromeEventHandler;
+    while (elt) {
+      if (elt.nodeName == "panel") {
+        elt.hidePopup();
+        break;
+      } else if (elt.nodeName == "chatbox") {
+        elt.close();
+        break;
+      }
+      elt = elt.parentNode;
+    }
+    // preventDefault stops the default window.close() function being called,
+    // which doesn't actually close anything but causes things to get into
+    // a bad state (an internal 'closed' flag is set and debug builds start
+    // asserting as the window is used.).
+    // None of the windows we inject this API into are suitable for this
+    // default close behaviour, so even if we took no action above, we avoid
+    // the default close from doing anything.
+    evt.preventDefault();
+  }, true);
 }
 
 function schedule(callback) {
   Services.tm.mainThread.dispatch(callback, Ci.nsIThread.DISPATCH_NORMAL);
 }
 
 function getChromeWindow(contentWin) {
   return contentWin.QueryInterface(Ci.nsIInterfaceRequestor)