Compare commits

..

No commits in common. "es-modules" and "master" have entirely different histories.

29 changed files with 2009 additions and 2998 deletions

View file

@ -4,8 +4,7 @@
<title>OxJS - A JavaScript Library for Web Applications</title> <title>OxJS - A JavaScript Library for Web Applications</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<link rel="stylesheet" type="text/css" href="index.css"/> <link rel="stylesheet" type="text/css" href="index.css"/>
<script type="text/javascript" src="source/UI/jquery/jquery-1.7.1.min.js"></script> <script type="text/javascript" src="dev/Ox.js"></script>
<script type="text/javascript" src="source/Ox.compat.js"></script>
<script type="text/javascript" src="index.js"></script> <script type="text/javascript" src="index.js"></script>
</head> </head>
<body></body> <body></body>

View file

@ -1,18 +0,0 @@
const init = [], initLoad = [];
window.Ox = function(value) {
console.log("delay stuff until we are done")
init.push(value)
};
window.Ox.load = function() {
initLoad.push(arguments)
};
(async () => {
const module = await import('./Ox/index.js');
console.log("Ox was loaded", init);
init.forEach(value => Ox(value))
delete init
initLoad.forEach(arguments => Ox.load.apply(null, arguments))
delete initLoad
})();

View file

@ -1,102 +0,0 @@
'use strict';
/*@
Ox <f> The `Ox` object
See `Ox.wrap` for details.
(value) -> <o> wrapped value
value <*> Any value
@*/
import * as OxCore from './js/Core.js';
import * as OxFunction from './js/Function.js';
import * as OxPolyfill from './js/Polyfill.js';
import * as OxArray from './js/Array.js';
import * as OxString from './js/String.js';
import * as OxCollection from './js/Collection.js';
import * as OxMath from './js/Math.js';
import * as OxAsync from './js/Async.js';
import * as OxColor from './js/Color.js';
import * as OxConstants from './js/Constants.js';
import * as OxDate from './js/Date.js';
import * as OxDOM from './js/DOM.js';
import * as OxEncoding from './js/Encoding.js';
import * as OxFormat from './js/Format.js';
import * as OxGeo from './js/Geo.js';
import * as OxHash from './js/Hash.js';
import * as OxHTML from './js/HTML.js';
import * as OxJavaScript from './js/JavaScript.js';
import * as OxLocale from './js/Locale.js';
import * as OxObject from './js/Object.js';
import * as OxRegExp from './js/RegExp.js';
import * as OxRequest from './js/Request.js';
import * as OxType from './js/Type.js';
import * as OxVideo from './js/Video.js';
const Ox = function(value) {
return OxCore.wrap(value)
};
Object.assign(Ox,
OxCore,
OxFunction,
OxPolyfill,
OxArray,
OxString,
OxCollection,
OxMath,
OxAsync,
OxColor,
OxConstants,
OxDate,
OxDOM,
OxEncoding,
OxFormat,
OxGeo,
OxHash,
OxHTML,
OxJavaScript,
OxLocale,
OxObject,
OxRegExp,
OxRequest,
OxType,
OxVideo,
);
export default Ox;
export { Ox };
// For backward compatibility with global usage
if (typeof window !== 'undefined') {
window.Ox = Ox;
Ox.loadPolyfill(window, Ox)
/*@
Ox.documentReady <function> Calls a callback function once the DOM is ready
(callback) -> <b> If true, the document was ready
callback <f> Callback function
@*/
Ox.documentReady = (function() {
var callbacks = [];
document.onreadystatechange = window.onload = function() {
if (document.readyState == 'complete') {
callbacks.forEach(function(callback) {
callback();
});
document.onreadystatechange = window.onload = null;
}
};
return function(callback) {
if (document.readyState == 'complete') {
callback();
return true;
} else {
callbacks.push(callback);
return false;
}
};
}());
}

View file

@ -1,19 +1,5 @@
'use strict'; 'use strict';
import * as OxCore from './Core.js';
import * as OxBase from './Base.js';
import * as OxFunction from './Function.js';
import * as OxType from './Type.js';
const Ox = {};
Object.assign(Ox,
OxCore,
OxBase,
OxFunction,
OxType,
);
/*@ /*@
Ox.api <f> Turns an array into a list API Ox.api <f> Turns an array into a list API
`Ox.api` takes an array and returns a function that allows you to run `Ox.api` takes an array and returns a function that allows you to run
@ -177,7 +163,7 @@ Ox.api <f> Turns an array into a list API
> Ox.test.apiResults[9].data > Ox.test.apiResults[9].data
{items: [{name: 'John Cale'}, {name: 'Brian Eno'}]} {items: [{name: 'John Cale'}, {name: 'Brian Eno'}]}
@*/ @*/
export function api(items, options) { Ox.api = function(items, options) {
options = options || {}; options = options || {};
@ -456,7 +442,7 @@ Ox.compact <f> Removes `null` or `undefined` values from an array
> Ox.compact([null,,1,,2,,3]) > Ox.compact([null,,1,,2,,3])
[1, 2, 3] [1, 2, 3]
@*/ @*/
export function compact(array) { Ox.compact = function(array) {
return array.filter(function(value) { return array.filter(function(value) {
return value != null; return value != null;
}); });
@ -475,7 +461,7 @@ Ox.find <f> Returns array elements that match a string
> Ox.find(['Bar', 'Barfoo', 'Foo', 'Foobar'], 'foo', true) > Ox.find(['Bar', 'Barfoo', 'Foo', 'Foobar'], 'foo', true)
['Foo', 'Foobar'] ['Foo', 'Foobar']
@*/ @*/
export function find(array, string, leading) { Ox.find = function(array, string, leading) {
var matches = [[], []]; var matches = [[], []];
string = string.toLowerCase(); string = string.toLowerCase();
array.forEach(function(value) { array.forEach(function(value) {
@ -494,7 +480,7 @@ Ox.flatten <f> Flattens an array
> Ox.flatten([1, [2, [3], 2], 1]) > Ox.flatten([1, [2, [3], 2], 1])
[1, 2, 3, 2, 1] [1, 2, 3, 2, 1]
@*/ @*/
export function flatten(array) { Ox.flatten = function(array) {
var ret = []; var ret = [];
array.forEach(function(value) { array.forEach(function(value) {
if (Ox.isArray(value)) { if (Ox.isArray(value)) {
@ -507,7 +493,7 @@ export function flatten(array) {
}; };
// FIXME: add docs and tests // FIXME: add docs and tests
export function getIndex(array, key, value) { Ox.getIndex = function(array, key, value) {
return Ox.indexOf(array, function(obj) { return Ox.indexOf(array, function(obj) {
return obj[key] === value; return obj[key] === value;
}); });
@ -523,13 +509,13 @@ Ox.getIndexById <f> Returns the first array index of an object with a given id
> Ox.getIndexById([{id: 'foo', str: 'Foo'}, {id: 'bar', str: 'Bar'}], 'baz') > Ox.getIndexById([{id: 'foo', str: 'Foo'}, {id: 'bar', str: 'Bar'}], 'baz')
-1 -1
@*/ @*/
export function getIndexById(array, id) { Ox.getIndexById = function(array, id) {
return getIndex(array, 'id', id); return Ox.getIndex(array, 'id', id);
}; };
// FIXME: add docs and tests // FIXME: add docs and tests
export function getObject(array, key, value) { Ox.getObject = function(array, key, value) {
var index = getIndex(array, key, value); var index = Ox.getIndex(array, key, value);
return index > -1 ? array[index] : null; return index > -1 ? array[index] : null;
}; };
@ -543,12 +529,12 @@ Ox.getObjectById <f> Returns the first object in an array with a given id
> Ox.getObjectById([{id: 'foo', str: 'Foo'}, {id: 'bar', str: 'Bar'}], 'baz') > Ox.getObjectById([{id: 'foo', str: 'Foo'}, {id: 'bar', str: 'Bar'}], 'baz')
null null
@*/ @*/
export function getObjectById(array, id) { Ox.getObjectById = function(array, id) {
return getObject(array, 'id', id); return Ox.getObject(array, 'id', id);
}; };
/* /*
export function indexOf(arr) { Ox.indexOf = function(arr) {
// indexOf for primitives, test for function, deep equal for others // indexOf for primitives, test for function, deep equal for others
}; };
*/ */
@ -569,7 +555,7 @@ Ox.last <f> Gets or sets the last element of an array
> Ox.last('123') > Ox.last('123')
'3' '3'
@*/ @*/
export function last(array, value) { Ox.last = function(array, value) {
var ret; var ret;
if (arguments.length == 1) { if (arguments.length == 1) {
ret = array[array.length - 1]; ret = array[array.length - 1];
@ -590,7 +576,7 @@ Ox.makeArray <f> Wraps any non-array in an array.
['foo'] ['foo']
@*/ @*/
// FIXME: rename to toArray // FIXME: rename to toArray
export function makeArray(value) { Ox.makeArray = function(value) {
var ret, type = Ox.typeOf(value); var ret, type = Ox.typeOf(value);
if (type == 'arguments' || type == 'nodelist') { if (type == 'arguments' || type == 'nodelist') {
ret = Ox.slice(value); ret = Ox.slice(value);
@ -613,7 +599,7 @@ Ox.nextValue <f> Next value, given an array of numbers, a number and a direction
> Ox.nextValue([], 1, 1) > Ox.nextValue([], 1, 1)
void 0 void 0
@*/ @*/
export function nextValue(array, value, direction) { Ox.nextValue = function(array, value, direction) {
var found = false, nextValue; var found = false, nextValue;
direction = direction || 1; direction = direction || 1;
direction == -1 && array.reverse(); direction == -1 && array.reverse();
@ -655,7 +641,7 @@ Ox.range <f> Python-style range
> Ox.range(-1, -2, -0.5) > Ox.range(-1, -2, -0.5)
[-1, -1.5] [-1, -1.5]
@*/ @*/
export function range() { Ox.range = function() {
var array = []; var array = [];
Ox.loop.apply(null, Ox.slice(arguments).concat(function(index) { Ox.loop.apply(null, Ox.slice(arguments).concat(function(index) {
array.push(index); array.push(index);
@ -782,7 +768,7 @@ Ox.unique <f> Removes duplicate values from an array
> Ox.unique('foo') > Ox.unique('foo')
'fo' 'fo'
@*/ @*/
export function unique(array) { Ox.unique = function(array) {
return Ox.filter(array, function(value, index) { return Ox.filter(array, function(value, index) {
return array.indexOf(value) == index; return array.indexOf(value) == index;
}); });
@ -795,7 +781,7 @@ Ox.zip <f> Zips an array of arrays
> Ox.zip([0, 1, 2], [3, 4, 5]) > Ox.zip([0, 1, 2], [3, 4, 5])
[[0, 3], [1, 4], [2, 5]] [[0, 3], [1, 4], [2, 5]]
@*/ @*/
export function zip() { Ox.zip = function() {
var args = arguments.length == 1 ? arguments[0] : Ox.slice(arguments), var args = arguments.length == 1 ? arguments[0] : Ox.slice(arguments),
array = []; array = [];
args[0].forEach(function(value, index) { args[0].forEach(function(value, index) {

View file

@ -1,297 +1,287 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js'; (function() {
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {}; function asyncMap(forEach, collection, iterator, that, callback) {
var type = Ox.typeOf(collection),
Object.assign(Ox, results = type == 'object' ? {} : [];
OxObject, callback = Ox.last(arguments);
OxConstants, that = arguments.length == 5 ? that : null;
OxMath forEach(collection, function(value, key, collection, callback) {
); iterator(value, key, collection, function(value) {
results[key] = value;
callback();
function internalAsyncMap(forEach, collection, iterator, that, callback) {
var type = Ox.typeOf(collection),
results = type == 'object' ? {} : [];
callback = Ox.last(arguments);
that = arguments.length == 5 ? that : null;
forEach(collection, function(value, key, collection, callback) {
iterator(value, key, collection, function(value) {
results[key] = value;
callback();
});
}, that, function() {
callback(type == 'string' ? results.join('') : results);
});
}
export function asyncMap(array, iterator, that, callback) {
array = Ox.makeArray(array);
callback = Ox.last(arguments);
that = arguments.length == 4 ? that : null;
if (array.some(Ox.isArray)) {
Ox.serialMap(array, function(value, key, array, callback) {
Ox.parallelMap(Ox.makeArray(value), iterator, callback);
}, callback);
} else {
Ox.parallelMap(array, iterator, callback);
}
};
/*@
Ox.nonblockingForEach <f> Non-blocking `forEach` with synchronous iterator
(col, iterator[, that], callback[, ms]) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
that <o> The iterator's `this` binding
callback <f> Callback function
ms <n> Number of milliseconds after which to insert a `setTimeout` call
@*/
export function nonblockingForEach(collection, iterator, that, callback, ms) {
var i = 0, keys, last = Ox.last(arguments),
n, time, type = Ox.typeOf(collection);
callback = Ox.isFunction(last) ? last : arguments[arguments.length - 2];
collection = type == 'array' || type == 'object'
? collection : Ox.slice(collection);
keys = type == 'object'
? Object.keys(collection) : Ox.range(collection.length);
ms = ms || 1000;
n = Ox.len(collection);
that = arguments.length == 5 || (
arguments.length == 4 && Ox.isFunction(last)
) ? that : null;
time = +new Date();
iterate();
function iterate() {
Ox.forEach(keys.slice(i), function(key) {
if (key in collection) {
if (iterator.call(
that, collection[key], key, collection
) === false) {
i = n;
return false;
}
}
i++;
if (+new Date() >= time + ms) {
return false; // break
}
});
if (i < n) {
setTimeout(function() {
time = +new Date();
iterate();
}, 1);
} else {
callback();
}
}
};
/*@
Ox.nonblockingMap <f> Non-blocking `map` with synchronous iterator
(collection, iterator[, that], callback[, ms]) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
that <o> The iterator's `this` binding
callback <f> Callback function
ms <n> Number of milliseconds after which to insert a `setTimeout` call
<script>
// var time = +new Date();
// Ox.nonblockingMap(
// Ox.range(1000000),
// function (value, index, array) {
// return +new Date() - time;
// },
// function(results) {
// Ox.print(results.length);
// },
// 1000
// );
</script>
> Ox.nonblockingMap(Ox.range(100000), Ox.identity, function(r) { Ox.test(r.length, 100000); })
undefined
@*/
export function nonblockingMap(collection, iterator, that, callback, ms) {
var last = Ox.last(arguments),
type = Ox.typeOf(collection),
results = type == 'object' ? {} : [];
callback = Ox.isFunction(last) ? last : arguments[arguments.length - 2];
that = arguments.length == 5 || (
arguments.length == 4 && Ox.isFunction(last)
) ? that : null;
Ox.nonblockingForEach(collection, function(value, key, collection) {
results[key] = iterator.call(that, value, key, collection);
}, function() {
callback(type == 'string' ? results.join('') : results);
}, ms);
};
/*@
Ox.parallelForEach <f> `forEach` with asynchronous iterator, running in parallel
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
<script>
Ox.test.pfeNumber = 0;
Ox.test.pfeIterator = function(value, index, array, callback) {
if (index < 5) {
Ox.test.pfeNumber++;
}
setTimeout(callback);
};
</script>
> Ox.parallelForEach(Ox.range(10), Ox.test.pfeIterator, function() { Ox.test(Ox.test.pfeNumber, 5); })
undefined
@*/
export function parallelForEach(collection, iterator, that, callback) {
var i = 0, n, type = Ox.typeOf(collection);
callback = callback || (arguments.length == 3 ? arguments[2] : Ox.noop);
collection = type == 'array' || type == 'object'
? collection : Ox.slice(collection);
n = Ox.len(collection);
that = arguments.length == 4 ? that : null;
Ox.forEach(collection, function(value, key, collection) {
iterator.call(that, value, key, collection, function() {
++i == n && callback();
});
});
};
/*@
Ox.parallelMap <f> Parallel `map` with asynchronous iterator
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
results <a|o|s> Results
<script>
// var time = +new Date();
// Ox.parallelMap(
// Ox.range(10),
// function (value, index, array, callback) {
// setTimeout(function() {
// callback(+new Date() - time);
// }, Ox.random(1000));
// },
// function(results) {
// Ox.print(results);
// }
// );
Ox.test.pmIterator = function(value, index, array, callback) {
setTimeout(callback(value - index));
};
</script>
> Ox.parallelMap(Ox.range(10), Ox.test.pmIterator, function(r) { Ox.test(Ox.sum(r), 0); })
undefined
@*/
export function parallelMap() {
internalAsyncMap.apply(null, [Ox.parallelForEach].concat(Ox.slice(arguments)));
};
/*@
Ox.serialForEach <f> `forEach` with asynchronous iterator, run serially
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
<script>
Ox.test.sfeNumber = 0;
Ox.test.sfeIterator = function(value, index, array, callback) {
Ox.test.sfeNumber++;
setTimeout(function() {
callback(index < 4);
}); });
}; }, that, function() {
</script> callback(type == 'string' ? results.join('') : results);
> Ox.serialForEach(Ox.range(10), Ox.test.sfeIterator, function() { Ox.test(Ox.test.sfeNumber, 5); }) });
undefined
@*/
export function serialForEach(collection, iterator, that, callback) {
var i = 0, keys, n, type = Ox.typeOf(collection);
callback = callback || (arguments.length == 3 ? arguments[2] : Ox.noop);
collection = type == 'array' || type == 'object'
? collection : Ox.slice(collection);
keys = type == 'object'
? Object.keys(collection) : Ox.range(collection.length);
n = Ox.len(collection);
that = arguments.length == 4 ? that : null;
iterate();
function iterate(value) {
if (value !== false) {
if (keys[i] in collection) {
iterator.call(
that,
collection[keys[i]],
keys[i],
collection,
++i < n ? iterate : callback
);
} else {
++i < n ? iterate() : callback();
}
} else {
callback();
}
} }
};
/*@ Ox.asyncMap = function(array, iterator, that, callback) {
Ox.serialMap <f> Serial `map` with asynchronous iterator array = Ox.makeArray(array);
(collection, iterator[, that], callback) -> <u> undefined callback = Ox.last(arguments);
collection <a|o|s> Collection that = arguments.length == 4 ? that : null;
iterator <f> Iterator function if (array.some(Ox.isArray)) {
value <*> Value Ox.serialMap(array, function(value, key, array, callback) {
key <n|s> Key Ox.parallelMap(Ox.makeArray(value), iterator, callback);
collection <a|o|s> The collection }, callback);
} else {
Ox.parallelMap(array, iterator, callback);
}
};
/*@
Ox.nonblockingForEach <f> Non-blocking `forEach` with synchronous iterator
(col, iterator[, that], callback[, ms]) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
that <o> The iterator's `this` binding
callback <f> Callback function callback <f> Callback function
that <o> The iterator's this binding ms <n> Number of milliseconds after which to insert a `setTimeout` call
callback <f> Callback function @*/
results <a|o|s> Results Ox.nonblockingForEach = function(collection, iterator, that, callback, ms) {
<script> var i = 0, keys, last = Ox.last(arguments),
// var time = +new Date(); n, time, type = Ox.typeOf(collection);
// Ox.serialMap( callback = Ox.isFunction(last) ? last : arguments[arguments.length - 2];
// Ox.range(10), collection = type == 'array' || type == 'object'
// function (value, index, array, callback) { ? collection : Ox.slice(collection);
// setTimeout(function() { keys = type == 'object'
// callback(+new Date() - time); ? Object.keys(collection) : Ox.range(collection.length);
// }, Ox.random(1000)); ms = ms || 1000;
// }, n = Ox.len(collection);
// function(results) { that = arguments.length == 5 || (
// Ox.print(results); arguments.length == 4 && Ox.isFunction(last)
// } ) ? that : null;
// ); time = +new Date();
Ox.test.smIterator = function(value, index, array, callback) { iterate();
setTimeout(callback(value - index)); function iterate() {
}; Ox.forEach(keys.slice(i), function(key) {
</script> if (key in collection) {
> Ox.serialMap(Ox.range(10), Ox.test.smIterator, function(r) { Ox.test(Ox.sum(r), 0); }) if (iterator.call(
undefined that, collection[key], key, collection
@*/ ) === false) {
export function serialMap(collection, iterator, that, callback) { i = n;
internalAsyncMap.apply(null, [Ox.serialForEach].concat(Ox.slice(arguments))); return false;
}; }
// FIXME: The above test with 10000 iterations blows the stack }
i++;
if (+new Date() >= time + ms) {
return false; // break
}
});
if (i < n) {
setTimeout(function() {
time = +new Date();
iterate();
}, 1);
} else {
callback();
}
}
};
/*@
Ox.nonblockingMap <f> Non-blocking `map` with synchronous iterator
(collection, iterator[, that], callback[, ms]) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
that <o> The iterator's `this` binding
callback <f> Callback function
ms <n> Number of milliseconds after which to insert a `setTimeout` call
<script>
// var time = +new Date();
// Ox.nonblockingMap(
// Ox.range(1000000),
// function (value, index, array) {
// return +new Date() - time;
// },
// function(results) {
// Ox.print(results.length);
// },
// 1000
// );
</script>
> Ox.nonblockingMap(Ox.range(100000), Ox.identity, function(r) { Ox.test(r.length, 100000); })
undefined
@*/
Ox.nonblockingMap = function(collection, iterator, that, callback, ms) {
var last = Ox.last(arguments),
type = Ox.typeOf(collection),
results = type == 'object' ? {} : [];
callback = Ox.isFunction(last) ? last : arguments[arguments.length - 2];
that = arguments.length == 5 || (
arguments.length == 4 && Ox.isFunction(last)
) ? that : null;
Ox.nonblockingForEach(collection, function(value, key, collection) {
results[key] = iterator.call(that, value, key, collection);
}, function() {
callback(type == 'string' ? results.join('') : results);
}, ms);
};
/*@
Ox.parallelForEach <f> `forEach` with asynchronous iterator, running in parallel
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
<script>
Ox.test.pfeNumber = 0;
Ox.test.pfeIterator = function(value, index, array, callback) {
if (index < 5) {
Ox.test.pfeNumber++;
}
setTimeout(callback);
};
</script>
> Ox.parallelForEach(Ox.range(10), Ox.test.pfeIterator, function() { Ox.test(Ox.test.pfeNumber, 5); })
undefined
@*/
Ox.parallelForEach = function(collection, iterator, that, callback) {
var i = 0, n, type = Ox.typeOf(collection);
callback = callback || (arguments.length == 3 ? arguments[2] : Ox.noop);
collection = type == 'array' || type == 'object'
? collection : Ox.slice(collection);
n = Ox.len(collection);
that = arguments.length == 4 ? that : null;
Ox.forEach(collection, function(value, key, collection) {
iterator.call(that, value, key, collection, function() {
++i == n && callback();
});
});
};
/*@
Ox.parallelMap <f> Parallel `map` with asynchronous iterator
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
results <a|o|s> Results
<script>
// var time = +new Date();
// Ox.parallelMap(
// Ox.range(10),
// function (value, index, array, callback) {
// setTimeout(function() {
// callback(+new Date() - time);
// }, Ox.random(1000));
// },
// function(results) {
// Ox.print(results);
// }
// );
Ox.test.pmIterator = function(value, index, array, callback) {
setTimeout(callback(value - index));
};
</script>
> Ox.parallelMap(Ox.range(10), Ox.test.pmIterator, function(r) { Ox.test(Ox.sum(r), 0); })
undefined
@*/
Ox.parallelMap = function() {
asyncMap.apply(null, [Ox.parallelForEach].concat(Ox.slice(arguments)));
};
/*@
Ox.serialForEach <f> `forEach` with asynchronous iterator, run serially
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
<script>
Ox.test.sfeNumber = 0;
Ox.test.sfeIterator = function(value, index, array, callback) {
Ox.test.sfeNumber++;
setTimeout(function() {
callback(index < 4);
});
};
</script>
> Ox.serialForEach(Ox.range(10), Ox.test.sfeIterator, function() { Ox.test(Ox.test.sfeNumber, 5); })
undefined
@*/
Ox.serialForEach = function(collection, iterator, that, callback) {
var i = 0, keys, n, type = Ox.typeOf(collection);
callback = callback || (arguments.length == 3 ? arguments[2] : Ox.noop);
collection = type == 'array' || type == 'object'
? collection : Ox.slice(collection);
keys = type == 'object'
? Object.keys(collection) : Ox.range(collection.length);
n = Ox.len(collection);
that = arguments.length == 4 ? that : null;
iterate();
function iterate(value) {
if (value !== false) {
if (keys[i] in collection) {
iterator.call(
that,
collection[keys[i]],
keys[i],
collection,
++i < n ? iterate : callback
);
} else {
++i < n ? iterate() : callback();
}
} else {
callback();
}
}
};
/*@
Ox.serialMap <f> Serial `map` with asynchronous iterator
(collection, iterator[, that], callback) -> <u> undefined
collection <a|o|s> Collection
iterator <f> Iterator function
value <*> Value
key <n|s> Key
collection <a|o|s> The collection
callback <f> Callback function
that <o> The iterator's this binding
callback <f> Callback function
results <a|o|s> Results
<script>
// var time = +new Date();
// Ox.serialMap(
// Ox.range(10),
// function (value, index, array, callback) {
// setTimeout(function() {
// callback(+new Date() - time);
// }, Ox.random(1000));
// },
// function(results) {
// Ox.print(results);
// }
// );
Ox.test.smIterator = function(value, index, array, callback) {
setTimeout(callback(value - index));
};
</script>
> Ox.serialMap(Ox.range(10), Ox.test.smIterator, function(r) { Ox.test(Ox.sum(r), 0); })
undefined
@*/
Ox.serialMap = function(collection, iterator, that, callback) {
asyncMap.apply(null, [Ox.serialForEach].concat(Ox.slice(arguments)));
};
// FIXME: The above test with 10000 iterations blows the stack
}());

View file

@ -1,49 +0,0 @@
/*@
Ox.filter <f> Filters a collection by a given condition
Unlike `Array.prototype.filter`, `Ox.filter` works for arrays, objects and
strings.
> Ox.filter([2, 1, 0], function(v, i) { return v == i; })
[1]
> Ox.filter({a: 'c', b: 'b', c: 'a'}, function(v, k) { return v == k; })
{b: 'b'}
> Ox.filter(' foo bar ', function(v) { return v != ' '; })
'foobar'
@*/
export function filter(collection, iterator, that) {
var ret, type = Ox.typeOf(collection);
iterator = iterator || Ox.identity;
if (type == 'object' || type == 'storage') {
ret = {};
Ox.forEach(collection, function(value, key) {
if (iterator.call(that, value, key, collection)) {
ret[key] = value;
}
});
} else {
ret = Ox.slice(collection).filter(iterator, that);
if (type == 'string') {
ret = ret.join('');
}
}
return ret;
};
/*@
Ox.indexOf <f> Returns the first index of a collection element that passes a test
> Ox.indexOf([1, 2, 3], function(val) { return val % 2 == 0; })
1
> Ox.indexOf({a: 1, b: 2, c: 3}, function(val) { return val % 2 == 0; })
'b'
> Ox.indexOf('FooBar', function(val) { return val == val.toUpperCase(); })
0
> Ox.indexOf([1, 2, 3], function(val) { return val == 0; })
-1
@*/
export function indexOf(collection, test) {
var index = Ox.forEach(collection, function(value) {
return !test(value); // break if test succeeds
});
return Ox.isObject(collection) ? Object.keys(collection)[index] || null
: index == collection.length ? -1 : index;
};

View file

@ -1,22 +1,5 @@
'use strict'; 'use strict';
import * as OxCore from './Core.js';
import * as OxFunction from './Function.js';
import * as OxConstants from './Constants.js';
import * as OxType from './Type.js';
import * as OxObject from './Object.js';
const Ox = {};
Object.assign(Ox,
OxCore,
OxConstants,
OxType,
OxObject,
OxFunction,
);
/*@ /*@
Ox.avg <f> Returns the average of an array's values, or an object's properties Ox.avg <f> Returns the average of an array's values, or an object's properties
(collection) -> <n> Average value (collection) -> <n> Average value
@ -28,8 +11,8 @@ Ox.avg <f> Returns the average of an array's values, or an object's properties
> Ox.avg('avg is 0.1') > Ox.avg('avg is 0.1')
0.1 0.1
@*/ @*/
export function avg(collection) { Ox.avg = function(collection) {
return Ox.sum(collection) / len(collection); return Ox.sum(collection) / Ox.len(collection);
}; };
/*@ /*@
@ -45,13 +28,13 @@ Ox.clone <f> Returns a (shallow or deep) copy of an array or object
> (function() { var a = [[0, 1]], b = Ox.clone(a, true); a[0][0] = null; return b[0]; }()) > (function() { var a = [[0, 1]], b = Ox.clone(a, true); a[0][0] = null; return b[0]; }())
[0, 1] [0, 1]
@*/ @*/
export function clone(collection, deep) { Ox.clone = function(collection, deep) {
var ret, type = Ox.typeOf(collection); var ret, type = Ox.typeOf(collection);
if (type != 'array' && type != 'object') { if (type != 'array' && type != 'object') {
ret = collection; ret = collection;
} else if (deep) { } else if (deep) {
ret = type == 'array' ? [] : {}; ret = type == 'array' ? [] : {};
forEach(collection, function(value, key) { Ox.forEach(collection, function(value, key) {
type = Ox.typeOf(value); type = Ox.typeOf(value);
ret[key] = type == 'array' || type == 'object' ret[key] = type == 'array' || type == 'object'
? Ox.clone(value, true) : value; ? Ox.clone(value, true) : value;
@ -76,7 +59,7 @@ Ox.contains <f> Tests if a collection contains a value
> Ox.contains('foobar', 'bar') > Ox.contains('foobar', 'bar')
true true
@*/ @*/
export function contains(collection, value) { Ox.contains = function(collection, value) {
var type = Ox.typeOf(collection); var type = Ox.typeOf(collection);
return ( return (
type == 'nodelist' || type == 'object' type == 'nodelist' || type == 'object'
@ -101,9 +84,9 @@ Ox.count <f> Counts the occurences of values in a collection
> Ox.count('foo', 'x') > Ox.count('foo', 'x')
0 0
@*/ @*/
export function count(collection, value) { Ox.count = function(collection, value) {
var count = {}; var count = {};
forEach(collection, function(value) { Ox.forEach(collection, function(value) {
count[value] = (count[value] || 0) + 1; count[value] = (count[value] || 0) + 1;
}); });
return value ? count[value] || 0 : count; return value ? count[value] || 0 : count;
@ -128,13 +111,42 @@ Ox.every <f> Tests if every element of a collection satisfies a given condition
> Ox.every([true, true, true]) > Ox.every([true, true, true])
true true
@*/ @*/
export function every(collection, iterator, that) { Ox.every = function(collection, iterator, that) {
iterator = iterator || Ox.identity; iterator = iterator || Ox.identity;
return forEach(collection, function(value, key, collection) { return Ox.forEach(collection, function(value, key, collection) {
return !!iterator.call(that, value, key, collection); return !!iterator.call(that, value, key, collection);
}) == len(collection); }) == Ox.len(collection);
}; };
/*@
Ox.filter <f> Filters a collection by a given condition
Unlike `Array.prototype.filter`, `Ox.filter` works for arrays, objects and
strings.
> Ox.filter([2, 1, 0], function(v, i) { return v == i; })
[1]
> Ox.filter({a: 'c', b: 'b', c: 'a'}, function(v, k) { return v == k; })
{b: 'b'}
> Ox.filter(' foo bar ', function(v) { return v != ' '; })
'foobar'
@*/
Ox.filter = function(collection, iterator, that) {
var ret, type = Ox.typeOf(collection);
iterator = iterator || Ox.identity;
if (type == 'object' || type == 'storage') {
ret = {};
Ox.forEach(collection, function(value, key) {
if (iterator.call(that, value, key, collection)) {
ret[key] = value;
}
});
} else {
ret = Ox.slice(collection).filter(iterator, that);
if (type == 'string') {
ret = ret.join('');
}
}
return ret;
};
/*@ /*@
Ox.forEach <f> forEach loop Ox.forEach <f> forEach loop
@ -159,7 +171,7 @@ Ox.forEach <f> forEach loop
> Ox.forEach({a: 'f', b: 'o', c: 'o'}, function(v, k) { return v != 'o' }); > Ox.forEach({a: 'f', b: 'o', c: 'o'}, function(v, k) { return v != 'o' });
1 1
@*/ @*/
export function forEach(collection, iterator, that) { Ox.forEach = function(collection, iterator, that) {
var i = 0, key, type = Ox.typeOf(collection); var i = 0, key, type = Ox.typeOf(collection);
if (type == 'object' || type == 'storage') { if (type == 'object' || type == 'storage') {
for (key in collection) { for (key in collection) {
@ -185,6 +197,25 @@ export function forEach(collection, iterator, that) {
return i; return i;
}; };
/*@
Ox.indexOf <f> Returns the first index of a collection element that passes a test
> Ox.indexOf([1, 2, 3], function(val) { return val % 2 == 0; })
1
> Ox.indexOf({a: 1, b: 2, c: 3}, function(val) { return val % 2 == 0; })
'b'
> Ox.indexOf('FooBar', function(val) { return val == val.toUpperCase(); })
0
> Ox.indexOf([1, 2, 3], function(val) { return val == 0; })
-1
@*/
Ox.indexOf = function(collection, test) {
var index = Ox.forEach(collection, function(value) {
return !test(value); // break if test succeeds
});
return Ox.isObject(collection) ? Object.keys(collection)[index] || null
: index == collection.length ? -1 : index;
};
/*@ /*@
Ox.indicesOf <f> Returns all indices of collection elements that pass a test Ox.indicesOf <f> Returns all indices of collection elements that pass a test
> Ox.indicesOf([1, 2, 3], function(val) { return val % 2 == 1; }) > Ox.indicesOf([1, 2, 3], function(val) { return val % 2 == 1; })
@ -196,9 +227,9 @@ Ox.indicesOf <f> Returns all indices of collection elements that pass a test
> Ox.indicesOf([1, 2, 3], function(val) { return val == 0; }) > Ox.indicesOf([1, 2, 3], function(val) { return val == 0; })
[] []
@*/ @*/
export function indicesOf(collection, test) { Ox.indicesOf = function(collection, test) {
var ret = []; var ret = [];
forEach(collection, function(value, index) { Ox.forEach(collection, function(value, index) {
test(value) && ret.push(index); test(value) && ret.push(index);
}); });
return ret; return ret;
@ -225,7 +256,7 @@ Ox.len <f> Returns the length of an array, nodelist, object, storage or string
> Ox.len(function(a, b, c) {}) > Ox.len(function(a, b, c) {})
undefined undefined
@*/ @*/
export function len(collection) { Ox.len = function(collection) {
var ret, type = Ox.typeOf(collection); var ret, type = Ox.typeOf(collection);
if ( if (
type == 'arguments' || type == 'array' type == 'arguments' || type == 'array'
@ -251,11 +282,11 @@ Ox.map <f> Transforms the values of an array, object or string
> Ox.map([,], function(v, i) { return i; }) > Ox.map([,], function(v, i) { return i; })
[,] [,]
@*/ @*/
export function map(collection, iterator, that) { Ox.map = function(collection, iterator, that) {
var ret, type = Ox.typeOf(collection); var ret, type = Ox.typeOf(collection);
if (type == 'object' || type == 'storage') { if (type == 'object' || type == 'storage') {
ret = {}; ret = {};
forEach(collection, function(value, key) { Ox.forEach(collection, function(value, key) {
ret[key] = iterator.call(that, value, key, collection); ret[key] = iterator.call(that, value, key, collection);
}); });
} else { } else {
@ -278,7 +309,7 @@ Ox.max <f> Returns the maximum value of a collection
> Ox.max([]) > Ox.max([])
-Infinity -Infinity
@*/ @*/
export function max(collection) { Ox.max = function(collection) {
var ret, values = Ox.values(collection); var ret, values = Ox.values(collection);
if (values.length < Ox.STACK_LENGTH) { if (values.length < Ox.STACK_LENGTH) {
ret = Math.max.apply(null, values); ret = Math.max.apply(null, values);
@ -301,7 +332,7 @@ Ox.min <f> Returns the minimum value of a collection
> Ox.min([]) > Ox.min([])
Infinity Infinity
@*/ @*/
export function min(collection) { Ox.min = function(collection) {
var ret, values = Ox.values(collection); var ret, values = Ox.values(collection);
if (values.length < Ox.STACK_LENGTH) { if (values.length < Ox.STACK_LENGTH) {
ret = Math.min.apply(null, values); ret = Math.min.apply(null, values);
@ -328,8 +359,8 @@ Ox.numberOf <f> Returns the number of elements in a collection that pass a test
> Ox.numberOf('foo', function(v, k, c) { return v == c[k - 1]; }) > Ox.numberOf('foo', function(v, k, c) { return v == c[k - 1]; })
1 1
@*/ @*/
export function numberOf(collection, test) { Ox.numberOf = function(collection, test) {
return len(Ox.filter(collection, test)); return Ox.len(Ox.filter(collection, test));
}; };
/*@ /*@
@ -350,7 +381,7 @@ Ox.remove <f> Removes an element from an array or object and returns it
> Ox.test.collection > Ox.test.collection
[['a', 'c'], {a: 0, c: 2}] [['a', 'c'], {a: 0, c: 2}]
@*/ @*/
export function remove(collection, element) { Ox.remove = function(collection, element) {
var ret, key; var ret, key;
if (Ox.isArray(collection)) { if (Ox.isArray(collection)) {
key = collection.indexOf(element); key = collection.indexOf(element);
@ -374,7 +405,7 @@ Ox.reverse <f> Reverses an array or string
> Ox.reverse('foobar') > Ox.reverse('foobar')
'raboof' 'raboof'
@*/ @*/
export function reverse(collection) { Ox.reverse = function(collection) {
return Ox.isArray(collection) return Ox.isArray(collection)
? Ox.clone(collection).reverse() ? Ox.clone(collection).reverse()
: collection.toString().split('').reverse().join(''); : collection.toString().split('').reverse().join('');
@ -389,7 +420,7 @@ Ox.shuffle <f> Randomizes the order of values within a collection
> Ox.shuffle('123').split('').sort().join('') > Ox.shuffle('123').split('').sort().join('')
'123' '123'
@*/ @*/
export function shuffle(collection) { Ox.shuffle = function(collection) {
var keys, ret, type = Ox.typeOf(collection), values; var keys, ret, type = Ox.typeOf(collection), values;
if (type == 'object' || type == 'storage') { if (type == 'object' || type == 'storage') {
keys = Object.keys(collection); keys = Object.keys(collection);
@ -412,6 +443,57 @@ export function shuffle(collection) {
return ret; return ret;
}; };
/*@
Ox.slice <f> Alias for `Array.prototype.slice.call`
(collection[, start[, stop]]) -> <a> Array
collection <a|o|s> Array-like
start <n> Start position
stop <n> Stop position
> (function() { return Ox.slice(arguments); }(1, 2, 3))
[1, 2, 3]
> Ox.slice('foo', 0, 1);
['f']
> Ox.slice({0: 'f', 1: 'o', 2: 'o', length: 3}, -2)
['o', 'o']
@*/
// FIXME: remove toArray alias
Ox.slice = Ox.toArray = function(collection, start, stop) {
return Array.prototype.slice.call(collection, start, stop);
};
// IE8 can't apply slice to NodeLists, returns an empty array if undefined is
// passed as stop and returns an array of null values if a string is passed as
// value. Firefox 3.6 returns an array of undefined values if a string is passed
// as value.
if (
Ox.slice([0]).length == 0
|| Ox.slice('0')[0] === null
|| Ox.slice('0')[0] === void 0
|| !(function() {
try {
return Ox.slice(document.getElementsByTagName('a'));
} catch (error) {}
}())
) {
// FIXME: remove toArray alias
Ox.slice = Ox.toArray = function(collection, start, stop) {
var args = stop === void 0 ? [start] : [start, stop],
array = [], index, length, ret;
if (Ox.typeOf(collection) == 'string') {
collection = collection.split('');
}
try {
ret = Array.prototype.slice.apply(collection, args);
} catch (error) {
length = collection.length;
for (index = 0; index < length; index++) {
array[index] = collection[index];
}
ret = Array.prototype.slice.apply(array, args);
}
return ret;
};
}
/*@ /*@
Ox.some <f> Tests if one or more elements of a collection meet a given condition Ox.some <f> Tests if one or more elements of a collection meet a given condition
Unlike `Array.prototype.some`, `Ox.some` works for arrays, objects and Unlike `Array.prototype.some`, `Ox.some` works for arrays, objects and
@ -425,11 +507,11 @@ Ox.some <f> Tests if one or more elements of a collection meet a given condition
> Ox.some([false, null, 0, '', void 0]) > Ox.some([false, null, 0, '', void 0])
false false
@*/ @*/
export function some(collection, iterator, that) { Ox.some = function(collection, iterator, that) {
iterator = iterator || Ox.identity; iterator = iterator || Ox.identity;
return forEach(collection, function(value, key, collection) { return Ox.forEach(collection, function(value, key, collection) {
return !iterator.call(that, value, key, collection); return !iterator.call(that, value, key, collection);
}) < len(collection); }) < Ox.len(collection);
}; };
/*@ /*@
@ -447,10 +529,10 @@ Ox.sum <f> Returns the sum of the values of a collection
> Ox.sum('08', -2, 'foo') > Ox.sum('08', -2, 'foo')
6 6
@*/ @*/
export function sum(collection) { Ox.sum = function(collection) {
var ret = 0; var ret = 0;
collection = arguments.length > 1 ? Ox.slice(arguments) : collection; collection = arguments.length > 1 ? Ox.slice(arguments) : collection;
forEach(collection, function(value) { Ox.forEach(collection, function(value) {
value = +value; value = +value;
ret += isFinite(value) ? value : 0; ret += isFinite(value) ? value : 0;
}); });
@ -459,7 +541,7 @@ export function sum(collection) {
/* FIXME: do we need this kind of zip functionality? /* FIXME: do we need this kind of zip functionality?
export function arrayToObject(array, key) { Ox.arrayToObject = function(array, key) {
var ret = {}; var ret = {};
array.forEach(function(v) { array.forEach(function(v) {
ret[v[key]] = v; ret[v[key]] = v;
@ -467,9 +549,9 @@ export function arrayToObject(array, key) {
return ret; return ret;
}; };
export function objectToArray(object, key) { Ox.objectToArray = function(object, key) {
var ret = []; var ret = [];
forEach(object, function(v, k) { Ox.forEach(object, function(v, k) {
ret.push(Ox.extend(v, key, k)); ret.push(Ox.extend(v, key, k));
}); });
return ret; return ret;
@ -492,13 +574,13 @@ Ox.values <f> Returns the values of a collection
> Ox.values([1,,3]) > Ox.values([1,,3])
[1,,3] [1,,3]
@*/ @*/
export function values(collection) { Ox.values = function(collection) {
var ret, type = Ox.typeOf(collection); var ret, type = Ox.typeOf(collection);
if (type == 'array' || type == 'nodelist') { if (type == 'array' || type == 'nodelist') {
ret = Ox.slice(collection); ret = Ox.slice(collection);
} else if (type == 'object' || type == 'storage') { } else if (type == 'object' || type == 'storage') {
ret = []; ret = [];
forEach(collection, function(value) { Ox.forEach(collection, function(value) {
ret.push(value); ret.push(value);
}); });
} else if (type == 'string') { } else if (type == 'string') {
@ -531,9 +613,9 @@ Ox.walk <f> Iterates over a nested data structure
> Ox.test.array > Ox.test.array
[['a'], ['b', 'c'], ['b', 'd']] [['a'], ['b', 'c'], ['b', 'd']]
@*/ @*/
export function walk(collection, iterator, that, keys) { Ox.walk = function(collection, iterator, that, keys) {
keys = keys || []; keys = keys || [];
forEach(collection, function(value, key) { Ox.forEach(collection, function(value, key) {
var keys_ = keys.concat(key); var keys_ = keys.concat(key);
iterator.call(that, value, keys_, collection); iterator.call(that, value, keys_, collection);
Ox.walk(collection[key], iterator, that, keys_); Ox.walk(collection[key], iterator, that, keys_);

View file

@ -1,17 +1,5 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxConstants,
OxMath
);
/*@ /*@
Ox.hsl <f> Takes RGB values and returns HSL values Ox.hsl <f> Takes RGB values and returns HSL values
(rgb) <[n]> HSL values (rgb) <[n]> HSL values
@ -27,7 +15,7 @@ Ox.hsl <f> Takes RGB values and returns HSL values
> Ox.hsl(0, 255, 0) > Ox.hsl(0, 255, 0)
[120, 1, 0.5] [120, 1, 0.5]
@*/ @*/
export function hsl(rgb) { Ox.hsl = function(rgb) {
var hsl = [0, 0, 0], max, min; var hsl = [0, 0, 0], max, min;
if (arguments.length == 3) { if (arguments.length == 3) {
rgb = Ox.slice(arguments); rgb = Ox.slice(arguments);
@ -74,7 +62,7 @@ Ox.rgb <f> Takes HSL values and returns RGB values
[0, 255, 0] [0, 255, 0]
@*/ @*/
export function rgb(hsl) { Ox.rgb = function(hsl) {
var rgb = [0, 0, 0], v1, v2, v3; var rgb = [0, 0, 0], v1, v2, v3;
if (arguments.length == 3) { if (arguments.length == 3) {
hsl = Ox.slice(arguments); hsl = Ox.slice(arguments);
@ -118,7 +106,7 @@ Ox.toHex <f> Format RGB array as hex value
> Ox.toHex([192, 128, 64]) > Ox.toHex([192, 128, 64])
'C08040' 'C08040'
@*/ @*/
export function toHex(rgb) { Ox.toHex = function(rgb) {
return rgb.map(function(value) { return rgb.map(function(value) {
return Ox.pad(value.toString(16).toUpperCase(), 'left', 2, '0'); return Ox.pad(value.toString(16).toUpperCase(), 'left', 2, '0');
}).join(''); }).join('');
@ -129,7 +117,7 @@ Ox.toRGB <f> Format hex value as RGB array
> Ox.toRGB('C08040') > Ox.toRGB('C08040')
[192, 128, 64] [192, 128, 64]
@*/ @*/
export function toRGB(hex) { Ox.toRGB = function(hex) {
return Ox.range(3).map(function(index) { return Ox.range(3).map(function(index) {
return parseInt(hex.substr(index * 2, 2), 16); return parseInt(hex.substr(index * 2, 2), 16);
}); });

View file

@ -1,38 +1,30 @@
'use strict'; 'use strict';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxMath
);
//@ Ox.AMPM <[s]> ['AM', 'PM'] //@ Ox.AMPM <[s]> ['AM', 'PM']
export const AMPM = ['AM', 'PM']; Ox.AMPM = ['AM', 'PM'];
//@ Ox.BASE_32_ALIASES <o> Base 32 aliases //@ Ox.BASE_32_ALIASES <o> Base 32 aliases
export const BASE_32_ALIASES = {'I': '1', 'L': '1', 'O': '0', 'U': 'V'}; Ox.BASE_32_ALIASES = {'I': '1', 'L': '1', 'O': '0', 'U': 'V'},
//@ Ox.BASE_32_DIGITS <o> Base 32 digits //@ Ox.BASE_32_DIGITS <o> Base 32 digits
export const BASE_32_DIGITS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; Ox.BASE_32_DIGITS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ';
//@ Ox.BCAD <[s]> ['BC', 'AD'] //@ Ox.BCAD <[s]> ['BC', 'AD']
export const BCAD = ['BC', 'AD']; Ox.BCAD = ['BC', 'AD'];
/*@ /*@
Ox.EARTH_RADIUS <n> Radius of the earth in meters Ox.EARTH_RADIUS <n> Radius of the earth in meters
See http://en.wikipedia.org/wiki/WGS-84 See http://en.wikipedia.org/wiki/WGS-84
*/ */
export const EARTH_RADIUS = 6378137; Ox.EARTH_RADIUS = 6378137;
//@ Ox.EARTH_CIRCUMFERENCE <n> Circumference of the earth in meters //@ Ox.EARTH_CIRCUMFERENCE <n> Circumference of the earth in meters
export const EARTH_CIRCUMFERENCE = 2 * Math.PI * EARTH_RADIUS; Ox.EARTH_CIRCUMFERENCE = 2 * Math.PI * Ox.EARTH_RADIUS;
//@ Ox.EARTH_SURFACE <n> Surface of the earth in square meters //@ Ox.EARTH_SURFACE <n> Surface of the earth in square meters
export const EARTH_SURFACE = 4 * Math.PI * Math.pow(EARTH_RADIUS, 2); Ox.EARTH_SURFACE = 4 * Math.PI * Math.pow(Ox.EARTH_RADIUS, 2);
//@ Ox.HTML_ENTITIES <o> HTML entities for ... (FIXME) //@ Ox.HTML_ENTITIES <o> HTML entities for ... (FIXME)
export const HTML_ENTITIES = { Ox.HTML_ENTITIES = {
'"': '&quot;', '&': '&amp;', "'": '&apos;', '<': '&lt;', '>': '&gt;' '"': '&quot;', '&': '&amp;', "'": '&apos;', '<': '&lt;', '>': '&gt;'
}; };
//@ Ox.KEYS <o> Names for key codes //@ Ox.KEYS <o> Names for key codes
// The dot notation ('0.numpad') allows for namespaced events ('key_0.numpad'), // The dot notation ('0.numpad') allows for namespaced events ('key_0.numpad'),
// so that binding to 'key_0' will catch both 'key_0' and 'key_0.numpad'. // so that binding to 'key_0' will catch both 'key_0' and 'key_0.numpad'.
export const KEYS = { Ox.KEYS = {
0: 'section', 8: 'backspace', 9: 'tab', 12: 'clear', 13: 'enter', 0: 'section', 8: 'backspace', 9: 'tab', 12: 'clear', 13: 'enter',
16: 'shift', 17: 'control', 18: 'alt', 20: 'capslock', 27: 'escape', 16: 'shift', 17: 'control', 18: 'alt', 20: 'capslock', 27: 'escape',
32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home', 32: 'space', 33: 'pageup', 34: 'pagedown', 35: 'end', 36: 'home',
@ -63,9 +55,9 @@ export const KEYS = {
// see dojo, for ex. // see dojo, for ex.
}; };
//@ Ox.LOCALE <s> Default locale //@ Ox.LOCALE <s> Default locale
export const LOCALE = 'en'; Ox.LOCALE = 'en';
//@ Ox.LOCALE_NAMES <o> Locale names //@ Ox.LOCALE_NAMES <o> Locale names
export const LOCALE_NAMES = { Ox.LOCALE_NAMES = {
'ar': 'العربية', 'ar': 'العربية',
'de': 'Deutsch', 'de': 'Deutsch',
'el': 'Ελληνικά', 'el': 'Ελληνικά',
@ -75,56 +67,51 @@ export const LOCALE_NAMES = {
'tr': 'Türkçe' 'tr': 'Türkçe'
}; };
//@ Ox.LOCALES <o> Locales per module //@ Ox.LOCALES <o> Locales per module
export const LOCALES = {}; Ox.LOCALES = {};
//@ Ox.MAX_LATITUDE <n> Maximum latitude of a Mercator projection //@ Ox.MAX_LATITUDE <n> Maximum latitude of a Mercator projection
export const MAX_LATITUDE = Ox.deg(Math.atan(Ox.sinh(Math.PI))); Ox.MAX_LATITUDE = Ox.deg(Math.atan(Ox.sinh(Math.PI)));
//@ Ox.MIN_LATITUDE <n> Minimum latitude of a Mercator projection //@ Ox.MIN_LATITUDE <n> Minimum latitude of a Mercator projection
export const MIN_LATITUDE = -Ox.MAX_LATITUDE; Ox.MIN_LATITUDE = -Ox.MAX_LATITUDE;
//@ Ox.MODIFIER_KEYS <o> Names for modifier keys //@ Ox.MODIFIER_KEYS <o> Names for modifier keys
// meta comes last so that one can differentiate between // meta comes last so that one can differentiate between
// alt_control_shift_meta.left and alt_control_shift_meta.right // alt_control_shift_meta.left and alt_control_shift_meta.right
export const MODIFIER_KEYS = { Ox.MODIFIER_KEYS = {
altKey: 'alt', // Mac: option altKey: 'alt', // Mac: option
ctrlKey: 'control', ctrlKey: 'control',
shiftKey: 'shift', shiftKey: 'shift',
metaKey: 'meta' // Mac: command metaKey: 'meta' // Mac: command
}; };
//@ Ox.MONTHS <[s]> Names of months //@ Ox.MONTHS <[s]> Names of months
export const MONTHS = [ Ox.MONTHS = [
'January', 'February', 'March', 'April', 'May', 'June', 'January', 'February', 'March', 'April', 'May', 'June',
'July', 'August', 'September', 'October', 'November', 'December' 'July', 'August', 'September', 'October', 'November', 'December'
]; ];
//@ Ox.SHORT_MONTHS <[s]> Short names of months //@ Ox.SHORT_MONTHS <[s]> Short names of months
export const SHORT_MONTHS = MONTHS.map(function(val) { Ox.SHORT_MONTHS = Ox.MONTHS.map(function(val) {
return val.slice(0, 3); return val.slice(0, 3);
}); });
//@ Ox.PATH <s> Path of Ox.js //@ Ox.PATH <s> Path of Ox.js
export const PATH = (function() { Ox.PATH = (function() {
// IE8 can't apply slice to NodeLists, see Ox.slice // IE8 can't apply slice to NodeLists, see Ox.slice
var index, regexp = /Ox\.js(\?.+|)$/, scripts, src; var index, regexp = /Ox\.js(\?.+|)$/,
try { scripts = document.getElementsByTagName('script'), src;
scripts = document.getElementsByTagName('script')
} catch(e) {
scripts = ''
}
for (index = scripts.length - 1; index >= 0; index--) { for (index = scripts.length - 1; index >= 0; index--) {
src = scripts[index].src; src = scripts[index].src;
if (regexp.test(src)) { if (regexp.test(src)) {
return src.replace(regexp, ''); return src.replace(regexp, '');
} }
} }
return ''
}()); }());
//@ Ox.MODE <s> Mode ('dev' or 'min') //@ Ox.MODE <s> Mode ('dev' or 'min')
export const MODE = PATH.slice(0, -1).split('/').pop(); Ox.MODE = Ox.PATH.slice(0, -1).split('/').pop();
//@ Ox.PREFIXES <[str]> `['', 'K', 'M', 'G', 'T', 'P']` //@ Ox.PREFIXES <[str]> `['', 'K', 'M', 'G', 'T', 'P']`
export const PREFIXES = ['', 'K', 'M', 'G', 'T', 'P']; Ox.PREFIXES = ['', 'K', 'M', 'G', 'T', 'P'];
//@ Ox.SEASONS <[s]> Names of the seasons of the year //@ Ox.SEASONS <[s]> Names of the seasons of the year
export const SEASONS = ['Winter', 'Spring', 'Summer', 'Fall']; Ox.SEASONS = ['Winter', 'Spring', 'Summer', 'Fall'];
//@ Ox.STACK_SIZE <n> Maximum number of arguments //@ Ox.STACK_SIZE <n> Maximum number of arguments
export const STACK_SIZE = 65536; Ox.STACK_SIZE = 65536;
//@ Ox.SYMBOLS <o> Unicode characters for symbols //@ Ox.SYMBOLS <o> Unicode characters for symbols
export const SYMBOLS = { Ox.SYMBOLS = {
dollar: '\u0024', cent: '\u00A2', pound: '\u00A3', currency: '\u00A4', dollar: '\u0024', cent: '\u00A2', pound: '\u00A3', currency: '\u00A4',
yen: '\u00A5', bullet: '\u2022', ellipsis: '\u2026', permille: '\u2030', yen: '\u00A5', bullet: '\u2022', ellipsis: '\u2026', permille: '\u2030',
colon: '\u20A1', cruzeiro: '\u20A2', franc: '\u20A3', lira: '\u20A4', colon: '\u20A1', cruzeiro: '\u20A2', franc: '\u20A3', lira: '\u20A4',
@ -151,12 +138,12 @@ export const SYMBOLS = {
click: '\uF803', apple: '\uF8FF' click: '\uF803', apple: '\uF8FF'
}; };
//@ Ox.VERSION <s> OxJS version number //@ Ox.VERSION <s> OxJS version number
export const VERSION = '0.1'; Ox.VERSION = '0.1';
//@ Ox.WEEKDAYS <[s]> Names of weekdays //@ Ox.WEEKDAYS <[s]> Names of weekdays
export const WEEKDAYS = [ Ox.WEEKDAYS = [
'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'
]; ];
//@ Ox.SHORT_WEEKDAYS <[s]> Short names of weekdays //@ Ox.SHORT_WEEKDAYS <[s]> Short names of weekdays
export const SHORT_WEEKDAYS = WEEKDAYS.map(function(val) { Ox.SHORT_WEEKDAYS = Ox.WEEKDAYS.map(function(val) {
return val.slice(0, 3); return val.slice(0, 3);
}); });

View file

@ -2,23 +2,15 @@
'use strict'; 'use strict';
import * as OxType from './Type.js'; /*@
import * as OxCollection from './Collection.js'; Ox <f> The `Ox` object
import * as OxObject from './Object.js'; See `Ox.wrap` for details.
import * as OxDOM from './DOM.js'; (value) -> <o> wrapped value
import * as OxString from './String.js'; value <*> Any value
import * as OxRequest from './Request.js'; @*/
this.Ox = function(value) {
const Ox = {}; return Ox.wrap(value);
};
Object.assign(Ox,
OxType,
OxCollection,
OxObject,
OxDOM,
OxString,
OxRequest,
);
/*@ /*@
Ox.load <f> Loads OxJS and, optionally, one or more modules Ox.load <f> Loads OxJS and, optionally, one or more modules
@ -60,7 +52,7 @@ Ox.load <f> Loads OxJS and, optionally, one or more modules
callback <f> Callback function callback <f> Callback function
success <b> If true, all modules have been loaded successfully success <b> If true, all modules have been loaded successfully
@*/ @*/
export function load() { Ox.load = function() {
var callback = arguments[arguments.length - 1], var callback = arguments[arguments.length - 1],
length, loaded = 0, localeFiles = [], modules = {}, succeeded = 0, length, loaded = 0, localeFiles = [], modules = {}, succeeded = 0,
type = Ox.typeOf(arguments[0]); type = Ox.typeOf(arguments[0]);
@ -84,18 +76,20 @@ export function load() {
if (!length) { if (!length) {
callback(true); callback(true);
} else { } else {
Ox.forEach(modules, async function(options, module) { Ox.forEach(modules, function(options, module) {
console.log("load module!", module, options) Ox.getFile(
// Ox.PATH + module + '/index.js?' + Ox.VERSION, Ox.PATH + module + '/' + module + '.js?' + Ox.VERSION,
const obj = await import('../../' + module + '/index.js?' + Ox.VERSION); function() {
Ox.load[module](options, function(success) { Ox.load[module](options, function(success) {
succeeded += success; succeeded += success;
if (++loaded == length) { if (++loaded == length) {
Ox.setLocale(Ox.LOCALE, function() { Ox.setLocale(Ox.LOCALE, function() {
callback(succeeded == length); callback(succeeded == length);
});
}
}); });
} }
}); );
}); });
} }
}); });
@ -116,7 +110,7 @@ Ox.localStorage <f> localStorage wrapper
> Ox.test.localStorage.delete('foo')() > Ox.test.localStorage.delete('foo')()
{} {}
@*/ @*/
export function localStorage(namespace) { Ox.localStorage = function(namespace) {
var localStorage; var localStorage;
try { try {
// this will fail if third party cookies/storage is not allowed // this will fail if third party cookies/storage is not allowed
@ -169,7 +163,7 @@ export function localStorage(namespace) {
Ox.Log <f> Logging module Ox.Log <f> Logging module
@*/ @*/
Ox.Log = (function() { Ox.Log = (function() {
var storage = localStorage('Ox'), var storage = Ox.localStorage('Ox'),
log = storage('log') || {filter: [], filterEnabled: true}, log = storage('log') || {filter: [], filterEnabled: true},
that = function() { that = function() {
var ret; var ret;
@ -245,7 +239,7 @@ Ox.loop <f> For-loop, functional-style
> Ox.loop(0, 3, 2, function() {}) > Ox.loop(0, 3, 2, function() {})
4 4
@*/ @*/
export function loop() { Ox.loop = function() {
var length = arguments.length, var length = arguments.length,
start = length > 2 ? arguments[0] : 0, start = length > 2 ? arguments[0] : 0,
stop = arguments[length > 2 ? 1 : 0], stop = arguments[length > 2 ? 1 : 0],
@ -269,7 +263,7 @@ Ox.print <f> Prints its arguments to the console
> Ox.print('foo', 'bar').split(' ').slice(1).join(' ') > Ox.print('foo', 'bar').split(' ').slice(1).join(' ')
'foo bar' 'foo bar'
@*/ @*/
export function print() { Ox.print = function() {
var args = Ox.slice(arguments), date = new Date(); var args = Ox.slice(arguments), date = new Date();
args.unshift( args.unshift(
date.toString().split(' ')[4] + '.' + (+date).toString().slice(-3) date.toString().split(' ')[4] + '.' + (+date).toString().slice(-3)
@ -282,7 +276,7 @@ export function print() {
Ox.trace <f> Prints its arguments to the console, followed by a stack trace Ox.trace <f> Prints its arguments to the console, followed by a stack trace
(arg, ...) -> <s> String (arg, ...) -> <s> String
@*/ @*/
export function trace() { Ox.trace = function() {
var args = Ox.slice(arguments); var args = Ox.slice(arguments);
try { try {
throw new Error(); throw new Error();
@ -302,10 +296,12 @@ Ox.uid <f> Returns a unique id
> Ox.uid() != Ox.uid() > Ox.uid() != Ox.uid()
true true
@*/ @*/
var _uid = 0; Ox.uid = (function() {
export function uid() { var uid = 0;
return ++_uid; return function() {
} return ++uid;
};
}());
/*@ /*@
Ox.wrap <f> Wraps a value so that one can directly call any Ox function on it Ox.wrap <f> Wraps a value so that one can directly call any Ox function on it
@ -321,7 +317,7 @@ Ox.wrap <f> Wraps a value so that one can directly call any Ox function on it
> Ox.wrap('foobar').value() > Ox.wrap('foobar').value()
'foobar' 'foobar'
@*/ @*/
export function wrap(value, chained) { Ox.wrap = function(value, chained) {
// somewhat inspired by underscore.js // somewhat inspired by underscore.js
var wrapper = { var wrapper = {
chain: function() { chain: function() {
@ -345,55 +341,3 @@ export function wrap(value, chained) {
}); });
return wrapper; return wrapper;
}; };
/*@
Ox.slice <f> Alias for `Array.prototype.slice.call`
(collection[, start[, stop]]) -> <a> Array
collection <a|o|s> Array-like
start <n> Start position
stop <n> Stop position
> (function() { return Ox.slice(arguments); }(1, 2, 3))
[1, 2, 3]
> Ox.slice('foo', 0, 1);
['f']
> Ox.slice({0: 'f', 1: 'o', 2: 'o', length: 3}, -2)
['o', 'o']
@*/
// FIXME: remove toArray alias
export function slice(collection, start, stop) {
return Array.prototype.slice.call(collection, start, stop);
};
// IE8 can't apply slice to NodeLists, returns an empty array if undefined is
// passed as stop and returns an array of null values if a string is passed as
// value. Firefox 3.6 returns an array of undefined values if a string is passed
// as value.
if (
slice([0]).length == 0
|| slice('0')[0] === null
|| slice('0')[0] === void 0
|| !(function() {
try {
return Ox.slice(document.getElementsByTagName('a'));
} catch (error) {}
}())
) {
// FIXME: remove toArray alias
slice = function(collection, start, stop) {
var args = stop === void 0 ? [start] : [start, stop],
array = [], index, length, ret;
if (Ox.typeOf(collection) == 'string') {
collection = collection.split('');
}
try {
ret = Array.prototype.slice.apply(collection, args);
} catch (error) {
length = collection.length;
for (index = 0; index < length; index++) {
array[index] = collection[index];
}
ret = Array.prototype.slice.apply(array, args);
}
return ret;
};
}

View file

@ -1,27 +1,5 @@
'use strict'; 'use strict';
import * as OxCore from './Core.js';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
import * as OxType from './Type.js';
import * as OxArray from './Array.js';
import * as OxCollection from './Collection.js';
import * as OxString from './String.js';
const Ox = {};
Object.assign(Ox,
OxCore,
OxObject,
OxConstants,
OxMath,
OxType,
OxArray,
OxCollection,
OxString,
);
/*@ /*@
Ox.$ <f> Generic HTML element, mimics jQuery Ox.$ <f> Generic HTML element, mimics jQuery
value <s|h|w|?> tagname, selector, html element, `window`, or `document` value <s|h|w|?> tagname, selector, html element, `window`, or `document`
@ -53,7 +31,7 @@ Ox.$ <f> Generic HTML element, mimics jQuery
> Ox.$('<input>').val('red').val() > Ox.$('<input>').val('red').val()
'red' 'red'
@*/ @*/
export function element(value) { Ox.$ = Ox.element = function $(value) {
var elements = Ox.isArray(value) ? value // array of elements var elements = Ox.isArray(value) ? value // array of elements
: Ox.isNodeList(value) ? Ox.slice(value) // nodelist : Ox.isNodeList(value) ? Ox.slice(value) // nodelist
@ -818,8 +796,6 @@ export function element(value) {
}; };
export const $ = element;
/*@ /*@
Ox.canvas <function> Generic canvas object Ox.canvas <function> Generic canvas object
Returns an object with the properties: `canvas`, `context`, `data` and Returns an object with the properties: `canvas`, `context`, `data` and
@ -830,7 +806,7 @@ Ox.canvas <function> Generic canvas object
height <n> Height in px height <n> Height in px
image <e> Image object image <e> Image object
@*/ @*/
export function canvas() { Ox.canvas = function() {
var c = {}, isImage = arguments.length == 1, var c = {}, isImage = arguments.length == 1,
image = isImage ? arguments[0] : { image = isImage ? arguments[0] : {
width: arguments[0], height: arguments[1] width: arguments[0], height: arguments[1]
@ -845,24 +821,13 @@ export function canvas() {
return c; return c;
}; };
var callbacks = [];
/*@ /*@
Ox.documentReady <function> Calls a callback function once the DOM is ready Ox.documentReady <function> Calls a callback function once the DOM is ready
(callback) -> <b> If true, the document was ready (callback) -> <b> If true, the document was ready
callback <f> Callback function callback <f> Callback function
@*/ @*/
export function documentReady(callback) { Ox.documentReady = (function() {
if (document.readyState == 'complete') { var callbacks = [];
callback();
return true;
} else {
callbacks.push(callback);
return false;
}
}
if (typeof document !== 'undefined') {
document.onreadystatechange = window.onload = function() { document.onreadystatechange = window.onload = function() {
if (document.readyState == 'complete') { if (document.readyState == 'complete') {
callbacks.forEach(function(callback) { callbacks.forEach(function(callback) {
@ -871,4 +836,13 @@ if (typeof document !== 'undefined') {
document.onreadystatechange = window.onload = null; document.onreadystatechange = window.onload = null;
} }
}; };
} return function(callback) {
if (document.readyState == 'complete') {
callback();
return true;
} else {
callbacks.push(callback);
return false;
}
};
}());

View file

@ -1,17 +1,5 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxConstants,
OxMath
);
//@ Ox.getDate <f> Get the day of a date, optionally UTC //@ Ox.getDate <f> Get the day of a date, optionally UTC
// see Ox.setSeconds for source code // see Ox.setSeconds for source code
@ -33,7 +21,7 @@ Ox.getDateInWeek <f> Get the date that falls on a given weekday in the same week
"Monday, December 27, 1999" "Monday, December 27, 1999"
@*/ @*/
// fixme: why is this Monday first? shouldn't it then be "getDateInISOWeek"?? // fixme: why is this Monday first? shouldn't it then be "getDateInISOWeek"??
export function getDateInWeek(date, weekday, utc) { Ox.getDateInWeek = function(date, weekday, utc) {
date = Ox.makeDate(date); date = Ox.makeDate(date);
var sourceWeekday = Ox.getISODay(date, utc), var sourceWeekday = Ox.getISODay(date, utc),
targetWeekday = Ox.isNumber(weekday) ? weekday targetWeekday = Ox.isNumber(weekday) ? weekday
@ -62,7 +50,7 @@ Ox.getDayOfTheYear <f> Get the day of the year for a given date
> Ox.getDayOfTheYear(new Date("12/31/2004")) > Ox.getDayOfTheYear(new Date("12/31/2004"))
366 366
@*/ @*/
export function getDayOfTheYear(date, utc) { Ox.getDayOfTheYear = function(date, utc) {
date = Ox.makeDate(date); date = Ox.makeDate(date);
var month = Ox.getMonth(date, utc), var month = Ox.getMonth(date, utc),
year = Ox.getFullYear(date, utc); year = Ox.getFullYear(date, utc);
@ -80,7 +68,7 @@ Ox.getDaysInMonth <f> Get the number of days in a given month
> Ox.getDaysInMonth(new Date('01/01/2004'), "February") > Ox.getDaysInMonth(new Date('01/01/2004'), "February")
29 29
@*/ @*/
export function getDaysInMonth(year, month) { Ox.getDaysInMonth = function(year, month) {
year = Ox.makeYear(year); year = Ox.makeYear(year);
month = Ox.isNumber(month) ? month month = Ox.isNumber(month) ? month
: Ox.indexOf(Ox.MONTHS, function(v) { : Ox.indexOf(Ox.MONTHS, function(v) {
@ -99,7 +87,7 @@ Ox.getDaysInYear <f> Get the number of days in a given year
> Ox.getDaysInYear(new Date('01/01/2004')) > Ox.getDaysInYear(new Date('01/01/2004'))
366 366
@*/ @*/
export function getDaysInYear(year, utc) { Ox.getDaysInYear = function(year, utc) {
return 365 + Ox.isLeapYear(Ox.makeYear(year, utc)); return 365 + Ox.isLeapYear(Ox.makeYear(year, utc));
}; };
@ -109,7 +97,7 @@ Ox.getFirstDayOfTheYear <f> Get the weekday of the first day of a given year
> Ox.getFirstDayOfTheYear(new Date('01/01/2000')) > Ox.getFirstDayOfTheYear(new Date('01/01/2000'))
6 6
@*/ @*/
export function getFirstDayOfTheYear(date, utc) { Ox.getFirstDayOfTheYear = function(date, utc) {
date = Ox.makeDate(date); date = Ox.makeDate(date);
date = Ox.setMonth(date, 0, utc); date = Ox.setMonth(date, 0, utc);
date = Ox.setDate(date, 1, utc); date = Ox.setDate(date, 1, utc);
@ -126,7 +114,7 @@ Ox.getISODate <f> Get the ISO date string for a given date
> Ox.getISODate(new Date('01/01/2000')) > Ox.getISODate(new Date('01/01/2000'))
'2000-01-01T00:00:00Z' '2000-01-01T00:00:00Z'
@*/ @*/
export function getISODate(date, utc) { Ox.getISODate = function(date, utc) {
return Ox.formatDate(Ox.makeDate(date), '%FT%TZ', utc); return Ox.formatDate(Ox.makeDate(date), '%FT%TZ', utc);
}; };
@ -140,7 +128,7 @@ Ox.getISODay <f> Get the ISO weekday of a given date
> Ox.getISODay(new Date('01/03/2000')) > Ox.getISODay(new Date('01/03/2000'))
1 1
@*/ @*/
export function getISODay(date, utc) { Ox.getISODay = function(date, utc) {
return Ox.getDay(Ox.makeDate(date), utc) || 7; return Ox.getDay(Ox.makeDate(date), utc) || 7;
}; };
@ -155,7 +143,7 @@ Ox.getISOWeek <f> Get the ISO week of a given date
1 1
@*/ @*/
export function getISOWeek(date, utc) { Ox.getISOWeek = function(date, utc) {
date = Ox.makeDate(date); date = Ox.makeDate(date);
// set date to Thursday of the same week // set date to Thursday of the same week
return Math.floor((Ox.getDayOfTheYear(Ox.setDate( return Math.floor((Ox.getDayOfTheYear(Ox.setDate(
@ -174,7 +162,7 @@ Ox.getISOYear <f> Get the ISO year of a given date
2000 2000
@*/ @*/
export function getISOYear(date, utc) { Ox.getISOYear = function(date, utc) {
date = Ox.makeDate(date); date = Ox.makeDate(date);
// set date to Thursday of the same week // set date to Thursday of the same week
return Ox.getFullYear(Ox.setDate( return Ox.getFullYear(Ox.setDate(
@ -192,7 +180,7 @@ export function getISOYear(date, utc) {
// see Ox.setSeconds for source code // see Ox.setSeconds for source code
//@ Ox.getTime <f> Alias for `+new Date()` //@ Ox.getTime <f> Alias for `+new Date()`
export function getTime(utc) { Ox.getTime = function(utc) {
return +new Date() - (utc ? Ox.getTimezoneOffset() : 0); return +new Date() - (utc ? Ox.getTimezoneOffset() : 0);
}; };
@ -201,7 +189,7 @@ Ox.getTimezoneOffset <f> Get the local time zone offset in milliseconds
([date]) -> <n> Offset in milliseconds ([date]) -> <n> Offset in milliseconds
date <d|u> Return offset at this date (if undefined, return current offset) date <d|u> Return offset at this date (if undefined, return current offset)
@*/ @*/
export function getTimezoneOffset(date) { Ox.getTimezoneOffset = function(date) {
return Ox.makeDate(date).getTimezoneOffset() * 60000; return Ox.makeDate(date).getTimezoneOffset() * 60000;
}; };
@ -213,7 +201,7 @@ Ox.getTimezoneOffsetString <f> Get the local time zone offset as a string
> Ox.getTimezoneOffsetString(new Date('01/01/2000')).length > Ox.getTimezoneOffsetString(new Date('01/01/2000')).length
5 5
@*/ @*/
export function getTimezoneOffsetString(date) { Ox.getTimezoneOffsetString = function(date) {
var offset = Ox.makeDate(date).getTimezoneOffset(); var offset = Ox.makeDate(date).getTimezoneOffset();
return (offset <= 0 ? '+' : '-') return (offset <= 0 ? '+' : '-')
+ Ox.pad(Math.floor(Math.abs(offset) / 60), 2) + Ox.pad(Math.floor(Math.abs(offset) / 60), 2)
@ -230,7 +218,7 @@ Ox.getWeek <f> Get the week of a given day
> Ox.getWeek(new Date('01/03/2000')) > Ox.getWeek(new Date('01/03/2000'))
1 1
@*/ @*/
export function getWeek(date, utc) { Ox.getWeek = function(date, utc) {
date = Ox.makeDate(date); date = Ox.makeDate(date);
return Math.floor((Ox.getDayOfTheYear(date, utc) return Math.floor((Ox.getDayOfTheYear(date, utc)
+ Ox.getFirstDayOfTheYear(date, utc) - 1) / 7); + Ox.getFirstDayOfTheYear(date, utc) - 1) / 7);
@ -245,7 +233,7 @@ Ox.isLeapYear <f> Returns true if a given year is a leap year
> Ox.isLeapYear(new Date('01/01/2004')) > Ox.isLeapYear(new Date('01/01/2004'))
true true
@*/ @*/
export function isLeapYear(year, utc) { Ox.isLeapYear = function(year, utc) {
year = Ox.makeYear(year, utc); year = Ox.makeYear(year, utc);
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
}; };
@ -267,7 +255,7 @@ Ox.makeDate <f> Takes a date, number or string, returns a date
> Ox.formatDate(Ox.makeDate(Ox.parseDate('-50')), '%Y') > Ox.formatDate(Ox.makeDate(Ox.parseDate('-50')), '%Y')
'-50' '-50'
@*/ @*/
export function makeDate(date) { Ox.makeDate = function(date) {
// Safari 4/5 (<= 534.59.10) doesn't parse YYYY, YYYY-MM or YYYY-MM-DD // Safari 4/5 (<= 534.59.10) doesn't parse YYYY, YYYY-MM or YYYY-MM-DD
if (Ox.isString(date) && Ox.isInvalidDate(new Date(date))) { if (Ox.isString(date) && Ox.isInvalidDate(new Date(date))) {
if (/^\d{4}$/.test(date)) { if (/^\d{4}$/.test(date)) {
@ -292,7 +280,7 @@ Ox.makeYear <f> Takes a date, number or string, returns a year
> Ox.makeYear('1970') > Ox.makeYear('1970')
1970 1970
@*/ @*/
export function makeYear(date, utc) { Ox.makeYear = function(date, utc) {
return Ox.isDate(date) ? Ox.getFullYear(date, utc) : parseInt(date, 10); return Ox.isDate(date) ? Ox.getFullYear(date, utc) : parseInt(date, 10);
}; };
@ -307,7 +295,7 @@ Ox.parseDate <f> Takes a string ('YYYY-MM-DD HH:MM:SS.MMM') and returns a date
> Ox.parseDate('50', true).getUTCFullYear() > Ox.parseDate('50', true).getUTCFullYear()
50 50
@*/ @*/
export function parseDate(string, utc) { Ox.parseDate = function(string, utc) {
var date, var date,
defaults = [, 1, 1, 0, 0, 0, 0], defaults = [, 1, 1, 0, 0, 0, 0],
values = /(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?/ values = /(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?/
@ -332,7 +320,7 @@ export function parseDate(string, utc) {
}; };
/* /*
export function parseDateRange(start, end, utc) { Ox.parseDateRange = function(start, end, utc) {
var dates = [ var dates = [
Ox.parseDate(start, utc), Ox.parseDate(start, utc),
Ox.parseDate(end, utc) Ox.parseDate(end, utc)

View file

@ -1,17 +1,5 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxConstants,
OxMath
);
/*@ /*@
Ox.encodeBase26 <b> Encode a number as bijective base26 Ox.encodeBase26 <b> Encode a number as bijective base26
See <a href="http://en.wikipedia.org/wiki/Bijective_numeration"> See <a href="http://en.wikipedia.org/wiki/Bijective_numeration">
@ -27,7 +15,7 @@ Ox.encodeBase26 <b> Encode a number as bijective base26
> Ox.encodeBase26(4461) > Ox.encodeBase26(4461)
'FOO' 'FOO'
@*/ @*/
export function encodeBase26(number) { Ox.encodeBase26 = function(number) {
var string = ''; var string = '';
while (number) { while (number) {
string = String.fromCharCode(65 + (number - 1) % 26) + string; string = String.fromCharCode(65 + (number - 1) % 26) + string;
@ -43,7 +31,7 @@ Ox.decodeBase26 <f> Decodes a bijective base26-encoded number
> Ox.decodeBase26('foo') > Ox.decodeBase26('foo')
4461 4461
@*/ @*/
export function decodeBase26(string) { Ox.decodeBase26 = function(string) {
return string.toUpperCase().split('').reverse().reduce(function(p, c, i) { return string.toUpperCase().split('').reverse().reduce(function(p, c, i) {
return p + (c.charCodeAt(0) - 64) * Math.pow(26, i); return p + (c.charCodeAt(0) - 64) * Math.pow(26, i);
}, 0); }, 0);
@ -57,7 +45,7 @@ Ox.encodeBase32 <b> Encode a number as base32
> Ox.encodeBase32(33819) > Ox.encodeBase32(33819)
'110V' '110V'
@*/ @*/
export function encodeBase32(number) { Ox.encodeBase32 = function(number) {
return Ox.map(number.toString(32), function(char) { return Ox.map(number.toString(32), function(char) {
return Ox.BASE_32_DIGITS[parseInt(char, 32)]; return Ox.BASE_32_DIGITS[parseInt(char, 32)];
}); });
@ -73,7 +61,7 @@ Ox.decodeBase32 <f> Decodes a base32-encoded number
> Ox.decodeBase32('?').toString() > Ox.decodeBase32('?').toString()
'NaN' 'NaN'
@*/ @*/
export function decodeBase32(string) { Ox.decodeBase32 = function(string) {
return parseInt(Ox.map(string.toUpperCase(), function(char) { return parseInt(Ox.map(string.toUpperCase(), function(char) {
var index = Ox.BASE_32_DIGITS.indexOf( var index = Ox.BASE_32_DIGITS.indexOf(
Ox.BASE_32_ALIASES[char] || char Ox.BASE_32_ALIASES[char] || char
@ -87,7 +75,7 @@ Ox.encodeBase64 <f> Encode a number as base64
> Ox.encodeBase64(32394) > Ox.encodeBase64(32394)
'foo' 'foo'
@*/ @*/
export function encodeBase64(number) { Ox.encodeBase64 = function(number) {
return btoa(Ox.encodeBase256(number)).replace(/=/g, ''); return btoa(Ox.encodeBase256(number)).replace(/=/g, '');
}; };
@ -96,7 +84,7 @@ Ox.decodeBase64 <f> Decodes a base64-encoded number
> Ox.decodeBase64('foo') > Ox.decodeBase64('foo')
32394 32394
@*/ @*/
export function decodeBase64(string) { Ox.decodeBase64 = function(string) {
return Ox.decodeBase256(atob(string)); return Ox.decodeBase256(atob(string));
}; };
@ -105,7 +93,7 @@ Ox.encodeBase128 <f> Encode a number as base128
> Ox.encodeBase128(1685487) > Ox.encodeBase128(1685487)
'foo' 'foo'
@*/ @*/
export function encodeBase128(number) { Ox.encodeBase128 = function(number) {
var string = ''; var string = '';
while (number) { while (number) {
string = Ox.char(number & 127) + string; string = Ox.char(number & 127) + string;
@ -119,7 +107,7 @@ Ox.decodeBase128 <f> Decode a base128-encoded number
> Ox.decodeBase128('foo') > Ox.decodeBase128('foo')
1685487 1685487
@*/ @*/
export function decodeBase128(string) { Ox.decodeBase128 = function(string) {
return string.split('').reverse().reduce(function(p, c, i) { return string.split('').reverse().reduce(function(p, c, i) {
return p + (c.charCodeAt(0) << i * 7); return p + (c.charCodeAt(0) << i * 7);
}, 0); }, 0);
@ -130,7 +118,7 @@ Ox.encodeBase256 <f> Encode a number as base256
> Ox.encodeBase256(6713199) > Ox.encodeBase256(6713199)
'foo' 'foo'
@*/ @*/
export function encodeBase256(number) { Ox.encodeBase256 = function(number) {
var string = ''; var string = '';
while (number) { while (number) {
string = Ox.char(number & 255) + string; string = Ox.char(number & 255) + string;
@ -144,7 +132,7 @@ Ox.decodeBase256 <f> Decode a base256-encoded number
> Ox.decodeBase256('foo') > Ox.decodeBase256('foo')
6713199 6713199
@*/ @*/
export function decodeBase256(string) { Ox.decodeBase256 = function(string) {
return string.split('').reverse().reduce(function(p, c, i) { return string.split('').reverse().reduce(function(p, c, i) {
return p + (c.charCodeAt(0) << i * 8); return p + (c.charCodeAt(0) << i * 8);
}, 0); }, 0);
@ -161,7 +149,7 @@ Ox.encodeDeflate <f> Encodes a string, using deflate
> Ox.decodeDeflate(Ox.encodeDeflate('foo'), function(str) { Ox.test(str, 'foo'); }) > Ox.decodeDeflate(Ox.encodeDeflate('foo'), function(str) { Ox.test(str, 'foo'); })
undefined undefined
@*/ @*/
export function encodeDeflate(string, callback) { Ox.encodeDeflate = function(string, callback) {
// Make sure we can encode the full unicode range of characters. // Make sure we can encode the full unicode range of characters.
string = Ox.encodeUTF8(string); string = Ox.encodeUTF8(string);
// We can only safely write to RGB, so we need 1 pixel for 3 bytes. // We can only safely write to RGB, so we need 1 pixel for 3 bytes.
@ -210,7 +198,7 @@ Ox.decodeDeflate <f> Decodes an deflate-encoded string
str <s> The decoded string str <s> The decoded string
@*/ @*/
export function decodeDeflate(string, callback) { Ox.decodeDeflate = function(string, callback) {
var image = new Image(), var image = new Image(),
// PNG file signature and IHDR chunk // PNG file signature and IHDR chunk
data = '\u0089PNG\r\n\u001A\n\u0000\u0000\u0000\u000DIHDR' data = '\u0089PNG\r\n\u001A\n\u0000\u0000\u0000\u000DIHDR'
@ -304,7 +292,7 @@ Ox.encodeUTF8 <f> Encodes a string as UTF-8
> Ox.encodeUTF8("¥€$") > Ox.encodeUTF8("¥€$")
"\u00C2\u00A5\u00E2\u0082\u00AC\u0024" "\u00C2\u00A5\u00E2\u0082\u00AC\u0024"
@*/ @*/
export function encodeUTF8(string) { Ox.encodeUTF8 = function(string) {
return Ox.map(string, function(char) { return Ox.map(string, function(char) {
var code = char.charCodeAt(0), var code = char.charCodeAt(0),
string = ''; string = '';
@ -332,7 +320,7 @@ Ox.decodeUTF8 <f> Decodes an UTF-8-encoded string
> Ox.decodeUTF8('\u00C2\u00A5\u00E2\u0082\u00AC\u0024') > Ox.decodeUTF8('\u00C2\u00A5\u00E2\u0082\u00AC\u0024')
'¥€$' '¥€$'
@*/ @*/
export function decodeUTF8(string) { Ox.decodeUTF8 = function(string) {
var code, i = 0, length = string.length, ret = ''; var code, i = 0, length = string.length, ret = '';
function error(byte, position) { function error(byte, position) {
throw new RangeError( throw new RangeError(

View file

@ -1,17 +1,5 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxConstants,
OxMath
);
/*@ /*@
Ox.formatArea <f> Formats a number of meters as square meters or kilometers Ox.formatArea <f> Formats a number of meters as square meters or kilometers
> Ox.formatArea(1000) > Ox.formatArea(1000)
@ -20,7 +8,7 @@ Ox.formatArea <f> Formats a number of meters as square meters or kilometers
'1 km\u00B2' '1 km\u00B2'
@*/ @*/
export function formatArea(number, decimals) { Ox.formatArea = function(number, decimals) {
var k = number >= 1000000 ? 'k' : ''; var k = number >= 1000000 ? 'k' : '';
decimals = Ox.isUndefined(decimals) ? 8 : decimals; decimals = Ox.isUndefined(decimals) ? 8 : decimals;
return Ox.formatNumber( return Ox.formatNumber(
@ -37,7 +25,7 @@ Ox.formatCount <f> Returns a string like "2 items", "1 item" or "no items".
> Ox.formatCount(1000, 'city', 'cities') > Ox.formatCount(1000, 'city', 'cities')
'1,000 cities' '1,000 cities'
@*/ @*/
export function formatCount(number, singular, plural) { Ox.formatCount = function(number, singular, plural) {
plural = (plural || singular + 's') + (number === 2 ? '{2}' : ''); plural = (plural || singular + 's') + (number === 2 ? '{2}' : '');
return (number === 0 ? Ox._('no') : Ox.formatNumber(number)) return (number === 0 ? Ox._('no') : Ox.formatNumber(number))
+ ' ' + Ox._(number === 1 ? singular : plural); + ' ' + Ox._(number === 1 ? singular : plural);
@ -48,7 +36,7 @@ Ox.formatCurrency <f> Formats a number with a currency symbol
> Ox.formatCurrency(1000, '$', 2) > Ox.formatCurrency(1000, '$', 2)
'$1,000.00' '$1,000.00'
@*/ @*/
export function formatCurrency(number, string, decimals) { Ox.formatCurrency = function(number, string, decimals) {
return string + Ox.formatNumber(number, decimals); return string + Ox.formatNumber(number, decimals);
}; };
@ -409,7 +397,7 @@ Ox.formatDateRange <f> Formats a date range as a string
> Ox.formatDateRange('-50-01-01 00:00:00', '-50-01-01 23:59:59') > Ox.formatDateRange('-50-01-01 00:00:00', '-50-01-01 23:59:59')
'Sun, Jan 1, 50 BC, 00:00:00 - 23:59:59' 'Sun, Jan 1, 50 BC, 00:00:00 - 23:59:59'
@*/ @*/
export function formatDateRange(start, end, utc) { Ox.formatDateRange = function(start, end, utc) {
end = end || Ox.formatDate(new Date(), '%Y-%m-%d'); end = end || Ox.formatDate(new Date(), '%Y-%m-%d');
var isOneUnit = false, var isOneUnit = false,
range = [start, end], range = [start, end],
@ -499,7 +487,7 @@ Ox.formatDateRangeDuration <f> Formats the duration of a date range as a string
> Ox.formatDateRangeDuration('2000-02', '2000-03', true) > Ox.formatDateRangeDuration('2000-02', '2000-03', true)
'1 month' '1 month'
@*/ @*/
export function formatDateRangeDuration(start, end, utc) { Ox.formatDateRangeDuration = function(start, end, utc) {
end = end || Ox.formatDate(new Date(), '%Y-%m-%d'); end = end || Ox.formatDate(new Date(), '%Y-%m-%d');
var date = Ox.parseDate(start, utc), var date = Ox.parseDate(start, utc),
dates = [start, end].map(function(string) { dates = [start, end].map(function(string) {
@ -547,7 +535,7 @@ Ox.formatDegrees <f> Formats degrees as D°MM'SS"
> Ox.formatDegrees(-111.11, 'lng') > Ox.formatDegrees(-111.11, 'lng')
"111°06'36\"W" "111°06'36\"W"
@*/ @*/
export function formatDegrees(degrees, mode) { Ox.formatDegrees = function(degrees, mode) {
var days = 0, var days = 0,
seconds = Math.round(Math.abs(degrees) * 3600), seconds = Math.round(Math.abs(degrees) * 3600),
sign = degrees < 0 ? '-' : '', sign = degrees < 0 ? '-' : '',
@ -570,13 +558,11 @@ Ox.formatDimensions <f> Formats valus as dimension
> Ox.formatDimensions([1920, 1080], 'px') > Ox.formatDimensions([1920, 1080], 'px')
"1,920 × 1,080 px" "1,920 × 1,080 px"
@*/ @*/
export function formatDimensions(array, string) { Ox.formatDimensions = Ox.formatResolution = function(array, string) {
return array.map(function(value) { return array.map(function(value) {
return Ox.formatNumber(value); return Ox.formatNumber(value);
}).join(' × ') + (string ? ' ' + string : ''); }).join(' × ') + (string ? ' ' + string : '');
}; };
export const formatResolution = formatDimensions;
/*@ /*@
Ox.formatDuration <f> Formats a duration as a string Ox.formatDuration <f> Formats a duration as a string
@ -609,7 +595,7 @@ Ox.formatDuration <f> Formats a duration as a string
> Ox.formatDuration(0, 'long') > Ox.formatDuration(0, 'long')
'' ''
@*/ @*/
export function formatDuration(seconds/*, decimals, format*/) { Ox.formatDuration = function(seconds/*, decimals, format*/) {
var last = Ox.last(arguments), var last = Ox.last(arguments),
format = last == 'short' || last == 'long' ? last : 'none', format = last == 'short' || last == 'long' ? last : 'none',
decimals = Ox.isNumber(arguments[1]) ? arguments[1] : 0, decimals = Ox.isNumber(arguments[1]) ? arguments[1] : 0,
@ -663,7 +649,7 @@ Ox.formatISBN <f> Formats a string as an ISBN of a given length (10 or 13)
> Ox.formatISBN('978-0-306-40615-7', 10) > Ox.formatISBN('978-0-306-40615-7', 10)
'0306406152' '0306406152'
@*/ @*/
export function formatISBN(isbn, length, dashes) { Ox.formatISBN = function(isbn, length, dashes) {
var ret = ''; var ret = '';
function getCheckDigit(isbn) { function getCheckDigit(isbn) {
var mod = isbn.length == 10 ? 11 : 10 var mod = isbn.length == 10 ? 11 : 10
@ -711,7 +697,7 @@ Ox.formatNumber <f> Formats a number with thousands separators
> Ox.formatNumber(666666.666) > Ox.formatNumber(666666.666)
"666,667" "666,667"
@*/ @*/
export function formatNumber(number, decimals) { Ox.formatNumber = function(number, decimals) {
var array = [], var array = [],
abs = Math.abs(number), abs = Math.abs(number),
split = abs.toFixed(decimals).split('.'); split = abs.toFixed(decimals).split('.');
@ -740,7 +726,7 @@ Ox.formatOrdinal <f> Formats a number as an ordinal
> Ox.formatOrdinal(13) > Ox.formatOrdinal(13)
"13th" "13th"
@*/ @*/
export function formatOrdinal(number) { Ox.formatOrdinal = function(number) {
var string = Ox.formatNumber(number), var string = Ox.formatNumber(number),
length = string.length, length = string.length,
last = string[length - 1], last = string[length - 1],
@ -765,7 +751,7 @@ Ox.formatPercent <f> Formats the relation of two numbers as a percentage
> Ox.formatPercent(1, 1000, 2) > Ox.formatPercent(1, 1000, 2)
"0.10%" "0.10%"
@*/ @*/
export function formatPercent(number, total, decimals) { Ox.formatPercent = function(number, total, decimals) {
return Ox.formatNumber(number / total * 100, decimals) + Ox._('%'); return Ox.formatNumber(number / total * 100, decimals) + Ox._('%');
}; };
@ -786,7 +772,7 @@ Ox.formatRoman <f> Formats a number as a roman numeral
> Ox.formatRoman(10000) > Ox.formatRoman(10000)
'MMMMMMMMMM' 'MMMMMMMMMM'
@*/ @*/
export function formatRoman(number) { Ox.formatRoman = function(number) {
var string = ''; var string = '';
Ox.forEach({ Ox.forEach({
M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90,
@ -803,7 +789,7 @@ export function formatRoman(number) {
/*@ /*@
Ox.formatSRT <f> Formats subtitles as SRT Ox.formatSRT <f> Formats subtitles as SRT
@*/ @*/
export function formatSRT(subtitles) { Ox.formatSRT = function(subtitles) {
return '\ufeff' + Ox.sortBy(subtitles, ['in', 'out']).map(function(subtitle, index) { return '\ufeff' + Ox.sortBy(subtitles, ['in', 'out']).map(function(subtitle, index) {
return [ return [
index + 1, index + 1,
@ -830,7 +816,7 @@ Ox.formatString <f> Basic string formatting
> Ox.formatString('{b}', {a: 'foobar'}, true) > Ox.formatString('{b}', {a: 'foobar'}, true)
'{b}' '{b}'
@*/ @*/
export function formatString(string, collection, keepUnmatched) { Ox.formatString = function(string, collection, keepUnmatched) {
return string.replace(/\{([^}]+)\}/g, function(string, match) { return string.replace(/\{([^}]+)\}/g, function(string, match) {
// make sure to not split at escaped dots ('\.') // make sure to not split at escaped dots ('\.')
var key, var key,
@ -858,7 +844,7 @@ Ox.formatUnit <f> Formats a number with a unit
> Ox.formatUnit(100/3, '%') > Ox.formatUnit(100/3, '%')
'33%' '33%'
@*/ @*/
export function formatUnit(number, string, decimals) { Ox.formatUnit = function(number, string, decimals) {
return Ox.formatNumber(number, decimals) return Ox.formatNumber(number, decimals)
+ (/^[:%]/.test(string) ? '' : ' ') + string; + (/^[:%]/.test(string) ? '' : ' ') + string;
}; };
@ -873,7 +859,7 @@ Ox.formatValue <f> Formats a numerical value
"1.15 GiB" "1.15 GiB"
@*/ @*/
// fixme: is this the best name? // fixme: is this the best name?
export function formatValue(number, string, bin) { Ox.formatValue = function(number, string, bin) {
var base = bin ? 1024 : 1000, var base = bin ? 1024 : 1000,
length = Ox.PREFIXES.length, length = Ox.PREFIXES.length,
ret; ret;

View file

@ -1,17 +1,5 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxConstants,
OxMath
);
/*@ /*@
Ox.cache <f> Memoize a function Ox.cache <f> Memoize a function
fn <f> function fn <f> function
@ -27,7 +15,7 @@ Ox.cache <f> Memoize a function
false false
@*/ @*/
// TODO: add async test // TODO: add async test
export function cache(fn, options) { Ox.cache = function(fn, options) {
var cache = {}, ret; var cache = {}, ret;
options = options || {}; options = options || {};
options.async = options.async || false; options.async = options.async || false;
@ -77,7 +65,7 @@ Ox.debounce <f> Runs a function once it stops being called for a given interval
ms <n|250> Interval in milliseconds ms <n|250> Interval in milliseconds
immediate <b|false> If true, function is called once immediately immediate <b|false> If true, function is called once immediately
@*/ @*/
export function debounce(fn/*, ms, immediate*/) { Ox.debounce = function(fn/*, ms, immediate*/) {
var args, var args,
immediate = Ox.last(arguments) === true, immediate = Ox.last(arguments) === true,
ms = Ox.isNumber(arguments[1]) ? arguments[1] : 250, ms = Ox.isNumber(arguments[1]) ? arguments[1] : 250,
@ -107,7 +95,7 @@ Ox.identity <f> Returns its first argument
> Ox.identity(Infinity) > Ox.identity(Infinity)
Infinity Infinity
@*/ @*/
export function identity(value) { Ox.identity = function(value) {
return value; return value;
}; };
@ -120,7 +108,7 @@ Ox.noop <f> Returns undefined and calls optional callback without arguments
> Ox.noop(1, 2, 3, function() { Ox.test(arguments.length, 0); }) > Ox.noop(1, 2, 3, function() { Ox.test(arguments.length, 0); })
undefined undefined
@*/ @*/
export function noop() { Ox.noop = function() {
var callback = Ox.last(arguments); var callback = Ox.last(arguments);
Ox.isFunction(callback) && callback(); Ox.isFunction(callback) && callback();
}; };
@ -130,7 +118,7 @@ Ox.once <f> Runs a function once, and then never again
(fn) -> <f> Function that will run only once (fn) -> <f> Function that will run only once
fn <f> Function to run once fn <f> Function to run once
@*/ @*/
export function once(fn) { Ox.once = function(fn) {
var once = false; var once = false;
return function() { return function() {
if (!once) { if (!once) {
@ -151,11 +139,11 @@ Ox.queue <f> Queue of asynchronous function calls with cached results
fn <f> Queued function fn <f> Queued function
maxThreads <n|10> Number of parallel function calls maxThreads <n|10> Number of parallel function calls
@*/ @*/
export function queue(fn, maxThreads) { Ox.queue = function(fn, maxThreads) {
maxThreads = maxThreads || 10; maxThreads = maxThreads || 10;
var processing = [], var processing = [],
queued = [], queued = [],
ret = cache(function() { ret = Ox.cache(function() {
var args = Ox.slice(arguments); var args = Ox.slice(arguments);
queued.push({args: args, key: getKey(args)}); queued.push({args: args, key: getKey(args)});
process(); process();
@ -211,7 +199,7 @@ Ox.throttle <f> Runs a function at most once per given interval
fn <f> Function to throttle fn <f> Function to throttle
ms <n|250> Interval in milliseconds ms <n|250> Interval in milliseconds
@*/ @*/
export function throttle(fn, ms) { Ox.throttle = function(fn, ms) {
var args, var args,
timeout; timeout;
ms = arguments.length == 1 ? 250 : ms; ms = arguments.length == 1 ? 250 : ms;
@ -234,7 +222,7 @@ export function throttle(fn, ms) {
Ox.time <f> Returns the time it takes to execute a given function Ox.time <f> Returns the time it takes to execute a given function
(fn) -> <n> Time in milliseconds (fn) -> <n> Time in milliseconds
@*/ @*/
export function time(fn) { Ox.time = function(fn) {
var time = new Date(); var time = new Date();
fn(); fn();
return new Date() - time; return new Date() - time;

View file

@ -1,488 +1,480 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js'; (function() {
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {}; // fixme: make all this work with different types of "points"
// i.e. {lat, lng}, [lat, lng]
Object.assign(Ox, function deg(point) {
OxObject, return Ox.map(point, function(val) {
OxConstants, return Ox.mod(Ox.deg(val) + 180, 360) - 180;
OxMath
);
// fixme: make all this work with different types of "points"
// i.e. {lat, lng}, [lat, lng]
function deg(point) {
return Ox.map(point, function(val) {
return Ox.mod(Ox.deg(val) + 180, 360) - 180;
});
}
function rad(point) {
return Ox.map(point, function(val) {
return Ox.rad(val);
});
}
function splitArea(area) {
return Ox.crossesDateline(area.sw, area.ne) ? [
{sw: area.sw, ne: {lat: area.ne.lat, lng: 180}},
{sw: {lat: area.sw.lat, lng: -180}, ne: area.ne}
] : [area];
}
/*@
Ox.crossesDateline <f> Returns true if a given line crosses the dateline
> Ox.crossesDateline({lat: 0, lng: -90}, {lat: 0, lng: 90})
false
> Ox.crossesDateline({lat: 0, lng: 90}, {lat: 0, lng: -90})
true
@*/
// FIXME: argument should be {w: ..., e: ...}
export function crossesDateline(pointA, pointB) {
return pointA.lng > pointB.lng;
};
/*@
Ox.getArea <f> Returns the area in square meters of a given rectancle
@*/
// FIXME: argument should be {sw: ..., ne: ...}
export function getArea(pointA, pointB) {
/*
area of a ring between two latitudes:
2 * PI * r^2 * abs(sin(latA) - sin(latB))
see http://mathforum.org/library/drmath/view/63767.html
=>
2 * Math.PI
* Math.pow(Ox.EARTH_RADIUS, 2)
* Math.abs(Math.sin(Ox.rad(latA)) - Math.sin(Ox.rad(latB)))
* Math.abs(Ox.rad(lngA) - Ox.rad(lngB))
/ (2 * Math.PI)
*/
if (Ox.crossesDateline(pointA, pointB)) {
pointB.lng += 360;
}
pointA = rad(pointA);
pointB = rad(pointB);
return Math.pow(Ox.EARTH_RADIUS, 2)
* Math.abs(Math.sin(pointA.lat) - Math.sin(pointB.lat))
* Math.abs(pointA.lng - pointB.lng);
};
/*@
Ox.getAverageBearing <f> Returns the average of two bearings
> Ox.getAverageBearing(0, 90)
45
> Ox.getAverageBearing(10, 350)
0
@*/
// FIXME: find the proper name of this operation
// FIMXE: use in manhattan grid example
export function getAverageBearing(bearingA, bearingB) {
return Ox.mod((bearingA + bearingB) / 2 + (
Math.abs(bearingA - bearingB) > 180 ? 180 : 0
), 360);
};
/*@
Ox.getBearing <f> Returns the bearing from one point to another
> Ox.getBearing({lat: -45, lng: 0}, {lat: 45, lng: 0})
0
> Ox.getBearing({lat: 0, lng: -90}, {lat: 0, lng: 90})
90
@*/
export function getBearing(pointA, pointB) {
pointA = rad(pointA);
pointB = rad(pointB);
var x = Math.cos(pointA.lat) * Math.sin(pointB.lat)
- Math.sin(pointA.lat) * Math.cos(pointB.lat)
* Math.cos(pointB.lng - pointA.lng),
y = Math.sin(pointB.lng - pointA.lng)
* Math.cos(pointB.lat);
return (Ox.deg(Math.atan2(y, x)) + 360) % 360;
};
// FIXME: name, docs
export function getBearingDifference(bearingA, bearingB) {
var difference = Math.abs(bearingA - bearingB);
return difference > 180 ? 360 - difference : difference;
};
/*@
Ox.getCenter <f> Returns the center of a recangle on a spehre
> Ox.getCenter({lat: -45, lng: -90}, {lat: 45, lng: 90})
{lat: 0, lng: 0}
@*/
export function getCenter(pointA, pointB) {
pointA = rad(pointA);
pointB = rad(pointB);
var x = Math.cos(pointB.lat)
* Math.cos(pointB.lng - pointA.lng),
y = Math.cos(pointB.lat)
* Math.sin(pointB.lng - pointA.lng),
d = Math.sqrt(
Math.pow(Math.cos(pointA.lat) + x, 2) + Math.pow(y, 2)
),
lat = Math.atan2(Math.sin(pointA.lat) + Math.sin(pointB.lat), d),
lng = pointA.lng + Math.atan2(y, Math.cos(pointA.lat) + x);
return deg({lat: lat, lng: lng});
};
/*@
Ox.getCircle <f> Returns points on a circle around a given point
(center, radius, precision) -> <a> Points
center <o> Center point ({lat, lng})
radius <n> Radius in meters
precision <n> Precision (the circle will have 2^precision segments)
@*/
export function getCircle(center, radius, precision) {
return Ox.range(
0, 360, 360 / Math.pow(2, precision)
).map(function(bearing) {
return Ox.getPoint(center, radius, bearing);
});
};
// FIXME: name, docs
export function getClosestBearing(bearing, bearings) {
var differences = bearings.map(function(bearing_) {
return getBearingDifference(bearing, bearing_);
});
return bearings[differences.indexOf(Ox.min(differences))];
};
/*@
Ox.getDegreesPerMeter <f> Returns degrees per meter at a given latitude
> 360 / Ox.getDegreesPerMeter(0)
Ox.EARTH_CIRCUMFERENCE
@*/
export function getDegreesPerMeter(lat) {
return 360 / Ox.EARTH_CIRCUMFERENCE / Math.cos(lat * Math.PI / 180);
};
/*@
Ox.getDistance <f> Returns the distance in meters between two points
> Ox.getDistance({lat: -45, lng: -90}, {lat: 45, lng: 90}) * 2
Ox.EARTH_CIRCUMFERENCE
@*/
export function getDistance(pointA, pointB) {
pointA = rad(pointA);
pointB = rad(pointB);
return Math.acos(
Math.sin(pointA.lat) * Math.sin(pointB.lat)
+ Math.cos(pointA.lat) * Math.cos(pointB.lat)
* Math.cos(pointB.lng - pointA.lng)
) * Ox.EARTH_RADIUS;
};
/*@
Ox.getLatLngByXY <f> Returns lat/lng for a given x/y on a 1x1 mercator projection
> Ox.getLatLngByXY({x: 0.5, y: 0.5})
{lat: -0, lng: 0}
@*/
export function getLatLngByXY(xy) {
function getValue(value) {
return (value - 0.5) * 2 * Math.PI;
}
return {
lat: -Ox.deg(Math.atan(Ox.sinh(getValue(xy.y)))),
lng: Ox.deg(getValue(xy.x))
};
};
/*@
Ox.getLine <f> Returns points on a line between two points
(pointA, pointB, precision) -> <a> Points
pointA <o> Start point ({lat, lng})
pointB <o> End point ({lat, lng})
precision <n> Precision (the line will have 2^precision segments)
@*/
export function getLine(pointA, pointB, precision) {
var line = [pointA, pointB], points;
while (precision > 0) {
points = [line[0]];
Ox.loop(line.length - 1, function(i) {
points.push(
Ox.getCenter(line[i], line[i + 1]),
line[i + 1]
);
}); });
line = points;
precision--;
} }
return line;
};
/*@ function rad(point) {
Ox.getMetersPerDegree <f> Returns meters per degree at a given latitude return Ox.map(point, function(val) {
> Ox.getMetersPerDegree(0) * 360 return Ox.rad(val);
Ox.EARTH_CIRCUMFERENCE
@*/
export function getMetersPerDegree(lat) {
return Math.cos(lat * Math.PI / 180) * Ox.EARTH_CIRCUMFERENCE / 360;
};
/*@
Ox.getPoint <f> Returns a point at a given distance/bearing from a given point
> Ox.getPoint({lat: -45, lng: 0}, Ox.EARTH_CIRCUMFERENCE / 4, 0)
{lat: 45, lng: 0}
@*/
export function getPoint(point, distance, bearing) {
var pointB = {};
point = rad(point);
distance /= Ox.EARTH_RADIUS;
bearing = Ox.rad(bearing);
pointB.lat = Math.asin(
Math.sin(point.lat) * Math.cos(distance)
+ Math.cos(point.lat) * Math.sin(distance) * Math.cos(bearing)
);
pointB.lng = point.lng + Math.atan2(
Math.sin(bearing) * Math.sin(distance) * Math.cos(point.lat),
Math.cos(distance) - Math.sin(point.lat) * Math.sin(pointB.lat)
);
return deg(pointB);
};
/*@
Ox.getXYByLatLng <f> Returns x/y on a 1x1 mercator projection for a given lat/lng
> Ox.getXYByLatLng({lat: 0, lng: 0})
{x: 0.5, y: 0.5}
@*/
export function getXYByLatLng(latlng) {
function getValue(value) {
return value / (2 * Math.PI) + 0.5;
}
return {
x: getValue(Ox.rad(latlng.lng)),
y: getValue(Ox.asinh(Math.tan(Ox.rad(-latlng.lat))))
};
};
/*@
Ox.isPolar <f> Returns true if a given point is outside the bounds of a mercator projection
> Ox.isPolar({lat: 90, lng: 0})
true
@*/
export function isPolar(point) {
return point.lat < Ox.MIN_LATITUDE || point.lat > Ox.MAX_LATITUDE;
};
/*@
Ox.containsArea <f> Returns true if an area contains another area
<script>
Ox.test.areas = [
{sw: {lat: -30, lng: -30}, ne: {lat: 30, lng: 30}},
{sw: {lat: -20, lng: -40}, ne: {lat: 20, lng: 40}},
{sw: {lat: -30, lng: 150}, ne: {lat: 30, lng: -150}},
{sw: {lat: 10, lng: -170}, ne: {lat: 20, lng: -160}}
];
</script>
> Ox.containsArea(Ox.test.areas[0], Ox.test.areas[1])
false
> Ox.containsArea(Ox.test.areas[2], Ox.test.areas[3])
true
@*/
// FIXME: Shouldn't this be rewritten as a test
// if the intersection is equal to the inner area?
export function containsArea(areaA, areaB) {
// If an area crosses the dateline,
// we split it into two parts,
// west and east of the dateline
var areas = [areaA, areaB].map(splitArea), ret;
function contains(areaA, areaB) {
return areaA.sw.lat <= areaB.sw.lat
&& areaA.sw.lng <= areaB.sw.lng
&& areaA.ne.lat >= areaB.ne.lat
&& areaA.ne.lng >= areaB.ne.lng;
}
// For each part of the inner area, test if it
// is contained in any part of the outer area
Ox.forEach(areas[1], function(area1) {
Ox.forEach(areas[0], function(area0) {
ret = contains(area0, area1);
// Break if the outer part contains the inner part
return !ret;
}); });
// Break if no outer part contains the inner part }
return ret;
});
return ret;
};
/*@ function splitArea(area) {
Ox.intersectAreas <f> Returns the intersection of two areas, or null return Ox.crossesDateline(area.sw, area.ne) ? [
<script> {sw: area.sw, ne: {lat: area.ne.lat, lng: 180}},
Ox.test.areas = [ {sw: {lat: area.sw.lat, lng: -180}, ne: area.ne}
{sw: {lat: -10, lng: -10}, ne: {lat: 0, lng: 0}}, ] : [area];
{sw: {lat: 0, lng: 0}, ne: {lat: 10, lng: 10}}, }
{sw: {lat: -30, lng: 150}, ne: {lat: 30, lng: -150}},
{sw: {lat: 25, lng: -155}, ne: {lat: 35, lng: -145}} /*@
]; Ox.crossesDateline <f> Returns true if a given line crosses the dateline
</script> > Ox.crossesDateline({lat: 0, lng: -90}, {lat: 0, lng: 90})
> Ox.intersectAreas([Ox.test.areas[0], Ox.test.areas[1]]) false
{sw: {lat: 0, lng: 0}, ne: {lat: 0, lng: 0}} > Ox.crossesDateline({lat: 0, lng: 90}, {lat: 0, lng: -90})
> Ox.intersectAreas([Ox.test.areas[2], Ox.test.areas[3]]) true
{sw: {lat: 25, lng: -155}, ne: {lat: 30, lng: -150}} @*/
@*/ // FIXME: argument should be {w: ..., e: ...}
// FIXME: handle the a corner case where Ox.crossesDateline = function(pointA, pointB) {
// two areas have two intersections return pointA.lng > pointB.lng;
export function intersectAreas(areas) { };
var intersections, ret;
// If an area crosses the dateline, /*@
// we split it into two parts, Ox.getArea <f> Returns the area in square meters of a given rectancle
// west and east of the dateline @*/
areas = areas.map(splitArea); // FIXME: argument should be {sw: ..., ne: ...}
ret = areas[0]; Ox.getArea = function(pointA, pointB) {
function intersect(areaA, areaB) { /*
return areaA.sw.lat > areaB.ne.lat area of a ring between two latitudes:
|| areaA.sw.lng > areaB.ne.lng 2 * PI * r^2 * abs(sin(latA) - sin(latB))
|| areaA.ne.lat < areaB.sw.lat see http://mathforum.org/library/drmath/view/63767.html
|| areaA.ne.lng < areaB.sw.lng =>
? null : { 2 * Math.PI
sw: { * Math.pow(Ox.EARTH_RADIUS, 2)
lat: Math.max(areaA.sw.lat, areaB.sw.lat), * Math.abs(Math.sin(Ox.rad(latA)) - Math.sin(Ox.rad(latB)))
lng: Math.max(areaA.sw.lng, areaB.sw.lng) * Math.abs(Ox.rad(lngA) - Ox.rad(lngB))
}, / (2 * Math.PI)
ne: { */
lat: Math.min(areaA.ne.lat, areaB.ne.lat), if (Ox.crossesDateline(pointA, pointB)) {
lng: Math.min(areaA.ne.lng, areaB.ne.lng) pointB.lng += 360;
} }
pointA = rad(pointA);
pointB = rad(pointB);
return Math.pow(Ox.EARTH_RADIUS, 2)
* Math.abs(Math.sin(pointA.lat) - Math.sin(pointB.lat))
* Math.abs(pointA.lng - pointB.lng);
};
/*@
Ox.getAverageBearing <f> Returns the average of two bearings
> Ox.getAverageBearing(0, 90)
45
> Ox.getAverageBearing(10, 350)
0
@*/
// FIXME: find the proper name of this operation
// FIMXE: use in manhattan grid example
Ox.getAverageBearing = function(bearingA, bearingB) {
return Ox.mod((bearingA + bearingB) / 2 + (
Math.abs(bearingA - bearingB) > 180 ? 180 : 0
), 360);
};
/*@
Ox.getBearing <f> Returns the bearing from one point to another
> Ox.getBearing({lat: -45, lng: 0}, {lat: 45, lng: 0})
0
> Ox.getBearing({lat: 0, lng: -90}, {lat: 0, lng: 90})
90
@*/
Ox.getBearing = function(pointA, pointB) {
pointA = rad(pointA);
pointB = rad(pointB);
var x = Math.cos(pointA.lat) * Math.sin(pointB.lat)
- Math.sin(pointA.lat) * Math.cos(pointB.lat)
* Math.cos(pointB.lng - pointA.lng),
y = Math.sin(pointB.lng - pointA.lng)
* Math.cos(pointB.lat);
return (Ox.deg(Math.atan2(y, x)) + 360) % 360;
};
// FIXME: name, docs
Ox.getBearingDifference = function(bearingA, bearingB) {
var difference = Math.abs(bearingA - bearingB);
return difference > 180 ? 360 - difference : difference;
};
/*@
Ox.getCenter <f> Returns the center of a recangle on a spehre
> Ox.getCenter({lat: -45, lng: -90}, {lat: 45, lng: 90})
{lat: 0, lng: 0}
@*/
Ox.getCenter = function(pointA, pointB) {
pointA = rad(pointA);
pointB = rad(pointB);
var x = Math.cos(pointB.lat)
* Math.cos(pointB.lng - pointA.lng),
y = Math.cos(pointB.lat)
* Math.sin(pointB.lng - pointA.lng),
d = Math.sqrt(
Math.pow(Math.cos(pointA.lat) + x, 2) + Math.pow(y, 2)
),
lat = Math.atan2(Math.sin(pointA.lat) + Math.sin(pointB.lat), d),
lng = pointA.lng + Math.atan2(y, Math.cos(pointA.lat) + x);
return deg({lat: lat, lng: lng});
};
/*@
Ox.getCircle <f> Returns points on a circle around a given point
(center, radius, precision) -> <a> Points
center <o> Center point ({lat, lng})
radius <n> Radius in meters
precision <n> Precision (the circle will have 2^precision segments)
@*/
Ox.getCircle = function(center, radius, precision) {
return Ox.range(
0, 360, 360 / Math.pow(2, precision)
).map(function(bearing) {
return Ox.getPoint(center, radius, bearing);
});
};
// FIXME: name, docs
Ox.getClosestBearing = function(bearing, bearings) {
var differences = bearings.map(function(bearing_) {
return getBearingDifference(bearing, bearing_);
});
return bearings[differences.indexOf(Ox.min(differences))];
};
/*@
Ox.getDegreesPerMeter <f> Returns degrees per meter at a given latitude
> 360 / Ox.getDegreesPerMeter(0)
Ox.EARTH_CIRCUMFERENCE
@*/
Ox.getDegreesPerMeter = function(lat) {
return 360 / Ox.EARTH_CIRCUMFERENCE / Math.cos(lat * Math.PI / 180);
};
/*@
Ox.getDistance <f> Returns the distance in meters between two points
> Ox.getDistance({lat: -45, lng: -90}, {lat: 45, lng: 90}) * 2
Ox.EARTH_CIRCUMFERENCE
@*/
Ox.getDistance = function(pointA, pointB) {
pointA = rad(pointA);
pointB = rad(pointB);
return Math.acos(
Math.sin(pointA.lat) * Math.sin(pointB.lat)
+ Math.cos(pointA.lat) * Math.cos(pointB.lat)
* Math.cos(pointB.lng - pointA.lng)
) * Ox.EARTH_RADIUS;
};
/*@
Ox.getLatLngByXY <f> Returns lat/lng for a given x/y on a 1x1 mercator projection
> Ox.getLatLngByXY({x: 0.5, y: 0.5})
{lat: -0, lng: 0}
@*/
Ox.getLatLngByXY = function(xy) {
function getValue(value) {
return (value - 0.5) * 2 * Math.PI;
}
return {
lat: -Ox.deg(Math.atan(Ox.sinh(getValue(xy.y)))),
lng: Ox.deg(getValue(xy.x))
}; };
} };
Ox.forEach(areas.slice(1), function(parts) {
if (ret.length == 1 && parts.length == 1) {
ret = intersect(ret[0], parts[0]);
} else {
// intersect each part of the intersection
// with all parts of the next area
intersections = Ox.compact(ret.map(function(part) {
return Ox.intersectAreas(parts.concat(part));
}));
ret = intersections.length == 0 ? null
: Ox.joinAreas(intersections);
}
if (ret === null) {
return false; // break
} else {
ret = splitArea(ret);
}
});
return ret ? Ox.joinAreas(ret) : null;
};
/*@ /*@
Ox.joinAreas <f> Joins an array of areas Ox.getLine <f> Returns points on a line between two points
<script> (pointA, pointB, precision) -> <a> Points
Ox.test.areas = [ pointA <o> Start point ({lat, lng})
{sw: {lat: -30, lng: 150}, ne: {lat: -20, lng: 160}}, pointB <o> End point ({lat, lng})
{sw: {lat: -10, lng: 170}, ne: {lat: 10, lng: -170}}, precision <n> Precision (the line will have 2^precision segments)
{sw: {lat: 20, lng: -160}, ne: {lat: 30, lng: -150}} @*/
]; Ox.getLine = function(pointA, pointB, precision) {
</script> var line = [pointA, pointB], points;
> Ox.joinAreas(Ox.test.areas) while (precision > 0) {
{sw: {lat: -30, lng: 150}, ne: {lat: 30, lng: -150}} points = [line[0]];
@*/ Ox.loop(line.length - 1, function(i) {
export function joinAreas(areas) { points.push(
// While the combined latitude is trivial (min to max), the combined longitude Ox.getCenter(line[i], line[i + 1]),
// spans from the eastern to the western edge of the largest gap between areas line[i + 1]
var ret = areas[0], );
gaps = [{ });
sw: {lat: -90, lng: ret.ne.lng}, line = points;
ne: {lat: 90, lng: ret.sw.lng} precision--;
}]; }
function containsGaps(area) { return line;
return Ox.getIndices(gaps, function(gap) { };
return Ox.containsArea({
sw: {lat: -90, lng: area.sw.lng}, /*@
ne: {lat: 90, lng: area.ne.lng} Ox.getMetersPerDegree <f> Returns meters per degree at a given latitude
}, gap); > Ox.getMetersPerDegree(0) * 360
}); Ox.EARTH_CIRCUMFERENCE
} @*/
function intersectsWithGaps(area) { Ox.getMetersPerDegree = function(lat) {
var ret = {}; return Math.cos(lat * Math.PI / 180) * Ox.EARTH_CIRCUMFERENCE / 360;
gaps.forEach(function(gap, i) { };
var intersection = Ox.intersectAreas([area, gap]);
if (intersection) { /*@
ret[i] = intersection; Ox.getPoint <f> Returns a point at a given distance/bearing from a given point
} > Ox.getPoint({lat: -45, lng: 0}, Ox.EARTH_CIRCUMFERENCE / 4, 0)
{lat: 45, lng: 0}
@*/
Ox.getPoint = function(point, distance, bearing) {
var pointB = {};
point = rad(point);
distance /= Ox.EARTH_RADIUS;
bearing = Ox.rad(bearing);
pointB.lat = Math.asin(
Math.sin(point.lat) * Math.cos(distance)
+ Math.cos(point.lat) * Math.sin(distance) * Math.cos(bearing)
);
pointB.lng = point.lng + Math.atan2(
Math.sin(bearing) * Math.sin(distance) * Math.cos(point.lat),
Math.cos(distance) - Math.sin(point.lat) * Math.sin(pointB.lat)
);
return deg(pointB);
};
/*@
Ox.getXYByLatLng <f> Returns x/y on a 1x1 mercator projection for a given lat/lng
> Ox.getXYByLatLng({lat: 0, lng: 0})
{x: 0.5, y: 0.5}
@*/
Ox.getXYByLatLng = function(latlng) {
function getValue(value) {
return value / (2 * Math.PI) + 0.5;
}
return {
x: getValue(Ox.rad(latlng.lng)),
y: getValue(Ox.asinh(Math.tan(Ox.rad(-latlng.lat))))
};
};
/*@
Ox.isPolar <f> Returns true if a given point is outside the bounds of a mercator projection
> Ox.isPolar({lat: 90, lng: 0})
true
@*/
Ox.isPolar = function(point) {
return point.lat < Ox.MIN_LATITUDE || point.lat > Ox.MAX_LATITUDE;
};
/*@
Ox.containsArea <f> Returns true if an area contains another area
<script>
Ox.test.areas = [
{sw: {lat: -30, lng: -30}, ne: {lat: 30, lng: 30}},
{sw: {lat: -20, lng: -40}, ne: {lat: 20, lng: 40}},
{sw: {lat: -30, lng: 150}, ne: {lat: 30, lng: -150}},
{sw: {lat: 10, lng: -170}, ne: {lat: 20, lng: -160}}
];
</script>
> Ox.containsArea(Ox.test.areas[0], Ox.test.areas[1])
false
> Ox.containsArea(Ox.test.areas[2], Ox.test.areas[3])
true
@*/
// FIXME: Shouldn't this be rewritten as a test
// if the intersection is equal to the inner area?
Ox.containsArea = function(areaA, areaB) {
// If an area crosses the dateline,
// we split it into two parts,
// west and east of the dateline
var areas = [areaA, areaB].map(splitArea), ret;
function contains(areaA, areaB) {
return areaA.sw.lat <= areaB.sw.lat
&& areaA.sw.lng <= areaB.sw.lng
&& areaA.ne.lat >= areaB.ne.lat
&& areaA.ne.lng >= areaB.ne.lng;
}
// For each part of the inner area, test if it
// is contained in any part of the outer area
Ox.forEach(areas[1], function(area1) {
Ox.forEach(areas[0], function(area0) {
ret = contains(area0, area1);
// Break if the outer part contains the inner part
return !ret;
});
// Break if no outer part contains the inner part
return ret;
}); });
return ret; return ret;
} };
function isContainedInGap(area) {
var ret = -1; /*@
Ox.forEach(gaps, function(gap, i) { Ox.intersectAreas <f> Returns the intersection of two areas, or null
if (Ox.containsArea(gap, area)) { <script>
ret = i; Ox.test.areas = [
{sw: {lat: -10, lng: -10}, ne: {lat: 0, lng: 0}},
{sw: {lat: 0, lng: 0}, ne: {lat: 10, lng: 10}},
{sw: {lat: -30, lng: 150}, ne: {lat: 30, lng: -150}},
{sw: {lat: 25, lng: -155}, ne: {lat: 35, lng: -145}}
];
</script>
> Ox.intersectAreas([Ox.test.areas[0], Ox.test.areas[1]])
{sw: {lat: 0, lng: 0}, ne: {lat: 0, lng: 0}}
> Ox.intersectAreas([Ox.test.areas[2], Ox.test.areas[3]])
{sw: {lat: 25, lng: -155}, ne: {lat: 30, lng: -150}}
@*/
// FIXME: handle the a corner case where
// two areas have two intersections
Ox.intersectAreas = function(areas) {
var intersections, ret;
// If an area crosses the dateline,
// we split it into two parts,
// west and east of the dateline
areas = areas.map(splitArea);
ret = areas[0];
function intersect(areaA, areaB) {
return areaA.sw.lat > areaB.ne.lat
|| areaA.sw.lng > areaB.ne.lng
|| areaA.ne.lat < areaB.sw.lat
|| areaA.ne.lng < areaB.sw.lng
? null : {
sw: {
lat: Math.max(areaA.sw.lat, areaB.sw.lat),
lng: Math.max(areaA.sw.lng, areaB.sw.lng)
},
ne: {
lat: Math.min(areaA.ne.lat, areaB.ne.lat),
lng: Math.min(areaA.ne.lng, areaB.ne.lng)
}
};
}
Ox.forEach(areas.slice(1), function(parts) {
if (ret.length == 1 && parts.length == 1) {
ret = intersect(ret[0], parts[0]);
} else {
// intersect each part of the intersection
// with all parts of the next area
intersections = Ox.compact(ret.map(function(part) {
return Ox.intersectAreas(parts.concat(part));
}));
ret = intersections.length == 0 ? null
: Ox.joinAreas(intersections);
}
if (ret === null) {
return false; // break return false; // break
} else {
ret = splitArea(ret);
} }
}); });
return ret; return ret ? Ox.joinAreas(ret) : null;
} };
areas.slice(1).forEach(function(area) {
var index, indices, intersections; /*@
if (area.sw.lat < ret.sw.lat) { Ox.joinAreas <f> Joins an array of areas
ret.sw.lat = area.sw.lat; <script>
} Ox.test.areas = [
if (area.ne.lat > ret.ne.lat) { {sw: {lat: -30, lng: 150}, ne: {lat: -20, lng: 160}},
ret.ne.lat = area.ne.lat; {sw: {lat: -10, lng: 170}, ne: {lat: 10, lng: -170}},
} {sw: {lat: 20, lng: -160}, ne: {lat: 30, lng: -150}}
// If the area is contained in a gap, split the gap in two ];
index = isContainedInGap(area); </script>
if (index > -1) { > Ox.joinAreas(Ox.test.areas)
gaps.push({ {sw: {lat: -30, lng: 150}, ne: {lat: 30, lng: -150}}
sw: gaps[index].sw, @*/
ne: {lat: 90, lng: area.sw.lng} Ox.joinAreas = function(areas) {
}); // While the combined latitude is trivial (min to max), the combined longitude
gaps.push({ // spans from the eastern to the western edge of the largest gap between areas
sw: {lat: -90, lng: area.ne.lng}, var ret = areas[0],
ne: gaps[index].ne gaps = [{
}); sw: {lat: -90, lng: ret.ne.lng},
gaps.splice(index, 1); ne: {lat: 90, lng: ret.sw.lng}
} else { }];
// If the area contains gaps, remove them function containsGaps(area) {
indices = containsGaps(area); return Ox.getIndices(gaps, function(gap) {
Ox.reverse(indices).forEach(function(index) { return Ox.containsArea({
gaps.splice(index, 1); sw: {lat: -90, lng: area.sw.lng},
}); ne: {lat: 90, lng: area.ne.lng}
// If the area intersects with gaps, shrink them }, gap);
intersections = intersectsWithGaps(area); });
Ox.forEach(intersections, function(intersection, index) { }
gaps[index] = { function intersectsWithGaps(area) {
sw: { var ret = {};
lat: -90, gaps.forEach(function(gap, i) {
lng: gaps[index].sw.lng == intersection.sw.lng var intersection = Ox.intersectAreas([area, gap]);
? intersection.ne.lng : gaps[index].sw.lng if (intersection) {
}, ret[i] = intersection;
ne: { }
lat: 90, });
lng: gaps[index].ne.lng == intersection.ne.lng return ret;
? intersection.sw.lng : gaps[index].ne.lng }
} function isContainedInGap(area) {
}; var ret = -1;
}); Ox.forEach(gaps, function(gap, i) {
} if (Ox.containsArea(gap, area)) {
}); ret = i;
if (gaps.length == 0) { return false; // break
ret.sw.lng = -180; }
ret.ne.lng = 180; });
} else { return ret;
gaps.sort(function(a, b) { }
return ( areas.slice(1).forEach(function(area) {
b.ne.lng var index, indices, intersections;
+ (Ox.crossesDateline(b.sw, b.ne) ? 360 : 0) if (area.sw.lat < ret.sw.lat) {
- b.sw.lng ret.sw.lat = area.sw.lat;
) - ( }
a.ne.lng if (area.ne.lat > ret.ne.lat) {
+ (Ox.crossesDateline(a.sw, a.ne) ? 360 : 0) ret.ne.lat = area.ne.lat;
- a.sw.lng }
); // If the area is contained in a gap, split the gap in two
}); index = isContainedInGap(area);
ret.sw.lng = gaps[0].ne.lng; if (index > -1) {
ret.ne.lng = gaps[0].sw.lng; gaps.push({
} sw: gaps[index].sw,
return ret; ne: {lat: 90, lng: area.sw.lng}
}; });
gaps.push({
sw: {lat: -90, lng: area.ne.lng},
ne: gaps[index].ne
});
gaps.splice(index, 1);
} else {
// If the area contains gaps, remove them
indices = containsGaps(area);
Ox.reverse(indices).forEach(function(index) {
gaps.splice(index, 1);
});
// If the area intersects with gaps, shrink them
intersections = intersectsWithGaps(area);
Ox.forEach(intersections, function(intersection, index) {
gaps[index] = {
sw: {
lat: -90,
lng: gaps[index].sw.lng == intersection.sw.lng
? intersection.ne.lng : gaps[index].sw.lng
},
ne: {
lat: 90,
lng: gaps[index].ne.lng == intersection.ne.lng
? intersection.sw.lng : gaps[index].ne.lng
}
};
});
}
});
if (gaps.length == 0) {
ret.sw.lng = -180;
ret.ne.lng = 180;
} else {
gaps.sort(function(a, b) {
return (
b.ne.lng
+ (Ox.crossesDateline(b.sw, b.ne) ? 360 : 0)
- b.sw.lng
) - (
a.ne.lng
+ (Ox.crossesDateline(a.sw, a.ne) ? 360 : 0)
- a.sw.lng
);
});
ret.sw.lng = gaps[0].ne.lng;
ret.ne.lng = gaps[0].sw.lng;
}
return ret;
};
}());

File diff suppressed because it is too large Load diff

View file

@ -1,21 +1,9 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxConstants,
OxMath
);
/*@ /*@
Ox.oshash <f> Calculates oshash for a given file or blob object. Async. Ox.oshash <f> Calculates oshash for a given file or blob object. Async.
@*/ @*/
export function oshash(file, callback) { Ox.oshash = function(file, callback) {
// Needs to go via string to work for files > 2GB // Needs to go via string to work for files > 2GB
var hash = fromString(file.size.toString()); var hash = fromString(file.size.toString());
@ -112,7 +100,7 @@ export function oshash(file, callback) {
/*@ /*@
Ox.SHA1 <f> Calculates SHA1 hash of the given string Ox.SHA1 <f> Calculates SHA1 hash of the given string
@*/ @*/
export function SHA1(msg) { Ox.SHA1 = function(msg) {
function rotate_left(n,s) { function rotate_left(n,s) {
var t4 = ( n<<s ) | (n>>>(32-s)); var t4 = ( n<<s ) | (n>>>(32-s));

View file

@ -1,21 +1,5 @@
'use strict'; 'use strict';
import * as OxArray from './Array.js';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
import * as OxString from './String.js';
const Ox = {};
Object.assign(Ox,
OxArray,
OxObject,
OxConstants,
OxMath,
OxString,
);
/*@ /*@
Ox.doc <f> Generates documentation for annotated JavaScript Ox.doc <f> Generates documentation for annotated JavaScript
(source) -> <[o]> Array of doc objects (source) -> <[o]> Array of doc objects

View file

@ -1,103 +1,90 @@
'use strict'; 'use strict';
import * as OxArray from './Array.js';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
import * as OxString from './String.js';
const Ox = {}; (function() {
Object.assign(Ox, var log, translations = {};
OxArray,
OxObject,
OxConstants,
OxMath,
OxString,
);
/*@
Ox.getLocale <f> Returns locale
() -> <s> Locale (like 'de' or 'fr')
@*/
Ox.getLocale = function() {
return Ox.LOCALE;
};
var log, translations = {}; /*@
Ox.setLocale <f> Sets locale
/*@ (locale[, url], callback)
Ox.getLocale <f> Returns locale locale <s> Locale (like 'de' or 'fr')
() -> <s> Locale (like 'de' or 'fr') url <s|[s]> one or more URLs of JSON file with additional translations
@*/ callback <f> Callback function
export function getLocale() { success <b> If true, locale has been set
return Ox.LOCALE; @*/
}; Ox.setLocale = function(locale, url, callback) {
var isValidLocale = Ox.contains(Object.keys(Ox.LOCALE_NAMES), locale),
/*@ urls = [];
Ox.setLocale <f> Sets locale if (arguments.length == 2) {
(locale[, url], callback) callback = arguments[1];
locale <s> Locale (like 'de' or 'fr') url = null;
url <s|[s]> one or more URLs of JSON file with additional translations
callback <f> Callback function
success <b> If true, locale has been set
@*/
export function setLocale(locale, url, callback) {
var isValidLocale = Ox.contains(Object.keys(Ox.LOCALE_NAMES), locale),
urls = [];
if (arguments.length == 2) {
callback = arguments[1];
url = null;
}
if (isValidLocale) {
Ox.LOCALE = locale;
if (locale == 'en') {
translations = {};
} else {
translations = {};
Ox.forEach(Ox.LOCALES, function(locales, module) {
if (
(module == 'Ox' || Ox.load[module])
&& Ox.contains(locales, locale)
) {
urls.push([
Ox.PATH + module + '/json/locale.'
+ locale + '.json'
]);
}
});
} }
url && Ox.makeArray(url).forEach(function(value) { if (isValidLocale) {
urls.push(Ox.makeArray(value)); Ox.LOCALE = locale;
}); if (locale == 'en') {
if (urls.length) { translations = {};
Ox.getJSON(urls, function(data) { } else {
Ox.forEach(data, function(values, url) { translations = {};
Ox.extend(translations, values); Ox.forEach(Ox.LOCALES, function(locales, module) {
if (
(module == 'Ox' || Ox.load[module])
&& Ox.contains(locales, locale)
) {
urls.push([
Ox.PATH + module + '/json/locale.'
+ locale + '.json'
]);
}
}); });
}
url && Ox.makeArray(url).forEach(function(value) {
urls.push(Ox.makeArray(value));
});
if (urls.length) {
Ox.getJSON(urls, function(data) {
Ox.forEach(data, function(values, url) {
Ox.extend(translations, values);
});
callback(true);
})
} else {
callback(true); callback(true);
}) }
} else { } else {
callback(true); callback(false);
} }
} else { };
callback(false);
}
};
/*@ /*@
Ox._ <f> Localizes a string Ox._ <f> Localizes a string
(string[, options]) -> <s> Localized string (string[, options]) -> <s> Localized string
string <s> English string string <s> English string
options <o> Options passed to Ox.formatString options <o> Options passed to Ox.formatString
@*/ @*/
export function _(value, options) { Ox._ = function(value, options) {
var translation = translations[value]; var translation = translations[value];
log && log(value, translation); log && log(value, translation);
translation = translation || value || ''; translation = translation || value || '';
return Ox.formatString(translation, options); return Ox.formatString(translation, options);
}; };
/*@ /*@
Ox._.log <f> Registers a logging function Ox._.log <f> Registers a logging function
(callback) -> <u> undefined (callback) -> <u> undefined
callback <f> Callback function callback <f> Callback function
english <s> English string english <s> English string
translation <s> Translated string translation <s> Translated string
@*/ @*/
_.log = function(callback) { Ox._.log = function(callback) {
log = callback; log = callback;
}; };
})();

View file

@ -1,20 +1,12 @@
'use strict'; 'use strict';
import * as OxArray from './Array.js';
const Ox = {};
Object.assign(Ox,
OxArray,
);
/*@ /*@
Ox.acosh <f> Inverse hyperbolic cosine Ox.acosh <f> Inverse hyperbolic cosine
Missing from `Math`. Missing from `Math`.
> Ox.acosh(1) > Ox.acosh(1)
0 0
@*/ @*/
export function acosh(x) { Ox.acosh = function(x) {
return Math.log(x + Math.sqrt(x * x - 1)); return Math.log(x + Math.sqrt(x * x - 1));
}; };
@ -24,7 +16,7 @@ Ox.asinh <f> Inverse hyperbolic sine
> Ox.asinh(0) > Ox.asinh(0)
0 0
@*/ @*/
export function asinh(x) { Ox.asinh = function(x) {
return Math.log(x + Math.sqrt(x * x + 1)); return Math.log(x + Math.sqrt(x * x + 1));
}; };
@ -34,7 +26,7 @@ Ox.atanh <f> Inverse hyperbolic tangent
> Ox.atanh(0) > Ox.atanh(0)
0 0
@*/ @*/
export function atanh(x) { Ox.atanh = function(x) {
return 0.5 * Math.log((1 + x) / (1 - x)); return 0.5 * Math.log((1 + x) / (1 - x));
}; };
@ -44,7 +36,7 @@ Ox.cosh <f> Hyperbolic cosine
> Ox.cosh(0) > Ox.cosh(0)
1 1
@*/ @*/
export function cosh(x) { Ox.cosh = function(x) {
return (Math.exp(x) + Math.exp(-x)) / 2; return (Math.exp(x) + Math.exp(-x)) / 2;
}; };
@ -54,7 +46,7 @@ Ox.deg <f> Takes radians, returns degrees
> Ox.deg(2 * Math.PI) > Ox.deg(2 * Math.PI)
360 360
@*/ @*/
export function deg(rad) { Ox.deg = function(rad) {
return rad * 180 / Math.PI; return rad * 180 / Math.PI;
}; };
@ -66,7 +58,7 @@ Ox.hypot <f> Returns the square root of the sum of the squares of its arguments
> Ox.hypot(1, 1, 1) > Ox.hypot(1, 1, 1)
Math.sqrt(3) Math.sqrt(3)
@*/ @*/
export function hypot() { Ox.hypot = function() {
return Math.sqrt(Ox.slice(arguments).reduce(function(sum, number) { return Math.sqrt(Ox.slice(arguments).reduce(function(sum, number) {
return sum + number * number; return sum + number * number;
}, 0)); }, 0));
@ -91,7 +83,7 @@ Ox.limit <f> Limits a number by a given mininum and maximum
> Ox.limit(-1, -2) > Ox.limit(-1, -2)
-2 -2
@*/ @*/
export function limit(/*number[[, min], max]*/) { Ox.limit = function(/*number[[, min], max]*/) {
var number = arguments[0], var number = arguments[0],
min = arguments.length == 3 ? arguments[1] : -Infinity, min = arguments.length == 3 ? arguments[1] : -Infinity,
max = arguments[arguments.length - 1]; max = arguments[arguments.length - 1];
@ -106,7 +98,7 @@ Ox.log <f> Returns the logarithm of a given number to a given base
> Ox.log(Math.E) > Ox.log(Math.E)
1 1
@*/ @*/
export function log(number, base) { Ox.log = function(number, base) {
return Math.log(number) / Math.log(base || Math.E); return Math.log(number) / Math.log(base || Math.E);
}; };
@ -118,7 +110,7 @@ Ox.mod <f> Modulo function
> Ox.mod(-11, 10) > Ox.mod(-11, 10)
9 9
@*/ @*/
export function mod(number, by) { Ox.mod = function(number, by) {
return (number % by + by) % by; return (number % by + by) % by;
}; };
@ -128,7 +120,7 @@ Ox.rad <f> Takes degrees, returns radians
> Ox.rad(360) > Ox.rad(360)
2 * Math.PI 2 * Math.PI
@*/ @*/
export function rad(deg) { Ox.rad = function(deg) {
return deg * Math.PI / 180; return deg * Math.PI / 180;
}; };
@ -144,7 +136,7 @@ Ox.random <f> Returns a random integer within a given range
> Ox.random(1, 2) == 1 > Ox.random(1, 2) == 1
true true
@*/ @*/
export function random() { Ox.random = function() {
var min = arguments.length == 2 ? arguments[0] : 0, var min = arguments.length == 2 ? arguments[0] : 0,
max = arguments.length ? Ox.last(arguments) : 2; max = arguments.length ? Ox.last(arguments) : 2;
return min + Math.floor(Math.random() * (max - min)); return min + Math.floor(Math.random() * (max - min));
@ -159,7 +151,7 @@ Ox.round <f> Rounds a number with a given number of decimals
> Ox.round(1 / 2) > Ox.round(1 / 2)
1 1
@*/ @*/
export function round(number, decimals) { Ox.round = function(number, decimals) {
var pow = Math.pow(10, decimals || 0); var pow = Math.pow(10, decimals || 0);
return Math.round(number * pow) / pow; return Math.round(number * pow) / pow;
}; };
@ -177,7 +169,7 @@ Ox.sign <f> Returns the sign of a number (-1, 0 or 1)
> Ox.sign(Infinity) > Ox.sign(Infinity)
1 1
@*/ @*/
export function sign(x) { Ox.sign = function(x) {
x = +x; x = +x;
return x !== x || x === 0 ? x : x < 0 ? -1 : 1; return x !== x || x === 0 ? x : x < 0 ? -1 : 1;
}; };
@ -188,7 +180,7 @@ Ox.sinh <f> Hyperbolic sine
> Ox.sinh(0) > Ox.sinh(0)
0 0
@*/ @*/
export function sinh(x) { Ox.sinh = function(x) {
return (Math.exp(x) - Math.exp(-x)) / 2; return (Math.exp(x) - Math.exp(-x)) / 2;
}; };
@ -202,7 +194,7 @@ Ox.splitInt <f> Splits an integer into an array of integers
> Ox.splitInt(100, 6) > Ox.splitInt(100, 6)
[16, 16, 17, 17, 17, 17] [16, 16, 17, 17, 17, 17]
@*/ @*/
export function splitInt(number, by) { Ox.splitInt = function(number, by) {
var div = Math.floor(number / by), var div = Math.floor(number / by),
mod = number % by; mod = number % by;
return Ox.range(by).map(function(i) { return Ox.range(by).map(function(i) {
@ -216,7 +208,7 @@ Ox.tanh <f> Hyperbolic tangent
> Ox.tanh(0) > Ox.tanh(0)
0 0
@*/ @*/
export function tanh(x) { Ox.tanh = function(x) {
return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x)); return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x));
}; };
@ -225,6 +217,6 @@ Ox.trunc <f> Truncates a number
> Ox.trunc(-1.5) > Ox.trunc(-1.5)
-1 -1
@*/ @*/
export function trunc(x) { Ox.trunc = function(x) {
return ~~x; return ~~x;
}; };

View file

@ -1,25 +1,5 @@
'use strict'; 'use strict';
import * as OxCore from './Core.js';
import * as OxFunction from './Function.js';
import * as OxConstants from './Constants.js';
import * as OxCollection from './Collection.js';
import * as OxMath from './Math.js';
import * as OxType from './Type.js';
import * as OxArray from './Array.js';
const Ox = {};
Object.assign(Ox,
OxCore,
OxFunction,
OxConstants,
OxCollection,
OxMath,
OxType,
OxArray,
);
/*@ /*@
Ox.extend <function> Extends an object with one or more other objects Ox.extend <function> Extends an object with one or more other objects
> Ox.extend({a: 1, b: 1, c: 1}, {b: 2, c: 2}, {c: 3}) > Ox.extend({a: 1, b: 1, c: 1}, {b: 2, c: 2}, {c: 3})
@ -29,10 +9,10 @@ Ox.extend <function> Extends an object with one or more other objects
> Ox.extend({a: 1}, 'b') > Ox.extend({a: 1}, 'b')
{a: 1, b: void 0} {a: 1, b: void 0}
@*/ @*/
export function extend(object) { Ox.extend = function(object) {
var args = Ox.slice(arguments, 1); var args = Ox.slice(arguments, 1);
if (!Ox.isObject(args[0])) { if (!Ox.isObject(args[0])) {
args = [makeObject(args)]; args = [Ox.makeObject(args)];
} }
Ox.forEach(args, function(arg) { Ox.forEach(args, function(arg) {
Ox.forEach(arg, function(value, key) { Ox.forEach(arg, function(value, key) {
@ -82,7 +62,7 @@ Ox.getset <f> Generic getter and setter function
> Ox.test.object.options({foo: "foo", bar: "bar"}).options() > Ox.test.object.options({foo: "foo", bar: "bar"}).options()
{"key": "val", "foo": "foo", "bar": "bar"} {"key": "val", "foo": "foo", "bar": "bar"}
@*/ @*/
export function getset(object, args, callback, that) { Ox.getset = function(object, args, callback, that) {
var object_ = Ox.clone(object), ret; var object_ = Ox.clone(object), ret;
if (args.length == 0) { if (args.length == 0) {
// [] // []
@ -92,7 +72,7 @@ export function getset(object, args, callback, that) {
ret = Ox.clone(object[args[0]]); ret = Ox.clone(object[args[0]]);
} else { } else {
// [key, val] or [{key: val, ...}] // [key, val] or [{key: val, ...}]
args = makeObject(args); args = Ox.makeObject(args);
object = Ox.extend(object, args); object = Ox.extend(object, args);
Ox.forEach(args, function(value, key) { Ox.forEach(args, function(value, key) {
if (!object_ || !Ox.isEqual(object_[key], value)) { if (!object_ || !Ox.isEqual(object_[key], value)) {
@ -104,7 +84,7 @@ export function getset(object, args, callback, that) {
return ret; return ret;
}; };
export function hasOwn(object, value) { Ox.hasOwn = function(object, value) {
return Object.prototype.hasOwnProperty.call(object, value); return Object.prototype.hasOwnProperty.call(object, value);
}; };
@ -113,7 +93,7 @@ Ox.keyOf <f> Equivalent of [].indexOf for objects
> Ox.keyOf({a: 1, b: 2, c: 3}, 1) > Ox.keyOf({a: 1, b: 2, c: 3}, 1)
'a' 'a'
@*/ @*/
export function keyOf(object, value) { Ox.keyOf = function(object, value) {
var key; var key;
Ox.forEach(object, function(v, k) { Ox.forEach(object, function(v, k) {
if (v === value) { if (v === value) {
@ -137,7 +117,7 @@ Ox.makeObject <f> Takes an array and returns an object
> (function() { return Ox.makeObject(arguments); }()) > (function() { return Ox.makeObject(arguments); }())
{} {}
@*/ @*/
export function makeObject(array) { Ox.makeObject = function(array) {
var ret = {}; var ret = {};
if (Ox.isObject(array[0])) { if (Ox.isObject(array[0])) {
// [{foo: 'bar'}] // [{foo: 'bar'}]
@ -154,7 +134,7 @@ Ox.methods <f> Returns a sorted list of all method names of an object
> Ox.methods({a: [], b: false, f: function() {}, n: 0, o: {}, s: ''}) > Ox.methods({a: [], b: false, f: function() {}, n: 0, o: {}, s: ''})
['f'] ['f']
@*/ @*/
export function methods(object, includePrototype) { Ox.methods = function(object, includePrototype) {
var key, keys; var key, keys;
if (includePrototype) { if (includePrototype) {
keys = []; keys = [];
@ -178,7 +158,7 @@ Ox.serialize <f> Parses an object into query parameters
> Ox.serialize({a: [1, 2], b: true, n: 1, o: {k: 'v'}, s: 'foo'}, true) > Ox.serialize({a: [1, 2], b: true, n: 1, o: {k: 'v'}, s: 'foo'}, true)
'a=[1,2]&b=true&n=1&o={"k":"v"}&s="foo"' 'a=[1,2]&b=true&n=1&o={"k":"v"}&s="foo"'
@*/ @*/
export function serialize(object, isJSON) { Ox.serialize = function(object, isJSON) {
var ret = []; var ret = [];
Ox.forEach(object, function(value, key) { Ox.forEach(object, function(value, key) {
var value; var value;
@ -204,7 +184,7 @@ Ox.unserialize <f> Parses query parameters into an object
{a: [1, 2], b: true, n: 1.2, o: {k: 'v'}, s1: 'foo', s2: 'bar'} {a: [1, 2], b: true, n: 1.2, o: {k: 'v'}, s1: 'foo', s2: 'bar'}
@*/ @*/
export function unserialize(string, isJSON) { Ox.unserialize = function(string, isJSON) {
var ret = {}; var ret = {};
Ox.filter(string.split('&')).forEach(function(value) { Ox.filter(string.split('&')).forEach(function(value) {
var array = value.split('='); var array = value.split('=');
@ -228,7 +208,7 @@ Ox.zipObject <f> Takes a keys and a values array, returns a new object
> Ox.zipObject(['a', 'b'], [1, 2]) > Ox.zipObject(['a', 'b'], [1, 2])
{a: 1, b: 2} {a: 1, b: 2}
@*/ @*/
export function zipObject(keys, values) { Ox.zipObject = function(keys, values) {
var object = {}; var object = {};
keys = Ox.makeArray(keys); keys = Ox.makeArray(keys);
values = Ox.makeArray(values); values = Ox.makeArray(values);

View file

@ -1,6 +1,6 @@
'use strict'; 'use strict';
export function loadPolyfill(window, Ox) { (function(window) {
var canDefineProperty = !!Object.defineProperty && (function() { var canDefineProperty = !!Object.defineProperty && (function() {
try { try {
@ -426,4 +426,5 @@ export function loadPolyfill(window, Ox) {
); );
} }
} }
}
}(this));

View file

@ -1,5 +1,3 @@
'use strict';
/*@ /*@
Ox.escapeRegExp <f> Escapes a string for use in a regular expression Ox.escapeRegExp <f> Escapes a string for use in a regular expression
(str) -> <r> Escaped string (str) -> <r> Escaped string
@ -10,6 +8,6 @@ Ox.escapeRegExp <f> Escapes a string for use in a regular expression
true true
@*/ @*/
// see https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions // see https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions
export function escapeRegExp(string) { Ox.escapeRegExp = function(string) {
return (string + '').replace(/([\/\\^$*+?.\-|(){}[\]])/g, '\\$1'); return (string + '').replace(/([\/\\^$*+?.\-|(){}[\]])/g, '\\$1');
}; };

View file

@ -1,25 +1,5 @@
'use strict'; 'use strict';
import * as OxArray from './Array.js';
import * as OxObject from './Object.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
import * as OxString from './String.js';
import * as OxType from './Type.js';
import * as OxCollection from './Collection.js';
const Ox = {};
Object.assign(Ox,
OxArray,
OxObject,
OxConstants,
OxMath,
OxString,
OxType,
OxCollection,
);
/*@ /*@
Ox.get <f> Get a remote resource Ox.get <f> Get a remote resource
(url, callback) -> <u> undefined (url, callback) -> <u> undefined
@ -30,7 +10,7 @@ Ox.get <f> Get a remote resource
code <n> Status code code <n> Status code
text <s> Status text text <s> Status text
@*/ @*/
export function get(url, callback) { Ox.get = function(url, callback) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('GET', url, true); request.open('GET', url, true);
request.onreadystatechange = function() { request.onreadystatechange = function() {
@ -69,7 +49,7 @@ Ox.getAsync <f> Runs an asynchonous loader for an array of URLs
code <n> Error code (like `404`) code <n> Error code (like `404`)
text <s> Error text (like `'Not Found'`) text <s> Error text (like `'Not Found'`)
@*/ @*/
export function getAsync(urls, get, callback) { Ox.getAsync = function(urls, get, callback) {
urls = Ox.makeArray(urls); urls = Ox.makeArray(urls);
var errors = {}, i = 0, n = urls.length, results = {}; var errors = {}, i = 0, n = urls.length, results = {};
function done() { function done() {
@ -96,7 +76,7 @@ export function getAsync(urls, get, callback) {
} }
function getSerial() { function getSerial() {
var url = urls.shift(); var url = urls.shift();
getAsync(url, get, function(result, error) { Ox.getAsync(url, get, function(result, error) {
extend(results, result, url); extend(results, result, url);
extend(errors, error, url); extend(errors, error, url);
urls.length ? getSerial() : done(); urls.length ? getSerial() : done();
@ -105,139 +85,142 @@ export function getAsync(urls, get, callback) {
urls.some(Ox.isArray) ? getSerial() : getParallel(); urls.some(Ox.isArray) ? getSerial() : getParallel();
}; };
(function() {
var cache = {}, var cache = {},
head = document.head head = document.head
|| document.getElementsByTagName('head')[0] || document.getElementsByTagName('head')[0]
|| document.documentElement; || document.documentElement;
function _getFile(type, url, callback) { function getFile(type, url, callback) {
var element, tagValue, typeValue, urlKey; var element, tagValue, typeValue, urlKey;
if (!cache[url]) { if (!cache[url]) {
if (!type) { if (!type) {
type = Ox.parseURL(url).pathname.split('.').pop(); type = Ox.parseURL(url).pathname.split('.').pop();
type = type == 'css' ? 'stylesheet' type = type == 'css' ? 'stylesheet'
: type == 'js' ? 'script' : 'image'; : type == 'js' ? 'script' : 'image';
} }
if (type == 'image') { if (type == 'image') {
element = new Image(); element = new Image();
element.onerror = onError;
element.onload = onLoad;
element.src = url;
} else {
tagValue = type == 'script' ? 'script' : 'link';
typeValue = type == 'script' ? 'text/javascript' : 'text/css';
urlKey = type == 'script' ? 'src' : 'href';
if (Ox.some(
document.getElementsByTagName(tagValue),
function(element) {
return element[urlKey] == url;
}
)) {
onLoad();
} else {
element = document.createElement(tagValue);
element.onerror = onError; element.onerror = onError;
element.onload = element.onreadystatechange = onLoad; element.onload = onLoad;
element.type = typeValue; element.src = url;
element[urlKey] = url; } else {
if (type == 'stylesheet') { tagValue = type == 'script' ? 'script' : 'link';
element.rel = 'stylesheet'; typeValue = type == 'script' ? 'text/javascript' : 'text/css';
urlKey = type == 'script' ? 'src' : 'href';
if (Ox.some(
document.getElementsByTagName(tagValue),
function(element) {
return element[urlKey] == url;
}
)) {
onLoad();
} else {
element = document.createElement(tagValue);
element.onerror = onError;
element.onload = element.onreadystatechange = onLoad;
element.type = typeValue;
element[urlKey] = url;
if (type == 'stylesheet') {
element.rel = 'stylesheet';
}
head.appendChild(element);
}
if (type == 'stylesheet') {
//fixme only call if browser does not support onload
// Safari 5 does not fire onload
waitForCSS();
} }
head.appendChild(element);
} }
if (type == 'stylesheet') { } else {
//fixme only call if browser does not support onload
// Safari 5 does not fire onload
waitForCSS();
}
}
} else {
callback(cache[url], null);
}
function onError() {
callback(null, {code: 404, text: 'Not Found'});
}
function onLoad() {
if (
!this || !this.readyState
|| this.readyState == 'loaded' || this.readyState == 'complete'
) {
// for an image, keep a reference to the element
// to keep the image in the browser cache
cache[url] = type == 'image' ? this : true;
callback(cache[url], null); callback(cache[url], null);
} }
} function onError() {
function waitForCSS() { callback(null, {code: 404, text: 'Not Found'});
var error = false; }
try { function onLoad() {
element.sheet.cssRule; if (
} catch (e) { !this || !this.readyState
error = true; || this.readyState == 'loaded' || this.readyState == 'complete'
setTimeout(function() { ) {
waitForCSS(); // for an image, keep a reference to the element
}, 25); // to keep the image in the browser cache
cache[url] = type == 'image' ? this : true;
callback(cache[url], null);
}
}
function waitForCSS() {
var error = false;
try {
element.sheet.cssRule;
} catch (e) {
error = true;
setTimeout(function() {
waitForCSS();
}, 25);
}
!error && onLoad();
} }
!error && onLoad();
} }
}
function getFiles(type, urls, callback) { function getFiles(type, urls, callback) {
getAsync(urls, function(url, callback) { Ox.getAsync(urls, function(url, callback) {
_getFile(type, url, callback); getFile(type, url, callback);
}, callback); }, callback);
} }
/*@ /*@
Ox.getFile <f> Loads a file (image, script or stylesheet) Ox.getFile <f> Loads a file (image, script or stylesheet)
(file, callback) -> <u> undefined (file, callback) -> <u> undefined
file <s|[s]> Local path or remote URL, or array of those, or array of such arrays file <s|[s]> Local path or remote URL, or array of those, or array of such arrays
Multiple files in the same array will be processed simultaneously, Multiple files in the same array will be processed simultaneously,
but multiple arrays of files will be processed in that order. but multiple arrays of files will be processed in that order.
callback <f> Callback function callback <f> Callback function
image <h> DOM element (if the file is an image) image <h> DOM element (if the file is an image)
@*/ @*/
export function getFile(url, callback) { Ox.getFile = function(url, callback) {
getFiles(null, url, callback); getFiles(null, url, callback);
}; };
/*@ /*@
Ox.getImage <f> Loads an image Ox.getImage <f> Loads an image
(file, callback) -> <u> undefined (file, callback) -> <u> undefined
file <s|[s]> Local path or remote URL, or array of those, or array of such arrays file <s|[s]> Local path or remote URL, or array of those, or array of such arrays
Multiple files in the same array will be processed simultaneously, Multiple files in the same array will be processed simultaneously,
but multiple arrays of files will be processed in that order. but multiple arrays of files will be processed in that order.
callback <f> Callback function callback <f> Callback function
image <h> DOM element image <h> DOM element
@*/ @*/
export function getImage(url, callback) { Ox.getImage = function(url, callback) {
getFiles('image', url, callback); getFiles('image', url, callback);
}; };
/*@ /*@
Ox.getScript <f> Loads a script Ox.getScript <f> Loads a script
(file, callback) -> <u> undefined (file, callback) -> <u> undefined
file <s|[s]> Local path or remote URL, or array of those, or array of such arrays file <s|[s]> Local path or remote URL, or array of those, or array of such arrays
Multiple files in the same array will be processed simultaneously, Multiple files in the same array will be processed simultaneously,
but multiple arrays of files will be processed in that order. but multiple arrays of files will be processed in that order.
callback <f> Callback function callback <f> Callback function
@*/ @*/
export function getScript(url, callback) { Ox.getScript = function(url, callback) {
getFiles('script', url, callback); getFiles('script', url, callback);
}; };
/*@ /*@
Ox.getStylesheet <f> Loads a stylesheet Ox.getStylesheet <f> Loads a stylesheet
(file, callback) -> <u> undefined (file, callback) -> <u> undefined
file <s|[s]> Local path or remote URL, or array of those, or array of such arrays file <s|[s]> Local path or remote URL, or array of those, or array of such arrays
Multiple files in the same array will be processed simultaneously, Multiple files in the same array will be processed simultaneously,
but multiple arrays of files will be processed in that order. but multiple arrays of files will be processed in that order.
callback <f> Callback function callback <f> Callback function
@*/ @*/
export function getStylesheet(url, callback) { Ox.getStylesheet = function(url, callback) {
getFiles('stylesheet', url, callback); getFiles('stylesheet', url, callback);
}; };
}());
/*@ /*@
Ox.getJSON <f> Get and parse one or more remote JSON files Ox.getJSON <f> Get and parse one or more remote JSON files
@ -251,10 +234,10 @@ Ox.getJSON <f> Get and parse one or more remote JSON files
code <n> Error code (like `404`) code <n> Error code (like `404`)
text <s> Error text (like `'Not Found'`) text <s> Error text (like `'Not Found'`)
@*/ @*/
export function getJSON(url, callback, isJSONC) { Ox.getJSON = function(url, callback, isJSONC) {
var urls = Ox.makeArray(url); var urls = Ox.makeArray(url);
getAsync(urls, function(url, callback) { Ox.getAsync(urls, function(url, callback) {
get(url, function(data, error) { Ox.get(url, function(data, error) {
callback(JSON.parse( callback(JSON.parse(
isJSONC ? Ox.minify(data || '') : data isJSONC ? Ox.minify(data || '') : data
), error); ), error);
@ -275,7 +258,7 @@ Ox.getJSONC <f> Get and parse a remote JSONC file
code <n> Error code (like `404`) code <n> Error code (like `404`)
text <s> Error text (like `'Not Found'`) text <s> Error text (like `'Not Found'`)
@*/ @*/
export function getJSONC(url, callback) { Ox.getJSONC = function(url, callback) {
Ox.getJSON(url, callback, true); Ox.getJSON(url, callback, true);
}; };
@ -292,9 +275,9 @@ Ox.getJSONP <f> Get and parse one or more remote JSONP files
code <n> Error code (like `404`) code <n> Error code (like `404`)
text <s> Error text (like `'Not Found'`) text <s> Error text (like `'Not Found'`)
@*/ @*/
export function getJSONP(url, callback) { Ox.getJSONP = function(url, callback) {
var urls = Ox.makeArray(url); var urls = Ox.makeArray(url);
getAsync(urls, function(url, callback) { Ox.getAsync(urls, function(url, callback) {
var id = 'callback' + Ox.uid(); var id = 'callback' + Ox.uid();
Ox.getJSONP[id] = function(data) { Ox.getJSONP[id] = function(data) {
delete Ox.getJSONP[id]; delete Ox.getJSONP[id];
@ -318,7 +301,7 @@ Ox.post <f> post to a remote resource
code <n> Status code code <n> Status code
text <s> Status text text <s> Status text
@*/ @*/
export function post(url, data, callback) { Ox.post = function(url, data, callback) {
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('post', url, true); request.open('post', url, true);
request.onreadystatechange = function() { request.onreadystatechange = function() {

View file

@ -1,21 +1,9 @@
'use strict'; 'use strict';
import * as OxCore from './Core.js';
import * as OxBase from './Base.js';
import * as OxCollection from './Collection.js';
const Ox = {};
Object.assign(Ox,
OxCore,
OxBase,
OxCollection,
);
/*@ /*@
Ox.char <f> Alias for String.fromCharCode Ox.char <f> Alias for String.fromCharCode
@*/ @*/
export const char = String.fromCharCode; Ox.char = String.fromCharCode;
/*@ /*@
Ox.clean <f> Remove leading, trailing and double whitespace from a string Ox.clean <f> Remove leading, trailing and double whitespace from a string
@ -30,7 +18,7 @@ Ox.clean <f> Remove leading, trailing and double whitespace from a string
> Ox.clean(' foo\tbar ') > Ox.clean(' foo\tbar ')
'foo bar' 'foo bar'
@*/ @*/
export function clean(string) { Ox.clean = function(string) {
return Ox.filter(Ox.map(string.split('\n'), function(string) { return Ox.filter(Ox.map(string.split('\n'), function(string) {
return string.replace(/\s+/g, ' ').trim() || ''; return string.replace(/\s+/g, ' ').trim() || '';
})).join('\n'); })).join('\n');
@ -42,7 +30,7 @@ Ox.codePointAt <f> Returns the code point at a given index
> Ox.codePointAt('\uD83D\uDCA9', 0) > Ox.codePointAt('\uD83D\uDCA9', 0)
0x1F4A9 0x1F4A9
@*/ @*/
export function codePointAt(string, index) { Ox.codePointAt = function(string, index) {
var first, length = string.length, ret, second; var first, length = string.length, ret, second;
if (index >= 0 && index < length) { if (index >= 0 && index < length) {
first = string.charCodeAt(index); first = string.charCodeAt(index);
@ -67,7 +55,7 @@ Ox.endsWith <f> Tests if a string ends with a given substring
> Ox.endsWith('foobar', 'foo') > Ox.endsWith('foobar', 'foo')
false false
@*/ @*/
export function endsWith(string, substring) { Ox.endsWith = function(string, substring) {
string = string.toString(); string = string.toString();
substring = substring.toString(); substring = substring.toString();
return string.slice(string.length - substring.length) == substring; return string.slice(string.length - substring.length) == substring;
@ -81,7 +69,7 @@ Ox.fromCodePoint <f> Returns a string for one or more given code points
> Ox.fromCodePoint(0x1F4A9) > Ox.fromCodePoint(0x1F4A9)
'\uD83D\uDCA9' '\uD83D\uDCA9'
@*/ @*/
export function fromCodePoint() { Ox.fromCodePoint = function() {
var ret = ''; var ret = '';
Ox.forEach(arguments, function(number) { Ox.forEach(arguments, function(number) {
if (number < 0 || number > 0x10FFFF || !Ox.isInt(number)) { if (number < 0 || number > 0x10FFFF || !Ox.isInt(number)) {
@ -111,7 +99,7 @@ Ox.isValidEmail <f> Tests if a string is a valid e-mail address
> Ox.isValidEmail('foo@bar..com') > Ox.isValidEmail('foo@bar..com')
false false
@*/ @*/
export function isValidEmail(string) { Ox.isValidEmail = function(string) {
return !!/^[0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,64}$/i.test(string); return !!/^[0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,64}$/i.test(string);
}; };
@ -152,7 +140,7 @@ Ox.pad <f> Pad a string to a given length
> Ox.pad('foo', -1) > Ox.pad('foo', -1)
'' ''
@*/ @*/
export function pad(string, position, length, padding) { Ox.pad = function(string, position, length, padding) {
var hasPosition = Ox.isString(arguments[1]), var hasPosition = Ox.isString(arguments[1]),
isNumber = Ox.isNumber(arguments[0]), isNumber = Ox.isNumber(arguments[0]),
last = Ox.last(arguments); last = Ox.last(arguments);
@ -178,7 +166,7 @@ Ox.parseDuration <f> Takes a formatted duration, returns seconds
> Ox.parseDuration('1::') > Ox.parseDuration('1::')
3600 3600
@*/ @*/
export function parseDuration(string) { Ox.parseDuration = function(string) {
return string.split(':').reverse().slice(0, 4).reduce(function(p, c, i) { return string.split(':').reverse().slice(0, 4).reduce(function(p, c, i) {
return p + (parseFloat(c) || 0) * (i == 3 ? 86400 : Math.pow(60, i)); return p + (parseFloat(c) || 0) * (i == 3 ? 86400 : Math.pow(60, i));
}, 0); }, 0);
@ -199,7 +187,7 @@ Ox.parsePath <f> Returns the components of a path
> Ox.parsePath('.foo') > Ox.parsePath('.foo')
{extension: '', filename: '.foo', pathname: ''} {extension: '', filename: '.foo', pathname: ''}
@*/ @*/
export function parsePath(string) { Ox.parsePath = function(string) {
var matches = /^(.+\/)?(.+?(\..+)?)?$/.exec(string); var matches = /^(.+\/)?(.+?(\..+)?)?$/.exec(string);
return { return {
pathname: matches[1] || '', pathname: matches[1] || '',
@ -218,7 +206,7 @@ Ox.parseSRT <f> Parses an srt subtitle file
> Ox.parseSRT('1\n01:02:00,000 --> 01:02:03,400\nHello World') > Ox.parseSRT('1\n01:02:00,000 --> 01:02:03,400\nHello World')
[{'in': 3720, out: 3723.4, text: 'Hello World'}] [{'in': 3720, out: 3723.4, text: 'Hello World'}]
@*/ @*/
export function parseSRT(string, fps) { Ox.parseSRT = function(string, fps) {
return string.replace(/\r\n/g, '\n').trim().split('\n\n') return string.replace(/\r\n/g, '\n').trim().split('\n\n')
.map(function(block) { .map(function(block) {
var lines = block.split('\n'), points; var lines = block.split('\n'), points;
@ -276,35 +264,22 @@ Ox.parseURL <f> Takes a URL, returns its components
> Ox.parseURL('http://www.foo.com:8080/bar/index.html?a=0&b=1#c').search > Ox.parseURL('http://www.foo.com:8080/bar/index.html?a=0&b=1#c').search
'?a=0&b=1' '?a=0&b=1'
@*/ @*/
export const parseURL = (function() { Ox.parseURL = (function() {
const keys = [ var a = document.createElement('a'),
'hash', 'host', 'hostname', 'origin', keys = ['hash', 'host', 'hostname', 'origin',
'pathname', 'port', 'protocol', 'search' 'pathname', 'port', 'protocol', 'search'];
]; return function(string) {
if (typeof document == 'undefined') { var ret = {};
return function(string) { a.href = string;
const a = new URL(string); keys.forEach(function(key) {
var ret = {}; ret[key] = a[key];
keys.forEach(function(key) { });
ret[key] = a[key]; return ret;
}); };
return ret;
}
} else {
var a = document.createElement('a');
return function(string) {
var ret = {};
a.href = string;
keys.forEach(function(key) {
ret[key] = a[key];
});
return ret;
};
}
}()); }());
// FIXME: can we get rid of this? // FIXME: can we get rid of this?
export function parseUserAgent(userAgent) { Ox.parseUserAgent = function(userAgent) {
var aliases = { var aliases = {
browser: { browser: {
'Firefox': /(Fennec|Firebird|Iceweasel|Minefield|Namoroka|Phoenix|SeaMonkey|Shiretoko)/ 'Firefox': /(Fennec|Firebird|Iceweasel|Minefield|Namoroka|Phoenix|SeaMonkey|Shiretoko)/
@ -465,7 +440,7 @@ Ox.repeat <f> Repeat a value multiple times
@*/ @*/
// FIXME: see https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js // FIXME: see https://github.com/paulmillr/es6-shim/blob/master/es6-shim.js
// for a faster version // for a faster version
export function repeat(value, times) { Ox.repeat = function(value, times) {
var ret; var ret;
if (Ox.isArray(value)) { if (Ox.isArray(value)) {
ret = []; ret = [];
@ -483,7 +458,7 @@ Ox.splice <f> `[].splice` for strings, returns a new string
> Ox.splice('12xxxxx89', 2, 5, 3, 4, 5, 6, 7) > Ox.splice('12xxxxx89', 2, 5, 3, 4, 5, 6, 7)
'123456789' '123456789'
@*/ @*/
export function splice(string, index, remove) { Ox.splice = function(string, index, remove) {
var array = string.split(''); var array = string.split('');
Array.prototype.splice.apply(array, Ox.slice(arguments, 1)); Array.prototype.splice.apply(array, Ox.slice(arguments, 1));
return array.join(''); return array.join('');
@ -499,7 +474,7 @@ Ox.startsWith <f> Tests if a string ends with a given substring
> Ox.startsWith('foobar', 'bar') > Ox.startsWith('foobar', 'bar')
false false
@*/ @*/
export function startsWith(string, substring) { Ox.startsWith = function(string, substring) {
string = string.toString(); string = string.toString();
substring = substring.toString(); substring = substring.toString();
return string.slice(0, substring.length) == substring; return string.slice(0, substring.length) == substring;
@ -514,7 +489,7 @@ Ox.toCamelCase <f> Takes a string with '-', '/' or '_', returns a camelCase stri
> Ox.toCamelCase('foo_bar_baz') > Ox.toCamelCase('foo_bar_baz')
'fooBarBaz' 'fooBarBaz'
@*/ @*/
export function toCamelCase(string) { Ox.toCamelCase = function(string) {
return string.replace(/[\-\/_][a-z]/g, function(string) { return string.replace(/[\-\/_][a-z]/g, function(string) {
return string[1].toUpperCase(); return string[1].toUpperCase();
}); });
@ -525,7 +500,7 @@ Ox.toDashes <f> Takes a camelCase string, returns a string with dashes
> Ox.toDashes('fooBarBaz') > Ox.toDashes('fooBarBaz')
'foo-bar-baz' 'foo-bar-baz'
@*/ @*/
export function toDashes(string) { Ox.toDashes = function(string) {
return string.replace(/[A-Z]/g, function(string) { return string.replace(/[A-Z]/g, function(string) {
return '-' + string.toLowerCase(); return '-' + string.toLowerCase();
}); });
@ -536,7 +511,7 @@ Ox.toSlashes <f> Takes a camelCase string, returns a string with slashes
> Ox.toSlashes('fooBarBaz') > Ox.toSlashes('fooBarBaz')
'foo/bar/baz' 'foo/bar/baz'
@*/ @*/
export function toSlashes(string) { Ox.toSlashes = function(string) {
return string.replace(/[A-Z]/g, function(string) { return string.replace(/[A-Z]/g, function(string) {
return '/' + string.toLowerCase(); return '/' + string.toLowerCase();
}); });
@ -549,7 +524,7 @@ Ox.toTitleCase <f> Returns a string with capitalized words
> Ox.toTitleCase('Apple releases iPhone, IBM stock plummets') > Ox.toTitleCase('Apple releases iPhone, IBM stock plummets')
'Apple Releases iPhone, IBM Stock Plummets' 'Apple Releases iPhone, IBM Stock Plummets'
@*/ @*/
export function toTitleCase(string) { Ox.toTitleCase = function(string) {
return string.split(' ').map(function(value) { return string.split(' ').map(function(value) {
var substring = value.slice(1), var substring = value.slice(1),
lowercase = substring.toLowerCase(); lowercase = substring.toLowerCase();
@ -565,7 +540,7 @@ Ox.toUnderscores <f> Takes a camelCase string, returns string with underscores
> Ox.toUnderscores('fooBarBaz') > Ox.toUnderscores('fooBarBaz')
'foo_bar_baz' 'foo_bar_baz'
@*/ @*/
export function toUnderscores(string) { Ox.toUnderscores = function(string) {
return string.replace(/[A-Z]/g, function(string) { return string.replace(/[A-Z]/g, function(string) {
return '_' + string.toLowerCase(); return '_' + string.toLowerCase();
}); });
@ -587,7 +562,7 @@ Ox.truncate <f> Truncate a string to a given length
> Ox.truncate('anticonstitutionellement', 'center', 16, '...') > Ox.truncate('anticonstitutionellement', 'center', 16, '...')
'anticon...lement' 'anticon...lement'
@*/ @*/
export function truncate(string, position, length, padding) { Ox.truncate = function(string, position, length, padding) {
var hasPosition = Ox.isString(arguments[1]), last = Ox.last(arguments); var hasPosition = Ox.isString(arguments[1]), last = Ox.last(arguments);
position = hasPosition ? arguments[1] : 'right'; position = hasPosition ? arguments[1] : 'right';
length = hasPosition ? arguments[2] : arguments[1]; length = hasPosition ? arguments[2] : arguments[1];
@ -614,7 +589,7 @@ Ox.words <f> Splits a string into words, removing punctuation
> Ox.words('Let\'s "split" array-likes into key/value pairs--okay?') > Ox.words('Let\'s "split" array-likes into key/value pairs--okay?')
['let\'s', 'split', 'array-likes', 'into', 'key', 'value', 'pairs', 'okay'] ['let\'s', 'split', 'array-likes', 'into', 'key', 'value', 'pairs', 'okay']
@*/ @*/
export function words(string) { Ox.words = function(string) {
var array = string.toLowerCase().split(/\b/), var array = string.toLowerCase().split(/\b/),
length = array.length, length = array.length,
startsWithWord = /\w/.test(array[0]); startsWithWord = /\w/.test(array[0]);
@ -660,7 +635,7 @@ Ox.wordwrap <f> Wrap a string at word boundaries
> Ox.wordwrap('These are short words', 16, true) > Ox.wordwrap('These are short words', 16, true)
'These are \nshort words' 'These are \nshort words'
@*/ @*/
export function wordwrap(string, length) { Ox.wordwrap = function(string, length) {
var balanced, lines, max, newline, words; var balanced, lines, max, newline, words;
string = String(string); string = String(string);
length = length || 80; length = length || 80;

View file

@ -1,27 +1,13 @@
'use strict'; 'use strict';
import * as OxObject from './Object.js';
import * as OxFunction from './Function.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
const Ox = {};
Object.assign(Ox,
OxObject,
OxFunction,
OxConstants,
OxMath
);
/*@ /*@
Ox.checkType <f> Throws a TypeError if a value is not of a given type Ox.checkType <f> Throws a TypeError if a value is not of a given type
(val, type) -> <u> undefined (val, type) -> <u> undefined
val <*> Any value val <*> Any value
type <s|[s]> Type, or array of types type <s|[s]> Type, or array of types
@*/ @*/
export function checkType(value, type) { Ox.checkType = function(value, type) {
if (!Ox.contains(Ox.makeArray(type), typeOf(value))) { if (!Ox.contains(Ox.makeArray(type), Ox.typeOf(value))) {
throw new TypeError(); throw new TypeError();
} }
}; };
@ -33,8 +19,8 @@ Ox.isArguments <f> Tests if a value is an arguments "array"
> Ox.isArguments((function() { return arguments; }())) > Ox.isArguments((function() { return arguments; }()))
true true
@*/ @*/
export function isArguments(value) { Ox.isArguments = function(value) {
return typeOf(value) == 'arguments'; return Ox.typeOf(value) == 'arguments';
}; };
/*@ /*@
@ -50,8 +36,8 @@ Ox.isArray <f> Tests if a value is an array
> Ox.isArray({0: 0, length: 1}) > Ox.isArray({0: 0, length: 1})
false false
@*/ @*/
export function isArray(value) { Ox.isArray = function(value) {
return typeOf(value) == 'array'; return Ox.typeOf(value) == 'array';
}; };
/*@ /*@
@ -61,8 +47,8 @@ Ox.isBoolean <f> Tests if a value is boolean
> Ox.isBoolean(false) > Ox.isBoolean(false)
true true
@*/ @*/
export function isBoolean(value) { Ox.isBoolean = function(value) {
return typeOf(value) == 'boolean'; return Ox.typeOf(value) == 'boolean';
}; };
/*@ /*@
@ -72,8 +58,8 @@ Ox.isDate <f> Tests if a value is a date
> Ox.isDate(new Date()) > Ox.isDate(new Date())
true true
@*/ @*/
export function isDate(value) { Ox.isDate = function(value) {
return typeOf(value) == 'date'; return Ox.typeOf(value) == 'date';
}; };
/*@ /*@
@ -83,7 +69,7 @@ Ox.isElement <f> Tests if a value is a DOM element
> Ox.isElement(document.createElement('a')) > Ox.isElement(document.createElement('a'))
true true
@*/ @*/
export function isElement(value) { Ox.isElement = function(value) {
return Ox.endsWith(Ox.typeOf(value), 'element'); return Ox.endsWith(Ox.typeOf(value), 'element');
}; };
@ -97,8 +83,8 @@ Ox.isEmpty <f> Tests if a value is an empty array, object or string
true true
> Ox.isEmpty('') > Ox.isEmpty('')
true true
> Ox.isEmpty(document.getElementsByTagName('')) > Ox.isEmpty(document.getElementsByTagName(''))
true true
> Ox.isEmpty(function() {}) > Ox.isEmpty(function() {})
false false
> Ox.isEmpty(false) > Ox.isEmpty(false)
@ -110,7 +96,7 @@ Ox.isEmpty <f> Tests if a value is an empty array, object or string
> Ox.isEmpty() > Ox.isEmpty()
false false
@*/ @*/
export function isEmpty(value) { Ox.isEmpty = function(value) {
return Ox.len(value) === 0; return Ox.len(value) === 0;
}; };
@ -171,12 +157,12 @@ Ox.isEqual <function> Tests if two values are equal
> Ox.isEqual(void 0, void 0) > Ox.isEqual(void 0, void 0)
true true
@*/ @*/
export function isEqual(a, b) { Ox.isEqual = function(a, b) {
var ret = false, type = typeOf(a); var ret = false, type = Ox.typeOf(a);
if (a === b) { if (a === b) {
// 0 === -0, but not equal // 0 === -0, but not equal
ret = a !== 0 || 1 / a === 1 / b; ret = a !== 0 || 1 / a === 1 / b;
} else if (type == typeOf(b)) { } else if (type == Ox.typeOf(b)) {
// NaN !== NaN, but equal // NaN !== NaN, but equal
if (a == b || a !== a) { if (a == b || a !== a) {
ret = true; ret = true;
@ -207,8 +193,8 @@ Ox.isError <f> Tests if a value is an error
> Ox.isError(new Error()) > Ox.isError(new Error())
true true
@*/ @*/
export function isError(value) { Ox.isError = function(value) {
return typeOf(value) == 'error'; return Ox.typeOf(value) == 'error';
}; };
/*@ /*@
@ -220,8 +206,8 @@ Ox.isFunction <f> Tests if a value is a function
> Ox.isFunction(new RegExp()) > Ox.isFunction(new RegExp())
false false
@*/ @*/
export function isFunction(value) { Ox.isFunction = function(value) {
return typeOf(value) == 'function'; return Ox.typeOf(value) == 'function';
}; };
/*@ /*@
@ -235,8 +221,8 @@ Ox.isInfinity <f> Tests if a value is positive or negative Infinity
> Ox.isInfinity(NaN) > Ox.isInfinity(NaN)
false false
@*/ @*/
export function isInfinity(value) { Ox.isInfinity = function(value) {
return typeOf(value) == 'number' && !isFinite(value) && !Ox.isNaN(value); return Ox.typeOf(value) == 'number' && !isFinite(value) && !Ox.isNaN(value);
}; };
/*@ /*@
@ -250,7 +236,7 @@ Ox.isInt <f> Tests if a value is an integer
> Ox.isInt(Infinity) > Ox.isInt(Infinity)
false false
@*/ @*/
export function isInt(value) { Ox.isInt = function(value) {
return isFinite(value) && value === Math.floor(value); return isFinite(value) && value === Math.floor(value);
}; };
@ -261,7 +247,7 @@ Ox.isInvalidDate <f> Tests if a value is an invalid date
> Ox.isInvalidDate(new Date('foo')) > Ox.isInvalidDate(new Date('foo'))
true true
@*/ @*/
export function isInvalidDate(value) { Ox.isInvalidDate = function(value) {
return Ox.isDate(value) && Ox.isNaN(value.getTime()); return Ox.isDate(value) && Ox.isNaN(value.getTime());
}; };
@ -272,7 +258,7 @@ Ox.isNaN <f> Tests if a value is `NaN`
> Ox.isNaN(NaN) > Ox.isNaN(NaN)
true true
@*/ @*/
export function isNaN(value) { Ox.isNaN = function(value) {
return value !== value; return value !== value;
}; };
@ -282,8 +268,8 @@ Ox.isNodeList <f> Tests if a value is a nodelist
> Ox.isNodeList(document.getElementsByTagName('a')) > Ox.isNodeList(document.getElementsByTagName('a'))
true true
@*/ @*/
export function isNodeList(value) { Ox.isNodeList = function(value) {
return typeOf(value) == 'nodelist'; return Ox.typeOf(value) == 'nodelist';
}; };
/*@ /*@
@ -293,8 +279,8 @@ Ox.isNull <f> Tests if a value is `null`
> Ox.isNull(null) > Ox.isNull(null)
true true
@*/ @*/
export function isNull(value) { Ox.isNull = function(value) {
return typeOf(value) == 'null'; return Ox.typeOf(value) == 'null';
}; };
/*@ /*@
@ -310,8 +296,8 @@ Ox.isNumber <f> Tests if a value is a number
> Ox.isNumber(NaN) > Ox.isNumber(NaN)
true true
@*/ @*/
export function isNumber(value) { Ox.isNumber = function(value) {
return typeOf(value) == 'number'; return Ox.typeOf(value) == 'number';
}; };
/*@ /*@
@ -329,8 +315,8 @@ Ox.isObject <f> Tests if a value is a an object
> Ox.isObject(/ /) > Ox.isObject(/ /)
false false
@*/ @*/
export function isObject(value) { Ox.isObject = function(value) {
return typeOf(value) == 'object'; return Ox.typeOf(value) == 'object';
}; };
/*@ /*@
@ -352,9 +338,9 @@ Ox.isPrimitive <f> Tests if a value is a primitive
> Ox.isPrimitive({}) > Ox.isPrimitive({})
false false
@*/ @*/
export function isPrimitive(value) { Ox.isPrimitive = function(value) {
return Ox.contains( return Ox.contains(
['boolean', 'null', 'number', 'string', 'undefined'], typeOf(value) ['boolean', 'null', 'number', 'string', 'undefined'], Ox.typeOf(value)
); );
}; };
@ -365,8 +351,8 @@ Ox.isRegExp <f> Tests if a value is a regular expression
> Ox.isRegExp(new RegExp()) > Ox.isRegExp(new RegExp())
true true
@*/ @*/
export function isRegExp(value) { Ox.isRegExp = function(value) {
return typeOf(value) == 'regexp'; return Ox.typeOf(value) == 'regexp';
}; };
/*@ /*@
@ -376,8 +362,8 @@ Ox.isString <f> Tests if a value is a string
> Ox.isString('') > Ox.isString('')
true true
@*/ @*/
export function isString(value) { Ox.isString = function(value) {
return typeOf(value) == 'string'; return Ox.typeOf(value) == 'string';
}; };
/*@ /*@
@ -387,8 +373,8 @@ Ox.isUndefined <f> Tests if a value is undefined
> Ox.isUndefined() > Ox.isUndefined()
true true
@*/ @*/
export function isUndefined(value) { Ox.isUndefined = function(value) {
return typeOf(value) == 'undefined'; return Ox.typeOf(value) == 'undefined';
}; };
/*@ /*@
@ -398,7 +384,7 @@ Ox.isValidDate <f> Tests if a value is a valid date
> Ox.isValidDate(new Date()) > Ox.isValidDate(new Date())
true true
@*/ @*/
export function isValidDate(value) { Ox.isValidDate = function(value) {
return Ox.isDate(value) && !Ox.isNaN(value.getTime()); return Ox.isDate(value) && !Ox.isNaN(value.getTime());
}; };
@ -447,7 +433,7 @@ Ox.typeOf <f> Returns the type of a value
> Ox.typeOf(JSON) > Ox.typeOf(JSON)
'json' 'json'
@*/ @*/
export function typeOf(value) { Ox.typeOf = function(value) {
return Object.prototype.toString.call(value).slice(8, -1).toLowerCase(); return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
}; };
// Firefox 3.6 returns 'Object' for arguments, // Firefox 3.6 returns 'Object' for arguments,
@ -456,13 +442,13 @@ export function typeOf(value) {
// Mobile Safari returns 'DOMWindow' for null and undefined // Mobile Safari returns 'DOMWindow' for null and undefined
// Firefox 30+ returns 'window' for window // Firefox 30+ returns 'window' for window
if ( if (
typeOf((function() { return arguments; }())) != 'arguments' Ox.typeOf((function() { return arguments; }())) != 'arguments'
|| (typeof document !== 'undefined' && typeOf(document.getElementsByTagName('a')) != 'nodelist') || Ox.typeOf(document.getElementsByTagName('a')) != 'nodelist'
|| typeof null != 'null' || Ox.typeOf(null) != 'null'
|| typeof window != 'global' || Ox.typeOf(window) != 'global'
|| typeOf() != 'undefined' || Ox.typeOf() != 'undefined'
) { ) {
typeOf = function(value) { Ox.typeOf = function(value) {
var type = Object.prototype.toString.call( var type = Object.prototype.toString.call(
value value
).slice(8, -1).toLowerCase(); ).slice(8, -1).toLowerCase();
@ -470,7 +456,7 @@ if (
type = 'null'; type = 'null';
} else if (value === void 0) { } else if (value === void 0) {
type = 'undefined'; type = 'undefined';
} else if (typeof window !== 'undefined' && value === window) { } else if (value === window) {
type = 'global'; type = 'global';
} else if (type == 'object' && typeof value.callee == 'function') { } else if (type == 'object' && typeof value.callee == 'function') {
type = 'arguments'; type = 'arguments';

View file

@ -1,35 +1,11 @@
'use strict'; 'use strict';
import * as OxCore from './Core.js';
import * as OxType from './Type.js';
import * as OxArray from './Array.js';
import * as OxObject from './Object.js';
import * as OxCollection from './Collection.js';
import * as OxFunction from './Function.js';
import * as OxConstants from './Constants.js';
import * as OxMath from './Math.js';
import * as OxString from './String.js';
const Ox = {};
Object.assign(Ox,
OxCore,
OxType,
OxArray,
OxObject,
OxFunction,
OxCollection,
OxConstants,
OxMath,
OxString,
);
/*@ /*@
Ox.getVideoFormat <f> Get supported video format Ox.getVideoFormat <f> Get supported video format
(formats) -> <a> List of supported formats (formats) -> <a> List of supported formats
format <s> First supported format form list format <s> First supported format form list
@*/ @*/
export function getVideoFormat(formats) { Ox.getVideoFormat = function(formats) {
var aliases = { var aliases = {
mp4: 'h264', mp4: 'h264',
m4v: 'h264', m4v: 'h264',

View file

@ -1,548 +0,0 @@
'use strict';
import * as AudioAudioElement from './js/Audio/AudioElement.js';
import * as AudioAudioPlayer from './js/Audio/AudioPlayer.js';
import * as BarBar from './js/Bar/Bar.js';
import * as BarProgressbar from './js/Bar/Progressbar.js';
import * as BarResizebar from './js/Bar/Resizebar.js';
import * as BarTabbar from './js/Bar/Tabbar.js';
import * as CalendarCalendarEditor from './js/Calendar/CalendarEditor.js';
import * as CalendarCalendar from './js/Calendar/Calendar.js';
import * as CodeDocPage from './js/Code/DocPage.js';
import * as CodeDocPanel from './js/Code/DocPanel.js';
import * as CodeExamplePage from './js/Code/ExamplePage.js';
import * as CodeExamplePanel from './js/Code/ExamplePanel.js';
import * as CodeSourceViewer from './js/Code/SourceViewer.js';
import * as CodeSyntaxHighlighter from './js/Code/SyntaxHighlighter.js';
import * as CoreAPI from './js/Core/API.js';
import * as CoreApp from './js/Core/App.js';
import * as CoreClipboard from './js/Core/Clipboard.js';
import * as CoreContainer from './js/Core/Container.js';
import * as CoreCookies from './js/Core/Cookies.js';
import * as CoreElement from './js/Core/Element.js';
import * as CoreEvent from './js/Core/Event.js';
import * as CoreFocus from './js/Core/Focus.js';
import * as CoreFullscreen from './js/Core/Fullscreen.js';
import * as CoreGarbageCollection from './js/Core/GarbageCollection.js';
import * as CoreHistory from './js/Core/History.js';
import * as CoreLoadingIcon from './js/Core/LoadingIcon.js';
import * as CoreLoadingScreen from './js/Core/LoadingScreen.js';
import * as CoreRequest from './js/Core/Request.js';
import * as CoreTheme from './js/Core/Theme.js';
import * as CoreUI from './js/Core/UI.js';
import * as CoreURL from './js/Core/URL.js';
import * as FormArrayEditable from './js/Form/ArrayEditable.js';
import * as FormArrayInput from './js/Form/ArrayInput.js';
import * as FormButtonGroup from './js/Form/ButtonGroup.js';
import * as FormButton from './js/Form/Button.js';
import * as FormCheckboxGroup from './js/Form/CheckboxGroup.js';
import * as FormCheckbox from './js/Form/Checkbox.js';
import * as FormColorInput from './js/Form/ColorInput.js';
import * as FormColorPicker from './js/Form/ColorPicker.js';
import * as FormDateInput from './js/Form/DateInput.js';
import * as FormDateTimeInput from './js/Form/DateTimeInput.js';
import * as FormEditableContent from './js/Form/EditableContent.js';
import * as FormEditable from './js/Form/Editable.js';
import * as FormFileButton from './js/Form/FileButton.js';
import * as FormFileInput from './js/Form/FileInput.js';
import * as FormFilter from './js/Form/Filter.js';
import * as FormFormElementGroup from './js/Form/FormElementGroup.js';
import * as FormFormItem from './js/Form/FormItem.js';
import * as FormForm from './js/Form/Form.js';
import * as FormFormPanel from './js/Form/FormPanel.js';
import * as FormInputGroup from './js/Form/InputGroup.js';
import * as FormInput from './js/Form/Input.js';
import * as FormInsertHTMLDialog from './js/Form/InsertHTMLDialog.js';
import * as FormLabel from './js/Form/Label.js';
import * as FormObjectArrayInput from './js/Form/ObjectArrayInput.js';
import * as FormObjectInput from './js/Form/ObjectInput.js';
import * as FormOptionGroup from './js/Form/OptionGroup.js';
import * as FormPicker from './js/Form/Picker.js';
import * as FormPlaceInput from './js/Form/PlaceInput.js';
import * as FormPlacePicker from './js/Form/PlacePicker.js';
import * as FormRange from './js/Form/Range.js';
import * as FormSelectInput from './js/Form/SelectInput.js';
import * as FormSelect from './js/Form/Select.js';
import * as FormSpreadsheet from './js/Form/Spreadsheet.js';
import * as FormTimeInput from './js/Form/TimeInput.js';
import * as ImageImageElement from './js/Image/ImageElement.js';
import * as ImageImageViewer from './js/Image/ImageViewer.js';
import * as ListChart from './js/List/Chart.js';
import * as ListColumnList from './js/List/ColumnList.js';
import * as ListCustomList from './js/List/CustomList.js';
import * as ListIconItem from './js/List/IconItem.js';
import * as ListIconList from './js/List/IconList.js';
import * as ListInfoList from './js/List/InfoList.js';
import * as ListListItem from './js/List/ListItem.js';
import * as ListList from './js/List/List.js';
import * as ListSortList from './js/List/SortList.js';
import * as ListTableList from './js/List/TableList.js';
import * as ListTreeList from './js/List/TreeList.js';
import * as MapMapEditor from './js/Map/MapEditor.js';
import * as MapMapImage from './js/Map/MapImage.js';
import * as MapMap from './js/Map/Map.js';
import * as MapMapMarkerImage from './js/Map/MapMarkerImage.js';
import * as MapMapMarker from './js/Map/MapMarker.js';
import * as MapMapPlace from './js/Map/MapPlace.js';
import * as MapMapRectangle from './js/Map/MapRectangle.js';
import * as MapMapRectangleMarker from './js/Map/MapRectangleMarker.js';
import * as MenuMainMenu from './js/Menu/MainMenu.js';
import * as MenuMenuButton from './js/Menu/MenuButton.js';
import * as MenuMenuItem from './js/Menu/MenuItem.js';
import * as MenuMenu from './js/Menu/Menu.js';
import * as PanelCollapsePanel from './js/Panel/CollapsePanel.js';
import * as PanelSlidePanel from './js/Panel/SlidePanel.js';
import * as PanelSplitPanel from './js/Panel/SplitPanel.js';
import * as PanelTabPanel from './js/Panel/TabPanel.js';
import * as VideoAnnotationFolder from './js/Video/AnnotationFolder.js';
import * as VideoAnnotationPanel from './js/Video/AnnotationPanel.js';
import * as VideoBlockVideoTimeline from './js/Video/BlockVideoTimeline.js';
import * as VideoClipPanel from './js/Video/ClipPanel.js';
import * as VideoLargeVideoTimeline from './js/Video/LargeVideoTimeline.js';
import * as VideoSmallVideoTimelineImage from './js/Video/SmallVideoTimelineImage.js';
import * as VideoSmallVideoTimeline from './js/Video/SmallVideoTimeline.js';
import * as VideoVideoAnnotationPanel from './js/Video/VideoAnnotationPanel.js';
import * as VideoVideoEditPanel from './js/Video/VideoEditPanel.js';
import * as VideoVideoElement from './js/Video/VideoElement.js';
import * as VideoVideoPlayer from './js/Video/VideoPlayer.js';
import * as VideoVideoPlayerMenu from './js/Video/VideoPlayerMenu.js';
import * as VideoVideoPlayerPanel from './js/Video/VideoPlayerPanel.js';
import * as VideoVideoPreview from './js/Video/VideoPreview.js';
import * as VideoVideoTimelinePanel from './js/Video/VideoTimelinePanel.js';
import * as VideoVideoTimelinePlayer from './js/Video/VideoTimelinePlayer.js';
import * as VideoYouTubeElement from './js/Video/YouTubeElement.js';
import * as WindowDialog from './js/Window/Dialog.js';
import * as WindowLayer from './js/Window/Layer.js';
import * as WindowSortDialog from './js/Window/SortDialog.js';
import * as WindowTooltip from './js/Window/Tooltip.js';
const UI = {}
Object.assign(UI,
AudioAudioElement,
AudioAudioPlayer,
BarBar,
BarProgressbar,
BarResizebar,
BarTabbar,
CalendarCalendarEditor,
CalendarCalendar,
CodeDocPage,
CodeDocPanel,
CodeExamplePage,
CodeExamplePanel,
CodeSourceViewer,
CodeSyntaxHighlighter,
CoreAPI,
CoreApp,
CoreClipboard,
CoreContainer,
CoreCookies,
CoreElement,
CoreEvent,
CoreFocus,
CoreFullscreen,
CoreGarbageCollection,
CoreHistory,
CoreLoadingIcon,
CoreLoadingScreen,
CoreRequest,
CoreTheme,
CoreUI,
CoreURL,
FormArrayEditable,
FormArrayInput,
FormButtonGroup,
FormButton,
FormCheckboxGroup,
FormCheckbox,
FormColorInput,
FormColorPicker,
FormDateInput,
FormDateTimeInput,
FormEditableContent,
FormEditable,
FormFileButton,
FormFileInput,
FormFilter,
FormFormElementGroup,
FormFormItem,
FormForm,
FormFormPanel,
FormInputGroup,
FormInput,
FormInsertHTMLDialog,
FormLabel,
FormObjectArrayInput,
FormObjectInput,
FormOptionGroup,
FormPicker,
FormPlaceInput,
FormPlacePicker,
FormRange,
FormSelectInput,
FormSelect,
FormSpreadsheet,
FormTimeInput,
ImageImageElement,
ImageImageViewer,
ListChart,
ListColumnList,
ListCustomList,
ListIconItem,
ListIconList,
ListInfoList,
ListListItem,
ListList,
ListSortList,
ListTableList,
ListTreeList,
MapMapEditor,
MapMapImage,
MapMap,
MapMapMarkerImage,
MapMapMarker,
MapMapPlace,
MapMapRectangle,
MapMapRectangleMarker,
MenuMainMenu,
MenuMenuButton,
MenuMenuItem,
MenuMenu,
PanelCollapsePanel,
PanelSlidePanel,
PanelSplitPanel,
PanelTabPanel,
VideoAnnotationFolder,
VideoAnnotationPanel,
VideoBlockVideoTimeline,
VideoClipPanel,
VideoLargeVideoTimeline,
VideoSmallVideoTimelineImage,
VideoSmallVideoTimeline,
VideoVideoAnnotationPanel,
VideoVideoEditPanel,
VideoVideoElement,
VideoVideoPlayer,
VideoVideoPlayerMenu,
VideoVideoPlayerPanel,
VideoVideoPreview,
VideoVideoTimelinePanel,
VideoVideoTimelinePlayer,
VideoYouTubeElement,
WindowDialog,
WindowLayer,
WindowSortDialog,
WindowTooltip,
);
export default UI;
export { UI };
if (typeof window !== 'undefined') {
window.Ox.UI = UI
Ox.load.UI = function(options, callback) {
options = Ox.extend({
hideScreen: true,
loadCSS: true,
loadThemes: true,
showScreen: false,
theme: 'oxlight'
}, options);
var browsers = [
{
name: 'Chrome Frame',
url: 'http://www.google.com/chromeframe/'
},
{
name: 'Chrome',
regexp: /Chrome\/(\d+)\./,
url: 'http://www.google.com/chrome/',
version: 10
},
{
name: 'Firefox',
regexp: /Firefox\/(\d+)\./,
url: 'http://www.mozilla.org/firefox/',
version: 4
},
{
name: 'Safari',
regexp: /Version\/(\d+).*? Safari/,
url: 'http://www.apple.com/safari/',
version: 5
},
{
name: 'WebKit',
regexp: /AppleWebKit\/(\d+)\./,
version: 534
},
{
name: 'Googlebot',
regexp: /Googlebot\/(\d+)\./,
version: 2
},
{
name: 'YandexBot',
regexp: /YandexBot\/(\d+)\./,
version: 3
},
{
name: 'YandexMobileBot',
regexp: /YandexMobileBot\/(\d+)\./,
version: 3
},
{
name: 'Internet Explorer',
url: 'http://windows.microsoft.com/en-US/internet-explorer/products/ie/home',
version: 9
}
],
browserSupported = false,
isInternetExplorer = /MSIE/.test(navigator.userAgent);
browsers.forEach(function(browser) {
var match = browser.regexp && browser.regexp.exec(navigator.userAgent);
if (match && match[1] >= browser.version) {
browserSupported = true;
}
});
Ox.UI = {};
Ox.UI.LoadingScreen = (function() {
var $body = Ox.$('body'),
$screen = Ox.$('<div>')
.addClass('OxLoadingScreen')
.css({
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
padding: '4px',
background: 'rgb(' + (
options.theme == 'oxlight' ? '240, 240, 240'
: options.theme == 'oxmedium' ? '144, 144, 144'
: '16, 16, 16'
) + ')',
opacity: 1,
zIndex: 1000
}),
css = {
position: 'absolute',
left: 0,
top: 0,
right: 0,
bottom: 0,
margin: 'auto',
MozUserSelect: 'none',
WebkitUserSelect: 'none'
},
loadingInterval,
$icon,
deg = 0;
browserSupported ? showIcon() : showWarning();
function showIcon() {
/*
// SVG transform performs worse than CSS transform
var src = Ox.PATH + 'UI/themes/' + options.theme + '/svg/symbolLoadingAnimated.svg'
Ox.getFile(src, function() {
Ox.$('<img>')
.attr({
src: src
})
.css(Ox.extend({
width: '32px',
height: '32px'
}, css))
.on({
mousedown: function(e) {
e.preventDefault();
}
})
.appendTo(div);
});
*/
var src = Ox.PATH + 'UI/themes/' + options.theme + '/svg/symbolLoading.svg'
Ox.getFile(src, function() {
$icon = Ox.$('<img>')
.attr({
src: src
})
.css(Ox.extend({
width: '32px',
height: '32px'
}, css))
.on({
mousedown: function(e) {
e.preventDefault()
}
})
.appendTo($screen);
});
}
function showWarning() {
var counter = 0;
browsers = browsers.filter(function(browser) {
return browser.url;
});
isInternetExplorer ? browsers.pop() : browsers.shift();
browsers.forEach(function(browser) {
browser.src = Ox.PATH + 'UI/png/browser' + browser.name.replace(' ', '') + '128.png';
Ox.getFile(browser.src, function() {
++counter == browsers.length && showIcons();
});
});
function showIcons() {
var $box = Ox.$('<div>')
.css(Ox.extend({
width: (browsers.length * 72) + 'px',
height: '72px'
}, css))
.appendTo($screen);
browsers.forEach(function(browser, i) {
Ox.$('<a>')
.attr({
href: browser.url,
title: (
browser.name == 'Chrome Frame'
? Ox._('Install') : Ox._('Download')
) + ' ' + browser.name
})
.css({
position: 'absolute',
left: (i * 72) + 'px',
width: '72px',
height: '72px'
})
.append(
Ox.$('<img>')
.attr({
src: browser.src
})
.css(Ox.extend({
width: '64px',
height: '64px',
border: 0,
cursor: 'pointer'
}, css))
.on({
mousedown: function(e) {
e.preventDefault();
}
})
)
.appendTo($box);
});
}
}
return {
hide: function() {
$('.OxLoadingScreen').animate({
opacity: browserSupported ? 0 : 0.9
}, 1000, function() {
if (browserSupported) {
clearInterval(loadingInterval);
loadingInterval = null;
$screen.remove();
} else {
$screen.on({
click: function() {
$screen.remove();
}
});
}
});
},
show: function() {
if (!loadingInterval) {
loadingInterval = setInterval(function() {
if ($icon) {
deg = (deg + 30) % 360;
$icon.css({
MozTransform: 'rotate(' + deg + 'deg)',
OTransform: 'rotate(' + deg + 'deg)',
WebkitTransform: 'rotate(' + deg + 'deg)',
transform: 'rotate(' + deg + 'deg)'
});
}
}, 83);
}
$screen.appendTo($body);
}
};
}());
Ox.documentReady(function() {
Ox.$('body').addClass('OxTheme' + Ox.toTitleCase(options.theme));
options.showScreen && Ox.UI.LoadingScreen.show();
});
loadUI();
function loadUI() {
var path = Ox.PATH + 'UI/jquery/jquery.js?' + Ox.VERSION;
Ox.getFile(path, function() {
path = Ox.PATH + 'UI/json/UI.json?' + Ox.VERSION;
Ox.getJSON(path, function(data) {
var counter = 0, length;
if (!options.loadCSS) {
data.files = data.files.filter(function(file) {
return !Ox.endsWith(file, '.css');
});
}
if (!options.loadThemes) {
data.files = data.files.filter(function(file) {
return !Ox.contains(file, '/themes/');
});
}
length = data.files.length;
Ox.UI.IMAGES = data.images;
Ox.UI.THEMES = {};
data.files.forEach(function(file) {
path = Ox.PATH + file + '?' + Ox.VERSION;
if (/\.jsonc$/.test(file)) {
Ox.getJSONC(path, function(data) {
var theme = /\/themes\/(\w+)\/json\//.exec(file)[1];
Ox.UI.THEMES[theme] = data;
++counter == length && initUI();
});
} else {
Ox.getFile(path, function() {
++counter == length && initUI();
});
}
});
});
});
}
function initUI() {
Ox.documentReady(function() {
// fixme: is this the right place to do this?
$.browser.mozilla && Ox.$document.on('dragstart', function() {
return false;
});
if (options.showScreen && options.hideScreen) {
Ox.UI.LoadingScreen.hide();
}
callback(browserSupported);
});
}
};
}