(function() { var $, Controller, Events, Log, Model, Module, Spine, isArray, isBlank, makeArray, moduleKeywords, __slice = Array.prototype.slice, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __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; }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 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; 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)) continue; 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 (this.logPrefix) args.unshift(this.logPrefix); if (typeof console !== "undefined" && console !== null) { if (typeof console.log === "function") console.log.apply(console, args); } return this; } }; moduleKeywords = ['included', 'extended']; Module = (function() { Module.include = function(obj) { var key, value, _ref; if (!obj) throw 'include(obj) requires obj'; for (key in obj) { value = obj[key]; if (__indexOf.call(moduleKeywords, key) < 0) this.prototype[key] = value; } if ((_ref = obj.included) != null) _ref.apply(this); return this; }; Module.extend = function(obj) { var key, value, _ref; if (!obj) throw 'extend(obj) requires obj'; for (key in obj) { value = obj[key]; if (__indexOf.call(moduleKeywords, key) < 0) this[key] = value; } if ((_ref = obj.extended) != null) _ref.apply(this); return this; }; Module.proxy = function(func) { var _this = this; return function() { return func.apply(_this, arguments); }; }; Module.prototype.proxy = function(func) { var _this = this; return function() { return func.apply(_this, arguments); }; }; function Module() { if (typeof this.init === "function") this.init.apply(this, arguments); } return Module; })(); Model = (function(_super) { __extends(Model, _super); Model.extend(Events); Model.records = {}; Model.crecords = {}; Model.attributes = []; Model.configure = function() { var attributes, name; name = arguments[0], attributes = 2 <= arguments.length ? __slice.call(arguments, 1) : []; this.className = name; this.records = {}; this.crecords = {}; 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 && ("" + id).match(/c-\d+/)) return this.findCID(id); if (!record) throw 'Unknown record'; return record.clone(); }; Model.findCID = function(cid) { var record; record = this.crecords[cid]; 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 = {}; this.crecords = {}; } records = this.fromJSON(values); if (!isArray(records)) records = [records]; for (_i = 0, _len = records.length; _i < _len; _i++) { record = records[_i]; record.id || (record.id = record.cid); this.records[record.id] = record; this.crecords[record.cid] = record; } this.trigger('refresh', !options.clear && this.cloneArray(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, 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('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.fromForm = function() { var _ref; return (_ref = new this).fromForm.apply(_ref, arguments); }; 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.idCounter = 0; Model.uid = function() { return this.idCounter++; }; function Model(atts) { Model.__super__.constructor.apply(this, arguments); if (atts) this.load(atts); this.cid || (this.cid = 'c-' + this.constructor.uid()); } 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; for (key in atts) { value = atts[key]; if (typeof this[key] === 'function') { 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 { 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.id === this.id || rec.cid === this.cid)); }; 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.trigger('save', options); return record; }; Model.prototype.updateAttribute = function(name, value) { this[name] = value; return this.save(); }; Model.prototype.updateAttributes = function(atts, options) { this.load(atts); return this.save(options); }; Model.prototype.changeID = function(id) { var records; records = this.constructor.records; records[id] = records[this.id]; delete records[this.id]; this.id = id; return this.save(); }; Model.prototype.destroy = function(options) { if (options == null) options = {}; this.trigger('beforeDestroy', options); delete this.constructor.records[this.id]; delete this.constructor.crecords[this.cid]; this.destroyed = true; this.trigger('destroy', options); this.trigger('change', 'destroy', options); this.unbind(); return this; }; Model.prototype.dup = function(newRecord) { var result; result = new this.constructor(this.attributes()); if (newRecord === false) { result.cid = this.cid; } else { delete result.id; } return result; }; Model.prototype.clone = function() { return Object.create(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 key, result, _i, _len, _ref; result = {}; _ref = $(form).serializeArray(); for (_i = 0, _len = _ref.length; _i < _len; _i++) { key = _ref[_i]; result[key.name] = key.value; } return this.load(result); }; Model.prototype.exists = function() { return this.id && this.id in this.constructor.records; }; Model.prototype.update = function(options) { var clone, records; this.trigger('beforeUpdate', options); records = this.constructor.records; records[this.id].load(this.attributes()); clone = records[this.id].clone(); clone.trigger('update', options); clone.trigger('change', 'update', options); return clone; }; Model.prototype.create = function(options) { var clone, record; this.trigger('beforeCreate', options); if (!this.id) this.id = this.cid; record = this.dup(false); this.constructor.records[this.id] = record; this.constructor.crecords[this.cid] = record; clone = record.clone(); clone.trigger('create', options); clone.trigger('change', 'create', options); return clone; }; Model.prototype.bind = function(events, callback) { var binder, unbinder, _this = this; this.constructor.bind(events, binder = function(record) { if (record && _this.eql(record)) return callback.apply(_this, arguments); }); this.constructor.bind('unbind', unbinder = function(record) { if (record && _this.eql(record)) { _this.constructor.unbind(events, binder); return _this.constructor.unbind('unbind', unbinder); } }); return binder; }; Model.prototype.one = function(events, callback) { var binder, _this = this; return binder = this.bind(events, function() { _this.constructor.unbind(events, binder); return callback.apply(_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.unbind = function() { return this.trigger('unbind'); }; return Model; })(Module); Controller = (function(_super) { __extends(Controller, _super); 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); if (this.attributes) this.el.attr(this.attributes); 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]; if (selector === '') { _results.push(this.el.bind(eventName, method)); } else { _results.push(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; })(Module); $ = (typeof window !== "undefined" && window !== null ? window.jQuery : void 0) || (typeof window !== "undefined" && window !== null ? window.Zepto : void 0) || 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); }; Spine = this.Spine = {}; if (typeof module !== "undefined" && module !== null) module.exports = Spine; Spine.version = '1.0.5'; 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(_super) { __extends(result, _super); function result() { result.__super__.constructor.apply(this, arguments); } return result; })(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(_super) { __extends(Instance, _super); function Instance() { Instance.__super__.constructor.apply(this, arguments); } return Instance; })(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);