LightBase Core Concepts: Elements of a Page
Page Template
In LightBase, a page is built up using a page template. You can set rules for which page template is returned for a given page request based on any available variable, so different pages, sections, times of day, users permissions or any other elements can drive the selection of page template. A page template is a simple cfm file kept in a projects layouts/page/ directory. The page template can include any client side content (HTML, javascript, etc.), and requests to the Render component for rendering any dynamic elements within the page. It can theoretically contain any CFML markup, but best practice is to include absolutely NO CFML in the page template and eventually that may be enforced with a Regex validator. This allows for extremely clear separation of concerns and makes it easy for designers with a background in HTML but no programming experience to work with LightBase templates.
Content Areas
Every page template contains one call to Render.mainContentArea() to render the content for the main content area, and 0..n calls to Render.contentArea(ContentAreaName) to include the content for any additional dynamic content areas (sidebar, right bar, pods of dynamic content, etc.).
The main content area uses a pseudo-page controller to determine which object controller method to call and the additional content areas use custom controllers for absolute flexibility in determining what functionality to display based on any variables available. So whether you want to drive right hand sidebar content based on time of day, the page being viewed, whether the user is logged in or the department they work for, you can easily implement a completely custom and completely independent controller for each content area.
Screens
Every content area makes any appropriate model calls to change the model state and/or to obtain the information to return to the user. It then includes the appropriate screen template from the /layouts/screen directory. The screen is then responsible for rendering any model information provided by the controller for that content area and returning that HTML to the page template to be inserted at the appropriate place within the page template. Screens can contain static content (maybe a title saying “User Form” on a user form screen, or a checkout message on a checkout screen) and 0..n UI components for simplifying the rendering of certain types of content using common patterns . For example, render.list(ListName) or render.form(FormName).
UI Components
UI components take an Iterating Business Object and the RequestObject used throughout a page request and return the appropriate HTML to the calling template (components can be used by a screen template or directly within a page template if the component should always be displayed as part of that page template).
Each UI component is comprised of a cfc in the com.view.uicomponent directory which has methods for any display specific logic (e.g. building up paging links for a paged table) and which calls a component template which is a cfm file in the /layout/component directory. So, within the /layout/component/table_default.cfm script you’ll see calls like #Render.pagingLinks()# which will drop the paging links into that part of the template. Again there should ideally be no CFML in the component templates to keep a clean separation of concerns between layout templates and any scripting logic required to implement it (which is stored in the associated component). Probably the best way of thinking about this is the idea of code behind pages in .NET with the difference that a given UI component is not hard coded to a single component template, so you can create different lists using different list templates but the same component or you can subclass the list UI component but still use the default list layout template.
Snippets
Snippets solve the problem that often an end client wants to be able to vary an arbitrary chunk of text within the site. Maybe they want to be able to change the message at the bottom of the view cart page to promote a different benefit every day in the run up to Christmas, or maybe they want to be able to keep the contact us form fresh with a different call to action every day. Heck, maybe they want to put a few words in the topbar in the site template and change them daily just to let people know the site is being kept fresh. This is distinct from where they need the ability to manage an entire “page” full of content where we’d provide them with an article manager for that page. Snippets allow the template designer to add a #Render.snippet(SnippetName)# anywhere in any template (page, screen or component) and providing the snippet name exists, the content will be automatically inserted as part of the rendering process.
A Little too Anal?
This might seem like a fairly complicated approach to view rendering. All I can say is that it is "as simple as possible and not one bit simpler" – at least for my use case. I posted my requirements for a rendering solution and this is the simplest solution I can envision that meets them all. It is also surprisingly easy to work with as I’ve implemented all of these ideas in different ways in the past, but they become so much easier and more elegant when you take an OO rendering approach while still supporting the use of a templating language for most of the layout.
Most importantly, there is very little that can't be implemented using this approach and it allows you to solve common problems extremely quickly and to easily add to your library of common solutions to continually enhance the toolbox for building future sites in less time with less effort.
Any thoughts?!



I've been following your posts for some time, not posting but just enjoying reading your frequent and often thought provoking comments on web programming. I use my own framework which opperates in a remarkably similar way to yours, albeit a little different, but was very interested by your use of page templates. I call these layouts in my framework, but as yet I am unable to allocate these at runtime based on a set of rules. How do you perform this allocation and where do you store the criteria? I was contemplating (don't wince) using an XML defs file since the rest of my framework uses XML to define the conditions that cause the application to pick one layout (template) over another, but I was wandering how you solved this?
Nick
Interesting site and project you have there - would love to hear more about your framework as it continues to progress!
While I don't use XML much, it is actually a great solution to these kinds of problems. The great things about XML as a framework designer are (a) that you get some validation for free as you can compare to a schema, and (b) much more importantly, it forces you to develop a grammar for your metadata which is really what meta programming and application generation is all about.
I have different types of layouts each of which work in a different way: page, screen and component are the main three. When you describe a specific list (such as an attorney list), one of the optional pieces of metadata is the name of the layout to use. Screens fundamentally only have a single layout (excluding skinning and i18n which I layer on top of this), and any given area is told what screen to use by its controller for a given page request. Finally, for the page layout, I haven't played with where to put the rules for this as none of my current projects in development have that need (although previous ones dd), but I'm guessing somewhere in a composed object under the render object, and of course the properties for all of these are injected using my DI engine, so you'd put these in your ColdSpring or (in my case) LightWire) config file. As it so happens in my case, the config file is in turn generated by concrete metadata in the database to make the db the authoritative reference, and the concrete metadata is in turn generated by the abstract metadata which describes your higher level business requirements in an artifact agnostic manner. This is a little complex, but if you want to generate 1,000 custom web applications next year it's actually a cool approach. I'll blog about this some more!
Thanks again for the comment!