// Only function to access $root directly other than $()
render:function(){
// Without format there is no view
if(this.view.format.length===0){
throw"agility.js: empty format in view.render()";
}
if(this.view.$root.size()===0){
this.view.$root=$(this.view.format);
}
else{
this.view.$root.html($(this.view.format).html());// can't overwrite $root as this would reset its presence in the DOM and all events already bound, and
}
// Ensure we have a valid (non-empty) $root
if(this.view.$root.size()===0){
throw'agility.js: could not generate html from format';
}
returnthis;
},// render
// Parse data-bind string of the type '[attribute][=] variable[, [attribute][=] variable ]...'
// If the variable is not an attribute, it must occur by itself
// all pairs in the list are assumed to be attributes
$node.prop("checked",self.model.get(bindData.key));// this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM)
});
// DOM --> Model
$node.change(function(){
varobj={};
obj[bindData.key]=$(this).prop("checked");
self.model.set(obj);// not silent as user might be listening to change events
});
// 1-way attribute binding
bindAttributesOneWay();
}
// <select>: 2-way binding
elseif($node.is('select')){
// Model --> DOM
self.bind('_change:'+bindData.key,function(){
varnodeName=$node.attr('name');
varmodelValue=self.model.get(bindData.key);
$node.val(modelValue);
});
// DOM --> Model
$node.change(function(){
varobj={};
obj[bindData.key]=$node.val();
self.model.set(obj);// not silent as user might be listening to change events
});
// 1-way attribute binding
bindAttributesOneWay();
}
// <input type="radio">: 2-way binding
elseif($node.is('input:radio')){
// Model --> DOM
self.bind('_change:'+bindData.key,function(){
varnodeName=$node.attr('name');
varmodelValue=self.model.get(bindData.key);
$node.siblings('input[name="'+nodeName+'"]').filter('[value="'+modelValue+'"]').prop("checked",true);// this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM)
});
// DOM --> Model
$node.change(function(){
if(!$node.prop("checked"))return;// only handles check=true events
varobj={};
obj[bindData.key]=$node.val();
self.model.set(obj);// not silent as user might be listening to change events
});
// 1-way attribute binding
bindAttributesOneWay();
}
// <input type="search"> (model is updated after every keypress event)
elseif($node.is('input[type="search"]')){
// Model --> DOM
self.bind('_change:'+bindData.key,function(){
$node.val(self.model.get(bindData.key));// this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM)
});
// Model <-- DOM
$node.keypress(function(){
// Without timeout $node.val() misses the last entered character
setTimeout(function(){
varobj={};
obj[bindData.key]=$node.val();
self.model.set(obj);// not silent as user might be listening to change events
},50);
});
// 1-way attribute binding
bindAttributesOneWay();
}
// <input type="text">, <input>, and <textarea>: 2-way binding
elseif($node.is('input:text, textarea')){
// Model --> DOM
self.bind('_change:'+bindData.key,function(){
$node.val(self.model.get(bindData.key));// this won't fire a DOM 'change' event, saving us from an infinite event loop (Model <--> DOM)
});
// Model <-- DOM
$node.change(function(){
varobj={};
obj[bindData.key]=$(this).val();
self.model.set(obj);// not silent as user might be listening to change events
util.isAgility=function(obj){returnobj._agility===true;};util.proxyAll=function(obj,dest){if(!obj||!dest){throw"agility.js: util.proxyAll needs two arguments";}
returnsize;};util.extendController=function(object){for(varcontrollerNameinobject.controller){(function(){varmatches,extend,eventName,previousHandler,currentHandler,newHandler;if(typeofobject.controller[controllerName]==='function'){matches=controllerName.match(/^(\~)*(.+)/);extend=matches[1];eventName=matches[2];if(!extend)return;previousHandler=object.controller[eventName]?(object.controller[eventName]._preProxy||object.controller[eventName]):undefined;currentHandler=object.controller[controllerName];newHandler=function(){if(previousHandler)previousHandler.apply(this,arguments);if(currentHandler)currentHandler.apply(this,arguments);};object.controller[eventName]=newHandler;deleteobject.controller[controllerName];}})();}};defaultPrototype={_agility:true,_container:{_insertObject:function(obj,selector,method){varself=this;if(!util.isAgility(obj)){throw"agility.js: append argument is not an agility object";}
throw'agility.js: unknown argument for getter';},reset:function(){this.model.set(this.model._initData,{reset:true});returnthis;},size:function(){returnutil.size(this.model._data);},each:function(fn){$.each(this.model._data,fn);returnthis;}},view:{format:'<div/>',style:'',$:function(selector){return(!selector||selector===ROOT_SELECTOR)?this.view.$root:this.view.$root.find(selector);},render:function(){if(this.view.format.length===0){throw"agility.js: empty format in view.render()";}
returnthis;}},controller:{_create:function(event){this.view.stylize();this.view.bindings();this.view.sync();},_destroy:function(event){this._container.empty();this.view.$().remove();},_append:function(event,obj,selector){this.view.$(selector).append(obj.view.$());},_prepend:function(event,obj,selector){this.view.$(selector).prepend(obj.view.$());},_before:function(event,obj,selector){if(!selector)throw'agility.js: _before needs a selector';this.view.$(selector).before(obj.view.$());},_after:function(event,obj,selector){if(!selector)throw'agility.js: _after needs a selector';this.view.$(selector).after(obj.view.$());},_remove:function(event,id){},'_change':function(event){}},destroy:function(){this.trigger('destroy',this._id);},append:function(){this._container.append.apply(this,arguments);returnthis;},prepend:function(){this._container.prepend.apply(this,arguments);returnthis;},after:function(){this._container.after.apply(this,arguments);returnthis;},before:function(){this._container.before.apply(this,arguments);returnthis;},remove:function(){this._container.remove.apply(this,arguments);returnthis;},size:function(){returnthis._container.size.apply(this,arguments);},each:function(){returnthis._container.each.apply(this,arguments);},empty:function(){returnthis._container.empty.apply(this,arguments);},bind:function(){this._events.bind.apply(this,arguments);returnthis;},trigger:function(){this._events.trigger.apply(this,arguments);returnthis;}};agility=function(){varargs=Array.prototype.slice.call(arguments,0),object={},prototype=defaultPrototype;if(typeofargs[0]==="object"&&util.isAgility(args[0])){prototype=args[0];args.shift();}
self.trigger('persist:save:success');},error:function(){self.trigger('persist:error');self.trigger('persist:save:error');}});returnthis;};this.load=function(){varself=this;if(this.model.get(id)===undefined)throw'agility.js: load() needs model id';if(this._data.persist.openRequests===0){this.trigger('persist:start');}
this._data.persist.openRequests++;this._data.persist.adapter.call(this,{type:'GET',id:this.model.get(id),complete:function(){self._data.persist.openRequests--;if(self._data.persist.openRequests===0){self.trigger('persist:stop');}},success:function(data,textStatus,jqXHR){self.model.set(data);self.trigger('persist:load:success');},error:function(){self.trigger('persist:error');self.trigger('persist:load:error');}});returnthis;};this.erase=function(){varself=this;if(this.model.get(id)===undefined)throw'agility.js: erase() needs model id';if(this._data.persist.openRequests===0){this.trigger('persist:start');}