Basic JavaScript

You should play around with the previous JavaScripts. Incorporate them into a “real” web page or two. When you feel familiar with them, we can start doing some more intensive programming.

A Smart “File Stamp”

It is very useful to have a “generic” part for your web pages, something that stays basically the same throughout each page. This “footer” or “header” can include a link back to your home page, the last date the page was updated, perhaps a link to the parent page if this is a subsidiary page on your web site. Let’s create a JavaScript that creates a table of this information on our web page. Add the following function to your “scripts.js” file:

function filestamp() {
homePage=new String('/html/NetLife/');
document.write('<table border="1" align="right">');
document.write('<tr><thalign="right">', document.title, '</th></tr>');
document.write('<tr><tdalign="right"><ahref="', homePage, '">Home</a></td></tr>');
document.write('</table>');
}

The first line creates a “String” object, calls it “homePage”, and gives it the value “/html/NetLife/”. What does that mean? Remember that JavaScript deals with objects. A “String” object is a collection of text. Your name could be a String object; your home town; just about anything normal that isn’t something which you can add or subtract. Things you can add, subtract, multiply, etc., are “Numbers”. Your income and your height in inches are numbers. Your phone number or social security number are strings.

In this case, we made a new String and we put “/html/NetLife/” into it. You will actually want to put your own home page path into. This tutorial site’s home page is http://www.hoboes.com/html/NetLife/ and the path is the part after the hostname, that is, /html/NetLife/. If your home page is http://www.sandiego.edu/~brunetti/, your home page path is /~brunetti/.

We will use the “homePage” String later in this program.

document.write('<table border="1" align="right">');

If you remember your HTML code for tables, you’ll recognize the part inside the straight quotes as the beginning of a right-aligned table with a thin border. “write()” is a function on the “document” object. It inserts HTML code into the web page (the “document”). What does it write? It writes whatever arguments you give it. You can give it as many arguments as you want. It will write each one, in order, to your web page.

document.write('<tr><thalign="right">', document.title, '</th></tr>');

If you count them, you’ll see three arguments given to “document.write()”. The first argument opens the table row and the table header; the second argument is something called “document.title”, and the third argument closes the table header and the table row. What is “document.title”? Remember that “document” is our web page. So “document.title” is the title of our web page. It is whatever we put between the “<title>” and “</title>” in the “<head>” area of the web page.

The next line is just like the previous one, except that it puts a link to the home page inside of a normal table cell. The last line closes the table.

Now, let’s make a web page to put use this script on. Call it “advanced.html”:

<html>

<head>
<title>JavaScript Programming Tutorial</title>
<script src="scripts.js" language="JavaScript"></script>
</head>

<body>
<script language="JavaScript">
filestamp();
</script>
<h1> Making a Global File Stamp</h1>
<p>Of course the unexpected often looks as if it were expected. Some indeed expect the unexpected. Such is life. This leaves me in a pretty pickle and I hope you won’t refer me and my questions to Sheet, for Sheet, according to this paper has been silent since last night.</p>
<p>Your questions? You know the loan was given to the shipyard don’t you?</p>
</body>

</html>

Scripting Your Web Pages

Home

And you should get a ‘file stamp’ on the right, top of your page, much like I have one to the right of this paragraph. See http://www.hoboes.com/NetLife/Web_Scripting/lessons/lesson5.html for the example.

Last Update

Many web pages on the net tell you when they were last updated. This is commonly done by the web designer actually typing in the new date whenever they make a change. But that’s prone to failure, because it is easy to forget. The better way is to use “server-side includes” to have the web server automatically add this information. If you don’t want to or can’t use server-side includes (most free web hosts don’t support them, for example), you can do the same thing with javascript. So, let’s add a “Last Updated On” line to our file stamp.

We’ve already used one property of our web page: document.title. The date and time that the web page was last changed is in another property, document.lastModified. So, let’s add another line to our “filestamp” script function:

function filestamp() {
...
document.write("<tr><thalign=\"right\">",document.title,"</th></tr>");
document.write("<tr><tdalign=\"right\">LastUpdated:",document.lastModified,"</td></tr>");
...
}

Scripting Your Web Pages

Last Updated: Wed, 29-May-2002 17:06:15 GMT

Home

If you’re doing this from your local hard drive, you might see a really old date or no date at all. That’s because browsers get this information from the server, and if you’re doing this from your hard drive, there is no server. If that happens, upload the script to your web account and try from there. See http://www.hoboes.com/NetLife/Web_Scripting/lessons/lesson6.html for the example.

Suppose we want to reformat the date to something smaller? Let’s change it so that it just gives the month/day/year. This requires creating a function that takes a date as its “argument” and returns the date in the format we want, in this case just month/day/year.

JavaScript has a number of built-in functions that give us the information we need. There is a “getYear()” function, a “getMonth()” function, and a “getDate()” function to get the year, month, and day of the month from a date. That’s all the information we need, but it isn’t quite as easy as that. You may have heard about javascript being “object oriented”. That means that it has “objects” that can do things. A date is also an object, and it can do things to itself: such as give you the year, month, and day of the month for that date. The “getYear()” function is attached to all date objects, and you need a date object in order to use it.

Even though it looks like one, document.lastModified is not a date. It is a bunch of text that looks like a date. To get the year, month, and day out of it, we need to convert the text into what JavaScript recognizes as a date. The command to do this is:

myDate = new Date(document.lastModified);

The “new” function creates a new object. This is going to be a “Date” object, so the full command is “new Date()”. And the “new” command, with respect to “Date” is very intelligent: it can take a text string that looks like a date, and create a date object from that text string. By using “new Date(document.lastModified)”, we are getting a date object that is the exact date and time that our web page was last changed.

In order to use this new date object, we have to give it a name, so we can refer to it later. Like our “homePage” string, we will use “changeDate = new Date(document.lastModified);” to create a Date object called “changeDate”.

Let's go ahead and add that line to our filestamp() script. Put it above all the “document.write()” lines, below the “homePage=” line.

homePage=new String('/html/NetLife/');
changeDate = new Date(document.lastModified);

Now, you can’t just replace “document.lastModified” in the document.write line with “changeDate”. Well, you can, but you’ll get an even longer date line than you had before (go ahead and try!). We need to make a function that takes our new date object and returns just the month, day of month, and year. Let’s call it formatDate(). Change “document.lastModified” in the “document.write()” line that includes it to “formatDate(changeDate)”:

document.write('<tr><td align="right">Last Updated: ', formatDate(changeDate), '</td></tr>');

Next, we have to write the “formatDate()” function:

function formatDate(theDate) {
thisyear = theDate.getYear();
while (thisyear >= 100) {
thisyear -= 100;
}
if (thisyear < 10) {
thisyear = '0' + thisyear;
}

thismonth = theDate.getMonth();
thismonth++;
thisday = theDate.getDate();
dateformatted=thismonth + '/' + thisday + '/' + thisyear;

return dateformatted;
}

And that should give you a date line in your “stamp” that looks like, for example, 6/29/01! See http://www.hoboes.com/NetLife/Web_Scripting/lessons/lesson7.html for the example.

Some of our new “formatDate()” function (in fact, probably most of it) is a bit confusing. Let’s take this function on, one step at a time.

function formatDate(theDate) {

This creates the function called formatDate, and specifies that it can receive one “argument”, which will be called “theDate” inside of this function. When we call the “formatDate()” function, we might call it with “formatDate(changeDate)” or “formatDate(currentDate)” or even “formatDate(birthDate)”. But whatever “argument” we send “formatDate()”, it will be called “theDate” inside of the function.

thisyear = theDate.getYear();

This creates a number called “thisyear” which is the “year” portion of “theDate”.

while (thisyear >= 100) {
thisyear -= 100;
}

One of the more useful features of scripting languages such as JavaScript is the ability to “loop”, that is, to perform the same line multiple times. You will most often see this with the “while()” command. This section “loops” until the year is less than 100. That is, it keeps going “while” the number “thisyear” is “greater than or equal to” 100. The loop is the part between the “{“ and the “}”.

The line “thisyear -= 100” automatically drops the number “thisyear” by 100. (You could also do “+=” to add to a number.) The number name is on the left, the “-=” means that we are going to reduce this number by a certain amount, and the actual amount is on the right.

This gives us a number without the century. However, there is still a problem: our year is a number. By removing the century, the year 2002 will be the number “2”. Usually we represent the year as two digits, for example, “02”. So we need to fix our year if the year is less than 10:

if (thisyear < 10) {
thisyear = '0' + thisyear;
}

This prepends a “0” to the year number if the year is under 10. Note that we put the “0” in quotes. This makes the “0” a string, not a number. If we didn’t do this, we would be adding 0 to 2, which just makes 2. By making one of our items in the “calculation” a string, we force the “addition” to be string addition, which simply combines the items.

thismonth = theDate.getMonth();

Next, we get the month, as a number, from theDate.

thismonth++;

Computers have a tendency to start at 0 whenever they can. In JavaScript, months go from 0 to 11, not 1 to 12. Humans, of course, go from 1 to 12. The line “thismonth++;” adds one to the variable “thismonth”. (You could also use “--” to reduce a number by one.)

thisday = theDate.getDate();

And we get the day of the month. Even in JavaScript, the day of the month starts at one, so we don’t need to use “++” to increase it by one. Believe it or not, this is consistent. It makes sense to start the month at 0, but the day of the month at one. We’ll get to why this is consistent later, when we talk about keeping lists of items. For now, just remember that the months start at 0, and the days start at 1.

dateformatted=thismonth + '/' + thisday + '/' + thisyear;

We create a line of text that has the month, a slash, the day, a slash, and the year. We put this line of text into a line of text called “dateformatted”.

return dateformatted;

We return that line of text to whatever part of our script called the “formatDate()” function.

}

The final “}” ends the function.

You should have a script file that looks sort of like this:

//time stamp functions

function filestamp() {
homePage = new String('/html/NetLife/');
changeDate = new Date(document.lastModified);
document.write('<table border="1" align="right">');
document.write('<tr><th align="right">', document.title, '</th></tr>');
document.write('<tr><td align="right">Last Updated: ', formatDate(changeDate), '</td></tr>');
document.write('<tr><td align="right"><a href="', homePage, '">Home</a></td></tr>');
document.write("</table>");
}

function formatDate(theDate) {
thisyear = theDate.getYear();
while (thisyear >= 100) {
thisyear -= 100;
}
if (thisyear < 10) {
thisyear = '0' + thisyear;
}

thismonth = theDate.getMonth();
thismonth++;
thisday = theDate.getDate();

dateformatted=thismonth + '/' + thisday + '/' + thisyear;

return dateformatted;
}

Smart Date

Now that we’ve created a “formatDate()” function, we can make that function smarter. Why not have it say “Today” if the date we sent it (the date we last modified our web page) is today? And “Yesterday” for yesterday? This is easy to do, but we need to do a lot more “checking” inside of our “if” statement. We’ve already used “if” to do something if a certain condition is met. But we can also do one thing if one condition is met, otherwise do a second thing if a second condition is met, and if neither of those conditions are met, do a final thing instead.

Change the top and bottom of your formatDate() function to:

function formatDate(theDate) {
today = new Date();
oneDay = 24*60*60*1000;
UTCDiff = today.getTimezoneOffset()*60*1000;
msToday = today.getMilliseconds() + today.getSeconds()*1000 +
today.getMinutes()*60*1000 + today.getHours()*60*60*1000 - UTCDiff;

if (theDate >= (today - msToday)) {
dateformatted = 'Today';
} else if (theDate >= today - msToday - oneDay) {
dateformatted = 'Yesterday';
} else {
thisyear = theDate.getYear();
...
dateformatted=thismonth + '/' + thisday + '/' + thisyear;
}

return dateformatted;
}

Our original “formatDate()” function is now within the last “else do this” section of our “if” statement. Determining whether a file was last modified “today” or “yesterday” is not as easy as it sounds at first: we can’t just check to see if the file was modified within the last 24 hours-24 hours ago is usually yesterday, not today. We need to determine when today started, and then see if the file was modified after today started. If so, the file was modified today. If not, we see if the file was modified in the 24-hour period before today. If so, it was modified yesterday. Otherwise, we create the date it was modified and show that. See http://www.hoboes.com/NetLife/Web_Scripting/lessons/lesson8.html for the example.

Dates in most programming languages are stored as numbers: they are usually stored as a certain number of days, seconds, or milliseconds from some arbitrary starting point. JavaScript uses milliseconds. Any date in JavaScript can be represented by the number of milliseconds that date is from the “starting date”. (The date of the starting date is immaterial, since you will always be calculating “off of” it. It might even change from client to client, but you don’t care.)

today = new Date();

If you ask for a new Date and don’t specify what that date is, you get right now. In JavaScript, a “Date” is really a date and a time. You’ll recall from our first timestamp that the date modified included the actual time the file was modified.

oneDay = 24*60*60*1000;

In order to determine whether the file was modified yesterday, we need to know what number makes up a day. Since JavaScript stores dates in milliseconds, we ask for 24 (hours per day), times 60 (minutes per hour), times 60 (seconds per minute), times 1000 (milliseconds per second). You could simply calculate that number on your calculator and then use it directly, but storing the number in a variable called “oneDay” makes it easier to remember what that number means when you look at your code later on.

UTCDiff = today.getTimezoneOffset()*60*1000;

Web page dates are stored in Universal Time (GMT: Greenwich Mean Time). If we want to know when the file was modified in the client’s local time, we need to determine the time zone offset. The time zone offset is given in minutes, so we need to multiply by 60 to get the seconds, and then by 1000 to get the milliseconds.

msToday = today.getMilliseconds() + today.getSeconds()*1000 +
today.getMinutes()*60*1000 + today.getHours()*60*60*1000 - UTCDiff;

Our “today” contains the date and time right up to now. This line determines what we need to remove from “today” to get the beginning of today. If it is 5:40 AM and 17 seconds and 553 milliseconds, this will (before the “UTCDiff”) give us 553 milliseconds plus 17 seconds plus 40 minutes plus 5 hours, converting each number into milliseconds. The calculation then removes the time zone difference. If we substract our “msToday” from our “today”, we get the beginning of today in local time.

if (theDate >= (today - msToday)) {
dateformatted = 'Today';

Our first “if” checks to see if “theDate” (which you’ll recall is the date our file was modified) is after or equal to the beginning of today. If so, it sets “dateformatted” to the word “Today”.

} else if (theDate >= today - msToday - oneDay) {
dateformatted = 'Yesterday';

If the first condition does not match, we check to see if “theDate” is after or equal to the beginning of today minus 24 hours. If so, we set “dateformatted” to the word “Yesterday”.

} else {
thisyear = theDate.getYear();

Finally, if neither of the first two conditions match, we do our previous calculation to create a string that represents the date that the file was modified.

Current Time

It can be useful, especially for dynamic pages, to show the current time on the web page. This lets the viewer know how up to date the information is--when they last reloaded the web page. We can format a “current time” date just like we formatted a date-only date. Add the following line to your “filestamp”:

document.write('<tr><td align="right">Current Time: ', formatTime(new Date()), '</td></tr>');

This calls a function called “formatTime()” with an argument of “new Date()”. We already know what “new Date()” does: it gets the current time. So we’re sending the current time to our new formatTime() function. Let’s create the function.

function formatTime(theDate) {
thishour = theDate.getHours();
thisminute = theDate.getMinutes();

if (thishour > 11) {
thishalf='PM';
} else {
thishalf='AM';
}

if (thishour > 12) {
thishour -= 12;
}

if (thisminute < 10) {
thisminute = '0'+thisminute;
}

timeformatted = thishour + ': ' + thisminute + ' ' + thishalf;

return timeformatted;

}

You should be able to follow this from the description of “formatDate()”. It does the same thing, but with hours and minutes instead of month, day, and year. We check the hour to see if it is AM or PM (and then substract 12 from the hour if the hour is 1 PM or later). We make sure the minutes are zero-padded on the left. And then we return a string that looks like “5:32 PM”. See http://www.hoboes.com/NetLife/Web_Scripting/lessons/lesson9.html for the example.

Using Lists

Our smart “formatDate()” function tells us if the date was yesterday or today. Why not also make it return the name of the weekday if the date is within six days past? This is relatively simple to check for: all we need to do is add an extra “else if” to our list of conditions, and see if the document’s modification date is within the last six days.

We could use one “else if” for each possible day, but this is time consuming and prone to error--and we don’t even really know what day three days past was. A better choice will be to determine what the current day is, offset this by the number of days past, and then check a list of weekdays to get the weekday name. That is, we’ll work with numbers first, because that’s what computers are good at. Once we get the number (i.e., the second day, third day, etc, of the week) we’ll look at a list and get the appropriate item from the list.

Add our new JavaScript code after the part where we check for yesterday:

} else if (theDate >= today - msToday - oneDay) {
dateformatted = 'Yesterday';

} else if (theDate >= today - msToday - oneDay*6) {
weekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
theWeekDay = theDate.getDay();
dateformatted = weekDays[theWeekDay];

} else {
...

This is pretty simple. The new part is the list of weekdays.

} else if (theDate >= today - msToday - oneDay*6) {

If “theDate” isn’t today and it isn’t yesterday, we see if it is one of the last six days, by multiplying “oneDay” by 6 and subtracting it from today. If theDate is greater than the result, we know that theDate is within six days of today.

weekDays = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];

Computers tend to work with numbers, but telling people that this page was last modified on weekday “6” isn’t very user-friendly. Here, we create a list of weekdays in English (more advanced JavaScript programmers would check the user’s language and create the list in that language).

Once we have a “list” (they’re usually called “arrays” by programmers), we can ask the computer for the first, second, third, etc., item from the list. The trick is that JavaScript, like many computer languages, starts counting from zero instead of from one. The first item in a list is item 0. The second item is item 1. As you get into more advanced programming you’ll find that this is a useful feature. For now, though, it’s probably confusing. Just remember that JavaScript starts counting at zero and you’ll be okay.

When you ask for an item from a list, you do so with the list’s name (in this case, “weekDays”) and the number of the item in brackets: “weekDays[3]” is the same as “Wednesday”. Wednesday is item 3 (the fourth item) in our list of weekdays. Where lists really become useful is that we can do that asking with a variable. If we have a variable called “payday” and it has “5” in it, “weekDays[payday]” will give you “Friday”. And that’s what we’re about to do.

theWeekDay = theDate.getDay();
dateformatted = weekDays[theWeekDay];

When we ask the “theDate” object to “getDay()”, it will return a number from 0 to 6, with zero being Sunday and 6 being Saturday. So we take that number and ask our “weekDays” list for the corresponding item in the list. That gives us the weekday when our web page was last modified. See http://www.hoboes.com/NetLife/Web_Scripting/lessons/lesson10.html for the example.