1 |
|
2 |
|
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 | }()
|