« Previous | Next »

Web Content Management in Smalltalk

09 Apr 2011

This site is made up of static pages, managed by a living web content management system written using Pharo Smalltalk, imaginatively called SmallCMS1. Content is written in Markdown syntax, and transformed into HTML using Discount. Templates are written in Smalltalk a la Seaside, but using HttpView2's html generator.

There are presently two main templates in SmallCMS1, for "regular" HTML pages and blog posts respectively. The template for regular pages invokes Discount to "HTML-ize" a page's content, and renders said content into a full-fledged HTML page. The blog post template does the same, and additionally generates a list of (currently non-hyperlinked) tags and Disqus Javascript. SmallCMS1 also generates a static RSS feed file of the blog posts.

So far, for the small number of pages that make up this site, SmallCMS1 works well. Even with just three templates - the two mentioned above, plus the one that generates index.html - there has been a fair bit of refactoring of the templating code. Here's the current "driver" method:

renderTemplateFor: aFileNode on: html with: aBlock

html html: [
    self renderSiteHeadFor: aFileNode on: html.
    html body: [
        self renderPageHeaderOn: html.
        html div id: 'wrap'; with: [
            html div class: 'inner'; with: [
                html div id: 'content'; with: [
                    aBlock value: aFileNode value: html ]].
            html text: '<br class="clear" />' ].
        self renderFooterOn: html ]] 

Here's how the blog post template calls the above method:

renderBlogPost: aFileNode on: html

    self updateMenu: aFileNode.

    self renderTemplateFor: aFileNode 
        on: html 
        with: [ :aNode :aCanvas | self renderBlogPostBody: aNode on: aCanvas ] 

And the index.html template calls it thusly:

renderSiteIndexFor: aFileNode on: html to: aStream

    self renderTemplateFor: aFileNode 
        on: html 
        with: [ :aNode :aCanvas |
            self renderIndexBodyOn: aCanvas.
            self renderSideBarOn: aCanvas ].

    aStream nextPutAll: html render 

Now I wish to generate an iPhone-friendly version of this site and have obtained suitable HTML templates and CSS. For each content file, SmallCMS1 generates a corresponding HTML file. D'ingTSTTCPW, I decided to generate an "iPhone-optimized" version of each HTML file, prefixing "m_" to each file name.

I began to modify the Smalltalk-coded templates, by sprinkling "isMobile" code forks here and there, expecting to refactor the template code later. The code started to look messy quite quickly though.

So I tried another approach: For each generated HTML file, parse it to extract the content fragment, and render this content fragment through an iPhone-specific template to generate the corresponding "m_" HTML file.

How that is done is the topic for the next post.

Tags: content management