rails-backbone-forms 0.10.1 → 0.11.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.
- data/lib/rails/backbone/forms/version.rb +1 -1
- data/vendor/assets/javascripts/backbone-forms/adapters/backbone.bootstrap-modal.js +76 -17
- data/vendor/assets/javascripts/backbone-forms/adapters/backbone.bootstrap-modal.min.js +1 -0
- data/vendor/assets/javascripts/backbone-forms/backbone-forms.js +331 -272
- data/vendor/assets/javascripts/backbone-forms/editors/list.js +84 -49
- data/vendor/assets/javascripts/backbone-forms/editors/list.min.js +1 -0
- data/vendor/assets/javascripts/backbone-forms/templates/bootstrap.js +6 -3
- data/vendor/assets/javascripts/backbone-forms/templates/default.js +2 -0
- data/vendor/assets/stylesheets/backbone-forms/templates/default.css +6 -0
- metadata +5 -6
- data/vendor/assets/javascripts/backbone-forms/editors/jquery-ui.js +0 -500
- data/vendor/assets/stylesheets/backbone-forms-bootstrap.css +0 -3
- data/vendor/assets/stylesheets/backbone-forms/editors/jquery-ui.css +0 -65
@@ -55,7 +55,7 @@
|
|
55
55
|
value = this.value || [];
|
56
56
|
|
57
57
|
//Create main element
|
58
|
-
var $el =
|
58
|
+
var $el = Form.helpers.parseHTML(Form.templates[this.schema.listTemplate]({
|
59
59
|
items: '<b class="bbf-tmp"></b>'
|
60
60
|
}));
|
61
61
|
|
@@ -105,10 +105,10 @@
|
|
105
105
|
self.$list.append(item.el);
|
106
106
|
|
107
107
|
item.editor.on('all', function(event) {
|
108
|
-
if (event
|
108
|
+
if (event === 'change') return;
|
109
109
|
|
110
110
|
// args = ["key:change", itemEditor, fieldEditor]
|
111
|
-
args = _.toArray(arguments);
|
111
|
+
var args = _.toArray(arguments);
|
112
112
|
args[0] = 'item:' + event;
|
113
113
|
args.splice(1, 0, self);
|
114
114
|
// args = ["item:key:change", this=listEditor, itemEditor, fieldEditor]
|
@@ -156,6 +156,7 @@
|
|
156
156
|
//Most editors can be added automatically
|
157
157
|
else {
|
158
158
|
_addItem();
|
159
|
+
item.editor.focus();
|
159
160
|
}
|
160
161
|
|
161
162
|
return item;
|
@@ -206,7 +207,7 @@
|
|
206
207
|
blur: function() {
|
207
208
|
if (!this.hasFocus) return;
|
208
209
|
|
209
|
-
focusedItem = _.find(this.items, function(item) { return item.editor.hasFocus; });
|
210
|
+
var focusedItem = _.find(this.items, function(item) { return item.editor.hasFocus; });
|
210
211
|
|
211
212
|
if (focusedItem) focusedItem.editor.blur();
|
212
213
|
},
|
@@ -265,7 +266,7 @@
|
|
265
266
|
this.list.removeItem(this);
|
266
267
|
},
|
267
268
|
'keydown input[type=text]': function(event) {
|
268
|
-
if(event.keyCode
|
269
|
+
if(event.keyCode !== 13) return;
|
269
270
|
event.preventDefault();
|
270
271
|
this.list.addItem();
|
271
272
|
this.list.$list.find("> li:last input").focus();
|
@@ -291,7 +292,7 @@
|
|
291
292
|
}).render();
|
292
293
|
|
293
294
|
//Create main element
|
294
|
-
var $el =
|
295
|
+
var $el = Form.helpers.parseHTML(Form.templates[this.schema.listItemTemplate]({
|
295
296
|
editor: '<b class="bbf-tmp"></b>'
|
296
297
|
}));
|
297
298
|
|
@@ -338,11 +339,15 @@
|
|
338
339
|
_.every(validators, function(validator) {
|
339
340
|
error = getValidator(validator)(value, formValues);
|
340
341
|
|
341
|
-
return
|
342
|
+
return error ? false : true;
|
342
343
|
});
|
343
344
|
|
344
345
|
//Show/hide error
|
345
|
-
|
346
|
+
if (error){
|
347
|
+
this.setError(error);
|
348
|
+
} else {
|
349
|
+
this.clearError();
|
350
|
+
}
|
346
351
|
|
347
352
|
//Return error to be aggregated by list
|
348
353
|
return error ? error : null;
|
@@ -367,10 +372,10 @@
|
|
367
372
|
|
368
373
|
|
369
374
|
/**
|
370
|
-
*
|
371
|
-
*
|
375
|
+
* Base modal object editor for use with the List editor; used by Object
|
376
|
+
* and NestedModal list types
|
372
377
|
*/
|
373
|
-
editors.List.Modal = editors.
|
378
|
+
editors.List.Modal = editors.Base.extend({
|
374
379
|
events: {
|
375
380
|
'click': 'openEditor'
|
376
381
|
},
|
@@ -384,26 +389,9 @@
|
|
384
389
|
*/
|
385
390
|
initialize: function(options) {
|
386
391
|
editors.Base.prototype.initialize.call(this, options);
|
387
|
-
|
388
|
-
var schema = this.schema;
|
389
392
|
|
390
393
|
//Dependencies
|
391
394
|
if (!editors.List.Modal.ModalAdapter) throw 'A ModalAdapter is required';
|
392
|
-
|
393
|
-
//Get nested schema if Object
|
394
|
-
if (schema.itemType == 'Object') {
|
395
|
-
if (!schema.subSchema) throw 'Missing required option "schema.subSchema"';
|
396
|
-
|
397
|
-
this.nestedSchema = schema.subSchema;
|
398
|
-
}
|
399
|
-
|
400
|
-
//Get nested schema if NestedModel
|
401
|
-
if (schema.itemType == 'NestedModel') {
|
402
|
-
if (!schema.model) throw 'Missing required option "schema.model"';
|
403
|
-
|
404
|
-
this.nestedSchema = schema.model.prototype.schema;
|
405
|
-
if (_.isFunction(this.nestedSchema)) this.nestedSchema = this.nestedSchema();
|
406
|
-
}
|
407
395
|
},
|
408
396
|
|
409
397
|
/**
|
@@ -478,11 +466,6 @@
|
|
478
466
|
//If there's a specified toString use that
|
479
467
|
if (schema.itemToString) return schema.itemToString(value);
|
480
468
|
|
481
|
-
//Otherwise check if it's NestedModel with it's own toString() method
|
482
|
-
if (schema.itemType == 'NestedModel') {
|
483
|
-
return new (schema.model)(value).toString();
|
484
|
-
}
|
485
|
-
|
486
469
|
//Otherwise use the generic method or custom overridden method
|
487
470
|
return this.itemToString(value);
|
488
471
|
},
|
@@ -490,50 +473,59 @@
|
|
490
473
|
openEditor: function() {
|
491
474
|
var self = this;
|
492
475
|
|
493
|
-
var form = new Form({
|
476
|
+
var form = this.modalForm = new Form({
|
494
477
|
schema: this.nestedSchema,
|
495
478
|
data: this.value
|
496
479
|
});
|
497
480
|
|
498
|
-
var modal = this.modal = new
|
481
|
+
var modal = this.modal = new editors.List.Modal.ModalAdapter({
|
499
482
|
content: form,
|
500
483
|
animate: true
|
501
|
-
})
|
484
|
+
});
|
485
|
+
|
486
|
+
modal.open();
|
502
487
|
|
503
488
|
this.trigger('open', this);
|
504
489
|
this.trigger('focus', this);
|
505
490
|
|
506
|
-
modal.on('cancel',
|
507
|
-
this.modal = null;
|
508
|
-
|
509
|
-
this.trigger('close', this);
|
510
|
-
this.trigger('blur', this);
|
511
|
-
}, this);
|
491
|
+
modal.on('cancel', this.onModalClosed, this);
|
512
492
|
|
513
|
-
modal.on('ok', _.bind(this.onModalSubmitted, this
|
493
|
+
modal.on('ok', _.bind(this.onModalSubmitted, this));
|
514
494
|
},
|
515
495
|
|
516
496
|
/**
|
517
497
|
* Called when the user clicks 'OK'.
|
518
498
|
* Runs validation and tells the list when ready to add the item
|
519
499
|
*/
|
520
|
-
onModalSubmitted: function(
|
521
|
-
var
|
500
|
+
onModalSubmitted: function() {
|
501
|
+
var modal = this.modal,
|
502
|
+
form = this.modalForm,
|
503
|
+
isNew = !this.value;
|
522
504
|
|
523
505
|
//Stop if there are validation errors
|
524
506
|
var error = form.validate();
|
525
507
|
if (error) return modal.preventClose();
|
526
|
-
this.modal = null;
|
527
508
|
|
528
|
-
//
|
509
|
+
//Store form value
|
529
510
|
this.value = form.getValue();
|
530
511
|
|
512
|
+
//Render item
|
531
513
|
this.renderSummary();
|
532
514
|
|
533
515
|
if (isNew) this.trigger('readyToAdd');
|
534
516
|
|
535
517
|
this.trigger('change', this);
|
536
|
-
|
518
|
+
|
519
|
+
this.onModalClosed();
|
520
|
+
},
|
521
|
+
|
522
|
+
/**
|
523
|
+
* Cleans up references, triggers events. To be called whenever the modal closes
|
524
|
+
*/
|
525
|
+
onModalClosed: function() {
|
526
|
+
this.modal = null;
|
527
|
+
this.modalForm = null;
|
528
|
+
|
537
529
|
this.trigger('close', this);
|
538
530
|
this.trigger('blur', this);
|
539
531
|
},
|
@@ -557,7 +549,6 @@
|
|
557
549
|
|
558
550
|
if (this.modal) {
|
559
551
|
this.modal.trigger('cancel');
|
560
|
-
this.modal.close();
|
561
552
|
}
|
562
553
|
}
|
563
554
|
}, {
|
@@ -572,4 +563,48 @@
|
|
572
563
|
isAsync: true
|
573
564
|
});
|
574
565
|
|
566
|
+
|
567
|
+
editors.List.Object = editors.List.Modal.extend({
|
568
|
+
initialize: function () {
|
569
|
+
editors.List.Modal.prototype.initialize.apply(this, arguments);
|
570
|
+
|
571
|
+
var schema = this.schema;
|
572
|
+
|
573
|
+
if (!schema.subSchema) throw 'Missing required option "schema.subSchema"';
|
574
|
+
|
575
|
+
this.nestedSchema = schema.subSchema;
|
576
|
+
}
|
577
|
+
});
|
578
|
+
|
579
|
+
|
580
|
+
editors.List.NestedModel = editors.List.Modal.extend({
|
581
|
+
initialize: function() {
|
582
|
+
editors.List.Modal.prototype.initialize.apply(this, arguments);
|
583
|
+
|
584
|
+
var schema = this.schema;
|
585
|
+
|
586
|
+
if (!schema.model) throw 'Missing required option "schema.model"';
|
587
|
+
|
588
|
+
var nestedSchema = schema.model.prototype.schema;
|
589
|
+
|
590
|
+
this.nestedSchema = (_.isFunction(nestedSchema)) ? nestedSchema() : nestedSchema;
|
591
|
+
},
|
592
|
+
|
593
|
+
/**
|
594
|
+
* Returns the string representation of the object value
|
595
|
+
*/
|
596
|
+
getStringValue: function() {
|
597
|
+
var schema = this.schema,
|
598
|
+
value = this.getValue();
|
599
|
+
|
600
|
+
if (_.isEmpty(value)) return null;
|
601
|
+
|
602
|
+
//If there's a specified toString use that
|
603
|
+
if (schema.itemToString) return schema.itemToString(value);
|
604
|
+
|
605
|
+
//Otherwise use the model
|
606
|
+
return new (schema.model)(value).toString();
|
607
|
+
},
|
608
|
+
});
|
609
|
+
|
575
610
|
})();
|
@@ -0,0 +1 @@
|
|
1
|
+
(function(){var e=Backbone.Form,t=e.editors;t.List=t.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(e){t.Base.prototype.initialize.call(this,e);var n=this.schema;if(!n)throw"Missing required option 'schema'";this.schema=_.extend({listTemplate:"list",listItemTemplate:"listItem"},n),this.Editor=function(){var e=n.itemType;return e?t.List[e]?t.List[e]:t[e]:t.Text}(),this.items=[]},render:function(){var t=this,n=this.value||[],r=e.helpers.parseHTML(e.templates[this.schema.listTemplate]({items:'<b class="bbf-tmp"></b>'}));return this.$list=r.find(".bbf-tmp").parent().empty(),n.length?_.each(n,function(e){t.addItem(e)}):this.Editor.isAsync||this.addItem(),this.setElement(r),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},addItem:function(e,n){var r=this,i=(new t.List.Item({list:this,schema:this.schema,value:e,Editor:this.Editor,key:this.key})).render(),s=function(){r.items.push(i),r.$list.append(i.el),i.editor.on("all",function(e){if(e==="change")return;var n=_.toArray(arguments);n[0]="item:"+e,n.splice(1,0,r),t.List.prototype.trigger.apply(this,n)},r),i.editor.on("change",function(){i.addEventTriggered||(i.addEventTriggered=!0,this.trigger("add",this,i.editor)),this.trigger("item:change",this,i.editor),this.trigger("change",this)},r),i.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},r),i.editor.on("blur",function(){if(!this.hasFocus)return;var e=this;setTimeout(function(){if(_.find(e.items,function(e){return e.editor.hasFocus}))return;e.trigger("blur",e)},0)},r);if(n||e)i.addEventTriggered=!0;n&&(r.trigger("add",r,i.editor),r.trigger("change",r))};return this.Editor.isAsync?i.editor.on("readyToAdd",s,this):(s(),i.editor.focus()),i},removeItem:function(e){var t=this.schema.confirmDelete;if(t&&!confirm(t))return;var n=_.indexOf(this.items,e);this.items[n].remove(),this.items.splice(n,1),e.addEventTriggered&&(this.trigger("remove",this,e.editor),this.trigger("change",this)),!this.items.length&&!this.Editor.isAsync&&this.addItem()},getValue:function(){var e=_.map(this.items,function(e){return e.getValue()});return _.without(e,undefined,"")},setValue:function(e){this.value=e,this.render()},focus:function(){if(this.hasFocus)return;this.items[0]&&this.items[0].editor.focus()},blur:function(){if(!this.hasFocus)return;var e=_.find(this.items,function(e){return e.editor.hasFocus});e&&e.editor.blur()},remove:function(){_.invoke(this.items,"remove"),t.Base.prototype.remove.call(this)},validate:function(){if(!this.validators)return null;var e=_.map(this.items,function(e){return e.validate()}),t=_.compact(e).length?!0:!1;if(!t)return null;var n={type:"list",message:"Some of the items in the list failed validation",errors:e};return n}}),t.List.Item=Backbone.View.extend({events:{'click [data-action="remove"]':function(e){e.preventDefault(),this.list.removeItem(this)},"keydown input[type=text]":function(e){if(e.keyCode!==13)return;e.preventDefault(),this.list.addItem(),this.list.$list.find("> li:last input").focus()}},initialize:function(e){this.list=e.list,this.schema=e.schema||this.list.schema,this.value=e.value,this.Editor=e.Editor||t.Text,this.key=e.key},render:function(){this.editor=(new this.Editor({key:this.key,schema:this.schema,value:this.value,list:this.list,item:this})).render();var t=e.helpers.parseHTML(e.templates[this.schema.listItemTemplate]({editor:'<b class="bbf-tmp"></b>'}));return t.find(".bbf-tmp").replaceWith(this.editor.el),this.setElement(t),this},getValue:function(){return this.editor.getValue()},setValue:function(e){this.editor.setValue(e)},focus:function(){this.editor.focus()},blur:function(){this.editor.blur()},remove:function(){this.editor.remove(),Backbone.View.prototype.remove.call(this)},validate:function(){var t=this.getValue(),n=this.list.form?this.list.form.getValue():{},r=this.schema.validators,i=e.helpers.getValidator;if(!r)return null;var s=null;return _.every(r,function(e){return s=i(e)(t,n),s?!1:!0}),s?this.setError(s):this.clearError(),s?s:null},setError:function(t){this.$el.addClass(e.classNames.error),this.$el.attr("title",t.message)},clearError:function(){this.$el.removeClass(e.classNames.error),this.$el.attr("title",null)}}),t.List.Modal=t.Base.extend({events:{click:"openEditor"},initialize:function(e){t.Base.prototype.initialize.call(this,e);if(!t.List.Modal.ModalAdapter)throw"A ModalAdapter is required"},render:function(){var e=this;return _.isEmpty(this.value)?this.openEditor():(this.renderSummary(),setTimeout(function(){e.trigger("readyToAdd")},0)),this.hasFocus&&this.trigger("blur",this),this},renderSummary:function(){var t=e.templates["list.Modal"];this.$el.html(t({summary:this.getStringValue()}))},itemToString:function(t){t=t||{};var n=[];return _.each(this.nestedSchema,function(r,i){var s=r.title?r.title:e.helpers.keyToTitle(i),o=t[i];if(_.isUndefined(o)||_.isNull(o))o="";n.push(s+": "+o)}),n.join("<br />")},getStringValue:function(){var e=this.schema,t=this.getValue();return _.isEmpty(t)?"[Empty]":e.itemToString?e.itemToString(t):this.itemToString(t)},openEditor:function(){var n=this,r=this.modalForm=new e({schema:this.nestedSchema,data:this.value}),i=this.modal=new t.List.Modal.ModalAdapter({content:r,animate:!0});i.open(),this.trigger("open",this),this.trigger("focus",this),i.on("cancel",this.onModalClosed,this),i.on("ok",_.bind(this.onModalSubmitted,this))},onModalSubmitted:function(){var e=this.modal,t=this.modalForm,n=!this.value,r=t.validate();if(r)return e.preventClose();this.value=t.getValue(),this.renderSummary(),n&&this.trigger("readyToAdd"),this.trigger("change",this),this.onModalClosed()},onModalClosed:function(){this.modal=null,this.modalForm=null,this.trigger("close",this),this.trigger("blur",this)},getValue:function(){return this.value},setValue:function(e){this.value=e},focus:function(){if(this.hasFocus)return;this.openEditor()},blur:function(){if(!this.hasFocus)return;this.modal&&this.modal.trigger("cancel")}},{ModalAdapter:Backbone.BootstrapModal,isAsync:!0}),t.List.Object=t.List.Modal.extend({initialize:function(){t.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.subSchema)throw'Missing required option "schema.subSchema"';this.nestedSchema=e.subSchema}}),t.List.NestedModel=t.List.Modal.extend({initialize:function(){t.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.model)throw'Missing required option "schema.model"';var n=e.model.prototype.schema;this.nestedSchema=_.isFunction(n)?n():n},getStringValue:function(){var e=this.schema,t=this.getValue();return _.isEmpty(t)?null:e.itemToString?e.itemToString(t):(new e.model(t)).toString()}})})()
|
@@ -31,7 +31,8 @@
|
|
31
31
|
<div class="control-group field-{{key}}">\
|
32
32
|
<label class="control-label" for="{{id}}">{{title}}</label>\
|
33
33
|
<div class="controls">\
|
34
|
-
|
34
|
+
{{editor}}\
|
35
|
+
<div class="help-inline">{{error}}</div>\
|
35
36
|
<div class="help-block">{{help}}</div>\
|
36
37
|
</div>\
|
37
38
|
</div>\
|
@@ -39,7 +40,9 @@
|
|
39
40
|
|
40
41
|
nestedField: '\
|
41
42
|
<div class="field-{{key}}">\
|
42
|
-
<div title="{{title}}" class="input-xlarge">{{editor}}
|
43
|
+
<div title="{{title}}" class="input-xlarge">{{editor}}\
|
44
|
+
<div class="help-inline">{{error}}</div>\
|
45
|
+
</div>\
|
43
46
|
<div class="help-block">{{help}}</div>\
|
44
47
|
</div>\
|
45
48
|
',
|
@@ -47,7 +50,7 @@
|
|
47
50
|
list: '\
|
48
51
|
<div class="bbf-list">\
|
49
52
|
<ul class="unstyled clearfix">{{items}}</ul>\
|
50
|
-
<button
|
53
|
+
<button class="btn bbf-add" data-action="add">Add</button>\
|
51
54
|
</div>\
|
52
55
|
',
|
53
56
|
|
@@ -31,6 +31,7 @@
|
|
31
31
|
<label for="{{id}}">{{title}}</label>\
|
32
32
|
<div class="bbf-editor">{{editor}}</div>\
|
33
33
|
<div class="bbf-help">{{help}}</div>\
|
34
|
+
<div class="bbf-error">{{error}}</div>\
|
34
35
|
</li>\
|
35
36
|
',
|
36
37
|
|
@@ -39,6 +40,7 @@
|
|
39
40
|
<label for="{{id}}">{{title}}</label>\
|
40
41
|
<div class="bbf-editor">{{editor}}</div>\
|
41
42
|
<div class="bbf-help">{{help}}</div>\
|
43
|
+
<div class="bbf-error">{{error}}</div>\
|
42
44
|
</li>\
|
43
45
|
',
|
44
46
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-backbone-forms
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.11.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-03-25 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: Rails 3.1 support for the backbone-forms library
|
15
15
|
email:
|
@@ -29,14 +29,13 @@ files:
|
|
29
29
|
- vendor/assets/javascripts/backbone-forms-bootstrap.js
|
30
30
|
- vendor/assets/javascripts/backbone-forms.js
|
31
31
|
- vendor/assets/javascripts/backbone-forms/adapters/backbone.bootstrap-modal.js
|
32
|
+
- vendor/assets/javascripts/backbone-forms/adapters/backbone.bootstrap-modal.min.js
|
32
33
|
- vendor/assets/javascripts/backbone-forms/backbone-forms.js
|
33
|
-
- vendor/assets/javascripts/backbone-forms/editors/jquery-ui.js
|
34
34
|
- vendor/assets/javascripts/backbone-forms/editors/list.js
|
35
|
+
- vendor/assets/javascripts/backbone-forms/editors/list.min.js
|
35
36
|
- vendor/assets/javascripts/backbone-forms/templates/bootstrap.js
|
36
37
|
- vendor/assets/javascripts/backbone-forms/templates/default.js
|
37
|
-
- vendor/assets/stylesheets/backbone-forms-bootstrap.css
|
38
38
|
- vendor/assets/stylesheets/backbone-forms.css
|
39
|
-
- vendor/assets/stylesheets/backbone-forms/editors/jquery-ui.css
|
40
39
|
- vendor/assets/stylesheets/backbone-forms/templates/bootstrap.css
|
41
40
|
- vendor/assets/stylesheets/backbone-forms/templates/default.css
|
42
41
|
homepage: ''
|
@@ -59,7 +58,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
58
|
version: '0'
|
60
59
|
requirements: []
|
61
60
|
rubyforge_project: rails-backbone-forms
|
62
|
-
rubygems_version: 1.8.
|
61
|
+
rubygems_version: 1.8.25
|
63
62
|
signing_key:
|
64
63
|
specification_version: 3
|
65
64
|
summary: A wrapper for backbone-forms in the Rails asset pipeline
|
@@ -1,500 +0,0 @@
|
|
1
|
-
;(function() {
|
2
|
-
|
3
|
-
var Form = Backbone.Form,
|
4
|
-
Base = Form.editors.Base,
|
5
|
-
createTemplate = Form.helpers.createTemplate,
|
6
|
-
triggerCancellableEvent = Form.helpers.triggerCancellableEvent,
|
7
|
-
exports = {};
|
8
|
-
|
9
|
-
/**
|
10
|
-
* Additional editors that depend on jQuery UI
|
11
|
-
*/
|
12
|
-
|
13
|
-
//DATE
|
14
|
-
exports['jqueryui.Date'] = Base.extend({
|
15
|
-
|
16
|
-
className: 'bbf-jui-date',
|
17
|
-
|
18
|
-
initialize: function(options) {
|
19
|
-
Base.prototype.initialize.call(this, options);
|
20
|
-
|
21
|
-
//Cast to Date
|
22
|
-
if (this.value && !_.isDate(this.value)) {
|
23
|
-
this.value = new Date(this.value);
|
24
|
-
}
|
25
|
-
|
26
|
-
//Set default date
|
27
|
-
if (!this.value) {
|
28
|
-
var date = new Date();
|
29
|
-
date.setSeconds(0);
|
30
|
-
date.setMilliseconds(0);
|
31
|
-
|
32
|
-
this.value = date;
|
33
|
-
}
|
34
|
-
},
|
35
|
-
|
36
|
-
render: function() {
|
37
|
-
var $el = this.$el;
|
38
|
-
|
39
|
-
$el.html('<input>');
|
40
|
-
|
41
|
-
var input = $('input', $el);
|
42
|
-
|
43
|
-
input.datepicker({
|
44
|
-
dateFormat: 'dd/mm/yy',
|
45
|
-
showButtonPanel: true
|
46
|
-
});
|
47
|
-
|
48
|
-
this._observeDatepickerEvents();
|
49
|
-
|
50
|
-
//Make sure setValue of this object is called, not of any objects extending it (e.g. DateTime)
|
51
|
-
exports['jqueryui.Date'].prototype.setValue.call(this, this.value);
|
52
|
-
|
53
|
-
return this;
|
54
|
-
},
|
55
|
-
|
56
|
-
/**
|
57
|
-
* @return {Date} Selected date
|
58
|
-
*/
|
59
|
-
getValue: function() {
|
60
|
-
var input = $('input', this.el),
|
61
|
-
date = input.datepicker('getDate');
|
62
|
-
|
63
|
-
return date;
|
64
|
-
},
|
65
|
-
|
66
|
-
setValue: function(value) {
|
67
|
-
$('input', this.el).datepicker('setDate', value);
|
68
|
-
},
|
69
|
-
|
70
|
-
focus: function() {
|
71
|
-
if (this.hasFocus) return;
|
72
|
-
|
73
|
-
this.$('input').datepicker('show');
|
74
|
-
},
|
75
|
-
|
76
|
-
blur: function() {
|
77
|
-
if (!this.hasFocus) return;
|
78
|
-
|
79
|
-
this.$('input').datepicker('hide');
|
80
|
-
},
|
81
|
-
|
82
|
-
_observeDatepickerEvents: function() {
|
83
|
-
var self = this;
|
84
|
-
this.$('input').datepicker('option', 'onSelect', function() {
|
85
|
-
self.trigger('change', self);
|
86
|
-
})
|
87
|
-
this.$('input').datepicker('option', 'onClose', function() {
|
88
|
-
if (!self.hasFocus) return;
|
89
|
-
self.trigger('blur', self);
|
90
|
-
});
|
91
|
-
this.$('input').datepicker('option', 'beforeShow', function() {
|
92
|
-
if (self.hasFocus) return {};
|
93
|
-
self.trigger('focus', self);
|
94
|
-
|
95
|
-
return {};
|
96
|
-
});
|
97
|
-
}
|
98
|
-
|
99
|
-
});
|
100
|
-
|
101
|
-
|
102
|
-
//DATETIME
|
103
|
-
exports['jqueryui.DateTime'] = exports['jqueryui.Date'].extend({
|
104
|
-
|
105
|
-
className: 'bbf-jui-datetime',
|
106
|
-
|
107
|
-
template: createTemplate('<select>{{hours}}</select> : <select>{{mins}}</select>'),
|
108
|
-
|
109
|
-
render: function() {
|
110
|
-
function pad(n) {
|
111
|
-
return n < 10 ? '0' + n : n
|
112
|
-
}
|
113
|
-
|
114
|
-
//Render the date element first
|
115
|
-
exports['jqueryui.Date'].prototype.render.call(this);
|
116
|
-
|
117
|
-
//Setup hour options
|
118
|
-
var hours = _.range(0, 24),
|
119
|
-
hoursOptions = [];
|
120
|
-
|
121
|
-
_.each(hours, function(hour) {
|
122
|
-
hoursOptions.push('<option value="'+hour+'">' + pad(hour) + '</option>');
|
123
|
-
});
|
124
|
-
|
125
|
-
//Setup minute options
|
126
|
-
var minsInterval = this.schema.minsInterval || 15,
|
127
|
-
mins = _.range(0, 60, minsInterval),
|
128
|
-
minsOptions = [];
|
129
|
-
|
130
|
-
_.each(mins, function(min) {
|
131
|
-
minsOptions.push('<option value="'+min+'">' + pad(min) + '</option>');
|
132
|
-
});
|
133
|
-
|
134
|
-
//Render time selects
|
135
|
-
this.$el.append(this.template({
|
136
|
-
hours: hoursOptions.join(),
|
137
|
-
mins: minsOptions.join()
|
138
|
-
}));
|
139
|
-
|
140
|
-
this._observeDatepickerEvents();
|
141
|
-
|
142
|
-
//Store references to selects
|
143
|
-
this.$hours = $('select:eq(0)', this.el);
|
144
|
-
this.$mins = $('select:eq(1)', this.el);
|
145
|
-
|
146
|
-
//Set time
|
147
|
-
this.setValue(this.value);
|
148
|
-
|
149
|
-
return this;
|
150
|
-
},
|
151
|
-
|
152
|
-
/**
|
153
|
-
* @return {Date} Selected datetime
|
154
|
-
*/
|
155
|
-
getValue: function() {
|
156
|
-
var input = $('input', this.el),
|
157
|
-
date = input.datepicker('getDate');
|
158
|
-
|
159
|
-
date.setHours(this.$hours.val());
|
160
|
-
date.setMinutes(this.$mins.val());
|
161
|
-
date.setMilliseconds(0);
|
162
|
-
|
163
|
-
return date;
|
164
|
-
},
|
165
|
-
|
166
|
-
setValue: function(date) {
|
167
|
-
exports['jqueryui.Date'].prototype.setValue.call(this, date);
|
168
|
-
|
169
|
-
this.$hours.val(date.getHours());
|
170
|
-
this.$mins.val(date.getMinutes());
|
171
|
-
}
|
172
|
-
|
173
|
-
});
|
174
|
-
|
175
|
-
|
176
|
-
//LIST
|
177
|
-
exports['jqueryui.List'] = Base.extend({
|
178
|
-
|
179
|
-
className: 'bbf-jui-list',
|
180
|
-
|
181
|
-
//Note: The extra div around the <ul> is used to limit the drag area
|
182
|
-
template: createTemplate('\
|
183
|
-
<ul></ul>\
|
184
|
-
<div><button class="bbf-list-add">Add</div>\
|
185
|
-
'),
|
186
|
-
|
187
|
-
itemTemplate: createTemplate('\
|
188
|
-
<li rel="{{id}}">\
|
189
|
-
<span class="bbf-list-text">{{text}}</span>\
|
190
|
-
<div class="bbf-list-actions">\
|
191
|
-
<button class="bbf-list-edit">Edit</button>\
|
192
|
-
<button class="bbf-list-del">Delete</button>\
|
193
|
-
</div>\
|
194
|
-
</li>\
|
195
|
-
'),
|
196
|
-
|
197
|
-
editorTemplate: createTemplate('\
|
198
|
-
<div class="bbf-field">\
|
199
|
-
<div class="bbf-list-editor"></div>\
|
200
|
-
</div>\
|
201
|
-
'),
|
202
|
-
|
203
|
-
events: {
|
204
|
-
'click .bbf-list-add': 'addNewItem',
|
205
|
-
'click .bbf-list-edit': 'editItem',
|
206
|
-
'click .bbf-list-del': 'deleteItem'
|
207
|
-
},
|
208
|
-
|
209
|
-
initialize: function(options) {
|
210
|
-
Base.prototype.initialize.call(this, options);
|
211
|
-
|
212
|
-
if (!this.schema) throw "Missing required option 'schema'";
|
213
|
-
|
214
|
-
this.schema.listType = this.schema.listType || 'Text';
|
215
|
-
|
216
|
-
if (this.schema.listType == 'NestedModel' && !this.schema.model)
|
217
|
-
throw "Missing required option 'schema.model'";
|
218
|
-
},
|
219
|
-
|
220
|
-
render: function() {
|
221
|
-
var $el = this.$el;
|
222
|
-
|
223
|
-
//Main element
|
224
|
-
$el.html(this.template());
|
225
|
-
|
226
|
-
//Create list
|
227
|
-
var self = this,
|
228
|
-
data = this.value || [],
|
229
|
-
schema = this.schema,
|
230
|
-
itemToString = this.itemToString,
|
231
|
-
itemTemplate = this.itemTemplate,
|
232
|
-
listEl = $('ul', $el);
|
233
|
-
|
234
|
-
_.each(data, function(itemData) {
|
235
|
-
var text = itemToString.call(self, itemData);
|
236
|
-
|
237
|
-
//Create DOM element
|
238
|
-
var li = $(itemTemplate({
|
239
|
-
id: itemData.id || '',
|
240
|
-
text: text
|
241
|
-
}));
|
242
|
-
|
243
|
-
//Attach data
|
244
|
-
$.data(li[0], 'data', itemData);
|
245
|
-
|
246
|
-
listEl.append(li);
|
247
|
-
});
|
248
|
-
|
249
|
-
//Make sortable
|
250
|
-
if (schema.sortable !== false) {
|
251
|
-
listEl.sortable({
|
252
|
-
axis: 'y',
|
253
|
-
cursor: 'move',
|
254
|
-
containment: 'parent'
|
255
|
-
});
|
256
|
-
|
257
|
-
$el.addClass('bbf-list-sortable');
|
258
|
-
}
|
259
|
-
|
260
|
-
//jQuery UI buttonize
|
261
|
-
$('button.bbf-list-add', $el).button({
|
262
|
-
text: false,
|
263
|
-
icons: { primary: 'ui-icon-plus' }
|
264
|
-
});
|
265
|
-
$('button.bbf-list-edit', $el).button({
|
266
|
-
text: false,
|
267
|
-
icons: { primary: 'ui-icon-pencil' }
|
268
|
-
});
|
269
|
-
$('button.bbf-list-del', $el).button({
|
270
|
-
text: false,
|
271
|
-
icons: { primary: 'ui-icon-trash' }
|
272
|
-
});
|
273
|
-
|
274
|
-
if (this.hasFocus) this.trigger('blur', this);
|
275
|
-
|
276
|
-
return this;
|
277
|
-
},
|
278
|
-
|
279
|
-
/**
|
280
|
-
* Formats an item for display in the list
|
281
|
-
* For example objects, dates etc. can have a custom
|
282
|
-
* itemToString method which says how it should be formatted.
|
283
|
-
*/
|
284
|
-
itemToString: function(data) {
|
285
|
-
if (!data) return data;
|
286
|
-
|
287
|
-
var schema = this.schema;
|
288
|
-
|
289
|
-
//If there's a specified toString use that
|
290
|
-
if (schema.itemToString) return schema.itemToString(data);
|
291
|
-
|
292
|
-
//Otherwise check if it's NestedModel with it's own toString() method
|
293
|
-
if (this.schema.listType == 'NestedModel') {
|
294
|
-
var model = new (this.schema.model)(data);
|
295
|
-
|
296
|
-
return model.toString();
|
297
|
-
}
|
298
|
-
|
299
|
-
//Last resort, just return the data as is
|
300
|
-
return data;
|
301
|
-
},
|
302
|
-
|
303
|
-
/**
|
304
|
-
* Add a new item to the list if it is completed in the editor
|
305
|
-
*/
|
306
|
-
addNewItem: function(event) {
|
307
|
-
if (event) event.preventDefault();
|
308
|
-
|
309
|
-
var self = this;
|
310
|
-
|
311
|
-
this.openEditor(null, function(value, editor) {
|
312
|
-
//Fire 'addItem' cancellable event
|
313
|
-
triggerCancellableEvent(self, 'addItem', [value, editor], function() {
|
314
|
-
var text = self.itemToString(value);
|
315
|
-
|
316
|
-
//Create DOM element
|
317
|
-
var li = $(self.itemTemplate({
|
318
|
-
id: value.id || '',
|
319
|
-
text: text
|
320
|
-
}));
|
321
|
-
|
322
|
-
//Store data
|
323
|
-
$.data(li[0], 'data', value);
|
324
|
-
|
325
|
-
$('ul', self.el).append(li);
|
326
|
-
|
327
|
-
//jQuery UI buttonize
|
328
|
-
$('button.bbf-list-edit', this.el).button({
|
329
|
-
text: false,
|
330
|
-
icons: { primary: 'ui-icon-pencil' }
|
331
|
-
});
|
332
|
-
$('button.bbf-list-del', this.el).button({
|
333
|
-
text: false,
|
334
|
-
icons: { primary: 'ui-icon-trash' }
|
335
|
-
});
|
336
|
-
|
337
|
-
self.trigger('add', self, value);
|
338
|
-
self.trigger('item:change', self, editor);
|
339
|
-
self.trigger('change', self);
|
340
|
-
});
|
341
|
-
});
|
342
|
-
},
|
343
|
-
|
344
|
-
/**
|
345
|
-
* Edit an existing item in the list
|
346
|
-
*/
|
347
|
-
editItem: function(event) {
|
348
|
-
event.preventDefault();
|
349
|
-
|
350
|
-
var self = this,
|
351
|
-
li = $(event.target).closest('li'),
|
352
|
-
originalValue = $.data(li[0], 'data');
|
353
|
-
|
354
|
-
this.openEditor(originalValue, function(newValue, editor) {
|
355
|
-
//Fire 'editItem' cancellable event
|
356
|
-
triggerCancellableEvent(self, 'editItem', [newValue, editor], function() {
|
357
|
-
//Update display
|
358
|
-
$('.bbf-list-text', li).html(self.itemToString(newValue));
|
359
|
-
|
360
|
-
//Store data
|
361
|
-
$.data(li[0], 'data', newValue);
|
362
|
-
|
363
|
-
self.trigger('item:change', self, editor);
|
364
|
-
self.trigger('change', self);
|
365
|
-
});
|
366
|
-
});
|
367
|
-
},
|
368
|
-
|
369
|
-
deleteItem: function(event) {
|
370
|
-
event.preventDefault();
|
371
|
-
|
372
|
-
var self = this,
|
373
|
-
li = $(event.target).closest('li'),
|
374
|
-
data = $.data(li[0], 'data');
|
375
|
-
|
376
|
-
var confirmDelete = (this.schema.confirmDelete) ? this.schema.confirmDelete : false,
|
377
|
-
confirmMsg = this.schema.confirmDeleteMsg || 'Are you sure?';
|
378
|
-
|
379
|
-
function remove() {
|
380
|
-
triggerCancellableEvent(self, 'removeItem', [data], function() {
|
381
|
-
li.remove();
|
382
|
-
|
383
|
-
self.trigger('remove', self, data);
|
384
|
-
self.trigger('change', self);
|
385
|
-
});
|
386
|
-
}
|
387
|
-
|
388
|
-
if (this.schema.confirmDelete) {
|
389
|
-
if (confirm(confirmMsg)) remove();
|
390
|
-
} else {
|
391
|
-
remove();
|
392
|
-
}
|
393
|
-
},
|
394
|
-
|
395
|
-
/**
|
396
|
-
* Opens the sub editor dialog
|
397
|
-
* @param {Mixed} Data (if editing existing list item, null otherwise)
|
398
|
-
* @param {Function} Save callback. receives: value
|
399
|
-
*/
|
400
|
-
openEditor: function(data, callback) {
|
401
|
-
var self = this,
|
402
|
-
schema = this.schema,
|
403
|
-
listType = schema.listType || 'Text';
|
404
|
-
|
405
|
-
var editor = Form.helpers.createEditor(listType, {
|
406
|
-
key: '',
|
407
|
-
schema: schema,
|
408
|
-
value: data
|
409
|
-
}).render();
|
410
|
-
|
411
|
-
var container = this.editorContainer = $(this.editorTemplate());
|
412
|
-
$('.bbf-list-editor', container).html(editor.el);
|
413
|
-
|
414
|
-
var saveAndClose = function() {
|
415
|
-
var errs = editor.validate();
|
416
|
-
if (errs) return;
|
417
|
-
|
418
|
-
callback(editor.getValue(), editor);
|
419
|
-
container.dialog('close');
|
420
|
-
}
|
421
|
-
|
422
|
-
var handleEnterPressed = function(event) {
|
423
|
-
if (event.keyCode != 13) return;
|
424
|
-
|
425
|
-
saveAndClose();
|
426
|
-
}
|
427
|
-
|
428
|
-
$(container).dialog({
|
429
|
-
resizable: false,
|
430
|
-
modal: true,
|
431
|
-
width: 500,
|
432
|
-
title: data ? 'Edit item' : 'New item',
|
433
|
-
buttons: {
|
434
|
-
'OK': saveAndClose,
|
435
|
-
'Cancel': function() {
|
436
|
-
container.dialog('close');
|
437
|
-
}
|
438
|
-
},
|
439
|
-
close: function() {
|
440
|
-
self.editorContainer = null;
|
441
|
-
|
442
|
-
$(document).unbind('keydown', handleEnterPressed);
|
443
|
-
|
444
|
-
editor.remove();
|
445
|
-
container.remove();
|
446
|
-
|
447
|
-
self.trigger('item:close', self, editor);
|
448
|
-
self.trigger('item:blur', self, editor);
|
449
|
-
self.trigger('blur', self);
|
450
|
-
}
|
451
|
-
});
|
452
|
-
|
453
|
-
this.trigger('item:open', this, editor);
|
454
|
-
this.trigger('item:focus', this, editor);
|
455
|
-
this.trigger('focus', this);
|
456
|
-
|
457
|
-
//Save and close dialog on Enter keypress
|
458
|
-
$(document).bind('keydown', handleEnterPressed);
|
459
|
-
},
|
460
|
-
|
461
|
-
getValue: function() {
|
462
|
-
var data = [];
|
463
|
-
|
464
|
-
$('li', this.el).each(function(index, li) {
|
465
|
-
data.push($.data(li, 'data'));
|
466
|
-
});
|
467
|
-
|
468
|
-
return data;
|
469
|
-
},
|
470
|
-
|
471
|
-
setValue: function(value) {
|
472
|
-
this.value = value;
|
473
|
-
this.render();
|
474
|
-
},
|
475
|
-
|
476
|
-
focus: function() {
|
477
|
-
if (this.hasFocus) return;
|
478
|
-
|
479
|
-
var item = this.$('li .bbf-list-edit').first();
|
480
|
-
if (item.length > 0) {
|
481
|
-
item.click();
|
482
|
-
}
|
483
|
-
else {
|
484
|
-
this.addNewItem();
|
485
|
-
}
|
486
|
-
},
|
487
|
-
|
488
|
-
blur: function() {
|
489
|
-
if (!this.hasFocus) return;
|
490
|
-
|
491
|
-
if (this.editorContainer) this.editorContainer.dialog('close');
|
492
|
-
}
|
493
|
-
|
494
|
-
});
|
495
|
-
|
496
|
-
|
497
|
-
//Exports
|
498
|
-
_.extend(Form.editors, exports);
|
499
|
-
|
500
|
-
})();
|