Bug 795518 - window.close() in social windows should close social panel. r=jaws
authorMark Hammond <mhammond@skippinet.com.au>
Tue, 02 Oct 2012 17:57:20 +1000
changeset 108842 3b58a62ebfd90055b6bb5da3f29790e82917c9a0
parent 108841 13140a27ff09204eb2eb43fe4851cc1cdb3e1fc5
child 108843 6c2462765e83bd944d3e4e325e44449fd196a56a
push id15723
push usermhammond@skippinet.com.au
push dateTue, 02 Oct 2012 07:57:35 +0000
treeherdermozilla-inbound@3b58a62ebfd9 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjaws
bugs795518
milestone18.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 795518 - window.close() in social windows should close social panel. r=jaws
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)