reptile7's JavaScript blog
Wednesday, July 18, 2007
 
That's the Way the Cookie Script Crumbles
Blog Entry #82

For most of today's post we will deconstruct the cookie script of HTML Goodies' JavaScript Script Tips #60-63. The Script Tips #60-63 Script can actually be accessed - Land o' Goshen! - by following the "Here's the Code" links in all four script tips, and is reproduced in the div below:

<script language="javascript">

<!--

// This script was made by Giedrius gietam@eunet.lt

cookie_name = "NameCookie2010";
var GuestName;

function putCookie( ) 
{
if (document.cookie) 
{ index = document.cookie.indexOf(cookie_name);
}
else { index = -1; } 

if (index == -1)
{
GuestName = window.prompt("Hello! What's your name?","Nobody");
if (GuestName == null) GuestName = "Nobody";
document.cookie = cookie_name + "=" + GuestName + "; expires=Tuesday, 05-Apr-2010 05:00:00 GMT";
}
else
{
namestart = (document.cookie.indexOf("=", index) + 1);
nameend = document.cookie.indexOf(";", index);
if (nameend == -1) { nameend = document.cookie.length; }
GuestName = document.cookie.substring(namestart, nameend);
if (GuestName == "Nobody")
{
GuestName = window.prompt("Hello again!!!" + "\n" + "Last time you didn't tell me your name. Maybe you want to do it now?","Nobody");
if ((GuestName != "Nobody") && (GuestName != null))
{ document.cookie = cookie_name + "=" + GuestName + "; expires=Tuesday, 05-Apr-2010 05:00:00 GMT"; }
if (GuestName == null) GuestName = "Nobody";
}
}
}

function getName( ) 
{
if (document.cookie)
{
index = document.cookie.indexOf(cookie_name);
if (index != -1)
{
namestart = (document.cookie.indexOf("=", index) + 1);
nameend = document.cookie.indexOf(";", index);
if (nameend == -1) { nameend = document.cookie.length; }
GuestName = document.cookie.substring(namestart, nameend);
return GuestName;
}
}
}

putCookie( );
GuestName = getName( );

//STOP HIDING THE SCRIPT-->

</script> 

<!-- What is below will appear on the page itself --> 

<script>
document.write("Hello, " + GuestName + ", nice to meet you!!!");
</script>

Joe provides a demo page for the Script Tips #60-63 Script here.

Let's get rolling, shall we? Scalpel please, nurse...



<script language="javascript">
cookie_name = "NameCookie2010";
var GuestName;

The Script Tips #60-63 Script will set on the user's hard disk a cookie whose name attribute value is NameCookie2010 and whose value attribute value is held in the script by the variable GuestName. We begin by assigning the NameCookie2010 string to the variable cookie_name; subsequently, GuestName is declared but not initialized.

putCookie( );

The action moves to the next-to-the-last command line of the script's first script element: a call for the putCookie( ) function.

function putCookie( ) {
if (document.cookie) {

Next we have an if statement whose condition tests if there are any cookies associated with the current document; recall from the previous post that the document.cookie expression returns those cookies with validly matching domain and path attribute values and that such cookies do not need to have been set by the current document. (The if line has the form of a property-detection conditional but is obviously not meant to test the browser's support for the cookie property, which was implemented in the very first versions of JavaScript and JScript and is recognized by all but the most ancient browsers.)

If none of the browser's cookies is valid, then document.cookie returns an empty string, which is converted to false in a Boolean context; conversely, a document.cookie string of one or more matching cookies would convert to true here. And if the if condition returns true...

index = document.cookie.indexOf(cookie_name); }

This line checks if cookie_name (NameCookie2010) is present in the document.cookie return; if so, the character index of the starting N in the document.cookie string is assigned to the variable index.

For example, if document.cookie returns:
(a) NameCookie2010=Joe; Cookie2Name=Cookie2Value, then
index will return 0;
(b) Cookie1Name=Cookie1Value; NameCookie2010=Joe, then
index will return 26;
(c) Cookie1Name=Cookie1Value, then
index will return -1.

else { index = -1; }

If document.cookie is 'empty' and the preceding if condition returns false, then -1 is assigned to index.

if (index == -1) {
GuestName = window.prompt("Hello! What's your name?","Nobody");
if (GuestName == null) GuestName = "Nobody";
document.cookie = cookie_name + "=" + GuestName
+ "; expires=Tuesday, 05-Apr-2010 05:00:00 GMT"; }

Whether or not there are any cookies associated with the current document, an index value of -1 signals that the user is a first-time visitor*, to which this if block applies.
(*The converse is not true: as we'll explain later, if the user is a first-time visitor, then it doesn't necessarily follow that index is -1.)

First, the name-soliciting prompt( ) box below pops up:

Cookie script prompt for first-time visitors

The user types into the prompt( ) input field a name that, after the OK button is clicked, is outputted/assigned to GuestName.
• If the user doesn't enter a name into the prompt( ) field but just clicks the OK button, then the presupplied string Nobody will be assigned to GuestName.
• If the user clicks the Cancel button, then the primitive value null is assigned to GuestName; in this case, the following if (GuestName == null) GuestName = "Nobody" command line assigns Nobody to GuestName.
• Contra Script Tip #61, Nobody is not assigned to GuestName if the user clears the prompt( ) field and clicks the OK button; rather, an empty string is assigned to GuestName in this case.

Second, a NameCookie2010 cookie is written to the user's hard disk: cookie_name, "=", GuestName, and "; expires=Tuesday, 05-Apr-2010 05:00:00 GMT" are concatenated and the resulting string is assigned to document.cookie. This statement differs from a normal assignment statement in that the NameCookie2010 cookie is added to, and does not overwrite, any previously existing document.cookie cookies.

NameCookie2010's expires attribute value features a four-digit year but otherwise conforms exactly to the expires format given in Netscape's cookie property documentation.

else {

The following else block executes if the document.cookie string contains a NameCookie2010 cookie. Its first few statements extract NameCookie2010's value value; if this value is Nobody, then the user is given another chance to offer a Name and write a new NameCookie2010=Name cookie.

namestart = (document.cookie.indexOf("=", index) + 1); /* The outer parentheses are unnecessary. */

The right side of this statement returns the character index in the document.cookie string that is one past the index of the first = character following index, the character index of NameCookie2010's starting N.

For example, if document.cookie returns
NameCookie2010=Joe; Cookie2Name=Cookie2Value, then
index returns 0 and
document.cookie.indexOf("=", index)+1 will return 15.

The document.cookie.indexOf("=", index)+1 expression thus gives the position of the first character of NameCookie2010's value value (J in the example above) - this index is assigned to the variable namestart.

nameend = document.cookie.indexOf(";", index);

The right side of this statement returns the character index in the document.cookie string of the first semicolon following the index index. For example, if document.cookie returns
NameCookie2010=Joe; Cookie2Name=Cookie2Value, then
document.cookie.indexOf(";", index) will return 18.

The document.cookie.indexOf(";", index) expression thus gives the index position one past the last character of NameCookie2010's value value - this index is assigned to the variable nameend.

if (nameend == -1) { nameend = document.cookie.length; }

This conditional comes into play if the NameCookie2010 cookie is the last cookie in the document.cookie return and consequently NameCookie2010's value value is not followed by a semicolon. (Contra Script Tip #61, this if statement has no connection to NameCookie2010's expires attribute, which is not returned in the document.cookie string.)

If, for example, document.cookie returns
Cookie1Name=Cookie1Value; NameCookie2010=Joe, then
document.cookie.length will return 44, which will be assigned to nameend.
As for the preceding line, nameend represents the index position** immediately following the last character of NameCookie2010's value value (**in this case a characterless position beyond the end of the string).

GuestName = document.cookie.substring(namestart, nameend);

This line returns, and assigns to GuestName, NameCookie2010's value value (Joe if we were to stay with the above examples).

if (GuestName == "Nobody") {
GuestName = window.prompt("Hello again!!!" + "\n"
+ "Last time you didn't tell me your name. Maybe you want to do it now?","Nobody");

If GuestName is equal to Nobody (vide supra), then the prompt( ) box below pops up:

Cookie script prompt for return visitors if GuestName is Nobody

A \n newline may not induce a line break in most HTML settings, but as you can see, it definitely induces a line break on a prompt( ) box.

if ((GuestName != "Nobody") && (GuestName != null)) {
document.cookie = cookie_name + "=" + GuestName
+ "; expires=Tuesday, 05-Apr-2010 05:00:00 GMT"; }

If the user does not merely click the prompt( ) OK or Cancel button (as before, these responses assign respectively Nobody and null to GuestName) but changes the prompt( ) input field string in some way and clicks the OK button, then a new NameCookie2010=GuestName cookie is written/added to the document.cookie string.

FYI: in JavaScript, comparison operators have a higher precedence than logical operators, and thus the parentheses surrounding (GuestName != Nobody) and (GuestName != null) are unnecessary.

if (GuestName == null) GuestName = "Nobody"; } } }

The putCookie( ) function ends with an if statement that assigns Nobody to GuestName if the user clicks the Cancel button on the "Hello again!!!" prompt( ) box; as Joe points out in Script Tip #62, this ensures that the user will be reprompted for a name upon a return visit.

GuestName = getName( );

We move now to the last command line of the script's first script element: a call for the getName( ) function, whose output will be assigned to GuestName.

function getName( ) {
if (document.cookie) {
index = document.cookie.indexOf(cookie_name);
if (index != -1) {

• The if (document.cookie) { line and its concluding } right brace can be removed, because the document.cookie condition necessarily returns true for both first-time and return visitors.
• As in the putCookie( ) function, the index = document.cookie.indexOf(cookie_name) line locates the NameCookie2010 cookie in the document.cookie string and assigns the character index of the starting N to index.
• The if (index != -1) { line and its concluding } right brace can be removed, because the index != -1 condition necessarily returns true for both first-time and return visitors.

namestart = (document.cookie.indexOf("=", index) + 1);
nameend = document.cookie.indexOf(";", index);
if (nameend == -1) { nameend = document.cookie.length; }
GuestName = document.cookie.substring(namestart, nameend);

As in the putCookie( ) function, these statements extract and assign to GuestName the NameCookie2010 value value.

return GuestName; } } }

NameCookie2010's value value is returned to the GuestName = getName( ) command line and assigned once again to GuestName.

We're ready to greet the user by name via the script's second script element:

<script>
document.write("Hello, " + GuestName + ", nice to meet you!!!");
</script>

Perhaps you are wondering, "Why don't we put the getName( ) function call in the document.write( ) command?" - well, that would be more efficient, wouldn't it?

document.write("Hello, " + getName( ) + ", nice to meet you!!!");

The Script Tip #64 Script

The Script Tip #64 Script attempts to distinguish first-time and return visitors via a FirstTime variable and makes the following minor changes to the Script Tips #60-63 Script:
(1) A 'global' var FirstTime declaration is placed just before the function putCookie( ) declaration.
(2) A FirstTime = "n" statement for flagging a return visitor is added to putCookie( )'s first if statement.
(3) A FirstTime = "y" statement for flagging a first-time visitor is added to putCookie( )'s first else statement.
(4) The second script element is recast as:
<script language="javascript">
if (FirstTime == "y") { document.write("Hello, " + GuestName + ", nice to meet you!!!"); }
else { document.write("Hello, " + GuestName + ", welcome back!!!"); }
</script>

In theory, a first-time visitor is greeted with Hello, (prompt( ) output), nice to meet you!!, whereas a return visitor is greeted with Hello, (prompt( ) output), welcome back!!!, and in practice - check out the Script Tip #64 Script demo page here - this is what the user is likely to see. We noted earlier that a -1 index value definitely identifies a first-time visitor. However, the if (document.cookie) and index = document.cookie.indexOf(cookie_name) command lines cannot be used to unambiguously identify a return visitor, and I'll explain why in the next entry.

reptile7

Comments: Post a Comment

<< Home

Powered by Blogger

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