Article
Enhancing Structural Markup with JavaScript
Panel Switching
Now, let's consider a more advanced dynamic effect -- a panel switcher. The objective here is to have a number of panels (marked up using divs) on a page, of which only one is visible at a time. A set of links that remain constantly visible can be used to select which of the panels is currently on display. This could be useful for building something like a tabbed interface for browsing a series of related screens without requiring a page refresh every time one of the tabs is selected.
A good rule to keep in mind whenever Javascript is used to enhance a page is that the page must still be usable with Javascript disabled. In this case, this means that the ideal solution would work as advertised with Javascript turned on, but would display all of the panels on the page in a non-Javascript environment, with each of the links linking directly to the relevant panel, using a URL fragment.
Here, then, is the simplest markup that could possibly work:
<a href="#p1">Panel 1</a> | <a href="#p2">Panel 2</a>
<div id="p1">This is Panel 1</div>
<div id="p2">This is Panel 2</div>
Surprisingly, the above is nearly all the markup we need in order to hook in some Javascript to create the desired effect. We could just go ahead and use the above code, but let's add a class to the links to explicitly state that we wish to do something special with them:
<a href="#p1" class="toggle">Panel 1</a> |
<a href="#p2" class="toggle">Panel 2</a>
Here's how the Javascript is going to work. When the page loads, the script will scan through all the links on the page looking for any that have "toggle" in their class. For any that are found, the href attribute will be examined, and the element with the ID specified there will be located and added to an array of targeted elements. All but the first of these elements will be "switched off", so when the page loads, only the first panel will remain visible. The links themselves will have Javascript event handlers attached to them so that, when they're activated, their corresponding panel can be displayed.
The full script can be viewed here . There follows a walk through of how the code works.
var et_toggleElements = [];
This first line creates a global empty array, which will hold references to the panel elements on the page. Because this script has a global variable and a number of functions, we will be prefixing each with "et_" (for "easy toggle") -- this lowers the chance of our functions suffering name clashes with other scripts loaded by the same page.
/* Initialisation */
function et_init() {
var i, link, id, target, first;
first = true;
for (i = 0; (link = document.links[i]); i++) {
So far, we've initialised some variables, set the first flag to true and started to iterate over all the links in the document. Declaring the variables using var is important because it ensures the variables are local to the function. Without this step, they would be globally accessible and could interfere with other scripts.
if (/\btoggle\b/.exec(link.className)) {
This conditional checks that the current link has 'toggle' in its class. We're using a regular expression, rather than just checking if link.className == 'toggle', because the class attribute can contain more than one class, separated by spaces. /\btoggle\b/ is the regular expression; the \b parts match a "word boundary", which could be a space or the beginning or end of the string.
id = link.href.split('#')[1];
If the link has toggle in its list of classes, we assume that the target of the link is a URL fragment.
link.href.split('#') splits the link href at the # mark -- we know that the part we're interested in comes after the #, so we directly index the resulting array with [1] to pull out the targeted ID.
target = document.getElementById(id);
et_toggleElements[et_toggleElements.length] = target;
Here, we make another assumption -- that the element indicated by the link actually exists. We grab that element using the getElementById() method, then add it on to our array of elements by assigning it to the array index that equals the current length of the array. This works because arrays are indexed from 0, but the array length counts starting from 1; hence, the length of the array is also the index of the next empty slot in the array.
if (first) {
first = false;
} else {
target.style.display = 'none';
}
This is where the first flag we defined earlier makes itself useful. We want the first panel on the site to remain visible, while the others are hidden using the Javascript equivalent of 'display: none' in CSS. The flag allows us to do this.
link.onclick = et_toggle;
}
}
}