WebUI: For cr-dialog, make Enter click the action-button, if it exists.
Within cr-dialogs, this makes Enter click the action-button, if it
exists. It conservatively rejects any Enter from a target other than
the dialog.
BUG=626420
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:closure_compilation
Review-Url: https://codereview.chromium.org/2788673003
Cr-Commit-Position: refs/heads/master@{#461585}
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index 9086deb6..55d2b7b 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -375,7 +375,8 @@
</settings-animated-pages>
<template is="dom-if" if="[[showDisconnectDialog_]]" restamp>
- <dialog is="cr-dialog" id="disconnectDialog" ignore-popstate
+ <dialog is="cr-dialog" id="disconnectDialog"
+ ignore-popstate ignore-enter-key
on-close="onDisconnectClosed_" close-text="$i18n{close}">
<div class="title">$i18n{syncDisconnectTitle}</div>
<div class="body">
diff --git a/chrome/browser/resources/settings/reset_page/powerwash_dialog.html b/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
index 5d83ffb..0bb75c3 100644
--- a/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/powerwash_dialog.html
@@ -10,7 +10,8 @@
<template>
<style include="settings-shared">
</style>
- <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}">
+ <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}"
+ ignore-enter-key>
<div class="title">$i18n{powerwashDialogTitle}</div>
<div class="body">
<span>
diff --git a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
index 1917bcb..0240e33 100644
--- a/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
+++ b/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html
@@ -19,7 +19,8 @@
margin: 0 8px;
}
</style>
- <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}" ignore-popstate>
+ <dialog is="cr-dialog" id="dialog" close-text="$i18n{close}"
+ ignore-popstate ignore-enter-key>
<div class="title">
[[getPageTitle_(isTriggered_, triggeredResetToolName_)]]
</div>
diff --git a/chrome/test/data/webui/cr_elements/cr_dialog_test.js b/chrome/test/data/webui/cr_elements/cr_dialog_test.js
index 7cd767e5..062211da 100644
--- a/chrome/test/data/webui/cr_elements/cr_dialog_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_dialog_test.js
@@ -26,6 +26,49 @@
expectNotEquals(button, document.activeElement);
});
+ test('enter key clicks action button', function() {
+ document.body.innerHTML = `
+ <dialog is="cr-dialog">
+ <div class="title">title</div>
+ <div class="body">
+ <button class="action-button" disabled>button</button>
+ <button id="other-button">other button</button>
+ </div>
+ </dialog>`;
+
+ var dialog = document.body.querySelector('dialog');
+ var actionButton = document.body.querySelector('.action-button');
+
+ dialog.showModal();
+
+ // MockInteractions triggers event listeners synchronously.
+ var clickedCounter = 0;
+ actionButton.addEventListener('click', function() {
+ clickedCounter += 1;
+ });
+
+ // Enter key should ignore disabled buttons.
+ MockInteractions.keyEventOn(dialog, 'keypress', 13, undefined, 'Enter');
+ assertEquals(0, clickedCounter);
+
+ // Enter key should trigger enabled buttons.
+ actionButton.disabled = false;
+ MockInteractions.keyEventOn(dialog, 'keypress', 13, undefined, 'Enter');
+ assertEquals(1, clickedCounter);
+
+ // Enter keys on other buttons should be ignored.
+ clickedCounter = 0;
+ var otherButton = document.body.querySelector('#other-button');
+ assertTrue(!!otherButton);
+ MockInteractions.keyEventOn(
+ otherButton, 'keypress', 13, undefined, 'Enter');
+ assertEquals(0, clickedCounter);
+
+ // Enter key on the action button should only fire the click handler once.
+ MockInteractions.tap(actionButton, 'keypress', 13, undefined, 'Enter');
+ assertEquals(1, clickedCounter);
+ });
+
test('focuses [autofocus] instead of title when present', function() {
document.body.innerHTML = `
<dialog is="cr-dialog">
diff --git a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js
index a84993e..d598988 100644
--- a/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js
+++ b/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js
@@ -30,6 +30,14 @@
value: false,
},
+ /**
+ * True if the dialog should ignore 'Enter' keypresses.
+ */
+ ignoreEnterKey: {
+ type: Boolean,
+ value: false,
+ },
+
showScrollBorders: {
type: Boolean,
value: false,
@@ -48,6 +56,9 @@
if (!this.ignorePopstate && this.open)
this.cancel();
}.bind(this));
+
+ if (!this.ignoreEnterKey)
+ this.addEventListener('keypress', this.onKeypress_.bind(this));
},
/** @override */
@@ -96,4 +107,21 @@
getCloseButton: function() {
return this.$.close;
},
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onKeypress_: function(e) {
+ if (e.target != this)
+ return;
+ if (e.key != 'Enter')
+ return;
+
+ var actionButton = this.querySelector('.action-button');
+ if (actionButton && !actionButton.disabled) {
+ actionButton.click();
+ e.preventDefault();
+ }
+ },
});