Chromium Code Reviews| Index: chrome/browser/resources/md_bookmarks/dialog_focus_manager.js |
| diff --git a/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..35cd9b5594df0b82b518e505c8e78ec33dabbb29 |
| --- /dev/null |
| +++ b/chrome/browser/resources/md_bookmarks/dialog_focus_manager.js |
| @@ -0,0 +1,96 @@ |
| +// Copyright 2017 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +cr.define('bookmarks', function() { |
| + /** |
| + * Manages focus restoration for modal dialogs. |
|
tsergeant
2017/06/28 03:47:58
I think it's worth going into a little more detail
calamity
2017/06/28 04:22:47
Done.
|
| + * @constructor |
| + */ |
| + function DialogFocusManager() { |
| + /** @private {HTMLDialogElement} */ |
| + this.previousFocusElement_ = null; |
| + |
| + /** @private {boolean} */ |
| + this.previousMouseFocus_ = false; |
| + |
| + /** @private {Set<HTMLDialogElement>} */ |
| + this.dialogs_ = new Set(); |
| + } |
| + |
| + DialogFocusManager.prototype = { |
| + /** |
| + * @param {HTMLDialogElement} dialog |
| + * @param {Function=} showFn |
| + */ |
| + showDialog: function(dialog, showFn) { |
| + if (!showFn) { |
| + showFn = function() { |
| + dialog.showModal(); |
| + }; |
| + } |
| + |
| + // Update the focus if there are no open dialogs or if this is the only |
| + // dialog and it's getting reshown. |
| + if (!this.dialogs_.size || |
| + (this.dialogs_.has(dialog) && this.dialogs_.size == 1)) { |
| + this.updatePreviousFocus_(); |
| + } |
| + |
| + if (!this.dialogs_.has(dialog)) { |
| + dialog.addEventListener('close', this.getCloseListener_(dialog)); |
| + this.dialogs_.add(dialog); |
| + } |
| + |
| + showFn(); |
| + }, |
| + |
| + /** @private */ |
| + updatePreviousFocus_: function() { |
| + this.previousFocusElement_ = this.getFocusedElement_(); |
| + this.previousMouseFocus_ = bookmarks.MouseFocusBehavior.isMouseFocused( |
| + this.previousFocusElement_); |
| + }, |
| + |
| + /** @private */ |
|
tsergeant
2017/06/28 03:47:58
Nit: @return annotation
calamity
2017/06/28 04:22:47
Done.
|
| + getFocusedElement_: function() { |
| + var focus = document.activeElement; |
| + while (focus.root && focus.root.activeElement) |
| + focus = focus.root.activeElement; |
| + |
| + return focus; |
| + }, |
| + |
| + /** |
| + * @param {HTMLDialogElement} dialog |
| + * @private |
| + */ |
| + getCloseListener_: function(dialog) { |
|
tsergeant
2017/06/28 03:47:58
This is nifty, I'm glad you figured out the async
calamity
2017/06/28 04:22:47
Acknowledged.
|
| + var closeListener = function(e) { |
| + // If the dialog is open, then it got reshown immediately and we |
| + // shouldn't clear it until it is closed again. |
| + if (dialog.open) |
| + return; |
| + |
| + assert(this.dialogs_.delete(dialog)); |
| + // Focus the originally focused element if there are no more dialogs. |
| + if (!this.dialogs_.size) { |
| + this.previousFocusElement_.focus(); |
| + if (this.previousMouseFocus_) { |
| + bookmarks.MouseFocusBehavior.addMouseFocusClass( |
| + this.previousFocusElement_); |
| + } |
| + } |
| + dialog.removeEventListener('close', closeListener); |
| + }.bind(this); |
| + |
| + return closeListener; |
| + }, |
|
tsergeant
2017/06/28 03:47:58
Nit: this should be a ; not a ,
calamity
2017/06/28 04:22:47
Done.
|
| + }, |
| + |
| + cr.addSingletonGetter(DialogFocusManager); |
| + |
| + return { |
| + DialogFocusManager: DialogFocusManager, |
| + }; |
| +}); |