Created
May 19, 2011 07:04
-
-
Save insin/980325 to your computer and use it in GitHub Desktop.
Exploratory WIP against a speculative API for DOMBuilder Templates
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| function Variable(name) { | |
| this.name = name; | |
| } | |
| function VariableNotFoundError(name, context) { | |
| this.name = name; | |
| this.context = context; | |
| } | |
| function Context() { | |
| this.stack = [{}]; | |
| this.top = this.stack[0]; | |
| } | |
| Context.prototype.push = function() { | |
| this.stack.push({}); | |
| this.top = this.stack[this.stack.length - 1]; | |
| } | |
| Context.prototype.pop = function() { | |
| if (this.stack.length > 1) { | |
| this.stack.pop(); | |
| } | |
| this.top = this.stack[this.stack.length - 1]; | |
| } | |
| Context.prototype.set = function(name, value) { | |
| this.top[name] = value; | |
| } | |
| Context.prototype.delete = function(name) { | |
| delete this.top[name]; | |
| } | |
| Context.prototype.zip = function(names, values) { | |
| var top = this.stack[this.stack.length - 1]; | |
| for (var i = 0, l = Math.min(names.length, values.length); i < l; i++) { | |
| top[names[i]] = values[i]; | |
| } | |
| } | |
| Context.prototype.resolve = function(variable) { | |
| var name = (variable instanceof Variable ? variable.name : ""+variable); | |
| if (this.top.hasOwnProperty(name)) { | |
| return this.top[name]; | |
| } | |
| for (var i = this.stack.length - 2; i > 0; i--) { | |
| if (his.stack[i].hasOwnProperty(name)) { | |
| return this.stack[i][name]; | |
| } | |
| } | |
| return null; | |
| } | |
| Context.prototype.resolveRequired = function(variable) { | |
| var result = this.resolve(variable); | |
| if (result === null) { | |
| throw new VariableNotFoundError(variable, this); | |
| } | |
| return result; | |
| } | |
| function Template(props, contents) { | |
| this.name = props.name; | |
| this.extends = props.extends; | |
| this.contents = contents; | |
| } | |
| function Block(name, contents) { | |
| this.name = name; | |
| this.contents = contents; | |
| } | |
| function TemplateNode() { } | |
| function TemplateTextNode() { } | |
| function TemplateHTMLNode() { } | |
| function ForNode(props, contents) { | |
| for (var prop in props) { | |
| this.loopVars = prop.split(','); | |
| this.listVar = props[prop]; | |
| break; | |
| } | |
| this.contents = contents; | |
| } | |
| ForNode.prototype.render = function(context) { | |
| var list = context.resolveRequired(this.listVar), l = list.length. item; | |
| var forloop = { | |
| counter: 1, | |
| counter0: 0, | |
| revcounter: l, | |
| revcounter0: l - 1, | |
| first: true, | |
| last: l === 1, | |
| parentloop: context.resolve('forloop') | |
| }; | |
| context.push(); | |
| context.set('forloop', forloop); | |
| for (var i = 0; i < l; i++) { | |
| item = list[i]; | |
| // Set current item(s) in context variable(s) | |
| if (this.loopVars.length === 1) { | |
| context.set(this.loopVars[0], item); | |
| } else { | |
| context.zip(this.loopVars, item); | |
| } | |
| // Update loop status variables | |
| if (i > 0) { | |
| forloop.counter++; | |
| forloop.counter0++; | |
| forloop.revcounter--; | |
| forloop.revcounter0--; | |
| forloop.first = false; | |
| forloop.last = (i === l - 1); | |
| } | |
| // Render contents | |
| for (var i = 0, l = this.contents.length; i < l; i++) { | |
| results.push(this.contents[i].render(context)); | |
| } | |
| } | |
| context.pop(); | |
| return results; | |
| } | |
| function IfNode(props, contents) { } | |
| // Marker nodes | |
| function EndFornode() { } | |
| function EndIfNode() { } | |
| // Template functions | |
| function $template(props) { | |
| return new Template(props, Array.prototype.slice.call(arguments, 1)); | |
| } | |
| function $block(name) { | |
| return new Block(name, Array.prototype.slice.call(arguments, 1)); | |
| } | |
| function $for(props) { | |
| return new ForNode(props, Array.prototype.slice.call(arguments, 1)); | |
| } | |
| function $if(props) { | |
| return new IfNode(props, Array.prototype.slice.call(arguments, 1)); | |
| } | |
| function $endfor() { | |
| return new EndForNode(); | |
| } | |
| function $endif() { | |
| return new EndIfNode(); | |
| } | |
| function $html(contents) { | |
| return new RawHTMLNode(contents); | |
| } | |
| function $var(name) { | |
| return new Variable(name); | |
| } | |
| // Helper functions | |
| function processMarkerNodes(item) { | |
| // Find these | |
| // $for/$if, element, element, $endfor/$endif | |
| // And end up with this | |
| // $for/$if[contents=[element, element] | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| $template({extends: "article_base"} | |
| , $block("content" | |
| , DIV({"class": "articles"} | |
| , $for({article: $var("articles")}) | |
| , DIV({id: "article{{ article.id }}"} | |
| , H2("{{ article.title }}") | |
| , DIV({"class": "body"} | |
| , $html("{{ article.text }}") | |
| ) | |
| ) | |
| , "In Loop" | |
| , $endfor | |
| , "Out of Loop" | |
| ) | |
| , "Out of Element" | |
| ) | |
| ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment