boxwood 0.75.0 → 0.77.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -13
- package/index.js +46 -82
- package/package.json +4 -4
- package/benchmark/fixtures/basic/boxwood.js +0 -3
- package/benchmark/fixtures/basic/data.json +0 -1
- package/benchmark/fixtures/basic/handlebars.hbs +0 -1
- package/benchmark/fixtures/basic/lodash.ejs +0 -1
- package/benchmark/fixtures/basic/mustache.mst +0 -1
- package/benchmark/fixtures/basic/underscore.ejs +0 -1
- package/benchmark/fixtures/basic/vanilla.js +0 -3
- package/benchmark/fixtures/div/boxwood.js +0 -5
- package/benchmark/fixtures/div/data.json +0 -1
- package/benchmark/fixtures/div/handlebars.hbs +0 -1
- package/benchmark/fixtures/div/lodash.ejs +0 -1
- package/benchmark/fixtures/div/mustache.mst +0 -1
- package/benchmark/fixtures/div/underscore.ejs +0 -1
- package/benchmark/fixtures/div/vanilla.js +0 -4
- package/benchmark/fixtures/escape/boxwood.js +0 -3
- package/benchmark/fixtures/escape/data.json +0 -3
- package/benchmark/fixtures/escape/handlebars.hbs +0 -1
- package/benchmark/fixtures/escape/lodash.ejs +0 -1
- package/benchmark/fixtures/escape/mustache.mst +0 -1
- package/benchmark/fixtures/escape/underscore.ejs +0 -1
- package/benchmark/fixtures/escape/vanilla.js +0 -5
- package/benchmark/fixtures/friends/boxwood.js +0 -56
- package/benchmark/fixtures/friends/data.json +0 -30
- package/benchmark/fixtures/friends/handlebars.hbs +0 -45
- package/benchmark/fixtures/friends/lodash.ejs +0 -48
- package/benchmark/fixtures/friends/mustache.mst +0 -45
- package/benchmark/fixtures/friends/underscore.ejs +0 -48
- package/benchmark/fixtures/friends/vanilla.js +0 -36
- package/benchmark/fixtures/if/boxwood.js +0 -21
- package/benchmark/fixtures/if/data.json +0 -12
- package/benchmark/fixtures/if/handlebars.hbs +0 -13
- package/benchmark/fixtures/if/lodash.ejs +0 -12
- package/benchmark/fixtures/if/mustache.mst +0 -13
- package/benchmark/fixtures/if/underscore.ejs +0 -12
- package/benchmark/fixtures/if/vanilla.js +0 -14
- package/benchmark/fixtures/projects/boxwood.js +0 -20
- package/benchmark/fixtures/projects/data.json +0 -26
- package/benchmark/fixtures/projects/handlebars.hbs +0 -15
- package/benchmark/fixtures/projects/lodash.ejs +0 -17
- package/benchmark/fixtures/projects/mustache.mst +0 -16
- package/benchmark/fixtures/projects/underscore.ejs +0 -17
- package/benchmark/fixtures/projects/vanilla.js +0 -21
- package/benchmark/fixtures/search/boxwood.js +0 -18
- package/benchmark/fixtures/search/data.json +0 -35
- package/benchmark/fixtures/search/handlebars.hbs +0 -18
- package/benchmark/fixtures/search/lodash.ejs +0 -22
- package/benchmark/fixtures/search/mustache.mst +0 -18
- package/benchmark/fixtures/search/underscore.ejs +0 -22
- package/benchmark/fixtures/search/vanilla.js +0 -26
- package/benchmark/fixtures/todos/boxwood.js +0 -9
- package/benchmark/fixtures/todos/data.json +0 -9
- package/benchmark/fixtures/todos/handlebars.hbs +0 -7
- package/benchmark/fixtures/todos/lodash.ejs +0 -7
- package/benchmark/fixtures/todos/mustache.mst +0 -7
- package/benchmark/fixtures/todos/underscore.ejs +0 -7
- package/benchmark/fixtures/todos/vanilla.js +0 -12
- package/benchmark/index.js +0 -112
package/README.md
CHANGED
|
@@ -56,7 +56,7 @@ const layout = require("./layout")
|
|
|
56
56
|
const banner = require("./banner")
|
|
57
57
|
|
|
58
58
|
module.exports = () => {
|
|
59
|
-
return layout([
|
|
59
|
+
return layout({ language: "en" }, [
|
|
60
60
|
banner({
|
|
61
61
|
title: "Hello, world!",
|
|
62
62
|
description: "Lorem ipsum dolor sit amet",
|
|
@@ -67,22 +67,24 @@ module.exports = () => {
|
|
|
67
67
|
|
|
68
68
|
```js
|
|
69
69
|
// example/layout/index.js
|
|
70
|
-
|
|
71
|
-
const { component, css, html, head, body } = require("boxwood")
|
|
70
|
+
const { component, css, html, body } = require("boxwood")
|
|
72
71
|
const head = require("./head")
|
|
73
72
|
|
|
74
73
|
const styles = css.load(__dirname)
|
|
75
74
|
|
|
76
75
|
module.exports = component(
|
|
77
|
-
(children) => {
|
|
78
|
-
return html(
|
|
76
|
+
({ language }, children) => {
|
|
77
|
+
return html({ lang: language }, [
|
|
78
|
+
head(),
|
|
79
|
+
body({ className: styles.layout }, children),
|
|
80
|
+
])
|
|
79
81
|
},
|
|
80
82
|
{ styles }
|
|
81
83
|
)
|
|
82
84
|
```
|
|
83
85
|
|
|
84
86
|
```js
|
|
85
|
-
// example/head/index.js
|
|
87
|
+
// example/layout/head/index.js
|
|
86
88
|
const { head, title } = require("boxwood")
|
|
87
89
|
|
|
88
90
|
module.exports = () => {
|
|
@@ -113,20 +115,22 @@ const test = require("node:test")
|
|
|
113
115
|
const assert = require("node:assert")
|
|
114
116
|
const { compile } = require("boxwood")
|
|
115
117
|
|
|
116
|
-
test("banner renders a title", () => {
|
|
118
|
+
test("banner renders a title", async () => {
|
|
117
119
|
const { template } = await compile(__dirname)
|
|
118
|
-
const html = template({ title:
|
|
119
|
-
assert(html.includes(
|
|
120
|
+
const html = template({ title: "foo" })
|
|
121
|
+
assert(html.includes("<h1>foo</h1>"))
|
|
120
122
|
})
|
|
121
123
|
|
|
122
|
-
test(
|
|
124
|
+
test("banner renders an optional description", async () => {
|
|
123
125
|
const { template } = await compile(__dirname)
|
|
124
|
-
const html = template({ title:
|
|
125
|
-
assert(html.includes(
|
|
126
|
-
assert(html.includes(
|
|
126
|
+
const html = template({ title: "foo", description: "bar" })
|
|
127
|
+
assert(html.includes("<h1>foo</h1>"))
|
|
128
|
+
assert(html.includes("<p>bar</p>"))
|
|
127
129
|
})
|
|
128
130
|
```
|
|
129
131
|
|
|
132
|
+
You can check the `test` dir for more examples.
|
|
133
|
+
|
|
130
134
|
## Maintainers
|
|
131
135
|
|
|
132
136
|
[@emilos](https://github.com/emilos)
|
package/index.js
CHANGED
|
@@ -2,7 +2,6 @@ const { join } = require("path")
|
|
|
2
2
|
const { readFileSync } = require("fs")
|
|
3
3
|
const csstree = require("css-tree")
|
|
4
4
|
const toHash = require("string-hash")
|
|
5
|
-
const YAML = require("yaml")
|
|
6
5
|
|
|
7
6
|
async function compile(path) {
|
|
8
7
|
const fn = require(path)
|
|
@@ -47,7 +46,7 @@ async function compile(path) {
|
|
|
47
46
|
if (Array.isArray(node)) {
|
|
48
47
|
node.forEach(walk)
|
|
49
48
|
} else if (Array.isArray(node.children)) {
|
|
50
|
-
node.children.
|
|
49
|
+
node.children.forEach(walk)
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
walk(tree)
|
|
@@ -175,24 +174,27 @@ const isUnescapedTag = (name) => {
|
|
|
175
174
|
}
|
|
176
175
|
|
|
177
176
|
const render = (input, escape = true) => {
|
|
178
|
-
if (
|
|
177
|
+
if (
|
|
178
|
+
typeof input === "undefined" ||
|
|
179
|
+
typeof input === "boolean" ||
|
|
180
|
+
input === null ||
|
|
181
|
+
input.ignore
|
|
182
|
+
) {
|
|
179
183
|
return ""
|
|
180
184
|
}
|
|
181
|
-
if (Array.isArray(input)) {
|
|
182
|
-
return input
|
|
183
|
-
.filter(Boolean)
|
|
184
|
-
.map((input) => render(input))
|
|
185
|
-
.join("")
|
|
186
|
-
}
|
|
187
185
|
if (typeof input === "number") {
|
|
188
186
|
return input.toString()
|
|
189
187
|
}
|
|
190
188
|
if (typeof input === "string") {
|
|
191
|
-
|
|
189
|
+
if (escape) {
|
|
190
|
+
return escapeHTML(input)
|
|
191
|
+
}
|
|
192
|
+
return input
|
|
192
193
|
}
|
|
193
|
-
if (input
|
|
194
|
-
return render(input.
|
|
194
|
+
if (Array.isArray(input)) {
|
|
195
|
+
return input.map((input) => render(input)).join("")
|
|
195
196
|
}
|
|
197
|
+
|
|
196
198
|
if (input.name === "raw") {
|
|
197
199
|
return render(input.children, false)
|
|
198
200
|
}
|
|
@@ -202,32 +204,14 @@ const render = (input, escape = true) => {
|
|
|
202
204
|
}
|
|
203
205
|
return `<${input.name}>`
|
|
204
206
|
}
|
|
205
|
-
if (input.attributes && input.children) {
|
|
206
|
-
return (
|
|
207
|
-
`<${input.name} ` +
|
|
208
|
-
attributes(input.attributes) +
|
|
209
|
-
">" +
|
|
210
|
-
render(input.children, isUnescapedTag(input.name)) +
|
|
211
|
-
`</${input.name}>`
|
|
212
|
-
)
|
|
213
|
-
}
|
|
214
|
-
if (input.attributes) {
|
|
215
|
-
return (
|
|
216
|
-
`<${input.name} ` + attributes(input.attributes) + `></${input.name}>`
|
|
217
|
-
)
|
|
218
|
-
}
|
|
219
|
-
if (input.children) {
|
|
220
|
-
return (
|
|
221
|
-
`<${input.name}>` +
|
|
222
|
-
render(input.children, isUnescapedTag(input.name)) +
|
|
223
|
-
`</${input.name}>`
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
return `<${input.name}></${input.name}>`
|
|
227
|
-
}
|
|
228
207
|
|
|
229
|
-
|
|
230
|
-
|
|
208
|
+
return (
|
|
209
|
+
`<${input.name}` +
|
|
210
|
+
(input.attributes ? " " + attributes(input.attributes) : "") +
|
|
211
|
+
">" +
|
|
212
|
+
render(input.children, isUnescapedTag(input.name)) +
|
|
213
|
+
`</${input.name}>`
|
|
214
|
+
)
|
|
231
215
|
}
|
|
232
216
|
|
|
233
217
|
const raw = (children) => {
|
|
@@ -504,15 +488,6 @@ function classes() {
|
|
|
504
488
|
return array.join(" ")
|
|
505
489
|
}
|
|
506
490
|
|
|
507
|
-
const yaml = {
|
|
508
|
-
load() {
|
|
509
|
-
const path = join(...arguments)
|
|
510
|
-
const file = path.endsWith(".yaml") ? path : join(path, "index.yaml")
|
|
511
|
-
const content = readFileSync(file, "utf8")
|
|
512
|
-
return YAML.parse(content)
|
|
513
|
-
},
|
|
514
|
-
}
|
|
515
|
-
|
|
516
491
|
const json = {
|
|
517
492
|
load() {
|
|
518
493
|
const path = join(...arguments)
|
|
@@ -530,23 +505,20 @@ function i18n(translations) {
|
|
|
530
505
|
|
|
531
506
|
i18n.load = function () {
|
|
532
507
|
const path = join(...arguments)
|
|
533
|
-
const data =
|
|
508
|
+
const data = json.load(path)
|
|
534
509
|
return function translate(language, key) {
|
|
535
|
-
if (!key) {
|
|
536
|
-
throw new Error(`TranslationError[${key}][${language}]: key is undefined`)
|
|
537
|
-
}
|
|
538
510
|
if (!language) {
|
|
539
|
-
throw new Error(
|
|
540
|
-
`TranslationError[${key}][${language}]: language is undefined`
|
|
541
|
-
)
|
|
511
|
+
throw new Error(`TranslationError: language is undefined`)
|
|
542
512
|
}
|
|
543
|
-
|
|
544
|
-
|
|
513
|
+
if (!key) {
|
|
514
|
+
throw new Error(`TranslationError: key is undefined`)
|
|
515
|
+
}
|
|
516
|
+
if (!data[key] || !data[key][language]) {
|
|
545
517
|
throw new Error(
|
|
546
|
-
`TranslationError[${key}][${language}]
|
|
518
|
+
`TranslationError: translation [${key}][${language}] is undefined`
|
|
547
519
|
)
|
|
548
520
|
}
|
|
549
|
-
return
|
|
521
|
+
return data[key][language]
|
|
550
522
|
}
|
|
551
523
|
}
|
|
552
524
|
|
|
@@ -556,24 +528,24 @@ function component(fn, { styles, i18n, scripts } = {}) {
|
|
|
556
528
|
return fn({}, a)
|
|
557
529
|
}
|
|
558
530
|
if (i18n) {
|
|
531
|
+
if (!a || !a.language) {
|
|
532
|
+
throw new Error(
|
|
533
|
+
`TranslationError: language is undefined for component:\n${fn.toString()}`
|
|
534
|
+
)
|
|
535
|
+
}
|
|
559
536
|
const { language } = a
|
|
560
537
|
function translate(key) {
|
|
561
538
|
if (!key) {
|
|
562
539
|
throw new Error(
|
|
563
|
-
`TranslationError
|
|
540
|
+
`TranslationError: key is undefined for component:\n${fn.toString()}`
|
|
564
541
|
)
|
|
565
542
|
}
|
|
566
|
-
if (!language) {
|
|
543
|
+
if (!i18n[key] || !i18n[key][language]) {
|
|
567
544
|
throw new Error(
|
|
568
|
-
`TranslationError[${key}][${language}]
|
|
545
|
+
`TranslationError: translation [${key}][${language}] is undefined for component:\n${fn.toString()}`
|
|
569
546
|
)
|
|
570
547
|
}
|
|
571
548
|
const translation = i18n[key][language]
|
|
572
|
-
if (!translation) {
|
|
573
|
-
throw new Error(
|
|
574
|
-
`TranslationError[${key}][${language}]: translation is undefined for component:\n${fn.toString()}`
|
|
575
|
-
)
|
|
576
|
-
}
|
|
577
549
|
return translation
|
|
578
550
|
}
|
|
579
551
|
return fn({ ...a, translate }, b || [])
|
|
@@ -582,25 +554,19 @@ function component(fn, { styles, i18n, scripts } = {}) {
|
|
|
582
554
|
}
|
|
583
555
|
return function (a, b) {
|
|
584
556
|
const tree = execute(a, b)
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
return tree.concat(styles.css, scripts.js)
|
|
588
|
-
}
|
|
589
|
-
return [tree, styles.css, scripts.js]
|
|
590
|
-
}
|
|
557
|
+
let nodes = Array.isArray(tree) ? tree : [tree]
|
|
558
|
+
|
|
591
559
|
if (styles) {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
}
|
|
595
|
-
return [tree, styles.css]
|
|
560
|
+
const data = Array.isArray(styles) ? styles : [styles]
|
|
561
|
+
nodes = nodes.concat(data.map((style) => style.css))
|
|
596
562
|
}
|
|
563
|
+
|
|
597
564
|
if (scripts) {
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
}
|
|
601
|
-
return [tree, scripts.js]
|
|
565
|
+
const data = Array.isArray(scripts) ? scripts : [scripts]
|
|
566
|
+
nodes = nodes.concat(data.map((script) => script.js))
|
|
602
567
|
}
|
|
603
|
-
|
|
568
|
+
|
|
569
|
+
return nodes
|
|
604
570
|
}
|
|
605
571
|
}
|
|
606
572
|
|
|
@@ -610,11 +576,9 @@ module.exports = {
|
|
|
610
576
|
classes,
|
|
611
577
|
doctype,
|
|
612
578
|
escape: escapeHTML,
|
|
613
|
-
fragment,
|
|
614
579
|
raw,
|
|
615
580
|
css,
|
|
616
581
|
js,
|
|
617
|
-
yaml,
|
|
618
582
|
json,
|
|
619
583
|
tag,
|
|
620
584
|
i18n,
|
package/package.json
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "boxwood",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.77.0",
|
|
4
4
|
"description": "Compile HTML templates into JS",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "node --test",
|
|
7
|
+
"test": "node --test --test-reporter=dot",
|
|
8
|
+
"test:debug": "node --test --test-reporter=spec",
|
|
8
9
|
"coverage": "c8 npm test",
|
|
9
10
|
"benchmark": "node --test benchmark/index.js",
|
|
10
11
|
"watch": "npm test -- --watch",
|
|
@@ -62,7 +63,6 @@
|
|
|
62
63
|
},
|
|
63
64
|
"dependencies": {
|
|
64
65
|
"css-tree": "^2.3.1",
|
|
65
|
-
"string-hash": "^1.1.3"
|
|
66
|
-
"yaml": "^2.4.2"
|
|
66
|
+
"string-hash": "^1.1.3"
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
foo
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
foo
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
foo
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
foo
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<div>foo</div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<div>foo</div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<div>foo</div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<div>foo</div>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{{foo}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<%- foo %>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{{foo}}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<%- foo %>
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const {
|
|
2
|
-
fragment,
|
|
3
|
-
doctype,
|
|
4
|
-
html,
|
|
5
|
-
head,
|
|
6
|
-
body,
|
|
7
|
-
meta,
|
|
8
|
-
img,
|
|
9
|
-
title,
|
|
10
|
-
div,
|
|
11
|
-
ul,
|
|
12
|
-
li,
|
|
13
|
-
a,
|
|
14
|
-
} = require("../../..")
|
|
15
|
-
|
|
16
|
-
module.exports = function ({ friends }) {
|
|
17
|
-
return fragment([
|
|
18
|
-
doctype(),
|
|
19
|
-
html({ lang: "en" }, [
|
|
20
|
-
head([meta({ charset: "UTF-8" }), title("Friends")]),
|
|
21
|
-
body([
|
|
22
|
-
div(
|
|
23
|
-
{ class: "friends" },
|
|
24
|
-
friends.map((friend) => {
|
|
25
|
-
return div({ class: "friend" }, [
|
|
26
|
-
ul([
|
|
27
|
-
li(`Name: ${friend.name}`),
|
|
28
|
-
li(`Balance: ${friend.balance}`),
|
|
29
|
-
li(`Age: ${friend.age}`),
|
|
30
|
-
li(`Address: ${friend.address}`),
|
|
31
|
-
li(["Image: ", img({ src: friend.picture })]),
|
|
32
|
-
li(`Company: ${friend.company}`),
|
|
33
|
-
li([
|
|
34
|
-
"Email: ",
|
|
35
|
-
a({ href: `mailto:${friend.email}` }, friend.email),
|
|
36
|
-
]),
|
|
37
|
-
li(`About: ${friend.about}`),
|
|
38
|
-
friend.tags.length &&
|
|
39
|
-
li(["Tags: ", ul(friend.tags.map((tag) => li(tag)))]),
|
|
40
|
-
friend.friends.length &&
|
|
41
|
-
li([
|
|
42
|
-
"Friends: ",
|
|
43
|
-
ul(
|
|
44
|
-
friend.friends.map((friend) =>
|
|
45
|
-
li(`${friend.name} (${friend.id})`)
|
|
46
|
-
)
|
|
47
|
-
),
|
|
48
|
-
]),
|
|
49
|
-
]),
|
|
50
|
-
])
|
|
51
|
-
})
|
|
52
|
-
),
|
|
53
|
-
]),
|
|
54
|
-
]),
|
|
55
|
-
])
|
|
56
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"friends": [
|
|
3
|
-
{
|
|
4
|
-
"name": "Jan Kowalski",
|
|
5
|
-
"id": 1,
|
|
6
|
-
"balance": "100 PLN",
|
|
7
|
-
"age": 50,
|
|
8
|
-
"address": "Warszawa",
|
|
9
|
-
"picture": "jankowalski.png",
|
|
10
|
-
"email": "jan@kowalski.pl",
|
|
11
|
-
"about": "I like fishing",
|
|
12
|
-
"company": "PKO",
|
|
13
|
-
"tags": ["fisherman"],
|
|
14
|
-
"friends": [
|
|
15
|
-
{
|
|
16
|
-
"name": "Piotr Nowak",
|
|
17
|
-
"id": 2,
|
|
18
|
-
"balance": "80 PLN",
|
|
19
|
-
"age": 40,
|
|
20
|
-
"address": "Kraków",
|
|
21
|
-
"picture": "piotrnowak.png",
|
|
22
|
-
"email": "piotr@nowak.pl",
|
|
23
|
-
"about": "I like cooking",
|
|
24
|
-
"company": "ING",
|
|
25
|
-
"tags": ["chef"]
|
|
26
|
-
}
|
|
27
|
-
]
|
|
28
|
-
}
|
|
29
|
-
]
|
|
30
|
-
}
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Friends</title>
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<div class="friends">
|
|
9
|
-
{{#each friends}}
|
|
10
|
-
<div class="friend">
|
|
11
|
-
<ul>
|
|
12
|
-
<li>Name: {{this.name}}</li>
|
|
13
|
-
<li>Balance: {{this.balance}}</li>
|
|
14
|
-
<li>Age: {{this.age}}</li>
|
|
15
|
-
<li>Address: {{this.address}}</li>
|
|
16
|
-
<li>Image: <img src="{{this.picture}}"></li>
|
|
17
|
-
<li>Company: {{this.company}}</li>
|
|
18
|
-
<li>Email: <a href="mailto:{{this.email}}">{{this.email}}</a></li>
|
|
19
|
-
<li>About: {{this.about}}</li>
|
|
20
|
-
{{#if tags.length}}
|
|
21
|
-
<li>
|
|
22
|
-
Tags:
|
|
23
|
-
<ul>
|
|
24
|
-
{{#each tags}}
|
|
25
|
-
<li>{{this}}</li>
|
|
26
|
-
{{/each}}
|
|
27
|
-
</ul>
|
|
28
|
-
</li>
|
|
29
|
-
{{/if}}
|
|
30
|
-
{{#if friends.length}}
|
|
31
|
-
<li>
|
|
32
|
-
Friends:
|
|
33
|
-
<ul>
|
|
34
|
-
{{#each friends}}
|
|
35
|
-
<li>{{this.name}} ({{this.id}})</li>
|
|
36
|
-
{{/each}}
|
|
37
|
-
</ul>
|
|
38
|
-
</li>
|
|
39
|
-
{{/if}}
|
|
40
|
-
</ul>
|
|
41
|
-
</div>
|
|
42
|
-
{{/each}}
|
|
43
|
-
</div>
|
|
44
|
-
</body>
|
|
45
|
-
</html>
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Friends</title>
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<div class="friends">
|
|
9
|
-
<% for (var i = 0, ilen = friends.length; i < ilen; i += 1) { %>
|
|
10
|
-
<% var friend = friends[i]; %>
|
|
11
|
-
<div class="friend">
|
|
12
|
-
<ul>
|
|
13
|
-
<li>Name: <%- friend.name %></li>
|
|
14
|
-
<li>Balance: <%- friend.balance %></li>
|
|
15
|
-
<li>Age: <%- friend.age %></li>
|
|
16
|
-
<li>Address: <%- friend.address %></li>
|
|
17
|
-
<li>Image: <img src="<%- friend.picture %>"></li>
|
|
18
|
-
<li>Company: <%- friend.company %></li>
|
|
19
|
-
<li>Email: <a href="mailto:<%- friend.email %>"><%- friend.email %></a></li>
|
|
20
|
-
<li>About: <%- friend.about %></li>
|
|
21
|
-
<% if (friend.tags.length) { %>
|
|
22
|
-
<li>
|
|
23
|
-
Tags:
|
|
24
|
-
<ul>
|
|
25
|
-
<% for (var j = 0, jlen = friend.tags.length; j < jlen; j += 1) { %>
|
|
26
|
-
<% var tag = friend.tags[i]; %>
|
|
27
|
-
<li><%- tag %></li>
|
|
28
|
-
<% } %>
|
|
29
|
-
</ul>
|
|
30
|
-
</li>
|
|
31
|
-
<% } %>
|
|
32
|
-
<% if (friend.friends.length) { %>
|
|
33
|
-
<li>
|
|
34
|
-
Friends:
|
|
35
|
-
<ul>
|
|
36
|
-
<% for (var k = 0, klen = friend.friends.length; k < klen; k += 1) { %>
|
|
37
|
-
<% var fr = friend.friends[i] %>
|
|
38
|
-
<li><%- fr.name %> (<%- fr.id %>)</li>
|
|
39
|
-
<% } %>
|
|
40
|
-
</ul>
|
|
41
|
-
</li>
|
|
42
|
-
<% } %>
|
|
43
|
-
</ul>
|
|
44
|
-
</div>
|
|
45
|
-
<% } %>
|
|
46
|
-
</div>
|
|
47
|
-
</body>
|
|
48
|
-
</html>
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Friends</title>
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<div class="friends">
|
|
9
|
-
{{#friends}}
|
|
10
|
-
<div class="friend">
|
|
11
|
-
<ul>
|
|
12
|
-
<li>Name: {{name}}</li>
|
|
13
|
-
<li>Balance: {{balance}}</li>
|
|
14
|
-
<li>Age: {{age}}</li>
|
|
15
|
-
<li>Address: {{address}}</li>
|
|
16
|
-
<li>Image: <img src="{{picture}}"></li>
|
|
17
|
-
<li>Company: {{company}}</li>
|
|
18
|
-
<li>Email: <a href="mailto:{{email}}">{{email}}</a></li>
|
|
19
|
-
<li>About: {{about}}</li>
|
|
20
|
-
{{#tags.length}}
|
|
21
|
-
<li>
|
|
22
|
-
Tags:
|
|
23
|
-
<ul>
|
|
24
|
-
{{#tags}}
|
|
25
|
-
<li>{{.}}</li>
|
|
26
|
-
{{/tags}}
|
|
27
|
-
</ul>
|
|
28
|
-
</li>
|
|
29
|
-
{{/tags.length}}
|
|
30
|
-
{{#friends.length}}
|
|
31
|
-
<li>
|
|
32
|
-
Friends:
|
|
33
|
-
<ul>
|
|
34
|
-
{{#friends}}
|
|
35
|
-
<li>{{name}} ({{id}})</li>
|
|
36
|
-
{{/friends}}
|
|
37
|
-
</ul>
|
|
38
|
-
</li>
|
|
39
|
-
{{/friends.length}}
|
|
40
|
-
</ul>
|
|
41
|
-
</div>
|
|
42
|
-
{{/friends}}
|
|
43
|
-
</div>
|
|
44
|
-
</body>
|
|
45
|
-
</html>
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html>
|
|
2
|
-
<html lang="en">
|
|
3
|
-
<head>
|
|
4
|
-
<meta charset="UTF-8">
|
|
5
|
-
<title>Friends</title>
|
|
6
|
-
</head>
|
|
7
|
-
<body>
|
|
8
|
-
<div class="friends">
|
|
9
|
-
<% for (var i = 0, ilen = friends.length; i < ilen; i += 1) { %>
|
|
10
|
-
<% var friend = friends[i]; %>
|
|
11
|
-
<div class="friend">
|
|
12
|
-
<ul>
|
|
13
|
-
<li>Name: <%- friend.name %></li>
|
|
14
|
-
<li>Balance: <%- friend.balance %></li>
|
|
15
|
-
<li>Age: <%- friend.age %></li>
|
|
16
|
-
<li>Address: <%- friend.address %></li>
|
|
17
|
-
<li>Image: <img src="<%- friend.picture %>"></li>
|
|
18
|
-
<li>Company: <%- friend.company %></li>
|
|
19
|
-
<li>Email: <a href="mailto:<%- friend.email %>"><%- friend.email %></a></li>
|
|
20
|
-
<li>About: <%- friend.about %></li>
|
|
21
|
-
<% if (friend.tags.length) { %>
|
|
22
|
-
<li>
|
|
23
|
-
Tags:
|
|
24
|
-
<ul>
|
|
25
|
-
<% for (var j = 0, jlen = friend.tags.length; j < jlen; j += 1) { %>
|
|
26
|
-
<% var tag = friend.tags[i]; %>
|
|
27
|
-
<li><%- tag %></li>
|
|
28
|
-
<% } %>
|
|
29
|
-
</ul>
|
|
30
|
-
</li>
|
|
31
|
-
<% } %>
|
|
32
|
-
<% if (friend.friends.length) { %>
|
|
33
|
-
<li>
|
|
34
|
-
Friends:
|
|
35
|
-
<ul>
|
|
36
|
-
<% for (var k = 0, klen = friend.friends.length; k < klen; k += 1) { %>
|
|
37
|
-
<% var fr = friend.friends[i] %>
|
|
38
|
-
<li><%- fr.name %> (<%- fr.id %>)</li>
|
|
39
|
-
<% } %>
|
|
40
|
-
</ul>
|
|
41
|
-
</li>
|
|
42
|
-
<% } %>
|
|
43
|
-
</ul>
|
|
44
|
-
</div>
|
|
45
|
-
<% } %>
|
|
46
|
-
</div>
|
|
47
|
-
</body>
|
|
48
|
-
</html>
|