--- /dev/null
+var Backbone, op, AppView, _ref, _;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+/**
+ * @class Application view, automatically attaching to an existing element
+ * found at `appSelector`.
+ * @extends Backbone.View
+ */
+AppView = exports.AppView = Backbone.View.extend({
+ appSelector: '#content .inner'
+ /**
+ * @constructor
+ */,
+ constructor: (function(){
+ function AppView(options){
+ var that, _this = this;
+ options == null && (options = {});
+ if (typeof options === 'function') {
+ this.initialize = options;
+ options = {};
+ } else {
+ if (that = options.initialize) {
+ this.initialize = that;
+ }
+ }
+ if (that = options.appSelector) {
+ this.appSelector = that;
+ }
+ options.el || (options.el = jQuery(this.appSelector)[0]);
+ Backbone.View.call(this, options);
+ jQuery(function(){
+ return _this.render();
+ });
+ return this;
+ }
+ return AppView;
+ }())
+ /**
+ * Override to set up your app. This method may be passed
+ * as an option to the constructor.
+ */,
+ initialize: function(){}
+ /**
+ * Append subviews.
+ */,
+ render: function(){
+ var _ref;
+ if (this.view && !((_ref = this.view.$el.parent()) != null && _ref.length)) {
+ return this.$el.append(this.view.el);
+ }
+ },
+ getClassName: function(){
+ return (this.constructor.name || this.constructor.displayName) + "";
+ },
+ toString: function(){
+ return this.getClassName() + "()";
+ }
+});
\ No newline at end of file
--- /dev/null
+require.define('/node_modules/kraken/app.js.js', function(require, module, exports, __dirname, __filename, undefined){
+
+var Backbone, op, AppView, _ref, _;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+/**
+ * @class Application view, automatically attaching to an existing element
+ * found at `appSelector`.
+ * @extends Backbone.View
+ */
+AppView = exports.AppView = Backbone.View.extend({
+ appSelector: '#content .inner'
+ /**
+ * @constructor
+ */,
+ constructor: (function(){
+ function AppView(options){
+ var that, _this = this;
+ options == null && (options = {});
+ if (typeof options === 'function') {
+ this.initialize = options;
+ options = {};
+ } else {
+ if (that = options.initialize) {
+ this.initialize = that;
+ }
+ }
+ if (that = options.appSelector) {
+ this.appSelector = that;
+ }
+ options.el || (options.el = jQuery(this.appSelector)[0]);
+ Backbone.View.call(this, options);
+ jQuery(function(){
+ return _this.render();
+ });
+ return this;
+ }
+ return AppView;
+ }())
+ /**
+ * Override to set up your app. This method may be passed
+ * as an option to the constructor.
+ */,
+ initialize: function(){}
+ /**
+ * Append subviews.
+ */,
+ render: function(){
+ var _ref;
+ if (this.view && !((_ref = this.view.$el.parent()) != null && _ref.length)) {
+ return this.$el.append(this.view.el);
+ }
+ },
+ getClassName: function(){
+ return (this.constructor.name || this.constructor.displayName) + "";
+ },
+ toString: function(){
+ return this.getClassName() + "()";
+ }
+});
+
+});
--- /dev/null
+var Backbone, op, BaseBackboneMixin, Mixin, mixinBase, _ref, _, __slice = [].slice;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+BaseBackboneMixin = exports.BaseBackboneMixin = {
+ initialize: function(){
+ return this.__apply_bind__();
+ }
+ /**
+ * A list of method-names to bind on `initialize`; set this on a subclass to override.
+ * @type Array<String>
+ */,
+ __bind__: []
+ /**
+ * Applies the contents of `__bind__`.
+ */,
+ __apply_bind__: function(){
+ var names;
+ names = _(this.pluckSuperAndSelf('__bind__')).chain().flatten().compact().unique().value();
+ if (names.length) {
+ return _.bindAll.apply(_, [this].concat(__slice.call(names)));
+ }
+ }
+ /**
+ * Whether we're ready.
+ * @type Boolean
+ */,
+ ready: false
+ /**
+ * Triggers the 'ready' event if it has not yet been triggered.
+ * Subsequent listeners added on this event will be auto-triggered.
+ * @returns {this}
+ */,
+ triggerReady: function(lock, event){
+ lock == null && (lock = 'ready');
+ event == null && (event = 'ready');
+ if (this[lock]) {
+ return this;
+ }
+ this[lock] = true;
+ this.trigger(event, this);
+ return this;
+ }
+ /**
+ * Resets the 'ready' event to its non-triggered state, firing a
+ * 'ready-reset' event.
+ * @returns {this}
+ */,
+ resetReady: function(lock, event){
+ lock == null && (lock = 'ready');
+ event == null && (event = 'ready');
+ if (!this[lock]) {
+ return this;
+ }
+ this[lock] = false;
+ this.trigger(event + "-reset", this);
+ return this;
+ }
+ /**
+ * Wrap {@link Backbone.Event#on} registration to handle registrations
+ * on 'ready' after we've broadcast the event. Handler will always still
+ * be registered, however, in case the emitter is reset.
+ *
+ * @param {String} events Space-separated events for which to register.
+ * @param {Function} callback
+ * @param {Object} [context]
+ * @returns {this}
+ */,
+ on: function(events, callback, context){
+ context == null && (context = this);
+ if (!callback) {
+ return this;
+ }
+ Backbone.Events.on.apply(this, arguments);
+ if (this.ready && _.contains(events.split(/\s+/), 'ready')) {
+ callback.call(context, this);
+ }
+ return this;
+ },
+ makeHandlersForCallback: function(cb){
+ var _this = this;
+ return {
+ success: function(){
+ return cb.call(_this, [null].concat(arguments));
+ },
+ error: function(it){
+ return cb.call(_this, it);
+ }
+ };
+ }
+ /**
+ * Count of outstanding tasks.
+ * @type Number
+ */,
+ waitingOn: 0
+ /**
+ * Increment the waiting task counter.
+ * @returns {this}
+ */,
+ wait: function(){
+ var count;
+ count = this.waitingOn;
+ this.waitingOn += 1;
+ if (count === 0 && this.waitingOn > 0) {
+ this.trigger('start-waiting', this);
+ }
+ return this;
+ }
+ /**
+ * Decrement the waiting task counter.
+ * @returns {this}
+ */,
+ unwait: function(){
+ var count;
+ count = this.waitingOn;
+ this.waitingOn -= 1;
+ if (this.waitingOn === 0 && count > 0) {
+ this.trigger('stop-waiting', this);
+ }
+ return this;
+ }
+ /**
+ * @param {Function} fn Function to wrap.
+ * @returns {Function} A function wrapping the passed function with a call
+ * to `unwait()`, then delegating with current context and arguments.
+ */,
+ unwaitAnd: function(fn){
+ var self;
+ self = this;
+ return function(){
+ self.unwait();
+ return fn.apply(this, arguments);
+ };
+ },
+ getClassName: function(){
+ return (this.constructor.name || this.constructor.displayName) + "";
+ },
+ toString: function(){
+ return this.getClassName() + "()";
+ }
+};
+/**
+ * @class Base mixin class. Extend this to create a new mixin, attaching the
+ * donor methods as you would instance methods.
+ *
+ * To mingle your mixin with another class or object:
+ *
+ * class MyMixin extends Mixin
+ * foo: -> "foo!"
+ *
+ * # Mix into an object...
+ * o = MyMixin.mix { bar:1 }
+ *
+ * # Mix into a Coco class...
+ * class Bar
+ * MyMixin.mix this
+ * bar : 1
+ *
+ */
+exports.Mixin = Mixin = (function(){
+ /**
+ * Mixes this mixin into the target. If `target` is not a class, a new
+ * object will be returned which inherits from the mixin.
+ */
+ Mixin.displayName = 'Mixin';
+ var prototype = Mixin.prototype, constructor = Mixin;
+ Mixin.mix = function(target){
+ var MixinClass;
+ if (!target) {
+ return that;
+ }
+ MixinClass = Mixin;
+ if (this instanceof Mixin) {
+ MixinClass = this.constructor;
+ }
+ if (this instanceof Function) {
+ MixinClass = this;
+ }
+ if (typeof target === 'function') {
+ __import(target.prototype, MixinClass.prototype);
+ } else {
+ target = __import(_.clone(MixinClass.prototype), target);
+ }
+ (target.__mixins__ || (target.__mixins__ = [])).push(MixinClass);
+ return target;
+ };
+ /**
+ * Coco metaprogramming hook to propagate class properties and methods.
+ */
+ Mixin.extended = function(SubClass){
+ var SuperClass, k, v, _own = {}.hasOwnProperty;
+ SuperClass = this;
+ for (k in SuperClass) if (_own.call(SuperClass, k)) {
+ v = SuperClass[k];
+ if (!SubClass[k]) {
+ SubClass[k] = v;
+ }
+ }
+ return SubClass;
+ };
+ function Mixin(){}
+ return Mixin;
+}());
+/**
+ * Mixes BaseBackboneMixin into another object or prototype.
+ * @returns {Object} The merged prototype object.
+ */
+mixinBase = exports.mixinBase = function(){
+ var bodies;
+ bodies = __slice.call(arguments);
+ return _.extend.apply(_, [_.clone(BaseBackboneMixin)].concat(__slice.call(bodies)));
+};
+function __import(obj, src){
+ var own = {}.hasOwnProperty;
+ for (var key in src) if (own.call(src, key)) obj[key] = src[key];
+ return obj;
+}
\ No newline at end of file
--- /dev/null
+require.define('/node_modules/kraken/base/base-mixin.js.js', function(require, module, exports, __dirname, __filename, undefined){
+
+var Backbone, op, BaseBackboneMixin, Mixin, mixinBase, _ref, _, __slice = [].slice;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+BaseBackboneMixin = exports.BaseBackboneMixin = {
+ initialize: function(){
+ return this.__apply_bind__();
+ }
+ /**
+ * A list of method-names to bind on `initialize`; set this on a subclass to override.
+ * @type Array<String>
+ */,
+ __bind__: []
+ /**
+ * Applies the contents of `__bind__`.
+ */,
+ __apply_bind__: function(){
+ var names;
+ names = _(this.pluckSuperAndSelf('__bind__')).chain().flatten().compact().unique().value();
+ if (names.length) {
+ return _.bindAll.apply(_, [this].concat(__slice.call(names)));
+ }
+ }
+ /**
+ * Whether we're ready.
+ * @type Boolean
+ */,
+ ready: false
+ /**
+ * Triggers the 'ready' event if it has not yet been triggered.
+ * Subsequent listeners added on this event will be auto-triggered.
+ * @returns {this}
+ */,
+ triggerReady: function(lock, event){
+ lock == null && (lock = 'ready');
+ event == null && (event = 'ready');
+ if (this[lock]) {
+ return this;
+ }
+ this[lock] = true;
+ this.trigger(event, this);
+ return this;
+ }
+ /**
+ * Resets the 'ready' event to its non-triggered state, firing a
+ * 'ready-reset' event.
+ * @returns {this}
+ */,
+ resetReady: function(lock, event){
+ lock == null && (lock = 'ready');
+ event == null && (event = 'ready');
+ if (!this[lock]) {
+ return this;
+ }
+ this[lock] = false;
+ this.trigger(event + "-reset", this);
+ return this;
+ }
+ /**
+ * Wrap {@link Backbone.Event#on} registration to handle registrations
+ * on 'ready' after we've broadcast the event. Handler will always still
+ * be registered, however, in case the emitter is reset.
+ *
+ * @param {String} events Space-separated events for which to register.
+ * @param {Function} callback
+ * @param {Object} [context]
+ * @returns {this}
+ */,
+ on: function(events, callback, context){
+ context == null && (context = this);
+ if (!callback) {
+ return this;
+ }
+ Backbone.Events.on.apply(this, arguments);
+ if (this.ready && _.contains(events.split(/\s+/), 'ready')) {
+ callback.call(context, this);
+ }
+ return this;
+ },
+ makeHandlersForCallback: function(cb){
+ var _this = this;
+ return {
+ success: function(){
+ return cb.call(_this, [null].concat(arguments));
+ },
+ error: function(it){
+ return cb.call(_this, it);
+ }
+ };
+ }
+ /**
+ * Count of outstanding tasks.
+ * @type Number
+ */,
+ waitingOn: 0
+ /**
+ * Increment the waiting task counter.
+ * @returns {this}
+ */,
+ wait: function(){
+ var count;
+ count = this.waitingOn;
+ this.waitingOn += 1;
+ if (count === 0 && this.waitingOn > 0) {
+ this.trigger('start-waiting', this);
+ }
+ return this;
+ }
+ /**
+ * Decrement the waiting task counter.
+ * @returns {this}
+ */,
+ unwait: function(){
+ var count;
+ count = this.waitingOn;
+ this.waitingOn -= 1;
+ if (this.waitingOn === 0 && count > 0) {
+ this.trigger('stop-waiting', this);
+ }
+ return this;
+ }
+ /**
+ * @param {Function} fn Function to wrap.
+ * @returns {Function} A function wrapping the passed function with a call
+ * to `unwait()`, then delegating with current context and arguments.
+ */,
+ unwaitAnd: function(fn){
+ var self;
+ self = this;
+ return function(){
+ self.unwait();
+ return fn.apply(this, arguments);
+ };
+ },
+ getClassName: function(){
+ return (this.constructor.name || this.constructor.displayName) + "";
+ },
+ toString: function(){
+ return this.getClassName() + "()";
+ }
+};
+/**
+ * @class Base mixin class. Extend this to create a new mixin, attaching the
+ * donor methods as you would instance methods.
+ *
+ * To mingle your mixin with another class or object:
+ *
+ * class MyMixin extends Mixin
+ * foo: -> "foo!"
+ *
+ * # Mix into an object...
+ * o = MyMixin.mix { bar:1 }
+ *
+ * # Mix into a Coco class...
+ * class Bar
+ * MyMixin.mix this
+ * bar : 1
+ *
+ */
+exports.Mixin = Mixin = (function(){
+ /**
+ * Mixes this mixin into the target. If `target` is not a class, a new
+ * object will be returned which inherits from the mixin.
+ */
+ Mixin.displayName = 'Mixin';
+ var prototype = Mixin.prototype, constructor = Mixin;
+ Mixin.mix = function(target){
+ var MixinClass;
+ if (!target) {
+ return that;
+ }
+ MixinClass = Mixin;
+ if (this instanceof Mixin) {
+ MixinClass = this.constructor;
+ }
+ if (this instanceof Function) {
+ MixinClass = this;
+ }
+ if (typeof target === 'function') {
+ __import(target.prototype, MixinClass.prototype);
+ } else {
+ target = __import(_.clone(MixinClass.prototype), target);
+ }
+ (target.__mixins__ || (target.__mixins__ = [])).push(MixinClass);
+ return target;
+ };
+ /**
+ * Coco metaprogramming hook to propagate class properties and methods.
+ */
+ Mixin.extended = function(SubClass){
+ var SuperClass, k, v, _own = {}.hasOwnProperty;
+ SuperClass = this;
+ for (k in SuperClass) if (_own.call(SuperClass, k)) {
+ v = SuperClass[k];
+ if (!SubClass[k]) {
+ SubClass[k] = v;
+ }
+ }
+ return SubClass;
+ };
+ function Mixin(){}
+ return Mixin;
+}());
+/**
+ * Mixes BaseBackboneMixin into another object or prototype.
+ * @returns {Object} The merged prototype object.
+ */
+mixinBase = exports.mixinBase = function(){
+ var bodies;
+ bodies = __slice.call(arguments);
+ return _.extend.apply(_, [_.clone(BaseBackboneMixin)].concat(__slice.call(bodies)));
+};
+function __import(obj, src){
+ var own = {}.hasOwnProperty;
+ for (var key in src) if (own.call(src, key)) obj[key] = src[key];
+ return obj;
+}
+
+});
--- /dev/null
+var Backbone, op, BaseBackboneMixin, mixinBase, BaseModel, BaseList, _ref, _, __slice = [].slice;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+_ref = require('kraken/base/base-mixin'), BaseBackboneMixin = _ref.BaseBackboneMixin, mixinBase = _ref.mixinBase;
+/**
+ * @class Base model, extending Backbone.Model, used by scaffold and others.
+ * @extends Backbone.Model
+ */
+BaseModel = exports.BaseModel = Backbone.Model.extend(mixinBase({
+ constructor: (function(){
+ function BaseModel(){
+ this.__class__ = this.constructor;
+ this.__superclass__ = this.constructor.__super__.constructor;
+ this.waitingOn = 0;
+ return Backbone.Model.apply(this, arguments);
+ }
+ return BaseModel;
+ }()),
+ url: function(){
+ return this.urlRoot + "/" + this.get('id') + ".json";
+ },
+ has: function(key){
+ return this.get(key) != null;
+ },
+ get: function(key){
+ return _.getNested(this.attributes, key);
+ }
+ /**
+ * Override to customize what data or assets the model requires,
+ * and how they should be loaded.
+ *
+ * By default, `load()` simply calls `loadModel()` via `loader()`.
+ *
+ * @see BaseModel#loader
+ * @see BaseModel#loadModel
+ * @returns {this}
+ */,
+ load: function(){
+ console.log(this + ".load()");
+ this.loader({
+ start: this.loadModel,
+ completeEvent: 'fetch-success'
+ });
+ return this;
+ }
+ /**
+ * Wraps the loading workflow boilerplate:
+ * - Squelches multiple loads from running at once
+ * - Squelches loads post-ready, unless forced
+ * - Triggers a start event
+ * - Triggers "ready" when complete
+ * - Wraps workflow with wait/unwait
+ * - Cleans up "loading" state
+ *
+ * @protected
+ * @param {Object} [opts={}] Options:
+ * @param {Function} opts.start Function that starts the loading process. Always called with `this` as the context.
+ * @param {String} [opts.startEvent='load'] Event to trigger before beginning the load.
+ * @param {String} [opts.completeEvent='load-success'] Event which signals loading has completed successfully.
+ * @param {String} [opts.errorEvent='load-error'] Event which signals loading has completed but failed.
+ * @param {Boolean} [opts.force=false] If true, reset ready state if we're ready before proceeding.
+ * @param {Boolean} [opts.readyIfError=false] If true, move fire the ready event when loading completes, even if it failed.
+ * @returns {this}
+ */,
+ loader: function(opts){
+ var _this = this;
+ opts == null && (opts = {});
+ opts = (__import({
+ force: false,
+ readyIfError: false,
+ startEvent: 'load',
+ completeEvent: 'load-success',
+ errorEvent: 'load-error'
+ }, opts));
+ if (opts.force) {
+ this.resetReady();
+ }
+ if (!opts.start) {
+ throw new Error('You must specify a `start` function to start loading!');
+ }
+ if (this.loading || this.ready) {
+ return this;
+ }
+ this.wait();
+ this.loading = true;
+ this.trigger(opts.startEvent, this);
+ this.once(opts.completeEvent, function(){
+ _this.loading = false;
+ _this.unwait();
+ if (opts.completeEvent !== 'load-success') {
+ _this.trigger('load-success', _this);
+ }
+ return _this.triggerReady();
+ });
+ this.once(opts.errorEvent, function(){
+ _this.loading = false;
+ _this.unwait();
+ if (opts.errorEvent !== 'load-error') {
+ _this.trigger('load-error', _this);
+ }
+ if (opts.readyIfError) {
+ return _this.triggerReady();
+ }
+ });
+ opts.start.call(this);
+ return this;
+ }
+ /**
+ * Runs `.fetch()`, triggering a `fetch` event at start, and
+ * `fetch-success` / `fetch-error` on completion.
+ *
+ * @protected
+ * @returns {this}
+ */,
+ loadModel: function(){
+ var _this = this;
+ this.wait();
+ this.trigger('fetch', this);
+ this.fetch({
+ success: function(){
+ _this.unwait();
+ return _this.trigger('fetch-success', _this);
+ },
+ error: function(){
+ _this.unwait();
+ return _this.trigger.apply(_this, ['fetch-error', _this].concat(__slice.call(arguments)));
+ }
+ });
+ return this;
+ },
+ serialize: function(v){
+ if (_.isBoolean(v)) {
+ v = Number(v);
+ } else if (_.isObject(v)) {
+ v = JSON.stringify(v);
+ }
+ return String(v);
+ }
+ /**
+ * Like `.toJSON()` in that it should return a plain object with no functions,
+ * but for the purpose of `.toKV()`, allowing you to customize the values
+ * included and keys used.
+ *
+ * @param {Object} [opts={}] Options:
+ * @param {Boolean} [opts.keepFunctions=false] If false, functions will be omitted from the result.
+ * @returns {Object}
+ */,
+ toKVPairs: function(opts){
+ var kvo, k, v;
+ opts == null && (opts = {});
+ opts = (__import({
+ keepFunctions: false
+ }, opts));
+ kvo = _.collapseObject(this.toJSON());
+ for (k in kvo) {
+ v = kvo[k];
+ if (opts.keepFunctions || typeof v !== 'function') {
+ kvo[k] = this.serialize(v);
+ }
+ }
+ return kvo;
+ }
+ /**
+ * Serialize the model into a `www-form-encoded` string suitable for use as
+ * a query string or a POST body.
+ * @returns {String}
+ */,
+ toKV: function(item_delim, kv_delim){
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ return _.toKV(this.toKVPairs(), item_delim, kv_delim);
+ }
+ /**
+ * @returns {String} URL identifying this model.
+ */,
+ toURL: function(){
+ return "?" + this.toKV.apply(this, arguments);
+ },
+ toString: function(){
+ return this.getClassName() + "(cid=" + this.cid + ", id=" + this.id + ")";
+ }
+}));
+__import(BaseModel, {
+ /**
+ * Factory method which constructs an instance of this model from a string of KV-pairs.
+ * This is a class method inherited by models which extend {BaseModel}.
+ * @static
+ * @param {String|Object} o Serialized KV-pairs (or a plain object).
+ * @returns {BaseModel} An instance of this model.
+ */
+ fromKV: function(o, item_delim, kv_delim){
+ var Cls;
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ if (typeof o === 'string') {
+ o = _.fromKV(o, item_delim, kv_delim);
+ }
+ Cls = typeof this === 'function'
+ ? this
+ : this.constructor;
+ return new Cls(_.uncollapseObject(o));
+ }
+});
+/**
+ * @class Base collection, extending Backbone.Collection, used by scaffold and others.
+ * @extends Backbone.Collection
+ */
+BaseList = exports.BaseList = Backbone.Collection.extend(mixinBase({
+ constructor: (function(){
+ function BaseList(){
+ this.__class__ = this.constructor;
+ this.__superclass__ = this.constructor.__super__.constructor;
+ this.waitingOn = 0;
+ return Backbone.Collection.apply(this, arguments);
+ }
+ return BaseList;
+ }()),
+ getIds: function(){
+ return this.models.map(function(it){
+ return it.id || it.get('id') || it.cid;
+ });
+ },
+ toKVPairs: function(){
+ return _.collapseObject(this.toJSON());
+ },
+ toKV: function(item_delim, kv_delim){
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ return _.toKV(this.toKVPairs(), item_delim, kv_delim);
+ },
+ toURL: function(item_delim, kv_delim){
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ return "?" + this.toKV.apply(this, arguments);
+ },
+ toString: function(){
+ return this.getClassName() + "[" + this.length + "]";
+ },
+ toStringWithIds: function(){
+ var modelIds;
+ modelIds = this.models.map(function(it){
+ var _ref;
+ return "\"" + ((_ref = it.id) != null
+ ? _ref
+ : it.cid) + "\"";
+ }).join(', ');
+ return this.getClassName() + "[" + this.length + "](" + modelIds + ")";
+ }
+}));
+function __import(obj, src){
+ var own = {}.hasOwnProperty;
+ for (var key in src) if (own.call(src, key)) obj[key] = src[key];
+ return obj;
+}
\ No newline at end of file
--- /dev/null
+require.define('/node_modules/kraken/base/base-model.js.js', function(require, module, exports, __dirname, __filename, undefined){
+
+var Backbone, op, BaseBackboneMixin, mixinBase, BaseModel, BaseList, _ref, _, __slice = [].slice;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+_ref = require('kraken/base/base-mixin'), BaseBackboneMixin = _ref.BaseBackboneMixin, mixinBase = _ref.mixinBase;
+/**
+ * @class Base model, extending Backbone.Model, used by scaffold and others.
+ * @extends Backbone.Model
+ */
+BaseModel = exports.BaseModel = Backbone.Model.extend(mixinBase({
+ constructor: (function(){
+ function BaseModel(){
+ this.__class__ = this.constructor;
+ this.__superclass__ = this.constructor.__super__.constructor;
+ this.waitingOn = 0;
+ return Backbone.Model.apply(this, arguments);
+ }
+ return BaseModel;
+ }()),
+ url: function(){
+ return this.urlRoot + "/" + this.get('id') + ".json";
+ },
+ has: function(key){
+ return this.get(key) != null;
+ },
+ get: function(key){
+ return _.getNested(this.attributes, key);
+ }
+ /**
+ * Override to customize what data or assets the model requires,
+ * and how they should be loaded.
+ *
+ * By default, `load()` simply calls `loadModel()` via `loader()`.
+ *
+ * @see BaseModel#loader
+ * @see BaseModel#loadModel
+ * @returns {this}
+ */,
+ load: function(){
+ console.log(this + ".load()");
+ this.loader({
+ start: this.loadModel,
+ completeEvent: 'fetch-success'
+ });
+ return this;
+ }
+ /**
+ * Wraps the loading workflow boilerplate:
+ * - Squelches multiple loads from running at once
+ * - Squelches loads post-ready, unless forced
+ * - Triggers a start event
+ * - Triggers "ready" when complete
+ * - Wraps workflow with wait/unwait
+ * - Cleans up "loading" state
+ *
+ * @protected
+ * @param {Object} [opts={}] Options:
+ * @param {Function} opts.start Function that starts the loading process. Always called with `this` as the context.
+ * @param {String} [opts.startEvent='load'] Event to trigger before beginning the load.
+ * @param {String} [opts.completeEvent='load-success'] Event which signals loading has completed successfully.
+ * @param {String} [opts.errorEvent='load-error'] Event which signals loading has completed but failed.
+ * @param {Boolean} [opts.force=false] If true, reset ready state if we're ready before proceeding.
+ * @param {Boolean} [opts.readyIfError=false] If true, move fire the ready event when loading completes, even if it failed.
+ * @returns {this}
+ */,
+ loader: function(opts){
+ var _this = this;
+ opts == null && (opts = {});
+ opts = (__import({
+ force: false,
+ readyIfError: false,
+ startEvent: 'load',
+ completeEvent: 'load-success',
+ errorEvent: 'load-error'
+ }, opts));
+ if (opts.force) {
+ this.resetReady();
+ }
+ if (!opts.start) {
+ throw new Error('You must specify a `start` function to start loading!');
+ }
+ if (this.loading || this.ready) {
+ return this;
+ }
+ this.wait();
+ this.loading = true;
+ this.trigger(opts.startEvent, this);
+ this.once(opts.completeEvent, function(){
+ _this.loading = false;
+ _this.unwait();
+ if (opts.completeEvent !== 'load-success') {
+ _this.trigger('load-success', _this);
+ }
+ return _this.triggerReady();
+ });
+ this.once(opts.errorEvent, function(){
+ _this.loading = false;
+ _this.unwait();
+ if (opts.errorEvent !== 'load-error') {
+ _this.trigger('load-error', _this);
+ }
+ if (opts.readyIfError) {
+ return _this.triggerReady();
+ }
+ });
+ opts.start.call(this);
+ return this;
+ }
+ /**
+ * Runs `.fetch()`, triggering a `fetch` event at start, and
+ * `fetch-success` / `fetch-error` on completion.
+ *
+ * @protected
+ * @returns {this}
+ */,
+ loadModel: function(){
+ var _this = this;
+ this.wait();
+ this.trigger('fetch', this);
+ this.fetch({
+ success: function(){
+ _this.unwait();
+ return _this.trigger('fetch-success', _this);
+ },
+ error: function(){
+ _this.unwait();
+ return _this.trigger.apply(_this, ['fetch-error', _this].concat(__slice.call(arguments)));
+ }
+ });
+ return this;
+ },
+ serialize: function(v){
+ if (_.isBoolean(v)) {
+ v = Number(v);
+ } else if (_.isObject(v)) {
+ v = JSON.stringify(v);
+ }
+ return String(v);
+ }
+ /**
+ * Like `.toJSON()` in that it should return a plain object with no functions,
+ * but for the purpose of `.toKV()`, allowing you to customize the values
+ * included and keys used.
+ *
+ * @param {Object} [opts={}] Options:
+ * @param {Boolean} [opts.keepFunctions=false] If false, functions will be omitted from the result.
+ * @returns {Object}
+ */,
+ toKVPairs: function(opts){
+ var kvo, k, v;
+ opts == null && (opts = {});
+ opts = (__import({
+ keepFunctions: false
+ }, opts));
+ kvo = _.collapseObject(this.toJSON());
+ for (k in kvo) {
+ v = kvo[k];
+ if (opts.keepFunctions || typeof v !== 'function') {
+ kvo[k] = this.serialize(v);
+ }
+ }
+ return kvo;
+ }
+ /**
+ * Serialize the model into a `www-form-encoded` string suitable for use as
+ * a query string or a POST body.
+ * @returns {String}
+ */,
+ toKV: function(item_delim, kv_delim){
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ return _.toKV(this.toKVPairs(), item_delim, kv_delim);
+ }
+ /**
+ * @returns {String} URL identifying this model.
+ */,
+ toURL: function(){
+ return "?" + this.toKV.apply(this, arguments);
+ },
+ toString: function(){
+ return this.getClassName() + "(cid=" + this.cid + ", id=" + this.id + ")";
+ }
+}));
+__import(BaseModel, {
+ /**
+ * Factory method which constructs an instance of this model from a string of KV-pairs.
+ * This is a class method inherited by models which extend {BaseModel}.
+ * @static
+ * @param {String|Object} o Serialized KV-pairs (or a plain object).
+ * @returns {BaseModel} An instance of this model.
+ */
+ fromKV: function(o, item_delim, kv_delim){
+ var Cls;
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ if (typeof o === 'string') {
+ o = _.fromKV(o, item_delim, kv_delim);
+ }
+ Cls = typeof this === 'function'
+ ? this
+ : this.constructor;
+ return new Cls(_.uncollapseObject(o));
+ }
+});
+/**
+ * @class Base collection, extending Backbone.Collection, used by scaffold and others.
+ * @extends Backbone.Collection
+ */
+BaseList = exports.BaseList = Backbone.Collection.extend(mixinBase({
+ constructor: (function(){
+ function BaseList(){
+ this.__class__ = this.constructor;
+ this.__superclass__ = this.constructor.__super__.constructor;
+ this.waitingOn = 0;
+ return Backbone.Collection.apply(this, arguments);
+ }
+ return BaseList;
+ }()),
+ getIds: function(){
+ return this.models.map(function(it){
+ return it.id || it.get('id') || it.cid;
+ });
+ },
+ toKVPairs: function(){
+ return _.collapseObject(this.toJSON());
+ },
+ toKV: function(item_delim, kv_delim){
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ return _.toKV(this.toKVPairs(), item_delim, kv_delim);
+ },
+ toURL: function(item_delim, kv_delim){
+ item_delim == null && (item_delim = '&');
+ kv_delim == null && (kv_delim = '=');
+ return "?" + this.toKV.apply(this, arguments);
+ },
+ toString: function(){
+ return this.getClassName() + "[" + this.length + "]";
+ },
+ toStringWithIds: function(){
+ var modelIds;
+ modelIds = this.models.map(function(it){
+ var _ref;
+ return "\"" + ((_ref = it.id) != null
+ ? _ref
+ : it.cid) + "\"";
+ }).join(', ');
+ return this.getClassName() + "[" + this.length + "](" + modelIds + ")";
+ }
+}));
+function __import(obj, src){
+ var own = {}.hasOwnProperty;
+ for (var key in src) if (own.call(src, key)) obj[key] = src[key];
+ return obj;
+}
+
+});
--- /dev/null
+var Backbone, op, BaseBackboneMixin, mixinBase, BaseModel, DataBinding, BaseView, ViewList, _ref, _, __slice = [].slice;
+Backbone = require('backbone');
+_ref = require('kraken/util'), _ = _ref._, op = _ref.op;
+_ref = require('kraken/base/base-mixin'), BaseBackboneMixin = _ref.BaseBackboneMixin, mixinBase = _ref.mixinBase;
+BaseModel = require('kraken/base/base-mixin').BaseModel;
+DataBinding = require('kraken/base/data-binding').DataBinding;
+/**
+ * @class Base view, extending Backbone.View, used by scaffold and others.
+ * @extends Backbone.View
+ */
+BaseView = exports.BaseView = Backbone.View.extend(mixinBase({
+ tagName: 'section',
+ model: BaseModel
+ /**
+ * Method-name called by `onReturnKeypress` when used as an event-handler.
+ * @type String
+ */,
+ callOnReturnKeypress: null
+ /**
+ * Parent view of this view.
+ * @type BaseView
+ */,
+ parent: null
+ /**
+ * Array of [view, selector]-pairs.
+ * @type Array<[BaseView, String]>
+ */,
+ subviews: []
+ /**
+ * Whether this view has been added to the DOM.
+ * @type Boolean
+ */,
+ isAttached: false,
+ constructor: (function(){
+ function BaseView(){
+ this.__class__ = this.constructor;
+ this.__superclass__ = this.constructor.__super__.constructor;
+ this.waitingOn = 0;
+ this.subviews = new ViewList;
+ this.onReturnKeypress = _.debounce(this.onReturnKeypress.bind(this), 50);
+ Backbone.View.apply(this, arguments);
+ return this.trigger('create', this);
+ }
+ return BaseView;
+ }()),
+ initialize: function(){
+ this.__apply_bind__();
+ this.setModel(this.model);
+ this.build();
+ return this.$el.on('form submit', function(it){
+ return it.preventDefault();
+ });
+ },
+ setModel: function(model){
+ var data;
+ if (this.model) {
+ this.model.off('change', this.render, this);
+ this.model.off('destroy', this.remove, this);
+ delete this.model.view;
+ data = this.$el.data();
+ delete data.model;
+ delete data.view;
+ }
+ if (this.model = model) {
+ this.model.view = this;
+ this.$el.data({
+ model: this.model,
+ view: this
+ });
+ this.model.on('change', this.render, this);
+ this.model.on('destroy', this.remove, this);
+ this.trigger('change:model', this, model);
+ }
+ return model;
+ },
+ setParent: function(parent){
+ var old_parent, _ref;
+ _ref = [this.parent, parent], old_parent = _ref[0], this.parent = _ref[1];
+ this.trigger('parent', this, parent, old_parent);
+ return this;
+ },
+ unsetParent: function(){
+ var old_parent, _ref;
+ _ref = [this.parent, null], old_parent = _ref[0], this.parent = _ref[1];
+ this.trigger('unparent', this, old_parent);
+ return this;
+ },
+ addSubview: function(view){
+ this.removeSubview(view);
+ this.subviews.push(view);
+ view.setParent(this);
+ return view;
+ },
+ removeSubview: function(view){
+ if (this.hasSubview(view)) {
+ view.remove();
+ this.subviews.remove(view);
+ view.unsetParent();
+ }
+ return view;
+ },
+ hasSubview: function(view){
+ return this.subviews.contains(view);
+ },
+ invokeSubviews: function(){
+ var _ref;
+ return (_ref = this.subviews).invoke.apply(_ref, arguments);
+ },
+ removeAllSubviews: function(){
+ this.subviews.forEach(this.removeSubview, this);
+ return this;
+ },
+ attach: function(el){
+ var _this = this;
+ this.$el.appendTo(el);
+ if (this.isAttached) {
+ return this;
+ }
+ this.isAttached = true;
+ _.delay(function(){
+ _this.delegateEvents();
+ return _this.trigger('attach', _this);
+ }, 50);
+ return this;
+ },
+ remove: function(){
+ this.$el.remove();
+ if (!this.isAttached) {
+ return this;
+ }
+ this.isAttached = false;
+ this.trigger('unattach', this);
+ return this;
+ },
+ clear: function(){
+ this.remove();
+ this.model.destroy();
+ this.trigger('clear', this);
+ return this;
+ },
+ hide: function(){
+ this.$el.hide();
+ this.trigger('hide', this);
+ return this;
+ },
+