reptile7's JavaScript blog
Wednesday, October 25, 2006
 
Torn Between Two Locations
Blog Entry #55

Joe discusses the following script over the course of Script Tips #5, #6, #7, #8, and #9:

<script language="javascript">
function JemWebCONFIRM( ) {
if (!confirm("YOUR MESSAGE GOES HERE"))
history.go(-1); return " " }
</script>

"That's it? Five script tips for five lines of code??"

Yeah, that was my reaction too. And even then, some key aspects of the script are left out or ignored, as we'll see later. Tellingly, Script Tip #8 contains a link to a demo page whose relevant source code differs considerably from the Script Tips #5-9 Script itself.

The Script Tips #5-9 Script is conceptually similar to the Primer #13 Script that we discussed in Blog Entry #28. Both scripts pop up a confirm( ) box whose "OK" and "Cancel" buttons correspond to a choice of Web locations; clicking the "OK" button takes the user to one location, whereas clicking "Cancel" takes the user to the other location. The scripts have significant differences, however, which we'll detail below.

Calling the JemWebCONFIRM( ) function

As shown above, the expressions of the Script Tips #5-9 Script are wrapped in the JemWebCONFIRM( ) function. (The expressions of the Primer #13 Script are not functionized, but Joe addresses their functionization in the Primer #13 Assignment.) JavaScript functions are treated generally in Chapter 6 ("Functions") of the JavaScript 1.5 Core Guide; we for our part discussed JavaScript functions in Blog Entry #23. Contra Script Tip #7, a JavaScript function is not "really a method"; syntactically, the opposite is true: JavaScript methods are functions associated with specific objects, as we learned in Blog Entry #43.

Amazingly, in none of Script Tips #5-9 does Joe discuss or provide code for calling the JemWebCONFIRM( ) function, so it's up to us to 'fill in the blank' here. Joe does at least say in his summary in Script Tip #9 that "[t]he function is enacted upon the loading of the page," and there are three simple ways we can do that:

After the closing brace } of the JemWebCONFIRM( ) function and before the closing </script> tag,
(1) JemWebCONFIRM( );
or
(2) window.onload=JemWebCONFIRM; /*parentheses do not follow the function name in this case*/
can be used to call the JemWebCONFIRM( ) function. More conventionally, we can coordinate the JemWebCONFIRM( ) function call with the document loading process via the <body> tag, i.e.,
(3) <body onload="JemWebCONFIRM( );">

We noted here in Blog Entry #10 that onload is an event handler of the window object, bringing us to...

Window object? What window object?

The confirm( ) method and the history object, which are respectively a method and a property of the window object, play important roles in the Script Tips #5-9 Script. Amazing omission #2: there is no mention, at all, of the window object in Script Tips #5-9.

In the classic JavaScript Navigator object hierarchy, the window object sits at the top, at a position higher than that of the document object, even as the JavaScript 1.3 Client-Side Reference informs us that both the window object and the document object are created by/for the <body> tag.

"Where does the window object fit in the DOM?"

Ah, an excellent question - Mozilla's DOM Reference contains a DOM window Reference, which states:

"The window object implements the Window interface, which in turn inherits from the [DOM] AbstractView interface. "

Turning to the DOM Level 2 Views Specification, we see no mention of the "Window interface" in the AbstractView Interface section. This doesn't mean that the W3C isn't hard at work on the matter, however; in April 2006 the W3C posted a Window Object 1.0 'working draft in development' - a draft that discusses neither the confirm( ) method nor the history object (nor most other window object methods and properties).

Back to onload for a moment. The Window Object 1.0 draft notes that window events are "not in this specification." Nonetheless, three classic JavaScript window object events - specifically, error, load, and unload - are listed in the "HTML event types" section of the DOM Level 2 Events Specification, so I think it's safe to say that at least the onerror, onload, and onunload window object event handlers are part of the DOM. Mozilla's DOM Reference has a page here for window.onload.

The confirm( ) command and its true/false outputs

Like the Primer #13 Script, the Script Tips #5-9 Script uses a confirm( ) command as the condition of an if statement to set up a user choice between two Web locations. (If you need an if...else refresher, then the JavaScript 1.5 Core Reference if...else statement entry is here.)

As noted in Blog Entry #28, clicking the "OK" and "Cancel" buttons of a confirm( ) box outputs the Boolean values true and false, respectively. In the Primer #13 Script, Joe ties the "OK" and "Cancel" confirm( ) box buttons to the execution of two separate units of code; this requires the use of both an if statement and an else statement (alternatively, two if statements could be used). In the Script Tips #5-9 Script, no commands execute if the user clicks the confirm( ) "OK" button, as we'll explain in a bit, so Joe (actually, JemWeb, to whom Joe credits the script's authorship) gets away with using a single if statement to set up the Web location choice.

Let's look now at the condition of that if statement:

if (!confirm("YOUR MESSAGE GOES HERE"))

On his demo page, Joe uses "Are you sure you want to enter?" for "YOUR MESSAGE GOES HERE" - seems reasonable.

We first consider the "Cancel" choice when the confirm( ) box pops up. If the user clicks the "Cancel" button, then confirm("Are you sure you want to enter?") returns false, and thus !confirm("Are you sure you want to enter?") returns true. Amazing omission #3: Joe says nothing at all about the ! logical operator, which we discussed in Blog Entry #47.

With the if condition true, the subsequent history.go(-1) command takes the user to the preceding (second-from-the-top) location in the browser's History folder - the history.go(-1) command is thus the functional equivalent of the "Back" button on the browser's toolbar. (We used a history.go(0) command as a "Refresh" button equivalent in the hybrid prompt/confirm box script of Blog Entry #29.)

And if the user clicks the "OK" confirm( ) button? In this case, confirm("Are you sure you want to enter?") returns true and thus !confirm("Are you sure you want to enter?") returns false; no commands are tied to this return and therefore the JemWebCONFIRM( ) function exits and the current document continues to load because, as Joe points out in Script Tip #8, "[t]his script is sitting on the page we wanted to go to."

"What about the return " " code at the end of the JemWebCONFIRM( ) function, huh?"

Joe doesn't say anything about that, either. In fact, the return " " code at the end of the JemWebCONFIRM( ) function serves no purpose and should be removed.

However, as I was drifting off to sleep last night, it occurred to me that an appropriately retooled Primer #13 Script can profitably employ a return statement, as follows:

<head><script type="text/javascript">
function HTMLGoodiesCONFIRM( ) {
var user_choice=window.confirm("Are you sure you want to enter HTML Goodies?");
if (user_choice)
window.alert("Good choice.");
else {
window.alert("Then you'll stay right here."); return user_choice; } }
</script></head>
<body>
Click <a href="http://www.htmlgoodies.com" onclick="return HTMLGoodiesCONFIRM( );">here</a> to go to HTML Goodies.
</body>

In the script above, the confirm( ) dialog is triggered by a link as opposed to when the page loads. If the user chooses the "Cancel" confirm( ) button, then false is returned to the onclick function call, which cancels the linking-to-www.htmlgoodies.com process; we previously demonstrated in Blog Entry #47 that click events are cancelable. FYI: the W3C DOM "HTML event types" link above notes that neither load events nor unload events are cancelable.

An if...else alternative to the Script Tips #5-9 Script

If desired, the if statement of the Script Tips #5-9 Script is easily recast as an if...else statement à la the Primer #13 Script; the resulting code reads more straightforwardly, IMO:

<script type="text/javascript">
function JemWebCONFIRM( ) {
if (window.confirm("Are you sure you want to enter?"))
window.alert("Welcome, visitor.");
else
{window.alert("Fair enough - we now return you to the previous page."); history.go(-1);} }
JemWebCONFIRM( );
</script>

In the next post, we'll look at the first of two browser detection scripts that respectively span Script Tips #10-12 and #13-15.

reptile7

Monday, October 16, 2006
 
Rollover Redux
Blog Entry #54

In Script Tips #2, #3, and #4, Joe goes over an image flip script that matches exactly, character for character, the Primer #15 Script that we discussed in Blog Entry #31; here it is again:

<a href="http://www.cnn.com"
onmouseover="document.pic1.src='menu1on.gif';"
onmouseout="document.pic1.src='menu1off.gif';">
<img src="menu1off.gif" border="0" name="pic1">
</a>

Joe provides neither a script demo nor the menu1off.gif and menu1on.gif images in Script Tips #2-4, but it's easy enough for me to give you a demo here; roll your mouse cursor over and away from the "CNN" image below:



(I've added a border="1" and subtracted the <a> tag code - clicking the image(s) will not take you to CNN's Web site. The menu1off.gif and menu1on.gif image files are small (<5 K) and do not need to be preloaded via the method outlined in Blog Entry #44.)

Is it worth our while to rediscuss the mechanics of the script above? Not really. But I can at least give you some new reference links in this post.

The anchor element

Links are treated generally in Chapter 12 of the W3C's HTML 4.01 Specification; Section 12.2 discusses the anchor element and its attributes, which interestingly (given that this is an HTML specification) include onmouseover and onmouseout.

'Classic' (pre-DOM) JavaScript divided links into link objects and anchor objects; a link object was an anchor element for which the href attribute was specified:

<a href="http://www.some_web_page.com">Text or image</a>

whereas an anchor object was an anchor element for which the name attribute was specified:

<a name="codeword"></a>

An anchor element having a href attribute and a name attribute was both a link object and an anchor object.

Using the 'object taxonomy' of the previous post, the link object and the anchor object are browser-related objects, and they've both been handed off to the DOM - sort of. In the DOM Level 2 HTML Specification, to my understanding, all anchor elements count as anchor objects, whereas "link object" refers to the link element associated with a document head. However, the DOM also defines document.links and document.anchors "collections" that correspond respectively to link and anchor objects in the classic JavaScript sense, thus allowing newer browsers to interpret relevant JavaScript code written in days of yore.

Because a major impetus of a standardization is to resolve 'inconsistencies of the past,' one wonders why the W3C doesn't use the document.links collection to refer to link elements in the document head, given that a document head can have more than one link element - that's what I would have done, anyway.

The onmouseover and onmouseout event handlers

Like its browser-related objects, classic JavaScript's event handlers - most of them - are now part of the DOM. Mozilla's DOM Reference has a page here for onmouseover and a page here for onmouseout. Strangely and incorrectly, the "Specification" sections of both pages contain a "Not part of specification" comment. Turning to the DOM Level 2 Events Specification, we see that the mouseover and mouseout events (as well as the click, mousedown, mouseup, and mousemove events) are indeed listed in the "Mouse event types" section thereof.

Moreover, the syntaxes given at Mozilla's onmouseover and onmouseout pages should be reversed; the event handling code should be assigned to the element.onmouseevent expression:

element.onmouseevent = event handling code;

and not vice versa.

This brings up an interesting point - an alternate, if more complicated, event handler syntax is possible (one that we saw in Blog Entry #24 during our discussion of the onunload event handler):

<a href="http://www.cnn.com" id="imageflip">
<img src="menu1off.gif" border="0" name="pic1">
</a>
<script type="text/javascript">
function overmouse( ) {
document.pic1.src="menu1on.gif"; }
function outmouse( ) {
document.pic1.src="menu1off.gif"; }
document.getElementById("imageflip").onmouseover = overmouse;
document.getElementById("imageflip").onmouseout = outmouse;
</script>

We briefly discussed the getElementById( ) method in Blog Entry #8; Mozilla's reference page for this method is here.
(Contra Blog Entry #8, the getElementById( ) method is not, and has never been, a JavaScript method; rather, it is a 'homegrown' DOM method that was introduced in the DOM Level 1 HTML Specification.)

Both onmouseover and onmouseout are also defined in the "Intrinsic events" section of Chapter 18 of the W3C's HTML 4.01 Specification.

Object/element hierarchy

OK, at the end of the previous post I promised you some hierarchy statements in this post, so here we go. Let's look at the statements that are assigned to the onmouseover and onmouseout event handlers:

document.pic1.src='menu1on.gif';
document.pic1.src='menu1off.gif';

From a classic JavaScript viewpoint, both the pic1 image object and the link object that contains it are immediate "descendants" of the document object - see the Navigator object hierarchy in Chapter 11 ("Using Navigator Objects") of the JavaScript 1.3 Client-Side Reference.

From a DOM viewpoint, the hierarchy situation is more complex. The pic1 <img> element is a child of its containing <a> element, which in turn is a child of the <body> element (anchor elements necessarily appear in the document body), which is a child of the <html> element, which is a child of the document as a whole; the pic1 image is still a descendant of the document, but not a direct descendant. Fortunately, the getElementById( ) method allows us to directly connect the root document with the pic1 image; if we assign pic1 to an id attribute (id="pic1") instead of a name attribute, then we can if desired write the image flip statements in a more up-to-date form as follows:

document.getElementById('pic1').src='menu1on.gif';
document.getElementById('pic1').src='menu1off.gif';

One more point about hierarchy: looking at the DOM tree appearing in W3Schools' HTML DOM Tutorial, to which I linked in the previous post, I was of the impression that the pic1 image and its src attribute (more generally, any HTML element and its attributes) constituted a DOM parent/child relationship; however, in the Attr Interface section of the DOM Level 3 Core Specification, the W3C states:

"The Attr interface represents an attribute in an Element object...Attr objects inherit the Node interface, but since they are not actually child nodes of the element they describe, the DOM does not consider them part of the document tree."

Before moving on - the W3C notes here that the border attribute of the img element has "been deprecated in favor of style sheets." A style="border-width:0px;" attribute can be substituted for border="0" in this regard.

Image flip via the CSS :hover pseudo-class

Lastly, Wikipedia has a "Rollover (web design)" entry with sample image flip code using a style block instead of the onmouseover/onmouseout event handlers and substituting a span element for the img element. The code below adapts the Wikipedia code to the Script Tips #2-4 script and executes successfully on my computer when using either MSIE 5.1.6 or Netscape 7.02:

<head>
<style type="text/css">
a {display:block; width:240px; height:30px;
background-image:url(image_path/menu1off.gif);}
a:hover {background-image:url(image_path/menu1on.gif);}
a span {display:none;}
</style></head>
<body>
<a href="http://www.cnn.com"><span>The images are displayed here.</span>
</a></body>

In the next entry, we'll examine a script that spans Script Tips #5-9 and is highlighted by the confirm( ) method, the ! logical operator, and the history object.

reptile7

Friday, October 06, 2006
 
Documentzilla Meets the W3C
Blog Entry #53

If someone were to ask me to recommend a JavaScript reference resource, then I would direct the questioner to Netscape's JavaScript manuals - it was Netscape that developed JavaScript, you will recall. However, there's very much a limit to what Netscape's reference materials will do for you. To really understand JavaScript, you've got to study practical JavaScript scripts, and we'll be doing just that as we journey through HTML Goodies' JavaScript Script Tips.

(Netscape's manuals are not devoid of practical examples, but most of them are too 'skeletal' for my tastes. Admittedly, this would be a wimpy excuse for not discussing them, because we should be able to 'fill in the blanks' at this point. In any case, the Script Tips offer us a more suitably programmatic course of instruction.)

We begin with Script Tip #1, whose title asks, "What's an 'object'?" Actually, the definition of "object" in a programming sense can get pretty complicated depending on how wide a net you want to cast, but for our present purposes, Dictionary.com's entry for object: Computers accurately captures the essence of what we'll be doing with objects:

"Any item that can be individually selected or manipulated, as a picture, data file, or piece of text."

We can divide the objects of JavaScript into three classes; we will be concerned with:
(1) Browser-related objects - termed "predefined client-side objects" or "Navigator objects" by Netscape - that are no longer part of JavaScript but are now described by the Document Object Model (DOM) standard promulgated by the World Wide Web Consortium (W3C); and
(2) "Core" objects intrinsic to the JavaScript language - both client-side and server-side JavaScript can make use of these objects.
Not discussed in any of the script tips are:
(3) User-created objects.
Joe is thus referring to the first two object classes above when he defines "objects" in Script Tip #1 as "things that already exist without having to be created through scripting."

Script Tip #1 briefly looks at the following short script:

<script language="javascript">
document.write("<font color='green'>Green Text</font>")
</script>

If the code above looks familiar, it should - it differs only slightly from the script appearing in HTML Goodies' JavaScript Primers #1, which we discussed in Blog Entry #2. It's not clear from the HTML Goodies site whether Primer #1 or Script Tip #1 was written first.

Anyway, as simple as the Script Tip #1 script is, a few comments are nonetheless in order.

We begin, appropriately enough, with the <script> tag itself, which in a way is one of the most important parts of any JavaScript script. Consider Frank Zappa's comments on the role of the frame in art:

"The most important thing in art is The Frame. For painting: literally; for other arts: figuratively - because, without this humble appliance, you can't know where The Art stops and The Real World begins."
- The Real Frank Zappa Book, p 140

We might correspondingly say that the humble, opening and closing <script> tags are necessary to set a boundary between the script and the code that surrounds it.

Chapter 18 of the W3C's HTML 4.01 Specification deals with the HTML script element. The W3C notes here that the language attribute of the script element has been deprecated. A more current formulation for specifying JavaScript as the scripting language uses the type attribute with the value "text/javascript"; however, according to the Internet Society's recently approved Scripting Media Types RFC 4329 informational document, the "text/javascript" content type is now obsolete. RFC 4329 states that a content type of "application/javascript" or "application/ecmascript" should be specified instead.

Which <script> tag variant should you use? On my computer,
<script language="javascript">,
<script type="text/javascript">, and even just
<script>
all work OK when using either MSIE 5.1.6 or Netscape 7.02; neither browser recognizes <script type="application/javascript"> or <script type="application/ecmascript">. (Netscape 7.02 does recognize <script type="application/x-javascript">, however - I picked up the x-javascript MIME subtype here.) Both <script language="javascript"> and <script type="text/javascript"> strike me as safe options in this regard for the time being, notwithstanding their 'obsolescence.'

We turn now to the single command of the Script Tip #1 script:

document.write("<font color='green'>Green Text</font>")

Joe remarks, "This HTML page you're looking at is, in my opinion, the most commonly used object. In JavaScript speak, the page is named 'document'." At this point, we already know quite a bit about the document object - we ran through a number of document object properties in Blog Entry #13, for example - anything new to add?

With respect to the object classes listed above, the document object is a browser-related object. As noted in Blog Entry #22, Netscape last provided documentation for the document object, and for all other browser-related objects, in JavaScript 1.3. Here is the document object page of the JavaScript 1.3 Client-Side Reference; it must be said that this page is much more intelligible than the document object documentation of the DOM, notwithstanding the now-"obsolete" status of the JavaScript 1.3 Client-Side Reference.

More recently, the Mozilla Foundation, an offspring of the now-defunct Netscape, maintains a Gecko DOM Reference with a DOM document Reference that summarizes the DOM's document object documentation and provides links to the specific document interface sections of the DOM Level 2 Core and HTML Specifications.
(Gecko is the "layout engine" of Mozilla-based browsers. It's gratifying to see that the Mozilla guys are fellow herpetophiles.)

Back to the script - as Joe notes, the document object is "acted upon" by its write( ) method, whose entry in the JavaScript 1.3 Client-Side Reference is here. The HTMLDocument interface in the DOM Level 2 HTML Specification suggests that a document.write( ) command should be preceded by a document.open( ) command, but this is obviously not necessary.

As noted in Blog Entry #2, the write(x) method writes its argument x to the display of the document; with respect to JavaScript data types, x can be a string, a number, a Boolean value, or even the keyword null. For example, document.write(false) writes false to the page; as a write( ) argument, false does not need to be quoted.
(In the name of completeness: document.write(undefined) writes undefined to the page when using Netscape 7.02 but throws an "'undefined' is undefined" runtime error with MSIE 5.1.6.)

If x is a string containing HTML, as in the present case, then the browser will render, and not print, that HTML; as shown in Script Tip #1:

document.write("<font color='green'>Green Text</font>")
displays
Green Text
but not
<font color='green'>Green Text</font>

If for some reason you want to print the HTML (as I'm doing in this post), then the < and > metacharacters must be escaped, i.e., replaced with their HTML character references, as follows:

document.write("&lt;font color='green'&gt;Green Text&lt;/font&gt;")
or less intuitively,
document.write("&#60;font color='green'&#62;Green Text&#60;/font&#62;")

60 and 62 are the ASCII decimal code positions for the < and > characters, respectively.

Now, about that document.write( ) argument...

The W3C notes here that both the font element and its color attribute are now deprecated; "their use is discouraged in favor of style sheets." Very well, then - we can alternately write:

document.write("<span style='color:green;'>Green Text</span>")

A JavaScript-based alternative is also at hand; we can use the fontcolor( ) method of the core JavaScript String object here as follows:

document.write("Green Text".fontcolor("green"))

Joe concludes Script Tip #1 by describing the document.write( ) command as "a very simple hierarchy statement." To my understanding, however, the document object and its write( ) method, although both part of the DOM, do not constitute a DOM "parent/child relationship"; methods do not occupy nodes on a "DOM tree." Rather than being a hierarchy statement, then, the document.write( ) expression merely reflects the object.method( ) syntax of JavaScript.

We'll see bona fide hierarchy statements in the script that spans Script Tips #2-4, which we'll go over in the next post.

reptile7


Powered by Blogger

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