Commit f79d2a8a authored by Kostantinos  Margaritis's avatar Kostantinos Margaritis Committed by Sindre Sorhus

Close #1143 PR: Atmajs: New ui & upgrade to NPM. Fixes #1110

parent bfbefb12
node_modules/atma-class/*
!node_modules/atma-class/lib/class.js
node_modules/includejs/*
!node_modules/includejs/lib/include.js
node_modules/jquery/*
!node_modules/jquery/dist
node_modules/jquery/dist/*
!node_modules/jquery/dist/jquery.js
node_modules/maskjs/*
!node_modules/maskjs/lib/mask.js
node_modules/ruta/*
!node_modules/ruta/lib/ruta.js
node_modules/todomvc-app-css/*
!node_modules/todomvc-app-css/index.css
node_modules/todomvc-common/*
!node_modules/todomvc-common/base.css
!node_modules/todomvc-common/base.js
{
"name": "todomvc-atmajs",
"version": "0.1.0",
"dependencies": {
"todomvc-common": "~0.3.0",
"jquery": "~2.0.2",
"maskjs": "~0.10.1",
"includejs": "~0.9.10",
"ruta": "~0.1.11",
"atma-class": "~1.0.68"
}
}
......@@ -3,7 +3,8 @@
<head>
<meta charset="utf-8">
<title>Atma.js • TodoMVC</title>
<link rel="stylesheet" href="bower_components/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-common/base.css">
<link rel="stylesheet" href="node_modules/todomvc-app-css/index.css">
</head>
<body>
<!--
......@@ -39,13 +40,13 @@
_If the controller loads a template, do not forget to review that._
-->
<script src="bower_components/todomvc-common/base.js"></script>
<script src="bower_components/jquery/jquery.js"></script>
<script src="node_modules/todomvc-common/base.js"></script>
<script src="node_modules/jquery/dist/jquery.js"></script>
<script src="bower_components/includejs/lib/include.js"></script>
<script src="bower_components/atma-class/lib/class.js"></script>
<script src="bower_components/maskjs/lib/mask.js"></script>
<script src="bower_components/ruta/lib/ruta.js"></script>
<script src="node_modules/includejs/lib/include.js"></script>
<script src="node_modules/atma-class/lib/class.js"></script>
<script src="node_modules/maskjs/lib/mask.js"></script>
<script src="node_modules/ruta/lib/ruta.js"></script>
<script src="js/app.js"></script>
......
......@@ -21,42 +21,42 @@
_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')
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,
......@@ -68,7 +68,7 @@
is_rawObject,
is_NullOrGlobal;
(function(){
is_Function = function(x) {
return typeof x === 'function';
};
......@@ -87,59 +87,59 @@
&& 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)
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;
......@@ -151,150 +151,150 @@
}
}
};
/* 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))
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')
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)
if (out == null)
out = {};
var type,
key,
val;
......@@ -304,43 +304,43 @@
? 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__)
if (proto.__proto__)
getProperties(proto.__proto__, out);
return out;
}
}());
// end:source /src/util/class.js
// source /src/util/proto.js
......@@ -348,26 +348,26 @@
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)
if (mix == null)
return;
if (is_ArrayLike(mix)) {
var i = mix.length;
while ( --i > -1 ) {
......@@ -375,237 +375,237 @@
}
return;
}
var Static;
if (is_Function(mix))
if (is_Function(mix))
Static = mix;
else if (is_Object(mix.Static))
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]))
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]))
if (is_rawObject(x[key]))
obj_defaults(protoValue, x[key]);
});
}
}
}
// PRIVATE
function proto_extend(proto, source) {
if (source == null)
if (source == null)
return;
if (typeof proto === 'function')
if (typeof proto === 'function')
proto = proto.prototype;
if (typeof source === 'function')
if (typeof source === 'function')
source = source.prototype;
var key, val;
for (key in source) {
val = source[key];
if (val != null)
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)
if (_base != null)
proto[PROTO] = _base.prototype;
for (var key in defaults) {
if (prototype[key] == null)
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__
// 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);
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)
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)
if (s.key)
asKey = s.key;
if (s.hasOwnProperty('serialize')) {
if (s.serialize == null)
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))
if (is_Date(val))
break;
var toJSON = val.toJSON;
if (toJSON == null)
if (toJSON == null)
break;
json[asKey] = val.toJSON();
continue;
//@removed - serialize any if toJSON is implemented
......@@ -613,58 +613,58 @@
// 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;
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,
......@@ -674,103 +674,103 @@
obj_extendDescriptorsDefaults,
obj_validate
;
(function(){
obj_inherit = function(target /* source, ..*/ ) {
if (is_Function(target))
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)
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)
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)
if (target[key] == null)
target[key] = defaults[key];
}
return target;
};
obj_extend = function(target, source) {
if (target == null)
if (target == null)
target = {};
if (source == null)
if (source == null)
return target;
var val,
key;
for(key in source) {
val = source[key];
if (val != null)
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;
......@@ -783,17 +783,17 @@
return _extendDescriptors(target, source, true);
};
function _extendDescriptors (target, source, defaultsOnly) {
if (target == null)
if (target == null)
return {};
if (source == null)
if (source == null)
return source;
var descr,
key;
for(key in source){
if (defaultsOnly === true && target[key] != null)
if (defaultsOnly === true && target[key] != null)
continue;
descr = getDescr(source, key);
if (descr == null) {
obj_extendDescriptors(target, source['__proto__']);
......@@ -808,24 +808,24 @@
return target;
};
}());
(function(){
obj_validate = function(a /*, b , ?isStrict, ?property, ... */) {
if (a == null)
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)
if (_props == null)
_props = {};
_props[x] = 1;
continue;
......@@ -842,106 +842,106 @@
continue;
}
}
if (validator == null)
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 -
// 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)
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)
if (typeof a === 'object' && aKey in a)
return Err_Unexpect(aKey);
continue;
}
aVal = a[key];
if (aVal == null)
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)
if (key in b || '?' + key in b)
continue;
return Err_Unexpect(key);
}
}
}
function checkProperty(aVal, bVal, ctx) {
if (bVal == null)
if (bVal == null)
return null;
if (typeof bVal === 'function') {
var error = bVal.call(ctx, aVal);
if (error == null || error === true)
if (error == null || error === true)
return null;
if (error === false)
if (error === false)
return Err_Invalid();
return Err_Custom(error);
}
if (aVal == null)
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
......@@ -957,42 +957,42 @@
: null;
}
}
if (bVal instanceof RegExp) {
return bVal.test(aVal) === false
? Err_Invalid()
: null;
}
if (Array.isArray(bVal)) {
if (Array.isArray(aVal) === false)
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)
if (typeof aVal !== typeof bVal)
return Err_Type(typeof aVal);
if (typeof aVal === 'object')
if (typeof aVal === 'object')
return checkObject(aVal, bVal);
return null;
}
var Err_Type,
Err_Expect,
Err_Unexpect,
......@@ -1000,7 +1000,7 @@
Err_Invalid
;
(function(){
Err_Type = create('type',
function TypeErr(expect) {
this.expect = expect;
......@@ -1077,12 +1077,12 @@
}
}
);
function create(type, Ctor, proto) {
proto.type = type;
proto.property = null;
proto.setInvalidProperty = setInvalidProperty;
Ctor.prototype = proto;
return function(mix){
return new Ctor(mix);
......@@ -1096,54 +1096,54 @@
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)
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)
if (patch == null)
return 'Undefined';
var has = false;
for(var key in patch){
has = true;
if (patches[key] == null)
if (patches[key] == null)
return 'Unsupported patcher: ' + key;
}
if (has === false)
if (has === false)
return 'No data';
return null;
};
// === private
function walk_mutator(obj, data, fn) {
for (var key in data)
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(
......@@ -1152,18 +1152,18 @@
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)
if (fn(val, mix, prop) === false)
return;
}
}
}
function arr_checkArray(val, mix, prop) {
if (arr_isArray(val) === false) {
// if DEBUG
......@@ -1172,7 +1172,7 @@
return false;
}
}
function arr_push(val, mix, prop){
if (mix.hasOwnProperty('$each')) {
for (var i = 0, imax = mix.$each.length; i < imax; i++){
......@@ -1182,7 +1182,7 @@
}
val.push(mix);
}
function arr_pop(val, mix, prop){
val[mix > 0 ? 'pop' : 'shift']();
}
......@@ -1191,7 +1191,7 @@
return query_match(item, mix);
});
}
function val_inc(val, mix, key){
return val + mix;
}
......@@ -1201,47 +1201,47 @@
function val_unset(){
return void 0;
}
function val_bit(val, mix){
if (mix.or)
if (mix.or)
return val | mix.or;
if (mix.and)
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])
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
......@@ -1251,15 +1251,15 @@
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:
......@@ -1292,23 +1292,23 @@
};
return fn.apply(ctx, _arguments);
};
fn_createDelegate = function(fn /* args */) {
var args = _Array_slice.call(arguments, 1);
return function(){
if (arguments.length > 0)
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 ){
......@@ -1318,13 +1318,13 @@
cache.push(args);
return cache.length;
};
// === private
function args_match(a, b){
if (a.length !== b.length)
if (a.length !== b.length)
return false;
var imax = a.length,
i = 0;
for (; i < imax; i++){
......@@ -1334,35 +1334,35 @@
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) {
......@@ -1377,7 +1377,7 @@
}
return p;
};
Promise.prototype.done = function() {
this.result = arguments;
this._isdone = true;
......@@ -1386,19 +1386,19 @@
}
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;
......@@ -1408,14 +1408,14 @@
}
};
}
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) {
......@@ -1430,11 +1430,11 @@
}
return p;
}
/*
* AJAX requests
*/
function _encode(data) {
var result = "";
if (typeof data === "string") {
......@@ -1449,7 +1449,7 @@
}
return result;
}
function new_xhr() {
var xhr;
if (window.XMLHttpRequest) {
......@@ -1463,16 +1463,16 @@
}
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) {
......@@ -1480,14 +1480,14 @@
return p;
}
if (data) {
if ('GET' === method) {
url += '?' + _encode(data);
data = null;
} else {
switch (contentType) {
case ct_URL_ENCODED:
data = _encode(data);
......@@ -1496,7 +1496,7 @@
try {
data = JSON.stringify(data);
} catch(error){
p.done(e_PRAPAIR_DATA, '');
return p;
}
......@@ -1507,30 +1507,30 @@
break;
}
}
}
xhr.open(method, url);
if (data)
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);
......@@ -1542,17 +1542,17 @@
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,
......@@ -1563,7 +1563,7 @@
put: _ajaxer('PUT'),
del: _ajaxer('DELETE'),
patch: _ajaxer('PATCH'),
/* Error codes */
ENOXHR: e_NO_XHR,
ETIMEOUT: e_TIMEOUT,
......@@ -1578,11 +1578,11 @@
* code.
*/
ajaxTimeout: 0,
contentType: ct_JSON
};
if (typeof define === 'function' && define.amd) {
/* AMD support */
define(function() {
......@@ -1591,31 +1591,31 @@
} 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
......@@ -1625,50 +1625,50 @@
});
};
});
// 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)
if (this.deserialize)
this.deserialize($serialization);
else
Serializable.deserialize(this, $serialization);
}
}
Serializable.serialize = function(instance) {
if (is_Function(instance.toJSON))
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);
......@@ -1677,7 +1677,7 @@
return instance;
}
}
if (is_Array(json) && is_Function(instance.push)) {
instance.length = 0;
for (var i = 0, imax = json.length; i < imax; i++){
......@@ -1685,48 +1685,48 @@
}
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)
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)
Mix = props.hasOwnProperty(key)
? props[key]
: null
;
if (asKeys[key]) {
asKey = asKeys[key];
}
if (Mix != null) {
if (is_Object(Mix))
if (is_Object(Mix))
Mix = Mix.deserialize;
if (is_String(Mix))
if (is_String(Mix))
Mix = class_get(Mix);
if (is_Function(Mix)) {
instance[asKey] = val instanceof Mix
? val
......@@ -1736,15 +1736,15 @@
}
}
}
instance[asKey] = val;
}
return instance;
}
}
}());
// end:source /src/business/Serializable.js
// source /src/business/Route.js
/**
......@@ -1753,162 +1753,162 @@
* 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;
},
......@@ -1918,49 +1918,49 @@
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)
if (this._rejected != null)
return this;
return dfr_bind(
this,
......@@ -1969,9 +1969,9 @@
callback
);
},
fail: function(callback) {
if (this._resolved != null)
if (this._resolved != null)
return this;
return dfr_bind(
this,
......@@ -1980,7 +1980,7 @@
callback
);
},
always: function(callback) {
return dfr_bind(
this,
......@@ -1989,7 +1989,7 @@
callback
);
},
pipe: function(mix /* ..methods */){
var dfr;
if (typeof mix === 'function') {
......@@ -1998,14 +1998,14 @@
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,
......@@ -2027,14 +2027,14 @@
}
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);
......@@ -2043,7 +2043,7 @@
override.pipe(dfr);
return;
}
dfr[name](override)
return;
}
......@@ -2051,7 +2051,7 @@
dfr[name].apply(dfr, arguments);
};
}
return this;
},
pipeCallback: function(){
......@@ -2066,12 +2066,12 @@
};
}
};
Deferred.run = function(fn, ctx){
var dfr = new Deferred();
if (ctx == null)
if (ctx == null)
ctx = dfr;
fn.call(ctx, dfr.resolveDelegate(), dfr.rejectDelegate(), dfr);
return dfr;
};
......@@ -2084,7 +2084,7 @@
var args = _Array_slice.call(arguments),
dfr = new Deferred;
args.unshift(dfr);
fn_apply(fn, this, args);
return dfr;
};
......@@ -2104,70 +2104,70 @@
return function(){
var args = _Array_slice.call(arguments),
id = fn_argsId(args_store, args);
if (dfrs[id] != null)
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)
if (callback == null)
return dfr;
if ( arguments_ != null)
if ( arguments_ != null)
fn_apply(callback, dfr, arguments_);
else
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)
if (arr == null)
return;
var imax = arr.length,
i = -1,
fn;
while ( ++i < imax ) {
fn = arr[i];
if (fn)
if (fn)
fn_apply(fn, ctx, args);
}
arr.length = 0;
}
function isDeferred(x){
if (x == null || typeof x !== 'object')
if (x == null || typeof x !== 'object')
return false;
if (x instanceof Deferred)
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 = {};
};
......@@ -2177,7 +2177,7 @@
if (callback != null){
(this._listeners[event] || (this._listeners[event] = [])).push(callback);
}
return this;
},
once: function(event, callback){
......@@ -2185,98 +2185,98 @@
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)
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,
......@@ -2285,27 +2285,27 @@
_store = data.Store,
_self = data.Self,
_overrides = data.Override,
key;
if (_base != null)
if (_base != null)
delete data.Base;
if (_extends != null)
if (_extends != null)
delete data.Extends;
if (_static != null)
if (_static != null)
delete data.Static;
if (_self != null)
if (_self != null)
delete data.Self;
if (_construct != null)
if (_construct != null)
delete data.Construct;
if (_store != null) {
if (_extends == null) {
_extends = _store;
} else if (is_Array(_extends)) {
......@@ -2313,47 +2313,47 @@
} else {
_extends = [_store, _extends];
}
delete data.Store;
}
if (_overrides != null)
if (_overrides != null)
delete data.Override;
if (_base == null && _extends == null && _self == null) {
if (data.toJSON === void 0)
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)
if (namespace != null)
class_register(namespace, _class);
return _class;
}
_class = function() {
//// consider to remove
////if (this instanceof _class === false)
//// 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;
......@@ -2367,68 +2367,68 @@
}
}
}
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)
if (namespace != null)
class_register(namespace, _class);
if (_static != null) {
obj_extendDescriptors(_class, _static);
}
if (_base != null)
if (_base != null)
class_inheritStatics(_class, _base);
if (_extends != null)
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,
......@@ -2436,29 +2436,29 @@
;
while ( ++i < imax ){
dfr = arguments[i];
if (dfr != null && typeof dfr.done === 'function')
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
......@@ -2467,116 +2467,116 @@
.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)
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)
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)
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)
if (result == null)
result = await._result = {};
result.__error = arguments[3];
}
if (--await._wait === 0) {
clearTimeout(await._timeout);
var error = result && result.__error
;
var val,
key;
if (error == null) {
for(key in result){
val = result[key];
error = val && val.error;
if (error)
if (error)
break;
}
}
if (error) {
await.reject(error, result);
return;
}
await.resolve(result);
}
}
}());
// end:source /src/business/Await.js
// source /src/store/Store.js
var StoreProto = {
// Abstract
fetch: null,
save: null,
del: null,
onSuccess: null,
onError: null,
Static: {
fetch: function(data){
return new this().fetch(data);
......@@ -2590,24 +2590,24 @@
storageEvents_remove,
storageEvents_overridenDefer
;
(function(){
var event_START = 'start',
event_SUCCESS = 'fulfilled',
event_FAIL = 'rejected';
var events_ = new EventEmitter,
hasBeforeListeners_,
hasAfterListeners_
;
storageEvents_onBefore = function(callback){
events_.on(event_START, callback);
hasBeforeListeners_ = true;
};
storageEvents_onAfter = function(onSuccess, onFailure){
events_
.on(event_SUCCESS, onSuccess)
......@@ -2615,7 +2615,7 @@
;
hasAfterListeners_ = true;
};
storageEvents_remove = function(callback){
events_
.off(event_SUCCESS, callback)
......@@ -2623,26 +2623,26 @@
.off(event_START, callback)
;
};
storageEvents_overridenDefer = function(type){
Deferred.prototype.defer.call(this);
if (hasBeforeListeners_)
if (hasBeforeListeners_)
emit([event_START, this, type]);
if (hasAfterListeners_)
if (hasAfterListeners_)
this.always(listenerDelegate(this, type));
return this;
};
// PRIVATE
function listenerDelegate(sender, type) {
return function(){
var isSuccess = sender._rejected == null,
arguments_ = isSuccess
arguments_ = isSuccess
? sender._resolved
: sender._rejected
,
......@@ -2653,68 +2653,68 @@
emit([event, sender, type].concat(arguments_));
};
}
function emit(arguments_/* [ event, sender, .. ]*/){
events_.trigger.apply(events_, arguments_);
}
}());
// end:source /src/store/events.js
// source /src/store/Remote.js
Class.Remote = (function(){
var str_CONTENT_TYPE = 'content-type',
str_JSON = 'json'
;
var XHRRemote = function(route){
this._route = new Route(route);
};
obj_inherit(XHRRemote, StoreProto, Serializable, Deferred, {
defer: storageEvents_overridenDefer,
serialize: function(){
return is_Array(this)
? json_proto_arrayToJSON.call(this)
: json_proto_toJSON.call(this)
;
},
deserialize: function(json){
return Serializable.deserialize(this, json);
},
fetch: function(data){
this.defer('fetch');
XHR.get(this._route.create(data || this), this);
return this;
},
save: function(callback){
this.defer('save');
var json = this.serialize(),
path = this._route.create(this),
method = this._route.hasAliases(this)
? 'put'
: 'post'
;
XHR[method](path, json, resolveDelegate(this, callback, 'save'));
return this;
},
patch: function(json){
this.defer('patch');
obj_patch(this, json);
XHR.patch(
this._route.create(this),
json,
......@@ -2722,44 +2722,44 @@
);
return this;
},
del: function(callback){
this.defer('del');
var json = this.serialize(),
path = this._route.create(this)
;
XHR.del(path, json, resolveDelegate(this, callback));
return this;
},
onSuccess: function(response){
parseFetched(this, response);
},
onError: function(errored, response, xhr){
reject(this, response, xhr);
}
});
function parseFetched(self, response){
var json;
try {
json = JSON.parse(response);
json = JSON.parse(response);
} catch(error) {
reject(self, error);
return;
}
self.deserialize(json);
self.resolve(self);
}
function reject(self, response, xhr){
var obj;
if (typeof response === 'string' && is_JsonResponse(xhr)) {
......@@ -2769,122 +2769,122 @@
obj = error;
}
}
self.reject(obj || response);
}
function is_JsonResponse(xhr){
var header = xhr.getResponseHeader(str_CONTENT_TYPE);
return header != null
&& header.toLowerCase().indexOf(str_JSON) !== -1;
}
function resolveDelegate(self, callback, action){
return function(error, response, xhr){
if (is_JsonResponse(xhr)) {
try {
response = JSON.parse(response);
} catch(error){
console.error('<XHR> invalid json response', response);
return reject(self, error, xhr);
}
}
// @obsolete -> use deferred
if (callback)
if (callback)
callback(error, response);
if (error)
if (error)
return reject(self, response, xhr);
if ('save' === action && is_Object(response)) {
if (is_Array(self)) {
var imax = self.length,
jmax = response.length,
i = -1
;
while ( ++i < imax && i < jmax){
Serializable.deserialize(self[i], response[i]);
}
} else {
self.deserialize(response);
}
return self.resolve(self);
}
self.resolve(response);
};
}
function Remote(route){
return new XHRRemote(route);
};
Remote.onBefore = storageEvents_onBefore;
Remote.onAfter = storageEvents_onAfter;
arr_each(['get', 'post', 'put', 'delete'], function(method){
Remote[method] = function(url, obj){
var json = obj;
if (obj.serialize != null)
if (obj.serialize != null)
json = obj.serialize();
if (json == null && obj.toJSON)
if (json == null && obj.toJSON)
json = obj.toJSON();
var dfr = new Deferred();
XHR[method](url, json, resolveDelegate(dfr));
return dfr;
};
});
return Remote;
}());
// end:source /src/store/Remote.js
// source /src/store/LocalStore.js
Class.LocalStore = (function(){
var LocalStore = function(route){
this._route = new Route(route);
};
obj_inherit(LocalStore, StoreProto, Serializable, Deferred, {
serialize: function(){
var json = is_Array(this)
? json_proto_arrayToJSON.call(this)
: json_proto_toJSON.call(this)
;
return JSON.stringify(json);
},
deserialize: function(json){
return Serializable.deserialize(this, json);
},
fetch: function(data){
var path = this._route.create(data || this),
object = localStorage.getItem(path);
if (object == null) {
return this.resolve(this);
}
if (is_String(object)){
try {
object = JSON.parse(object);
......@@ -2892,81 +2892,81 @@
return this.reject(e);
}
}
this.deserialize(object);
return this.resolve(this);
},
save: function(callback){
var path = this._route.create(this),
store = this.serialize();
localStorage.setItem(path, store);
callback && callback();
return this.resolve(this);
},
del: function(mix){
if (mix == null && arguments.length !== 0) {
return this.reject('<localStore:del> - selector is specified, but is undefined');
}
// Single
if (arr_isArray(this) === false) {
store_del(this._route, mix || this);
return this.resolve();
}
// Collection
if (mix == null) {
for (var i = 0, imax = this.length; i < imax; i++){
this[i] = null;
}
this.length = 0;
store_del(this._route, this);
return this.resolve();
}
var array = this.remove(mix);
if (array.length === 0) {
// was nothing removed
return this.resolve();
}
return this.save();
},
onError: function(error){
this.reject({
error: error
});
}
});
function store_del(route, data){
var path = route.create(data);
localStorage.removeItem(path);
}
var Constructor = function(route){
return new LocalStore(route);
};
Constructor.prototype = LocalStore.prototype;
return Constructor;
}());
// end:source /src/store/LocalStore.js
// source /src/Class.Static.js
/**
......@@ -2980,88 +2980,88 @@
i = 1,
length = arguments.length,
key;
for (; i < length; i++) {
key = arr[i];
cntx[key] = cntx[key].bind(cntx);
}
return cntx;
};
Class.cfg = function(mix, value){
if (is_String(mix)) {
if (arguments.length === 1)
if (arguments.length === 1)
return _cfg[mix];
_cfg[mix] = value;
return;
}
if (is_Object(mix)) {
for(var key in mix){
Class.cfg(key, mix[key]);
}
}
};
Class.Model = {};
Class.Serializable = Serializable;
Class.Deferred = Deferred;
Class.EventEmitter = EventEmitter;
Class.Await = Await;
Class.validate = obj_validate;
Class.stringify = class_stringify;
Class.parse = class_parse;
Class.patch = class_patch;
Class.properties = class_properties;
// end:source /src/Class.Static.js
// source /src/collection/Collection.js
Class.Collection = (function(){
// source ArrayProto.js
var ArrayProto = (function(){
function check(x, mix) {
if (mix == null)
return false;
if (typeof mix === 'function')
if (typeof mix === 'function')
return mix(x);
if (typeof mix === 'object'){
if (x.constructor === mix.constructor && x.constructor !== Object) {
return x === mix;
}
var value, matcher;
for (var key in mix) {
value = x[key];
matcher = mix[key];
if (typeof matcher === 'string') {
var c = matcher[0],
index = 1;
if ('<' === c || '>' === c){
if ('=' === matcher[1]){
c +='=';
index++;
}
matcher = matcher.substring(index);
switch (c) {
case '<':
if (value >= matcher)
......@@ -3082,73 +3082,73 @@
}
}
}
// eqeq to match by type diffs.
if (value != matcher)
if (value != matcher)
return false;
}
return true;
}
console.warn('No valid matcher', mix);
return false;
}
var ArrayProto = {
length: 0,
push: function(/*mix*/) {
var imax = arguments.length,
i = -1;
while ( ++i < imax ) {
this[this.length++] = create(this._ctor, arguments[i]);
}
return this;
},
pop: function() {
var instance = this[--this.length];
this[this.length] = null;
return instance;
},
shift: function(){
if (this.length === 0)
if (this.length === 0)
return null;
var first = this[0],
imax = this.length - 1,
i = 0;
for (; i < imax; i++){
this[i] = this[i + 1];
}
this[imax] = null;
this.length--;
return first;
},
unshift: function(mix){
this.length++;
var imax = this.length;
while (--imax) {
this[imax] = this[imax - 1];
}
this[0] = create(this._ctor, mix);
return this;
},
splice: function(index, count /* args */){
var length = this.length;
var i, imax, y;
// clear range after length until index
if (index >= length) {
count = 0;
......@@ -3156,65 +3156,65 @@
this[i] = void 0;
}
}
var rm_count = count,
rm_start = index,
rm_end = index + rm_count,
add_count = arguments.length - 2,
new_length = length + add_count - rm_count;
// move block
var block_start = rm_end,
block_end = length,
block_shift = new_length - length;
if (0 < block_shift) {
// move forward
i = block_end;
while (--i >= block_start) {
this[i + block_shift] = this[i];
}
}
if (0 > block_shift) {
// move backwards
i = block_start;
i = block_start;
while (i < block_end) {
this[i + block_shift] = this[i];
i++;
}
}
// insert
i = rm_start;
y = 2;
for (; y < arguments.length; y) {
this[i++] = create(this._ctor, arguments[y++]);
}
this.length = new_length;
return this;
},
slice: function(){
return fn_apply(_Array_slice, this, arguments);
},
sort: function(fn){
_Array_sort.call(this, fn);
return this;
},
reverse: function(){
var array = _Array_slice.call(this),
imax = this.length,
......@@ -3225,62 +3225,62 @@
}
return this;
},
toString: function(){
return _Array_slice.call(this, 0).toString()
},
each: forEach,
forEach: forEach,
where: function(mix){
var collection = new this.constructor();
for (var i = 0, x, imax = this.length; i < imax; i++){
x = this[i];
if (check(x, mix)) {
collection[collection.length++] = x;
}
}
return collection;
},
remove: function(mix){
var index = -1,
array = [];
for (var i = 0, imax = this.length; i < imax; i++){
if (check(this[i], mix)) {
array.push(this[i]);
continue;
}
this[++index] = this[i];
}
for (i = ++index; i < imax; i++) {
this[i] = null;
}
this.length = index;
return array;
},
first: function(mix){
if (mix == null)
return this[0];
var i = this.indexOf(mix);
return i !== -1
? this[i]
: null;
},
last: function(mix){
if (mix == null)
return this[this.length - 1];
var i = this.lastIndexOf(mix);
return i !== -1
? this[i]
......@@ -3289,20 +3289,20 @@
indexOf: function(mix, index){
if (mix == null)
return -1;
if (index != null) {
if (index < 0)
if (index < 0)
index = 0;
if (index >= this.length)
if (index >= this.length)
return -1;
}
else{
index = 0;
}
var imax = this.length;
for(; index < imax; index++) {
if (check(this[index], mix))
......@@ -3313,29 +3313,29 @@
lastIndexOf: function(mix, index){
if (mix == null)
return -1;
if (index != null) {
if (index >= this.length)
if (index >= this.length)
index = this.length - 1;
if (index < 0)
if (index < 0)
return -1;
}
else {
index = this.length - 1;
}
for (; index > -1; index--) {
if (check(this[index], mix))
return index;
}
return -1;
},
map: function(fn){
var arr = [],
imax = this.length,
i = -1;
......@@ -3344,7 +3344,7 @@
}
return arr;
},
filter: function(fn, ctx){
var coll = new this.constructor(),
imax = this.length,
......@@ -3357,7 +3357,7 @@
return coll;
}
};
// ES6 iterator
if (typeof Symbol !== 'undefined' && Symbol.iterator) {
ArrayProto[Symbol.iterator] = function(){
......@@ -3376,7 +3376,7 @@
}
};
}
function forEach(fn, ctx){
var imax = this.length,
i = -1
......@@ -3386,139 +3386,139 @@
}
return this;
}
return ArrayProto;
}());
// end:source ArrayProto.js
function create(Constructor, mix) {
if (mix instanceof Constructor)
if (mix instanceof Constructor)
return mix;
return new Constructor(mix);
}
var CollectionProto = {
toArray: function(){
var array = new Array(this.length);
for (var i = 0, imax = this.length; i < imax; i++){
array[i] = this[i];
}
return array;
},
toJSON: json_proto_arrayToJSON
};
function Collection(/* (ClassName, Child, Proto) (Child, Proto) */) {
var length = arguments.length,
Proto = arguments[length - 1],
Child = arguments[length - 2],
className
;
if (length > 2)
if (length > 2)
className = arguments[0];
Proto._ctor = Child;
obj_inherit(Proto, CollectionProto, ArrayProto);
return className == null
? Class(Proto)
: Class(className, Proto)
;
}
return Collection;
}());
// end:source /src/collection/Collection.js
// source /src/fn/fn.js
(function(){
// source memoize.js
var fn_memoize,
fn_memoizeAsync;
(function(){
fn_memoize = function(fn) {
var _cache = {},
_args = [];
return function() {
var id = fn_argsId(arguments, _args);
return _cache[id] == null
? (_cache[id] = fn_apply(fn, this, arguments))
: _cache[id];
};
};
fn_memoizeAsync = function(fn) {
var _cache = {},
_cacheCbs = {},
_args = [];
return function(){
var args = _Array_slice.call(arguments),
callback = args.pop();
var id = fn_argsId(args, _args);
if (_cache[id]){
fn_apply(callback, this, _cache[id])
return;
return;
}
if (_cacheCbs[id]) {
_cacheCbs[id].push(callback);
return;
}
_cacheCbs[id] = [callback];
args = _Array_slice.call(args);
args.push(fn_resolveDelegate(_cache, _cacheCbs, id));
fn_apply(fn, this, args);
};
};
// === private
function fn_resolveDelegate(cache, cbs, id) {
return function(){
cache[id] = arguments;
for (var i = 0, x, imax = cbs[id].length; i < imax; i++){
x = cbs[id][i];
fn_apply(x, this, arguments);
}
cbs[i] = null;
cache = null;
cbs = null;
};
}
}());
// end:source memoize.js
Class.Fn = {
memoize: fn_memoize,
memoizeAsync: fn_memoizeAsync
};
}());
// end:source /src/fn/fn.js
exports.Class = Class;
}));
\ No newline at end of file
......@@ -4,26 +4,26 @@
'use strict';
var _global, _exports;
if (typeof exports !== 'undefined' && (root === exports || root == null)){
// raw nodejs module
_global = _exports = global;
_global = _exports = global;
}
if (_global == null) {
_global = typeof window === 'undefined' ? global : window;
}
if (_exports == null) {
_exports = root || _global;
}
if (typeof include !== 'undefined' && typeof include.js === 'function') {
// allow only one `include` per application
_exports.include = include;
_exports.includeLib = include.Lib || _global.includeLib;
return;
}
factory(_global, _exports, _global.document);
}(this, function (global, exports, document) {
......@@ -31,8 +31,8 @@
// end:source ../src/head.js
// source ../src/1.scope-vars.js
// source ../src/1.scope-vars.js
/**
* .cfg
* : path := root path. @default current working path, im browser window.location;
......@@ -41,7 +41,7 @@
* Example "/script/main.js" within this window.location "{domain}/apps/1.html"
* will become "{domain}/apps/script/main.js" instead of "{domain}/script/main.js"
*/
var bin = {
js: {},
css: {},
......@@ -64,42 +64,42 @@
load: {}
},
__array_slice = Array.prototype.slice,
XMLHttpRequest = global.XMLHttpRequest;
// end:source ../src/1.scope-vars.js
// end:source ../src/1.scope-vars.js
// source ../src/2.Helper.js
var Helper = { /** TODO: improve url handling*/
reportError: function(e) {
console.error('IncludeJS Error:', e, e.message, e.url);
typeof handler.onerror === 'function' && handler.onerror(e);
}
},
XHR = function(resource, callback) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
xhr.readyState === 4 && callback && callback(resource, xhr.responseText);
};
xhr.open('GET', typeof resource === 'object' ? resource.url : resource, true);
xhr.send();
};
// end:source ../src/2.Helper.js
// source ../src/utils/fn.js
function fn_proxy(fn, ctx) {
return function(){
fn.apply(ctx, arguments);
};
}
function fn_doNothing(fn) {
typeof fn === 'function' && fn();
}
......@@ -109,9 +109,9 @@
obj_getProperty,
obj_setProperty
;
(function(){
obj_inherit = function(target /* source, ..*/ ) {
if (typeof target === 'function') {
target = target.prototype;
......@@ -120,31 +120,31 @@
imax = arguments.length,
source, key;
for (; i < imax; i++) {
source = typeof arguments[i] === 'function'
? arguments[i].prototype
: arguments[i];
for (key in source) {
target[key] = source[key];
}
}
return target;
};
obj_getProperty = function(obj, property) {
var chain = property.split('.'),
length = chain.length,
i = 0;
for (; i < length; i++) {
if (obj == null)
if (obj == null)
return null;
obj = obj[chain[i]];
}
return obj;
};
obj_setProperty = function(obj, property, value) {
var chain = property.split('.'),
imax = chain.length - 1,
......@@ -152,24 +152,24 @@
key;
while ( ++i < imax ) {
key = chain[i];
if (obj[key] == null)
if (obj[key] == null)
obj[key] = {};
obj = obj[key];
}
obj[chain[i]] = value;
};
}());
// end:source ../src/utils/object.js
// source ../src/utils/array.js
function arr_invoke(arr, args, ctx) {
if (arr == null || arr instanceof Array === false) {
return;
}
for (var i = 0, length = arr.length; i < length; i++) {
if (typeof arr[i] !== 'function') {
continue;
......@@ -180,9 +180,9 @@
arr[i].apply(ctx, args);
}
}
}
function arr_ensure(obj, xpath) {
if (!xpath) {
return obj;
......@@ -191,12 +191,12 @@
imax = arr.length - 1,
i = 0,
key;
for (; i < imax; i++) {
key = arr[i];
obj = obj[key] || (obj[key] = {});
}
key = arr[imax];
return obj[key] || (obj[key] = []);
}
......@@ -212,63 +212,63 @@
path_combine,
path_isRelative
;
(function(){
path_getDir = function(path) {
return path.substring(0, path.lastIndexOf('/') + 1);
};
path_getFile = function(path) {
path = path
.replace('file://', '')
.replace(/\\/g, '/')
.replace(/\?[^\n]+$/, '');
if (/^\/\w+:\/[^\/]/i.test(path)){
// win32 drive
return path.substring(1);
}
return path;
};
path_getExtension = function(path) {
var query = path.indexOf('?');
if (query === -1) {
return path.substring(path.lastIndexOf('.') + 1);
}
return path.substring(path.lastIndexOf('.', query) + 1, query);
};
path_resolveCurrent = function() {
if (document == null) {
return typeof module === 'undefined'
? ''
? ''
: path_win32Normalize(module.parent.filename);
}
var scripts = document.getElementsByTagName('script'),
last = scripts[scripts.length - 1],
url = last && last.getAttribute('src') || '';
if (url[0] === '/') {
return url;
}
var location = window
.location
.pathname
.replace(/\/[^\/]+\.\w+$/, '');
if (location[location.length - 1] !== '/') {
location += '/';
}
return location + url;
};
path_normalize = function(path) {
return path
.replace(/\\/g, '/')
......@@ -276,31 +276,31 @@
.replace(/([^:\/])\/{2,}/g, '$1/')
;
};
path_win32Normalize = function(path){
path = path_normalize(path);
if (path.substring(0, 5) === 'file:')
return path;
return 'file:///' + path;
};
path_resolveUrl = function(url, parent) {
if (reg_hasProtocol.test(url))
if (reg_hasProtocol.test(url))
return path_collapse(url);
if (url.substring(0, 2) === './')
if (url.substring(0, 2) === './')
url = url.substring(2);
if (url[0] === '/' && parent != null && parent.base != null) {
url = path_combine(parent.base, url);
if (reg_hasProtocol.test(url))
if (reg_hasProtocol.test(url))
return path_collapse(url);
}
if (url[0] === '/' && cfg.path) {
url = cfg.path + url.substring(1);
if (reg_hasProtocol.test(url))
if (reg_hasProtocol.test(url))
return path_collapse(url);
}
if (url[0] === '/') {
......@@ -310,13 +310,13 @@
} else if (parent != null && parent.location != null) {
url = parent.location + url;
}
return path_collapse(url);
};
path_isRelative = function(path) {
var c = path.charCodeAt(0);
switch (c) {
case 47:
// /
......@@ -327,10 +327,10 @@
// h
return reg_hasProtocol.test(path) === false;
}
return true;
};
path_combine = function() {
var out = '',
imax = arguments.length,
......@@ -339,96 +339,96 @@
;
while ( ++i < imax ){
x = arguments[i];
if (!x)
if (!x)
continue;
x = path_normalize(x);
if (out === '') {
out = x;
continue;
}
if (out[out.length - 1] !== '/')
if (out[out.length - 1] !== '/')
out += '/'
if (x[0] === '/')
if (x[0] === '/')
x = x.substring(1);
out += x;
}
return out;
};
function path_collapse(url) {
while (url.indexOf('../') !== -1) {
url = url.replace(reg_subFolder, '');
}
return url.replace(/\/\.\//g, '/');
}
}());
// end:source ../src/utils/path.js
// source ../src/utils/tree.js
var tree_resolveUsage;
(function(){
tree_resolveUsage = function(resource, usage, next){
var use = [],
imax = usage.length,
i = -1,
obj, path, name, index, parent
;
while( ++i < imax ) {
name = path = usage[i];
index = path.indexOf('.');
if ( index !== -1) {
name = path.substring(0, index);
path = path.substring(index + 1);
}
parent = use_resolveParent(name, resource.parent, resource);
if (parent == null)
if (parent == null)
return null;
if (parent.state !== 4){
resource.state = 3;
parent.on(4, next, parent, 'push');
return null;
}
obj = parent.exports;
if (name !== path)
if (name !== path)
obj = obj_getProperty(obj, path);
// if DEBUG
(typeof obj === 'object' && obj == null)
&& console.warn('<include:use> Used resource has no exports', name, resource.url);
// endif
use[i] = obj;
}
return use;
};
function use_resolveParent(name, resource, initiator){
if (resource == null) {
// if DEBUG
console.warn('<include> Usage Not Found:', name);
console.warn('- Ensure to have it included before with the correct alias')
console.warn('- Initiator Stacktrace:');
var arr = [], res = initiator;
while(res != null){
arr.push(res.url);
......@@ -436,61 +436,61 @@
}
console.warn(arr.join('\n'));
// endif
return null;
}
var includes = resource.includes,
i = -1,
imax = includes.length,
include, exports, alias
;
while( ++i < imax ) {
include = includes[i];
alias = include.route.alias || Routes.parseAlias(include.route);
if (alias === name)
if (alias === name)
return include.resource;
}
return use_resolveParent(name, resource.parent, initiator);
}
}());
// end:source ../src/utils/tree.js
// source ../src/2.Routing.js
var RoutesLib = function() {
var routes = {},
regexpAlias = /([^\\\/]+)\.\w+$/;
return {
/**
* @param route {String} = Example: '.reference/libjs/{0}/{1}.js'
*/
register: function(namespace, route, currentInclude) {
if (typeof route === 'string' && path_isRelative(route)) {
var res = currentInclude || include,
location = res.location || path_getDir(res.url || path_resolveCurrent());
if (path_isRelative(location)) {
location = '/' + location;
}
route = location + route;
}
routes[namespace] = route instanceof Array ? route : route.split(/[\{\}]/g);
},
/**
* @param {String} template = Example: 'scroller/scroller.min?ui=black'
*/
......@@ -505,28 +505,28 @@
x,
length,
arr;
if (aliasIndex !== -1){
alias = template.substring(aliasIndex + 2);
template = template.substring(0, aliasIndex);
}
if (questionMark !== -1) {
arr = template.substring(questionMark + 1).split('&');
params = {};
for (i = 0, length = arr.length; i < length; i++) {
x = arr[i].split('=');
params[x[0]] = x[1];
}
template = template.substring(0, questionMark);
}
template = template.split('/');
route = routes[namespace];
if (route == null){
return {
path: template.join('/'),
......@@ -534,25 +534,25 @@
alias: alias
};
}
path = route[0];
for (i = 1; i < route.length; i++) {
if (i % 2 === 0) {
path += route[i];
} else {
/** if template provides less "breadcrumbs" than needed -
* take always the last one for failed peaces */
var index = route[i] << 0;
if (index > template.length - 1) {
index = template.length - 1;
}
path += template[index];
if (i === route.length - 2){
for(index++; index < template.length; index++){
path += '/' + template[index];
......@@ -560,14 +560,14 @@
}
}
}
return {
path: path,
params: params,
alias: alias
};
},
/**
* @arg includeData :
* 1. string - URL to resource
......@@ -584,11 +584,11 @@
*/
each: function(type, includeData, fn, namespace, xpath) {
var key;
if (includeData == null) {
return;
}
if (type === 'lazy' && xpath == null) {
for (key in includeData) {
this.each(type, includeData[key], fn, null, key);
......@@ -609,49 +609,49 @@
}
return;
}
if (typeof includeData === 'string') {
var x = this.resolve(namespace, includeData);
if (namespace){
namespace += '.' + includeData;
}
fn(namespace, x, xpath);
return;
}
console.error('Include Package is invalid', arguments);
},
getRoutes: function(){
return routes;
},
parseAlias: function(route){
var path = route.path,
result = regexpAlias.exec(path);
return result && result[1];
}
};
};
var Routes = RoutesLib();
/*{test}
console.log(JSON.stringify(Routes.resolve(null,'scroller.js::Scroller')));
Routes.register('lib', '.reference/libjs/{0}/lib/{1}.js');
console.log(JSON.stringify(Routes.resolve('lib','scroller::Scroller')));
console.log(JSON.stringify(Routes.resolve('lib','scroller/scroller.mobile?ui=black')));
Routes.register('framework', '.reference/libjs/framework/{0}.js');
console.log(JSON.stringify(Routes.resolve('framework','dom/jquery')));
*/
// end:source ../src/2.Routing.js
// source ../src/3.Events.js
......@@ -663,20 +663,20 @@
};
}
var readycollection = [];
function onReady() {
Events.ready = fn_doNothing;
if (readycollection == null) {
return;
}
arr_invoke(readycollection);
readycollection = null;
}
/** TODO: clean this */
if ('onreadystatechange' in document) {
document.onreadystatechange = function() {
if (/complete|interactive/g.test(document.readyState) === false) {
......@@ -689,294 +689,294 @@
}else {
window.onload = onReady;
}
return {
ready: function(callback) {
readycollection.unshift(callback);
}
};
})(document);
// end:source ../src/3.Events.js
// source ../src/6.ScriptStack.js
/** @TODO Refactor loadBy* {combine logic} */
var ScriptStack = (function() {
var head,
currentResource,
stack = [],
_cb_complete = [],
_paused;
function loadScript(url, callback) {
//console.log('load script', url);
var tag = document.createElement('script');
tag.type = 'text/javascript';
tag.src = url;
if ('onreadystatechange' in tag) {
tag.onreadystatechange = function() {
(this.readyState === 'complete' || this.readyState === 'loaded') && callback();
};
} else {
tag.onload = tag.onerror = callback;
}
;(head || (head = document.getElementsByTagName('head')[0])).appendChild(tag);
}
function loadByEmbedding() {
if (_paused) {
return;
}
if (stack.length === 0){
trigger_complete();
return;
}
if (currentResource != null) {
return;
}
var resource = (currentResource = stack[0]);
if (resource.state === 1) {
return;
}
resource.state = 1;
global.include = resource;
global.iparams = resource.route.params;
function resourceLoaded(e) {
if (e && e.type === 'error') {
console.log('Script Loaded Error', resource.url);
}
var i = 0,
length = stack.length;
for (; i < length; i++) {
if (stack[i] === resource) {
stack.splice(i, 1);
break;
}
}
if (i === length) {
console.error('Loaded Resource not found in stack', resource);
return;
}
if (resource.state !== 2.5)
resource.readystatechanged(3);
currentResource = null;
loadByEmbedding();
}
if (resource.source) {
__eval(resource.source, resource);
resourceLoaded();
return;
}
loadScript(resource.url, resourceLoaded);
}
function processByEval() {
if (_paused) {
return;
}
if (stack.length === 0){
trigger_complete();
return;
}
if (currentResource != null) {
return;
}
var resource = stack[0];
if (resource.state < 2) {
return;
}
currentResource = resource;
resource.state = 1;
global.include = resource;
//console.log('evaling', resource.url, stack.length);
__eval(resource.source, resource);
for (var i = 0, x, length = stack.length; i < length; i++) {
x = stack[i];
if (x === resource) {
stack.splice(i, 1);
break;
}
}
if (resource.state !== 2.5)
resource.readystatechanged(3);
currentResource = null;
processByEval();
}
function trigger_complete() {
var i = -1,
imax = _cb_complete.length;
while (++i < imax) {
_cb_complete[i]();
}
_cb_complete.length = 0;
}
return {
load: function(resource, parent, forceEmbed) {
this.add(resource, parent);
if (!cfg.eval || forceEmbed) {
loadByEmbedding();
return;
}
// was already loaded, with custom loader for example
if (resource.source) {
resource.state = 2;
processByEval();
return;
}
XHR(resource, function(resource, response) {
if (!response) {
console.error('Not Loaded:', resource.url);
console.error('- Initiator:', resource.parent && resource.parent.url || '<root resource>');
}
resource.source = response;
resource.state = 2;
processByEval();
});
},
add: function(resource, parent){
if (resource.priority === 1)
return stack.unshift(resource);
if (parent == null)
return stack.push(resource);
var imax = stack.length,
i = -1
;
// move close to parent
while( ++i < imax){
if (stack[i] === parent)
return stack.splice(i, 0, resource);
}
// was still not added
stack.push(resource);
},
/* Move resource in stack close to parent */
moveToParent: function(resource, parent) {
var length = stack.length,
parentIndex = -1,
resourceIndex = -1,
i;
for (i = 0; i < length; i++) {
if (stack[i] === resource) {
resourceIndex = i;
break;
}
}
if (resourceIndex === -1) {
return;
}
for (i= 0; i < length; i++) {
if (stack[i] === parent) {
parentIndex = i;
break;
}
}
if (parentIndex === -1) {
return;
}
if (resourceIndex < parentIndex) {
return;
}
stack.splice(resourceIndex, 1);
stack.splice(parentIndex, 0, resource);
},
pause: function(){
_paused = true;
},
resume: function(){
_paused = false;
if (currentResource != null)
return;
this.touch();
},
touch: function(){
var fn = cfg.eval
? processByEval
: loadByEmbedding
;
fn();
},
complete: function(callback){
if (_paused !== true && stack.length === 0) {
callback();
return;
}
_cb_complete.push(callback);
}
};
var head,
currentResource,
stack = [],
_cb_complete = [],
_paused;
function loadScript(url, callback) {
//console.log('load script', url);
var tag = document.createElement('script');
tag.type = 'text/javascript';
tag.src = url;
if ('onreadystatechange' in tag) {
tag.onreadystatechange = function() {
(this.readyState === 'complete' || this.readyState === 'loaded') && callback();
};
} else {
tag.onload = tag.onerror = callback;
}
;(head || (head = document.getElementsByTagName('head')[0])).appendChild(tag);
}
function loadByEmbedding() {
if (_paused) {
return;
}
if (stack.length === 0){
trigger_complete();
return;
}
if (currentResource != null) {
return;
}
var resource = (currentResource = stack[0]);
if (resource.state === 1) {
return;
}
resource.state = 1;
global.include = resource;
global.iparams = resource.route.params;
function resourceLoaded(e) {
if (e && e.type === 'error') {
console.log('Script Loaded Error', resource.url);
}
var i = 0,
length = stack.length;
for (; i < length; i++) {
if (stack[i] === resource) {
stack.splice(i, 1);
break;
}
}
if (i === length) {
console.error('Loaded Resource not found in stack', resource);
return;
}
if (resource.state !== 2.5)
resource.readystatechanged(3);
currentResource = null;
loadByEmbedding();
}
if (resource.source) {
__eval(resource.source, resource);
resourceLoaded();
return;
}
loadScript(resource.url, resourceLoaded);
}
function processByEval() {
if (_paused) {
return;
}
if (stack.length === 0){
trigger_complete();
return;
}
if (currentResource != null) {
return;
}
var resource = stack[0];
if (resource.state < 2) {
return;
}
currentResource = resource;
resource.state = 1;
global.include = resource;
//console.log('evaling', resource.url, stack.length);
__eval(resource.source, resource);
for (var i = 0, x, length = stack.length; i < length; i++) {
x = stack[i];
if (x === resource) {
stack.splice(i, 1);
break;
}
}
if (resource.state !== 2.5)
resource.readystatechanged(3);
currentResource = null;
processByEval();
}
function trigger_complete() {
var i = -1,
imax = _cb_complete.length;
while (++i < imax) {
_cb_complete[i]();
}
_cb_complete.length = 0;
}
return {
load: function(resource, parent, forceEmbed) {
this.add(resource, parent);
if (!cfg.eval || forceEmbed) {
loadByEmbedding();
return;
}
// was already loaded, with custom loader for example
if (resource.source) {
resource.state = 2;
processByEval();
return;
}
XHR(resource, function(resource, response) {
if (!response) {
console.error('Not Loaded:', resource.url);
console.error('- Initiator:', resource.parent && resource.parent.url || '<root resource>');
}
resource.source = response;
resource.state = 2;
processByEval();
});
},
add: function(resource, parent){
if (resource.priority === 1)
return stack.unshift(resource);
if (parent == null)
return stack.push(resource);
var imax = stack.length,
i = -1
;
// move close to parent
while( ++i < imax){
if (stack[i] === parent)
return stack.splice(i, 0, resource);
}
// was still not added
stack.push(resource);
},
/* Move resource in stack close to parent */
moveToParent: function(resource, parent) {
var length = stack.length,
parentIndex = -1,
resourceIndex = -1,
i;
for (i = 0; i < length; i++) {
if (stack[i] === resource) {
resourceIndex = i;
break;
}
}
if (resourceIndex === -1) {
return;
}
for (i= 0; i < length; i++) {
if (stack[i] === parent) {
parentIndex = i;
break;
}
}
if (parentIndex === -1) {
return;
}
if (resourceIndex < parentIndex) {
return;
}
stack.splice(resourceIndex, 1);
stack.splice(parentIndex, 0, resource);
},
pause: function(){
_paused = true;
},
resume: function(){
_paused = false;
if (currentResource != null)
return;
this.touch();
},
touch: function(){
var fn = cfg.eval
? processByEval
: loadByEmbedding
;
fn();
},
complete: function(callback){
if (_paused !== true && stack.length === 0) {
callback();
return;
}
_cb_complete.push(callback);
}
};
})();
// end:source ../src/6.ScriptStack.js
// source ../src/4.IncludeDeferred.js
// source ../src/4.IncludeDeferred.js
/**
* STATES:
* 0: Resource Created
......@@ -986,30 +986,30 @@
* 3: Evaluated - Childs Loading
* 4: Childs Loaded - Completed
*/
var IncludeDeferred = function() {
this.callbacks = [];
this.state = -1;
};
IncludeDeferred.prototype = { /** state observer */
on: function(state, callback, sender, mutator) {
if (this === sender && this.state === -1) {
callback(this);
return this;
}
// this === sender in case when script loads additional
// resources and there are already parents listeners
if (mutator == null) {
mutator = (this.state < 3 || this === sender)
? 'unshift'
: 'push'
;
}
state <= this.state ? callback(this) : this.callbacks[mutator]({
state: state,
callback: callback
......@@ -1017,16 +1017,16 @@
return this;
},
readystatechanged: function(state) {
var i, length, x, currentInclude;
if (state > this.state) {
this.state = state;
}
if (this.state === 3) {
var includes = this.includes;
if (includes != null && includes.length) {
for (i = 0; i < includes.length; i++) {
if (includes[i].resource.state !== 4) {
......@@ -1034,33 +1034,33 @@
}
}
}
this.state = 4;
}
i = 0;
length = this.callbacks.length;
if (length === 0){
return;
}
//do not set asset resource to global
if (this.type === 'js' && this.state === 4) {
currentInclude = global.include;
global.include = this;
}
for (; i < length; i++) {
x = this.callbacks[i];
if (x == null || x.state > this.state) {
continue;
}
this.callbacks.splice(i,1);
length--;
i--;
/* if (!DEBUG)
try {
*/
......@@ -1070,19 +1070,19 @@
console.error(error.toString(), 'file:', this.url);
}
*/
if (this.state < 4){
break;
}
}
if (currentInclude != null){
global.include = currentInclude;
}
},
/** assets loaded and DomContentLoaded */
ready: function(callback) {
var that = this;
return this.on(4, function() {
......@@ -1091,7 +1091,7 @@
});
}, this);
},
/** assets loaded */
done: function(callback) {
var that = this;
......@@ -1105,33 +1105,33 @@
? 0
: includes.length
;
if (length > 0 && this.response == null){
this.response = {};
var resource,
route;
for(var i = 0, x; i < length; i++){
x = includes[i];
resource = x.resource;
route = x.route;
if (typeof resource.exports === 'undefined')
continue;
var type = resource.type;
switch (type) {
case 'js':
case 'load':
case 'ajax':
var alias = route.alias || Routes.parseAlias(route),
obj = type === 'js'
? (this.response)
: (this.response[type] || (this.response[type] = {}))
;
if (alias != null) {
obj_setProperty(obj, alias, resource.exports);
break;
......@@ -1140,8 +1140,8 @@
break;
}
}
}
}
var response = this.response || emptyResponse;
var that = this;
if (this._use == null && this._usage != null){
......@@ -1157,41 +1157,41 @@
callback.apply(null, [response].concat(this._use));
return;
}
callback(response);
}
};
// end:source ../src/4.IncludeDeferred.js
// source ../src/5.Include.js
// end:source ../src/4.IncludeDeferred.js
// source ../src/5.Include.js
var Include,
IncludeLib = {};
(function(IncludeDeferred) {
Include = function() {
IncludeDeferred.call(this);
};
stub_release(Include.prototype);
obj_inherit(Include, IncludeDeferred, {
// Array: exports
_use: null,
// Array: names
_usage: null,
isBrowser: true,
isNode: false,
setCurrent: function(data) {
var url = data.url,
resource = this.getResourceById(url, 'js');
if (resource == null) {
if (url[0] === '/' && this.base)
url = this.base + url.substring(1);
var resource = new Resource(
'js'
, { path: url }
......@@ -1203,19 +1203,19 @@
if (resource.state < 3) {
console.error("<include> Resource should be loaded", data);
}
/**@TODO - probably state shoulb be changed to 2 at this place */
resource.state = 3;
global.include = resource;
},
cfg: function(arg) {
switch (typeof arg) {
case 'object':
var key, value;
for (key in arg) {
value = arg[key];
switch(key){
case 'loader':
for(var x in value){
......@@ -1231,7 +1231,7 @@
cfg[key] = value;
break;
}
}
break;
case 'string':
......@@ -1251,12 +1251,12 @@
if (mix == null) {
return Routes.getRoutes();
}
if (arguments.length === 2) {
Routes.register(mix, arguments[1], this);
return this;
}
for (var key in mix) {
Routes.register(key, mix[key], this);
}
......@@ -1273,36 +1273,36 @@
},
/** @TODO - `id` property seems to be unsed and always equal to `url` */
register: function(_bin) {
var base = this.base,
key,
info,
infos,
imax,
i;
function transform(info){
if (base == null)
if (base == null)
return info;
if (info.url[0] === '/')
info.url = base + info.url.substring(1);
if (info.parent[0] === '/')
info.parent = base + info.parent.substring(1);
info.id = info.url;
return info;
}
for (key in _bin) {
infos = _bin[key];
imax = infos.length;
i = -1;
while ( ++i < imax ) {
info = transform(infos[i]);
var id = info.id,
url = info.url,
namespace = info.namespace,
......@@ -1310,17 +1310,17 @@
resource = new Resource(),
state = info.state
;
if (! (id || url))
if (! (id || url))
continue;
if (url) {
if (url[0] === '/') {
url = url.substring(1);
}
resource.location = path_getDir(url);
}
resource.state = state == null
? (key === 'js' ? 3 : 4)
: state
......@@ -1330,7 +1330,7 @@
resource.url = url || id;
resource.parent = parent;
resource.base = parent && parent.base || base;
switch (key) {
case 'load':
case 'lazy':
......@@ -1341,13 +1341,13 @@
}
resource.exports = container.innerHTML;
if (CustomLoader.exists(resource)){
resource.state = 3;
CustomLoader.load(resource, CustomLoader_onComplete);
}
break;
}
//
(bin[key] || (bin[key] = {}))[id] = resource;
}
......@@ -1366,42 +1366,42 @@
if (url == null) {
resource = new Include();
resource.state = 4;
return resource;
}
resource = new Resource();
resource.state = 4;
resource.location = path_getDir(path_normalize(url));
resource.parent = parent;
return resource;
},
getResource: function(url, type){
if (this.base && url[0] === '/')
url = this.base + url.substring(1);
return incl_getResource(url, type)
},
getResourceById: function(url, type){
var _bin = bin[type],
_res = _bin[url];
if (_res != null)
if (_res != null)
return _res;
if (this.base && url[0] === '/') {
_res = _bin[path_combine(this.base, url)];
if (_res != null)
if (_res != null)
return _res;
}
if (this.base && this.location) {
_res = _bin[path_combine(this.base, this.location, url)];
if (_res != null)
if (_res != null)
return _res;
}
if (this.location) {
_res = _bin[path_combine(this.location, url)];
if (_res != null)
if (_res != null)
return _res;
}
return null;
......@@ -1409,18 +1409,18 @@
getResources: function(){
return bin;
},
plugin: function(pckg, callback) {
var urls = [],
length = 0,
j = 0,
i = 0,
onload = function(url, response) {
j++;
embedPlugin(response);
if (j === length - 1 && callback) {
callback();
callback = null;
......@@ -1429,98 +1429,98 @@
Routes.each('', pckg, function(namespace, route) {
urls.push(route.path[0] === '/' ? route.path.substring(1) : route.path);
});
length = urls.length;
for (; i < length; i++) {
XHR(urls[i], onload);
}
return this;
},
client: function(){
if (cfg.server === true)
if (cfg.server === true)
stub_freeze(this);
return this;
},
server: function(){
if (cfg.server !== true)
if (cfg.server !== true)
stub_freeze(this);
return this;
},
use: function(){
if (this.parent == null) {
console.error('<include.use> Parent resource is undefined');
return this;
}
this._usage = arguments;
return this;
},
pauseStack: fn_proxy(ScriptStack.pause, ScriptStack),
resumeStack: fn_proxy(ScriptStack.resume, ScriptStack),
allDone: function(callback){
ScriptStack.complete(function(){
var pending = include.getPending('js'),
await = pending.length;
if (await === 0) {
callback();
return;
}
var i = -1,
imax = await;
while( ++i < imax ){
pending[i].on(4, check);
}
function check() {
if (--await < 1)
if (--await < 1)
callback();
}
});
},
getPending: function(type){
var resources = [],
res, key, id;
for(key in bin){
if (type != null && type !== key)
if (type != null && type !== key)
continue;
for (id in bin[key]){
res = bin[key][id];
if (res.state < 4)
resources.push(res);
}
}
return resources;
},
Lib: IncludeLib
});
// >> FUNCTIONS
function incl_getResource(url, type) {
var id = url;
if (path_isRelative(url) === true)
if (path_isRelative(url) === true)
id = '/' + id;
if (type != null){
return bin[type][id];
}
for (var key in bin) {
if (bin[key].hasOwnProperty(id)) {
return bin[key][id];
......@@ -1528,12 +1528,12 @@
}
return null;
}
function embedPlugin(source) {
eval(source);
}
function enableModules() {
if (typeof Object.defineProperty === 'undefined'){
console.warn('Browser do not support Object.defineProperty');
......@@ -1544,7 +1544,7 @@
return global.include;
}
});
Object.defineProperty(global, 'exports', {
get: function() {
var current = global.include;
......@@ -1555,26 +1555,26 @@
}
});
}
function includePackage(resource, type, mix){
var pckg = mix.length === 1 ? mix[0] : __array_slice.call(mix);
if (resource instanceof Resource) {
return resource.include(type, pckg);
}
return new Resource('js').include(type, pckg);
}
function createIncluder(type) {
return function(){
return includePackage(this, type, arguments);
};
}
function doNothing() {
return this;
}
function stub_freeze(include) {
include.js =
include.css =
......@@ -1585,25 +1585,25 @@
include.inject =
doNothing;
}
function stub_release(proto) {
var fns = ['js', 'css', 'load', 'ajax', 'embed', 'lazy'],
i = fns.length;
while (--i !== -1){
proto[fns[i]] = createIncluder(fns[i]);
}
proto['inject'] = proto.js;
}
}(IncludeDeferred));
// end:source ../src/5.Include.js
// end:source ../src/5.Include.js
// source ../src/7.CustomLoader.js
var CustomLoader = (function() {
// source loader/json.js
var JSONParser = {
process: function(source, res){
try {
......@@ -1614,32 +1614,32 @@
}
}
};
// end:source loader/json.js
cfg.loader = {
json : JSONParser
};
function loader_isInstance(x) {
if (typeof x === 'string')
return false;
return typeof x.ready === 'function' || typeof x.process === 'function';
}
function createLoader(url) {
var extension = path_getExtension(url),
loader = cfg.loader[extension];
if (loader_isInstance(loader)) {
return loader;
}
var path = loader,
namespace;
if (typeof path === 'object') {
// is route {namespace: path}
for (var key in path) {
......@@ -1648,7 +1648,7 @@
break;
}
}
return (cfg.loader[extension] = new Resource(
'js',
Routes.resolve(namespace, path),
......@@ -1659,54 +1659,54 @@
1
));
}
function loader_completeDelegate(callback, resource) {
return function(response){
callback(resource, response);
};
}
function loader_process(source, resource, loader, callback) {
if (loader.process == null) {
callback(resource, source);
return;
}
var delegate = loader_completeDelegate(callback, resource),
syncResponse = loader.process(source, resource, delegate);
// match also null
if (typeof syncResponse !== 'undefined') {
callback(resource, syncResponse);
}
}
function tryLoad(resource, loader, callback) {
if (typeof resource.exports === 'string') {
loader_process(resource.exports, resource, loader, callback);
return;
}
function onLoad(resource, response){
loader_process(response, resource, loader, callback);
}
if (loader.load)
if (loader.load)
return loader.load(resource, onLoad);
XHR(resource, onLoad);
}
return {
load: function(resource, callback) {
var loader = createLoader(resource.url);
if (loader.process) {
tryLoad(resource, loader, callback);
return;
}
loader.on(4, function() {
tryLoad(resource, loader.exports, callback);
}, null, 'push');
......@@ -1715,12 +1715,12 @@
if (!resource.url) {
return false;
}
var ext = path_getExtension(resource.url);
return cfg.loader.hasOwnProperty(ext);
},
/**
* IHandler:
* { process: function(content) { return _handler(content); }; }
......@@ -1731,20 +1731,20 @@
register: function(extension, handler){
if (typeof handler === 'string'){
var resource = include;
if (resource.location == null) {
if (resource.location == null) {
resource = {
location: path_getDir(path_resolveCurrent())
};
}
handler = path_resolveUrl(handler, resource);
}
cfg.loader[extension] = handler;
}
};
}());
// end:source ../src/7.CustomLoader.js
// source ../src/8.LazyModule.js
var LazyModule = {
......@@ -1757,10 +1757,10 @@
obj = obj[prop] || (obj[prop] = {});
}
arr = null;
Object.defineProperty(obj, module, {
get: function() {
delete obj[module];
try {
var r = __eval(code, global.include);
......@@ -1782,18 +1782,18 @@
// end:source ../src/8.LazyModule.js
// source ../src/9.Resource.js
var Resource;
(function(Include, Routes, ScriptStack, CustomLoader) {
Resource = function(type, route, namespace, xpath, parent, id, priority) {
Include.call(this);
this.childLoaded = fn_proxy(this.childLoaded, this);
var url = route && route.path;
if (url != null)
if (url != null)
this.url = url = path_resolveUrl(url, parent);
this.type = type;
this.xpath = xpath;
this.route = route;
......@@ -1801,44 +1801,44 @@
this.priority = priority;
this.namespace = namespace;
this.base = parent && parent.base;
if (id == null && url)
if (id == null && url)
id = (path_isRelative(url) ? '/' : '') + url;
var resource = bin[type] && bin[type][id];
if (resource) {
if (resource.state < 4 && type === 'js')
if (resource.state < 4 && type === 'js')
ScriptStack.moveToParent(resource, parent);
return resource;
}
if (url == null) {
this.state = 3;
this.location = path_getDir(path_resolveCurrent());
return this;
}
this.state = 0;
this.location = path_getDir(url);
(bin[type] || (bin[type] = {}))[id] = this;
if (cfg.version)
if (cfg.version)
this.url += (this.url.indexOf('?') === -1 ? '?' : '&') + 'v=' + cfg.version;
return process(this);
};
Resource.prototype = obj_inherit(Resource, Include, {
state: null,
location: null,
includes: null,
response: null,
url: null,
base: null,
type: null,
......@@ -1847,12 +1847,12 @@
parent: null,
priority: null,
namespace: null,
setBase: function(baseUrl){
this.base = baseUrl;
return this;
},
childLoaded: function(child) {
var resource = this,
includes = resource.includes;
......@@ -1871,23 +1871,23 @@
},
create: function(type, route, namespace, xpath, id) {
var resource;
this.state = this.state >= 3
? 3
: 2;
this.response = null;
if (this.includes == null)
if (this.includes == null)
this.includes = [];
resource = new Resource(type, route, namespace, xpath, this, id);
this.includes.push({
resource: resource,
route: route
});
return resource;
},
include: function(type, pckg) {
......@@ -1895,7 +1895,7 @@
children = [],
child;
Routes.each(type, pckg, function(namespace, route, xpath) {
if (that.route != null && that.route.path === route.path) {
// loading itself
return;
......@@ -1903,46 +1903,46 @@
child = that.create(type, route, namespace, xpath);
children.push(child);
});
var i = -1,
imax = children.length;
while ( ++i < imax ){
children[i].on(4, this.childLoaded);
}
return this;
},
pause: function(){
this.state = 2.5;
var that = this;
return function(exports){
if (arguments.length === 1)
if (arguments.length === 1)
that.exports = exports;
that.readystatechanged(3);
};
},
getNestedOfType: function(type){
return resource_getChildren(this.includes, type);
}
});
// private
function process(resource) {
var type = resource.type,
parent = resource.parent,
url = resource.url;
if (document == null && type === 'css') {
resource.state = 4;
return resource;
}
if (CustomLoader.exists(resource) === false) {
switch (type) {
case 'js':
......@@ -1956,7 +1956,7 @@
break;
case 'css':
resource.state = 4;
var tag = document.createElement('link');
tag.href = url;
tag.rel = "stylesheet";
......@@ -1965,24 +1965,24 @@
break;
}
} else {
if ('js' === type || 'embed' === type) {
ScriptStack.add(resource, resource.parent);
}
CustomLoader.load(resource, onXHRCompleted);
}
return resource;
}
function onXHRCompleted(resource, response) {
if (!response) {
console.warn('Resource cannt be loaded', resource.url);
//- resource.readystatechanged(4);
//- return;
}
switch (resource.type) {
case 'js':
case 'embed':
......@@ -2004,46 +2004,46 @@
document.getElementsByTagName('head')[0].appendChild(tag);
break;
}
resource.readystatechanged(4);
}
function resource_getChildren(includes, type, out) {
if (includes == null)
if (includes == null)
return null;
if (out == null)
if (out == null)
out = [];
var imax = includes.length,
i = -1,
x;
while ( ++i < imax ){
x = includes[i].resource;
if (type === x.type)
if (type === x.type)
out.push(x);
if (x.includes != null)
if (x.includes != null)
resource_getChildren(x.includes, type, out);
}
return out;
}
}(Include, Routes, ScriptStack, CustomLoader));
// end:source ../src/9.Resource.js
// source ../src/10.export.js
IncludeLib.Routes = RoutesLib;
IncludeLib.Resource = Resource;
IncludeLib.ScriptStack = ScriptStack;
IncludeLib.registerLoader = CustomLoader.register;
exports.include = new Include();
exports.includeLib = IncludeLib;
// end:source ../src/10.export.js
}));
......@@ -2051,14 +2051,14 @@
function __eval(source, include) {
"use strict";
var iparams = include && include.route.params;
/* if !DEBUG
try {
*/
return eval.call(window, source);
/* if !DEBUG
} catch (error) {
error.url = include && include.url;
......@@ -2066,6 +2066,6 @@ function __eval(source, include) {
console.error(error);
}
*/
}
// end:source ../src/global-vars.js
\ No newline at end of file
(function(root, factory){
"use strict";
if (root == null) {
root = typeof window !== 'undefined' && typeof document !== 'undefined'
? window
root = typeof window !== 'undefined' && typeof document !== 'undefined'
? window
: global;
}
root.ruta = factory(root);
}(this, function(global){
"use strict";
// source ../src/vars.js
var mask = global.mask || Mask;
// settings
/** define if routes like '/path' are strict by default,
* or set explicit '!/path' - strict, '^/path' - not strict
*
......@@ -30,13 +30,13 @@
// source ../src/utils/log.js
var log_error;
(function(){
log_error = function(){
var args = _Array_slice.call(arguments);
console.error.apply(console, ['Ruta'].concat(args));
};
}());
// end:source ../src/utils/log.js
// source ../src/utils/path.js
......@@ -45,152 +45,152 @@
path_join,
path_fromCLI
;
(function(){
path_normalize = function(str) {
var length = str.length,
i = 0,
j = length - 1;
for(; i < length; i++) {
if (str[i] === '/')
if (str[i] === '/')
continue;
break;
}
for (; j > i; j--) {
if (str[j] === '/')
if (str[j] === '/')
continue;
break;
}
return str.substring(i, j + 1);
};
path_split = function(path) {
path = path_normalize(path);
return path === ''
? []
: path.split('/');
};
path_join = function(pathParts) {
return '/' + pathParts.join('/');
};
path_fromCLI = function(commands){
if (typeof commands === 'string')
if (typeof commands === 'string')
commands = cli_split(commands);
var parts = cli_parseArguments(commands);
return parts_serialize(parts);
};
// == private
function cli_split(string){
var args = string.trim().split(/\s+/);
var imax = args.length,
i = -1,
c, arg;
while ( ++i < imax ){
arg = args[i];
if (arg.length === 0)
if (arg.length === 0)
continue;
c = arg[0];
if (c !== '"' && c !== "'")
if (c !== '"' && c !== "'")
continue;
var start = i;
for( ; i < imax; i++ ){
arg = args[i];
if (arg[arg.length - 1] === c) {
var str = args
.splice(start, i - start + 1)
.join(' ')
.slice(1, -1)
;
args.splice(start, 0, str);
imax = args.length;
break;
}
}
}
return args;
}
function cli_parseArguments(argv){
var imax = argv.length,
i = 0,
params = {},
args = [],
key, val, x;
for (; i < imax; i++){
x = argv[i];
if (x[0] === '-') {
key = x.replace(/^[\-]+/, '');
if (i < imax - 1 && argv[i + 1][0] !== '-') {
val = argv[i + 1];
i++;
} else {
val = true;
}
params[key] = val;
continue;
}
args.push(x);
}
return {
path: args,
query: params
};
};
}
}());
// end:source ../src/utils/path.js
// source ../src/utils/query.js
var query_deserialize,
query_serialize
;
(function(){
query_deserialize = function(query, delimiter) {
if (delimiter == null)
if (delimiter == null)
delimiter = '&';
var obj = {},
parts = query.split(delimiter),
i = 0,
imax = parts.length,
x, val;
for (; i < imax; i++) {
x = parts[i].split('=');
val = x[1] == null
......@@ -202,45 +202,45 @@
return obj;
};
query_serialize = function(params, delimiter) {
if (delimiter == null)
if (delimiter == null)
delimiter = '&';
var query = '',
key, val;
for(key in params) {
val = params[key];
if (val == null)
if (val == null)
continue;
// serialize as flag
if (typeof val === 'boolean')
if (typeof val === 'boolean')
val = null;
query = query + (query ? delimiter : '') + key;
if (val != null)
if (val != null)
query += '=' + encode(val);
}
return query;
};
// = private
function obj_setProperty(obj, property, value) {
var chain = property.split('.'),
imax = chain.length,
i = -1,
key;
while ( ++i < imax - 1) {
key = chain[i];
if (obj[key] == null)
if (obj[key] == null)
obj[key] = {};
obj = obj[key];
}
obj[chain[i]] = value;
}
function decode(str) {
......@@ -260,92 +260,92 @@
}
}
}());
// end:source ../src/utils/query.js
// source ../src/utils/rgx.js
var rgx_fromString,
// Url part should be completely matched, so add ^...$ and create RegExp
rgx_aliasMatcher,
// :debugger(d|debug) => { alias: 'debugger', matcher: RegExp }
rgx_parsePartWithRegExpAlias
;
(function(){
rgx_fromString = function(str, flags) {
return new RegExp(str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"), flags);
};
rgx_aliasMatcher = function(str){
if (str[0] === '^')
if (str[0] === '^')
return new RegExp(str);
var groups = str.split('|');
for (var i = 0, imax = groups.length; i < imax; i++){
groups[i] = '^' + groups[i] + '$';
}
return new RegExp(groups.join('|'));
};
rgx_parsePartWithRegExpAlias = function(str){
var pStart = str.indexOf('('),
pEnd = str.lastIndexOf(')')
;
if (pStart === -1 || pEnd === -1) {
log_error('Expected alias part with regexp', str);
return null;
}
var rgx = str.substring(pStart + 1, pEnd);
return {
alias: str.substring(1, pStart),
matcher: rgx_aliasMatcher(rgx)
};
};
}());
// end:source ../src/utils/rgx.js
// source ../src/utils/parts.js
/**
* '/foo/bar?a=b' =>
* { path: ['foo', 'bar'], query: { a: 'b' } }
*/
var parts_serialize,
parts_deserialize
;
(function(){
parts_serialize = function(parts){
var path = path_join(parts.path);
if (parts.query == null)
if (parts.query == null)
return path;
return path
+ '?'
+ query_serialize(parts.query, '&')
;
};
parts_deserialize = function(url){
var query = url.indexOf('?'),
path = query === -1
? url
: url.substring(0, query);
return {
path: path_split(path),
query: query === -1
......@@ -353,29 +353,29 @@
: query_deserialize(url.substring(query + 1), '&')
};
};
}());
// end:source ../src/utils/parts.js
// source ../src/route/Collection.js
var Routes = (function(){
// source Route.js
// source parse.js
var route_parseDefinition, // out route, definition
// path should be already matched by the route
route_parsePath // route, path
var route_parseDefinition, // out route, definition
// path should be already matched by the route
route_parsePath // route, path
;
(function(){
route_parseDefinition = function(route, definition) {
var c = definition.charCodeAt(0);
switch(c){
case 33:
......@@ -398,13 +398,13 @@
log_error('parser - expect group closing');
end ++;
}
route.match = new RegExp(definition.substring(start, end));
return;
}
var parts = definition.split('/'),
search,
searchIndex,
......@@ -414,8 +414,8 @@
c0,
index,
c1;
var last = parts[imax - 1];
searchIndex = last.indexOf('?');
if (searchIndex > (imax === 1 ? -1 : 0)) {
......@@ -423,67 +423,67 @@
search = last.substring(searchIndex + 1);
parts[imax - 1] = last.substring(0, searchIndex);
}
var matcher = '',
alias = null,
strictCount = 0;
var gettingMatcher = true,
isOptional,
isAlias,
rgx;
var array = route.path = [];
for (; i < imax; i++) {
x = parts[i];
if (x === '')
if (x === '')
continue;
c0 = x.charCodeAt(0);
c1 = x.charCodeAt(1);
isOptional = c0 === 63; /* ? */
isAlias = (isOptional ? c1 : c0) === 58; /* : */
index = 0;
if (isOptional)
if (isOptional)
index++;
if (isAlias)
if (isAlias)
index++;
if (index !== 0)
if (index !== 0)
x = x.substring(index);
// if DEBUG
if (!isOptional && !gettingMatcher)
if (!isOptional && !gettingMatcher)
log_error('Strict part found after optional', definition);
// endif
if (isOptional)
if (isOptional)
gettingMatcher = false;
var bracketIndex = x.indexOf('(');
if (isAlias && bracketIndex !== -1) {
var end = x.length - 1;
if (x[end] !== ')')
if (x[end] !== ')')
end+= 1;
rgx = new RegExp(rgx_aliasMatcher(x.substring(bracketIndex + 1, end)));
x = x.substring(0, bracketIndex);
}
if (!isOptional && !isAlias) {
array.push(x);
continue;
}
if (isAlias) {
array.push({
alias: x,
......@@ -491,100 +491,100 @@
optional: isOptional
});
}
}
if (search) {
var query = route.query = {};
parts = search.split('&');
i = -1;
imax = parts.length;
var key, value, str, eqIndex;
while(++i < imax){
str = parts[i];
eqIndex = str.indexOf('=');
if (eqIndex === -1) {
query[str] = ''; // <empty string>
continue;
}
key = str.substring(0, eqIndex);
value = str.substring(eqIndex + 1);
if (value.charCodeAt(0) === 40) {
// (
value = new RegExp(rgx_aliasMatcher(value));
}
query[key] = value;
}
if (route.path.length === 0) {
route.strict = false;
}
}
};
route_parsePath = function(route, path) {
var queryIndex = path.indexOf('?'),
query = queryIndex === -1
? null
: path.substring(queryIndex + 1),
current = {
path: path,
params: query == null
? {}
: query_deserialize(query, '&')
};
if (route.query) {
// ensura aliased queries, like ?:debugger(d|debug)
for (var key in route.query){
if (key[0] === '?')
if (key[0] === '?')
key = key.substring(1);
if (key[0] === ':') {
var alias = rgx_parsePartWithRegExpAlias(key),
name = alias.alias;
current.params[name] = getAliasedValue(current.params, alias.matcher);
}
}
}
if (queryIndex !== -1) {
path = path.substring(0, queryIndex);
}
if (route.path != null) {
var pathArr = path_split(path),
routePath = route.path,
routeLength = routePath.length,
imax = pathArr.length,
i = 0,
part,
x;
for (; i < imax; i++) {
part = pathArr[i];
x = i < routeLength ? routePath[i] : null;
if (x) {
if (typeof x === 'string')
if (typeof x === 'string')
continue;
if (x.alias) {
current.params[x.alias] = part;
continue;
......@@ -592,16 +592,16 @@
}
}
}
return current;
};
// = private
function getAliasedValue(obj, matcher) {
for (var key in obj){
if (matcher.test(key))
if (matcher.test(key))
return obj[key];
}
}
......@@ -611,321 +611,311 @@
var route_match,
route_isMatch
;
(function(){
route_match = function(url, routes, currentMethod){
var parts = parts_deserialize(url);
for (var i = 0, route, imax = routes.length; i < imax; i++){
route = routes[i];
if (route_isMatch(parts, route, currentMethod)) {
route.current = route_parsePath(route, url);
return route;
}
}
return null;
};
route_isMatch = function(parts, route, currentMethod) {
if (currentMethod != null &&
route.method != null &&
route.method !== currentMethod) {
return false;
}
if (route.match) {
return route.match.test(
typeof parts === 'string'
? parts
: parts_serialize(parts)
);
}
if (typeof parts === 'string')
if (typeof parts === 'string')
parts = parts_deserialize(parts);
// route defines some query, match these with the current path{parts}
if (route.query) {
var query = parts.query,
key, value;
if (query == null)
if (query == null)
return false;
for(key in route.query){
value = route.query[key];
var c = key[0];
if (c === ':') {
// '?:isGlob(g|glob) will match if any is present
var alias = rgx_parsePartWithRegExpAlias(key);
if (alias == null || hasKey(query, alias.matcher) === false)
return false;
continue;
}
if (c === '?')
if (c === '?')
continue;
if (typeof value === 'string') {
if (query[key] == null)
if (query[key] == null)
return false;
if (value && query[key] !== value)
if (value && query[key] !== value)
return false;
continue;
}
if (value.test && !value.test(query[key]))
if (value.test && !value.test(query[key]))
return false;
}
}
var routePath = route.path,
routeLength = routePath.length;
if (routeLength === 0) {
if (route.strict)
if (route.strict)
return parts.path.length === 0;
return true;
}
for (var i = 0, x, imax = parts.path.length; i < imax; i++){
x = routePath[i];
if (i >= routeLength)
if (i >= routeLength)
return route.strict !== true;
if (typeof x === 'string') {
if (parts.path[i] === x)
if (parts.path[i] === x)
continue;
return false;
}
if (x.matcher && x.matcher.test(parts.path[i]) === false) {
return false;
}
if (x.optional)
if (x.optional)
return true;
if (x.alias)
if (x.alias)
continue;
return false;
}
if (i < routeLength)
if (i < routeLength)
return routePath[i].optional === true;
return true;
};
function hasKey(obj, rgx){
for(var key in obj){
if (rgx.test(key))
if (rgx.test(key))
return true;
}
return false;
}
}());
// end:source match.js
var regexp_var = '([^\\\\]+)';
function Route(definition, value) {
this.method = definition.charCodeAt(0) === 36
? definition.substring(1, definition.indexOf(' ')).toUpperCase()
: null
;
if (this.method != null) {
definition = definition.substring( this.method.length + 2 );
}
this.strict = _cfg_isStrict;
this.value = value;
this.definition = definition;
route_parseDefinition(this, definition);
}
Route.prototype = {
path: null,
query: null,
value: null,
current: null
};
// end:source Route.js
function RouteCollection() {
this.routes = [];
}
RouteCollection.prototype = {
add: function(regpath, value){
this.routes.push(new Route(regpath, value));
return this;
},
get: function(path, currentMethod){
return route_match(path, this.routes, currentMethod);
},
clear: function(){
this.routes.length = 0;
return this;
}
};
RouteCollection.parse = function(definition, path){
var route = {};
route_parseDefinition(route, definition);
return route_parsePath(route, path);
};
return RouteCollection;
}());
// end:source ../src/route/Collection.js
// source ../src/emit/Location.js
var Location = (function(){
if (typeof window === 'undefined') {
return function(){};
}
// source Hash.js
function HashEmitter(listener) {
if (typeof window === 'undefined' || 'onhashchange' in window === false)
return null;
this.listener = listener;
var that = this;
window.onhashchange = function() {
that.changed(location.hash);
};
return this;
}
(function() {
function hash_normalize(hash) {
return hash.replace(/^[!#/]+/, '/');
}
HashEmitter.prototype = {
navigate: function(hash) {
if (hash == null) {
this.changed(location.hash);
return;
}
location.hash = hash;
},
changed: function(hash) {
this
.listener
.changed(hash_normalize(hash));
},
current: function() {
return hash_normalize(location.hash);
}
};
}());
// end:source Hash.js
// source History.js
function HistoryEmitter(listener){
function HistoryEmitter(listener){
if (typeof window === 'undefined')
return null;
if (!(window.history && window.history.pushState))
return null;
var that = this;
that.listener = listener;
that.initial = location.pathname;
window.onpopstate = function(){
if (that.initial === location.pathname) {
that.initial = null;
return;
}
that.changed();
};
return that;
}
(function(){
HistoryEmitter.prototype = {
navigate: function(url){
if (url == null) {
this.changed();
return;
}
history.pushState({}, null, url);
HistoryEmitter.prototype = {
navigate: function(url){
if (url == null) {
this.changed();
},
changed: function(){
this.listener.changed(location.pathname + location.search);
},
current: function(){
return location.pathname + location.search;
return;
}
};
}());
history.pushState({}, null, url);
this.initial = null;
this.changed();
},
changed: function(){
this.listener.changed(location.pathname + location.search);
},
current: function(){
return location.pathname + location.search;
}
};
// end:source History.js
function Location(collection, type) {
this.collection = collection || new Routes();
if (type) {
var Constructor = type === 'hash'
? HashEmitter
......@@ -933,25 +923,25 @@
;
this.emitter = new Constructor(this);
}
if (this.emitter == null)
if (this.emitter == null)
this.emitter = new HistoryEmitter(this);
if (this.emitter == null)
if (this.emitter == null)
this.emitter = new HashEmitter(this);
if (this.emitter == null)
if (this.emitter == null)
log_error('Router can not be initialized - (nor HistoryAPI / nor hashchange');
}
Location.prototype = {
changed: function(path){
var item = this.collection.get(path);
if (item)
this.action(item);
},
action: function(route){
if (typeof route.value === 'function') {
......@@ -971,43 +961,43 @@
return this.emitter.current();
}
};
return Location;
}());
// end:source ../src/emit/Location.js
// source ../src/ruta.js
var routes = new Routes(),
router;
function router_ensure() {
if (router == null)
if (router == null)
router = new Location(routes);
return router;
}
var Ruta = {
Collection: Routes,
setRouterType: function(type){
if (router == null)
if (router == null)
router = new Location(routes, type);
return this;
},
setStrictBehaviour: function(isStrict){
_cfg_isStrict = isStrict;
return this;
},
add: function(regpath, mix){
router_ensure();
routes.add(regpath, mix);
return this;
},
get: function(path){
return routes.get(path);
},
......@@ -1021,48 +1011,48 @@
currentPath: function(){
return router_ensure().currentPath();
},
notifyCurrent: function(){
router_ensure().navigate();
return this;
},
parse: Routes.parse,
$utils: {
/*
* Format URI path from CLI command:
* some action -foo bar === /some/action?foo=bar
*/
pathFromCLI: path_fromCLI,
query: {
serialize: query_serialize,
deserialize: query_deserialize
}
}
};
// end:source ../src/ruta.js
// source ../src/mask/attr/anchor-dynamic.js
(function() {
mask.registerAttrHandler('x-dynamic', function(node, value, model, ctx, tag){
tag.onclick = navigate;
}, 'client');
function navigate(event) {
event.preventDefault();
event.stopPropagation();
Ruta.navigate(this.href);
}
}());
// end:source ../src/mask/attr/anchor-dynamic.js
return Ruta;
}));
\ No newline at end of file
......@@ -12,104 +12,81 @@ button {
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
font-weight: inherit;
color: inherit;
-webkit-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
font-smoothing: antialiased;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eaeaea url('bg.png');
background: #f5f5f5;
color: #4d4d4d;
width: 550px;
min-width: 230px;
max-width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
font-weight: 300;
}
button,
input[type="checkbox"] {
outline: none;
outline: none;
}
.hidden {
display: none;
}
#todoapp {
background: #fff;
background: rgba(255, 255, 255, 0.9);
margin: 130px 0 40px 0;
border: 1px solid #ccc;
position: relative;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.15);
}
#todoapp:before {
content: '';
border-left: 1px solid #f5d6d6;
border-right: 1px solid #f5d6d6;
width: 2px;
position: absolute;
top: 0;
left: 40px;
height: 100%;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::-moz-placeholder {
font-style: italic;
color: #a9a9a9;
font-weight: 300;
color: #e6e6e6;
}
#todoapp input::input-placeholder {
font-style: italic;
font-weight: 300;
color: #e6e6e6;
}
#todoapp h1 {
position: absolute;
top: -120px;
top: -155px;
width: 100%;
font-size: 70px;
font-weight: bold;
font-size: 100px;
font-weight: 100;
text-align: center;
color: #b3b3b3;
color: rgba(255, 255, 255, 0.3);
text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
color: rgba(175, 47, 47, 0.15);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
-o-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
#header {
padding-top: 15px;
border-radius: inherit;
}
#header:before {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
height: 15px;
z-index: 2;
border-bottom: 1px solid #6c615c;
background: #8d7d77;
background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
border-top-left-radius: 1px;
border-top-right-radius: 1px;
}
#new-todo,
.edit {
position: relative;
......@@ -117,6 +94,7 @@ input[type="checkbox"] {
width: 100%;
font-size: 24px;
font-family: inherit;
font-weight: inherit;
line-height: 1.4em;
border: 0;
outline: none;
......@@ -124,29 +102,25 @@ input[type="checkbox"] {
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.02);
z-index: 2;
box-shadow: none;
background: rgba(0, 0, 0, 0.003);
box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03);
}
#main {
position: relative;
z-index: 2;
border-top: 1px dotted #adadad;
border-top: 1px solid #e6e6e6;
}
label[for='toggle-all'] {
......@@ -155,19 +129,19 @@ label[for='toggle-all'] {
#toggle-all {
position: absolute;
top: -42px;
left: -4px;
width: 40px;
top: -55px;
left: -12px;
width: 60px;
height: 34px;
text-align: center;
/* Mobile Safari */
border: none;
border: none; /* Mobile Safari */
}
#toggle-all:before {
content: '»';
font-size: 28px;
color: #d9d9d9;
padding: 0 25px 7px;
content: '';
font-size: 22px;
color: #e6e6e6;
padding: 10px 27px 10px 27px;
}
#toggle-all:checked:before {
......@@ -183,7 +157,7 @@ label[for='toggle-all'] {
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px dotted #ccc;
border-bottom: 1px solid #ededed;
}
#todo-list li:last-child {
......@@ -215,28 +189,18 @@ label[for='toggle-all'] {
top: 0;
bottom: 0;
margin: auto 0;
/* Mobile Safari */
border: none;
border: none; /* Mobile Safari */
-webkit-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
#todo-list li .toggle:after {
content: '✔';
/* 40 + a couple of pixels visual adjustment */
line-height: 43px;
font-size: 20px;
color: #d9d9d9;
text-shadow: 0 -1px 0 #bfbfbf;
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#ededed" stroke-width="3"/></svg>');
}
#todo-list li .toggle:checked:after {
color: #85ada7;
text-shadow: 0 1px 0 #669991;
bottom: 1px;
position: relative;
content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="-10 -18 100 135"><circle cx="50" cy="50" r="50" fill="none" stroke="#bddad5" stroke-width="3"/><path fill="#5dc2af" d="M72 25L42 71 27 56l-4 4 20 20 34-52z"/></svg>');
}
#todo-list li label {
......@@ -246,12 +210,11 @@ label[for='toggle-all'] {
margin-left: 45px;
display: block;
line-height: 1.2;
-webkit-transition: color 0.4s;
transition: color 0.4s;
}
#todo-list li.completed label {
color: #a9a9a9;
color: #d9d9d9;
text-decoration: line-through;
}
......@@ -264,21 +227,18 @@ label[for='toggle-all'] {
width: 40px;
height: 40px;
margin: auto 0;
font-size: 22px;
color: #a88a8a;
-webkit-transition: all 0.2s;
transition: all 0.2s;
font-size: 30px;
color: #cc9a9a;
margin-bottom: 11px;
transition: color 0.2s ease-out;
}
#todo-list li .destroy:hover {
text-shadow: 0 0 1px #000,
0 0 10px rgba(199, 107, 107, 0.8);
-webkit-transform: scale(1.3);
transform: scale(1.3);
color: #af5b5e;
}
#todo-list li .destroy:after {
content: '';
content: '×';
}
#todo-list li:hover .destroy {
......@@ -295,29 +255,25 @@ label[for='toggle-all'] {
#footer {
color: #777;
padding: 0 15px;
position: absolute;
right: 0;
bottom: -31px;
left: 0;
padding: 10px 15px;
height: 20px;
z-index: 1;
text-align: center;
border-top: 1px solid #e6e6e6;
}
#footer:before {
content: '';
position: absolute;
right: 0;
bottom: 31px;
bottom: 0;
left: 0;
height: 50px;
z-index: -1;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
0 6px 0 -3px rgba(255, 255, 255, 0.8),
0 7px 1px -3px rgba(0, 0, 0, 0.3),
0 43px 0 -6px rgba(255, 255, 255, 0.8),
0 44px 2px -6px rgba(0, 0, 0, 0.2);
overflow: hidden;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2),
0 8px 0 -3px #f6f6f6,
0 9px 1px -3px rgba(0, 0, 0, 0.2),
0 16px 0 -6px #f6f6f6,
0 17px 2px -6px rgba(0, 0, 0, 0.2);
}
#todo-count {
......@@ -325,6 +281,10 @@ label[for='toggle-all'] {
text-align: left;
}
#todo-count strong {
font-weight: 300;
}
#filters {
margin: 0;
padding: 0;
......@@ -339,49 +299,72 @@ label[for='toggle-all'] {
}
#filters li a {
color: #83756f;
margin: 2px;
color: inherit;
margin: 3px;
padding: 3px 7px;
text-decoration: none;
border: 1px solid transparent;
border-radius: 3px;
}
#filters li a.selected,
#filters li a:hover {
border-color: rgba(175, 47, 47, 0.1);
}
#filters li a.selected {
font-weight: bold;
border-color: rgba(175, 47, 47, 0.2);
}
#clear-completed {
#clear-completed,
html #clear-completed:active {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
font-size: 11px;
padding: 0 10px;
border-radius: 3px;
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
cursor: pointer;
visibility: hidden;
position: relative;
}
#clear-completed::after {
visibility: visible;
content: 'Clear completed';
position: absolute;
right: 0;
white-space: nowrap;
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
#clear-completed:hover::after {
text-decoration: underline;
}
#info {
margin: 65px auto 0;
color: #a6a6a6;
font-size: 12px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
color: #bfbfbf;
font-size: 10px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
text-align: center;
}
#info p {
line-height: 1;
}
#info a {
color: inherit;
text-decoration: none;
font-weight: 400;
}
#info a:hover {
text-decoration: underline;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox and Opera
Can't use it globally since it destroys checkboxes in Firefox
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all,
#todo-list li .toggle {
......@@ -393,10 +376,6 @@ label[for='toggle-all'] {
}
#toggle-all {
top: -56px;
left: -15px;
width: 65px;
height: 41px;
-webkit-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
......@@ -404,151 +383,12 @@ label[for='toggle-all'] {
}
}
.hidden {
display: none;
}
hr {
margin: 20px 0;
border: 0;
border-top: 1px dashed #C5C5C5;
border-bottom: 1px dashed #F7F7F7;
}
.learn a {
font-weight: normal;
text-decoration: none;
color: #b83f45;
}
.learn a:hover {
text-decoration: underline;
color: #787e7e;
}
.learn h3,
.learn h4,
.learn h5 {
margin: 10px 0;
font-weight: 500;
line-height: 1.2;
color: #000;
}
.learn h3 {
font-size: 24px;
}
.learn h4 {
font-size: 18px;
}
.learn h5 {
margin-bottom: 0;
font-size: 14px;
}
.learn ul {
padding: 0;
margin: 0 0 30px 25px;
}
.learn li {
line-height: 20px;
}
.learn p {
font-size: 15px;
font-weight: 300;
line-height: 1.3;
margin-top: 0;
margin-bottom: 0;
}
.quote {
border: none;
margin: 20px 0 60px 0;
}
.quote p {
font-style: italic;
}
.quote p:before {
content: '“';
font-size: 50px;
opacity: .15;
position: absolute;
top: -20px;
left: 3px;
}
.quote p:after {
content: '”';
font-size: 50px;
opacity: .15;
position: absolute;
bottom: -42px;
right: 3px;
}
.quote footer {
position: absolute;
bottom: -40px;
right: 0;
}
.quote footer img {
border-radius: 3px;
}
.quote footer a {
margin-left: 5px;
vertical-align: middle;
}
.speech-bubble {
position: relative;
padding: 10px;
background: rgba(0, 0, 0, .04);
border-radius: 5px;
}
.speech-bubble:after {
content: '';
position: absolute;
top: 100%;
right: 30px;
border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04);
}
.learn-bar > .learn {
position: absolute;
width: 272px;
top: 8px;
left: -300px;
padding: 10px;
border-radius: 5px;
background-color: rgba(255, 255, 255, .6);
-webkit-transition-property: left;
transition-property: left;
-webkit-transition-duration: 500ms;
transition-duration: 500ms;
}
@media (min-width: 899px) {
.learn-bar {
width: auto;
margin: 0 0 0 300px;
}
.learn-bar > .learn {
left: 8px;
@media (max-width: 430px) {
#footer {
height: 50px;
}
.learn-bar #todoapp {
width: 550px;
margin: 130px auto 40px auto;
#filters {
bottom: 10px;
}
}
hr {
margin: 20px 0;
border: 0;
border-top: 1px dashed #c5c5c5;
border-bottom: 1px dashed #f7f7f7;
}
.learn a {
font-weight: normal;
text-decoration: none;
color: #b83f45;
}
.learn a:hover {
text-decoration: underline;
color: #787e7e;
}
.learn h3,
.learn h4,
.learn h5 {
margin: 10px 0;
font-weight: 500;
line-height: 1.2;
color: #000;
}
.learn h3 {
font-size: 24px;
}
.learn h4 {
font-size: 18px;
}
.learn h5 {
margin-bottom: 0;
font-size: 14px;
}
.learn ul {
padding: 0;
margin: 0 0 30px 25px;
}
.learn li {
line-height: 20px;
}
.learn p {
font-size: 15px;
font-weight: 300;
line-height: 1.3;
margin-top: 0;
margin-bottom: 0;
}
#issue-count {
display: none;
}
.quote {
border: none;
margin: 20px 0 60px 0;
}
.quote p {
font-style: italic;
}
.quote p:before {
content: '“';
font-size: 50px;
opacity: .15;
position: absolute;
top: -20px;
left: 3px;
}
.quote p:after {
content: '”';
font-size: 50px;
opacity: .15;
position: absolute;
bottom: -42px;
right: 3px;
}
.quote footer {
position: absolute;
bottom: -40px;
right: 0;
}
.quote footer img {
border-radius: 3px;
}
.quote footer a {
margin-left: 5px;
vertical-align: middle;
}
.speech-bubble {
position: relative;
padding: 10px;
background: rgba(0, 0, 0, .04);
border-radius: 5px;
}
.speech-bubble:after {
content: '';
position: absolute;
top: 100%;
right: 30px;
border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04);
}
.learn-bar > .learn {
position: absolute;
width: 272px;
top: 8px;
left: -300px;
padding: 10px;
border-radius: 5px;
background-color: rgba(255, 255, 255, .6);
transition-property: left;
transition-duration: 500ms;
}
@media (min-width: 899px) {
.learn-bar {
width: auto;
padding-left: 300px;
}
.learn-bar > .learn {
left: 8px;
}
}
/* global _ */
(function () {
'use strict';
/* jshint ignore:start */
// Underscore's Template Module
// Courtesy of underscorejs.org
var _ = (function (_) {
......@@ -114,6 +116,7 @@
if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
}
/* jshint ignore:end */
function redirect() {
if (location.hostname === 'tastejs.github.io') {
......@@ -175,13 +178,17 @@
if (learnJSON.backend) {
this.frameworkJSON = learnJSON.backend;
this.frameworkJSON.issueLabel = framework;
this.append({
backend: true
});
} else if (learnJSON[framework]) {
this.frameworkJSON = learnJSON[framework];
this.frameworkJSON.issueLabel = framework;
this.append();
}
this.fetchIssueCount();
}
Learn.prototype.append = function (opts) {
......@@ -212,6 +219,26 @@
document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
};
Learn.prototype.fetchIssueCount = function () {
var issueLink = document.getElementById('issue-count-link');
if (issueLink) {
var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos');
var xhr = new XMLHttpRequest();
xhr.open('GET', url, true);
xhr.onload = function (e) {
var parsedResponse = JSON.parse(e.target.responseText);
if (parsedResponse instanceof Array) {
var count = parsedResponse.length
if (count !== 0) {
issueLink.innerHTML = 'This app has ' + count + ' open issues';
document.getElementById('issue-count').style.display = 'inline';
}
}
};
xhr.send();
}
};
redirect();
getFile('learn.json', Learn);
})();
{
"private": true,
"dependencies": {
"atma-class": "^1.0.68",
"includejs": "^0.9.10",
"jquery": "^2.1.3",
"maskjs": "^0.10.1",
"ruta": "^0.1.12",
"todomvc-common": "^1.0.1",
"todomvc-app-css": "^1.0.0",
}
}
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