Apache AutoIndexer with jQuery

Apache's mod_autoindex is really rather boring on the surface.  However I will show you there is quite a lot you can do with it given a little understanding of how it functions.  If you need a file listing this is an excellent means to accomplish that goal.  You can wrap the auto-generated output with simple HTML, PHP, Perl or any other file type Apache can process.

In our case, we aren't going to generate anything using PHP or SSI or any other server-side mechanisms.  We are going to create a custom header and footer which wraps the basic unordered list output format with CSS and jQuery calls.  We will create the .htaccess file and other supporting files at the root of a /images folder on our server; in my case this is a Joomla installation's uploaded images folder.  I just want a quick and dirty means for authors to browse images uploaded into certain folders of this system.

The purpose of this article is to show you how to integrate interesting features into the Apache AutoIndexer.  This is not meant to teach you really anything about jQuery.  I do hope you will read the excellent documentation and tutorials the jQuery authors and users have provided for that.

Examples

Lets just start with a couple of examples of this code in action.

Joomla Fruit Shop Sample Data

Joomla Parks Sample Data animals folder shows a nice variety of sizes.

.htaccess

The .htaccess file in your images folder will enable you to modify the configuration of the Apache autoindex module.  You will need to enable the Indexes option to turn on the autoindex module.  Then you will want to configure it with only the XHTML and SuppressHTMLPreamble options.  These tell it to output well formed XHTML and don't insert any of its own HTML before the content section.  Also, you will need to force the mime type on the "header" and "readme" files to ensure Apache knows they are HTML.  Then specify the basename (without the .html extension) of those two files. Also, we will prepend the filenames with a '.' to hide them from the autoindex module.

Your .htaccess file should look something like this:

Options +Indexes
IndexOptions XHTML SuppressHTMLPreamble
# Apache is drain bamaged slightly
<files ".readme.html">
   ForceType text/html
</files>
<files ".header.html">
   ForceType text/html
</files>
HeaderName /images/.header
ReadmeName /images/.readme

.header.html

Now, we are going to write our own HTML for everything leading up to the unordered list which Apache generates for us.  We need to include an empty title tag, a link to our stylesheet, jquery itself, our custom document.ready() handler and then, as the very last header item, we need to include our script which attaches the preview image overlay to each image on the page.  I'm also including a <h1> which will match the title text as well as a <div> for the content jQuery will be generating.  Most importantly, notice that I am wrapping the entire <ul> from apache in a <div> that our CSS will completely hide from display.  The <ul> will be solely used as a data provider for our jQuery script.

The jQuery script itself that I have written performs a number of tasks prior to the image popup code running.  When the document.ready() event fires the script populates the title and our <h1> with the path information so the user has some breadcrumbs.  Then loops through all of the list items in Apache's unordered file list.  It checks for supported image file extensions in the listing and labels them with a "type_image" class so the popup preview script can attach to just the images.  Other files get a generic file icon.  Directories get a folder icon.  Finally, we emit a new <div> element for each file into the content area <div>.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
<html xmlns="http://www.w3.org/1999/xhtml"> 
 <head> 
  <title></title> 
  <meta http-equiv="Content-type" content="text/html;charset=UTF-8" />
  <link rel="stylesheet" href="/images/.index.css" type="text/css" />
  <script type="text/javascript" src="http://jquery.com/src/jquery-latest.pack.js"></script>
  <script type="text/javascript">
  //<![CDATA[
  $().ready(function () {

        $("li a").each(function(n) {
                // set the title to the parent folder 
                if( $(this).attr("href").substr( 0, 1 ) == "/" ){
                        $("title").text( window.location.pathname );
                        $("h1#foldername").text( window.location.pathname );
                }
                
                // if it is an image then make a thumbnail, otherwise use a generic file icon
                switch( $(this).attr("href").substr( -4, 4 ).toLowerCase() ){
                        case ".jpg":
                        case "jpeg":
                        case ".png":
                        case ".gif":
                                icon = $(this).attr("href");
                                classname = "type_image";
                                labelreg = new RegExp( "_", "g" );
                                break;
                        default:
                                icon = "/icons/generic.png";
                                classname = "type_file";
                                labelreg = new RegExp( "_", "g" );
                                break;
                }
                // if its a directory override everything we just said.
                if( $(this).attr("href").substr( -1, 1 ) == "/" ){
                        icon = "/icons/folder.png";
                        classname = "type_folder";
                }

                $("div#contentarea").html( 
                        $("div#contentarea").html() + 
                        '<div class="file" id="file' + n + '">' + 
                        '<a class="' + classname + '" id="link' + n + '" href="' + $(this).attr("href") + '" title="' + $(this).attr("href") + '">' + 
                        '<img class="' + classname + '" src="' + icon + '" alt="' + $(this).attr("href") + '"/>' +
                        '</a><br/>' + 
                        '<span class="filename">' + $(this).attr("href").replace(labelreg, " ") + '</span>' + 
                        '</div>' 
                );
        });
        
  });
 //]]>
 </script>
 <script type="text/javascript" src="/images/.ipgb.js"></script>
 </head> 
 <body>
 <h1 id="foldername"></h1>
 <div id="contentarea">
 </div>
 <div id="sourcedata">

.readme.html

This very simply closes all of the HTML tags opened in the header.

  </div><!-- id=sourcedata -->
  </body>
</html>

.index.css

The stylesheet is a critical component in this.  First of all, it hides Apache's unordered listing of files.  Granted, we should be doing this in Javascript to allow for a graceful fallback in case scripting is blocked.  That is an exercise for you to implement.  Secondly, it creates boxes for each file to live inside.  These boxes are 144 pixels square with 16 pixels of padding around them, are centered and float to the left of each other so they dynamically rearrange when the browser window is resized.

div#sourcedata {
        visibility: hidden;
        display: none;
        height: 0px;
}
div.file {
        float:left;
        width: 144px;
        height: 144px;
        padding: 16px;
        text-align: center;
}
div.file img.type_image {
        width: 90%;
}
 
div.file img.type_folder {
        width: 40px;
        height: 44px;
}
 
div.file img.type_file {
        width: 40px;
        height: 44px;
}

Other Files

You'll need two other files .ipgb.js and .loading.gif.  I have utilized a slightly modified version of this script to build the actual jQuery image boxes.  You can easily substitute any other script you like.  You can download the entire jqAutoIndexer.zip code bundle created in this demo.

---