rails-backbone-forms 0.11.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,10 +1,7 @@
1
- ;(function() {
2
-
3
- var Form = Backbone.Form,
4
- editors = Form.editors;
1
+ ;(function(Form) {
5
2
 
6
3
  /**
7
- * LIST
4
+ * List editor
8
5
  *
9
6
  * An array editor. Creates a list of other editor items.
10
7
  *
@@ -12,8 +9,8 @@
12
9
  * @param {String} [options.schema.itemType] The editor type for each item in the list. Default: 'Text'
13
10
  * @param {String} [options.schema.confirmDelete] Text to display in a delete confirmation dialog. If falsey, will not ask for confirmation.
14
11
  */
15
- editors.List = editors.Base.extend({
16
-
12
+ Form.editors.List = Form.editors.Base.extend({
13
+
17
14
  events: {
18
15
  'click [data-action="add"]': function(event) {
19
16
  event.preventDefault();
@@ -22,16 +19,16 @@
22
19
  },
23
20
 
24
21
  initialize: function(options) {
22
+ options = options || {};
23
+
24
+ var editors = Form.editors;
25
+
25
26
  editors.Base.prototype.initialize.call(this, options);
26
27
 
27
28
  var schema = this.schema;
28
29
  if (!schema) throw "Missing required option 'schema'";
29
30
 
30
- //List schema defaults
31
- this.schema = _.extend({
32
- listTemplate: 'list',
33
- listItemTemplate: 'listItem'
34
- }, schema);
31
+ this.template = options.template || this.constructor.template;
35
32
 
36
33
  //Determine the editor to use
37
34
  this.Editor = (function() {
@@ -55,12 +52,10 @@
55
52
  value = this.value || [];
56
53
 
57
54
  //Create main element
58
- var $el = Form.helpers.parseHTML(Form.templates[this.schema.listTemplate]({
59
- items: '<b class="bbf-tmp"></b>'
60
- }));
55
+ var $el = $($.trim(this.template()));
61
56
 
62
57
  //Store a reference to the list (item container)
63
- this.$list = $el.find('.bbf-tmp').parent().empty();
58
+ this.$list = $el.is('[data-items]') ? $el : $el.find('[data-items]');
64
59
 
65
60
  //Add existing items
66
61
  if (value.length) {
@@ -89,11 +84,13 @@
89
84
  * @param {Boolean} [userInitiated] If the item was added by the user clicking 'add'
90
85
  */
91
86
  addItem: function(value, userInitiated) {
92
- var self = this;
87
+ var self = this,
88
+ editors = Form.editors;
93
89
 
94
90
  //Create the item
95
91
  var item = new editors.List.Item({
96
92
  list: this,
93
+ form: this.form,
97
94
  schema: this.schema,
98
95
  value: value,
99
96
  Editor: this.Editor,
@@ -218,7 +215,7 @@
218
215
  remove: function() {
219
216
  _.invoke(this.items, 'remove');
220
217
 
221
- editors.Base.prototype.remove.call(this);
218
+ Form.editors.Base.prototype.remove.call(this);
222
219
  },
223
220
 
224
221
  /**
@@ -247,6 +244,16 @@
247
244
 
248
245
  return fieldError;
249
246
  }
247
+ }, {
248
+
249
+ //STATICS
250
+ template: _.template('\
251
+ <div>\
252
+ <div data-items></div>\
253
+ <button type="button" data-action="add">Add</button>\
254
+ </div>\
255
+ ', null, Form.templateSettings)
256
+
250
257
  });
251
258
 
252
259
 
@@ -259,7 +266,8 @@
259
266
  * @param {Mixed} options.value Value
260
267
  * @param {Object} options.schema Field schema
261
268
  */
262
- editors.List.Item = Backbone.View.extend({
269
+ Form.editors.List.Item = Form.editors.Base.extend({
270
+
263
271
  events: {
264
272
  'click [data-action="remove"]': function(event) {
265
273
  event.preventDefault();
@@ -277,8 +285,11 @@
277
285
  this.list = options.list;
278
286
  this.schema = options.schema || this.list.schema;
279
287
  this.value = options.value;
280
- this.Editor = options.Editor || editors.Text;
288
+ this.Editor = options.Editor || Form.editors.Text;
281
289
  this.key = options.key;
290
+ this.template = options.template || this.schema.itemTemplate || this.constructor.template;
291
+ this.errorClassName = options.errorClassName || this.constructor.errorClassName;
292
+ this.form = options.form;
282
293
  },
283
294
 
284
295
  render: function() {
@@ -288,15 +299,14 @@
288
299
  schema: this.schema,
289
300
  value: this.value,
290
301
  list: this.list,
291
- item: this
302
+ item: this,
303
+ form: this.form
292
304
  }).render();
293
305
 
294
306
  //Create main element
295
- var $el = Form.helpers.parseHTML(Form.templates[this.schema.listItemTemplate]({
296
- editor: '<b class="bbf-tmp"></b>'
297
- }));
307
+ var $el = $($.trim(this.template()));
298
308
 
299
- $el.find('.bbf-tmp').replaceWith(this.editor.el);
309
+ $el.find('[data-editor]').append(this.editor.el);
300
310
 
301
311
  //Replace the entire element so there isn't a wrapper tag
302
312
  this.setElement($el);
@@ -330,7 +340,7 @@
330
340
  var value = this.getValue(),
331
341
  formValues = this.list.form ? this.list.form.getValue() : {},
332
342
  validators = this.schema.validators,
333
- getValidator = Form.helpers.getValidator;
343
+ getValidator = this.getValidator;
334
344
 
335
345
  if (!validators) return null;
336
346
 
@@ -357,7 +367,7 @@
357
367
  * Show a validation error
358
368
  */
359
369
  setError: function(err) {
360
- this.$el.addClass(Form.classNames.error);
370
+ this.$el.addClass(this.errorClassName);
361
371
  this.$el.attr('title', err.message);
362
372
  },
363
373
 
@@ -365,9 +375,21 @@
365
375
  * Hide validation errors
366
376
  */
367
377
  clearError: function() {
368
- this.$el.removeClass(Form.classNames.error);
378
+ this.$el.removeClass(this.errorClassName);
369
379
  this.$el.attr('title', null);
370
380
  }
381
+ }, {
382
+
383
+ //STATICS
384
+ template: _.template('\
385
+ <div>\
386
+ <span data-editor></span>\
387
+ <button type="button" data-action="remove">&times;</button>\
388
+ </div>\
389
+ ', null, Form.templateSettings),
390
+
391
+ errorClassName: 'error'
392
+
371
393
  });
372
394
 
373
395
 
@@ -375,23 +397,33 @@
375
397
  * Base modal object editor for use with the List editor; used by Object
376
398
  * and NestedModal list types
377
399
  */
378
- editors.List.Modal = editors.Base.extend({
400
+ Form.editors.List.Modal = Form.editors.Base.extend({
401
+
379
402
  events: {
380
403
  'click': 'openEditor'
381
404
  },
382
405
 
383
406
  /**
384
407
  * @param {Object} options
408
+ * @param {Form} options.form The main form
385
409
  * @param {Function} [options.schema.itemToString] Function to transform the value for display in the list.
386
410
  * @param {String} [options.schema.itemType] Editor type e.g. 'Text', 'Object'.
387
411
  * @param {Object} [options.schema.subSchema] Schema for nested form,. Required when itemType is 'Object'
388
412
  * @param {Function} [options.schema.model] Model constructor function. Required when itemType is 'NestedModel'
389
413
  */
390
414
  initialize: function(options) {
391
- editors.Base.prototype.initialize.call(this, options);
415
+ options = options || {};
416
+
417
+ Form.editors.Base.prototype.initialize.call(this, options);
392
418
 
393
419
  //Dependencies
394
- if (!editors.List.Modal.ModalAdapter) throw 'A ModalAdapter is required';
420
+ if (!Form.editors.List.Modal.ModalAdapter) throw 'A ModalAdapter is required';
421
+
422
+ this.form = options.form;
423
+ if (!options.form) throw 'Missing required option: "form"';
424
+
425
+ //Template
426
+ this.template = options.template || this.constructor.template;
395
427
  },
396
428
 
397
429
  /**
@@ -423,11 +455,9 @@
423
455
  * Renders the list item representation
424
456
  */
425
457
  renderSummary: function() {
426
- var template = Form.templates['list.Modal'];
427
-
428
- this.$el.html(template({
458
+ this.$el.html($.trim(this.template({
429
459
  summary: this.getStringValue()
430
- }));
460
+ })));
431
461
  },
432
462
 
433
463
  /**
@@ -438,12 +468,18 @@
438
468
  * @return {String}
439
469
  */
440
470
  itemToString: function(value) {
471
+ var createTitle = function(key) {
472
+ var context = { key: key };
473
+
474
+ return Form.Field.prototype.createTitle.call(context);
475
+ };
476
+
441
477
  value = value || {};
442
478
 
443
479
  //Pretty print the object keys and values
444
480
  var parts = [];
445
481
  _.each(this.nestedSchema, function(schema, key) {
446
- var desc = schema.title ? schema.title : Form.helpers.keyToTitle(key),
482
+ var desc = schema.title ? schema.title : createTitle(key),
447
483
  val = value[key];
448
484
 
449
485
  if (_.isUndefined(val) || _.isNull(val)) val = '';
@@ -471,14 +507,15 @@
471
507
  },
472
508
 
473
509
  openEditor: function() {
474
- var self = this;
510
+ var self = this,
511
+ ModalForm = this.form.constructor;
475
512
 
476
- var form = this.modalForm = new Form({
513
+ var form = this.modalForm = new ModalForm({
477
514
  schema: this.nestedSchema,
478
515
  data: this.value
479
516
  });
480
517
 
481
- var modal = this.modal = new editors.List.Modal.ModalAdapter({
518
+ var modal = this.modal = new Form.editors.List.Modal.ModalAdapter({
482
519
  content: form,
483
520
  animate: true
484
521
  });
@@ -553,6 +590,9 @@
553
590
  }
554
591
  }, {
555
592
  //STATICS
593
+ template: _.template('\
594
+ <div><%= summary %></div>\
595
+ ', null, Form.templateSettings),
556
596
 
557
597
  //The modal adapter that creates and manages the modal dialog.
558
598
  //Defaults to BootstrapModal (http://github.com/powmedia/backbone.bootstrap-modal)
@@ -563,10 +603,10 @@
563
603
  isAsync: true
564
604
  });
565
605
 
566
-
567
- editors.List.Object = editors.List.Modal.extend({
606
+
607
+ Form.editors.List.Object = Form.editors.List.Modal.extend({
568
608
  initialize: function () {
569
- editors.List.Modal.prototype.initialize.apply(this, arguments);
609
+ Form.editors.List.Modal.prototype.initialize.apply(this, arguments);
570
610
 
571
611
  var schema = this.schema;
572
612
 
@@ -577,9 +617,9 @@
577
617
  });
578
618
 
579
619
 
580
- editors.List.NestedModel = editors.List.Modal.extend({
620
+ Form.editors.List.NestedModel = Form.editors.List.Modal.extend({
581
621
  initialize: function() {
582
- editors.List.Modal.prototype.initialize.apply(this, arguments);
622
+ Form.editors.List.Modal.prototype.initialize.apply(this, arguments);
583
623
 
584
624
  var schema = this.schema;
585
625
 
@@ -604,7 +644,7 @@
604
644
 
605
645
  //Otherwise use the model
606
646
  return new (schema.model)(value).toString();
607
- },
647
+ }
608
648
  });
609
649
 
610
- })();
650
+ })(Backbone.Form);
@@ -1 +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()}})})()
1
+ (function(e){e.editors.List=e.editors.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(t){t=t||{};var n=e.editors;n.Base.prototype.initialize.call(this,t);var r=this.schema;if(!r)throw"Missing required option 'schema'";this.template=t.template||this.constructor.template,this.Editor=function(){var e=r.itemType;return e?n.List[e]?n.List[e]:n[e]:n.Text}(),this.items=[]},render:function(){var e=this,t=this.value||[],n=$($.trim(this.template()));return this.$list=n.is("[data-items]")?n:n.find("[data-items]"),t.length?_.each(t,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem(),this.setElement(n),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},addItem:function(t,n){var r=this,i=e.editors,s=(new i.List.Item({list:this,form:this.form,schema:this.schema,value:t,Editor:this.Editor,key:this.key})).render(),o=function(){r.items.push(s),r.$list.append(s.el),s.editor.on("all",function(e){if(e==="change")return;var t=_.toArray(arguments);t[0]="item:"+e,t.splice(1,0,r),i.List.prototype.trigger.apply(this,t)},r),s.editor.on("change",function(){s.addEventTriggered||(s.addEventTriggered=!0,this.trigger("add",this,s.editor)),this.trigger("item:change",this,s.editor),this.trigger("change",this)},r),s.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},r),s.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||t)s.addEventTriggered=!0;n&&(r.trigger("add",r,s.editor),r.trigger("change",r))};return this.Editor.isAsync?s.editor.on("readyToAdd",o,this):(o(),s.editor.focus()),s},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"),e.editors.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}},{template:_.template(' <div> <div data-items></div> <button type="button" data-action="add">Add</button> </div> ',null,e.templateSettings)}),e.editors.List.Item=e.editors.Base.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(t){this.list=t.list,this.schema=t.schema||this.list.schema,this.value=t.value,this.Editor=t.Editor||e.editors.Text,this.key=t.key,this.template=t.template||this.schema.itemTemplate||this.constructor.template,this.errorClassName=t.errorClassName||this.constructor.errorClassName,this.form=t.form},render:function(){this.editor=(new this.Editor({key:this.key,schema:this.schema,value:this.value,list:this.list,item:this,form:this.form})).render();var e=$($.trim(this.template()));return e.find("[data-editor]").append(this.editor.el),this.setElement(e),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 e=this.getValue(),t=this.list.form?this.list.form.getValue():{},n=this.schema.validators,r=this.getValidator;if(!n)return null;var i=null;return _.every(n,function(n){return i=r(n)(e,t),i?!1:!0}),i?this.setError(i):this.clearError(),i?i:null},setError:function(e){this.$el.addClass(this.errorClassName),this.$el.attr("title",e.message)},clearError:function(){this.$el.removeClass(this.errorClassName),this.$el.attr("title",null)}},{template:_.template(' <div> <span data-editor></span> <button type="button" data-action="remove">&times;</button> </div> ',null,e.templateSettings),errorClassName:"error"}),e.editors.List.Modal=e.editors.Base.extend({events:{click:"openEditor"},initialize:function(t){t=t||{},e.editors.Base.prototype.initialize.call(this,t);if(!e.editors.List.Modal.ModalAdapter)throw"A ModalAdapter is required";this.form=t.form;if(!t.form)throw'Missing required option: "form"';this.template=t.template||this.constructor.template},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(){this.$el.html($.trim(this.template({summary:this.getStringValue()})))},itemToString:function(t){var n=function(t){var n={key:t};return e.Field.prototype.createTitle.call(n)};t=t||{};var r=[];return _.each(this.nestedSchema,function(e,i){var s=e.title?e.title:n(i),o=t[i];if(_.isUndefined(o)||_.isNull(o))o="";r.push(s+": "+o)}),r.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 t=this,n=this.form.constructor,r=this.modalForm=new n({schema:this.nestedSchema,data:this.value}),i=this.modal=new e.editors.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")}},{template:_.template(" <div><%= summary %></div> ",null,e.templateSettings),ModalAdapter:Backbone.BootstrapModal,isAsync:!0}),e.editors.List.Object=e.editors.List.Modal.extend({initialize:function(){e.editors.List.Modal.prototype.initialize.apply(this,arguments);var t=this.schema;if(!t.subSchema)throw'Missing required option "schema.subSchema"';this.nestedSchema=t.subSchema}}),e.editors.List.NestedModel=e.editors.List.Modal.extend({initialize:function(){e.editors.List.Modal.prototype.initialize.apply(this,arguments);var t=this.schema;if(!t.model)throw'Missing required option "schema.model"';var n=t.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()}})})(Backbone.Form)
@@ -1,95 +1,70 @@
1
- /**
2
- * Include this file _after_ the main backbone-forms file to override the default templates.
3
- * You only need to include templates you want to override.
1
+ /**
2
+ * Include this template file after backbone-forms.amd.js to override the default templates
4
3
  *
5
- * Requirements when customising templates:
6
- * - Each template must have one 'parent' element tag.
7
- * - "data-type" attributes are required.
8
- * - The main placeholder tags such as the following are required: fieldsets, fields
4
+ * 'data-*' attributes control where elements are placed
9
5
  */
10
- ;(function() {
11
- var Form = Backbone.Form;
6
+ ;(function(Form) {
12
7
 
13
-
14
- //TWITTER BOOTSTRAP TEMPLATES
15
- //Requires Bootstrap 2.x
16
- Form.setTemplates({
8
+
9
+ /**
10
+ * Bootstrap templates for Backbone Forms
11
+ */
12
+ Form.template = _.template('\
13
+ <form class="form-horizontal" data-fieldsets></form>\
14
+ ');
17
15
 
18
- //HTML
19
- form: '\
20
- <form class="form-horizontal">{{fieldsets}}</form>\
21
- ',
22
16
 
23
- fieldset: '\
24
- <fieldset>\
25
- <legend>{{legend}}</legend>\
26
- {{fields}}\
27
- </fieldset>\
28
- ',
17
+ Form.Fieldset.template = _.template('\
18
+ <fieldset data-fields>\
19
+ <% if (legend) { %>\
20
+ <legend><%= legend %></legend>\
21
+ <% } %>\
22
+ </fieldset>\
23
+ ');
29
24
 
30
- field: '\
31
- <div class="control-group field-{{key}}">\
32
- <label class="control-label" for="{{id}}">{{title}}</label>\
33
- <div class="controls">\
34
- {{editor}}\
35
- <div class="help-inline">{{error}}</div>\
36
- <div class="help-block">{{help}}</div>\
37
- </div>\
38
- </div>\
39
- ',
40
25
 
41
- nestedField: '\
42
- <div class="field-{{key}}">\
43
- <div title="{{title}}" class="input-xlarge">{{editor}}\
44
- <div class="help-inline">{{error}}</div>\
45
- </div>\
46
- <div class="help-block">{{help}}</div>\
26
+ Form.Field.template = _.template('\
27
+ <div class="control-group field-<%= key %>">\
28
+ <label class="control-label" for="<%= editorId %>"><%= title %></label>\
29
+ <div class="controls">\
30
+ <span data-editor></span>\
31
+ <div class="help-inline" data-error></div>\
32
+ <div class="help-block"><%= help %></div>\
47
33
  </div>\
48
- ',
34
+ </div>\
35
+ ');
49
36
 
50
- list: '\
51
- <div class="bbf-list">\
52
- <ul class="unstyled clearfix">{{items}}</ul>\
53
- <button class="btn bbf-add" data-action="add">Add</button>\
37
+
38
+ Form.NestedField.template = _.template('\
39
+ <div class="field-<%= key %>">\
40
+ <div title="<%= title %>" class="input-xlarge">\
41
+ <span data-editor></span>\
42
+ <div class="help-inline" data-error></div>\
54
43
  </div>\
55
- ',
44
+ <div class="help-block"><%= help %></div>\
45
+ </div>\
46
+ ');
56
47
 
57
- listItem: '\
58
- <li class="clearfix">\
59
- <div class="pull-left">{{editor}}</div>\
60
- <button type="button" class="btn bbf-del" data-action="remove">&times;</button>\
61
- </li>\
62
- ',
63
48
 
64
- date: '\
65
- <div class="bbf-date">\
66
- <select data-type="date" class="bbf-date">{{dates}}</select>\
67
- <select data-type="month" class="bbf-month">{{months}}</select>\
68
- <select data-type="year" class="bbf-year">{{years}}</select>\
69
- </div>\
70
- ',
49
+ Form.editors.List.template = _.template('\
50
+ <div class="bbf-list">\
51
+ <ul class="unstyled clearfix" data-items></ul>\
52
+ <button class="btn bbf-add" data-action="add">Add</button>\
53
+ </div>\
54
+ ');
71
55
 
72
- dateTime: '\
73
- <div class="bbf-datetime">\
74
- <p>{{date}}</p>\
75
- <p>\
76
- <select data-type="hour" style="width: 4em">{{hours}}</select>\
77
- :\
78
- <select data-type="min" style="width: 4em">{{mins}}</select>\
79
- </p>\
80
- </div>\
81
- ',
82
56
 
83
- 'list.Modal': '\
84
- <div class="bbf-list-modal">\
85
- {{summary}}\
86
- </div>\
87
- '
88
- }, {
57
+ Form.editors.List.Item.template = _.template('\
58
+ <li class="clearfix">\
59
+ <div class="pull-left" data-editor></div>\
60
+ <button type="button" class="btn bbf-del" data-action="remove">&times;</button>\
61
+ </li>\
62
+ ');
89
63
 
90
- //CLASSNAMES
91
- error: 'error' //Set on the field tag when validation fails
92
- });
64
+
65
+ Form.editors.List.Object.template = Form.editors.List.NestedModel.template = _.template('\
66
+ <div class="bbf-list-modal"><%= summary %></div>\
67
+ ');
93
68
 
94
69
 
95
- })();
70
+ })(Backbone.Form);