todomvc
Version:
> Helping you select an MV\* framework
1,529 lines (1,419 loc) • 411 kB
JavaScript
(function() {
//just a shim for cordova, because the actual dependency will differ between
//Android and iOS
define('cordova',[],function() {
return window.cordova;
});
define('lavaca/util/extend',[],function() {
/**
* Establishes inheritance between types. After a type is extended, it receives its own static
* convenience method, extend(TSub, overrides).
* @class lavaca.util.extend
*/
/**
* Establishes inheritance between types. After a type is extended, it receives its own static
* convenience method, extend(TSub, overrides).
* @method extend
* @static
*
*/
/**
* Establishes inheritance between types. After a type is extended, it receives its own static
* convenience method, extend(TSub, overrides).
* @method extend
* @static
* @param {Function} TSub The child type which will inherit from superType
* @param {Object} overrides A hash of key-value pairs that will be added to the subType
* @return {Function} The subtype
*
*/
/**
* Establishes inheritance between types. After a type is extended, it receives its own static
* convenience method, extend(TSub, overrides).
* @method extend
* @static
* @param {Function} TSuper The base type to extend
* @param {Function} TSub The child type which will inherit from superType
* @param {Object} overrides A hash of key-value pairs that will be added to the subType
* @return {Function} The subtype
*/
var extend = function(TSuper, TSub, overrides) {
if (typeof TSuper === 'object') {
overrides = TSuper;
TSuper = Object;
TSub = function() {
// Empty
};
} else if (typeof TSub === 'object') {
overrides = TSub;
TSub = TSuper;
TSuper = Object;
}
function ctor() {
// Empty
}
ctor.prototype = TSuper.prototype;
TSub.prototype = new ctor;
TSub.prototype.constructor = TSub;
if (overrides) {
for (var name in overrides) {
TSub.prototype[name] = overrides[name];
}
}
TSub.extend = function(T, overrides) {
if (typeof T === 'object') {
overrides = T;
T = function() {
TSub.apply(this, arguments);
};
}
extend(TSub, T, overrides);
return T;
};
return TSub;
};
return extend;
});
define('lavaca/util/Promise',['require','./extend'],function(require) {
var extend = require('./extend');
/**
* Utility type for asynchronous programming
* @class lavaca.util.Promise
*
* @constructor
*
* @param {Object} thisp What the "this" keyword resolves to in callbacks
*/
var Promise = extend(function(thisp) {
/**
* What the "this" keyword resolves to in callbacks
* @property {Object} thisp
* @default null
*/
this.thisp = thisp;
/**
* Pending handlers for the success event
* @property {Array} resolvedQueue
* @default []
*/
this.resolvedQueue = [];
/**
* Pending handlers for the error event
* @property {Array} rejectedQueue
* @default []
*/
this.rejectedQueue = [];
}, {
/**
* Flag indicating that the promise completed successfully
* @property {Boolean} succeeded
* @default false
*/
succeeded: false,
/**
* Flag indicating that the promise failed to complete
* @property {Boolean} failed
* @default false
*/
failed: false,
/**
* Queues a callback to be executed when the promise succeeds
* @method success
*
* @param {Function} callback The callback to execute
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
success: function(callback) {
if (callback) {
if (this.succeeded) {
callback.apply(this.thisp, this.resolveArgs);
} else {
this.resolvedQueue.push(callback);
}
}
return this;
},
/**
* Queues a callback to be executed when the promise fails
* @method error
*
* @param {Function} callback The callback to execute
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
error: function(callback) {
if (callback) {
if (this.failed) {
callback.apply(this.thisp, this.rejectArgs);
} else {
this.rejectedQueue.push(callback);
}
}
return this;
},
/**
* Queues a callback to be executed when the promise is either rejected or resolved
* @method always
*
* @param {Function} callback The callback to execute
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
always: function(callback) {
return this.then(callback, callback);
},
/**
* Queues up callbacks after the promise is completed
* @method then
*
* @param {Function} resolved A callback to execute when the operation succeeds
* @param {Function} rejected A callback to execute when the operation fails
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
then: function(resolved, rejected) {
return this
.success(resolved)
.error(rejected);
},
/**
* Resolves the promise successfully
* @method resolve
*
* @params {Object} value Values to pass to the queued success callbacks
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
resolve: function(/* value1, value2, valueN */) {
if (!this.succeeded && !this.failed) {
this.succeeded = true;
this.resolveArgs = [].slice.call(arguments, 0);
var i = -1,
callback;
while (!!(callback = this.resolvedQueue[++i])) {
callback.apply(this.thisp, this.resolveArgs);
}
}
return this;
},
/**
* Resolves the promise as a failure
* @method reject
*
* @params {String} err Failure messages
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
reject: function(/* err1, err2, errN */) {
if (!this.succeeded && !this.failed) {
this.failed = true;
this.rejectArgs = [].slice.call(arguments, 0);
var i = -1,
callback;
while (!!(callback = this.rejectedQueue[++i])) {
callback.apply(this.thisp, this.rejectArgs);
}
}
return this;
},
/**
* Queues this promise to be resolved only after several other promises
* have been successfully resolved, or immediately rejected when one
* of those promises is rejected
* @method when
*
* @params {Lavaca.util.Promise} promise One or more other promises
* @return {Lavaca.util.Promise} This promise (for chaining)
*/
when: function(/* promise1, promise2, promiseN */) {
var self = this,
values = [],
i = -1,
pendingPromiseCount = arguments.length,
promise;
while (!!(promise = arguments[++i])) {
(function(index) {
promise
.success(function(v) {
values[index] = v;
if (--pendingPromiseCount < 1) {
self.resolve.apply(self, values);
}
})
.error(function() {
self.reject.apply(self, arguments);
});
})(i);
}
promise = null;
return this;
},
/**
* Produces a callback that resolves the promise with any number of arguments
* @method resolver
* @return {Function} The callback
*/
resolver: function() {
var self = this;
return function() {
self.resolve.apply(self, arguments);
};
},
/**
* Produces a callback that rejects the promise with any number of arguments
* @method rejector
*
* @return {Function} The callback
*/
rejector: function() {
var self = this;
return function() {
self.reject.apply(self, arguments);
};
}
});
/**
*
* Creates a promise to be resolved only after several other promises
* have been successfully resolved, or immediately rejected when one
* of those promises is rejected
* @method when
* @static
* @params {Lavaca.util.Promise} promise One or more other promises
* @return {Lavaca.util.Promise} The new promise
*/
/**
* Creates a promise to be resolved only after several other promises
* have been successfully resolved, or immediately rejected when one
* of those promises is rejected
* @method when
* @static
* @param {Object} thisp The execution context of the promise
* @params {Lavaca.util.Promise} promise One or more other promises
* @return {Lavaca.util.Promise} The new promise
*/
Promise.when = function(thisp/*, promise1, promise2, promiseN */) {
var thispIsPromise = thisp instanceof Promise,
promise = new Promise(thispIsPromise ? window : thisp),
args = [].slice.call(arguments, thispIsPromise ? 0 : 1);
return promise.when.apply(promise, args);
};
return Promise;
});
define('lavaca/env/Device',['require','$','cordova','lavaca/util/Promise'],function(require) {
var $ = require('$'),
Cordova = require('cordova'),
Promise = require('lavaca/util/Promise');
/**
* Static utility type for working with Cordova (aka PhoneGap) and other non-standard native functionality
* @class lavaca.env.Device
*/
var _initHasRun = false,
_onInit = [];
var Device = {};
/**
* Indicates whether or not the app is being run through Cordova
* @method isCordova
* @static
*
* @return {Boolean} True if app is being run through Cordova
*/
Device.isCordova = function() {
return !!Cordova;
};
/**
* Registers a plugin to be initialized when the device is ready
* @method register
* @static
*
* @param {String} name
* @param {Function} TPlugin The plugin to register. The plugin should be a constructor function
*/
Device.register = function(name, TPlugin) {
function install() {
if (!window.plugins) {
window.plugins = {};
}
window.plugins[name] = new TPlugin();
}
if (_initHasRun) {
install();
} else {
_onInit.push(install);
}
};
/**
* Executes a Cordova command, if Cordova is available
* @method exec
* @static
*
* @param {String} className The name of the native class
* @param {String} methodName The name of the class method to call
* @param {Array} args Arguments to pass the method
* @return {Lavaca.util.Promise} A promise
*/
Device.exec = function(className, methodName, args) {
var promise = new Promise(window);
if (Cordova) {
Cordova.exec(promise.resolver(), promise.rejector(), className, methodName, args);
} else {
promise.reject();
}
return promise;
};
/**
* Executes a callback when the device is ready to be used
* @method init
* @static
*
* @param {Function} callback The handler to execute when the device is ready
*/
Device.init = function(callback) {
if (!Cordova) {
$(document).ready(callback);
}
else if (document.addEventListener) {
// Android fix
document.addEventListener('deviceready', callback, false);
} else {
$(document).on('deviceready', callback);
}
};
$(document).ready(function() {
var i = -1,
installPlugin;
while (!!(installPlugin = _onInit[++i])) {
installPlugin();
}
_initHasRun = true;
});
return Device;
});
define('lavaca/util/Disposable',['require','./extend'],function(require) {
var extend = require('./extend');
function _disposeOf(obj) {
var n,
o,
i;
for (n in obj) {
if (obj.hasOwnProperty(n)) {
o = obj[n];
if (o) {
if (typeof o === 'object' && typeof o.dispose === 'function') {
o.dispose();
} else if (o instanceof Array) {
for (i = o.length - 1; i > -1; i--) {
if (o[i] && typeof o[i].dispose === 'function') {
o[i].dispose();
} else {
_disposeOf(o[i]);
}
}
}
}
}
}
}
/**
* Abstract type for types that need to ready themselves for GC
* @class lavaca.util.Disposable
* @constructor
*
*/
var Disposable = extend({
/**
* Readies the object to be garbage collected
* @method dispose
*
*/
dispose: function() {
_disposeOf(this);
}
});
return Disposable;
});
define('mout/object/hasOwn',[],function () {
/**
* Safer Object.hasOwnProperty
*/
function hasOwn(obj, prop){
return Object.prototype.hasOwnProperty.call(obj, prop);
}
return hasOwn;
});
define('mout/object/forIn',[],function () {
var _hasDontEnumBug,
_dontEnums;
function checkDontEnum(){
_dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
];
_hasDontEnumBug = true;
for (var key in {'toString': null}) {
_hasDontEnumBug = false;
}
}
/**
* Similar to Array/forEach but works over object properties and fixes Don't
* Enum bug on IE.
* based on: http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
*/
function forIn(obj, fn, thisObj){
var key, i = 0;
// no need to check if argument is a real object that way we can use
// it for arrays, functions, date, etc.
//post-pone check till needed
if (_hasDontEnumBug == null) checkDontEnum();
for (key in obj) {
if (exec(fn, obj, key, thisObj) === false) {
break;
}
}
if (_hasDontEnumBug) {
while (key = _dontEnums[i++]) {
// since we aren't using hasOwn check we need to make sure the
// property was overwritten
if (obj[key] !== Object.prototype[key]) {
if (exec(fn, obj, key, thisObj) === false) {
break;
}
}
}
}
}
function exec(fn, obj, key, thisObj){
return fn.call(thisObj, obj[key], key, obj);
}
return forIn;
});
define('mout/object/forOwn',['./hasOwn', './forIn'], function (hasOwn, forIn) {
/**
* Similar to Array/forEach but works over object properties and fixes Don't
* Enum bug on IE.
* based on: http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
*/
function forOwn(obj, fn, thisObj){
forIn(obj, function(val, key){
if (hasOwn(obj, key)) {
return fn.call(thisObj, obj[key], key, obj);
}
});
}
return forOwn;
});
define('mout/lang/isPlainObject',[],function () {
/**
* Checks if the value is created by the `Object` constructor.
*/
function isPlainObject(value) {
return (!!value
&& typeof value === 'object'
&& value.constructor === Object);
}
return isPlainObject;
});
define('mout/object/deepMixIn',['./forOwn', '../lang/isPlainObject'], function (forOwn, isPlainObject) {
/**
* Mixes objects into the target object, recursively mixing existing child
* objects.
*/
function deepMixIn(target, objects) {
var i = 0,
n = arguments.length,
obj;
while(++i < n){
obj = arguments[i];
if (obj) {
forOwn(obj, copyProp, target);
}
}
return target;
}
function copyProp(val, key) {
var existing = this[key];
if (isPlainObject(val) && isPlainObject(existing)) {
deepMixIn(existing, val);
} else {
this[key] = val;
}
}
return deepMixIn;
});
define('lavaca/events/EventDispatcher',['require','lavaca/util/Disposable','mout/object/deepMixIn'],function(require) {
var Disposable = require('lavaca/util/Disposable'),
deepMixIn = require('mout/object/deepMixIn');
/**
* Basic event dispatcher type
* @class lavaca.events.EventDispatcher
* @extends lavaca.util.Disposable
* @constructor
*
*/
var EventDispatcher = Disposable.extend({
/**
* When true, do not fire events
* @property suppressEvents
* @type Boolean
* @default false
*
*/
suppressEvents: false,
/**
* Bind an event handler to this object
* @method on
*
* @param {String} type The name of the event
* @param {Function} callback The function to execute when the event occurs
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Bind an event handler to this object
* @method on
*
* @param {String} type The name of the event
* @param {Function} callback The function to execute when the event occurs
* @param {Object} thisp The context of the handler
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
on: function(type, callback, thisp) {
var calls = this.callbacks || (this.callbacks = {}),
list = calls[type] || (calls[type] = []);
list[list.length] = {fn: callback, thisp: thisp};
return this;
},
/**
* Unbinds all event handler from this object
* @method off
*
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Unbinds all event handlers for an event
* @method off
*
* @param {String} type The name of the event
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Unbinds a specific event handler
* @method off
*
* @param {String} type The name of the event
* @param {Function} callback The function handling the event
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Unbinds a specific event handler
* @method off
*
* @param {String} type The name of the event
* @param {Function} callback The function handling the event
* @param {Object} thisp The context of the handler
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
off: function(type, callback, thisp) {
var calls = this.callbacks,
list,
handler,
i = -1,
newList,
isCallback,
isThisp;
if (!type) {
delete this.callbacks;
} else if (calls) {
if (!callback) {
delete calls[type];
} else {
list = calls[type];
if (list) {
newList = calls[type] = [];
while (!!(handler = list[++i])) {
isCallback = handler.fn === callback ||
handler.fn.fn === callback ||
(handler.fn.guid && handler.fn.guid === callback.guid) || // Check if is jQuery proxy of callback
(handler.fn._zid && handler.fn._zid === callback._zid); // Check if is Zepto proxy of callback
isThisp = thisp && (handler.thisp === thisp || handler.fn.thisp === thisp);
if (!isCallback || (thisp && !isThisp)) {
newList[newList.length] = handler;
}
}
}
}
}
return this;
},
/**
* Dispatches an event
* @method trigger
*
* @param {String} type The type of event to dispatch
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Dispactches an event with additional parameters
* @method trigger
*
* @param {String} type The type of event to dispatch
* @param {Object} params Additional data points to add to the event
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
trigger: function(type, params) {
if (!this.suppressEvents && this.callbacks) {
var list = this.callbacks[type],
event = this.createEvent(type, params),
i = -1,
handler;
if (list) {
while (!!(handler = list[++i])) {
handler.fn.apply(handler.thisp || this, [event]);
}
}
}
return this;
},
/**
* Creates an event object
* @method createEvent
*
* @param {String} type The type of event to create
* @return {Object} The event object
*/
/**
* Creates an event object with additional params
* @method createEvent
*
* @param {String} type The type of event to create
* @param {Object} params Additional data points to add to the event
* @return {Object} The event object
*/
createEvent: function(type, params) {
return deepMixIn({}, params || {}, {
type: type,
target: params && params.target ? params.target : this,
currentTarget: this
});
}
});
return EventDispatcher;
});
define('lavaca/env/ChildBrowser',['require','lavaca/env/Device','lavaca/events/EventDispatcher','lavaca/util/Promise'],function(require) {
var Device = require('lavaca/env/Device'),
EventDispatcher = require('lavaca/events/EventDispatcher'),
Promise = require('lavaca/util/Promise');
/**
* A sub-browser management utility (also accessible via window.plugins.childBrowser)
* @class lavaca.env.ChildBrowser
* @extends Lavaca.events.EventDispatcher
*
* @event open
* @event close
* @event change
*
* @constructor
*/
var ChildBrowser = EventDispatcher.extend({
/**
* Opens a web page in the child browser (or navigates to it)
* @method showWebPage
*
* @param {String} loc The URL to open
* @return {Lavaca.util.Promise} A promise
*/
showWebPage: function(loc) {
if (Device.isCordova()) {
return Device
.exec('ChildBrowser', 'showWebPage', [loc])
.error(function() {
window.location.href = loc;
});
} else {
window.open(loc);
return new Promise(window).resolve();
}
},
/**
* Closes the child browser, if it's open
* @method close
*
* @return {Lavaca.util.Promise} A promise
*/
close: function() {
return Device.exec('ChildBrowser', 'close', []);
}
});
Device.register('childBrowser', ChildBrowser);
return ChildBrowser;
});
define('lavaca/env/Detection',['require','$'],function(require) {
var $ = require('$');
var Detection = {};
Detection.agent = navigator.userAgent.toLowerCase();
Detection.scrWidth = screen.width;
Detection.scrHeight = screen.height;
Detection.viewportWidth = window.innerWidth;
Detection.viewportHeight = window.innerHeight;
Detection.elemWidth = document.documentElement.clientWidth;
Detection.elemHeight = document.documentElement.clientHeight;
Detection.otherBrowser = (Detection.agent.search(/series60/i) > -1) || (Detection.agent.search(/symbian/i) > -1) || (Detection.agent.search(/windows\sce/i) > -1) || (Detection.agent.search(/blackberry/i) > -1);
Detection.mobileOS = typeof orientation !== 'undefined';
Detection.touchOS = 'ontouchstart' in document.documentElement;
Detection.blackberry = Detection.agent.search(/blackberry/i) > -1;
Detection.ipad = Detection.agent.search(/ipad/i) > -1;
Detection.ipod = Detection.agent.search(/ipod/i) > -1;
Detection.iphone = Detection.agent.search(/iphone/i) > -1;
Detection.palm = Detection.agent.search(/palm/i) > -1;
Detection.symbian = Detection.agent.search(/symbian/i) > -1;
Detection.iOS = Detection.iphone || Detection.ipod || Detection.ipad;
Detection.iOS5 = Detection.iOS && Detection.agent.search(/os 5_/i) > 0;
Detection.iOSChrome = Detection.iOS && Detection.agent.search(/CriOS/i) > 0;
Detection.android = (Detection.agent.search(/android/i) > -1) || (!Detection.iOS && !Detection.otherBrowser && Detection.touchOS && Detection.mobileOS);
Detection.android2 = Detection.android && (Detection.agent.search(/android\s2/i) > -1);
Detection.isMobile = Detection.android || Detection.iOS || Detection.mobileOS || Detection.touchOS;
Detection.android23AndBelow = (function() {
var matches = Detection.agent.match(/android\s(\d)\.(\d)/i);
var vi, vd;
if (Array.isArray(matches) && matches.length === 3) {
vi = parseInt(matches[1], 10);
vd = parseInt(matches[2], 10);
return (vi === 2 && vd < 3) || vi < 2;
}
return false;
}());
Detection.iOS4AndBelow = (function() {
var matches = Detection.agent.match(/os\s(\d)_/i);
var v;
if (Array.isArray(matches) && matches.length === 2) {
v = parseInt(matches[1], 10);
return v <= 4;
}
return false;
}());
Detection.addCustomDetection = function(condition, feature, selector) {
var el;
if (Detection.hasOwnProperty(feature)) {
throw Error('Namespace "' + feature + '" is already taken by Detection module');
}
Detection[feature] = condition;
if (selector !== null) {
el = selector ? $(selector) : $(document.documentElement);
el.toggleClass(feature, typeof condition === 'function' ? condition() : condition);
}
};
Detection.animationEnabled = !Detection.android;
return Detection;
});
define('lavaca/env/Device',['require','$','cordova','lavaca/util/Promise'],function(require) {
var $ = require('$'),
Cordova = require('cordova'),
Promise = require('lavaca/util/Promise');
/**
* Static utility type for working with Cordova (aka PhoneGap) and other non-standard native functionality
* @class lavaca.env.Device
*/
var _initHasRun = false,
_onInit = [];
var Device = {};
/**
* Indicates whether or not the app is being run through Cordova
* @method isCordova
* @static
*
* @return {Boolean} True if app is being run through Cordova
*/
Device.isCordova = function() {
return !!Cordova;
};
/**
* Registers a plugin to be initialized when the device is ready
* @method register
* @static
*
* @param {String} name
* @param {Function} TPlugin The plugin to register. The plugin should be a constructor function
*/
Device.register = function(name, TPlugin) {
function install() {
if (!window.plugins) {
window.plugins = {};
}
window.plugins[name] = new TPlugin();
}
if (_initHasRun) {
install();
} else {
_onInit.push(install);
}
};
/**
* Executes a Cordova command, if Cordova is available
* @method exec
* @static
*
* @param {String} className The name of the native class
* @param {String} methodName The name of the class method to call
* @param {Array} args Arguments to pass the method
* @return {Lavaca.util.Promise} A promise
*/
Device.exec = function(className, methodName, args) {
var promise = new Promise(window);
if (Cordova) {
Cordova.exec(promise.resolver(), promise.rejector(), className, methodName, args);
} else {
promise.reject();
}
return promise;
};
/**
* Executes a callback when the device is ready to be used
* @method init
* @static
*
* @param {Function} callback The handler to execute when the device is ready
*/
Device.init = function(callback) {
if (!Cordova) {
$(document).ready(callback);
}
else if (document.addEventListener) {
// Android fix
document.addEventListener('deviceready', callback, false);
} else {
$(document).on('deviceready', callback);
}
};
$(document).ready(function() {
var i = -1,
installPlugin;
while (!!(installPlugin = _onInit[++i])) {
installPlugin();
}
_initHasRun = true;
});
return Device;
});
define('lavaca/events/EventDispatcher',['require','lavaca/util/Disposable','mout/object/deepMixIn'],function(require) {
var Disposable = require('lavaca/util/Disposable'),
deepMixIn = require('mout/object/deepMixIn');
/**
* Basic event dispatcher type
* @class lavaca.events.EventDispatcher
* @extends lavaca.util.Disposable
* @constructor
*
*/
var EventDispatcher = Disposable.extend({
/**
* When true, do not fire events
* @property suppressEvents
* @type Boolean
* @default false
*
*/
suppressEvents: false,
/**
* Bind an event handler to this object
* @method on
*
* @param {String} type The name of the event
* @param {Function} callback The function to execute when the event occurs
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Bind an event handler to this object
* @method on
*
* @param {String} type The name of the event
* @param {Function} callback The function to execute when the event occurs
* @param {Object} thisp The context of the handler
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
on: function(type, callback, thisp) {
var calls = this.callbacks || (this.callbacks = {}),
list = calls[type] || (calls[type] = []);
list[list.length] = {fn: callback, thisp: thisp};
return this;
},
/**
* Unbinds all event handler from this object
* @method off
*
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Unbinds all event handlers for an event
* @method off
*
* @param {String} type The name of the event
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Unbinds a specific event handler
* @method off
*
* @param {String} type The name of the event
* @param {Function} callback The function handling the event
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Unbinds a specific event handler
* @method off
*
* @param {String} type The name of the event
* @param {Function} callback The function handling the event
* @param {Object} thisp The context of the handler
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
off: function(type, callback, thisp) {
var calls = this.callbacks,
list,
handler,
i = -1,
newList,
isCallback,
isThisp;
if (!type) {
delete this.callbacks;
} else if (calls) {
if (!callback) {
delete calls[type];
} else {
list = calls[type];
if (list) {
newList = calls[type] = [];
while (!!(handler = list[++i])) {
isCallback = handler.fn === callback ||
handler.fn.fn === callback ||
(handler.fn.guid && handler.fn.guid === callback.guid) || // Check if is jQuery proxy of callback
(handler.fn._zid && handler.fn._zid === callback._zid); // Check if is Zepto proxy of callback
isThisp = thisp && (handler.thisp === thisp || handler.fn.thisp === thisp);
if (!isCallback || (thisp && !isThisp)) {
newList[newList.length] = handler;
}
}
}
}
}
return this;
},
/**
* Dispatches an event
* @method trigger
*
* @param {String} type The type of event to dispatch
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
/**
* Dispactches an event with additional parameters
* @method trigger
*
* @param {String} type The type of event to dispatch
* @param {Object} params Additional data points to add to the event
* @return {Lavaca.events.EventDispatcher} This event dispatcher (for chaining)
*/
trigger: function(type, params) {
if (!this.suppressEvents && this.callbacks) {
var list = this.callbacks[type],
event = this.createEvent(type, params),
i = -1,
handler;
if (list) {
while (!!(handler = list[++i])) {
handler.fn.apply(handler.thisp || this, [event]);
}
}
}
return this;
},
/**
* Creates an event object
* @method createEvent
*
* @param {String} type The type of event to create
* @return {Object} The event object
*/
/**
* Creates an event object with additional params
* @method createEvent
*
* @param {String} type The type of event to create
* @param {Object} params Additional data points to add to the event
* @return {Object} The event object
*/
createEvent: function(type, params) {
return deepMixIn({}, params || {}, {
type: type,
target: params && params.target ? params.target : this,
currentTarget: this
});
}
});
return EventDispatcher;
});
define('lavaca/fx/Transform',['require','$'],function(require) {
var $ = require('$');
var _props = {
transform: 'transform',
webkitTransform: '-webkit-transform',
MozTransform: '-moz-transform',
OTransform: '-o-transform',
MSTransform: '-ms-transform'
},
_prop,
_cssProp,
_3d = false,
UNDEFINED;
var Transform = {};
(function() {
var style = document.createElement('div').style,
s;
for (s in _props) {
if (s in style) {
_prop = s;
_cssProp = _props[s];
style[s] = 'translate3d(0,0,0)';
_3d = style[s].indexOf('translate3d') > -1 && navigator.userAgent.indexOf('Android') === -1;
break;
}
}
})();
function _isUndefined(value) {
return value === UNDEFINED;
}
function _toOriginUnit(v) {
return typeof v === 'number' ? v * 100 + '%' : v;
}
function _scrubRotateValue(v) {
return typeof v === 'number' ? v + 'deg' : v;
}
function _scrubTranslateValue(v) {
return typeof v === 'number' ? v + 'px' : v;
}
function _scrubScaleValue(v) {
return typeof v === 'number' ? v + ',' + v : v;
}
function _scrubTransformValue(prop, value) {
var isRotate = prop.indexOf('rotate') === 0,
isScale = prop === 'scale',
isTranslate = prop.indexOf('translate') === 0,
//isAxisSpecific = /(X|Y|Z)$/.test(prop),
p,
css = [];
if (typeof value === 'object') {
for (p in value) {
css.push(prop
+ p.toUpperCase()
+ '('
+ (isTranslate
? _scrubTranslateValue(value[p])
: isRotate
? _scrubRotateValue(value[p])
: isScale
? _scrubScaleValue(value[p])
: value[p])
+ ')');
}
} else {
if (isScale) {
value = _scrubScaleValue(value);
} else if (isRotate) {
value = _scrubRotateValue(value);
} else if (isTranslate) {
value = _scrubTranslateValue(value);
}
css.push(prop + '(' + value + ')');
}
return css.join(' ');
}
/**
* Static utility type for working with CSS transforms
* @class lavaca.fx.Transform
*/
/**
* Whether or not transforms are supported by the browser
* @method isSupported
* @static
*
* @return {Boolean} True when transforms are supported
*/
Transform.isSupported = function() {
return !!_prop;
};
/**
* Whether or not 3D transforms are supported by the browser
* @method is3dSupported
* @static
*
* @return {Boolean} True when 3D transforms are supported
*/
Transform.is3dSupported = function() {
return _3d;
};
/**
* Converts a transform hash into a CSS string
* @method toCSS
* @static
*
* @param {Object} opts A hash of CSS transform values, with properties in
* the form {translateX: 1, translateY: 1} or {translate: {x: 1, y: 1}}
* @opt {Object} translate An object or string containing the translation values
* @opt {Object} translateX A string (in any unit) or number (in pixels) representing the X translation value
* @opt {Object} translateY A string (in any unit) or number (in pixels) representing the Y translation value
* @opt {Object} translateZ A string (in any unit) or number (in pixels) representing the Z translation value
* @opt {String} translate3d A string containing the 3D translation values
* @opt {Object} rotate An object, string, or number (in degrees) containing the rotation value(s)
* @opt {Object} rotateX A string (in any unit) or number (in degrees) representing the X rotation value
* @opt {Object} rotateY A string (in any unit) or number (in degrees) representing the Y rotation value
* @opt {Object} rotateZ A string (in any unit) or number (in degrees) representing the Z rotation value
* @opt {String} rotate3d A string containing the 3D rotation values
* @opt {Object} scale An object, string or number (in percentage points) containing the scale value(s)
* @opt {Object} scaleX A string (in any unit) or number (in percentage points) representing the X scale value
* @opt {Object} scaleY A string (in any unit) or number (in percentage points) representing the Y scale value
* @opt {Object} scaleZ A string (in any unit) or number (in percentage points) representing the Z scale value
* @opt {String} scale3d Astring containing the 3D scale values
* @opt {Object} skew An object or string containing the skew values
* @opt {Object} skewX A string (in any unit) or number (in pixels) representing the X skew value
* @opt {Object} skewY A string (in any unit) or number (in pixels) representing the Y skew value
* @opt {String} matrix A string containing the matrix transform values
* @opt {String} matrix3d A string containing the 3D matrix transform values
* @opt {String} perspective A string containing the perspective transform values
* @return {String} The generated CSS string
*/
Transform.toCSS = function(opts) {
var css = [],
prop;
if (typeof opts === 'object') {
for (prop in opts) {
css.push(_scrubTransformValue(prop, opts[prop]));
}
} else {
css.push(opts);
}
return css.join(' ');
};
/**
* Gets the name of the transform CSS property
* @method cssProperty
* @static
*
* @return {String} The name of the CSS property
*/
Transform.cssProperty = function() {
return _cssProp;
};
/**
* Transforms an element
* @method $.fn.transform
*
* @param {String} value The CSS transform string
* @return {jQuery} The jQuery object, for chaining
*/
/**
* Transforms an element
* @method $.fn.transform
*
* @param {Object} opt A hash of CSS transform values, with properties in
* the form {translateX: 1, translateY: 1} or {translate: {x: 1, y: 1}}
* @opt {Object} translate An object or string containing the translation values
* @opt {Object} translateX A string (in any unit) or number (in pixels) representing the X translation value
* @opt {Object} translateY A string (in any unit) or number (in pixels) representing the Y translation value
* @opt {Object} translateZ A string (in any unit) or number (in pixels) representing the Z translation value
* @opt {String} translate3d A string containing the 3D translation values
* @opt {Object} rotate An object, string, or number (in degrees) containing the rotation value(s)
* @opt {Object} rotateX A string (in any unit) or number (in degrees) representing the X rotation value
* @opt {Object} rotateY A string (in any unit) or number (in degrees) representing the Y rotation value
* @opt {Object} rotateZ A string (in any unit) or number (in degrees) representing the Z rotation value
* @opt {String} rotate3d A string containing the 3D rotation values
* @opt {Object} scale An object, string or number (in percentage points) containing the scale value(s)
* @opt {Object} scaleX A string (in any unit) or number (in percentage points) representing the X scale value
* @opt {Object} scaleY A string (in any unit) or number (in percentage points) representing the Y scale value
* @opt {Object} scaleZ A string (in any unit) or number (in percentage points) representing the Z scale value
* @opt {String} scale3d Astring containing the 3D scale values
* @opt {Object} skew An object or string containing the skew values
* @opt {Object} skewX A string (in any unit) or number (in pixels) representing the X skew value
* @opt {Object} skewY A string (in any unit) or number (in pixels) representing the Y skew value
* @opt {String} matrix A string containing the matrix transform values
* @opt {String} matrix3d A string containing the 3D matrix transform values
* @opt {String} perspective A string containing the perspective transform values
* @return {jQuery} The jQuery object, for chaining
*/
/**
* Transforms an element
* @method $.fn.transform
*
* @param {String} value The CSS transform string
* @param {String} origin The CSS transform origin
* @return {jQuery} The jQuery object, for chaining
*/
/**
* Transforms an element
* @method $.fn.transform
*
* @param {Object} opt A hash of CSS transform values, with properties in
* the form {translateX: 1, translateY: 1} or {translate: {x: 1, y: 1}}
* @opt {Object} translate An object or string containing the translation values
* @opt {Object} translateX A string (in any unit) or number (in pixels) representing the X translation value
* @opt {Object} translateY A string (in any unit) or number (in pixels) representing the Y translation value
* @opt {Object} translateZ A string (in any unit) or number (in pixels) representing the Z translation value
* @opt {String} translate3d A string containing the 3D translation values
* @opt {Object} rotate An object, string, or number (in degrees) containing the rotation value(s)
* @opt {Object} rotateX A string (in any unit) or number (in degrees) representing the X rotation value
* @opt {Object} rotateY A string (in any unit) or number (in degrees) representing the Y rotation value
* @opt {Object} rotateZ A string (in any unit) or number (in degrees) representing the Z rotation value
* @opt {String} rotate3d A string containing the 3D rotation values
* @opt {Object} scale An object, string or number (in percentage points) containing the scale value(s)
* @opt {Object} scaleX A string (in any unit) or number (in percentage points) representing the X scale value
* @opt {Object} scaleY A string (in any unit) or number (in percentage points) representing the Y scale value
* @opt {Object} scaleZ A string (in any unit) or number (in percentage points) representing the Z scale value
* @opt {String} scale3d Astring containing the 3D scale values
* @opt {Object} skew An object or string containing the skew values
* @opt {Object} skewX A string (in any unit) or number (in pixels) representing the X skew value
* @opt {Object} skewY A string (in any unit) or number (in pixels) representing the Y skew value
* @opt {String} matrix A string containing the matrix transform values
* @opt {String} matrix3d A string containing the 3D matrix transform values
* @opt {String} perspective A string containing the perspective transform values
* @param {String} origin The CSS transform origin
* @return {jQuery} The jQuery object, for chaining
*/
/**
* Transforms an element
* @method $.fn.transform
*
* @param {String} value The CSS transform string
* @param {Object} origin The CSS transform origin, in the form {x: N, y: N},
* where N is a decimal percentage between -1 and 1 or N is a pixel value > 1 or < -1.
* @return {jQuery} The jQuery object, for chaining
*/
/**
* Transforms an element
* @method $.fn.transform
*
* @param {Object} opt A hash of CSS transform values, with properties in
* the form {translateX: 1, translateY: 1} or {translate: {x: 1, y: 1}}
* @opt {Object} translate An object or string containing the translation values
* @opt {Object} translateX A string (in any unit) or number (in pixels) representing the X translation value
* @opt {Object} translateY A string (in any unit) or number (in pixels) representing the Y translation value
* @opt {Object} translateZ A string (in any unit) or number (in pixels) representing the Z translation value
* @opt {String} translate3d A string containing the 3D translation values
* @opt {Object} rotate An object, string, or number (in degrees) containing the rotation value(s)
* @opt {Object} rotateX A string (in any unit) or number (in degrees) representing the X rotation value
* @opt {Object} rotateY A string (in any unit) or number (in degrees) representing the Y rotation value
* @opt {Object} rotateZ A string (in any unit) or number (in degrees) representing the Z rotation value
* @opt {String} rotate3d A string containing the 3D rotation values
* @opt {Object} scale An object, string or number (in percentage points) containing the scale value(s)
* @opt {Object} scaleX A string (in any unit) or number (in percentage points) representing the X scale value
* @opt {Object} scaleY A string (in any unit) or number (in percentage points) representing the Y scale value
* @opt {Object} scaleZ A string (in any unit) or number (in percentage points) representing the Z scale value
* @opt {String} scale3d Astring containing the 3D scale values
* @opt {Object} skew An object or string containing the skew values
* @opt {Object} skewX A string (in any unit) or number (in pixels) representing the X skew value
* @opt {Object} skewY A string (in any unit) or number (in pixels) representing the Y skew value
* @opt {String} matrix A string containing the matrix transform values
* @opt {String} matrix3d A string containing the 3D matrix transform values
* @opt {String} perspective A string containing the perspective transform values
* @param {Object} origin The CSS transform origin, in the form {x: N, y: N},
* where N is a decimal percentage between -1 and 1 or N is a pixel value > 1 or < -1.
* @return {jQuery} The jQuery object, for chaining
*/
$.fn.transform = function(value, origin) {
if (Transform.isSupported()) {
value = Transform.toCSS(value);
if (origin) {
if (typeof origin === 'object') {
origin = _toOriginUnit(origin.x) + (_isUndefined(origin.y) ? '' : ' ' + _toOriginUnit(origin.y));
}
}
this.each(function() {
this.style[_prop] = value;
if (origin) {
this.style[_prop + 'Origin'] = origin;
}
});
}
return this;
};
return Transform;
});
define('lavaca/fx/Animation',['require','$','./Transform'],function(require) {
var $ = require('$'),
Transform = require('./Transform');
var Animation = {};
var _props = {
animation: ['animation', 'animationend', 'keyframes'],
webkitAnimation: ['-webkit-animation', 'webkitAnimationEnd', '-webkit-keyframes'],
MozAnimation: ['-moz-animation', 'animationend', '-moz-keyframes'],
OAnimation: ['-o-animation', 'oAnimationEnd', '-o-keyframes'],
MSAnimation: ['-ms-animation', 'MSAnimationEnd', '-ms-keyframes']
},
_prop,
_cssProp,
_declaration,
_event;
(function() {
var style = document.createElement('div').style,
s,
opts;
for (s in _props) {
if (s in style) {
opts = _props[s];
_prop = s;
_cssProp = opts[0];
_event = opts[1];
_declaration = opts[2];
break;
}
}
})();
/**
* Static utility type for working with CSS keyframe animations
* @class lavaca.fx.Animation
*/
/**
* Whether or not animations are supported by the browser
* @method isSupported
* @static
*
* @return {Boolean} True if CSS keyframe animations are supported
*/
Animation.isSupported = function() {
return !!_prop;
};
/**
* Converts a list of keyframes to a CSS animation
* @method keyframesToCSS
* @static
*
* @param {String} name The name of the keyframe animation
* @param {Object} keyframes A list of timestamped keyframes in the form {'0%': {color: 'red'}, '100%': 'color: blue'}
* @return {String} The CSS keyframe animation declaration
*/
Animation.keyframesToCSS = function(name, keyframes) {
var css = ['@', _declaration, ' ', name, '{'],
time,
keyframe,
prop,
value;
for (time in keyframes) {
css.push(time, '{');
keyframe = keyframes[time];
if (typeof keyframe === 'string') {
css.push(keyframe);
} else {
for (prop in keyframe) {
value = keyframe[prop];
if (prop === 'transform' && Transform) {
prop = Transform.cssProperty();
value = Transform.toCSS(value);
}
css.push(prop, ':', value, ';');
}
}
css.push('}');
}
css.push('}');
return css.join('');
};
/**
* Generates a keyframe animation
* @