From c1e61f8647db06c69fbba07154521d7582f47a2f Mon Sep 17 00:00:00 2001 From: Brad Pardee Date: Thu, 19 Dec 2013 09:45:19 -0500 Subject: [PATCH 1/3] Create separate List#renderItems for use in setValue since render here was creating an orphaned el (Resolves #282) --- distribution.amd/editors/list.js | 32 +++++++++++++++++----------- distribution.amd/editors/list.min.js | 2 +- distribution/editors/list.js | 32 +++++++++++++++++----------- distribution/editors/list.min.js | 2 +- src/editors/extra/list.js | 32 +++++++++++++++++----------- 5 files changed, 62 insertions(+), 38 deletions(-) diff --git a/distribution.amd/editors/list.js b/distribution.amd/editors/list.js index fc1474be..ffd9e380 100644 --- a/distribution.amd/editors/list.js +++ b/distribution.amd/editors/list.js @@ -50,15 +50,31 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba }, render: function() { - var self = this, - value = this.value || []; - //Create main element var $el = $($.trim(this.template())); //Store a reference to the list (item container) this.$list = $el.is('[data-items]') ? $el : $el.find('[data-items]'); + this.renderItems(); + + this.setElement($el); + this.$el.attr('id', this.id); + this.$el.attr('name', this.key); + + if (this.hasFocus) this.trigger('blur', this); + + return this; + }, + + renderItems: function() { + var self = this, + value = this.value || []; + + // Remove any old items + this.items = []; + this.$list.empty(); + //Add existing items if (value.length) { _.each(value, function(itemValue) { @@ -70,14 +86,6 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba else { if (!this.Editor.isAsync) this.addItem(); } - - this.setElement($el); - this.$el.attr('id', this.id); - this.$el.attr('name', this.key); - - if (this.hasFocus) this.trigger('blur', this); - - return this; }, /** @@ -194,7 +202,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba setValue: function(value) { this.value = value; - this.render(); + this.renderItems(); }, focus: function() { diff --git a/distribution.amd/editors/list.min.js b/distribution.amd/editors/list.min.js index 772f5831..16a0bf62 100644 --- a/distribution.amd/editors/list.min.js +++ b/distribution.amd/editors/list.min.js @@ -1 +1 @@ -define(["jquery","underscore","backbone","backbone-forms"],function(e,t,n){(function(r){r.editors.List=r.editors.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(e){e=e||{};var t=r.editors;t.Base.prototype.initialize.call(this,e);var n=this.schema;if(!n)throw new Error("Missing required option 'schema'");this.template=e.template||this.constructor.template,this.Editor=function(){var e=n.itemType;return e?t.List[e]?t.List[e]:t[e]:t.Text}(),this.items=[]},render:function(){var n=this,r=this.value||[],i=e(e.trim(this.template()));return this.$list=i.is("[data-items]")?i:i.find("[data-items]"),r.length?t.each(r,function(e){n.addItem(e)}):this.Editor.isAsync||this.addItem(),this.setElement(i),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},addItem:function(e,n){var i=this,s=r.editors,o=(new s.List.Item({list:this,form:this.form,schema:this.schema,value:e,Editor:this.Editor,key:this.key})).render(),u=function(){i.items.push(o),i.$list.append(o.el),o.editor.on("all",function(e){if(e==="change")return;var n=t.toArray(arguments);n[0]="item:"+e,n.splice(1,0,i),s.List.prototype.trigger.apply(this,n)},i),o.editor.on("change",function(){o.addEventTriggered||(o.addEventTriggered=!0,this.trigger("add",this,o.editor)),this.trigger("item:change",this,o.editor),this.trigger("change",this)},i),o.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},i),o.editor.on("blur",function(){if(!this.hasFocus)return;var e=this;setTimeout(function(){if(t.find(e.items,function(e){return e.editor.hasFocus}))return;e.trigger("blur",e)},0)},i);if(n||e)o.addEventTriggered=!0;n&&(i.trigger("add",i,o.editor),i.trigger("change",i))};return this.Editor.isAsync?o.editor.on("readyToAdd",u,this):(u(),o.editor.focus()),o},removeItem:function(e){var n=this.schema.confirmDelete;if(n&&!confirm(n))return;var r=t.indexOf(this.items,e);this.items[r].remove(),this.items.splice(r,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=t.map(this.items,function(e){return e.getValue()});return t.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=t.find(this.items,function(e){return e.editor.hasFocus});e&&e.editor.blur()},remove:function(){t.invoke(this.items,"remove"),r.editors.Base.prototype.remove.call(this)},validate:function(){if(!this.validators)return null;var e=t.map(this.items,function(e){return e.validate()}),n=t.compact(e).length?!0:!1;if(!n)return null;var r={type:"list",message:"Some of the items in the list failed validation",errors:e};return r}},{template:t.template('
',null,r.templateSettings)}),r.editors.List.Item=r.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(e){this.list=e.list,this.schema=e.schema||this.list.schema,this.value=e.value,this.Editor=e.Editor||r.editors.Text,this.key=e.key,this.template=e.template||this.schema.itemTemplate||this.constructor.template,this.errorClassName=e.errorClassName||this.constructor.errorClassName,this.form=e.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 t=e(e.trim(this.template()));return t.find("[data-editor]").append(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(),n.View.prototype.remove.call(this)},validate:function(){var e=this.getValue(),n=this.list.form?this.list.form.getValue():{},r=this.schema.validators,i=this.getValidator;if(!r)return null;var s=null;return t.every(r,function(t){return s=i(t)(e,n),s?!1:!0}),s?this.setError(s):this.clearError(),s?s: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:t.template('
',null,r.templateSettings),errorClassName:"error"}),r.editors.List.Modal=r.editors.Base.extend({events:{click:"openEditor"},initialize:function(e){e=e||{},r.editors.Base.prototype.initialize.call(this,e);if(!r.editors.List.Modal.ModalAdapter)throw new Error("A ModalAdapter is required");this.form=e.form;if(!e.form)throw new Error('Missing required option: "form"');this.template=e.template||this.constructor.template},render:function(){var e=this;return t.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(e.trim(this.template({summary:this.getStringValue()})))},itemToString:function(e){var n=function(e){var t={key:e};return r.Field.prototype.createTitle.call(t)};e=e||{};var i=[];return t.each(this.nestedSchema,function(r,s){var o=r.title?r.title:n(s),u=e[s];if(t.isUndefined(u)||t.isNull(u))u="";i.push(o+": "+u)}),i.join("
")},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?"[Empty]":e.itemToString?e.itemToString(n):this.itemToString(n)},openEditor:function(){var e=this,n=this.form.constructor,i=this.modalForm=new n({schema:this.nestedSchema,data:this.value}),s=this.modal=new r.editors.List.Modal.ModalAdapter({content:i,animate:!0});s.open(),this.trigger("open",this),this.trigger("focus",this),s.on("cancel",this.onModalClosed,this),s.on("ok",t.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:t.template("
<%= summary %>
",null,r.templateSettings),ModalAdapter:n.BootstrapModal,isAsync:!0}),r.editors.List.Object=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.subSchema)throw new Error('Missing required option "schema.subSchema"');this.nestedSchema=e.subSchema}}),r.editors.List.NestedModel=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.model)throw new Error('Missing required option "schema.model"');var n=e.model.prototype.schema;this.nestedSchema=t.isFunction(n)?n():n},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?null:e.itemToString?e.itemToString(n):(new e.model(n)).toString()}})})(n.Form)}) \ No newline at end of file +define(["jquery","underscore","backbone","backbone-forms"],function(e,t,n){(function(r){r.editors.List=r.editors.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(e){e=e||{};var t=r.editors;t.Base.prototype.initialize.call(this,e);var n=this.schema;if(!n)throw new Error("Missing required option 'schema'");this.template=e.template||this.constructor.template,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=e(e.trim(this.template()));return this.$list=t.is("[data-items]")?t:t.find("[data-items]"),this.renderItems(),this.setElement(t),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},renderItems:function(){var e=this,n=this.value||[];this.items=[],this.$list.empty(),n.length?t.each(n,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem()},addItem:function(e,n){var i=this,s=r.editors,o=(new s.List.Item({list:this,form:this.form,schema:this.schema,value:e,Editor:this.Editor,key:this.key})).render(),u=function(){i.items.push(o),i.$list.append(o.el),o.editor.on("all",function(e){if(e==="change")return;var n=t.toArray(arguments);n[0]="item:"+e,n.splice(1,0,i),s.List.prototype.trigger.apply(this,n)},i),o.editor.on("change",function(){o.addEventTriggered||(o.addEventTriggered=!0,this.trigger("add",this,o.editor)),this.trigger("item:change",this,o.editor),this.trigger("change",this)},i),o.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},i),o.editor.on("blur",function(){if(!this.hasFocus)return;var e=this;setTimeout(function(){if(t.find(e.items,function(e){return e.editor.hasFocus}))return;e.trigger("blur",e)},0)},i);if(n||e)o.addEventTriggered=!0;n&&(i.trigger("add",i,o.editor),i.trigger("change",i))};return this.Editor.isAsync?o.editor.on("readyToAdd",u,this):(u(),o.editor.focus()),o},removeItem:function(e){var n=this.schema.confirmDelete;if(n&&!confirm(n))return;var r=t.indexOf(this.items,e);this.items[r].remove(),this.items.splice(r,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=t.map(this.items,function(e){return e.getValue()});return t.without(e,undefined,"")},setValue:function(e){this.value=e,this.renderItems()},focus:function(){if(this.hasFocus)return;this.items[0]&&this.items[0].editor.focus()},blur:function(){if(!this.hasFocus)return;var e=t.find(this.items,function(e){return e.editor.hasFocus});e&&e.editor.blur()},remove:function(){t.invoke(this.items,"remove"),r.editors.Base.prototype.remove.call(this)},validate:function(){if(!this.validators)return null;var e=t.map(this.items,function(e){return e.validate()}),n=t.compact(e).length?!0:!1;if(!n)return null;var r={type:"list",message:"Some of the items in the list failed validation",errors:e};return r}},{template:t.template('
',null,r.templateSettings)}),r.editors.List.Item=r.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(e){this.list=e.list,this.schema=e.schema||this.list.schema,this.value=e.value,this.Editor=e.Editor||r.editors.Text,this.key=e.key,this.template=e.template||this.schema.itemTemplate||this.constructor.template,this.errorClassName=e.errorClassName||this.constructor.errorClassName,this.form=e.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 t=e(e.trim(this.template()));return t.find("[data-editor]").append(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(),n.View.prototype.remove.call(this)},validate:function(){var e=this.getValue(),n=this.list.form?this.list.form.getValue():{},r=this.schema.validators,i=this.getValidator;if(!r)return null;var s=null;return t.every(r,function(t){return s=i(t)(e,n),s?!1:!0}),s?this.setError(s):this.clearError(),s?s: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:t.template('
',null,r.templateSettings),errorClassName:"error"}),r.editors.List.Modal=r.editors.Base.extend({events:{click:"openEditor"},initialize:function(e){e=e||{},r.editors.Base.prototype.initialize.call(this,e);if(!r.editors.List.Modal.ModalAdapter)throw new Error("A ModalAdapter is required");this.form=e.form;if(!e.form)throw new Error('Missing required option: "form"');this.template=e.template||this.constructor.template},render:function(){var e=this;return t.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(e.trim(this.template({summary:this.getStringValue()})))},itemToString:function(e){var n=function(e){var t={key:e};return r.Field.prototype.createTitle.call(t)};e=e||{};var i=[];return t.each(this.nestedSchema,function(r,s){var o=r.title?r.title:n(s),u=e[s];if(t.isUndefined(u)||t.isNull(u))u="";i.push(o+": "+u)}),i.join("
")},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?"[Empty]":e.itemToString?e.itemToString(n):this.itemToString(n)},openEditor:function(){var e=this,n=this.form.constructor,i=this.modalForm=new n({schema:this.nestedSchema,data:this.value}),s=this.modal=new r.editors.List.Modal.ModalAdapter({content:i,animate:!0});s.open(),this.trigger("open",this),this.trigger("focus",this),s.on("cancel",this.onModalClosed,this),s.on("ok",t.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:t.template("
<%= summary %>
",null,r.templateSettings),ModalAdapter:n.BootstrapModal,isAsync:!0}),r.editors.List.Object=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.subSchema)throw new Error('Missing required option "schema.subSchema"');this.nestedSchema=e.subSchema}}),r.editors.List.NestedModel=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.model)throw new Error('Missing required option "schema.model"');var n=e.model.prototype.schema;this.nestedSchema=t.isFunction(n)?n():n},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?null:e.itemToString?e.itemToString(n):(new e.model(n)).toString()}})})(n.Form)}) \ No newline at end of file diff --git a/distribution/editors/list.js b/distribution/editors/list.js index 36509bc4..cc17ac90 100644 --- a/distribution/editors/list.js +++ b/distribution/editors/list.js @@ -48,15 +48,31 @@ }, render: function() { - var self = this, - value = this.value || []; - //Create main element var $el = $($.trim(this.template())); //Store a reference to the list (item container) this.$list = $el.is('[data-items]') ? $el : $el.find('[data-items]'); + this.renderItems(); + + this.setElement($el); + this.$el.attr('id', this.id); + this.$el.attr('name', this.key); + + if (this.hasFocus) this.trigger('blur', this); + + return this; + }, + + renderItems: function() { + var self = this, + value = this.value || []; + + // Remove any old items + this.items = []; + this.$list.empty(); + //Add existing items if (value.length) { _.each(value, function(itemValue) { @@ -68,14 +84,6 @@ else { if (!this.Editor.isAsync) this.addItem(); } - - this.setElement($el); - this.$el.attr('id', this.id); - this.$el.attr('name', this.key); - - if (this.hasFocus) this.trigger('blur', this); - - return this; }, /** @@ -192,7 +200,7 @@ setValue: function(value) { this.value = value; - this.render(); + this.renderItems(); }, focus: function() { diff --git a/distribution/editors/list.min.js b/distribution/editors/list.min.js index 2411b129..be5d88ab 100644 --- a/distribution/editors/list.min.js +++ b/distribution/editors/list.min.js @@ -1 +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 new Error("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('
',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('
',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 new Error("A ModalAdapter is required");this.form=t.form;if(!t.form)throw new Error('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("
")},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("
<%= summary %>
",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 new Error('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 new Error('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) \ No newline at end of file +(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 new Error("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=$($.trim(this.template()));return this.$list=e.is("[data-items]")?e:e.find("[data-items]"),this.renderItems(),this.setElement(e),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},renderItems:function(){var e=this,t=this.value||[];this.items=[],this.$list.empty(),t.length?_.each(t,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem()},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.renderItems()},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('
',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('
',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 new Error("A ModalAdapter is required");this.form=t.form;if(!t.form)throw new Error('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("
")},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("
<%= summary %>
",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 new Error('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 new Error('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) \ No newline at end of file diff --git a/src/editors/extra/list.js b/src/editors/extra/list.js index 36509bc4..cc17ac90 100644 --- a/src/editors/extra/list.js +++ b/src/editors/extra/list.js @@ -48,15 +48,31 @@ }, render: function() { - var self = this, - value = this.value || []; - //Create main element var $el = $($.trim(this.template())); //Store a reference to the list (item container) this.$list = $el.is('[data-items]') ? $el : $el.find('[data-items]'); + this.renderItems(); + + this.setElement($el); + this.$el.attr('id', this.id); + this.$el.attr('name', this.key); + + if (this.hasFocus) this.trigger('blur', this); + + return this; + }, + + renderItems: function() { + var self = this, + value = this.value || []; + + // Remove any old items + this.items = []; + this.$list.empty(); + //Add existing items if (value.length) { _.each(value, function(itemValue) { @@ -68,14 +84,6 @@ else { if (!this.Editor.isAsync) this.addItem(); } - - this.setElement($el); - this.$el.attr('id', this.id); - this.$el.attr('name', this.key); - - if (this.hasFocus) this.trigger('blur', this); - - return this; }, /** @@ -192,7 +200,7 @@ setValue: function(value) { this.value = value; - this.render(); + this.renderItems(); }, focus: function() { From 9ce8d3f565b66c34f16bdced43674691d9b1417d Mon Sep 17 00:00:00 2001 From: Brad Pardee Date: Sat, 22 Mar 2014 11:13:19 -0400 Subject: [PATCH 2/3] Don't empty on setValue, it could have default items for a custom template. Instead remove each item element --- src/editors/extra/list.js | 65 ++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/src/editors/extra/list.js b/src/editors/extra/list.js index cc17ac90..150a2872 100644 --- a/src/editors/extra/list.js +++ b/src/editors/extra/list.js @@ -2,7 +2,7 @@ /** * List editor - * + * * An array editor. Creates a list of other editor items. * * Special options: @@ -59,9 +59,9 @@ this.setElement($el); this.$el.attr('id', this.id); this.$el.attr('name', this.key); - + if (this.hasFocus) this.trigger('blur', this); - + return this; }, @@ -69,9 +69,12 @@ var self = this, value = this.value || []; - // Remove any old items + // Easier to just empty the $list but we could potentially have default items + // for a custom template. + _.each(this.items, function(item) { + item.$el.remove(); + }); this.items = []; - this.$list.empty(); //Add existing items if (value.length) { @@ -104,11 +107,11 @@ Editor: this.Editor, key: this.key }).render(); - + var _addItem = function() { self.items.push(item); self.$list.append(item.el); - + item.editor.on('all', function(event) { if (event === 'change') return; @@ -142,11 +145,11 @@ self.trigger('blur', self); }, 0); }, self); - + if (userInitiated || value) { item.addEventTriggered = true; } - + if (userInitiated) { self.trigger('add', self, item.editor); self.trigger('change', self); @@ -163,7 +166,7 @@ _addItem(); item.editor.focus(); } - + return item; }, @@ -180,7 +183,7 @@ this.items[index].remove(); this.items.splice(index, 1); - + if (item.addEventTriggered) { this.trigger('remove', this, item.editor); this.trigger('change', this); @@ -202,18 +205,18 @@ this.value = value; this.renderItems(); }, - + focus: function() { if (this.hasFocus) return; if (this.items[0]) this.items[0].editor.focus(); }, - + blur: function() { if (!this.hasFocus) return; var focusedItem = _.find(this.items, function(item) { return item.editor.hasFocus; }); - + if (focusedItem) focusedItem.editor.blur(); }, @@ -225,10 +228,10 @@ Form.editors.Base.prototype.remove.call(this); }, - + /** * Run validation - * + * * @return {Object|Null} */ validate: function() { @@ -318,7 +321,7 @@ //Replace the entire element so there isn't a wrapper tag this.setElement($el); - + return this; }, @@ -329,11 +332,11 @@ setValue: function(value) { this.editor.setValue(value); }, - + focus: function() { this.editor.focus(); }, - + blur: function() { this.editor.blur(); }, @@ -402,7 +405,7 @@ /** - * Base modal object editor for use with the List editor; used by Object + * Base modal object editor for use with the List editor; used by Object * and NestedModal list types */ Form.editors.List.Modal = Form.editors.Base.extend({ @@ -421,9 +424,9 @@ */ initialize: function(options) { options = options || {}; - + Form.editors.Base.prototype.initialize.call(this, options); - + //Dependencies if (!Form.editors.List.Modal.ModalAdapter) throw new Error('A ModalAdapter is required'); @@ -472,7 +475,7 @@ * Function which returns a generic string representation of an object * * @param {Object} value - * + * * @return {String} */ itemToString: function(value) { @@ -509,7 +512,7 @@ //If there's a specified toString use that if (schema.itemToString) return schema.itemToString(value); - + //Otherwise use the generic method or custom overridden method return this.itemToString(value); }, @@ -534,7 +537,7 @@ this.trigger('focus', this); modal.on('cancel', this.onModalClosed, this); - + modal.on('ok', _.bind(this.onModalSubmitted, this)); }, @@ -558,7 +561,7 @@ this.renderSummary(); if (isNew) this.trigger('readyToAdd'); - + this.trigger('change', this); this.onModalClosed(); @@ -582,16 +585,16 @@ setValue: function(value) { this.value = value; }, - + focus: function() { if (this.hasFocus) return; this.openEditor(); }, - + blur: function() { if (!this.hasFocus) return; - + if (this.modal) { this.modal.trigger('cancel'); } @@ -606,7 +609,7 @@ //Defaults to BootstrapModal (http://github.com/powmedia/backbone.bootstrap-modal) //Can be replaced with another adapter that implements the same interface. ModalAdapter: Backbone.BootstrapModal, - + //Make the wait list for the 'ready' event before adding the item to the list isAsync: true }); @@ -649,7 +652,7 @@ //If there's a specified toString use that if (schema.itemToString) return schema.itemToString(value); - + //Otherwise use the model return new (schema.model)(value).toString(); } From 2ee0c5dd49c9fdd54207aab76de77950662a7a93 Mon Sep 17 00:00:00 2001 From: Brad Pardee Date: Sat, 22 Mar 2014 11:23:05 -0400 Subject: [PATCH 3/3] Forgot to build distribution --- distribution.amd/editors/list.js | 65 +++++++++++++++------------- distribution.amd/editors/list.min.js | 2 +- distribution/editors/list.js | 65 +++++++++++++++------------- distribution/editors/list.min.js | 2 +- 4 files changed, 70 insertions(+), 64 deletions(-) diff --git a/distribution.amd/editors/list.js b/distribution.amd/editors/list.js index ffd9e380..a1cf69ab 100644 --- a/distribution.amd/editors/list.js +++ b/distribution.amd/editors/list.js @@ -4,7 +4,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba /** * List editor - * + * * An array editor. Creates a list of other editor items. * * Special options: @@ -61,9 +61,9 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba this.setElement($el); this.$el.attr('id', this.id); this.$el.attr('name', this.key); - + if (this.hasFocus) this.trigger('blur', this); - + return this; }, @@ -71,9 +71,12 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba var self = this, value = this.value || []; - // Remove any old items + // Easier to just empty the $list but we could potentially have default items + // for a custom template. + _.each(this.items, function(item) { + item.$el.remove(); + }); this.items = []; - this.$list.empty(); //Add existing items if (value.length) { @@ -106,11 +109,11 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba Editor: this.Editor, key: this.key }).render(); - + var _addItem = function() { self.items.push(item); self.$list.append(item.el); - + item.editor.on('all', function(event) { if (event === 'change') return; @@ -144,11 +147,11 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba self.trigger('blur', self); }, 0); }, self); - + if (userInitiated || value) { item.addEventTriggered = true; } - + if (userInitiated) { self.trigger('add', self, item.editor); self.trigger('change', self); @@ -165,7 +168,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba _addItem(); item.editor.focus(); } - + return item; }, @@ -182,7 +185,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba this.items[index].remove(); this.items.splice(index, 1); - + if (item.addEventTriggered) { this.trigger('remove', this, item.editor); this.trigger('change', this); @@ -204,18 +207,18 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba this.value = value; this.renderItems(); }, - + focus: function() { if (this.hasFocus) return; if (this.items[0]) this.items[0].editor.focus(); }, - + blur: function() { if (!this.hasFocus) return; var focusedItem = _.find(this.items, function(item) { return item.editor.hasFocus; }); - + if (focusedItem) focusedItem.editor.blur(); }, @@ -227,10 +230,10 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba Form.editors.Base.prototype.remove.call(this); }, - + /** * Run validation - * + * * @return {Object|Null} */ validate: function() { @@ -320,7 +323,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba //Replace the entire element so there isn't a wrapper tag this.setElement($el); - + return this; }, @@ -331,11 +334,11 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba setValue: function(value) { this.editor.setValue(value); }, - + focus: function() { this.editor.focus(); }, - + blur: function() { this.editor.blur(); }, @@ -404,7 +407,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba /** - * Base modal object editor for use with the List editor; used by Object + * Base modal object editor for use with the List editor; used by Object * and NestedModal list types */ Form.editors.List.Modal = Form.editors.Base.extend({ @@ -423,9 +426,9 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba */ initialize: function(options) { options = options || {}; - + Form.editors.Base.prototype.initialize.call(this, options); - + //Dependencies if (!Form.editors.List.Modal.ModalAdapter) throw new Error('A ModalAdapter is required'); @@ -474,7 +477,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba * Function which returns a generic string representation of an object * * @param {Object} value - * + * * @return {String} */ itemToString: function(value) { @@ -511,7 +514,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba //If there's a specified toString use that if (schema.itemToString) return schema.itemToString(value); - + //Otherwise use the generic method or custom overridden method return this.itemToString(value); }, @@ -536,7 +539,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba this.trigger('focus', this); modal.on('cancel', this.onModalClosed, this); - + modal.on('ok', _.bind(this.onModalSubmitted, this)); }, @@ -560,7 +563,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba this.renderSummary(); if (isNew) this.trigger('readyToAdd'); - + this.trigger('change', this); this.onModalClosed(); @@ -584,16 +587,16 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba setValue: function(value) { this.value = value; }, - + focus: function() { if (this.hasFocus) return; this.openEditor(); }, - + blur: function() { if (!this.hasFocus) return; - + if (this.modal) { this.modal.trigger('cancel'); } @@ -608,7 +611,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba //Defaults to BootstrapModal (http://github.com/powmedia/backbone.bootstrap-modal) //Can be replaced with another adapter that implements the same interface. ModalAdapter: Backbone.BootstrapModal, - + //Make the wait list for the 'ready' event before adding the item to the list isAsync: true }); @@ -651,7 +654,7 @@ define(['jquery', 'underscore', 'backbone', 'backbone-forms'], function($, _, Ba //If there's a specified toString use that if (schema.itemToString) return schema.itemToString(value); - + //Otherwise use the model return new (schema.model)(value).toString(); } diff --git a/distribution.amd/editors/list.min.js b/distribution.amd/editors/list.min.js index 16a0bf62..764201d0 100644 --- a/distribution.amd/editors/list.min.js +++ b/distribution.amd/editors/list.min.js @@ -1 +1 @@ -define(["jquery","underscore","backbone","backbone-forms"],function(e,t,n){(function(r){r.editors.List=r.editors.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(e){e=e||{};var t=r.editors;t.Base.prototype.initialize.call(this,e);var n=this.schema;if(!n)throw new Error("Missing required option 'schema'");this.template=e.template||this.constructor.template,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=e(e.trim(this.template()));return this.$list=t.is("[data-items]")?t:t.find("[data-items]"),this.renderItems(),this.setElement(t),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},renderItems:function(){var e=this,n=this.value||[];this.items=[],this.$list.empty(),n.length?t.each(n,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem()},addItem:function(e,n){var i=this,s=r.editors,o=(new s.List.Item({list:this,form:this.form,schema:this.schema,value:e,Editor:this.Editor,key:this.key})).render(),u=function(){i.items.push(o),i.$list.append(o.el),o.editor.on("all",function(e){if(e==="change")return;var n=t.toArray(arguments);n[0]="item:"+e,n.splice(1,0,i),s.List.prototype.trigger.apply(this,n)},i),o.editor.on("change",function(){o.addEventTriggered||(o.addEventTriggered=!0,this.trigger("add",this,o.editor)),this.trigger("item:change",this,o.editor),this.trigger("change",this)},i),o.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},i),o.editor.on("blur",function(){if(!this.hasFocus)return;var e=this;setTimeout(function(){if(t.find(e.items,function(e){return e.editor.hasFocus}))return;e.trigger("blur",e)},0)},i);if(n||e)o.addEventTriggered=!0;n&&(i.trigger("add",i,o.editor),i.trigger("change",i))};return this.Editor.isAsync?o.editor.on("readyToAdd",u,this):(u(),o.editor.focus()),o},removeItem:function(e){var n=this.schema.confirmDelete;if(n&&!confirm(n))return;var r=t.indexOf(this.items,e);this.items[r].remove(),this.items.splice(r,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=t.map(this.items,function(e){return e.getValue()});return t.without(e,undefined,"")},setValue:function(e){this.value=e,this.renderItems()},focus:function(){if(this.hasFocus)return;this.items[0]&&this.items[0].editor.focus()},blur:function(){if(!this.hasFocus)return;var e=t.find(this.items,function(e){return e.editor.hasFocus});e&&e.editor.blur()},remove:function(){t.invoke(this.items,"remove"),r.editors.Base.prototype.remove.call(this)},validate:function(){if(!this.validators)return null;var e=t.map(this.items,function(e){return e.validate()}),n=t.compact(e).length?!0:!1;if(!n)return null;var r={type:"list",message:"Some of the items in the list failed validation",errors:e};return r}},{template:t.template('
',null,r.templateSettings)}),r.editors.List.Item=r.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(e){this.list=e.list,this.schema=e.schema||this.list.schema,this.value=e.value,this.Editor=e.Editor||r.editors.Text,this.key=e.key,this.template=e.template||this.schema.itemTemplate||this.constructor.template,this.errorClassName=e.errorClassName||this.constructor.errorClassName,this.form=e.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 t=e(e.trim(this.template()));return t.find("[data-editor]").append(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(),n.View.prototype.remove.call(this)},validate:function(){var e=this.getValue(),n=this.list.form?this.list.form.getValue():{},r=this.schema.validators,i=this.getValidator;if(!r)return null;var s=null;return t.every(r,function(t){return s=i(t)(e,n),s?!1:!0}),s?this.setError(s):this.clearError(),s?s: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:t.template('
',null,r.templateSettings),errorClassName:"error"}),r.editors.List.Modal=r.editors.Base.extend({events:{click:"openEditor"},initialize:function(e){e=e||{},r.editors.Base.prototype.initialize.call(this,e);if(!r.editors.List.Modal.ModalAdapter)throw new Error("A ModalAdapter is required");this.form=e.form;if(!e.form)throw new Error('Missing required option: "form"');this.template=e.template||this.constructor.template},render:function(){var e=this;return t.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(e.trim(this.template({summary:this.getStringValue()})))},itemToString:function(e){var n=function(e){var t={key:e};return r.Field.prototype.createTitle.call(t)};e=e||{};var i=[];return t.each(this.nestedSchema,function(r,s){var o=r.title?r.title:n(s),u=e[s];if(t.isUndefined(u)||t.isNull(u))u="";i.push(o+": "+u)}),i.join("
")},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?"[Empty]":e.itemToString?e.itemToString(n):this.itemToString(n)},openEditor:function(){var e=this,n=this.form.constructor,i=this.modalForm=new n({schema:this.nestedSchema,data:this.value}),s=this.modal=new r.editors.List.Modal.ModalAdapter({content:i,animate:!0});s.open(),this.trigger("open",this),this.trigger("focus",this),s.on("cancel",this.onModalClosed,this),s.on("ok",t.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:t.template("
<%= summary %>
",null,r.templateSettings),ModalAdapter:n.BootstrapModal,isAsync:!0}),r.editors.List.Object=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.subSchema)throw new Error('Missing required option "schema.subSchema"');this.nestedSchema=e.subSchema}}),r.editors.List.NestedModel=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.model)throw new Error('Missing required option "schema.model"');var n=e.model.prototype.schema;this.nestedSchema=t.isFunction(n)?n():n},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?null:e.itemToString?e.itemToString(n):(new e.model(n)).toString()}})})(n.Form)}) \ No newline at end of file +define(["jquery","underscore","backbone","backbone-forms"],function(e,t,n){(function(r){r.editors.List=r.editors.Base.extend({events:{'click [data-action="add"]':function(e){e.preventDefault(),this.addItem(null,!0)}},initialize:function(e){e=e||{};var t=r.editors;t.Base.prototype.initialize.call(this,e);var n=this.schema;if(!n)throw new Error("Missing required option 'schema'");this.template=e.template||this.constructor.template,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=e(e.trim(this.template()));return this.$list=t.is("[data-items]")?t:t.find("[data-items]"),this.renderItems(),this.setElement(t),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},renderItems:function(){var e=this,n=this.value||[];t.each(this.items,function(e){e.$el.remove()}),this.items=[],n.length?t.each(n,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem()},addItem:function(e,n){var i=this,s=r.editors,o=(new s.List.Item({list:this,form:this.form,schema:this.schema,value:e,Editor:this.Editor,key:this.key})).render(),u=function(){i.items.push(o),i.$list.append(o.el),o.editor.on("all",function(e){if(e==="change")return;var n=t.toArray(arguments);n[0]="item:"+e,n.splice(1,0,i),s.List.prototype.trigger.apply(this,n)},i),o.editor.on("change",function(){o.addEventTriggered||(o.addEventTriggered=!0,this.trigger("add",this,o.editor)),this.trigger("item:change",this,o.editor),this.trigger("change",this)},i),o.editor.on("focus",function(){if(this.hasFocus)return;this.trigger("focus",this)},i),o.editor.on("blur",function(){if(!this.hasFocus)return;var e=this;setTimeout(function(){if(t.find(e.items,function(e){return e.editor.hasFocus}))return;e.trigger("blur",e)},0)},i);if(n||e)o.addEventTriggered=!0;n&&(i.trigger("add",i,o.editor),i.trigger("change",i))};return this.Editor.isAsync?o.editor.on("readyToAdd",u,this):(u(),o.editor.focus()),o},removeItem:function(e){var n=this.schema.confirmDelete;if(n&&!confirm(n))return;var r=t.indexOf(this.items,e);this.items[r].remove(),this.items.splice(r,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=t.map(this.items,function(e){return e.getValue()});return t.without(e,undefined,"")},setValue:function(e){this.value=e,this.renderItems()},focus:function(){if(this.hasFocus)return;this.items[0]&&this.items[0].editor.focus()},blur:function(){if(!this.hasFocus)return;var e=t.find(this.items,function(e){return e.editor.hasFocus});e&&e.editor.blur()},remove:function(){t.invoke(this.items,"remove"),r.editors.Base.prototype.remove.call(this)},validate:function(){if(!this.validators)return null;var e=t.map(this.items,function(e){return e.validate()}),n=t.compact(e).length?!0:!1;if(!n)return null;var r={type:"list",message:"Some of the items in the list failed validation",errors:e};return r}},{template:t.template('
',null,r.templateSettings)}),r.editors.List.Item=r.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(e){this.list=e.list,this.schema=e.schema||this.list.schema,this.value=e.value,this.Editor=e.Editor||r.editors.Text,this.key=e.key,this.template=e.template||this.schema.itemTemplate||this.constructor.template,this.errorClassName=e.errorClassName||this.constructor.errorClassName,this.form=e.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 t=e(e.trim(this.template()));return t.find("[data-editor]").append(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(),n.View.prototype.remove.call(this)},validate:function(){var e=this.getValue(),n=this.list.form?this.list.form.getValue():{},r=this.schema.validators,i=this.getValidator;if(!r)return null;var s=null;return t.every(r,function(t){return s=i(t)(e,n),s?!1:!0}),s?this.setError(s):this.clearError(),s?s: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:t.template('
',null,r.templateSettings),errorClassName:"error"}),r.editors.List.Modal=r.editors.Base.extend({events:{click:"openEditor"},initialize:function(e){e=e||{},r.editors.Base.prototype.initialize.call(this,e);if(!r.editors.List.Modal.ModalAdapter)throw new Error("A ModalAdapter is required");this.form=e.form;if(!e.form)throw new Error('Missing required option: "form"');this.template=e.template||this.constructor.template},render:function(){var e=this;return t.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(e.trim(this.template({summary:this.getStringValue()})))},itemToString:function(e){var n=function(e){var t={key:e};return r.Field.prototype.createTitle.call(t)};e=e||{};var i=[];return t.each(this.nestedSchema,function(r,s){var o=r.title?r.title:n(s),u=e[s];if(t.isUndefined(u)||t.isNull(u))u="";i.push(o+": "+u)}),i.join("
")},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?"[Empty]":e.itemToString?e.itemToString(n):this.itemToString(n)},openEditor:function(){var e=this,n=this.form.constructor,i=this.modalForm=new n({schema:this.nestedSchema,data:this.value}),s=this.modal=new r.editors.List.Modal.ModalAdapter({content:i,animate:!0});s.open(),this.trigger("open",this),this.trigger("focus",this),s.on("cancel",this.onModalClosed,this),s.on("ok",t.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:t.template("
<%= summary %>
",null,r.templateSettings),ModalAdapter:n.BootstrapModal,isAsync:!0}),r.editors.List.Object=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.subSchema)throw new Error('Missing required option "schema.subSchema"');this.nestedSchema=e.subSchema}}),r.editors.List.NestedModel=r.editors.List.Modal.extend({initialize:function(){r.editors.List.Modal.prototype.initialize.apply(this,arguments);var e=this.schema;if(!e.model)throw new Error('Missing required option "schema.model"');var n=e.model.prototype.schema;this.nestedSchema=t.isFunction(n)?n():n},getStringValue:function(){var e=this.schema,n=this.getValue();return t.isEmpty(n)?null:e.itemToString?e.itemToString(n):(new e.model(n)).toString()}})})(n.Form)}) \ No newline at end of file diff --git a/distribution/editors/list.js b/distribution/editors/list.js index cc17ac90..150a2872 100644 --- a/distribution/editors/list.js +++ b/distribution/editors/list.js @@ -2,7 +2,7 @@ /** * List editor - * + * * An array editor. Creates a list of other editor items. * * Special options: @@ -59,9 +59,9 @@ this.setElement($el); this.$el.attr('id', this.id); this.$el.attr('name', this.key); - + if (this.hasFocus) this.trigger('blur', this); - + return this; }, @@ -69,9 +69,12 @@ var self = this, value = this.value || []; - // Remove any old items + // Easier to just empty the $list but we could potentially have default items + // for a custom template. + _.each(this.items, function(item) { + item.$el.remove(); + }); this.items = []; - this.$list.empty(); //Add existing items if (value.length) { @@ -104,11 +107,11 @@ Editor: this.Editor, key: this.key }).render(); - + var _addItem = function() { self.items.push(item); self.$list.append(item.el); - + item.editor.on('all', function(event) { if (event === 'change') return; @@ -142,11 +145,11 @@ self.trigger('blur', self); }, 0); }, self); - + if (userInitiated || value) { item.addEventTriggered = true; } - + if (userInitiated) { self.trigger('add', self, item.editor); self.trigger('change', self); @@ -163,7 +166,7 @@ _addItem(); item.editor.focus(); } - + return item; }, @@ -180,7 +183,7 @@ this.items[index].remove(); this.items.splice(index, 1); - + if (item.addEventTriggered) { this.trigger('remove', this, item.editor); this.trigger('change', this); @@ -202,18 +205,18 @@ this.value = value; this.renderItems(); }, - + focus: function() { if (this.hasFocus) return; if (this.items[0]) this.items[0].editor.focus(); }, - + blur: function() { if (!this.hasFocus) return; var focusedItem = _.find(this.items, function(item) { return item.editor.hasFocus; }); - + if (focusedItem) focusedItem.editor.blur(); }, @@ -225,10 +228,10 @@ Form.editors.Base.prototype.remove.call(this); }, - + /** * Run validation - * + * * @return {Object|Null} */ validate: function() { @@ -318,7 +321,7 @@ //Replace the entire element so there isn't a wrapper tag this.setElement($el); - + return this; }, @@ -329,11 +332,11 @@ setValue: function(value) { this.editor.setValue(value); }, - + focus: function() { this.editor.focus(); }, - + blur: function() { this.editor.blur(); }, @@ -402,7 +405,7 @@ /** - * Base modal object editor for use with the List editor; used by Object + * Base modal object editor for use with the List editor; used by Object * and NestedModal list types */ Form.editors.List.Modal = Form.editors.Base.extend({ @@ -421,9 +424,9 @@ */ initialize: function(options) { options = options || {}; - + Form.editors.Base.prototype.initialize.call(this, options); - + //Dependencies if (!Form.editors.List.Modal.ModalAdapter) throw new Error('A ModalAdapter is required'); @@ -472,7 +475,7 @@ * Function which returns a generic string representation of an object * * @param {Object} value - * + * * @return {String} */ itemToString: function(value) { @@ -509,7 +512,7 @@ //If there's a specified toString use that if (schema.itemToString) return schema.itemToString(value); - + //Otherwise use the generic method or custom overridden method return this.itemToString(value); }, @@ -534,7 +537,7 @@ this.trigger('focus', this); modal.on('cancel', this.onModalClosed, this); - + modal.on('ok', _.bind(this.onModalSubmitted, this)); }, @@ -558,7 +561,7 @@ this.renderSummary(); if (isNew) this.trigger('readyToAdd'); - + this.trigger('change', this); this.onModalClosed(); @@ -582,16 +585,16 @@ setValue: function(value) { this.value = value; }, - + focus: function() { if (this.hasFocus) return; this.openEditor(); }, - + blur: function() { if (!this.hasFocus) return; - + if (this.modal) { this.modal.trigger('cancel'); } @@ -606,7 +609,7 @@ //Defaults to BootstrapModal (http://github.com/powmedia/backbone.bootstrap-modal) //Can be replaced with another adapter that implements the same interface. ModalAdapter: Backbone.BootstrapModal, - + //Make the wait list for the 'ready' event before adding the item to the list isAsync: true }); @@ -649,7 +652,7 @@ //If there's a specified toString use that if (schema.itemToString) return schema.itemToString(value); - + //Otherwise use the model return new (schema.model)(value).toString(); } diff --git a/distribution/editors/list.min.js b/distribution/editors/list.min.js index be5d88ab..c32b8915 100644 --- a/distribution/editors/list.min.js +++ b/distribution/editors/list.min.js @@ -1 +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 new Error("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=$($.trim(this.template()));return this.$list=e.is("[data-items]")?e:e.find("[data-items]"),this.renderItems(),this.setElement(e),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},renderItems:function(){var e=this,t=this.value||[];this.items=[],this.$list.empty(),t.length?_.each(t,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem()},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.renderItems()},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('
',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('
',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 new Error("A ModalAdapter is required");this.form=t.form;if(!t.form)throw new Error('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("
")},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("
<%= summary %>
",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 new Error('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 new Error('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) \ No newline at end of file +(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 new Error("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=$($.trim(this.template()));return this.$list=e.is("[data-items]")?e:e.find("[data-items]"),this.renderItems(),this.setElement(e),this.$el.attr("id",this.id),this.$el.attr("name",this.key),this.hasFocus&&this.trigger("blur",this),this},renderItems:function(){var e=this,t=this.value||[];_.each(this.items,function(e){e.$el.remove()}),this.items=[],t.length?_.each(t,function(t){e.addItem(t)}):this.Editor.isAsync||this.addItem()},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.renderItems()},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('
',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('
',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 new Error("A ModalAdapter is required");this.form=t.form;if(!t.form)throw new Error('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("
")},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("
<%= summary %>
",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 new Error('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 new Error('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) \ No newline at end of file