Bug 1106932 - allow opening the loop panel from the menu, focus the panel immediately, r=mikedeboer
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Thu, 01 Oct 2015 15:56:41 -0400
changeset 265665 58acf8a0176e5cc381e33814140750fb781b72be
parent 265664 616c04d4e5a1d7e46033447078bb73bb17e3a653
child 265666 10aec9211e477521da35fa265777d8ecd732a18d
child 265773 2308353160d2c7b75d6471874af62c965159e2ee
push id15477
push usergijskruitbosch@gmail.com
push dateFri, 02 Oct 2015 13:56:34 +0000
treeherderfx-team@58acf8a0176e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmikedeboer
bugs1106932
milestone44.0a1
Bug 1106932 - allow opening the loop panel from the menu, focus the panel immediately, r=mikedeboer
browser/base/content/browser-loop.js
browser/base/content/browser-menubar.inc
browser/locales/en-US/chrome/browser/browser.dtd
--- a/browser/base/content/browser-loop.js
+++ b/browser/base/content/browser-loop.js
@@ -55,45 +55,59 @@ var LoopUI;
       return selectedTab && selectedTab.getAttribute("data-tab-name");
     },
 
     /**
      * @return {Promise}
      */
     promiseDocumentVisible(aDocument) {
       if (!aDocument.hidden) {
-        return Promise.resolve();
+        return Promise.resolve(aDocument);
       }
 
       return new Promise((resolve) => {
         aDocument.addEventListener("visibilitychange", function onVisibilityChanged() {
           aDocument.removeEventListener("visibilitychange", onVisibilityChanged);
-          resolve();
+          resolve(aDocument);
         });
       });
     },
 
     /**
      * Toggle between opening or hiding the Loop panel.
      *
      * @param {DOMEvent} [event] Optional event that triggered the call to this
      *                           function.
      * @param {String}   [tabId] Optional name of the tab to select after the panel
      *                           has opened. Does nothing when the panel is hidden.
      * @return {Promise}
      */
     togglePanel: function(event, tabId = null) {
+      if (!this.panel) {
+        // We're on the hidden window! What fun!
+        let obs = win => {
+          Services.obs.removeObserver(obs, "browser-delayed-startup-finished");
+          win.LoopUI.togglePanel(event, tabId);
+        };
+        Services.obs.addObserver(obs, "browser-delayed-startup-finished", false);
+        return OpenBrowserWindow();
+      }
       if (this.panel.state == "open") {
         return new Promise(resolve => {
           this.panel.hidePopup();
           resolve();
         });
       }
 
-      return this.openCallPanel(event, tabId);
+      return this.openCallPanel(event, tabId).then(doc => {
+        let fm = Services.focus;
+        fm.moveFocus(doc.defaultView, null, fm.MOVEFOCUS_FIRST, fm.FLAG_NOSCROLL);
+      }).catch(err => {
+        Cu.reportError(x);
+      });
     },
 
     /**
      * Opens the panel for Loop and sizes it appropriately.
      *
      * @param {event}  event   The event opening the panel, used to anchor
      *                         the panel to the button which triggers it.
      * @param {String} [tabId] Identifier of the tab to select when the panel is
@@ -125,40 +139,42 @@ var LoopUI;
           // for the content to load - because it's already there.
           if (("contentWindow" in iframe) && iframe.contentWindow.document.readyState == "complete") {
             showTab();
             return;
           }
 
           let documentDOMLoaded = () => {
             iframe.removeEventListener("DOMContentLoaded", documentDOMLoaded, true);
-  	    this.injectLoopAPI(iframe.contentWindow);
-  	    iframe.contentWindow.addEventListener("loopPanelInitialized", function loopPanelInitialized() {
+            this.injectLoopAPI(iframe.contentWindow);
+            iframe.contentWindow.addEventListener("loopPanelInitialized", function loopPanelInitialized() {
               iframe.contentWindow.removeEventListener("loopPanelInitialized",
-                                                       loopPanelInitialized);
+                loopPanelInitialized);
               showTab();
-	    });
-	  };
-	  iframe.addEventListener("DOMContentLoaded", documentDOMLoaded, true); 
+            });
+          };
+          iframe.addEventListener("DOMContentLoaded", documentDOMLoaded, true);
         };
 
         // Used to clear the temporary "login" state from the button.
         Services.obs.notifyObservers(null, "loop-status-changed", null);
 
         this.shouldResumeTour().then((resume) => {
           if (resume) {
             // Assume the conversation with the visitor wasn't open since we would
             // have resumed the tour as soon as the visitor joined if it was (and
             // the pref would have been set to false already.
             this.MozLoopService.resumeTour("waiting");
             resolve();
             return;
           }
 
-          this.PanelFrame.showPopup(window, event ? event.target : this.toolbarButton.node,
+          let anchor = event ? event.target : this.toolbarButton.anchor;
+
+          this.PanelFrame.showPopup(window, anchor,
             "loop", null, "about:looppanel",
             // Loop wants a fixed size for the panel. This also stops it dynamically resizing.
             { width: 330, height: 410 },
             callback);
         });
       });
     },
 
--- a/browser/base/content/browser-menubar.inc
+++ b/browser/base/content/browser-menubar.inc
@@ -502,16 +502,22 @@
                         label="&addons.label;"
                         accesskey="&addons.accesskey;"
                         key="key_openAddons"
                         command="Tools:Addons"/>
               <menuitem id="menu_openApps"
                         label="&webapps.label;"
                         accesskey="&webapps.accesskey;"
                         oncommand="BrowserOpenApps();"/>
+
+              <menuitem id="menu_openLoop"
+                        label="&loopMenuItem.label;"
+                        accesskey = "&loopMenuItem.accesskey;"
+                        oncommand="LoopUI.togglePanel();"/>
+
 #ifdef MOZ_SERVICES_SYNC
               <!-- only one of sync-setup, sync-syncnowitem or sync-reauthitem will be showing at once -->
               <menuitem id="sync-setup"
                         label="&syncSignIn.label;"
                         accesskey="&syncSignIn.accesskey;"
                         observes="sync-setup-state"
                         oncommand="gSyncUI.openSetup(null, 'menubar')"/>
               <menuitem id="sync-syncnowitem"
--- a/browser/locales/en-US/chrome/browser/browser.dtd
+++ b/browser/locales/en-US/chrome/browser/browser.dtd
@@ -224,16 +224,18 @@ These should match what Safari and other
 <!ENTITY downloads.accesskey          "D">
 <!ENTITY downloads.commandkey         "j">
 <!ENTITY downloadsUnix.commandkey     "y">
 <!ENTITY addons.label                 "Add-ons">
 <!ENTITY addons.accesskey             "A">
 <!ENTITY addons.commandkey            "A">
 <!ENTITY webapps.label                "Apps">
 <!ENTITY webapps.accesskey            "p">
+<!ENTITY loopMenuItem.label           "Start a conversation…">
+<!ENTITY loopMenuItem.accesskey       "t">
 
 <!ENTITY webDeveloperMenu.label       "Web Developer">
 <!ENTITY webDeveloperMenu.accesskey   "W">
 
 <!ENTITY devToolsCmd.keycode          "VK_F12">
 <!ENTITY devToolsCmd.keytext          "F12">
 
 <!ENTITY devtoolsConnect.label        "Connect…">