reptile7's JavaScript blog
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".


Comments: Post a Comment

<< Home

Powered by Blogger

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