
Introduction
My previous DHTML Web Tab article implemented a simple client-side web tab using HTML, JavaScript and CSS. Using the same methods of configurability and implementation style as the previous web tab, this article extends the web tab by providing a hierarchical system of web tabs with visual DXImageTransform
filter effects. That is, each tab can consist of further sub tabs. For UI simplicity, the hierarchy of tabs is limited to one level deep.
Configuration
Parallel to the previous implementation, the tabs and their respective local/remote content sources are specified in an array; each string item in the arrays represent a tab and details of it separated by a �|� pipe character. Note that each string item as well as an array is followed by a �,� comma, except the last. The difference from the previous implementation however, is that the first string element in each array defines the parent tab and the subsequent string elements in that same array define the child tabs. For example, the tabs in the above screenshot were constructed using the following configuration:
var tabs = new Array
(
new Array("Google|http://www.google.com/",
"News|http://news.google.com/", "Froogle|http://froogle.google.com/"),
new Array("Microsoft|http://www.microsoft.com/|*",
"MSDN|http://www.msdn.com/",
"Office|http://office.microsoft.com/home/default.aspx"),
new Array("Yahoo!|http://www.yahoo.com/",
"News|http://news.yahoo.com/",
"Finance|http://finance.yahoo.com/",
"Mail|http://mail.yahoo.com/")
);
In general, every first element in each array defines a parent tab and the subsequent elements as corresponding child tabs. The following template summarizes:
�Parent tab-text | URI | [*]�, [�Child1 tab-text | URI�],
[�Child2 tab-text | URI�], [�ChildX tab-text | URI�], ...
Square brackets �[�]� denote optional parameters, thus, child tabs are optional. The following screenshot example illustrates how to use the template:

A second �|� pipe character followed by a �*� wildcard character after specifying the URI of a parent tab will make that specific parent tab a default selected tab when the page loads, example:
"Google | http://www.google.com/ | *"
Internet Explorer DXImageTransform
filter effects can be applied to child tabs via assigning a global variable named DXImageTransformFilter
to one of the many DXImageTransform
filters. A few examples of DXImageTransform
filters included:
DXImageTransform.Microsoft.Wheel(duration=2, spokes=5)
DXImageTransform.Microsoft.Barn(duration=2, orientation=horizontal)
DXImageTransform.Microsoft.Blinds(duration=2, bands=5)
DXImageTransform.Microsoft.CheckerBoard(duration=2)
DXImageTransform.Microsoft.Fade(duration=2)
DXImageTransform.Microsoft.GradientWipe(duration=2, wipeStyle=0)
DXImageTransform.Microsoft.Iris(duration=2, irisStyle=STAR)
DXImageTransform.Microsoft.Iris(duration=2, irisStyle=CIRCLE)
DXImageTransform.Microsoft.Pixelate(duration=2, maxSquare=40)
DXImageTransform.Microsoft.Wheel(duration=2, spokes=5)
DXImageTransform.Microsoft.RandomDissolve(duration=0.5)
DXImageTransform.Microsoft.Spiral(duration=2)
DXImageTransform.Microsoft.Stretch(duration=2, stretchStyle=push)
DXImageTransform.Microsoft.Strips(duration=2, motion=rightdown)
For more on DXImageTransform
filter effects and their configuration, see Introduction to Filters and Transitions in MSDN. All of the above listed example DXImageTransform
filter effects are stored into an array named DXImageTransformLibrary
; thus, a library of filters can be built-up. Assigning the global variable DXImageTransformFilter
to null
will use a random filter effect from the library of filters. For example:
A visual �fade� effect DXImageTransform
filter:
var DXImageTransformFilter =
�DXImageTransform.Microsoft.Fade(duration=2)�
Again, the same visual �fade� effect DXImageTransform
filter, but specified from the library:
var DXImageTransformFilter = DXImageTransformLibrary[4];
Or, use a random DXImageTransform
filter effect:
var DXImageTransformFilter = null;
That completes the configuration of the web tab in script; the final step is to declare HTML <DIV>
container objects in the body of the web page as:
<DIV ID="divTabStrip">
<DIV ID="divTabFrame">
Finally, the web tab is initialized via calling the tabOnLoad
function:
<BODY onLoad="tabOnLoad()">
Look & Feel
Borrowing from the previous implementation of the DHTML Web Tab, the look & feel of the tabs are adjusted entirely with CSS. For completeness, the basics are described. When a tab is selected by being clicked upon, its look & feel is defined by the .tabOn
style. Conversely, a tab�s neutral look & feel in its unselected state is defined by the .tabOff
style. The attributes that are configurable for each .tabOn
& .tabOff
style are as below, .tabOn
style shown in this example:
FONT-FAMILY: Verdana;
FONT-SIZE: 11;
FONT-WEIGHT: 700;
TEXT-ALIGN: CENTER;
COLOR: #FFFFFF;
BACKGROUND-COLOR: #FF9900;
BORDER-BOTTOM: #FF9900 1PX SOLID;
BORDER-TOP: #FF9900 1PX SOLID;
BORDER-LEFT: #FF9900 1PX SOLID;
BORDER-RIGHT: #000000 1PX SOLID;
HEIGHT: 20;
CURSOR: HAND;
Likewise, the look & feel of the tab frame, which just essentially is an <IFRAME>
, is adjusted via the CSS .tabFrame
style; attributes configurable are:
BORDER-RIGHT: #FF9900 9PX SOLID;
BORDER-TOP: #FF9900 9PX SOLID;
SCROLLBAR-FACE-COLOR: #6699CC;
SCROLLBAR-HIGHLIGHT-COLOR: #FFFFFF;
BORDER-LEFT: #FF9900 9PX SOLID; WIDTH: 100%;
SCROLLBAR-SHADOW-COLOR: #6699CC;
SCROLLBAR-ARROW-COLOR: #FFFFFF;
BORDER-BOTTOM: #FF9900 9PX SOLID;
SCROLLBAR-DARKSHADOW-COLOR: #6699CC;
HEIGHT: 95%;
A point worthy of reiteration from the previous article is that the BORDER-TOP
color style attribute of the <IFRAME>
main tab content area, .tabFrame
, has to be the same as the BORDER-BOTTOM
color style attribute of the tab buttons when they are selected, .tabOn
. This is so that when the tab button is selected, it will look as part of the <IFRAME>
and provide a continuous and consistent look.
Design
Just as the previous implementation, this web tab is again composed of HTML buttons for the tabs and an <IFRAME>
for the main content area. However, in addition to this implementation, every child set of tabs reside in an individual table division:

The first table division is where all the parent tabs reside. A parent tab can consist of zero or more child tabs. Each of those child set of tabs belong to a subsequent unique table division.
All child sets (table divisions which house the sub tabs) are by default hidden from view. Aside the main operation of populating the <IFRAME>
with content upon clicking a parent tab, the unique table division which houses the corresponding sub tabs in the tab hierarchy appear visually with a DXImageTransform
filter effect.
Since only one table division (child set of sub tabs) is visible at a time, in theory, this should eliminate any potential horizontal scrolling that may be caused by a tab strip consisting of a large number of tabs/sub tabs.
Implementation
The hierarchy of tabs are managed by using an array of arrays; - each item in the array is an array itself. This is purely so to simplify the construction of the web tab � rather than looping through one user-defined array at a time, a nested loop can be implemented to loop through nested arrays; thus referencing only one user-defined array.
The web tab is constructed when the tabOnLoad
function is called, it�s the �main� entry point of the web tab construction. This declares a HTML table, but before the table is completed, calls are made to the tabLoadParents()
and tabLoadChildren()
functions:
HTML += "<TABLE BORDER='0' CELLPADDING='0' CELLSPACING='0' WIDTH='100%'>";
HTML += "<TD ALIGN='LEFT'>";
tabLoadParents();
tabLoadChildren();
The tabLoadParents()
function seeks out the parent tabs by looping through each array, picking out the first string element in each. Every first string element in each array is then split at every �|� pipe character to extract various parts of the string, creating a HTML button with the .tabOff
CSS style as well as assigning the buttons with a unique ID and an onClick
event handled by the tabOnClick
function:
for (var i = 1; i < tabs.length; i++)
{
var tab = tabs[i][0].split("|");
HTML += "<INPUT TYPE='BUTTON' ID="+ i +
" CLASS='tabOff' VALUE="+tab[0] +
" onClick='tabOnClick("+i+", "+i+", 0)'>";
}
Every HTML button created in the tabLoadParents()
function is added to a table division which in turn is appended to the HTML table created earlier.
Next, the tabOnLoad
function calls the tabLoadChildren()
function. The tabLoadChildren()
function first establishes what DXImageTransform
filter effect has been selected to be used on child tabs when they appear. If no filter has been selected, then a random filter is applied from the DXImageTransformLibrary
:
if (DXImageTransformFilter == null)
{
DXImageTransform = DXImageTransformLibrary[Math.round
((Math.random()*DXImageTransformLibrary.length-1)+0)];
}
The tabLoadChildren()
function then performs its main task of seeking out child sets of sub tabs from the array of arrays via a nested for
-loop. Since every first element in each array defines a parent tab, the subsequent elements define the parent tab�s corresponding child tabs; thus, the nested for
-loop begins at the second position of each array and loops until the last element in each array is reached.
for (var i = 1; i < tabs.length; i++)
{
HTML += "<TD STYLE="+DXImageTransform+" ID=child"+i+">";
for (var j = 1; j < tabs[i].length; j++)
{
var tab = tabs[i][j].split("|");
var childID = i + "" + j;
HTML += "<INPUT TYPE='BUTTON' ID="+ childID +
" CLASS='tabOff' VALUE="+tab[0] +
" onClick='tabOnClick("+childID+", "+i+", "+j+")'> ";
}
HTML += "</TD>;
}
Every string element representing a child tab is given the same treatment of being split at every �|� pipe character to extract various parts of the string, creating a HTML button with the .tabOff
style as well as assigning them with a unique ID and an onClick
event handled by the tabOnClick
function. After the nested for
-loop has completed an iteration, that is, seeked out a child set of tabs, then that child set is allocated its own table division which is then appended to the HTML table created earlier. Every table division is also allocated a unique ID representing a child set of tabs.
After making calls to the tabLoadParents()
and tabLoadChildren()
functions to construct the respective parent and child tabs, the tabOnLoad()
function then completes the HTML table constructed earlier and binds it to the divTabStrip
<DIV>
container object:
divTabStrip.innerHTML = HTML;
The tabOnClick
function is called when any tab, either parent or child is clicked. The purpose of this function is to change the style of the clicked tab to the .tabOn
style and change all other tabs to the .tabOff
style as well as updating the <IFRAME>
content area. The function requires three parameters; ID
, parent
and child
. The first parameter represents the ID of which tab (HTML button) has been clicked � either parent or child so that the .tabOn
CSS class can be applied to it. The last two parameters pinpoint the exact location of the clicked tab in the nested arrays so that further information can be sought-out about that tab to update the contents of the <IFRAME>
:
var tab = tabs[parent][child].split("|");
divTabFrame.innerHTML = "<IFRAME SRC="+tab[1]+" CLASS='tabFrame'></IFRAME>";
If the tabOnClick
function is called by a tab with the last parameter child
set to 0
, it signifies that the caller is a parent tab which has been clicked and therefore instructs all child sets of sub tabs (table divisions) to disappear except the corresponding child set of sub tabs that belong to the clicked parent tab:
if (child == 0)
{
for (var i = 1; i < tabs.length; i++)
{
tabHide("child"+i);
}
tabShow("child"+ID);
}
The tabShow
and tabHide
functions respectively show and hide table divisions which house sets of child tabs. The functions are called with a parameter defining the ID of which table division to show or hide. A call to each of these functions apply the selected DXImageTransform
filter to the table division in question, using:
var e = document.getElementById(ID);
e.filters[0].Apply();
When a call is made to show a particular table division to show a set of child tabs, the table division is made visible playing the DXImageTransform
filter effect, using:
e.style.display = "block";
e.filters[0].Play();
Likewise, if a call is made to hide a particular table division to hide a set of child tabs, the table division is made invisible and the DXImageTransform
filter effect stopped:
e.style.display = "none";
e.filters[0].Stop();
Notes
- As a quick bug/logical error fix, an empty nested array is required to be declared before any other tab hierarchy arrays are defined:
var tabs = new Array
(
new Array(),
new Array("Google|http://www.google.com/|*",
"News|http://news.google.com/",
"Froogle|http://froogle.google.com/"),
new Array(�)
);
- Extended from DHTML Web Tab Control.
- Tested only with IE6.