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();
+    }
+  },
 });