reptile7's JavaScript blog
Saturday, January 21, 2012
Lightbox IV
Blog Entry #239

At this point - when the lightbox.html page has loaded - we have largely coded the lightbox image viewer; we still have to
(a) set the height of the overlay div,
(b) center the loading.gif image and the lightbox div in the viewport,
(c) load an image into the lightboxImage img placeholder,
(d) write a caption (if relevant) to the lightboxCaption div,
(e) set up the press <kbd>x</kbd> to close behavior, and of course
(f) bring the whole shebang to life as it's all currently zeroed out.

We'll get to each of these operations in due course. Meanwhile, the lightbox.html page's rel="lightbox" links - be they thumbnail image links or textual links - are now sitting in front of us, ready for action. When a lightbox link is clicked, the lightbox.js showLightbox( ) function is called and, via the this keyword, passed the link by the following conditional in the lightbox.js initLightbox( ) function:

if (anchor.getAttribute("href") && (anchor.getAttribute("rel") == "lightbox")) {
    anchor.onclick = function ( ) { showLightbox(this); return false; } }

The showLightbox( ) function first gives the passed link object an objLink identifier and then 'gets' six of the lightbox image viewer's elements:

function showLightbox(objLink) {
    var objOverlay = document.getElementById("overlay");
    var objLoadingImage = document.getElementById("loadingImage");
    var objLightbox = document.getElementById("lightbox");
    var objImage = document.getElementById("lightboxImage");
    var objLightboxDetails = document.getElementById("lightboxDetails");
    var objCaption = document.getElementById("lightboxCaption");

In source order, the overlay div, the loadingImage img, the lightbox div, the lightboxImage img, the lightboxDetails div, and the lightboxCaption div are given objOverlay, objLoadingImage, objLightbox, objImage, objLightboxDetails, and objCaption identifiers, respectively. If you've been keeping score at home, you will note that these are the very same variable names that these elements were given when they were created in the initLightbox( ) function; it follows that the above getElementById( ) statements can be thrown out (1) if the obj- variables are declared globally

var loadingImage = "loading.gif";
var closeButton = "close.gif";
var objOverlay, objLoadingImage, objLightbox, objImage, objLightboxDetails, objCaption;
function getPageScroll( ) { ... }

and (2) if we subtract the var keywords that precede the declarations of these variables in the initLightbox( ) function.

function initLightbox( ) { ...
    objOverlay = document.createElement("div"); ...
    objLoadingImage = document.createElement("img"); ...

Next, the showLightbox( ) function places calls to the lightbox.js getPageScroll( ) and getPageSize( ) functions:

var arrayPageScroll = getPageScroll( );
var arrayPageSize = getPageSize( );

The getPageScroll( ) function determines via a three-clause conditional how many pixels the page has been scrolled vertically; its arrayPageScroll return will be used to set top values that vertically center the loading.gif image and the lightbox div in the viewport. Here's the getPageScroll( ) function:

/* Returns array with x,y page scroll values. Core code from - */
function getPageScroll( ) {
    var yScroll;
    if (self.pageYOffset) {
        yScroll = self.pageYOffset; }
    else if (document.documentElement && document.documentElement.scrollTop) { // Explorer 6 Strict
        yScroll = document.documentElement.scrollTop; }
    else if (document.body) { // all other Explorers
        yScroll = document.body.scrollTop; }
    arrayPageScroll = new Array("", yScroll);
    return arrayPageScroll; }

Contra the /* Returns array with x,y page scroll values. */ comment, the getPageScroll( ) function does not address horizontal (x-axis) scrolling. The /* Core code from - */ comment is referring to an "Viewport properties" page that is no longer hosted by but, courtesy of the Internet Archive, can still be seen here (this is the 30 December 2005 version of the page, which was contemporary with the development of the lightbox image viewer in late 2005).

The if (self.pageYOffset) yScroll = self.pageYOffset; clause tests the browser's support for the pageYOffset property of the window object and then assigns the pageYOffset return to a yScroll variable if the page has been scrolled vertically. A classical JavaScript property that dates to JavaScript 1.2, pageYOffset is today supported by the most recent versions of all of the major browsers, including Internet Explorer. The W3C will be adding pageYOffset to an HTML5 Window interface.

There's just one little problem with the if (self.pageYOffset) test: if the user didn't do any vertical scrolling before clicking a lightbox link (as would be the case at the "Lightbox" tutorial's isolated demo page), then self.pageYOffset will return 0, a value that converts to false in a logical context. Fortunately, the else if (document.body) yScroll = document.body.scrollTop; clause will with most browsers deliver a 0 to yScroll in this case, but if for whatever reason you did want to work with the pageYOffset property, then a

if (/\d+/.test(window.pageYOffset)) yScroll = window.pageYOffset;
/* I trust y'all know that the window and self object references are synonymous. */

clause will provide you with the true condition return you are looking for.

The pageYOffset property is not supported by pre-IE 9 versions of Internet Explorer, ergo the two else if clauses. Both of these clauses work with the scrollTop property, which was first implemented by Microsoft in IE 5; they respectively assign document.documentElement.scrollTop and document.body.scrollTop to yScroll for a true condition return.

The documentElement attribute of the Document interface, which goes back to Level 1 of the Core DOM, references the html element of an HTML document. The body attribute of the HTMLDocument interface, which goes back to Level 1 of the HTML DOM, normally (in the absence of frames) references a document's body element. Microsoft's scrollTop page states that scrollTop applies to both the body and html elements. However - and as a Mac user I am not able to confirm this - the QuirksMode "Viewport properties" page reports that when IE 6 is running in "strict mode" (a standards-compliant mode), it doesn't support document.body.scrollTop, notwithstanding that document.body was no less W3C-kosher than document.documentElement was at the time IE 6 was released (2001), whereas for all other IE 5+ versions document.body.scrollTop is OK.

IE 6's strict mode is triggered by placing a valid document type declaration at the top of a document, for example:


If the declaration is invalid or if it isn't there in the first place, then IE 6 runs in "quirks [IE 5-compatible] mode". According to Wikipedia's "Quirks mode" entry, IE 6's strict mode can be switched to quirks mode by preceding the declaration with an XML prolog or a comment, thereby providing a mechanism via which we can get rid of the document.documentElement code and route all IE 6 users through the else if (document.body) yScroll = document.body.scrollTop; clause.

(The following paragraph is somewhat outdated but I'm going to leave it intact 'for historical purposes':
Of course, this being the year 2012, you may be wondering why we would be interested in accommodating IE 6 users at all. As it happens, Microsoft itself maintains an "Internet Explorer 6 Countdown" page on which it proclaims that it's time to say goodbye (bold in original) to IE 6 and that friends don't let friends use Internet Explorer 6 (there's even a Death to IE 6 in the page's title bar), so if you want to stiff the 7.7% of the world that is still using IE 6 and chuck that first else if clause, then our friends in Redmond have got your back.)

As noted above, the scrollTop property today has widespread support (its Netscape support goes back to Netscape 7); accordingly, the W3C will be adding it to the Core DOM's Element interface. In both the OS X and SheepShaver environments, the browsers on my computer that support scrollTop do so for the body element and not for the html element; interestingly, I find that these browsers uniformly return 0 (not undefined) for document.documentElement.scrollTop whether or not I've done any vertical scrolling, and thus they would pass a /\d+/.test(document.documentElement.scrollTop) test for IE 6 users* in the absence of the pageYOffset code. I would therefore argue that we should scrap both the pageYOffset code and the document.documentElement code and reduce the y-axis part of the getPageScroll( ) function to:

if (/\d+/.test(document.body.scrollTop)) yScroll = document.body.scrollTop;

*Like the self.pageYOffset condition, the document.documentElement && document.documentElement.scrollTop condition converts to false if the page hasn't been scrolled vertically.


The Scrolling offset subsection of the QuirksMode "Viewport properties" page gives commands that can determine how many pixels a page has been scrolled horizontally:

var x;
if (self.pageYOffset) {
    x = self.pageXOffset; }
else if (document.documentElement && document.documentElement.scrollTop) {
    x = document.documentElement.scrollLeft; }
else if (document.body) {
    x = document.body.scrollLeft; }

For the getPageScroll( ) function, the author subtracted the pageXOffset/scrollLeft statements evidently on the sensible assumption that the document width will not exceed the viewport width in the overwhelming majority of cases, although I myself would include an xScroll = document.body.scrollLeft; statement (to be added to the above if (/\d+/.test(document.body.scrollTop)) conditional) to be on the safe side.

The arrayPageScroll return

The yScroll value is assigned to the second element of an arrayPageScroll array (i.e., yScroll becomes arrayPageScroll[1]), which is subsequently returned to the var arrayPageScroll = getPageScroll( ); statement in the showLightbox( ) function. There's no need to put yScroll in an array if we don't address horizontal scrolling; rather, we can directly return yScroll itself to the showLightbox( ) function. Conversely, if we take horizontal scrolling into account, then yes, an array that holds both xScroll and yScroll values is what we'll want to return.

In sum, here's how I would code the getPageScroll( ) function:

function getPageScroll( ) {
    var xScroll, yScroll, arrayPageScroll;
    if (/\d+/.test(document.body.scrollTop)) {
        xScroll = document.body.scrollLeft;
        yScroll = document.body.scrollTop; }
    arrayPageScroll = new Array(xScroll, yScroll);
    return arrayPageScroll; }

The preceding function leaves Netscape 6 users out in the cold, but that's life.

We'll discuss the getPageSize( ) function in the following entry.


Comments: Post a Comment

<< Home

Powered by Blogger

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