I've been really frustrated with the XUL template system for a while and have thought about writing a javascript object to handle templating through direct interface with the DOM. Today I read
XUL Templates are a Waste of Time. While Im not completely sure I agree with everything Jeremy Bowers says, reading his rant convinced me it was time to try out writing my own javascript template system. I broke with standards in this endeavor because one of my biggest complaints about the current template system is the time I spend translating to and from XML-RDF. I appreciate what RDF is trying to do in a lot of cases and I think that, overall RDF is a great idea. I hate xml-rdf though. This is especially true when I need to translate flat SQL selects into RDF just so I can display them in a flat list again. Toward this end I decided to use the simplest data structure to represent the data for my template system.
|
| 1 | var testTable = [['id', 'name'], |
| 2 | [ 1, 'Programmers' ], |
| 3 | [ 2, 'WebAdmin' ], |
| 4 | [ 3, 'Broadband']]; |
This data table gets turned into a data source (this entails creating an object the has columnNames and rows). Then I just call a function passing in a template ( '<menuitem label="{name}" value="{id}" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" />'), a data source and a control that I want to add the template nodes to. This is currently just a prrof of concept that I threw together to figure out the feasibility of this project. As a side note, for HTML template generation you can just user element.innerHTML += element.template.format(obj). Also, if the format is throwing you, it accepts an object(hashtable) and replaces keys inside of the '{', '}' with the value from the object passed in.
The places I see for improvement are:
- Not needing to specify the URI. I dont know if I can get around this one.
- I need to figure out a way to nest templates. Currently I haven't even thought about it yet.
- It would be nice to be able to specify a url to pull the data source from and have that data source refresh dynamically
|
| 1 | var JsTemplater = new (function(){ |
| 2 | |
| 3 | this.DataSource = function ( dataTable ){ |
| 4 | this.columnHeaders = dataTable[0]; |
| 5 | dataTable.remove(0); |
| 6 | this.rows = dataTable; |
| 7 | }; |
| 8 | |
| 9 | this.DataSource.__doc__ = 'Constructor for a Template Datasource'; |
| 10 | |
| 11 | this.attachTemplateToNode = function( template, datasource, element ){ |
| 12 | template = new String(template); |
| 13 | element.template = template; |
| 14 | element.datasource = datasource; |
| 15 | element.bind = function(){ |
| 16 | for( var row=0 ; row < element.datasource.rows.length ; row++ ){ |
| 17 | var obj = new Object(); |
| 18 | for( var col=0 ; col < element.datasource.columnHeaders.length ;col++){ |
| 19 | obj[element.datasource.columnHeaders[col]] = element.datasource.rows[row][col]; |
| 20 | |
| 21 | } |
| 22 | var str = element.template.format(obj); |
| 23 | var parser = new DOMParser(); |
| 24 | var resultDoc = parser.parseFromString(str, 'application/xml'); |
| 25 | if (resultDoc.documentElement.tagName == "parsererror") |
| 26 | throw 'there was an error parsing the following template\n\n'+template; |
| 27 | |
| 28 | element.appendChild(resultDoc.documentElement); |
| 29 | }; |
| 30 | }; |
| 31 | }; |
| 32 | })(); |