lettuce
Version:
Lettuce JS, Mini Mobile Framework for Romantic with DSL.
280 lines (234 loc) • 5.92 kB
JavaScript
//= require <superclass>
//= require <superevent>
var SuperModel = new SuperClass();
SuperModel.extend(SuperEvent);
SuperModel.extend({
records: {},
attributes: [],
isModel: true,
// records is an object, since we want
// to be able to use non-integer ids
recordsValues: function(){
var result = []
for (var key in this.records)
result.push(this.records[key])
return result;
},
setup: function(name){
var result = new SuperClass(SuperModel);
// Can't use .name, so we use .className
result.className = name;
return result;
},
rawFind: function(id){
var record = this.records[id];
if( !record ) throw(this.className + ": Unknown Record #" + id);
return record;
},
findByAttribute: function(name, value){
for(var key in this.records){
if(this.records[key][name] == value){
return this.records[key].dup();
}
}
},
find: function(id){
var record = this.rawFind(id);
return(record.dup());
},
exists: function(id){
try {
return this.find(id);
} catch (e) {
return false;
}
},
all: function(){
return this.dupArray(this.recordsValues());
},
first: function(){
var record = this.recordsValues()[0];
return(record && record.dup());
},
last: function(){
var values = this.recordsValues()
var record = values[values.length - 1];
return(record && record.dup());
},
select: function(callback){
var result = [];
for(var key in this.records){
if(callback(this.records[key]))
result.push(this.records[key]);
}
return this.dupArray(result);
},
each: function(callback){
for(var key in this.records) {
callback(this.records[key]);
}
},
count: function(){
return this.recordsValues().length;
},
deleteAll: function(){
for(var key in this.records){
delete this.records[key];
}
},
destroyAll: function(){
for(var key in this.records){
this.records[key].destroy();
}
},
update: function(id, atts){
this.find(id).updateAttributes(atts);
},
create: function(atts){
var record = new this(atts);
record.save();
return record;
},
destroy: function(id){
this.find(id).destroy();
},
populate: function(values){
this.records = [];
for (var i=0, il = values.length; i < il; i++) {
var record = new this(values[i])
record.newRecord = false;
this.records[record.id] = record;
}
this.trigger("populate");
},
fromArray: function(array){
var result = [];
for (var i in array)
result[i] = new this(array[i]);
return result;
},
dupArray: function(array){
return jQuery.each(array, function(i, item){
return(item && item.dup());
});
}
});
SuperModel.include({
init: function(atts){
this.newRecord = true;
this.load(atts);
this.reloadChanges();
},
isNew: function(){
return this.newRecord;
},
save: function(){
this.trigger("beforeSave");
this.isNew() ? this.create() : this.update();
this.trigger("afterSave");
this.trigger("save");
},
load: function(attributes){
for(var name in attributes){
this[name] = attributes[name];
}
},
updateAttribute: function(name, value){
this[name] = value;
return this.save();
},
updateAttributes: function(attributes){
this.load(attributes);
return this.save();
},
dup: function(){
var result = new this._class(this.attributes());
result.newRecord = this.newRecord;
return result;
},
attributes: function(){
var result = {};
for(var i in this._class.attributes) {
var attr = this._class.attributes[i];
result[attr] = this[attr];
}
result.id = this.id;
return result;
},
changes: function(){
var result = {};
var atts = this.attributes();
var patts = this.previousAttributes;
for (var key in atts) {
if (atts[key] != patts[key])
result[key] = [patts[key], atts[key]];
}
return result;
},
// Private
trigger: function(name){
this._class.trigger(name, this);
},
reloadChanges: function(){
this.previousChanges = (this.previousAttributes ? this.changes() : {});
this.previousAttributes = this.attributes();
},
generateID: function(){
var last = this._class.last();
var lastId = last ? last.id : 0;
return(lastId += 1);
},
rawDestroy: function(){
delete this._class.records[this.id];
},
destroy: function(){
this.trigger("beforeDestroy");
this.rawDestroy();
this.trigger("afterDestroy");
this.trigger("destroy");
},
rawCreate: function(){
if( !this.id ) return;
this._class.records[this.id] = this.dup();
},
create: function(){
this.trigger("beforeCreate");
if( !this.id ) this.id = this.generateID();
this.newRecord = false;
this.rawCreate();
this.reloadChanges();
this.trigger("afterCreate");
this.trigger("create");
return this.id;
},
rawUpdate: function(){
var item = this._class.rawFind(this.id);
item.load(this.attributes());
},
update: function(){
this.trigger("beforeUpdate");
this.rawUpdate();
this.reloadChanges();
this.trigger("afterUpdate");
this.trigger("update");
return true;
}
});
// Setters and Getters
SuperModel.setters = function(obj){
for(var key in obj)
this.__defineSetter__(key, obj[key]);
};
SuperModel.fn.setters = SuperModel.setters;
SuperModel.getters = function(obj){
for(var key in obj)
this.__defineGetter__(key, obj[key]);
};
SuperModel.fn.getters = SuperModel.getters;
// Serialization
SuperModel.serializeRecords = function(){
var result = {};
for(var key in this.records)
result[key] = this.records[key].attributes();
return result;
};