LP1977554 - Add Password visibility toggle on login screens
authorScott Angel <scottangel@mobiusconsortium.org>
Tue, 24 Jan 2023 17:26:17 +0000 (11:26 -0600)
committerGalen Charlton <gmc@equinoxOLI.org>
Fri, 28 Apr 2023 19:39:09 +0000 (19:39 +0000)
Added an icon to each login input of a closed eye when input type is set to password.
If you click the icon it switches to an open eye and the input type is set to text.
It's a pretty standard way to allow people to view their password before submitting it.

Signed-off-by: Scott Angel <scottangel@mobiusconsortium.org>
Signed-off-by: Stephanie Leary <stephanie.leary@equinoxoli.org>
Signed-off-by: Galen Charlton <gmc@equinoxOLI.org>

Open-ILS/src/eg2/src/app/staff/login.component.html
Open-ILS/src/eg2/src/app/staff/login.component.ts
Open-ILS/src/eg2/src/styles.css
Open-ILS/src/templates-bootstrap/opac/css/style.css.tt2
Open-ILS/src/templates-bootstrap/opac/parts/base.tt2
Open-ILS/src/templates-bootstrap/opac/parts/login/form.tt2
Open-ILS/src/templates-bootstrap/opac/parts/login/login_modal.tt2
Open-ILS/src/templates/opac/css/style.css.tt2
Open-ILS/src/templates/opac/parts/js.tt2
Open-ILS/src/templates/opac/parts/login/form.tt2
Open-ILS/src/templates/staff/t_login.tt2

index 939fe52..987cd6a 100644 (file)
         <div class="row row-cols-auto mt-3">
           <label class="form-label col-form-label fw-bold col-4 text-end" for="password" i18n>Password</label>
           <div class="col-8">
-            <input 
-              type="password" 
-              class="form-control"
-              id="password" 
-              name="password"
-              required
-              autocomplete="current-password"
-              i18n-placeholder
-              placeholder="Password" 
-              [(ngModel)]="args.password"/>
+          <input 
+            [type]="passwordVisible ? 'text' : 'password'"
+            class="form-control"
+            id="password"
+            name="password"
+            required
+            autocomplete="current-password"
+            i18n-placeholder
+            placeholder="Password"
+            spellcheck="false"
+            [(ngModel)]="args.password"/>
+          <span id="show_password" class="input-group-text pointer" (click)="togglePasswordVisibility()">
+            <span class="material-icons">{{ passwordVisible ? 'visibility' : 'visibility_off' }}</span>
+          </span>
           </div>
         </div>
 
index 50ec9c6..02d6580 100644 (file)
@@ -15,6 +15,7 @@ export class StaffLoginComponent implements OnInit {
     loginFailed: boolean;
     routeTo: string;
     pendingXactsDate: Date;
+    passwordVisible: boolean;
 
     args = {
       username : '',
@@ -118,6 +119,11 @@ export class StaffLoginComponent implements OnInit {
             }
         );
     }
+
+    togglePasswordVisibility() {
+        this.passwordVisible = !this.passwordVisible;
+    }
+
 }
 
 
index bf4b325..ca59afa 100644 (file)
@@ -560,4 +560,11 @@ a {
 
 .popover-body {
   padding: 0;
-}
\ No newline at end of file
+}
+
+/*
+   CSS Cursor classes
+*/
+.pointer {
+  cursor: pointer;
+}
index 1a9e146..92d651b 100755 (executable)
@@ -4019,3 +4019,7 @@ padding: 15px;
 .form-control {
     border: 1px solid [% css_colors.border_standard %];
 }
+
+.pointer {
+    cursor: pointer;
+}
index 91030b7..bff11bd 100755 (executable)
                                $("#loginModal").on('shown.bs.modal', function(){
                                        $(this).find('#username_field').focus();
                                });
+                // password visibility eye
+                let btn = document.getElementById('show_password');
+                let input = document.getElementById('password_field');
+                let icon = btn.querySelector('i');
+                btn.addEventListener('click', () => {
+                    input.type == 'password' ? [input.type = 'text', icon.setAttribute('class','fas fa-eye')] : [input.type = 'password', icon.setAttribute('class', 'fas fa-eye-slash')];
+                    input.focus();
+                });
                        });
                </script>
 
index fcd8d87..b9a09bd 100755 (executable)
                        <input class="form-control" type='text' id="username_field" name="username" autofocus />
                </div>
                <div class="col-sm w-50">
-                       <input class="form-control" id="password_field" name="password" type="password"/>
+                       <div class="input-group">
+                               <input class="form-control" id="password_field" name="password" type="password" spellcheck="false"/>
+                               <span id="show_password" class="input-group-text pointer"><i class="fas fa-eye-slash"></i></span>
+                       </div>
                </div>
        </div>
        <div class="row">
index a778b7c..bbbb560 100755 (executable)
                                <input class="form-control" type='text' id="username_field" name="username"/>
                        </div>
                        <div class="col-sm w-50">
-                               <input class="form-control" id="password_field" name="password" type="password"/>
+                <div class="input-group">
+                    <input class="form-control" id="password_field" name="password" type="password" spellcheck="false"/>
+                    <span id="show_password" class="input-group-text pointer"><i class="fas fa-eye-slash"></i></span>
+                </div>
                        </div>
                </div>
                <div class="row">
index c17da05..07cdb14 100644 (file)
@@ -3501,3 +3501,6 @@ span.egtd { display:table-cell; }
 
 */
 
+.pointer {
+    cursor: pointer;
+}
index c597c31..0e35c0f 100644 (file)
 }
 </script>
 
+<!-- Password Visibility Checkbox -->
+<script>
+    let checkbox = document.getElementById('password_visibility_checkbox');
+    let input = document.getElementById('password_field');
+    checkbox.addEventListener('change', () => {
+        if(checkbox.checked) input.type = 'text';
+        else input.type = 'password';
+        input.focus();
+    });
+</script>
+
 [%- IF ctx.use_stripe %]
 <script type="text/javascript">unHideMe($("pay_fines_now"));[%# the DOM is loaded now, right? %]</script>
 [% END -%]
index 6ceca0b..c84ed85 100644 (file)
         <div class='float-left'>
             <label for="password_field" class="lbl1" >[% l('PIN Number or Password') %]</label>
             <div class="input_bg">
-                <input id="password_field" name="password" type="password" />
+                <input id="password_field" name="password" type="password" spellcheck="false"/>
+            </div>
+            <div class="input_bg">
+                <input id="password_visibility_checkbox" type="checkbox" />
+                <label for="password_visibility_checkbox">Show Password</label>
             </div>
             [% INCLUDE "opac/parts/login/password_hint.tt2" %]
             [% IF reset_password == 'true' %]
index 2dc7fc4..0ad9813 100644 (file)
             <div class="form-group">
               <label class="col-md-4 control-label" for="login-password">[% l('Password') %]</label>
               <div class="col-md-8">
-                <input type="password" id="login-password" class="form-control"
-                  placeholder="Password" ng-model="args.password"/>
+                <div class="input-group">
+                  <input type="password" id="login-password" class="form-control"
+                    placeholder="Password" spellcheck="false" ng-model="args.password"/>
+                  <span id="show_password" class="input-group-addon pointer"><i class="glyphicon glyphicon-eye-close"></i></span>
+                </div>
               </div>
             </div>
 
     <div class="col-md-3"></div><!-- offset? -->
   </div>
 </div>
+<script>
+    // password visibility eye
+    let btn = document.getElementById('show_password');
+    let input = document.getElementById('login-password');
+    let icon = btn.querySelector('i');
+    btn.addEventListener('click', () => {
+      input.type == 'password' ? [input.type = 'text', icon.setAttribute('class', 'glyphicon glyphicon-eye-open')] : [input.type = 'password', icon.setAttribute('class', 'glyphicon glyphicon-eye-close')];
+      input.focus();
+    });
+</script>
\ No newline at end of file