diff --git a/core/core.libraries.yml b/core/core.libraries.yml index 41406af..13b26d3 100644 --- a/core/core.libraries.yml +++ b/core/core.libraries.yml @@ -206,6 +206,15 @@ drupal.progress: - core/jquery - core/drupalSettings +drupal.revealpass: + version: VERSION + js: + misc/revealpass.js: {} + dependencies: + - core/drupal + - core/jquery + - core/jquery.once + drupal.states: version: VERSION js: diff --git a/core/lib/Drupal/Core/Form/FormBuilderInterface.php b/core/lib/Drupal/Core/Form/FormBuilderInterface.php index 43d2e9f..450addb 100644 --- a/core/lib/Drupal/Core/Form/FormBuilderInterface.php +++ b/core/lib/Drupal/Core/Form/FormBuilderInterface.php @@ -158,8 +158,7 @@ public function rebuildForm($form_id, FormStateInterface &$form_state, $old_form * $form_state = new FormState(); * $values['name'] = 'robo-user'; * $values['mail'] = 'robouser@example.com'; - * $values['pass']['pass1'] = 'password'; - * $values['pass']['pass2'] = 'password'; + * $values['pass']['pass'] = 'password'; * $values['op'] = t('Create new account'); * $form_state->setValues($values); * drupal_form_submit('user_register_form', $form_state); diff --git a/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php b/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php index 9bc32b7..e6eb75f 100644 --- a/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php +++ b/core/lib/Drupal/Core/Render/Element/PasswordConfirm.php @@ -17,82 +17,30 @@ * * @FormElement("password_confirm") */ -class PasswordConfirm extends FormElement { +class PasswordConfirm extends Password { /** * {@inheritdoc} */ public function getInfo() { $class = get_class($this); - return array( - '#input' => TRUE, - '#process' => array( - array($class, 'processPasswordConfirm'), - ), - '#theme_wrappers' => array('form_element'), - ); - } - - /** - * {@inheritdoc} - */ - public static function valueCallback(&$element, $input, FormStateInterface $form_state) { - if ($input === FALSE) { - $element += array('#default_value' => array()); - return $element['#default_value'] + array('pass1' => '', 'pass2' => ''); - } + $info = parent::getInfo(); + $info['#process'] = array( + array($class, 'processAjaxForm'), + array($class, 'processPattern'), + array($class, 'processPasswordConfirm'), + ); + return $info; } /** * Expand a password_confirm field into two text boxes. */ public static function processPasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) { - $element['pass1'] = array( - '#type' => 'password', - '#title' => t('Password'), - '#value' => empty($element['#value']) ? NULL : $element['#value']['pass1'], - '#required' => $element['#required'], - '#attributes' => array('class' => array('password-field')), - ); - $element['pass2'] = array( - '#type' => 'password', - '#title' => t('Confirm password'), - '#value' => empty($element['#value']) ? NULL : $element['#value']['pass2'], - '#required' => $element['#required'], - '#attributes' => array('class' => array('password-confirm')), - ); - $element['#element_validate'] = array(array(get_called_class(), 'validatePasswordConfirm')); - $element['#tree'] = TRUE; - - if (isset($element['#size'])) { - $element['pass1']['#size'] = $element['pass2']['#size'] = $element['#size']; - } - + $element['#attributes']['class'][] = 'password-field'; + $element['#attributes']['class'][] = 'password-confirm'; + $element['#attached']['library'][] = 'core/drupal.revealpass'; + $element['#attributes']['data-drupal-revealpass'] = TRUE; return $element; } - - /** - * Validates a password_confirm element. - */ - public static function validatePasswordConfirm(&$element, FormStateInterface $form_state, &$complete_form) { - $pass1 = trim($element['pass1']['#value']); - $pass2 = trim($element['pass2']['#value']); - if (!empty($pass1) || !empty($pass2)) { - if (strcmp($pass1, $pass2)) { - $form_state->setError($element, t('The specified passwords do not match.')); - } - } - elseif ($element['#required'] && $form_state->getUserInput()) { - $form_state->setError($element, t('Password field is required.')); - } - - // Password field must be converted from a two-element array into a single - // string regardless of validation results. - $form_state->setValueForElement($element['pass1'], NULL); - $form_state->setValueForElement($element['pass2'], NULL); - $form_state->setValueForElement($element, $pass1); - - return $element; - } - } diff --git a/core/misc/revealpass.js b/core/misc/revealpass.js new file mode 100644 index 0000000..d9f3e07 --- /dev/null +++ b/core/misc/revealpass.js @@ -0,0 +1,38 @@ +(function ($, Drupal) { + + "use strict"; + + var showPass = Drupal.t('Show password'); + var hidePass = Drupal.t('Hide password'); + + function revealClickHandle(event) { + var $pass = $(event.data.password); + var $button = $(event.target); + + if ($pass.attr('type') === 'password') { + $pass.attr('type', 'text'); + $button.text(hidePass); + } + else { + $pass.attr('type', 'password'); + $button.text(showPass); + } + } + + function revealLink(index, element) { + var $trigger = $( + '' + ); + + $trigger.on('click', {password: element}, revealClickHandle); + $trigger.insertAfter(element); + } + + Drupal.behaviors.revealPass = { + attach: function (context) { + $(context).find('input[type=password][data-drupal-revealpass]') + .once('revealpass') + .each(revealLink); + } + }; +})(jQuery, Drupal); \ No newline at end of file diff --git a/core/modules/contact/src/Tests/ContactPersonalTest.php b/core/modules/contact/src/Tests/ContactPersonalTest.php index 51124c9..d8cd2a8 100644 --- a/core/modules/contact/src/Tests/ContactPersonalTest.php +++ b/core/modules/contact/src/Tests/ContactPersonalTest.php @@ -251,8 +251,7 @@ protected function checkContactAccess($response, $contact_value = NULL) { $edit = array( 'name' => $name, 'mail' => $this->randomMachineName() . '@example.com', - 'pass[pass1]' => $pass = $this->randomString(), - 'pass[pass2]' => $pass, + 'pass' => $this->randomString(), 'notify' => FALSE, ); if (isset($contact_value)) { diff --git a/core/modules/dblog/src/Tests/DbLogTest.php b/core/modules/dblog/src/Tests/DbLogTest.php index 4dc37e4..daa7e58 100644 --- a/core/modules/dblog/src/Tests/DbLogTest.php +++ b/core/modules/dblog/src/Tests/DbLogTest.php @@ -229,8 +229,7 @@ private function doUser() { $edit = array(); $edit['name'] = $name; $edit['mail'] = $name . '@example.com'; - $edit['pass[pass1]'] = $pass; - $edit['pass[pass2]'] = $pass; + $edit['pass'] = $pass; $edit['status'] = 1; $this->drupalPostForm('admin/people/create', $edit, t('Create new account')); $this->assertResponse(200); diff --git a/core/modules/simpletest/src/WebTestBase.php b/core/modules/simpletest/src/WebTestBase.php index 3c826bf..9ff6aef 100644 --- a/core/modules/simpletest/src/WebTestBase.php +++ b/core/modules/simpletest/src/WebTestBase.php @@ -954,10 +954,7 @@ protected function installParameters() { 'account' => array( 'name' => $this->root_user->name, 'mail' => $this->root_user->getEmail(), - 'pass' => array( - 'pass1' => $this->root_user->pass_raw, - 'pass2' => $this->root_user->pass_raw, - ), + 'pass' => $this->root_user->pass_raw, ), // \Drupal\Core\Render\Element\Checkboxes::valueCallback() requires // NULL instead of FALSE values for programmatic form submissions to diff --git a/core/modules/system/src/Tests/Form/FormTest.php b/core/modules/system/src/Tests/Form/FormTest.php index a377e6e..34e8f1f 100644 --- a/core/modules/system/src/Tests/Form/FormTest.php +++ b/core/modules/system/src/Tests/Form/FormTest.php @@ -71,11 +71,9 @@ function testRequiredFields() { $elements['password']['element'] = array('#title' => $this->randomMachineName(), '#type' => 'password'); $elements['password']['empty_values'] = $empty_strings; + // @todo remove element? $elements['password_confirm']['element'] = array('#title' => $this->randomMachineName(), '#type' => 'password_confirm'); - // Provide empty values for both password fields. - foreach ($empty_strings as $key => $value) { - $elements['password_confirm']['empty_values'][$key] = array('pass1' => $value, 'pass2' => $value); - } + $elements['password_confirm']['empty_values'] = $empty_strings; $elements['textarea']['element'] = array('#title' => $this->randomMachineName(), '#type' => 'textarea'); $elements['textarea']['empty_values'] = $empty_strings; @@ -532,7 +530,7 @@ function testDisabledElements() { // All the elements should be marked as disabled, including the ones below // the disabled container. $actual_count = count($disabled_elements); - $expected_count = 41; + $expected_count = 40; $this->assertEqual($actual_count, $expected_count, String::format('Found @actual elements with disabled property (expected @expected).', array( '@actual' => count($disabled_elements), '@expected' => $expected_count, diff --git a/core/modules/user/src/Tests/UserCreateFailMailTest.php b/core/modules/user/src/Tests/UserCreateFailMailTest.php index 677effe..a1fb1f6 100644 --- a/core/modules/user/src/Tests/UserCreateFailMailTest.php +++ b/core/modules/user/src/Tests/UserCreateFailMailTest.php @@ -37,8 +37,7 @@ protected function testUserAdd() { $edit = array( 'name' => $name, 'mail' => $this->randomMachineName() . '@example.com', - 'pass[pass1]' => $pass = $this->randomString(), - 'pass[pass2]' => $pass, + 'pass' => $this->randomString(), 'notify' => TRUE, ); $this->drupalPostForm('admin/people/create', $edit, t('Create new account')); diff --git a/core/modules/user/src/Tests/UserCreateTest.php b/core/modules/user/src/Tests/UserCreateTest.php index 911c9ae..029d11e 100644 --- a/core/modules/user/src/Tests/UserCreateTest.php +++ b/core/modules/user/src/Tests/UserCreateTest.php @@ -94,8 +94,7 @@ protected function testUserAdd() { $edit = array( 'name' => $name, 'mail' => $this->randomMachineName() . '@example.com', - 'pass[pass1]' => $pass = $this->randomString(), - 'pass[pass2]' => $pass, + 'pass' => $this->randomString(), 'notify' => $notify, ); $this->drupalPostForm('admin/people/create', $edit, t('Create new account')); diff --git a/core/modules/user/src/Tests/UserEditTest.php b/core/modules/user/src/Tests/UserEditTest.php index 4ee1b18..fa67f07 100644 --- a/core/modules/user/src/Tests/UserEditTest.php +++ b/core/modules/user/src/Tests/UserEditTest.php @@ -30,18 +30,6 @@ function testUserEdit() { $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t('The name %name is already taken.', array('%name' => $edit['name']))); - // Check that filling out a single password field does not validate. - $edit = array(); - $edit['pass[pass1]'] = ''; - $edit['pass[pass2]'] = $this->randomMachineName(); - $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); - $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.'); - - $edit['pass[pass1]'] = $this->randomMachineName(); - $edit['pass[pass2]'] = ''; - $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); - $this->assertText(t("The specified passwords do not match."), 'Typing mismatched passwords displays an error message.'); - // Test that the error message appears when attempting to change the mail or // pass without the current password. $edit = array(); @@ -55,8 +43,7 @@ function testUserEdit() { // Test that the user must enter current password before changing passwords. $edit = array(); - $edit['pass[pass1]'] = $new_pass = $this->randomMachineName(); - $edit['pass[pass2]'] = $new_pass; + $edit['pass'] = $new_pass = $this->randomMachineName(); $this->drupalPostForm("user/" . $user1->id() . "/edit", $edit, t('Save')); $this->assertRaw(t("Your current password is missing or incorrect; it's required to change the %name.", array('%name' => t('Password')))); diff --git a/core/modules/user/src/Tests/UserLanguageCreationTest.php b/core/modules/user/src/Tests/UserLanguageCreationTest.php index 65e37f9..26932bc 100644 --- a/core/modules/user/src/Tests/UserLanguageCreationTest.php +++ b/core/modules/user/src/Tests/UserLanguageCreationTest.php @@ -55,8 +55,7 @@ function testLocalUserCreation() { $edit = array( 'name' => $username, 'mail' => $this->randomMachineName(4) . '@example.com', - 'pass[pass1]' => $username, - 'pass[pass2]' => $username, + 'pass' => $username, ); $this->drupalPostForm($langcode . '/admin/people/create', $edit, t('Create new account')); @@ -94,8 +93,7 @@ function testLocalUserCreation() { // Set pass_raw so we can login the new user. $user->pass_raw = $this->randomMachineName(10); $edit = array( - 'pass[pass1]' => $user->pass_raw, - 'pass[pass2]' => $user->pass_raw, + 'pass' => $user->pass_raw, ); $this->drupalPostForm($user_edit, $edit, t('Save')); diff --git a/core/modules/user/src/Tests/UserPasswordResetTest.php b/core/modules/user/src/Tests/UserPasswordResetTest.php index 1d27865..163858b 100644 --- a/core/modules/user/src/Tests/UserPasswordResetTest.php +++ b/core/modules/user/src/Tests/UserPasswordResetTest.php @@ -91,7 +91,7 @@ function testUserPasswordReset() { // Change the forgotten password. $password = user_password(); - $edit = array('pass[pass1]' => $password, 'pass[pass2]' => $password); + $edit = array('pass' => $password); $this->drupalPostForm(NULL, $edit, t('Save')); $this->assertText(t('The changes have been saved.'), 'Forgotten password changed.'); diff --git a/core/modules/user/src/Tests/UserRegistrationTest.php b/core/modules/user/src/Tests/UserRegistrationTest.php index f6a34bd..4af733d 100644 --- a/core/modules/user/src/Tests/UserRegistrationTest.php +++ b/core/modules/user/src/Tests/UserRegistrationTest.php @@ -70,15 +70,8 @@ function testRegistrationWithoutEmailVerification() { $edit['name'] = $name = $this->randomMachineName(); $edit['mail'] = $mail = $edit['name'] . '@example.com'; - // Try entering a mismatching password. - $edit['pass[pass1]'] = '99999.0'; - $edit['pass[pass2]'] = '99999'; - $this->drupalPostForm('user/register', $edit, t('Create new account')); - $this->assertText(t('The specified passwords do not match.'), 'Typing mismatched passwords displays an error message.'); - // Enter a correct password. - $edit['pass[pass1]'] = $new_pass = $this->randomMachineName(); - $edit['pass[pass2]'] = $new_pass; + $edit['pass'] = $this->randomMachineName(); $this->drupalPostForm('user/register', $edit, t('Create new account')); $this->container->get('entity.manager')->getStorage('user')->resetCache(); $accounts = entity_load_multiple_by_properties('user', array('name' => $name, 'mail' => $mail)); @@ -92,8 +85,7 @@ function testRegistrationWithoutEmailVerification() { $edit = array(); $edit['name'] = $name = $this->randomMachineName(); $edit['mail'] = $mail = $edit['name'] . '@example.com'; - $edit['pass[pass1]'] = $pass = $this->randomMachineName(); - $edit['pass[pass2]'] = $pass; + $edit['pass'] = $pass = $this->randomMachineName(); $this->drupalPostForm('user/register', $edit, t('Create new account')); $this->assertText(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.'), 'Users are notified of pending approval'); @@ -169,8 +161,7 @@ function testRegistrationDefaultValues() { $edit = array(); $edit['name'] = $name = $this->randomMachineName(); $edit['mail'] = $mail = $edit['name'] . '@example.com'; - $edit['pass[pass1]'] = $new_pass = $this->randomMachineName(); - $edit['pass[pass2]'] = $new_pass; + $edit['pass'] = $this->randomMachineName(); $this->drupalPostForm(NULL, $edit, t('Create new account')); // Check user fields. diff --git a/core/modules/user/src/Tests/UserRolesAssignmentTest.php b/core/modules/user/src/Tests/UserRolesAssignmentTest.php index 124a263..2e0605b 100644 --- a/core/modules/user/src/Tests/UserRolesAssignmentTest.php +++ b/core/modules/user/src/Tests/UserRolesAssignmentTest.php @@ -54,8 +54,7 @@ function testCreateUserWithRole() { $edit = array( 'name' => $this->randomMachineName(), 'mail' => $this->randomMachineName() . '@example.com', - 'pass[pass1]' => $pass = $this->randomString(), - 'pass[pass2]' => $pass, + 'pass' => $this->randomString(), "roles[$rid]" => $rid, ); $this->drupalPostForm('admin/people/create', $edit, t('Create new account')); diff --git a/core/modules/user/user.module b/core/modules/user/user.module index 82aca31..be166c2 100644 --- a/core/modules/user/user.module +++ b/core/modules/user/user.module @@ -1348,9 +1348,6 @@ function user_element_info_alter(array &$types) { */ function user_form_process_password_confirm($element) { $password_settings = array( - 'confirmTitle' => t('Passwords match:'), - 'confirmSuccess' => t('yes'), - 'confirmFailure' => t('no'), 'showStrengthIndicator' => FALSE, );