/*! * CanJS - 2.0.4 * http://canjs.us/ * Copyright (c) 2013 Bitovi * Mon, 23 Dec 2013 19:49:25 GMT * Licensed MIT * Includes: can/component,can/construct,can/map,can/list,can/observe,can/compute,can/model,can/view,can/control,can/route,can/control/route,can/view/mustache,can/view/bindings,can/view/live,can/view/scope,can/util/string * Download from: http://canjs.com */ (function(undefined) { // ## util/can.js var __m4 = (function() { var can = window.can || {}; if (typeof GLOBALCAN === 'undefined' || GLOBALCAN !== false) { window.can = can; } can.isDeferred = function(obj) { var isFunction = this.isFunction; // Returns `true` if something looks like a deferred. return obj && isFunction(obj.then) && isFunction(obj.pipe); }; var cid = 0; can.cid = function(object, name) { if (object._cid) { return object._cid } else { return object._cid = (name || "") + (++cid) } } can.VERSION = '2.0.4'; can.simpleExtend = function(d, s) { for (var prop in s) { d[prop] = s[prop] } return d; } return can; })(); // ## util/array/each.js var __m5 = (function(can) { can.each = function(elements, callback, context) { var i = 0, key; if (elements) { if (typeof elements.length === 'number' && elements.pop) { if (elements.attr) { elements.attr('length'); } for (key = elements.length; i < key; i++) { if (callback.call(context || elements[i], elements[i], i, elements) === false) { break; } } } else if (elements.hasOwnProperty) { if (can.Map && elements instanceof can.Map) { can.__reading && can.__reading(elements, '__keys'); elements = elements.__get() } for (key in elements) { if (elements.hasOwnProperty(key)) { if (callback.call(context || elements[key], elements[key], key, elements) === false) { break; } } } } } return elements; }; return can; })(__m4); // ## util/inserted/inserted.js var __m6 = (function(can) { // Given a list of elements, check if they are in the dom, if they // are in the dom, trigger inserted on them. can.inserted = function(elems) { // prevent mutations from changing the looping elems = can.makeArray(elems); var inDocument = false, checked = false, children; for (var i = 0, elem; (elem = elems[i]) !== undefined; i++) { if (!inDocument) { if (elem.getElementsByTagName) { if (can.has(can.$(document), elem).length) { inDocument = true; } else { return; } } else { continue; } } if (inDocument && elem.getElementsByTagName) { children = can.makeArray(elem.getElementsByTagName("*")); can.trigger(elem, "inserted", [], false); for (var j = 0, child; (child = children[j]) !== undefined; j++) { // Trigger the destroyed event can.trigger(child, "inserted", [], false); } } } } can.appendChild = function(el, child) { if (child.nodeType === 11) { var children = can.makeArray(child.childNodes); } else { var children = [child] } el.appendChild(child); can.inserted(children) } can.insertBefore = function(el, child, ref) { if (child.nodeType === 11) { var children = can.makeArray(child.childNodes); } else { var children = [child]; } el.insertBefore(child, ref); can.inserted(children) } })(__m4); // ## util/event.js var __m7 = (function(can) { // event.js // --------- // _Basic event wrapper._ can.addEvent = function(event, fn) { var allEvents = this.__bindEvents || (this.__bindEvents = {}), eventList = allEvents[event] || (allEvents[event] = []); eventList.push({ handler: fn, name: event }); return this; }; // can.listenTo works without knowing how bind works // the API was heavily influenced by BackboneJS: // http://backbonejs.org/ can.listenTo = function(other, event, handler) { var idedEvents = this.__listenToEvents; if (!idedEvents) { idedEvents = this.__listenToEvents = {}; } var otherId = can.cid(other); var othersEvents = idedEvents[otherId]; if (!othersEvents) { othersEvents = idedEvents[otherId] = { obj: other, events: {} }; } var eventsEvents = othersEvents.events[event] if (!eventsEvents) { eventsEvents = othersEvents.events[event] = [] } eventsEvents.push(handler); can.bind.call(other, event, handler); } can.stopListening = function(other, event, handler) { var idedEvents = this.__listenToEvents, iterIdedEvents = idedEvents, i = 0; if (!idedEvents) { return this; } if (other) { var othercid = can.cid(other); (iterIdedEvents = {})[othercid] = idedEvents[othercid]; // you might be trying to listen to something that is not there if (!idedEvents[othercid]) { return this; } } for (var cid in iterIdedEvents) { var othersEvents = iterIdedEvents[cid], eventsEvents; other = idedEvents[cid].obj; if (!event) { eventsEvents = othersEvents.events; } else { (eventsEvents = {})[event] = othersEvents.events[event] } for (var eventName in eventsEvents) { var handlers = eventsEvents[eventName] || []; i = 0; while (i < handlers.length) { if ((handler && handler === handlers[i]) || (!handler)) { can.unbind.call(other, eventName, handlers[i]) handlers.splice(i, 1); } else { i++; } } // no more handlers? if (!handlers.length) { delete othersEvents.events[eventName] } } if (can.isEmptyObject(othersEvents.events)) { delete idedEvents[cid] } } return this; } can.removeEvent = function(event, fn) { if (!this.__bindEvents) { return this; } var events = this.__bindEvents[event] || [], i = 0, ev, isFunction = typeof fn == 'function'; while (i < events.length) { ev = events[i] if ((isFunction && ev.handler === fn) || (!isFunction && ev.cid === fn)) { events.splice(i, 1); } else { i++; } } return this; }; can.dispatch = function(event, args) { if (!this.__bindEvents) { return; } if (typeof event == "string") { event = { type: event } } var eventName = event.type, handlers = (this.__bindEvents[eventName] || []).slice(0), args = [event].concat(args || []), ev; for (var i = 0, len = handlers.length; i < len; i++) { ev = handlers[i]; ev.handler.apply(this, args); } } return can; })(__m4); // ## util/jquery/jquery.js var __m2 = (function($, can) { var isBindableElement = function(node) { //console.log((node.nodeName && (node.nodeType == 1 || node.nodeType == 9) || node === window)) return (node.nodeName && (node.nodeType == 1 || node.nodeType == 9) || node == window); }; // _jQuery node list._ $.extend(can, $, { trigger: function(obj, event, args) { if (obj.nodeName || obj === window) { $.event.trigger(event, args, obj, true); } else if (obj.trigger) { obj.trigger(event, args); } else { if (typeof event === 'string') { event = { type: event } } event.target = event.target || obj; can.dispatch.call(obj, event, args); } }, addEvent: can.addEvent, removeEvent: can.removeEvent, // jquery caches fragments, we always needs a new one buildFragment: function(elems, context) { var oldFragment = $.buildFragment, ret; elems = [elems]; // Set context per 1.8 logic context = context || document; context = !context.nodeType && context[0] || context; context = context.ownerDocument || context; ret = oldFragment.call(jQuery, elems, context); return ret.cacheable ? $.clone(ret.fragment) : ret.fragment || ret; }, $: $, each: can.each, bind: function(ev, cb) { // If we can bind to it... if (this.bind && this.bind !== can.bind) { this.bind(ev, cb) } else if (isBindableElement(this)) { $.event.add(this, ev, cb); } else { // Make it bind-able... can.addEvent.call(this, ev, cb) } return this; }, unbind: function(ev, cb) { // If we can bind to it... if (this.unbind && this.unbind !== can.unbind) { this.unbind(ev, cb) } else if (isBindableElement(this)) { $.event.remove(this, ev, cb); } else { // Make it bind-able... can.removeEvent.call(this, ev, cb) } return this; }, delegate: function(selector, ev, cb) { if (this.delegate) { this.delegate(selector, ev, cb) } else if (isBindableElement(this)) { $(this).delegate(selector, ev, cb) } else { // make it bind-able ... } return this; }, undelegate: function(selector, ev, cb) { if (this.undelegate) { this.undelegate(selector, ev, cb) } else if (isBindableElement(this)) { $(this).undelegate(selector, ev, cb) } else { // make it bind-able ... } return this; }, proxy: function(fn, context) { return function() { return fn.apply(context, arguments) } } }); // Wrap binding functions. // Aliases can.on = can.bind; can.off = can.unbind; // Wrap modifier functions. $.each(["append", "filter", "addClass", "remove", "data", "get", "has"], function(i, name) { can[name] = function(wrapped) { return wrapped[name].apply(wrapped, can.makeArray(arguments).slice(1)); }; }); // Memory safe destruction. var oldClean = $.cleanData; $.cleanData = function(elems) { $.each(elems, function(i, elem) { if (elem) { can.trigger(elem, "removed", [], false); } }); oldClean(elems); }; var oldDomManip = $.fn.domManip, cbIndex; // feature detect which domManip we are using $.fn.domManip = function(args, cb1, cb2) { for (var i = 1; i < arguments.length; i++) { if (typeof arguments[i] === "function") { cbIndex = i; break; } } return oldDomManip.apply(this, arguments) } $(document.createElement("div")).append(document.createElement("div")) $.fn.domManip = (cbIndex == 2 ? function(args, table, callback) { return oldDomManip.call(this, args, table, function(elem) { if (elem.nodeType === 11) { var elems = can.makeArray(elem.childNodes); } var ret = callback.apply(this, arguments); can.inserted(elems ? elems : [elem]); return ret; }) } : function(args, callback) { return oldDomManip.call(this, args, function(elem) { if (elem.nodeType === 11) { var elems = can.makeArray(elem.childNodes); } var ret = callback.apply(this, arguments); can.inserted(elems ? elems : [elem]); return ret; }) }) $.event.special.inserted = {}; $.event.special.removed = {}; return can; })(jQuery, __m4, __m5, __m6, __m7); // ## util/string/string.js var __m10 = (function(can) { // ##string.js // _Miscellaneous string utility functions._ // Several of the methods in this plugin use code adapated from Prototype // Prototype JavaScript framework, version 1.6.0.1. // © 2005-2007 Sam Stephenson var strUndHash = /_|-/, strColons = /\=\=/, strWords = /([A-Z]+)([A-Z][a-z])/g, strLowUp = /([a-z\d])([A-Z])/g, strDash = /([a-z\d])([A-Z])/g, strReplacer = /\{([^\}]+)\}/g, strQuote = /"/g, strSingleQuote = /'/g, strHyphenMatch = /-+(.)?/g, strCamelMatch = /[a-z][A-Z]/g, // Returns the `prop` property from `obj`. // If `add` is true and `prop` doesn't exist in `obj`, create it as an // empty object. getNext = function(obj, prop, add) { var result = obj[prop]; if (result === undefined && add === true) { result = obj[prop] = {} } return result }, // Returns `true` if the object can have properties (no `null`s). isContainer = function(current) { return (/^f|^o/).test(typeof current); }, convertBadValues = function(content) { // Convert bad values into empty strings var isInvalid = content === null || content === undefined || (isNaN(content) && ("" + content === 'NaN')); return ("" + (isInvalid ? '' : content)) }; can.extend(can, { // Escapes strings for HTML. esc: function(content) { return convertBadValues(content) .replace(/&/g, '&') .replace(//g, '>') .replace(strQuote, '"') .replace(strSingleQuote, "'"); }, getObject: function(name, roots, add) { // The parts of the name we are looking up // `['App','Models','Recipe']` var parts = name ? name.split('.') : [], length = parts.length, current, r = 0, i, container, rootsLength; // Make sure roots is an `array`. roots = can.isArray(roots) ? roots : [roots || window]; rootsLength = roots.length if (!length) { return roots[0]; } // For each root, mark it as current. for (r; r < rootsLength; r++) { current = roots[r]; container = undefined; // Walk current to the 2nd to last object or until there // is not a container. for (i = 0; i < length && isContainer(current); i++) { container = current; current = getNext(container, parts[i]); } // If we found property break cycle if (container !== undefined && current !== undefined) { break } } // Remove property from found container if (add === false && current !== undefined) { delete container[parts[i - 1]] } // When adding property add it to the first root if (add === true && current === undefined) { current = roots[0] for (i = 0; i < length && isContainer(current); i++) { current = getNext(current, parts[i], true); } } return current; }, // Capitalizes a string. capitalize: function(s, cache) { // Used to make newId. return s.charAt(0).toUpperCase() + s.slice(1); }, camelize: function(str) { return convertBadValues(str).replace(strHyphenMatch, function(match, chr) { return chr ? chr.toUpperCase() : '' }) }, hyphenate: function(str) { return convertBadValues(str).replace(strCamelMatch, function(str, offset) { return str.charAt(0) + '-' + str.charAt(1).toLowerCase(); }); }, // Underscores a string. underscore: function(s) { return s .replace(strColons, '/') .replace(strWords, '$1_$2') .replace(strLowUp, '$1_$2') .replace(strDash, '_') .toLowerCase(); }, // Micro-templating. sub: function(str, data, remove) { var obs = []; str = str || ''; obs.push(str.replace(strReplacer, function(whole, inside) { // Convert inside to type. var ob = can.getObject(inside, data, remove === true ? false : undefined); if (ob === undefined || ob === null) { obs = null; return ""; } // If a container, push into objs (which will return objects found). if (isContainer(ob) && obs) { obs.push(ob); return ""; } return "" + ob; })); return obs === null ? obs : (obs.length <= 1 ? obs[0] : obs); }, // These regex's are used throughout the rest of can, so let's make // them available. replacer: strReplacer, undHash: strUndHash }); return can; })(__m2); // ## construct/construct.js var __m9 = (function(can) { // ## construct.js // `can.Construct` // _This is a modified version of // [John Resig's class](http://ejohn.org/blog/simple-javascript-inheritance/). // It provides class level inheritance and callbacks._ // A private flag used to initialize a new class instance without // initializing it's bindings. var initializing = 0; can.Construct = function() { if (arguments.length) { return can.Construct.extend.apply(can.Construct, arguments); } }; can.extend(can.Construct, { constructorExtends: true, newInstance: function() { // Get a raw instance object (`init` is not called). var inst = this.instance(), arg = arguments, args; // Call `setup` if there is a `setup` if (inst.setup) { args = inst.setup.apply(inst, arguments); } // Call `init` if there is an `init` // If `setup` returned `args`, use those as the arguments if (inst.init) { inst.init.apply(inst, args || arguments); } return inst; }, // Overwrites an object with methods. Used in the `super` plugin. // `newProps` - New properties to add. // `oldProps` - Where the old properties might be (used with `super`). // `addTo` - What we are adding to. _inherit: function(newProps, oldProps, addTo) { can.extend(addTo || newProps, newProps || {}) }, // used for overwriting a single property. // this should be used for patching other objects // the super plugin overwrites this _overwrite: function(what, oldProps, propName, val) { what[propName] = val; }, // Set `defaults` as the merger of the parent `defaults` and this // object's `defaults`. If you overwrite this method, make sure to // include option merging logic. setup: function(base, fullName) { this.defaults = can.extend(true, {}, base.defaults, this.defaults); }, // Create's a new `class` instance without initializing by setting the // `initializing` flag. instance: function() { // Prevents running `init`. initializing = 1; var inst = new this(); // Allow running `init`. initializing = 0; return inst; }, // Extends classes. extend: function(fullName, klass, proto) { // Figure out what was passed and normalize it. if (typeof fullName != 'string') { proto = klass; klass = fullName; fullName = null; } if (!proto) { proto = klass; klass = null; } proto = proto || {}; var _super_class = this, _super = this.prototype, name, shortName, namespace, prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor). prototype = this.instance(); // Copy the properties over onto the new prototype. can.Construct._inherit(proto, _super, prototype); // The dummy class constructor. function Constructor() { // All construction is actually done in the init method. if (!initializing) { return this.constructor !== Constructor && arguments.length && Constructor.constructorExtends ? // We are being called without `new` or we are extending. arguments.callee.extend.apply(arguments.callee, arguments) : // We are being called with `new`. Constructor.newInstance.apply(Constructor, arguments); } } // Copy old stuff onto class (can probably be merged w/ inherit) for (name in _super_class) { if (_super_class.hasOwnProperty(name)) { Constructor[name] = _super_class[name]; } } // Copy new static properties on class. can.Construct._inherit(klass, _super_class, Constructor); // Setup namespaces. if (fullName) { var parts = fullName.split('.'), shortName = parts.pop(), current = can.getObject(parts.join('.'), window, true), namespace = current, _fullName = can.underscore(fullName.replace(/\./g, "_")), _shortName = can.underscore(shortName); current[shortName] = Constructor; } // Set things that shouldn't be overwritten. can.extend(Constructor, { constructor: Constructor, prototype: prototype, namespace: namespace, _shortName: _shortName, fullName: fullName, _fullName: _fullName }); // Dojo and YUI extend undefined if (shortName !== undefined) { Constructor.shortName = shortName; } // Make sure our prototype looks nice. Constructor.prototype.constructor = Constructor; // Call the class `setup` and `init` var t = [_super_class].concat(can.makeArray(arguments)), args = Constructor.setup.apply(Constructor, t); if (Constructor.init) { Constructor.init.apply(Constructor, args || t); } return Constructor; } }); can.Construct.prototype.setup = function() {}; can.Construct.prototype.init = function() {}; return can.Construct; })(__m10); // ## control/control.js var __m8 = (function(can) { // ## control.js // `can.Control` // _Controller_ // Binds an element, returns a function that unbinds. var bind = function(el, ev, callback) { can.bind.call(el, ev, callback); return function() { can.unbind.call(el, ev, callback); }; }, isFunction = can.isFunction, extend = can.extend, each = can.each, slice = [].slice, paramReplacer = /\{([^\}]+)\}/g, special = can.getObject("$.event.special", [can]) || {}, // Binds an element, returns a function that unbinds. delegate = function(el, selector, ev, callback) { can.delegate.call(el, selector, ev, callback); return function() { can.undelegate.call(el, selector, ev, callback); }; }, // Calls bind or unbind depending if there is a selector. binder = function(el, ev, callback, selector) { return selector ? delegate(el, can.trim(selector), ev, callback) : bind(el, ev, callback); }, basicProcessor; var Control = can.Control = can.Construct( { // Setup pre-processes which methods are event listeners. setup: function() { // Allow contollers to inherit "defaults" from super-classes as it // done in `can.Construct` can.Construct.setup.apply(this, arguments); // If you didn't provide a name, or are `control`, don't do anything. if (can.Control) { // Cache the underscored names. var control = this, funcName; // Calculate and cache actions. control.actions = {}; for (funcName in control.prototype) { if (control._isAction(funcName)) { control.actions[funcName] = control._action(funcName); } } } }, // Moves `this` to the first argument, wraps it with `jQuery` if it's an element _shifter: function(context, name) { var method = typeof name == "string" ? context[name] : name; if (!isFunction(method)) { method = context[method]; } return function() { context.called = name; return method.apply(context, [this.nodeName ? can.$(this) : this].concat(slice.call(arguments, 0))); }; }, // Return `true` if is an action. _isAction: function(methodName) { var val = this.prototype[methodName], type = typeof val; // if not the constructor return (methodName !== 'constructor') && // and is a function or links to a function (type == "function" || (type == "string" && isFunction(this.prototype[val]))) && // and is in special, a processor, or has a funny character !! (special[methodName] || processors[methodName] || /[^\w]/.test(methodName)); }, // Takes a method name and the options passed to a control // and tries to return the data necessary to pass to a processor // (something that binds things). _action: function(methodName, options) { // If we don't have options (a `control` instance), we'll run this // later. paramReplacer.lastIndex = 0; if (options || !paramReplacer.test(methodName)) { // If we have options, run sub to replace templates `{}` with a // value from the options or the window var convertedName = options ? can.sub(methodName, this._lookup(options)) : methodName; if (!convertedName) { return null; } // If a `{}` template resolves to an object, `convertedName` will be // an array var arr = can.isArray(convertedName), // Get the name name = arr ? convertedName[1] : convertedName, // Grab the event off the end parts = name.split(/\s+/g), event = parts.pop(); return { processor: processors[event] || basicProcessor, parts: [name, parts.join(" "), event], delegate: arr ? convertedName[0] : undefined }; } }, _lookup: function(options) { return [options, window] }, // An object of `{eventName : function}` pairs that Control uses to // hook up events auto-magically. processors: {}, // A object of name-value pairs that act as default values for a // control instance defaults: {} }, { // Sets `this.element`, saves the control in `data, binds event // handlers. setup: function(element, options) { var cls = this.constructor, pluginname = cls.pluginName || cls._fullName, arr; // Want the raw element here. this.element = can.$(element) if (pluginname && pluginname !== 'can_control') { // Set element and `className` on element. this.element.addClass(pluginname); } (arr = can.data(this.element, "controls")) || can.data(this.element, "controls", arr = []); arr.push(this); // Option merging. this.options = extend({}, cls.defaults, options); // Bind all event handlers. this.on(); // Gets passed into `init`. return [this.element, this.options]; }, on: function(el, selector, eventName, func) { if (!el) { // Adds bindings. this.off(); // Go through the cached list of actions and use the processor // to bind var cls = this.constructor, bindings = this._bindings, actions = cls.actions, element = this.element, destroyCB = can.Control._shifter(this, "destroy"), funcName, ready; for (funcName in actions) { // Only push if we have the action and no option is `undefined` if (actions.hasOwnProperty(funcName) && (ready = actions[funcName] || cls._action(funcName, this.options))) { bindings.push(ready.processor(ready.delegate || element, ready.parts[2], ready.parts[1], funcName, this)); } } // Setup to be destroyed... // don't bind because we don't want to remove it. can.bind.call(element, "removed", destroyCB); bindings.push(function(el) { can.unbind.call(el, "removed", destroyCB); }); return bindings.length; } if (typeof el == 'string') { func = eventName; eventName = selector; selector = el; el = this.element; } if (func === undefined) { func = eventName; eventName = selector; selector = null; } if (typeof func == 'string') { func = can.Control._shifter(this, func); } this._bindings.push(binder(el, eventName, func, selector)); return this._bindings.length; }, // Unbinds all event handlers on the controller. off: function() { var el = this.element[0]; each(this._bindings || [], function(value) { value(el); }); // Adds bindings. this._bindings = []; }, // Prepares a `control` for garbage collection destroy: function() { //Control already destroyed if (this.element === null) { return; } var Class = this.constructor, pluginName = Class.pluginName || Class._fullName, controls; // Unbind bindings. this.off(); if (pluginName && pluginName !== 'can_control') { // Remove the `className`. this.element.removeClass(pluginName); } // Remove from `data`. controls = can.data(this.element, "controls"); controls.splice(can.inArray(this, controls), 1); can.trigger(this, "destroyed"); // In case we want to know if the `control` is removed. this.element = null; } }); var processors = can.Control.processors, // Processors do the binding. // They return a function that unbinds when called. // The basic processor that binds events. basicProcessor = function(el, event, selector, methodName, control) { return binder(el, event, can.Control._shifter(control, methodName), selector); }; // Set common events to be processed as a `basicProcessor` each(["change", "click", "contextmenu", "dblclick", "keydown", "keyup", "keypress", "mousedown", "mousemove", "mouseout", "mouseover", "mouseup", "reset", "resize", "scroll", "select", "submit", "focusin", "focusout", "mouseenter", "mouseleave", // #104 - Add touch events as default processors // TOOD feature detect? "touchstart", "touchmove", "touchcancel", "touchend", "touchleave" ], function(v) { processors[v] = basicProcessor; }); return Control; })(__m2, __m9); // ## util/bind/bind.js var __m13 = (function(can) { // ## Bind helpers can.bindAndSetup = function() { // Add the event to this object can.addEvent.apply(this, arguments); // If not initializing, and the first binding // call bindsetup if the function exists. if (!this._init) { if (!this._bindings) { this._bindings = 1; // setup live-binding this._bindsetup && this._bindsetup(); } else { this._bindings++; } } return this; }; can.unbindAndTeardown = function(ev, handler) { // Remove the event handler can.removeEvent.apply(this, arguments); if (this._bindings == null) { this._bindings = 0; } else { this._bindings--; } // If there are no longer any bindings and // there is a bindteardown method, call it. if (!this._bindings) { this._bindteardown && this._bindteardown(); } return this; } return can; })(__m2); // ## util/batch/batch.js var __m14 = (function(can) { // Which batch of events this is for -- might not want to send multiple // messages on the same batch. This is mostly for event delegation. var batchNum = 1, // how many times has start been called without a stop transactions = 0, // an array of events within a transaction batchEvents = [], stopCallbacks = []; can.batch = { start: function(batchStopHandler) { transactions++; batchStopHandler && stopCallbacks.push(batchStopHandler); }, stop: function(force, callStart) { if (force) { transactions = 0; } else { transactions--; } if (transactions == 0) { var items = batchEvents.slice(0), callbacks = stopCallbacks.slice(0); batchEvents = []; stopCallbacks = []; batchNum++; callStart && can.batch.start(); can.each(items, function(args) { can.trigger.apply(can, args); }); can.each(callbacks, function(cb) { cb(); }); } }, trigger: function(item, event, args) { // Don't send events if initalizing. if (!item._init) { if (transactions == 0) { return can.trigger(item, event, args); } else { event = typeof event === "string" ? { type: event } : event; event.batchNum = batchNum; batchEvents.push([ item, event, args ]); } } } } })(__m4); // ## map/map.js var __m12 = (function(can, bind) { // ## map.js // `can.Map` // _Provides the observable pattern for JavaScript Objects._ // Removes all listeners. var bindToChildAndBubbleToParent = function(child, prop, parent) { can.listenTo.call(parent, child, "change", function() { // `batchTrigger` the type on this... var args = can.makeArray(arguments), ev = args.shift(); args[0] = (prop === "*" ? [parent.indexOf(child), args[0]] : [prop, args[0]]).join("."); // track objects dispatched on this map ev.triggeredNS = ev.triggeredNS || {}; // if it has already been dispatched exit if (ev.triggeredNS[parent._cid]) { return; } ev.triggeredNS[parent._cid] = true; // send change event with modified attr to parent can.trigger(parent, ev, args); // send modified attr event to parent //can.trigger(parent, args[0], args); }); }, // An `id` to track events for a given map. observeId = 0, attrParts = function(attr, keepKey) { if (keepKey) { return [attr]; } return can.isArray(attr) ? attr : ("" + attr).split("."); }, makeBindSetup = function(wildcard) { return function() { var parent = this; this._each(function(child, prop) { if (child && child.bind) { bindToChildAndBubbleToParent(child, wildcard || prop, parent) } }) }; }, // A map that temporarily houses a reference // to maps that have already been made for a plain ole JS object madeMap = null, teardownMap = function() { for (var cid in madeMap) { if (madeMap[cid].added) { delete madeMap[cid].obj._cid; } } madeMap = null; }, getMapFromObject = function(obj) { return madeMap && madeMap[obj._cid] && madeMap[obj._cid].instance }; var Map = can.Map = can.Construct.extend({ setup: function() { can.Construct.setup.apply(this, arguments); if (can.Map) { if (!this.defaults) { this.defaults = {}; } // a list of the compute properties this._computes = []; for (var prop in this.prototype) { if (typeof this.prototype[prop] !== "function") { this.defaults[prop] = this.prototype[prop]; } else if (this.prototype[prop].isComputed) { this._computes.push(prop) } } } // if we inerit from can.Map, but not can.List if (can.List && !(this.prototype instanceof can.List)) { this.List = Map.List({ Map: this }, {}); } }, _computes: [], // keep so it can be overwritten bind: can.bindAndSetup, on: can.bindAndSetup, unbind: can.unbindAndTeardown, off: can.unbindAndTeardown, id: "id", helpers: { addToMap: function(obj, instance) { var teardown; if (!madeMap) { teardown = teardownMap; madeMap = {} } // record if it has a Cid before we add one var hasCid = obj._cid; var cid = can.cid(obj); // only update if there already isn't one if (!madeMap[cid]) { madeMap[cid] = { obj: obj, instance: instance, added: !hasCid } } return teardown; }, canMakeObserve: function(obj) { return obj && !can.isDeferred(obj) && (can.isArray(obj) || can.isPlainObject(obj) || (obj instanceof can.Map)); }, unhookup: function(items, parent) { return can.each(items, function(item) { if (item && item.unbind) { can.stopListening.call(parent, item, "change"); } }); }, // Listens to changes on `child` and "bubbles" the event up. // `child` - The object to listen for changes on. // `prop` - The property name is at on. // `parent` - The parent object of prop. // `ob` - (optional) The Map object constructor // `list` - (optional) The observable list constructor hookupBubble: function(child, prop, parent, Ob, List) { Ob = Ob || Map; List = List || Map.List; // If it's an `array` make a list, otherwise a child. if (child instanceof Map) { // We have an `map` already... // Make sure it is not listening to this already // It's only listening if it has bindings already. parent._bindings && Map.helpers.unhookup([child], parent); } else if (can.isArray(child)) { child = getMapFromObject(child) || new List(child); } else { child = getMapFromObject(child) || new Ob(child); } // only listen if something is listening to you if (parent._bindings) { // Listen to all changes and `batchTrigger` upwards. bindToChildAndBubbleToParent(child, prop, parent) } return child; }, // A helper used to serialize an `Map` or `Map.List`. // `map` - The observable. // `how` - To serialize with `attr` or `serialize`. // `where` - To put properties, in an `{}` or `[]`. serialize: function(map, how, where) { // Go through each property. map.each(function(val, name) { // If the value is an `object`, and has an `attrs` or `serialize` function. where[name] = Map.helpers.canMakeObserve(val) && can.isFunction(val[how]) ? // Call `attrs` or `serialize` to get the original data back. val[how]() : // Otherwise return the value. val; }); return where; }, makeBindSetup: makeBindSetup }, // starts collecting events // takes a callback for after they are updated // how could you hook into after ejs keys: function(map) { var keys = []; can.__reading && can.__reading(map, '__keys'); for (var keyName in map._data) { keys.push(keyName); } return keys; } }, { setup: function(obj) { // `_data` is where we keep the properties. this._data = {} // The namespace this `object` uses to listen to events. can.cid(this, ".map"); // Sets all `attrs`. this._init = 1; this._setupComputes(); var teardownMapping = obj && can.Map.helpers.addToMap(obj, this); var data = can.extend(can.extend(true, {}, this.constructor.defaults || {}), obj) this.attr(data); teardownMapping && teardownMapping() this.bind('change', can.proxy(this._changes, this)); delete this._init; }, _setupComputes: function() { var computes = this.constructor._computes; this._computedBindings = {}; for (var i = 0, len = computes.length, prop; i < len; i++) { prop = computes[i]; this[prop] = this[prop].clone(this); this._computedBindings[prop] = { count: 0 } } }, _bindsetup: makeBindSetup(), _bindteardown: function() { var self = this; this._each(function(child) { Map.helpers.unhookup([child], self) }) }, _changes: function(ev, attr, how, newVal, oldVal) { can.batch.trigger(this, { type: attr, batchNum: ev.batchNum }, [newVal, oldVal]); }, _triggerChange: function(attr, how, newVal, oldVal) { can.batch.trigger(this, "change", can.makeArray(arguments)) }, // no live binding iterator _each: function(callback) { var data = this.__get(); for (var prop in data) { if (data.hasOwnProperty(prop)) { callback(data[prop], prop) } } }, attr: function(attr, val) { // This is super obfuscated for space -- basically, we're checking // if the type of the attribute is not a `number` or a `string`. var type = typeof attr; if (type !== "string" && type !== "number") { return this._attrs(attr, val) } else if (arguments.length === 1) { // If we are getting a value. // Let people know we are reading. can.__reading && can.__reading(this, attr) return this._get(attr) } else { // Otherwise we are setting. this._set(attr, val); return this; } }, each: function() { can.__reading && can.__reading(this, '__keys'); return can.each.apply(undefined, [this.__get()].concat(can.makeArray(arguments))) }, removeAttr: function(attr) { // Info if this is List or not var isList = can.List && this instanceof can.List, // Convert the `attr` into parts (if nested). parts = attrParts(attr), // The actual property to remove. prop = parts.shift(), // The current value. current = isList ? this[prop] : this._data[prop]; // If we have more parts, call `removeAttr` on that part. if (parts.length) { return current.removeAttr(parts) } else { if (isList) { this.splice(prop, 1) } else if (prop in this._data) { // Otherwise, `delete`. delete this._data[prop]; // Create the event. if (!(prop in this.constructor.prototype)) { delete this[prop] } // Let others know the number of keys have changed can.batch.trigger(this, "__keys"); this._triggerChange(prop, "remove", undefined, current); } return current; } }, // Reads a property from the `object`. _get: function(attr) { var value = typeof attr === 'string' && !! ~attr.indexOf('.') && this.__get(attr); if (value) { return value; } // break up the attr (`"foo.bar"`) into `["foo","bar"]` var parts = attrParts(attr), // get the value of the first attr name (`"foo"`) current = this.__get(parts.shift()); // if there are other attributes to read return parts.length ? // and current has a value current ? // lookup the remaining attrs on current current._get(parts) : // or if there's no current, return undefined undefined : // if there are no more parts, return current current; }, // Reads a property directly if an `attr` is provided, otherwise // returns the "real" data object itself. __get: function(attr) { if (attr) { if (this[attr] && this[attr].isComputed && can.isFunction(this.constructor.prototype[attr])) { return this[attr]() } else { return this._data[attr] } } else { return this._data; } }, // Sets `attr` prop as value on this object where. // `attr` - Is a string of properties or an array of property values. // `value` - The raw value to set. _set: function(attr, value, keepKey) { // Convert `attr` to attr parts (if it isn't already). var parts = attrParts(attr, keepKey), // The immediate prop we are setting. prop = parts.shift(), // The current value. current = this.__get(prop); // If we have an `object` and remaining parts. if (Map.helpers.canMakeObserve(current) && parts.length) { // That `object` should set it (this might need to call attr). current._set(parts, value) } else if (!parts.length) { // We're in "real" set territory. if (this.__convert) { value = this.__convert(prop, value) } this.__set(prop, value, current) } else { throw "can.Map: Object does not exist" } }, __set: function(prop, value, current) { // Otherwise, we are setting it on this `object`. // TODO: Check if value is object and transform // are we changing the value. if (value !== current) { // Check if we are adding this for the first time -- // if we are, we need to create an `add` event. var changeType = this.__get().hasOwnProperty(prop) ? "set" : "add"; // Set the value on data. this.___set(prop, // If we are getting an object. Map.helpers.canMakeObserve(value) ? // Hook it up to send event. Map.helpers.hookupBubble(value, prop, this) : // Value is normal. value); if (changeType == "add") { // If there is no current value, let others know that // the the number of keys have changed can.batch.trigger(this, "__keys", undefined); } // `batchTrigger` the change event. this._triggerChange(prop, changeType, value, current); //can.batch.trigger(this, prop, [value, current]); // If we can stop listening to our old value, do it. current && Map.helpers.unhookup([current], this); } }, // Directly sets a property on this `object`. ___set: function(prop, val) { if (this[prop] && this[prop].isComputed && can.isFunction(this.constructor.prototype[prop])) { this[prop](val); } this._data[prop] = val; // Add property directly for easy writing. // Check if its on the `prototype` so we don't overwrite methods like `attrs`. if (!(can.isFunction(this.constructor.prototype[prop]))) { this[prop] = val } }, bind: function(eventName, handler) { var computedBinding = this._computedBindings && this._computedBindings[eventName] if (computedBinding) { if (!computedBinding.count) { computedBinding.count = 1; var self = this; computedBinding.handler = function(ev, newVal, oldVal) { can.batch.trigger(self, { type: eventName, batchNum: ev.batchNum }, [newVal, oldVal]) } this[eventName].bind("change", computedBinding.handler) } else { computedBinding.count++ } } return can.bindAndSetup.apply(this, arguments); }, unbind: function(eventName, handler) { var computedBinding = this._computedBindings && this._computedBindings[eventName] if (computedBinding) { if (computedBinding.count == 1) { computedBinding.count = 0; this[eventName].unbind("change", computedBinding.handler); delete computedBinding.handler; } else { computedBinding.count++ } } return can.unbindAndTeardown.apply(this, arguments); }, serialize: function() { return can.Map.helpers.serialize(this, 'serialize', {}); }, _attrs: function(props, remove) { if (props === undefined) { return Map.helpers.serialize(this, 'attr', {}) } props = can.simpleExtend({}, props); var prop, self = this, newVal; can.batch.start(); this.each(function(curVal, prop) { // you can not have a _cid property! if (prop === "_cid") { return; } newVal = props[prop]; // If we are merging... if (newVal === undefined) { remove && self.removeAttr(prop); return; } if (self.__convert) { newVal = self.__convert(prop, newVal) } // if we're dealing with models, want to call _set to let converter run if (newVal instanceof can.Map) { self.__set(prop, newVal, curVal) // if its an object, let attr merge } else if (Map.helpers.canMakeObserve(curVal) && Map.helpers.canMakeObserve(newVal) && curVal.attr) { curVal.attr(newVal, remove) // otherwise just set } else if (curVal != newVal) { self.__set(prop, newVal, curVal) } delete props[prop]; }) // Add remaining props. for (var prop in props) { if (prop !== "_cid") { newVal = props[prop]; this._set(prop, newVal, true) } } can.batch.stop() return this; }, compute: function(prop) { if (can.isFunction(this.constructor.prototype[prop])) { return can.compute(this[prop], this); } else { return can.compute(this, prop); } } }); Map.prototype.on = Map.prototype.bind; Map.prototype.off = Map.prototype.unbind; return Map; })(__m2, __m13, __m9, __m14); // ## list/list.js var __m15 = (function(can, Map) { // Helpers for `observable` lists. var splice = [].splice, // test if splice works correctly spliceRemovesProps = (function() { // IE's splice doesn't remove properties var obj = { 0: "a", length: 1 }; splice.call(obj, 0, 1); return !obj[0]; })(), list = Map( { Map: Map }, { setup: function(instances, options) { this.length = 0; can.cid(this, ".map") this._init = 1; instances = instances || []; if (can.isDeferred(instances)) { this.replace(instances) } else { var teardownMapping = instances.length && can.Map.helpers.addToMap(instances, this); this.push.apply(this, can.makeArray(instances || [])); } teardownMapping && teardownMapping(); // this change needs to be ignored this.bind('change', can.proxy(this._changes, this)); can.simpleExtend(this, options); delete this._init; }, _triggerChange: function(attr, how, newVal, oldVal) { Map.prototype._triggerChange.apply(this, arguments) // `batchTrigger` direct add and remove events... if (!~attr.indexOf('.')) { if (how === 'add') { can.batch.trigger(this, how, [newVal, +attr]); can.batch.trigger(this, 'length', [this.length]); } else if (how === 'remove') { can.batch.trigger(this, how, [oldVal, +attr]); can.batch.trigger(this, 'length', [this.length]); } else { can.batch.trigger(this, how, [newVal, +attr]) } } }, __get: function(attr) { return attr ? this[attr] : this; }, ___set: function(attr, val) { this[attr] = val; if (+attr >= this.length) { this.length = (+attr + 1) } }, _each: function(callback) { var data = this.__get(); for (var i = 0; i < data.length; i++) { callback(data[i], i) } }, _bindsetup: Map.helpers.makeBindSetup("*"), // Returns the serialized form of this list. serialize: function() { return Map.helpers.serialize(this, 'serialize', []); }, splice: function(index, howMany) { var args = can.makeArray(arguments), i; for (i = 2; i < args.length; i++) { var val = args[i]; if (Map.helpers.canMakeObserve(val)) { args[i] = Map.helpers.hookupBubble(val, "*", this, this.constructor.Map, this.constructor) } } if (howMany === undefined) { howMany = args[1] = this.length - index; } var removed = splice.apply(this, args); if (!spliceRemovesProps) { for (var i = this.length; i < removed.length + this.length; i++) { delete this[i] } } can.batch.start(); if (howMany > 0) { this._triggerChange("" + index, "remove", undefined, removed); Map.helpers.unhookup(removed, this); } if (args.length > 2) { this._triggerChange("" + index, "add", args.slice(2), removed); } can.batch.stop(); return removed; }, _attrs: function(items, remove) { if (items === undefined) { return Map.helpers.serialize(this, 'attr', []); } // Create a copy. items = can.makeArray(items); can.batch.start(); this._updateAttrs(items, remove); can.batch.stop() }, _updateAttrs: function(items, remove) { var len = Math.min(items.length, this.length); for (var prop = 0; prop < len; prop++) { var curVal = this[prop], newVal = items[prop]; if (Map.helpers.canMakeObserve(curVal) && Map.helpers.canMakeObserve(newVal)) { curVal.attr(newVal, remove) } else if (curVal != newVal) { this._set(prop, newVal) } else { } } if (items.length > this.length) { // Add in the remaining props. this.push.apply(this, items.slice(this.length)); } else if (items.length < this.length && remove) { this.splice(items.length) } } }), // Converts to an `array` of arguments. getArgs = function(args) { return args[0] && can.isArray(args[0]) ? args[0] : can.makeArray(args); }; // Create `push`, `pop`, `shift`, and `unshift` can.each({ push: "length", unshift: 0 }, // Adds a method // `name` - The method name. // `where` - Where items in the `array` should be added. function(where, name) { var orig = [][name] list.prototype[name] = function() { // Get the items being added. var args = [], // Where we are going to add items. len = where ? this.length : 0, i = arguments.length, res, val, constructor = this.constructor; // Go through and convert anything to an `map` that needs to be converted. while (i--) { val = arguments[i]; args[i] = Map.helpers.canMakeObserve(val) ? Map.helpers.hookupBubble(val, "*", this, this.constructor.Map, this.constructor) : val; } // Call the original method. res = orig.apply(this, args); if (!this.comparator || args.length) { this._triggerChange("" + len, "add", args, undefined); } return res; } }); can.each({ pop: "length", shift: 0 }, // Creates a `remove` type method function(where, name) { list.prototype[name] = function() { var args = getArgs(arguments), len = where && this.length ? this.length - 1 : 0; var res = [][name].apply(this, args) // Create a change where the args are // `len` - Where these items were removed. // `remove` - Items removed. // `undefined` - The new values (there are none). // `res` - The old, removed values (should these be unbound). this._triggerChange("" + len, "remove", undefined, [res]) if (res && res.unbind) { can.stopListening.call(this, res, "change"); } return res; } }); can.extend(list.prototype, { indexOf: function(item, fromIndex) { this.attr('length') return can.inArray(item, this, fromIndex) }, join: function() { return [].join.apply(this.attr(), arguments) }, reverse: [].reverse, slice: function() { var temp = Array.prototype.slice.apply(this, arguments); return new this.constructor(temp); }, concat: function() { var args = []; can.each(can.makeArray(arguments), function(arg, i) { args[i] = arg instanceof can.List ? arg.serialize() : arg; }); return new this.constructor(Array.prototype.concat.apply(this.serialize(), args)); }, forEach: function(cb, thisarg) { return can.each(this, cb, thisarg || this); }, replace: function(newList) { if (can.isDeferred(newList)) { newList.then(can.proxy(this.replace, this)); } else { this.splice.apply(this, [0, this.length].concat(can.makeArray(newList || []))); } return this; } }); can.List = Map.List = list; return can.List; })(__m2, __m12); // ## compute/compute.js var __m16 = (function(can, bind) { var names = ["__reading", "__clearReading", "__setReading"], setup = function(observed) { var old = {}; for (var i = 0; i < names.length; i++) { old[names[i]] = can[names[i]] } can.__reading = function(obj, attr) { // Add the observe and attr that was read // to `observed` observed.push({ obj: obj, attr: attr + "" }); }; can.__clearReading = function() { return observed.splice(0, observed.length); } can.__setReading = function(o) { [].splice.apply(observed, [0, observed.length].concat(o)) } return old; }, // empty default function k = function() {}; // returns the // - observes and attr methods are called by func // - the value returned by func // ex: `{value: 100, observed: [{obs: o, attr: "completed"}]}` var getValueAndObserved = function(func, self) { var observed = [], old = setup(observed), // Call the "wrapping" function to get the value. `observed` // will have the observe/attribute pairs that were read. value = func.call(self); // Set back so we are no longer reading. can.simpleExtend(can, old); return { value: value, observed: observed }; }, // Calls `callback(newVal, oldVal)` everytime an observed property // called within `getterSetter` is changed and creates a new result of `getterSetter`. // Also returns an object that can teardown all event handlers. computeBinder = function(getterSetter, context, callback, computeState) { // track what we are observing var observing = {}, // a flag indicating if this observe/attr pair is already bound matched = true, // the data to return data = { // we will maintain the value while live-binding is taking place value: undefined, // a teardown method that stops listening teardown: function() { for (var name in observing) { var ob = observing[name]; ob.observe.obj.unbind(ob.observe.attr, onchanged); delete observing[name]; } } }, batchNum; // when a property value is changed var onchanged = function(ev) { // If the compute is no longer bound (because the same change event led to an unbind) // then do not call getValueAndBind, or we will leak bindings. if (computeState && !computeState.bound) { return; } if (ev.batchNum === undefined || ev.batchNum !== batchNum) { // store the old value var oldValue = data.value, // get the new value newvalue = getValueAndBind(); // update the value reference (in case someone reads) data.value = newvalue; // if a change happened if (newvalue !== oldValue) { callback(newvalue, oldValue); } batchNum = batchNum = ev.batchNum; } }; // gets the value returned by `getterSetter` and also binds to any attributes // read by the call var getValueAndBind = function() { var info = getValueAndObserved(getterSetter, context), newObserveSet = info.observed; var value = info.value, ob; matched = !matched; // go through every attribute read by this observe for (var i = 0, len = newObserveSet.length; i < len; i++) { ob = newObserveSet[i]; // if the observe/attribute pair is being observed if (observing[ob.obj._cid + "|" + ob.attr]) { // mark at as observed observing[ob.obj._cid + "|" + ob.attr].matched = matched; } else { // otherwise, set the observe/attribute on oldObserved, marking it as being observed observing[ob.obj._cid + "|" + ob.attr] = { matched: matched, observe: ob }; ob.obj.bind(ob.attr, onchanged); } } // Iterate through oldObserved, looking for observe/attributes // that are no longer being bound and unbind them for (var name in observing) { var ob = observing[name]; if (ob.matched !== matched) { ob.observe.obj.unbind(ob.observe.attr, onchanged); delete observing[name]; } } return value; }; // set the initial value data.value = getValueAndBind(); data.isListening = !can.isEmptyObject(observing); return data; } // if no one is listening ... we can not calculate every time can.compute = function(getterSetter, context, eventName) { if (getterSetter && getterSetter.isComputed) { return getterSetter; } // stores the result of computeBinder var computedData, // how many listeners to this this compute bindings = 0, // the computed object computed, // an object that keeps track if the computed is bound // onchanged needs to know this. It's possible a change happens and results in // something that unbinds the compute, it needs to not to try to recalculate who it // is listening to computeState = { bound: false, // true if this compute is calculated from other computes and observes hasDependencies: false }, // The following functions are overwritten depending on how compute() is called // a method to setup listening on = k, // a method to teardown listening off = k, // the current cached value (only valid if bound = true) value, // how to read the value get = function() { return value }, // sets the value set = function(newVal) { value = newVal; }, // this compute can be a dependency of other computes canReadForChangeEvent = true, // save for clone args = can.makeArray(arguments), updater = function(newValue, oldValue) { value = newValue; // might need a way to look up new and oldVal can.batch.trigger(computed, "change", [newValue, oldValue]) }, // the form of the arguments form; computed = function(newVal) { // setting ... if (arguments.length) { // save a reference to the old value var old = value; // setter may return a value if // setter is for a value maintained exclusively by this compute var setVal = set.call(context, newVal, old); // if this has dependencies return the current value if (computed.hasDependencies) { return get.call(context); } if (setVal === undefined) { // it's possible, like with the DOM, setting does not // fire a change event, so we must read value = get.call(context); } else { value = setVal; } // fire the change if (old !== value) { can.batch.trigger(computed, "change", [value, old]); } return value; } else { // Another compute wants to bind to this compute if (can.__reading && canReadForChangeEvent) { // Tell the compute to listen to change on this computed can.__reading(computed, 'change'); // We are going to bind on this compute. // If we are not bound, we should bind so that // we don't have to re-read to get the value of this compute. !computeState.bound && can.compute.temporarilyBind(computed) } // if we are bound, use the cached value if (computeState.bound) { return value; } else { return get.call(context); } } } if (typeof getterSetter === "function") { set = getterSetter; get = getterSetter; canReadForChangeEvent = eventName === false ? false : true; computed.hasDependencies = false; on = function(update) { computedData = computeBinder(getterSetter, context || this, update, computeState); computed.hasDependencies = computedData.isListening value = computedData.value; } off = function() { computedData && computedData.teardown(); } } else if (context) { if (typeof context == "string") { // `can.compute(obj, "propertyName", [eventName])` var propertyName = context, isObserve = getterSetter instanceof can.Map; if (isObserve) { computed.hasDependencies = true; } get = function() { if (isObserve) { return getterSetter.attr(propertyName); } else { return getterSetter[propertyName]; } } set = function(newValue) { if (isObserve) { getterSetter.attr(propertyName, newValue) } else { getterSetter[propertyName] = newValue; } } var handler; on = function(update) { handler = function() { update(get(), value) }; can.bind.call(getterSetter, eventName || propertyName, handler) // use getValueAndObserved because // we should not be indicating that some parent // reads this property if it happens to be binding on it value = getValueAndObserved(get).value } off = function() { can.unbind.call(getterSetter, eventName || propertyName, handler) } } else { // `can.compute(initialValue, setter)` if (typeof context === "function") { value = getterSetter; set = context; context = eventName; form = "setter"; } else { // `can.compute(initialValue,{get:, set:, on:, off:})` value = getterSetter; var options = context; get = options.get || get; set = options.set || set; on = options.on || on; off = options.off || off; } } } else { // `can.compute(5)` value = getterSetter; } can.cid(computed, "compute") return can.simpleExtend(computed, { isComputed: true, _bindsetup: function() { computeState.bound = true; // setup live-binding // while binding, this does not count as a read var oldReading = can.__reading; delete can.__reading; on.call(this, updater); can.__reading = oldReading; }, _bindteardown: function() { off.call(this, updater) computeState.bound = false; }, bind: can.bindAndSetup, unbind: can.unbindAndTeardown, clone: function(context) { if (context) { if (form == "setter") { args[2] = context } else { args[1] = context } } return can.compute.apply(can, args); } }); }; // a list of temporarily bound computes var computes, unbindComputes = function() { for (var i = 0, len = computes.length; i < len; i++) { computes[i].unbind("change", k) } computes = null; } // Binds computes for a moment to retain their value and prevent caching can.compute.temporarilyBind = function(compute) { compute.bind("change", k) if (!computes) { computes = []; setTimeout(unbindComputes, 10) } computes.push(compute) }; can.compute.binder = computeBinder; can.compute.truthy = function(compute) { return can.compute(function() { var res = compute(); if (typeof res === "function") { res = res() } return !!res; }) } return can.compute; })(__m2, __m13, __m14); // ## observe/observe.js var __m11 = (function(can) { can.Observe = can.Map; can.Observe.startBatch = can.batch.start; can.Observe.stopBatch = can.batch.stop; can.Observe.triggerBatch = can.batch.trigger; return can; })(__m2, __m12, __m15, __m16); // ## view/view.js var __m19 = (function(can) { // ## view.js // `can.view` // _Templating abstraction._ var isFunction = can.isFunction, makeArray = can.makeArray, // Used for hookup `id`s. hookupId = 1, $view = can.view = can.template = function(view, data, helpers, callback) { // If helpers is a `function`, it is actually a callback. if (isFunction(helpers)) { callback = helpers; helpers = undefined; } var pipe = function(result) { return $view.frag(result); }, // In case we got a callback, we need to convert the can.view.render // result to a document fragment wrapCallback = isFunction(callback) ? function(frag) { callback(pipe(frag)); } : null, // Get the result, if a renderer function is passed in, then we just use that to render the data result = isFunction(view) ? view(data, helpers, wrapCallback) : $view.render(view, data, helpers, wrapCallback), deferred = can.Deferred(); if (isFunction(result)) { return result; } if (can.isDeferred(result)) { result.then(function(result, data) { deferred.resolve.call(deferred, pipe(result), data); }, function() { deferred.fail.apply(deferred, arguments); }); return deferred; } // Convert it into a dom frag. return pipe(result); }; can.extend($view, { // creates a frag and hooks it up all at once frag: function(result, parentNode) { return $view.hookup($view.fragment(result), parentNode); }, // simply creates a frag // this is used internally to create a frag // insert it // then hook it up fragment: function(result) { var frag = can.buildFragment(result, document.body); // If we have an empty frag... if (!frag.childNodes.length) { frag.appendChild(document.createTextNode('')); } return frag; }, // Convert a path like string into something that's ok for an `element` ID. toId: function(src) { return can.map(src.toString().split(/\/|\./g), function(part) { // Dont include empty strings in toId functions if (part) { return part; } }).join("_"); }, hookup: function(fragment, parentNode) { var hookupEls = [], id, func; // Get all `childNodes`. can.each(fragment.childNodes ? can.makeArray(fragment.childNodes) : fragment, function(node) { if (node.nodeType === 1) { hookupEls.push(node); hookupEls.push.apply(hookupEls, can.makeArray(node.getElementsByTagName('*'))); } }); // Filter by `data-view-id` attribute. can.each(hookupEls, function(el) { if (el.getAttribute && (id = el.getAttribute('data-view-id')) && (func = $view.hookups[id])) { func(el, parentNode, id); delete $view.hookups[id]; el.removeAttribute('data-view-id'); } }); return fragment; }, // auj // heir hookups: {}, hook: function(cb) { $view.hookups[++hookupId] = cb; return " data-view-id='" + hookupId + "'"; }, cached: {}, cachedRenderers: {}, cache: true, register: function(info) { this.types["." + info.suffix] = info; }, types: {}, ext: ".ejs", registerScript: function() {}, preload: function() {}, render: function(view, data, helpers, callback) { // If helpers is a `function`, it is actually a callback. if (isFunction(helpers)) { callback = helpers; helpers = undefined; } // See if we got passed any deferreds. var deferreds = getDeferreds(data); if (deferreds.length) { // Does data contain any deferreds? // The deferred that resolves into the rendered content... var deferred = new can.Deferred(), dataCopy = can.extend({}, data); // Add the view request to the list of deferreds. deferreds.push(get(view, true)) // Wait for the view and all deferreds to finish... can.when.apply(can, deferreds).then(function(resolved) { // Get all the resolved deferreds. var objs = makeArray(arguments), // Renderer is the last index of the data. renderer = objs.pop(), // The result of the template rendering with data. result; // Make data look like the resolved deferreds. if (can.isDeferred(data)) { dataCopy = usefulPart(resolved); } else { // Go through each prop in data again and // replace the defferreds with what they resolved to. for (var prop in data) { if (can.isDeferred(data[prop])) { dataCopy[prop] = usefulPart(objs.shift()); } } } // Get the rendered result. result = renderer(dataCopy, helpers); // Resolve with the rendered view. deferred.resolve(result, dataCopy); // If there's a `callback`, call it back with the result. callback && callback(result, dataCopy); }, function() { deferred.reject.apply(deferred, arguments) }); // Return the deferred... return deferred; } else { // get is called async but in // ff will be async so we need to temporarily reset if (can.__reading) { var reading = can.__reading; can.__reading = null; } // No deferreds! Render this bad boy. var response, // If there's a `callback` function async = isFunction(callback), // Get the `view` type deferred = get(view, async); if (can.Map && can.__reading) { can.__reading = reading; } // If we are `async`... if (async) { // Return the deferred response = deferred; // And fire callback with the rendered result. deferred.then(function(renderer) { callback(data ? renderer(data, helpers) : renderer); }) } else { // if the deferred is resolved, call the cached renderer instead // this is because it's possible, with recursive deferreds to // need to render a view while its deferred is _resolving_. A _resolving_ deferred // is a deferred that was just resolved and is calling back it's success callbacks. // If a new success handler is called while resoliving, it does not get fired by // jQuery's deferred system. So instead of adding a new callback // we use the cached renderer. // We also add __view_id on the deferred so we can look up it's cached renderer. // In the future, we might simply store either a deferred or the cached result. if (deferred.state() === "resolved" && deferred.__view_id) { var currentRenderer = $view.cachedRenderers[deferred.__view_id]; return data ? currentRenderer(data, helpers) : currentRenderer; } else { // Otherwise, the deferred is complete, so // set response to the result of the rendering. deferred.then(function(renderer) { response = data ? renderer(data, helpers) : renderer; }); } } return response; } }, registerView: function(id, text, type, def) { // Get the renderer function. var func = (type || $view.types[$view.ext]).renderer(id, text); def = def || new can.Deferred(); // Cache if we are caching. if ($view.cache) { $view.cached[id] = def; def.__view_id = id; $view.cachedRenderers[id] = func; } // Return the objects for the response's `dataTypes` // (in this case view). return def.resolve(func); } }); // Makes sure there's a template, if not, have `steal` provide a warning. var checkText = function(text, url) { if (!text.length) { throw "can.view: No template or empty template:" + url; } }, // `Returns a `view` renderer deferred. // `url` - The url to the template. // `async` - If the ajax request should be asynchronous. // Returns a deferred. get = function(obj, async) { var url = typeof obj === 'string' ? obj : obj.url, suffix = obj.engine || url.match(/\.[\w\d]+$/), type, // If we are reading a script element for the content of the template, // `el` will be set to that script element. el, // A unique identifier for the view (used for caching). // This is typically derived from the element id or // the url for the template. id, // The ajax request used to retrieve the template content. jqXHR; //If the url has a #, we assume we want to use an inline template //from a script element and not current page's HTML if (url.match(/^#/)) { url = url.substr(1); } // If we have an inline template, derive the suffix from the `text/???` part. // This only supports `