Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial work to add password visibility toggle button on Student Dashboard login form #2818

Merged
merged 5 commits into from
Jan 13, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelogs/password-toggle.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
significance: patch
type: added
entry: Ability to show typed password for verification.
76 changes: 76 additions & 0 deletions assets/js/app/llms-visibility-toggle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
/**
* Handle Password Visibility Toggle for LifterLMS Forms
*
* @package LifterLMS/Scripts
*
* @since TBD
*/

LLMS.PasswordVisibility = {

/**
* Initialize references and setup event binding
*
* @since TBD
* @return void
*/
init: function() {
this.$toggleButtons = $( '.llms-visibility-toggle button' );

if ( this.$toggleButtons.length ) {
this.$toggleButtons.removeClass( 'hide-if-no-js' );
this.bind();
}
},

/**
* Bind DOM events for toggle buttons
*
* @since TBD
* @return void
*/
bind: function() {
var self = this;

// Remove any previous click events and bind the new click event
this.$toggleButtons.off('click').on('click', function(event) {
self.toggleVisibility( $(this) );
});
},

/**
* Toggle visibility of password fields
*
* @since TBD
* @param {Object} $button The jQuery object of the clicked button
* @return void
*/
toggleVisibility: function( $button ) {
var isVisible = parseInt( $button.attr('data-toggle'), 10 );
var $form = $button.closest( '.llms-form-fields' );
var $passwordFields = $form.find( 'input.llms-field-input' );
var $icon = $button.find( 'i' );
var $stateText = $button.find( '.llms-visibility-toggle-state' );

// Toggle the visibility state
if ( isVisible === 1 ) {
// Show password
$passwordFields.filter('[type="password"]').attr('type', 'text');
$button.attr('data-toggle', 0);
$icon.removeClass('fa-eye').addClass('fa-eye-slash');
$stateText.text(LLMS.l10n.translate('Hide Password'));
} else {
// Hide password
$passwordFields.filter('[type="text"]').attr('type', 'password');
$button.attr('data-toggle', 1);
$icon.removeClass('fa-eye-slash').addClass('fa-eye');
$stateText.text(LLMS.l10n.translate('Show Password'));
}
}

};

// Initialize the Password Visibility module on document ready
jQuery(document).ready(function($) {
LLMS.PasswordVisibility.init();
});
25 changes: 25 additions & 0 deletions assets/scss/_includes/_buttons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,31 @@ a.llms-button-secondary {

}

.llms-button-plain {
background: transparent;
border: none;
border-radius: 3px;
color: #1D2327;
cursor: pointer;
font-size: 16px;
font-weight: 700;
text-decoration: none;
text-shadow: none;
line-height: 1;
margin: 0;
max-width: 100%;
padding: 1px 3px;
position: relative;

&:hover, &:active {
color: #1D2327;
}
&:focus {
color: #1D2327;
}

}

.llms-course-continue-button {
display: inline-block;
}
22 changes: 22 additions & 0 deletions assets/scss/_includes/_llms-form-field.scss
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,28 @@
height: 100%;
}

&:has(.llms-visibility-toggle) {
align-items: center;
display: grid;
grid-template-areas:
"label toggle"
"input input";
grid-template-columns: 1fr auto;

label {
grid-area: label;
}

input {
grid-area: input;
}

.llms-visibility-toggle {
grid-area: toggle;
justify-self: end;
}
}

}


Expand Down
30 changes: 16 additions & 14 deletions includes/class.llms.person.handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -166,12 +166,13 @@ public static function get_login_fields( $layout = 'columns' ) {
'type' => ! $usernames ? 'email' : 'text',
),
array(
'columns' => ( 'columns' == $layout ) ? 6 : 12,
'id' => 'llms_password',
'label' => __( 'Password', 'lifterlms' ),
'last_column' => ( 'columns' == $layout ) ? true : true,
'required' => true,
'type' => 'password',
'columns' => ( 'columns' == $layout ) ? 6 : 12,
'id' => 'llms_password',
'label' => __( 'Password', 'lifterlms' ),
'last_column' => ( 'columns' == $layout ) ? true : true,
'required' => true,
'type' => 'password',
'visibility_toggle' => true,
),
array(
'columns' => ( 'columns' == $layout ) ? 3 : 12,
Expand Down Expand Up @@ -280,14 +281,15 @@ private static function get_password_fields() {
$fields = array();

$fields[] = array(
'columns' => 6,
'classes' => 'llms-password',
'id' => 'password',
'label' => __( 'Password', 'lifterlms' ),
'last_column' => false,
'match' => 'password_confirm',
'required' => true,
'type' => 'password',
'columns' => 6,
'classes' => 'llms-password',
'id' => 'password',
'label' => __( 'Password', 'lifterlms' ),
'last_column' => false,
'match' => 'password_confirm',
'required' => true,
'type' => 'password',
'visibility_toggle' => true,
);
$fields[] = array(
'columns' => 6,
Expand Down
108 changes: 62 additions & 46 deletions includes/forms/class-llms-form-field.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,29 +23,30 @@ class LLMS_Form_Field {
* @var array {
* Array of field settings.
*
* @type array $attributes Associative array of HTML attributes to add to the field element.
* @type bool $checked Determines if radio and checkbox fields are checked.
* @type int $columns Number of columns the field wrapper should occupy when rendered. Accepts integers >= 1 and <= 12.
* @type string[]|string $classes Additional CSS classes to add to the field element. Accepts a string or an array of strings.
* @type string $data_store Determines where to store field values. Accepts "users" or "usermeta" to store on the respective WP core tables.
* @type string|false $data_store_key Determines the key name to use when storing the field value. Pass `false` to disable automatic storage. Defaults to the value of the `$name` property.
* @type string $description A string to use as the field's description or helper text.
* @type string $default The default value to use for the field.
* @type bool $disabled Whether or not the field is enabled.
* @type string $id The field's HTML "id" attribute. Must be unique. If not supplied, an ID is automatically generated.
* @type string $label Text to use in the label element associated with the field.
* @type bool $label_show_empty When true and no `$label` is supplied, will show an empty label element.
* @type bool $last_column When true, outputs a clearfix element following the element's wrapper. Allows ending a "row" of fields.
* @type bool $match Match this field to another field for validation purposes. Must be the `$id` of another field in the form.
* @type string $name The field's HTML "name" attribute. Default's to the value of `$id` when not supplied.
* @type array $options An associative array of options used for select, checkbox groups, and radio fields.
* @type string $options_preset A string representing a pre-defined set of `$options`. Accepts "countries" or "states". Custom presets can be defined using the filter "llms_form_field_options_preset_{$preset_id}".
* @type string $placeholder The field's HTML placeholder attribute.
* @type bool $required Determines if the field is marked as required.
* @type string $selected Alias of `$default`.
* @type string $type Field type. Accepts any HTML5 input type (text, email, tel, etc...), radio, checkbox, select, textarea, button, reset, submit, and html.
* @type string $value Value of the field.
* @type string[]|string $wrapper_classes Additional CSS classes to add to the field's wrapper element. Accepts a string or an array of strings.
* @type array $attributes Associative array of HTML attributes to add to the field element.
* @type bool $checked Determines if radio and checkbox fields are checked.
* @type int $columns Number of columns the field wrapper should occupy when rendered. Accepts integers >= 1 and <= 12.
* @type string[]|string $classes Additional CSS classes to add to the field element. Accepts a string or an array of strings.
* @type string $data_store Determines where to store field values. Accepts "users" or "usermeta" to store on the respective WP core tables.
* @type string|false $data_store_key Determines the key name to use when storing the field value. Pass `false` to disable automatic storage. Defaults to the value of the `$name` property.
* @type string $description A string to use as the field's description or helper text.
* @type string $default The default value to use for the field.
* @type bool $disabled Whether or not the field is enabled.
* @type string $id The field's HTML "id" attribute. Must be unique. If not supplied, an ID is automatically generated.
* @type string $label Text to use in the label element associated with the field.
* @type bool $label_show_empty When true and no `$label` is supplied, will show an empty label element.
* @type bool $last_column When true, outputs a clearfix element following the element's wrapper. Allows ending a "row" of fields.
* @type bool $match Match this field to another field for validation purposes. Must be the `$id` of another field in the form.
* @type string $name The field's HTML "name" attribute. Default's to the value of `$id` when not supplied.
* @type array $options An associative array of options used for select, checkbox groups, and radio fields.
* @type string $options_preset A string representing a pre-defined set of `$options`. Accepts "countries" or "states". Custom presets can be defined using the filter "llms_form_field_options_preset_{$preset_id}".
* @type string $placeholder The field's HTML placeholder attribute.
* @type bool $required Determines if the field is marked as required.
* @type string $selected Alias of `$default`.
* @type string $type Field type. Accepts any HTML5 input type (text, email, tel, etc...), radio, checkbox, select, textarea, button, reset, submit, and html.
* @type string $value Value of the field.
* @type string $visibility_toggle Determines if the field should show a button to toggle field masking (for password fields).
* @type string[]|string $wrapper_classes Additional CSS classes to add to the field's wrapper element. Accepts a string or an array of strings.
* }
*/
protected $settings = array();
Expand Down Expand Up @@ -202,29 +203,30 @@ public function explode_options_to_fields( $is_hidden = false ) {
protected function get_defaults() {

return array(
'attributes' => array(),
'checked' => false,
'columns' => 12,
'classes' => array(), // Or string of space-separated classes.
'data_store' => 'usermeta', // Users or usermeta.
'data_store_key' => '', // Defaults to value passed for "name".
'description' => '',
'default' => '',
'disabled' => false,
'id' => '',
'label' => '',
'label_show_empty' => false,
'last_column' => true,
'match' => '', // Test.
'name' => '', // Defaults to value passed for "id".
'options' => array(),
'options_preset' => '',
'placeholder' => '',
'required' => false,
'selected' => '', // Alias of "default".
'type' => 'text',
'value' => '',
'wrapper_classes' => array(), // Or string of space-separated classes.
'attributes' => array(),
'checked' => false,
'columns' => 12,
'classes' => array(), // Or string of space-separated classes.
'data_store' => 'usermeta', // Users or usermeta.
'data_store_key' => '', // Defaults to value passed for "name".
'description' => '',
'default' => '',
'disabled' => false,
'id' => '',
'label' => '',
'label_show_empty' => false,
'last_column' => true,
'match' => '', // Test.
'name' => '', // Defaults to value passed for "id".
'options' => array(),
'options_preset' => '',
'placeholder' => '',
'required' => false,
'selected' => '', // Alias of "default".
'type' => 'text',
'value' => '',
'visibility_toggle' => false,
'wrapper_classes' => array(), // Or string of space-separated classes.
);
}

Expand Down Expand Up @@ -262,6 +264,18 @@ protected function get_description_html() {
return $this->settings['description'] ? sprintf( '<span class="llms-description">%s</span>', $this->settings['description'] ) : '';
}

/**
* Retrieve HTML for the visibility toggle button
*
* @since TBD
*
* @return string
*/
protected function get_visibility_toggle_html() {

return $this->settings['visibility_toggle'] ? '<div class="llms-visibility-toggle"><button type="button" class="llms-button-plain hide-if-no-js" data-toggle="1"><i class="fa fa-eye"></i> <span class="llms-visibility-toggle-state">' . esc_html__( 'Show Password', 'lifterlms' ) . '</span></button></div>' : '';
}

/**
* Retrieve the full HTML for the field.
*
Expand Down Expand Up @@ -457,6 +471,8 @@ public function get_html() {
$after .= $this->get_description_html();
}

$after .= $this->get_visibility_toggle_html();

$after .= '</div>';

if ( $this->settings['last_column'] ) {
Expand Down
Loading