Making Websites Without Serverside Scripting

Here is an interesting task: make a semi decent website, which is pretty, and maintainable without using any server side scripting or server side includes. In other words, we want a website that has a header, footer, a navigation sidebar and layout modeled via css without doing any copying and pasting. The above mentioned layout elements should only appear in a single place for ease of maintenance. Why would someone need something like that?

Well, the Novel Netdrive service my school uses has weird issues with php. At one point it was allowing me to use it, then it stopped, then it was working again. Needless to say, I couldn’t rely on it. What I needed was a set of fairly static pages where I could post some resources and tools for my students.

Naturally I wanted the site to look presentable and I hated the idea of copying and pasting the header, footer and the navigation sidebar all over the place. So I opted for some clever client side scripting. I started with something like this:

<!DOCTYPE HTML PUBLIC 
  "-//W3C//DTD HTML 4.01 Transitional//EN"
  "http://www.w3.org/TR/html4/loose.dtd">
 
<html>
   <head>
      <title>Luke's CMPT 109 Page</title>
      <link rel="stylesheet" href="layout.css" type="text/css" media="screen" />
      <link rel="shortcut icon" href="favicon.ico">
      <script type="text/javascript" src="jquery.min.js"></script>
      <script type="text/javascript" src="funcm.js"></script>
   </head>
   <body>
      <div id="header">
         <!-- header stuff -->
      </div>
      <div id="sidebar">
         <h2>NAVIGATION</h2>
         <ol>
            <li><a href="/">Home Page</a></li>
            <li><a href="foo.html" class="aj">Foo</a></li>
            <li><a href="bar.html" class="aj">Bar</a></li>
            <li><a href="baz.html" class="aj">Baz</a></li>
         </ol>
      </div>
      <div id="content">
         <!-- Content goes here -->
      </div>
      <div id="footer">
         <!-- footer stuff -->
      </div>
   </body>
</html>

Note that the above page is completely static, and the links are fully functional. This is intended, because I wanted it to degrade gracefully. If someone visited the site using one of the many text based browsers they would be able to navigate it without any problems. Not that my students would ever use one of these, but I don’t like the idea of depending on Javascript for crucial navigation without providing this sort of fall back.

What I could do next was to add a click event to every links with the class of “aj” and use an asynchronous call to load an external HTML page into the “content” div. Unfortunately, that would mean that all the pages would have the same URL. Any attempt to link to pages foo, bar or baz would fail miserably. Furthermore, the back and forward button functionality would be broken.

Naturally, loading pages into “content” div is what I really wanted in the end, but I also needed a unique URL for each of them and a working back button. That meant I needed to approach the problem a bit differently.

I decided to rewrite all the relevant links at runtime so that they would point back at our index.html page:

$("a.aj").each( function() {
    h = $(this).attr("href");
    $(this).attr("href", "/?p=" + h.substr(0, h.indexOf(".")));
});

I used JQuery because it makes stuff like modifying certain selection of links incredibly easy. If the page loaded and Javascript was enabled the links would get quietly changed to this:

<a href="/?p=foo" class="aj">Foo</a>
<a href="/?p=bar" class="aj">Bar</a>
<a href="/?p=baz" class="aj">Baz</a>

Note that I could have used foo.html in the query string but I didn’t want to. The URL’s were ugly as it was, so I decided to keep them short and as simple as possible. So the .html suffix was dropped for the sake of clarity. Next step was evaluating the query string and actually loading the pages:

 $(document).ready(function() {
   page = getQueryVariable("p");
   if(page)
      $("#content").load(page + ".html");
});

I skipped the link rewriting code in the above for clarity but it should theoretically be somewhere in that anonymous function block. The function getQueryVariable can be defined as follows:

function getQueryVariable(variable) 
{
   vars = window.location.search.substring(1).split("&");
   for (i in vars) 
   {
      pair = vars[i].split("=");
      if (pair[0] == variable) 
         return pair[1];
   }
   return false;
}

It should be self explanatory. Grab the query string, split it on the & character, iterate through the list and return the value of matching attribute, or false if none is found.

With that framework in place, I created foo.html, bar.html and baz.html files as plain HTML documents without a defined stylesheet. Loading it into the “content” div in index.html would force the styles defined on that page to be used on the imported content as well. Visiting the pages directly might be a bit jarring because they would be very plain but it shouldn’t be a huge issue.

Anyone visiting the page with Javascript enabled browser would see the “fixed” links that would cause the page to reload and import the desired content from the external file. Browsing without Javascript would yield links leading directly to the pages.

The only time the site wouldn’t work properly was if someone followed a link or a bookmark which in the /?p= format but with Javascript disabled. They would end up on the homepage without any indication of what happened. That sort of behavior could be a bit annoying but I’m not sure how to fix it at this point.

Other than that, the few lines of Javascript should save you tons of copy-pasting, and shave many hours from future maintenance. There is of course possibility that this method could be exploited and. I tested few obvious things and I couldn’t get it to load any remote web pages in any way. It doesn’t mean it is not possible so be aware that someone could potentially cause your page load external content with a GET request formated just the right way. It’s nowhere near as bad as that silly ny.com page.

[tags]javascript, jquery, html, server side scripting, web design[/tags]

This entry was posted in programming and tagged , . Bookmark the permalink.



4 Responses to Making Websites Without Serverside Scripting

  1. Tino GERMANY Mozilla Firefox Ubuntu Linux says:

    I have been in a similar situation, where I did not dare to rely on a working php install when setting up a website. Since I am not a big fan of javascript my solution was quite different.

    I created a number of m4 macros and had html/m4 source files that relied on the macros for navigation menus, header, footer etc. People who used the system needed to remember to run ‘make’ every time they changed the source files to generate the static html files.

    Some people would probably say its better to go all XML and xsl transforms for something like this. Then one can generate nice print-formatted content from the same source files etc. But that just seemed a bit too overpowered for the simple things I was doing.

    Reply  |  Quote
  2. Gamberoni UNITED KINGDOM Mozilla Firefox Windows says:

    Have you looked at what Steve Gibson has done with just css? Try http://www.grc.com/menudemo.htm — I think this is close to what you were trying to achieve?

    Reply  |  Quote
  3. Luke Maciak UNITED STATES Mozilla Firefox Ubuntu Linux Terminalist says:

    @Tino – thanks for bringing up m4 Tino! I never used it, but it does seem like a more “accessible” way of doing this stuff. Then again, maintenance seems like a pain in the ass due to the fact you need to “re-compile” the thing. It’s an interesting alternative.

    @Gamberoni – well, I wasn’t really interested in menus. I wanted to have a page template with a header (with all the css, and javascript links), footer and a sidebar that would be in one place where they could be edited easily. In most server side languages you can do something like this when you create a new page:

    <?php include "header.php"; ?>
    <?php include "sidebar.php";?>
    <!-- your content goes here
    <?php include "footer.php" ?>

    I wanted something like that – to be able to import these static documents all over the place. If you don’t do this the maintenance becomes a nightmare since you have to copy and paste your stuff all over. Then when something changes you have to go back and edit every single file.

    Reply  |  Quote
  4. Pingback: Terminally Incoherent » Blog Archive » Your Homepage on Google AppEngine UNITED STATES WordPress

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>