polymer-rails-forms 0.2.01 → 0.3.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.
- checksums.yaml +4 -4
- data/assets/rails-forms/rails-form-helpers.html +295 -422
- data/assets/rails-forms/rails-form-validators.html +24 -18
- data/assets/rails-forms/rails-form.html +533 -186
- metadata +4 -3
@@ -1,5 +1,6 @@
|
|
1
1
|
<link rel="import" href="rails-form-helpers.html" >
|
2
2
|
<link rel="import" href="rails-form-validators.html" >
|
3
|
+
<link rel="import" href="rails-form-autocomplete.html" >
|
3
4
|
<link rel="import" href="gc-paper-decorator.html" >
|
4
5
|
<link rel="import" href="form-spinner.html" >
|
5
6
|
<link rel="import" href="../paper-button/paper-button.html" >
|
@@ -8,70 +9,112 @@
|
|
8
9
|
|
9
10
|
<script src='pikaday.js'></script>
|
10
11
|
|
12
|
+
<style>
|
13
|
+
/*
|
14
|
+
these are attached to the body if scrollTarget is set, so they need to be outside of the shadowDOM
|
15
|
+
*/
|
16
|
+
.pseudo-select {
|
17
|
+
opacity: 1;
|
18
|
+
display: block;
|
19
|
+
transition: opacity 250ms ease-out;
|
20
|
+
position: absolute;
|
21
|
+
top: 100%;
|
22
|
+
width: 106%;
|
23
|
+
background-color: white;
|
24
|
+
box-shadow: -2px 1px 10px #888;
|
25
|
+
z-index: 1;
|
26
|
+
margin-top: -10px;
|
27
|
+
}
|
28
|
+
|
29
|
+
.pseudo-select > div {
|
30
|
+
min-height: 2em;
|
31
|
+
border-bottom: solid 1px;
|
32
|
+
padding: 5px 3%;
|
33
|
+
position: relative;
|
34
|
+
}
|
35
|
+
|
36
|
+
.pseudo-select > div:hover {
|
37
|
+
background-color: #D5DAFF;
|
38
|
+
}
|
39
|
+
|
40
|
+
.pseudo-select > div paper-checkbox {
|
41
|
+
float: left;
|
42
|
+
margin-right: 15px;
|
43
|
+
}
|
44
|
+
</style>
|
45
|
+
|
11
46
|
<polymer-element name="rails-form">
|
12
47
|
<template>
|
13
48
|
<link rel='stylesheet' href='pikaday.css'>
|
14
49
|
<style>
|
15
|
-
|
16
|
-
display:
|
50
|
+
#inputs-wrapper {
|
51
|
+
display: flex;
|
52
|
+
flex-wrap: wrap;
|
53
|
+
flex-direction: row;
|
54
|
+
position: relative;
|
17
55
|
}
|
18
|
-
|
19
|
-
|
56
|
+
|
57
|
+
.input, .nest, .list-group, .group, .step{
|
58
|
+
flex: 1;
|
59
|
+
min-width: 100%;
|
60
|
+
max-width: 0;
|
61
|
+
position: relative;
|
62
|
+
display: inline-block;
|
63
|
+
box-sizing: border-box;
|
64
|
+
margin-bottom: 0px;
|
20
65
|
}
|
21
66
|
|
22
|
-
|
23
|
-
|
24
|
-
color: #5bc0de;
|
67
|
+
.input {
|
68
|
+
padding: 0px 10px;
|
25
69
|
}
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
margin-bottom: 5px;
|
30
|
-
padding-left: 30px;
|
31
|
-
padding-right: 30px;
|
32
|
-
background-color: #5bc0de;
|
33
|
-
border-color: #46b8da;
|
34
|
-
color: white;
|
35
|
-
clear: both;
|
36
|
-
margin-right: 15px;
|
70
|
+
|
71
|
+
.input.json {
|
72
|
+
padding: 0px;
|
37
73
|
}
|
38
74
|
|
39
|
-
|
75
|
+
.input.json .json-wrapper > textarea {
|
40
76
|
display: none;
|
41
77
|
}
|
42
78
|
|
43
|
-
|
44
|
-
display:
|
79
|
+
.nest {
|
80
|
+
display: flex;
|
81
|
+
flex-wrap: wrap;
|
45
82
|
}
|
46
83
|
|
47
|
-
|
48
|
-
|
84
|
+
.step:last-of-type {
|
85
|
+
margin-bottom: -60px; /* To suck the submit buttom up */
|
49
86
|
}
|
50
87
|
|
51
|
-
gc-input-decorator {
|
52
|
-
|
88
|
+
gc-input-decorator.invalid /deep/ .error {
|
89
|
+
display: none !important;
|
53
90
|
}
|
54
91
|
|
55
|
-
|
56
|
-
|
92
|
+
/* File upload CSS */
|
93
|
+
.btn-file-upload input[type=file] {
|
94
|
+
position: absolute;
|
95
|
+
top: 0;
|
96
|
+
left: 0;
|
97
|
+
width: 100%;
|
98
|
+
height: 100%;
|
99
|
+
font-size: 999px;
|
100
|
+
text-align: right;
|
101
|
+
filter: alpha(opacity=0);
|
102
|
+
opacity: 0;
|
103
|
+
outline: none;
|
104
|
+
background: white;
|
105
|
+
cursor: pointer;
|
106
|
+
display: block;
|
107
|
+
z-index: 1;
|
57
108
|
}
|
58
109
|
|
59
|
-
.btn-
|
110
|
+
.btn-file-upload {
|
60
111
|
position: relative;
|
61
112
|
overflow: hidden;
|
62
|
-
width: 100%;
|
63
|
-
height: 59px;
|
64
|
-
display: table;
|
65
|
-
}
|
66
|
-
|
67
|
-
.btn-image-upload core-icon {
|
68
|
-
height: 105px;
|
69
|
-
width: 105px;
|
70
|
-
margin: 0 auto;
|
71
113
|
display: block;
|
72
|
-
|
114
|
+
|
73
115
|
}
|
74
116
|
|
117
|
+
/* Image upload CSS */
|
75
118
|
.btn-image-upload input[type=file] {
|
76
119
|
position: absolute;
|
77
120
|
top: 0;
|
@@ -84,78 +127,78 @@
|
|
84
127
|
opacity: 0;
|
85
128
|
outline: none;
|
86
129
|
background: white;
|
87
|
-
cursor:
|
130
|
+
cursor: pointer;
|
88
131
|
display: block;
|
132
|
+
z-index: 1;
|
89
133
|
}
|
90
134
|
|
91
|
-
.
|
92
|
-
|
93
|
-
|
135
|
+
.btn-image-upload {
|
136
|
+
position: relative;
|
137
|
+
overflow: hidden;
|
94
138
|
display: block;
|
95
|
-
|
96
|
-
|
139
|
+
font-size: 1000%;
|
140
|
+
width: 1.5em;
|
141
|
+
height: 1em;
|
142
|
+
text-align: center;
|
143
|
+
margin: 0px auto;
|
144
|
+
background-size: contain;
|
145
|
+
background-repeat: no-repeat;
|
146
|
+
background-position: center;
|
97
147
|
}
|
98
148
|
|
99
|
-
.
|
149
|
+
.btn-image-upload core-icon {
|
150
|
+
height: 100%;
|
100
151
|
width: 100%;
|
152
|
+
margin: 0 auto;
|
153
|
+
display: block;
|
154
|
+
color: #666;
|
155
|
+
font-size: 10%;
|
101
156
|
}
|
102
157
|
|
103
|
-
.
|
104
|
-
|
105
|
-
display: flex;
|
106
|
-
flex-direction: row;
|
158
|
+
.has-image .btn-image-upload core-icon {
|
159
|
+
display: none;
|
107
160
|
}
|
108
161
|
|
109
|
-
.
|
110
|
-
|
111
|
-
cursor: pointer;
|
162
|
+
.has-image .btn-image-upload p {
|
163
|
+
display: none;
|
112
164
|
}
|
113
165
|
|
114
|
-
.
|
115
|
-
|
116
|
-
|
117
|
-
padding-top: 10px;
|
118
|
-
min-height: 55px;
|
166
|
+
.btn-image-upload div {
|
167
|
+
height: 75%;
|
168
|
+
width: 100%;
|
119
169
|
}
|
120
170
|
|
121
|
-
.
|
122
|
-
|
123
|
-
margin: 0px;
|
171
|
+
.btn-image-upload p {
|
172
|
+
font-size: 10%;
|
173
|
+
margin-top: 0px;
|
124
174
|
}
|
125
175
|
|
126
|
-
|
127
|
-
|
128
|
-
|
176
|
+
/* Lists */
|
177
|
+
|
178
|
+
.list-group > .list-form {
|
179
|
+
display: none;
|
129
180
|
}
|
130
181
|
|
131
|
-
.list-
|
132
|
-
|
133
|
-
position: relative;
|
134
|
-
float: right;
|
135
|
-
box-sizing: border-box;
|
136
|
-
width: 72%;
|
137
|
-
max-height: 81px;
|
182
|
+
.list-group > .list-item {
|
183
|
+
display: block;
|
138
184
|
}
|
139
185
|
|
140
|
-
.list-
|
141
|
-
|
142
|
-
float: left;
|
143
|
-
box-sizing: border-box;
|
144
|
-
width: 25%;
|
145
|
-
margin: 0;
|
146
|
-
font-weight: 500;
|
147
|
-
font-size: 14px;
|
186
|
+
.list-group.focused .list-item, .list-group.is-invalid .list-item, .list-group.is-blank > .list-item {
|
187
|
+
display: none;
|
148
188
|
}
|
149
189
|
|
150
|
-
.list-group .list-
|
190
|
+
.list-group.focused .list-form, .list-group.is-invalid .list-form, .list-group.is-blank > .list-form {
|
151
191
|
display: block;
|
152
|
-
|
153
|
-
margin: 0;
|
154
|
-
padding: 0 15px;
|
155
|
-
box-sizing: border-box;
|
192
|
+
overflow: hidden;
|
156
193
|
}
|
157
194
|
|
158
|
-
.list-group .list-item
|
195
|
+
.list-group .list-item-display {
|
196
|
+
display: flex;
|
197
|
+
border-bottom: solid 1px;
|
198
|
+
margin-bottom: 5px;
|
199
|
+
}
|
200
|
+
|
201
|
+
.list-group .list-item-display > core-icon {
|
159
202
|
height: 0px;
|
160
203
|
border: solid 1px #A1A1A1;
|
161
204
|
padding: 7px;
|
@@ -163,25 +206,68 @@
|
|
163
206
|
border-radius: 8px;
|
164
207
|
color: red;
|
165
208
|
margin-right: 10px;
|
209
|
+
cursor: pointer;
|
166
210
|
}
|
167
211
|
|
168
|
-
.list-group .list-
|
169
|
-
|
212
|
+
.list-group .list-item-display > div {
|
213
|
+
cursor: pointer;
|
214
|
+
flex: 1;
|
170
215
|
}
|
171
216
|
|
172
|
-
.
|
173
|
-
|
217
|
+
.nest.addable {
|
218
|
+
padding-left: 25%;
|
174
219
|
}
|
175
220
|
|
176
|
-
.
|
177
|
-
|
178
|
-
|
221
|
+
.nest.addable .add-button {
|
222
|
+
flex: 1;
|
223
|
+
min-width: 25%;
|
224
|
+
max-width: 25%;
|
225
|
+
margin: 0;
|
226
|
+
padding: 0px 1em 0px 0em;
|
227
|
+
box-sizing: border-box;
|
228
|
+
min-height: 4em;
|
229
|
+
margin-left: -25%;
|
230
|
+
}
|
231
|
+
|
232
|
+
.nest.addable .add-button core-icon {
|
233
|
+
min-width: 2em;
|
234
|
+
min-height: 2em;
|
235
|
+
|
236
|
+
margin-left: -2.5em;
|
237
|
+
display: inline-block;
|
238
|
+
position: absolute;
|
239
|
+
left: 0;
|
240
|
+
color: #5bc0de;
|
241
|
+
}
|
242
|
+
|
243
|
+
.nest.addable .add-button div {
|
244
|
+
display: inline-block;
|
245
|
+
}
|
246
|
+
|
247
|
+
.list-group .list-form .list-group .list-item {
|
248
|
+
min-width: 100%;
|
249
|
+
}
|
250
|
+
|
251
|
+
.addable .list-form, .addable .list-item {
|
252
|
+
min-width: 100%;
|
253
|
+
}
|
254
|
+
|
255
|
+
.list-group .list-form {
|
256
|
+
|
179
257
|
}
|
180
258
|
|
259
|
+
.list-group .list-item {
|
260
|
+
padding: 10px;
|
261
|
+
box-sizing: border-box;
|
262
|
+
}
|
263
|
+
|
264
|
+
|
265
|
+
/* Checkboxes */
|
181
266
|
paper-checkbox input[type=checkbox] {
|
182
267
|
display: none;
|
183
268
|
}
|
184
269
|
|
270
|
+
/* Selects */
|
185
271
|
.select-wrapper {
|
186
272
|
position: relative;
|
187
273
|
}
|
@@ -218,6 +304,13 @@
|
|
218
304
|
height: 35px;
|
219
305
|
}
|
220
306
|
|
307
|
+
/* Firefox fix */
|
308
|
+
.select-wrapper .select-icon svg {
|
309
|
+
width: 35px;
|
310
|
+
right: 0;
|
311
|
+
left: auto;
|
312
|
+
}
|
313
|
+
|
221
314
|
.select-wrapper .pseudo-select > div {
|
222
315
|
min-height: 2em;
|
223
316
|
border-bottom: solid 1px;
|
@@ -234,88 +327,103 @@
|
|
234
327
|
margin-right: 15px;
|
235
328
|
}
|
236
329
|
|
330
|
+
.input.id {
|
331
|
+
display: none;
|
332
|
+
}
|
333
|
+
|
334
|
+
/* Autocomplete */
|
335
|
+
|
336
|
+
.autocomplete-selector {
|
337
|
+
position: absolute;
|
338
|
+
background-color: white;
|
339
|
+
box-shadow: -2px 1px 10px #888;
|
340
|
+
z-index: 1;
|
341
|
+
padding: 5px;
|
342
|
+
border: solid 1px #888;
|
343
|
+
box-sizing: border-box;
|
344
|
+
margin-top: -11px;
|
345
|
+
}
|
346
|
+
|
347
|
+
.autocomplete-selector .autocomplete-list-item {
|
348
|
+
border-bottom: solid 1px #ccc;
|
349
|
+
margin-top: 5px;
|
350
|
+
padding: 0px 10px 0px 0px;
|
351
|
+
}
|
352
|
+
|
353
|
+
.autocomplete-selector .autocomplete-list-item:last-of-type {
|
354
|
+
border-bottom: 0px;
|
355
|
+
}
|
356
|
+
|
357
|
+
.autocomplete-selector .autocomplete-list-item.core-selected {
|
358
|
+
background-color: #D5DAFF;
|
359
|
+
}
|
360
|
+
|
361
|
+
.autocomplete-selector .autocomplete-list-item:hover {
|
362
|
+
background-color: #D5DAFF;
|
363
|
+
}
|
364
|
+
|
365
|
+
/* Submit Button */
|
366
|
+
|
367
|
+
#submit-button, .step .next-button, .step .back-button {
|
368
|
+
margin-top: 15px;
|
369
|
+
margin-bottom: 5px;
|
370
|
+
padding-left: 30px;
|
371
|
+
padding-right: 30px;
|
372
|
+
background-color: #5bc0de;
|
373
|
+
border-color: #46b8da;
|
374
|
+
color: white;
|
375
|
+
clear: both;
|
376
|
+
margin-right: 15px;
|
377
|
+
}
|
378
|
+
|
379
|
+
.stepped .step .back-button {
|
380
|
+
display: none;
|
381
|
+
}
|
382
|
+
|
383
|
+
.stepped .step ~ .step .back-button {
|
384
|
+
display: inline-block;
|
385
|
+
}
|
386
|
+
|
387
|
+
.stepped #submit-button, .stepped .next-button {
|
388
|
+
float: right;
|
389
|
+
clear: inherit;
|
390
|
+
}
|
391
|
+
|
392
|
+
.stepped .back-button {
|
393
|
+
float: left;
|
394
|
+
}
|
395
|
+
|
396
|
+
#submit-button.in-transit span{
|
397
|
+
display: none;
|
398
|
+
}
|
399
|
+
|
400
|
+
#submit-button.in-transit form-spinner {
|
401
|
+
display: block;
|
402
|
+
}
|
403
|
+
|
404
|
+
#submit-button form-spinner {
|
405
|
+
display: none;
|
406
|
+
}
|
237
407
|
</style>
|
238
408
|
<!-- TODO: structures should be arrays to preserve order -->
|
239
409
|
<form id="rails_form" _action="{{ action }}" method="{{ method }}" enctype="multipart/form-data">
|
240
|
-
<
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
<template if="{{ structure[key] | isNest }}">
|
245
|
-
<template if="{{ structure[key].allowAdd }}">
|
246
|
-
<paper-button class='{{ key | scopeToClass }}' on-click="{{ addItem }}"><core-icon icon="add-circle-outline"></core-icon>{{ structure[key].label }}</paper-button>
|
247
|
-
</template>
|
248
|
-
<template if="{{ structure[key] | isMultiple }}">
|
249
|
-
<template if="{{ !structure[key].allowAdd }}">
|
250
|
-
<template repeat="{{ item in data | scopeNestData(key) | enumerate }}">
|
251
|
-
<template ref="form-group" bind="{{ structure[key].structure as structure }}" parentContext="{{ key | updateParentContext }}" scope="{{ scope | updateScope(key) | addIndex(item) }}" data="{{ data | scopeDataToIndex(item) }}"></template>
|
252
|
-
</template>
|
253
|
-
</template>
|
254
|
-
|
255
|
-
<template if='{{ structure[key].allowAdd }}'>
|
256
|
-
<template bind="{{ data as data }}">
|
257
|
-
<div class='list'>
|
258
|
-
<template repeat="{{ item in data | scopeNestData(key) | enumerate }}">
|
259
|
-
<div class='list-group {{ item | isEmpty }}'>
|
260
|
-
<div class='list-item {{ item | listItemClassName }}'>
|
261
|
-
{{ item | createListItem }}
|
262
|
-
</div>
|
263
|
-
<div class='list-form {{ item | listItemClassName }}'>
|
264
|
-
<template ref="form-group" bind="{{ structure[key].structure as structure }}" parentContext="{{ key | updateParentContext }}" scope="{{ scope | updateScope(key) | addIndex(item) }}" data="{{ data | scopeDataToIndex(item) }}"></template>
|
265
|
-
</div>
|
266
|
-
</div>
|
267
|
-
</template>
|
268
|
-
</div>
|
269
|
-
</template>
|
270
|
-
</template>
|
271
|
-
</template>
|
272
|
-
|
273
|
-
<template if="{{ structure[key] | isNotMultiple }}">
|
274
|
-
<template bind="{{ context as context }}">
|
275
|
-
<template ref="form-group" bind="{{ structure[key].structure as structure }}" parentContext="{{ key | updateParentContext }}" scope="{{ scope | updateScope(key) }}" data="{{ data | scopeNestData(key) }}"></template>
|
276
|
-
</template>
|
277
|
-
</template>
|
278
|
-
</template>
|
279
|
-
|
280
|
-
<template if="{{ structure[key] | isField }}">
|
281
|
-
<template bind="{{ data as data }}">
|
282
|
-
<div class="input {{ key | scopeToClass }}" scope="{{ data | scopeFieldData(key) }}">
|
283
|
-
{{ structure[key] | createInput }}
|
284
|
-
</div>
|
285
|
-
</template>
|
286
|
-
</template>
|
287
|
-
</div>
|
288
|
-
</template>
|
289
|
-
</template>
|
290
|
-
</template>
|
410
|
+
<div id='inputs-wrapper'>
|
411
|
+
|
412
|
+
</div>
|
413
|
+
|
291
414
|
<div class='sumbit-button-wrapper'>
|
292
415
|
<paper-button id='submit-button' raised>
|
293
416
|
<span class='submit-text'>{{ submitText }}</span>
|
294
|
-
<form-spinner height="1.5" width="1.5"></form-spinner>
|
417
|
+
<form-spinner height="1.5" width="1.5" unit='em'></form-spinner>
|
295
418
|
</paper-button>
|
296
|
-
<!-- <paper-button id='test-button' raised>Test</paper-button> -->
|
297
419
|
<template if="{{ xhr }}">
|
298
420
|
<core-xhr id='xhr'></core-xhr>
|
299
421
|
</template>
|
300
|
-
</div>
|
422
|
+
</div>
|
423
|
+
|
301
424
|
</form>
|
302
425
|
</template>
|
303
426
|
<script>
|
304
|
-
/*
|
305
|
-
Default Structure Item: {
|
306
|
-
type: "string",
|
307
|
-
label: "",
|
308
|
-
options: {
|
309
|
-
floatingLabel: true,
|
310
|
-
unscoped: false,
|
311
|
-
events: {}
|
312
|
-
},
|
313
|
-
attributes: {
|
314
|
-
|
315
|
-
}
|
316
|
-
}
|
317
|
-
*/
|
318
|
-
|
319
427
|
Polymer( Polymer.mixin ({
|
320
428
|
publish: {
|
321
429
|
scope: "",
|
@@ -328,21 +436,17 @@
|
|
328
436
|
unscopedData: null
|
329
437
|
},
|
330
438
|
|
331
|
-
|
332
|
-
parentStructure: null,
|
333
|
-
parentData: null,
|
334
|
-
|
439
|
+
jsonData: null,
|
335
440
|
inTransit: false,
|
336
|
-
|
337
|
-
toArray: function(str){
|
338
|
-
return [str];
|
339
|
-
},
|
441
|
+
steps: null,
|
340
442
|
|
341
443
|
created: function(){
|
342
|
-
this.structure =
|
444
|
+
this.structure = [];
|
343
445
|
this.inputList = [];
|
344
|
-
this.indexStore = {};
|
345
446
|
|
447
|
+
this.errors = {};
|
448
|
+
this.validatedInputs = {};
|
449
|
+
|
346
450
|
var data = this.data === null ? {} : this.data;
|
347
451
|
if (!!this.scope && this.scope.replace(/\s/g, "").length > 0){
|
348
452
|
if (data[this.scope] === void(0)) data[this.scope] = {};
|
@@ -352,17 +456,14 @@
|
|
352
456
|
}
|
353
457
|
|
354
458
|
this.unscopedData = data;
|
355
|
-
this.
|
356
|
-
},
|
357
|
-
|
358
|
-
handleXhrCallback: function(){
|
359
|
-
|
459
|
+
this.jsonData = {};
|
360
460
|
},
|
361
461
|
|
362
462
|
domReady: function(){
|
463
|
+
this.buildForm();
|
464
|
+
|
363
465
|
var form = this.shadowRoot.querySelector("form"),
|
364
|
-
button = this.shadowRoot.querySelector("#submit-button")
|
365
|
-
test = this.shadowRoot.querySelector("#test-button");
|
466
|
+
button = this.shadowRoot.querySelector("#submit-button");
|
366
467
|
|
367
468
|
var callback = function(resp){
|
368
469
|
this.inTransit = false;
|
@@ -372,6 +473,7 @@
|
|
372
473
|
button.addEventListener("click", function(e){
|
373
474
|
// console.log(this.action, this.unscopedData);
|
374
475
|
// return;
|
476
|
+
|
375
477
|
if (this.inTransit) return;
|
376
478
|
if (this.isFormInvalid()) return;
|
377
479
|
|
@@ -401,12 +503,6 @@
|
|
401
503
|
}
|
402
504
|
}.bind(this), false)
|
403
505
|
|
404
|
-
this.appendInputs();
|
405
|
-
var inputObserver = new ArrayObserver(this.inputList);
|
406
|
-
inputObserver.open(function(splices){
|
407
|
-
this.appendInputs();
|
408
|
-
}.bind(this))
|
409
|
-
|
410
506
|
form.addEventListener("change", function(e){
|
411
507
|
var group = this.findParent(e.target, ".list-group")
|
412
508
|
if (!!group){
|
@@ -427,9 +523,260 @@
|
|
427
523
|
|
428
524
|
},
|
429
525
|
|
430
|
-
|
431
|
-
|
526
|
+
handleXhrCallback: function(){
|
527
|
+
|
528
|
+
},
|
529
|
+
|
530
|
+
buildForm: function(){
|
531
|
+
var wrapper = this.shadowRoot.querySelector("#inputs-wrapper"),
|
532
|
+
self = this;
|
533
|
+
|
534
|
+
if (!Array.isArray(this.structure)) return;
|
535
|
+
|
536
|
+
this.buildStructure(this.structure, this.data, wrapper, this.scope);
|
537
|
+
|
538
|
+
this.steps = wrapper.querySelectorAll(".step.form-step");
|
539
|
+
if (this.steps.length > 0){
|
540
|
+
this.addClass(this.shadowRoot.querySelector("form"), "stepped");
|
541
|
+
this.showStep(0);
|
542
|
+
|
543
|
+
this.steps[this.steps.length - 1].querySelector(".next-button").style.display = 'none';
|
544
|
+
}
|
545
|
+
},
|
546
|
+
|
547
|
+
currentStep: 0,
|
548
|
+
showStep: function(index){
|
549
|
+
for (var i=0; i<this.steps.length; i++){
|
550
|
+
if (i === index){
|
551
|
+
this.steps[i].style.display = "";
|
552
|
+
} else {
|
553
|
+
this.steps[i].style.display = "none";
|
554
|
+
}
|
555
|
+
}
|
556
|
+
|
557
|
+
if (index === this.steps.length - 1){
|
558
|
+
this.shadowRoot.querySelector("#submit-button").style.display = "";
|
559
|
+
} else {
|
560
|
+
this.shadowRoot.querySelector("#submit-button").style.display = "none";
|
561
|
+
}
|
562
|
+
},
|
563
|
+
|
564
|
+
nextStep: function(){
|
565
|
+
if (this.currentStep < this.steps.length - 1){
|
566
|
+
this.currentStep += 1;
|
567
|
+
this.showStep(this.currentStep);
|
568
|
+
}
|
569
|
+
},
|
570
|
+
|
571
|
+
previousStep: function(){
|
572
|
+
if (this.currentStep > 0){
|
573
|
+
this.currentStep -= 1;
|
574
|
+
this.showStep(this.currentStep);
|
575
|
+
}
|
576
|
+
},
|
577
|
+
|
578
|
+
updateStructureDOM: function(splices, structure, data, wrapper, scope, dom, domKeys){
|
579
|
+
var self = this;
|
580
|
+
|
581
|
+
for (var i=0; i<splices.length; i++){
|
582
|
+
/* delete removed children */
|
583
|
+
for (var j=0; j<splices[i].removed.length; j++){
|
584
|
+
var key = splices[i].removed[j].key,
|
585
|
+
element = domKeys[key];
|
586
|
+
|
587
|
+
element.parentNode.removeChild(element),
|
588
|
+
dom.splice(dom.indexOf(element), 1);
|
589
|
+
|
590
|
+
delete dom[key];
|
591
|
+
delete data[key];
|
592
|
+
}
|
593
|
+
|
594
|
+
/* add new children */
|
595
|
+
for (var j=0; j<splices[i].addedCount; j++){
|
596
|
+
var index = splices[i].index + j,
|
597
|
+
previousElement = dom[index -1],
|
598
|
+
field = self.createField(structure[index], data, scope);
|
599
|
+
|
600
|
+
if (!!previousElement){
|
601
|
+
wrapper.appendChild(field);
|
602
|
+
} else {
|
603
|
+
previousElement.parentNode.insertBefore(field, previousElement.nextSibling);
|
604
|
+
}
|
605
|
+
|
606
|
+
dom.push(field);
|
607
|
+
domKeys[structure[index].key] = field;
|
608
|
+
}
|
609
|
+
}
|
610
|
+
},
|
611
|
+
|
612
|
+
buildStructure: function(structure, data, wrapper, scope){
|
613
|
+
/* handling DOM insertion and removal */
|
614
|
+
var dom = [],
|
615
|
+
domKeys = {},
|
616
|
+
self = this;
|
617
|
+
|
618
|
+
new ArrayObserver(structure).open(function(splices){
|
619
|
+
self.updateStructureDOM(splices, structure, data, wrapper, scope, dom, domKeys);
|
620
|
+
self.fire("structure-changed", { ref: this });
|
621
|
+
});
|
622
|
+
|
623
|
+
/* actually building the form */
|
624
|
+
for (var i=0; i<structure.length; i++){
|
625
|
+
var field = self.createField(structure[i], data, scope)
|
626
|
+
wrapper.appendChild(field);
|
627
|
+
|
628
|
+
dom.push(field);
|
629
|
+
domKeys[structure[i].key] = field;
|
630
|
+
|
631
|
+
if ((structure[i].type === "nest") && structure[i].multiple){
|
632
|
+
var watched_data = !!structure[i].unscoped ? this.unscopedData[structure[i].key] : data[structure[i].key];
|
633
|
+
new ArrayObserver(watched_data).open( (function(s, f){
|
634
|
+
return function(splices){
|
635
|
+
var nField = self.createField(s, data, scope);
|
636
|
+
f.parentNode.insertBefore(nField, f);
|
637
|
+
f.parentNode.removeChild(f);
|
638
|
+
f = nField;
|
639
|
+
|
640
|
+
self.fire("data-inserted", {ref: this});
|
641
|
+
};
|
642
|
+
})(structure[i], field) );
|
643
|
+
}
|
644
|
+
}
|
645
|
+
|
646
|
+
return wrapper;
|
647
|
+
},
|
648
|
+
|
649
|
+
createField: function(structure, data, scope){
|
650
|
+
var key = structure.key,
|
651
|
+
self = this;
|
652
|
+
|
653
|
+
if (structure.type === "group"){
|
654
|
+
var wrap = this.createWithAttributes("div", {"class": ["group", structure.key, structure.additionalClasses].join(" ")}),
|
655
|
+
contents = this.buildStructure(structure.structure, data, wrap, scope);
|
656
|
+
|
657
|
+
return wrap;
|
658
|
+
} else if (structure.type === "step") {
|
659
|
+
var wrap = this.createWithAttributes("div", {"class": ["step form-step", structure.key, structure.additionalClasses].join(" ")}),
|
660
|
+
next_button = this.createWithAttributes("paper-button", { "class": "next-button", text: (structure.nextText || "Next"), raised: true }),
|
661
|
+
back_button = this.createWithAttributes("paper-button", { "class": "back-button", text: (structure.backText || "Back"), raised: true }),
|
662
|
+
contents = this.buildStructure(structure.structure, data, wrap, scope);
|
663
|
+
|
664
|
+
next_button.addEventListener("click", function(){ this.nextStep(); }.bind(this), false);
|
665
|
+
back_button.addEventListener("click", function(){ this.previousStep(); }.bind(this), false);
|
666
|
+
|
667
|
+
wrap.appendChild(back_button);
|
668
|
+
wrap.appendChild(next_button);
|
669
|
+
|
670
|
+
return wrap;
|
671
|
+
} else if (structure.type === "nest"){
|
672
|
+
var wrap = self.createWithAttributes("div", {"class": "nest " + key}),
|
673
|
+
nested_data = self.scopeNestData(structure, key, data),
|
674
|
+
nested_scope = self.updateScope(structure, key, scope);
|
675
|
+
|
676
|
+
if (structure.allowAdd){
|
677
|
+
var add_button = self.createWithAttributes("paper-button", {"class": "add-button " + self.scopeToClass(structure, key, scope)}),
|
678
|
+
add_icon = self.createWithAttributes("core-icon", {icon: "add-circle-outline"}),
|
679
|
+
add_button_text = self.createWithAttributes("div", {text: structure.label || key.replace(/_/g)});
|
680
|
+
|
681
|
+
add_button.appendChild(add_icon);
|
682
|
+
add_button.appendChild(add_button_text);
|
683
|
+
|
684
|
+
wrap.appendChild(add_button);
|
685
|
+
this.addClass(wrap, 'addable');
|
686
|
+
|
687
|
+
add_button.addEventListener('click', function(){
|
688
|
+
var items = wrap.querySelectorAll('.list-group'),
|
689
|
+
blank = false;
|
690
|
+
|
691
|
+
for (var i=0; i<items.length; i++){
|
692
|
+
if (self.checkForBlank(items[i])){
|
693
|
+
blank = true;
|
694
|
+
break;
|
695
|
+
}
|
696
|
+
}
|
697
|
+
|
698
|
+
if (!blank) nested_data.unshift({});
|
699
|
+
}, false);
|
700
|
+
}
|
701
|
+
|
702
|
+
if (structure.multiple){
|
703
|
+
|
704
|
+
for (var i=0; i<nested_data.length; i++){
|
705
|
+
if (structure.allowAdd){
|
706
|
+
var item_wrapper = self.createWithAttributes("div", {"class": "list-group"}),
|
707
|
+
list_item = self.createWithAttributes("div", {"class": "list-item"}),
|
708
|
+
list_form = self.createWithAttributes("div", {"class": "list-form"});
|
709
|
+
|
710
|
+
list_item.appendChild( self.createListItem(nested_data[i], structure, nested_data) );
|
711
|
+
item_wrapper.appendChild(list_item);
|
712
|
+
item_wrapper.appendChild(list_form);
|
713
|
+
|
714
|
+
self.buildStructure(structure.structure, nested_data[i], list_form, self.addIndex(nested_scope, i));
|
715
|
+
} else {
|
716
|
+
var item_wrapper = self.createWithAttributes("div", {"class": "list-group"});
|
717
|
+
self.buildStructure(structure.structure, nested_data[i], item_wrapper, self.addIndex(nested_scope, i));
|
718
|
+
}
|
719
|
+
|
720
|
+
wrap.appendChild(item_wrapper);
|
721
|
+
self.checkForBlank(item_wrapper);
|
722
|
+
}
|
723
|
+
} else {
|
724
|
+
self.buildStructure(structure.structure, nested_data, wrap, nested_scope);
|
725
|
+
}
|
726
|
+
|
727
|
+
return wrap;
|
728
|
+
|
729
|
+
} else {
|
730
|
+
//TODO: set defaults here
|
731
|
+
var options = structure.options || {},
|
732
|
+
fieldData = self.scopeFieldData((options.unscoped ? self.unscopedData : data), structure, key),
|
733
|
+
wrap = self.createWithAttributes("div", {"class": "input " + structure.type + " " + key}),
|
734
|
+
inputElement = self.createInput(structure, fieldData, key, scope);
|
735
|
+
|
736
|
+
wrap.appendChild(inputElement);
|
737
|
+
return wrap;
|
738
|
+
}
|
739
|
+
},
|
740
|
+
|
741
|
+
getField: function(key){
|
742
|
+
var key = key.split("."),
|
743
|
+
structure = this.structure;
|
744
|
+
for (var i=0; i<key.length; i++){
|
745
|
+
if (!structure) return null;
|
746
|
+
var field = structure.filter(function(item){ return item.key === key[i] })[0];
|
747
|
+
if (!field) return null;
|
748
|
+
|
749
|
+
structure = field.structure;
|
750
|
+
}
|
751
|
+
|
752
|
+
return field;
|
753
|
+
},
|
754
|
+
|
755
|
+
loadData: function(data){
|
756
|
+
//TODO: deal with unscoped data somehow
|
757
|
+
var recursive = function(d1, d2, structure){
|
758
|
+
if (Array.isArray(d1) && Array.isArray(d2)){
|
759
|
+
for (var i=0; i<d2.length; i++){
|
760
|
+
if (!d1[i]) d1.push({});
|
761
|
+
recursive(d1[i], d2[i], structure);
|
762
|
+
}
|
763
|
+
} else {
|
764
|
+
for (var i=0; i<structure.length; i++){
|
765
|
+
if (d2[structure[i].key] !== void(0)){
|
766
|
+
if (structure[i].type === 'nest'){
|
767
|
+
recursive(d1[structure[i].key], d2[structure[i].key], structure[i].structure);
|
768
|
+
} else {
|
769
|
+
d1[structure[i].key] = d2[structure[i].key];
|
770
|
+
}
|
771
|
+
}
|
772
|
+
}
|
773
|
+
}
|
774
|
+
}
|
775
|
+
|
776
|
+
this.async(function(){
|
777
|
+
recursive(this.data, data, this.structure);
|
778
|
+
});
|
432
779
|
}
|
433
|
-
}, FormHelpers, Validation));
|
780
|
+
}, FormHelpers, Validation, Autocomplete));
|
434
781
|
</script>
|
435
782
|
</polymer-element>
|