reptile7's JavaScript blog
Friday, May 18, 2012
 
Take Me to the value, Part 2
Blog Entry #251

In today's post we will put forward an alternative coding for the cookie redirect script of HTML Goodies' "How Can I Set A Cookie Based On A User's Selection On A Form?" tutorial. We stick with the script's checkbox interface in the Original overhaul section; we'll go after the checkboxes in the subsequent Checkbox more is less section.

Original overhaul

Setting the cookie

Recall that each cookie.html checkbox input has an onclick attribute that feeds device, this.name, and exp to the cookieRedirect.js SetCookie( ) function if the checkbox is clicked.

<input type="checkbox" name="Android" onclick="SetCookie('device', this.name, exp);">Android

The SetCookie( ) arguments are respectively used to set the name, value, and expires attributes of the redirection cookie. If desired, the SetCookie( ) call can be equipped with additional arguments for setting the path, domain, and secure attributes of the redirection cookie, e.g.:

onclick="SetCookie('device', this.name, exp, '/', '.earthlink.net', true);"

My preferred approach to parameterizing SetCookie( ) is to
(a) set all of the checkbox names to device and
(b) give each checkbox a value attribute set to the appropriate iPhone|iPad|Android|Palm string and then
(c) pass this.name and this.value to SetCookie( ).
An element should not be passing expressions to a function if those expressions are wholly unrelated to the element; to the extent that you make use of them, the redirection cookie's expires/path/domain/secure settings should be kept out of the onclick assignment and hard-coded in the SetCookie( ) function body.

Regarding the redirection cookie's expiration date:

• The exp Date object is defined (created and postdated) globally and thus over and over for first-time/return visits; moving the exp definition to the SetCookie( ) function wouldn't guarantee that it'd be executed only once (depending on how the visitor interacts with the checkboxes) although I think we're better off putting it there than deploying it as top-level code.

• Via the Date object's getDate( ) and setDate( ) methods, we can postdate exp by a day-based calculation vis-à-vis a millisecond-based calculation. Quoting Microsoft:
dateObj.setDate(numDate);

If the value of numDate is greater than the number of days in the month stored in the Date object or is a negative number, the date is set to a date equal to numDate minus the number of days in the stored month. For example, if the stored date is January 5, 1996, and setDate(32) is called, the date changes to February 1, 1996. Negative numbers have a similar behavior.
• The toGMTString( ) method of the Date object is deprecated; you should use the toUTCString( ) method instead.

Putting it all together gives us:

function SetCookie(name, value) {
    var exp = new Date( );
    exp.setDate(exp.getDate( ) + 30);
    document.cookie = name + "=" + value + "; expires=" + exp.toUTCString( )
    /* + "; path=somePath; domain=someDomain; secure"; */ }
...
<input type="checkbox" name="device" value="Android" onclick="SetCookie(this.name, this.value);">Android


Other notes:

(1) In the original SetCookie( ) function the value argument is subjected to an escape( ) operation, which might be needed if the visitor were inputting the value; however, you the Webmaster are the one setting that value, and as long as you don't put any 'offending characters' (spaces, commas, semicolons, non-ASCII characters) in the value, then the escape( ) treatment is unnecessary. BTW, the escape( ) function is deprecated.

(2) The use of arguments as a property of a Function object as appears in the original SetCookie( ) function (e.g., var argv = SetCookie.arguments;) is also deprecated, but as shown above the arguments code - with or without a preceding SetCookie reference, and including the argv[i] ?: conditional stuff - is easily chucked once the SetCookie( ) parameterization has been brought under control.

Getting the cookie

The cookieRedirect.js script sports discrete functions for locating the redirection cookie's name (GetCookie( )) and for extracting the redirection cookie's value (getCookieVal( )). Does it seem to you, as it does to me, that this is taking the modularity/division-of-labor thing a bit too far? We have previously worked with value-extracting cookie scripts, e.g., the HTML Goodies JavaScript Script Tips #60-63 Script: these scripts extract a cookie value à la the getCookieVal( ) function; however, they determine the (j/offset) starting index of the value via a straightforward

valueIndex = document.cookie.indexOf("=", nameIndex) + 1;

statement and not via a separate function/while loop, and there's no reason to not do this in the cookieRedirect.js script and thereby cut out the GetCookie( ) function.

function getCookieVal(cookieName) {
    var nameIndex = document.cookie.indexOf(cookieName);
    if (nameIndex != -1) {
        var valueIndex = document.cookie.indexOf("=", nameIndex) + 1;
        var endstr = document.cookie.indexOf(";", valueIndex);
        if (endstr == -1) endstr = document.cookie.length;
        return document.cookie.substring(valueIndex, endstr); }
    else return null; }
var favorite = getCookieVal("device");


The original getCookieVal( ) return is subjected to an unescape( ) operation, which is unnecessary if the SetCookie( ) value didn't need to be escape( )d in the first place (vide supra). Like the escape( ) function, the unescape( ) function is deprecated.

Redirecting the visitor

Is it really necessary to run through a switch statement to map a cookie value onto its redirection URL? Nope, not at all. If we were to all-lowercase the iphone/ipad/android/palm checkbox names ⇒ values, then an

if (favorite) window.location = favorite + ".html";

statement* that (a) appends an .html extension to favorite and
(b) assigns the resulting string to window.location
is all we would need to redirect the visitor - couldn't be simpler, eh?

*The original statement's condition tests if favorite is not equal to null, which is overkill given that non-empty strings convert to true in a logical context whereas null itself converts to false in a logical context.

Delete it

Sandwiched between the SetCookie( ) function and the var favorite = GetCookie("device"); statement in the cookieRedirect.js script is a DeleteCookie( ) function:

function DeleteCookie(name) {
    var exp = new Date( );
    exp.setTime(exp.getTime( ) - 1);
    var cval = GetCookie(name);
    document.cookie = name + "=" + cval + "; expires=" + exp.toGMTString( ); }


The DeleteCookie( ) function overwrites the original device=value cookie with a new device=value cookie whose expiration date is set one millisecond into the past, effectively deleting the original device=value cookie. The DeleteCookie( ) function is never called and can itself be deleted; conversely, there is something to be said for appending a button to the checkbox menu

<button type="button" onclick="DeleteCookie('device', this.form);">Clear the cookie and reset the form</button>

and an arguments[1].reset( ); command to the DeleteCookie( ) function body so that the visitor can start over, if desired.

Checkbox more is less

Let's do this next time.

Comments: Post a Comment

<< Home

Powered by Blogger

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