reptile7's JavaScript blog
Thursday, November 22, 2007
 
Rolling Out the Yellow Carpet, Part 2
Blog Entry #95

Today's post updates the layer-based "drop down menu" script of HTML Goodies' JavaScript Script Tips #76-78; a cross-browser demo will follow.

From layer to div

We begin by converting the click layer to a div element. Replace the layer element start-tag with:

<div id="click">
<!-- And, of course, replace </layer> with </div>. -->

"Where are the showmenu( ) and unshow( ) function calls??" We'll get to them in the "Better function triggers" section below.

Here's the CSS we'll apply to the click div element:

#click {
background-color: yellow;
position: absolute;
left: 200px;
top: 25px;
clip: rect(0px, 250px, 25px, 0px); }

The CSS position, left, and top properties are detailed in Chapter 9 ("Visual formatting model") of the CSS 2.1 Specification. If you'd rather not slog through the W3C's material (can't say that I blame you), then check out HTML Goodies' "So, You Want Positioning, Huh?" tutorial for a kinder, gentler discussion of CSS absolute positioning.

The CSS clip property is detailed here in Chapter 11 ("Visual effects") of the CSS 2.1 Specification; it is largely analogous to the layer element's clip attribute but with an important exception: its four length values set, in order, the top, right, bottom, and left edges of the initially visible region of the click div element.

Regarding the rect part of the clip property value, the W3C notes, In CSS 2.1, all clipping regions are rectangular. We anticipate future extensions to permit non-rectangular clipping.

The link menu

We next turn to the link menu's table element container, whose start-tag is:

<table border="0" cellspacing="10">

If desired, the border and cellspacing attributes (neither of which is deprecated) can be replaced with the following style rule set:

table {
border: 0;
border-collapse: separate;
border-spacing: 10px; }

The CSS border-collapse and border-spacing properties are discussed here in Chapter 17 ("Tables") of the CSS 2.1 Specification.

Preceding the table is an "HTML Goodies Categories" string marked up with a font element:

<font face="arial black" color="black">HTML Goodies Categories</font>

The "HTML Goodies Categories" string is semantically a table caption, so let's mark it up instead with a caption element:

<table>
<caption>HTML Goodies Categories</caption>
<tr> <!-- etc. -->

The font element's face and color attributes can be replaced with the following style rule set:

caption {
font-family: "arial black"; /* typeface values containing whitespace should be quoted */
color: black; }

Philip Shaw's "code style" Web site shows here that Arial Black is a "most common" font on both PC and Mac computers; however, to not leave out any users that don't have it, you might want to replace the above font-family declaration with:

font-family: arial, sans-serif; font-weight: bold;

As a font element string, the "HTML Goodies Categories" is left-justified with respect to the parent layer element, but as a caption element string, it becomes centered with respect to the parent table element; you can add a text-align: left; declaration to the caption CSS if you'd like to keep it left-justified.

The links in the table cells are given a 'one smaller'* font size relative to the font size of the "HTML Goodies Categories" string via the font element and its size attribute, e.g.:

<td><font size="-1"><a href="http://www.htmlgoodies.com/stips">Script Tips</a></font></td>
<!-- *In practice on my computer, if the "HTML Goodies Categories" string has a 16pt font size, then the size="-1" markup gives the "Script Tips" string a 13pt font size. -->

The table cell font elements can be replaced collectively by one simple CSS rule:

a { font-size: smaller; }

We finally address the links themselves, all of which are defective in one way or another; in source order:

(1) The "Script Tips" link leads to a "404 - File not found" page; the actual Script Tips URL is http://www.htmlgoodies.com/beyond/javascript/stips/.

(2) The "New Page" link also leads to a "404 - File not found" page; it is meant to lead to the About HTML Goodies sector, whose actual URL is http://www.htmlgoodies.com/introduction/about/.

(3) The "Beyond HTML" link is meant to lead to the index page of the Beyond HTML directory; the http://www.htmlgoodies.com/beyond URL is correct but the page in question is not reliably accessible - upon multiple attempts to follow this link, I was often routed to the HTML Goodies home page.

(4) Bizarrely, the "Tutorials" link takes me to a "404 - File not found" page when using MSIE and to the Getting Started Tutorial sector when using Netscape! It is meant to lead to the index page of the HTML and Graphics Tutorials directory, whose actual URL is http://www.htmlgoodies.com/tutorials/.

(5) The "Newsletters" link leads to a "404 - File not found" page; the actual Newsletter Archive URL is http://www.htmlgoodies.com/introduction/newsletter_archive/.

(6) The "Master List" link leads to a "404 - File not found" page; the actual Master List URL is http://www.htmlgoodies.com/beyond/master/.

I don't particularly like this set of link targets and will use a different set for my demo below.

The script element

My first go at revamping the script element's showmenu( ) function

var startx = 25;
function showmenu( ) {
for (j = 0; j < 70; j++) {
startx++;
document.getElementById("click").style.clip = "rect(0, 250, " + startx + ", 0)";
for (x = 0; x < #; x++) {
void(0); } } }

was semi-successful; the above code displayed the initially invisible region of the click div element but did so all at once and not gradually, regardless of the number (#) that I used for the inner for loop count, when using either MSIE 5.1.6 or Netscape 7.02. This outcome could have been expected, however; as documented in Blog Entry #45, neither of these browsers was able to cleanly separate the effects of the nested for loops of the animation script of HTML Goodies' JavaScript Primers #28.

Moreover, even if a user's browser executes the for loops per the script author's intention, the speed of the click rollout would be a function of the user's processor speed, which is obviously not desirable.

Fortunately and alternatively, a gradual, processor-independent click rollout is easily achieved by recursively calling the showmenu( ) function in a scheduled manner via the setTimeout( ) method of the window object:

var startx = 25;
function showmenu( ) {
startx++;
document.getElementById("click").style.clip = "rect(0, 250, " + startx + ", 0)";
if (startx < 95) window.setTimeout("showmenu( );", 70); }

The above setTimeout( ) command produces a ≅5-second rollout (70 milliseconds/pixel × 70 pixels = 4900 milliseconds).

The corresponding unshow( ) function is:

function unshow( ) {
startx--;
document.getElementById("click").style.clip = "rect(0, 250, " + startx + ", 0)";
if (startx > 25) window.setTimeout("unshow( );", 70); }

Better function triggers

For this entry, I originally intended to write a short section on the return false statements appearing in the click layer's onmouseover/onmouseout attribute values. Here's what Joe says about these statements at the end of Script Tip #76:
Note the returns are false. That means the function effect will not remain. It will want to go away, but we can't just have it popping in and out. We need to smooth that run.
If I understand him correctly, Joe is stating that the return false statements are needed to 'shut down' the showmenu( ) and unshow( ) functions when they are finished executing, and I thought, "This shouldn't be necessary.**" But for reasons beyond my understanding, the combination of the div element, the mouseevent function calls, and the gradual 'scrolling' does indeed on my computer result in some strange rollout/rollup behavior. I can initially roll out the link menu without any problems, but, for example, within the click yellow rectangle, as soon as I move the mouse cursor off of the "HTML Goodies Categories" string, the menu spontaneously rolls back up and then often rolls back down again, with or without the return false statements - not good if a user wanted to follow any of the links, needless to say. After much experimentation, I was able to "smooth" the situation somewhat via the use of the JavaScript event object plus some browser-specific coding that, as a matter of principle, I would just as soon not get into here.

I don't care for the mouseevent interface anyway, and it occurred to me that push buttons

<button type="button" onclick="showmenu( );">Roll It Out</button>
<button type="button" onclick="unshow( );">Roll It Up</button>

might be more reliable tools for calling the showmenu( ) and unshow( ) functions; this proved to be the case.

**More generally, the cancelation of events via a false function return can be used to suppress the default behaviors of certain HTML elements: for a good example thereof, see HTML Goodies' "Checkboxes: Only Two" tutorial, which we discussed in Blog Entry #47. But there's nothing to suppress - at least on the HTML side - when the mouse cursor is moved over and away from a layer or div element, so the return false statements should be deletable.

Demo

In the div below, click the Roll It Out button to roll out the link menu; each of the links is 'live' as of this writing, and will open in a new browser window. Clicking the Roll It Up button will roll up the link menu.


In Script Tips #76 and #78, Joe links to a tutorial that discusses a complementary MSIE-specific drop-down menu script, which we'll check over in the next post.

reptile7

Monday, November 12, 2007
 
Rolling Out the Yellow Carpet
Blog Entry #94

In conjunction with the release in 1997 of the Navigator 4 browser, Netscape introduced a proprietary HTML layer element for specifying a block of positioned content. Netscape correspondingly implemented in JavaScript 1.2 a client-side layer object. Netscape fleshed out the layer element/object in a "Dynamic HTML in Netscape Communicator" resource, which you won't find at the Mozilla Development Center but which a helpful Russian site has archived here.
(July 2016 Update: That helpful Russian site isn't around anymore - go get the resource at the Internet Archive.)

The layer element is somewhat of a cross between the div element and the iframe element. A layer element/object:
(a) can be (indeed, is meant to be) positioned absolutely on the page;
(b) can be moved dynamically, and even
(c) stacked along a "z-axis" perpendicular to the page;
(d) can be resized à la the window object;
(e) can be "clipped", i.e., displayed/hidden in whole or in part;
(f) can be given background colors and backgrounds à la the body element; and
(g) can load an external file via a src attribute.

Notwithstanding its versatility, however, the layer element/object is only supported by Netscape 4.x; it wasn't picked up by the W3C or by Microsoft, and from Netscape 6 onwards was dropped by Netscape/Mozilla itself, which evidently regarded it to be redundant vis-à-vis other HTML elements and CSS (in particular, the positioning capabilities and visual effects of CSS level 2).

HTML Goodies' JavaScript Script Tips #76, #77, and #78 cover a script that uses a layer, named click, to gradually roll out and roll up a tabular menu of links. In today's entry, we'll discuss the Script Tips #76-78 Script's click layer and how the script's script element acts on it (or would act on it, if the layer element/object had cross-browser support). In the following entry, we'll revamp the script and make it work with current browsers.

The Script Tips #76-78 Script can be accessed by following the Here's the Code links in all three script tips and is reproduced in the div below:

<html>

<head>

<script language="javascript">
<!--

/* Script by Tom Richardson Jr.
Permission to use this script as long as this part stays intact
Visit my website at http://home.rmci.net/gooftroop

You can change the speed of the selection to come down by changing the
x variable to be less than a greater number or you can make it go
slower by changing the x variable to be less than a smaller number. */

function showmenu( ) {

startx = document.layers["click"].clip.bottom;

for (j = 0; j < 70; j++) {

document.layers["click"].clip.bottom = startx + j;

for (x = 0; x < 120; x++) {

void(0);

} } }

function unshow( ) {

startx = document.layers["click"].clip.bottom;

for (j = 0; j < 70; j++) {

document.layers["click"].clip.bottom = startx - j;

for (x = 0; x < 120; x++) {

void(0);

} } }

// -->

</script>

</head>

<body bgcolor="#ffffff">

<layer bgcolor="yellow" name="click" left="200" top="25" clip="250,25" 
onmouseover="showmenu( ); return false;" onmouseout="unshow( ); return false;">

<font face="arial black" color="black">HTML Goodies Categories</font>
<br>
<table border="0" cellspacing="10">
<tr>
<td><font size="-1"><a href="http://www.htmlgoodies.com/stips">Script Tips</a></font></td>
<td><font size="-1"><a href="http://www.htmlgoodies.com/new.html">New Page</a></font></td>
<td><font size="-1"><a href="http://www.htmlgoodies.com/beyond">Beyond HTML</a></font></td>
</tr>
<tr>
<td><font size="-1"><a href="http://www.htmlgoodies.com/tutors">Tutorials</a></font></td>
<td><font size="-1"><a href="http://www.htmlgoodies.com/letters">Newsletters</a></font></td>
<td><font size="-1"><a href="http://www.htmlgoodies.com/tutors/master.html">Master List</a></font></td> 
</tr>
</table>

</layer>

</body>

</html>

The click layer

The Script Tips #76-78 Script document's body element has one child: a layer element whose start-tag is:

<layer bgcolor="yellow" name="click" left="200" top="25" clip="250,25"
onmouseover="showmenu( ); return false;" onmouseout="unshow( ); return false;">

Let's run through the layer element attributes in order.

(1) Like the body, table, tr, td, and th elements, the layer element has a bgcolor attribute that (when present) gives it a solid background color, yellow in this case.

(2) The layer is given a name="click" attribute identifier, but Netscape would have preferred that we use an id attribute for this purpose: The id attribute was previously called name. The name attribute still works, but its use is discouraged, since it is only applicable to the <layer> tag [and not to the <ilayer> tag].

A name/id attribute is unnecessary here, however; in the script's script element, the click layer can be referenced via a document.layers[0] expression.

(3-4) The left and top attributes position the left and top edges of the click layer relative to the left and top edges of the document content area: left="200" pushes click's left edge 200 pixels to the right of the document's left edge, whereas top="25" pushes click's top edge 25 pixels below the top of the document. I find that left and top are %Length; attributes, i.e., the left/top value can be a pixel integer or a percentage.

(5) Regarding the clip attribute, in Script Tip #76 Joe says:
Now we get into shaping the layer when it first appears. The attribute "CLIP" is set to two numbers. The first number [250] refers to the width and the second [25] to the height.
Not a bad start, but there's more to it than this. The clip attribute "clips" a layer (sort of like clipping a newspaper article) by defining a rectangle that surrounds a visible subset of the layer relative to the actual edges of the layer; the rest of the layer outside the rectangle is not visible. A clip="250,25" attribute is shorthand for clip="0,0,250,25", whose four number values have the following meanings:
• The first 0: the left edge of the layer's visible region is 0 pixels to the right of the layer's left edge (the two edges coincide).
• The second 0: the top edge of the layer's visible region is 0 pixels below the layer's top edge (the two edges coincide).
250: the right edge of the layer's visible region is 250 pixels to the right of the layer's left edge.
25: the bottom edge of the layer's visible region is 25 pixels below the layer's top edge.

The visible region of a clip="a,b,c,d" layer thus has a width of c-a and a height of d-b, and it follows that the visible region of a clip="c,d" layer has a width of c and a height of d, as is the case here.

FYI: the layer element has specific width and height attributes for setting its actual width and height, respectively.

(6-7) The onmouseover and onmouseout event handlers will call the script element's showmenu( ) and unshow( ) functions, respectively. At first glance, the accompanying return false statements seem unnecessary, but I'll have more to say about them later.

The initially visible region of the click layer holds an "HTML Goodies Categories" string marked up with a (deprecated) font element. The initially invisible region of the click layer holds a two-row, six-cell table. Each table cell contains a link to an HTML Goodies sector; most of these links, which are also marked up with font elements, are broken. We'll clean up this code after we deconstruct the script, bringing us to...

Deconstructing the Script Tips #76-78 Script

Let's suppose that you're browsing with Netscape 4.x and that you follow Script Tip #76's Script's Effect link to the script demo page. Per the discussion above, you see a 'boldened'* "HTML Goodies Categories" string in a 250px-by-25px yellow rectangle (*assuming that the Arial Black font is on your computer):

HTML Goodies Categories

You move the mouse cursor over the "HTML Goodies Categories" string, triggering the script's showmenu( ) function.

function showmenu( ) {
startx = document.layers["click"].clip.bottom;

Layers are referenced as are other document 'collections' (forms, images, links, etc.): either (a) via a layers[ ] array indexed with ordinal numbers or associatively

document.layers[0] // or
document.layers["click"]

or (b) by name:

document.click

The read/write clip.bottom property of the layer object corresponds to the fourth number value of the layer element's clip attribute, i.e., clip.bottom specifies the pixel distance between a layer's actual top edge and the bottom edge of its visible region. The document.layers["click"].clip.bottom value, set at 25 in the script's HTML, is assigned to the variable startx.

for (j = 0; j < 70; j++) {
document.layers["click"].clip.bottom = startx + j;
for (x = 0; x < 120; x++) {
void(0); } } }

A pair of nested for loops expands the click visible region by shifting the clip.bottom edge 'southward'. As the counter variable j of the outer loop increments, startx+j and document.layers["click"].clip.bottom also increment; each iteration of the outer loop thus adds a 250px-by-1px 'layer' to (the bottom of) the click visible region.

The inner loop, Joe notes in Script Tip #77, doesn't produce anything. It simply marks time until the first loop can run again, enabling the rest of the click layer to be displayed gradually and not all at once. Its void(0) operator expression is a placeholder of sorts, returning undefined, which has no effect in JavaScript, Netscape states. (Contra the void operator entry in the JavaScript 1.5 Core Reference, void(0) does not return 0; contra Script Tip #78, the void(0) expression does not stop the loop à la the break statement.) Can the void(0) command be commented out? Consider the animation script of HTML Goodies' JavaScript Primers #28, which uses a statementless

for (x = 1; x < 800; x = x + 1) { }

loop to set a time delay. However, the syntax of the for statement shows that the statement(s) in braces is the one for parameter that isn't optional, so let's just let the void(0) line be.

And how does this all work in practice? As I have Netscape Communicator 4.79 (which you can download for free here) on my hard disk, I can report that when I adjust the inner for loop condition to x<1200, then the script works as advertised; mousing over the "HTML Goodies Categories" string smoothly rolls out the click link menu to give:

HTML Goodies Categories
Script TipsNew PageBeyond HTML
TutorialsNewslettersMaster List

(The links won't take you anywhere - their href attributes have been set to empty strings.)

At this point we have a 250px-by-95px block of content. For rolling up the click link menu, moving the mouse cursor off of the click layer triggers the script's unshow( ) function, which, Joe points out in Script Tip #78, differs from the showmenu( ) function by one keystroke; specifically, the click clip.bottom value is decremented by the outer for loop via:

document.layers["click"].clip.bottom = startx - j;

At the end of the unshow( ) function, the click layer's visible region has shrunk to the 250px-by-25px block shown earlier.

We're now ready to bring the Script Tips #76-78 Script into the modern era and we'll do that in the next post.

reptile7

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


Powered by Blogger

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