Skip to content
Browse files

Merge pull request #133 from katowulf/master

Correct radio change events and optimize CollectionBinder::getManagerForModel
  • Loading branch information...
2 parents b9bf021 + ff53fcb commit 21b44e9ac5726a0c6fe0ca69f0a7456fd9e355b8 @theironcook committed Apr 28, 2013
View
12 Backbone.CollectionBinder.js
@@ -71,17 +71,7 @@
},
getManagerForModel: function(model){
- var i, elManager, elManagers = _.values(this._elManagers);
-
- for(i = 0; i < elManagers.length; i++){
- elManager = elManagers[i];
-
- if(elManager.getModel() === model){
- return elManager;
- }
- }
-
- return undefined;
+ return this._elManagers[_.isObject(model)? model.cid : model];
},
_onCollectionAdd: function(model){
View
2 Backbone.CollectionBinder.min.js
@@ -2,4 +2,4 @@
// (c) 2013 Bart Wood
// Distributed Under MIT License
-(function(){if(!Backbone){throw"Please include Backbone.js before Backbone.ModelBinder.js"}if(!Backbone.ModelBinder){throw"Please include Backbone.ModelBinder.js before Backbone.CollectionBinder.js"}Backbone.CollectionBinder=function(e,t){_.bindAll(this);this._elManagers={};this._elManagerFactory=e;if(!this._elManagerFactory)throw"elManagerFactory must be defined.";this._elManagerFactory.trigger=this.trigger;this._options=t||{}};Backbone.CollectionBinder.VERSION="1.0.1";_.extend(Backbone.CollectionBinder.prototype,Backbone.Events,{bind:function(e,t){this.unbind();if(!e)throw"collection must be defined";if(!t)throw"parentEl must be defined";this._collection=e;this._elManagerFactory.setParentEl(t);this._onCollectionReset();this._collection.on("add",this._onCollectionAdd,this);this._collection.on("remove",this._onCollectionRemove,this);this._collection.on("reset",this._onCollectionReset,this);this._collection.on("sort",this._onCollectionSort,this)},unbind:function(){if(this._collection!==undefined){this._collection.off("add",this._onCollectionAdd);this._collection.off("remove",this._onCollectionRemove);this._collection.off("reset",this._onCollectionReset);this._collection.off("sort",this._onCollectionSort)}this._removeAllElManagers()},getManagerForEl:function(e){var t,n,r=_.values(this._elManagers);for(t=0;t<r.length;t++){n=r[t];if(n.isElContained(e)){return n}}return undefined},getManagerForModel:function(e){var t,n,r=_.values(this._elManagers);for(t=0;t<r.length;t++){n=r[t];if(n.getModel()===e){return n}}return undefined},_onCollectionAdd:function(e){this._elManagers[e.cid]=this._elManagerFactory.makeElManager(e);this._elManagers[e.cid].createEl();if(this._options["autoSort"]){this.sortRootEls()}},_onCollectionRemove:function(e){this._removeElManager(e)},_onCollectionReset:function(){this._removeAllElManagers();this._collection.each(function(e){this._onCollectionAdd(e)},this);this.trigger("elsReset",this._collection)},_onCollectionSort:function(){if(this._options["autoSort"]){this.sortRootEls()}},_removeAllElManagers:function(){_.each(this._elManagers,function(e){e.removeEl();delete this._elManagers[e._model.cid]},this);delete this._elManagers;this._elManagers={}},_removeElManager:function(e){if(this._elManagers[e.cid]!==undefined){this._elManagers[e.cid].removeEl();delete this._elManagers[e.cid]}},sortRootEls:function(){this._collection.each(function(e,t){var n=this.getManagerForModel(e);if(n){var r=n.getEl();var i=$(this._elManagerFactory.getParentEl()).children();if(i[t]!==r[0]){r.detach();r.insertBefore(i[t])}}},this)}});Backbone.CollectionBinder.ElManagerFactory=function(e,t){_.bindAll(this);this._elHtml=e;this._bindings=t;if(!_.isString(this._elHtml))throw"elHtml must be a valid html string"};_.extend(Backbone.CollectionBinder.ElManagerFactory.prototype,{setParentEl:function(e){this._parentEl=e},getParentEl:function(){return this._parentEl},makeElManager:function(e){var t={_model:e,createEl:function(){this._el=$(this._elHtml);$(this._parentEl).append(this._el);if(this._bindings){if(_.isString(this._bindings)){this._modelBinder=new Backbone.ModelBinder;this._modelBinder.bind(this._model,this._el,Backbone.ModelBinder.createDefaultBindings(this._el,this._bindings))}else if(_.isObject(this._bindings)){this._modelBinder=new Backbone.ModelBinder;this._modelBinder.bind(this._model,this._el,this._bindings)}else{throw"Unsupported bindings type, please use a boolean or a bindings hash"}}this.trigger("elCreated",this._model,this._el)},removeEl:function(){if(this._modelBinder!==undefined){this._modelBinder.unbind()}this._el.remove();this.trigger("elRemoved",this._model,this._el)},isElContained:function(e){return this._el===e||$(this._el).has(e).length>0},getModel:function(){return this._model},getEl:function(){return this._el}};_.extend(t,this);return t}});Backbone.CollectionBinder.ViewManagerFactory=function(e){_.bindAll(this);this._viewCreator=e;if(!_.isFunction(this._viewCreator))throw"viewCreator must be a valid function that accepts a model and returns a backbone view"};_.extend(Backbone.CollectionBinder.ViewManagerFactory.prototype,{setParentEl:function(e){this._parentEl=e},getParentEl:function(){return this._parentEl},makeElManager:function(e){var t={_model:e,createEl:function(){this._view=this._viewCreator(e);$(this._parentEl).append(this._view.render(this._model).el);this.trigger("elCreated",this._model,this._view)},removeEl:function(){if(this._view.close!==undefined){this._view.close()}else{this._view.$el.remove();console.log("warning, you should implement a close() function for your view, you might end up with zombies")}this.trigger("elRemoved",this._model,this._view)},isElContained:function(e){return this._view.el===e||this._view.$el.has(e).length>0},getModel:function(){return this._model},getView:function(){return this._view},getEl:function(){return this._view.$el}};_.extend(t,this);return t}})}).call(this)
+(function(){if(!Backbone){throw"Please include Backbone.js before Backbone.ModelBinder.js"}if(!Backbone.ModelBinder){throw"Please include Backbone.ModelBinder.js before Backbone.CollectionBinder.js"}Backbone.CollectionBinder=function(e,t){_.bindAll(this);this._elManagers={};this._elManagerFactory=e;if(!this._elManagerFactory)throw"elManagerFactory must be defined.";this._elManagerFactory.trigger=this.trigger;this._options=t||{}};Backbone.CollectionBinder.VERSION="1.0.1";_.extend(Backbone.CollectionBinder.prototype,Backbone.Events,{bind:function(e,t){this.unbind();if(!e)throw"collection must be defined";if(!t)throw"parentEl must be defined";this._collection=e;this._elManagerFactory.setParentEl(t);this._onCollectionReset();this._collection.on("add",this._onCollectionAdd,this);this._collection.on("remove",this._onCollectionRemove,this);this._collection.on("reset",this._onCollectionReset,this);this._collection.on("sort",this._onCollectionSort,this)},unbind:function(){if(this._collection!==undefined){this._collection.off("add",this._onCollectionAdd);this._collection.off("remove",this._onCollectionRemove);this._collection.off("reset",this._onCollectionReset);this._collection.off("sort",this._onCollectionSort)}this._removeAllElManagers()},getManagerForEl:function(e){var t,n,r=_.values(this._elManagers);for(t=0;t<r.length;t++){n=r[t];if(n.isElContained(e)){return n}}return undefined},getManagerForModel:function(e){return this._elManagers[_.isObject(e)?e.cid:e]},_onCollectionAdd:function(e){this._elManagers[e.cid]=this._elManagerFactory.makeElManager(e);this._elManagers[e.cid].createEl();if(this._options["autoSort"]){this.sortRootEls()}},_onCollectionRemove:function(e){this._removeElManager(e)},_onCollectionReset:function(){this._removeAllElManagers();this._collection.each(function(e){this._onCollectionAdd(e)},this);this.trigger("elsReset",this._collection)},_onCollectionSort:function(){if(this._options["autoSort"]){this.sortRootEls()}},_removeAllElManagers:function(){_.each(this._elManagers,function(e){e.removeEl();delete this._elManagers[e._model.cid]},this);delete this._elManagers;this._elManagers={}},_removeElManager:function(e){if(this._elManagers[e.cid]!==undefined){this._elManagers[e.cid].removeEl();delete this._elManagers[e.cid]}},sortRootEls:function(){this._collection.each(function(e,t){var n=this.getManagerForModel(e);if(n){var r=n.getEl();var i=$(this._elManagerFactory.getParentEl()).children();if(i[t]!==r[0]){r.detach();r.insertBefore(i[t])}}},this)}});Backbone.CollectionBinder.ElManagerFactory=function(e,t){_.bindAll(this);this._elHtml=e;this._bindings=t;if(!_.isString(this._elHtml))throw"elHtml must be a valid html string"};_.extend(Backbone.CollectionBinder.ElManagerFactory.prototype,{setParentEl:function(e){this._parentEl=e},getParentEl:function(){return this._parentEl},makeElManager:function(e){var t={_model:e,createEl:function(){this._el=$(this._elHtml);$(this._parentEl).append(this._el);if(this._bindings){if(_.isString(this._bindings)){this._modelBinder=new Backbone.ModelBinder;this._modelBinder.bind(this._model,this._el,Backbone.ModelBinder.createDefaultBindings(this._el,this._bindings))}else if(_.isObject(this._bindings)){this._modelBinder=new Backbone.ModelBinder;this._modelBinder.bind(this._model,this._el,this._bindings)}else{throw"Unsupported bindings type, please use a boolean or a bindings hash"}}this.trigger("elCreated",this._model,this._el)},removeEl:function(){if(this._modelBinder!==undefined){this._modelBinder.unbind()}this._el.remove();this.trigger("elRemoved",this._model,this._el)},isElContained:function(e){return this._el===e||$(this._el).has(e).length>0},getModel:function(){return this._model},getEl:function(){return this._el}};_.extend(t,this);return t}});Backbone.CollectionBinder.ViewManagerFactory=function(e){_.bindAll(this);this._viewCreator=e;if(!_.isFunction(this._viewCreator))throw"viewCreator must be a valid function that accepts a model and returns a backbone view"};_.extend(Backbone.CollectionBinder.ViewManagerFactory.prototype,{setParentEl:function(e){this._parentEl=e},getParentEl:function(){return this._parentEl},makeElManager:function(e){var t={_model:e,createEl:function(){this._view=this._viewCreator(e);$(this._parentEl).append(this._view.render(this._model).el);this.trigger("elCreated",this._model,this._view)},removeEl:function(){if(this._view.close!==undefined){this._view.close()}else{this._view.$el.remove();console.log("warning, you should implement a close() function for your view, you might end up with zombies")}this.trigger("elRemoved",this._model,this._view)},isElContained:function(e){return this._view.el===e||this._view.$el.has(e).length>0},getModel:function(){return this._model},getView:function(){return this._view},getEl:function(){return this._view.$el}};_.extend(t,this);return t}})}).call(this)
View
12 Backbone.ModelBinder.js
@@ -407,19 +407,19 @@
switch (el.attr('type')) {
case 'radio':
if (el.val() === convertedValue) {
+ // must defer the change trigger or the change will actually fire with the old value
+ el.prop('checked') || _.defer(function() { el.trigger('change'); });
el.prop('checked', true);
}
else {
+ // must defer the change trigger or the change will actually fire with the old value
el.prop('checked', false);
}
break;
case 'checkbox':
- if (convertedValue) {
- el.prop('checked', true);
- }
- else {
- el.prop('checked', false);
- }
+ // must defer the change trigger or the change will actually fire with the old value
+ el.prop('checked') === !!convertedValue || _.defer(function() { el.trigger('change') });
+ el.prop('checked', !!convertedValue);
break;
case 'file':
break;
View
2 Backbone.ModelBinder.min.js
@@ -1,4 +1,4 @@
// Backbone.ModelBinder v1.0.2
// (c) 2013 Bart Wood
// Distributed Under MIT License
-(function(e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","backbone"],e)}else{e(_,$,Backbone)}})(function(e,t,n){if(!n){throw"Please include Backbone.js before Backbone.ModelBinder.js"}n.ModelBinder=function(){e.bindAll(this)};n.ModelBinder.SetOptions=function(e){n.ModelBinder.options=e};n.ModelBinder.VERSION="1.0.2";n.ModelBinder.Constants={};n.ModelBinder.Constants.ModelToView="ModelToView";n.ModelBinder.Constants.ViewToModel="ViewToModel";e.extend(n.ModelBinder.prototype,{bind:function(e,n,r,i){this.unbind();this._model=e;this._rootEl=n;this._setOptions(i);if(!this._model)this._throwException("model must be specified");if(!this._rootEl)this._throwException("rootEl must be specified");if(r){this._attributeBindings=t.extend(true,{},r);this._initializeAttributeBindings();this._initializeElBindings()}else{this._initializeDefaultBindings()}this._bindModelToView();this._bindViewToModel()},bindCustomTriggers:function(e,t,n,r,i){this._triggers=n;this.bind(e,t,r,i)},unbind:function(){this._unbindModelToView();this._unbindViewToModel();if(this._attributeBindings){delete this._attributeBindings;this._attributeBindings=undefined}},_setOptions:function(t){this._options=e.extend({boundAttribute:"name"},n.ModelBinder.options,t);if(!this._options["modelSetOptions"]){this._options["modelSetOptions"]={}}this._options["modelSetOptions"].changeSource="ModelBinder";if(!this._options["changeTriggers"]){this._options["changeTriggers"]={"*":"change","[contenteditable]":"blur"}}if(!this._options["initialCopyDirection"]){this._options["initialCopyDirection"]=n.ModelBinder.Constants.ModelToView}},_initializeAttributeBindings:function(){var t,n,r,i,s;for(t in this._attributeBindings){n=this._attributeBindings[t];if(e.isString(n)){r={elementBindings:[{selector:n}]}}else if(e.isArray(n)){r={elementBindings:n}}else if(e.isObject(n)){r={elementBindings:[n]}}else{this._throwException("Unsupported type passed to Model Binder "+r)}for(i=0;i<r.elementBindings.length;i++){s=r.elementBindings[i];s.attributeBinding=r}r.attributeName=t;this._attributeBindings[t]=r}},_initializeDefaultBindings:function(){var e,n,r,i,s;this._attributeBindings={};n=t("["+this._options["boundAttribute"]+"]",this._rootEl);for(e=0;e<n.length;e++){r=n[e];i=t(r).attr(this._options["boundAttribute"]);if(!this._attributeBindings[i]){s={attributeName:i};s.elementBindings=[{attributeBinding:s,boundEls:[r]}];this._attributeBindings[i]=s}else{this._attributeBindings[i].elementBindings.push({attributeBinding:this._attributeBindings[i],boundEls:[r]})}}},_initializeElBindings:function(){var e,n,r,i,s,o,u;for(e in this._attributeBindings){n=this._attributeBindings[e];for(r=0;r<n.elementBindings.length;r++){i=n.elementBindings[r];if(i.selector===""){s=t(this._rootEl)}else{s=t(i.selector,this._rootEl)}if(s.length===0){this._throwException("Bad binding found. No elements returned for binding selector "+i.selector)}else{i.boundEls=[];for(o=0;o<s.length;o++){u=s[o];i.boundEls.push(u)}}}}},_bindModelToView:function(){this._model.on("change",this._onModelChange,this);if(this._options["initialCopyDirection"]===n.ModelBinder.Constants.ModelToView){this.copyModelAttributesToView()}},copyModelAttributesToView:function(t){var n,r;for(n in this._attributeBindings){if(t===undefined||e.indexOf(t,n)!==-1){r=this._attributeBindings[n];this._copyModelToView(r)}}},copyViewValuesToModel:function(){var e,n,r,i,s,o;for(e in this._attributeBindings){n=this._attributeBindings[e];for(r=0;r<n.elementBindings.length;r++){i=n.elementBindings[r];if(this._isBindingUserEditable(i)){if(this._isBindingRadioGroup(i)){o=this._getRadioButtonGroupCheckedEl(i);if(o){this._copyViewToModel(i,o)}}else{for(s=0;s<i.boundEls.length;s++){o=t(i.boundEls[s]);if(this._isElUserEditable(o)){this._copyViewToModel(i,o)}}}}}}},_unbindModelToView:function(){if(this._model){this._model.off("change",this._onModelChange);this._model=undefined}},_bindViewToModel:function(){e.each(this._options["changeTriggers"],function(e,n){t(this._rootEl).delegate(n,e,this._onElChanged)},this);if(this._options["initialCopyDirection"]===n.ModelBinder.Constants.ViewToModel){this.copyViewValuesToModel()}},_unbindViewToModel:function(){if(this._options&&this._options["changeTriggers"]){e.each(this._options["changeTriggers"],function(e,n){t(this._rootEl).undelegate(n,e,this._onElChanged)},this)}},_onElChanged:function(e){var n,r,i,s;n=t(e.target)[0];r=this._getElBindings(n);for(i=0;i<r.length;i++){s=r[i];if(this._isBindingUserEditable(s)){this._copyViewToModel(s,n)}}},_isBindingUserEditable:function(e){return e.elAttribute===undefined||e.elAttribute==="text"||e.elAttribute==="html"},_isElUserEditable:function(e){var t=e.attr("contenteditable");return t||e.is("input")||e.is("select")||e.is("textarea")},_isBindingRadioGroup:function(e){var n,r;var i=e.boundEls.length>0;for(n=0;n<e.boundEls.length;n++){r=t(e.boundEls[n]);if(r.attr("type")!=="radio"){i=false;break}}return i},_getRadioButtonGroupCheckedEl:function(e){var n,r;for(n=0;n<e.boundEls.length;n++){r=t(e.boundEls[n]);if(r.attr("type")==="radio"&&r.attr("checked")){return r}}return undefined},_getElBindings:function(e){var t,n,r,i,s,o;var u=[];for(t in this._attributeBindings){n=this._attributeBindings[t];for(r=0;r<n.elementBindings.length;r++){i=n.elementBindings[r];for(s=0;s<i.boundEls.length;s++){o=i.boundEls[s];if(o===e){u.push(i)}}}}return u},_onModelChange:function(){var e,t;for(e in this._model.changedAttributes()){t=this._attributeBindings[e];if(t){this._copyModelToView(t)}}},_copyModelToView:function(e){var r,i,s,o,u,a;u=this._model.get(e.attributeName);for(r=0;r<e.elementBindings.length;r++){i=e.elementBindings[r];for(s=0;s<i.boundEls.length;s++){o=i.boundEls[s];if(!o._isSetting){a=this._getConvertedValue(n.ModelBinder.Constants.ModelToView,i,u);this._setEl(t(o),i,a)}}}},_setEl:function(e,t,n){if(t.elAttribute){this._setElAttribute(e,t,n)}else{this._setElValue(e,n)}},_setElAttribute:function(t,r,i){switch(r.elAttribute){case"html":t.html(i);break;case"text":t.text(i);break;case"enabled":t.prop("disabled",!i);break;case"displayed":t[i?"show":"hide"]();break;case"hidden":t[i?"hide":"show"]();break;case"css":t.css(r.cssAttribute,i);break;case"class":var s=this._model.previous(r.attributeBinding.attributeName);var o=this._model.get(r.attributeBinding.attributeName);if(!e.isUndefined(s)||!e.isUndefined(o)){s=this._getConvertedValue(n.ModelBinder.Constants.ModelToView,r,s);t.removeClass(s)}if(i){t.addClass(i)}break;default:t.attr(r.elAttribute,i)}},_setElValue:function(e,t){if(e.attr("type")){switch(e.attr("type")){case"radio":if(e.val()===t){e.prop("checked",true)}else{e.prop("checked",false)}break;case"checkbox":if(t){e.prop("checked",true)}else{e.prop("checked",false)}break;case"file":break;default:e.val(t)}}else if(e.is("input")||e.is("select")||e.is("textarea")){e.val(t||(t===0?"0":""))}else{e.text(t||(t===0?"0":""))}},_copyViewToModel:function(e,r){var i,s,o;if(!r._isSetting){r._isSetting=true;i=this._setModel(e,t(r));r._isSetting=false;if(i&&e.converter){s=this._model.get(e.attributeBinding.attributeName);o=this._getConvertedValue(n.ModelBinder.Constants.ModelToView,e,s);this._setEl(t(r),e,o)}}},_getElValue:function(e,t){switch(t.attr("type")){case"checkbox":return t.prop("checked")?true:false;default:if(t.attr("contenteditable")!==undefined){return t.html()}else{return t.val()}}},_setModel:function(e,t){var r={};var i=this._getElValue(e,t);i=this._getConvertedValue(n.ModelBinder.Constants.ViewToModel,e,i);r[e.attributeBinding.attributeName]=i;return this._model.set(r,this._options["modelSetOptions"])},_getConvertedValue:function(e,t,n){if(t.converter){n=t.converter(e,n,t.attributeBinding.attributeName,this._model,t.boundEls)}return n},_throwException:function(e){if(this._options.suppressThrows){if(console&&console.error){console.error(e)}}else{throw e}}});n.ModelBinder.CollectionConverter=function(t){this._collection=t;if(!this._collection){throw"Collection must be defined"}e.bindAll(this,"convert")};e.extend(n.ModelBinder.CollectionConverter.prototype,{convert:function(e,t){if(e===n.ModelBinder.Constants.ModelToView){return t?t.id:undefined}else{return this._collection.get(t)}}});n.ModelBinder.createDefaultBindings=function(e,n,r,i){var s,o,u,a;var f={};s=t("["+n+"]",e);for(o=0;o<s.length;o++){u=s[o];a=t(u).attr(n);if(!f[a]){var l={selector:"["+n+'="'+a+'"]'};f[a]=l;if(r){f[a].converter=r}if(i){f[a].elAttribute=i}}}return f};n.ModelBinder.combineBindings=function(t,n){e.each(n,function(e,n){var r={selector:e.selector};if(e.converter){r.converter=e.converter}if(e.elAttribute){r.elAttribute=e.elAttribute}if(!t[n]){t[n]=r}else{t[n]=[t[n],r]}});return t};return n.ModelBinder})
+(function(e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","backbone"],e)}else{e(_,$,Backbone)}})(function(e,t,n){if(!n){throw"Please include Backbone.js before Backbone.ModelBinder.js"}n.ModelBinder=function(){e.bindAll(this)};n.ModelBinder.SetOptions=function(e){n.ModelBinder.options=e};n.ModelBinder.VERSION="1.0.2";n.ModelBinder.Constants={};n.ModelBinder.Constants.ModelToView="ModelToView";n.ModelBinder.Constants.ViewToModel="ViewToModel";e.extend(n.ModelBinder.prototype,{bind:function(e,n,r,i){this.unbind();this._model=e;this._rootEl=n;this._setOptions(i);if(!this._model)this._throwException("model must be specified");if(!this._rootEl)this._throwException("rootEl must be specified");if(r){this._attributeBindings=t.extend(true,{},r);this._initializeAttributeBindings();this._initializeElBindings()}else{this._initializeDefaultBindings()}this._bindModelToView();this._bindViewToModel()},bindCustomTriggers:function(e,t,n,r,i){this._triggers=n;this.bind(e,t,r,i)},unbind:function(){this._unbindModelToView();this._unbindViewToModel();if(this._attributeBindings){delete this._attributeBindings;this._attributeBindings=undefined}},_setOptions:function(t){this._options=e.extend({boundAttribute:"name"},n.ModelBinder.options,t);if(!this._options["modelSetOptions"]){this._options["modelSetOptions"]={}}this._options["modelSetOptions"].changeSource="ModelBinder";if(!this._options["changeTriggers"]){this._options["changeTriggers"]={"*":"change","[contenteditable]":"blur"}}if(!this._options["initialCopyDirection"]){this._options["initialCopyDirection"]=n.ModelBinder.Constants.ModelToView}},_initializeAttributeBindings:function(){var t,n,r,i,s;for(t in this._attributeBindings){n=this._attributeBindings[t];if(e.isString(n)){r={elementBindings:[{selector:n}]}}else if(e.isArray(n)){r={elementBindings:n}}else if(e.isObject(n)){r={elementBindings:[n]}}else{this._throwException("Unsupported type passed to Model Binder "+r)}for(i=0;i<r.elementBindings.length;i++){s=r.elementBindings[i];s.attributeBinding=r}r.attributeName=t;this._attributeBindings[t]=r}},_initializeDefaultBindings:function(){var e,n,r,i,s;this._attributeBindings={};n=t("["+this._options["boundAttribute"]+"]",this._rootEl);for(e=0;e<n.length;e++){r=n[e];i=t(r).attr(this._options["boundAttribute"]);if(!this._attributeBindings[i]){s={attributeName:i};s.elementBindings=[{attributeBinding:s,boundEls:[r]}];this._attributeBindings[i]=s}else{this._attributeBindings[i].elementBindings.push({attributeBinding:this._attributeBindings[i],boundEls:[r]})}}},_initializeElBindings:function(){var e,n,r,i,s,o,u;for(e in this._attributeBindings){n=this._attributeBindings[e];for(r=0;r<n.elementBindings.length;r++){i=n.elementBindings[r];if(i.selector===""){s=t(this._rootEl)}else{s=t(i.selector,this._rootEl)}if(s.length===0){this._throwException("Bad binding found. No elements returned for binding selector "+i.selector)}else{i.boundEls=[];for(o=0;o<s.length;o++){u=s[o];i.boundEls.push(u)}}}}},_bindModelToView:function(){this._model.on("change",this._onModelChange,this);if(this._options["initialCopyDirection"]===n.ModelBinder.Constants.ModelToView){this.copyModelAttributesToView()}},copyModelAttributesToView:function(t){var n,r;for(n in this._attributeBindings){if(t===undefined||e.indexOf(t,n)!==-1){r=this._attributeBindings[n];this._copyModelToView(r)}}},copyViewValuesToModel:function(){var e,n,r,i,s,o;for(e in this._attributeBindings){n=this._attributeBindings[e];for(r=0;r<n.elementBindings.length;r++){i=n.elementBindings[r];if(this._isBindingUserEditable(i)){if(this._isBindingRadioGroup(i)){o=this._getRadioButtonGroupCheckedEl(i);if(o){this._copyViewToModel(i,o)}}else{for(s=0;s<i.boundEls.length;s++){o=t(i.boundEls[s]);if(this._isElUserEditable(o)){this._copyViewToModel(i,o)}}}}}}},_unbindModelToView:function(){if(this._model){this._model.off("change",this._onModelChange);this._model=undefined}},_bindViewToModel:function(){e.each(this._options["changeTriggers"],function(e,n){t(this._rootEl).delegate(n,e,this._onElChanged)},this);if(this._options["initialCopyDirection"]===n.ModelBinder.Constants.ViewToModel){this.copyViewValuesToModel()}},_unbindViewToModel:function(){if(this._options&&this._options["changeTriggers"]){e.each(this._options["changeTriggers"],function(e,n){t(this._rootEl).undelegate(n,e,this._onElChanged)},this)}},_onElChanged:function(e){var n,r,i,s;n=t(e.target)[0];r=this._getElBindings(n);for(i=0;i<r.length;i++){s=r[i];if(this._isBindingUserEditable(s)){this._copyViewToModel(s,n)}}},_isBindingUserEditable:function(e){return e.elAttribute===undefined||e.elAttribute==="text"||e.elAttribute==="html"},_isElUserEditable:function(e){var t=e.attr("contenteditable");return t||e.is("input")||e.is("select")||e.is("textarea")},_isBindingRadioGroup:function(e){var n,r;var i=e.boundEls.length>0;for(n=0;n<e.boundEls.length;n++){r=t(e.boundEls[n]);if(r.attr("type")!=="radio"){i=false;break}}return i},_getRadioButtonGroupCheckedEl:function(e){var n,r;for(n=0;n<e.boundEls.length;n++){r=t(e.boundEls[n]);if(r.attr("type")==="radio"&&r.attr("checked")){return r}}return undefined},_getElBindings:function(e){var t,n,r,i,s,o;var u=[];for(t in this._attributeBindings){n=this._attributeBindings[t];for(r=0;r<n.elementBindings.length;r++){i=n.elementBindings[r];for(s=0;s<i.boundEls.length;s++){o=i.boundEls[s];if(o===e){u.push(i)}}}}return u},_onModelChange:function(){var e,t;for(e in this._model.changedAttributes()){t=this._attributeBindings[e];if(t){this._copyModelToView(t)}}},_copyModelToView:function(e){var r,i,s,o,u,a;u=this._model.get(e.attributeName);for(r=0;r<e.elementBindings.length;r++){i=e.elementBindings[r];for(s=0;s<i.boundEls.length;s++){o=i.boundEls[s];if(!o._isSetting){a=this._getConvertedValue(n.ModelBinder.Constants.ModelToView,i,u);this._setEl(t(o),i,a)}}}},_setEl:function(e,t,n){if(t.elAttribute){this._setElAttribute(e,t,n)}else{this._setElValue(e,n)}},_setElAttribute:function(t,r,i){switch(r.elAttribute){case"html":t.html(i);break;case"text":t.text(i);break;case"enabled":t.prop("disabled",!i);break;case"displayed":t[i?"show":"hide"]();break;case"hidden":t[i?"hide":"show"]();break;case"css":t.css(r.cssAttribute,i);break;case"class":var s=this._model.previous(r.attributeBinding.attributeName);var o=this._model.get(r.attributeBinding.attributeName);if(!e.isUndefined(s)||!e.isUndefined(o)){s=this._getConvertedValue(n.ModelBinder.Constants.ModelToView,r,s);t.removeClass(s)}if(i){t.addClass(i)}break;default:t.attr(r.elAttribute,i)}},_setElValue:function(t,n){if(t.attr("type")){switch(t.attr("type")){case"radio":if(t.val()===n){t.prop("checked")||e.defer(function(){t.trigger("change")});t.prop("checked",true)}else{t.prop("checked",false)}break;case"checkbox":t.prop("checked")===!!n||e.defer(function(){t.trigger("change")});t.prop("checked",!!n);break;case"file":break;default:t.val(n)}}else if(t.is("input")||t.is("select")||t.is("textarea")){t.val(n||(n===0?"0":""))}else{t.text(n||(n===0?"0":""))}},_copyViewToModel:function(e,r){var i,s,o;if(!r._isSetting){r._isSetting=true;i=this._setModel(e,t(r));r._isSetting=false;if(i&&e.converter){s=this._model.get(e.attributeBinding.attributeName);o=this._getConvertedValue(n.ModelBinder.Constants.ModelToView,e,s);this._setEl(t(r),e,o)}}},_getElValue:function(e,t){switch(t.attr("type")){case"checkbox":return t.prop("checked")?true:false;default:if(t.attr("contenteditable")!==undefined){return t.html()}else{return t.val()}}},_setModel:function(e,t){var r={};var i=this._getElValue(e,t);i=this._getConvertedValue(n.ModelBinder.Constants.ViewToModel,e,i);r[e.attributeBinding.attributeName]=i;return this._model.set(r,this._options["modelSetOptions"])},_getConvertedValue:function(e,t,n){if(t.converter){n=t.converter(e,n,t.attributeBinding.attributeName,this._model,t.boundEls)}return n},_throwException:function(e){if(this._options.suppressThrows){if(console&&console.error){console.error(e)}}else{throw e}}});n.ModelBinder.CollectionConverter=function(t){this._collection=t;if(!this._collection){throw"Collection must be defined"}e.bindAll(this,"convert")};e.extend(n.ModelBinder.CollectionConverter.prototype,{convert:function(e,t){if(e===n.ModelBinder.Constants.ModelToView){return t?t.id:undefined}else{return this._collection.get(t)}}});n.ModelBinder.createDefaultBindings=function(e,n,r,i){var s,o,u,a;var f={};s=t("["+n+"]",e);for(o=0;o<s.length;o++){u=s[o];a=t(u).attr(n);if(!f[a]){var l={selector:"["+n+'="'+a+'"]'};f[a]=l;if(r){f[a].converter=r}if(i){f[a].elAttribute=i}}}return f};n.ModelBinder.combineBindings=function(t,n){e.each(n,function(e,n){var r={selector:e.selector};if(e.converter){r.converter=e.converter}if(e.elAttribute){r.elAttribute=e.elAttribute}if(!t[n]){t[n]=r}else{t[n]=[t[n],r]}});return t};return n.ModelBinder})
View
6 spec/javascripts/defaultBindings.spec.js
@@ -74,12 +74,12 @@ describe('default bindings', function(){
});
it('converter bindings', function(){
- var defaultConverter = function(direction, value){
+ var defaultConverter = function(direction, value, key){
if(direction === Backbone.ModelBinder.Constants.ModelToView){
- return 'XXX' + value;
+ return key === 'isActive'? value : 'XXX' + value;
}
else {
- return value.replace('XXX');
+ return _.isString(value)? value.replace('XXX') : value;
}
};

0 comments on commit 21b44e9

Please sign in to comment.
Something went wrong with that request. Please try again.