Previous Page
Next Page

Displaying "New to You" Messages

You can use cookies and JavaScript to alert frequent visitors to your site to items that are new to them. This gives the user a more personalized experience when they visit your site, making it a smarter and friendlier place. Script 10.9 and Script 10.10 add a little "New!" image to the beginning of lines when the cookie says that a line has been added since the last time the visitor was there (Figure 10.9). Again, you'll see familiar code from previous examples in this chapter.

Script 10.9. The CSS used in the HTML of this page applies the next script's results to the page.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
     <title>New for You</title>
     <script language="Javascript"  type="text/javascript"  src="script07.js">
     </script>
     <style type="text/css">
        p.newImg {
           padding-left: 35px;
           background-image: url(images/new.gif);
           background-repeat: no-repeat;
       }
      </style>
</head>
<body bgcolor="#FFFFFF">
     <p>Negrino and Smith's most recent books:</p>
     <p id="New-20060901"><a href="http://www. javascriptworld.com/">JavaScript && Ajax 
for the Web: Visual QuickStart Guide, 6th Edition</a></p>
     <p id="New-20051221"><a href="http://www. dreamweaverbook.com/">Dreamweaver 8 for 
Windows &amp; Macintosh: Visual QuickStart Guide</a></p>
</body>
</html>

Script 10.10. This script can help you personalize your site by alerting the user to new content.

window.onload = initPage;

function initPage() {
     var now = new Date();
     var lastVisit = new Date(cookieVal ("pageVisit"));
     var expireDate = new Date();
     expireDate.setMonth(expireDate.getMonth()+6);

     document.cookie = "pageVisit=" + now + ";expires=" + expireDate.toGMTString();
     var allGrafs = document.getElementsByTagName("p");

     for (var i=0; i<allGrafs.length; i++) {
        if (allGrafs[i].id.indexOf("New-") != -1) {
           newCheck(allGrafs[i],allGrafs[i]. id.substring(4));
        }
     }

     function newCheck(grafElement,dtString) {
        var yyyy = parseInt(dtString.substring (0,4),10);
        var mm = parseInt(dtString.substring (4,6),10);
        var dd = parseInt(dtString.substring (6,8),10);
        var lastChgd = new Date(yyyy,mm-1,dd);

        if (lastChgd.getTime() > lastVisit. getTime()) {
           grafElement.className = (grafElement.className == "") ? "newImg" : "newImg " + 
 grafElement.className;
        }
     }
}

function cookieVal(cookieName) {
     var thisCookie = document.cookie.split("; ");

     for (var i=0; i<thisCookie.length; i++) {
        if (cookieName == thisCookie[i].split ("=")[0]) {
           return thisCookie[i].split("=")[1];
        }
     }
     return "1 January 1970";
}

Figure 10.9. JavaScript can ask a cookie when you've last visited a site and flag new items for you.


To display a "New to You" message:

1.
p.newImg {
  padding-left:
  35px; background-image: url(images/new.gif);
  background-repeat: no-repeat;
}



In Script 10.9, we use CSS to specify that anything on the page marked as a paragraph (within a <p> tag) which also has a class of newImg will have 35 pixels of padding added to the left and a "New!" image put in the background. However, since the padding ensures that nothing appears in front of the paragraph contents, the image won't look like a background pattern.

2.
<p id="New-20060901"><a href= "http://www.javascriptworld.com/">JavaScript &amp; Ajax for 
the Web: Visual QuickStart Guide, 6th Edition</a></p>
<p id="New-20051221"><a href= "http://www.dreamweaverbook.com/">Dreamweaver 8 for Windows 
&amp; Macintosh: Visual QuickStart Guide</a></p>



The id attributes on these two paragraphs will signal to the JavaScript (as we'll see shortly) that they contain dates that get compared against the information set up in the following steps.

3.
var lastVisit = new Date(cookieVal ("pageVisit"));
var expireDate = new Date();
expireDate.setMonth(expireDate. getMonth()+6);



In Script 10.10, this section initializes the now, lastVisit, and expireDate dates. The first is the current date, the second is the saved date of the surfer's last visit to the site, and the last will be the expiration date of the cookie when it's rewritten.

4.
document.cookie = "pageVisit=" + now + ";expires=" + expireDate. toGMTString();



This line writes the cookie, putting the current date into the pageVisit value and the value of expireDate into expires.

5.
var allGrafs = document.getElementsByTagName("p");



This line creates an array of all the <p> elements on the page, which allows us to go through each of them one by one looking for just the ones we care about.

6.
for (var i=0; i<allGrafs.length; i++) {



Here, we start a loop to go through the array, looking at each paragraph element in turn.

7.
if (allGrafs[i].id.indexOf("New-") != -1) {



If this paragraph has an id attribute that contains the text "New-", then we know that this is a paragraph we care about, so do the following.

8.
newCheck(allGrafs[i], allGrafs[i]. id.substring(4));



We want to check to see if this paragraph has something in it that will be new to the visitor. The newCheck() function will do that, and it's passed two parameters: the current paragraph element (allGrafs[i]) and the second part of the id attribute. The substring() grabs the part of the string from the fifth character on to the end, and as that's all we care about here, that's all we'll pass. (Remember that JavaScript strings are zero-relative, which is why the fifth character of the string is found at position 4.)

9.
function newCheck(grafElement, dtString) {



This function is expecting two parameters to be passed in, which will be referred to internally as grafElement (that paragraph element) and dtString (the second part of the id attribute).

10.
var yyyy = parseInt(dtString. substring(0,4),10);
var mm = parseInt(dtString. substring(4,6),10);
var dd = parseInt(dtString. substring(6,8),10);



Here, the date is parsed out of a string; so, for example, "20060901" is 1 September 2006.

The yyyy variable gets the first 4 digits (starting at digit 0 and ending just before digit 4), with the result of "2006". The mm variable gets the fourth and fifth digits, and the dd variable gets the sixth and seventh digits. In each case, we also do a parseInt() on the result, which forces the value returned by substring() into an integer.

More about substring()

The command substring(to,from) returns the characters in a string, starting with the to position and ending with the character just before the from position, zero-relative. So, if the string contains "20060807", and you want characters 5 and 6, you want to use substring(4,6). Your result is the string "08".

The from parameter is optional; leaving it off means you'll get the string starting from the to position all the way to the end.


11.
var lastChgd = new Date(yyyy, mm-1, dd);



Finally, we can set lastChgd, because we've got a year, month, and day. But wait! JavaScript and its bizarre dates now hit us, and we have to subtract 1 from the month to get the correct resultjust the month, mind you, not the year or day. Really. Months are zero-relative, years and days are one-relative. (See Chapter 13, "Making Your Pages Dynamic," for more on dates and their oddities.)

12.
if (lastChgd.getTime() > lastVisit. getTime()) {



Now we can compare the two dates, and only do the following line if the date that the information last changed is after the date the surfer last visited.

13.
grafElement.className = (grafElement.className == "") ? "newImg" : "newImg " + grafElement
.className;



Now, here's the slick part: we know that this is a paragraph that should display the "New!" image. So, if we add a class attribute of newImg to the <p> tag, that style (declared on the HTML page) automatically then applies to that paragraph, resulting in the display of the image.

That is, we can use JavaScript to add an attribute (and its associated value) to an element. In this case, the element is a <p>, the attribute is class, and the value of the attribute is newImg. As the element may already have an existing class, this code takes care to add the value and not just overwrite what's currently there.

Once this new attribute has been added, it triggers the browser's rendering engine to immediately and automatically apply the style to the element, causing the image to appear.

grafElement Alternative

By the way, the grafElement code could have been written as:

if (grafElement.className == "") {
   grafElement.className = "newImg";
}
else {
   grafElement.className = "newImg " + grafElement.className;
}

However, the shorthand style included in the script is not only more like what's being used on the Web, it's cleaner and more compact. (See the sidebar "There's No One Right Way," in Chapter 2, for more information.)


14.
function cookieVal(cookieName) {
  var thisCookie = document.cookie. split("; ");

  for (var i=0; i<thisCookie. length; i++) {
     if (cookieName == thisCookie[i].split("=")[0]) {
        return thisCookie[i]. split("=")[1];
     }
  }
  return "1 January 1970";
}



This is the now-familiar cookieVal() function. The only difference here is that it has been changed to return "1 January 1970" instead of zero if no cookie with that name was found, which makes the code a bit simpler elsewhere. The oddity of that date is that JavaScript thinks that is when time began, so everything should be after that. That date won't appear to the user; it's just an internal reference date for JavaScript.

Tip

  • You're probably more familiar with parseInt() being passed only a single parameter. Here, two are passed: the string to be converted, and 10. That last parameter tells parseInt() to always return a decimal number. Otherwise, when parseInt() is passed a string starting with 0, it may try to turn the result into octal (base 8 numbering), with incorrect results. In this case, a call to parseInt("09") doesn't return the same result as parseInt("09",10), and the latter is what we want. It's just a weird JavaScript thing that you need to be aware of.



Previous Page
Next Page