forked from georgi/patroon
-
Notifications
You must be signed in to change notification settings - Fork 1
/
README.txt
198 lines (160 loc) · 8.2 KB
/
README.txt
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
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
JFill - a Javascript Template Engine
======================================
JFill is a javascript HTML template engine. It takes a template in the
form of a DOM subtree, and fills it from a java object, using string
interpolation inside attribute values and text nodes. It recursively
expands arrays and subobjects into the template.
### Usage
template = new JFill.Template(jquery_expression); // if using jQuery
template = new JFill.Template(id); // if not using jQuery
Removes the given element subtree from the DOM, returning a
template object.
nodes = template.fill(data) // returns array with filled node(s)
$(jexpr).jfill(template, data) // jquery-based appends filled node(s)
Fills the template using the data object. If the data is an array,
fills multiple copies of the template, one for each data object in
the array. The data properties can be text or nested objects or
arrays.
Filling has the following rules:
+ Baseline - String Interpolation: In any text or attribute anywhere
in the template DOM subtree, any string of the form {...} is
replaced with its javascript evaluation, in the context of the
current data object. For example if the data object has a property
"name", the template could have a tag such as:
<div>Name: {name}</div>
or an arbitrary expression
<div>Spelling: {name.toUpperCase.split('').join('-')}</div>
+ Conditional: If any element has an attribute jfill:if="condition",
JFill evalutes the condition expression in the context of the
current data object; if the result is false or undefined, the
element and its subtree will be pruned, otherwise the element is
filled normally. (The condition expression may optionally be
enclosed in braces { } ).
+ Scoping: If any element has an attribute jfill:scope="subdata",
JFill evalutes the subdata expression in the context of the current
data object. If the result is undefined, the element and its
subtree will be pruned, same as for jfill:if. Otherwise, JFill
recursively fills the element's subtree in the context of the
resulting object or array. (The subdata expression may optionally
be enclosed in braces { }.).
+ Metadata: In the evaluation context, a metadata object named jfill
is available at each scope, having the following properties:
jfill.data - The object at the current scope
jfill.parent - The medata of the containing scope. undefined if
at the root scope.
jfill.array - If currently filling from an array, this
references the entire array.
jfill.index - If currently filling from an array, the value is
the index of the current object in jfill.array.
Otherwise the value is undefined.
jfill.oddEven - The string "odd" if jfill.index is odd, "even"
if jfill.index is even. Undefined if not
filling from an array.
jfill.isFirst - True if filling from an array and at the first
item in the array, i.e. if jfill.index == 0.
Undefined if not filling from an array.
jfill.isLast - True if filling from an array and at the last
item in the array, i.e. if jfill.index ==
jfill.array.length-1. Undefined if not filling
from an array.
jfill.firstLast - If filling from an array, one of the strings:
"", "first", "last", or "first last", based on
isFirst and isLast. Undefined if not filling
from an array.
For example, a template for an array row might include:
<tr class="{jfill.firstLast} {jfill.oddEven}">...</tr>
+ Arrays and Id's: When filling an element from an array, if the
element has an id, the template can include javascript to compute
a unique id for each copy. For example:
<li jfill:scope="items" id="item-{itemid}">...</li>
As a convenience, if the template doesn't fill with a new id, jfill
will append "-" plus the array index. Thus the following are
equivalent:
<li jfill:scope="items" id="item">...</li>
<li jfill:scope="items" id="item-{jfill.index}">...</li>
### Example
Data is in the form an object or array of objects, which can contain
properties in the form of text or nested objects or arrays. For example:
var data = {
comment: [{
time: "2008-09-07 12:28:33",
name: "David Beckham",
website: "beckham.com",
text: "I watched the euro finals on tv..."
}, {
time: "2008-09-07 14:28:33",
name: "Tuncay",
website: "",
text: "Me too"
}]
};
This data can be filled into the following template:
<div class="comments">
<div id="comments-template">
<div class="comment {jfill.firstLast}">
<div class="top">
<span class="index">{jfill.index+1}.</span>
{website.length > 0 ? linkTo(name, website) : name} said
<a title="{time}"></a>:
</div>
<div class="content">
{text}
</div>
</div>
</div>
</div>
The result would be as follows -- notice that the "comment" part of the
template has been repeated once for each item in the data.comment array:
<div class="comments">
<div id="comments-template">
<div class="comment first">
<div class="top">
<span class="index">1.</span>
<a href="http://backham.com">David Beckham</a> said
<a title="2008-09-07 12:28:33">2 hours ago</a>
</div>
<div class="text">
I watched the euro finals on tv...
</div>
</div>
<div class="comment last">
<div class="top">
<span class="index">2.</span>
Tuncay said
<a title="2008-09-07 14:28:33">1 minute ago</a>
</div>
<div class="text">
Me too
</div>
</div>
</div>
</div>
The code to run the above example with jQuery is:
var template = new JFill.Template('#comments-template');
$('comments').jfill(template, data);
The code to run the above example without jQuery is:
var template = new JFill.Template('comments-template');
var container = document.getElementsByClassName('comments')[0];
var result = template.fill(data);
for (var i=0; i<result.length; i++) {
container.appendChild(result[i]);
}
// since the example data is a single object rather than an array, the result
// in this case will have only one child, so we could simply use
// container.appendChild(result[0]);
// but showing the more general code for reference.
For a more complex working example, see example.html
### Credits
JFill is derived from Patroon by Matthias Georgi, which has a simple
structure and is implemented with small elegant code. Changes have been
made to give a bit more flexibility and power while trying to mostly keep
the same basic simplicity and power. However those changes affect the
functionality, and arguably the spirit, in a non-backwards-compatible way,
and so the library has been renamed.
The major differences in functionality are:
- put in a JFill namespace rather than defining Template at global scope
- added "jfill" metadata object to interpolation context.
- introduced jfill:scope attribute to specify subscope context, rather than matching objects to class names
- introduced jfill:if attribute for conditional parts of template
- doesn't add <span> around interpolated text -- result's html structure always matches template
- doesn't support creating new nodes via interpolated text. therefore doesn't have helpers.