This repository was archived by the owner on Apr 22, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 36
Expand file tree
/
Copy pathsupermodel.min.js
More file actions
1 lines (1 loc) · 11.5 KB
/
supermodel.min.js
File metadata and controls
1 lines (1 loc) · 11.5 KB
1
(function(root,callback){if(typeof define!=="undefined"&&define.amd){define(["exports","backbone","underscore"],callback)}else if(typeof exports!=="undefined"){callback(exports,require("backbone"),require("underscore"))}else{callback(root.Supermodel={},root.Backbone,root._)}})(this,function(Supermodel,Backbone,_){Supermodel.VERSION="0.0.4";var Association=function(model,options){this.required(options,"name");_.extend(this,_.pick(options,"name","where","source","store"));_.defaults(this,{source:this.name,store:"_"+this.name});var ctor=model;do{if(!ctor.associations()[this.name])continue;throw new Error("Association already exists: "+this.name)}while(ctor=ctor.parent);model.associations()[this.name]=this;if(this.initialize)model.all().on("initialize",this.initialize,this);if(this.change)model.all().on("change",this.change,this);if(this.parse)model.all().on("parse",this.parse,this);if(this.destroy)model.all().on("destroy",this.destroy,this);if(this.create)model.all().on("add",this.create,this)};_.extend(Association.prototype,{associate:function(model,other){if(!this.inverse)return;model.trigger("associate:"+this.inverse,model,other)},dissociate:function(model,other){if(!this.inverse)return;model.trigger("dissociate:"+this.inverse,model,other)},required:function(options){var option;for(var i=1;i<arguments.length;i++){if(options[option=arguments[i]])continue;throw new Error("Option required: "+option)}},andThis:function(func){var context=this;return function(){return func.apply(context,[this].concat(_.toArray(arguments)))}}});var One=function(model,options){this.required(options,"inverse","model");Association.apply(this,arguments);_.extend(this,_.pick(options,"inverse","model","id"));_.defaults(this,{id:this.name+"_id"});model.all().on("associate:"+this.name,this.replace,this).on("dissociate:"+this.name,this.remove,this)};_.extend(One.prototype,Association.prototype,{create:function(model){model[this.name]=_.bind(this.access,this,model)},access:function(model,other){if(arguments.length<2)return model[this.store];this.replace(model,other)},initialize:function(model,options){this.parse(model,model.attributes);var id=model.get(this.id);if(id==null)return;var other=this.alter(model,id);if(!other)return;var owner=options.collection&&options.collection.owner;if(!owner||owner!=other)this.associate(other,model)},parse:function(model,resp){if(!resp||!_.has(resp,this.source))return;var attrs=resp[this.source];delete resp[this.source];this.replace(model,attrs)},change:function(model){var idAttr=model.constructor.prototype.idAttribute;if(!idAttr)idAttr=Backbone.Model.prototype.idAttribute;if(model.hasChanged(idAttr)){var other=model[this.store];if(other){this.associate(other,model)}}if(!model.hasChanged(this.id))return;this.replace(model,model.get(this.id))},remove:function(model){this.replace(model,null)},destroy:function(model){var other=model[this.store];if(!other)return;this.remove(model);this.dissociate(other,model)},replace:function(model,other){var other=this.alter(model,other);if(other){this.associate(other,model);model.trigger("replace:"+this.name,model,other)}},alter:function(model,other){var id,current;if(!model)return;current=model[this.store];if(other!=null&&!_.isObject(other)){id=other;(other={})[this.model.prototype.idAttribute]=id}if(other&&!(other instanceof Model))other=this.model.create(other);if(current===other){if(other&&other.getId()!=model.get(this.id)){var attr;(attr={})[this.id]=other.id;model.set(attr,{silent:true})}return}if(!other)model.unset(this.id);if(current){current.off("all",null,this);delete model[this.store];this.dissociate(current,model)}if(other){model.set(this.id,other.id);model[this.store]=other;other.on("all",function(eventName,object){var splittedEvent=eventName.split(":");var reservedNamespace=splittedEvent[1];if(this.inverse==reservedNamespace)return;var headEvent=splittedEvent[0];var tailEvents=_.rest(splittedEvent).join(":");var newEvent=headEvent+":"+this.name;if(tailEvents)newEvent+=":"+tailEvents;arguments[0]=newEvent;model.trigger.apply(model,arguments)},this);return other}}});var ManyToOne=function(model,options){this.required(options,"inverse","collection");Association.apply(this,arguments);_.extend(this,_.pick(options,"collection","inverse","id"));model.all().on("associate:"+this.name,this._associate,this).on("dissociate:"+this.name,this._dissociate,this)};_.extend(ManyToOne.prototype,Association.prototype,{create:function(model){if(!model[this.name])model[this.name]=_.bind(this.get,this,model)},get:function(model){var collection=model[this.store];if(collection)return collection;collection=model[this.store]=(new this.collection).on("add",this.add,this).on("remove",this.remove,this).on("reset",this.reset,this);collection.owner=model;collection.on("all",function(eventName,object){var splittedEvents=eventName.split(":");var reservedNamespace=splittedEvents[1];if(this.inverse==reservedNamespace)return;var headEvent=splittedEvents[0];var tailEvents=_.rest(splittedEvents).join(":");var newEvent=headEvent+":"+this.name;if(tailEvents)newEvent+=":"+tailEvents;arguments[0]=newEvent;model.trigger.apply(model,arguments)},this);return collection},parse:function(model,resp){if(!resp)return;var attrs=resp[this.source];if(!attrs)return;delete resp[this.source];var collection=this.get(model);attrs=collection.parse(attrs);if(!this.where){collection.reset(attrs);return}collection.reset(_.filter(_.map(attrs,function(attrs){return new collection.model(attrs)}),this.where))},initialize:function(model){this.parse(model,model.attributes)},add:function(model,collection){if(!model||!collection)return;this.associate(model,collection.owner)},change:function(model){var idAttr=model.constructor.prototype.idAttribute;if(!idAttr)idAttr=Backbone.Model.prototype.idAttribute;if(model.hasChanged(idAttr)){var collection=model[this.store];if(collection){var self=this;_.each(collection.models,function(other){self.associate(other,model)})}}},remove:function(model,collection){if(!model||!collection)return;this.dissociate(model,collection.owner)},reset:function(collection){if(!collection)return;collection.each(function(model){this.associate(model,collection.owner)},this)},destroy:function(model){var collection;if(!model||!(collection=model[this.store]))return;collection.each(function(other){this.dissociate(other,model)},this)},_associate:function(model,other){if(!model||!other)return;if(this.where&&!this.where(other))return;this.get(model).add(other)},_dissociate:function(model,other){if(!model||!other||!model[this.store])return;model[this.store].remove(other)}});var ManyToMany=function(model,options){this.required(options,"collection","through","source");Association.apply(this,arguments);_.extend(this,_.pick(options,"collection","through"));this._associate=this.andThis(this._associate);this._dissociate=this.andThis(this._dissociate)};_.extend(ManyToMany.prototype,Association.prototype,{create:function(model){if(!model[this.name])model[this.name]=_.bind(this.get,this,model)},get:function(model){var collection=model[this.store];if(collection)return collection;collection=new this.collection;collection.owner=model;model[this.store]=collection;this.reset(model[this.through]().on("add",this.add,this).on("remove",this.remove,this).on("reset",this.reset,this).on("associate:"+this.source,this._associate).on("dissociate:"+this.source,this._dissociate));collection.on("all",function(eventName){var splittedEvents=eventName.split(":");var reservedNamespace=[splittedEvents[1],splittedEvents[2]];if(this.through===reservedNamespace[0]||_.indexOf(reservedNamespace,this.name)>-1)return;var headEvent=splittedEvents[0];var tailEvents=_.rest(splittedEvents).join(":");var newEventName=headEvent+":"+this.name;if(tailEvents)newEventName+=":"+tailEvents;arguments[0]=newEventName;model.trigger.apply(model,arguments);var newEventThrough=headEvent+":"+this.through;if(tailEvents)newEventThrough+=":"+tailEvents;arguments[0]=newEventThrough;model.trigger.apply(model,arguments)},this);return collection},add:function(model,through){if(!model||!through||!(model=model[this.source]()))return;if(this.where&&!this.where(model))return;through.owner[this.name]().add(model)},remove:function(model,through){if(!model||!through||!(model=model[this.source]()))return;var exists=through.any(function(o){return o[this.source]()===model},this);if(!exists)through.owner[this.name]().remove(model)},reset:function(through){if(!through)return;var models=_.compact(_.uniq(_.invoke(through.models,this.source)));if(this.where)models=_.filter(models,this.where);through.owner[this.name]().reset(models)},_associate:function(through,model,other){if(!through||!model||!other)return;if(this.where&&!this.where(other))return;through.owner[this.name]().add(other)},_dissociate:function(through,model,other){if(!through||!model||!other)return;var exists=through.any(function(o){return o[this.source]()===other},this);if(!exists)through.owner[this.name]().remove(other)}});var Has=function(model){this.model=model};_.extend(Has.prototype,{one:function(name,options){options.name=name;new One(this.model,options);return this},many:function(name,options){options.name=name;var Association=options.through?ManyToMany:ManyToOne;new Association(this.model,options);return this}});var Model=Supermodel.Model=Backbone.Model.extend({cidAttribute:"cid",constructor:function(){if(this.initialize!==Model.prototype.initialize){var self=this;var overridedInit=this.initialize;this.initialize=_.wrap(Model.prototype.initialize,function(supermodelInit){supermodelInit.call(self,arguments[2]);overridedInit.call(self,arguments[2])})}return Backbone.Model.apply(this,arguments)},initialize:function(arguments,options){this.set(this.cidAttribute,this.cid);var ctor=this.constructor;do{ctor.all().add(this)}while(ctor=ctor.parent);this.trigger("initialize",this,options)},toJSON:function(){var o=Backbone.Model.prototype.toJSON.apply(this,arguments);delete o[this.cidAttribute];if(this.withJSON){for(var i=0;i<this.withJSON.length;i++){var related=this.withJSON[i];if(this[related]&&this[related]()){o[related]=this[related]().toJSON()}}}return o},parse:function(resp){this.trigger("parse",this,resp);return resp},getId:function(){if(this.id)return this.id;else return this.cid},clone:function(){var attrsCopy=this.cloneAttributes();return new this.constructor(attrsCopy)},cloneAttributes:function(){var attrsCopy=_.extend({},this.attributes);var ctor=this.constructor;delete attrsCopy[ctor.prototype.cidAttribute];delete attrsCopy[ctor.prototype.idAttribute];var allAssociations=ctor.allAssociations();for(var assoc in allAssociations){delete attrsCopy[allAssociations[assoc].id]}return attrsCopy}},{create:function(attrs,options){var id=attrs&&attrs[this.prototype.idAttribute];var model=this.find(attrs);if(!options)options={};if(model){if(attrs!==model.attributes){model.set(model.parse(attrs),_.extend(options,{silent:false}));return model}if(options.validate){model._validate({},options)}return model}var parent=this;while(parent=parent.parent){if(!parent.all().get(id))continue;throw new Error('Model with id "'+id+'" already exists.')}options.parse=true;return new this(attrs,options)},find:function(attrs,merge){if(!attrs)return false;var cid=attrs[this.prototype.cidAttribute];var id=attrs[this.prototype.idAttribute];return(cid||id)&&this.all().get(cid||id)||false},has:function(){return new Has(this)},all:function(){if(!this._all){var Constructor=this;var All=Backbone.Collection.extend({model:Constructor});this._all=new All}return this._all},associations:function(){return this._associations||(this._associations={})},allAssociations:function(){var allAssociations={};var ctor=this;do{_.extend(allAssociations,ctor._associations)}while(ctor=ctor.parent);return allAssociations},reset:function(){this._all=null;this._associations={}}})});