mvcoffee-rails 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ea31ad877ff2df7c89044220364a4a4f5d190e9e
4
- data.tar.gz: d9f80c635636fcae94ba85e2e9b4fab2d7303c5e
3
+ metadata.gz: e9916798d3f4a71110165422ca99db1016e80eb5
4
+ data.tar.gz: 338f1937a5a62c97eb576c49d1922718778ed9f7
5
5
  SHA512:
6
- metadata.gz: 445a355dc07dd67793b6f005bcbe6f8ef4789ab3d8ff397a8795811c7685b68aefeead3953f393ae3ec9cc58252b4d47e4fd3776f0934ebb04aa18a2bdac419c
7
- data.tar.gz: 460d5812bc921b80ea4fe06c62a43fece0a40731b69737f2bf9ff6d6676c4367da0a3b3eb0a3bef47644c1e222a1cb763a290b8aa93e8f3cbd8d505993885b15
6
+ metadata.gz: 927fbd5fb7792dc5d4b96a238ee48da0c4d4c123dd25ec8c7040e775a71fc8cb8cdd371e4a1dac8c835e7b2e6e4f7768e27caa3929df7b5f5d4df8a501c0538e
7
+ data.tar.gz: e046d368d2f20dc2923b10dc65b909d548c3662482e17527bd77fe129c801bc52489464e1e7a7282d46bf585e8abb8ab332dd805c934e87ee02ee8104335ca70
@@ -4,10 +4,10 @@
4
4
 
5
5
  MVCoffee
6
6
 
7
- Copyright 2014, Kirk Bowers
7
+ Copyright 2016, Kirk Bowers
8
8
  MIT License
9
9
 
10
- Version 1.0.0
10
+ Version 1.1.0
11
11
  */
12
12
 
13
13
  (function() {
@@ -394,6 +394,7 @@ Version 1.0.0
394
394
  scope = scope != null ? scope : this.opts.clientizeScope;
395
395
  $searchInside = jQuery(scope);
396
396
  applyClientize = function(selector, event, validation, submission) {
397
+ event += ".mvcoffee";
397
398
  return $searchInside.find(selector).each(function(index, element) {
398
399
  var customization, j, len1, ref, thisCustom;
399
400
  customization = {};
@@ -405,6 +406,7 @@ Version 1.0.0
405
406
  }
406
407
  }
407
408
  if (!customization.ignore) {
409
+ jQuery(element).off(event);
408
410
  return jQuery(element).on(event, function(eventObject) {
409
411
  var callback, confirm, doPost;
410
412
  callback = element.id;
@@ -1170,7 +1172,14 @@ Version 1.0.0
1170
1172
  if (options == null) {
1171
1173
  options = {};
1172
1174
  }
1173
- methodName = options.as || MVCoffee.Pluralizer.pluralize(name);
1175
+ if (options.as) {
1176
+ methodName = options.as;
1177
+ } else {
1178
+ methodName = MVCoffee.Pluralizer.pluralize(name);
1179
+ if (options.scope) {
1180
+ methodName = options.scope + '_' + methodName;
1181
+ }
1182
+ }
1174
1183
  if (!this.prototype.hasOwnProperty("_associations_children")) {
1175
1184
  this.prototype._associations_children = [];
1176
1185
  }
@@ -1184,6 +1193,9 @@ Version 1.0.0
1184
1193
  if (modelStore != null) {
1185
1194
  constraints = {};
1186
1195
  constraints[foreignKey] = this.id;
1196
+ if (options.scope) {
1197
+ constraints[options.scope] = true;
1198
+ }
1187
1199
  if (options.through) {
1188
1200
  joinTable = options.through;
1189
1201
  joins = modelStore.where(joinTable, constraints);
@@ -1,2 +1,3 @@
1
- (function(){var DEFAULT_OPTS,MVCoffee,bind=function(fn,me){return function(){return fn.apply(me,arguments)}},slice=[].slice,hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1};if(typeof exports!=="undefined"&&exports!==null){MVCoffee=exports}else{this.MVCoffee||(this.MVCoffee={});MVCoffee=this.MVCoffee}if(!Array.isArray){Array.isArray=function(arg){return Object.prototype.toString.call(arg)==="[object Array]"}}MVCoffee.Pluralizer=function(){function Pluralizer(){}Pluralizer.irregulars={man:"men",woman:"women",child:"children",person:"people",mouse:"mice",goose:"geese",datum:"data",alumnus:"alumni",hippopotamus:"hippopotami"};Pluralizer.addIrregulars=function(words){var plur,results,sing;results=[];for(sing in words){plur=words[sing];results.push(this.irregulars[sing]=plur)}return results};Pluralizer.addIrregular=Pluralizer.addIrregulars;Pluralizer.pluralize=function(word){var lastIndex,lastLetter,lastTwo,lastWord,len,result,words;words=word.split("_");lastIndex=words.length-1;lastWord=words[lastIndex];result=this.irregulars[lastWord];if(result){words[lastIndex]=result;return words.join("_")}len=lastWord.length;lastLetter=lastWord[len-1];lastTwo=lastWord.slice(len-2,+(len-1)+1||9e9);if(lastLetter==="s"||lastLetter==="z"){lastWord+="es"}else if(lastTwo==="ch"||lastTwo==="sh"){lastWord+="es"}else if(lastLetter==="y"){lastWord=lastWord.substring(0,len-1)+"ies"}else{lastWord+="s"}words[lastIndex]=lastWord;return words.join("_")};return Pluralizer}();DEFAULT_OPTS={debug:false,clientizeScope:"body"};MVCoffee.Runtime=function(){function Runtime(opts){var opt,value;if(opts==null){opts={}}this._ajaxWithClientize=bind(this._ajaxWithClientize,this);this.patch=bind(this.patch,this);this["delete"]=bind(this["delete"],this);this.post=bind(this.post,this);this.submit=bind(this.submit,this);this.fetch=bind(this.fetch,this);this.redirect=bind(this.redirect,this);this.visit=bind(this.visit,this);this.dontClientize=bind(this.dontClientize,this);this.clientize=bind(this.clientize,this);this.log=bind(this.log,this);this.processServerData=bind(this.processServerData,this);this._preProcessServerData=bind(this._preProcessServerData,this);this.getErrors=bind(this.getErrors,this);this.getSession=bind(this.getSession,this);this.setSession=bind(this.setSession,this);this.getFlash=bind(this.getFlash,this);this.setFlash=bind(this.setFlash,this);this.broadcast=bind(this.broadcast,this);this.narrowcast=bind(this.narrowcast,this);this.opts=DEFAULT_OPTS;for(opt in opts){value=opts[opt];this.opts[opt]=value}this.controllers={};this.modelStore=new MVCoffee.ModelStore;this.active=[];this.listeners=[];this._flash={};this._oldFlash={};this._clientizeCustomizations=[];this._neverClientizeSelectors=[];this.session={};this.dataId="mvcoffee_json";this.onfocusId=null}Runtime.prototype.register_controllers=function(contrs){var contr,id,results;results=[];for(id in contrs){contr=contrs[id];results.push(this._addController(new contr(id,this),id))}return results};Runtime.prototype._addController=function(contr,id){if(id!=null){return this.controllers[id]=contr}else{return this.controllers[contr.selector]=contr}};Runtime.prototype.register_listeners=function(){var args,j,len1,listenerClass,results;args=1<=arguments.length?slice.call(arguments,0):[];results=[];for(j=0,len1=args.length;j<len1;j++){listenerClass=args[j];results.push(this.listeners.push(new listenerClass(this)))}return results};Runtime.prototype.register_models=function(models){return this.modelStore.register_models(models)};Runtime.prototype.narrowcast=function(){var args,controller,i,message,messages,results,sent;controller=arguments[0],messages=arguments[1],args=3<=arguments.length?slice.call(arguments,2):[];if(!Array.isArray(messages)){messages=[messages]}sent=false;i=0;results=[];while(!sent&&i<messages.length){message=messages[i];if(message&&controller[message]!=null&&typeof controller[message]==="function"){sent=true;controller[message].apply(controller,args)}results.push(i++)}return results};Runtime.prototype.broadcast=function(){var args,controller,j,k,len1,len2,listener,messages,ref,ref1,results;messages=arguments[0],args=2<=arguments.length?slice.call(arguments,1):[];if(!Array.isArray(messages)){messages=[messages]}ref=this.active;for(j=0,len1=ref.length;j<len1;j++){controller=ref[j];this.narrowcast.apply(this,[controller,messages].concat(slice.call(args)))}ref1=this.listeners;results=[];for(k=0,len2=ref1.length;k<len2;k++){listener=ref1[k];results.push(this.narrowcast.apply(this,[listener,messages].concat(slice.call(args))))}return results};Runtime.prototype._recycleFlash=function(){this._oldFlash=this._flash;return this._flash={}};Runtime.prototype.setFlash=function(opts){var key,opt,results;results=[];for(key in opts){opt=opts[key];results.push(this._flash[key]=opt)}return results};Runtime.prototype.getFlash=function(key){var ref;return(ref=this._flash[key])!=null?ref:this._oldFlash[key]};Runtime.prototype.setSession=function(opts){var key,opt,results;results=[];for(key in opts){opt=opts[key];results.push(this.session[key]=opt)}return results};Runtime.prototype.getSession=function(key){return this.session[key]};Runtime.prototype.getErrors=function(){return this.errors};Runtime.prototype._preProcessServerData=function(data){var key,ref,value;if(data){if(this.opts.debug){this.log("Got data from server: "+JSON.stringify(data))}this.modelStore.load(data);if(data.flash!=null){this.setFlash(data.flash)}if(data.session!=null){ref=data.session;for(key in ref){value=ref[key];this.log("Setting session value "+key+" to value "+value+" from server");this.session[key]=value}}this.errors=data.errors;if(data.redirect!=null){this.redirect(data.redirect);return false}else{return true}}else{return true}};Runtime.prototype.processServerData=function(data,callback_message){var error_callback_message;if(callback_message==null){callback_message=""}if(this._preProcessServerData(data)){if(this.errors){if(callback_message){error_callback_message=[callback_message+"_errors","errors"]}else{error_callback_message="errors"}end;return this.broadcast(error_callback_message,this.errors)}else{return this.broadcast([callback_message,"render"])}}};Runtime.prototype.log=function(message){if(this.opts.debug){return console.log(message)}};Runtime.prototype.go=function(){var contr,id,json,newActive,parsed,ref,token;this.log("MVCoffee runtime firing 'go'");token=jQuery("meta[name='csrf-token']");if(token!=null?token.length:void 0){this.authenticity_token=token.attr("content")}this._recycleFlash();this.resetClientizeCustomizations();json=jQuery("#"+this.dataId).html();parsed=null;if(json){parsed=jQuery.parseJSON(json)}if(this._preProcessServerData(parsed)){newActive=[];ref=this.controllers;for(id in ref){contr=ref[id];if(jQuery("#"+id).length>0){this.log("Starting controller identified by "+id);newActive.push(contr)}}if(this.active.length){this.broadcast("stop");window.onbeforeunload=null;window.onfocus=null;window.onblur=null;if(this.onfocusId){clearInterval(this.onfocusId)}this.onfocusId=null}if(newActive.length){this.active=newActive;this.broadcast("start");window.onfocus=function(_this){return function(){_this._startSafariKludge();return _this.broadcast("resume")}}(this);window.onblur=function(_this){return function(){_this._stopSafariKludge();return _this.broadcast("pause")}}(this);this._startSafariKludge()}else{this.active=[]}this.clientize();return this.broadcast("render")}};Runtime.prototype._startSafariKludge=function(){this._stopSafariKludge();this.lastFired=(new Date).getTime();return this.onfocusId=setInterval(function(_this){return function(){var now;now=(new Date).getTime();if(now-_this.lastFired>2e3){_this.broadcast("pause");_this.broadcast("resume")}return _this.lastFired=now}}(this),500)};Runtime.prototype._stopSafariKludge=function(){if(this.onfocusId!=null){clearInterval(this.onfocusId)}return this.onfocusId=null};Runtime.prototype.clientize=function(scope){var $searchInside,applyClientize,self;if(scope==null){scope=null}if(typeof Turbolinks!=="undefined"&&Turbolinks!==null){self=this;scope=scope!=null?scope:this.opts.clientizeScope;$searchInside=jQuery(scope);applyClientize=function(selector,event,validation,submission){return $searchInside.find(selector).each(function(index,element){var customization,j,len1,ref,thisCustom;customization={};ref=self._clientizeCustomizations;for(j=0,len1=ref.length;j<len1;j++){thisCustom=ref[j];if(jQuery(element).is(thisCustom.selector)){customization=thisCustom}}if(!customization.ignore){return jQuery(element).on(event,function(eventObject){var callback,confirm,doPost;callback=element.id;if(customization.callback){callback=customization.callback}doPost=validation(customization,callback);if(doPost){confirm=jQuery(element).data("confirm");if(customization.confirm){confirm=customization.confirm}if(confirm){if(confirm instanceof Function){doPost=confirm()}else{doPost=window.confirm(confirm)}}}if(doPost){submission(element,callback)}return false})}})};applyClientize("form","submit",function(customization,callback){var method,model;model=customization.model;if(model!=null){model.populate();method="errors";if(callback){method=[callback+"_errors","errors"]}if(customization.controller!=null){self.narrowcast(customization.controller,method,model.errors)}return model.isValid()}else{return true}},function(element,callback){var params,url;if(element.method==="get"||element.method==="GET"){params=jQuery(element).serialize();url=element.action;if(params){if(/\?/.test(url)){url+="&"+params}else{url+="?"+params}}return self.visit(url)}else{return self.submit(element,callback)}});return applyClientize("a","click",function(customization,callback){return true},function(element,callback){var method;method=jQuery(element).data("method");if(method==="post"){return self.post(element.href,{},callback)}else if(method==="delete"){return self["delete"](element.href,{},callback)}else if(method==="patch"){return self.patch(element.href,{},callback)}else{return self.visit(element.href)}})}};Runtime.prototype.neverClientize=function(){var arg,args,j,len1,results;args=1<=arguments.length?slice.call(arguments,0):[];results=[];for(j=0,len1=args.length;j<len1;j++){arg=args[j];results.push(this._neverClientizeSelectors.push({selector:arg,ignore:true}))}return results};Runtime.prototype.resetClientizeCustomizations=function(){return this._clientizeCustomizations=this._neverClientizeSelectors.slice()};Runtime.prototype.addClientizeCustomization=function(customization){return this._clientizeCustomizations.push(customization)};Runtime.prototype.dontClientize=function(selector){return this._clientizeCustomizations.push({selector:selector,ignore:true})};Runtime.prototype._setSessionCookie=function(){var cookie,expiration,params;params=jQuery.param(this.session);expiration=new Date;expiration.setTime(expiration.getTime()+1e3);cookie="mvcoffee_session="+params+"; path=/; expires="+expiration.toGMTString();document.cookie=cookie;return this.log("Sending cookie = "+cookie)};Runtime.prototype.visit=function(url){this._recycleFlash();this._setSessionCookie();return Turbolinks.visit(url)};Runtime.prototype.redirect=function(url){this._setSessionCookie();return Turbolinks.visit(url)};Runtime.prototype.fetch=function(url,callback_message){if(callback_message==null){callback_message=""}this._setSessionCookie();return jQuery.get(url,null,function(_this){return function(data){return _this.processServerData(data,callback_message)}}(this),"json")};Runtime.prototype.submit=function(submitee,callback_message){var element;if(callback_message==null){callback_message=""}this._setSessionCookie();element=submitee;if(submitee instanceof jQuery){element=submitee.get(0)}jQuery.post(element.action,jQuery(element).serialize(),function(_this){return function(data){return _this.processServerData(data,callback_message)}}(this),"json");return false};Runtime.prototype.post=function(url,params,callback_message){if(params==null){params={}}if(callback_message==null){callback_message=""}return this._ajaxWithClientize("POST",url,params,callback_message)};Runtime.prototype["delete"]=function(url,params,callback_message){if(params==null){params={}}if(callback_message==null){callback_message=""}return this._ajaxWithClientize("DELETE",url,params,callback_message)};Runtime.prototype.patch=function(url,params,callback_message){if(params==null){params={}}if(callback_message==null){callback_message=""}return this._ajaxWithClientize("PATCH",url,params,callback_message)};Runtime.prototype._ajaxWithClientize=function(type,url,params,callback_message){var self;this._setSessionCookie();self=this;return jQuery.ajax({url:url,data:params,type:type,success:function(_this){return function(data){return self.processServerData(data,callback_message)}}(this),dataType:"json"})};Runtime.prototype.run=function(){var self;this.log("MVCoffee runtime run");self=this;jQuery(function(){return self.go()});return jQuery(document).on("pagebeforeshow",function(){return self.go()})};return Runtime}();MVCoffee.Controller=function(){function Controller(id1,_runtime){this.id=id1;this._runtime=_runtime;this.errors=bind(this.errors,this);this.selector="#"+this.id;this.timerId=null;this.isActive=false;this.processServerData=this._runtime.processServerData;this.getFlash=this._runtime.getFlash;this.setFlash=this._runtime.setFlash;this.getSession=this._runtime.getSession;this.setSession=this._runtime.setSession;this.getErrors=this._runtime.getErrors;this.broadcast=this._runtime.broadcast;this.dontClientize=this._runtime.dontClientize;this.reclientize=this._runtime.clientize;this.visit=this._runtime.visit;this.fetch=this._runtime.fetch;this.post=this._runtime.post;this["delete"]=this._runtime["delete"];this.patch=this._runtime.patch;this.submit=this._runtime.submit;this.log=this._runtime.log;this.timerCount=0}Controller.prototype.addClientizeCustomization=function(customization){customization.controller=this;return this._runtime.addClientizeCustomization(customization)};Controller.prototype.rerender=function(opts){var $element,as_var,collection,element,item,j,len1,locals,ref,ref1,template_path;element=(ref=opts.selector)!=null?ref:opts.element;$element=jQuery(element);template_path=opts.template;locals=(ref1=opts.locals)!=null?ref1:{};$element.empty();collection=opts.collection;if(collection){as_var=opts.as;if(as_var){for(j=0,len1=collection.length;j<len1;j++){item=collection[j];locals[as_var]=item;$element.append(JST[template_path](locals))}}}else{$element.append(JST[template_path](locals))}return this.reclientize($element)};Controller.prototype.start=function(){this.isActive=true;this.onStart();if(this.refresh!=null){return this.startTimer()}};Controller.prototype.resume=function(){this.onResume();if(this.refresh!=null&&!this.isActive){this.isActive=true;this.refresh();return this.startTimer()}};Controller.prototype.pause=function(){this.onPause();if(this.refresh!=null){this.isActive=false;return this.stopTimer()}};Controller.prototype.stop=function(){this.isActive=false;this.onStop();if(this.refresh!=null){return this.stopTimer()}};Controller.prototype.refreshInterval=6e4;Controller.prototype.refresh=null;Controller.prototype.onStart=function(){};Controller.prototype.onPause=function(){};Controller.prototype.onResume=function(){};Controller.prototype.onStop=function(){};Controller.prototype.render=function(){};Controller.prototype.errors=function(errors){return console.log("!!!!! The errors method was called on controller "+this.toString()+" but not implemented!!!!!")};Controller.prototype.toString=function(){return this.id};Controller.prototype.startTimer=function(){var self;if(this.timerId!=null){this.stopTimer()}if(this.refreshInterval!=null&&this.refreshInterval>0){self=this;this.timerCount+=1;return this.timerId=setInterval(function(){return self.refresh.call(self)},this.refreshInterval)}};Controller.prototype.stopTimer=function(){if(this.timerId!=null){clearInterval(this.timerId)}return this.timerId=null};return Controller}();MVCoffee.ModelStore=function(){ModelStore.prototype.MIN_DATA_FORMAT_VERSION="1.0.0";function ModelStore(models){if(models==null){models={}}this.modelDefs={};this.store={};this.register_models(models)}ModelStore.prototype.register_models=function(models){var classdef,name,results;if(models==null){models={}}results=[];for(name in models){classdef=models[name];results.push(this._addModel(name,classdef))}return results};ModelStore.prototype._addModel=function(name,classdef){var base,base1;this.modelDefs[name]=classdef;(base=classdef.prototype).modelName||(base.modelName=name);(base1=classdef.prototype).modelNamePlural||(base1.modelNamePlural=MVCoffee.Pluralizer.pluralize(name));classdef.prototype.modelStore=this;return this.store[name]={}};ModelStore.prototype.knowsAbout=function(name){return this.store[name]!=null};ModelStore.prototype.load_model_data=function(modelName,data){var j,len1,model,modelObj,results;if(Array.isArray(data)){results=[];for(j=0,len1=data.length;j<len1;j++){modelObj=data[j];model=new this.modelDefs[modelName](modelObj);results.push(this.store[modelName][model.id]=model)}return results}else{model=new this.modelDefs[modelName](data);return this.store[modelName][model.id]=model}};ModelStore.prototype.load=function(object){var commands,foreignKeys,j,k,len1,len2,modelId,modelName,record,ref,ref1,ref2,results,toBeRemoved;if(object.mvcoffee_version==null||object.mvcoffee_version<this.MIN_DATA_FORMAT_VERSION){throw"MVCoffee.DataStore requires minimum data format "+this.MIN_DATA_FORMAT_VERSION}ref=object.models;for(modelName in ref){commands=ref[modelName];if(this.modelDefs[modelName]!=null){if(commands.replace_on!=null){if(Array.isArray(commands.replace_on)){toBeRemoved=[];ref1=commands.replace_on;for(j=0,len1=ref1.length;j<len1;j++){foreignKeys=ref1[j];toBeRemoved=toBeRemoved.concat(this.where(modelName,foreignKeys))}}else{toBeRemoved=this.where(modelName,commands.replace_on)}for(k=0,len2=toBeRemoved.length;k<len2;k++){record=toBeRemoved[k];this.remove(modelName,record.id)}}}}ref2=object.models;results=[];for(modelName in ref2){commands=ref2[modelName];if(this.modelDefs[modelName]!=null){if(commands.data!=null){this.load_model_data(modelName,commands.data)}if(commands["delete"]!=null){if(Array.isArray(commands["delete"])){results.push(function(){var l,len3,ref3,results1;ref3=commands["delete"];results1=[];for(l=0,len3=ref3.length;l<len3;l++){modelId=ref3[l];results1.push(this._delete_with_cascade(modelName,modelId))}return results1}.call(this))}else{results.push(this._delete_with_cascade(modelName,commands["delete"]))}}else{results.push(void 0)}}else{results.push(void 0)}}return results};ModelStore.prototype.save=function(modelName,modelObj){var ref;return(ref=this.store[modelName])!=null?ref[modelObj.id]=modelObj:void 0};ModelStore.prototype.find=function(model,id){var ref;return(ref=this.store[model])!=null?ref[id]:void 0};ModelStore.prototype.findBy=function(model,conditions){var id,match,prop,record,records,ref,result,value;records=(ref=this.store[model])!=null?ref:{};result=null;for(id in records){record=records[id];match=true;for(prop in conditions){value=conditions[prop];if(record[prop]!==value){match=false}}if(match){result||(result=record)}}return result};ModelStore.prototype.where=function(model,conditions){var id,match,prop,record,records,result,value;records=this.store[model];result=[];for(id in records){record=records[id];match=true;for(prop in conditions){value=conditions[prop];if(record[prop]!==value){match=false}}if(match){result.push(record)}}return result};ModelStore.prototype.all=function(model){var id,record,records,result;records=this.store[model];result=[];for(id in records){record=records[id];result.push(record)}return result};ModelStore.prototype["delete"]=function(model,id){return delete this.store[model][id]};ModelStore.prototype.remove=function(model,id){return delete this.store[model][id]};ModelStore.prototype._delete_with_cascade=function(model,id){var record;record=this.store[model][id];if(record["delete"]!=null&&record["delete"]instanceof Function){return record["delete"]()}else{return delete this.store[model][id]}};return ModelStore}();MVCoffee.Model=function(){function Model(obj){this.addError=bind(this.addError,this);if(obj!=null){this.update(obj)}}Model.prototype.modelName=null;Model.prototype.fields=[];Model.prototype._associations_children=[];Model.prototype.errors=[];Model.prototype.errorsForField={};Model.prototype.valid=true;Model.order=function(array,order,opts){var desc,ignoreCase,prop,ref,result,value;if(opts==null){opts={}}result=array;ref=order.split(/\s+/),prop=ref[0],desc=ref[1];value=1;if(desc!=null&&desc==="desc"){value=-1}ignoreCase=false;if(opts.ignoreCase){ignoreCase=true}result.sort(function(a,b){a=a[prop];b=b[prop];if(ignoreCase){if(a.toLowerCase){a=a.toLowerCase()}if(b.toLowerCase){b=b.toLowerCase()}}if(a>b){return value}else if(a<b){return-value}else{return 0}});return result};Model.all=function(options){var result;if(options==null){options={}}result=this.prototype.modelStore.all(this.prototype.modelName);if(options.order){result=this.order(result,options.order,options)}return result};Model.find=function(id){return this.prototype.modelStore.find(this.prototype.modelName,id)};Model.findBy=function(conditions){return this.prototype.modelStore.findBy(this.prototype.modelName,conditions)};Model.where=function(conditions){return this.prototype.modelStore.where(this.prototype.modelName,conditions)};Model.prototype.save=function(){if(this.validate()){return this.modelStore.save(this.modelName,this)}};Model.prototype.store=function(){return this.modelStore.save(this.modelName,this)};Model.prototype.update=function(obj){var field,results,value;results=[];for(field in obj){if(!hasProp.call(obj,field))continue;value=obj[field];if((value instanceof Object||value instanceof Array)&&this.modelStore.knowsAbout(field)){results.push(this.modelStore.load_model_data(field,value))}else{results.push(this[field]=value)}}return results};Model.prototype["delete"]=function(){var assoc,child,children,j,k,len1,len2,ref;ref=this._associations_children;for(j=0,len1=ref.length;j<len1;j++){assoc=ref[j];children=this[assoc]();if(Array.isArray(children)){for(k=0,len2=children.length;k<len2;k++){child=children[k];child["delete"]()}}else{if(children!=null){children["delete"]()}}}return this.modelStore["delete"](this.modelName,this.id)};Model.prototype.destroy=function(){return this["delete"]()};Model.prototype.remove=function(){return this.modelStore.remove(this.modelName,this.id)};Model.findFieldIndex=function(field){var fields,i,index,j,ref;fields=this.prototype.fields;index=-1;for(i=j=0,ref=fields.length;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){if(fields[i].name===field){index=i}}return index};Model.validates=function(field,test){var fields,index;if(!this.prototype.hasOwnProperty("fields")){this.prototype.fields=[]}fields=this.prototype.fields;index=this.findFieldIndex(field);if(index<0){return fields.push({name:field,validates:[test]})}else{field=fields[index];if(field.validates!=null){if(Array.isArray(field.validates)){return field.validates.push(test)}else{return field.validates=[field.validates,test]}}else{return field.validates=[test]}}};Model.types=function(field,type){var fields,index;if(!this.prototype.hasOwnProperty("fields")){this.prototype.fields=[]}fields=this.prototype.fields;index=this.findFieldIndex(field);if(index<0){return fields.push({name:field,type:type})}else{return fields[index].type=type}};Model.displays=function(field,display){var fields,index;if(!this.prototype.hasOwnProperty("fields")){this.prototype.fields=[]}fields=this.prototype.fields;index=this.findFieldIndex(field);if(index<0){return fields.push({name:field,display:display})}else{return fields[index].display=display}};Model.hasMany=function(name,options){var methodName,self;if(options==null){options={}}methodName=options.as||MVCoffee.Pluralizer.pluralize(name);if(!this.prototype.hasOwnProperty("_associations_children")){this.prototype._associations_children=[]}this.prototype._associations_children.push(methodName);self=this;return this.prototype[methodName]=function(){var constraints,foreignKey,j,join,joinTable,joins,len1,modelStore,record,result;modelStore=self.prototype.modelStore;foreignKey=options.foreignKey||options.foreign_key||self.prototype.modelName+"_id";result=[];if(modelStore!=null){constraints={};constraints[foreignKey]=this.id;if(options.through){joinTable=options.through;joins=modelStore.where(joinTable,constraints);for(j=0,len1=joins.length;j<len1;j++){join=joins[j];record=modelStore.find(name,join[name+"_id"]);if(record){result.push(record)}}}else{result=modelStore.where(name,constraints)}}if(options.order){result=self.order(result,options.order)}return result}};Model.has_many=Model.hasMany;Model.hasOne=function(name,options){var methodName,self;if(options==null){options={}}methodName=options.as||name;if(!this.prototype.hasOwnProperty("_associations_children")){this.prototype._associations_children=[]}this.prototype._associations_children.push(methodName);self=this;return this.prototype[methodName]=function(){var constraints,foreignKey,modelStore,result;modelStore=self.prototype.modelStore;foreignKey=options.foreignKey||options.foreign_key||self.prototype.modelName+"_id";result=null;if(modelStore!=null){constraints={};constraints[foreignKey]=this.id;result=modelStore.findBy(name,constraints)}return result}};Model.has_one=Model.hasOne;Model.belongsTo=function(name,options){var foreignKey,methodName,self;if(options==null){options={}}methodName=options.as||name;foreignKey=options.foreignKey||options.foreign_key||name+"_id";self=this;return this.prototype[methodName]=function(){var modelStore,result;modelStore=self.prototype.modelStore;result=null;if(modelStore!=null){result=modelStore.find(name,this[foreignKey])}return result}};Model.belongs_to=Model.belongsTo;Model.prototype.isValid=function(){return this.valid};Model.prototype.populate=function(obj){var field,j,len1,ref,selector;if(obj!=null){this.update(obj)}else{ref=this.fields;for(j=0,len1=ref.length;j<len1;j++){field=ref[j];if(this.modelName!=null){selector="#"+this.modelName+"_"+field.name}else{selector="#"+field.name}if(field.type!=null&&field.type==="boolean"){this[field.name]=jQuery(selector).is(":checked")}else{this[field.name]=jQuery(selector).val()}}}return this.validate()};Model.prototype.validate=function(){var confirm,field,isNumber,j,k,len1,len2,matches,ref,subval,tokenizer,validation,validations,value;this.valid=true;this.errors=[];this.errorsForField={};ref=this.fields;for(j=0,len1=ref.length;j<len1;j++){field=ref[j];if(field.validates!=null){validations=field.validates;if(!Array.isArray(validations)){validations=[validations]}for(k=0,len2=validations.length;k<len2;k++){validation=validations[k];if(validation.test==="acceptance"){value=validation.accept;if(value==null){value="1"}this.__performValidation(field,validation,null,"must be accepted",function(val){return val===value})}else if(validation.test==="confirmation"){confirm=this[field.name+"_confirmation"];this.__performValidation(field,validation,null,"doesn't match confirmation",function(val){return val!=null&&val!==""&&confirm!=null&&val===confirm})}else if(validation.test==="email"){this.__performValidation(field,validation,null,"must be a valid email address",function(val){return val!=null&&val.match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/)})}else if(validation.test==="exclusion"){matches=validation["in"]||[];this.__performValidation(field,validation,null,"is reserved",function(val){return val!=null&&!(indexOf.call(matches,val)>=0)})}else if(validation.test==="format"){matches=validation["with"]||/.*/;this.__performValidation(field,validation,null,"is invalid",function(val){return val!=null&&matches.test(val)})}else if(validation.test==="inclusion"){matches=validation["in"]||[];this.__performValidation(field,validation,null,"is not included in the list",function(val){return val!=null&&indexOf.call(matches,val)>=0})}else if(validation.test==="length"){tokenizer=function(val){return val.split("")};if(validation.tokenizer!=null){tokenizer=validation.tokenizer}if(validation.minimum!=null){if(typeof validation.minimum==="number"){subval=null;value=validation.minimum}else{subval=validation.minimum;value=subval.value}this.__performValidation(field,validation,subval,"is too short (minimum is "+value+" characters)",function(val){return val!=null&&tokenizer(val).length>=value})}if(validation.maximum!=null){if(typeof validation.maximum==="number"){subval=null;value=validation.maximum}else{subval=validation.maximum;value=subval.value}this.__performValidation(field,validation,subval,"is too long (maximum is "+value+" characters)",function(val){return val==null||tokenizer(val).length<=value})}if(validation["is"]!=null){if(typeof validation["is"]==="number"){subval=null;value=validation["is"]}else{subval=validation["is"];value=subval.value}this.__performValidation(field,validation,subval,"is the wrong length (must be "+value+" characters)",function(val){return val!=null&&tokenizer(val).length===value})}}else if(validation.test==="numericality"){if(validation.only_integer!=null&&validation.only_integer){isNumber=this.__performValidation(field,validation,null,"must be an integer",function(val){return/^[-+]?\d+$/.test(val)})}else{isNumber=this.__performValidation(field,validation,null,"must be a number",function(val){var number;number=parseFloat(val);return/^[-+]?\d*\.?\d*(e\d+)?$/.test(val)&&number===number})}if(isNumber){if(validation.greater_than!=null){if(typeof validation.greater_than==="number"){value=validation.greater_than;subval=null}else{subval=validation.greater_than;value=subval.value}this.__performValidation(field,validation,subval,"must be greater than "+value,function(val){return parseFloat(val)>value})}if(validation.greater_than_or_equal_to!=null){if(typeof validation.greater_than_or_equal_to==="number"){subval=null;value=validation.greater_than_or_equal_to}else{subval=validation.greater_than_or_equal_to;value=subval.value}this.__performValidation(field,validation,subval,"must be greater than or equal to "+value,function(val){return parseFloat(val)>=value})}if(validation.equal_to!=null){if(typeof validation.equal_to==="number"){subval=null;value=validation.equal_to}else{subval=validation.equal_to;value=subval.value}this.__performValidation(field,validation,subval,"must be equal to "+value,function(val){return parseFloat(val)===value})}if(validation.less_than!=null){if(typeof validation.less_than==="number"){value=validation.less_than;subval=null}else{subval=validation.less_than;value=subval.value}this.__performValidation(field,validation,subval,"must be less than "+value,function(val){return parseFloat(val)<value})}if(validation.less_than_or_equal_to!=null){if(typeof validation.less_than_or_equal_to==="number"){subval=null;value=validation.less_than_or_equal_to}else{subval=validation.less_than_or_equal_to;value=subval.value}this.__performValidation(field,validation,subval,"must be less than or equal to "+value,function(val){return parseFloat(val)<=value})}if(validation.odd!=null){if(typeof validation.odd==="boolean"){subval=null;value=validation.odd}else{subval=validation.odd;value=true}if(value){this.__performValidation(field,validation,subval,"must be odd",function(val){return Math.abs(parseFloat(val))%2===1})}}if(validation.even!=null){if(typeof validation.even==="boolean"){subval=null;value=validation.even}else{subval=validation.even;value=true}if(value){this.__performValidation(field,validation,subval,"must be even",function(val){return parseFloat(val)%2===0})}}}}else if(validation.test==="presence"){this.__performValidation(field,validation,null,"can't be empty",function(val){return val!=null&&/\S+/.test(val)})}else if(validation.test==="absence"){this.__performValidation(field,validation,null,"must be blank",function(val){return!(val!=null&&/\S+/.test(val))})}else{if(typeof this[validation.test]!=="function"){
2
- throw"custom validation is not a function"}this.__performValidation(field,validation,null,"is invalid",this[validation.test])}}}}return this.valid};Model.prototype.__performValidation=function(field,validation,subval,message,comparison){var data;if(validation.only_if!=null&&!this[validation.only_if]()){return true}if(validation.unless!=null&&this[validation.unless]()){return true}if(subval!=null){if(subval.only_if!=null&&!this[subval.only_if]()){return true}if(subval.unless!=null&&this[subval.unless]()){return true}}data=this[field.name];if(validation.allow_null!=null&&validation.allow_null&&data==null){return true}if(validation.allow_blank!=null&&validation.allow_blank&&(data==null||!/\S+/.test(data))){return true}if(!comparison(data)){this.addError(field,validation,subval,message);return false}return true};Model.prototype.addError=function(field,validation,subval,message){var base,errorMessage,name,name1;this.valid=false;name=field.display;if(name==null){name=field.name;if(name.length>0){name=name[0].toUpperCase()+name.slice(1);name=name.split("_").join(" ")}}if((subval!=null?subval.message:void 0)!=null){errorMessage=name+" "+subval.message}else if((validation!=null?validation.message:void 0)!=null){errorMessage=name+" "+validation.message}else{errorMessage=name+" "+message}this.errors.push(errorMessage);if((base=this.errorsForField)[name1=field.name]==null){base[name1]=[]}return this.errorsForField[field.name].push(errorMessage)};return Model}()}).call(this);
1
+ (function(){var DEFAULT_OPTS,MVCoffee,bind=function(fn,me){return function(){return fn.apply(me,arguments)}},slice=[].slice,hasProp={}.hasOwnProperty,indexOf=[].indexOf||function(item){for(var i=0,l=this.length;i<l;i++){if(i in this&&this[i]===item)return i}return-1};if(typeof exports!=="undefined"&&exports!==null){MVCoffee=exports}else{this.MVCoffee||(this.MVCoffee={});MVCoffee=this.MVCoffee}if(!Array.isArray){Array.isArray=function(arg){return Object.prototype.toString.call(arg)==="[object Array]"}}MVCoffee.Pluralizer=function(){function Pluralizer(){}Pluralizer.irregulars={man:"men",woman:"women",child:"children",person:"people",mouse:"mice",goose:"geese",datum:"data",alumnus:"alumni",hippopotamus:"hippopotami"};Pluralizer.addIrregulars=function(words){var plur,results,sing;results=[];for(sing in words){plur=words[sing];results.push(this.irregulars[sing]=plur)}return results};Pluralizer.addIrregular=Pluralizer.addIrregulars;Pluralizer.pluralize=function(word){var lastIndex,lastLetter,lastTwo,lastWord,len,result,words;words=word.split("_");lastIndex=words.length-1;lastWord=words[lastIndex];result=this.irregulars[lastWord];if(result){words[lastIndex]=result;return words.join("_")}len=lastWord.length;lastLetter=lastWord[len-1];lastTwo=lastWord.slice(len-2,+(len-1)+1||9e9);if(lastLetter==="s"||lastLetter==="z"){lastWord+="es"}else if(lastTwo==="ch"||lastTwo==="sh"){lastWord+="es"}else if(lastLetter==="y"){lastWord=lastWord.substring(0,len-1)+"ies"}else{lastWord+="s"}words[lastIndex]=lastWord;return words.join("_")};return Pluralizer}();DEFAULT_OPTS={debug:false,clientizeScope:"body"};MVCoffee.Runtime=function(){function Runtime(opts){var opt,value;if(opts==null){opts={}}this._ajaxWithClientize=bind(this._ajaxWithClientize,this);this.patch=bind(this.patch,this);this["delete"]=bind(this["delete"],this);this.post=bind(this.post,this);this.submit=bind(this.submit,this);this.fetch=bind(this.fetch,this);this.redirect=bind(this.redirect,this);this.visit=bind(this.visit,this);this.dontClientize=bind(this.dontClientize,this);this.clientize=bind(this.clientize,this);this.log=bind(this.log,this);this.processServerData=bind(this.processServerData,this);this._preProcessServerData=bind(this._preProcessServerData,this);this.getErrors=bind(this.getErrors,this);this.getSession=bind(this.getSession,this);this.setSession=bind(this.setSession,this);this.getFlash=bind(this.getFlash,this);this.setFlash=bind(this.setFlash,this);this.broadcast=bind(this.broadcast,this);this.narrowcast=bind(this.narrowcast,this);this.opts=DEFAULT_OPTS;for(opt in opts){value=opts[opt];this.opts[opt]=value}this.controllers={};this.modelStore=new MVCoffee.ModelStore;this.active=[];this.listeners=[];this._flash={};this._oldFlash={};this._clientizeCustomizations=[];this._neverClientizeSelectors=[];this.session={};this.dataId="mvcoffee_json";this.onfocusId=null}Runtime.prototype.register_controllers=function(contrs){var contr,id,results;results=[];for(id in contrs){contr=contrs[id];results.push(this._addController(new contr(id,this),id))}return results};Runtime.prototype._addController=function(contr,id){if(id!=null){return this.controllers[id]=contr}else{return this.controllers[contr.selector]=contr}};Runtime.prototype.register_listeners=function(){var args,j,len1,listenerClass,results;args=1<=arguments.length?slice.call(arguments,0):[];results=[];for(j=0,len1=args.length;j<len1;j++){listenerClass=args[j];results.push(this.listeners.push(new listenerClass(this)))}return results};Runtime.prototype.register_models=function(models){return this.modelStore.register_models(models)};Runtime.prototype.narrowcast=function(){var args,controller,i,message,messages,results,sent;controller=arguments[0],messages=arguments[1],args=3<=arguments.length?slice.call(arguments,2):[];if(!Array.isArray(messages)){messages=[messages]}sent=false;i=0;results=[];while(!sent&&i<messages.length){message=messages[i];if(message&&controller[message]!=null&&typeof controller[message]==="function"){sent=true;controller[message].apply(controller,args)}results.push(i++)}return results};Runtime.prototype.broadcast=function(){var args,controller,j,k,len1,len2,listener,messages,ref,ref1,results;messages=arguments[0],args=2<=arguments.length?slice.call(arguments,1):[];if(!Array.isArray(messages)){messages=[messages]}ref=this.active;for(j=0,len1=ref.length;j<len1;j++){controller=ref[j];this.narrowcast.apply(this,[controller,messages].concat(slice.call(args)))}ref1=this.listeners;results=[];for(k=0,len2=ref1.length;k<len2;k++){listener=ref1[k];results.push(this.narrowcast.apply(this,[listener,messages].concat(slice.call(args))))}return results};Runtime.prototype._recycleFlash=function(){this._oldFlash=this._flash;return this._flash={}};Runtime.prototype.setFlash=function(opts){var key,opt,results;results=[];for(key in opts){opt=opts[key];results.push(this._flash[key]=opt)}return results};Runtime.prototype.getFlash=function(key){var ref;return(ref=this._flash[key])!=null?ref:this._oldFlash[key]};Runtime.prototype.setSession=function(opts){var key,opt,results;results=[];for(key in opts){opt=opts[key];results.push(this.session[key]=opt)}return results};Runtime.prototype.getSession=function(key){return this.session[key]};Runtime.prototype.getErrors=function(){return this.errors};Runtime.prototype._preProcessServerData=function(data){var key,ref,value;if(data){if(this.opts.debug){this.log("Got data from server: "+JSON.stringify(data))}this.modelStore.load(data);if(data.flash!=null){this.setFlash(data.flash)}if(data.session!=null){ref=data.session;for(key in ref){value=ref[key];this.log("Setting session value "+key+" to value "+value+" from server");this.session[key]=value}}this.errors=data.errors;if(data.redirect!=null){this.redirect(data.redirect);return false}else{return true}}else{return true}};Runtime.prototype.processServerData=function(data,callback_message){var error_callback_message;if(callback_message==null){callback_message=""}if(this._preProcessServerData(data)){if(this.errors){if(callback_message){error_callback_message=[callback_message+"_errors","errors"]}else{error_callback_message="errors"}end;return this.broadcast(error_callback_message,this.errors)}else{return this.broadcast([callback_message,"render"])}}};Runtime.prototype.log=function(message){if(this.opts.debug){return console.log(message)}};Runtime.prototype.go=function(){var contr,id,json,newActive,parsed,ref,token;this.log("MVCoffee runtime firing 'go'");token=jQuery("meta[name='csrf-token']");if(token!=null?token.length:void 0){this.authenticity_token=token.attr("content")}this._recycleFlash();this.resetClientizeCustomizations();json=jQuery("#"+this.dataId).html();parsed=null;if(json){parsed=jQuery.parseJSON(json)}if(this._preProcessServerData(parsed)){newActive=[];ref=this.controllers;for(id in ref){contr=ref[id];if(jQuery("#"+id).length>0){this.log("Starting controller identified by "+id);newActive.push(contr)}}if(this.active.length){this.broadcast("stop");window.onbeforeunload=null;window.onfocus=null;window.onblur=null;if(this.onfocusId){clearInterval(this.onfocusId)}this.onfocusId=null}if(newActive.length){this.active=newActive;this.broadcast("start");window.onfocus=function(_this){return function(){_this._startSafariKludge();return _this.broadcast("resume")}}(this);window.onblur=function(_this){return function(){_this._stopSafariKludge();return _this.broadcast("pause")}}(this);this._startSafariKludge()}else{this.active=[]}this.clientize();return this.broadcast("render")}};Runtime.prototype._startSafariKludge=function(){this._stopSafariKludge();this.lastFired=(new Date).getTime();return this.onfocusId=setInterval(function(_this){return function(){var now;now=(new Date).getTime();if(now-_this.lastFired>2e3){_this.broadcast("pause");_this.broadcast("resume")}return _this.lastFired=now}}(this),500)};Runtime.prototype._stopSafariKludge=function(){if(this.onfocusId!=null){clearInterval(this.onfocusId)}return this.onfocusId=null};Runtime.prototype.clientize=function(scope){var $searchInside,applyClientize,self;if(scope==null){scope=null}if(typeof Turbolinks!=="undefined"&&Turbolinks!==null){self=this;scope=scope!=null?scope:this.opts.clientizeScope;$searchInside=jQuery(scope);applyClientize=function(selector,event,validation,submission){event+=".mvcoffee";return $searchInside.find(selector).each(function(index,element){var customization,j,len1,ref,thisCustom;customization={};ref=self._clientizeCustomizations;for(j=0,len1=ref.length;j<len1;j++){thisCustom=ref[j];if(jQuery(element).is(thisCustom.selector)){customization=thisCustom}}if(!customization.ignore){jQuery(element).off(event);return jQuery(element).on(event,function(eventObject){var callback,confirm,doPost;callback=element.id;if(customization.callback){callback=customization.callback}doPost=validation(customization,callback);if(doPost){confirm=jQuery(element).data("confirm");if(customization.confirm){confirm=customization.confirm}if(confirm){if(confirm instanceof Function){doPost=confirm()}else{doPost=window.confirm(confirm)}}}if(doPost){submission(element,callback)}return false})}})};applyClientize("form","submit",function(customization,callback){var method,model;model=customization.model;if(model!=null){model.populate();method="errors";if(callback){method=[callback+"_errors","errors"]}if(customization.controller!=null){self.narrowcast(customization.controller,method,model.errors)}return model.isValid()}else{return true}},function(element,callback){var params,url;if(element.method==="get"||element.method==="GET"){params=jQuery(element).serialize();url=element.action;if(params){if(/\?/.test(url)){url+="&"+params}else{url+="?"+params}}return self.visit(url)}else{return self.submit(element,callback)}});return applyClientize("a","click",function(customization,callback){return true},function(element,callback){var method;method=jQuery(element).data("method");if(method==="post"){return self.post(element.href,{},callback)}else if(method==="delete"){return self["delete"](element.href,{},callback)}else if(method==="patch"){return self.patch(element.href,{},callback)}else{return self.visit(element.href)}})}};Runtime.prototype.neverClientize=function(){var arg,args,j,len1,results;args=1<=arguments.length?slice.call(arguments,0):[];results=[];for(j=0,len1=args.length;j<len1;j++){arg=args[j];results.push(this._neverClientizeSelectors.push({selector:arg,ignore:true}))}return results};Runtime.prototype.resetClientizeCustomizations=function(){return this._clientizeCustomizations=this._neverClientizeSelectors.slice()};Runtime.prototype.addClientizeCustomization=function(customization){return this._clientizeCustomizations.push(customization)};Runtime.prototype.dontClientize=function(selector){return this._clientizeCustomizations.push({selector:selector,ignore:true})};Runtime.prototype._setSessionCookie=function(){var cookie,expiration,params;params=jQuery.param(this.session);expiration=new Date;expiration.setTime(expiration.getTime()+1e3);cookie="mvcoffee_session="+params+"; path=/; expires="+expiration.toGMTString();document.cookie=cookie;return this.log("Sending cookie = "+cookie)};Runtime.prototype.visit=function(url){this._recycleFlash();this._setSessionCookie();return Turbolinks.visit(url)};Runtime.prototype.redirect=function(url){this._setSessionCookie();return Turbolinks.visit(url)};Runtime.prototype.fetch=function(url,callback_message){if(callback_message==null){callback_message=""}this._setSessionCookie();return jQuery.get(url,null,function(_this){return function(data){return _this.processServerData(data,callback_message)}}(this),"json")};Runtime.prototype.submit=function(submitee,callback_message){var element;if(callback_message==null){callback_message=""}this._setSessionCookie();element=submitee;if(submitee instanceof jQuery){element=submitee.get(0)}jQuery.post(element.action,jQuery(element).serialize(),function(_this){return function(data){return _this.processServerData(data,callback_message)}}(this),"json");return false};Runtime.prototype.post=function(url,params,callback_message){if(params==null){params={}}if(callback_message==null){callback_message=""}return this._ajaxWithClientize("POST",url,params,callback_message)};Runtime.prototype["delete"]=function(url,params,callback_message){if(params==null){params={}}if(callback_message==null){callback_message=""}return this._ajaxWithClientize("DELETE",url,params,callback_message)};Runtime.prototype.patch=function(url,params,callback_message){if(params==null){params={}}if(callback_message==null){callback_message=""}return this._ajaxWithClientize("PATCH",url,params,callback_message)};Runtime.prototype._ajaxWithClientize=function(type,url,params,callback_message){var self;this._setSessionCookie();self=this;return jQuery.ajax({url:url,data:params,type:type,success:function(_this){return function(data){return self.processServerData(data,callback_message)}}(this),dataType:"json"})};Runtime.prototype.run=function(){var self;this.log("MVCoffee runtime run");self=this;jQuery(function(){return self.go()});return jQuery(document).on("pagebeforeshow",function(){return self.go()})};return Runtime}();MVCoffee.Controller=function(){function Controller(id1,_runtime){this.id=id1;this._runtime=_runtime;this.errors=bind(this.errors,this);this.selector="#"+this.id;this.timerId=null;this.isActive=false;this.processServerData=this._runtime.processServerData;this.getFlash=this._runtime.getFlash;this.setFlash=this._runtime.setFlash;this.getSession=this._runtime.getSession;this.setSession=this._runtime.setSession;this.getErrors=this._runtime.getErrors;this.broadcast=this._runtime.broadcast;this.dontClientize=this._runtime.dontClientize;this.reclientize=this._runtime.clientize;this.visit=this._runtime.visit;this.fetch=this._runtime.fetch;this.post=this._runtime.post;this["delete"]=this._runtime["delete"];this.patch=this._runtime.patch;this.submit=this._runtime.submit;this.log=this._runtime.log;this.timerCount=0}Controller.prototype.addClientizeCustomization=function(customization){customization.controller=this;return this._runtime.addClientizeCustomization(customization)};Controller.prototype.rerender=function(opts){var $element,as_var,collection,element,item,j,len1,locals,ref,ref1,template_path;element=(ref=opts.selector)!=null?ref:opts.element;$element=jQuery(element);template_path=opts.template;locals=(ref1=opts.locals)!=null?ref1:{};$element.empty();collection=opts.collection;if(collection){as_var=opts.as;if(as_var){for(j=0,len1=collection.length;j<len1;j++){item=collection[j];locals[as_var]=item;$element.append(JST[template_path](locals))}}}else{$element.append(JST[template_path](locals))}return this.reclientize($element)};Controller.prototype.start=function(){this.isActive=true;this.onStart();if(this.refresh!=null){return this.startTimer()}};Controller.prototype.resume=function(){this.onResume();if(this.refresh!=null&&!this.isActive){this.isActive=true;this.refresh();return this.startTimer()}};Controller.prototype.pause=function(){this.onPause();if(this.refresh!=null){this.isActive=false;return this.stopTimer()}};Controller.prototype.stop=function(){this.isActive=false;this.onStop();if(this.refresh!=null){return this.stopTimer()}};Controller.prototype.refreshInterval=6e4;Controller.prototype.refresh=null;Controller.prototype.onStart=function(){};Controller.prototype.onPause=function(){};Controller.prototype.onResume=function(){};Controller.prototype.onStop=function(){};Controller.prototype.render=function(){};Controller.prototype.errors=function(errors){return console.log("!!!!! The errors method was called on controller "+this.toString()+" but not implemented!!!!!")};Controller.prototype.toString=function(){return this.id};Controller.prototype.startTimer=function(){var self;if(this.timerId!=null){this.stopTimer()}if(this.refreshInterval!=null&&this.refreshInterval>0){self=this;this.timerCount+=1;return this.timerId=setInterval(function(){return self.refresh.call(self)},this.refreshInterval)}};Controller.prototype.stopTimer=function(){if(this.timerId!=null){clearInterval(this.timerId)}return this.timerId=null};return Controller}();MVCoffee.ModelStore=function(){ModelStore.prototype.MIN_DATA_FORMAT_VERSION="1.0.0";function ModelStore(models){if(models==null){models={}}this.modelDefs={};this.store={};this.register_models(models)}ModelStore.prototype.register_models=function(models){var classdef,name,results;if(models==null){models={}}results=[];for(name in models){classdef=models[name];results.push(this._addModel(name,classdef))}return results};ModelStore.prototype._addModel=function(name,classdef){var base,base1;this.modelDefs[name]=classdef;(base=classdef.prototype).modelName||(base.modelName=name);(base1=classdef.prototype).modelNamePlural||(base1.modelNamePlural=MVCoffee.Pluralizer.pluralize(name));classdef.prototype.modelStore=this;return this.store[name]={}};ModelStore.prototype.knowsAbout=function(name){return this.store[name]!=null};ModelStore.prototype.load_model_data=function(modelName,data){var j,len1,model,modelObj,results;if(Array.isArray(data)){results=[];for(j=0,len1=data.length;j<len1;j++){modelObj=data[j];model=new this.modelDefs[modelName](modelObj);results.push(this.store[modelName][model.id]=model)}return results}else{model=new this.modelDefs[modelName](data);return this.store[modelName][model.id]=model}};ModelStore.prototype.load=function(object){var commands,foreignKeys,j,k,len1,len2,modelId,modelName,record,ref,ref1,ref2,results,toBeRemoved;if(object.mvcoffee_version==null||object.mvcoffee_version<this.MIN_DATA_FORMAT_VERSION){throw"MVCoffee.DataStore requires minimum data format "+this.MIN_DATA_FORMAT_VERSION}ref=object.models;for(modelName in ref){commands=ref[modelName];if(this.modelDefs[modelName]!=null){if(commands.replace_on!=null){if(Array.isArray(commands.replace_on)){toBeRemoved=[];ref1=commands.replace_on;for(j=0,len1=ref1.length;j<len1;j++){foreignKeys=ref1[j];toBeRemoved=toBeRemoved.concat(this.where(modelName,foreignKeys))}}else{toBeRemoved=this.where(modelName,commands.replace_on)}for(k=0,len2=toBeRemoved.length;k<len2;k++){record=toBeRemoved[k];this.remove(modelName,record.id)}}}}ref2=object.models;results=[];for(modelName in ref2){commands=ref2[modelName];if(this.modelDefs[modelName]!=null){if(commands.data!=null){this.load_model_data(modelName,commands.data)}if(commands["delete"]!=null){if(Array.isArray(commands["delete"])){results.push(function(){var l,len3,ref3,results1;ref3=commands["delete"];results1=[];for(l=0,len3=ref3.length;l<len3;l++){modelId=ref3[l];results1.push(this._delete_with_cascade(modelName,modelId))}return results1}.call(this))}else{results.push(this._delete_with_cascade(modelName,commands["delete"]))}}else{results.push(void 0)}}else{results.push(void 0)}}return results};ModelStore.prototype.save=function(modelName,modelObj){var ref;return(ref=this.store[modelName])!=null?ref[modelObj.id]=modelObj:void 0};ModelStore.prototype.find=function(model,id){var ref;return(ref=this.store[model])!=null?ref[id]:void 0};ModelStore.prototype.findBy=function(model,conditions){var id,match,prop,record,records,ref,result,value;records=(ref=this.store[model])!=null?ref:{};result=null;for(id in records){record=records[id];match=true;for(prop in conditions){value=conditions[prop];if(record[prop]!==value){match=false}}if(match){result||(result=record)}}return result};ModelStore.prototype.where=function(model,conditions){var id,match,prop,record,records,result,value;records=this.store[model];result=[];for(id in records){record=records[id];match=true;for(prop in conditions){value=conditions[prop];if(record[prop]!==value){match=false}}if(match){result.push(record)}}return result};ModelStore.prototype.all=function(model){var id,record,records,result;records=this.store[model];result=[];for(id in records){record=records[id];result.push(record)}return result};ModelStore.prototype["delete"]=function(model,id){return delete this.store[model][id]};ModelStore.prototype.remove=function(model,id){return delete this.store[model][id]};ModelStore.prototype._delete_with_cascade=function(model,id){var record;record=this.store[model][id];if(record["delete"]!=null&&record["delete"]instanceof Function){return record["delete"]()}else{return delete this.store[model][id]}};return ModelStore}();MVCoffee.Model=function(){function Model(obj){this.addError=bind(this.addError,this);if(obj!=null){this.update(obj)}}Model.prototype.modelName=null;Model.prototype.fields=[];Model.prototype._associations_children=[];Model.prototype.errors=[];Model.prototype.errorsForField={};Model.prototype.valid=true;Model.order=function(array,order,opts){var desc,ignoreCase,prop,ref,result,value;if(opts==null){opts={}}result=array;ref=order.split(/\s+/),prop=ref[0],desc=ref[1];value=1;if(desc!=null&&desc==="desc"){value=-1}ignoreCase=false;if(opts.ignoreCase){ignoreCase=true}result.sort(function(a,b){a=a[prop];b=b[prop];if(ignoreCase){if(a.toLowerCase){a=a.toLowerCase()}if(b.toLowerCase){b=b.toLowerCase()}}if(a>b){return value}else if(a<b){return-value}else{return 0}});return result};Model.all=function(options){var result;if(options==null){options={}}result=this.prototype.modelStore.all(this.prototype.modelName);if(options.order){result=this.order(result,options.order,options)}return result};Model.find=function(id){return this.prototype.modelStore.find(this.prototype.modelName,id)};Model.findBy=function(conditions){return this.prototype.modelStore.findBy(this.prototype.modelName,conditions)};Model.where=function(conditions){return this.prototype.modelStore.where(this.prototype.modelName,conditions)};Model.prototype.save=function(){if(this.validate()){return this.modelStore.save(this.modelName,this)}};Model.prototype.store=function(){return this.modelStore.save(this.modelName,this)};Model.prototype.update=function(obj){var field,results,value;results=[];for(field in obj){if(!hasProp.call(obj,field))continue;value=obj[field];if((value instanceof Object||value instanceof Array)&&this.modelStore.knowsAbout(field)){results.push(this.modelStore.load_model_data(field,value))}else{results.push(this[field]=value)}}return results};Model.prototype["delete"]=function(){var assoc,child,children,j,k,len1,len2,ref;ref=this._associations_children;for(j=0,len1=ref.length;j<len1;j++){assoc=ref[j];children=this[assoc]();if(Array.isArray(children)){for(k=0,len2=children.length;k<len2;k++){child=children[k];child["delete"]()}}else{if(children!=null){children["delete"]()}}}return this.modelStore["delete"](this.modelName,this.id)};Model.prototype.destroy=function(){return this["delete"]()};Model.prototype.remove=function(){return this.modelStore.remove(this.modelName,this.id)};Model.findFieldIndex=function(field){var fields,i,index,j,ref;fields=this.prototype.fields;index=-1;for(i=j=0,ref=fields.length;0<=ref?j<ref:j>ref;i=0<=ref?++j:--j){if(fields[i].name===field){index=i}}return index};Model.validates=function(field,test){var fields,index;if(!this.prototype.hasOwnProperty("fields")){this.prototype.fields=[]}fields=this.prototype.fields;index=this.findFieldIndex(field);if(index<0){return fields.push({name:field,validates:[test]})}else{field=fields[index];if(field.validates!=null){if(Array.isArray(field.validates)){return field.validates.push(test)}else{return field.validates=[field.validates,test]}}else{return field.validates=[test]}}};Model.types=function(field,type){var fields,index;if(!this.prototype.hasOwnProperty("fields")){this.prototype.fields=[]}fields=this.prototype.fields;index=this.findFieldIndex(field);if(index<0){return fields.push({name:field,type:type})}else{return fields[index].type=type}};Model.displays=function(field,display){var fields,index;if(!this.prototype.hasOwnProperty("fields")){this.prototype.fields=[]}fields=this.prototype.fields;index=this.findFieldIndex(field);if(index<0){return fields.push({name:field,display:display})}else{return fields[index].display=display}};Model.hasMany=function(name,options){var methodName,self;if(options==null){options={}}if(options.as){methodName=options.as}else{methodName=MVCoffee.Pluralizer.pluralize(name);if(options.scope){methodName=options.scope+"_"+methodName}}if(!this.prototype.hasOwnProperty("_associations_children")){this.prototype._associations_children=[]}this.prototype._associations_children.push(methodName);self=this;return this.prototype[methodName]=function(){var constraints,foreignKey,j,join,joinTable,joins,len1,modelStore,record,result;modelStore=self.prototype.modelStore;foreignKey=options.foreignKey||options.foreign_key||self.prototype.modelName+"_id";result=[];if(modelStore!=null){constraints={};constraints[foreignKey]=this.id;if(options.scope){constraints[options.scope]=true}if(options.through){joinTable=options.through;joins=modelStore.where(joinTable,constraints);for(j=0,len1=joins.length;j<len1;j++){join=joins[j];record=modelStore.find(name,join[name+"_id"]);if(record){result.push(record)}}}else{result=modelStore.where(name,constraints)}}if(options.order){result=self.order(result,options.order)}return result}};Model.has_many=Model.hasMany;Model.hasOne=function(name,options){var methodName,self;if(options==null){options={}}methodName=options.as||name;if(!this.prototype.hasOwnProperty("_associations_children")){this.prototype._associations_children=[]}this.prototype._associations_children.push(methodName);self=this;return this.prototype[methodName]=function(){var constraints,foreignKey,modelStore,result;modelStore=self.prototype.modelStore;foreignKey=options.foreignKey||options.foreign_key||self.prototype.modelName+"_id";result=null;if(modelStore!=null){constraints={};constraints[foreignKey]=this.id;result=modelStore.findBy(name,constraints)}return result}};Model.has_one=Model.hasOne;Model.belongsTo=function(name,options){var foreignKey,methodName,self;if(options==null){options={}}methodName=options.as||name;foreignKey=options.foreignKey||options.foreign_key||name+"_id";self=this;return this.prototype[methodName]=function(){var modelStore,result;modelStore=self.prototype.modelStore;result=null;if(modelStore!=null){result=modelStore.find(name,this[foreignKey])}return result}};Model.belongs_to=Model.belongsTo;Model.prototype.isValid=function(){return this.valid};Model.prototype.populate=function(obj){var field,j,len1,ref,selector;if(obj!=null){this.update(obj)}else{ref=this.fields;for(j=0,len1=ref.length;j<len1;j++){field=ref[j];if(this.modelName!=null){selector="#"+this.modelName+"_"+field.name}else{selector="#"+field.name}if(field.type!=null&&field.type==="boolean"){this[field.name]=jQuery(selector).is(":checked")}else{this[field.name]=jQuery(selector).val()}}}return this.validate()};Model.prototype.validate=function(){var confirm,field,isNumber,j,k,len1,len2,matches,ref,subval,tokenizer,validation,validations,value;this.valid=true;this.errors=[];this.errorsForField={};ref=this.fields;for(j=0,len1=ref.length;j<len1;j++){field=ref[j];if(field.validates!=null){validations=field.validates;if(!Array.isArray(validations)){validations=[validations]}for(k=0,len2=validations.length;k<len2;k++){validation=validations[k];if(validation.test==="acceptance"){value=validation.accept;if(value==null){value="1"}this.__performValidation(field,validation,null,"must be accepted",function(val){return val===value})}else if(validation.test==="confirmation"){confirm=this[field.name+"_confirmation"];this.__performValidation(field,validation,null,"doesn't match confirmation",function(val){return val!=null&&val!==""&&confirm!=null&&val===confirm})}else if(validation.test==="email"){this.__performValidation(field,validation,null,"must be a valid email address",function(val){return val!=null&&val.match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/)})}else if(validation.test==="exclusion"){matches=validation["in"]||[];this.__performValidation(field,validation,null,"is reserved",function(val){return val!=null&&!(indexOf.call(matches,val)>=0)})}else if(validation.test==="format"){matches=validation["with"]||/.*/;this.__performValidation(field,validation,null,"is invalid",function(val){return val!=null&&matches.test(val)})}else if(validation.test==="inclusion"){matches=validation["in"]||[];this.__performValidation(field,validation,null,"is not included in the list",function(val){return val!=null&&indexOf.call(matches,val)>=0})}else if(validation.test==="length"){tokenizer=function(val){return val.split("")};if(validation.tokenizer!=null){tokenizer=validation.tokenizer}if(validation.minimum!=null){if(typeof validation.minimum==="number"){subval=null;value=validation.minimum}else{subval=validation.minimum;value=subval.value}this.__performValidation(field,validation,subval,"is too short (minimum is "+value+" characters)",function(val){return val!=null&&tokenizer(val).length>=value})}if(validation.maximum!=null){if(typeof validation.maximum==="number"){subval=null;value=validation.maximum}else{subval=validation.maximum;value=subval.value}this.__performValidation(field,validation,subval,"is too long (maximum is "+value+" characters)",function(val){return val==null||tokenizer(val).length<=value})}if(validation["is"]!=null){if(typeof validation["is"]==="number"){subval=null;value=validation["is"]}else{subval=validation["is"];value=subval.value}this.__performValidation(field,validation,subval,"is the wrong length (must be "+value+" characters)",function(val){return val!=null&&tokenizer(val).length===value})}}else if(validation.test==="numericality"){if(validation.only_integer!=null&&validation.only_integer){isNumber=this.__performValidation(field,validation,null,"must be an integer",function(val){return/^[-+]?\d+$/.test(val)})}else{isNumber=this.__performValidation(field,validation,null,"must be a number",function(val){var number;number=parseFloat(val);return/^[-+]?\d*\.?\d*(e\d+)?$/.test(val)&&number===number})}if(isNumber){if(validation.greater_than!=null){if(typeof validation.greater_than==="number"){value=validation.greater_than;subval=null}else{subval=validation.greater_than;value=subval.value}this.__performValidation(field,validation,subval,"must be greater than "+value,function(val){return parseFloat(val)>value})}if(validation.greater_than_or_equal_to!=null){if(typeof validation.greater_than_or_equal_to==="number"){subval=null;value=validation.greater_than_or_equal_to}else{subval=validation.greater_than_or_equal_to;value=subval.value}this.__performValidation(field,validation,subval,"must be greater than or equal to "+value,function(val){return parseFloat(val)>=value})}if(validation.equal_to!=null){if(typeof validation.equal_to==="number"){subval=null;value=validation.equal_to}else{subval=validation.equal_to;value=subval.value}this.__performValidation(field,validation,subval,"must be equal to "+value,function(val){return parseFloat(val)===value})}if(validation.less_than!=null){if(typeof validation.less_than==="number"){value=validation.less_than;subval=null}else{subval=validation.less_than;value=subval.value}this.__performValidation(field,validation,subval,"must be less than "+value,function(val){return parseFloat(val)<value})}if(validation.less_than_or_equal_to!=null){if(typeof validation.less_than_or_equal_to==="number"){subval=null;value=validation.less_than_or_equal_to}else{subval=validation.less_than_or_equal_to;value=subval.value}this.__performValidation(field,validation,subval,"must be less than or equal to "+value,function(val){return parseFloat(val)<=value})}if(validation.odd!=null){if(typeof validation.odd==="boolean"){subval=null;value=validation.odd}else{subval=validation.odd;value=true}if(value){this.__performValidation(field,validation,subval,"must be odd",function(val){return Math.abs(parseFloat(val))%2===1})}}if(validation.even!=null){if(typeof validation.even==="boolean"){subval=null;value=validation.even}else{subval=validation.even;value=true}if(value){this.__performValidation(field,validation,subval,"must be even",function(val){return parseFloat(val)%2===0})}}}}else if(validation.test==="presence"){this.__performValidation(field,validation,null,"can't be empty",function(val){return val!=null&&/\S+/.test(val);
2
+
3
+ })}else if(validation.test==="absence"){this.__performValidation(field,validation,null,"must be blank",function(val){return!(val!=null&&/\S+/.test(val))})}else{if(typeof this[validation.test]!=="function"){throw"custom validation is not a function"}this.__performValidation(field,validation,null,"is invalid",this[validation.test])}}}}return this.valid};Model.prototype.__performValidation=function(field,validation,subval,message,comparison){var data;if(validation.only_if!=null&&!this[validation.only_if]()){return true}if(validation.unless!=null&&this[validation.unless]()){return true}if(subval!=null){if(subval.only_if!=null&&!this[subval.only_if]()){return true}if(subval.unless!=null&&this[subval.unless]()){return true}}data=this[field.name];if(validation.allow_null!=null&&validation.allow_null&&data==null){return true}if(validation.allow_blank!=null&&validation.allow_blank&&(data==null||!/\S+/.test(data))){return true}if(!comparison(data)){this.addError(field,validation,subval,message);return false}return true};Model.prototype.addError=function(field,validation,subval,message){var base,errorMessage,name,name1;this.valid=false;name=field.display;if(name==null){name=field.name;if(name.length>0){name=name[0].toUpperCase()+name.slice(1);name=name.split("_").join(" ")}}if((subval!=null?subval.message:void 0)!=null){errorMessage=name+" "+subval.message}else if((validation!=null?validation.message:void 0)!=null){errorMessage=name+" "+validation.message}else{errorMessage=name+" "+message}this.errors.push(errorMessage);if((base=this.errorsForField)[name1=field.name]==null){base[name1]=[]}return this.errorsForField[field.name].push(errorMessage)};return Model}()}).call(this);
@@ -114,7 +114,7 @@ module MVCoffee
114
114
  merge_model_data(model_name, data)
115
115
  end
116
116
 
117
- def merge_model_data(model_name, data)
117
+ def merge_model_data(model_name, data, extra = {})
118
118
  obj = @json[:models][model_name] || {}
119
119
 
120
120
  result = nil
@@ -135,6 +135,14 @@ module MVCoffee
135
135
  result = [data.as_json]
136
136
  end
137
137
 
138
+ # This bit of nastiness allows us to add the scope attribute to a model, even
139
+ # if the model doesn't have the scope in its to_hash method.
140
+ if extra and extra.any?
141
+ result.each do |a|
142
+ a.merge! extra
143
+ end
144
+ end
145
+
138
146
  if obj[:data]
139
147
  obj[:data].concat result
140
148
  else
@@ -168,8 +176,8 @@ module MVCoffee
168
176
  replace_model_data(model_name, data, foreign_keys)
169
177
  end
170
178
 
171
- def replace_model_data(model_name, data, foreign_keys = {})
172
- merge_model_data(model_name, data)
179
+ def replace_model_data(model_name, data, foreign_keys = {}, extra = {})
180
+ merge_model_data(model_name, data, extra)
173
181
 
174
182
  # This is guaranteed to be non-nil after set_model_data has been called.
175
183
  obj = @json[:models][model_name]
@@ -277,7 +285,7 @@ module MVCoffee
277
285
  # This sets `@items` to `@department.items` and sets the client session key
278
286
  # `"department_id"` to `@department.id`.
279
287
  #
280
- def fetch_has_many(entity, has_many_of)
288
+ def fetch_has_many(entity, has_many_of, opts = {})
281
289
  table_name = has_many_of.to_s.singularize
282
290
  child_name = table_name
283
291
  method_call = table_name.pluralize.to_sym
@@ -294,14 +302,29 @@ module MVCoffee
294
302
 
295
303
  parent_table_name = entity.class.table_name.singularize
296
304
  foreign_key = "#{parent_table_name}_id"
297
-
298
- data = entity.send method_call
299
-
300
- replace_on = { foreign_key => entity.id }
301
-
302
- set_session replace_on
305
+
306
+ perform_has_many_replace(entity, table_name, foreign_key, method_call, opts)
303
307
 
304
- replace_model_data table_name, data, replace_on
308
+ # replace_on = { foreign_key => entity.id }
309
+ #
310
+ # if opts[:scope]
311
+ # scope_method = opts[:scope].to_sym
312
+ # scope_key = opts[:scope].to_s
313
+ #
314
+ # data = [method_call, scope_method].inject(entity) do |ent, meth|
315
+ # ent.send meth
316
+ # end
317
+ #
318
+ # replace_on[scope_key] = true
319
+ #
320
+ # replace_model_data table_name, data, replace_on, { scope_key => true }
321
+ # else
322
+ # data = entity.send method_call
323
+ #
324
+ # replace_model_data table_name, data, replace_on
325
+ # end
326
+ #
327
+ # set_session replace_on
305
328
  end
306
329
 
307
330
  # Destroys the given `entity` and communicates to the client to remove this
@@ -339,7 +362,7 @@ module MVCoffee
339
362
  # * Check if the #{has_many_of}_updated_at is > the session value
340
363
  # * If so, do the same fetch as fetch_has_many
341
364
  # and put the session value of the new updated_at
342
- def refresh_has_many(entity, has_many_of)
365
+ def refresh_has_many(entity, has_many_of, opts = {})
343
366
  table_name = has_many_of.to_s.singularize
344
367
  child_name = table_name
345
368
  method_call = table_name.pluralize.to_sym
@@ -359,6 +382,9 @@ module MVCoffee
359
382
 
360
383
  updated_at_call = "#{childs_name}_updated_at"
361
384
  session_key = "#{parent_table_name}[#{child_name}[#{entity.id}]]"
385
+ if opts[:scope]
386
+ session_key += "->#{opts[:scope]}"
387
+ end
362
388
 
363
389
  server_age = nil
364
390
 
@@ -369,17 +395,22 @@ module MVCoffee
369
395
  stale = client_stale? session_key, server_age
370
396
 
371
397
  if stale
372
- data = entity.send method_call
373
-
374
- replace_on = { foreign_key => entity.id }
375
-
376
- set_session replace_on
398
+ # data = entity.send method_call
399
+ #
400
+ # replace_on = { foreign_key => entity.id }
401
+ #
402
+ # set_session replace_on
403
+ #
404
+ # replace_model_data table_name, data, replace_on
405
+
406
+
407
+
377
408
 
378
409
  server_age_hash = { session_key => server_age }
379
410
  Rails.logger.info "-- MVCoffee -- Refresh has many: server age session message = #{server_age_hash}"
380
411
  set_session server_age_hash
381
412
 
382
- replace_model_data table_name, data, replace_on
413
+ perform_has_many_replace(entity, table_name, foreign_key, method_call, opts)
383
414
  else
384
415
  # return an empty array if we didn't fetch anything fresh
385
416
  []
@@ -442,5 +473,33 @@ module MVCoffee
442
473
  @json.to_json
443
474
  end
444
475
 
476
+
477
+ private
478
+
479
+ def perform_has_many_replace(entity, table_name, foreign_key, method_call, opts)
480
+ replace_on = { foreign_key => entity.id }
481
+
482
+ if opts[:scope]
483
+ scope_method = opts[:scope].to_sym
484
+ scope_key = opts[:scope].to_s
485
+
486
+ data = [method_call, scope_method].inject(entity) do |ent, meth|
487
+ ent.send meth
488
+ end
489
+
490
+ replace_on[scope_key] = true
491
+
492
+ result = replace_model_data table_name, data, replace_on, { scope_key => true }
493
+ else
494
+ data = entity.send method_call
495
+
496
+ result = replace_model_data table_name, data, replace_on
497
+ end
498
+
499
+ set_session replace_on
500
+
501
+ result
502
+ end
503
+
445
504
  end
446
505
  end
@@ -1,5 +1,5 @@
1
1
  module Mvcoffee
2
2
  module Rails
3
- VERSION = "1.0.0"
3
+ VERSION = "1.1.0"
4
4
  end
5
5
  end
@@ -15,6 +15,7 @@ module ActionController
15
15
  # that is guaranteed not to clash with anything. I use these aliases below in the
16
16
  # render_mvcoffee method.
17
17
  alias :_mvcoffee_alias_render :render
18
+ alias :render! :render
18
19
  alias :_mvcoffee_alias_redirect_to :redirect_to
19
20
 
20
21
  # Call this class macro in your application_controller.rb file if you want to
@@ -103,20 +104,28 @@ module MVCoffee
103
104
  # wipe out the cache on the client). This is desirable for actions that only want
104
105
  # to maintain the session when the request is over json.
105
106
  def render_mvcoffee(action = nil, opts = {})
106
- respond_to do |format|
107
- format.html {
108
- if @mvcoffee.redirect
109
- if opts == {} and action.respond_to? :to_hash
110
- opts = action
111
- end
107
+ # if opts == {} and action.respond_to? :to_hash
108
+ # # If you pass options directly to render, it is likely something like 'json:'
109
+ # # so it should override the monkeypatch
110
+ # _mvcoffee_alias_render action
111
+ # else
112
+
113
+ respond_to do |format|
114
+ format.html {
115
+ if @mvcoffee.redirect
116
+ if opts == {} and action.respond_to? :to_hash
117
+ opts = action
118
+ end
112
119
 
113
- _mvcoffee_alias_redirect_to @mvcoffee.redirect, @mvcoffee.flash.merge(opts)
114
- else
115
- _mvcoffee_alias_render action, opts
116
- end
117
- }
118
- format.json { _mvcoffee_alias_render json: @mvcoffee.to_json }
119
- end
120
+ _mvcoffee_alias_redirect_to @mvcoffee.redirect, @mvcoffee.flash.merge(opts)
121
+ else
122
+ _mvcoffee_alias_render action, opts
123
+ end
124
+ }
125
+ format.json { _mvcoffee_alias_render json: @mvcoffee.to_json }
126
+ end
127
+
128
+ # end
120
129
  end
121
130
 
122
131
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mvcoffee-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kirk Bowers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-12-31 00:00:00.000000000 Z
11
+ date: 2016-10-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  version: 1.3.6
91
91
  requirements: []
92
92
  rubyforge_project:
93
- rubygems_version: 2.2.3
93
+ rubygems_version: 2.4.5.1
94
94
  signing_key:
95
95
  specification_version: 4
96
96
  summary: The server-side Rails gem that makes it easy to use the MVCoffee client-side