Bug 1604752 - Port bug 1601708: Return focus to the previously active element when a subdialog closes. r=mkmelin
authorRichard Marti <richard.marti@gmail.com>
Wed, 18 Dec 2019 13:27:49 +0100
changeset 37789 164933b1df705b2545d414840282b2506bf78918
parent 37788 89fbfe35a1f5d2d1aba9b5768752209f8ddc87aa
child 37790 e2bc4de4ca67b44eddfaf6bdc60e3ae7bcd2fff2
push id397
push userclokep@gmail.com
push dateMon, 10 Feb 2020 21:16:13 +0000
reviewersmkmelin
bugs1604752, 1601708
Bug 1604752 - Port bug 1601708: Return focus to the previously active element when a subdialog closes. r=mkmelin
mail/components/preferences/subdialogs.js
--- a/mail/components/preferences/subdialogs.js
+++ b/mail/components/preferences/subdialogs.js
@@ -600,16 +600,17 @@ var gSubDialog = {
    * to the end of the _dialogs array.
    * @type {Array}
    */
   _dialogs: [],
   _dialogStack: null,
   _dialogTemplate: null,
   _nextDialogID: 0,
   _preloadDialog: null,
+  _topLevelPrevActiveElement: null,
   get _topDialog() {
     return this._dialogs.length > 0
       ? this._dialogs[this._dialogs.length - 1]
       : undefined;
   },
 
   init() {
     this._dialogStack = document.getElementById("dialogStack");
@@ -622,20 +623,23 @@ var gSubDialog = {
   },
 
   open(aURL, aFeatures = null, aParams = null, aClosingCallback = null) {
     // If we're already open/opening on this URL, do nothing.
     if (this._topDialog && this._topDialog._openedURL == aURL) {
       return;
     }
 
-    if (this._dialogs.length == 0) {
+    if (this._dialogs.length) {
+      this._topDialog._prevActiveElement = document.activeElement;
+    } else {
       // When opening the first dialog, show the dialog stack to make sure
       // the browser binding can be constructed.
       this._dialogStack.hidden = false;
+      this._topLevelPrevActiveElement = document.activeElement;
     }
 
     this._preloadDialog.open(aURL, aFeatures, aParams, aClosingCallback);
     this._dialogs.push(this._preloadDialog);
     this._preloadDialog = new SubDialog({
       template: this._dialogTemplate,
       parentElement: this._dialogStack,
       id: this._nextDialogID++,
@@ -670,39 +674,33 @@ var gSubDialog = {
         : undefined;
     if (lowerDialog) {
       lowerDialog._overlay.removeAttribute("topmost");
       lowerDialog._removeDialogEventListeners();
     }
   },
 
   _onDialogClose(dialog) {
-    let fm = Services.focus;
     if (this._topDialog == dialog) {
       // XXX: When a top-most dialog is closed, we reuse the closed dialog and
       //      remove the preloadDialog. This is a temporary solution before we
       //      rewrite all the test cases in Bug 1359023.
       this._preloadDialog._overlay.remove();
       this._preloadDialog = this._dialogs.pop();
     } else {
       dialog._overlay.remove();
       this._dialogs.splice(this._dialogs.indexOf(dialog), 1);
     }
 
     if (this._topDialog) {
-      fm.moveFocus(
-        this._topDialog._frame.contentWindow,
-        null,
-        fm.MOVEFOCUS_FIRST,
-        fm.FLAG_BYKEY
-      );
+      this._topDialog._prevActiveElement.focus();
       this._topDialog._overlay.setAttribute("topmost", true);
       this._topDialog._addDialogEventListeners();
     } else {
-      fm.moveFocus(window, null, fm.MOVEFOCUS_ROOT, fm.FLAG_BYKEY);
+      this._topLevelPrevActiveElement.focus();
       this._dialogStack.hidden = true;
       this._removeStackEventListeners();
     }
   },
 
   _ensureStackEventListeners() {
     this._dialogStack.addEventListener("dialogopen", this);
     this._dialogStack.addEventListener("dialogclose", this);