-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbase.js
174 lines (156 loc) · 5.28 KB
/
base.js
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
;(w => {
// shortcuts to reduce minified size
let t = 'template'
let bindTemplate = (host, template, values) => {
let node = template.content.cloneNode(true)
let container = document.createElement('div')
container.appendChild(node)
renderData(container, values)
while (container.childNodes.length) {
host.appendChild(container.childNodes.item(0))
}
}
let parse = JSON.parse
let useGet = use => (url, options, cb) =>
typeof options == 'function'
? use(url, {}, options)
: use(url, options, cb)
let toForm = (event_or_form = event) =>
event_or_form instanceof HTMLFormElement
? event_or_form
: (event_or_form.preventDefault(), event_or_form.target)
let fetchJSON = method => (url, body) =>
fetch(url, {
method,
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(body),
})
w.renderData = (container, values) => {
let apply = (attr, f) => {
container.querySelectorAll(`[data-${attr}]`).forEach(e => {
let key = e.dataset[attr],
value = values[key],
t = e.tagName == 'TEMPLATE',
last = e
if (t && value && (attr == 'show' || attr == 'if')) value = [1]
if (!Array.isArray(value)) return f(e, value, key)
value.forEach(value => {
let node = (t ? e.content : e).cloneNode(true)
f(node, value, key)
value && typeof value == 'object' && renderData(node, value)
if (!t)
return last.insertAdjacentElement('afterend', node), last = node
for (let child of node.childNodes)
child.nodeType == Node.TEXT_NODE
? last.insertAdjacentText('afterend', child.textContent)
: (last.insertAdjacentElement('afterend', child), last = child)
})
e.remove()
})
}
apply('text', (e, v) => e.textContent = v)
apply('class', (e, v, k) => v == true ? e.classList.add(k) : v && e.classList.add(...v.split(' ')))
apply('show', (e, v) => e.hidden = !v)
apply('if', (e, v) => v || e.remove())
apply('readonly', (e, v) => e.readOnly = !!v)
for (let attr of ['open', 'checked', 'disabled', 'selected', 'hidden'])
apply(attr, (e, v) => e[attr] = !!v)
for (let attr of [
'id',
'title',
'href',
'src',
'alt',
'value',
'action',
'onsubmit',
'onclick',
])
apply(attr, (e, v) => v && (e[attr] = v))
}
w.renderTemplate = async (host, binds = {}) => {
let name = host.dataset.template
let values = binds[host.dataset.bind] || binds
let template
host.textContent = ''
if (name.endsWith('.html')) {
template = document.createElement(t)
getText(name, html => {
// deepcode ignore DOMXSS: the template is authored by the application developer, not from untrusted users
template.innerHTML = html
next()
})
} else {
template = document.querySelector(`${t}[data-name="${name}"]`)
template ? next() : console.error(t, `not found:`, name)
}
function next() {
Array.isArray(values)
? values.forEach(values => bindTemplate(host, template, values))
: bindTemplate(host, template, values)
}
}
w.scanTemplates = (root = document.body, binds = {}) =>
root
.querySelectorAll(`[data-${t}]`)
.forEach(host => renderTemplate(host, binds))
w.fillForm = (form, o) => {
let e
for (let k in o) (e = form[k]) && (e.value = o[k])
}
w.d2 = x => x < 10 ? '0' + x : x
w.toInputDate = date => {
let d = new Date(date)
return d.getFullYear() + '-' + d2(d.getMonth() + 1) + '-' + d2(d.getDate())
}
w.toInputTime = date => {
let d = new Date(date)
return d2(d.getHours()) + ':' + d2(d.getMinutes())
}
w.getText = useGet(async (url, options, cb) => {
let text = localStorage.getItem(url)
let p = fetch(url, options).then(res => res.text())
let cache = options && options.cache
let skipCache = cache && cache != 'force-cache'
p.then(newText => {
let diff = newText != text
;(skipCache || diff) && cb?.(newText)
diff && localStorage.setItem(url, newText)
})
return !skipCache && text ? (cb?.(text), text) : p
})
w.getJSON = useGet((url, options, cb) =>
getText(url, options, cb && (text => cb(parse(text)))).then(parse),
)
w.submitJSON = event_or_form => {
let form = toForm(event_or_form)
let body = {}
for (let input of form.elements)
if (input.name && (input.type != 'checkbox' || input.checked))
body[input.name] = input.value
return fetchJSON(form.method)(form.action, body)
}
w.submitForm = event_or_form => {
let form = toForm(event_or_form)
let body = new URLSearchParams(new FormData(form))
let { method, action } = form
return method == 'get'
? fetch(action + '?' + body)
: fetch(action, {
method,
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body,
})
}
w.uploadForm = event_or_form => {
let form = toForm(event_or_form)
return fetch(form.action, {
method: form.method,
body: new FormData(form),
})
}
w.postJSON = fetchJSON('POST')
w.patchJSON = fetchJSON('PATCH')
w.putJSON = fetchJSON('PUT')
w.del = url => fetch(url, { method:'DELETE' })
})(window)