rails-backbone-forms 0.10.1 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
})();
|