Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

update spine

  • Loading branch information...
commit 2eec00812e31d5f889f26344523ceb1e71035875 1 parent 90b966b
@maccman authored
Showing with 226 additions and 192 deletions.
  1. +215 −182 app/javascripts/lib/spine.js
  2. +11 −10 app/javascripts/lib/spine.model.ajax.js
View
397 app/javascripts/lib/spine.js
@@ -15,6 +15,15 @@
return Array.prototype.slice.call(args, 0);
};
+ // Shim Array, as these functions aren't in IE
+ if (typeof Array.prototype.indexOf === "undefined")
+ Array.prototype.indexOf = function(value){
+ for ( var i = 0; i < this.length; i++ )
+ if ( this[ i ] === value )
+ return i;
+ return -1;
+ };
+
var Events = Spine.Events = {
bind: function(ev, callback) {
var evs = ev.split(" ");
@@ -31,13 +40,14 @@
var ev = args.shift();
var list, calls, i, l;
- if (!(calls = this._callbacks)) return this;
- if (!(list = this._callbacks[ev])) return this;
+ if (!(calls = this._callbacks)) return false;
+ if (!(list = this._callbacks[ev])) return false;
for (i = 0, l = list.length; i < l; i++)
if (list[i].apply(this, args) === false)
- return false;
- return this;
+ break;
+
+ return true;
},
unbind: function(ev, callback){
@@ -50,12 +60,16 @@
if (!(calls = this._callbacks)) return this;
if (!(list = this._callbacks[ev])) return this;
- for (i = 0, l = list.length; i < l; i++) {
+ if ( !callback ) {
+ delete this._callbacks[ev];
+ return this;
+ }
+
+ for (i = 0, l = list.length; i < l; i++)
if (callback === list[i]) {
list.splice(i, 1);
break;
}
- }
return this;
}
@@ -155,6 +169,7 @@
Class.prototype.proxy = Class.proxy;
Class.prototype.proxyAll = Class.proxyAll;
Class.inst = Class.init;
+ Class.sub = Class.create;
// Models
@@ -169,154 +184,164 @@
Model.extend(Events);
- // Alias create
- Model.createSub = Model.create;
- Model.setup = function(name, atts){
- var model = Model.createSub();
- if (name) model.name = name;
- if (atts) model.attributes = atts;
- return model;
- };
-
Model.extend({
- created: function(sub){
- this.records = {};
- this.attributes = [];
-
- this.bind("create", this.proxy(function(record){
- this.trigger("change", "create", record);
- }));
- this.bind("update", this.proxy(function(record){
- this.trigger("change", "update", record);
- }));
- this.bind("destroy", this.proxy(function(record){
- this.trigger("change", "destroy", record);
- }));
- },
-
- find: function(id){
- var record = this.records[id];
- if ( !record ) throw("Unknown record");
- return record.dup();
- },
-
- exists: function(id){
- try {
- return this.find(id);
- } catch (e) {
- return false;
- }
- },
-
- refresh: function(values){
- this.records = {};
-
- for (var i=0, il = values.length; i < il; i++) {
- var record = this.init(values[i]);
- record.newRecord = false;
- this.records[record.id] = record;
- }
-
- this.trigger("refresh");
- },
-
- 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);
- },
-
- findByAttribute: function(name, value){
- for (var key in this.records)
- if (this.records[key][name] == value)
- return this.records[key].dup();
- },
-
- findAllByAttribute: function(name, value){
- return(this.select(function(item){
- return(item[name] == value);
- }));
- },
-
- each: function(callback){
- for (var key in this.records)
- callback(this.records[key]);
- },
-
- 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());
- },
-
- 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 = this.init(atts);
- record.save();
- return record;
- },
-
- destroy: function(id){
- this.find(id).destroy();
- },
-
- sync: function(callback){
- this.bind("change", callback);
- },
-
- fetch: function(callback){
- callback ? this.bind("fetch", callback) : this.trigger("fetch");
- },
-
- toJSON: function(){
- return this.recordsValues();
- },
-
- // Private
-
- recordsValues: function(){
- var result = [];
- for (var key in this.records)
- result.push(this.records[key]);
- return result;
- },
-
- dupArray: function(array){
- var result = [];
- for (var i=0; i < array.length; i++)
- result.push(array[i].dup());
- return result;
- }
+ setup: function(name, atts){
+ var model = Model.sub();
+ if (name) model.name = name;
+ if (atts) model.attributes = atts;
+ return model;
+ },
+
+ created: function(sub){
+ this.records = {};
+ this.attributes = [];
+
+ this.bind("create", this.proxy(function(record){
+ this.trigger("change", "create", record);
+ }));
+ this.bind("update", this.proxy(function(record){
+ this.trigger("change", "update", record);
+ }));
+ this.bind("destroy", this.proxy(function(record){
+ this.trigger("change", "destroy", record);
+ }));
+ },
+
+ find: function(id){
+ var record = this.records[id];
+ if ( !record ) throw("Unknown record");
+ return record.clone();
+ },
+
+ exists: function(id){
+ try {
+ return this.find(id);
+ } catch (e) {
+ return false;
+ }
+ },
+
+ refresh: function(values){
+ this.records = {};
+
+ for (var i=0, il = values.length; i < il; i++) {
+ var record = this.init(values[i]);
+ record.newRecord = false;
+ this.records[record.id] = record;
+ }
+
+ this.trigger("refresh");
+ },
+
+ select: function(callback){
+ var result = [];
+
+ for (var key in this.records)
+ if (callback(this.records[key]))
+ result.push(this.records[key]);
+
+ return this.cloneArray(result);
+ },
+
+ findByAttribute: function(name, value){
+ for (var key in this.records)
+ if (this.records[key][name] == value)
+ return this.records[key].clone();
+ },
+
+ findAllByAttribute: function(name, value){
+ return(this.select(function(item){
+ return(item[name] == value);
+ }));
+ },
+
+ each: function(callback){
+ for (var key in this.records)
+ callback(this.records[key]);
+ },
+
+ all: function(){
+ return this.cloneArray(this.recordsValues());
+ },
+
+ first: function(){
+ var record = this.recordsValues()[0];
+ return(record && record.clone());
+ },
+
+ last: function(){
+ var values = this.recordsValues()
+ var record = values[values.length - 1];
+ return(record && record.clone());
+ },
+
+ 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 = this.init(atts);
+ record.save();
+ return record;
+ },
+
+ destroy: function(id){
+ this.find(id).destroy();
+ },
+
+ sync: function(callback){
+ this.bind("change", callback);
+ },
+
+ fetch: function(params){
+ $.isFunction(params) ? this.bind("fetch", params) : this.trigger("fetch", params);
+ },
+
+ toJSON: function(){
+ return this.recordsValues();
+ },
+
+ fromJSON: function(objects){
+ var self = this;
+ if (typeof objects == "string")
+ objects = JSON.parse(objects)
+ if (typeof objects == "array")
+ return($.map(objects, function(){
+ return self.init(this);
+ }));
+ else
+ return this.init(objects);
+ },
+
+ // Private
+
+ recordsValues: function(){
+ var result = [];
+ for (var key in this.records)
+ result.push(this.records[key]);
+ return result;
+ },
+
+ cloneArray: function(array){
+ var result = [];
+ for (var i=0; i < array.length; i++)
+ result.push(array[i].dup());
+ return result;
+ }
});
Model.include({
@@ -330,6 +355,10 @@
isNew: function(){
return this.newRecord;
},
+
+ isValid: function(){
+ return(!this.validate());
+ },
validate: function(){ },
@@ -355,14 +384,15 @@
save: function(){
var error = this.validate();
- if (error) {
- if ( !this.trigger("error", error) )
+ if ( error ) {
+ if ( !this.trigger("error", this, error) )
throw("Validation failed: " + error);
}
- this.trigger("beforeSave");
+ this.trigger("beforeSave", this);
this.newRecord ? this.create() : this.update();
- this.trigger("save");
+ this.trigger("save", this);
+ return this;
},
updateAttribute: function(name, value){
@@ -376,9 +406,9 @@
},
destroy: function(){
- this.trigger("beforeDestroy");
+ this.trigger("beforeDestroy", this);
delete this.parent.records[this.id];
- this.trigger("destroy");
+ this.trigger("destroy", this);
},
dup: function(){
@@ -386,9 +416,16 @@
result.newRecord = this.newRecord;
return result;
},
+
+ clone: function(){
+ return Object.create(this);
+ },
reload: function(){
- return(this.parent.find(this.id));
+ if ( this.newRecord ) return this;
+ var original = this.parent.find(this.id);
+ this.load(original.attributes());
+ return original;
},
toJSON: function(){
@@ -402,30 +439,30 @@
// Private
update: function(){
- this.trigger("beforeUpdate");
- this.parent.records[this.id] = this.dup();
- this.trigger("update");
+ this.trigger("beforeUpdate", this);
+ var records = this.parent.records;
+ records[this.id].load(this.attributes());
+ this.trigger("update", records[this.id].clone());
},
create: function(){
- this.trigger("beforeCreate");
+ this.trigger("beforeCreate", this);
if ( !this.id ) this.id = Spine.guid();
- this.newRecord = false;
- this.parent.records[this.id] = this.dup();
- this.trigger("create");
+ this.newRecord = false;
+ var records = this.parent.records;
+ records[this.id] = this.dup();
+ this.trigger("create", records[this.id].clone());
},
bind: function(events, callback){
- this.parent.bind(events, this.proxy(function(record){
+ return this.parent.bind(events, this.proxy(function(record){
if ( record && this.eql(record) )
callback.apply(this, arguments);
}));
},
- trigger: function(events){
- var args = makeArray(arguments);
- args.splice(1, 0, this);
- this.parent.trigger.apply(this.parent, args);
+ trigger: function(){
+ return this.parent.trigger.apply(this.parent, arguments);
}
});
@@ -438,16 +475,16 @@
initializer: function(options){
this.options = options;
-
+
for (var key in this.options)
this[key] = this.options[key];
-
+
if (!this.el) this.el = document.createElement(this.tag);
this.el = $(this.el);
-
+
if ( !this.events ) this.events = this.parent.events;
if ( !this.elements ) this.elements = this.parent.elements;
-
+
if (this.events) this.delegateEvents();
if (this.elements) this.refreshElements();
if (this.proxied) this.proxyAll.apply(this, this.proxied);
@@ -487,11 +524,7 @@
Controller.include(Events);
Controller.include(Log);
- Spine.App = Controller.create({
- create: function(properties){
- this.parent.include(properties);
- return this;
- }
- }).init();
+ Spine.App = Class.create();
+ Spine.App.extend(Events)
Controller.fn.App = Spine.App;
})();
View
21 app/javascripts/lib/spine.model.ajax.js
@@ -18,15 +18,15 @@ var urlError = function() {
throw new Error("A 'url' property or function must be specified");
};
-var ajaxSync = function(method, record){
+var ajaxSync = function(method, record, params){
if (Model._noSync) return;
- var params = {
+ params = $.extend({
type: methodMap[method],
contentType: "application/json",
dataType: "json",
processData: false
- };
+ }, params || {});
if (method == "create" && record.model)
params.url = getUrl(record.parent);
@@ -40,19 +40,20 @@ var ajaxSync = function(method, record){
if (Model.ajaxPrefix) {
var prefix = record.parent.name.toLowerCase();
+ data = {};
data[prefix] = record;
} else {
data = record;
}
-
+ data = $.extend(data, params.data);
params.data = JSON.stringify(data);
}
-
- if (method == "read")
+
+ if (method == "read" && !params.success)
params.success = function(data){
- (record.refresh || record.load).call(record, data);
+ (record.refresh || record.load).call(record, data);
};
-
+
params.error = function(xhr, s, e){
record.trigger("ajaxError", xhr, s, e);
};
@@ -63,8 +64,8 @@ var ajaxSync = function(method, record){
Model.Ajax = {
extended: function(){
this.sync(ajaxSync);
- this.fetch(this.proxy(function(){
- ajaxSync("read", this);
+ this.fetch(this.proxy(function(params){
+ ajaxSync("read", this, params);
}));
}
};
Please sign in to comment.
Something went wrong with that request. Please try again.