3vot-model
Version:
3VOT Model based on SpineJS
764 lines (664 loc) • 19.8 kB
JavaScript
var Events = require("./events");
var Module = require("./module");
var ModelUtils = require("../utils/model")
var Model = (function() {
Module.clone(Model,Module);
Model.extend(Events);
Model.records = [];
Model.irecords = {};
Model.attributes = [];
Model.configure = function() {
var attributes, name;
name = arguments[0], attributes = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
this.className = name;
this.deleteAll();
if (attributes.length) {
this.attributes = attributes;
}
this.attributes && (this.attributes = makeArray(this.attributes));
this.attributes || (this.attributes = []);
this.unbind();
return this;
};
Model.toString = function() {
return "" + this.className + "(" + (this.attributes.join(", ")) + ")";
};
Model.find = function(id, notFound) {
if (notFound == null) {
notFound = this.notFound;
}
var _ref = this.irecords[id]
return (this.irecords[id] != null ? _ref.clone() : void 0) || (typeof notFound === "function" ? notFound(id) : void 0);
};
Model.findAll = function(ids, notFound) {
var id, _i, _len, _results;
_results = [];
for (_i = 0, _len = ids.length; _i < _len; _i++) {
id = ids[_i];
if (this.find(id, notFound)) {
_results.push(this.find(id));
}
}
return _results;
};
Model.notFound = function(id) {
return null;
};
Model.exists = function(id) {
return Boolean(this.irecords[id]);
};
Model.addRecord = function(record, options) {
var _base, _base1, _name, _name1;
if (options == null) {
options = {};
}
if (record.id && this.irecords[record.id]) {
this.irecords[record.id].remove(options);
if (!options.clear) {
record = this.irecords[record.id].load(record);
}
}
record.id || (record.id = record.cid);
if ((_base = this.irecords)[_name = record.id] == null) {
_base[_name] = record;
}
if ((_base1 = this.irecords)[_name1 = record.cid] == null) {
_base1[_name1] = record;
}
return this.records.push(record);
};
Model.refresh = function(values, options) {
var record, records, result, _i, _len;
if (options == null) {
options = {};
}
if (options.clear) {
this.deleteAll();
}
records = this.fromJSON(values);
if (!isArray(records)) {
records = [records];
}
for (_i = 0, _len = records.length; _i < _len; _i++) {
record = records[_i];
this.addRecord(record, options);
}
this.sort();
result = this.cloneArray(records);
this.trigger('refresh', result, options);
return result;
};
Model.select = function(callback) {
var record, _i, _len, _ref, _results;
_ref = this.records;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
record = _ref[_i];
if (callback(record)) {
_results.push(record.clone());
}
}
return _results;
};
Model.findByAttribute = function(name, value) {
var record, _i, _len, _ref;
_ref = this.records;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
record = _ref[_i];
if (record[name] === value) {
return record.clone();
}
}
return null;
};
Model.findAllByAttribute = function(name, value) {
return this.select(function(item) {
return item[name] === value;
});
};
Model.each = function(callback) {
var record, _i, _len, _ref, _results;
_ref = this.records;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
record = _ref[_i];
_results.push(callback(record.clone()));
}
return _results;
};
Model.all = function() {
return this.cloneArray(this.records);
};
Model.slice = function(begin, end) {
if (begin == null) {
begin = 0;
}
return this.cloneArray(this.records.slice(begin, end));
};
Model.first = function(end) {
var _ref;
if (end == null) {
end = 1;
}
if (end > 1) {
return this.cloneArray(this.records.slice(0, end));
} else {
return (_ref = this.records[0]) != null ? _ref.clone() : void 0;
}
};
Model.last = function(begin) {
var _ref;
if (typeof begin === 'number') {
return this.cloneArray(this.records.slice(-begin));
} else {
return (_ref = this.records[this.records.length - 1]) != null ? _ref.clone() : void 0;
}
};
Model.count = function() {
return this.records.length;
};
Model.deleteAll = function() {
this.records = [];
return this.irecords = {};
};
Model.destroyAll = function(options) {
var record, _i, _len, _ref, _results;
_ref = this.records;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
record = _ref[_i];
_results.push(record.destroy(options));
}
return _results;
};
Model.update = function(id, atts, options) {
return this.find(id).updateAttributes(atts, options);
};
Model.create = function(atts, options) {
var record;
record = new this(atts);
return record.save(options);
};
Model.destroy = function(id, options) {
return this.find(id).destroy(options);
};
Model.change = function(callbackOrParams) {
if (typeof callbackOrParams === 'function') {
return this.bind('change', callbackOrParams);
} else {
return this.trigger.apply(this, ['change'].concat(__slice.call(arguments)));
}
};
Model.fetch = function(callbackOrParams) {
if (typeof callbackOrParams === 'function') {
return this.bind('fetch', callbackOrParams);
} else {
return this.trigger.apply(this, ['fetch'].concat(__slice.call(arguments)));
}
};
Model.toJSON = function() {
return this.records;
};
Model.fromJSON = function(objects) {
var value, _i, _len, _results;
if (!objects) {
return;
}
if (typeof objects === 'string') {
objects = JSON.parse(objects);
}
if (isArray(objects)) {
_results = [];
for (_i = 0, _len = objects.length; _i < _len; _i++) {
value = objects[_i];
if (value instanceof this) {
_results.push(value);
} else {
_results.push(new this(value));
}
}
return _results;
} else {
if (objects instanceof this) {
return objects;
}
return new this(objects);
}
};
Model.fromForm = function() {
var _ref;
return (_ref = new this).fromForm.apply(_ref, arguments);
};
Model.sort = function() {
if (this.comparator) {
this.records.sort(this.comparator);
}
return this;
};
Model.cloneArray = function(array) {
var value, _i, _len, _results;
_results = [];
for (_i = 0, _len = array.length; _i < _len; _i++) {
value = array[_i];
_results.push(value.clone());
}
return _results;
};
Model.idCounter = 0;
Model.uid = function(prefix) {
var uid;
if (prefix == null) {
prefix = '';
}
uid = prefix + this.idCounter++;
if (this.exists(uid)) {
uid = this.uid(prefix);
}
return uid;
};
function Model(atts) {
Model.__super__.constructor.apply(this, arguments);
if ((this.constructor.uuid != null) && typeof this.constructor.uuid === 'function') {
this.cid = this.constructor.uuid();
if (!this.id) {
this.id = this.cid;
}
} else {
this.cid = (atts != null ? atts.cid : void 0) || this.constructor.uid('c-');
}
if (atts) {
this.load(atts);
}
}
Model.prototype.isNew = function() {
return !this.exists();
};
Model.prototype.isValid = function() {
return !this.validate();
};
Model.prototype.validate = function() {};
Model.prototype.load = function(atts) {
var key, value;
if (atts.id) {
this.id = atts.id;
}
for (key in atts) {
value = atts[key];
if (typeof this[key] === 'function') {
if (typeof value === 'function') {
continue;
}
this[key](value);
} else {
this[key] = value;
}
}
return this;
};
Model.prototype.load = function(atts) {
var key, value;
if (atts.id) {
this.id = atts.id;
}
for (key in atts) {
value = atts[key];
if (typeof this[key] === 'function') {
if (typeof value === 'function') {
continue;
}
this[key](value);
} else {
this[key] = value;
}
}
return this;
};
Model.prototype.attributes = function() {
var key, result, _i, _len, _ref;
result = {};
_ref = this.constructor.attributes;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
key = _ref[_i];
if (key in this) {
if (typeof this[key] === 'function') {
result[key] = this[key]();
} else if(this[key] != null){
result[key] = this[key];
}
}
}
if (this.id) {
result.id = this.id;
}
return result;
};
Model.prototype.eql = function(rec) {
return rec && rec.constructor === this.constructor && ((rec.cid === this.cid) || (rec.id && rec.id === this.id));
};
Model.prototype.stripCloneAttrs = function() {
var key, value;
if (this.hasOwnProperty('cid')) {
return;
}
for (key in this) {
if (!__hasProp.call(this, key)) continue;
value = this[key];
console.log(value)
if ([].indexOf.call(this.constructor.attributes, key) >= 0) {
delete this[key];
}
}
return this;
};
Model.prototype.updateAttribute = function(name, value, options) {
var atts;
atts = {};
atts[name] = value;
return this.updateAttributes(atts, options);
};
Model.prototype.updateAttributes = function(atts, options) {
this.load(atts);
return this.save(options);
};
Model.prototype.changeID = function(id) {
var records;
if (id === this.id) {
return;
}
records = this.constructor.irecords;
records[id] = records[this.id];
if (this.cid !== this.id) {
delete records[this.id];
}
this.id = id;
return this.save({ignoreAjax: true});
};
Model.prototype.remove = function(options) {
var i, record, records, _i, _len;
if (options == null) {
options = {};
}
records = this.constructor.records.slice(0);
for (i = _i = 0, _len = records.length; _i < _len; i = ++_i) {
record = records[i];
if (!(this.eql(record))) {
continue;
}
records.splice(i, 1);
break;
}
this.constructor.records = records;
if (options.clear) {
delete this.constructor.irecords[this.id];
return delete this.constructor.irecords[this.cid];
}
};
Model.prototype.dup = function(newRecord) {
var atts;
if (newRecord == null) {
newRecord = true;
}
atts = this.attributes();
if (newRecord) {
delete atts.id;
} else {
atts.cid = this.cid;
}
return new this.constructor(atts);
};
Model.prototype.clone = function() {
return createObject(this);
};
Model.prototype.reload = function() {
var original;
if (this.isNew()) {
return this;
}
original = this.constructor.find(this.id);
this.load(original.attributes());
return original;
};
Model.prototype.toJSON = function() {
return this.attributes();
};
Model.prototype.toString = function() {
return "<" + this.constructor.className + " (" + (JSON.stringify(this)) + ")>";
};
Model.prototype.fromForm = function(form) {
var checkbox, key, name, result, _i, _j, _k, _len, _len1, _len2, _name, _ref, _ref1, _ref2;
result = {};
_ref = $(form).find('[type=checkbox]:not([value])');
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
checkbox = _ref[_i];
result[checkbox.name] = $(checkbox).prop('checked');
}
_ref1 = $(form).find('[type=checkbox][name$="[]"]');
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
checkbox = _ref1[_j];
name = checkbox.name.replace(/\[\]$/, '');
result[name] || (result[name] = []);
if ($(checkbox).prop('checked')) {
result[name].push(checkbox.value);
}
}
_ref2 = $(form).serializeArray();
for (_k = 0, _len2 = _ref2.length; _k < _len2; _k++) {
key = _ref2[_k];
result[_name = key.name] || (result[_name] = key.value);
}
return this.load(result);
};
Model.prototype.exists = function() {
return this.constructor.exists(this.id);
};
Model.prototype.refresh = function(data) {
var root;
root = this.constructor.irecords[this.id];
root.load(data);
this.trigger('refresh');
return this;
};
Model.prototype.save = function(options) {
var error, record;
if (options == null) {
options = {};
}
if (options.validate !== false) {
error = this.validate();
if (error) {
this.trigger('error', error);
return false;
}
}
this.trigger('beforeSave', options);
record = this.isNew() ? this.create(options) : this.update(options);
this.stripCloneAttrs();
this.trigger('save', options);
return record;
};
Model.query = function(params,options){
var _this = this;
if(this.ajax) return this.ajax.call(this, 'query', params, options )
.then(function(responseData){
_this.refresh(responseData);
return responseData;
});
throw "Ajax Module not defined"
}
Model.read = function(id, options){
var _this = this;
if(this.ajax) return this.ajax.call(this, 'read', id, options )
.then(function(data){
var instance = _this.exists(id);
if(instance){ instance.refresh(data); return instance; }
return _this.create(data, { ignoreAjax: true });
});
throw "Ajax Module not defined"
}
Model.api = function(){
var _this = this;
if(this.ajax && this.ajax.api) return this.ajax.api.apply(this, arguments )
throw "Ajax Module or api method not defined"
}
Model.prototype.create = function(options) {
if(!options) options = {};
var clone, record;
var _this = this;
this.trigger('beforeCreate', options);
this.id || (this.id = this.cid);
record = this.dup(false);
var parentModel = this.constructor;
parentModel.addRecord(record);
parentModel.sort();
clone = record.clone();
clone.trigger('create', options);
clone.trigger('change', 'create', options);
if(parentModel.ajax && !options.ignoreAjax) return parentModel.ajax.call(clone, 'create', this.constructor, options )
.then(function(data){
if (!(ModelUtils.isBlank(data) || _this.destroyed)) {
if (data.id && _this.id !== data.id) {
_this.changeID(data.id);
}
_this.refresh(data);
return _this;
}
});
return clone;
};
Model.prototype.update = function(options) {
if(!options) options = {};
var _this = this;
var clone, records;
this.trigger('beforeUpdate', options);
records = this.constructor.irecords;
var parentModel = this.constructor;
if(!parentModel.previousAttributes) parentModel.previousAttributes = {}
var previousRecord = records[this.id]
parentModel.previousAttributes[this.id] = JSON.stringify(previousRecord.attributes());
previousRecord.load(this.attributes());
this.constructor.sort();
clone = records[this.id].clone();
clone.trigger('update', options);
clone.trigger('change', 'update', options);
if(parentModel.ajax && !options.ignoreAjax) return parentModel.ajax.call(clone, 'update', this.constructor, options )
.then( function(data){ delete parentModel.previousAttributes[clone.id]; return clone; })
.then(function(data){ if(data){_this.refresh(data)}; return clone; })
.fail(function(err){ delete parentModel.previousAttributes[clone.id]; throw err; });
return clone;
};
Model.prototype.destroy = function(options) {
if (options == null) options = {};
if (options.clear == null) options.clear = true;
var _this = this;
var parentModel = this.constructor;
this.trigger('beforeDestroy', options);
this.remove(options);
this.destroyed = true;
this.trigger('destroy', options);
this.trigger('change', 'destroy', options);
if (this.listeningTo) {
this.stopListening();
}
this.unbind();
if(parentModel.ajax && !options.ignoreAjax) return parentModel.ajax.call(this, 'destroy', this.constructor, options )
.then(function(){ return _this; });
return this;
};
Model.prototype.bind = function(events, callback) {
var binder, singleEvent, _fn, _i, _len, _ref;
this.constructor.bind(events, binder = (function(_this) {
return function(record) {
if (record && _this.eql(record)) {
return callback.apply(_this, arguments);
}
};
})(this));
_ref = events.split(' ');
_fn = (function(_this) {
return function(singleEvent) {
var unbinder;
return _this.constructor.bind("unbind", unbinder = function(record, event, cb) {
if (record && _this.eql(record)) {
if (event && event !== singleEvent) {
return;
}
if (cb && cb !== callback) {
return;
}
_this.constructor.unbind(singleEvent, binder);
return _this.constructor.unbind("unbind", unbinder);
}
});
};
})(this);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
singleEvent = _ref[_i];
_fn(singleEvent);
}
return this;
};
Model.prototype.one = function(events, callback) {
var handler;
return this.bind(events, handler = (function(_this) {
return function() {
_this.unbind(events, handler);
return callback.apply(_this, arguments);
};
})(this));
};
Model.prototype.trigger = function() {
var args, _ref;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
args.splice(1, 0, this);
return (_ref = this.constructor).trigger.apply(_ref, args);
};
Model.prototype.listenTo = function() {
return Events.listenTo.apply(this, arguments);
};
Model.prototype.listenToOnce = function() {
return Events.listenToOnce.apply(this, arguments);
};
Model.prototype.stopListening = function() {
return Events.stopListening.apply(this, arguments);
};
Model.prototype.unbind = function(events, callback) {
var event, _i, _len, _ref, _results;
if (arguments.length === 0) {
return this.trigger('unbind');
} else if (events) {
_ref = events.split(' ');
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
event = _ref[_i];
_results.push(this.trigger('unbind', event, callback));
}
return _results;
}
};
return Model;
})();
Model.setup = function(name, attributes) {
var Instance;
if (attributes == null) {
attributes = [];
}
Instance = (function(_super) {
Module.clone(Instance, _super);
function Instance() {
return Instance.__super__.constructor.apply(this, arguments);
}
return Instance;
})(this);
Instance.configure.apply(Instance, [name].concat(__slice.call(attributes)));
return Instance;
};
Model.options = {};
var createObject = ModelUtils.createObject;
var isArray = ModelUtils.isArray;
var makeArray = ModelUtils.makeArray;
module.exports = Model
Model.prototype.on = Model.prototype.bind;
Model.prototype.off = Model.prototype.unbind;
Model.prototype.emit = Model.prototype.trigger;
__hasProp = {}.hasOwnProperty,
__slice = [].slice;