Stuart Moulthrop
& Nancy Kaplan
University of Baltimore
School of Information Arts and Technologies ·
Revised 2008
Part 8: Toward Web 2.0
To many who work on the Internet, Web 2.0 is a poorly defined buzzword that has become meaningless after endless repetition by self-described visionaries. So let's get something out of the way: Web 2.0 does not refer to an official standard, in the way HTML 4.01, CSS-2, or ECMAScript 3.0 all do. Web 2.0 is more of a working improvisation based on a number of developments in Web technologies that have come along since the de facto completion of the HTML standard.
For our purposes, let's think of Web 2.0 as a loose, generic name for anything that extends the Web experience beyond simple, one-shot information retrieval (point, click, and display).
There many, many ways to implement Web 2.0 concepts, from Flash and other channels for interactive media, to the vast array of programming interventions, for instance, the wide, wide world of Java applets. Since we're now nearly at the end of the line in this class, we'll consider only three fairly modest examples of advanced Web authoring -- really more Web 1.0x than 2.0; but these limited illustrations will give you a glimpse of the Web's future, which will probably favor dynamic, highly configurable presentations over static page presentations.
We'll look briefly at three enhancements to HTML: CSS Rollovers, Dynamic HTML (DHTML), and JavaScript.
One of the first enhancements to basic HTML was the rollover, a technique for highlighting the state of an HTML link anchor. Before Cascading Style Sheets came along, people had to use JavaScript to replace one graphic with another in the link anchor. It's still possible to use JavaScript for this purpose, though revisions to that scripting language have made the practice considerably more complicated than it once was
These days, most folks tend to enable rollovers using CSS tricks. The trio of buttons above show the effect in action. Here's the secret explained.
Here are the tags that lie within the BODY container of the present page:
<a id="one" href=""><img src="images/blank.gif" alt="a button"></a> <a id="two" href=""><img src="images/blank.gif" alt="a button"></a> <a id="three" href=""><img src="images/blank.gif" alt="a button"></a>
Basically, we have three iterations of a familiar structure: an image element wrapped in a link anchor element. The anchors each have an ID attribute. It's also significant that each loads the same image: a GIF called blank.gif, which is a totally transparent rectangle with dimensions 100x33. The transparency of this base image is crucial to the effect.
8.2.2 · CSSNow let's look at the CSS part of this business, which is found within an internal stylesheet in the head portion of this page (they could, of course, have been placed elsewhere).
<style type="text/css">
a img {height: 33px; width: 100px; border-width: 0;
background: top left no-repeat;}
a#one img {background-image: url(images/exBtnOff.jpg);}
a#two img {background-image: url(images/exBtnOff.jpg);}
a#three img {background-image: url(images/exBtnOff.jpg);}
a#one:hover img {background-image: url(images/exBtnOver.gif);}
a#two:hover img {background-image: url(images/exBtnOver.gif);}
a#three:hover img {background-image: url(images/exBtnOver.gif);}
a#one:active img {background-image: url(images/exBtnOver.gif);}
a#two:active img {background-image: url(images/exBtnOver.gif);}
a#three:active img {background-image: url(images/exBtnOver.gif);}
</style>
Remember that CSS allows us (a) to style various states of any anchor element; and (b) to set a background-image for anchor elements, as well. We use these two opportunities to coax HTML and CSS into doing something uncharacterisitically dynamic -- replacing the background image for our link anchor as the button state changes.
We can't affect the main, or foreground graphic, only the background. But since the foreground graphic is totally transparent, that doesn't matter.
It does matter very much that our alternating graphics, exBtnOn.gif and exBtnOff.jpg, have identical dimensions. If you've ever worked with JavaScript rollovers, you know this drill.
File formats are also significant here. While we could have used Graphics Interchange Format (GIF) for all images in this projet, we've deliberately left the off graphic a JPEG, to emphasize the fact that it does not use transparency or animation.
The on graphic employs GIF animation (explained in Part 3). This explains the color cycling you see as you mouse over each button. (It also explains the pixel distortion, since GIF dithers some of the color values through which our cycle runs; this is a quick and crude illustration.)
So that's the CSS graphical rollover trick. It's fallen somewhat out of favor, as Web coders learn to do more with variable font styling, or simple color effects, which don't involve loading graphics. Still, if the pages you're building demand high-impact graphics, then you may find this rather old-fashioned technique useful.
Dynamic HTML is really just another name for HTML 4.0, the current (more or less final) standard for basic HTML. However, part of the rationale behind this ultimate standard was construction of a Document Object Model, a framework that makes HTML tags available for use by scripting languages, such as JavaScript.
The tricks we'll show here all depend on simple scripts, which we'll show, though without detailed explanation, since learning JavaScript requires a course unto itself these days.
Theodor Holm Nelson, the Man Who Invented Hypertext, also coined the term stretchtext to describe one possibility for dynamic writing: sentences and paragraphs that could be expanded on user intervention, to present a more detailed, or more accurate, expression.
Here's an example:
I am not a crook. Believe me.
As with our CSS rollovers, the trick here comes in two parts: HTML and something extra, in this case JavaScript. Here's the HTML part, or the markup for the text you see in the gray box above:
<p style="font-weight: 700;" id="paraSix" onMouseOver="paraSixChange()" onMouseOut="paraSixChangeBack()"> I am not a crook. <span id="truth" style="display: none"> Most of the time. </span> Believe me. </p>
If you look carefully, you'll see that the single paragraph here contains within it a SPAN with an internal CSS style of display: none. This attribute makes the span invisible, and effectively removes it from the line.
Our paragraph also contains two special attributes, onMouseOver and onMouseOut, which are referred to in scripting as event handlers. Handlers allow HTML tags to communicate directly with JavaScript functions.
We'll see a bit more about how this works in a bit, but first some cautions. The event handlers shown here are very old -- they were in fact written in the last century. JavaScript has since moved on to other ways of handling handlers -- and alas, they are considerably more complicated than what you see here.
So proceed with care. Our example here works in both Mozilla and Internet Explorer... this year. At some point in the future, that may not be true. For the moment, though, we can use this ancient relic as a convenient illustration of a simpler, more innocent form of scripting, and thus of some possibilities for DHTML.
Here's the relevant script, wrapped in an internal <SCRIPT></SCRIPT> container in the HEAD portion of this page.
function paraSixChange()
{
truth.style.display="";
}
function paraSixChangeBack()
{
truth.style.display="none";
}
We won't be going into the details of JavaScript here, but you can probably figure out quite a bit just by studying the two simple functions above. Each refers to something called truth, which is of course the hidden SPAN in our markup. Each also sets this name at the head of a chain (or syntax) divided by periods, or dots. This is a technique called dot notation, and it's something with which you're already familiar from Web addresses (e.g., iat.ubalt.edu). The dots in dot notation express affliation. Our span called truth has something attached to it called style (its internal stylesheet, actually), and attached to that is something called display. Using the assignment operator (the equals sign), we can change the value of this thing (which is called a property). And that's the whole trick.
The truth is in there.
8.3.2 · Replacing innerHTMLIn this next example, we don't just modify a line of text -- we completely replace it.
Here's the markup:
<span id="paraThree" onClick="paraThreeChange()"> Click to lose your innerHTML. </span>
And now the JavaScript function, paraThreeChange():
We repeat our previous warnings about Very Old Code. JavaScript programmers no longer use simple onClick handlers like the one in this example. The structure still works, but if you set out to learn JavaScript comprehensively, you'll have to deal with considerably more complicated arrangements.
var threeChange = 0;
function paraThreeChange()
{
if(threeChange == 0)
{
document.all['paraThree'].innerHTML="<h1>This text is not the same.</h1>";
threeChange = 1;
}
else
{
document.all['paraThree'].innerHTML="Click for innerHTML replacement.";
threeChange = 0;
}
}
There's a bit more to this script. It starts by declaring a variable (threeChange), which records to state of the span, replaced (1) or unreplaced (0). Within the function, we use a logical structure, called an if/else construction, to make one set of changes or its opposite, depending on how the record variable is set.
Here's where the markup meets the script: in our use of the property innerHTML, which has quite a remarkable power. The innerHTML property of any HTML element indicates everything inside a container. We can change these contents using JavaScript. If you think about it, the possibilities are gigantic; and probably scary, too.
8.3.3 · Modifying Active CSS StyleHere's an example of a fairly sophisticated DHTML trick that uses a bit of JavaScript that is both contemporary, and simple enough to understand. On the demonstration page, click on the paragraph of text. You'll see the same paragaph again, but in very different style. Click a second time to return to the original state.
For reasons that will become obvious, we've given this little demo its own page, which you can open in a separate window here.
In this demonstration, your mouseclick runs a JavaScript function that does something fairly radical -- it creates a new internal style sheet in your document! Since style sheets cascade, the new sheet (which is placed within the BODY, not the HEAD) overrules the original style sheet. This has the effect of replacing that style sheet's effects (though not the style sheet itself).
Once you've made the replacement, a record variable is set, so that your second click runs a different branch of the JavaScript function. This branch removes the added style sheet.
Note that this particular effect in JavaScript (and HTML 4) allows modification of crucial page elements on the fly, without reloading the page from the server. This is a good illustration of Web 2.0 principles, under which pages take on dynamic possibilities that do not involve transfers external to the browser.
Here's a technical anatomy of this project. First, the HTML, which is very simple:
<div id="main">
<p onClick="modCSS()">
... paragraph text here ...
</p>
<div>
As you can see, we have a DIV with an ID (needed so the style sheets can do their thing), and one of those old-fashioned onClick() handlers inserted into the paragraph element that sits inside the DIV.
Now here's the JavaScript, which sits within a <SCRIPT></SCRIPT> container in the HEAD portion of the page:
var switchFlag = false;
function modCSS()
{
if(switchFlag == false)
{
switchFlag = true;
var elem = document.createElement("style");
var txt = document.createTextNode("#main { font: 24pt Lucida Sans Unicode;
color: #009900; background-color: #CCCC22; padding: 10; width: 500;
border: 8px dotted #FF0000; }");
elem.appendChild(txt);
elem.setAttribute("id", "newSheet");
document.body.appendChild(elem);
}
else
{
switchFlag = false;
document.body.removeChild(document.getElementById('newSheet'));
}
}
We set the record variable switchFlag to false outside the function, so it has the proper initial value. (We're using Boolean true/false rather than arithmetic 1/0 in this example: there's no practical difference.)
Within the function, you see another if/else structure, as in 8.3.2, above. On the false branch (no transformation has yet taken place), we do several things. First, we create a variable called elem, and in the process, we add a new HTML element to our document! Specifically, we add a new <STYLE></STYLE> container, or internal style sheet. We can do this because both Document Object Models, Microsoft's and the World Wide Web Consortium's, allow us to add elements through the document.createElement() method, implemented in all browsers' built-in versions of JavaScript.
Having created a new style sheet, we next put something inside it, using another variable called txt (the name is arbitrary), which creates something called a textNode, which is to say, a set of text information that can be installed within some other page element, so long as it is a container. We do the installing with the appendChild() method, which comes next.
At this point, we've built a virtual style sheet and given it contents. However, the style sheet isn't actually part of our document yet. We do that by using the appendChild() method on the document itself. But before we do that, we use the setAttribute() method on the new style sheet, to give it an ID.
The reason for this last move should be apparent if you look at the opposite branch of the if/else, which sets the page back to its original state once it has been modified. We need to have a name to call the added style sheet by, in order to use the removeChild() method to erase it.
This example is fairly complicated, compared to other things we're showing you hereabouts; but in the real world, this is still a fairly modest bit of code. Generally speaking, scripts are highly detailed, and sometimes maddeningly abstract. Unfortunately, they've gotten worse in these respects in the decade or so that they've been around. Though there are a few happy islands of simplicity still out there, and we'll visit a few before we're done.
JavaScript is a specialized scripting language intimately associated with Web browsers, though it can also be found on servers and other devices these days. The language was originally developed by Netscape, a company that made Web browsers, as an augmentation of their Navigator software.
The name is misleading. Though it shares basic syntax with a family of programming languages that includes Java, Javascript has no formal connection to Java, which was created by Sun Microsystems as a general-purpose programming language for Internet-based applications.
A scripting language differs from a programming language in one major respect: scripting languages generally depend on another body of software, usually an application, in order to function. Scripts extend other programs. Thus scripting is (or used to be) a simpler task than programming, since scripters could depend upon application programmers to handle the heavier work of software engineering, like memory management, hardware integration, and security.
So it was in the beginning for JavaScript (circa 1996). The language offered a useful way to extend the functionality of Web browsers, particularly Netscape Navigator, thanks to a new way of looking at HTML code through something called the Document Object Model (DOM). Basically, this scheme identified every element in HTML with a software object, a construct that ties together data, procedures, and logic to permit powerful transformations.Microsoft Corporation, Netscape's primary competitor in the early browser market, had its own ideas about scripting languages, just as it infamously did about the Java programming language. So Microsoft developed its own Document Object Model, which was inconsistent in many ways with the Netscape DOM. The latter eventually became the model accepted by the Worldwide Web Consortium (W3C). In the case of HTML, the W3C's model won out, so that both Microsoft and non-Microsoft browsers treat core HTML code identically. Not so for JavaScript. Nearing the end of the first decade of the 21st century, both Microsoft's DOM and its W3C alternative remain in play.
As a result, when it comes to Web scripting, the Browser Wars of the 1990s seem never to have ended. Learning JavaScript these days means coming to terms with extra code and special methods required for compatibility for both major families of browser, Netscape descendants (Firefox, Safari) and the latest from Microsoft.
For this reason, among others, we offer only limited coverage of JavaScript here. The code has become so dense and involved as to be practically unintelligible for novices. Happily, though, there are still a few simple and powerful things that can be done with the language.
8.4.1 · Date-Sensitive Text with document.write()
In the gray strip above, you should see a readout of the current date and time (as set on your computer), followed by a message appropriate to the day of the week.
This simpleminded example shows how you can use two affordances of JavaScript, the Date object, and the document.write() method, to customize text on your page.
Here's the JavaScript code that generates what you see. It occurs within a <SCRIPT></SCRIPT> container written into the BODY portion of the document (i.e., in-line).
var theDate = new Date();
document.write("Hello, it's "+theDate+"<br />");
if(theDate.getDay() == 1) document.write("Major Monday.");
if(theDate.getDay() == 2) document.write("Terrible Tuesday.");
if(theDate.getDay() == 3) document.write("Welcome to Wednesday.");
if(theDate.getDay() == 4) document.write("Not Yet Friday.");
if(theDate.getDay() == 5) document.write("Fried Day.");
if(theDate.getDay() == 6) document.write("Work That Weekend.");
if(theDate.getDay() == 0) document.write("Is it Monday yet?");
The statement var sets up a variable, into which we plug an instance of JavaScript's built-in Date object (which is what that keyword new does for us). The Date object knows what time it is, picking up its information from your computer's clock. We use the write() method of the document object (heart of the Document Object Model) to add the information contained in the Date object to the visible text of our page.
Next we march through a series of if statements that test the value returned by the getDay() method of the Date object (or our instance of that object, theDate). The result will be a number between 0 and 6, corresponding to a day of the week. If statements (of the sort we're using here), use the space between the righthand parenthesis and whatever comes next to stand for then, introducing the consequence of a positive result. So if it's Monday (day code 1), we write "Major Monday" onto the screen, and so forth.
You can use document.write() for many other purposes. Aside from setting time and date conditions on expressions, you can also use document.write() to report changeable or dynamic information. Perhaps the most common use of this method is the JavaScript date stamp:
The in-line JavaScript code for this feature goes like this:
document.write("The document was last modified "+
document.lastModified);
8.4.2 · Processing Form Fields
Aside from using write() statements to customize text on Web pages, perhaps the most common use of JavaScript is for checking input on HTML forms.
Try entering something other than a proper month name into the form field below:
This little illustration shows how you can use JavaScript to process input from form fields. The script that runs when you click the button looks like this:
var monthNames = new Array("January","February","March","April",
"May","June","July","August","September","November","December");
function deFormIty()
{
garbageIn = document.forms[0].elements[0].value;
noMatch = 0;
for(z=0; z<12; z++)
{
if(garbageIn == monthNames[z]) noMatch = 1;
}
if(noMatch == 1)
{
window.alert("Thanks for your input.");
}
else
{
window.alert(garbageIn + " is not a month.");
}
document.forms[0].elements[0].value="";
}
We begin outside the function body by building an Array, which is a data object containing the 12 names of the months (properly capitalized, you'll notice). Since this array only needs to be created once, we set it up in a directly-executable statement that runs when the page loads. The array then sits patiently in memory waiting for the function to be called.
Within the function itself, whatever the user has typed into the first (and only) element of the first (and only) form on this page, and assigns that to the variable garbageIn. Then a variable called noMatch is set to 0.
Next we come to a structure called a for loop. Loops repeat things, and a for loop keeps track of its repetition. It's a way of marching through a list -- or an Array. Our loop runs through the twelve index values of the monthNames array, from 0 to 11. If what the user typed matches any of these values, noMatch is set to 1.
Outside the for loop, we test for the value of noMatch. If it is 1, meaning the user's input matched at least one of the legal month names, we put up an alert box full of thanks. If noMatch is still 0, meaning the user's input was not one of the legitimate names, we put up the other alert box. No matter what the outcome, we blank out the input field by assigning it a value of null ("").
There's one small subtlety here: because some browsers won't let you use JavaScript functions as form actions (though MSIE does), what appears to be a submit button isn't really. It's actually this:
<INPUT TYPE="button" onClick="deFormIty()">
In fact the ACTION attribute of this form is blank(!). That's unorthodox, but allowed. If you wanted to do form checking in a real, live form -- one that actually transmits data back to a server -- you'd set the ACTION attribute to something non-null.
8.4.3 · Randomly Selected TextEach time you click the submit button above, you should see something different in the alert box that pops up. This effect demonstrates JavaScript's ability to generate random (strictly speaking, pseudo-random) numbers. This little feature can be a great deal of fun, since it lets you make your Web pages considerably less predictable than most.
Here's the script:
var randy = 0;
var randyOld = 0;
var babble = new Array("Spleenburgers!","Mink Belly Futures!",
"Petroleum Beans!","Municipal Bondage!","Hair Harmonics!",
"Marzipan Bunnies!","Unlicensed Magnetism!",
"Single Personality Disorder!","Mind Flux Restorative!",
"Amazon Head Cheese!","Digital Intangibles!",
"Tangible Dirigibles!","Monster Shopping Carts!",
"Amateur Anatomy!");
function randomiso()
{
while(randy = randyOld)
{
randy = Math.floor(Math.random()*babble.length);
}
randyOld = randy;
window.alert(babble[randy]);
}
As you can see, the function body is preceded by two directly-executable variable declarations that set the variables randy and randyOld both to 0. It's very important that these variables begin with the same value, and that this initial declaration not happen inside the function body. We'll explain below. There's also a third variable declaration, for the Array babble, which is written outside the function body because it only needs to be executed once.
Within the function, the first thing you see is a while loop. This is another sort of loop that tells JavaScript to repeat the enclosed instructions while a certain condition is true, and to stop as soon as that condition is no longer true. The condition in this case is the equivalency of the two variables randy and randyOld, and the statement that executes as long as these two variables are equal is this:
randy = Math.floor(Math.random()*babble.length);
This is the statement that generates the random number. Since you're not learning JavaScript in detail here, we'll skip the specifics. You only need to understand that this statement may give randy a value that differs from randyOld, though there is some chance (1 in 14 in the current example) that it won't. That's why we've used the while loop: if the randomizer comes up with a value that matches the previous value of randy, which is also the value of randyOld, then we repeat the statement until it presents a different value.
You can think of this structure as a kind of magic curse that impels its victim to keep rolling a pair of dice until s/he rolls two different numbers in succession. (Program this stuff long enough, and everything seems like a curse.)
Now for the heart of the matter: the random-number statement. As you can see, the statement calls two methods of the Math object, a pre-built JavaScript object used for mathematical operations. These two methods are nested one within the other. The inner method is the one that actually does the randomizing. The method Math.random() generates a messy decimal number between 0 and 1 (something like 0.125735907). That's nice, but not quite what we want. We're looking for an integer chosen at random between 0 and 13, matching the index numbers of the array babble, which has 14 elements. So we multiply Math.random() by 14.
This may not be immediately apparent as you gaze upon the code, partly because JavaScript uses an asterisk (*) as its multiplication operator, and partly because you don't see the number 14. You see babble.length, which happens to be 14. The length property of any array is the number of elements it contains. We could have plugged in the number 14, but then we'd have to change the code every time we added or subtracted elements to babble. By referring to the array's property, which changes automatically when we resize the array, we create a function that dynamically adapts to new conditions.
So far we've only explained the inner of our nested methods: all of the above is contained within the parentheses of another method, Math.floor(). This is a rounding-off method. It takes a number with a messy repeating decimal and rounds it down to the nearest integer. (Its cousin Math.ceil() rounds up and Math.round() goes either way, depending which is closest.) We need to apply the rounding-off method because when you multiply a messy decimal number by another number, you almost always get another number with a messy decimal at the end. For instance, 0.125735907 * 14 = 1.760302698. Math.floor() converts this mess to 1. But why round down to 1 instead of up to 2? That's because the range of numbers we wish to match runs from 0 to 13. If we round down, the lowest value we can ever encounter is 0, which is in the range, and the highest value is 13, ditto. If we rounded up, we'd never get 0 and we would at some point encounter 14, which is outside the range.
If this seems like an awful lot of bother over a random number, remember: spontaneity takes careful planning!
And so we conclude our quick survey of Web 2.0, The First Steps. If the intricacies of random-number generation in JavaScript start your pulse to racing, then you'll really like Web 2.0.
Even if you have more normal responses, you'll probably find things like CSS hacks, the odd DHTML trick, and the simpler sort of JavaScript maneuvers useful additions to your repertoire.
Onward to Webs 2.0, 3.x, and beyond!
Index · Part 1 · Part 2 · Part 3 · Part 4 · Part 5 · Part 6 · Part 7 · Part 9 · Top
Course and Materials ©1997 - 2008 by Stuart Moulthrop
and Nancy Kaplan
