Outer Court

Basic
Goodies
Design
Tech
Email

Tech - MSIE5 - DOM - DHTML popup-folders

Here's how to create a popup-folder inside a webpage, similar to those you'd see on your Windows-desktop. This approach only works with Internet Explorer 5 as it uses DOM, the Document Object Model. This however is a W3C development and may become a standard used by more browsers over time.

Pseudo-folders

To create a popup-folder, we need a mix of JavaScript and CSS. For example to turn on and off a simple object like this:

<div id="mywindow" class="win">Content<div>

You'd write in the stylesheet to hide it:

#mywindow { visibility: hidden }

And in the script to dynamically turn it on (like when the user clicks on an icon):

mywindow.style.visibility="visible";

Imagine each of these objects with a certain style attached, like a different background-color then the one used on your page, and you already have windows. To make them instantly recognizable as such, you'd have to use the system colors.

We need more elements inside these windows, so we'll put them as more div's or span's inside the window-object. What we cover here will be the title-bar with resize and close buttons, the window content with the file and folder list, and the status bar with a file-size information. In the following sample, we have a folder "images" with a title-bar, the class "caption" (inside it an icon, an empty title waiting to be dynamically created from the id, a maximize and close button). The window-content links to another folder "flowers" and an image called "portrait.gif":

<div id="images" class="win">

  <div class="caption">
    <div class="captiontext">
      <span class="icon"></span>
      <span>&nbsp;</span>
    </div>
    <div class="captionbtn">
      <span class="maxbtn" title="Maximize"></span>
      <span class="xbtn" title="Close"></span>
    </div>
  </div>

  <div class="wincontent">
    <ul>
      <li class="folder">
        <span>flowers</span>
      </li>
      <li>
        <span>portrait</span>
        <span class="extension">.gif</span>
        <span class="kb">12</span>
      </li>
    </ul>
  </div>

  <div class="statusbar">&nbsp;</div>

</div>

It should look like this on a finished page (here with Windows default colors):

A grey window with a blue title-bar and the content as a white window inside, with a list of icons and text

What we need to get the final look and feel are the accompanying styles and events, since the HTML written so far contains just the information about the folder. Let's write the style for the window:

.win
{ position: absolute;
  width: 200px; height: 180px;
  border: 2px threedhighlight outset;
  background-color: threedface;
  font-family: "MS Sans Serif"; font-size: 8pt;
  padding: 2px;
  cursor: default;
  visibility: hidden;
}

It's positioned as absolute so it can be dragged around by clicking on the title-bar. The title-bar is also the element which changes the color when the window is hilited. The events of the window, which we assume to be opened by either clicking on a desktop-icon or choosing a folder within a folder, would be:

<div id="images" class="win" onMouseOver="hi(this)" onMouseOut="lo(this)">

"this" submits a reference to the object itself. Now we can make use of the intuitive approach of the DOM to hilite the window's status-bar. In the DOM, an element within another element is thought of as children/ parent relation-ship, two children on the same level are siblings. If we name the submitted "this" parameter "elm" we could now change the status-bar color to correspond to the windows "active"-status with this JavaScript:

function hi(elm)
{ elm.firstChild.style.color="captiontext";
  elm.firstChild.style.backgroundColor="activecaption";
}

Similar to this, we can now code the script/ define the style for all the other elements. We have a double-click element on the title-bar which changes the window-size as well as the maximize-button picture, we have the x-icon on the top right to close (actually, hide) the window, we have a window-content with a list of files and their various icons (list-style images), we have a status-bar dynamically showing a files KB value if you click on the element once. Let's take a look at the full HTML to define the "images" window, with all the events:

<div id="images" class="win" onMouseOver="hi(this)" onMouseOut="lo(this)">
  <div class="caption" onDblClick="maxMed(this.parentNode)"
      onMouseDown="grabEl(this.offsetParent)">
    <div class="captiontext">
      <span onDblClick="closeClick(this)" class="icon"></span><span>&nbsp;</span>
    </div>
    <div class="captionbtn">
      <span class="maxbtn" title="Maximize"
        onClick="maxMed(this.parentNode.parentNode.parentNode)"></span>
      <span class="xbtn" title="Close" onClick="xClick(this)"></span>
    </div>
  </div>
  <div class="wincontent">
    <ul>
      <li class="folder" onClick="mark(this)"
        onDblClick="newWin(this)"><span>flowers</span></li>
      <li onClick="mark(this)" onDblClick="openFile(this)"><span>portrait</span>
        <span class="extension">.gif</span><span class="kb">12</span></li>
    </ul>
  </div>
  <div class="statusbar">&nbsp;</div>
</div>

This would work on a page which links to the complete Desktop-like page Stylesheet and JavaScript, in an environment containing the folder with all necessary pictures.

Since we defined the window as invisible above, we need to somehow pop it up. You can do this by a normal link, or for example by this desktop-icon element:

<div class="startFolder" onDblClick="newWin('images')" title="Double-click to open">
<span>images</span>
</div>

The id "images" will now be used as a title for the folder and replace the &nbsp;. Now that the window is open, what happens if the user double-clicks on another folder? When a folder is double-clicked, another folder pops up with the name given. The name here is "flowers", so in order for this to work, there should be another window-definition just like this which has the id "flowers" and could contain more images. Since every window uses just one id, you can simply copy and paste the first complete definition and then change it. Since all the file and folder definitions submit their content by an object-reference, there is only little to change for each new list-entry.

Pseudo-programs

But what happens if the user double-clicks on a file? This depends on how far you want to take this approach. Maybe you want to have some sort of a system to easily browse many images. What you'd need would be an internal previewing program. The GIF and JPEG "pseudo-program" the script expects to be defined somewhere in the page is written like this:

<div id="preview" class="win" onMouseOver="hi(this)" onMouseOut="lo(this)">
  <div class="caption"
    onDblClick="maxMed(this.parentNode)" onMouseDown="grabEl(this.offsetParent)">
    <div class="captiontext">
      <span class="icon"></span>
      <span>View</span>
    </div>
    <div class="captionbtn">
      <span class="maxbtn" title="Maximize"
        onClick="maxMed(this.parentNode.parentNode.parentNode)"></span>
    </div>
  </div>
  <div class="wincontent">&nbsp;</div>
</div>

What we got here is just a special-case window, with some missing elements and some exceptions in the style and script used. It changes the background-picture to the picture-name clicked on by the user. If the user clicks on "images/portrait.gif", the "View" program looks up exactly this file, so there needs to be a real "images" folder with a real "portrait.gif". But we can also take elements which don't exist in any real folders, like explanatory texts. Such a text could be:

<div id="about" class="text">
All images in this folder were painted by me.
</div>

It would be represented as a file just like the images, only that it's extension would be ".txt" (the dot is there so you could turn on the extensions in an alternate folder-view). The openFile function would now start the appropriate program. For the text files, the script refers to a Notepad-like program which should also be in the page.

<div id="notepad" class="win" onMouseOver="hi(this)" onMouseOut="lo(this)">
  <div class="caption"
    onDblClick="maxMed(this.parentNode)" onMouseDown="grabEl(this.offsetParent)">
    <div class="captiontext">
      <span onDblClick="closeClick(this)" class="icon"></span>
      <span>Read</span>
    </div>
    <div class="captionbtn">
      <span class="maxbtn" title="Maximize"
        onClick="maxMed(this.parentNode.parentNode.parentNode)"></span>
      <span class="xbtn" title="Close" onClick="xClick(this)"></span>
    </div>
  </div>
  <div class="wincontent"><div>&nbsp;</div></div>
</div>

Again, pretty much the same HTML used for other windows, as the differences lie mostly in the script and style. For example, the View program cannot be closed, so it missed the x-button. Now when you click on the pseudo-text-file named "about", then the script starts the Read program and loads the text. What it actually does is making the "read"-object visible and copying the content of the "about" element into the blank "wincontent".
If the user clicks on a file-format that isn't handled with a pseudo-program you may want to spawn an external viewer by assigning the path to the document.location.href so the browser will treat it just like a normal link. For example in the case of a MIDI-music file or an AVI-video, the Windows Media Player might be started, at first glance behaving just like another window from your pseudo-desktop page.

If you have MSIE5, you can view the sample page that puts it all together with different folders, images, sounds and text.

 

To the demo page