-
Notifications
You must be signed in to change notification settings - Fork 0
/
mustache.ts
126 lines (119 loc) · 3.31 KB
/
mustache.ts
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
import { DefaultState } from "./utils/state"
import Mustache from "mustache"
export { defaultMustacheTemplate } from "./defaults/_generated"
type Options = {
/**
* Mustache helpers to extend template functionality.
*/
helpers?: object
}
/**
* Render a Mustache template into a container
*
* @param template Mustache template
* @param options Options object.
* @returns Render function
* @group Autocomplete
* @category Mustache
/**
* @example
* ```js
* import { fromMustacheTemplate } from "@nosto/autocomplete/mustache";
*
* const render = fromMustacheTemplate(`
* <div>
* <h1>{{title}}</h1>
* <ul>
* {{#products}}
* <li>{{name}}</li>
* {{/products}}
* </ul>
* </div>
* `, {
* helpers: {
* toJson: function () {
* return JSON.stringify(this)
* }});
*
* render(document.getElementById("container"), {
* title: "My Title",
* products: [
* { name: "Product 1" },
* { name: "Product 2" },
* { name: "Product 3" }
* ]
* });
* ```
*/
export function fromMustacheTemplate<State extends object = DefaultState>(
template: string,
options?: Options
) {
if (Mustache === undefined) {
throw new Error(
"Mustache is not defined. Please include the Mustache dependency or library in your page."
)
}
const { helpers } = options || {}
return (container: HTMLElement, state: State) => {
container.innerHTML = Mustache.render(template, {
...state,
imagePlaceholder: "https://cdn.nosto.com/nosto/9/mock",
toJson: function () {
return JSON.stringify(this)
},
showListPrice: function () {
return this.listPrice !== this.price
},
...helpers,
})
return Promise.resolve(undefined)
}
}
/**
* Load a remote Mustache template and render it into a container
*
* @param url Remote Mustache template URL
* @returns Render function
* @group Autocomplete
* @category Mustache
* @example
* ```js
* import { fromRemoteMustacheTemplate } from "@nosto/autocomplete/mustache";
*
* const render = fromRemoteMustacheTemplate("https://example.com/template.mustache");
* ```
*/
export function fromRemoteMustacheTemplate<State extends object = DefaultState>(
url: string,
options?: {
helpers?: object
}
): (container: HTMLElement, state: State) => PromiseLike<void> {
return (container, state) => {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
xhr.open("GET", url)
xhr.onload = async () => {
if (xhr.status === 200) {
await fromMustacheTemplate(xhr.responseText, options)(container, state)
resolve(undefined)
} else {
reject(
new Error(
`Failed to fetch remote mustache template: ${xhr.statusText}`
)
)
}
}
xhr.onerror = () => {
reject(
new Error(
`Failed to fetch remote mustache template: ${xhr.statusText}`
)
)
}
xhr.send()
})
}
}