(function() { var $, Controller, Events, Log, Model, Module, Spine, guid, isArray, isBlank, makeArray, moduleKeywords; var __slice = Array.prototype.slice, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (this[i] === item) return i; } return -1; }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; Events = { bind: function(ev, callback) { var calls, evs, name, _i, _len; evs = ev.split(' '); calls = this.hasOwnProperty('_callbacks') && this._callbacks || (this._callbacks = {}); for (_i = 0, _len = evs.length; _i < _len; _i++) { name = evs[_i]; calls[name] || (calls[name] = []); calls[name].push(callback); } return this; }, one: function(ev, callback) { return this.bind(ev, function() { this.unbind(ev, arguments.callee); return callback.apply(this, arguments); }); }, trigger: function() { var args, callback, ev, list, _i, _len, _ref; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; ev = args.shift(); list = this.hasOwnProperty('_callbacks') && ((_ref = this._callbacks) != null ? _ref[ev] : void 0); if (!list) { return false; } for (_i = 0, _len = list.length; _i < _len; _i++) { callback = list[_i]; if (callback.apply(this, args) === false) { break; } } return true; }, unbind: function(ev, callback) { var cb, i, list, _len, _ref; if (!ev) { this._callbacks = {}; return this; } list = (_ref = this._callbacks) != null ? _ref[ev] : void 0; if (!list) { return this; } if (!callback) { delete this._callbacks[ev]; return this; } for (i = 0, _len = list.length; i < _len; i++) { cb = list[i]; if (cb === callback) { list = list.slice(); list.splice(i, 1); this._callbacks[ev] = list; break; } } return this; } }; Log = { trace: true, logPrefix: '(App)', log: function() { var args; args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; if (!this.trace) { return; } if (typeof console === 'undefined') { return; } if (this.logPrefix) { args.unshift(this.logPrefix); } console.log.apply(console, args); return this; } }; moduleKeywords = ['included', 'extended']; Module = (function() { Module.include = function(obj) { var included, key, value; if (!obj) { throw 'include(obj) requires obj'; } for (key in obj) { value = obj[key]; if (__indexOf.call(moduleKeywords, key) < 0) { this.prototype[key] = value; } } included = obj.included; if (included) { included.apply(this); } return this; }; Module.extend = function(obj) { var extended, key, value; if (!obj) { throw 'extend(obj) requires obj'; } for (key in obj) { value = obj[key]; if (__indexOf.call(moduleKeywords, key) < 0) { this[key] = value; } } extended = obj.extended; if (extended) { extended.apply(this); } return this; }; Module.proxy = function(func) { return __bind(function() { return func.apply(this, arguments); }, this); }; Module.prototype.proxy = function(func) { return __bind(function() { return func.apply(this, arguments); }, this); }; function Module() { if (typeof this.init === "function") { this.init.apply(this, arguments); } } return Module; })(); Model = (function() { __extends(Model, Module); Model.extend(Events); Model.records = {}; Model.attributes = []; Model.configure = function() { var attributes, name; name = arguments[0], attributes = 2 <= arguments.length ? __slice.call(arguments, 1) : []; this.className = name; this.records = {}; 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) { var record; record = this.records[id]; if (!record) { throw 'Unknown record'; } return record.clone(); }; Model.exists = function(id) { try { return this.find(id); } catch (e) { return false; } }; Model.refresh = function(values, options) { var record, records, _i, _len; if (options == null) { options = {}; } if (options.clear) { this.records = {}; } records = this.fromJSON(values); if (!isArray(records)) { records = [records]; } for (_i = 0, _len = records.length; _i < _len; _i++) { record = records[_i]; record.newRecord = false; record.id || (record.id = guid()); this.records[record.id] = record; } this.trigger('refresh', !options.clear && records); return this; }; Model.select = function(callback) { var id, record, result; result = (function() { var _ref, _results; _ref = this.records; _results = []; for (id in _ref) { record = _ref[id]; if (callback(record)) { _results.push(record); } } return _results; }).call(this); return this.cloneArray(result); }; Model.findByAttribute = function(name, value) { var id, record, _ref; _ref = this.records; for (id in _ref) { record = _ref[id]; 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 key, value, _ref, _results; _ref = this.records; _results = []; for (key in _ref) { value = _ref[key]; _results.push(callback(value.clone())); } return _results; }; Model.all = function() { return this.cloneArray(this.recordsValues()); }; Model.first = function() { var record; record = this.recordsValues()[0]; return record != null ? record.clone() : void 0; }; Model.last = function() { var record, values; values = this.recordsValues(); record = values[values.length - 1]; return record != null ? record.clone() : void 0; }; Model.count = function() { return this.recordsValues().length; }; Model.deleteAll = function() { var key, value, _ref, _results; _ref = this.records; _results = []; for (key in _ref) { value = _ref[key]; _results.push(delete this.records[key]); } return _results; }; Model.destroyAll = function() { var key, value, _ref, _results; _ref = this.records; _results = []; for (key in _ref) { value = _ref[key]; _results.push(this.records[key].destroy()); } return _results; }; Model.update = function(id, atts) { return this.find(id).updateAttributes(atts); }; Model.create = function(atts) { var record; record = new this(atts); return record.save(); }; Model.destroy = function(id) { return this.find(id).destroy(); }; Model.change = function(callbackOrParams) { if (typeof callbackOrParams === 'function') { return this.bind('change', callbackOrParams); } else { return this.trigger('change', callbackOrParams); } }; Model.fetch = function(callbackOrParams) { if (typeof callbackOrParams === 'function') { return this.bind('fetch', callbackOrParams); } else { return this.trigger('fetch', callbackOrParams); } }; Model.toJSON = function() { return this.recordsValues(); }; 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]; _results.push(new this(value)); } return _results; } else { return new this(objects); } }; Model.recordsValues = function() { var key, result, value, _ref; result = []; _ref = this.records; for (key in _ref) { value = _ref[key]; result.push(value); } return result; }; 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.prototype.newRecord = true; function Model(atts) { Model.__super__.constructor.apply(this, arguments); this.ids = []; if (atts) { this.load(atts); } } Model.prototype.isNew = function() { return this.newRecord; }; Model.prototype.isValid = function() { return !this.validate(); }; Model.prototype.validate = function() {}; Model.prototype.load = function(atts) { var key, value, _results; _results = []; for (key in atts) { value = atts[key]; _results.push(typeof this[key] === 'function' ? this[key](value) : this[key] = value); } return _results; }; 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 { result[key] = this[key]; } } } if (this.id) { result.id = this.id; } return result; }; Model.prototype.eql = function(rec) { var _ref, _ref2; return rec && rec.constructor === this.constructor && (rec.id === this.id || (_ref = this.id, __indexOf.call(rec.ids, _ref) >= 0) || (_ref2 = rec.id, __indexOf.call(this.ids, _ref2) >= 0)); }; Model.prototype.save = function() { var error; error = this.validate(); if (error) { this.trigger('error', error); return false; } this.trigger('beforeSave'); if (this.newRecord) { this.create(); } else { this.update(); } this.trigger('save'); return this; }; Model.prototype.updateAttribute = function(name, value) { this[name] = value; return this.save(); }; Model.prototype.updateAttributes = function(atts) { this.load(atts); return this.save(); }; Model.prototype.changeID = function(id) { var records; this.ids.push(this.id); records = this.constructor.records; records[id] = records[this.id]; delete records[this.id]; this.id = id; return this.save(); }; Model.prototype.destroy = function() { this.trigger('beforeDestroy'); delete this.constructor.records[this.id]; this.destroyed = true; this.trigger('destroy'); this.trigger('change', 'destroy'); this.unbind(); return this; }; Model.prototype.dup = function(newRecord) { var result; result = new this.constructor(this.attributes()); if (newRecord === false) { result.newRecord = this.newRecord; } else { delete result.id; } return result; }; Model.prototype.clone = function() { return Object.create(this); }; Model.prototype.reload = function() { var original; if (this.newRecord) { 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.exists = function() { return this.id && this.id in this.constructor.records; }; Model.prototype.update = function() { var clone, records; this.trigger('beforeUpdate'); records = this.constructor.records; records[this.id].load(this.attributes()); clone = records[this.id].clone(); clone.trigger('update'); return clone.trigger('change', 'update'); }; Model.prototype.create = function() { var clone, records; this.trigger('beforeCreate'); if (!this.id) { this.id = guid(); } this.newRecord = false; records = this.constructor.records; records[this.id] = this.dup(false); clone = records[this.id].clone(); clone.trigger('create'); return clone.trigger('change', 'create'); }; Model.prototype.bind = function(events, callback) { var binder, unbinder; this.constructor.bind(events, binder = __bind(function(record) { if (record && this.eql(record)) { return callback.apply(this, arguments); } }, this)); this.constructor.bind('unbind', unbinder = __bind(function(record) { if (record && this.eql(record)) { this.constructor.unbind(events, binder); return this.constructor.unbind('unbind', unbinder); } }, this)); return binder; }; 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.unbind = function() { return this.trigger('unbind'); }; return Model; })(); Controller = (function() { __extends(Controller, Module); Controller.include(Events); Controller.include(Log); Controller.prototype.eventSplitter = /^(\S+)\s*(.*)$/; Controller.prototype.tag = 'div'; function Controller(options) { this.release = __bind(this.release, this); var key, value, _ref; this.options = options; _ref = this.options; for (key in _ref) { value = _ref[key]; this[key] = value; } if (!this.el) { this.el = document.createElement(this.tag); } this.el = $(this.el); if (this.className) { this.el.addClass(this.className); } this.release(function() { return this.el.remove(); }); if (!this.events) { this.events = this.constructor.events; } if (!this.elements) { this.elements = this.constructor.elements; } if (this.events) { this.delegateEvents(); } if (this.elements) { this.refreshElements(); } Controller.__super__.constructor.apply(this, arguments); } Controller.prototype.release = function(callback) { if (typeof callback === 'function') { return this.bind('release', callback); } else { return this.trigger('release'); } }; Controller.prototype.$ = function(selector) { return $(selector, this.el); }; Controller.prototype.delegateEvents = function() { var eventName, key, match, method, selector, _ref, _results; _ref = this.events; _results = []; for (key in _ref) { method = _ref[key]; if (typeof method !== 'function') { method = this.proxy(this[method]); } match = key.match(this.eventSplitter); eventName = match[1]; selector = match[2]; _results.push(selector === '' ? this.el.bind(eventName, method) : this.el.delegate(selector, eventName, method)); } return _results; }; Controller.prototype.refreshElements = function() { var key, value, _ref, _results; _ref = this.elements; _results = []; for (key in _ref) { value = _ref[key]; _results.push(this[value] = this.$(key)); } return _results; }; Controller.prototype.delay = function(func, timeout) { return setTimeout(this.proxy(func), timeout || 0); }; Controller.prototype.html = function(element) { this.el.html(element.el || element); this.refreshElements(); return this.el; }; Controller.prototype.append = function() { var e, elements, _ref; elements = 1 <= arguments.length ? __slice.call(arguments, 0) : []; elements = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = elements.length; _i < _len; _i++) { e = elements[_i]; _results.push(e.el || e); } return _results; })(); (_ref = this.el).append.apply(_ref, elements); this.refreshElements(); return this.el; }; Controller.prototype.appendTo = function(element) { this.el.appendTo(element.el || element); this.refreshElements(); return this.el; }; Controller.prototype.prepend = function() { var e, elements, _ref; elements = 1 <= arguments.length ? __slice.call(arguments, 0) : []; elements = (function() { var _i, _len, _results; _results = []; for (_i = 0, _len = elements.length; _i < _len; _i++) { e = elements[_i]; _results.push(e.el || e); } return _results; })(); (_ref = this.el).prepend.apply(_ref, elements); this.refreshElements(); return this.el; }; Controller.prototype.replace = function(element) { var previous, _ref; _ref = [this.el, element.el || element], previous = _ref[0], this.el = _ref[1]; previous.replaceWith(this.el); this.delegateEvents(); this.refreshElements(); return this.el; }; return Controller; })(); $ = this.jQuery || this.Zepto || function(element) { return element; }; if (typeof Object.create !== 'function') { Object.create = function(o) { var Func; Func = function() {}; Func.prototype = o; return new Func(); }; } isArray = function(value) { return Object.prototype.toString.call(value) === '[object Array]'; }; isBlank = function(value) { var key; if (!value) { return true; } for (key in value) { return false; } return true; }; makeArray = function(args) { return Array.prototype.slice.call(args, 0); }; guid = function() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r, v; r = Math.random() * 16 | 0; v = c === 'x' ? r : r & 3 | 8; return v.toString(16); }).toUpperCase(); }; Spine = this.Spine = {}; if (typeof module !== "undefined" && module !== null) { module.exports = Spine; } Spine.version = '1.0.0'; Spine.isArray = isArray; Spine.isBlank = isBlank; Spine.$ = $; Spine.Events = Events; Spine.Log = Log; Spine.Module = Module; Spine.Controller = Controller; Spine.Model = Model; Module.extend.call(Spine, Events); Module.create = Module.sub = Controller.create = Controller.sub = Model.sub = function(instances, statics) { var result; result = (function() { __extends(result, this); function result() { result.__super__.constructor.apply(this, arguments); } return result; }).call(this); if (instances) { result.include(instances); } if (statics) { result.extend(statics); } if (typeof result.unbind === "function") { result.unbind(); } return result; }; Model.setup = function(name, attributes) { var Instance; if (attributes == null) { attributes = []; } Instance = (function() { __extends(Instance, this); function Instance() { Instance.__super__.constructor.apply(this, arguments); } return Instance; }).call(this); Instance.configure.apply(Instance, [name].concat(__slice.call(attributes))); return Instance; }; Module.init = Controller.init = Model.init = function(a1, a2, a3, a4, a5) { return new this(a1, a2, a3, a4, a5); }; Spine.Class = Module; }).call(this);