Solved

Serialize On-Key-Up Functions

Posted on 2016-10-15
3
28 Views
Last Modified: 2016-10-25
I'm working on a half-baked jQuery script that uses .on("keyup", function(event){ to copy some data from an input control to JS variables and other selected form elements.  The objective here is to mimic the Apple way of handling passwords, obscuring all the characters except the last one typed.  I'm testing in Chrome; have not tried other browsers yet.

I've discovered that I can type fast enough that my fingers outrun the browser's ability to complete the function, resulting in goofy information as the event objects race forward.  The observed effect is that the number of characters submitted is correct, but some characters are duplicated and others may be lost.

You can see it in action here (type fast!)
https://iconoun.com/demo/password_reveal_intype.php

Is there a way to serialize these requests, or otherwise cause the on-key-up function to run to completion for each character that is entered?  Or is there a better way to process each keystroke as quickly as it occurs?
<?php // demo/password_reveal_intype.php
/**
 * Demonstrate how to reveal only the last character of a password
 * as it is being typed, similar to the way Apple devices work
 */
error_reporting(E_ALL);

$get = NULL;
if (!empty($_GET)) $get = print_r($_GET, TRUE);

$html = <<<EOD
<!DOCTYPE html>
<!-- demo/password_reveal_intype.html -->
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<style type="text/css">
/* Stype Sheet Here */
</style>

<script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>
<script>
$(document).ready(function(){

    $("#pwinput").focus();

    $("#pwinput").on("keyup", function(event){
        if (event.which == 09) return;

        var star = "*";
        var text = "";
        var pwrd = $("#pwinput").val();
        var long = pwrd.length - 1;
        var char = pwrd.substr(long,1);
        var hidn = $("#pwhiddn").val();

        if (event.which == 08){
            var hlen = hidn.length - 1;
            if (hlen >= 0){
                $("#pwhiddn").val(hidn.substr(0,hlen));
            }
        }
        else{
            $("#pwhiddn").val(hidn + char);
        }

        if (pwrd){
            text = star.repeat(long) + char;
        }

        $("#pwinput").val(text);
    });
});
</script>

<title>HTML5 Page With jQuery in UTF-8 Encoding</title>
</head>
<body>

<noscript>Your browsing experience will be much better with JavaScript enabled!</noscript>

<p>
From the last request: $get
<form>
<input name="pw_4_display" id="pwinput" placeholder="Enter Password" type="text" autocomplete="off" />
<input name="pw_4_action"  id="pwhiddn" type="hidden" />
<br>
<input type="submit" />
</form>
</p>

</body>
</html>
EOD;

echo $html;

Open in new window

Thanks and regards, Ray
0
Comment
Question by:Ray Paseur
  • 2
3 Comments
 
LVL 32

Accepted Solution

by:
ste5an earned 500 total points
ID: 41845161
What should happen when the input is pasted into your field? I think you should take a look at the change event instead.
0
 
LVL 108

Author Comment

by:Ray Paseur
ID: 41846148
I've modified the script somewhat, and by using separate handlers for paste, keyup, and keypress, the race condition is gone, and I can type as fast as I want.  The only remaining hurdle is IE11 or below, where all I can do is shake my head and wonder what the Microsoft team is thinking.  IE handles the form submit correctly, but does not display anything in the visual input control field.
<?php // demo/password_reveal_intype.php
/**
 * Demonstrate how to reveal only the last character of a password
 * as it is being typed, similar to the way Apple devices work
 *
 * Using paste to collect input strings
 * Using keypress to collect input characters
 * Using keyup to handle backspace
 */
error_reporting(E_ALL);

$req = NULL;
if (!empty($_POST)) $req = print_r($_POST, TRUE);

$html = <<<EOD
<!DOCTYPE html>
<!-- demo/password_reveal_intype.html -->
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />
<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<style type="text/css">
/* Stype Sheet Here */
</style>

<script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>
<script>
/* Clear Extraneous Display-Only Input on Submit */
function pw_clear_input(){
    $("#pwinput").remove();
}

$(document).ready(function(){

    /* Only One Input Control on this Page */
    $("#pwinput").focus();

    /* Handle "Paste" Functionality */
    $("#pwinput").on("paste", function(event){
        var star = "*";
        var text = "";
        var long = 0;
        var char = "?";

        event.preventDefault();

        /* The Prior Input, if Any */
        var hidn = $("#pwhiddn").val();

        /* Capture Clipboard before Paste Finishes */
        var clip = undefined;

        if (window.clipboardData && window.clipboardData.getData){ // IE
            clip = window.clipboardData.getData('Text');
        }
        else{
            var clipboardData = (event.originalEvent || event).clipboardData;
            if (clipboardData && clipboardData.getData){
                clip = clipboardData.getData('text/plain');
            }
        }

        /* Concatenate Clipboard to Existing Input (if any) and Save in Hidden Element */
        hidn = hidn + clip;
        $("#pwhiddn").val(hidn);

        /* Create Obscured Password - Last Character Showing */
        long = hidn.length - 1;
        char = hidn.substr(long,1);
        text = star.repeat(long) + char;

        $("#pwinput").val(text);
    });

    /* Handle Each New Character of Input */
    $("#pwinput").on("keypress", function(event){
        var star = "*";
        var text = "";
        var long = 0;
        var char = "?";

        // Ignore Backspace, Return (Enter), End, Delete Keys */
        if (event.which == 8)  return;
        if (event.which == 10) return;
        if (event.which == 13) return;
        if (event.which == 35) return;
        if (event.which == 46) return;

        event.preventDefault();

        var hidn = $("#pwhiddn").val();
        var char = String.fromCharCode(event.which);

        /* Concatenate Character to Existing Input (if any) and Save in Hidden Element */
        hidn = hidn + char;
        $("#pwhiddn").val(hidn);

        /* Create Obscured Password - Last Character Showing */
        long = hidn.length - 1;
        char = hidn.substr(long,1);
        text = star.repeat(long) + char;

        $("#pwinput").val(text);
    });

    /* Handle Backspace Character(s) */
    $("#pwinput").on("keyup", function(event){
        var star = "*";
        var text = "";
        var long = 0;
        var char = "?";

        if (event.which != 8) return; // Only handle backspace

        event.preventDefault();

        /* Remove Character from Existing Input (if any) and Save in Hidden Element */
        var hidn = $("#pwhiddn").val();
        long = hidn.length - 1;
        if (long >= 0){
            hidn = hidn.substr(0,long);
            $("#pwhiddn").val(hidn);
        }

        /* Create Obscured Password - Only last Character Showing */
        long = hidn.length - 1;
        if (long >= 0){
            char = hidn.substr(long,1);
            text = star.repeat(long) + char;
        }

        $("#pwinput").val(text);
    });

});
</script>

<title>HTML5 Page With jQuery in UTF-8 Encoding</title>
</head>
<body>

<noscript>Your browsing experience will be much better with JavaScript enabled!</noscript>

<p>
Arguments from the last request: $req
<form id="pwform" method="post" onSubmit="return pw_clear_input()">
<input name="pw_4_display" id="pwinput" placeholder="Enter Password" type="text" autocomplete="off" />
<input name="pw_4_action"  id="pwhiddn" type="hidden" />
<br>
<input type="submit" />
</form>
</p>

</body>
</html>
EOD;

echo $html;

Open in new window

0
 
LVL 108

Assisted Solution

by:Ray Paseur
Ray Paseur earned 0 total points
ID: 41858586
The question and suggestions here led to an update to this article.  See Example #3.
https://www.experts-exchange.com/articles/19779/Passwords-in-HTML-Forms-Allow-the-Client-to-Show-or-Hide.html
0

Featured Post

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction Knockoutjs (Knockout) is a JavaScript framework (Model View ViewModel or MVVM framework).   The main ideology behind Knockout is to control from JavaScript how a page looks whilst creating an engaging user experience in the least …
How to build a simple, quick and effective accordion menu using just 15 lines of jQuery and 2 css classes
The viewer will learn how to dynamically set the form action using jQuery.
The viewer will learn the basics of jQuery, including how to invoke it on a web page. Reference your jQuery libraries: (CODE) Include your new external js/jQuery file: (CODE) Write your first lines of code to setup your site for jQuery.: (CODE)

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

21 Experts available now in Live!

Get 1:1 Help Now