LP1977554 - Add Password visibility toggle on login screens
authorScott Angel <scottangel@mobiusconsortium.org>
Tue, 24 Jan 2023 17:26:17 +0000 (11:26 -0600)
committerScott Angel <scottangel@mobiusconsortium.org>
Tue, 24 Jan 2023 17:36:29 +0000 (11:36 -0600)
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>
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 63c8b82..5b30af2 100644 (file)
 
         <div class="form-group row">
           <label class="col-lg-4 text-right font-weight-bold" for="password" i18n>Password</label>
+          <div class="input-group col-lg-8 p-0">
           <input 
-            type="password" 
-            class="form-control col-lg-8"
-            id="password" 
+            [type]="passwordVisible ? 'text' : 'password'"
+            class="form-control"
+            id="password"
             name="password"
             required
             autocomplete="current-password"
             i18n-placeholder
-            placeholder="Password" 
+            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>
 
         <div class="form-group row" *ngIf="workstations && workstations.length">
index 956b18c..d6ef14a 100644 (file)
@@ -14,6 +14,7 @@ export class StaffLoginComponent implements OnInit {
     workstations: any[];
     loginFailed: boolean;
     routeTo: string;
+    passwordVisible: boolean;
 
     args = {
       username : '',
@@ -115,6 +116,11 @@ export class StaffLoginComponent implements OnInit {
             }
         );
     }
+
+    togglePasswordVisibility() {
+        this.passwordVisible = !this.passwordVisible;
+    }
+
 }
 
 
index 2af095a..23d71ca 100644 (file)
@@ -360,3 +360,10 @@ input.small {
   background-color: #f9dede;
   color: #212121;
 }
+
+/*
+   CSS Cursor classes
+*/
+.pointer {
+  cursor: pointer;
+}
index fbbd9dd..f16195e 100755 (executable)
@@ -4084,3 +4084,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 44c4544..cb88dcb 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