reptile7's JavaScript blog
Sunday, March 25, 2012
Date, Close, Copy
Blog Entry #245

Today we will take up HTML Goodies' "Top 10 JavaScript Snippets for Common Tasks" tutorial, which was composed by Scott Clark. The "JavaScript Snippets" tutorial offers...ah, the title is clear enough, isn't it? Not all of the snippets are worth covering; the business end of one of them isn't even JavaScript. The most useful and interesting snippet is the Calendar snippet, which deserves its own entry and we'll go through it in detail next time (or the time after that). This entry will give quick takes for the Date Display, Close Window, and Copy Selected Text snippets.

Today is the day

The Date Display snippet is a script that writes to the page the current date in the format:

Sunday, January 01, 2012

The script first creates a now Date object. It then sets up an array of day names that map onto the 0-to-6 returns of the Date object's getDay( ) method and an array of month names that map onto the 0-to-11 returns of the Date object's getMonth( ) method.

var now = new Date( );
var days = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday");
var months = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December");

The script's next statement gets now's getDate( ) return:

var date = ((now.getDate( ) < 10) ? "0" : "") + now.getDate( );

A leading zero is prepended to getDate( ) returns in the 1-to-9 range; if you don't feel the need to do this, then the date assignment can be simplified to var date = now.getDate( );.

Embarrassingly, the script gets the year part of the date via now's getYear( ) return. The Date object's getYear( ) method was deprecated and replaced by a getFullYear( ) method in JavaScript 1.3, which was the last version of classical JavaScript. I'm not going to discuss the getYear( ) code or even put it in front of you - go look at it if you want.

Anyway, using now's getFullYear( ) return, we are ready to concatenate the various parts of the date and write the resulting string to the page:

today = days[now.getDay( )] + ", " + months[now.getMonth()] + " " + date + ", " + now.getFullYear( );

For its rendering, the script can be placed/referenced via a script element in a div or span element (or in most other elements, for that matter - both %flow; and %inline; elements can contain script elements). Alternatively, the concluding document.write(today); command can be exchanged for a statement that assigns today to the innerHTML of a suitable element.

In the Date Display section's first sentence Scott italicizes his Friday, June 11, 2010 sample date. The original script does not in fact italicize the today string but it is simple enough to do that via the italics( ) method of the String object (which is not part of the ECMAScript standard but nonetheless has cross-browser support):

document.write(today.italics( ));

FYI: JavaScript's Date object has a toLocaleDateString( ) method that outputs the today format exactly when using Chrome and is only off by a comma when using Opera but falls short with other browsers, e.g., for my sample date Firefox's toLocaleDateString( ) return is 01/01/2012 whereas Safari gives January 1, 2012. IE 5 for Mac does not support the toLocaleDateString( ) method but its new Date("Jan 1, 2012").toLocaleString( ); return is Sunday, 01 January, 2012 12:00:00 AM, implying that more recent versions of IE give a Sunday, 01 January, 2012 toLocaleDateString( ) format - close enough, wouldn't you say?
(If anyone at Mozilla is reading this: unlike its toLocaleString( ) 'parent', the toLocaleDateString( ) method does not go back to JS 1.0 but first appeared in the JS 1.5 spec; check JS 1.4's Date object section - it's not there.)

The window will close

The Close Window snippet provides three simple ways to close a pop-up window. Before going any further, I should note that if you're going to make use of pop-up windows, then they should be opened via clicking buttons or links; browser pop-up blocking, which will be enabled for most of your visitors, typically prevents the opening of secondary windows by load and mouseover events but does not interfere with click-triggered openings (at least that's how things go on my computer).

This snippet caught my eye for two reasons:

(1) Its first close subsnippet unnecessarily uses a JavaScript URL as an onclick event handler:

<form><input type="button" value="Close Window" onclick="javascript:window.close( );"></form>
/* As the Close Window button is a 'user interface element', the form container is semantically inappropriate and should be thrown out. */

I was originally going to comment, "A JavaScript URL can be assigned to the href attribute of an anchor element, and THAT'S IT," but this is actually not true. In theory, JavaScript URLs can be used with any element attribute whose value has a %URI; data type: the action attribute of the form element, the cite attribute of the blockquote/q elements, etc.; however, this page reports that these pairings are not supported by modern browsers much of the time. (sorry, this resource is currently not available).

In any event, the onclick="javascript:window.close( );" attribute is valid HTML: onclick has a %Script; data type and %Script;'s replacement text is CDATA, e.g., we can validly assign a string like "Hello World" to onclick even though this won't do anything for us. Indeed, clicking an <input type="button" value="Button text" onclick="Hello World"> button will throw an Unexpected identifier (or equivalent) error with most browsers, which expect onclick to be set to a function/object - JavaScript is not always so "weakly typed", eh? Conversely, onclick="javascript:window.close( );" is in practice a legitimate JavaScript assignment because the browser sees the JavaScript URL not as a string (it would see an img src URL as a string) but as a function to execute, as can be verified by giving the button an id and running a typeof document.getElementById("buttonID").onclick command. Having said all this, the javascript: protocol is excess baggage and should be thrown out.

The second close subsnippet plants the javascript:window.close( ); URL in an anchor element, where it belongs:

<a href="javascript:window.close( );">Click to Close Window</a>

(2) The third close subsnippet features a setTimeout( ) command with an unusual first-argument syntax:

<body onload="window.setTimeout(window.close, 20000);">

'window.close( )' is what you would usually see. In the window.close expression, close seems to be a property of the window object, and plumbing the window object with a loop

for (var i in window) { document.write("window." + i + " = " + window[i] + "<br>"); }

does produce a window.close = function close() { [native code] } property with some browsers. More precisely, window.close is a reference for the window.close( ) function in the same way that myFunction would be a reference for a function myFunction( ) { /* function body statements */ } function, and the use of a function reference for the first setTimeout( ) argument has long had cross-browser support (one small clarification: IE 5 for Mac only supports the stringified function call syntax).

Copy and paste

The Copy Selected Text snippet presents code that gets a user's mousical text selection and loads it into a textarea field. (Is this really a common task? Maybe I need to get out more.) An it form holds the textarea field and a push button interface for triggering the copy/paste action:

<form name="it"><div align="center">
<input type="button" name="btnCopy" value="Press to copy the highlighted text" onclick="copyit(this.form.select1);"><p>
<textarea name="select1" rows="4" cols="45"></textarea>

Clicking the btnCopy button calls the following function:

function copyit(theField) {
    var selectedText = document.selection;
    if (selectedText.type == "Text") {
        var newRange = selectedText.createRange( );
        theField.focus( );
        theField.value = newRange.text; }
    else { window.alert("Select some text on the page and then press this button."); } }

The copyit( ) functionality is based on Microsoft's proprietary selection interface, which we briefly discussed in the Link and color section of Blog Entry #181. In brief: The user selection (document.selection) is given a selectedText identifier and then type-tested as to whether it contains only Text; if true, then its createRange( ) method is called to create a newRange TextRange object whose text property return, the actual text of the user selection, is subsequently assigned to the value of the theField textarea element. In addition, a theField.focus( ); command imparts focus to the textarea field.

So, how does it work? Can't tell ya: as of this writing, IE is the only major browser that supports the Microsoft selection interface - Opera used to support it, but no longer does so - and thus I as a Mac user am left high and dry vis-à-vis running the code; more specifically, the browsers on my computer throw a selectedText is undefined (or equivalent) error when I click the btnCopy button. Fortunately, the copyit( ) function is easily cross-browserized: condition the original copyit( ) function body via an if (document.selection) { ... } clause and then add the else if clause below.

else if (window.getSelection) {
    var selectedText = window.getSelection( ).toString( );
    if (selectedText) { // If selectedText is not an empty string
        theField.focus( );
        theField.value = selectedText; }
    else window.alert("Please select some text."); }

The else if functionality is based on Mozilla's selection interface, which we briefly discussed in the Are you selected? section of Blog Entry #182. The getSelection( ) method of the window object, and the toString( ) method of the selection object that window.getSelection( ) returns, are today supported by the most recent versions of all of the major browsers, including IE.

Do we need a demo for this guy? Oh, why not:

Select some text anywhere in this div and then click the Press... button.

Web developers often use JavaScript for common tasks on their websites. In this tutorial we'll show you the top 10 JavaScript snippets you can use on your webpages by just cutting and pasting!
In this article we're going to cover the following popular script snippets!

And by the way, today's date is:
A Date Display demo is included for good measure. I've tidied up the Copy Selected Text HTML a bit, namely, I've removed the it form container and exchanged the div's deprecated align="center" attribute for a text-align:center; style declaration; the textarea field is accessed in the copyit( ) function via a getElementById( ) command. N.B. In Blog Entry #182 I stated, The W3C will be bringing the Mozilla selection interface into HTML5; that interface has since been taken out of HTML5 and is slated to be defined in a future Selection API specification.
We'll continue our "JavaScript Snippets" commentary in the following entry.

Wednesday, March 14, 2012
Rotator Redux
Blog Entry #244

We return to the topic of animation in today's post with a look at HTML Goodies' "Adding Rotating Images to Your Web Site" tutorial, which is authored by Michael Rohde. The "Rotating Images" tutorial offers a script that cycles array items through a common div placeholder; in the tutorial the script works with a set of linking images, although there's no reason that you couldn't use the script with other types of content, as points out in the tutorial comment thread.

Rotator deconstruction

Here's the author's placeholder HTML:

<layer id="placeholderlayer"></layer><div id="placeholderdiv"></div>

I see you rolling your eyes: "The layer element??" The "Rotating Images" tutorial went live in May 2010, and it's definitely pretty weird that the author felt a need to reach out to Netscape 4.x users, who are the ONLY folks who would have support for the layer element/object, because there shouldn't be anyone out there using Netscape 4.x at this point, there really shouldn't. But whatever. In the "Notes on invalid documents" section of the HTML 4.01 Specification the W3C prescribes, If a user agent encounters an element it does not recognize, it should try to render the element's content. The placeholderlayer layer holds no content and accordingly is ignored by non-Netscape 4.x browsers; layout-wise it collapses into nothingness à la an empty div element.

The linking images array has the following format:

var items = new Array( );
items[0] = "<a href='link.htm'><img alt='image0 (9K)' src='/Images/image0.jpg' height='300' width='300' border='0' /></a>";
items[1] = "<a href='link.htm'><img alt='image1 (9K)' src='/Images/image1.jpg' height='300' width='300' border='0' /></a>"; // Etc.

Ugh, stringified HTML (whose unescaped </a sequences would prevent the main document's validation) - we'll retool this data later, but for now:

• There are six items elements in all; you are of course free to increase or decrease the number of elements.

• The link targets (which are all specified as link.htm but, per the tutorial text, should be ordinalized: link0.html, link1.html, etc.) are placed in the same directory that holds the main document whereas the image files are placed in a separate directory; as the /Images/image#.jpg relative URL seems to cause some confusion for the newbies in the comment thread, it would probably be a better idea to put everything in the same directory.

• The border attribute of the img element is deprecated; we should use an a img { border: none; } style declaration to ensure that the images are borderless.

The linking images are rotated by a rotater( ) (sic) function that is called when the main document loads. Strangely, two rotater( ) functions appear in the tutorial code; the first of these functions is given below:

var howOften = 5;
var current = 0;
function rotater( ) {
    document.getElementById("placeholder").innerHTML = items[current];
    current = (current == items.length - 1) ? 0 : current + 1;
    window.setTimeout("rotater( );", howOften * 1000); }
window.onload = rotater;

The progress of the rotation is tracked by a current variable, which is initialized to 0. Suppose for a moment that the placeholder div's id is placeholder and not placeholderdiv. The above function initially gets the placeholder div and sets its innerHTML to items[0], the image0.jpg/link0.html linking image. Next, a ?: conditional statement increments current to 1. Finally, a setTimeout( ) command re-calls the function after 5 (howOften) seconds.

In the second rotater( ) iteration, the image1.jpg/link1.html linking image is loaded into the placeholder div; current is incremented to 2; rotater( ) is re-called after a 5-second delay; and so on. The ?: statement resets current to 0 if current has reached items.length - 1 (5).

The first rotater( ) function would be perfectly adequate for all modern JavaScript-supporting GUI browsers; in practice it is overwritten by its more elaborate successor:

var ns6 = document.getElementById && !document.all;
function rotater( ) {
    if (document.layers) {
        document.placeholderlayer.document.close( ); }
    if (ns6)
        document.getElementById("placeholderdiv").innerHTML = items[current];
    if (document.all)
        placeholderdiv.innerHTML = items[current];
    current = (current == items.length - 1) ? 0 : current + 1;
    window.setTimeout("rotater( );", howOften * 1000); }

The second rotater( ) function's body begins with a conditional that writes items[0] to the document of the placeholderlayer layer if the browser supports document.layers, which as noted earlier is only true for Netscape 4.x. For those of you who are really curious, the client-side layer object and its document property are discussed in the "Using JavaScript With Positioned Content" chapter of Netscape's "Dynamic HTML in Netscape Communicator" resource.

After the layer code is a second if clause that sets the placeholderdiv div's innerHTML to items[0] for browsers with getElementById( ) support AND whose document.all return cannot be converted to true; this clause is operative for the Mozilla browsers, Chrome/Safari, and Opera.

For document.all
Firefox, Camino, and Netscape 9 return [object HTML document.all class],
Chrome and Safari return [object HTMLAllCollection], and
Opera returns [object HTMLCollection];
unorthodoxly, all of these values convert to false in a logical context (thus leading to a true return for the ns condition) - see Opera developer Hallvord Steen's "!document.all == true" blog post for more on this.

The aforelisted browsers do in fact implement the all( ) collection; for example, they all give red and bolded text with:
<div id="div1">This is some div text.</div>
<script type="text/javascript">
document.all("div1").style.color = "red";
document.all("div1").style.fontWeight = "bold";

However, IE is the only major browser for which the document.all return ([object Collection] with IE 5.1.6) converts to true in a logical context, and its users are flagged by a third if clause that sets placeholderdiv.innerHTML to items[0]. In a Note at the end of Example Two in its "Introduction to Dynamic HTML" resource, Microsoft explains:
Note When Windows Internet Explorer encounters a tag that defines an id or name, it creates a reference to it in the global scope so that it can be easily located by script; however, this is considered non-standard behavior. To ensure the widest browser support for your DHTML, use getElementById( ) to locate target elements.
Its non-standard status notwithstanding, the ability of id and name attribute values to double as object references is now a cross-browser feature: the non-IE OS X GUI browsers on my computer all support it. (IE 4.5 running in the SheepShaver environment also supports it, and thus it was actually a cross-platform feature from the get-go.)

The second rotater( ) function concludes with the same current-adjusting conditional and recursive rotater( ) function call that the first one does.

Streamline it

In its original form the "Rotating Images" script effectively cycles three things:
(1) the img src value;
(2) the img alt value; and
(3) the link href value.
It is really necessary to cycle entire elements through the placeholderdiv div? Not at all. A more efficient approach is to use a linking img itself as the common placeholder

<a id="anchorID" href="link0.html" target="_blank">
<img id="imageID" width="48" height="48" src="image0.gif" alt="image0 (9K)" />

and then cycle the src/alt/href data through that placeholder. The script code below can be used to organize the data and to preload the rotating images:

var theImages = new Array( );
var linkURLs = new Array( );
for (i = 0; i < 6; i++) {
    theImages[i] = new Image( );
    theImages[i].src = "image" + i + ".gif";
    theImages[i].alt = "image" + i + " (9K)";
    linkURLs[i] = "link" + i + ".html"; }

With theImages and linkURLs arrays in place, all that remains is to update the rotator function as follows:

var current = 0, howOften = 5;
function rotator( ) {
    document.getElementById("imageID").src = theImages[current].src;
    document.getElementById("imageID").alt = theImages[current].alt;
    document.getElementById("anchorID").href = linkURLs[current];
    current = (current == theImages.length - 1) ? 0 : current + 1;
    window.setTimeout("rotator( );", howOften * 1000); }
window.onload = rotator;

(If you like, you can respectively access the placeholder's img and anchor elements with classical JavaScript's images[ ] and links[ ] collections so that those legions of Netscape 4.x users can continue to run your code.)

The "Rotating Images" tutorial doesn't provide a demo, which saddened commenter Rob. Well, I would never want to sadden anyone if I could help it:

image0 (4 KB)

Demo changes

• The howOften delay has been cut to 2.

• The theImages.srcs are set discretely as the uploaded images have irregular URLs.

• The anchorID links point to relevant entries in Merriam-Webster's online dictionary.
Some of the tutorial commenters ask for things that we've covered on prior occasions - e.g., AMP wants to pause the rotation with a mouseover, Tara wants a slide show - and it is tempting to respond to these people (given that the HTML Goodies management evidently can't be bothered to respond to them), but I think our time is better spent moving on to the next Beyond HTML : JavaScript sector tutorial, "Top 10 JavaScript Snippets for Common Tasks", in the following entry.


Sunday, March 04, 2012
Lightbox VIII
Blog Entry #243

We're getting there - this post will be the last in our lightbox image viewer series.

showLightbox( ) finale

After centering the loading.gif image in the viewport, displaying the overlay div/loading.gif image, loading a lightbox image into the lightboxImage img placeholder, centering the lightbox div in the viewport, and writing a caption to the lightboxCaption div, the showLightbox( ) function switches off the loading.gif image and switches on the lightbox div:

if (objLoadingImage) { = "none"; } = "block";

In the lightbox.js script in operation at his "Lightbox JS" page (but not in the lightbox.js script in the lightbox/ package offered by the HTML Goodies tutorial), Lokesh inserts the code below, which hides select boxes as they will 'peek' through the image in IE, between the preceding statements:

selects = document.getElementsByTagName("select");
for (i = 0; i != selects.length; i++) {
    selects[i].style.visibility = "hidden"; }

A getElementsByTagName( ) command gets the select elements in the lightbox.html document and then a for loop invisibilizes them by setting their CSS visibility property to hidden. Are these operations necessary? I coded a nine-option selection list with a size="5" attribute and added it to the lightbox.html page; upon running the showLightbox( ) function, I found that the list's vertical scrolling mechanism was in fact painted on top of both the lightbox overlay

Vertical scrollbar pokes thru lightbox overlay

and the lightbox image with Netscape 6/7/9 but not with any other browser. Upon subtracting the size attribute, the list is rendered completely under the lightbox overlay/image with all of the lightbox.js-supporting browsers on my computer. I don't know how this all shakes out for Windows users - maybe the above code is needed and maybe it isn't, but perhaps you should include it to be on the safe side; if you do keep it, however, you should place it before the = "block"; statement that displays the overlay div.

After displaying the lightbox div, the showLightbox( ) function updates the height of the overlay div in case the rendered lightbox increases the height of the lightbox.html page: if the lightbox extends below the bottom edge of the viewport and if the original lightbox.html height was less than the viewport height, then the original arrayPageSize[1]+"px" overlay div height will not cover (surround) the beyond-the-viewport part of the lightbox.

arrayPageSize = getPageSize( ); = (arrayPageSize[1] + "px");

The showLightbox( ) function concludes by calling the listenKey( ) function so as to set up the press x to close behavior (vide infra) and unnecessarily returning false.

listenKey( ); // Check for "x" keypress
return false;

X hides the lightbox

The lightbox's lower-right-hand corner comprises a keyboardMsg div

objKeyboardMsg = document.createElement("div"); = "keyboardMsg";

bearing a press x to close keyboard message.

objKeyboardMsg.innerHTML = "press <kbd>x</kbd> to close";

Pressing x (or shift-x) on the keyboard does indeed zero out the overlay and lightbox divs and returns the user to the lightbox.html page; this behavior is handled by the lightbox.js listenKey( ), getKey( ), and hideLightbox( ) functions.

The listenKey( ) function body consists of a single statement that coassociates the document object, keypress events, and the getKey( ) function:

function listenKey( ) { document.onkeypress = getKey; }

Pressing a character value-producing key or keys generates a keypress event (just pressing, say, a shift key won't do it) and calls the getKey( ) function:

function getKey(e) {
    if (e == null) { // IE
        keycode = event.keyCode; }
    else { // Mozilla
        keycode = e.which; }
    key = String.fromCharCode(keycode).toLowerCase( );
    if (key == "x") { hideLightbox( ); } }

The getKey( ) function body begins with an if...else statement that determines the decimal Unicode code position of the pressed-key(s) character value.

• For IE 4-8, the e == null if condition returns true; these browsers get the key character code position via the keyCode property of Microsoft's proprietary event model, which we discussed in Blog Entry #108. IE 4-8 actually return undefined for the e expression; however, the null and undefined values are comparatively equal. As both null and undefined convert to false in a logical context, the condition could have been written as !e.

• All other event object-supporting browsers, including IE 9+, go through the else clause and get the key character code position via the which property of the Netscape-cum-W3C event model, which we discussed in Blog Entry #107.

The keycode key character code position is converted to the key character value itself by the fromCharCode( ) method of the String object; the String object's toLowerCase( ) method is then applied to the fromCharCode( ) return (whether it needs it or not). If the key toLowerCase( ) return is x, then the hideLightbox( ) function is called.

The listenKey( )/getKey( ) functionality can be written more compactly as:

document.onkeypress = function (e) {
    keycode = e ? e.which : event.keyCode;
    key = String.fromCharCode(keycode).toLowerCase( );
    if (key == "x") hideLightbox( ); }

(A related-if-obsolete aside:
Unless Mozilla has inside information that the rest of us aren't privy to, it is not true that the entire KeyboardEvent interface is slated to be deprecated, although the W3C does plan to phase out the keypress event (but not the keydown/keyup events) in favor of a textinput event. The textinput event is tied to a TextEvent interface (not a TextInput interface) and does have limited support as of this writing but is not yet 'ready for prime time' - you can't use it with the document object, for example.

December 2016 Update: The KeyboardEvent interface is still alive and well, if in a state of flux; the W3C has given the keypress event a "legacy" status; the textInput event and the TextEvent interface have been dropped.)

Here's the hideLightbox( ) function:

function hideLightbox( ) {
    objOverlay = document.getElementById("overlay");
    objLightbox = document.getElementById("lightbox"); = "none"; = "none";
    document.onkeypress = ""; /* Disable keypress listener */ }

The hideLightbox( ) function first gets the overlay and lightbox divs; if we were to globally declare objOverlay and objLightbox, which are respectively used to variabilize the overlay and lightbox divs when they are created in the initLightbox( ) function, then the getElementById( ) statements would be unnecessary. The overlay/lightbox divs are then zeroed out in the usual manner.

If you hid your lightbox.html selection lists earlier, then you can bring them back at this stage via:

for (i = 0; i != selects.length; i++) { selects[i].style.visibility = "visible"; }
/* If selects is not declared with the var keyword in the showLightbox( ) function, then there's no need to re-get the lightbox.html select elements in the hideLightbox( ) function as selects will have a 'global scope'. */

Finally, document.onkeypress is 'cleared' by setting it to an empty string (which stays an empty string with the Mozilla browsers and IE 5.x but is converted by Chrome/Safari to null and by Opera to function anonymous (event) {\n\n}); there's no point in re-executing the getKey( ) function via any subsequent keypresses at the lightbox.html page once the overlay/lightbox divs are gone (even though doing so won't have any effect).

Clicking (a) the overlay div or (b) the close.gif or lightbox image (more precisely, the objLink link container for these images) also calls the hideLightbox( ) function as detailed in the Viewer behavior section of Blog Entry #237. Moreover, in his "Lightbox JS" lightbox.js script Lokesh wraps the keyboard message's x in a <a href="#" onclick="hideLightbox( ); return false;"></a> container so as to provide yet another hideLightbox( ) trigger if the x is clicked.

A final comment on design

For the most part I've given you my "here's how I would do it" lightbox code as we've gone along. I was going to wrap up this entry by revisiting a key aspect of the lightbox image viewer's design, namely, the use of the initLightbox( ) function to create the viewer's HTML markup, which rubs me the wrong way as it violates the "keep structure and behavior separate" principle, but it subsequently occurred to me that it makes sense to do it that way if you're going to apply the viewer to a lot of pages. At the least, however, the initLightbox( ) style settings should be transferred to the lightbox.css style sheet:

#overlay, #lightbox { display: none; }
#overlay, #loadingImage, #lightbox, #closeButton { position: absolute; }
#overlay { top: 0px; left: 0px; }

As noted earlier in this series, the lightboxCaption div doesn't need to be initially zeroed out, the zIndex settings should all be removed, and the overlay div's width should be set to arrayPageSize[0]+"px" in the showLightbox( ) function.

I still like the idea of hard-coding the viewer HTML in the lightbox.html document if you're going to apply the viewer to just one page; there's not that much HTML to begin with and it takes up very little space if you eliminate the white space between its tags.

And that concludes our discourse on the lightbox image viewer. FYI: Lokesh has also crafted a much more complex, second-generation lightbox2 image viewer; we won't be discussing it but I've tried Lokesh's single image and image set lightbox2 examples and they work as advertised.

In the following entry we'll check over the next Beyond HTML : JavaScript sector tutorial, "Adding Rotating Images to Your Web Site".


Powered by Blogger

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