Commit 3bdc9168 authored by David Luecke's avatar David Luecke

CanJS 1.1.3 + RequireJS

parent 6dd68ec0
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>CanJS + RequireJS • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css">
</head>
<body>
<section id="todoapp">
</section>
<div id="info">
<p>Double-click to edit a todo</p>
<p>Written by <a href="http://bitovi.com">Bitovi</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</div>
<script src="../../../assets/base.js"></script>
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->
<script data-main="js/app" src="../../../assets/require.min.js"></script>
</body>
</html>
/*global require*/
require.config({
paths: {
jquery: '../../../../assets/jquery.min',
can: 'lib/can'
}
});
require(['can/util/library', 'can/route', 'app/todos', 'app/models/todo', 'can/view/ejs', 'can/view/mustache'],
function (can, route, Todos, Model) {
'use strict';
// Set up a route that maps to the `filter` attribute
route(':filter');
// Delay routing until we initialized everything
route.ready(false);
// View helper for pluralizing strings
can.Mustache.registerHelper('plural', function (str, count) {
return str + (count !== 1 ? 's' : '');
});
// Find all Todos
Model.findAll({}, function (todos) {
// Wire it up. Instantiate a new Todos control
new Todos('#todoapp', {
// The (Todo) model that the control should use
Model: Model,
// The list of Todos retrieved from the model
todos: todos,
// The control state for filtering the view (in our case the router)
state: can.route,
// The view to render
view: 'views/todos.mustache'
});
});
// Now we can start routing
route.ready(true);
});
\ No newline at end of file
/*global define*/
define(['can/util/library', 'can/model'], function (can, Model) {
'use strict';
var LocalStorage = Model({
// Implement local storage handling
localStore: function (cb) {
var name = this.name,
data = JSON.parse(window.localStorage[name] || (window.localStorage[name] = '[]')),
res = cb.call(this, data);
if (res !== false) {
can.each(data, function (todo) {
delete todo.editing;
});
window.localStorage[name] = JSON.stringify(data);
}
},
findAll: function () {
var def = new can.Deferred();
this.localStore(function (todos) {
var instances = [],
self = this;
can.each(todos, function (todo) {
instances.push(new self(todo));
});
def.resolve({data: instances});
});
return def;
},
destroy: function (id) {
var def = new can.Deferred();
this.localStore(function (todos) {
for (var i = 0; i < todos.length; i++) {
if (todos[i].id === id) {
todos.splice(i, 1);
break;
}
}
def.resolve({});
});
return def;
},
create: function (attrs) {
var def = new can.Deferred();
this.localStore(function (todos) {
attrs.id = attrs.id || parseInt(100000 * Math.random(), 10);
todos.push(attrs);
});
def.resolve({id: attrs.id});
return def;
},
update: function (id, attrs) {
var def = new can.Deferred(), todo;
this.localStore(function (todos) {
for (var i = 0; i < todos.length; i++) {
if (todos[i].id === id) {
todo = todos[i];
break;
}
}
can.extend(todo, attrs);
});
def.resolve({});
return def;
}
}, {});
return LocalStorage;
});
\ No newline at end of file
/*global define*/
define(['can/util/library', 'can/observe', 'app/models/localstorage'], function (can, Observe, LocalStorage) {
'use strict';
// Basic Todo entry model
// { text: 'todo', complete: false }
var Todo = LocalStorage({
storageName: 'todos-canjs-requirejs'
}, {
// Returns if this instance matches a given filter
// (currently `active` and `complete`)
matches: function (state) {
return !state || (state === 'active' && !this.attr('complete')) ||
(state === 'completed' && this.attr('complete'));
}
});
// Extend the existing Todo.List to add some helper methods
Todo.List = Todo.List({
completed: function () {
var completed = 0;
this.each(function (todo) {
completed += todo.attr('complete') ? 1 : 0;
});
return completed;
},
remaining: function () {
return this.attr('length') - this.completed();
},
allComplete: function () {
return this.attr('length') === this.completed();
},
// Returns a new can.Observe.List that contains only the Todos
// matching the current filter
byFilter: function(filter) {
var filtered = new Observe.List();
can.each(this, function(todo) {
if(todo.matches(filter)) {
filtered.push(todo);
}
});
return filtered;
},
// Returns the list to display based on the currently set `filter`
displayList: function() {
return this.byFilter(this.attr('filter'));
}
});
return Todo;
});
/*global define*/
define(['can/util/library', 'can/control'], function (can, Control) {
'use strict';
var ENTER_KEY = 13;
var Todos = Control({
// Default options
defaults: {
view: 'views/todos.ejs'
}
}, {
// Initialize the Todos list
init: function () {
// Render the Todos we passed in the options
this.element.append(can.view(this.options.view, {
todos: this.options.todos
}));
},
// Listen for when a new Todo has been entered
'#new-todo keyup': function (el, e) {
var value = can.trim(el.val());
if (e.which === ENTER_KEY && value !== '') {
// Create a new Model which was passed as an option when initializing the control
new this.options.Model({
text: value,
complete: false
}).save(function () {
el.val('');
});
}
},
// Handle a newly created Todo (`Model` that was passed when initializing this Control)
'{Model} created': function (list, e, item) {
this.options.todos.push(item);
// Reset the filter so that you always see your new todo
this.options.state.attr('filter', '');
},
// Listener for when the filter observe
'{state} filter': function (state, event, filter) {
// Update the filter of our Todo list
this.options.todos.attr('filter', filter || '');
// Remove the `selected` class from the old link and add it to the link for the current location hash
this.element.find('#filters a').removeClass('selected').filter('[href="' + window.location.hash + '"]')
.addClass('selected');
},
// Listen for editing a Todo
'.todo dblclick': function (el) {
el.data('todo').attr('editing', true).save(function () {
el.children('.edit').focus();
});
},
// Update a todo
updateTodo: function (el) {
var value = can.trim(el.val());
var todo = el.closest('.todo').data('todo');
// If we don't have a todo we don't need to do anything
if (!todo) {
return;
}
if (value === '') {
todo.destroy();
} else {
todo.attr({
editing: false,
text: value
}).save();
}
},
// Listen for an edited Todo
'.todo .edit keyup': function (el, e) {
if (e.which === ENTER_KEY) {
this.updateTodo(el);
}
},
'.todo .edit focusout': 'updateTodo',
// Listen for the toggled completion of a Todo
'.todo .toggle click': function (el) {
el.closest('.todo').data('todo')
.attr('complete', el.is(':checked'))
.save();
},
// Listen for a removed Todo
'.todo .destroy click': function (el) {
el.closest('.todo').data('todo').destroy();
},
// Listen for toggle all completed Todos
'#toggle-all click': function (el) {
var toggle = el.prop('checked');
can.each(this.options.todos, function (todo) {
todo.attr('complete', toggle).save();
});
},
// Listen for removing all completed Todos
'#clear-completed click': function () {
can.each(this.options.todos.byFilter('completed'), function (todo) {
todo.destroy();
});
}
});
return Todos;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/control', 'can/model', 'can/view/ejs', 'can/route'], function (can) {
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/string'], 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, {
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 ?
// We are being called without `new` or we are extending.
arguments.callee.extend.apply(arguments.callee, arguments) :
// We are being called with `new`.
this.constructor.newInstance.apply(this.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,
_shortName: _shortName,
fullName: fullName,
_fullName: _fullName
});
// 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;
}
});
return can.Construct;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/construct'], function (can, Construct) {
var isFunction = can.isFunction,
isArray = can.isArray,
makeArray = can.makeArray,
proxy = function (funcs) {
//args that should be curried
var args = makeArray(arguments),
self;
// get the functions to callback
funcs = args.shift();
// if there is only one function, make funcs into an array
if (!isArray(funcs)) {
funcs = [funcs];
}
// keep a reference to us in self
self = this;
return function class_cb() {
// add the arguments after the curried args
var cur = args.concat(makeArray(arguments)),
isString, length = funcs.length,
f = 0,
func;
// go through each function to call back
for (; f < length; f++) {
func = funcs[f];
if (!func) {
continue;
}
// set called with the name of the function on self (this is how this.view works)
isString = typeof func == "string";
// call the function
cur = (isString ? self[func] : func).apply(self, cur || []);
// pass the result to the next function (if there is a next function)
if (f < length - 1) {
cur = !isArray(cur) || cur._use_call ? [cur] : cur
}
}
return cur;
}
}
can.Construct.proxy = can.Construct.prototype.proxy = proxy;
// this corrects the case where can/control loads after can/construct/proxy, so static props don't have proxy
var correctedClasses = [can.Control, can.Model],
i = 0;
for (; i < correctedClasses.length; i++) {
if (correctedClasses[i]) {
correctedClasses[i].proxy = proxy;
}
}
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/construct'], function (can, Construct) {
// tests if we can get super in .toString()
var isFunction = can.isFunction,
fnTest = /xyz/.test(function () {
xyz;
}) ? /\b_super\b/ : /.*/;
// overwrites a single property so it can still call super
can.Construct._overwrite = function (addTo, base, name, val) {
// Check if we're overwriting an existing function
addTo[name] = isFunction(val) && isFunction(base[name]) && fnTest.test(val) ? (function (name, fn) {
return function () {
var tmp = this._super,
ret;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = base[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, val) : val;
}
// overwrites an object with methods, sets up _super
// newProps - new properties
// oldProps - where the old properties might be
// addTo - what we are adding to
can.Construct._inherit = function (newProps, oldProps, addTo) {
addTo = addTo || newProps
for (var name in newProps) {
can.Construct._overwrite(addTo, oldProps, name, newProps[name]);
}
}
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/construct'], 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, [options, window]) : 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
};
}
},
// 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();
// Get's 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, "destroyed", destroyCB);
bindings.push(function (el) {
can.unbind.call(el, "destroyed", 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 () {
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;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['jquery', 'can/util/library', 'can/control'], function ($, can) {
//used to determine if a control instance is one of controllers
//controllers can be strings or classes
var i, isAControllerOf = function (instance, controllers) {
for (i = 0; i < controllers.length; i++) {
if (typeof controllers[i] == 'string' ? instance.constructor._shortName == controllers[i] : instance instanceof controllers[i]) {
return true;
}
}
return false;
},
makeArray = can.makeArray,
old = can.Control.setup;
can.Control.setup = function () {
// if you didn't provide a name, or are control, don't do anything
if (this !== can.Control) {
var pluginName = this.pluginName || this._fullName;
// create jQuery plugin
if (pluginName !== 'can_control') {
this.plugin(pluginName);
}
old.apply(this, arguments);
}
};
$.fn.extend({
controls: function () {
var controllerNames = makeArray(arguments),
instances = [],
controls, c, cname;
//check if arguments
this.each(function () {
controls = can.$(this).data("controls");
if (!controls) {
return;
}
for (var i = 0; i < controls.length; i++) {
c = controls[i];
if (!controllerNames.length || isAControllerOf(c, controllerNames)) {
instances.push(c);
}
}
});
return instances;
},
control: function (control) {
return this.controls.apply(this, arguments)[0];
}
});
can.Control.plugin = function (pluginname) {
var control = this;
if (!$.fn[pluginname]) {
$.fn[pluginname] = function (options) {
var args = makeArray(arguments),
//if the arg is a method on this control
isMethod = typeof options == "string" && $.isFunction(control.prototype[options]),
meth = args[0],
returns;
this.each(function () {
//check if created
var plugin = can.$(this).control(control);
if (plugin) {
if (isMethod) {
// call a method on the control with the remaining args
returns = plugin[meth].apply(plugin, args.slice(1));
}
else {
// call the plugin's update method
plugin.update.apply(plugin, args);
}
}
else {
//create a new control instance
control.newInstance.apply(control, [this].concat(args));
}
});
return returns !== undefined ? returns : this;
};
}
}
can.Control.prototype.update = function (options) {
can.extend(this.options, options);
this.on();
};
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/route', 'can/control'], function (can) {
// ## control/route.js
// _Controller route integration._
can.Control.processors.route = function (el, event, selector, funcName, controller) {
selector = selector || "";
can.route(selector);
var batchNum, check = function (ev, attr, how) {
if (can.route.attr('route') === (selector) && (ev.batchNum === undefined || ev.batchNum !== batchNum)) {
batchNum = ev.batchNum;
var d = can.route.attr();
delete d.route;
if (can.isFunction(controller[funcName])) {
controller[funcName](d);
} else {
controller[controller[funcName]](d);
}
}
};
can.route.bind('change', check);
return function () {
can.route.unbind('change', check);
};
};
return can;
});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/observe'], function (can, Observe) {
can.each([can.Observe, can.Model], function (clss) {
// in some cases model might not be defined quite yet.
if (clss === undefined) {
return;
}
can.extend(clss, {
attributes: {},
convert: {
"date": function (str) {
var type = typeof str;
if (type === "string") {
return isNaN(Date.parse(str)) ? null : Date.parse(str)
} else if (type === 'number') {
return new Date(str)
} else {
return str
}
},
"number": function (val) {
return parseFloat(val);
},
"boolean": function (val) {
return Boolean(val === "false" ? 0 : val);
},
"default": function (val, oldVal, error, type) {
var construct = can.getObject(type),
context = window,
realType;
// if type has a . we need to look it up
if (type.indexOf(".") >= 0) {
// get everything before the last .
realType = type.substring(0, type.lastIndexOf("."));
// get the object before the last .
context = can.getObject(realType);
}
return typeof construct == "function" ? construct.call(context, val, oldVal) : val;
}
},
serialize: {
"default": function (val, type) {
return isObject(val) && val.serialize ? val.serialize() : val;
},
"date": function (val) {
return val && val.getTime()
}
}
});
// overwrite setup to do this stuff
var oldSetup = clss.setup;
clss.setup = function (superClass, stat, proto) {
var self = this;
oldSetup.call(self, superClass, stat, proto);
can.each(["attributes"], function (name) {
if (!self[name] || superClass[name] === self[name]) {
self[name] = {};
}
});
can.each(["convert", "serialize"], function (name) {
if (superClass[name] != self[name]) {
self[name] = can.extend({}, superClass[name], self[name]);
}
});
};
});
var oldSetup = can.Observe.prototype.setup;
can.Observe.prototype.setup = function (obj) {
var diff = {};
oldSetup.call(this, obj);
can.each(this.constructor.defaults, function (value, key) {
if (!this.hasOwnProperty(key)) {
diff[key] = value;
}
}, this);
this._init = 1;
this.attr(diff);
delete this._init;
};
can.Observe.prototype.__convert = function (prop, value) {
// check if there is a
var Class = this.constructor,
oldVal = this.attr(prop),
type, converter;
if (Class.attributes) {
// the type of the attribute
type = Class.attributes[prop];
converter = Class.convert[type] || Class.convert['default'];
}
return value === null || !type ?
// just use the value
value :
// otherwise, pass to the converter
converter.call(Class, value, oldVal, function () {}, type);
};
can.Observe.prototype.serialize = function (attrName) {
var where = {},
Class = this.constructor,
attrs = {};
if (attrName != undefined) {
attrs[attrName] = this[attrName];
} else {
attrs = this.__get();
}
can.each(attrs, function (val, name) {
var type, converter;
type = Class.attributes ? Class.attributes[name] : 0;
converter = Class.serialize ? Class.serialize[type] : 0;
// if the value is an object, and has a attrs or serialize function
where[name] = val && typeof val.serialize == 'function' ?
// call attrs or serialize to get the original data back
val.serialize() :
// otherwise if we have a converter
converter ?
// use the converter
converter(val, type) :
// or return the val
val
});
return attrName != undefined ? where[attrName] : where;
};
return can.Observe;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/observe', 'can/util/object'], function (can) {
var flatProps = function (a) {
var obj = {};
for (var prop in a) {
if (typeof a[prop] !== 'object' || a[prop] === null || a[prop] instanceof Date) {
obj[prop] = a[prop]
}
}
return obj;
};
can.extend(can.Observe.prototype, {
backup: function () {
this._backupStore = this._attrs();
return this;
},
isDirty: function (checkAssociations) {
return this._backupStore && !can.Object.same(this._attrs(), this._backupStore, undefined, undefined, undefined, !! checkAssociations);
},
restore: function (restoreAssociations) {
var props = restoreAssociations ? this._backupStore : flatProps(this._backupStore)
if (this.isDirty(restoreAssociations)) {
this._attrs(props);
}
return this;
}
})
return can.Observe;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library'], function (can) {
// 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 oldReading;
if (can.Observe) {
// Set a callback on can.Observe to know
// when an attr is read.
// Keep a reference to the old reader
// if there is one. This is used
// for nested live binding.
oldReading = can.Observe.__reading;
can.Observe.__reading = function (obj, attr) {
// Add the observe and attr that was read
// to `observed`
observed.push({
obj: obj,
attr: attr
});
};
}
var 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.
if (can.Observe) {
can.Observe.__reading = oldReading;
}
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) {
// 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 (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;
matched = !matched;
// go through every attribute read by this observe
can.each(newObserveSet, function (ob) {
// 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) {
if (getterSetter && getterSetter.isComputed) {
return getterSetter;
}
// get the value right away
// TODO: eventually we can defer this until a bind or a read
var computedData, bindings = 0,
computed, canbind = true;
if (typeof getterSetter === "function") {
computed = function (value) {
if (value === undefined) {
// we are reading
if (computedData) {
// If another compute is calling this compute for the value,
// it needs to bind to this compute's change so it will re-compute
// and re-bind when this compute changes.
if (bindings && can.Observe.__reading) {
can.Observe.__reading(computed, 'change');
}
return computedData.value;
} else {
return getterSetter.call(context || this)
}
} else {
return getterSetter.apply(context || this, arguments)
}
}
} else {
// we just gave it a value
computed = function (val) {
if (val === undefined) {
// If observing, record that the value is being read.
if (can.Observe.__reading) {
can.Observe.__reading(computed, 'change');
}
return getterSetter;
} else {
var old = getterSetter;
getterSetter = val;
if (old !== val) {
can.Observe.triggerBatch(computed, "change", [val, old]);
}
return val;
}
}
canbind = false;
}
computed.isComputed = true;
computed.bind = function (ev, handler) {
can.addEvent.apply(computed, arguments);
if (bindings === 0 && canbind) {
// setup live-binding
computedData = computeBinder(getterSetter, context || this, function (newValue, oldValue) {
can.Observe.triggerBatch(computed, "change", [newValue, oldValue])
});
}
bindings++;
}
computed.unbind = function (ev, handler) {
can.removeEvent.apply(computed, arguments);
bindings--;
if (bindings === 0 && canbind) {
computedData.teardown();
}
};
return computed;
};
can.compute.binder = computeBinder;
return can.compute;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/observe'], function (can) {
// ** - 'this' will be the deepest item changed
// * - 'this' will be any changes within *, but * will be the
// this returned
// tells if the parts part of a delegate matches the broken up props of the event
// gives the prop to use as 'this'
// - parts - the attribute name of the delegate split in parts ['foo','*']
// - props - the split props of the event that happened ['foo','bar','0']
// - returns - the attribute to delegate too ('foo.bar'), or null if not a match
var matches = function (parts, props) {
//check props parts are the same or
var len = parts.length,
i = 0,
// keeps the matched props we will use
matchedProps = [],
prop;
// if the event matches
for (i; i < len; i++) {
prop = props[i]
// if no more props (but we should be matching them)
// return null
if (typeof prop !== 'string') {
return null;
} else
// if we have a "**", match everything
if (parts[i] == "**") {
return props.join(".");
} else
// a match, but we want to delegate to "*"
if (parts[i] == "*") {
// only do this if there is nothing after ...
matchedProps.push(prop);
}
else if (prop === parts[i]) {
matchedProps.push(prop);
} else {
return null;
}
}
return matchedProps.join(".");
},
// gets a change event and tries to figure out which
// delegates to call
delegate = function (event, prop, how, newVal, oldVal) {
// pre-split properties to save some regexp time
var props = prop.split("."),
delegates = (this._observe_delegates || []).slice(0),
delegate, attr, matchedAttr, hasMatch, valuesEqual;
event.attr = prop;
event.lastAttr = props[props.length - 1];
// for each delegate
for (var i = 0; delegate = delegates[i++];) {
// if there is a batchNum, this means that this
// event is part of a series of events caused by a single
// attrs call. We don't want to issue the same event
// multiple times
// setting the batchNum happens later
if ((event.batchNum && delegate.batchNum === event.batchNum) || delegate.undelegated) {
continue;
}
// reset match and values tests
hasMatch = undefined;
valuesEqual = true;
// yeah, all this under here has to be redone v
// for each attr in a delegate
for (var a = 0; a < delegate.attrs.length; a++) {
attr = delegate.attrs[a];
// check if it is a match
if (matchedAttr = matches(attr.parts, props)) {
hasMatch = matchedAttr;
}
// if it has a value, make sure it's the right value
// if it's set, we should probably check that it has a
// value no matter what
if (attr.value && valuesEqual) {
valuesEqual = attr.value === "" + this.attr(attr.attr)
} else if (valuesEqual && delegate.attrs.length > 1) {
// if there are multiple attributes, each has to at
// least have some value
valuesEqual = this.attr(attr.attr) !== undefined
}
}
// if there is a match and valuesEqual ... call back
if (hasMatch && valuesEqual) {
// how to get to the changed property from the delegate
var from = prop.replace(hasMatch + ".", "");
// if this event is part of a batch, set it on the delegate
// to only send one event
if (event.batchNum) {
delegate.batchNum = event.batchNum
}
// if we listen to change, fire those with the same attrs
// TODO: the attrs should probably be using from
if (delegate.event === 'change') {
arguments[1] = from;
event.curAttr = hasMatch;
delegate.callback.apply(this.attr(hasMatch), can.makeArray(arguments));
} else if (delegate.event === how) {
// if it's a match, callback with the location of the match
delegate.callback.apply(this.attr(hasMatch), [event, newVal, oldVal, from]);
} else if (delegate.event === 'set' && how == 'add') {
// if we are listening to set, we should also listen to add
delegate.callback.apply(this.attr(hasMatch), [event, newVal, oldVal, from]);
}
}
}
};
can.extend(can.Observe.prototype, {
delegate: function (selector, event, handler) {
selector = can.trim(selector);
var delegates = this._observe_delegates || (this._observe_delegates = []),
attrs = [],
selectorRegex = /([^\s=,]+)(?:=("[^",]*"|'[^',]*'|[^\s"',]*))?(,?)\s*/g,
matches;
// parse each property in the selector
while (matches = selectorRegex.exec(selector)) {
// we need to do a little doctoring to make up for the quotes.
if (matches[2] && $.inArray(matches[2].substr(0, 1), ['"', "'"]) >= 0) {
matches[2] = matches[2].substr(1, -1);
}
attrs.push({
// the attribute name
attr: matches[1],
// the attribute name, pre-split for speed
parts: matches[1].split('.'),
// the value associated with this property (if there was one given)
value: matches[2],
// whether this selector combines with the one after it with AND or OR
or: matches[3] === ','
});
}
// delegates has pre-processed info about the event
delegates.push({
// the attrs name for unbinding
selector: selector,
// an object of attribute names and values {type: 'recipe',id: undefined}
// undefined means a value was not defined
attrs: attrs,
callback: handler,
event: event
});
if (delegates.length === 1) {
this.bind("change", delegate)
}
return this;
},
undelegate: function (selector, event, handler) {
selector = can.trim(selector);
var i = 0,
delegates = this._observe_delegates || [],
delegateOb;
if (selector) {
while (i < delegates.length) {
delegateOb = delegates[i];
if (delegateOb.callback === handler || (!handler && delegateOb.selector === selector)) {
delegateOb.undelegated = true;
delegates.splice(i, 1)
} else {
i++;
}
}
} else {
// remove all delegates
delegates = [];
}
if (!delegates.length) {
//can.removeData(this, "_observe_delegates");
this.unbind("change", delegate)
}
return this;
}
});
// add helpers for testing ..
can.Observe.prototype.delegate.matches = matches;
return can.Observe;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/observe', 'can/observe/compute'], function (can) {
can.extend(can.Observe.List.prototype, {
filter: function (callback) {
// The filtered list
var filtered = new this.constructor();
var self = this;
// Creates the binder for a single element at a given index
var generator = function (element, index) {
// The event handler that updates the filtered list
var binder = function (ev, val) {
var index = filtered.indexOf(element);
// Remove it from the list if it exists but the new value is false
if (!val && index !== -1) {
filtered.splice(index, 1);
}
// Add it to the list if it isn't in there and the new value is true
if (val && index === -1) {
filtered.push(element);
}
};
// a can.compute that executes the callback
var compute = can.compute(function () {
return callback(element, self.indexOf(element), self);
});
// Update the filtered list on any compute change
compute.bind('change', binder);
// Call binder explicitly for the initial list
binder(null, compute());
};
// We also want to know when something gets added to our original list
this.bind('add', function (ev, data, index) {
can.each(data, function (element, i) {
// Call the generator for each newly added element
// The index is the start index + the loop index
generator(element, index + i);
});
});
// Removed items should be removed from both lists
this.bind('remove', function (ev, data, index) {
can.each(data, function (element, i) {
var index = filtered.indexOf(element);
if (index !== -1) {
filtered.splice(index, 1);
}
});
});
// Run the generator for each list element
this.forEach(generator);
return filtered;
},
map: function (callback) {
var mapped = new can.Observe.List();
var self = this;
// Again, lets run a generator function
var generator = function (element, index) {
// The can.compute for the mapping
var compute = can.compute(function () {
return callback(element, index, self);
});
compute.bind('change', function (ev, val) {
// On change, replace the current value with the new one
mapped.splice(index, 1, val);
});
mapped.push(compute());
}
this.forEach(generator);
// We also want to know when something gets added to our original list
this.bind('add', function (ev, data, index) {
can.each(data, function (element, i) {
// Call the generator for each newly added element
// The index is the start index + the loop index
generator(element, index + i);
});
});
this.bind('remove', function (ev, data, index) {
// The indices in the mapped list are the same so lets just splice it out
mapped.splice(index, data.length);
})
return mapped;
}
});
return can.Observe.List;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/observe/attributes'], function (can) {
can.classize = function (s, join) {
// this can be moved out ..
// used for getter setter
var parts = s.split(can.undHash),
i = 0;
for (; i < parts.length; i++) {
parts[i] = can.capitalize(parts[i]);
}
return parts.join(join || '');
}
var classize = can.classize,
proto = can.Observe.prototype,
old = proto.__set;
proto.__set = function (prop, value, current, success, error) {
// check if there's a setter
var cap = classize(prop),
setName = "set" + cap,
errorCallback = function (errors) {
var stub = error && error.call(self, errors);
// if 'setter' is on the page it will trigger
// the error itself and we dont want to trigger
// the event twice. :)
if (stub !== false) {
can.trigger(self, "error", [prop, errors], true);
}
return false;
},
self = this;
// if we have a setter
if (this[setName] &&
// call the setter, if returned value is undefined,
// this means the setter is async so we
// do not call update property and return right away
(value = this[setName](value, function () {
old.call(self, prop, value, current, success, errorCallback)
}, errorCallback)) === undefined) {
return;
}
old.call(self, prop, value, current, success, errorCallback);
return this;
};
return can.Observe;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/library', 'can/observe/attributes'], function (can) {
//validations object is by property. You can have validations that
//span properties, but this way we know which ones to run.
// proc should return true if there's an error or the error message
var validate = function (attrNames, options, proc) {
// normalize argumetns
if (!proc) {
proc = options;
options = {};
}
options = options || {};
attrNames = can.makeArray(attrNames)
// run testIf if it exists
if (options.testIf && !options.testIf.call(this)) {
return;
}
var self = this;
can.each(attrNames, function (attrName) {
// Add a test function for each attribute
if (!self.validations[attrName]) {
self.validations[attrName] = [];
}
self.validations[attrName].push(function (newVal) {
// if options has a message return that, otherwise, return the error
var res = proc.call(this, newVal, attrName);
return res === undefined ? undefined : (options.message || res);
})
});
};
var old = can.Observe.prototype.__set;
can.Observe.prototype.__set = function (prop, value, current, success, error) {
var self = this,
validations = self.constructor.validations,
errorCallback = function (errors) {
var stub = error && error.call(self, errors);
// if 'setter' is on the page it will trigger
// the error itself and we dont want to trigger
// the event twice. :)
if (stub !== false) {
can.trigger(self, "error", [prop, errors], true);
}
return false;
};
old.call(self, prop, value, current, success, errorCallback);
if (validations && validations[prop]) {
var errors = self.errors(prop);
errors && errorCallback(errors)
}
return this;
}
can.each([can.Observe, can.Model], function (clss) {
// in some cases model might not be defined quite yet.
if (clss === undefined) {
return;
}
var oldSetup = clss.setup;
can.extend(clss, {
setup: function (superClass) {
oldSetup.apply(this, arguments);
if (!this.validations || superClass.validations === this.validations) {
this.validations = {};
}
},
validate: validate,
validationMessages: {
format: "is invalid",
inclusion: "is not a valid option (perhaps out of range)",
lengthShort: "is too short",
lengthLong: "is too long",
presence: "can't be empty",
range: "is out of range"
},
validateFormatOf: function (attrNames, regexp, options) {
validate.call(this, attrNames, options, function (value) {
if ((typeof value != 'undefined' && value != '') && String(value).match(regexp) == null) {
return this.constructor.validationMessages.format;
}
});
},
validateInclusionOf: function (attrNames, inArray, options) {
validate.call(this, attrNames, options, function (value) {
if (typeof value == 'undefined') {
return;
}
if (can.grep(inArray, function (elm) {
return (elm == value);
}).length == 0) {
return this.constructor.validationMessages.inclusion;
}
});
},
validateLengthOf: function (attrNames, min, max, options) {
validate.call(this, attrNames, options, function (value) {
if ((typeof value == 'undefined' && min > 0) || value.length < min) {
return this.constructor.validationMessages.lengthShort + " (min=" + min + ")";
} else if (typeof value != 'undefined' && value.length > max) {
return this.constructor.validationMessages.lengthLong + " (max=" + max + ")";
}
});
},
validatePresenceOf: function (attrNames, options) {
validate.call(this, attrNames, options, function (value) {
if (typeof value == 'undefined' || value === "" || value === null) {
return this.constructor.validationMessages.presence;
}
});
},
validateRangeOf: function (attrNames, low, hi, options) {
validate.call(this, attrNames, options, function (value) {
if (typeof value != 'undefined' && value < low || value > hi) {
return this.constructor.validationMessages.range + " [" + low + "," + hi + "]";
}
});
}
});
});
can.extend(can.Observe.prototype, {
errors: function (attrs, newVal) {
// convert attrs to an array
if (attrs) {
attrs = can.isArray(attrs) ? attrs : [attrs];
}
var errors = {},
self = this,
attr,
// helper function that adds error messages to errors object
// attr - the name of the attribute
// funcs - the validation functions
addErrors = function (attr, funcs) {
can.each(funcs, function (func) {
var res = func.call(self, isTest ? (self.__convert ? self.__convert(attr, newVal) : newVal) : self[attr]);
if (res) {
if (!errors[attr]) {
errors[attr] = [];
}
errors[attr].push(res);
}
});
},
validations = this.constructor.validations,
isTest = attrs && attrs.length === 1 && arguments.length === 2;
// go through each attribute or validation and
// add any errors
can.each(attrs || validations || {}, function (funcs, attr) {
// if we are iterating through an array, use funcs
// as the attr name
if (typeof attr == 'number') {
attr = funcs;
funcs = validations[attr];
}
// add errors to the
addErrors(attr, funcs || []);
});
// return errors as long as we have one
return can.isEmptyObject(errors) ? null : isTest ? errors[attrs[0]] : errors;
}
});
return can.Observe;
});
\ No newline at end of file
This diff is collapsed.
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/can'], 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) {
for (key in elements) {
if (elements.hasOwnProperty(key)) {
if (callback.call(context || elements[key], elements[key], key, elements) === false) {
break;
}
}
}
}
}
return elements;
};
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(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);
};
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/can'], function (can) {
// deferred.js
// ---------
// _Lightweight, jQuery style deferreds._
// extend is usually provided by the wrapper but to avoid steal.then calls
// we define a simple extend here as well
var extend = function (target, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) {
target[key] = src[key];
}
}
},
Deferred = function (func) {
if (!(this instanceof Deferred)) return new Deferred();
this._doneFuncs = [];
this._failFuncs = [];
this._resultArgs = null;
this._status = "";
// Check for option `function` -- call it with this as context and as first
// parameter, as specified in jQuery API.
func && func.call(this, this);
};
can.Deferred = Deferred;
can.when = Deferred.when = function () {
var args = can.makeArray(arguments);
if (args.length < 2) {
var obj = args[0];
if (obj && (can.isFunction(obj.isResolved) && can.isFunction(obj.isRejected))) {
return obj;
} else {
return Deferred().resolve(obj);
}
} else {
var df = Deferred(),
done = 0,
// Resolve params -- params of each resolve, we need to track them down
// to be able to pass them in the correct order if the master
// needs to be resolved.
rp = [];
can.each(args, function (arg, j) {
arg.done(function () {
rp[j] = (arguments.length < 2) ? arguments[0] : arguments;
if (++done == args.length) {
df.resolve.apply(df, rp);
}
}).fail(function () {
df.reject(arguments);
});
});
return df;
}
}
var resolveFunc = function (type, _status) {
return function (context) {
var args = this._resultArgs = (arguments.length > 1) ? arguments[1] : [];
return this.exec(context, this[type], args, _status);
}
},
doneFunc = function (type, _status) {
return function () {
var self = this;
// In Safari, the properties of the `arguments` object are not enumerable,
// so we have to convert arguments to an `Array` that allows `can.each` to loop over them.
can.each(Array.prototype.slice.call(arguments), function (v, i, args) {
if (!v) return;
if (v.constructor === Array) {
args.callee.apply(self, v)
} else {
// Immediately call the `function` if the deferred has been resolved.
if (self._status === _status) v.apply(self, self._resultArgs || []);
self[type].push(v);
}
});
return this;
}
};
extend(Deferred.prototype, {
pipe: function (done, fail) {
var d = can.Deferred();
this.done(function () {
d.resolve(done.apply(this, arguments));
});
this.fail(function () {
if (fail) {
d.reject(fail.apply(this, arguments));
} else {
d.reject.apply(d, arguments);
}
});
return d;
},
resolveWith: resolveFunc("_doneFuncs", "rs"),
rejectWith: resolveFunc("_failFuncs", "rj"),
done: doneFunc("_doneFuncs", "rs"),
fail: doneFunc("_failFuncs", "rj"),
always: function () {
var args = can.makeArray(arguments);
if (args.length && args[0]) this.done(args[0]).fail(args[0]);
return this;
},
then: function () {
var args = can.makeArray(arguments);
// Fail `function`(s)
if (args.length > 1 && args[1]) this.fail(args[1]);
// Done `function`(s)
if (args.length && args[0]) this.done(args[0]);
return this;
},
state: function () {
switch (this._status) {
case 'rs':
return 'resolved';
case 'rj':
return 'rejected';
default:
return 'pending';
}
},
isResolved: function () {
return this._status === "rs";
},
isRejected: function () {
return this._status === "rj";
},
reject: function () {
return this.rejectWith(this, arguments);
},
resolve: function () {
return this.resolveWith(this, arguments);
},
exec: function (context, dst, args, st) {
if (this._status !== "") return this;
this._status = st;
can.each(dst, function (d) {
d.apply(context, args);
});
return this;
}
});
return can;
});
\ No newline at end of file
This diff is collapsed.
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/can'], function (can) {
// event.js
// ---------
// _Basic event wrapper._
can.addEvent = function (event, fn) {
if (!this.__bindEvents) {
this.__bindEvents = {};
}
var eventName = event.split(".")[0];
if (!this.__bindEvents[eventName]) {
this.__bindEvents[eventName] = [];
}
this.__bindEvents[eventName].push({
handler: fn,
name: event
});
return this;
};
can.removeEvent = function (event, fn) {
if (!this.__bindEvents) {
return;
}
var i = 0,
events = this.__bindEvents[event.split(".")[0]],
ev;
while (i < events.length) {
ev = events[i]
if ((fn && ev.handler === fn) || (!fn && ev.name === event)) {
events.splice(i, 1);
} else {
i++;
}
}
return this;
};
can.dispatch = function (event) {
if (!this.__bindEvents) {
return;
}
var eventName = event.type.split(".")[0],
handlers = (this.__bindEvents[eventName] || []).slice(0),
self = this,
args = [event].concat(event.data || []);
can.each(handlers, function (ev) {
event.data = args.slice(1);
ev.handler.apply(self, args);
});
}
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/can'], function (can) {
// fragment.js
// ---------
// _DOM Fragment support._
var fragmentRE = /^\s*<(\w+)[^>]*>/,
fragment = function (html, name) {
if (name === undefined) {
name = fragmentRE.test(html) && RegExp.$1;
}
if (html && can.isFunction(html.replace)) {
// Fix "XHTML"-style tags in all browsers
html = html.replace(/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, "<$1></$2>");
}
var container = document.createElement('div'),
temp = document.createElement('div')
// IE's parser will strip any `<tr><td>` tags when `innerHTML`
// is called on a `tbody`. To get around this, we construct a
// valid table with a `tbody` that has the `innerHTML` we want.
// Then the container is the `firstChild` of the `tbody`.
// [source](http://www.ericvasilik.com/2006/07/code-karma.html).
if (name === "tbody" || name === "tfoot" || name === "thead") {
temp.innerHTML = "<table>" + html + "</table>";
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild;
} else if (name === "tr") {
temp.innerHTML = "<table><tbody>" + html + "</tbody></table>";
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild.firstChild;
} else if (name === "td" || name === "th") {
temp.innerHTML = "<table><tbody><tr>" + html + "</tr></tbody></table>";
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild.firstChild.firstChild;
} else if (name === 'option') {
temp.innerHTML = "<select>" + html + "</select>";
container = temp.firstChild.nodeType === 3 ? temp.lastChild : temp.firstChild;
} else {
container.innerHTML = '' + html;
}
// IE8 barfs if you pass slice a `childNodes` object, so make a copy.
var tmp = {},
children = container.childNodes;
tmp.length = children.length;
for (var i = 0; i < children.length; i++) {
tmp[i] = children[i];
}
return [].slice.call(tmp);
}
can.buildFragment = function (html, nodes) {
var parts = fragment(html),
frag = document.createDocumentFragment();
can.each(parts, function (part) {
frag.appendChild(part);
})
return frag;
};
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['jquery', 'can/util/can', 'can/util/array/each'], function ($, can) {
// _jQuery node list._
$.extend(can, $, {
trigger: function (obj, event, args) {
if (obj.trigger) {
obj.trigger(event, args);
} else {
$.event.trigger(event, args, obj, true);
}
},
addEvent: function (ev, cb) {
$([this]).bind(ev, cb);
return this;
},
removeEvent: function (ev, cb) {
$([this]).unbind(ev, cb);
return this;
},
// jquery caches fragments, we always needs a new one
buildFragment: function (result, element) {
var ret = $.buildFragment([result], $(element));
return ret.cacheable ? $.clone(ret.fragment) : ret.fragment;
},
$: $,
each: can.each
});
// Wrap binding functions.
$.each(['bind', 'unbind', 'undelegate', 'delegate'], function (i, func) {
can[func] = function () {
var t = this[func] ? this : $([this]);
t[func].apply(t, arguments);
return this;
};
});
// Wrap modifier functions.
$.each(["append", "filter", "addClass", "remove", "data", "get"], 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, "destroyed", [], false);
}
});
oldClean(elems);
};
return can;
});
\ No newline at end of file
/*
* CanJS - 1.1.3 (2012-12-11)
* http://canjs.us/
* Copyright (c) 2012 Bitovi
* Licensed MIT
*/
define(['can/util/jquery'], function (can) {
return can;
});
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?" autofocus>
</header>
<section id="main" class="<%= todos.attr("length") === 0 ? "hidden" : "" %>">
<input id="toggle-all" type="checkbox" <%= todos.allComplete() ? "checked" : "" %>>
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
<% can.each(todos.displayList(), function( todo ) { %>
<li class="todo <%= todo.attr('complete') ? 'completed' : '' %> <%= todo.attr('editing') ? 'editing' : '' %>"
<%= (el)-> el.data('todo', todo) %>>
<div class="view">
<input class="toggle" type="checkbox" <%= todo.attr('complete') ? 'checked' : '' %>>
<label><%= todo.attr('text') %></label>
<button class="destroy"></button>
</div>
<input class="edit" value="<%= todo.attr('text') %>">
</li>
<% }) %>
</ul>
</section>
<footer id="footer" class="<%= todos.attr('length') === 0 ? 'hidden' : '' %>">
<span id="todo-count">
<strong><%= todos.remaining() %></strong>
item<%= todos.remaining() == 1 ? "" : "s" %> left
</span>
<ul id="filters">
<li><a class="selected" href="#!">All</a></li>
<li><a href="#!active">Active</a></li>
<li><a href="#!completed">Completed</a></li>
</ul>
<button id="clear-completed" class="<%= todos.completed() === 0 ? 'hidden' : '' %>">
Clear <%= todos.completed() %>
completed item<%= todos.completed() == 1 ? "" : "s" %>
</button>
</footer>
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment