reptile7's JavaScript blog
Friday, November 02, 2007
 
Bouncer Script C
Blog Entry #93

Today's post concludes our discussion of the trilogy of password-protection scripts spanning HTML Goodies' JavaScript Script Tips #73-75 with a look at the Script Tip #75 Script. Let's begin with a bit of "compare and contrast"; as we'll see below:

• Unlike the Script Tip #73 Script but like the Script Tip #74 Script, the Script Tip #75 Script does not contain its password or its target Web page URL.

• Like the Script Tip #74 Script, the Script Tip #75 Script uses a user's inputs into form controls (text boxes) to build its target Web page URL.

• Unlike the Script Tip #74 Script, the Script Tip #75 Script 'camouflages' the assembly of its target Web page URL via an array that maps the user's inputs onto other text strings that (partially) compose the URL.

The Script Tip #75 Script can be accessed by following Script Tip #75's Here's the Code link and is reproduced in the div below:

<script language="javascript">

function GoIn( )
{
var Password = new Array("p","j","l","z","o","e","m","b","x","z");

function getNumbers( )
{
return document.userInput.u1.value;
return document.userInput.u2.value;
return document.userInput.u3.value;
}

var input1 = document.userInput.u1.value;
var input2 = document.userInput.u2.value;
var input3 = document.userInput.u3.value;

var pw1 = Password[input1];
var pw2 = Password[input2];
var pw3 = Password[input3];

var pw = pw1 + pw2 + pw3; 
if (pw == pw1 + pw2 + pw3)
{ location.href = pw + ".html"; }
}
</script> 
Put in Your Three-Number Password to Enter: <center>
<form name="userInput">
<input type="text" name ="u1" size="2">
<input type="text" name ="u2" size="2">
<input type="text" name ="u3" size="2">
<input type="button" value="Enter" onclick="GoIn( );">
</form>
</center>

Deconstructing the Script Tip #75 Script

Here's what happens when the user follows Script Tip #75's Here's the Script link to the script demo page:

Put in Your Three-Number Password to Enter: <center>
<form name="userInput">
<input type="text" name="u1" size="2" />
<input type="text" name="u2" size="2" />
<input type="text" name="u3" size="2" />

The user is initially asked to enter respectively* the numbers of a three-digit password into three small text fields named u1, u2, and u3.
(*OK, the word "respectively" doesn't appear on the page, but this is of course what the user is supposed to do. We'll briefly address the non-respective input of digits in the "Data Validation" section below.)

Regarding the size="2" attributes, Joe says, Following the form [t]ag are three input text boxes, each set to accept only two characters. Actually, if we wanted to prevent the user from entering more than two characters into each box, we would do that via the maxlength attribute of the input element, e.g.:

<input type="text" name="u1" size="2" maxlength="2" />

(size="2" means that, when typing in a fixed-width font, the user can see at most two characters in the box, but it doesn't stop the user from entering additional characters.)

<input type="button" value="Enter" onclick="GoIn( );" />

The user attempts to access the target page by clicking the Enter button, which triggers the script's GoIn( ) function.

function GoIn( ) {
var Password = new Array("p","j","l","z","o","e","m","b","x","z");

An array of ten one-letter strings is created and given the identifier Password.

Joe remarks, The function starts with an array. We've used the format before...A comma separates each item, with no spaces. According to my records, however, this is the first time in HTML Goodies' JavaScript materials we've seen a "condensed" array (to use JavaScript Kit's term): an array whose values are listed as a series of Array( ) object parameters and not on their own command lines, i.e., the "regular" syntax would be:

var Password = new Array( );
Password[0] = "p";
Password[1] = "j";
Password[2] = "l";
Password[3] = "z";
Password[4] = "o";
Password[5] = "e";
Password[6] = "m";
Password[7] = "b";
Password[8] = "x";
Password[9] = "z";

Moreover, Netscape's Array object page shows that spaces between condensed array values are OK:

var Password = new Array("p", "j", "l", "z", "o", "e", "m", "b", "x", "z");

Joe furthermore states, Any time you set up an array in JavaScript, the array list members are given numbers starting at zero and counting up until JavaScript runs out of things to count, and this is indeed true for a 'normal', non-associative array. However, you should be aware that this is not true for an associative array of the type we encountered in the guitar chord chart script of Script Tips #56-59 - I can confirm that the values of such arrays are not automatically indexed with ordinal numbers by the browser.

function getNumbers( ) {
return document.userInput.u1.value;
return document.userInput.u2.value;
return document.userInput.u3.value; }

This pointless block of code should be removed; there's no need at all to simply return, to the script, the numbers the user put into the text boxes. And there isn't even a getNumbers( ) function call in the script!

var input1 = document.userInput.u1.value;
var input2 = document.userInput.u2.value;
var input3 = document.userInput.u3.value;

These statements respectively assign the value values (i.e., entered numbers) of the u1, u2, and u3 fields to the variables input1, input2, and input3. Data-type-wise, the input# values are strings.

var pw1 = Password[input1];
var pw2 = Password[input2];
var pw3 = Password[input3];

The input# variables are plugged into Password[ ] expressions in which they serve as index numbers for the Password array; for these expressions, JavaScript automatically converts the input# strings to numbers. The Password[input#] returns are respectively assigned to the variables pw1, pw2, and pw3.

var pw = pw1 + pw2 + pw3;

The pw# strings are concatenated as shown above, and the resulting string is assigned to the variable pw.

if (pw == pw1 + pw2 + pw3) {
location.href = pw + ".html"; } }

The string .html is appended to pw and the resulting URL string is assigned to location.href, setting up a link to pw.html. The if (pw == pw1 + pw2 + pw3) { ... } container, whose condition necessarily returns true, serves no purpose and should be removed.

At the script's demo page, an input1=1 input2=4 input3=5 password takes the user to a joe.html target page; as shown earlier, Password[1] returns j, Password[4] returns o, and Password[5] returns e. For other input1=# input2=# input3=# three-digit passwords, the user is sent to a "404 - File not found" page.

Data validation

At this point, I'm sure at least a few of you are thinking, "So what happens if the user puts 145 into the u1 field and leaves the u2 and u3 fields blank? For that matter, what happens if the user respectively enters, say, A, B, and C into the u# fields?" In these cases:
(a) 145, the empty string, A, B, and C are not recognized as valid index numbers for the Password array;
(b) the pw# variables return undefined and the pw variable returns NaN, and as a result,
(c) nothing happens - no linking occurs and no errors are thrown, and the script document just sits there - at least that's what I see on my computer.

Per the discussion above, adding maxlength="1" attributes to the u# input elements will choke off the input1=145 possibility but not the input1=A input2=B input3=C possibility - what to do? Fortunately, we can very easily preempt all invalid u# inputs via a simple regular expression as follows:

(1) In the script's GoIn( ) function, follow the var input# = document.userInput.u#.value; statements with the if block below:

if (!/^\d$/.test(input1) || !/^\d$/.test(input2) || !/^\d$/.test(input3)) {
window.alert("Your password is invalid.\nPlease enter a single number into each text box.");
document.forms[0].reset( );
document.forms[0].u1.focus( ); }

Comments
• The ^\d$ regexp pattern matches a single [0-9] digit.
^\d$ and input# are compared via the test( ) method of the core JavaScript RegExp object.
• If any of the u# fields does not contain a single digit, then /^\d$/.test(input#) returns false but is converted to true by the ! NOT logical operator.

(2) Wrap GoIn( )'s subsequent statements in an else { ... } container.

Centering a form

The Script Tip #75 Script has one presentational aspect: a center element that centers the userInput form and its controls. The form element is a block-level element, and you'd therefore think that a form could be centered by setting its CSS margin-left and margin-right properties to auto: not quite true. If we replace the script's center element with a

form { margin-left: auto; margin-right: auto; }

style rule, then the userInput controls become left-justified (to use the argot of CSS, they 'float left'); this is because the form element itself has an effective width of 100%, i.e., it spans the entire width of the browser window - this can be verified by giving the form a border via a border: 1px solid CSS declaration. However, if we also give the form a specific width that is less than the browser window width, e.g.,

form {margin-left: auto; margin-right: auto; width: 350px; }

then the form and its controls will be nicely centered.

A 'structured' form

The u# text boxes are a group of "thematically related controls", and the pre-userInput "Put in Your Three-Number Password to Enter:" string is semantically a caption, so perhaps we should further mark up the userInput form with a fieldset element and a legend element:

<form name="userInput" action="">
<fieldset>
<legend>Put in Your Three-Number Password to Enter:</legend>
<input name="u1" size="2" />
<input name="u2" size="2" />
<input name="u3" size="2" />
</fieldset>
<input type="button" value="Enter" onclick="GoIn( );" />
</form>

(Validation note: placing the "Put in Your Three-Number Password to Enter:" string in a legend element removes its violation of the content model of the body element, which should not have a #PCDATA 'child'.)

Here's what it looks like on the page:

Put in Your Three-Number Password to Enter:



FYI: HTML Goodies' Forms Tutorial sector contains a somewhat-dated "Fieldsets and Legends" tutorial, which notes that the fieldset and legend elements were once proprietary MSIE-specific elements and were accordingly "ignored" by Netscape; however, the W3C picked them up for HTML 4.0 and modern versions of Netscape do recognize them. In addition to discussing and illustrating fieldsets and legends, this tutorial offers an old-school, but effective, method for setting a form width: put the form in the cell of a one-row, one-cell table and equip the parent table element with a width="###" attribute (the width attribute has been deprecated for the td element but is still legit for the table element).

One box

If you'd prefer that the user enter the password into one text box and not three, then the necessary changes are quite simple:

(1) Replace the u# text boxes with:

<input name="u1" size="5" maxlength="3" />

(2) In the GoIn( ) function, replace the var input# = document.userInput.u#.value; statements with:

var myInput = document.forms[0].u1.value;
var input1 = myInput.charAt(0); // returns the 0th u1 character
var input2 = myInput.charAt(1); // returns the 1st u1 character
var input3 = myInput.charAt(2); // returns the 2nd u1 character

The charAt( ) method of the String object is discussed here.

(3) To preempt non-three-digit passwords, follow the preceding four statements with:

if (!/^\d{3}$/.test(myInput)) {
window.alert("Your password is invalid.\nPlease enter a three-digit number into the text box."); // etc.

In the next entry we'll take up the Script Tips #76-78 Script, which in effect unfurls and furls a menu of links in response to mouseover and mouseout events, respectively.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

Actually, reptile7's JavaScript blog is powered by Café La Llave. ;-)