Bug 1552627 - r=dveditz
authorGijs Kruitbosch <gijskruitbosch@gmail.com>
Mon, 20 May 2019 06:32:46 +0000
changeset 474475 29d9eb1276a71d4f4f1edefe4b0e720e4b16f952
parent 474474 f798f327a76198fc38ae07358768e556fe126039
child 474476 6fefc560ddc453a3a41dc1048a917f0cc0d69655
push id36040
push userrgurzau@mozilla.com
push dateMon, 20 May 2019 13:43:21 +0000
treeherdermozilla-central@319a369ccde4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdveditz
bugs1552627
milestone68.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 1552627 - r=dveditz Differential Revision: https://phabricator.services.mozilla.com/D31722
toolkit/components/prompts/src/SharedPromptUtils.jsm
toolkit/mozapps/handling/content/dialog.js
toolkit/mozapps/handling/content/dialog.xul
--- a/toolkit/components/prompts/src/SharedPromptUtils.jsm
+++ b/toolkit/components/prompts/src/SharedPromptUtils.jsm
@@ -59,32 +59,53 @@ var EnableDelayHelper = function({enable
     this.enableDialog = makeSafe(enableDialog);
     this.disableDialog = makeSafe(disableDialog);
     this.focusTarget = focusTarget;
 
     this.disableDialog();
 
     this.focusTarget.addEventListener("blur", this);
     this.focusTarget.addEventListener("focus", this);
+    // While the user key-repeats, we want to renew the timer until keyup:
+    this.focusTarget.addEventListener("keyup", this, true);
+    this.focusTarget.addEventListener("keydown", this, true);
     this.focusTarget.document.addEventListener("unload", this);
 
     this.startOnFocusDelay();
 };
 
 this.EnableDelayHelper.prototype = {
     get delayTime() {
         return Services.prefs.getIntPref("security.dialog_enable_delay");
     },
 
     handleEvent(event) {
-        if (event.target != this.focusTarget &&
+        if (!event.type.startsWith("key") &&
+            event.target != this.focusTarget &&
             event.target != this.focusTarget.document)
             return;
 
         switch (event.type) {
+            case "keyup":
+                // As soon as any key goes up, we can stop treating keypresses
+                // as indicative of key-repeating that should prolong the timer.
+                this.focusTarget.removeEventListener("keyup", this, true);
+                this.focusTarget.removeEventListener("keydown", this, true);
+                break;
+
+            case "keydown":
+                // Renew timer for repeating keydowns:
+                if (this._focusTimer) {
+                    this._focusTimer.cancel();
+                    this._focusTimer = null;
+                    this.startOnFocusDelay();
+                    event.preventDefault();
+                }
+                break;
+
             case "blur":
                 this.onBlur();
                 break;
 
             case "focus":
                 this.onFocus();
                 break;
 
@@ -106,16 +127,18 @@ this.EnableDelayHelper.prototype = {
 
     onFocus() {
         this.startOnFocusDelay();
     },
 
     onUnload() {
         this.focusTarget.removeEventListener("blur", this);
         this.focusTarget.removeEventListener("focus", this);
+        this.focusTarget.removeEventListener("keyup", this, true);
+        this.focusTarget.removeEventListener("keydown", this, true);
         this.focusTarget.document.removeEventListener("unload", this);
 
         if (this._focusTimer) {
             this._focusTimer.cancel();
             this._focusTimer = null;
         }
 
         this.focusTarget = this.enableDialog = this.disableDialog = null;
--- a/toolkit/mozapps/handling/content/dialog.js
+++ b/toolkit/mozapps/handling/content/dialog.js
@@ -99,17 +99,17 @@ var dialog = {
       }
       this._windowCtxt.QueryInterface(Ci.nsIInterfaceRequestor);
     }
 
     this.isPrivate = usePrivateBrowsing ||
                      (window.opener && PrivateBrowsingUtils.isWindowPrivate(window.opener));
 
     this._itemChoose  = document.getElementById("item-choose");
-    this._okButton    = document.documentElement.getButton("accept");
+    this._okButton    = document.documentElement.getButton("extra1");
 
     var description = {
       image: document.getElementById("description-image"),
       text:  document.getElementById("description-text"),
     };
     var options = document.getElementById("item-action-text");
     var checkbox = {
       desc: document.getElementById("remember"),
@@ -126,17 +126,19 @@ var dialog = {
     checkbox.text.textContent    = window.arguments[6];
 
     // Hide stuff that needs to be hidden
     if (!checkbox.desc.label)
       checkbox.desc.hidden = true;
 
     // UI is ready, lets populate our list
     this.populateList();
-    document.addEventListener("dialogaccept", () => { this.onAccept(); });
+    // Explicitly not an 'accept' button to avoid having `enter` accept the dialog.
+    document.addEventListener("dialogextra1", () => { this.onOK(); });
+    document.addEventListener("dialogaccept", e => { e.preventDefault(); });
 
     this._delayHelper = new EnableDelayHelper({
       disableDialog: () => {
         this._buttonDisabled = true;
         this.updateOKButton();
       },
       enableDialog: () => {
         this._buttonDisabled = false;
@@ -284,17 +286,20 @@ var dialog = {
         parent.ensureSelectedElementIsVisible();
       }
     });
   },
 
  /**
   * Function called when the OK button is pressed.
   */
-  onAccept: function onAccept() {
+  onOK: function onOK() {
+    if (this._buttonDisabled) {
+      return;
+    }
     var checkbox = document.getElementById("remember");
     if (!checkbox.hidden) {
       // We need to make sure that the default is properly set now
       if (this.selectedItem.obj) {
         // default OS handler doesn't have this property
         this._handlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
         this._handlerInfo.preferredApplicationHandler = this.selectedItem.obj;
       } else {
@@ -303,16 +308,17 @@ var dialog = {
     }
     this._handlerInfo.alwaysAskBeforeHandling = !checkbox.checked;
 
     var hs = Cc["@mozilla.org/uriloader/handler-service;1"].
              getService(Ci.nsIHandlerService);
     hs.store(this._handlerInfo);
 
     this._handlerInfo.launchWithURI(this._URI, this._windowCtxt);
+    window.close();
   },
 
  /**
   * Determines if the OK button should be disabled or not
   */
   updateOKButton: function updateOKButton() {
     this._okButton.disabled = this._itemChoose.selected ||
                               this._buttonDisabled;
@@ -330,17 +336,17 @@ var dialog = {
 
   /**
    * Function called when the user double clicks on an item of the list
    */
   onDblClick: function onDblClick() {
     if (this.selectedItem == this._itemChoose)
       this.chooseApplication();
     else
-      document.documentElement.acceptDialog();
+      this.onOK();
   },
 
   // Getters / Setters
 
  /**
   * Returns/sets the selected element in the richlistbox
   */
   get selectedItem() {
--- a/toolkit/mozapps/handling/content/dialog.xul
+++ b/toolkit/mozapps/handling/content/dialog.xul
@@ -8,16 +8,17 @@
 
 <!DOCTYPE dialog SYSTEM "chrome://mozapps/locale/handling/handling.dtd">
 
 <dialog id="handling"
         onload="dialog.initialize();"
         style="min-width: &window.emWidth;; min-height: &window.emHeight;;"
         persist="width height screenX screenY"
         aria-describedby="description-text"
+        buttons="cancel,extra1"
         xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 
   <script src="chrome://mozapps/content/handling/dialog.js" type="application/javascript"/>
 
   <stringbundleset id="strings">
     <stringbundle id="base-strings"
                   src="chrome://mozapps/locale/handling/handling.properties"/>
   </stringbundleset>
@@ -40,12 +41,12 @@
     </richlistbox>
   </vbox>
 
   <checkbox id="remember" aria-describedby="remember-text" oncommand="dialog.onCheck();"/>
   <description id="remember-text"/>
 
   <hbox class="dialog-button-box" pack="end">
     <button dlgtype="cancel" class="dialog-button"/>
-    <button dlgtype="accept" label="&accept;" class="dialog-button"/>
+    <button dlgtype="extra1" label="&accept;" class="dialog-button"/>
   </hbox>
 
 </dialog>