Bug 1245262 - Long press keyboard shortcut for containers menu r?Gijs draft
authorJonathan Kingston <jkt@mozilla.com>
Tue, 10 Jan 2017 15:06:33 +0000
changeset 458605 20d28539c156cbc7ddcc83e81644bbbb81ade15c
parent 458532 7011ed1427de2b6f075c46cc6f4618d3e9fcd2a4
child 541687 efd76ad2c027154b0d6249ae7fb0a6ece931dfcf
push id40996
push userjkingston@mozilla.com
push dateTue, 10 Jan 2017 16:20:35 +0000
reviewersGijs
bugs1245262
milestone53.0a1
Bug 1245262 - Long press keyboard shortcut for containers menu r?Gijs MozReview-Commit-ID: 43ShHmiH3Uw
browser/app/profile/firefox.js
browser/base/content/browser.js
browser/components/contextualidentity/test/browser/browser_newtabButton.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1420,16 +1420,17 @@ pref("privacy.trackingprotection.ui.enab
 pref("privacy.trackingprotection.ui.enabled", false);
 #endif
 pref("privacy.trackingprotection.introCount", 0);
 pref("privacy.trackingprotection.introURL", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tracking-protection/start/");
 
 // Enable Contextual Identity Containers
 #ifdef NIGHTLY_BUILD
 pref("privacy.userContext.enabled", true);
+pref("privacy.userContext.newTab.timeout", 1000);
 pref("privacy.userContext.ui.enabled", true);
 pref("privacy.usercontext.about_newtab_segregation.enabled", true);
 #else
 pref("privacy.userContext.enabled", false);
 pref("privacy.userContext.ui.enabled", false);
 pref("privacy.usercontext.about_newtab_segregation.enabled", false);
 #endif
 
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -1222,16 +1222,17 @@ var gBrowserInit = {
     Services.obs.addObserver(gXPInstallObserver, "addon-install-blocked", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-origin-blocked", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-failed", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-confirmation", false);
     Services.obs.addObserver(gXPInstallObserver, "addon-install-complete", false);
     window.messageManager.addMessageListener("Browser:URIFixup", gKeywordURIFixup);
 
     BrowserOffline.init();
+    NewTabShortcut.init();
     IndexedDBPromptHelper.init();
 
     if (AppConstants.E10S_TESTING_ONLY)
       gRemoteTabsUI.init();
 
     // Initialize the full zoom setting.
     // We do this before the session restore service gets initialized so we can
     // apply full zoom settings to tabs restored by the session restore service.
@@ -1564,16 +1565,17 @@ var gBrowserInit = {
         Cu.reportError(ex);
       }
 
       if (this.gmpInstallManager) {
         this.gmpInstallManager.uninit();
       }
 
       BrowserOffline.uninit();
+      NewTabShortcut.uninit();
       IndexedDBPromptHelper.uninit();
       LightweightThemeListener.uninit();
       PanelUI.uninit();
       AutoShowBookmarksToolbar.uninit();
     }
 
     // Final window teardown, do this last.
     window.XULBrowserWindow = null;
@@ -1646,16 +1648,19 @@ if (AppConstants.platform == "macosx") {
   };
 
   gBrowserInit.nonBrowserWindowDelayedStartup = function() {
     this._delayedStartupTimeoutId = null;
 
     // initialise the offline listener
     BrowserOffline.init();
 
+    // initialize the new tab shortcut
+    NewTabShortcut.init();
+
     // initialize the private browsing UI
     gPrivateBrowsingUI.init();
 
     // initialize the sync UI
     gSyncUI.init();
 
     if (AppConstants.E10S_TESTING_ONLY) {
       gRemoteTabsUI.init();
@@ -1670,16 +1675,17 @@ if (AppConstants.platform == "macosx") {
     // If nonBrowserWindowDelayedStartup hasn't run yet, we have no work to do -
     // just cancel the pending timeout and return;
     if (this._delayedStartupTimeoutId) {
       clearTimeout(this._delayedStartupTimeoutId);
       return;
     }
 
     BrowserOffline.uninit();
+    NewTabShortcut.uninit();
   };
 }
 
 
 /* Legacy global init functions */
 var BrowserStartup        = gBrowserInit.onLoad.bind(gBrowserInit);
 var BrowserShutdown       = gBrowserInit.onUnload.bind(gBrowserInit);
 
@@ -5927,16 +5933,95 @@ function setStyleDisabled(disabled) {
 var LanguageDetectionListener = {
   init() {
     window.messageManager.addMessageListener("Translation:DocumentState", msg => {
       Translation.documentStateReceived(msg.target, msg.data);
     });
   }
 };
 
+var NewTabShortcut = {
+  init() {
+    let elm = document.getElementById("key_newNavigatorTab");
+
+    this._key = elm.getAttribute("key");
+
+    this._timeout = Services.prefs.getIntPref("privacy.userContext.newTab.timeout");
+
+    this._menupopup = document.getElementById("alltabs-popup");
+
+    window.addEventListener("keydown", this);
+    window.addEventListener("keyup", this);
+  },
+
+  uninint() {
+    if (!Services.prefs.getBoolPref("privacy.userContext.enabled")) {
+      return;
+    }
+
+    window.removeEventListener("keydown", this);
+    window.removeEventListener("keyup", this);
+  },
+
+  handleEvent(event) {
+    let accelKey = AppConstants.platform == "macosx" ? "metaKey" : "ctrlKey";
+    if (event.key != this._key || !event[accelKey]) {
+      this._clearTimer();
+      return;
+    }
+
+    // Lets return early if the userContext is disabled
+    if (!Services.prefs.getBoolPref("privacy.userContext.enabled")) {
+      return false;
+    }
+
+    // Let's see if this is a long press.
+    if (event.type == "keydown" && !this._timer) {
+      if (event.shiftKey) {
+        return;
+      }
+      this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+      this._timer.initWithCallback(this, this._timeout, this._timer.TYPE_ONE_SHOT);
+    } else if (event.type == "keyup") {
+      // Timeout has not expired yet
+      if (this._timer) {
+        this._clearTimer();
+        BrowserOpenTab();
+      }
+    }
+
+    // We suppress the default behavior of accel+T.
+    event.preventDefault();
+  },
+
+  _clearTimer() {
+    if (this._timer) {
+      this._timer.cancel();
+      this._timer = null;
+    }
+  },
+
+  // Timer expired
+  notify() {
+    this._clearTimer();
+    this._openContainerMenu();
+  },
+
+  _openContainerMenu() {
+    let tabbrowser = document.getElementById('tabbrowser-tabs');
+    let newTabOverflowButton = document.getElementById("newtab-popup");
+    let newTabButton = document.getAnonymousElementByAttribute(tabbrowser, "anonid", "newtab-popup");
+
+    if (tabbrowser.getAttribute("overflow") == "true") {
+      newTabOverflowButton.showPopup();
+    } else {
+      newTabButton.showPopup();
+    }
+  }
+};
 
 var BrowserOffline = {
   _inited: false,
 
   // BrowserOffline Public Methods
   init() {
     if (!this._uiElement)
       this._uiElement = document.getElementById("workOfflineMenuitemState");
--- a/browser/components/contextualidentity/test/browser/browser_newtabButton.js
+++ b/browser/components/contextualidentity/test/browser/browser_newtabButton.js
@@ -1,10 +1,13 @@
 "use strict";
 
+const Cu = Components.utils;
+Cu.import("resource://gre/modules/Preferences.jsm");
+
 // Testing that when the user opens the add tab menu and clicks menu items
 // the correct context id is opened
 
 add_task(function* test() {
   yield SpecialPowers.pushPrefEnv({"set": [
       ["privacy.userContext.enabled", true]
   ]});
 
@@ -43,8 +46,29 @@ add_task(function* test_private_mode() {
   let newTab2 = privateDocument.getElementById("new-tab-button");
   // Check to ensure we are talking about the right button
   ok(!!newTab.clientWidth, "new tab button should not be hidden");
   ok(!newTab2.clientWidth, "overflow new tab button should be hidden");
   let popup = privateDocument.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
   ok(!popup, "new tab should not have a popup");
   yield BrowserTestUtils.closeWindow(privateWindow);
 });
+
+add_task(function* test() {
+  yield SpecialPowers.pushPrefEnv({"set": [
+      ["privacy.userContext.enabled", true]
+  ]});
+  let newTabTimeout = Preferences.get("privacy.userContext.newTab.timeout");
+
+  let newTab = document.getElementById('tabbrowser-tabs');
+  let newTabButton = document.getAnonymousElementByAttribute(newTab, "anonid", "tabs-newtab-button");
+  ok(newTabButton, "New tab button exists");
+  ok(!newTabButton.hidden, "New tab button is visible");
+  yield BrowserTestUtils.waitForCondition(() => !!document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup"), "Wait for popup to exist");
+  let popup = document.getAnonymousElementByAttribute(newTab, "anonid", "newtab-popup");
+
+  let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
+  EventUtils.synthesizeKey("t", {accelKey: true, type: 'keydown'}, window);
+  yield new Promise(resolve => setTimeout(resolve, newTabTimeout));
+  EventUtils.synthesizeKey("t", {accelKey: true, type: 'keyup'}, window);
+  yield popupShownPromise;
+  ok(true, "Promise resolved as the menu loaded on longpress");
+});