========================== HTML Templating Mechanisms ========================== :Version: $Revision: 1.4 $ Current Situation and Issues ============================ Syntax ------ Roundup currently uses an element-based HTML-tag-alike templating syntax:: The templates were initially parsed using recursive regular expression parsing, and since no template tag could be encapsulate itself, the parser worked just fine. Then we got the ```` tag, which could have other ```` tags inside. This forced us to move towards a more complete parser, using the standard python sgmllib/htmllib parser. The downside of this switch is that constructs of the form:: "> don't parse as we'd hope. It would be almost impossible to modify the sgmllib parser to parse the above "correctly", so a wholly new parser would be required. That is a large undertaking, and doesn't address another couple of issues that have arisen: 1. the template syntax is not well-formed, and therefore is a pain to parse and doesn't play well with other tools, and 2. user requirements generally have to be anticipated and accounted for in templating functions (like ``plain()`` and ``checklist()`` above), and we are therefore artificially restrictive. Arguments for switching templating systems: *Pros* - more flexibility in templating control and content - we can be well-formed *Cons* - installed user base (though they'd have to edit their templates with the next release anyway) - current templating system is pretty trivial, and a more flexible system is likely to be more complex Templates --------- We should also take this opportunity to open up the flexibility of the templates through: 1. allowing the instance to define a "page" template, which holds the overall page structure, including header and footer Possible approaches =================== Zope's PageTemplates -------------------- Using Zope's PageTemplates seems to be the best approach of the lot. In my opinion, it's the peak of HTML templating technology at present. With appropriate infrastructure, the above two examples would read: status checklist ... which doesn't look that much more complicated... honest... Other fun can be had when you start playing with stuff like:
mailto link subject received date
Implementation ~~~~~~~~~~~~~~ I'm envisaging an infrastructure layer where each template has the following variables defined: *class* the current class of node being displayed *item* the current node from the database, if we're viewing a specific node (*classname*) the current node is also available under its classname, so a *user* node would also be available under the name *user*. *form* the current CGI form information *instance* the current instance *db* the current open database *config* the current instance config *util* utility methods Then accesses through an *item*:: class HTMLItem: def __getattr__(self, attr): ''' return an HTMLItem instance ''' def history(self, ...) def classhelp(self, ...) def remove(self, ...) String, Number, Date, Interval HTMLProperty a wrapper object which may be stringified for the current plain() behaviour and has methods emulating all the current display functions, so ``item/name/plain`` would emulate the current ``call="plain()``". Also, ``python:item.name.plain(name=value)`` would work just fine:: class HTMLProperty: def __init__(self, instance, db, ...) def __str__(self): return self.plain() class StringHTMLProperty(HTLProperty): def plain(self, ...) def field(self, ...) def stext(self, ...) def multiline(self, ...) def email(self, ...) class NumberHTMLProperty(HTMLProperty): def plain(self, ...) def field(self, ...) class BooleanHTMLProperty(HTMLProperty): def plain(self, ...) def field(self, ...) class DateHTMLProperty(HTMLProperty): def plain(self, ...) def field(self, ...) def reldate(self, ...) class IntervalHTMLProperty(HTMLProperty): def plain(self, ...) def field(self, ...) Link HTMLProperty the wrapper object would include the above as well as being able to access the class information. Stringifying the object itself would result in the value from the item being displayed. Accessing attributes of this object would result in the appropriate entry from the class being queried for the property accessed (so item/assignedto/name would look up the user entry identified by the assignedto property on item, and then the name property of that user):: class LinkHTMLProperty(HTMLProperty): ''' Be a HTMLItem too ''' def __getattr__(self, attr): ''' return a new HTMLProperty ''' def download(self, ...) def checklist(self, ...) Multilink HTMLProperty the wrapper would also be iterable, returning a wrapper object like the Link case for each entry in the multilink:: class MultilinkHTMLProperty(HTMLProperty): def __len__(self): ''' length of the multilink ''' def __getitem(self, num): ''' return a new HTMLItem ''' def checklist(self, ...) def list(self, ...) *util* the util object will handle:: class Util: def __init__(self, ...) def filterspec(self, ...) def note(self, ...) def submit(self, ...) Action ====== 1. Investigate how PageTemplates would be integrated into Roundup: - we could go for a fully-divorced-from-Zope approach, which would involve bundling PageTemplates/TAL/ZTUtils in with Roundup, with all the Zope-specific bits removed. - we could try to coexist with a Zope installation, but there the problem would be that Zope includes its own copy of PageTemplates/TAL/ZTUtils and we'd be installing a version in site-packages, which would be bad. The latter may allow nicer integration with Zope itself, giving Zope Roundup users access to acquired information in their templates. 2. Implement the Roundup infrastructure detailed in the `implementation`_ above.