todomvc
Version:
> Helping you select an MV\* framework
2,543 lines (1,998 loc) • 67.9 kB
JavaScript
// source /src/license.txt
/*!
* ClassJS v1.0.67
* Part of the Atma.js Project
* http://atmajs.com/
*
* MIT license
* http://opensource.org/licenses/MIT
*
* (c) 2012, 2014 Atma.js and other contributors
*/
// end:source /src/license.txt
// source /src/umd.js
(function(root, factory){
"use strict";
var _global = typeof window === 'undefined' || window.navigator == null
? global
: window
,
_exports
;
_exports = root || _global;
function construct(){
return factory(_global, _exports);
};
if (typeof define === 'function' && define.amd) {
return define(construct);
}
// Browser OR Node
construct();
if (typeof module !== 'undefined')
module.exports = _exports.Class;
}(this, function(global, exports){
"use strict";
// end:source /src/umd.js
// source /src/vars.js
var _Array_slice = Array.prototype.slice,
_Array_sort = Array.prototype.sort,
_cfg = {
ModelHost: null, // @default: Class.Model
};
var str_CLASS_IDENTITY = '__$class__';
// end:source /src/vars.js
// source /src/util/is.js
var is_Function,
is_Object,
is_Array,
is_ArrayLike,
is_String,
is_Date,
is_notEmptyString,
is_rawObject,
is_NullOrGlobal;
(function(){
is_Function = function(x) {
return typeof x === 'function';
};
is_Object = function(x) {
return x != null
&& typeof x === 'object';
};
is_Date = function(x){
return x != null
&& x.constructor.name === 'Date'
&& x instanceof Date;
};
is_Array = function(x) {
return x != null
&& typeof x.length === 'number'
&& typeof x.slice === 'function';
};
is_ArrayLike = is_Array;
is_String = function(x) {
return typeof x === 'string';
};
is_notEmptyString = function(x) {
return typeof x === 'string'
&& x !== '';
};
is_rawObject = function(obj) {
if (obj == null)
return false;
if (typeof obj !== 'object')
return false;
return obj.constructor === Object;
};
is_NullOrGlobal = function(ctx){
return ctx === void 0 || ctx === global;
};
}());
// end:source /src/util/is.js
// source /src/util/array.js
var arr_each,
arr_isArray,
arr_remove
;
(function(){
arr_each = function(array, callback) {
if (arr_isArray(array)) {
for (var i = 0, imax = array.length; i < imax; i++){
callback(array[i], i);
}
return;
}
callback(array);
};
arr_isArray = function(array) {
return array != null
&& typeof array === 'object'
&& typeof array.length === 'number'
&& typeof array.splice === 'function';
};
arr_remove = function(array, fn){
var imax = array.length,
i = -1;
while ( ++i < imax){
if (fn(array[i]) === true) {
array.splice(i, 1);
i--;
imax--;
}
}
};
/* polyfill */
if (typeof Array.isArray !== 'function') {
Array.isArray = function(array){
if (array instanceof Array){
return true;
}
if (array == null || typeof array !== 'object') {
return false;
}
return array.length !== void 0 && typeof array.slice === 'function';
};
}
}());
// end:source /src/util/array.js
// source /src/util/class.js
var class_register,
class_get,
class_patch,
class_stringify,
class_parse,
class_properties
;
(function(){
class_register = function(namespace, class_){
obj_setProperty(
_cfg.ModelHost || Class.Model,
namespace,
class_
);
};
class_get = function(namespace){
return obj_getProperty(
_cfg.ModelHost || Class.Model,
namespace
);
};
class_patch = function(mix, Proto){
var class_ = is_String(mix)
? class_get(mix)
: mix
;
// if DEBUG
!is_Function(class_)
&& console.error('<class:patch> Not a Function', mix);
// endif
Proto.Base = class_;
class_ = Class(Proto);
if (is_String(mix))
class_register(mix, class_);
return class_;
};
class_stringify = function(class_){
return JSON.stringify(class_, stringify);
};
class_parse = function(str){
return JSON.parse(str, parse);
};
class_properties = function(Ctor) {
return getProperties(Ctor);
};
// private
function stringify(key, val) {
if (val == null || typeof val !== 'object')
return val;
var current = this,
obj = current[key]
;
if (obj[str_CLASS_IDENTITY] && obj.toJSON) {
return stringifyMetaJSON(obj[str_CLASS_IDENTITY], val)
////val[str_CLASS_IDENTITY] = obj[str_CLASS_IDENTITY];
////return val;
}
return val;
}
function stringifyMetaJSON(className, json){
var out = {};
out['json'] = json;
out[str_CLASS_IDENTITY] = className;
return out;
}
function parse(key, val) {
var Ctor;
if (val != null && typeof val === 'object' && val[str_CLASS_IDENTITY]) {
Ctor = Class(val[str_CLASS_IDENTITY]);
if (typeof Ctor === 'function') {
val = new Ctor(val.json);
} else {
console.error('<class:parse> Class was not registered', val[str_CLASS_IDENTITY]);
}
}
return val;
}
function getProperties(proto, out){
if (typeof proto === 'function')
proto = proto.prototype;
if (out == null)
out = {};
var type,
key,
val;
for(key in proto){
val = proto[key];
type = val == null
? null
: typeof val
;
if (type === 'function')
continue;
var c = key.charCodeAt(0);
if (c === 95 && key !== '_id')
// _
continue;
if (c >= 65 && c <= 90)
// A-Z
continue;
if (type === 'object') {
var ctor = val.constructor,
ctor_name = ctor && ctor.name
;
if (ctor_name !== 'Object' && ctor_name && global[ctor_name] === ctor) {
// built-in objects
out[key] = ctor_name;
continue;
}
out[key] = getProperties(val);
continue;
}
out[key] = type;
}
if (proto.__proto__)
getProperties(proto.__proto__, out);
return out;
}
}());
// end:source /src/util/class.js
// source /src/util/proto.js
var class_inherit,
class_inheritStatics,
class_extendProtoObjects
;
(function(){
var PROTO = '__proto__';
var _toString = Object.prototype.toString,
_isArguments = function(args){
return _toString.call(args) === '[object Arguments]';
};
class_inherit = PROTO in Object.prototype
? inherit
: inherit_protoLess
;
class_inheritStatics = function(_class, mix){
if (mix == null)
return;
if (is_ArrayLike(mix)) {
var i = mix.length;
while ( --i > -1 ) {
class_inheritStatics(_class, mix[i]);
}
return;
}
var Static;
if (is_Function(mix))
Static = mix;
else if (is_Object(mix.Static))
Static = mix.Static;
if (Static == null)
return;
obj_extendDescriptorsDefaults(_class, Static);
};
class_extendProtoObjects = function(proto, _base, _extends){
var key,
protoValue;
for (key in proto) {
protoValue = proto[key];
if (!is_rawObject(protoValue))
continue;
if (_base != null){
if (is_rawObject(_base.prototype[key]))
obj_defaults(protoValue, _base.prototype[key]);
}
if (_extends != null) {
arr_each(_extends, function(x){
x = proto_getProto(x);
if (is_rawObject(x[key]))
obj_defaults(protoValue, x[key]);
});
}
}
}
// PRIVATE
function proto_extend(proto, source) {
if (source == null)
return;
if (typeof proto === 'function')
proto = proto.prototype;
if (typeof source === 'function')
source = source.prototype;
var key, val;
for (key in source) {
val = source[key];
if (val != null)
proto[key] = val;
}
}
function proto_override(super_, fn) {
var proxy;
if (super_) {
proxy = function(mix){
var args = arguments.length === 1 && _isArguments(mix)
? mix
: arguments
;
return fn_apply(super_, this, args);
}
} else{
proxy = fn_doNothing;
}
return function(){
this['super'] = proxy;
return fn_apply(fn, this, arguments);
};
}
function inherit(_class, _base, _extends, original, _overrides, defaults) {
var prototype = original,
proto = original;
prototype.constructor = _class.prototype.constructor;
if (_extends != null) {
proto[PROTO] = {};
arr_each(_extends, function(x) {
proto_extend(proto[PROTO], x);
});
proto = proto[PROTO];
}
if (_base != null)
proto[PROTO] = _base.prototype;
for (var key in defaults) {
if (prototype[key] == null)
prototype[key] = defaults[key];
}
for (var key in _overrides) {
prototype[key] = proto_override(prototype[key], _overrides[key]);
}
_class.prototype = prototype;
}
// browser that doesnt support __proto__
function inherit_protoLess(_class, _base, _extends, original, _overrides, defaults) {
if (_base != null) {
var tmp = function() {};
tmp.prototype = _base.prototype;
_class.prototype = new tmp();
_class.prototype.constructor = _class;
}
if (_extends != null) {
arr_each(_extends, function(x) {
delete x.constructor;
proto_extend(_class, x);
});
}
var prototype = _class.prototype;
obj_defaults(prototype, defaults);
for (var key in _overrides) {
prototype[key] = proto_override(prototype[key], _overrides[key]);
}
proto_extend(_class, original);
}
function proto_getProto(mix) {
return is_Function(mix)
? mix.prototype
: mix
;
}
}());
// end:source /src/util/proto.js
// source /src/util/json.js
// Create from Complex Class Instance a lightweight json object
var json_key_SER = '__$serialization',
json_proto_toJSON,
json_proto_arrayToJSON
;
(function(){
json_proto_toJSON = function(serialization){
var object = this,
json = {},
key, val, s;
if (serialization == null)
serialization = object[json_key_SER];
var asKey;
for(key in object){
asKey = key;
if (serialization != null && serialization.hasOwnProperty(key)) {
s = serialization[key];
if (s != null && typeof s === 'object') {
if (s.key)
asKey = s.key;
if (s.hasOwnProperty('serialize')) {
if (s.serialize == null)
continue;
json[asKey] = s.serialize(object[key]);
continue;
}
}
}
// _ (private)
if (key.charCodeAt(0) === 95)
continue;
if ('Static' === key || 'Validate' === key)
continue;
val = object[key];
if (val == null)
continue;
if ('_id' === key) {
json[asKey] = val;
continue;
}
switch (typeof val) {
case 'function':
continue;
case 'object':
if (is_Date(val))
break;
var toJSON = val.toJSON;
if (toJSON == null)
break;
json[asKey] = val.toJSON();
continue;
//@removed - serialize any if toJSON is implemented
//if (toJSON === json_proto_toJSON || toJSON === json_proto_arrayToJSON) {
// json[asKey] = val.toJSON();
// continue;
//}
break;
}
json[asKey] = val;
}
// make mongodb's _id property not private
if (object._id != null)
json._id = object._id;
return json;
};
json_proto_arrayToJSON = function() {
var array = this,
imax = array.length,
i = 0,
output = new Array(imax),
x;
for (; i < imax; i++) {
x = array[i];
if (x != null && typeof x === 'object') {
var toJSON = x.toJSON;
if (toJSON === json_proto_toJSON || toJSON === json_proto_arrayToJSON) {
output[i] = x.toJSON();
continue;
}
if (toJSON == null) {
output[i] = json_proto_toJSON.call(x);
continue;
}
}
output[i] = x;
}
return output;
};
}());
// end:source /src/util/json.js
// source /src/util/object.js
var obj_inherit,
obj_getProperty,
obj_setProperty,
obj_defaults,
obj_extend,
obj_extendDescriptors,
obj_extendDescriptorsDefaults,
obj_validate
;
(function(){
obj_inherit = function(target /* source, ..*/ ) {
if (is_Function(target))
target = target.prototype;
var i = 1,
imax = arguments.length,
source, key;
for (; i < imax; i++) {
source = is_Function(arguments[i])
? arguments[i].prototype
: arguments[i]
;
for (key in source) {
if ('Static' === key) {
if (target.Static != null) {
for (key in source.Static) {
target.Static[key] = source.Static[key];
}
continue;
}
}
target[key] = source[key];
}
}
return target;
};
obj_getProperty = function(obj, property) {
var chain = property.split('.'),
imax = chain.length,
i = -1;
while ( ++i < imax ) {
if (obj == null)
return null;
obj = obj[chain[i]];
}
return obj;
};
obj_setProperty = function(obj, property, value) {
var chain = property.split('.'),
imax = chain.length,
i = -1,
key;
while ( ++i < imax - 1) {
key = chain[i];
if (obj[key] == null)
obj[key] = {};
obj = obj[key];
}
obj[chain[i]] = value;
};
obj_defaults = function(target, defaults) {
for (var key in defaults) {
if (target[key] == null)
target[key] = defaults[key];
}
return target;
};
obj_extend = function(target, source) {
if (target == null)
target = {};
if (source == null)
return target;
var val,
key;
for(key in source) {
val = source[key];
if (val != null)
target[key] = val;
}
return target;
};
(function(){
var getDescr = Object.getOwnPropertyDescriptor,
define = Object.defineProperty;
if (getDescr == null) {
obj_extendDescriptors = obj_extend;
obj_extendDescriptorsDefaults = obj_defaults;
return;
}
obj_extendDescriptors = function(target, source){
return _extendDescriptors(target, source, false);
};
obj_extendDescriptorsDefaults = function(target, source){
return _extendDescriptors(target, source, true);
};
function _extendDescriptors (target, source, defaultsOnly) {
if (target == null)
return {};
if (source == null)
return source;
var descr,
key;
for(key in source){
if (defaultsOnly === true && target[key] != null)
continue;
descr = getDescr(source, key);
if (descr == null) {
obj_extendDescriptors(target, source['__proto__']);
continue;
}
if (descr.value !== void 0) {
target[key] = descr.value;
continue;
}
define(target, key, descr);
}
return target;
};
}());
(function(){
obj_validate = function(a /*, b , ?isStrict, ?property, ... */) {
if (a == null)
return Err_Invalid('object');
_props = null;
_strict = false;
var i = arguments.length,
validator, x;
while (--i > 0) {
x = arguments[i];
switch(typeof x){
case 'string':
if (_props == null)
_props = {};
_props[x] = 1;
continue;
case 'boolean':
_strict = x;
continue;
case 'undefined':
continue;
default:
if (i !== 1) {
return Err_Invalid('validation argument at ' + i)
}
validator = x;
continue;
}
}
if (validator == null)
validator = a.Validate;
if (validator == null)
// if no validation object - accept any.
return null;
return checkObject(a, validator, a);
};
// private
// unexpect in `a` if not in `b`
var _strict = false,
// validate only specified properties
_props = null;
// a** - payload
// b** - expect
// strict -
function checkObject(a, b, ctx) {
var error,
optional,
key, aVal, aKey;
for(key in b){
if (_props != null && a === ctx && _props.hasOwnProperty(key) === false) {
continue;
}
switch(key.charCodeAt(0)) {
case 63:
// ? (optional)
aKey = key.substring(1);
aVal = a[aKey];
//! accept falsy value
if (!aVal)
continue;
error = checkProperty(aVal, b[key], ctx);
if (error != null) {
error.setInvalidProperty(aKey);
return error;
}
continue;
case 45:
// - (unexpect)
aKey = key.substring(1);
if (typeof a === 'object' && aKey in a)
return Err_Unexpect(aKey);
continue;
}
aVal = a[key];
if (aVal == null)
return Err_Expect(key);
error = checkProperty(aVal, b[key], ctx);
if (error != null) {
error.setInvalidProperty(key);
return error;
}
}
if (_strict) {
for(key in a){
if (key in b || '?' + key in b)
continue;
return Err_Unexpect(key);
}
}
}
function checkProperty(aVal, bVal, ctx) {
if (bVal == null)
return null;
if (typeof bVal === 'function') {
var error = bVal.call(ctx, aVal);
if (error == null || error === true)
return null;
if (error === false)
return Err_Invalid();
return Err_Custom(error);
}
if (aVal == null)
return Err_Expect();
if (typeof bVal === 'string') {
var str = 'string',
num = 'number',
bool = 'boolean'
;
switch(bVal) {
case str:
return typeof aVal !== str || aVal.length === 0
? Err_Type(str)
: null;
case num:
return typeof aVal !== num
? Err_Type(num)
: null;
case bool:
return typeof aVal !== bool
? Err_Type(bool)
: null;
}
}
if (bVal instanceof RegExp) {
return bVal.test(aVal) === false
? Err_Invalid()
: null;
}
if (Array.isArray(bVal)) {
if (Array.isArray(aVal) === false)
return Err_Type('array');
var i = -1,
imax = aVal.length,
error;
while ( ++i < imax ){
error = checkObject(aVal[i], bVal[0])
if (error) {
error.setInvalidProperty(i);
return error;
}
}
return null;
}
if (typeof aVal !== typeof bVal)
return Err_Type(typeof aVal);
if (typeof aVal === 'object')
return checkObject(aVal, bVal);
return null;
}
var Err_Type,
Err_Expect,
Err_Unexpect,
Err_Custom,
Err_Invalid
;
(function(){
Err_Type = create('type',
function TypeErr(expect) {
this.expect = expect;
},
{
toString: function(){
return 'Invalid type.'
+ (this.expect
? ' Expect: ' + this.expect
: '')
+ (this.property
? ' Property: ' + this.property
: '')
;
}
}
);
Err_Expect = create('expect',
function ExpectErr(property) {
this.property = property;
},
{
toString: function(){
return 'Property expected.'
+ (this.property
? '`' + this.property + '`'
: '')
;
}
}
);
Err_Unexpect = create('unexpect',
function UnexpectErr(property) {
this.property = property;
},
{
toString: function(){
return 'Unexpected property'
+ (this.property
? '`' + this.property + '`'
: '')
;
}
}
);
Err_Custom = create('custom',
function CustomErr(error) {
this.error = error
},
{
toString: function(){
return 'Custom validation: '
+ this.error
+ (this.property
? ' Property: ' + this.property
: '')
;
}
}
);
Err_Invalid = create('invalid',
function InvalidErr(expect) {
this.expect = expect
}, {
toString: function(){
return 'Invalid.'
+ (this.expect
? ' Expect: ' + this.expect
: '')
+ (this.property
? ' Property: ' + this.property
: '')
;
}
}
);
function create(type, Ctor, proto) {
proto.type = type;
proto.property = null;
proto.setInvalidProperty = setInvalidProperty;
Ctor.prototype = proto;
return function(mix){
return new Ctor(mix);
}
}
function setInvalidProperty(prop){
if (this.property == null) {
this.property = prop;
return;
}
this.property = prop + '.' + this.property;
}
}()); /*< Errors */
}());
}());
// end:source /src/util/object.js
// source /src/util/patchObject.js
var obj_patch,
obj_patchValidate;
(function(){
obj_patch = function(obj, patch){
for(var key in patch){
var patcher = patches[key];
if (patcher)
patcher[fn_WALKER](obj, patch[key], patcher[fn_MODIFIER]);
else
console.error('Unknown or not implemented patcher', key);
}
return obj;
};
obj_patchValidate = function(patch){
if (patch == null)
return 'Undefined';
var has = false;
for(var key in patch){
has = true;
if (patches[key] == null)
return 'Unsupported patcher: ' + key;
}
if (has === false)
return 'No data';
return null;
};
// === private
function walk_mutator(obj, data, fn) {
for (var key in data)
fn(obj_getProperty(obj, key), data[key], key);
}
function walk_modifier(obj, data, fn){
for(var key in data)
obj_setProperty(
obj,
key,
fn(obj_getProperty(obj, key), data[key], key)
);
}
function fn_IoC(){
var fns = arguments;
return function(val, mix, prop){
for (var i = 0, fn, imax = fns.length; i < imax; i++){
fn = fns[i];
if (fn(val, mix, prop) === false)
return;
}
}
}
function arr_checkArray(val, mix, prop) {
if (arr_isArray(val) === false) {
// if DEBUG
console.warn('<patch> property is not an array', prop);
// endif
return false;
}
}
function arr_push(val, mix, prop){
if (mix.hasOwnProperty('$each')) {
for (var i = 0, imax = mix.$each.length; i < imax; i++){
val.push(mix.$each[i]);
}
return;
}
val.push(mix);
}
function arr_pop(val, mix, prop){
val[mix > 0 ? 'pop' : 'shift']();
}
function arr_pull(val, mix, prop) {
arr_remove(val, function(item){
return query_match(item, mix);
});
}
function val_inc(val, mix, key){
return val + mix;
}
function val_set(val, mix, key){
return mix;
}
function val_unset(){
return void 0;
}
function val_bit(val, mix){
if (mix.or)
return val | mix.or;
if (mix.and)
return val & mix.and;
return val;
}
var query_match;
(function(){
/** @TODO improve object matcher */
query_match = function(obj, mix){
for (var key in mix) {
if (obj[key] !== mix[key])
return false;
}
return true;
};
}());
var fn_WALKER = 0,
fn_MODIFIER = 1
;
var patches = {
'$push': [walk_mutator, fn_IoC(arr_checkArray, arr_push)],
'$pop': [walk_mutator, fn_IoC(arr_checkArray, arr_pop)],
'$pull': [walk_mutator, fn_IoC(arr_checkArray, arr_pull)],
'$inc': [walk_modifier, val_inc],
'$set': [walk_modifier, val_set],
'$unset': [walk_modifier, val_unset],
'$bit': [walk_modifier, val_unset],
};
}());
// end:source /src/util/patchObject.js
// source /src/util/function.js
var fn_proxy,
fn_apply,
fn_createDelegate,
fn_doNothing,
fn_argsId
;
(function(){
fn_proxy = function(fn, ctx) {
return function() {
return fn_apply(fn, ctx, arguments);
};
};
fn_apply = function(fn, ctx, _arguments){
switch (_arguments.length) {
case 0:
return fn.call(ctx);
case 1:
return fn.call(ctx, _arguments[0]);
case 2:
return fn.call(ctx,
_arguments[0],
_arguments[1]);
case 3:
return fn.call(ctx,
_arguments[0],
_arguments[1],
_arguments[2]);
case 4:
return fn.call(ctx,
_arguments[0],
_arguments[1],
_arguments[2],
_arguments[3]);
case 5:
return fn.call(ctx,
_arguments[0],
_arguments[1],
_arguments[2],
_arguments[3],
_arguments[4]
);
};
return fn.apply(ctx, _arguments);
};
fn_createDelegate = function(fn /* args */) {
var args = _Array_slice.call(arguments, 1);
return function(){
if (arguments.length > 0)
args = args.concat(_Array_slice.call(arguments));
return fn_apply(fn, null, args);
};
};
fn_doNothing = function(){};
fn_argsId = function(args, cache){
if (args.length === 0)
return 0;
var imax = cache.length,
i = -1;
while( ++i < imax ){
if (args_match(cache[i], args))
return i + 1;
}
cache.push(args);
return cache.length;
};
// === private
function args_match(a, b){
if (a.length !== b.length)
return false;
var imax = a.length,
i = 0;
for (; i < imax; i++){
if (a[i] !== b[i])
return false;
}
return true;
}
}());
// end:source /src/util/function.js
// source /src/xhr/XHR.js
var XHR = {};
(function(){
// source promise.js
/*
* Copyright 2012-2013 (c) Pierre Duquesne <stackp@online.fr>
* Licensed under the New BSD License.
* https://github.com/stackp/promisejs
*/
(function(exports) {
var ct_URL_ENCODED = 'application/x-www-form-urlencoded',
ct_JSON = 'application/json';
var e_NO_XHR = 1,
e_TIMEOUT = 2,
e_PRAPAIR_DATA = 3;
function Promise() {
this._callbacks = [];
}
Promise.prototype.then = function(func, context) {
var p;
if (this._isdone) {
p = func.apply(context, this.result);
} else {
p = new Promise();
this._callbacks.push(function () {
var res = func.apply(context, arguments);
if (res && typeof res.then === 'function')
res.then(p.done, p);
});
}
return p;
};
Promise.prototype.done = function() {
this.result = arguments;
this._isdone = true;
for (var i = 0; i < this._callbacks.length; i++) {
this._callbacks[i].apply(null, arguments);
}
this._callbacks = [];
};
function join(promises) {
var p = new Promise();
var results = [];
if (!promises || !promises.length) {
p.done(results);
return p;
}
var numdone = 0;
var total = promises.length;
function notifier(i) {
return function() {
numdone += 1;
results[i] = Array.prototype.slice.call(arguments);
if (numdone === total) {
p.done(results);
}
};
}
for (var i = 0; i < total; i++) {
promises[i].then(notifier(i));
}
return p;
}
function chain(funcs, args) {
var p = new Promise();
if (funcs.length === 0) {
p.done.apply(p, args);
} else {
funcs[0].apply(null, args).then(function() {
funcs.splice(0, 1);
chain(funcs, arguments).then(function() {
p.done.apply(p, arguments);
});
});
}
return p;
}
/*
* AJAX requests
*/
function _encode(data) {
var result = "";
if (typeof data === "string") {
result = data;
} else {
var e = encodeURIComponent;
for (var k in data) {
if (data.hasOwnProperty(k)) {
result += '&' + e(k) + '=' + e(data[k]);
}
}
}
return result;
}
function new_xhr() {
var xhr;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else if (window.ActiveXObject) {
try {
xhr = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}
}
return xhr;
}
function ajax(method, url, data, headers) {
var p = new Promise(),
contentType = headers && headers['Content-Type'] || promise.contentType;
var xhr,
payload;
try {
xhr = new_xhr();
} catch (e) {
p.done(e_NO_XHR, "");
return p;
}
if (data) {
if ('GET' === method) {
url += '?' + _encode(data);
data = null;
} else {
switch (contentType) {
case ct_URL_ENCODED:
data = _encode(data);
break;
case ct_JSON:
try {
data = JSON.stringify(data);
} catch(error){
p.done(e_PRAPAIR_DATA, '');
return p;
}
default:
// @TODO notify not supported content type
// -> fallback to url encode
data = _encode(data);
break;
}
}
}
xhr.open(method, url);
if (data)
xhr.setRequestHeader('Content-Type', contentType);
for (var h in headers) {
if (headers.hasOwnProperty(h)) {
xhr.setRequestHeader(h, headers[h]);
}
}
function onTimeout() {
xhr.abort();
p.done(e_TIMEOUT, "", xhr);
}
var timeout = promise.ajaxTimeout;
if (timeout) {
var tid = setTimeout(onTimeout, timeout);
}
xhr.onreadystatechange = function() {
if (timeout) {
clearTimeout(tid);
}
if (xhr.readyState === 4) {
var err = (!xhr.status ||
(xhr.status < 200 || xhr.status >= 300) &&
xhr.status !== 304);
p.done(err, xhr.responseText, xhr);
}
};
xhr.send(data);
return p;
}
function _ajaxer(method) {
return function(url, data, headers) {
return ajax(method, url, data, headers);
};
}
var promise = {
Promise: Promise,
join: join,
chain: chain,
ajax: ajax,
get: _ajaxer('GET'),
post: _ajaxer('POST'),
put: _ajaxer('PUT'),
del: _ajaxer('DELETE'),
patch: _ajaxer('PATCH'),
/* Error codes */
ENOXHR: e_NO_XHR,
ETIMEOUT: e_TIMEOUT,
E_PREPAIR_DATA: e_PRAPAIR_DATA,
/**
* Configuration parameter: time in milliseconds after which a
* pending AJAX request is considered unresponsive and is
* aborted. Useful to deal with bad connectivity (e.g. on a
* mobile network). A 0 value disables AJAX timeouts.
*
* Aborted requests resolve the promise with a ETIMEOUT error
* code.
*/
ajaxTimeout: 0,
contentType: ct_JSON
};
if (typeof define === 'function' && define.amd) {
/* AMD support */
define(function() {
return promise;
});
} else {
exports.promise = promise;
}
})(this);
// end:source promise.js
}.call(XHR));
arr_each(['get'], function(key){
XHR[key] = function(path, sender){
this
.promise[key](path)
.then(function(errored, response, xhr){
if (errored) {
sender.onError(errored, response, xhr);
return;
}
sender.onSuccess(response);
});
};
});
arr_each(['del', 'post', 'put', 'patch'], function(key){
XHR[key] = function(path, data, cb){
this
.promise[key](path, data)
.then(function(error, response, xhr){
cb(error, response, xhr);
});
};
});
// end:source /src/xhr/XHR.js
// source /src/business/Serializable.js
var Serializable;
(function(){
Serializable = function($serialization) {
if (this === Class || this == null || this === global) {
var Ctor = function(data){
this[json_key_SER] = obj_extend(this[json_key_SER], $serialization);
Serializable.call(this, data);
};
return Ctor;
}
if ($serialization != null) {
if (this.deserialize)
this.deserialize($serialization);
else
Serializable.deserialize(this, $serialization);
}
}
Serializable.serialize = function(instance) {
if (is_Function(instance.toJSON))
return instance.toJSON();
return json_proto_toJSON.call(instance, instance[json_key_SER]);
};
Serializable.deserialize = function(instance, json) {
if (is_String(json)) {
try {
json = JSON.parse(json);
}catch(error){
console.error('<json:deserialize>', json);
return instance;
}
}
if (is_Array(json) && is_Function(instance.push)) {
instance.length = 0;
for (var i = 0, imax = json.length; i < imax; i++){
instance.push(json[i]);
}
return instance;
}
var props = instance[json_key_SER],
asKeys, asKey,
key,
val,
Mix;
if (props != null) {
var pname = '__desAsKeys';
asKeys = props[pname];
if (asKeys == null) {
asKeys = props[pname] = {};
for (key in props) {
if (key !== '__desAsKeys' && props[key].hasOwnProperty('key') === true)
asKeys[props[key].key] = key;
}
}
}
for (key in json) {
val = json[key];
asKey = key;
if (props != null) {
Mix = props.hasOwnProperty(key)
? props[key]
: null
;
if (asKeys[key]) {
asKey = asKeys[key];
}
if (Mix != null) {
if (is_Object(Mix))
Mix = Mix.deserialize;
if (is_String(Mix))
Mix = class_get(Mix);
if (is_Function(Mix)) {
instance[asKey] = val instanceof Mix
? val
: new Mix(val)
;
continue;
}
}
}
instance[asKey] = val;
}
return instance;
}
}());
// end:source /src/business/Serializable.js
// source /src/business/Route.js
/**
* var route = new Route('/user/:id');
*
* route.create({id:5}) // -> '/user/5'
*/
var Route = (function(){
function Route(route){
this.route = route_parse(route);
}
Route.prototype = {
constructor: Route,
create: function(object){
var path, query;
path = route_interpolate(this.route.path, object, '/');
if (path == null) {
return null;
}
if (this.route.query) {
query = route_interpolate(this.route.query, object, '&');
if (query == null) {
return null;
}
}
return path + (query ? '?' + query : '');
},
hasAliases: function(object){
var i = 0,
imax = this.route.path.length,
alias
;
for (; i < imax; i++){
alias = this.route.path[i].parts[1];
if (alias && object[alias] == null) {
return false;
}
}
return true;
}
};
var regexp_pathByColon = /^([^:\?]*)(\??):(\??)([\w]+)$/,
regexp_pathByBraces = /^([^\{\?]*)(\{(\??)([\w]+)\})?([^\s]*)?$/;
function parse_single(string) {
var match = regexp_pathByColon.exec(string);
if (match) {
return {
optional: (match[2] || match[3]) === '?',
parts: [match[1], match[4]]
};
}
match = regexp_pathByBraces.exec(string);
if (match) {
return {
optional: match[3] === '?',
parts: [match[1], match[4], match[5]]
};
}
console.error('Paths breadcrumbs should be matched by regexps');
return { parts: [string] };
}
function parse_path(path, delimiter) {
var parts = path.split(delimiter);
for (var i = 0, imax = parts.length; i < imax; i++){
parts[i] = parse_single(parts[i]);
}
return parts;
}
function route_parse(route) {
var question = /[^\:\{]\?[^:]/.exec(route),
query = null;
if (question){
question = question.index + 1;
query = route.substring(question + 1);
route = route.substring(0, question);
}
return {
path: parse_path(route, '/'),
query: query == null ? null : parse_path(query, '&')
};
}
/** - route - [] */
function route_interpolate(breadcrumbs, object, delimiter) {
var route = [],
key,
parts;
for (var i = 0, x, imax = breadcrumbs.length; i < imax; i++){
x = breadcrumbs[i];
parts = x.parts.slice(0);
if (parts[1] == null) {
// is not an interpolated breadcrumb
route.push(parts[0]);
continue;
}
key = parts[1];
parts[1] = object[key];
if (parts[1] == null){
if (!x.optional) {
console.error('Object has no value, for not optional part - ', key);
return null;
}
continue;
}
route.push(parts.join(''));
}
return route.join(delimiter);
}
return Route;
}());
// end:source /src/business/Route.js
// source /src/business/Deferred.js
var Deferred;
(function(){
Deferred = function(){};
Deferred.prototype = {
_isAsync: true,
_done: null,
_fail: null,
_always: null,
_resolved: null,
_rejected: null,
defer: function(){
this._rejected = null;
this._resolved = null;
},
isResolved: function(){
return this._resolved != null;
},
isRejected: function(){
return this._rejected != null;
},
isBusy: function(){
return this._resolved == null && this._rejected == null;
},
resolve: function() {
var done = this._done,
always = this._always
;
this._resolved = arguments;
dfr_clearListeners(this);
arr_callOnce(done, this, arguments);
arr_callOnce(always, this, [ this ]);
return this;
},
reject: function() {
var fail = this._fail,
always = this._always
;
this._rejected = arguments;
dfr_clearListeners(this);
arr_callOnce(fail, this, arguments);
arr_callOnce(always, this, [ this ]);
return this;
},
resolveDelegate: function(){
return fn_proxy(this.resolve, this);
},
rejectDelegate: function(){
return fn_proxy(this.reject, this);
},
then: function(filterSuccess, filterError){
return this.pipe(filterSuccess, filterError);
},
done: function(callback) {
if (this._rejected != null)
return this;
return dfr_bind(
this,
this._resolved,
this._done || (this._done = []),
callback
);
},
fail: function(callback) {
if (this._resolved != null)
return this;
return dfr_bind(
this,
this._rejected,
this._fail || (this._fail = []),
callback
);
},
always: function(callback) {
return dfr_bind(
this,
this._rejected || this._resolved,
this._always || (this._always = []),
callback
);
},
pipe: function(mix /* ..methods */){
var dfr;
if (typeof mix === 'function') {
dfr = new Deferred;
var done_ = mix,
fail_ = arguments.length > 1
? arguments[1]
: null;
this
.done(delegate(dfr, 'resolve', done_))
.fail(delegate(dfr, 'reject', fail_))
;
return dfr;
}
dfr = mix;
var imax = arguments.length,
done = imax === 1,
fail = imax === 1,
i = 0, x;
while( ++i < imax ){
x = arguments[i];
switch(x){
case 'done':
done = true;
break;
case 'fail':
fail = true;
break;
default:
console.error('Unsupported pipe channel', arguments[i])
break;
}
}
done && this.done(dfr.resolveDelegate());
fail && this.fail(dfr.rejectDelegate());
function pipe(dfr, method) {
return function(){
dfr[method].apply(dfr, arguments);
};
}
function delegate(dfr, name, fn) {
return function(){
if (fn != null) {
var override = fn.apply(this, arguments);
if (override != null) {
if (isDeferred(override) === true) {
override.pipe(dfr);
return;
}
dfr[name](override)
return;
}
}
dfr[name].apply(dfr, arguments);
};
}
return this;
},
pipeCallback: function(){
var self = this;
return function(error){
if (error != null) {
self.reject(error);
return;
}
var args = _Array_slice.call(arguments, 1);
fn_apply(self.resolve, self, args);
};
}
};
Deferred.run = function(fn, ctx){
var dfr = new Deferred();
if (ctx == null)
ctx = dfr;
fn.call(ctx, dfr.resolveDelegate(), dfr.rejectDelegate(), dfr);
return dfr;
};
/**
* Create function wich gets deferred object with first argument.
* Created function returns always that deferred object
*/
Deferred.create = function(fn){
return function(){
var args = _Array_slice.call(arguments),
dfr = new Deferred;
args.unshift(dfr);
fn_apply(fn, this, args);
return dfr;
};
};
/**
* Similar as `create` it will also cache the deferred object,
* sothat the target function is called once pro specific arguments
*
* var fn = Deferred.memoize((dfr, name) => dfr.resolve(name));
* fn('foo');
* fn('baz');
* fn('foo');
* - is called only once for `foo`, and once for `baz`
*/
Deferred.memoize = function(fn){
var dfrs = {}, args_store = [];
return function(){
var args = _Array_slice.call(arguments),
id = fn_argsId(args_store, args);
if (dfrs[id] != null)
return dfrs[id];
var dfr = dfrs[id] = new Deferred;
args.unshift(dfr);
fn_apply(fn, this, args);
return dfr;
};
};
// PRIVATE
function dfr_bind(dfr, arguments_, listeners, callback){
if (callback == null)
return dfr;
if ( arguments_ != null)
fn_apply(callback, dfr, arguments_);
else
listeners.push(callback);
return dfr;
}
function dfr_clearListeners(dfr) {
dfr._done = null;
dfr._fail = null;
dfr._always = null;
}
function arr_callOnce(arr, ctx, args) {
if (arr == null)
return;
var imax = arr.length,
i = -1,
fn;
while ( ++i < imax ) {
fn = arr[i];
if (fn)
fn_apply(fn, ctx, args);
}
arr.length = 0;
}
function isDeferred(x){
if (x == null || typeof x !== 'object')
return false;
if (x instanceof Deferred)
return true;
return typeof x.done === 'function'
&& typeof x.fail === 'function'
;
}
}());
// end:source /src/business/Deferred.js
// source /src/business/EventEmitter.js
var EventEmitter;
(function(){
EventEmitter = function() {
this._listeners = {};
};
EventEmitter.prototype = {
constructor: EventEmitter,
on: function(event, callback) {
if (callback != null){
(this._listeners[event] || (this._listeners[event] = [])).push(callback);
}
return this;
},
once: function(event, callback){
if (callback != null) {
callback._once = true;
(this._listeners[event] || (this._listeners[event] = [])).push(callback);
}
return this;
},
pipe: function(event){
var that = this,
args;
return function(){
args = _Array_slice.call(arguments);
args.unshift(event);
fn_apply(that.trigger, that, args);
};
},
emit: event_trigger,
trigger: event_trigger,
off: function(event, callback) {
var listeners = this._listeners[event];
if (listeners == null)
return this;
if (arguments.length === 1) {
listeners.length = 0;
return this;
}
var imax = listeners.length,
i = -1;
while (++i < imax) {
if (listeners[i] === callback) {
listeners.splice(i, 1);
i--;
imax--;
}
}
return this;
}
};
function event_trigger() {
var args = _Array_slice.call(arguments),
event = args.shift(),
fns = this._listeners[event],
fn, imax, i = 0;
if (fns == null)
return this;
for (imax = fns.length; i < imax; i++) {
fn = fns[i];
fn_apply(fn, this, args);
if (fn._once === true){
fns.splice(i, 1);
i--;
imax--;
}
}
return this;
}
}());
// end:source /src/business/EventEmitter.js
// source /src/Class.js
var Class = function(mix) {
var namespace,
data;
if (is_String(mix)) {
namespace = mix;
if (arguments.length === 1)
return class_get(mix);
data = arguments[1];
data[str_CLASS_IDENTITY] = namespace;
} else {
data = mix;
}
var _base = data.Base,
_extends = data.Extends,
_static = data.Static,
_construct = data.Construct,
_class = null,
_store = data.Store,
_self = data.Self,
_overrides = data.Override,
key;
if (_base != null)
delete data.Base;
if (_extends != null)
delete data.Extends;
if (_static != null)
delete data.Static;
if (_self != null)
delete data.Self;
if (_construct != null)
delete data.Construct;
if (_store != null) {
if (_extends == null) {
_extends = _store;
} else if (is_Array(_extends)) {
_extends.unshift(_store)
} else {
_extends = [_store, _extends];
}
delete data.Store;
}
if (_overrides != null)
delete data.Override;
if (_base == null && _extends == null && _self == null) {
if (data.toJSON === void 0)
data.toJSON = json_proto_toJSON;
_class = _construct == null
? function() {}
: _construct
;
data.constructor = _class.prototype.constructor;
if (_static != null) {
obj_extendDescriptors(_class, _static);
}
_class.prototype = data;
if (namespace != null)
class_register(namespace, _class);
return _class;
}
_class = function() {
//// consider to remove
////if (this instanceof _class === false)
//// return new (_class.bind.apply(_class, [null].concat(_Array_slice.call(arguments))));
if (_extends != null) {
var isarray = _extends instanceof Array,
imax = isarray ? _extends.length : 1,
i = 0,
x = null;
for (; i < imax; i++) {
x = isarray
? _extends[i]
: _extends
;
if (typeof x === 'function') {
fn_apply(x, this, arguments);
}
}
}
if (_base != null) {
fn_apply(_base, this, arguments);
}
if (_self != null && is_NullOrGlobal(this) === false) {
for (var key in _self) {
this[key] = fn_proxy(_self[key], this);
}
}
if (_construct != null) {
var r = fn_apply(_construct, this, arguments);
if (r != null) {
return r;
}
}
this['super'] = null;
return this;
};
if (namespace != null)
class_register(namespace, _class);
if (_static != null) {
obj_extendDescriptors(_class, _static);
}
if (_base != null)
class_inheritStatics(_class, _base);
if (_extends != null)
class_inheritStatics(_class, _extends);
class_extendProtoObjects(data, _base, _extends);
class_inherit(_class, _base, _extends, data, _overrides, {
toJSON: json_proto_toJSON
});
data = null;
_static = null;
return _class;
};
// end:source /src/Class.js
// source /src/business/Await.js
var Await;
(function(){
Await = Class({
Extends: Deferred.prototype,
_wait: 0,
_timeout: null,
_result: null,
_resolved: [],
Construct: function(/* promises <optional> */){
var imax = arguments.length,
i = -1,
dfr
;
while ( ++i < imax ){
dfr = arguments[i];
if (dfr != null && typeof dfr.done === 'function')
await_deferredDelegate(this, null, dfr);
}
},
delegate: function(name, errorable) {
return await_createDelegate(this, name, errorable);
},
deferred: function(name) {
return await_deferredDelegate(
this,
name,
new Deferred);
},
Static: {
TIMEOUT: 2000
}
});
function await_deferredDelegate(await, name, dfr){
var delegate = await_createDelegate(await, name, true),
args
;
return dfr
.done(function(){
args = _Array_slice.call(arguments);
args.unshift(null);
delegate.apply(null, args);
})
.fail(function(error){
delegate(error);
})
;
}
function await_createDelegate(await, name, errorable){
if (errorable == null)
errorable = true;
if (await._timeout)
clearTimeout(await._timeout);
await.defer();
await._wait++;
if (name){
if (!await._result)
await._result = {};
if (name in await._result)
console.warn('<await>', name, 'already awaiting');
await._result[name] = null;
}
var delegate = fn_createDelegate(await_listener, await, name, errorable)
;
await._timeout = setTimeout(delegate, Await.TIMEOUT);
return delegate;
}
function await_listener(await, name, errorable /* .. args */ ) {
if (arguments.length === 0) {
// timeout
await._wait = 0;
await.reject('408: Timeout');
return;
}
if (await._wait === 0)
return;
var result = await._result;
if (name) {
var args = _Array_slice.call(arguments, 3);
result[name] = {
error: errorable ? args.shift() : null,
arguments: args
};
} else if (errorable && arguments[3] != null) {
if (result == null)
result = await._result = {};
result.__error = arguments[3];
}
if (--await._wait === 0) {
clearTimeout(await._timeout);
var error = result && result.__error
;
var val,