/
template.coffee
119 lines (101 loc) · 3.64 KB
/
template.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
{ EventEmitter } = require 'events'
{ Builder:DefaultBuilder } = require 'asyncxml'
{ schema, self_closing } = require './schema'
{ doctype } = require './doctype'
{ aliases } = require './alias'
EVENTS = [
'new','add'
'show', 'hide'
'attr','text', 'raw'
'remove', 'replace'
'data','close','end'
]
##
# i made these function name short ,
# because its a little bit faster than with long names
pp = (proto, name) -> # populate tag with specific child tag genertor
proto[ name] = -> @tag.apply this, [name].concat arguments...
proto["$"+name] = -> @$tag.apply this, [name].concat arguments...
ff = (proto, tags) -> # fill with tags
for tagname in tags
pp proto, tagname if tagname
return
class Template extends EventEmitter
constructor: (opts = {}, template) ->
# options
[template, opts] = [opts, {}] if typeof opts is 'function'
# defaults
opts.encoding ?= 'utf-8'
opts.doctype ?= off
opts.end ?= on
# schema
schema_input = opts.schema
# resolve schema name input
s = aliases[schema_input] or schema_input or 'xml'
# load self closing schema
opts.self_closing = self_closing[s]?(opts)
# load tag list (xml schema)
opts.schema = schema[s]?(opts).split(' ')
# get builder class from options
Builder = opts.Builder ? DefaultBuilder
# create new builder class to extend it with a schema
class ExtendedBuilder extends Builder
# create tag method shortcuts defined by schema
ff ExtendedBuilder::, opts.schema
# instantiate
@xml = new ExtendedBuilder opts
# tag class is defined by builder
Tag = @xml.Tag
# create new tag class to extend it with a schema
class ExtendedTag extends Tag
# create tag method shortcuts defined by schema
ff ExtendedTag::, opts.schema
# write it back so builder can use it to instantiate a new tag
@xml.Tag = @xml.opts.Tag = ExtendedTag
## FIXME replace this with new checker middleware api when possible
# add self closing tag behavior
# some of the html tags dont need a closing tag
end_tag = Tag::end
@xml.Tag::end = ->
if opts.self_closing is on or opts.self_closing.match @name
end_tag.call this, arguments...
else
@text("", force:yes) if @isempty
end_tag.call this, arguments...
# pipe events through
EVENTS.forEach (event) =>
@xml.on event, (args...) =>
@emit event, args...
##
# start the templating process after user listened for events
process.nextTick =>
# load doctype if enabled
if opts.doctype is on
opts.doctype = 'html'
# resolve doctype name input
d = aliases[opts.doctype] or opts.doctype
# write doctype
if opts.doctype and (dt = doctype[d]?(opts))
dt += "\n" if opts.pretty
@xml.emit 'data', @xml, dt
# templating process ...
if typeof template is 'function'
template.call @xml
@end() if opts.end
else
@end(template)
register: =>
@xml.register arguments...
end: =>
@xml.end arguments...
ready: (callback) =>
if @xml.closed is yes
callback()
else
@xml.once('end', callback)
# exports
Template.schema = schema
Template.doctype = doctype
Template.self_closing = self_closing
Template.aliases = aliases
module.exports = Template