polymer-rails-forms 0.1.12 → 0.1.13

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.
@@ -0,0 +1,744 @@
1
+ <script>
2
+ /* TODO clean this up */
3
+ var FormHelpers = {
4
+ /* Utility things */
5
+ log: function(o){
6
+ console.log("Data", o)
7
+ },
8
+
9
+ capitalize: function(str){
10
+ if (str && str.length > 1){
11
+ return str.split(" ").map( function(s){ return s[0].toUpperCase() + s.substr(1) } ).join(" ");
12
+ } else {
13
+ return "";
14
+ }
15
+ },
16
+
17
+ findParent: function(el, selector){
18
+ var parent = el.parentNode;
19
+
20
+ if (parent !== null){
21
+ if (parent.querySelector(selector) !== null){
22
+ return el;
23
+ } else {
24
+ return this.findParent(parent, selector)
25
+ }
26
+ } else {
27
+ return null;
28
+ }
29
+ },
30
+
31
+ addClass: function(el, cls){
32
+ var reg = new RegExp("\\s/+" + cls, "g")
33
+ this.removeClass(el, cls);
34
+ el.className = el.className + " " + cls;
35
+ },
36
+
37
+ removeClass: function(el, cls){
38
+ var reg = new RegExp("\\s+" + cls, "g")
39
+ el.className = el.className.replace(reg, "");
40
+ },
41
+
42
+ hasClass: function(el, cls){
43
+ var reg = new RegExp("\\s+" + cls, "g")
44
+ return reg.test(el.className);
45
+ },
46
+
47
+ indexStore: {},
48
+ genIndexStoreKey: function(){
49
+ var key = "_" + ((Math.random() * 1000000) | 0);
50
+ while(this.indexStore[key] !== void(0)){
51
+ key = "_" + ((Math.random() * 1000000) | 0);
52
+ }
53
+
54
+ return key;
55
+ },
56
+
57
+ addToIndexStore: function(obj, index){
58
+ var key = this.genIndexStoreKey();
59
+ this.indexStore[key] = {obj: obj, index: index}
60
+ },
61
+
62
+ removeFromIndexStore: function(obj){
63
+ for (var x in this.indexStore){
64
+ if (this.indexStore[x].obj === obj) delete this.indexStore[x];
65
+ }
66
+ },
67
+
68
+ updateIndex: function(obj, index){
69
+ for (var x in this.indexStore){
70
+ if (this.indexStore[x].obj === obj) this.indexStore[x].index = index;
71
+ }
72
+ },
73
+
74
+ enumerate: function(obj){
75
+ //TODO: keygen should check for uniquness
76
+ for (var i=0; i<obj.length; i++){
77
+ this.addToIndexStore(obj[i], i)
78
+ }
79
+
80
+ return obj
81
+ },
82
+
83
+ getIndex: function(obj){
84
+ for (var x in this.indexStore){
85
+ if (this.indexStore[x].obj === obj) return this.indexStore[x].index;
86
+ }
87
+ },
88
+
89
+ /* Type Checks */
90
+
91
+ getKeys: function(o){
92
+ return Object.keys(o);
93
+ },
94
+
95
+ isArray: function(v){
96
+ return Array.isArray(v);
97
+ },
98
+
99
+ isNotArray: function(v){
100
+ return !Array.isArray(v);
101
+ },
102
+
103
+ isNest: function(v){
104
+ return v.type === "nest";
105
+ },
106
+
107
+ isField: function(v){
108
+ return v.type !== "nest";
109
+ },
110
+
111
+ isMultiple: function(s){
112
+ return s.multiple;
113
+ },
114
+
115
+ isNotMultiple: function(s){
116
+ return !s.multiple
117
+ },
118
+
119
+ isHidden: function(o){
120
+ return o.type === 'hidden' ? "hidden" : "";
121
+ },
122
+
123
+ isEmpty: function(o){
124
+ var blank = true;
125
+ for (var x in this.structure[this.key].structure){
126
+ if (!blank) break;
127
+ if (this.structure[this.key].structure[x].type !== 'nest'){
128
+ if (this.structure[this.key].structure[x].type === 'json'){
129
+ for (var y in o[x]){
130
+ if (typeof o[x][y] !== 'object'){
131
+ if (!(o[x][y] === null || o[x][y].length === 0)){
132
+ blank = false;
133
+ break;
134
+ }
135
+ }
136
+ }
137
+ } else {
138
+ console.log(!(o[x] === null || o[x].length === 0))
139
+ if (!(o[x] === null || o[x].length === 0)){
140
+ blank = false;
141
+ break;
142
+ }
143
+ }
144
+ }
145
+ }
146
+
147
+ if (!blank){
148
+ return "";
149
+ } else {
150
+ return "is-blank";
151
+ }
152
+ },
153
+
154
+ exists: function(o, key){
155
+ return o[key] !== void(0)
156
+ },
157
+
158
+ notExists: function(o, key){
159
+ return o[key] === void (0)
160
+ },
161
+
162
+ displayableField: function(field){
163
+ return ["string"].indexOf(field.type) !== -1;
164
+ },
165
+
166
+ /* Scope things */
167
+ wrapperClass: function(structure){
168
+ if (structure.type === "nest"){
169
+ if (structure.allowAdd) {
170
+ return 'wrapper list-wrapper'
171
+ } else {
172
+ return 'wrapper'
173
+ }
174
+ } else {
175
+ return 'input-wrapper'
176
+ }
177
+ },
178
+
179
+ addIndex: function(scope, obj){
180
+ var index = this.getIndex(obj);
181
+
182
+ this.scope = this.structure[this.key].multiple ? scope + "[" + index + "]" : scope;
183
+ return this.scope;
184
+ },
185
+
186
+ addItem: function(e, d, t){
187
+ var parent = this.findParent(t, ".list-wrapper"),
188
+ items = parent.querySelectorAll(".list-form"),
189
+ invalid = parent.querySelectorAll(".input-wrapper.is-invalid input")[0];
190
+
191
+ for (var i=0; i<items.length; i++){
192
+ var inputs = items[i].querySelectorAll("input"),
193
+ blank = true;
194
+
195
+ for (var j=0; j<inputs.length; j++){
196
+ if (inputs[j].value.replace(/\s/g, "").length !== 0){ blank = false; break; }
197
+ }
198
+
199
+ if (blank){
200
+ invalid = inputs[0];
201
+ break;
202
+ }
203
+ }
204
+
205
+ if (!invalid){
206
+ var data = this.classToData(t.className),
207
+ newData = {};
208
+
209
+ this.addToIndexStore(newData, data.length);
210
+ data.push(newData)
211
+ } else {
212
+ invalid.focus();
213
+ }
214
+ },
215
+
216
+ updateScope: function(key){
217
+ var scope = this.scope + "[" + this.key + "_attributes]";
218
+ this.scope = scope;
219
+ return this.scope;
220
+ },
221
+
222
+ scopeFieldData: function(data, key){
223
+ if (data[key] === void(0)) data[key] = null;
224
+ return data;
225
+ },
226
+
227
+ scopeNestData: function(data, key){
228
+ if (this.structure[key].multiple){
229
+ if (data[key] === void(0)){
230
+ if (this.structure[key].allowAdd) {
231
+ data[key] = [];
232
+ } else {
233
+ data[key] = [{}];
234
+ }
235
+ }
236
+
237
+ this.data = data[key];
238
+ } else {
239
+ if (data[key] === void(0)) data[key] = {};
240
+ this.data = data[key];
241
+ }
242
+
243
+ return this.data;
244
+ },
245
+
246
+ updateParentContext: function(key){
247
+ this.parentContext = key;
248
+ this.parentStructure = this.structure;
249
+ this.parentData = this.data;
250
+ },
251
+
252
+ scopeDataToIndex: function(data, obj){
253
+ var index = this.getIndex(obj);
254
+
255
+ this.data = this.data[index];
256
+ return this.data
257
+ },
258
+
259
+ listItemClassName: function(obj){
260
+ return this.key + "-" + this.getIndex(obj);
261
+ },
262
+
263
+ /* Effects */
264
+ freezeElement: function(el){
265
+ var left = el.offsetLeft,
266
+ top = el.offsetTop;
267
+
268
+ el.style.position = 'absolute';
269
+ el.style.left = left;
270
+ el.style.top = top;
271
+ },
272
+
273
+ freezeFormCoords: { width: null, height: null, oWidth: null, oHeight: null },
274
+ freezeCoords: [],
275
+ freezeForm: function(selectors){
276
+ selectors = selectors || ".input-wrapper, .wrapper, .list-item, .sumbit-button-wrapper, #submit-button";
277
+
278
+ var form = this.shadowRoot.querySelector("form"),
279
+ elements = this.shadowRoot.querySelectorAll(selectors);
280
+
281
+ this.freezeFormCoords = {
282
+ width: parseInt(form.offsetWidth, 10),
283
+ height: parseInt(form.offsetHeight, 10),
284
+ oWidth: form.style.width,
285
+ oHeight: form.style.height
286
+ },
287
+
288
+ this.addClass(form, 'frozen');
289
+ form.style.width = this.freezeFormCoords.width + "px";
290
+ form.style.height = this.freezeFormCoords.height + "px";
291
+
292
+ this.freezeCoords = [];
293
+ for (var i=0; i<elements.length; i++){
294
+ this.freezeCoords[i] = {};
295
+ this.freezeCoords[i].element = elements[i];
296
+ this.freezeCoords[i].top = parseInt(elements[i].offsetTop, 10);
297
+ this.freezeCoords[i].left = parseInt(elements[i].offsetLeft, 10);
298
+ this.freezeCoords[i].oTop = elements[i].style.top;
299
+ this.freezeCoords[i].oLeft = elements[i].style.left;
300
+ this.freezeCoords[i].oPos = elements[i].style.position;
301
+ }
302
+
303
+ for (var i=0; i<this.freezeCoords.length; i++){
304
+ this.freezeCoords[i].element.style.top = this.freezeCoords[i].top + "px";
305
+ this.freezeCoords[i].element.style.left = this.freezeCoords[i].left + "px";
306
+ this.freezeCoords[i].element.style.position = 'absolute';
307
+ }
308
+ },
309
+
310
+ unfreezeForm: function(){
311
+ var form = this.shadowRoot.querySelector("form");
312
+
313
+ for (var i=0; i<this.freezeCoords.length; i++){
314
+ this.freezeCoords[i].element.style.top = this.freezeCoords[i].oTop;
315
+ this.freezeCoords[i].element.style.left = this.freezeCoords[i].oLeft;
316
+ this.freezeCoords[i].element.style.position = this.freezeCoords[i].oPos;
317
+ }
318
+
319
+ form.style.width = this.freezeFormCoords.oWidth;
320
+ form.style.height = this.freezeFormCoords.oHeight;
321
+ this.removeClass(form, 'frozen');
322
+ },
323
+
324
+ /* Creating Element */
325
+ createListItem: function(obj){
326
+ var className = this.listItemClassName(obj),
327
+ isEmpty = Object.keys(obj).length === 0,
328
+ container = document.createElement("div");
329
+ this.addClass(container, "list-item-display")
330
+
331
+ if (this.structure[this.key].display_fields){
332
+ for (var i=0; i<this.structure[this.key].display_fields.length; i++){
333
+ var field = this.structure[this.key].display_fields[i],
334
+ baseField = field.split(".")[0],
335
+ nameField = field.split(".")[field.split(".").length - 1]
336
+
337
+ var el = document.createElement("div"),
338
+ label = this.createWithAttributes("span", { text: this.capitalize(nameField.replace(/_/g, " ")) + ": " });
339
+
340
+ var value = document.createElement("span"),
341
+ val = document.createTextNode("");
342
+
343
+ if (this.structure[this.key].structure[field.split(".")[0]].type === "json"){
344
+ var struct = field.split("."),
345
+ o = obj;
346
+
347
+ for (var j=0; j<struct.length - 1; j++){
348
+ //TODO: this doesn't account for Arrays... which I'm fine with for now.
349
+ if (!obj[struct[j]]) obj[struct[j]] = {};
350
+ o = o[struct[j]]
351
+ }
352
+
353
+ var f = struct[struct.length - 1]
354
+ if (!o[f]) o[f] = "";
355
+ val.bind("textContent", new PathObserver(obj, field))
356
+ } else {
357
+ if (!obj[baseField]) obj[baseField] = "";
358
+ val.bind("textContent", new PathObserver(obj, field));
359
+ }
360
+
361
+ el.appendChild(label)
362
+ el.appendChild(value)
363
+ value.appendChild(val)
364
+
365
+ container.appendChild(el);
366
+ }
367
+ } else {
368
+ container.appendChild(this.createWithAttributes("div", {text: "item " + (this.getIndex(obj) + 1)}))
369
+ }
370
+
371
+ var self = this;
372
+ this.inputList.push({ element: container, container: ".list-item." + className, events: {} })
373
+
374
+ container.addEventListener("click", function(e){
375
+ var stop = function(e){ e.stopPropagation(); }
376
+ group = self.findParent(container, ".list-group"),
377
+ first_input = group.querySelector(".input-wrapper gc-input-decorator");
378
+
379
+ stop(e);
380
+ var alreadyFocued = self.shadowRoot.querySelectorAll(".list-group.focused");
381
+ for (var i=0; i<alreadyFocued.length; i++){
382
+ self.removeClass(alreadyFocued[i], 'focused')
383
+ }
384
+
385
+ first_input.focused = true;
386
+ setTimeout(function(){
387
+ first_input.querySelector("input").focus();
388
+ }, 100)
389
+
390
+ self.addClass(group, "focused");
391
+ group.addEventListener("click", stop, false);
392
+ window.addEventListener("click", function(e){
393
+ window.removeEventListener("click", arguments.callee)
394
+ group.removeEventListener("click", stop)
395
+ self.removeClass(group, "focused");
396
+ }, false)
397
+ }, false)
398
+ },
399
+
400
+ createInput: function(structure){
401
+ var default_structure = {
402
+ type: "string",
403
+ label: "",
404
+ options: {
405
+ floatingLabel: true,
406
+ unscoped: false,
407
+ events: {}
408
+ },
409
+ attributes: {
410
+
411
+ }
412
+ }
413
+
414
+ function setOptions(obj, defaults){
415
+ for (var x in defaults){
416
+ if (typeof defaults[x] === 'object'){
417
+ if (obj[x] === void(0)) obj[x] = {};
418
+ setOptions(obj[x], defaults[x]);
419
+ } else {
420
+ if (obj[x] === void(0)){
421
+ obj[x] = defaults[x];
422
+ }
423
+ }
424
+ }
425
+ }
426
+
427
+ setOptions(structure, default_structure);
428
+ var el = this.getElement(structure),
429
+ obj = { element: el, container: "." + this.scopeToClass(this.key), events: structure.options.events };
430
+
431
+ this.inputList.push(obj)
432
+ },
433
+
434
+ scopeToClass: function(key){
435
+ var className = this.scope.replace(/\[/g, "_").replace(/\]/g, "") + "_" + key;
436
+ return className;
437
+ },
438
+
439
+ classToData: function(className){
440
+ var cn = className.split("_").slice(1).join("_"),
441
+ data = this.data;
442
+
443
+ function nest(str){
444
+ var p = str.split("_attributes_");
445
+ if (p.length > 1){
446
+ data = data[p[0]]
447
+ cn = p.slice(1).join("_attributes_");
448
+ return true;
449
+ } else {
450
+ return false
451
+ }
452
+ }
453
+
454
+ function arr(str){
455
+ var p = str.split("_");
456
+ if (p.length > 1 && !isNaN(p[0])){
457
+ data = data[p[0]];
458
+ cn = p.slice(1).join("_");
459
+ return true;
460
+ } else {
461
+ return false
462
+ }
463
+ }
464
+
465
+ while (nest(cn) || arr(cn)){ }
466
+ return data[cn];
467
+ },
468
+
469
+ checkForBlank: function(group){
470
+ var inputs = group.querySelectorAll("input"),
471
+ blank = true;
472
+
473
+ for (var i=0; i<inputs.length; i++){
474
+ if (inputs[i].value.replace(/\s/g, "").length !== 0){
475
+ blank = false;
476
+ break;
477
+ }
478
+ }
479
+
480
+ if (blank){
481
+ this.addClass(group, 'is-blank');
482
+ } else {
483
+ this.removeClass(group, 'is-blank');
484
+ }
485
+ },
486
+
487
+ updateFieldScope: function(){
488
+ return this.structure[this.key].options.unscoped ? this.key : this.scope + "[" + this.key + "]"
489
+ },
490
+
491
+ getElement: function(structure){
492
+ var inputs = {
493
+ string: function(){
494
+ return this.createBasicInput("text");
495
+ }.bind(this),
496
+
497
+ email: function(){
498
+ return this.createBasicInput("text");
499
+ },
500
+
501
+ hidden: function(){
502
+ return this.createBasicInput("hidden");
503
+ }.bind(this),
504
+
505
+ json: function(){
506
+ return this.createJSONField(structure.fields);
507
+ }.bind(this),
508
+
509
+ password: function(){
510
+ return this.createBasicInput("password");
511
+ }.bind(this),
512
+
513
+ integer: function(){
514
+ return this.createBasicInput("text");
515
+ }.bind(this),
516
+
517
+ url: function(){
518
+ return this.createBasicInput("text");
519
+ }.bind(this),
520
+
521
+ textarea: function(){
522
+ return this.createBasicInput("textarea")
523
+ }.bind(this),
524
+
525
+ checkbox: function(){
526
+ var box = document.createElement("paper-checkbox"),
527
+ input = this.createWithAttributes('input', {type: "checkbox", name: this.updateFieldScope()});
528
+
529
+ box.label = this.capitalize(this.structure[this.key].label || this.key);
530
+ box.appendChild(input);
531
+
532
+ box.addEventListener("change", function(e){
533
+ this.data[this.key] = e.target.checked ? 1 : 0;
534
+ input.checked = e.target.checked;
535
+ }.bind(this), false)
536
+
537
+ return box;
538
+
539
+ }.bind(this),
540
+
541
+ date: function(){
542
+ var wrapper = this.createBasicInput("text"),
543
+ input = wrapper.querySelector("input");
544
+
545
+ var picker = new Pikaday({ field: input, bound: false });
546
+
547
+ input.addEventListener("focus", function(){
548
+ picker.show();
549
+ });
550
+
551
+ return wrapper;
552
+ }.bind(this),
553
+
554
+ location: function(){
555
+ var wrapper = document.createElement("gc-input-decorator"),
556
+ input = document.createElement( "input" );
557
+ //google-location-input
558
+ if (!this.data[this.key]) this.data[this.key] = { value: null, lat: null, lng: null }
559
+
560
+ wrapper.label = this.capitalize(this.structure[this.key].label || this.key);
561
+ wrapper.floatingLabel = this.structure[this.key].options.floatingLabel;
562
+
563
+ input.type = "text";
564
+ input.name = this.updateFieldScope();
565
+ input.bind('value', new PathObserver(this.data[this.key], "value"))
566
+
567
+ var autocomplete = new google.maps.places.Autocomplete(
568
+ input, { types: ['(cities)'] }
569
+ );
570
+
571
+ var self = this;
572
+ google.maps.event.addListener(autocomplete, 'place_changed', function () {
573
+ var place = autocomplete.getPlace();
574
+
575
+ self.data[self.key].value = input.value;
576
+ self.data[self.key].lat = place.geometry.location.lat();
577
+ self.data[self.key].lng = place.geometry.location.lng();
578
+
579
+ if (self.structure[self.key].options.events.select){
580
+ self.structure[self.key].options.events.select(self.data[self.key])
581
+ }
582
+ })
583
+
584
+ wrapper.appendChild(input);
585
+ return wrapper;
586
+ }.bind(this),
587
+
588
+ image: function(){
589
+ var wrapper = this.createWithAttributes("span", { "class": "btn-image-upload" }),
590
+ input = this.createWithAttributes("input", { type: "file", name: this.updateFieldScope() }),
591
+ icon_wrapper = this.createWithAttributes("div", {"class": "image-icon-wrapper"}),
592
+ explanation = this.createWithAttributes("p", {text: "Click here to upload an image"}),
593
+ icon = this.createWithAttributes("core-icon", {icon: "image:photo"});
594
+
595
+ icon_wrapper.appendChild(icon);
596
+ wrapper.appendChild(input);
597
+ wrapper.appendChild(icon_wrapper);
598
+ wrapper.appendChild(explanation);
599
+
600
+ this.addValidation('image', input)
601
+ input.addEventListener("click", function(e){ e.stopPropagation(); }, true)
602
+
603
+ var self = this;
604
+ input.addEventListener("change", function(){
605
+ if (this.files.length){
606
+ var oFReader = new FileReader();
607
+ oFReader.readAsDataURL(this.files[0]);
608
+
609
+ oFReader.onload = function (oFREvent) {
610
+ wrapper.parentNode.style.backgroundImage = "url(" + oFREvent.target.result + ")";
611
+ self.addClass(wrapper.parentNode, "has-image");
612
+ };
613
+ } else {
614
+ self.removeClass(wrapper.parentNode, 'has-image');
615
+ wrapper.parentNode.style.backgroundImage = "";
616
+ }
617
+ }, true)
618
+
619
+ return wrapper;
620
+ }.bind(this),
621
+
622
+ html: function(){
623
+ var content = document.createElement('div');
624
+ content.innerHTML = this.structure[this.key].content;
625
+ return content;
626
+ }.bind(this)
627
+
628
+ }
629
+
630
+ try {
631
+ return inputs[structure.type]()
632
+ } catch(e){
633
+ throw "Unknown field type: " + structure.type
634
+ }
635
+ },
636
+
637
+ appendInputs: function(){
638
+ for (var i=0; i<this.inputList.length; i++){
639
+ var obj = this.inputList[i],
640
+ container = this.shadowRoot.querySelector(obj.container);
641
+
642
+ //TODO: insert points
643
+ if (!obj.position || obj.position === 'append'){
644
+ if (this.findParent(obj.element, obj.container) === null){
645
+ container.appendChild(obj.element)
646
+ }
647
+ } else if (!!obj.position && obj.position === 'before') {
648
+ if ([].indexOf.call(container.parentNode.childNodes, obj.element) === -1){
649
+ container.parentNode.insertBefore(obj.element, container)
650
+ }
651
+ }
652
+
653
+ if (!!obj.events.onFocus) container.addEventListener("focus", obj.events.onFocus, false);
654
+ if (!!obj.events.onBlur) container.addEventListener("blur", obj.events.onBlur, false);
655
+ }
656
+ },
657
+
658
+ createBasicInput: function(type, name, label){
659
+ var wrapper = document.createElement("gc-input-decorator"),
660
+ input = document.createElement( type === "textarea" ? "textarea" : "input" );
661
+
662
+ wrapper.label = this.capitalize(label || this.structure[this.key].label || this.key);
663
+ wrapper.floatingLabel = this.structure[this.key].options.floatingLabel;
664
+
665
+ input.type = type;
666
+ input.name = name || this.updateFieldScope();
667
+ input.id = this.scopeToClass(this.key)
668
+ if (this.structure[this.key].required) input.required = true;
669
+ input.bind('value', new PathObserver(this.data, this.key))
670
+
671
+ this.addValidation(type, input)
672
+
673
+ if (type === 'textarea') input.rows = 3;
674
+ if (type !== "hidden"){
675
+ wrapper.appendChild(input);
676
+ return wrapper;
677
+ } else {
678
+ return input;
679
+ }
680
+
681
+ },
682
+
683
+ createJSONField: function(fields){
684
+ //TODO: only basic JSON support, if you want crazy complicated stuff, just use a textarea or custom input
685
+ var wrapper = this.createWithAttributes('div', { "class": "json-wrapper" }),
686
+ input = this.createWithAttributes("textarea", { name: this.updateFieldScope(), "class": "hidden" }),
687
+ isList = this.parentStructure !== null && this.parentStructure[this.parentContext].allowAdd;
688
+
689
+ if (!this.data[this.key]) this.data[this.key] = {};
690
+
691
+ var observer = new ObjectObserver(this.data[this.key])
692
+ observer.open(function(){
693
+ input.value = JSON.stringify(this.data[this.key])
694
+ }.bind(this))
695
+
696
+ input.bind('value', new PathObserver(this.data, this.key))
697
+
698
+ wrapper.appendChild(input);
699
+ for (var i=0; i<fields.length; i++){
700
+ this.data[this.key][fields[i]] = "";
701
+ var input_wrapper = this.createWithAttributes("div", { "class": (isList ? "input-wrapper" : "input") + " json-input-wrapper"})
702
+ decorator = document.createElement("gc-input-decorator"),
703
+ el = this.createWithAttributes('input');
704
+
705
+ input_wrapper.appendChild(decorator);
706
+ decorator.label = this.capitalize(fields[i]);
707
+ decorator.floatingLabel = true;
708
+ decorator.appendChild(el);
709
+
710
+ el.bind("value", new PathObserver(this.data[this.key], fields[i]))
711
+
712
+ //TODO: create a parentStruture thing. check the parent structure for isNull or allowAdd
713
+ //change the container selector appropriately
714
+ if (isList){
715
+ var className = "." + this.parentContext + "-" + this.getIndex(this.data) + " .input-wrapper." + this.key;
716
+ var o = { element: input_wrapper, container: className, events: {}, position: "before" }
717
+ } else {
718
+ var o = { element: input_wrapper, container: "." + this.scopeToClass(this.key), events: {} };
719
+ }
720
+
721
+ this.inputList.push(o)
722
+ //wrapper.appendChild(decorator);
723
+ }
724
+
725
+ return wrapper;
726
+ },
727
+
728
+ createWithAttributes: function(type, attributes){
729
+ var el = document.createElement(type)
730
+ if (attributes){
731
+ for (var x in attributes){
732
+ if (x === 'text'){
733
+ var t = document.createTextNode(attributes[x]);
734
+ el.appendChild(t);
735
+ } else {
736
+ el.setAttribute(x, attributes[x]);
737
+ }
738
+ }
739
+ }
740
+
741
+ return el;
742
+ }
743
+ }
744
+ </script>