Bug 784535 - enable opening chats from worker. r=jaws
authorShane Caraveo
Sun, 26 Aug 2012 16:51:24 -0700
changeset 105568 5dbb817a449c00c557a0691b0e7b3af2a611e38d
parent 105567 224d02609af4cfd6a046914c0e8784605e0c6b9e
child 105569 7ca10f967b059335645909eea2dbb32ca3adbd5e
push id55
push usershu@rfrn.org
push dateThu, 30 Aug 2012 01:33:09 +0000
reviewersjaws
bugs784535
milestone17.0a1
Bug 784535 - enable opening chats from worker. r=jaws
browser/base/content/browser-social.js
browser/base/content/socialchat.xml
browser/base/content/test/browser_social_chatwindow.js
browser/base/content/test/browser_social_mozSocial_API.js
browser/base/content/test/social_sidebar.html
browser/base/content/test/social_worker.js
toolkit/components/social/MozSocialAPI.jsm
toolkit/components/social/WorkerAPI.jsm
--- a/browser/base/content/browser-social.js
+++ b/browser/base/content/browser-social.js
@@ -167,19 +167,19 @@ let SocialChatBar = {
   },
   // Whether the chats can be shown for this window.
   get canShow() {
     let docElem = document.documentElement;
     let chromeless = docElem.getAttribute("disablechrome") ||
                      docElem.getAttribute("chromehidden").indexOf("extrachrome") >= 0;
     return Social.uiVisible && !chromeless;
   },
-  newChat: function(aProvider, aURL, aCallback) {
+  openChat: function(aProvider, aURL, aCallback, aMode) {
     if (this.canShow)
-      this.chatbar.newChat(aProvider, aURL, aCallback);
+      this.chatbar.openChat(aProvider, aURL, aCallback, aMode);
   },
   update: function() {
     if (!this.canShow)
       this.chatbar.removeAll();
   }
 }
 
 function sizeSocialPanelToContent(iframe) {
--- a/browser/base/content/socialchat.xml
+++ b/browser/base/content/socialchat.xml
@@ -130,16 +130,17 @@
         <getter>
           return document.getAnonymousElementByAttribute(this, "anonid", "spacer").boxObject.width;
         </getter>
       </property>
 
       <field name="selectedChat"/>
 
       <field name="menuitemMap">new WeakMap()</field>
+      <field name="chatboxForURL">new Map();</field>
 
       <property name="firstCollapsedChild">
         <getter><![CDATA[
           let child = this.lastChild;
           while (child && !child.collapsed) {
             child = child.previousSibling;
           }
           return child;
@@ -235,36 +236,55 @@
       <method name="remove">
         <parameter name="aChatbox"/>
         <body><![CDATA[
           if (this.selectedChat == aChatbox) {
             this.selectedChat = aChatbox.previousSibling ? aChatbox.previousSibling : aChatbox.nextSibling
           }
           this.removeChild(aChatbox);
           this.resize();
+          this.chatboxForURL.delete(aChatbox.getAttribute('src'));
         ]]></body>
       </method>
 
       <method name="removeAll">
         <body><![CDATA[
           while (this.firstChild) {
             this.removeChild(this.firstChild);
           }
+          this.chatboxForURL = new Map();
         ]]></body>
       </method>
 
-      <method name="newChat">
+      <method name="openChat">
         <parameter name="aProvider"/>
         <parameter name="aURL"/>
         <parameter name="aCallback"/>
+        <parameter name="aMode"/>
         <body><![CDATA[
-          let cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
+          let cb = this.chatboxForURL.get(aURL);
+          if (cb) {
+            cb = cb.get();
+            if (cb.parentNode) {
+              // ensure this chatbox is visible
+              if (this.selectedChat != cb)
+                this.selectedChat = cb;
+              if (cb.collapsed)
+                this.showChat(cb);
+              return;
+            }
+            this.chatboxForURL.delete(aURL);
+          }
+          cb = document.createElementNS("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", "chatbox");
+          if (aMode == "minimized")
+            cb.minimized = true;
           this.selectedChat = cb;
-          this.appendChild(cb);
+          this.insertBefore(cb, this.firstChild);
           cb.init(aProvider, aURL, aCallback);
+          this.chatboxForURL.set(aURL, Cu.getWeakReference(cb));
         ]]></body>
       </method>
 
     </implementation>
     <handlers>
       <handler event="overflow"><![CDATA[
         // make sure we're not getting an overflow from content
         if (event.originalTarget != this.innerbox)
--- a/browser/base/content/test/browser_social_chatwindow.js
+++ b/browser/base/content/test/browser_social_chatwindow.js
@@ -50,17 +50,17 @@ var tests = {
           break;
         case "got-chatbox-message":
           ok(true, "got chatbox message");
           ok(e.data.result == "ok", "got chatbox windowRef result: "+e.data.result);
           chats.selectedChat.toggle();
           break;
       }
     }
-    port.postMessage({topic: "test-init"});
+    port.postMessage({topic: "test-init", data: { id: 1 }});
   },
   testManyChats: function(next) {
     // open enough chats to overflow the window, then check
     // if the menupopup is visible
     let port = Social.provider.port;
     ok(port, "provider has a port");
     let width = document.documentElement.boxObject.width;
     let numToOpen = (width / 200) + 1;
@@ -82,13 +82,31 @@ var tests = {
           }
           ok(!chats.selectedChat, "chats are all closed");
           next();
           break;
       }
     }
     let num = numToOpen;
     while (num-- > 0) {
-      port.postMessage({topic: "test-chatbox-open"});
+      port.postMessage({topic: "test-chatbox-open", data: { id: num }});
     }
+  },
+  testWorkerChatWindow: function(next) {
+    let port = Social.provider.port;
+    ok(port, "provider has a port");
+    port.onmessage = function (e) {
+      let topic = e.data.topic;
+      switch (topic) {
+        case "got-chatbox-message":
+          ok(true, "got a chat window opened");
+          let chats = document.getElementById("pinnedchats");
+          while (chats.selectedChat) {
+            chats.selectedChat.close();
+          }
+          ok(!chats.selectedChat, "chats are all closed");
+          next();
+          break;
+      }
+    }
+    port.postMessage({topic: "test-worker-chat" });
   }
 }
-
--- a/browser/base/content/test/browser_social_mozSocial_API.js
+++ b/browser/base/content/test/browser_social_mozSocial_API.js
@@ -49,16 +49,17 @@ var tests = {
           if (e.data.result == "shown") {
             ok(true, "panel shown");
             let panel = document.getElementById("social-notification-panel");
             panel.hidePopup();
           } else if (e.data.result == "hidden") {
             ok(true, "panel hidden");
             next();
           }
+          break;
         case "got-sidebar-message":
           // The sidebar message will always come first, since it loads by default
           ok(true, "got sidebar message");
           gotSidebarMessage = true;
           checkNext();
           break;
       }
     }
--- a/browser/base/content/test/social_sidebar.html
+++ b/browser/base/content/test/social_sidebar.html
@@ -7,21 +7,25 @@
         var port = navigator.mozSocial.getWorker().port;
         port.onmessage = function(e) {
           var topic = e.data.topic;
           switch (topic) {
             case "test-flyout-open":
               navigator.mozSocial.openPanel("social_flyout.html");
               break;
             case "test-chatbox-open":
-              navigator.mozSocial.openChatWindow("social_chat.html",
-                function(chatwin) {
-                  port.postMessage({topic: "chatbox-opened",
-                                    result: chatwin ? "ok" : "failed"});
-                });
+              var url = "social_chat.html";
+              var data = e.data.data;
+              if (data && data.id) {
+                url = url + "?id="+data.id;
+              }
+              navigator.mozSocial.openChatWindow(url, function(chatwin) {
+                port.postMessage({topic: "chatbox-opened",
+                                  result: chatwin ? "ok" : "failed"});
+              });
               break;
             case "test-isVisible":
               port.postMessage({topic: "test-isVisible-response",
                                 result: navigator.mozSocial.isVisible});
               break;
           }
         }
         port.postMessage({topic: "sidebar-message", result: "ok"});
--- a/browser/base/content/test/social_worker.js
+++ b/browser/base/content/test/social_worker.js
@@ -1,13 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-let testPort, sidebarPort;
+let testPort, sidebarPort, apiPort;
 
 onconnect = function(e) {
   let port = e.ports[0];
   port.onmessage = function onMessage(event) {
     let topic = event.data.topic;
     switch (topic) {
       case "test-init":
         testPort = port;
@@ -41,35 +41,39 @@ onconnect = function(e) {
           testPort.postMessage({topic:"got-panel-message",
                                 location: event.data.location
                                });
         break;
       case "status-panel-visibility":
         testPort.postMessage({topic:"got-social-panel-visibility", result: event.data.result });
         break;
       case "test-chatbox-open":
-        sidebarPort.postMessage({topic:"test-chatbox-open"});
+        sidebarPort.postMessage( event.data );
         break;
       case "chatbox-message":
         testPort.postMessage({topic:"got-chatbox-message", result: event.data.result});
         break;
       case "chatbox-visibility":
         testPort.postMessage({topic:"got-chatbox-visibility", result: event.data.result});
         break;
       case "test-flyout-open":
         sidebarPort.postMessage({topic:"test-flyout-open"});
         break;
       case "flyout-message":
         testPort.postMessage({topic:"got-flyout-message", result: event.data.result});
         break;
       case "flyout-visibility":
         testPort.postMessage({topic:"got-flyout-visibility", result: event.data.result});
         break;
+      case "test-worker-chat":
+        apiPort.postMessage({topic: "social.request-chat", data: "https://example.com/browser/browser/base/content/test/social_chat.html" });
+        break;
       case "social.initialize":
         // This is the workerAPI port, respond and set up a notification icon.
+        apiPort = port;
         port.postMessage({topic: "social.initialize-response"});
         let profile = {
           portrait: "https://example.com/portrait.jpg",
           userName: "trickster",
           displayName: "Kuma Lisa",
           profileURL: "http://en.wikipedia.org/wiki/Kuma_Lisa"
         };
         port.postMessage({topic: "social.user-profile", data: profile});
--- a/toolkit/components/social/MozSocialAPI.jsm
+++ b/toolkit/components/social/MozSocialAPI.jsm
@@ -193,16 +193,16 @@ function ensureProviderOrigin(provider, 
   if (provider.origin != uri.prePath) {
     Cu.reportError("mozSocial: unable to load new location, " +
                    provider.origin + " != " + uri.prePath);
     return null;
   }
   return fullURL;
 }
 
-function openChatWindow(chromeWindow, provider, url, callback) {
+function openChatWindow(chromeWindow, provider, url, callback, mode) {
   if (!chromeWindow.SocialChatBar)
     return;
   let fullURL = ensureProviderOrigin(provider, url);
   if (!fullURL)
     return;
-  chromeWindow.SocialChatBar.newChat(provider, fullURL, callback);
+  chromeWindow.SocialChatBar.openChat(provider, fullURL, callback, mode);
 }
--- a/toolkit/components/social/WorkerAPI.jsm
+++ b/toolkit/components/social/WorkerAPI.jsm
@@ -6,16 +6,17 @@
 
 "use strict";
 
 const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "getFrameWorkerHandle", "resource://gre/modules/FrameWorker.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "openChatWindow", "resource://gre/modules/MozSocialAPI.jsm");
 
 const EXPORTED_SYMBOLS = ["WorkerAPI"];
 
 function WorkerAPI(provider, port) {
   if (!port)
     throw new Error("Can't initialize WorkerAPI with a null port");
 
   this._provider = provider;
@@ -65,16 +66,20 @@ WorkerAPI.prototype = {
       cookies.forEach(function(aCookie) {
         let [name, value] = aCookie.split("=");
         results.push({name: unescape(name.trim()),
                       value: unescape(value.trim())});
       });
       this._port.postMessage({topic: "social.cookies-get-response",
                               data: results});
     },
+    'social.request-chat': function(data) {
+      let xulWindow = Services.wm.getMostRecentWindow("navigator:browser").getTopWin();
+      openChatWindow(xulWindow, this._provider, data, null, "minimized");
+    },
     'social.notification-create': function(data) {
       let port = this._port;
       let provider = this._provider;
       let {id, type, icon, body, action, actionArgs} = data;
       let alertsService = Cc["@mozilla.org/alerts-service;1"]
                               .getService(Ci.nsIAlertsService);
       function listener(subject, topic, data) {
         if (topic === "alertclickcallback") {