UNPKG

6.4 kBJavaScriptView Raw
1
2/* litejs.com/MIT-LICENSE.txt */
3
4!function() {
5 var dummy = El("div")
6
7 El.bindings.schemaToForm = schemaToForm
8 schemaToForm.once = 1
9
10 function allOf(schema) {
11 return Array.isArray(schema.allOf) ?
12 schema.allOf.reduce(function(memo, item) {
13 return JSON.mergePatch(memo, item)
14 }, {}):
15 schema
16 }
17
18 function schemaToForm(form, schema, link, template, event) {
19 var scope = this
20 , model = scope.model || null
21
22 link = link || "self"
23
24 form.fill = function(model) {
25 View.blur()
26 form.fillForm(model)
27 }
28
29 xhr.getSchema(schema, function(err, schema) {
30 var i, selfHref, fieldset
31 , _link = schema
32
33 if (schema.links) for (i = 0; _link = schema.links[i++]; ) {
34 if (_link.rel == "self") {
35 selfHref = _link.href
36 }
37 if (_link.rel == link) {
38 schema = _link.schema || schema
39 break
40 }
41 }
42
43 form.fillForm = fillForm
44 function fillForm(model) {
45 if (fieldset) El.kill(fieldset)
46 fieldset = El(template + "-fieldset")
47 drawSchema(schema, null, fieldset, model && model.data || null, null, scope, model)
48 El.append(form, fieldset)
49 }
50
51 fillForm(model)
52
53 El.on(form, "submit", function() {
54 var data = El.val(this)
55 , _scope = Object.assign({}, scope.route, model && model.data)
56 , href = (_link.href || selfHref).format(_scope)
57 JSON.schemaApply(schema, data)
58
59 if (model) {
60 var changed = []
61 , clone = JSON.clone(model.data)
62 JSON.mergePatch(clone, data, changed)
63
64 if (changed.length) {
65 data = Item.copy({}, data, changed)
66 } else {
67 data = null
68 }
69 }
70
71 try { document.activeElement.blur() } catch(e) {}
72
73 if (data) View.emit(event || "makeReq", _link, href, data)
74 })
75
76 })
77
78 function drawSchema(schema, key, fieldset, data, namePrefix, scope, model, def) {
79 var alternatives, keys, i, root, tmp
80 , alSelected
81 , count = 0
82
83 schema = allOf(schema)
84
85 if (schema.properties || schema.anyOf) {
86 if (key !== null) {
87 namePrefix = namePrefix ? namePrefix + "[" + key + "]" : key
88 if (schema.title) {
89 El.append(fieldset, El.append(El(template + "-subheader"), schema.title))
90 }
91 }
92 }
93
94 if (schema.properties) {
95 Object.each(schema.properties, function(sub, _key) {
96 drawSchema(
97 sub,
98 _key,
99 fieldset,
100 data === null ? null : (sub.type == "object" || sub.properties || sub.anyOf ? data[_key] : data) || {},
101 namePrefix,
102 scope,
103 model,
104 def
105 )
106 })
107 if (!schema.anyOf) return
108 }
109
110 if (schema.anyOf) {
111 var title
112 schema = schema.anyOf.map(allOf)
113 key = []
114
115 alternatives = {}
116 keys = Object.keys(schema[0].properties)
117
118 for (i = 0; tmp = schema[i++]; ) {
119 keys = keys.filter(function(val) {
120 return tmp.properties[val] && tmp.properties[val]["enum"]
121 })
122 }
123
124 scope.selected = {}
125 for (i = 0; tmp = schema[i++]; ) {
126 root = El(".grid.b2.w12")
127 tmp = JSON.clone(tmp)
128 keys.each(function(val) {
129 title = title || tmp.properties[val].title
130 tmp.properties[val]["enum"].each(function(val) {
131 key.push(val)
132 alternatives[val] = root
133 })
134 delete tmp.properties[val]
135 })
136 root._draw = [tmp, null, root, data, namePrefix, scope, model]
137 }
138
139 schema = {
140 title: title,
141 "enum": key
142 }
143 key = keys[0]
144 }
145
146 var ro = model && model.acl && !model.acl("write", key) ? "-ro" : ""
147
148
149 var row = El(template + (
150 schema["ui:el"] && El.cache[template + "-" + schema["ui:el"]] ? "-" + schema["ui:el"] :
151 schema["enum"] ? "-enum" + ro :
152 schema.type == "boolean" ? "-boolean" + ro :
153 schema.type == "array" ? "-" + schema.type :
154 schema.resourceCollection ? "-list" + ro :
155 ro ))
156 , sc = El.scope(row, scope)
157 , val = data === null ? (def && def[key] || schema["default"]) : (key == null ? data : data[key])
158
159 sc.name = _(schema.title || key || "")
160 sc.value = val
161 sc.add = function(e) { add() }
162 sc.del = del
163 if (ro !== "") sc.noAdd = true
164
165 Object.assign(sc, schema)
166
167 if (schema.type == "array") {
168 var content = El.find(row, ".js-items")
169 , hidden = El("input[type=hidden]")
170
171 El.append(content, hidden)
172
173 key = namePrefix ? namePrefix + "[" + key + "]" : key
174
175 El.attr(hidden, "name", key)
176
177 if (Array.isArray(schema.items)) {
178 sc.noAdd = true
179 schema.items.each(function(item, i) {
180 add(val && val[i], item)
181 })
182 } else if (schema.resourceCollection) {
183 api(schema.resourceCollection.format(scope.route, scope)).each(add2)
184 } else if (Array.isArray(val) && val.length) {
185 val.each(function(v) { add(v) })
186 } else if (schema.minItems) {
187 for (i = schema.minItems; i--; ) {
188 add()
189 }
190 }
191 El.render(row, sc)
192 El.append(fieldset, row)
193 return
194 }
195 El.render(row, sc)
196 El.append(fieldset, row)
197
198 function add2(val, i) {
199 var map = {}
200 map[i] = sc.value && sc.value.indexOf(val.data.id) != -1 || null
201
202 drawSchema(
203 { type: "boolean", title: val.data.name },
204 "" + i,
205 content,
206 data && map || null,
207 key,
208 scope,
209 model
210 )
211 }
212
213 function add(val, itemSchema) {
214 var root = El(template + "-array-item")
215 , rootScope = El.scope(root, sc)
216 El.append(content, root)
217 El.render(root, rootScope)
218
219 root = El.find(root, ".js-item") || root
220
221 drawSchema(
222 itemSchema || schema.items,
223 null,
224 root,
225 data && val || null,
226 key + "[" + (count++) + "]",
227 scope,
228 model,
229 val
230 )
231 }
232
233 var field = El.find(row, ".field")
234 if (field) El.attr(field, "name", namePrefix && key ? namePrefix + "[" + key + "]" : namePrefix || key)
235
236 if (val !== void 0 && field) {
237 El.val(field, val)
238 }
239
240 if (schema.readonly) {
241 field.disabled = true
242 }
243
244 if (alternatives) {
245 El.on(field, "change", alUp)
246 alUp()
247 }
248
249 function alUp() {
250 var val = El.val(field)
251 scope["selected"][key] = val
252 if (alSelected != alternatives[val]) {
253 if (alSelected) {
254 El.append(dummy, alSelected)
255 }
256 alSelected = alternatives[val]
257 if (alSelected._draw) {
258 drawSchema.apply(null, alSelected._draw)
259 alSelected._draw = null
260 }
261 El.append(fieldset, (alSelected = alternatives[val]), row.nextSibling)
262 } else {
263 El.render(alSelected, scope)
264 }
265 }
266 }
267 }
268
269 function del() {
270 El.kill(El.closest(this, ".js-del"))
271 }
272}()