|   | |||||
Automated Website MaintenanceIt's all about separating style from content. Crucial, that is. If you do that, then you can change the look of the whole site by changing one file, and you can edit your content with a minimum of presentation-related crud obscuring the view. You can also do arguably useful stuff like skinnable websites. Of course, it's obvious from that blue border that style's not my thing, and there's not much content here either. I could say meta at this point, but honestly I feel less like a computer scientist every day and I can't be bothered. This page will describe how I've tried to set up this site to be maintainable, and maybe some of the other stuff it uses for message boards and whatever. Basically, the idea is to set things up so that the computer does all the donkey work (what computers are for), and the author can focus on spouting, ranting, and ego expansion (what websites are for). The computer can do donkey-work at any of three stages: static processing, dynamic processing, and client-side processing. Client side stuff (javascript) is for nifty effects like pointer trails, and less nifty effects such as scrolling status bar messages. It's got not a lot to do with maintainable websites, so I won't talk about that. Other people have similar pages about similar things, among them Bob Hepple, Matt J. Gumbley, and Ralf S. Engelschall. If you want to know more about how I've done this, and you have a matrix account,
you can always poke around in Static procesingStatic processing (for which I use m4) happens once, when you build your website. For example, all my hrefs have mouseover handlers to put some explanatory text in the status bar (at the bottom of the window). It would be tiresome to have to put the javascript in every time I'm typing a link; the code for a link like Matrix might look like: <a href="http://matrix.netsoc.tcd.ie" onMouseOver="window.status='Matrix, Netsoc\'s members\' server'; return true;" onMouseOut="window.status=''; return true;"> Matrix</a> So instead, I use an m4 macro. When I edit my webpages,
I insert a link with Here's another example: sometimes, a footnote seems like a worthwhile
thing to include, perhaps explaining what a bananafish is¹ hd_note([[]],[[What's a bananafish?]], [[Why, I've known some bananafish to swim into a banana hole and eat as many as seventy-eight bananas. hd_link([[http://www.geocities.com/Vienna/3597/A_Perfect_Day_For_Bananafish.html]], [[More about bananafish]],[[Is this abridged?]])]]) Such definition bits would make a great tool for educational websites; you could develop
a stylesheet that had an unobtrusive link class, and automatically add mouseover definitions for every
word in a glossary, so when someone is reading something and they've forgotten what MCMC When doing a didactic bit like this, you don't want to have to go escaping your html every time you want to quote a macro; that's donkey work. So I have a macro to escape HTML as well. Other useful ones define a variable containing the contents of a file, and one to include an M4 file with out too much mangling (in fairness, m4 is not really meant for processing m4 files and confusion can easily result if you try to use it for same). Here's an up-to-date view of the m4 file, globals.inc, that defines all those macros (included automatically using the hd_includeM4 macro). It may be worth bearing in mind that m4 is harder to read than it is to write. divert(-1) changequote([[,]]) define([[_NoteNumber]], 0) define([[hd_link]], [[define([[_escaped]],patsubst([[[[$3]]]],[[']],[[\\']]))define([[_escaped_url]],patsubst([[[[$1]]]],[[']],[[\\']])) <a href="$1" onMouseOver="window.status='_escaped (_escaped_url)'; return true;" onMouseOut="window.status=''; return true;">$2</a>]]) define([[hd_note]], [[define([[_escaped]],patsubst([[[[$2]]]],[[']],[[\\']]))<a href="javascript:show('note[[]]_NoteNumber')" onMouseOver="window.status='_escaped'; return true;" onMouseOut="window.status=''; return true;">ifelse($1,[[]],[[¹]],$1)</a> <span id="note[[]]_NoteNumber" class="myStyle"><table width=400 bgcolor="#49DAEF"><tr><td>$3</td></tr><tr><td align="center"> <a href="javascript:hide('note[[]]_NoteNumber')">close</a> </td></tr></table></span>[[]]define([[_NoteNumber]],incr(_NoteNumber))]]) define([[hd_escapeHTML]], [[ patsubst(patsubst(patsubst([[[[[[[[$1]]]]]]]],[[&]],[[&]]), [[<]],[[<]]), [[>]],[[>]]) ]]) define([[hd_defineFile]], [[divert(-1) dnl **** Not thread safe! don't use parallel make! *** changequote(`,') syscmd(`echo "define($1, [[[[" > tmpHDm4_12765') syscmd(`cat $2 >> tmpHDm4_12765') syscmd(`echo "]]]])" >> tmpHDm4_12765') syscmd(`perl -pi -e "s#\\\$'`'`\@#\]\]\\$\[\[\]\]\[\[\@#g" tmpHDm4_12765') changequote([[,]]) include([[tmpHDm4_12765]]) syscmd([[rm tmpHDm4_12765]]) divert]]) define([[hd_includeM4]], [[hd_defineFile([[_tmptmptmp]], $1) hd_escapeHTML(_tmptmptmp($[[]]1,$[[]]2,$[[]]3,$[[]]4,$[[]]5, $[[]]6, $[[]]7)) undefine([[_tmptmptmp]])]]) divert The bottom of every page on this site has a comments area, powered by php. The php code that generates the message board is the same for every page. Similarly, the html that generates that blue border is the same for every page. So all the pages are generated from the same template. The template when the website was last made looked like this: include(`globals.inc') <html> <head> <title>hd_title</title> <link rel="stylesheet" href="style.css" type="text/css"> <SCRIPT TYPE="text/javascript" LANGUAGE="JavaScript"><!-- function show(object) { if (document.layers && document.layers[object] != null) { if (document.layers[object].left + document.layers[object].width > window.InnerWidth) document.layers[object].left -= window.InnerWidth - (document.layers[object].left + document.layers[object].width) document.layers[object].visibility = 'visible'; } else if (document.all) { myObj=document.all[object] if (myObj.offsetLeft + myObj.offsetWidth > document.body.clientWidth-10) myObj.style.posLeft = myObj.offsetLeft - (-document.body.clientWidth +10 + (myObj.offsetLeft + myObj.offsetWidth)) document.all[object].style.visibility = 'visible'; } } function hide(object) { if (document.layers && document.layers[object] != null) document.layers[object].visibility = 'hidden'; else if (document.all) document.all[object].style.visibility = 'hidden'; } //--></SCRIPT> <STYLE TYPE="text/css"><!-- .myStyle { position: absolute; visibility: hidden; } //--></STYLE> </head> <body marginwidth=0 marginheight=0 leftmargin=0 topmargin=0 bgcolor="#ffffff"> include([[header.inc]]) include(hd_content) include([[footer.inc]]) </body> </html> The template's pretty straightforward. First the file The time is perhaps ripe for a big picture overview. Here's how the whole thing works: I write
a webpage with a pages := $(patsubst %.webm4,%.php,$(wildcard *.webm4)) incs := template $(wildcard *.inc) website : $(pages) cp *.php *.css /home/hdenman/public_html/ %.php : %.webm4 $(incs) m4 -Dhd_content=$< -Dhd_title="$(shell head -1 $< | perl -ne 'm/\s*\<\s*[hH].+?\>(.+?)\</; print "$$1\n";')" < template > $@ Here's how it works. First, the line
File that end in .inc are files designed to be included in other files (another extension chosen arbitrarily).
The line The next bit is a makefile rule, that tells the make program how to make the thing called 'website'.
The syntax The final part of the makefile is another rule. It says that any file ending in .php depends on a file with
the same name with a .webm4 extension, and on all the include files. For example, The whole point of make programs is to automatically detect when a prerequisite has been changed and to generate
any dependent targets. So when I run Dynamic processingDynamic processing is what languages like php and asp do. The difference between dynamic and static processing is that while in static processing, the macro expansions etc. are done once, in dynamic processing the server runs through expansions etc. every time a page is requested. So while you can do all the stuff described above using php or asp, and many people, especially non-unix people, do, I think it's a waste of processing power to do it for every request. What php and the like are really good for is pulling stuff out of a database and putting it on a webpage. They can also take stuff from a form on a webpage and put it into a database. By these powers combined, you can do bulletin boards, blogs, content-management systems, webwide collaboration, and all sorts of good interactive stuff. Anyway, there's so much stuff out there on dynamic processing. A good place to start is Jas' php page. Webmonkey heaven is at IRT. Security considerationsDescribed nicely here and here. If you like security, you might find this more interesting than poring over bugtraq archives. Comments welcome... |   |