X Quick-Start

Installation

Download the X distribution file and unzip it into the folder of your choice. Be sure to select the "Use folder names" option when unzipping. After unzipping you will find a folder named Cross-Browser.com which has several sub-folders. In this root folder you will find a web page, index.html, which serves as the index for the distribution package.

Folder Structure

Under the root folder Cross-Browser.com are the following sub-folders.

/css/ Default styles and other general-purpose stylesheets.

/images/ Images used by the demos.

/talk/ General articles.

/templates/ Specific and general-purpose template files.

/toys/ Demos that do not use the X Library.

/x/ A few prebuilt library files: x_core.js and x_event.js.

/x/docs/ X Library documentation files.

/x/examples/ Examples and demos that demonstrate the use of X.

/x/lib/ This is the actual library. It contains all XML and Javascript source files for the X Library.

/x/menus/ More examples that demonstrate the use of X.

/x/xc/ Contains the source code and VC++ project files for the X Compiler. This folder also has the xc.exe executable file.

Library Files

There are very many .js files in the distribution package. This section summarizes their purposes.

Cross-Browser.com/x/ - Prebuilt Library Files

This folder contains a few general-purpose, prebuilt library files: x_core.js and x_event.js. They are provided for your convenience. In almost every application there will be X functions that you always need. These files contain some of the most commonly used X functions. These files do not constitute the X Library itself. The functions in these files are taken from the actual library folder /x/lib/.

The contents of the x_core.js and x_event.js files are as follows. Click a link to see that symbol in the X Viewer.

x_core.js xGetElementById, xGetElementsByTagName, xGetElementsByClassName, xMoveTo, xLeft, xTop, xPageX, xPageY, xScrollLeft, xScrollTop, xHasPoint, xResizeTo, xWidth, xHeight, xClientWidth, xClientHeight, xStyle, xOpacity, xGetComputedStyle, xCamelize, xDef, xStr, xNum, xLibrary.

x_event.js xAddEventListener, xRemoveEventListener, xEvent, xStopPropagation, xPreventDefault.

Cross-Browser.com/x/lib/ - X Library Files

This folder contains the actual library. It contains .xml and .js files. There is an XML file and a Javascript file for every symbol in the library. So, the X Library is not made up of a few files which each contain many functions and objects. All the functions and objects (symbols) in the X Library are each in individual files. This separation into individual files, along with the dependency information in the XML file, allows you to create a library file which only contains the X symbols your application uses. XC completely automates this task.

Read more about the structure of X. Use the X Viewer to browse the sources and documentation for all X Library symbols.

Tutorial: Collapsible/Expandable Sections

As an example, let's develop an unobtrusive page-enhancement using the X Library.

Enhance What?

First we need a web page to work with. You can't develop a page-enhancement without a page, LOL! When I am starting a new demo I usually start with a copy of this template: html4_strict_template.html. There are other template files in that same folder. We will start this project with the following HTML file. Its name will be "demo1.html". It has a very simple, CSS-controlled layout.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>X Quick-Start Demo</title>
<meta name='author' content='Mike Foster (Cross-Browser.com)'>
<meta name='description' content='This is the HTML for the tutorial in the X Quick-Start document.'>
<link rel='stylesheet' type='text/css' href='demo1.css'>
</head>
<body>
<div id="Page">
  <div id="Header">
    <h1>Cross-Browser.com</h1>
    <p>X Quick-Start Demo</p>
  </div>
  <div id="NavBar">
    <ul>
      <li><a href="http://cross-browser.com/">Home</a></li>
      <li><a href="http://cross-browser.com/x/docs/x_quickstart.php">X Quick-Start</a></li>
      <li><a href="http://cross-browser.com/x/lib/">X Viewer</a></li>
    </ul>
  </div>
  <div id="Main">
    <h2 class='collapsible'>H2 Heading</h2>
    <div>
      <h3 class='collapsible'>H3 Heading</h3>
      <div>
        <p>Lorem ipsum dolor sit amet...</p>
        <p>Nam ornare, felis non fauc...</p>
      </div>
      <h3 class='collapsible'>H3 Heading</h3>
      <div>
        <h4 class='collapsible'>H4 Heading</h4>
        <div>
          <p>Aenean tempor. Mauris to...</p>
          <p>Nulla feugiat hendrerit ...</p>
        </div>
        <h4 class='collapsible'>H4 Heading</h4>
        <div>
          <p>Nulla a lacus. Nulla fac...</p>
          <p>Suspendisse dapibus, mag...</p>
        </div>
      </div>
    </div>
  </div>
  <div id="Footer">
    <p>Footer</p>
  </div>
</div>
</body>
</html>
    

Design

Let's come up with a brief description of what we want our enhancement to do.

  • We want the script to place an icon to the left of heading elements. When the icon is clicked the section under the heading should collapse. When the icon is clicked again the section should expand.
  • We don't want this enhancement on all headings, just the ones we specify - and we will specify them by adding 'collapsible' to their class attribute.
  • The enhancement should be very easy to add to a web page. We don't want to have to modify Javascript every time we use this on a new page.

Implementation

After a browser completely loads a web page, as well as all CSS, Javascript and image files included by the page, the load event will then occur. This is when we will initialize our enhancement. We will use xAddEventListener to register a function which will be called when the load event occurs. Like all X functions, xAddEventListener is in the folder /x/lib/ and we must now add a SCRIPT element to the HTML file which will cause that function's code to be loaded when the HTML file loads.

We should naturally wonder if xAddEventListener uses some other functions from the X Library. Use the X Viewer to find out. View xAddEventListener and scroll down to the "Dependencies" section. We see that xAddEventListener depends on xGetElementById and if you follow that dependency link you will see that xGetElementById has no dependents. So we need to add another SCRIPT element to cause the xGetElementById code to be loaded when the HTML file loads.

Now we are ready to start writing the code for our enhancement - but where will we put this code? Let's put it in its own file and name it "demo1.js". So we need to add one more SCRIPT element to our HTML file to cause "demo1.js" to be loaded when the HTML file loads.

The following is the HEAD element from the "demo1.html" file, showing the three SCRIPT elements that have been added.

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>X Quick-Start Demo</title>
<meta name='author' content='Mike Foster (Cross-Browser.com)'>
<meta name='description' content='This is the HTML for the tutorial in the X Quick-Start document.'>
<link rel='stylesheet' type='text/css' href='demo1.css'>
<script type='text/javascript' src='../lib/xaddeventlistener.js'></script>
<script type='text/javascript' src='../lib/xgetelementbyid.js'></script>
<script type='text/javascript' src='demo1.js'></script>
</head>
    

In the file "demo1.js" let's register a function to be called when the load event occurs. Use the X Viewer to see descriptions of the arguments we must provide to xAddEventListener.

xAddEventListener(window, 'load', initializeCollapsible, false);

function initializeCollapsible()
{
  //
}
    

Looking back at our design requirements we see that we need to get a list of all elements that have "collapsible" in their className property. Looking in the DOM section of the X Viewer Index we find xGetElementsByClassName, and that's just what we need. But now we need to add another SCRIPT element to the HTML file but we first see if xGetElementsByClassName has any dependencies and we see that it has one: xGetElementsByTagName which has no dependents. So we add two more SCRIPT elements to the HTML file, as shown in the following.

<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>X Quick-Start Demo</title>
<meta name='author' content='Mike Foster (Cross-Browser.com)'>
<meta name='description' content='This is the HTML for the tutorial in the X Quick-Start document.'>
<link rel='stylesheet' type='text/css' href='demo1.css'>
<script type='text/javascript' src='../lib/xaddeventlistener.js'></script>
<script type='text/javascript' src='../lib/xgetelementbyid.js'></script>
<script type='text/javascript' src='../lib/xgetelementsbyclassname.js'></script>
<script type='text/javascript' src='../lib/xgetelementsbytagname.js'></script>
<script type='text/javascript' src='demo1.js'></script>
</head>
    

So, using xGetElementsByClassName, we will get an array of elements and then loop through the array, as shown in the following.

xAddEventListener(window, 'load', initializeCollapsible, false);

function initializeCollapsible()
{
  var i, headings = xGetElementsByClassName('collapsible');
  for (i = 0; i < headings.length; i++) {
    //
  }
}
    

Looking back at our design requirements we see that we need to create an "icon" element for each element in the array. So let's create a DIV for the icon element and define two CSS classes for it, one for the collapse icon and one for the expand icon. These CSS classes can set a background image and also set the icon element's size to be the same as the image.

But how are we going to position the icon to the left of the heading itself? We could do it the hard way or the easy way. I like easy!

Let's back up for a minute and talk about the CSS position property. The default value for this property is "static" and it means the element will be positioned according to the flow of HTML. This is how all HTML elements are normally rendered, but if the position property has any other value then the element is considered to be positioned. If the element's position property has the value "relative" then the element will be rendered exactly as if its position property had been "static" but now the left and top properties will offset the element from its default (static) position. If the element's position property has the value "absolute" then the element will be positioned with respect to its nearest positioned ancestor. It is no longer in the flow.

We will use this to our advantage. We will insert the icon element into the heading element. We will give the heading element position:relative and give the icon element position:absolute. Now the browser will position the heading in the flow and position the icon with respect to the heading and all we have to do is move it to the left (a negative value) by a few pixels, and we can easily do that in the CSS. So let's look at the CSS for this project in the following.

.collapsible {
  position:relative;
}
.CollapseIcon, .ExpandIcon {
  position:absolute;
  left:-16px;
  top:5px;
  width:9px;
  height:9px;
  cursor:pointer;
}
.CollapseIcon {
  background-image:url("../../images/minus9x9.gif");
}
.ExpandIcon {
  background-image:url("../../images/plus9x9.gif");
}
    

Now we have a firm grasp on how this thing is going to work and the remaining Javascript should just fall right into place. In the following we create the icon element and insert it into the heading element.

xAddEventListener(window, 'load', initializeCollapsible, false);

function initializeCollapsible()
{
  var i, icon, headings = xGetElementsByClassName('collapsible');
  for (i = 0; i < headings.length; i++) {
    icon = document.createElement('div');
    headings[i].appendChild(icon);
  }
}
    

We've completed most of our enhancement's initialization. Now from the design requirements we see that a click on the icon must collapse or expand the icon's corresponding section. We will define a "section" to be the first element following the heading. Looking at the HTML we see that a section is the next sibling of its heading. Go to the X Viewer and look in the DOM section and you will find a function named xNextSib. This is what we need to find a section element which follows a heading element. So we must add another SCRIPT element to the HTML file which causes the xNextSib code to get loaded.

An icon element must remember which section element it is associated with so that the section can be collapsed or expanded when the icon is clicked. We find the section element with xNextSib and then we assign it to a custom property on the icon element. We will name the custom property collapsibleSection, as follows.

xAddEventListener(window, 'load', initializeCollapsible, false);

function initializeCollapsible()
{
  var i, icon, headings = xGetElementsByClassName('collapsible');
  for (i = 0; i < headings.length; i++) {
    icon = document.createElement('div');
    icon.collapsibleSection = xNextSib(headings[i]);
    headings[i].appendChild(icon);
  }
}
    

Now we need to listen for a click event on an icon element. We will use the DOM0 instead of the DOM2 event interface. The DOM2 event interface (addEventListener) has the advantage of allowing more than one listener for the same event on the same element, but that is not an issue here because our code creates the icon elements. The DOM0 event interface has an advantage which we will see shortly.

xAddEventListener(window, 'load', initializeCollapsible, false);

function initializeCollapsible()
{
  var i, icon, headings = xGetElementsByClassName('collapsible');
  for (i = 0; i < headings.length; i++) {
    icon = document.createElement('div');
    icon.collapsibleSection = xNextSib(headings[i]);
    icon.onclick = iconOnClick;
    headings[i].appendChild(icon);
  }
}

function iconOnClick()
{
  //
}
    

So now the function iconOnClick will be called whenever an icon element is clicked. We will now see the advantage to using the DOM0 event interface here. In iconOnClick our code can refer to the keyword this which will reference the specific icon element that was clicked!

The listener's task is to either collapse or expand its associated section element. To accomplish collapsing and expanding we will simply set the section element's display property to "none" or "block". We will first look at the value of display to determine if we need to expand or collapse the section. We know which section to collapse or expand because, in the initialization loop, we saved a reference to it in the icon element's collapsibleSection property.

function iconOnClick()
{
  var section = this.collapsibleSection;
  if (section.style.display != 'block') {
    section.style.display = 'block';
  }
  else {
    section.style.display = 'none';
  }
}
    

If we just collapsed the section then we want to change the icon's class to "ExpandIcon". If we just expanded the section then we want to change the icon's class to "CollapseIcon". Also, it would be a nice touch to change the icon's title property to correspond to its class, so the user would get an appropriate tooltip when the mouse is over the icon.

function iconOnClick()
{
  var section = this.collapsibleSection;
  if (section.style.display != 'block') {
    section.style.display = 'block';
    this.className = 'CollapseIcon';
    this.title = 'Click to collapse';
  }
  else {
    section.style.display = 'none';
    this.className = 'ExpandIcon';
    this.title = 'Click to expand';
  }
}
    

It looks like we are finished - but we are not. Look closely at the initialization function as well as the CSS. Did I forget something?

What image will be initially displayed for the icons? What CSS class do the icons have initially? What is the initial value of an icon's title property? There is none! When the icons are first created (when the page first loads) they will have no background image and no value for the title property.

We could just add some code to the initialization loop that sets an icon's inital CSS class and title property... but notice that our code in the iconOnClick function does exactly that! So the initialization function can just call the icon's iconOnClick function to initialize its CSS class and title property.

function initializeCollapsible()
{
  var i, icon, headings = xGetElementsByClassName('collapsible');
  for (i = 0; i < headings.length; i++) {
    icon = document.createElement('div');
    icon.collapsibleSection = xNextSib(headings[i]);
    icon.onclick = iconOnClick;
    icon.onclick();
    headings[i].appendChild(icon);
  }
}
    

Look at the following, which is the second line in the iconOnClick function.

  if (section.style.display != 'block') {
    

Did I make a mistake here? What will be the value of a section element's initial display property? It will be an empty string! But obviously the section gets rendered, so its real display property must actually have the value "block" - and it does. However, the properties of element.style correspond to the HTML element's inline STYLE attribute - NOT to any styles applied by its id or class attributes. Therefore the value of a section element's initial display property will be an empty string. Now that if statement should make more sense.

This if statement is important although it appears to be trivial. If I were not also using iconOnClick to initialize the icon then I would have tested for != 'none' instead of testing for != 'block' and swapped the code blocks following the if statement.

We could stop here, but let's add one more feature. When the mouse is over an icon we can change the background of its section to give a visual indication of what will get collapsed if they click the icon.

The following is our entire "demo1.js" file.

xAddEventListener(window, 'load', initializeCollapsible, false);

function initializeCollapsible()
{
  var i, icon, headings = xGetElementsByClassName('collapsible');
  for (i = 0; i < headings.length; i++) {
    icon = document.createElement('div');
    icon.collapsibleSection = xNextSib(headings[i]);
    icon.onclick = iconOnClick;
    icon.onclick();
    icon.onmouseover = iconOnMouseover;
    icon.onmouseout = iconOnMouseout;
    headings[i].appendChild(icon);
  }
}

function iconOnClick()
{
  var section = this.collapsibleSection;
  if (section.style.display != 'block') {
    section.style.display = 'block';
    this.className = 'CollapseIcon';
    this.title = 'Click to collapse';
  }
  else {
    section.style.display = 'none';
    this.className = 'ExpandIcon';
    this.title = 'Click to expand';
  }
}

function iconOnMouseover()
{
  this.collapsibleSection.style.backgroundColor = '#cccccc';
}

function iconOnMouseout()
{
  this.collapsibleSection.style.backgroundColor = 'transparent';
}
    

Conclusion

There is more we could do to this demo. You know that saying... software is never done ;-).

There is a more efficient way to utilize xGetElementsByClassName with its function call-back parameter.

We could put all the Javascript in one file instead of it being in separate files (XC automates this process).

This is a fun project and I'm sure you can think of more features to add.

You can try out the enhancement and download the files here.

Did you like this tutorial? Did you hate it? Did you add some more cool features to the demo? Come to the forums and tell us about it.

Related Documents

X Index - X Library Index.

XC Reference - X Library Compiler Reference.

X Structure - X Library Structure.

About Cross-Browser.com

Cross-Browser.com is the home of X - a cross-browser Javascript library, and many demos, applications, articles and documentation.

License

By your use of X and/or CBE and/or any Javascript from this site you consent to the GNU LGPL - please read it. If you have any questions about the license, read the FAQ and/or come to the forums.

Developer Support

Browser Support

The X core is designed for Opera 5+ (*), Mozilla, Firefox, Safari, WebKit, Internet Explorer 4+, Konqueror, Netscape 4.75+ (*) and browsers with similar object models. Object-detection instead of browser-detection is used exclusively. Currently, I'm testing with the following browsers. X has been tested by others on a wide variety of platforms.

WinXP: Opera 9.20, Firefox 2.0.0.3, Apollo 1.0.Alpha1 and Internet Explorer 4, 5 and 7.

Win2K: Opera 7.51, FireFox 1.5.0.7 and Internet Explorer 6.