diff --git a/.travis.yml b/.travis.yml index e4450de..b545f17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,8 @@ sudo: false language: node_js node_js: - - 6 - - 7 - - 8 + - 10 + - 12 before_install: # Get installer script. @@ -12,15 +11,16 @@ before_install: install: - npm install --only=dev - - node nodegame-installer.js @dev --install-dir node_modules --no-spinner --branch v4 --yes - - mv node_modules/JSUS/node_modules/resolve node_modules/ - - mv node_modules/JSUS/node_modules/fs-extra node_modules/ + # --branch v4 + - node nodegame-installer.js @dev --install-dir node_modules --no-spinner --yes --no-check-parent-dir + # - mv node_modules/JSUS/node_modules/resolve node_modules/ + # - mv node_modules/JSUS/node_modules/fs-extra node_modules/ script: # Add JSUS tests here. - - ls -la node_modules/JSUS/node_modules/ - - ls -la node_modules/ + # - ls -la node_modules/JSUS/node_modules/ + # - ls -la node_modules/ - npm test # Test Ultimatum game. diff --git a/CHANGELOG b/CHANGELOG index 4b95370..d717d0b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,9 +1,44 @@ -# ChangeLog +# Change Log + +## 1.7.2 +- Fixed `#PARSE.isNumber` receiving empty string returning NaN instead of +false. + +## 1.7.0 and 1.7.1 +- `#ARRAY.rep` works with non-array (it creates the array for you). + +## 1.6.0 +- `#DOM.makeTabbable` to make divs and other HTML elements accessible via tab. +- `#DOM.makeClickable` to make divs and other HTML elements clickable with by pressing SPACE or ENTER. +- `#ARRAY.seq` applies the callback function also when start equals end. +- `#RANDOM.randomDate` has a default start date: 01/01/1900. + +## 1.5.0 +- `#OBJ.add|removeClass` accept a force parameter to be applied to normal objects. + +## 1.4.0 +- `#OBJ.randomKey` picks a random key from object. +- `#RANDOM.randomDate` creates a random date object within interval. + +## 1.3.0 +- `#OBJ.reverseObj` accepts a callback to edit keys and values. + +## 1.2.0 +- `#OBJ.reverseObj` switch all keys with values. + +## 1.1.1 +- `#PARSE.isNumber` fixed bug when ueq and leq params were set. + +## 1.1.0 +- `#PARSE.isMobileAgent` returns TRUE if a user agent is for a mobile device. + +## 1.0.1 +- `#FS` is using path.sep. ## 1.0.0 - `J` is exported as a top level object in the browser's window. - `#JSUS.get` alias of `JSUS.require` removed. `#JSUS.get` is now a method of the DOM library. -- DOM library rewritten. Several methods removed and code optimized. Methods _added_: get, add|append, addAttributes. Methods _modified_: generateUniqueId, addCSS, addJS. Methods _removed_: getElement, addElement, addAttributes2Elem, getButton, addButton, getFieldset, addFieldset, getTextInput, addTextInput, getTextArea, addTextArea, getCanvas, addCanvas, getSlider, addSlider, getRadioButton, addRadioButton, getLabel, addLabel, getSelect, addSelect, getIFrame, addIFrame, addBreak, getDiv, addDiv. +- DOM library rewritten. Several methods removed and code optimized. Methods _added_: get, add|append, addAttributes. Methods _modified_: generateUniqueId, addCSS, addJS. Methods _removed_: getElement, addElement, addAttributes2Elem, getButton, addButton, getFieldset, addFieldset, getTextInput, addTextInput, getTextArea, addTextArea, getCanvas, addCanvas, getSlider, addSlider, getRadioButton, addRadioButton, getLabel, addLabel, getSelect, addSelect, getIFrame, addIFrame, addBreak, getDiv, addDiv. - `#DOM.shuffleElements` accepts a callback. - '#OBJ.keys` improved, read inline docs for new options. - `#OBJ.objGetAllKeys` removed. diff --git a/LICENSE b/LICENSE index 26c0955..054092c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2015 Stefano Balietti +Copyright (c) 2018 Stefano Balietti Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/README.md b/README.md index f6ee070..1f4ea13 100644 --- a/README.md +++ b/README.md @@ -17,29 +17,10 @@ Collection of general purpose javascript functions. JSUS helps! 9. COMPATIBILITY 10. QUEUE - -All methods of all libraries are available directly as -JSUS.[methodName]. - -```javascript -JSUS.seq(1,10,2); // [ 1, 3, 5, 7, 9 ]; -``` - -To get a copy of one of the registered JSUS libraries do: - -```javascript -var ARRAY = JSUS.require('ARRAY'); -ARRAY.seq(1,10,2); // [ 1, 3, 5, 7, 9 ]; -``` - ## Browser In the browser, two objects are exported: `JSUS` and its shorthand `J`. -## Full Documentation. - -Full API description available [here](http://nodegame.github.io/JSUS/docs/jsus.js.html). - ## Build Create your customized build of JSUS.js using the make file in the bin directory @@ -49,43 +30,6 @@ node make.js build -a // Full build node make.js build -l obj,array -o jsus-oa.js // Only object and array libs. ``` - -## API Documentation - -Create html API documentation using the make file in the bin directory - -```javascript -node make.js doc -``` - -## Make help - - Usage: make.jsus.js [options] [command] - - Commands: - - build [options] [options] - Creates a custom build of JSUS.js - - doc - Build documentation files - - Options: - - -h, --help output usage information - -V, --version output the version number - - - Usage: build [options] [options] - - Options: - - -h, --help output usage information - -l, --lib choose libraries to include - -A, --analyse analyse build - -a, --all full build of JSUS - -o, --output - ## License [MIT](LICENSE) diff --git a/build/jsus.js b/build/jsus.js index a3b559f..82ad1a9 100644 --- a/build/jsus.js +++ b/build/jsus.js @@ -261,13 +261,15 @@ if (start === Infinity) return false; if ('number' !== typeof end) return false; if (end === Infinity) return false; - if (start === end) return [start]; - + // TODO: increment zero might be fine if start=end. Check. if (increment === 0) return false; if (!JSUS.inArray(typeof increment, ['undefined', 'number'])) { return false; } - + if (start === end) { + if (!func) return [ start ]; + return [ func(start) ]; + } increment = increment || 1; func = func || function(e) {return e;}; @@ -301,8 +303,6 @@ * @param {Function} cb The callback for each element in the array * @param {object} context Optional. The context of execution of the * callback. Defaults ARRAY.each - * - * @return {boolean} TRUE, if execution was successful */ ARRAY.each = function(array, cb, context) { var i, len; @@ -318,9 +318,8 @@ context = context || this; len = array.length; for (i = 0 ; i < len; i++) { - cb.call(context, array[i]); + cb.call(context, array[i], i); } - return true; }; /** @@ -556,9 +555,7 @@ var start = 0; var limit = S; var extracted = []; - if (!self) { - limit = S-1; - } + if (!self) limit = S-1; for (i=0; i < N; i++) { do { @@ -714,7 +711,8 @@ * * The original array is not modified. * - * @param {array} array the array to repeat + * @param {array|mixed} array the array to repeat. If not an array, it + * it will be made an array. * @param {number} times The number of times the array must be appended * to itself * @@ -722,13 +720,12 @@ */ ARRAY.rep = function(array, times) { var i, result; - if (!array) return; + if (!ARRAY.isArray(array)) array = [ array ]; if (!times) return array.slice(0); if (times < 1) { JSUS.log('times must be greater or equal 1', 'ERR'); return; } - i = 1; result = array.slice(0); for (; i < times; i++) { @@ -994,7 +991,7 @@ /** * # DOM - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2019 Stefano Balietti * MIT Licensed * * Helper library to perform generic operation with DOM elements. @@ -1174,6 +1171,19 @@ return content; }; + /** + * ### DOM.write2 + * + * Like `DOM.write` but with support for HTML in text (no return value) + * + * @see DOM.write + */ + DOM.write2 = function(root, text) { + if ('undefined' === typeof text) text = ""; + if (JSUS.isNode(text) || JSUS.isElement(text)) root.appendChild(text); + else root.innerHTML += text; + }; + /** * ### DOM.writeln * @@ -1197,6 +1207,18 @@ return content; }; + /** + * ### DOM.writeln2 + * + * Like `DOM.writeln` but with support for HTML in text (no return value) + * + * @see DOM.writeln + */ + DOM.writeln2 = function(root, text, rc) { + DOM.write2(root, text); + this.add(rc || 'br', root); + }; + /** * ### DOM.sprintf * @@ -1393,7 +1415,7 @@ * @param {Node} parent The parent node * @param {array} order Optional. A pre-specified order. Defaults, random * @param {function} cb Optional. A callback to execute one each shuffled - * element (after re-positioning). This is always the last parameter, + * element (after re-positioning). This is always the last parameter, * so if order is omitted, it goes second. The callback takes as input: * - the element * - the new order @@ -1432,7 +1454,7 @@ throw new TypeError('DOM.shuffleElements: order must be ' + 'array. Found: ' + order); } - + // DOM4 compliant browsers. children = parent.children; @@ -1785,17 +1807,20 @@ /** * ### DOM.removeClass * - * Removes a specific class from the classNamex attribute of a given element + * Removes a specific class from the className attribute of a given element * - * @param {HTMLElement} el An HTML element + * @param {HTMLElement|object} elem An HTML element, or an object with + * a className property if force is TRUE * @param {string} className The name of a CSS class already in the element + * @param {boolean} force Optional. If TRUE, the method is applied also + * to non HTMLElements * * @return {HTMLElement|undefined} The HTML element with the removed * class, or undefined if the inputs are misspecified */ - DOM.removeClass = function(elem, className) { - var regexpr, o; - if (!DOM.isElement(elem)) { + DOM.removeClass = function(elem, className, force) { + var regexpr; + if (!force && !DOM.isElement(elem)) { throw new TypeError('DOM.removeClass: elem must be HTMLElement. ' + 'Found: ' + elem); } @@ -1805,7 +1830,7 @@ 'HTMLElement. Found: ' + className); } regexpr = new RegExp('(?:^|\\s)' + className + '(?!\\S)'); - o = elem.className = elem.className.replace(regexpr, '' ); + elem.className = elem.className.replace(regexpr, '' ); } return elem; }; @@ -1817,14 +1842,17 @@ * * Takes care not to overwrite already existing classes. * - * @param {HTMLElement} elem An HTML element + * @param {HTMLElement|object} elem An HTML element, or an object with + * a className property if force is TRUE * @param {string|array} className The name/s of CSS class/es + * @param {boolean} force Optional. If TRUE, the method is applied also + * to non HTMLElements * * @return {HTMLElement} The HTML element with the additional * class, or undefined if the inputs are misspecified */ - DOM.addClass = function(elem, className) { - if (!DOM.isElement(elem)) { + DOM.addClass = function(elem, className, force) { + if (!force && !DOM.isElement(elem)) { throw new TypeError('DOM.addClass: elem must be HTMLElement. ' + 'Found: ' + elem); } @@ -2177,7 +2205,7 @@ */ DOM.blinkTitle = (function(id) { var clearBlinkInterval, finalTitle, elem; - clearBlinkInterval = function(opts) { + clearBlinkInterval = function() { clearInterval(id); id = null; if (elem) { @@ -2259,7 +2287,8 @@ } else if (!JSUS.isArray(titles)) { throw new TypeError(where + 'titles must be string, ' + - 'array of strings or undefined.'); + 'array of strings or undefined. Found: ' + + titles); } rotationId = 0; period = options.period || 1000; @@ -2348,6 +2377,56 @@ return !dim ? { x: x, y: y } : dim === 'x' ? x : y; }; + /** + * ### DOM.makeTabbable + * + * Adds the tabindex property to an HTML element + * + * @param {HTMLElement} elem The element to make tabbable + * @param {object} opts Optional. Configuration options, avalable: + * - index: the tabindex, default 0 + * - clickable: if TRUE, calls DOM.makeClickable on the element. + * Default: FALSE + * + * @return {HTMLElement} The tabbable element + */ + DOM.makeTabbable = function(elem, opts) { + opts = opts || {}; + elem.setAttribute('tabindex', opts.index || 0); + if (opts.clicklable) DOM.makeClickable(elem); + return elem; + }; + + /** + * ### DOM.makeClickable + * + * Adds a listener that clicks on the element if SPACE or ENTER are hit + * + * The kewydown event listener callback is available under `cb`. + * + * @param {HTMLElement} elem The element to make clickable + * @param {boolean} add If FALSE, the listener is removed. Default: TRUE + * + * @return {HTMLElement} The clickable element + */ + DOM.makeClickable = (function() { + function clickCb(event) { + if (event.keyCode === 32 || event.keyCode === 13) { + event.preventDefault(); + event.target.click(); + } + } + var cb; + cb = function(elem, add) { + if ('undefined' === typeof add) add = true; + if (add) elem.addEventListener('keydown', clickCb); + else elem.removeEventListener('keydown', clickCb); + return elem; + }; + cb.cb = clickCb; + return cb; + })(); + // ## Helper methods /** @@ -4088,7 +4167,7 @@ /** * # FS - * Copyright(c) 2016 Stefano Balietti + * Copyright(c) 2018 Stefano Balietti * MIT Licensed * * Collection of static functions related to file system operations. @@ -4109,8 +4188,8 @@ } var resolve = require('resolve'), - path = require('path'), - fs = require('fs') + path = require('path'), + fs = require('fs'); function FS() {} @@ -4155,10 +4234,10 @@ 'string or undefined. Found: ' + basedir); } // Added this line because it might fail. - if (module === 'JSUS') return path.resolve(__dirname, '..') + '/'; + if (module === 'JSUS') return path.resolve(__dirname, '..') + path.sep; str = resolve.sync(module, {basedir: basedir || __dirname}); stop = str.indexOf(module) + module.length; - return str.substr(0, stop) + '/'; + return str.substr(0, stop) + path.sep; }; /** @@ -4235,7 +4314,7 @@ }; } - if (dir[dir.length] !== '/') dir = dir + '/'; + if (dir[dir.length] !== path.sep) dir = dir + path.sep; fs.readdir(dir, function(err, files) { var asq, mycb; @@ -4297,7 +4376,7 @@ return false; } - dirOut = path.resolve(dirOut) + '/'; + dirOut = path.resolve(dirOut) + path.sep; dirs = [dirIn, dirOut]; for (i = 0; i < 2; i++) { @@ -4373,7 +4452,7 @@ /** * # OBJ - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2019 Stefano Balietti * MIT Licensed * * Collection of static functions to manipulate JavaScript objects @@ -4706,38 +4785,167 @@ /** * ## OBJ.keys * - * Scans an object an returns all the keys of the properties, - * into an array. + * Returns all the keys of an object until desired level of nestedness * - * The second paramter controls the level of nested objects - * to be evaluated. Defaults 0 (nested properties are skipped). + * The second parameter can be omitted, and the level can be specified + * inside the options object passed as second parameter. * * @param {object} obj The object from which extract the keys - * @param {number} level Optional. The level of recursion. Defaults 0 + * @param {number} level Optional. How many nested levels to scan. + * Default: 0, meaning 0 recursion, i.e., only first level keys. + * @param {object} options Optional. Configuration options: + * + * - type: 'all': all keys (default), + * 'level': keys of the specified level, + * 'leaf': keys that are leaves, i.e., keys that are at the + * the desired level or that do not point to an object + * - concat: true/false: If TRUE, keys are prefixed by parent keys + * - separator: a character to inter between parent and children keys; + * (default: '.') + * - distinct: if TRUE, only unique keys are returned (default: false) + * - parent: the name of initial parent key (default: '') + * - array: an array to which the keys will be appended (default: []) + * - skip: an object containing keys to skip + * - cb: a callback to be applied to every key before adding to results. + * The return value of the callback is interpreted as follows: + * - string|number: inserted as it is + * - array: concatenated + * - undefined: the original key is inserted + * - null: nothing is inserted * * @return {array} The array containing the extracted keys * * @see Object.keys */ - OBJ.keys = OBJ.objGetAllKeys = function(obj, level, curLevel) { - var result, key; - if (!obj) return []; - level = 'number' === typeof level && level >= 0 ? level : 0; - curLevel = 'number' === typeof curLevel && curLevel >= 0 ? curLevel : 0; - result = []; - for (key in obj) { - if (obj.hasOwnProperty(key)) { - result.push(key); - if (curLevel < level) { - if ('object' === typeof obj[key]) { - result = result.concat(OBJ.objGetAllKeys(obj[key], - (curLevel+1))); + OBJ.keys = (function() { + return function(obj, level, options) { + var keys, type, allKeys, leafKeys, levelKeys; + var separator, myLevel, curParent; + + if (arguments.length === 2 && 'object' === typeof level) { + options = level; + level = options.level; + } + + options = options || {}; + + type = options.type ? options.type.toLowerCase() : 'all'; + if (type === 'all') allKeys = true; + else if (type === 'leaf') leafKeys = true; + else if (type === 'level') levelKeys = true; + else throw new Error('keys: unknown type option: ' + type); + + if (options.cb && 'function' !== typeof options.cb) { + throw new TypeError('JSUS.keys: options.cb must be function ' + + 'or undefined. Found: ' + options.cb); + } + + if ('undefined' === typeof level) myLevel = 0; + else if ('number' === typeof level) myLevel = level; + else if ('string' === typeof level) myLevel = parseInt(level, 10); + if ('number' !== typeof myLevel || isNaN(myLevel)) { + throw new Error('JSUS.keys: level must be number, undefined ' + + 'or a parsable string. Found: ' + level); + } + // No keys at level -1; + if (level < 0) return []; + + if (options.concat) { + if ('undefined' === typeof options.separator) separator = '.'; + else separator = options.separator; + } + + if (options.parent) curParent = options.parent + separator; + else curParent = ''; + + if (!options.concat && options.distinct) keys = {}; + + return _keys(obj, myLevel, 0, curParent, options.concat, + allKeys, leafKeys, levelKeys, separator, + options.array || [], keys, options.skip || {}, + options.cb); + } + + function _keys(obj, level, curLevel, curParent, + concatKeys, allKeys, leafKeys, levelKeys, + separator, res, uniqueKeys, skipKeys, cb) { + + var key, isLevel, isObj, tmp; + isLevel = curLevel === level; + for (key in obj) { + if (obj.hasOwnProperty(key)) { + + isObj = 'object' === typeof obj[key]; + if (allKeys || + (leafKeys && (isLevel || !isObj)) || + (levelKeys && isLevel)) { + + if (concatKeys) { + tmp = curParent + key; + if (!skipKeys[tmp]) { + if (cb) _doCb(tmp, res, cb); + else res.push(tmp); + } + } + else if (!skipKeys[key]) { + if (uniqueKeys){ + if (!uniqueKeys[key]) { + if (cb) _doCb(key, res, cb); + else res.push(key); + uniqueKeys[key] = true; + } + } + else { + if (cb) _doCb(key, res, cb); + else res.push(key); + } + } + } + if (isObj && (curLevel < level)) { + _keys(obj[key], level, (curLevel+1), + concatKeys ? curParent + key + separator : key, + concatKeys, allKeys, leafKeys, levelKeys, + separator, res, uniqueKeys, skipKeys, cb); + } + } + } + return res; + } + + function _doCb(key, res, cb) { + var tmp; + tmp = cb(key); + // If string, substitute it. + if ('string' === typeof tmp || 'number' === typeof tmp) { + res.push(tmp); + } + // If array, expand it. + else if (JSUS.isArray(tmp) && tmp.length) { + if (tmp.length < 4) { + res.push(tmp[0]); + if (tmp.length > 1) { + res.push(tmp[1]); + if (tmp.length > 2) { + res.push(tmp[2]); + } } } + else { + (function() { + var i = -1, len = tmp.length; + for ( ; ++i < len ; ) { + res.push(tmp[i]); + } + })(tmp, res); + } } + else if ('undefined' === typeof tmp) { + res.push(key); + } + // Else, e.g. null, ignore it. } - return result; - }; + })(); + /** * ## OBJ.implode @@ -5111,7 +5319,7 @@ }; /** - * ## OBJ.subobj + * ## OBJ.subobj | subObj * * Creates a copy of an object containing only the properties * passed as second parameter @@ -5129,7 +5337,7 @@ * * @see OBJ.getNestedValue */ - OBJ.subobj = function(o, select) { + OBJ.subobj = OBJ.subObj = function(o, select) { var out, i, key; if (!o) return false; out = {}; @@ -5464,14 +5672,13 @@ /** * ## OBJ.melt * - * Creates a new object with the specified combination of - * properties - values + * Creates a new object with specific combination of properties - values * * The values are assigned cyclically to the properties, so that * they do not need to have the same length. E.g. * * ```javascript - * J.createObj(['a','b','c'], [1,2]); // { a: 1, b: 2, c: 1 } + * J.melt(['a','b','c'], [1,2]); // { a: 1, b: 2, c: 1 } * ``` * @param {array} keys The names of the keys to add to the object * @param {array} values The values to associate to the keys @@ -5527,6 +5734,25 @@ return name; }; + /** + * ## OBJ.randomKey + * + * Returns a random key from an existing object + * + * @param {object} obj The object from which the key will be extracted + * + * @return {string} The random key + */ + OBJ.randomKey = function(obj) { + var keys; + if ('object' !== typeof obj) { + throw new TypeError('OBJ.randomKey: obj must be object. ' + + 'Found: ' + obj); + } + keys = Object.keys(obj); + return keys[ keys.length * Math.random() << 0]; + }; + /** * ## OBJ.augment * @@ -5650,7 +5876,8 @@ OBJ.getKeyByValue = function(obj, value, allKeys) { var key, out; if ('object' !== typeof obj) { - throw new TypeError('OBJ.getKeyByValue: obj must be object.'); + throw new TypeError('OBJ.getKeyByValue: obj must be object. ' + + 'Found: ' + obj); } if (allKeys) out = []; for (key in obj) { @@ -5664,6 +5891,40 @@ return out; }; + /** + * ## OBJ.reverseObj + * + * Returns a new object where they keys and values are switched + * + * @param {object} obj The object to reverse + * @param {function} cb Optional. A callback processing a key-value pair. + * Takes as inputs current key and value and must return an array with + * updated key and value: [ newKey, newValue ]. + * + * @return {object} The reversed object + */ + OBJ.reverseObj = function(o, cb) { + var k, res; + if (cb && 'function' !== typeof cb) { + throw new TypeError('OBJ.reverseObj: cb must be function or ' + + 'undefined. Found: ' + cb); + } + res = {}; + if (!o) return res; + for (k in o) { + if (o.hasOwnProperty(k)) { + if (cb) { + k = cb(k, o[k]); + res[k[1]] = res[k[0]]; + } + else { + res[o[k]] = k; + } + } + } + return res; + }; + JSUS.extend(OBJ); })('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS); @@ -5731,6 +5992,35 @@ decodeURIComponent(results[1].replace(/\+/g, " ")); }; + /** + * ## PARSE.isMobileAgent + * + * Returns TRUE if a user agent is for a mobile device + * + * @param {string} agent Optional. The user agent to check. Default: + * navigator.userAgent + * + * @return {boolean} TRUE if a user agent is for a mobile device + */ + PARSE.isMobileAgent = function(agent) { + var rx; + if (!agent){ + if (!navigator) { + throw new Error('JSUS.isMobileAgent: agent undefined and ' + + 'no navigator. Are you in the browser?'); + } + agent = navigator.userAgent; + } + else if ('string' !== typeof agent) { + throw new TypeError('JSUS.isMobileAgent: agent must be undefined ' + + 'or string. Found: ' + agent); + } + rx = new RegExp('Android|webOS|iPhone|iPad|BlackBerry|' + + 'Windows Phone|Opera Mini|IEMobile|Mobile', 'i'); + + return rx.test(agent); + }; + /** * ## PARSE.tokenize * @@ -5847,6 +6137,8 @@ * encoded by `PARSE.stringify` * * @param {string} str The string to decode + * @param {function} cb Optional. A callback to apply to each decoded item + * * @return {mixed} The decoded value * * @see JSON.parse @@ -5862,6 +6154,8 @@ len_inf = PARSE.marker_inf.length, len_minus_inf = PARSE.marker_minus_inf.length; + var customCb; + function walker(o) { var i; if ('object' !== typeof o) return reviver(o); @@ -5871,6 +6165,8 @@ else o[i] = reviver(o[i]); } } + // On the full object. + if (customCb) customCb(o); return o; } @@ -5903,12 +6199,13 @@ return -Infinity; } - } + return value; } - return function(str) { + return function(str, cb) { + customCb = cb; return walker(JSON.parse(str)); }; @@ -5924,19 +6221,21 @@ * @param {mixed} n The value to check * @param {number} lower Optional. If set, n must be greater than lower * @param {number} upper Optional. If set, n must be smaller than upper + * @param {boolean} leq Optional. If TRUE, n can also be equal to lower + * @param {boolean} ueq Optional. If TRUE, n can also be equal to upper * * @return {boolean|number} The parsed integer, or FALSE if none was found * * @see PARSE.isFloat * @see PARSE.isNumber */ - PARSE.isInt = function(n, lower, upper) { + PARSE.isInt = function(n, lower, upper, leq, ueq) { var regex, i; regex = /^-?\d+$/; if (!regex.test(n)) return false; i = parseInt(n, 10); if (i !== parseFloat(n)) return false; - return PARSE.isNumber(i, lower, upper); + return PARSE.isNumber(i, lower, upper, leq, ueq); }; /** @@ -5949,18 +6248,20 @@ * @param {mixed} n The value to check * @param {number} lower Optional. If set, n must be greater than lower * @param {number} upper Optional. If set, n must be smaller than upper + * @param {boolean} leq Optional. If TRUE, n can also be equal to lower + * @param {boolean} ueq Optional. If TRUE, n can also be equal to upper * * @return {boolean|number} The parsed float, or FALSE if none was found * * @see PARSE.isInt * @see PARSE.isNumber */ - PARSE.isFloat = function(n, lower, upper) { + PARSE.isFloat = function(n, lower, upper, leq, ueq) { var regex; regex = /^-?\d*(\.\d+)?$/; if (!regex.test(n)) return false; if (n.toString().indexOf('.') === -1) return false; - return PARSE.isNumber(n, lower, upper); + return PARSE.isNumber(n, lower, upper, leq, ueq); }; /** @@ -5973,17 +6274,23 @@ * @param {mixed} n The value to check * @param {number} lower Optional. If set, n must be greater than lower * @param {number} upper Optional. If set, n must be smaller than upper + * @param {boolean} leq Optional. If TRUE, n can also be equal to lower + * @param {boolean} ueq Optional. If TRUE, n can also be equal to upper * * @return {boolean|number} The parsed number, or FALSE if none was found * * @see PARSE.isInt * @see PARSE.isFloat */ - PARSE.isNumber = function(n, lower, upper) { - if (isNaN(n) || !isFinite(n)) return false; + PARSE.isNumber = function(n, lower, upper, leq, ueq) { + if (isNaN(n) || !isFinite(n) || n === "") return false; n = parseFloat(n); - if ('number' === typeof lower && n < lower) return false; - if ('number' === typeof upper && n > upper) return false; + if ('number' === typeof lower && (leq ? n < lower : n <= lower)) { + return false; + } + if ('number' === typeof upper && (ueq ? n > upper : n >= upper)) { + return false; + } return n; }; @@ -6522,7 +6829,7 @@ } else { b = a; - a = 0; + a = 0; } } if (a === b) return a; @@ -6554,6 +6861,44 @@ return Math.floor(RANDOM.random(a, b) + 1); }; + /** + * ## RANDOM.randomDate + * + * Generates a pseudo-random date between + * + * @param {Date} startDate Optional. The lower date. Default: 01-01-1900. + * @param {Date} endDate Optional. The upper date. Default: today. + * + * @return {number} A random date in the chosen interval + * + * @see RANDOM.randomDate + */ + RANDOM.randomDate = (function() { + function isValidDate(date) { + return date && + Object.prototype.toString.call(date) === "[object Date]" && + !isNaN(date); + } + return function(startDate, endDate) { + if ('undefined' === typeof startDate) { + startDate = new Date("1900"); + } + else if (!isValidDate(startDate)) { + throw new TypeError('randomDate: startDate must be a valid ' + + 'date. Found: ' + startDate); + } + if ('undefined' === typeof endDate) { + endDate = new Date(); + } + else if (!isValidDate(endDate)) { + throw new TypeError('randomDate: endDate must be a valid ' + + 'date or undefined. Found: ' + endDate); + } + return new Date(startDate.getTime() + Math.random() * + (endDate.getTime() - startDate.getTime())); + }; + })(); + /** * ## RANDOM.sample * @@ -6911,7 +7256,7 @@ /** * # TIME - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2021 Stefano Balietti * MIT Licensed * * Collection of static functions related to the generation, @@ -6923,28 +7268,34 @@ function TIME() {} + function pad(number) { + return (number < 10) ? '0' + number : number; + } + + function _getTime(ms) { + var d, res; + d = new Date(); + res = pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + + pad(d.getSeconds()); + if (ms) res += ':' + pad(d.getMilliseconds()); + return res; + } + // Polyfill for Date.toISOString (IE7, IE8, IE9) // Kudos: https://developer.mozilla.org/en-US/docs/Web/ // JavaScript/Reference/Global_Objects/Date/toISOString if (!Date.prototype.toISOString) { - (function() { - - function pad(number) { - return (number < 10) ? '0' + number : number; - } - - Date.prototype.toISOString = function() { - var ms = (this.getUTCMilliseconds() / 1000).toFixed(3); - return this.getUTCFullYear() + - '-' + pad(this.getUTCMonth() + 1) + - '-' + pad(this.getUTCDate()) + - 'T' + pad(this.getUTCHours()) + - ':' + pad(this.getUTCMinutes()) + - ':' + pad(this.getUTCSeconds()) + - '.' + ms.slice(2, 5) + 'Z'; - }; - }()); + Date.prototype.toISOString = function() { + var ms = (this.getUTCMilliseconds() / 1000).toFixed(3); + return this.getUTCFullYear() + + '-' + pad(this.getUTCMonth() + 1) + + '-' + pad(this.getUTCDate()) + + 'T' + pad(this.getUTCHours()) + + ':' + pad(this.getUTCMinutes()) + + ':' + pad(this.getUTCSeconds()) + + '.' + ms.slice(2, 5) + 'Z'; + }; } /** @@ -6976,9 +7327,7 @@ * @see TIME.getTimeM */ TIME.getTime = function() { - var d; - d = new Date(); - return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds(); + return _getTime(); }; /** @@ -6995,10 +7344,7 @@ * @see TIME.getTime */ TIME.getTimeM = function() { - var d; - d = new Date(); - return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + - ':' + d.getMilliseconds(); + return _getTime(true); }; /** @@ -7032,7 +7378,6 @@ return result; }; - /** * ## TIME.now * diff --git a/build/jsus.min.js b/build/jsus.min.js index b4810d2..60151e8 100644 --- a/build/jsus.min.js +++ b/build/jsus.min.js @@ -8,4 +8,4 @@ * See README.md for extra help. * --- */ -(function(e){var t=e.JSUS={};t._classes={},"undefined"==typeof console&&(console={}),"undefined"==typeof console.log&&(console.log=function(){}),t.log=function(e){console.log(e)},t.extend=function(e,n){var r,i;if("object"!=typeof e&&"function"!=typeof e)return n;"undefined"==typeof n&&(n=n||this,"function"==typeof e?(r=e.toString(),r=r.substr("function ".length),r=r.substr(0,r.indexOf("("))):r=e.constructor||e.__proto__.constructor,r&&(this._classes[r]=e));for(i in e)e.hasOwnProperty(i)&&(typeof n[i]!="object"?n[i]=e[i]:t.extend(e[i],n[i]));return e.prototype&&t.extend(e.prototype,n.prototype||n),n},t.require=function(e,n){var r;n="undefined"==typeof n?!0:n;if(n&&"undefined"==typeof t.clone)return t.log("JSUS.require: JSUS.clone not found, but clone requested. Cannot continue."),!1;if("undefined"==typeof e)r=t._classes;else{r=t._classes[e];if("undefined"==typeof r)return t.log("JSUS.require: could not find component "+e),!1}return n?t.clone(r):r},t.isNodeJS=function(){return"undefined"!=typeof module&&"undefined"!=typeof module.exports&&"function"==typeof require},t.isNodeJS()?(require("./lib/compatibility"),require("./lib/obj"),require("./lib/array"),require("./lib/time"),require("./lib/eval"),require("./lib/dom"),require("./lib/random"),require("./lib/parse"),require("./lib/queue"),require("./lib/fs")):e.J=e.JSUS})("undefined"!=typeof module&&"undefined"!=typeof module.exports?module.exports:window),function(e){"use strict";function t(){}Array.prototype.filter||(Array.prototype.filter=function(e){if(this===void 0||this===null)throw new TypeError;var t=new Object(this),n=t.length>>>0;if(typeof e!="function")throw new TypeError;var r=[],i=arguments[1];for(var s=0;s=n)o.push(i(s)),s-=r;return o},t.each=function(e,t,n){var r,i;if("object"!=typeof e)throw new TypeError("ARRAY.each: array must be object. Found: "+e);if("function"!=typeof t)throw new TypeError("ARRAY.each: cb must be function. Found: "+t);n=n||this,i=e.length;for(r=0;r=t&&(s.push(a),f=0,a=[]),a.push(n[u]),n.splice(u,1),r=n.length,f++;return a.length>0&&s.push(a),s},t._latinSquare=function(t,n,r){r="undefined"==typeof r?!0:r;if(t===n&&!r)return!1;var i=[],s=[];for(var o=0;oe&&(n=e),t._latinSquare(e,n,!0))},t.latinSquareNoSelf=function(e,n){return n||(n=e-1),!e||e<0||n<0?!1:(n>e&&(n=e-1),t._latinSquare(e,n,!1))},t.generateCombinations=function n(e,t){var r,i,s,o,u;s=[];for(r=0;r0;s--)r=Math.floor(Math.random()*(s+1)),i=t[r],t[r]=t[s],t[s]=i;return t},t.getNRandom=function(e,n){return t.shuffle(e).slice(0,n)},t.distinct=function(e){var n=[];return e?(t.each(e,function(e){t.inArray(e,n)||n.push(e)}),n):n},t.transpose=function(e){if(!e)return;var n,r,i,s,o=[];n=e.length||0,r=t.isArray(e[0])?e[0].length:0;if(n===0||r===0)return o;for(i=0;it)throw new Error("DOM.generateUniqueId: could not find unique id within "+t+" trials.")}return s}}(),r.removeClass=function(e,t){var n,i;if(!r.isElement(e))throw new TypeError("DOM.removeClass: elem must be HTMLElement. Found: "+e);if(t){if("string"!=typeof t||t.trim()==="")throw new TypeError("DOM.removeClass: className must be HTMLElement. Found: "+t);n=new RegExp("(?:^|\\s)"+t+"(?!\\S)"),i=e.className=e.className.replace(n,"")}return e},r.addClass=function(e,t){if(!r.isElement(e))throw new TypeError("DOM.addClass: elem must be HTMLElement. Found: "+e);if(t){t instanceof Array&&(t=t.join(" "));if("string"!=typeof t||t.trim()==="")throw new TypeError("DOM.addClass: className must be HTMLElement. Found: "+t);e.className?e.className+=" "+t:e.className=t}return e},r.getElementsByClassName=function(e,t,n){var r,i,s,o,u,a;r=[],s=n||"*";if(e.evaluate){o="//"+s+'[contains(concat(" ", normalize-space(@class), " "), "'+t+' ")]',o=e.evaluate(o,e,null,0,null);while(i=o.iterateNext())r.push(i)}else{a=new RegExp("(^| )"+t+"( |$)"),o=e.getElementsByTagName(s);for(u=0;u1){var i=new Object(arguments[1]);for(var s in i)t.call(i,s)&&(r[s]=i[s])}return r}}():Object.create}(),t.equals=function(e,n){var r,i,s,o;r=typeof e,i=typeof n;if(r!==i)return!1;if("undefined"===r||"undefined"===i)return e===n;if(e===null||n===null)return e===n;if("number"===r&&isNaN(e)&&"number"===i&&isNaN(n))return isNaN(e)&&isNaN(n);s={number:"",string:"","boolean":""};if(r in s)return e===n;if("function"===r)return e.toString()===n.toString();for(o in e)if(e.hasOwnProperty(o)){if("undefined"==typeof n[o]&&"undefined"!=typeof e[o])return!1;if(!n[o]&&e[o])return!1;if("function"==typeof e[o]){if(e[o].toString()!==n[o].toString())return!1}else if(!t.equals(e[o],n[o]))return!1}for(o in n)if(n.hasOwnProperty(o)){if("undefined"==typeof e[o]&&"undefined"!=typeof n[o])return!1;if(!e[o]&&n[o])return!1}return!0},t.isEmpty=function(e){var t;if(!e)return!0;if("string"==typeof e)return e.trim()==="";if("number"==typeof e)return!1;if("function"==typeof e)return!1;for(t in e)if(e.hasOwnProperty(t))return!1;return!0},t.size=t.getListSize=function(e){var t,n;if(!e)return 0;if("number"==typeof e)return 0;if("string"==typeof e)return 0;t=0;for(n in e)e.hasOwnProperty(n)&&t++;return t},t._obj2Array=function(e,n,r,i){var s,o;if("object"!=typeof e)return[e];if(r){i="undefined"!=typeof i?i:1;if(i>r)return[e];i+=1}s=[];for(o in e)e.hasOwnProperty(o)&&(n&&s.push(o),"object"==typeof e[o]?s=s.concat(t._obj2Array(e[o],n,r,i)):s.push(e[o]));return s},t.obj2Array=function(e,n){return t._obj2Array(e,!1,n)},t.obj2KeyedArray=t.obj2KeyArray=function(e,n){return t._obj2Array(e,!0,n)},t.obj2QueryString=function(e){var t,n;if("object"!=typeof e)throw new TypeError("JSUS.objectToQueryString: obj must be object.");t=[];for(n in e)e.hasOwnProperty(n)&&t.push(encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return"?"+t.join("&")},t.keys=t.objGetAllKeys=function(e,n,r){var i,s;if(!e)return[];n="number"==typeof n&&n>=0?n:0,r="number"==typeof r&&r>=0?r:0,i=[];for(s in e)e.hasOwnProperty(s)&&(i.push(s),r=i)t(r,s,a);else{l=o||!e.isArray(r);for(f in r)r.hasOwnProperty(f)&&("object"==typeof r[f]&&i&&u+1<=i?n(r[f],s,u+1,l?a.concat(f):a):t(r[f],s,l?a.concat(f):a))}},function(t,u,a,f){var l;if("object"!=typeof t)throw new TypeError("JSUS.split: o must be object. Found: "+t);if("string"!=typeof u||u.trim()==="")throw new TypeError("JSUS.split: key must a non-empty string. Found: "+u);if(a&&("number"!=typeof a||a<0))throw new TypeError("JSUS.split: l must a non-negative number or undefined. Found: "+a);return r=e.clone(t),"object"!=typeof t[u]?[r]:(l=[],s=u,r[u]={},i="undefined"==typeof a?1:a,o=f,n(t[u],l,0,[]),s=undefined,r=undefined,i=undefined,o=undefined,l)}}(),t.melt=function(e,t){var n={},r=t.length;for(var i=0;ir)return}return i},t.augment=function(e,n,r){var i,s;r=r||t.keys(e);for(i=0;in?!1:e)},t.isEmail=function(e){var t;return"string"!=typeof e?!1:e.trim().length<5?!1:(t=e.indexOf("@"),t===-1||t===0||t===e.length-1?!1:(t=e.lastIndexOf("."),t===-1||t===e.length-1||t>t+1?!1:!0))},t.range=function(r,i){var s,o,u,a,f,l,c,h,p,d,v;a=[];if("undefined"==typeof r)return a;if("number"==typeof r)r=""+r;else if("string"!=typeof r)throw new TypeError("PARSE.range: expr must be string, number, undefined. Found: "+r);if("undefined"==typeof i)i=r;else if(e.isArray(i)){if(i.length===0)return a;f=Math.min.apply(null,i),l=Math.max.apply(null,i)}else if("object"==typeof i){if("function"!=typeof i.next)throw new TypeError("PARSE.range: available.next must be function. Found: "+i.next);if("function"!=typeof i.isFinished)throw new TypeError("PARSE.range: available.isFinished must be function. Found: "+i.isFinished);if("number"!=typeof i.begin)throw new TypeError("PARSE.range: available.begin must be number. Found: "+i.begin);if("number"!=typeof i.end)throw new TypeError("PARSE.range: available.end must be number. Found: "+i.end);f=i.begin,l=i.end}else{if("string"!=typeof i)throw new TypeError("PARSE.range: available must be string, array, object or undefined. Found: "+i);i=n(i),h=i.match(/([-+]?\d+)/g);if(h===null)throw new Error("PARSE.range: no numbers in available: "+i);c=Math.min.apply(null,h),i=t.range(i,{begin:c,end:Math.max.apply(null,h),value:c,next:function(){return this.value++},isFinished:function(){return this.value>this.end}}),f=Math.min.apply(null,i),l=Math.max.apply(null,i)}r=r.replace(/end/g,parseInt(l,10)),r=r.replace(/begin/g,parseInt(f,10)),r=n(r),r=r.replace(/([-+]?\d+\.\d+)/g,function(e,t){return parseInt(t,10)}),p=/[^ \*\d<>=!\|&\.\[\],\(\)\-\+%]/g;if(r.match(p))throw new Error("PARSE.range: invalid characters found: "+r);r=r.replace(/([^& ]) *& *([^& ])/g,"$1&&$2"),r=r.replace(/([^| ]) *\| *([^| ])/g,"$1||$2"),r=r.replace(/([-+]?\d+)/g,"(x==$1)"),r=r.replace(/% *\(x==([-+]?\d+)\)/,"!(x%$1)"),r=r.replace(/!\(x%([-+]?\d+)\) *={1,} *\(x==([-+]?\d+)\)/g,"(x%$1==$2)"),r=r.replace(/([<>]=?) *\(x==([-+]?\d+)\)/g,"(x$1$2)"),r=r.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==(\+?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x>=$1&&x<=$3&&!((x- $1)%$2))"),r=r.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==(-\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x<=$1&&x>=$3&&!((x- $1)%$2))"),r=r.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x>=$1&&x<=$2)"),r=r.replace(/([(\[]) *\(x==([-+]?\d+)\) *, *\(x==([-+]?\d+)\) *([\])])/g,function(e,t,n,r,i){return"(x>"+(t=="("?"":"=")+n+"&&x<"+(i==")"?"":"=")+r+")"}),r=r.replace("*",1),r=r.replace(/\s/g,""),r=r.replace(/\)[,] *(!*)\(/g,")||$1("),p=/[^ \d<>=!\|&,\(\)\-\+%x\.]/g,d=/[^ &!|\(] *\(/g,v=/\.[^\d]|[^\d]\./;if(r.match(p))throw new Error("PARSE.range: invalid characters found: "+r);if(r.match(d))throw new Error("PARSE.range: invalid character before opending bracket found: "+r);if(r.match(v))throw new Error("PARSE.range: invalid dot found: "+r);if(e.isArray(i)){s=-1,o=i.length;for(;++s1?n[1].trim():""},e.extend(t)}("undefined"!=typeof JSUS?JSUS:module.parent.exports.JSUS),function(e){"use strict";function n(){this.queue=[],this.inProgress={}}var t={};t.getQueue=function(){return new n},n.prototype.isReady=function(){return e.isEmpty(this.inProgress)},n.prototype.onReady=function(t){if("function"!=typeof t)throw new TypeError("Queue.onReady: cb must be function. Found: "+t);e.isEmpty(this.inProgress)?t():this.queue.push(t)},n.prototype.add=function(t){if(t&&"string"!=typeof t)throw new Error("Queue.add: key must be string.");t=e.uniqueKey(this.inProgress,t);if("string"!=typeof t)throw new Error("Queue.add: an error occurred generating unique key.");return this.inProgress[t]=t,t},n.prototype.remove=function(t){if("string"!=typeof t)throw new Error("Queue.remove: key must be string.");delete this.inProgress[t],e.isEmpty(this.inProgress)&&this.executeAndClear()},n.prototype.getRemoveCb=function(e){var t;if("string"!=typeof e)throw new Error("Queue.getRemoveCb: key must be string.");return t=this,function(){t.remove(e)}},n.prototype.executeAndClear=function(){var e,t;e=-1,t=this.queue.length;for(;++e=1?s(o,u):(r=Math.sqrt(-2*Math.log(p)/p),a=c*r,n=h*r,i=!0,u*a+o))}}()},t.nextNormal=t.getNormalGenerator(),t.nextLogNormal=function(e,n){if("number"!=typeof e)throw new TypeError("nextLogNormal: mu must be number.");if("number"!=typeof n)throw new TypeError("nextLogNormal: sigma must be number.");return Math.exp(t.nextNormal(e,n))},t.nextExponential=function(e){if("number"!=typeof e)throw new TypeError("nextExponential: lambda must be number.");if(e<=0)throw new TypeError("nextExponential: lambda must be greater than 0.");return-Math.log(1-Math.random())/e},t.nextBinomial=function(e,t){var n,r;if("number"!=typeof e)throw new TypeError("nextBinomial: p must be number.");if("number"!=typeof t)throw new TypeError("nextBinomial: trials must be number.");if(e<0||e>1)throw new TypeError("nextBinomial: p must between 0 and 1.");if(t<1)throw new TypeError("nextBinomial: trials must be greater than 0.");n=0,r=0;while(n 0 or undefined. Found: "+t);if("undefined"!=typeof n){if("string"!=typeof n||n.trim()==="")throw new Error("randomString: chars must a non-empty string or undefined. Found: "+n)}else if(r)throw new Error("randomString: useChars is TRUE, but chars is undefined.");t=t||6,n=n||"a",i="";if(!r){n.indexOf("a")>-1&&(i+="abcdefghijklmnopqrstuvwxyz"),n.indexOf("A")>-1&&(i+="ABCDEFGHIJKLMNOPQRSTUVWXYZ"),n.indexOf("1")>-1&&(i+="0123456789"),n.indexOf("!")>-1&&(i+="!~`@#$%^&*()_+-={}[]:\";'<>?,./|\\"),u=n.indexOf("_");if(u>-1){u=n.charAt(u+1),u=e.isInt(u,0)||1;if(u===1)i+=" ";else if(u===2)i+=" ";else if(u===3)i+=" ";else{o=-1;for(;++o>>0;if(typeof e!="function")throw new TypeError;var r=[],i=arguments[1];for(var s=0;s=n)o.push(i(s)),s-=r;return o},t.each=function(e,t,n){var r,i;if("object"!=typeof e)throw new TypeError("ARRAY.each: array must be object. Found: "+e);if("function"!=typeof t)throw new TypeError("ARRAY.each: cb must be function. Found: "+t);n=n||this,i=e.length;for(r=0;r=t&&(s.push(a),f=0,a=[]),a.push(n[u]),n.splice(u,1),r=n.length,f++;return a.length>0&&s.push(a),s},t._latinSquare=function(t,n,r){r="undefined"==typeof r?!0:r;if(t===n&&!r)return!1;var i=[],s=[];for(var o=0;oe&&(n=e),t._latinSquare(e,n,!0))},t.latinSquareNoSelf=function(e,n){return n||(n=e-1),!e||e<0||n<0?!1:(n>e&&(n=e-1),t._latinSquare(e,n,!1))},t.generateCombinations=function n(e,t){var r,i,s,o,u;s=[];for(r=0;r0;s--)r=Math.floor(Math.random()*(s+1)),i=t[r],t[r]=t[s],t[s]=i;return t},t.getNRandom=function(e,n){return t.shuffle(e).slice(0,n)},t.distinct=function(e){var n=[];return e?(t.each(e,function(e){t.inArray(e,n)||n.push(e)}),n):n},t.transpose=function(e){if(!e)return;var n,r,i,s,o=[];n=e.length||0,r=t.isArray(e[0])?e[0].length:0;if(n===0||r===0)return o;for(i=0;it)throw new Error("DOM.generateUniqueId: could not find unique id within "+t+" trials.")}return s}}(),r.removeClass=function(e,t,n){var i;if(!n&&!r.isElement(e))throw new TypeError("DOM.removeClass: elem must be HTMLElement. Found: "+e);if(t){if("string"!=typeof t||t.trim()==="")throw new TypeError("DOM.removeClass: className must be HTMLElement. Found: "+t);i=new RegExp("(?:^|\\s)"+t+"(?!\\S)"),e.className=e.className.replace(i,"")}return e},r.addClass=function(e,t,n){if(!n&&!r.isElement(e))throw new TypeError("DOM.addClass: elem must be HTMLElement. Found: "+e);if(t){t instanceof Array&&(t=t.join(" "));if("string"!=typeof t||t.trim()==="")throw new TypeError("DOM.addClass: className must be HTMLElement. Found: "+t);e.className?e.className+=" "+t:e.className=t}return e},r.getElementsByClassName=function(e,t,n){var r,i,s,o,u,a;r=[],s=n||"*";if(e.evaluate){o="//"+s+'[contains(concat(" ", normalize-space(@class), " "), "'+t+' ")]',o=e.evaluate(o,e,null,0,null);while(i=o.iterateNext())r.push(i)}else{a=new RegExp("(^| )"+t+"( |$)"),o=e.getElementsByTagName(s);for(u=0;u1){var i=new Object(arguments[1]);for(var s in i)t.call(i,s)&&(r[s]=i[s])}return r}}():Object.create}(),t.equals=function(e,n){var r,i,s,o;r=typeof e,i=typeof n;if(r!==i)return!1;if("undefined"===r||"undefined"===i)return e===n;if(e===null||n===null)return e===n;if("number"===r&&isNaN(e)&&"number"===i&&isNaN(n))return isNaN(e)&&isNaN(n);s={number:"",string:"","boolean":""};if(r in s)return e===n;if("function"===r)return e.toString()===n.toString();for(o in e)if(e.hasOwnProperty(o)){if("undefined"==typeof n[o]&&"undefined"!=typeof e[o])return!1;if(!n[o]&&e[o])return!1;if("function"==typeof e[o]){if(e[o].toString()!==n[o].toString())return!1}else if(!t.equals(e[o],n[o]))return!1}for(o in n)if(n.hasOwnProperty(o)){if("undefined"==typeof e[o]&&"undefined"!=typeof n[o])return!1;if(!e[o]&&n[o])return!1}return!0},t.isEmpty=function(e){var t;if(!e)return!0;if("string"==typeof e)return e.trim()==="";if("number"==typeof e)return!1;if("function"==typeof e)return!1;for(t in e)if(e.hasOwnProperty(t))return!1;return!0},t.size=t.getListSize=function(e){var t,n;if(!e)return 0;if("number"==typeof e)return 0;if("string"==typeof e)return 0;t=0;for(n in e)e.hasOwnProperty(n)&&t++;return t},t._obj2Array=function(e,n,r,i){var s,o;if("object"!=typeof e)return[e];if(r){i="undefined"!=typeof i?i:1;if(i>r)return[e];i+=1}s=[];for(o in e)e.hasOwnProperty(o)&&(n&&s.push(o),"object"==typeof e[o]?s=s.concat(t._obj2Array(e[o],n,r,i)):s.push(e[o]));return s},t.obj2Array=function(e,n){return t._obj2Array(e,!1,n)},t.obj2KeyedArray=t.obj2KeyArray=function(e,n){return t._obj2Array(e,!0,n)},t.obj2QueryString=function(e){var t,n;if("object"!=typeof e)throw new TypeError("JSUS.objectToQueryString: obj must be object.");t=[];for(n in e)e.hasOwnProperty(n)&&t.push(encodeURIComponent(n)+"="+encodeURIComponent(e[n]));return"?"+t.join("&")},t.keys=function(){function t(e,r,i,s,o,u,a,f,l,c,h,p,d){var v,m,g,y;m=i===r;for(v in e)if(e.hasOwnProperty(v)){g="object"==typeof e[v];if(u||a&&(m||!g)||f&&m)o?(y=s+v,p[y]||(d?n(y,c,d):c.push(y))):p[v]||(h?h[v]||(d?n(v,c,d):c.push(v),h[v]=!0):d?n(v,c,d):c.push(v));g&&i1&&(n.push(i[1]),i.length>2&&n.push(i[2]))):function(){var e=-1,t=i.length;for(;++e=i)t(r,s,a);else{l=o||!e.isArray(r);for(f in r)r.hasOwnProperty(f)&&("object"==typeof r[f]&&i&&u+1<=i?n(r[f],s,u+1,l?a.concat(f):a):t(r[f],s,l?a.concat(f):a))}},function(t,u,a,f){var l;if("object"!=typeof t)throw new TypeError("JSUS.split: o must be object. Found: "+t);if("string"!=typeof u||u.trim()==="")throw new TypeError("JSUS.split: key must a non-empty string. Found: "+u);if(a&&("number"!=typeof a||a<0))throw new TypeError("JSUS.split: l must a non-negative number or undefined. Found: "+a);return r=e.clone(t),"object"!=typeof t[u]?[r]:(l=[],s=u,r[u]={},i="undefined"==typeof a?1:a,o=f,n(t[u],l,0,[]),s=undefined,r=undefined,i=undefined,o=undefined,l)}}(),t.melt=function(e,t){var n={},r=t.length;for(var i=0;ir)return}return i},t.randomKey=function(e){var t;if("object"!=typeof e)throw new TypeError("OBJ.randomKey: obj must be object. Found: "+e);return t=Object.keys(e),t[t.length*Math.random()<<0]},t.augment=function(e,n,r){var i,s;r=r||t.keys(e);for(i=0;in:e>=n)?!1:e)},t.isEmail=function(e){var t;return"string"!=typeof e?!1:e.trim().length<5?!1:(t=e.indexOf("@"),t===-1||t===0||t===e.length-1?!1:(t=e.lastIndexOf("."),t===-1||t===e.length-1||t>t+1?!1:!0))},t.range=function(r,i){var s,o,u,a,f,l,c,h,p,d,v;a=[];if("undefined"==typeof r)return a;if("number"==typeof r)r=""+r;else if("string"!=typeof r)throw new TypeError("PARSE.range: expr must be string, number, undefined. Found: "+r);if("undefined"==typeof i)i=r;else if(e.isArray(i)){if(i.length===0)return a;f=Math.min.apply(null,i),l=Math.max.apply(null,i)}else if("object"==typeof i){if("function"!=typeof i.next)throw new TypeError("PARSE.range: available.next must be function. Found: "+i.next);if("function"!=typeof i.isFinished)throw new TypeError("PARSE.range: available.isFinished must be function. Found: "+i.isFinished);if("number"!=typeof i.begin)throw new TypeError("PARSE.range: available.begin must be number. Found: "+i.begin);if("number"!=typeof i.end)throw new TypeError("PARSE.range: available.end must be number. Found: "+i.end);f=i.begin,l=i.end}else{if("string"!=typeof i)throw new TypeError("PARSE.range: available must be string, array, object or undefined. Found: "+i);i=n(i),h=i.match(/([-+]?\d+)/g);if(h===null)throw new Error("PARSE.range: no numbers in available: "+i);c=Math.min.apply(null,h),i=t.range(i,{begin:c,end:Math.max.apply(null,h),value:c,next:function(){return this.value++},isFinished:function(){return this.value>this.end}}),f=Math.min.apply(null,i),l=Math.max.apply(null,i)}r=r.replace(/end/g,parseInt(l,10)),r=r.replace(/begin/g,parseInt(f,10)),r=n(r),r=r.replace(/([-+]?\d+\.\d+)/g,function(e,t){return parseInt(t,10)}),p=/[^ \*\d<>=!\|&\.\[\],\(\)\-\+%]/g;if(r.match(p))throw new Error("PARSE.range: invalid characters found: "+r);r=r.replace(/([^& ]) *& *([^& ])/g,"$1&&$2"),r=r.replace(/([^| ]) *\| *([^| ])/g,"$1||$2"),r=r.replace(/([-+]?\d+)/g,"(x==$1)"),r=r.replace(/% *\(x==([-+]?\d+)\)/,"!(x%$1)"),r=r.replace(/!\(x%([-+]?\d+)\) *={1,} *\(x==([-+]?\d+)\)/g,"(x%$1==$2)"),r=r.replace(/([<>]=?) *\(x==([-+]?\d+)\)/g,"(x$1$2)"),r=r.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==(\+?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x>=$1&&x<=$3&&!((x- $1)%$2))"),r=r.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==(-\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x<=$1&&x>=$3&&!((x- $1)%$2))"),r=r.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,"(x>=$1&&x<=$2)"),r=r.replace(/([(\[]) *\(x==([-+]?\d+)\) *, *\(x==([-+]?\d+)\) *([\])])/g,function(e,t,n,r,i){return"(x>"+(t=="("?"":"=")+n+"&&x<"+(i==")"?"":"=")+r+")"}),r=r.replace("*",1),r=r.replace(/\s/g,""),r=r.replace(/\)[,] *(!*)\(/g,")||$1("),p=/[^ \d<>=!\|&,\(\)\-\+%x\.]/g,d=/[^ &!|\(] *\(/g,v=/\.[^\d]|[^\d]\./;if(r.match(p))throw new Error("PARSE.range: invalid characters found: "+r);if(r.match(d))throw new Error("PARSE.range: invalid character before opending bracket found: "+r);if(r.match(v))throw new Error("PARSE.range: invalid dot found: "+r);if(e.isArray(i)){s=-1,o=i.length;for(;++s1?n[1].trim():""},e.extend(t)}("undefined"!=typeof JSUS?JSUS:module.parent.exports.JSUS),function(e){"use strict";function n(){this.queue=[],this.inProgress={}}var t={};t.getQueue=function(){return new n},n.prototype.isReady=function(){return e.isEmpty(this.inProgress)},n.prototype.onReady=function(t){if("function"!=typeof t)throw new TypeError("Queue.onReady: cb must be function. Found: "+t);e.isEmpty(this.inProgress)?t():this.queue.push(t)},n.prototype.add=function(t){if(t&&"string"!=typeof t)throw new Error("Queue.add: key must be string.");t=e.uniqueKey(this.inProgress,t);if("string"!=typeof t)throw new Error("Queue.add: an error occurred generating unique key.");return this.inProgress[t]=t,t},n.prototype.remove=function(t){if("string"!=typeof t)throw new Error("Queue.remove: key must be string.");delete this.inProgress[t],e.isEmpty(this.inProgress)&&this.executeAndClear()},n.prototype.getRemoveCb=function(e){var t;if("string"!=typeof e)throw new Error("Queue.getRemoveCb: key must be string.");return t=this,function(){t.remove(e)}},n.prototype.executeAndClear=function(){var e,t;e=-1,t=this.queue.length;for(;++e=1?s(o,u):(r=Math.sqrt(-2*Math.log(p)/p),a=c*r,n=h*r,i=!0,u*a+o))}}()},t.nextNormal=t.getNormalGenerator(),t.nextLogNormal=function(e,n){if("number"!=typeof e)throw new TypeError("nextLogNormal: mu must be number.");if("number"!=typeof n)throw new TypeError("nextLogNormal: sigma must be number.");return Math.exp(t.nextNormal(e,n))},t.nextExponential=function(e){if("number"!=typeof e)throw new TypeError("nextExponential: lambda must be number.");if(e<=0)throw new TypeError("nextExponential: lambda must be greater than 0.");return-Math.log(1-Math.random())/e},t.nextBinomial=function(e,t){var n,r;if("number"!=typeof e)throw new TypeError("nextBinomial: p must be number.");if("number"!=typeof t)throw new TypeError("nextBinomial: trials must be number.");if(e<0||e>1)throw new TypeError("nextBinomial: p must between 0 and 1.");if(t<1)throw new TypeError("nextBinomial: trials must be greater than 0.");n=0,r=0;while(n 0 or undefined. Found: "+t);if("undefined"!=typeof n){if("string"!=typeof n||n.trim()==="")throw new Error("randomString: chars must a non-empty string or undefined. Found: "+n)}else if(r)throw new Error("randomString: useChars is TRUE, but chars is undefined.");t=t||6,n=n||"a",i="";if(!r){n.indexOf("a")>-1&&(i+="abcdefghijklmnopqrstuvwxyz"),n.indexOf("A")>-1&&(i+="ABCDEFGHIJKLMNOPQRSTUVWXYZ"),n.indexOf("1")>-1&&(i+="0123456789"),n.indexOf("!")>-1&&(i+="!~`@#$%^&*()_+-={}[]:\";'<>?,./|\\"),u=n.indexOf("_");if(u>-1){u=n.charAt(u+1),u=e.isInt(u,0)||1;if(u===1)i+=" ";else if(u===2)i+=" ";else if(u===3)i+=" ";else{o=-1;for(;++o'; - out += '
' + nodename + '
'; - out += '
'; - - // Loop through all child directories first - if(node.dirs){ - var dirs = []; - for(var i in node.dirs){ - if(node.dirs.hasOwnProperty(i)) dirs.push({ name: i, html: nodeHtml(i, node.dirs[i], path + i + '/', root) }); - } - // Have to store them in an array first and then sort them alphabetically here - dirs.sort(function(a, b){ return (a.name > b.name) ? 1 : (a.name == b.name) ? 0 : -1; }); - - for(var k = 0; k < dirs.length; k += 1) out += dirs[k].html; - } - - // Now loop through all the child files alphabetically - if(node.files){ - node.files.sort(); - for(var j = 0; j < node.files.length; j += 1){ - out += '' + node.files[j] + ''; - } - } - - // Close things off - out += '
'; - - return out; -} - -/** - * ## toggleTree - * - * Toggles the visibility of the folder tree - */ -function toggleTree(){ - // Do the actual toggling by modifying the class on the body element. That way we can get some nice CSS transitions going. - if(sidebarVisible){ - document.body.className = document.body.className.replace(/\s*sidebar/g,''); - sidebarVisible = false; - }else{ - document.body.className += ' sidebar'; - sidebarVisible = true; - } - if(window.localStorage){ - if(sidebarVisible){ - window.localStorage.docker_showSidebar = 'yes'; - }else{ - window.localStorage.docker_showSidebar = 'no'; - } - } -} - -/** - * ## wireUpTabs - * - * Wires up events on the sidebar tabe - */ -function wireUpTabs(){ - var tabEl = document.getElementById('sidebar_switch'); - var children = tabEl.childNodes; - - // Each tab has a class corresponding of the id of its tab pane - for(var i = 0, l = children.length; i < l; i += 1){ - // Ignore text nodes - if(children[i].nodeType !== 1) continue; - children[i].addEventListener('click', function(c){ - return function(){ switchTab(c); }; - }(children[i].className)); - } -} - -/** - * ## switchTab - * - * Switches tabs in the sidebar - * - * @param {string} tab The ID of the tab to switch to - */ -function switchTab(tab){ - var tabEl = document.getElementById('sidebar_switch'); - var children = tabEl.childNodes; - - // Easiest way to go through tabs without any kind of selector is just to look at the tab bar - for(var i = 0, l = children.length; i < l; i += 1){ - // Ignore text nodes - if(children[i].nodeType !== 1) continue; - - // Figure out what tab pane this tab button corresponts to - var t = children[i].className.replace(/\s.*$/,''); - if(t === tab){ - // Show the tab pane, select the tab button - document.getElementById(t).style.display = 'block'; - if(children[i].className.indexOf('selected') === -1) children[i].className += ' selected'; - }else{ - // Hide the tab pane, deselect the tab button - document.getElementById(t).style.display = 'none'; - children[i].className = children[i].className.replace(/\sselected/,''); - } - } - - // Store the last open tab in localStorage - if(window.localStorage) window.localStorage.docker_sidebarTab = tab; -} - -/** - * ## window.onload - * - * When the document is ready, make the sidebar and all that jazz - */ -window.onload = function(){ - makeTree(tree, relativeDir, thisFile); - wireUpTabs(); - - // Switch to the last viewed sidebar tab if stored, otherwise default to folder tree - if(window.localStorage && window.localStorage.docker_sidebarTab){ - switchTab(window.localStorage.docker_sidebarTab); - }else{ - switchTab('tree'); - } -}; \ No newline at end of file diff --git a/docs/doc-style.css b/docs/doc-style.css deleted file mode 100644 index d205080..0000000 --- a/docs/doc-style.css +++ /dev/null @@ -1,369 +0,0 @@ -body { - font-family: "Palatino Linotype", "Book Antiqua", Palatino, FreeSerif, serif; - font-size: 15px; - line-height: 22px; - margin: 0; - padding: 0; } - -p, h1, h2, h3, h4, h5, h6 { - margin: 0 0 15px 0; } - -h1 { - margin-top: 40px; } - -#tree, #headings { - position: absolute; - top: 30px; - left: 0; - bottom: 0; - width: 290px; - padding: 10px 0; - overflow: auto; } - -#sidebar_wrapper { - position: fixed; - top: 0; - left: 0; - bottom: 0; - width: 0; - overflow: hidden; } - -#sidebar_switch { - position: absolute; - top: 0; - left: 0; - width: 290px; - height: 29px; - border-bottom: 1px solid; } - #sidebar_switch span { - display: block; - float: left; - width: 50%; - text-align: center; - line-height: 29px; - cursor: pointer; } - #sidebar_switch .selected { - font-weight: bold; } - -.slidey #sidebar_wrapper { - -webkit-transition: width 250ms linear; - -moz-transition: width 250ms linear; - -ms-transition: width 250ms linear; - -o-transition: width 250ms linear; - transition: width 250ms linear; } - -.sidebar #sidebar_wrapper { - width: 290px; } - -#tree .nodename { - text-indent: 12px; - background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAg0lEQVQYlWNIS0tbAcSK////Z8CHGTIzM7+mp6d/ASouwqswKyvrO1DRfyg+CcRaxCgE4Z9A3AjEbIQUgjHQOQvwKgS6+ffChQt3AiUDcCqsra29d/v27R6ghCVWN2ZnZ/9YuXLlRqBAPBALYvVMR0fHmQcPHrQBOUZ4gwfqFj5CAQ4Al6wLIYDwo9QAAAAASUVORK5CYII=); - background-repeat: no-repeat; - background-position: left center; - cursor: pointer; } -#tree .open > .nodename { - background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAlElEQVQYlWNIS0tbCsT/8eCN////Z2B49OhRfHZ29jdsioDiP27evJkNVggkONeuXbscm8Jly5atA8rzwRSCsG5DQ8MtZEU1NTUPgOLGUHm4QgaQFVlZWT9BijIzM39fuHChDCaHohBkBdCq9SCF8+bN2wHkC+FSCMLGkyZNOvb9+3dbNHEMhSDsDsRMxCjEiolWCADeUBHgU/IGQQAAAABJRU5ErkJggg==); - background-position: left 7px; } -#tree .dir, #tree .file { - position: relative; - min-height: 20px; - line-height: 20px; - padding-left: 12px; } - #tree .dir > .children, #tree .file > .children { - display: none; } - #tree .dir.open > .children, #tree .file.open > .children { - display: block; } -#tree .file { - padding-left: 24px; - display: block; - text-decoration: none; } -#tree > .dir { - padding-left: 0; } - -#headings .heading a { - text-decoration: none; - padding-left: 10px; - display: block; } -#headings .h1 { - padding-left: 0; - margin-top: 10px; - font-size: 1.3em; } -#headings .h2 { - padding-left: 10px; - margin-top: 8px; - font-size: 1.1em; } -#headings .h3 { - padding-left: 20px; - margin-top: 5px; - font-size: 1em; } -#headings .h4 { - padding-left: 30px; - margin-top: 3px; - font-size: 0.9em; } -#headings .h5 { - padding-left: 40px; - margin-top: 1px; - font-size: 0.8em; } -#headings .h6 { - padding-left: 50px; - font-size: 0.75em; } - -#sidebar-toggle { - position: fixed; - top: 0; - left: 0; - width: 5px; - bottom: 0; - z-index: 2; - cursor: pointer; } - #sidebar-toggle:hover { - width: 10px; } - -.slidey #sidebar-toggle, .slidey #container { - -webkit-transition: all 250ms linear; - -moz-transition: all 250ms linear; - -ms-transition: all 250ms linear; - -o-transition: all 250ms linear; - transition: all 250ms linear; } - -.sidebar #sidebar-toggle { - left: 290px; } - -#container { - position: fixed; - left: 5px; - right: 0; - top: 0; - bottom: 0; - overflow: auto; } - -.sidebar #container { - left: 295px; } - -.no-sidebar #sidebar_wrapper, .no-sidebar #sidebar-toggle { - display: none; } -.no-sidebar #container { - left: 0; } - -#page { - padding-top: 40px; } - -table td { - border: 0; - outline: 0; } - -.docs.markdown { - padding: 10px 50px; } - -td.docs { - max-width: 450px; - min-width: 450px; - min-height: 5px; - padding: 10px 25px 1px 50px; - overflow-x: hidden; - vertical-align: top; - text-align: left; } - -.docs pre { - margin: 15px 0 15px; - padding: 5px; - padding-left: 10px; - border: 1px solid; - font-size: 12px; - overflow: auto; } - .docs pre.code_stats { - font-size: 60%; } -.docs p tt, .docs p code, .docs li tt, .docs li code { - border: 1px solid; - font-size: 12px; - padding: 0 0.2em; } - -.dox { - border-top: 1px solid; - padding-top: 10px; - padding-bottom: 10px; } - .dox .details { - padding: 10px; - border: 1px solid; - margin-bottom: 10px; } - .dox .dox_tag_title { - font-weight: bold; } - .dox .dox_tag_detail { - margin-left: 10px; } - .dox .dox_tag_detail span { - margin-right: 5px; } - .dox .dox_type { - font-style: italic; } - .dox .dox_tag_name { - font-weight: bold; } - -.pilwrap { - position: relative; - padding-top: 1px; } - .pilwrap .pilcrow { - font: 12px Arial; - text-decoration: none; - color: #454545; - position: absolute; - top: 3px; - left: -20px; - padding: 1px 2px; - opacity: 0; - -webkit-transition: opacity 0.2s linear; - -moz-transition: opacity 0.2s linear; - -ms-transition: opacity 0.2s linear; - -o-transition: opacity 0.2s linear; - transition: opacity 0.2s linear; } - .pilwrap:hover .pilcrow { - opacity: 1; } - -td.code { - padding: 8px 15px 8px 25px; - width: 100%; - vertical-align: bottom; - border-left: 1px solid; } - -.background { - border-left: 1px solid; - position: absolute; - z-index: -1; - top: 0; - right: 0; - bottom: 0; - left: 525px; } - -pre, tt, code { - font-size: 12px; - line-height: 18px; - font-family: Menlo, Monaco, Consolas, "Lucida Console", monospace; - margin: 0; - padding: 0; } - -.line-num { - display: inline-block; - width: 50px; - text-align: right; - opacity: 0.3; - margin-left: -20px; - text-decoration: none; } - -/* All the stuff that can depend on colour scheme goes below here: */ -body { - background: white; - color: #2f2f24; } - -a { - color: #261a3b; } - a:visited { - color: #261a3b; } - -#sidebar_wrapper { - background: #f4f4f3; } - -#sidebar_switch { - background: #ededec; - border-bottom-color: #dededc; } - #sidebar_switch span { - color: #2d2d22; } - #sidebar_switch span:hover { - background: #f4f4f3; } - #sidebar_switch .selected { - background: #fafafa; - color: #252519; } - -#tree .file { - color: #252519; } - -#headings .heading a { - color: #252519; } - -#sidebar-toggle { - background: #e9e9e8; } - #sidebar-toggle:hover { - background: #dededc; } - -.docs.markdown { - background: white; } -.docs pre { - border-color: #dededc; } -.docs p tt, .docs p code, .docs li tt, .docs li code { - border-color: #dededc; - background: #f4f4f3; } - -.highlight { - background: #f4f4f3; - color: auto; } - -.dox { - border-top-color: #e6e6e4; } - .dox .details { - background: #f4f4f3; - border-color: #dededc; } - -.pilwrap .pilcrow { - color: #3a3a2f; } - -td.code, .background { - border-left-color: #dededc; } -body .highlight .hll { background-color: #ffffcc } -body .highlight { background: #f8f8f8; } -body .highlight .c { color: #408080; font-style: italic } /* Comment */ -body .highlight .err { border: 1px solid #FF0000 } /* Error */ -body .highlight .k { color: #008000; font-weight: bold } /* Keyword */ -body .highlight .o { color: #666666 } /* Operator */ -body .highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ -body .highlight .cp { color: #BC7A00 } /* Comment.Preproc */ -body .highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ -body .highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ -body .highlight .gd { color: #A00000 } /* Generic.Deleted */ -body .highlight .ge { font-style: italic } /* Generic.Emph */ -body .highlight .gr { color: #FF0000 } /* Generic.Error */ -body .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ -body .highlight .gi { color: #00A000 } /* Generic.Inserted */ -body .highlight .go { color: #808080 } /* Generic.Output */ -body .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ -body .highlight .gs { font-weight: bold } /* Generic.Strong */ -body .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ -body .highlight .gt { color: #0040D0 } /* Generic.Traceback */ -body .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ -body .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ -body .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ -body .highlight .kp { color: #008000 } /* Keyword.Pseudo */ -body .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ -body .highlight .kt { color: #B00040 } /* Keyword.Type */ -body .highlight .m { color: #666666 } /* Literal.Number */ -body .highlight .s { color: #BA2121 } /* Literal.String */ -body .highlight .na { color: #7D9029 } /* Name.Attribute */ -body .highlight .nb { color: #008000 } /* Name.Builtin */ -body .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ -body .highlight .no { color: #880000 } /* Name.Constant */ -body .highlight .nd { color: #AA22FF } /* Name.Decorator */ -body .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ -body .highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ -body .highlight .nf { color: #0000FF } /* Name.Function */ -body .highlight .nl { color: #A0A000 } /* Name.Label */ -body .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ -body .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ -body .highlight .nv { color: #19177C } /* Name.Variable */ -body .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ -body .highlight .w { color: #bbbbbb } /* Text.Whitespace */ -body .highlight .mf { color: #666666 } /* Literal.Number.Float */ -body .highlight .mh { color: #666666 } /* Literal.Number.Hex */ -body .highlight .mi { color: #666666 } /* Literal.Number.Integer */ -body .highlight .mo { color: #666666 } /* Literal.Number.Oct */ -body .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ -body .highlight .sc { color: #BA2121 } /* Literal.String.Char */ -body .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ -body .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ -body .highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ -body .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ -body .highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ -body .highlight .sx { color: #008000 } /* Literal.String.Other */ -body .highlight .sr { color: #BB6688 } /* Literal.String.Regex */ -body .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ -body .highlight .ss { color: #19177C } /* Literal.String.Symbol */ -body .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ -body .highlight .vc { color: #19177C } /* Name.Variable.Class */ -body .highlight .vg { color: #19177C } /* Name.Variable.Global */ -body .highlight .vi { color: #19177C } /* Name.Variable.Instance */ -body .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/docs/jsus.js.html b/docs/jsus.js.html deleted file mode 100644 index 56800bd..0000000 --- a/docs/jsus.js.html +++ /dev/null @@ -1,379 +0,0 @@ - - - - jsus.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - JSUS: JavaScript UtilS. -

-
- - -

Copyright(c) 2015 Stefano Balietti -MIT Licensed

-
-

Collection of general purpose javascript functions. JSUS helps!

- - -
-

- - See README.md for extra help. -

-
- -
-
-
(function(exports) {
-
-    var JSUS = exports.JSUS = {};
-
-
-

- - JSUS._classes -

-
- - -

Reference to all the extensions

-
    JSUS._classes = {};
-
-
- -
-

Make sure that the console is available also in old browser, e.g. < IE8.

-
    if ('undefined' === typeof console) console = {};
-    if ('undefined' === typeof console.log) console.log = function() {};
-
-
-
-

- - JSUS.log -

-
- -
-

Reference to standard out, by default console.log

- -

Override to redirect the standard output of all JSUS functions.

-
-
-
Params
-
- txt - string - Text to output -
-
-
-
    JSUS.log = function(txt) {
-        console.log(txt);
-    };
-
-
-
-

- - JSUS.extend -

-
- -
-

Extends JSUS with additional methods and or properties

- -

The first parameter can be an object literal or a function. -A reference of the original extending object is stored in -JSUS._classes

- -

If a second parameter is passed, that will be the target of the -extension.

-
-
-
Params
-
- additional - object - Text to output -
-
- target - object - function - The object to extend -
-
Returns
-
- - object - function - target The extended object -
-
See
-
- JSUS.get - -
-
-
-
    JSUS.extend = function(additional, target) {
-        var name, prop;
-        if ('object' !== typeof additional &&
-            'function' !== typeof additional) {
-            return target;
-        }
-
-
- -
-

If we are extending JSUS, store a reference -of the additional object into the hidden -JSUS._classes object;

-
        if ('undefined' === typeof target) {
-            target = target || this;
-            if ('function' === typeof additional) {
-                name = additional.toString();
-                name = name.substr('function '.length);
-                name = name.substr(0, name.indexOf('('));
-            }
-
-
- -
-

Must be object.

-
            else {
-                name = additional.constructor ||
-                    additional.__proto__.constructor;
-            }
-            if (name) {
-                this._classes[name] = additional;
-            }
-        }
-
-        for (prop in additional) {
-            if (additional.hasOwnProperty(prop)) {
-                if (typeof target[prop] !== 'object') {
-                    target[prop] = additional[prop];
-                } else {
-                    JSUS.extend(additional[prop], target[prop]);
-                }
-            }
-        }
-
-
- -
-

Additional is a class (Function) -TODO: this is true also for {}

-
        if (additional.prototype) {
-            JSUS.extend(additional.prototype, target.prototype || target);
-        }
-
-        return target;
-    };
-
-
-
-

- - JSUS.require -

-
- -
-

Returns a copy of one / all the objects extending JSUS

- -

The first parameter is a string representation of the name of -the requested extending object. If no parameter is passed a copy -of all the extending objects is returned.

-
-
-
Params
-
- className - string - The name of the requested JSUS library -
-
Returns
-
- - function - boolean - The copy of the JSUS library, or - FALSE if the library does not exist -
-
-
-
    JSUS.require = JSUS.get = function(className) {
-        if ('undefined' === typeof JSUS.clone) {
-            JSUS.log('JSUS.clone not found. Cannot continue.');
-            return false;
-        }
-        if ('undefined' === typeof className) return JSUS.clone(JSUS._classes);
-        if ('undefined' === typeof JSUS._classes[className]) {
-            JSUS.log('Could not find class ' + className);
-            return false;
-        }
-        return JSUS.clone(JSUS._classes[className]);
-    };
-
-
-
-

- - JSUS.isNodeJS -

-
- -
-

Returns TRUE when executed inside Node.JS environment

-
-
-
Returns
-
- - boolean - TRUE when executed inside Node.JS environment -
-
-
-
    JSUS.isNodeJS = function() {
-        return 'undefined' !== typeof module &&
-            'undefined' !== typeof module.exports &&
-            'function' === typeof require;
-    };
-
-
-

- - Node.JS includes -

-
- - -

if node

-
    if (JSUS.isNodeJS()) {
-        require('./lib/compatibility');
-        require('./lib/obj');
-        require('./lib/array');
-        require('./lib/time');
-        require('./lib/eval');
-        require('./lib/dom');
-        require('./lib/random');
-        require('./lib/parse');
-        require('./lib/queue');
-        require('./lib/fs');
-    }
-
-
- -
-

end node

-
})(
-    'undefined' !== typeof module && 'undefined' !== typeof module.exports ?
-        module.exports: window
-);
-
-
-
- - diff --git a/docs/lib/array.js.html b/docs/lib/array.js.html deleted file mode 100644 index 559a5d1..0000000 --- a/docs/lib/array.js.html +++ /dev/null @@ -1,1538 +0,0 @@ - - - - array.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - ARRAY -

-
- - -

Copyright(c) 2016 Stefano Balietti -MIT Licensed

-
-

Collection of static functions to manipulate arrays

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    function ARRAY() {}
-
-
-
-

- - ARRAY.filter -

-
- -
-

Add the filter method to ARRAY objects in case the method is not -supported natively.

-
- -
-
    if (!Array.prototype.filter) {
-        Array.prototype.filter = function(fun /*, thisp */) {
-            if (this === void 0 || this === null) throw new TypeError();
-
-            var t = new Object(this);
-            var len = t.length >>> 0;
-            if (typeof fun !== "function") throw new TypeError();
-
-            var res = [];
-            var thisp = arguments[1];
-            for (var i = 0; i < len; i++) {
-                if (i in t) {
-                    var val = t[i]; // in case fun mutates this
-                    if (fun.call(thisp, val, i, t)) {
-                        res.push(val);
-                    }
-                }
-            }
-            return res;
-        };
-    }
-
-
-
-

- - ARRAY.isArray -

-
- -
-

Returns TRUE if a variable is an Array

- -

This method is exactly the same as Array.isArray, -but it works on a larger share of browsers.

-
-
-
Params
-
- o - object - The variable to check. -
-
See
-
- Array.isArray - -
-
-
-
    ARRAY.isArray = (function(f) {
-        if ('function' === typeof f) return f;
-        else return function(o) {
-            if (!o) return false;
-            return Object.prototype.toString.call(o) === '[object Array]';
-        };
-    })(Array.isArray);
-
-
-
-

- - ARRAY.seq -

-
- -
-

Returns an array of sequential numbers from start to end

- -

If start > end the series goes backward.

- -

The distance between two subsequent numbers can be controlled -by the increment parameter.

- -

When increment is not a divider of Abs(start - end), end will -be missing from the series.

- -

A callback function to apply to each element of the sequence -can be passed as fourth parameter.

- -

Returns FALSE, in case parameters are incorrectly specified

-
-
-
Params
-
- start - number - The first element of the sequence -
-
- end - number - The last element of the sequence -
-
- increment - number - Optional. The increment between two - subsequents element of the sequence -
-
- func - Function - Optional. A callback function that can modify - each number of the sequence before returning it -
-
Returns
-
- - array - The final sequence -
-
-
-
    ARRAY.seq = function(start, end, increment, func) {
-        var i, out;
-        if ('number' !== typeof start) return false;
-        if (start === Infinity) return false;
-        if ('number' !== typeof end) return false;
-        if (end === Infinity) return false;
-        if (start === end) return [start];
-
-        if (increment === 0) return false;
-        if (!JSUS.inArray(typeof increment, ['undefined', 'number'])) {
-            return false;
-        }
-
-        increment = increment || 1;
-        func = func || function(e) {return e;};
-
-        i = start;
-        out = [];
-
-        if (start < end) {
-            while (i <= end) {
-                out.push(func(i));
-                i = i + increment;
-            }
-        }
-        else {
-            while (i >= end) {
-                out.push(func(i));
-                i = i - increment;
-            }
-        }
-
-        return out;
-    };
-
-
-
-

- - ARRAY.each -

-
- -
-

Executes a callback on each element of the array

- -

If an error occurs returns FALSE.

-
-
-
Params
-
- array - array - The array to loop in -
-
- func - Function - The callback for each element in the array -
-
- context - object - Optional. The context of execution of the - callback. Defaults ARRAY.each -
-
Returns
-
- - boolean - TRUE, if execution was successful -
-
-
-
    ARRAY.each = function(array, func, context) {
-        if ('object' !== typeof array) return false;
-        if (!func) return false;
-
-        context = context || this;
-        var i, len = array.length;
-        for (i = 0 ; i < len; i++) {
-            func.call(context, array[i]);
-        }
-        return true;
-    };
-
-
-
-

- - ARRAY.map -

-
- -
-

Executes a callback to each element of the array and returns the result

- -

Any number of additional parameters can be passed after the -callback function.

-
-
-
Returns
-
- - array - The result of the mapping execution -
-
See
-
- ARRAY.each - -
-
-
-
    ARRAY.map = function() {
-        var i, len, args, out, o;
-        var array, func;
-
-        array = arguments[0];
-        func = arguments[1];
-
-        if (!ARRAY.isArray(array)) {
-            JSUS.log('ARRAY.map: first parameter must be array. Found: ' +
-                     array);
-            return;
-        }
-        if ('function' !== typeof func) {
-            JSUS.log('ARRAY.map: second parameter must be function. Found: ' +
-                     func);
-            return;
-        }
-
-        len = arguments.length;
-        if (len === 3) args = [null, arguments[2]];
-        else if (len === 4) args = [null, arguments[2], arguments[3]];
-        else {
-            len = len - 1;
-            args = new Array(len);
-            for (i = 1; i < (len); i++) {
-                args[i] = arguments[i+1];
-            }
-        }
-
-        out = [], len = array.length;
-        for (i = 0; i < len; i++) {
-            args[0] = array[i];
-            o = func.apply(this, args);
-            if ('undefined' !== typeof o) out.push(o);
-        }
-        return out;
-    };
-
-
-
-

- - ARRAY.removeElement -

-
- -
-

Removes an element from the the array, and returns it

- -

For objects, deep equality comparison is performed -through JSUS.equals.

- -

If no element is removed returns FALSE.

-
-
-
Params
-
- needle - mixed - The element to search in the array -
-
- haystack - array - The array to search in -
-
Returns
-
- - mixed - The element that was removed, FALSE if none was removed -
-
See
-
- JSUS.equals - -
-
-
-
    ARRAY.removeElement = function(needle, haystack) {
-        var func, i;
-        if ('undefined' === typeof needle || !haystack) return false;
-
-        if ('object' === typeof needle) {
-            func = JSUS.equals;
-        }
-        else {
-            func = function(a, b) {
-                return (a === b);
-            };
-        }
-
-        for (i = 0; i < haystack.length; i++) {
-            if (func(needle, haystack[i])){
-                return haystack.splice(i,1);
-            }
-        }
-        return false;
-    };
-
-
-
-

- - ARRAY.inArray -

-
- -
-

Returns TRUE if the element is contained in the array, -FALSE otherwise

- -

For objects, deep equality comparison is performed -through JSUS.equals.

-
-
-
Params
-
- needle - mixed - The element to search in the array -
-
- haystack - array - The array to search in -
-
Returns
-
- - boolean - TRUE, if the element is contained in the array -
-
See
-
- JSUS.equals - -
-
-
-
    ARRAY.inArray = function(needle, haystack) {
-        var func, i, len;
-        if (!haystack) return false;
-        func = JSUS.equals;
-        len = haystack.length;
-        for (i = 0; i < len; i++) {
-            if (func.call(this, needle, haystack[i])) {
-                return true;
-            }
-        }
-        return false;
-    };
-
-    ARRAY.in_array = function(needle, haystack) {
-        console.log('***ARRAY.in_array is deprecated. ' +
-                    'Use ARRAY.inArray instead.***');
-        return ARRAY.inArray(needle, haystack);
-    };
-
-
-
-

- - ARRAY.getNGroups -

-
- -
-

Returns an array of N array containing the same number of elements -If the length of the array and the desired number of elements per group -are not multiple, the last group could have less elements

- -

The original array is not modified.

- -

@see ARRAY.getGroupsSizeN - @see ARRAY.generateCombinations - @see ARRAY.matchN

-
-
-
Params
-
- array - array - The array to split in subgroups -
-
- N - number - The number of subgroups -
-
Returns
-
- - array - Array containing N groups -
-
-
-
    ARRAY.getNGroups = function(array, N) {
-        return ARRAY.getGroupsSizeN(array, Math.floor(array.length / N));
-    };
-
-
-
-

- - ARRAY.getGroupsSizeN -

-
- -
-

Returns an array of arrays containing N elements each

- -

The last group could have less elements

-
-
-
Params
-
- array - array - The array to split in subgroups -
-
- N - number - The number of elements in each subgroup -
-
Returns
-
- - array - Array containing groups of size N -
-
See
-
- ARRAY.getNGroups -
-
See
-
- ARRAY.generateCombinations -
-
See
-
- ARRAY.matchN - -
-
-
-
    ARRAY.getGroupsSizeN = function(array, N) {
-
-        var copy = array.slice(0);
-        var len = copy.length;
-        var originalLen = copy.length;
-        var result = [];
-
-
- -
-

Init values for the loop algorithm.

-
        var i, idx;
-        var group = [], count = 0;
-        for (i=0; i < originalLen; i++) {
-
-
- -
-

Get a random idx between 0 and array length.

-
            idx = Math.floor(Math.random()*len);
-
-
- -
-

Prepare the array container for the elements of a new group.

-
            if (count >= N) {
-                result.push(group);
-                count = 0;
-                group = [];
-            }
-
-
- -
-

Insert element in the group.

-
            group.push(copy[idx]);
-
-
- -
-

Update.

-
            copy.splice(idx,1);
-            len = copy.length;
-            count++;
-        }
-
-
- -
-

Add any remaining element.

-
        if (group.length > 0) {
-            result.push(group);
-        }
-
-        return result;
-    };
-
-
-
-

- - ARRAY._latinSquare -

-
- -
-

Generate a random Latin Square of size S

- -

If N is defined, it returns "Latin Rectangle" (SxN)

- -

A parameter controls for self-match, i.e. whether the symbol "i" -is found or not in in column "i".

-
-
-
API
-
- private - -
Params
-
- S - number - The number of rows -
-
- Optional. - number - N The number of columns. Defaults N = S -
-
- Optional. - boolean - If TRUE self-match is allowed. Defaults TRUE -
-
Returns
-
- - array - The resulting latin square (or rectangle) -
-
-
-
    ARRAY._latinSquare = function(S, N, self) {
-        self = ('undefined' === typeof self) ? true : self;
-
-
- -
-

Infinite loop.

-
        if (S === N && !self) return false;
-        var seq = [];
-        var latin = [];
-        for (var i=0; i< S; i++) {
-            seq[i] = i;
-        }
-
-        var idx = null;
-
-        var start = 0;
-        var limit = S;
-        var extracted = [];
-        if (!self) {
-            limit = S-1;
-        }
-
-        for (i=0; i < N; i++) {
-            do {
-                idx = JSUS.randomInt(start,limit);
-            }
-            while (JSUS.inArray(idx, extracted));
-            extracted.push(idx);
-
-            if (idx == 1) {
-                latin[i] = seq.slice(idx);
-                latin[i].push(0);
-            }
-            else {
-                latin[i] = seq.slice(idx).concat(seq.slice(0,(idx)));
-            }
-
-        }
-
-        return latin;
-    };
-
-
-
-

- - ARRAY.latinSquare -

-
- -
-

Generate a random Latin Square of size S

- -

If N is defined, it returns "Latin Rectangle" (SxN)

-
-
-
Params
-
- S - number - The number of rows -
-
- Optional. - number - N The number of columns. Defaults N = S -
-
Returns
-
- - array - The resulting latin square (or rectangle) -
-
-
-
    ARRAY.latinSquare = function(S, N) {
-        if (!N) N = S;
-        if (!S || S < 0 || (N < 0)) return false;
-        if (N > S) N = S;
-
-        return ARRAY._latinSquare(S, N, true);
-    };
-
-
-
-

- - ARRAY.latinSquareNoSelf -

-
- -
-

Generate a random Latin Square of size Sx(S-1), where -in each column "i", the symbol "i" is not found

- -

If N < S, it returns a "Latin Rectangle" (SxN)

-
-
-
Params
-
- S - number - The number of rows -
-
- Optional. - number - N The number of columns. Defaults N = S-1 -
-
Returns
-
- - array - The resulting latin square (or rectangle) -
-
-
-
    ARRAY.latinSquareNoSelf = function(S, N) {
-        if (!N) N = S-1;
-        if (!S || S < 0 || (N < 0)) return false;
-        if (N > S) N = S-1;
-
-        return ARRAY._latinSquare(S, N, false);
-    };
-
-
-
-

- - ARRAY.generateCombinations -

-
- -
-

Generates all distinct combinations of exactly r elements each

-
-
-
Params
-
- array - array - The array from which the combinations are extracted -
-
- r - number - The number of elements in each combination -
-
Returns
-
- - array - The total sets of combinations -
-
See
-
- ARRAY.getGroupSizeN -
-
See
-
- ARRAY.getNGroups -
-
See
- -
-
-
    ARRAY.generateCombinations = function combinations(arr, k) {
-        var i, subI, ret, sub, next;
-        ret = [];
-        for (i = 0; i < arr.length; i++) {
-            if (k === 1) {
-                ret.push( [ arr[i] ] );
-            }
-            else {
-                sub = combinations(arr.slice(i+1, arr.length), k-1);
-                for (subI = 0; subI < sub.length; subI++ ){
-                    next = sub[subI];
-                    next.unshift(arr[i]);
-                    ret.push( next );
-                }
-            }
-        }
-        return ret;
-    };
-
-
-
-

- - ARRAY.matchN -

-
- -
-

Match each element of the array with N random others

- -

If strict is equal to true, elements cannot be matched multiple times.

- -

Important: this method has a bug / feature. If the strict parameter -is set, the last elements could remain without match, because all the -other have been already used. Another recombination would be able -to match all the elements instead.

-
-
-
Params
-
- array - array - The array in which operate the matching -
-
- N - number - The number of matches per element -
-
- strict - boolean - Optional. If TRUE, matched elements cannot be - repeated. Defaults, FALSE -
-
Returns
-
- - array - The results of the matching -
-
See
-
- ARRAY.getGroupSizeN -
-
See
-
- ARRAY.getNGroups -
-
See
-
- ARRAY.generateCombinations - -
-
-
-
    ARRAY.matchN = function(array, N, strict) {
-        var result, i, copy, group, len, found;
-        if (!array) return;
-        if (!N) return array;
-
-        result = [];
-        len = array.length;
-        found = [];
-        for (i = 0 ; i < len ; i++) {
-
-
- -
-

Recreate the array.

-
            copy = array.slice(0);
-            copy.splice(i,1);
-            if (strict) {
-                copy = ARRAY.arrayDiff(copy,found);
-            }
-            group = ARRAY.getNRandom(copy,N);
-
-
- -
-

Add to the set of used elements.

-
            found = found.concat(group);
-
-
- -
-

Re-add the current element.

-
            group.splice(0,0,array[i]);
-            result.push(group);
-
-
- -
-

Update.

-
            group = [];
-        }
-        return result;
-    };
-
-
-
-

- - ARRAY.rep -

-
- -
-

Appends an array to itself a number of times and return a new array

- -

The original array is not modified.

-
-
-
Params
-
- array - array - the array to repeat -
-
- times - number - The number of times the array must be appended - to itself -
-
Returns
-
- - array - A copy of the original array appended to itself -
-
-
-
    ARRAY.rep = function(array, times) {
-        var i, result;
-        if (!array) return;
-        if (!times) return array.slice(0);
-        if (times < 1) {
-            JSUS.log('times must be greater or equal 1', 'ERR');
-            return;
-        }
-
-        i = 1;
-        result = array.slice(0);
-        for (; i < times; i++) {
-            result = result.concat(array);
-        }
-        return result;
-    };
-
-
-
-

- - ARRAY.stretch -

-
- -
-

Repeats each element of the array N times

- -

N can be specified as an integer or as an array. In the former case all -the elements are repeat the same number of times. In the latter, each -element can be repeated a custom number of times. If the length of the -times array differs from that of the array to stretch a recycle rule -is applied.

- -

The original array is not modified.

- -

E.g.:

- - -
 var foo = [1,2,3];
-
- ARRAY.stretch(foo, 2); // [1, 1, 2, 2, 3, 3]
-
- ARRAY.stretch(foo, [1,2,3]); // [1, 2, 2, 3, 3, 3];
-
- ARRAY.stretch(foo, [2,1]); // [1, 1, 2, 3, 3];
-
- - -
-
-
Params
-
- array - array - the array to strech -
-
- times - number - array - The number of times each element - must be repeated -
-
Returns
-
- - array - A stretched copy of the original array -
-
-
-
    ARRAY.stretch = function(array, times) {
-        var result, i, repeat, j;
-        if (!array) return;
-        if (!times) return array.slice(0);
-        if ('number' === typeof times) {
-            if (times < 1) {
-                JSUS.log('times must be greater or equal 1', 'ERR');
-                return;
-            }
-            times = ARRAY.rep([times], array.length);
-        }
-
-        result = [];
-        for (i = 0; i < array.length; i++) {
-            repeat = times[(i % times.length)];
-            for (j = 0; j < repeat ; j++) {
-                result.push(array[i]);
-            }
-        }
-        return result;
-    };
-
-
-
-

- - ARRAY.arrayIntersect -

-
- -
-

Computes the intersection between two arrays

- -

Arrays can contain both primitive types and objects.

-
-
-
Params
-
- a1 - array - The first array -
-
- a2 - array - The second array -
-
Returns
-
- - array - All the values of the first array that are found - also in the second one -
-
-
-
    ARRAY.arrayIntersect = function(a1, a2) {
-        return a1.filter( function(i) {
-            return JSUS.inArray(i, a2);
-        });
-    };
-
-
-
-

- - ARRAY.arrayDiff -

-
- -
-

Performs a diff between two arrays

- -

Arrays can contain both primitive types and objects.

-
-
-
Params
-
- a1 - array - The first array -
-
- a2 - array - The second array -
-
Returns
-
- - array - All the values of the first array that are not - found in the second one -
-
-
-
    ARRAY.arrayDiff = function(a1, a2) {
-        return a1.filter( function(i) {
-            return !(JSUS.inArray(i, a2));
-        });
-    };
-
-
-
-

- - ARRAY.shuffle -

-
- -
-

Shuffles the elements of the array using the Fischer algorithm

- -

The original array is not modified, and a copy is returned.

-
-
-
Params
-
- shuffle - array - The array to shuffle -
-
Returns
-
- - array - copy The shuffled array -
-
See
- -
-
-
    ARRAY.shuffle = function(array) {
-        var copy, len, j, tmp, i;
-        if (!array) return;
-        copy = Array.prototype.slice.call(array);
-        len = array.length-1; // ! -1
-        for (i = len; i > 0; i--) {
-            j = Math.floor(Math.random()*(i+1));
-            tmp = copy[j];
-            copy[j] = copy[i];
-            copy[i] = tmp;
-        }
-        return copy;
-    };
-
-
-
-

- - ARRAY.getNRandom -

-
- -
-

Select N random elements from the array and returns them

-
-
-
Params
-
- array - array - The array from which extracts random elements -
-
Returns
-
- - array - An new array with N elements randomly chosen -
-
-
-
    ARRAY.getNRandom = function(array, N) {
-        return ARRAY.shuffle(array).slice(0,N);
-    };
-
-
-
-

- - ARRAY.distinct -

-
- -
-

Removes all duplicates entries from an array and returns a copy of it

- -

Does not modify original array.

- -

Comparison is done with JSUS.equals.

-
-
-
Params
-
- array - array - The array from which eliminates duplicates -
-
Returns
-
- - array - A copy of the array without duplicates -
-
See
-
- JSUS.equals - -
-
-
-
    ARRAY.distinct = function(array) {
-        var out = [];
-        if (!array) return out;
-
-        ARRAY.each(array, function(e) {
-            if (!ARRAY.inArray(e, out)) {
-                out.push(e);
-            }
-        });
-        return out;
-    };
-
-
-
-

- - ARRAY.transpose -

-
- -
-

Transposes a given 2D array.

- -

The original array is not modified, and a new copy is -returned.

-
-
-
Params
-
- array - array - The array to transpose -
-
Returns
-
- - array - The Transposed Array -
-
-
-
    ARRAY.transpose = function(array) {
-        if (!array) return;
-
-
- -
-

Calculate width and height

-
        var w, h, i, j, t = [];
-        w = array.length || 0;
-        h = (ARRAY.isArray(array[0])) ? array[0].length : 0;
-        if (w === 0 || h === 0) return t;
-
-        for ( i = 0; i < h; i++) {
-            t[i] = [];
-            for ( j = 0; j < w; j++) {
-                t[i][j] = array[j][i];
-            }
-        }
-        return t;
-    };
-
-    JSUS.extend(ARRAY);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/compatibility.js.html b/docs/lib/compatibility.js.html deleted file mode 100644 index 14dc39b..0000000 --- a/docs/lib/compatibility.js.html +++ /dev/null @@ -1,130 +0,0 @@ - - - - compatibility.js - - - - - - - - - -
- - - - - - - - - - - -
-
-
-

- - COMPATIBILITY -

-
- -
-

Copyright(c) 2015 Stefano Balietti -MIT Licensed

- -

Tests browsers ECMAScript 5 compatibility

- -

For more information see http://kangax.github.com/es5-compat-table/

-
-
-
(function(JSUS) {
-    "use strict";
-
-    function COMPATIBILITY() {}
-
-
-
-

- - COMPATIBILITY.compatibility -

-
- -
-

Returns a report of the ECS5 features available

- -

Useful when an application routinely performs an operation -depending on a potentially unsupported ECS5 feature.

- -

Transforms multiple try-catch statements in a if-else

-
-
-
Returns
-
- - object - support The compatibility object -
-
-
-
    COMPATIBILITY.compatibility = function() {
-
-        var support = {};
-
-        try {
-            Object.defineProperty({}, "a", {enumerable: false, value: 1});
-            support.defineProperty = true;
-        }
-        catch(e) {
-            support.defineProperty = false;
-        }
-
-        try {
-            eval('({ get x(){ return 1 } }).x === 1');
-            support.setter = true;
-        }
-        catch(err) {
-            support.setter = false;
-        }
-
-        try {
-            var value;
-            eval('({ set x(v){ value = v; } }).x = 1');
-            support.getter = true;
-        }
-        catch(err) {
-            support.getter = false;
-        }
-
-        return support;
-    };
-
-
-    JSUS.extend(COMPATIBILITY);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/dom.js.html b/docs/lib/dom.js.html deleted file mode 100644 index 678fc8d..0000000 --- a/docs/lib/dom.js.html +++ /dev/null @@ -1,3269 +0,0 @@ - - - - dom.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - DOM -

-
- -
-

Copyright(c) 2016 Stefano Balietti -MIT Licensed

- -

Collection of static functions related to DOM manipulation

- -

Helper library to perform generic operation with DOM elements.

- -

The general syntax is the following: Every HTML element has associated -a get* and a add* method, whose syntax is very similar.

- -
    -
  • The get* method creates the element and returns it.
  • -
  • The add* method creates the element, append it as child to a root element, -and then returns it.
  • -
- -

The syntax of both method is the same, but the add* method -needs the root element as first parameter. E.g.

- -
    -
  • getButton(id, text, attributes);
  • -
  • addButton(root, id, text, attributes);
  • -
- -

The last parameter is generally an object containing a list of -of key-values pairs as additional attributes to set to the element.

- -

Only the methods which do not follow the above-mentioned syntax -will receive further explanation.

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    var onFocusChange, changeTitle;
-
-    function DOM() {}
-
-
-

- - GENERAL -

-
- -
-
-
-
-

- - DOM.write -

-
- -
-

Write a text, or append an HTML element or node, into a root element

-
-
-
Params
-
- root - Element - The HTML element where to write into -
-
- text - mixed - The text to write. Default, an ampty string -
-
Returns
-
- - TextNode - The text node inserted in the root element -
-
See
-
- DOM.writeln - -
-
-
-
    DOM.write = function(root, text) {
-        var content;
-        if ('undefined' === typeof text || text === null) text = "";
-        if (JSUS.isNode(text) || JSUS.isElement(text)) content = text;
-        else content = document.createTextNode(text);
-        root.appendChild(content);
-        return content;
-    };
-
-
-
-

- - DOM.writeln -

-
- -
-

Write a text and a break into a root element

- -

Default break element is
tag

-
-
-
Params
-
- root - Element - The HTML element where to write into -
-
- text - mixed - The text to write. Default, an ampty string -
-
- rc - string - the name of the tag to use as a break element -
-
Returns
-
- - TextNode - The text node inserted in the root element -
-
See
-
- DOM.write -
-
See
-
- DOM.addBreak - -
-
-
-
    DOM.writeln = function(root, text, rc) {
-        var content;
-        content = DOM.write(root, text);
-        this.addBreak(root, rc);
-        return content;
-    };
-
-
-
-

- - DOM.sprintf -

-
- -
-

Builds up a decorated HTML text element

- -

Performs string substitution from an args object where the first -character of the key bears the following semantic:

- -
    -
  • '@': variable substitution with escaping
  • -
  • '!': variable substitution without variable escaping
  • -
  • '%': wraps a portion of string into a span element to which is - possible to associate a css class or id. Alternatively, - it also possible to add in-line style. E.g.:
  • -
- - -
     sprintf('%sImportant!%s An error has occurred: %pre@err%pre', {
-             '%pre': {
-                     style: 'font-size: 12px; font-family: courier;'
-             },
-             '%s': {
-                     id: 'myId',
-                     'class': 'myClass',
-             },
-             '@err': 'file not found',
-     }, document.body);
-
- - - -

Special span elements are %strong and %em, which add -respectively a strong and em tag instead of the default -span tag. They cannot be styled.

-
-
-
Params
-
- string - string - A text to transform -
-
- args - object - Optional. An object containing string - transformations -
-
- root - Element - Optional. An HTML element to which append the - string. Defaults, a new span element -
-
Returns
-
- - Element - The root element. -
-
-
-
    DOM.sprintf = function(string, args, root) {
-
-        var text, span, idx_start, idx_finish, idx_replace, idxs;
-        var spans, key, i;
-
-        root = root || document.createElement('span');
-        spans = {};
-
-
- -
-

Create an args object, if none is provided. -Defaults %em and %strong are added.

-
        args = args || {};
-        args['%strong'] = '';
-        args['%em'] = '';
-
-
- -
-

Transform arguments before inserting them.

-
        for (key in args) {
-            if (args.hasOwnProperty(key)) {
-
-                switch(key.charAt(0)) {
-
-                case '%': // Span/Strong/Emph .
-
-                    idx_start = string.indexOf(key);
-
-
- -
-

Pattern not found. No error.

-
                    if (idx_start === -1) continue;
-
-                    idx_replace = idx_start + key.length;
-                    idx_finish = string.indexOf(key, idx_replace);
-
-                    if (idx_finish === -1) {
-                        JSUS.log('Error. Could not find closing key: ' + key);
-                        continue;
-                    }
-
-
- -
-

Can be strong, emph or a generic span.

-
                    spans[idx_start] = key;
-
-                    break;
-
-                case '@': // Replace and sanitize.
-                    string = string.replace(key, escape(args[key]));
-                    break;
-
-                case '!': // Replace and not sanitize.
-                    string = string.replace(key, args[key]);
-                    break;
-
-                default:
-                    JSUS.log('Identifier not in [!,@,%]: ' + key[0]);
-
-                }
-            }
-        }
-
-
- -
-

No span to create, return what we have.

-
        if (!JSUS.size(spans)) {
-            return root.appendChild(document.createTextNode(string));
-        }
-
-
- -
-

Re-assamble the string.

-
        idxs = JSUS.keys(spans).sort(function(a, b){ return a - b; });
-        idx_finish = 0;
-        for (i = 0; i < idxs.length; i++) {
-
-
- -
-

Add span.

-
            key = spans[idxs[i]];
-            idx_start = string.indexOf(key);
-
-
- -
-

Add fragments of string.

-
            if (idx_finish !== idx_start-1) {
-                root.appendChild(document.createTextNode(
-                    string.substring(idx_finish, idx_start)));
-            }
-
-            idx_replace = idx_start + key.length;
-            idx_finish = string.indexOf(key, idx_replace);
-
-            if (key === '%strong') {
-                span = document.createElement('strong');
-            }
-            else if (key === '%em') {
-                span = document.createElement('em');
-            }
-            else {
-                span = JSUS.getElement('span', null, args[key]);
-            }
-
-            text = string.substring(idx_replace, idx_finish);
-
-            span.appendChild(document.createTextNode(text));
-
-            root.appendChild(span);
-            idx_finish = idx_finish + key.length;
-        }
-
-
- -
-

Add the final part of the string.

-
        if (idx_finish !== string.length) {
-            root.appendChild(document.createTextNode(
-                string.substring(idx_finish)));
-        }
-
-        return root;
-    };
-
-
-
-

- - DOM.isNode -

-
- -
-

Returns TRUE if the object is a DOM node

-
-
-
Params
-
- The - mixed - variable to check -
-
Returns
-
- - boolean - TRUE, if the the object is a DOM node -
-
-
-
    DOM.isNode = function(o) {
-        if (!o || 'object' !== typeof o) return false;
-        return 'object' === typeof Node ? o instanceof Node :
-            'number' === typeof o.nodeType &&
-            'string' === typeof o.nodeName;
-    };
-
-
-
-

- - DOM.isElement -

-
- -
-

Returns TRUE if the object is a DOM element

- -

Notice: instanceof HTMLElement is not reliable in Safari, even if -the method is defined.

-
-
-
Params
-
- The - mixed - variable to check -
-
Returns
-
- - boolean - TRUE, if the the object is a DOM element -
-
-
-
    DOM.isElement = function(o) {
-        return o && 'object' === typeof o && o.nodeType === 1 &&
-            'string' === typeof o.nodeName;
-    };
-
-
-
-

- - DOM.shuffleElements -

-
- -
-

Shuffles the order of children of a parent Element

- -

All children must have the id attribute (live list elements cannot -be identified by position).

- -

Notice the difference between Elements and Nodes:

- -

http://stackoverflow.com/questions/7935689/ -what-is-the-difference-between-children-and-childnodes-in-javascript

-
-
-
Params
-
- parent - Node - The parent node -
-
- order - array - Optional. A pre-specified order. Defaults, random -
-
Returns
-
- - array - The order used to shuffle the nodes -
-
-
-
    DOM.shuffleElements = function(parent, order) {
-        var i, len, idOrder, children, child;
-        var id, forceId, missId;
-        if (!JSUS.isNode(parent)) {
-            throw new TypeError('DOM.shuffleElements: parent must be a node. ' +
-                               'Found: ' + parent);
-        }
-        if (!parent.children || !parent.children.length) {
-            JSUS.log('DOM.shuffleElements: parent has no children.', 'ERR');
-            return false;
-        }
-        if (order) {
-            if (!JSUS.isArray(order)) {
-                throw new TypeError('DOM.shuffleElements: order must array.' +
-                                   'Found: ' + order);
-            }
-            if (order.length !== parent.children.length) {
-                throw new Error('DOM.shuffleElements: order length must ' +
-                                'match the number of children nodes.');
-            }
-        }
-
-
- -
-

DOM4 compliant browsers.

-
        children = parent.children;
-
-
- -
-

https://developer.mozilla.org/en/DOM/Element.children -[IE lt 9] IE < 9

-
        if ('undefined' === typeof children) {
-            child = this.firstChild;
-            while (child) {
-                if (child.nodeType == 1) children.push(child);
-                child = child.nextSibling;
-            }
-        }
-
-        len = children.length;
-        idOrder = new Array(len);
-        if (!order) order = JSUS.sample(0, (len-1));
-        for (i = 0 ; i < len; i++) {
-            id = children[order[i]].id;
-            if ('string' !== typeof id || id === "") {
-                throw new Error('DOM.shuffleElements: no id found on ' +
-                                'child n. ' + order[i] + '.');
-            }
-            idOrder[i] = id;
-        }
-
-
- -
-

Two fors are necessary to follow the real sequence (Live List). -However, parent.children is a special object, so the sequence -could be unreliable.

-
        for (i = 0 ; i < len; i++) {
-            parent.appendChild(children[idOrder[i]]);
-        }
-        return idOrder;
-    };
-
-
-
-

- - DOM.shuffleNodes -

-
- -
-

It actually shuffles Elements.

-
-
-
-
-
    DOM.shuffleNodes = function(parent, order) {
-        console.log('***DOM.shuffleNodes is deprecated. ' +
-                    'Use Dom.shuffleElements instead.***');
-        return DOM.shuffleElements(parent, order);
-    };
-
-
-
-

- - DOM.getElement -

-
- -
-

Creates a generic HTML element with id and attributes as specified

-
-
-
Params
-
- elem - string - The name of the tag -
-
- id - string - Optional. The id of the tag -
-
- attributes - object - Optional. Object containing attributes for - the newly created element -
-
Returns
-
- - HTMLElement - The newly created HTML element -
-
See
-
- DOM.addAttributes2Elem - -
-
-
-
    DOM.getElement = function(elem, id, attributes) {
-        var e = document.createElement(elem);
-        if ('undefined' !== typeof id) {
-            e.id = id;
-        }
-        return this.addAttributes2Elem(e, attributes);
-    };
-
-
-
-

- - DOM.addElement -

-
- -
-

Creates and appends a generic HTML element with specified attributes

-
-
-
Params
-
- elem - string - The name of the tag -
-
- root - HTMLElement - The root element to which the new element will - be appended -
-
- id - string - Optional. The id of the tag -
-
- attributes - object - Optional. Object containing attributes for - the newly created element -
-
Returns
-
- - HTMLElement - The newly created HTML element -
-
See
-
- DOM.getElement -
-
See
-
- DOM.addAttributes2Elem - -
-
-
-
    DOM.addElement = function(elem, root, id, attributes) {
-        var el = this.getElement(elem, id, attributes);
-        return root.appendChild(el);
-    };
-
-
-
-

- - DOM.addAttributes2Elem -

-
- -
-

Adds attributes to an HTML element and returns it.

- -

Attributes are defined as key-values pairs. -Attributes 'label' is ignored, attribute 'className' ('class') and -'style' are special and are delegated to special methods.

-
-
-
Params
-
- e - HTMLElement - The element to decorate -
-
- a - object - Object containing attributes to add to the element -
-
Returns
-
- - HTMLElement - The decorated element -
-
See
-
- DOM.addLabel -
-
See
-
- DOM.addClass -
-
See
-
- DOM.style - -
-
-
-
    DOM.addAttributes2Elem = function(e, a) {
-        var key;
-        if (!e || !a) return e;
-        if ('object' != typeof a) return e;
-        for (key in a) {
-            if (a.hasOwnProperty(key)) {
-                if (key === 'id') {
-                    e.id = a[key];
-                }
-                else if (key === 'class' || key === 'className') {
-                    DOM.addClass(e, a[key]);
-                }
-                else if (key === 'style') {
-                    DOM.style(e, a[key]);
-                }
-                else if (key === 'label') {
-
-
- -
-

Handle the case.

-
                    JSUS.log('DOM.addAttributes2Elem: label attribute is not ' +
-                             'supported. Use DOM.addLabel instead.');
-                }
-                else {
-                    e.setAttribute(key, a[key]);
-                }
-
-
- -
-TODO: handle special cases - -
            }
-        }
-        return e;
-    };
-
-
-
-

- - DOM.populateSelect -

-
- -
-

Appends a list of options into a HTML select element. -The second parameter list is an object containing -a list of key-values pairs as text-value attributes for -the option.

-
-
-
Params
-
- select - HTMLElement - HTML select element -
-
- list - object - Options to add to the select element -
-
-
-
    DOM.populateSelect = function(select, list) {
-        var key, opt;
-        if (!select || !list) return;
-        for (key in list) {
-            if (list.hasOwnProperty(key)) {
-                opt = document.createElement('option');
-                opt.value = list[key];
-                opt.appendChild(document.createTextNode(key));
-                select.appendChild(opt);
-            }
-        }
-    };
-
-
-
-

- - DOM.removeChildrenFromNode -

-
- -
-

Removes all children from a node.

-
-
-
Params
-
- e - HTMLElement - HTML element. -
-
-
-
    DOM.removeChildrenFromNode = function(e) {
-        while (e.hasChildNodes()) {
-            e.removeChild(e.firstChild);
-        }
-    };
-
-
-
-

- - DOM.insertAfter -

-
- -
-

Insert a node element after another one.

- -

The first parameter is the node to add.

-
-
-
    DOM.insertAfter = function(node, referenceNode) {
-        referenceNode.insertBefore(node, referenceNode.nextSibling);
-    };
-
-
-
-

- - DOM.generateUniqueId -

-
- -
-

Generate a unique id for the page (frames included).

- -

TODO: now it always create big random strings, it does not actually -check if the string exists.

-
-
-
    DOM.generateUniqueId = function(prefix) {
-        var search = [window];
-        if (window.frames) {
-            search = search.concat(window.frames);
-        }
-
-        function scanDocuments(id) {
-            var found = true;
-            while (found) {
-                for (var i=0; i < search.length; i++) {
-                    found = search[i].document.getElementById(id);
-                    if (found) {
-                        id = '' + id + '_' + JSUS.randomInt(0, 1000);
-                        break;
-                    }
-                }
-            }
-            return id;
-        }
-
-
-        return scanDocuments(prefix + '_' + JSUS.randomInt(0, 10000000));
-
-
- -
-

return scanDocuments(prefix);

-
    };
-
-
-

- - GET/ADD -

-
- -
-
-
-
-

- - DOM.getButton -

-
- -
-
-
-
-
    DOM.getButton = function(id, text, attributes) {
-        var sb;
-        sb = document.createElement('button');
-        if ('undefined' !== typeof id) sb.id = id;
-        sb.appendChild(document.createTextNode(text || 'Send'));
-        return this.addAttributes2Elem(sb, attributes);
-    };
-
-
-
-

- - DOM.addButton -

-
- -
-
-
-
-
    DOM.addButton = function(root, id, text, attributes) {
-        var b = this.getButton(id, text, attributes);
-        return root.appendChild(b);
-    };
-
-
-
-

- - DOM.getFieldset -

-
- -
-
-
-
-
    DOM.getFieldset = function(id, legend, attributes) {
-        var f = this.getElement('fieldset', id, attributes);
-        var l = document.createElement('Legend');
-        l.appendChild(document.createTextNode(legend));
-        f.appendChild(l);
-        return f;
-    };
-
-
-
-

- - DOM.addFieldset -

-
- -
-
-
-
-
    DOM.addFieldset = function(root, id, legend, attributes) {
-        var f = this.getFieldset(id, legend, attributes);
-        return root.appendChild(f);
-    };
-
-
-
-

- - DOM.getTextInput -

-
- -
-
-
-
-
    DOM.getTextInput = function(id, attributes) {
-        var ti =  document.createElement('input');
-        if ('undefined' !== typeof id) ti.id = id;
-        ti.setAttribute('type', 'text');
-        return this.addAttributes2Elem(ti, attributes);
-    };
-
-
-
-

- - DOM.addTextInput -

-
- -
-
-
-
-
    DOM.addTextInput = function(root, id, attributes) {
-        var ti = this.getTextInput(id, attributes);
-        return root.appendChild(ti);
-    };
-
-
-
-

- - DOM.getTextArea -

-
- -
-
-
-
-
    DOM.getTextArea = function(id, attributes) {
-        var ta =  document.createElement('textarea');
-        if ('undefined' !== typeof id) ta.id = id;
-        return this.addAttributes2Elem(ta, attributes);
-    };
-
-
-
-

- - DOM.addTextArea -

-
- -
-
-
-
-
    DOM.addTextArea = function(root, id, attributes) {
-        var ta = this.getTextArea(id, attributes);
-        return root.appendChild(ta);
-    };
-
-
-
-

- - DOM.getCanvas -

-
- -
-
-
-
-
    DOM.getCanvas = function(id, attributes) {
-        var canvas = document.createElement('canvas');
-        var context = canvas.getContext('2d');
-
-        if (!context) {
-            alert('Canvas is not supported');
-            return false;
-        }
-
-        canvas.id = id;
-        return this.addAttributes2Elem(canvas, attributes);
-    };
-
-
-
-

- - DOM.addCanvas -

-
- -
-
-
-
-
    DOM.addCanvas = function(root, id, attributes) {
-        var c = this.getCanvas(id, attributes);
-        return root.appendChild(c);
-    };
-
-
-
-

- - DOM.getSlider -

-
- -
-
-
-
-
    DOM.getSlider = function(id, attributes) {
-        var slider = document.createElement('input');
-        slider.id = id;
-        slider.setAttribute('type', 'range');
-        return this.addAttributes2Elem(slider, attributes);
-    };
-
-
-
-

- - DOM.addSlider -

-
- -
-
-
-
-
    DOM.addSlider = function(root, id, attributes) {
-        var s = this.getSlider(id, attributes);
-        return root.appendChild(s);
-    };
-
-
-
-

- - DOM.getRadioButton -

-
- -
-
-
-
-
    DOM.getRadioButton = function(id, attributes) {
-        var radio = document.createElement('input');
-        radio.id = id;
-        radio.setAttribute('type', 'radio');
-        return this.addAttributes2Elem(radio, attributes);
-    };
-
-
-
-

- - DOM.addRadioButton -

-
- -
-
-
-
-
    DOM.addRadioButton = function(root, id, attributes) {
-        var rb = this.getRadioButton(id, attributes);
-        return root.appendChild(rb);
-    };
-
-
-
-

- - DOM.getLabel -

-
- -
-
-
-
-
    DOM.getLabel = function(forElem, id, labelText, attributes) {
-        if (!forElem) return false;
-        var label = document.createElement('label');
-        label.id = id;
-        label.appendChild(document.createTextNode(labelText));
-
-        if ('undefined' === typeof forElem.id) {
-            forElem.id = this.generateUniqueId();
-        }
-
-        label.setAttribute('for', forElem.id);
-        this.addAttributes2Elem(label, attributes);
-        return label;
-    };
-
-
-
-

- - DOM.addLabel -

-
- -
-
-
-
-
    DOM.addLabel = function(root, forElem, id, labelText, attributes) {
-        if (!root || !forElem || !labelText) return false;
-        var l = this.getLabel(forElem, id, labelText, attributes);
-        root.insertBefore(l, forElem);
-        return l;
-    };
-
-
-
-

- - DOM.getSelect -

-
- -
-
-
-
-
    DOM.getSelect = function(id, attributes) {
-        return this.getElement('select', id, attributes);
-    };
-
-
-
-

- - DOM.addSelect -

-
- -
-
-
-
-
    DOM.addSelect = function(root, id, attributes) {
-        return this.addElement('select', root, id, attributes);
-    };
-
-
-
-

- - DOM.getIFrame -

-
- -
-
-
-
-
    DOM.getIFrame = function(id, attributes) {
-        attributes = attributes || {};
-        if (!attributes.name) {
-            attributes.name = id; // For Firefox
-        }
-        return this.getElement('iframe', id, attributes);
-    };
-
-
-
-

- - DOM.addIFrame -

-
- -
-
-
-
-
    DOM.addIFrame = function(root, id, attributes) {
-        var ifr = this.getIFrame(id, attributes);
-        return root.appendChild(ifr);
-    };
-
-
-
-

- - DOM.addBreak -

-
- -
-
-
-
-
    DOM.addBreak = function(root, rc) {
-        var RC = rc || 'br';
-        var br = document.createElement(RC);
-        return root.appendChild(br);
-
-
- -
-

return this.insertAfter(br,root);

-
    };
-
-
-
-

- - DOM.getDiv -

-
- -
-
-
-
-
    DOM.getDiv = function(id, attributes) {
-        return this.getElement('div', id, attributes);
-    };
-
-
-
-

- - DOM.addDiv -

-
- -
-
-
-
-
    DOM.addDiv = function(root, id, attributes) {
-        return this.addElement('div', root, id, attributes);
-    };
-
-
-

- - CSS / JS -

-
- -
-
-
-
-

- - DOM.addCSS -

-
- -
-

If no root element is passed, it tries to add the CSS -link element to document.head, document.body, and -finally document. If it fails, returns FALSE.

-
-
-
    DOM.addCSS = function(root, css, id, attributes) {
-        root = root || document.head || document.body || document;
-        if (!root) return false;
-
-        attributes = attributes || {};
-
-        attributes = JSUS.merge(attributes, {rel : 'stylesheet',
-                                             type: 'text/css',
-                                             href: css
-                                            });
-
-        return this.addElement('link', root, id, attributes);
-    };
-
-
-
-

- - DOM.addJS -

-
- -
-
-
-
-
    DOM.addJS = function(root, js, id, attributes) {
-        root = root || document.head || document.body || document;
-        if (!root) return false;
-
-        attributes = attributes || {};
-
-        attributes = JSUS.merge(attributes, {charset : 'utf-8',
-                                             type: 'text/javascript',
-                                             src: js
-                                            });
-
-        return this.addElement('script', root, id, attributes);
-    };
-
-
-
-

- - DOM.highlight -

-
- -
-

Provides a simple way to highlight an HTML element -by adding a colored border around it.

- -

Three pre-defined modes are implemented:

- -
    -
  • OK: green
  • -
  • WARN: yellow
  • -
  • ERR: red (default)
  • -
- -

Alternatively, it is possible to specify a custom -color as HEX value. Examples:

- - -
highlight(myDiv, 'WARN'); // yellow border
-highlight(myDiv);          // red border
-highlight(myDiv, '#CCC'); // grey border
-
- - -
-
-
Params
-
- elem - HTMLElement - The element to highlight -
-
- code - string - The type of highlight -
-
See
-
- DOM.addBorder -
-
See
-
- DOM.style - -
-
-
-
    DOM.highlight = function(elem, code) {
-        var color;
-        if (!elem) return;
-
-
- -
-

default value is ERR

-
        switch (code) {
-        case 'OK':
-            color =  'green';
-            break;
-        case 'WARN':
-            color = 'yellow';
-            break;
-        case 'ERR':
-            color = 'red';
-            break;
-        default:
-            if (code.charAt(0) === '#') {
-                color = code;
-            }
-            else {
-                color = 'red';
-            }
-        }
-
-        return this.addBorder(elem, color);
-    };
-
-
-
-

- - DOM.addBorder -

-
- -
-

Adds a border around the specified element. Color, -width, and type can be specified.

-
-
-
    DOM.addBorder = function(elem, color, width, type) {
-        var properties;
-        if (!elem) return;
-
-        color = color || 'red';
-        width = width || '5px';
-        type = type || 'solid';
-
-        properties = { border: width + ' ' + type + ' ' + color };
-        return DOM.style(elem, properties);
-    };
-
-
-
-

- - DOM.style -

-
- -
-

Styles an element as an in-line css.

- -

Existing style properties are maintained, and new ones added.

-
-
-
Params
-
- elem - HTMLElement - The element to style -
-
- Objects - object - containing the properties to add. -
-
Returns
-
- - HTMLElement - The styled element -
-
-
-
    DOM.style = function(elem, properties) {
-        var i;
-        if (!elem || !properties) return;
-        if (!DOM.isElement(elem)) return;
-
-        for (i in properties) {
-            if (properties.hasOwnProperty(i)) {
-                elem.style[i] = properties[i];
-            }
-        }
-        return elem;
-    };
-
-
-
-

- - DOM.removeClass -

-
- -
-

Removes a specific class from the classNamex attribute of a given element

-
-
-
Params
-
- el - HTMLElement - An HTML element -
-
- c - string - The name of a CSS class already in the element -
-
Returns
-
- - HTMLElement - undefined - The HTML element with the removed - class, or undefined if the inputs are misspecified -
-
-
-
    DOM.removeClass = function(el, c) {
-        var regexpr, o;
-        if (!el || !c) return;
-        regexpr = new RegExp('(?:^|\\s)' + c + '(?!\\S)');
-        o = el.className = el.className.replace( regexpr, '' );
-        return el;
-    };
-
-
-
-

- - DOM.addClass -

-
- -
-

Adds one or more classes to the className attribute of the given element

- -

Takes care not to overwrite already existing classes.

-
-
-
Params
-
- el - HTMLElement - An HTML element -
-
- c - string - array - The name/s of CSS class/es -
-
Returns
-
- - HTMLElement - undefined - The HTML element with the additional - class, or undefined if the inputs are misspecified -
-
-
-
    DOM.addClass = function(el, c) {
-        if (!el) return;
-        if (c instanceof Array) c = c.join(' ');
-        else if ('string' !== typeof c) return;
-        if (!el.className || el.className === '') el.className = c;
-        else el.className += (' ' + c);
-        return el;
-    };
-
-
-
-

- - DOM.getElementsByClassName -

-
- -
-

Returns an array of elements with requested class name

-
-
-
Params
-
- document - object - The document object of a window or iframe -
-
- className - string - The requested className -
-
- - string - nodeName Optional. If set only elements with - the specified tag name will be searched -
-
Returns
-
- - array - Array of elements with the requested class name -
-
See
- -
See
- -
-
-
    DOM.getElementsByClassName = function(document, className, nodeName) {
-        var result, node, tag, seek, i, rightClass;
-        result = [];
-        tag = nodeName || '*';
-        if (document.evaluate) {
-            seek = '//' + tag +
-                '[contains(concat(" ", normalize-space(@class), " "), "' +
-                className + ' ")]';
-            seek = document.evaluate(seek, document, null, 0, null );
-            while ((node = seek.iterateNext())) {
-                result.push(node);
-            }
-        }
-        else {
-            rightClass = new RegExp( '(^| )'+ className +'( |$)' );
-            seek = document.getElementsByTagName(tag);
-            for (i = 0; i < seek.length; i++)
-                if (rightClass.test((node = seek[i]).className )) {
-                    result.push(seek[i]);
-                }
-        }
-        return result;
-    };
-
-
-

- - IFRAME -

-
- -
-
-
-
-

- - DOM.getIFrameDocument -

-
- -
-

Returns a reference to the document of an iframe object

-
-
-
Params
-
- iframe - HTMLIFrameElement - The iframe object -
-
Returns
-
- - HTMLDocument - null - The document of the iframe, or - null if not found. -
-
-
-
    DOM.getIFrameDocument = function(iframe) {
-        if (!iframe) return null;
-        return iframe.contentDocument ||
-            iframe.contentWindow ? iframe.contentWindow.document : null;
-    };
-
-
-
-

- - DOM.getIFrameAnyChild -

-
- -
-

Gets the first available child of an IFrame

- -

Tries head, body, lastChild and the HTML element

-
-
-
Params
-
- iframe - HTMLIFrameElement - The iframe object -
-
Returns
-
- - HTMLElement - undefined - The child, or undefined if none is found -
-
-
-
    DOM.getIFrameAnyChild = function(iframe) {
-        var contentDocument;
-        if (!iframe) return;
-        contentDocument = W.getIFrameDocument(iframe);
-        return contentDocument.head || contentDocument.body ||
-            contentDocument.lastChild ||
-            contentDocument.getElementsByTagName('html')[0];
-    };
-
-
-

- - RIGHT-CLICK -

-
- -
-
-
-
-

- - DOM.disableRightClick -

-
- -
-

Disables the popup of the context menu by right clicking with the mouse

-
-
-
Params
-
- Optional. - Document - A target document object. Defaults, document -
-
See
-
- DOM.enableRightClick - -
-
-
-
    DOM.disableRightClick = function(doc) {
-        doc = doc || document;
-        if (doc.layers) {
-            doc.captureEvents(Event.MOUSEDOWN);
-            doc.onmousedown = function clickNS4(e) {
-                if (doc.layers || doc.getElementById && !doc.all) {
-                    if (e.which == 2 || e.which == 3) {
-                        return false;
-                    }
-                }
-            };
-        }
-        else if (doc.all && !doc.getElementById) {
-            doc.onmousedown = function clickIE4() {
-                if (event.button == 2) {
-                    return false;
-                }
-            };
-        }
-        doc.oncontextmenu = new Function("return false");
-    };
-
-
-
-

- - DOM.enableRightClick -

-
- -
-

Enables the popup of the context menu by right clicking with the mouse

- -

It unregisters the event handlers created by DOM.disableRightClick

-
-
-
Params
-
- Optional. - Document - A target document object. Defaults, document -
-
See
-
- DOM.disableRightClick - -
-
-
-
    DOM.enableRightClick = function(doc) {
-        doc = doc || document;
-        if (doc.layers) {
-            doc.releaseEvents(Event.MOUSEDOWN);
-            doc.onmousedown = null;
-        }
-        else if (doc.all && !doc.getElementById) {
-            doc.onmousedown = null;
-        }
-        doc.oncontextmenu = null;
-    };
-
-
-
-

- - DOM.addEvent -

-
- -
-

Adds an event listener to an element (cross-browser)

-
-
-
Params
-
- element - Element - A target element -
-
- event - string - The name of the event to handle -
-
- func - function - The event listener -
-
- Optional. - boolean - If TRUE, the event will initiate a capture. - Available only in some browsers. Default, FALSE -
-
Returns
-
- - boolean - TRUE, on success. However, the return value is - browser dependent. -
-
See
- -
-
-
    DOM.addEvent = function(element, event, func, capture) {
-        capture = !!capture;
-        if (element.attachEvent) return element.attachEvent('on' + event, func);
-        else return element.addEventListener(event, func, capture);
-    };
-
-
-
-

- - DOM.removeEvent -

-
- -
-

Removes an event listener from an element (cross-browser)

-
-
-
Params
-
- element - Element - A target element -
-
- event - string - The name of the event to remove -
-
- func - function - The event listener -
-
- Optional. - boolean - If TRUE, the event was registered - as a capture. Available only in some browsers. Default, FALSE -
-
Returns
-
- - boolean - TRUE, on success. However, the return value is - browser dependent. -
-
See
-
- DOM.addEvent - -
-
-
-
    DOM.removeEvent = function(element, event, func, capture) {
-        capture = !!capture;
-        if (element.detachEvent) return element.detachEvent('on' + event, func);
-        else return element.removeEventListener(event, func, capture);
-    };
-
-
-
-

- - DOM.disableBackButton -

-
- -
-

Disables/re-enables backward navigation in history of browsed pages

- -

When disabling, it inserts twice the current url.

- -

It will still be possible to manually select the uri in the -history pane and nagivate to it.

-
-
-
Params
-
- disable - boolean - Optional. If TRUE disables back button, - if FALSE, re-enables it. Default: TRUE. -
-
Returns
-
- - boolean - The state of the back button (TRUE = disabled), - or NULL if the method is not supported by browser. -
-
-
-
    DOM.disableBackButton = (function(isDisabled) {
-        return function(disable) {
-            disable = 'undefined' === typeof disable ? true : disable;
-            if (disable && !isDisabled) {
-                if (!history.pushState || !history.go) {
-                    node.warn('DOM.disableBackButton: method not ' +
-                              'supported by browser.');
-                    return null;
-                }
-                history.pushState(null, null, location.href);
-                window.onpopstate = function(event) {
-                    history.go(1);
-                };
-            }
-            else if (isDisabled) {
-                window.onpopstate = null;
-            }
-            isDisabled = disable;
-            return disable;
-        };
-    })(false);
-
-
-
-

- - DOM.playSound -

-
- -
-

Plays a sound

-
-
-
Params
-
- sound - various - Audio tag or path to audio file to be played -
-
-
-
    DOM.playSound = 'undefined' === typeof Audio ?
-        function() {
-            console.log('JSUS.playSound: Audio tag not supported in your' +
-                    ' browser. Cannot play sound.');
-        } :
-        function(sound) {
-        var audio;
-        if ('string' === typeof sound) {
-            audio = new Audio(sound);
-        }
-        else if ('object' === typeof sound &&
-            'function' === typeof sound.play) {
-            audio = sound;
-        }
-        else {
-            throw new TypeError('JSUS.playSound: sound must be string' +
-               ' or audio element.');
-        }
-        audio.play();
-    };
-
-
-
-

- - DOM.onFocusIn -

-
- -
-

Registers a callback to be executed when the page acquires focus

-
-
-
Params
-
- cb - function - null - Callback executed if page acquires focus, - or NULL, to delete an existing callback. -
-
- ctx - object - function - Optional. Context of execution for cb -
-
See
-
- onFocusChange - -
-
-
-
    DOM.onFocusIn = function(cb, ctx) {
-        var origCb;
-        if ('function' !== typeof cb && null !== cb) {
-            throw new TypeError('JSUS.onFocusIn: cb must be function or null.');
-        }
-        if (ctx) {
-            if ('object' !== typeof ctx && 'function' !== typeof ctx) {
-                throw new TypeError('JSUS.onFocusIn: ctx must be object, ' +
-                                    'function or undefined.');
-            }
-            origCb = cb;
-            cb = function() { origCb.call(ctx); };
-        }
-
-        onFocusChange(cb);
-    };
-
-
-
-

- - DOM.onFocusOut -

-
- -
-

Registers a callback to be executed when the page loses focus

-
-
-
Params
-
- cb - function - Callback executed if page loses focus, - or NULL, to delete an existing callback. -
-
- ctx - object - function - Optional. Context of execution for cb -
-
See
-
- onFocusChange - -
-
-
-
    DOM.onFocusOut = function(cb, ctx) {
-        var origCb;
-        if ('function' !== typeof cb && null !== cb) {
-            throw new TypeError('JSUS.onFocusOut: cb must be ' +
-                                'function or null.');
-        }
-        if (ctx) {
-            if ('object' !== typeof ctx && 'function' !== typeof ctx) {
-                throw new TypeError('JSUS.onFocusIn: ctx must be object, ' +
-                                    'function or undefined.');
-            }
-            origCb = cb;
-            cb = function() { origCb.call(ctx); };
-        }
-        onFocusChange(undefined, cb);
-    };
-
-
-
-

- - DOM.blinkTitle -

-
- -
-

Changes the title of the page in regular intervals

- -

Calling the function without any arguments stops the blinking -If an array of strings is provided, that array will be cycled through. -If a signle string is provided, the title will alternate between '!!!' - and that string.

-
-
-
Params
-
- titles - mixed - New title to blink -
-
- options - object - Optional. Configuration object. - Accepted values and default in parenthesis: - - -
- stopOnFocus (false): Stop blinking if user switched to tab
-- stopOnClick (false): Stop blinking if user clicks on the
-    specified element
-- finalTitle (document.title): Title to set after blinking is done
-- repeatFor (undefined): Show each element in titles at most
-    N times -- might be stopped earlier by other events.
-- startOnBlur(false): Start blinking if user switches
-     away from tab
-- period (1000) How much time between two blinking texts in the title
-
- -
-
-
Returns
-
- - function - null - A function to clear the blinking of texts, - or NULL, if the interval was not created yet (e.g. with startOnBlur - option), or just destroyed. -
-
-
-
    DOM.blinkTitle = (function(id) {
-        var clearBlinkInterval, finalTitle, elem;
-        clearBlinkInterval = function(opts) {
-            clearInterval(id);
-            id = null;
-            if (elem) {
-                elem.removeEventListener('click', clearBlinkInterval);
-                elem = null;
-            }
-            if (finalTitle) {
-                document.title = finalTitle;
-                finalTitle = null;
-            }
-        };
-        return function(titles, options) {
-            var period, where, rotation;
-            var rotationId, nRepeats;
-
-            if (null !== id) clearBlinkInterval();
-            if ('undefined' === typeof titles) return null;
-
-            where = 'JSUS.blinkTitle: ';
-            options = options || {};
-
-
- -
-

Option finalTitle.

-
            if ('undefined' === typeof options.finalTitle) {
-                finalTitle = document.title;
-            }
-            else if ('string' === typeof options.finalTitle) {
-                finalTitle = options.finalTitle;
-            }
-            else {
-                throw new TypeError(where + 'options.finalTitle must be ' +
-                                    'string or undefined. Found: ' +
-                                    options.finalTitle);
-            }
-
-
- -
-

Option repeatFor.

-
            if ('undefined' !== typeof options.repeatFor) {
-                nRepeats = JSUS.isInt(options.repeatFor, 0);
-                if (false === nRepeats) {
-                    throw new TypeError(where + 'options.repeatFor must be ' +
-                                        'a positive integer. Found: ' +
-                                        options.repeatFor);
-                }
-            }
-
-
- -
-

Option stopOnFocus.

-
            if (options.stopOnFocus) {
-                JSUS.onFocusIn(function() {
-                    clearBlinkInterval();
-                    onFocusChange(null, null);
-                });
-            }
-
-
- -
-

Option stopOnClick.

-
            if ('undefined' !== typeof options.stopOnClick) {
-                if ('object' !== typeof options.stopOnClick ||
-                    !options.stopOnClick.addEventListener) {
-
-                    throw new TypeError(where + 'options.stopOnClick must be ' +
-                                        'an HTML element with method ' +
-                                        'addEventListener. Found: ' +
-                                        options.stopOnClick);
-                }
-                elem = options.stopOnClick;
-                elem.addEventListener('click', clearBlinkInterval);
-            }
-
-
- -
-

Option startOnBlur.

-
            if (options.startOnBlur) {
-                options.startOnBlur = null;
-                JSUS.onFocusOut(function() {
-                    JSUS.blinkTitle(titles, options);
-                });
-                return null;
-            }
-
-
- -
-

Prepare the rotation.

-
            if ('string' === typeof titles) {
-                titles = [titles, '!!!'];
-            }
-            else if (!JSUS.isArray(titles)) {
-                throw new TypeError(where + 'titles must be string, ' +
-                                    'array of strings or undefined.');
-            }
-            rotationId = 0;
-            period = options.period || 1000;
-
-
- -
-

Function to be executed every period.

-
            rotation = function() {
-                changeTitle(titles[rotationId]);
-                rotationId = (rotationId+1) % titles.length;
-
-
- -
-

Control the number of times it should be cycled through.

-
                if ('number' === typeof nRepeats) {
-                    if (rotationId === 0) {
-                        nRepeats--;
-                        if (nRepeats === 0) clearBlinkInterval();
-                    }
-                }
-            };
-
-
- -
-

Perform first rotation right now.

-
            rotation();
-            id = setInterval(rotation, period);
-
-
- -
-

Return clear function.

-
            return clearBlinkInterval;
-        };
-    })(null);
-
-
-
-

- - DOM.cookieSupport -

-
- -
-

Tests for cookie support

-
-
-
Returns
-
- - boolean - null - The type of support for cookies. Values: - -
    -
  • null: no cookies
  • -
  • false: only session cookies
  • -
  • true: session cookies and persistent cookies (although - the browser might clear them on exit)
  • -
- -Kudos: http://stackoverflow.com/questions/2167310/ - how-to-show-a-message-only-if-cookies-are-disabled-in-browser
-
-
-
-
    DOM.cookieSupport = function() {
-        var c, persist;
-        persist = true;
-        do {
-            c = 'gCStest=' + Math.floor(Math.random()*100000000);
-            document.cookie = persist ? c +
-                ';expires=Tue, 01-Jan-2030 00:00:00 GMT' : c;
-
-            if (document.cookie.indexOf(c) !== -1) {
-                document.cookie= c + ';expires=Sat, 01-Jan-2000 00:00:00 GMT';
-                return persist;
-            }
-        } while (!(persist = !persist));
-
-        return null;
-    };
-
-
-
-

- - DOM.viewportSize -

-
- -
-

Returns the current size of the viewport in pixels

- -

The viewport's size is the actual visible part of the browser's -window. This excludes, for example, the area occupied by the -JavaScript console.

-
-
-
Params
-
- dim - string - Optional. Controls the return value ('x', or 'y') -
-
Returns
-
- - object - number - An object containing x and y property, or - number specifying the value for x or y - -Kudos: http://stackoverflow.com/questions/3437786/ - get-the-size-of-the-screen-current-web-page-and-browser-window -
-
-
-
    DOM.viewportSize = function(dim) {
-        var w, d, e, g, x, y;
-        if (dim && dim !== 'x' && dim !== 'y') {
-            throw new TypeError('DOM.viewportSize: dim must be "x","y" or ' +
-                                'undefined. Found: ' + dim);
-        }
-        w = window;
-        d = document;
-        e = d.documentElement;
-        g = d.getElementsByTagName('body')[0];
-        x = w.innerWidth || e.clientWidth || g.clientWidth,
-        y = w.innerHeight|| e.clientHeight|| g.clientHeight;
-        return !dim ? {x: x, y: y} : dim === 'x' ? x : y;
-    };
-
-
-

- - Helper methods -

-
- -
-
-
-
-

- - onFocusChange -

-
- -
-

Helper function for DOM.onFocusIn and DOM.onFocusOut (cross-browser)

- -

Expects only one callback, either inCb, or outCb.

-
-
-
Params
-
- inCb - function - null - Optional. Executed if page acquires focus, - or NULL, to delete an existing callback. -
-
- outCb - function - null - Optional. Executed if page loses focus, - or NULL, to delete an existing callback. - -Kudos: http://stackoverflow.com/questions/1060008/ - is-there-a-way-to-detect-if-a-browser-window-is-not-currently-active -
-
See
- -
-
-
    onFocusChange = (function(document) {
-        var inFocusCb, outFocusCb, event, hidden, evtMap;
-
-        if (!document) {
-            return function() {
-                JSUS.log('onFocusChange: no document detected.');
-                return;
-            };
-        }
-
-        if ('hidden' in document) {
-            hidden = 'hidden';
-            event = 'visibilitychange';
-        }
-        else if ('mozHidden' in document) {
-            hidden = 'mozHidden';
-            event = 'mozvisibilitychange';
-        }
-        else if ('webkitHidden' in document) {
-            hidden = 'webkitHidden';
-            event = 'webkitvisibilitychange';
-        }
-        else if ('msHidden' in document) {
-            hidden = 'msHidden';
-            event = 'msvisibilitychange';
-        }
-
-        evtMap = {
-            focus: true, focusin: true, pageshow: true,
-            blur: false, focusout: false, pagehide: false
-        };
-
-        function onchange(evt) {
-            var isHidden;
-            evt = evt || window.event;
-
-
- -
-

If event is defined as one from event Map.

-
            if (evt.type in evtMap) isHidden = evtMap[evt.type];
-
-
- -
-

Or use the hidden property.

-
            else isHidden = this[hidden] ? true : false;
-
-
- -
-

Call the callback, if defined.

-
            if (!isHidden) { if (inFocusCb) inFocusCb(); }
-            else { if (outFocusCb) outFocusCb(); }
-        }
-
-        return function(inCb, outCb) {
-            var onchangeCb;
-
-            if ('undefined' !== typeof inCb) inFocusCb = inCb;
-            else outFocusCb = outCb;
-
-            onchangeCb = !inFocusCb && !outFocusCb ? null : onchange;
-
-
- -
-

Visibility standard detected.

-
            if (event) {
-                if (onchangeCb) document.addEventListener(event, onchange);
-                else document.removeEventListener(event, onchange);
-            }
-            else if ('onfocusin' in document) {
-                document.onfocusin = document.onfocusout = onchangeCb;
-            }
-
-
- -
-

All others.

-
            else {
-                window.onpageshow = window.onpagehide
-                    = window.onfocus = window.onblur = onchangeCb;
-            }
-        };
-    })('undefined' !== typeof document ? document : null);
-
-
-
-

- - changeTitle -

-
- -
-

Changes title of page

-
-
-
Params
-
- title - string - New title of the page -
-
-
-
    changeTitle = function(title) {
-        if ('string' === typeof title) {
-            document.title = title;
-        }
-        else {
-            throw new TypeError('JSUS.changeTitle: title must be string. ' +
-                                'Found: ' + title);
-        }
-    };
-
-    JSUS.extend(DOM);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/eval.js.html b/docs/lib/eval.js.html deleted file mode 100644 index a42f6ee..0000000 --- a/docs/lib/eval.js.html +++ /dev/null @@ -1,164 +0,0 @@ - - - - eval.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - EVAL -

-
- - -

Copyright(c) 2015 Stefano Balietti -MIT Licensed

-
-

Evaluation of strings as JavaScript commands

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    function EVAL() {}
-
-
-
-

- - EVAL.eval -

-
- -
-

Cross-browser eval function with context.

- -

If no context is passed a reference, this is used.

- -

In old IEs it will use window.execScript instead.

-
-
-
Params
-
- str - string - The command to executes -
-
- context - object - Optional. Execution context. Defaults, this -
-
Returns
-
- - mixed - The return value of the executed commands -
-
See
-
- eval -
-
See
-
- execScript -
-
See
-
- JSON.parse - -
-
-
-
    EVAL.eval = function(str, context) {
-        var func;
-        if (!str) return;
-        context = context || this;
-
-
- -
-

Eval must be called indirectly -i.e. eval.call is not possible

-
        func = function(str) {
-
-
- -
-

TODO: Filter str.

-
            str = '(' + str + ')';
-            if ('undefined' !== typeof window && window.execScript) {
-
-
- -
-

Notice: execScript doesn’t return anything.

-
                window.execScript('__my_eval__ = ' + str);
-                return __my_eval__;
-            }
-            else {
-                return eval(str);
-            }
-        };
-        return func.call(context, str);
-    };
-
-    JSUS.extend(EVAL);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/fs.js.html b/docs/lib/fs.js.html deleted file mode 100644 index dd6d9c6..0000000 --- a/docs/lib/fs.js.html +++ /dev/null @@ -1,556 +0,0 @@ - - - - fs.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - FS -

-
- - -

Copyright(c) 2016 Stefano Balietti -MIT Licensed

-
-

Collection of static functions related to file system operations

-
- -
-
(function(JSUS) {
-
-    "use strict";
-
-    if (!JSUS.isNodeJS()){
-        JSUS.log('Cannot load JSUS.FS outside of Node.JS.');
-        return false;
-    }
-
-    var resolve = require('resolve'),
-    path = require('path'),
-    fs = require('fs')
-
-
-    function FS() {}
-
-
-
-

- - FS.existsSync -

-
- -
-

Backward-compatible version of fs.existsSync

-
-
-
    FS.existsSync = ('undefined' === typeof fs.existsSync) ?
-        path.existsSync : fs.existsSync;
-
-
-
-

- - FS.resolveModuleDir -

-
- -
-

Resolves the root directory of a module

- -

Npm does not install a dependency if the same module -is available in a parent folder. This method returns -the full path of the root directory of the specified -module as installed by npm.

- -

Trailing slash is added.

-
-
-
Params
-
- module - string - The name of the module -
-
- basedir - string - Optional. The basedir from which to start - searching -
-
Returns
-
- - string - The path of the root directory of the module -
-
See
- -
-
-
    FS.resolveModuleDir = function(module, basedir) {
-        var str, stop;
-        if ('string' !== typeof module) {
-            throw new TypeError('FS.resolveModuleDir: module must be string.');
-        }
-        if (basedir && 'string' !== typeof basedir) {
-            throw new TypeError('FS.resolveModuleDir: basedir must be ' +
-                                'string or undefined.');
-        }
-
-
- -
-

Added this line because it might fail.

-
        if (module === 'JSUS') return path.resolve(__dirname, '..') + '/';
-        str = resolve.sync(module, {basedir: basedir || __dirname});
-        stop = str.indexOf(module) + module.length;
-        return str.substr(0, stop) + '/';
-    };
-
-
-
-

- - FS.deleteIfExists -

-
- -
-

Deletes a file or directory

- -

Returns false if the file does not exist.

-
-
-
Params
-
- file - string - The path to the file or directory -
-
- cb - function - Optional. A callback to execute after successful - file deletion -
-
Returns
-
- - boolean - TRUE, if file is found. An error can still occurs - during async removal -
-
See
-
- FS.cleanDir - -
-
-
-
    FS.deleteIfExists = function(file, cb) {
-        var stats;
-        if (!FS.existsSync(file)) {
-            return false;
-        }
-        stats = fs.lstatSync(file);
-        if (stats.isDirectory()) {
-            fs.rmdir(file, function(err) {
-                if (err) throw err;
-                if (cb) cb();
-            });
-        }
-        else {
-            fs.unlink(file, function(err) {
-                if (err) throw err;
-                if (cb) cb();
-            });
-        }
-        return true;
-    };
-
-
-
-

- - FS.cleanDir -

-
- -
-

Removes all files from a target directory

- -

It is possible to specify an extension as second parameter. -In such case, only file with that extension will be removed. -The '.' (dot) must be included as part of the extension.

-
-
-
Params
-
- dir - string - The directory to clean -
-
- ext - string - Optional. If set, only files with this extension - will be removed -
-
- cb - function - Optional. A callback function to call if - no error is raised -
-
Returns
-
- - boolean - TRUE, if the operation is successful -
-
See
-
- FS.deleteIfExists - -
-
-
-
    FS.cleanDir = function(dir, ext, cb) {
-        var filterFunc;
-        if (!dir) {
-            JSUS.log('You must specify a directory to clean.');
-            return false;
-        }
-        if (ext) {
-            filterFunc = function(file) {
-                return path.extname(file) ===  ext;
-            };
-        }
-        else {
-            filterFunc = function() {
-                return true;
-            };
-        }
-
-        if (dir[dir.length] !== '/') dir = dir + '/';
-
-        fs.readdir(dir, function(err, files) {
-            var asq, mycb;
-            if (err) {
-                JSUS.log(err);
-                return;
-            }
-
-
- -
-

Create async queue if a callback was specified.

-
            if (cb) asq = JSUS.getQueue();
-
-
- -
-

Create a nested callback for the async queue, if necessary.

-
            files.filter(filterFunc).forEach(function(file) {
-                if (cb) {
-                    asq.add(file);
-                    mycb = asq.getRemoveCb(file);
-                }
-                JSUS.deleteIfExists(dir + file, mycb);
-            });
-
-            if (cb) {
-                asq.onReady(cb);
-            }
-        });
-
-        return true;
-    };
-
-
-
-

- - FS.copyFromDir -

-
- -
-

Copies all files from a source directory to a destination -directory.

- -

It is possible to specify an extension as second parameter (e.g. '.js'). -In such case, only file with that extension will be copied.

- -

Warning! If an extension filter is not specified, and if subdirectories -are found, an error will occur.

-
-
-
Params
-
- dirIn - string - The source directory -
-
- dirOut - string - The destination directory -
-
- ext - string - Optional. If set, only files with this extension - will be copied -
-
- cb - function - Optional. A callback function to call if - no error is raised -
-
Returns
-
- - boolean - TRUE, if the operation is successful -
-
See
-
- FS.copyFile - -
-
-
-
    FS.copyFromDir = function(dirIn, dirOut, ext, cb) {
-        var i, dir, dirs, stats;
-        if (!dirIn) {
-            JSUS.log('You must specify a source directory.');
-            return false;
-        }
-        if (!dirOut) {
-            JSUS.log('You must specify a destination directory.');
-            return false;
-        }
-
-        dirOut = path.resolve(dirOut) + '/';
-        dirs = [dirIn, dirOut];
-
-        for (i = 0; i < 2; i++) {
-            dir = dirs[i];
-            if (!FS.existsSync(dir)) {
-                console.log(dir + ' does not exist.');
-                return false;
-            }
-
-            stats = fs.lstatSync(dir);
-            if (!stats.isDirectory()) {
-                console.log(dir + ' is not a directory.');
-                return false;
-            }
-        }
-
-        fs.readdir(dirIn, function(err, files) {
-            var asq, i, mycb;
-            if (err) {
-                JSUS.log(err);
-                throw new Error();
-            }
-
-
- -
-

Create async queue if a callback was specified.

-
            if (cb) asq = JSUS.getQueue();
-            for (i in files) {
-                if (ext && path.extname(files[i]) !== ext) {
-                    continue;
-                }
-
-
- -
-

Create a nested callback for the asq, if necessary.

-
                if (cb) {
-                    asq.add(i);
-                    mycb = asq.getRemoveCb(i);
-                }
-                FS.copyFile(dirIn + files[i], dirOut + files[i], mycb);
-            }
-
-            if (cb) {
-                asq.onReady(cb);
-            }
-        });
-
-        return true;
-    };
-
-
-
-

- - FS.copyFile -

-
- -
-

Copies a file into another path

-
-
-
Params
-
- srcFile - string - The source file -
-
- destFile - string - The destination file -
-
- cb - function - Optional. If set, the callback will be executed - upon success -
-
Returns
-
- - boolean - TRUE, if the operation is successful -
-
-
-
    FS.copyFile = function(srcFile, destFile, cb) {
-        var fdr, fdw;
-        fdr = fs.createReadStream(srcFile);
-        fdw = fs.createWriteStream(destFile);
-        fdr.on('end', function() {
-            if (cb) return cb(null);
-        });
-        return fdr.pipe(fdw);
-    };
-
-    JSUS.extend(FS);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/obj.js.html b/docs/lib/obj.js.html deleted file mode 100644 index 3e78c61..0000000 --- a/docs/lib/obj.js.html +++ /dev/null @@ -1,2433 +0,0 @@ - - - - obj.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - OBJ -

-
- - -

Copyright(c) 2017 Stefano Balietti -MIT Licensed

-
-

Collection of static functions to manipulate JavaScript objects

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    function OBJ() {}
-
-    var compatibility = null;
-
-    if ('undefined' !== typeof JSUS.compatibility) {
-        compatibility = JSUS.compatibility();
-    }
-
-
-
-

- - OBJ.createObj -

-
- -
-

Polyfill for Object.create (when missing)

-
-
-
    OBJ.createObj = (function() {
-
-
- -
-

From MDN Object.create (Polyfill)

-
        if (typeof Object.create !== 'function') {
-
-
- -
-

Production steps of ECMA-262, Edition 5, 15.2.3.5 -Reference: http://es5.github.io/#x15.2.3.5

-
            return (function() {
-
-
- -
-

To save on memory, use a shared constructor

-
                function Temp() {}
-
-
- -
-

make a safe reference to Object.prototype.hasOwnProperty

-
                var hasOwn = Object.prototype.hasOwnProperty;
-
-                return function(O) {
-
-
- -
-
    -
  1. If Type(O) is not Object or Null
  2. -
-
                    if (typeof O != 'object') {
-                        throw new TypeError('Object prototype may only ' +
-                                            'be an Object or null');
-                    }
-
-
- -
-
    -
  1. Let obj be the result of creating a new object as if -by the expression new Object() where Object is the -standard built-in constructor with that name
  2. -
  3. Set the [[Prototype]] internal property of obj to O.
  4. -
-
                    Temp.prototype = O;
-                    var obj = new Temp();
-                    Temp.prototype = null;
-
-
- -
-
    -
  1. If the argument Properties is present and not -undefined, add own properties to obj as if by calling -the standard built-in function Object.defineProperties -with arguments obj and Properties.
  2. -
-
                    if (arguments.length > 1) {
-
-
- -
-

Object.defineProperties does ToObject on -its first argument.

-
                        var Properties = new Object(arguments[1]);
-                        for (var prop in Properties) {
-                            if (hasOwn.call(Properties, prop)) {
-                                obj[prop] = Properties[prop];
-                            }
-                        }
-                    }
-
-
- -
-
    -
  1. Return obj
  2. -
-
                    return obj;
-                };
-            })();
-        }
-        return Object.create;
-    })();
-
-
-
-

- - OBJ.equals -

-
- -
-

Checks for deep equality between two objects, strings or primitive types

- -

All nested properties are checked, and if they differ in at least -one returns FALSE, otherwise TRUE.

- -

Takes care of comparing the following special cases:

- -
    -
  • undefined
  • -
  • null
  • -
  • NaN
  • -
  • Infinity
  • -
  • {}
  • -
  • falsy values
  • -
-
-
-
Params
-
- o1 - object - The first object -
-
- o2 - object - The second object -
-
Returns
-
- - boolean - TRUE if the objects are deeply equal -
-
-
-
    OBJ.equals = function(o1, o2) {
-        var type1, type2, primitives, p;
-        type1 = typeof o1;
-        type2 = typeof o2;
-
-        if (type1 !== type2) return false;
-
-        if ('undefined' === type1 || 'undefined' === type2) {
-            return (o1 === o2);
-        }
-        if (o1 === null || o2 === null) {
-            return (o1 === o2);
-        }
-        if (('number' === type1 && isNaN(o1)) &&
-            ('number' === type2 && isNaN(o2))) {
-            return (isNaN(o1) && isNaN(o2));
-        }
-
-
- -
-

Check whether arguments are not objects

-
        primitives = {number: '', string: '', boolean: ''};
-        if (type1 in primitives) {
-            return o1 === o2;
-        }
-
-        if ('function' === type1) {
-            return o1.toString() === o2.toString();
-        }
-
-        for (p in o1) {
-            if (o1.hasOwnProperty(p)) {
-
-                if ('undefined' === typeof o2[p] &&
-                    'undefined' !== typeof o1[p]) return false;
-
-                if (!o2[p] && o1[p]) return false;
-
-                if ('function' === typeof o1[p]) {
-                    if (o1[p].toString() !== o2[p].toString()) return false;
-                }
-                else
-                    if (!OBJ.equals(o1[p], o2[p])) return false;
-            }
-        }
-
-
- -
-

Check whether o2 has extra properties -TODO: improve, some properties have already been checked!

-
        for (p in o2) {
-            if (o2.hasOwnProperty(p)) {
-                if ('undefined' === typeof o1[p] &&
-                    'undefined' !== typeof o2[p]) return false;
-
-                if (!o1[p] && o2[p]) return false;
-            }
-        }
-
-        return true;
-    };
-
-
-
-

- - OBJ.isEmpty -

-
- -
-

Returns TRUE if an object has no own properties (supports other types)

- -

Map of input-type and return values:

- -
    -
  • undefined: TRUE
  • -
  • null: TRUE
  • -
  • string: TRUE if string === '' or if contains only spaces
  • -
  • number: FALSE if different from 0
  • -
  • function: FALSE
  • -
  • array: TRUE, if it contains zero elements
  • -
  • object: TRUE, if it does not contain own properties
  • -
- -

Notice: for object, it is much faster than Object.keys(o).length === 0, -because it does not pull out all keys. Own properties must be enumerable.

-
-
-
Params
-
- o - mixed - The object (or other type) to check -
-
Returns
-
- - boolean - TRUE, if the object is empty -
-
-
-
    OBJ.isEmpty = function(o) {
-        var key;
-        if (!o) return true;
-        if ('string' === typeof o) return o.trim() === '';
-        if ('number' === typeof o) return false;
-        if ('function' === typeof o) return false;
-        for (key in o) if (o.hasOwnProperty(key)) return false;
-        return true;
-    };
-
-
-
-

- - OBJ.size -

-
- -
-

Counts the number of own properties of an object.

- -

Prototype chain properties are excluded.

-
-
-
Params
-
- obj - object - The object to check -
-
Returns
-
- - number - The number of properties in the object -
-
-
-
    OBJ.size = OBJ.getListSize = function(obj) {
-        var n, key;
-        if (!obj) return 0;
-        if ('number' === typeof obj) return 0;
-        if ('string' === typeof obj) return 0;
-
-        n = 0;
-        for (key in obj) {
-            if (obj.hasOwnProperty(key)) {
-                n++;
-            }
-        }
-        return n;
-    };
-
-
-
-

- - OBJ._obj2Array -

-
- -
-

Explodes an object into an array of keys and values, -according to the specified parameters.

- -

A fixed level of recursion can be set.

-
-
-
API
-
- private - -
Params
-
- obj - object - The object to convert in array -
-
- keyed - boolean - TRUE, if also property names should be included. - Defaults, FALSE -
-
- level - number - Optional. The level of recursion. - Defaults, undefined -
-
Returns
-
- - array - The converted object -
-
-
-
    OBJ._obj2Array = function(obj, keyed, level, cur_level) {
-        var result, key;
-        if ('object' !== typeof obj) return [obj];
-
-        if (level) {
-            cur_level = ('undefined' !== typeof cur_level) ? cur_level : 1;
-            if (cur_level > level) return [obj];
-            cur_level = cur_level + 1;
-        }
-
-        result = [];
-        for (key in obj) {
-            if (obj.hasOwnProperty(key)) {
-                if (keyed) result.push(key);
-                if ('object' === typeof obj[key]) {
-                    result = result.concat(OBJ._obj2Array(obj[key], keyed,
-                                                          level, cur_level));
-                }
-                else {
-                    result.push(obj[key]);
-                }
-            }
-        }
-        return result;
-    };
-
-
-
-

- - OBJ.obj2Array -

-
- -
-

Converts an object into an array, keys are lost

- -

Recursively put the values of the properties of an object into -an array and returns it.

- -

The level of recursion can be set with the parameter level. -By default recursion has no limit, i.e. that the whole object -gets totally unfolded into an array.

-
-
-
Params
-
- obj - object - The object to convert in array -
-
- level - number - Optional. The level of recursion. Defaults, - undefined -
-
Returns
-
- - array - The converted object -
-
See
-
- OBJ._obj2Array -
-
See
-
- OBJ.obj2KeyedArray - -
-
-
-
    OBJ.obj2Array = function(obj, level) {
-        return OBJ._obj2Array(obj, false, level);
-    };
-
-
-
-

- - OBJ.obj2KeyedArray -

-
- -
-

Converts an object into array, keys are preserved

- -

Creates an array containing all keys and values of an object and -returns it.

-
-
-
Params
-
- obj - object - The object to convert in array -
-
- level - number - Optional. The level of recursion. Defaults, - undefined -
-
Returns
-
- - array - The converted object -
-
See
-
- OBJ.obj2Array - -
-
-
-
    OBJ.obj2KeyedArray = OBJ.obj2KeyArray = function(obj, level) {
-        return OBJ._obj2Array(obj, true, level);
-    };
-
-
-
-

- - OBJ.obj2QueryString -

-
- -
-

Creates a querystring with the key-value pairs of the given object.

-
-
-
Params
-
- obj - object - The object to convert -
-
Returns
-
- - string - The created querystring - -Kudos: -
-
See
- -
-
-
    OBJ.obj2QueryString = function(obj) {
-        var str;
-        var key;
-
-        if ('object' !== typeof obj) {
-            throw new TypeError(
-                    'JSUS.objectToQueryString: obj must be object.');
-        }
-
-        str = [];
-        for (key in obj) {
-            if (obj.hasOwnProperty(key)) {
-                str.push(encodeURIComponent(key) + '=' +
-                         encodeURIComponent(obj[key]));
-            }
-        }
-
-        return '?' + str.join('&');
-    };
-
-
-
-

- - OBJ.keys -

-
- -
-

Scans an object an returns all the keys of the properties, -into an array.

- -

The second paramter controls the level of nested objects -to be evaluated. Defaults 0 (nested properties are skipped).

-
-
-
Params
-
- obj - object - The object from which extract the keys -
-
- level - number - Optional. The level of recursion. Defaults 0 -
-
Returns
-
- - array - The array containing the extracted keys -
-
See
-
- Object.keys - -
-
-
-
    OBJ.keys = OBJ.objGetAllKeys = function(obj, level, curLevel) {
-        var result, key;
-        if (!obj) return [];
-        level = 'number' === typeof level && level >= 0 ? level : 0;
-        curLevel = 'number' === typeof curLevel && curLevel >= 0 ? curLevel : 0;
-        result = [];
-        for (key in obj) {
-            if (obj.hasOwnProperty(key)) {
-                result.push(key);
-                if (curLevel < level) {
-                    if ('object' === typeof obj[key]) {
-                        result = result.concat(OBJ.objGetAllKeys(obj[key],
-                                                                 (curLevel+1)));
-                    }
-                }
-            }
-        }
-        return result;
-    };
-
-
-
-

- - OBJ.implode -

-
- -
-

Separates each property into a new object and returns them into an array

- -

E.g.

- - -
var a = { b:2, c: {a:1}, e:5 };
-OBJ.implode(a); // [{b:2}, {c:{a:1}}, {e:5}]
-
- - -
-
-
Params
-
- obj - object - The object to implode -
-
Returns
-
- - array - The array containing all the imploded properties -
-
-
-
    OBJ.implode = OBJ.implodeObj = function(obj) {
-        var result, key, o;
-        if (!obj) return [];
-        result = [];
-        for (key in obj) {
-            if (obj.hasOwnProperty(key)) {
-                o = {};
-                o[key] = obj[key];
-                result.push(o);
-            }
-        }
-        return result;
-    };
-
-
-
-

- - OBJ.clone -

-
- -
-

Creates a perfect copy of the object passed as parameter

- -

Recursively scans all the properties of the object to clone. -Properties of the prototype chain are copied as well.

- -

Primitive types and special values are returned as they are.

-
-
-
Params
-
- obj - object - The object to clone -
-
Returns
-
- - object - The clone of the object -
-
-
-
    OBJ.clone = function(obj) {
-        var clone, i, value;
-        if (!obj) return obj;
-        if ('number' === typeof obj) return obj;
-        if ('string' === typeof obj) return obj;
-        if ('boolean' === typeof obj) return obj;
-
-
- -
-

NaN and +-Infinity are numbers, so no check is necessary.

-
        if ('function' === typeof obj) {
-            clone = function() {
-                var len, args;
-                len = arguments.length;
-                if (!len) return obj.call(clone);
-                else if (len === 1) return obj.call(clone, arguments[0]);
-                else if (len === 2) {
-                    return obj.call(clone, arguments[0], arguments[1]);
-                }
-                else {
-                    args = new Array(len);
-                    for (i = 0; i < len; i++) {
-                        args[i] = arguments[i];
-                    }
-                    return obj.apply(clone, args);
-                }
-            };
-        }
-        else {
-            clone = Object.prototype.toString.call(obj) === '[object Array]' ?
-                [] : {};
-        }
-        for (i in obj) {
-
-
- -
-

It is not NULL and it is an object. -Even if it is an array we need to use CLONE, -because slice() does not clone arrays of objects.

-
            if (obj[i] && 'object' === typeof obj[i]) {
-                value = OBJ.clone(obj[i]);
-            }
-            else {
-                value = obj[i];
-            }
-
-            if (obj.hasOwnProperty(i)) {
-                clone[i] = value;
-            }
-            else {
-
-
- -
-

We know if object.defineProperty is available.

-
                if (compatibility && compatibility.defineProperty) {
-                    Object.defineProperty(clone, i, {
-                        value: value,
-                        writable: true,
-                        configurable: true
-                    });
-                }
-                else {
-                    setProp(clone, i, value);
-                }
-            }
-        }
-        return clone;
-    };
-
-    function setProp(clone, i, value) {
-        try {
-            Object.defineProperty(clone, i, {
-                value: value,
-                writable: true,
-                configurable: true
-            });
-        }
-        catch(e) {
-            clone[i] = value;
-        }
-    }
-
-
-
-

- - OBJ.classClone -

-
- -
-

Creates a copy (keeping class) of the object passed as parameter

- -

Recursively scans all the properties of the object to clone. -The clone is an instance of the type of obj.

-
-
-
Params
-
- obj - object - The object to clone -
-
- depth - Number - how deep the copy should be -
-
Returns
-
- - object - The clone of the object -
-
-
-
    OBJ.classClone = function(obj, depth) {
-        var clone, i;
-        if (depth === 0) {
-            return obj;
-        }
-
-        if (obj && 'object' === typeof obj) {
-            clone = Object.prototype.toString.call(obj) === '[object Array]' ?
-                [] : JSUS.createObj(obj.constructor.prototype);
-
-            for (i in obj) {
-                if (obj.hasOwnProperty(i)) {
-                    if (obj[i] && 'object' === typeof obj[i]) {
-                        clone[i] = JSUS.classClone(obj[i], depth - 1);
-                    }
-                    else {
-                        clone[i] = obj[i];
-                    }
-                }
-            }
-            return clone;
-        }
-        else {
-            return JSUS.clone(obj);
-        }
-    };
-
-
-
-

- - OBJ.join -

-
- -
-

Performs a left join on the keys of two objects

- -

Creates a copy of obj1, and in case keys overlap -between obj1 and obj2, the values from obj2 are taken.

- -

Returns a new object, the original ones are not modified.

- -

E.g.

- - -
var a = { b:2, c:3, e:5 };
-var b = { a:10, b:2, c:100, d:4 };
-OBJ.join(a, b); // { b:2, c:100, e:5 }
-
- - -
-
-
Params
-
- obj1 - object - The object where the merge will take place -
-
- obj2 - object - The merging object -
-
Returns
-
- - object - The joined object -
-
See
-
- OBJ.merge - -
-
-
-
    OBJ.join = function(obj1, obj2) {
-        var clone, i;
-        clone = OBJ.clone(obj1);
-        if (!obj2) return clone;
-        for (i in clone) {
-            if (clone.hasOwnProperty(i)) {
-                if ('undefined' !== typeof obj2[i]) {
-                    if ('object' === typeof obj2[i]) {
-                        clone[i] = OBJ.join(clone[i], obj2[i]);
-                    } else {
-                        clone[i] = obj2[i];
-                    }
-                }
-            }
-        }
-        return clone;
-    };
-
-
-
-

- - OBJ.merge -

-
- -
-

Merges two objects in one

- -

In case keys overlap the values from obj2 are taken.

- -

Only own properties are copied.

- -

Returns a new object, the original ones are not modified.

- -

E.g.

- - -
var a = { a:1, b:2, c:3 };
-var b = { a:10, b:2, c:100, d:4 };
-OBJ.merge(a, b); // { a: 10, b: 2, c: 100, d: 4 }
-
- - -
-
-
Params
-
- obj1 - object - The object where the merge will take place -
-
- obj2 - object - The merging object -
-
Returns
-
- - object - The merged object -
-
See
-
- OBJ.join -
-
See
-
- OBJ.mergeOnKey - -
-
-
-
    OBJ.merge = function(obj1, obj2) {
-        var clone, i;
-
-
- -
-

Checking before starting the algorithm

-
        if (!obj1 && !obj2) return false;
-        if (!obj1) return OBJ.clone(obj2);
-        if (!obj2) return OBJ.clone(obj1);
-
-        clone = OBJ.clone(obj1);
-        for (i in obj2) {
-
-            if (obj2.hasOwnProperty(i)) {
-
-
- -
-

it is an object and it is not NULL

-
                if (obj2[i] && 'object' === typeof obj2[i]) {
-
-
- -
-

If we are merging an object into -a non-object, we need to cast the -type of obj1

-
                    if ('object' !== typeof clone[i]) {
-                        if (Object.prototype.toString.call(obj2[i]) ===
-                            '[object Array]') {
-
-                            clone[i] = [];
-                        }
-                        else {
-                            clone[i] = {};
-                        }
-                    }
-                    clone[i] = OBJ.merge(clone[i], obj2[i]);
-                }
-                else {
-                    clone[i] = obj2[i];
-                }
-            }
-        }
-        return clone;
-    };
-
-
-
-

- - OBJ.mixin -

-
- -
-

Adds all the properties of obj2 into obj1

- -

Original object is modified.

-
-
-
Params
-
- obj1 - object - The object to which the new properties will be added -
-
- obj2 - object - The mixin-in object -
-
Returns
-
- - object - obj1 -
-
-
-
    OBJ.mixin = function(obj1, obj2) {
-        var i;
-        if (!obj1 && !obj2) return;
-        if (!obj1) return obj2;
-        if (!obj2) return obj1;
-        for (i in obj2) {
-            obj1[i] = obj2[i];
-        }
-        return obj1;
-    };
-
-
-
-

- - OBJ.mixout -

-
- -
-

Copies only non-overlapping properties from obj2 to obj1

- -

Check only if a property is defined, not its value. -Original object is modified.

-
-
-
Params
-
- obj1 - object - The object to which the new properties will be added -
-
- obj2 - object - The mixin-in object -
-
Returns
-
- - object - obj1 -
-
-
-
    OBJ.mixout = function(obj1, obj2) {
-        var i;
-        if (!obj1 && !obj2) return;
-        if (!obj1) return obj2;
-        if (!obj2) return obj1;
-        for (i in obj2) {
-            if ('undefined' === typeof obj1[i]) obj1[i] = obj2[i];
-        }
-        return obj1;
-    };
-
-
-
-

- - OBJ.mixcommon -

-
- -
-

Copies only overlapping properties from obj2 to obj1

- -

Check only if a property is defined, not its value. -Original object is modified.

-
-
-
Params
-
- obj1 - object - The object to which the new properties will be added -
-
- obj2 - object - The mixin-in object -
-
Returns
-
- - object - obj1 -
-
-
-
    OBJ.mixcommon = function(obj1, obj2) {
-        var i;
-        if (!obj1 && !obj2) return;
-        if (!obj1) return obj2;
-        if (!obj2) return obj1;
-        for (i in obj2) {
-            if ('undefined' !== typeof obj1[i]) obj1[i] = obj2[i];
-        }
-        return obj1;
-    };
-
-
-
-

- - OBJ.mergeOnKey -

-
- -
-

Merges the properties of obj2 into a new property named 'key' in obj1.

- -

Returns a new object, the original ones are not modified.

- -

This method is useful when we want to merge into a larger -configuration (e.g. with properties min, max, value) object, another one -that contains just a subset of properties (e.g. value).

-
-
-
Params
-
- obj1 - object - The object where the merge will take place -
-
- obj2 - object - The merging object -
-
- key - string - The name of property under which the second object - will be merged -
-
Returns
-
- - object - The merged object -
-
See
-
- OBJ.merge - -
-
-
-
    OBJ.mergeOnKey = function(obj1, obj2, key) {
-        var clone, i;
-        clone = OBJ.clone(obj1);
-        if (!obj2 || !key) return clone;
-        for (i in obj2) {
-            if (obj2.hasOwnProperty(i)) {
-                if (!clone[i] || 'object' !== typeof clone[i]) {
-                    clone[i] = {};
-                }
-                clone[i][key] = obj2[i];
-            }
-        }
-        return clone;
-    };
-
-
-
-

- - OBJ.subobj -

-
- -
-

Creates a copy of an object containing only the properties -passed as second parameter

- -

The parameter select can be an array of strings, or the name -of a property.

- -

Use '.' (dot) to point to a nested property, however if a property -with a '.' in the name is found, it will be used first.

-
-
-
Params
-
- o - object - The object to dissect -
-
- select - string - array - The selection of properties to extract -
-
Returns
-
- - object - The subobject with the properties from the parent -
-
See
-
- OBJ.getNestedValue - -
-
-
-
    OBJ.subobj = function(o, select) {
-        var out, i, key;
-        if (!o) return false;
-        out = {};
-        if (!select) return out;
-        if (!(select instanceof Array)) select = [select];
-        for (i=0; i < select.length; i++) {
-            key = select[i];
-            if (o.hasOwnProperty(key)) {
-                out[key] = o[key];
-            }
-            else if (OBJ.hasOwnNestedProperty(key, o)) {
-                OBJ.setNestedValue(key, OBJ.getNestedValue(key, o), out);
-            }
-        }
-        return out;
-    };
-
-
-
-

- - OBJ.skim -

-
- -
-

Creates a copy of an object with some of the properties removed

- -

The parameter remove can be an array of strings, or the name -of a property.

- -

Use '.' (dot) to point to a nested property, however if a property -with a '.' in the name is found, it will be deleted first.

-
-
-
Params
-
- o - object - The object to dissect -
-
- remove - string - array - The selection of properties to remove -
-
Returns
-
- - object - The subobject with the properties from the parent -
-
See
-
- OBJ.getNestedValue - -
-
-
-
    OBJ.skim = function(o, remove) {
-        var out, i;
-        if (!o) return false;
-        out = OBJ.clone(o);
-        if (!remove) return out;
-        if (!(remove instanceof Array)) remove = [remove];
-        for (i = 0; i < remove.length; i++) {
-            if (out.hasOwnProperty(i)) {
-                delete out[i];
-            }
-            else {
-                OBJ.deleteNestedKey(remove[i], out);
-            }
-        }
-        return out;
-    };
-
-
-
-

- - OBJ.setNestedValue -

-
- -
-

Sets the value of a nested property of an object and returns it.

- -

If the object is not passed a new one is created. -If the nested property is not existing, a new one is created.

- -

Use '.' (dot) to point to a nested property.

- -

The original object is modified.

-
-
-
Params
-
- str - string - The path to the value -
-
- value - mixed - The value to set -
-
Returns
-
- - object - boolean - The modified object, or FALSE if error - occurrs -
-
See
-
- OBJ.getNestedValue -
-
See
-
- OBJ.deleteNestedKey - -
-
-
-
    OBJ.setNestedValue = function(str, value, obj) {
-        var keys, k;
-        if (!str) {
-            JSUS.log('Cannot set value of undefined property', 'ERR');
-            return false;
-        }
-        obj = ('object' === typeof obj) ? obj : {};
-        keys = str.split('.');
-        if (keys.length === 1) {
-            obj[str] = value;
-            return obj;
-        }
-        k = keys.shift();
-        obj[k] = OBJ.setNestedValue(keys.join('.'), value, obj[k]);
-        return obj;
-    };
-
-
-
-

- - OBJ.getNestedValue -

-
- -
-

Returns the value of a property of an object, as defined -by a path string.

- -

Use '.' (dot) to point to a nested property.

- -

Returns undefined if the nested property does not exist.

- -

E.g.

- - -
var o = { a:1, b:{a:2} };
-OBJ.getNestedValue('b.a', o); // 2
-
- - -
-
-
Params
-
- str - string - The path to the value -
-
- obj - object - The object from which extract the value -
-
Returns
-
- - mixed - The extracted value -
-
See
-
- OBJ.setNestedValue -
-
See
-
- OBJ.deleteNestedKey - -
-
-
-
    OBJ.getNestedValue = function(str, obj) {
-        var keys, k;
-        if (!obj) return;
-        keys = str.split('.');
-        if (keys.length === 1) {
-            return obj[str];
-        }
-        k = keys.shift();
-        return OBJ.getNestedValue(keys.join('.'), obj[k]);
-    };
-
-
-
-

- - OBJ.deleteNestedKey -

-
- -
-

Deletes a property from an object, as defined by a path string

- -

Use '.' (dot) to point to a nested property.

- -

The original object is modified.

- -

E.g.

- - -
var o = { a:1, b:{a:2} };
-OBJ.deleteNestedKey('b.a', o); // { a:1, b: {} }
-
- - -
-
-
Params
-
- str - string - The path string -
-
- obj - object - The object from which deleting a property -
-
- TRUE, - boolean - if the property was existing, and then deleted -
-
See
-
- OBJ.setNestedValue -
-
See
-
- OBJ.getNestedValue - -
-
-
-
    OBJ.deleteNestedKey = function(str, obj) {
-        var keys, k;
-        if (!obj) return;
-        keys = str.split('.');
-        if (keys.length === 1) {
-            delete obj[str];
-            return true;
-        }
-        k = keys.shift();
-        if ('undefined' === typeof obj[k]) {
-            return false;
-        }
-        return OBJ.deleteNestedKey(keys.join('.'), obj[k]);
-    };
-
-
-
-

- - OBJ.hasOwnNestedProperty -

-
- -
-

Returns TRUE if a (nested) property exists

- -

Use '.' to specify a nested property.

- -

E.g.

- - -
var o = { a:1, b:{a:2} };
-OBJ.hasOwnNestedProperty('b.a', o); // TRUE
-
- - -
-
-
Params
-
- str - string - The path of the (nested) property -
-
- obj - object - The object to test -
-
Returns
-
- - boolean - TRUE, if the (nested) property exists -
-
-
-
    OBJ.hasOwnNestedProperty = function(str, obj) {
-        var keys, k;
-        if (!obj) return false;
-        keys = str.split('.');
-        if (keys.length === 1) {
-            return obj.hasOwnProperty(str);
-        }
-        k = keys.shift();
-        return OBJ.hasOwnNestedProperty(keys.join('.'), obj[k]);
-    };
-
-
-
-

- - OBJ.split -

-
- -
-

Splits an object along a specified dimension

- -

All fragments are returned in an array (as copies).

- -

It creates as many new objects as the number of properties -contained in the specified dimension. E.g.

- - -
 var o = { a: 1,
-           b: {c: 2,
-               d: 3
-           },
-           e: 4
- };
-
- o = OBJ.split(o, 'b');
-
- // o becomes:
-
- [{ a: 1,
-    b: {c: 2},
-    e: 4
- },
- { a: 1,
-   b: {d: 3},
-   e: 4
- }];
-
- - -
-
-
Params
-
- o - object - The object to split -
-
- key - string - The name of the property to split -
-
- l - number - Optional. The recursion level. Default: 1. -
-
- positionAsKey - boolean - Optional. If TRUE, the position - of an element in the array to split will be used as key. -
-
Returns
-
- - array - A list of copies of the object with split values -
-
-
-
    OBJ.split = (function() {
-        var makeClone, splitValue;
-        var model, level, _key, posAsKeys;
-
-        makeClone = function(value, out, keys) {
-            var i, len, tmp, copy;
-            copy = JSUS.clone(model);
-
-            switch(keys.length) {
-            case 0:
-                copy[_key] = JSUS.clone(value);
-                break;
-            case 1:
-                copy[_key][keys[0]] = JSUS.clone(value);
-                break;
-            case 2:
-                copy[_key][keys[0]] = {};
-                copy[_key][keys[0]][keys[1]] = JSUS.clone(value);
-                break;
-            default:
-                i = -1, len = keys.length-1;
-                tmp = copy[_key];
-                for ( ; ++i < len ; ) {
-                    tmp[keys[i]] = {};
-                    tmp = tmp[keys[i]];
-                }
-                tmp[keys[keys.length-1]] = JSUS.clone(value);
-            }
-            out.push(copy);
-            return;
-        };
-
-        splitValue = function(value, out, curLevel, keysArray) {
-            var i, curPosAsKey;
-
-
- -
-

level == 0 means no limit.

-
            if (level && (curLevel >= level)) {
-                makeClone(value, out, keysArray);
-            }
-            else {
-
-                curPosAsKey = posAsKeys || !JSUS.isArray(value);
-
-                for (i in value) {
-                    if (value.hasOwnProperty(i)) {
-
-                        if ('object' === typeof value[i] &&
-                            (level && ((curLevel+1) <= level))) {
-
-                            splitValue(value[i], out, (curLevel+1),
-                                       curPosAsKey ?
-                                       keysArray.concat(i) : keysArray);
-                        }
-                        else {
-                            makeClone(value[i], out, curPosAsKey ?
-                                      keysArray.concat(i) : keysArray);
-                        }
-                    }
-                }
-            }
-        };
-
-        return function(o, key, l, positionAsKey) {
-            var out;
-            if ('object' !== typeof o) {
-                throw new TypeError('JSUS.split: o must be object. Found: ' +
-                                    o);
-            }
-            if ('string' !== typeof key || key.trim() === '') {
-                throw new TypeError('JSUS.split: key must a non-empty ' +
-                                    'string. Found: ' + key);
-            }
-            if (l && ('number' !== typeof l || l < 0)) {
-                throw new TypeError('JSUS.split: l must a non-negative ' +
-                                    'number or undefined. Found: ' + l);
-            }
-            model = JSUS.clone(o);
-            if ('object' !== typeof o[key]) return [model];
-
-
- -
-

Init.

-
            out = [];
-            _key = key;
-            model[key] = {};
-            level = 'undefined' === typeof l ? 1 : l;
-            posAsKeys = positionAsKey;
-
-
- -
-

Recursively compute split.

-
            splitValue(o[key], out, 0, []);
-
-
- -
-

Cleanup.

-
            _key = undefined;
-            model = undefined;
-            level = undefined;
-            posAsKeys = undefined;
-
-
- -
-

Return.

-
            return out;
-        };
-    })();
-
-
-
-

- - OBJ.melt -

-
- -
-

Creates a new object with the specified combination of -properties - values

- -

The values are assigned cyclically to the properties, so that -they do not need to have the same length. E.g.

- - -
 J.createObj(['a','b','c'], [1,2]); // { a: 1, b: 2, c: 1 }
-
- - -
-
-
Params
-
- keys - array - The names of the keys to add to the object -
-
- values - array - The values to associate to the keys -
-
Returns
-
- - object - A new object with keys and values melted together -
-
-
-
    OBJ.melt = function(keys, values) {
-        var o = {}, valen = values.length;
-        for (var i = 0; i < keys.length; i++) {
-            o[keys[i]] = values[i % valen];
-        }
-        return o;
-    };
-
-
-
-

- - OBJ.uniqueKey -

-
- -
-

Creates a random unique key name for a collection

- -

User can specify a tentative unique key name, and if already -existing an incremental index will be added as suffix to it.

- -

Notice: the method does not actually create the key -in the object, but it just returns the name.

-
-
-
Params
-
- obj - object - The collection for which a unique key will be created -
-
- prefixName - string - Optional. A tentative key name. Defaults, - a 15-digit random number -
-
- stop - number - Optional. The number of tries before giving up - searching for a unique key name. Defaults, 1000000. -
-
Returns
-
- - string - undefined - The unique key name, or undefined if it was - not found -
-
-
-
    OBJ.uniqueKey = function(obj, prefixName, stop) {
-        var name, duplicateCounter;
-        if (!obj) {
-            JSUS.log('Cannot find unique name in undefined object', 'ERR');
-            return;
-        }
-        duplicateCounter = 1;
-        prefixName = '' + (prefixName ||
-                           Math.floor(Math.random()*1000000000000000));
-        stop = stop || 1000000;
-        name = prefixName;
-        while (obj[name]) {
-            name = prefixName + duplicateCounter;
-            duplicateCounter++;
-            if (duplicateCounter > stop) {
-                return;
-            }
-        }
-        return name;
-    };
-
-
-
-

- - OBJ.augment -

-
- -
-

Pushes the values of the properties of an object into another one

- -

User can specifies the subset of keys from both objects -that will subject to augmentation. The values of the other keys -will not be changed

- -

Notice: the method modifies the first input paramteer

- -

E.g.

- - -
var a = { a:1, b:2, c:3 };
-var b = { a:10, b:2, c:100, d:4 };
-OBJ.augment(a, b); // { a: [1, 10], b: [2, 2], c: [3, 100]}
-
-OBJ.augment(a, b, ['b', 'c', 'd']);
-// { a: 1, b: [2, 2], c: [3, 100], d: [4]});
-
- - -
-
-
Params
-
- obj1 - object - The object whose properties will be augmented -
-
- obj2 - object - The augmenting object -
-
- key - array - Optional. Array of key names common to both objects - taken as the set of properties to augment -
-
-
-
    OBJ.augment = function(obj1, obj2, keys) {
-        var i, k;
-        keys = keys || OBJ.keys(obj1);
-
-        for (i = 0 ; i < keys.length; i++) {
-            k = keys[i];
-            if ('undefined' !== typeof obj1[k] &&
-                Object.prototype.toString.call(obj1[k]) !== '[object Array]') {
-                obj1[k] = [obj1[k]];
-            }
-            if ('undefined' !== obj2[k]) {
-                if (!obj1[k]) obj1[k] = [];
-                obj1[k].push(obj2[k]);
-            }
-        }
-    };
-
-
-
-

- - OBJ.pairwiseWalk -

-
- -
-

Executes a callback on all pairs of attributes with the same name

- -

The results of each callback are aggregated in a new object under the -same property name.

- -

Does not traverse nested objects, and properties of the prototype -are excluded.

- -

Returns a new object, the original ones are not modified.

- -

E.g.

- - -
var a = { b:2, c:3, d:5 };
-var b = { a:10, b:2, c:100, d:4 };
-var sum = function(a,b) {
-    if ('undefined' !== typeof a) {
-        return 'undefined' !== typeof b ? a + b : a;
-    }
-    return b;
-};
-OBJ.pairwiseWalk(a, b, sum); // { a:10, b:4, c:103, d:9 }
-
- - -
-
-
Params
-
- o1 - object - The first object -
-
- o2 - object - The second object -
-
Returns
-
- - object - The object aggregating the results -
-
-
-
    OBJ.pairwiseWalk = function(o1, o2, cb) {
-        var i, out;
-        if (!o1 && !o2) return;
-        if (!o1) return o2;
-        if (!o2) return o1;
-
-        out = {};
-        for (i in o1) {
-            if (o1.hasOwnProperty(i)) {
-                out[i] = o2.hasOwnProperty(i) ? cb(o1[i], o2[i]) : cb(o1[i]);
-            }
-        }
-
-        for (i in o2) {
-            if (o2.hasOwnProperty(i)) {
-                if ('undefined' === typeof out[i]) {
-                    out[i] = cb(undefined, o2[i]);
-                }
-            }
-        }
-        return out;
-    };
-
-
-
-

- - OBJ.getKeyByValue -

-
- -
-

Returns the key/s associated with a specific value

- -

Uses OBJ.equals so it can perform complicated comparisons of -the value of the keys.

- -

Properties of the prototype are not skipped.

-
-
-
Params
-
- obj - object - The object to search -
-
- value - mixed - The value to match -
-
- allKeys - boolean - Optional. If TRUE, all keys with the - specific value are returned. Default FALSE -
-
Returns
-
- - object - The object aggregating the results -
-
See
-
- OBJ.equals - -
-
-
-
    OBJ.getKeyByValue = function(obj, value, allKeys) {
-        var key, out;
-        if ('object' !== typeof obj) {
-            throw new TypeError('OBJ.getKeyByValue: obj must be object.');
-        }
-        if (allKeys) out = [];
-        for (key in obj) {
-            if (obj.hasOwnProperty(key) ) {
-                if (OBJ.equals(value, obj[key])) {
-                    if (!allKeys) return key;
-                    else out.push(key);
-                }
-            }
-        }
-        return out;
-    };
-
-    JSUS.extend(OBJ);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/parse.js.html b/docs/lib/parse.js.html deleted file mode 100644 index 2b6a949..0000000 --- a/docs/lib/parse.js.html +++ /dev/null @@ -1,1271 +0,0 @@ - - - - parse.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - PARSE -

-
- - -

Copyright(c) 2016 Stefano Balietti -MIT Licensed

-
-

Collection of static functions related to parsing strings

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    function PARSE() {}
-
-
-
-

- - PARSE.stringify_prefix -

-
- -
-

Prefix used by PARSE.stringify and PARSE.parse -to decode strings with special meaning

-
-
-
See
-
- PARSE.stringify -
-
See
-
- PARSE.parse - -
-
-
-
    PARSE.stringify_prefix = '!?_';
-
-    PARSE.marker_func = PARSE.stringify_prefix + 'function';
-    PARSE.marker_null = PARSE.stringify_prefix + 'null';
-    PARSE.marker_und = PARSE.stringify_prefix + 'undefined';
-    PARSE.marker_nan = PARSE.stringify_prefix + 'NaN';
-    PARSE.marker_inf = PARSE.stringify_prefix + 'Infinity';
-    PARSE.marker_minus_inf = PARSE.stringify_prefix + '-Infinity';
-
-
-
-

- - PARSE.getQueryString -

-
- -
-

Parses current querystring and returns the requested variable.

- -

If no variable name is specified, returns the full query string. -If requested variable is not found returns false.

-
-
-
Params
-
- name - string - Optional. If set, returns only the value - associated with this variable -
-
- referer - string - Optional. If set, searches this string -
-
Returns
-
- - string - boolean - The querystring, or a part of it, or FALSE - -Kudos: -
-
See
- -
-
-
    PARSE.getQueryString = function(name, referer) {
-        var regex, results;
-        if (referer && 'string' !== typeof referer) {
-            throw new TypeError('JSUS.getQueryString: referer must be string ' +
-                                'or undefined.');
-        }
-        referer = referer || window.location.search;
-        if ('undefined' === typeof name) return referer;
-        name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
-        regex = new RegExp("[\\?&]" + name + "=([^&#]*)");
-        results = regex.exec(referer);
-        return results === null ? false :
-            decodeURIComponent(results[1].replace(/\+/g, " "));
-    };
-
-
-
-

- - PARSE.tokenize -

-
- -
-

Splits a string in tokens that users can specified as input parameter. -Additional options can be specified with the modifiers parameter

- -
    -
  • limit: An integer that specifies the number of split items -after the split limit will not be included in the array
  • -
-
-
-
Params
-
- str - string - The string to split -
-
- separators - array - Array containing the separators words -
-
- modifiers - object - Optional. Configuration options - for the tokenizing -
-
Returns
-
- - array - Tokens in which the string was split -
-
-
-
    PARSE.tokenize = function(str, separators, modifiers) {
-        var pattern, regex;
-        if (!str) return;
-        if (!separators || !separators.length) return [str];
-        modifiers = modifiers || {};
-
-        pattern = '[';
-
-        JSUS.each(separators, function(s) {
-            if (s === ' ') s = '\\s';
-
-            pattern += s;
-        });
-
-        pattern += ']+';
-
-        regex = new RegExp(pattern);
-        return str.split(regex, modifiers.limit);
-    };
-
-
-
-

- - PARSE.stringify -

-
- -
-

Stringifies objects, functions, primitive, undefined or null values

- -

Makes uses JSON.stringify with a special reviver function, that -strinfifies also functions, undefined, and null values.

- -

A special prefix is prepended to avoid name collisions.

-
-
-
Params
-
- o - mixed - The value to stringify -
-
- spaces - number - Optional the number of indentation spaces. - Defaults, 0 -
-
Returns
-
- - string - The stringified result -
-
See
-
- JSON.stringify -
-
See
-
- PARSE.stringify_prefix - -
-
-
-
    PARSE.stringify = function(o, spaces) {
-        return JSON.stringify(o, function(key, value) {
-            var type = typeof value;
-            if ('function' === type) {
-                return PARSE.stringify_prefix + value.toString();
-            }
-
-            if ('undefined' === type) return PARSE.marker_und;
-            if (value === null) return PARSE.marker_null;
-            if ('number' === type && isNaN(value)) return PARSE.marker_nan;
-            if (value === Number.POSITIVE_INFINITY) return PARSE.marker_inf;
-            if (value === Number.NEGATIVE_INFINITY) {
-                return PARSE.marker_minus_inf;
-            }
-
-            return value;
-
-        }, spaces);
-    };
-
-
-
-

- - PARSE.stringifyAll -

-
- -
-

Copies all the properties of the prototype before stringifying

- -

Notice: The original object is modified!

-
-
-
Params
-
- o - mixed - The value to stringify -
-
- spaces - number - Optional the number of indentation spaces. - Defaults, 0 -
-
Returns
-
- - string - The stringified result -
-
See
-
- PARSE.stringify - -
-
-
-
    PARSE.stringifyAll = function(o, spaces) {
-        var i;
-        if ('object' === typeof o) {
-            for (i in o) {
-                if (!o.hasOwnProperty(i)) {
-                    if ('object' === typeof o[i]) {
-                        o[i] = PARSE.stringifyAll(o[i]);
-                    }
-                    else {
-                        o[i] = o[i];
-                    }
-                }
-            }
-        }
-        return PARSE.stringify(o);
-    };
-
-
-
-

- - PARSE.parse -

-
- -
-

Decodes strings in objects and other values

- -

Uses JSON.parse and then looks for special strings -encoded by PARSE.stringify

-
-
-
Params
-
- str - string - The string to decode -
-
Returns
-
- - mixed - The decoded value -
-
See
-
- JSON.parse -
-
See
-
- PARSE.stringify_prefix - -
-
-
-
    PARSE.parse = (function() {
-
-        var len_prefix = PARSE.stringify_prefix.length,
-            len_func = PARSE.marker_func.length,
-            len_null = PARSE.marker_null.length,
-            len_und = PARSE.marker_und.length,
-            len_nan = PARSE.marker_nan.length,
-            len_inf = PARSE.marker_inf.length,
-            len_minus_inf = PARSE.marker_minus_inf.length;
-
-        function walker(o) {
-            var i;
-            if ('object' !== typeof o) return reviver(o);
-            for (i in o) {
-                if (o.hasOwnProperty(i)) {
-                    if ('object' === typeof o[i]) walker(o[i]);
-                    else o[i] = reviver(o[i]);
-                }
-            }
-            return o;
-        }
-
-        function reviver(value) {
-            var type;
-            type = typeof value;
-
-            if (type === 'string') {
-                if (value.substring(0, len_prefix) !== PARSE.stringify_prefix) {
-                    return value;
-                }
-                else if (value.substring(0, len_func) === PARSE.marker_func) {
-                    return JSUS.eval(value.substring(len_prefix));
-                }
-                else if (value.substring(0, len_null) === PARSE.marker_null) {
-                    return null;
-                }
-                else if (value.substring(0, len_und) === PARSE.marker_und) {
-                    return undefined;
-                }
-
-                else if (value.substring(0, len_nan) === PARSE.marker_nan) {
-                    return NaN;
-                }
-                else if (value.substring(0, len_inf) === PARSE.marker_inf) {
-                    return Infinity;
-                }
-                else if (value.substring(0, len_minus_inf) ===
-                         PARSE.marker_minus_inf) {
-
-                    return -Infinity;
-                }
-
-            }
-            return value;
-        }
-
-        return function(str) {
-            return walker(JSON.parse(str));
-        };
-
-    })();
-
-
-
-

- - PARSE.isInt -

-
- -
-

Checks if a value is an integer number or a string containing one

- -

Non-numbers, Infinity, NaN, and floats will return FALSE

-
-
-
Params
-
- n - mixed - The value to check -
-
- lower - number - Optional. If set, n must be greater than lower -
-
- upper - number - Optional. If set, n must be smaller than upper -
-
Returns
-
- - boolean - number - The parsed integer, or FALSE if none was found -
-
See
-
- PARSE.isFloat -
-
See
-
- PARSE.isNumber - -
-
-
-
    PARSE.isInt = function(n, lower, upper) {
-        var regex, i;
-        regex = /^-?\d+$/;
-        if (!regex.test(n)) return false;
-        i = parseInt(n, 10);
-        if (i !== parseFloat(n)) return false;
-        return PARSE.isNumber(i, lower, upper);
-    };
-
-
-
-

- - PARSE.isFloat -

-
- -
-

Checks if a value is a float number or a string containing one

- -

Non-numbers, Infinity, NaN, and integers will return FALSE

-
-
-
Params
-
- n - mixed - The value to check -
-
- lower - number - Optional. If set, n must be greater than lower -
-
- upper - number - Optional. If set, n must be smaller than upper -
-
Returns
-
- - boolean - number - The parsed float, or FALSE if none was found -
-
See
-
- PARSE.isInt -
-
See
-
- PARSE.isNumber - -
-
-
-
    PARSE.isFloat = function(n, lower, upper) {
-        var regex;
-        regex = /^-?\d*(\.\d+)?$/;
-        if (!regex.test(n)) return false;
-        if (n.toString().indexOf('.') === -1) return false;
-        return PARSE.isNumber(n, lower, upper);
-    };
-
-
-
-

- - PARSE.isNumber -

-
- -
-

Checks if a value is a number (int or float) or a string containing one

- -

Non-numbers, Infinity, NaN will return FALSE

-
-
-
Params
-
- n - mixed - The value to check -
-
- lower - number - Optional. If set, n must be greater than lower -
-
- upper - number - Optional. If set, n must be smaller than upper -
-
Returns
-
- - boolean - number - The parsed number, or FALSE if none was found -
-
See
-
- PARSE.isInt -
-
See
-
- PARSE.isFloat - -
-
-
-
    PARSE.isNumber = function(n, lower, upper) {
-        if (isNaN(n) || !isFinite(n)) return false;
-        n = parseFloat(n);
-        if ('number' === typeof lower && n < lower) return false;
-        if ('number' === typeof upper && n > upper) return false;
-        return n;
-    };
-
-
-
-

- - PARSE.isEmail -

-
- -
-

Returns TRUE if the email's format is valid

-
-
-
Params
-
- The - string - email to check -
-
Returns
-
- - boolean - TRUE, if the email format is valid -
-
-
-
    PARSE.isEmail = function(email) {
-        var idx;
-        if ('string' !== typeof email) return false;
-        if (email.trim().length < 5) return false;
-        idx = email.indexOf('@');
-        if (idx === -1 || idx === 0 || idx === (email.length-1)) return false;
-        idx = email.lastIndexOf('.');
-        if (idx === -1 || idx === (email.length-1) || idx > (idx+1)) {
-            return false;
-        }
-        return true;
-    };
-
-
-
-

- - PARSE.range -

-
- -
-

Decodes semantic strings into an array of integers

- -

Let n, m and l be integers, then the tokens of the string are -interpreted in the following way:

- -
    -
  • *: Any integer
  • -
  • n: The integer n
  • -
  • begin: The smallest integer in available
  • -
  • end: The largest integer in available
  • -
  • <n, <=n, >n, >=n: Any integer (strictly) smaller/larger than n
  • -
  • n..m, [n,m]: Any integer between n and m (both inclusively)
  • -
  • n..l..m: Any i
  • -
  • [n,m): Any integer between n (inclusively) and m (exclusively)
  • -
  • (n,m]: Any integer between n (exclusively) and m (inclusively)
  • -
  • (n,m): Any integer between n and m (both exclusively)
  • -
  • %n: Divisible by n
  • -
  • %n = m: Divisible with rest m
  • -
  • !: Logical not
  • -
  • |, ||, ,: Logical or
  • -
  • &, &&: Logical and
  • -
- -

The elements of the resulting array are all elements of the available -array which satisfy the expression defined by expr.

- -

Examples:

- -

PARSE.range('2..5, >8 & !11', '[-2,12]'); // [2,3,4,5,9,10,12]

- -

PARSE.range('begin...end/2 | 3*end/4...3...end', '[0,40) & %2 = 1'); - // [1,3,5,7,9,11,13,15,17,19,29,35] (end == 39)

- -

PARSE.range('<=19, 22, %5', '>6 & !>27'); - // [7,8,9,10,11,12,13,14,15,16,17,18,19,20,22,25]

- -

PARSE.range('*','(3,8) & !%4, 22, (10,12]'); // [5,6,7,11,12,22]

- -

PARSE.range('<4', { - begin: 0, - end: 21, - prev: 0, - cur: 1, - next: function() { - var temp = this.prev; - this.prev = this.cur; - this.cur += temp; - return this.cur; - }, - isFinished: function() { - return this.cur + this.prev > this.end; - } - }); // [5, 8, 13, 21]

-
-
-
Params
-
- expr - string - number - The selection expression -
-
- available - mixed - Optional. If undefined expr is used. If: - - string: it is interpreted according to the same rules as expr; - - array: it is used as it is; - - object: provide functions next, isFinished and attributes begin, end -
-
Returns
-
- - array - The array containing the specified values -
-
See
-
- JSUS.eval - -
-
-
-
    PARSE.range = function(expr, available) {
-        var i,len, x;
-        var solution;
-        var begin, end, lowerBound, numbers;
-        var invalidChars, invalidBeforeOpeningBracket, invalidDot;
-
-        solution = [];
-        if ('undefined' === typeof expr) return solution;
-
-
- -
-

TODO: this could be improved, i.e. if it is a number, many -checks and regular expressions could be avoided.

-
        if ('number' === typeof expr) expr = '' + expr;
-        else if ('string' !== typeof expr) {
-            throw new TypeError('PARSE.range: expr must be string, number, ' +
-                                'undefined.');
-        }
-
-
- -
-

If no available numbers defined, assumes all possible are allowed.

-
        if ('undefined' === typeof available) {
-            available = expr;
-        }
-        else if (JSUS.isArray(available)) {
-            if (available.length === 0) return solution;
-            begin = Math.min.apply(null, available);
-            end = Math.max.apply(null, available);
-        }
-        else if ('object' === typeof available) {
-            if ('function' !== typeof available.next) {
-                throw new TypeError('PARSE.range: available.next must be ' +
-                                    'function.');
-            }
-            if ('function' !== typeof available.isFinished) {
-                throw new TypeError('PARSE.range: available.isFinished must ' +
-                                    'be function.');
-            }
-            if ('number' !== typeof available.begin) {
-                throw new TypeError('PARSE.range: available.begin must be ' +
-                                    'number.');
-            }
-            if ('number' !== typeof available.end) {
-                throw new TypeError('PARSE.range: available.end must be ' +
-                                    'number.');
-            }
-
-            begin = available.begin;
-            end = available.end;
-        }
-        else if ('string' === typeof available) {
-
-
- -
-

If the availble points are also only given implicitly, -compute set of available numbers by first guessing a bound.

-
            available = preprocessRange(available);
-
-            numbers = available.match(/([-+]?\d+)/g);
-            if (numbers === null) {
-                throw new Error(
-                    'PARSE.range: no numbers in available: ' + available);
-            }
-            lowerBound = Math.min.apply(null, numbers);
-
-            available = PARSE.range(available, {
-                begin: lowerBound,
-                end: Math.max.apply(null, numbers),
-                value: lowerBound,
-                next: function() {
-                    return this.value++;
-                },
-                isFinished: function() {
-                    return this.value > this.end;
-                }
-            });
-            begin = Math.min.apply(null, available);
-            end = Math.max.apply(null, available);
-        }
-        else {
-            throw new TypeError('PARSE.range: available must be string, ' +
-                                'array, object or undefined.');
-        }
-
-
- -
-

end -> maximal available value.

-
        expr = expr.replace(/end/g, parseInt(end, 10));
-
-
- -
-

begin -> minimal available value.

-
        expr = expr.replace(/begin/g, parseInt(begin, 10));
-
-
- -
-

Do all computations.

-
        expr = preprocessRange(expr);
-
-
- -
-

Round all floats

-
        expr = expr.replace(/([-+]?\d+\.\d+)/g, function(match, p1) {
-            return parseInt(p1, 10);
-        });
-
-
- -
-

Validate expression to only contain allowed symbols.

-
        invalidChars = /[^ \*\d<>=!\|&\.\[\],\(\)\-\+%]/g;
-        if (expr.match(invalidChars)) {
-            throw new Error('PARSE.range: invalid characters found: ' + expr);
-        }
-
-
- -
-

& -> && and | -> ||.

-
        expr = expr.replace(/([^& ]) *& *([^& ])/g, "$1&&$2");
-        expr = expr.replace(/([^| ]) *\| *([^| ])/g, "$1||$2");
-
-
- -
-

n -> (x == n).

-
        expr = expr.replace(/([-+]?\d+)/g, "(x==$1)");
-
-
- -
-

n has already been replaced by (x==n) so match for that from now on.

-
-
-
- -
-

%n -> !(x%n)

-
        expr = expr.replace(/% *\(x==([-+]?\d+)\)/,"!(x%$1)");
-
-
- -
-

%n has already been replaced by !(x%n) so match for that from now on. -%n = m, %n == m -> (x%n == m).

-
        expr = expr.replace(/!\(x%([-+]?\d+)\) *={1,} *\(x==([-+]?\d+)\)/g,
-            "(x%$1==$2)");
-
-
- -
-

n, >=n -> (x < n), (x <= n), (x > n), (x >= n)

-
        expr = expr.replace(/([<>]=?) *\(x==([-+]?\d+)\)/g, "(x$1$2)");
-
-
- -
-

n..l..m -> (x >= n && x <= m && !((x-n)%l)) for positive l.

-
        expr = expr.replace(
-            /\(x==([-+]?\d+)\)\.{2,}\(x==(\+?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,
-            "(x>=$1&&x<=$3&&!((x- $1)%$2))");
-
-
- -
-

n..l..m -> (x <= n && x >= m && !((x-n)%l)) for negative l.

-
        expr = expr.replace(
-            /\(x==([-+]?\d+)\)\.{2,}\(x==(-\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,
-            "(x<=$1&&x>=$3&&!((x- $1)%$2))");
-
-
- -
-

n..m -> (x >= n && x <= m).

-
        expr = expr.replace(/\(x==([-+]?\d+)\)\.{2,}\(x==([-+]?\d+)\)/g,
-                "(x>=$1&&x<=$2)");
-
-
- -
-

(n,m), ... ,[n,m] -> (x > n && x < m), ... , (x >= n && x <= m).

-
        expr = expr.replace(
-            /([(\[]) *\(x==([-+]?\d+)\) *, *\(x==([-+]?\d+)\) *([\])])/g,
-                function (match, p1, p2, p3, p4) {
-                    return "(x>" + (p1 == '(' ? '': '=') + p2 + "&&x<" +
-                        (p4 == ')' ? '' : '=') + p3 + ')';
-            }
-        );
-
-
- -
-
    -
  • -> true.
  • -
-
        expr = expr.replace('*', 1);
-
-
- -
-

Remove spaces.

-
        expr = expr.replace(/\s/g, '');
-
-
- -
-

a, b -> (a) || (b)

-
        expr = expr.replace(/\)[,] *(!*)\(/g, ")||$1(");
-
-
- -
-

Validating the expression before eval"ing it.

-
        invalidChars = /[^ \d<>=!\|&,\(\)\-\+%x\.]/g;
-
-
- -
-

Only & | ! may be before an opening bracket.

-
        invalidBeforeOpeningBracket = /[^ &!|\(] *\(/g;
-
-
- -
-

Only dot in floats.

-
        invalidDot = /\.[^\d]|[^\d]\./;
-
-        if (expr.match(invalidChars)) {
-            throw new Error('PARSE.range: invalid characters found: ' + expr);
-        }
-        if (expr.match(invalidBeforeOpeningBracket)) {
-            throw new Error('PARSE.range: invalid character before opending ' +
-                            'bracket found: ' + expr);
-        }
-        if (expr.match(invalidDot)) {
-            throw new Error('PARSE.range: invalid dot found: ' + expr);
-        }
-
-        if (JSUS.isArray(available)) {
-            i = -1, len = available.length;
-            for ( ; ++i < len ; ) {
-                x = parseInt(available[i], 10);
-                if (JSUS.eval(expr.replace(/x/g, x))) {
-                    solution.push(x);
-                }
-            }
-        }
-        else {
-            while (!available.isFinished()) {
-                x = parseInt(available.next(), 10);
-                if (JSUS.eval(expr.replace(/x/g, x))) {
-                    solution.push(x);
-                }
-            }
-        }
-        return solution;
-    };
-
-    function preprocessRange(expr) {
-        var mult = function(match, p1, p2, p3) {
-            var n1 = parseInt(p1, 10);
-            var n3 = parseInt(p3, 10);
-            return p2 == '*' ? n1*n3 : n1/n3;
-        };
-        var add = function(match, p1, p2, p3) {
-            var n1 = parseInt(p1, 10);
-            var n3 = parseInt(p3, 10);
-            return p2 == '-' ? n1 - n3 : n1 + n3;
-        };
-        var mod = function(match, p1, p2, p3) {
-            var n1 = parseInt(p1, 10);
-            var n3 = parseInt(p3, 10);
-            return n1 % n3;
-        };
-
-        while (expr.match(/([-+]?\d+) *([*\/]) *([-+]?\d+)/g)) {
-            expr = expr.replace(/([-+]?\d+) *([*\/]) *([-+]?\d+)/, mult);
-        }
-
-        while (expr.match(/([-+]?\d+) *([-+]) *([-+]?\d+)/g)) {
-            expr = expr.replace(/([-+]?\d+) *([-+]) *([-+]?\d+)/, add);
-        }
-        while (expr.match(/([-+]?\d+) *% *([-+]?\d+)/g)) {
-            expr = expr.replace(/([-+]?\d+) *% *([-+]?\d+)/, mod);
-        }
-        return expr;
-    }
-
-
-
-

- - PARSE.funcName -

-
- -
-

Returns the name of the function

- -

Function.name is a non-standard JavaScript property, -although many browsers implement it. This is a cross-browser -implementation for it.

- -

In case of anonymous functions, an empty string is returned.

-
-
-
Params
-
- func - function - The function to check -
-
Returns
-
- - string - The name of the function - -Kudos to: -http://matt.scharley.me/2012/03/09/monkey-patch-name-ie.html -
-
-
-
    if ('undefined' !== typeof Function.prototype.name) {
-        PARSE.funcName = function(func) {
-            if ('function' !== typeof func) {
-                throw new TypeError('PARSE.funcName: func must be function.');
-            }
-            return func.name;
-        };
-    }
-    else {
-        PARSE.funcName = function(func) {
-            var funcNameRegex, res;
-            if ('function' !== typeof func) {
-                throw new TypeError('PARSE.funcName: func must be function.');
-            }
-            funcNameRegex = /function\s([^(]{1,})\(/;
-            res = (funcNameRegex).exec(func.toString());
-            return (res && res.length > 1) ? res[1].trim() : "";
-        };
-    }
-
-    JSUS.extend(PARSE);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/queue.js.html b/docs/lib/queue.js.html deleted file mode 100644 index 4999918..0000000 --- a/docs/lib/queue.js.html +++ /dev/null @@ -1,359 +0,0 @@ - - - - queue.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - QUEUE -

-
- - -

Copyright(c) 2015 Stefano Balietti -MIT Licensed

-
-

Handles a simple queue of operations

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    var QUEUE = {};
-
-    QUEUE.getQueue = function() {
-        return new Queue();
-    };
-
-
-
-

- - Queue constructor -

-
- -
-
-
-
-
    function Queue() {
-
-
-
-

- - Queue.queue -

-
- -
-

The list of functions waiting to be executed.

-
-
-
        this.queue = [];
-
-
-
-

- - Queue.inProgress -

-
- -
-

The list of operations ids currently in progress.

-
-
-
        this.inProgress = {};
-    }
-
-
-
-

- - Queue.isReady -

-
- -
-

Returns TRUE if no operation is in progress

-
-
-
Returns
-
- - boolean - TRUE, if no operation is in progress -
-
-
-
    Queue.prototype.isReady = function() {
-        return JSUS.isEmpty(this.inProgress);
-    };
-
-
-
-

- - Queue.onReady -

-
- -
-

Executes the specified callback once the queue has been cleared

- -

Multiple functions to execute can be added, and they are executed -sequentially once the queue is cleared.

- -

If the queue is already cleared, the function is executed immediately.

-
-
-
Params
-
- cb - function - The callback to execute -
-
-
-
    Queue.prototype.onReady = function(cb) {
-        if ('function' !== typeof cb) {
-            throw new TypeError('Queue.onReady: cb must be function. Found: ' +
-                               cb);
-        }
-        if (JSUS.isEmpty(this.inProgress)) cb();
-        else this.queue.push(cb);
-    };
-
-
-
-

- - Queue.add -

-
- -
-

Adds an item to the inProgress index

-
-
-
Params
-
- key - string - A tentative key name -
-
Returns
-
- - string - The unique key to be used to unregister the operation -
-
-
-
    Queue.prototype.add = function(key) {
-        if (key && 'string' !== typeof key) {
-            throw new Error('Queue.add: key must be string.');
-        }
-        key = JSUS.uniqueKey(this.inProgress, key);
-        if ('string' !== typeof key) {
-            throw new Error('Queue.add: an error occurred ' +
-                            'generating unique key.');
-        }
-        this.inProgress[key] = key;
-        return key;
-    };
-
-
-
-

- - Queue.remove -

-
- -
-

Remove a specified key from the inProgress index

-
-
-
Params
-
- key - string - The key to remove from the inProgress index. -
-
-
-
    Queue.prototype.remove = function(key) {
-        if ('string' !== typeof key) {
-            throw new Error('Queue.remove: key must be string.');
-        }
-        delete this.inProgress[key];
-        if (JSUS.isEmpty(this.inProgress)) {
-            this.executeAndClear();
-        }
-    };
-
-
-
-

- - Queue.getRemoveCb -

-
- -
-

Returns a callback to remove an item from the inProgress index

- -

This method is useful when the callbacks is defined inside loops, -so that a closure is created around the variable key.

-
-
-
Params
-
- key - string - The key to remove from the inProgress index. -
-
See
-
- Queue.remove - -
-
-
-
    Queue.prototype.getRemoveCb = function(key) {
-        var that;
-        if ('string' !== typeof key) {
-            throw new Error('Queue.getRemoveCb: key must be string.');
-        }
-        that = this;
-        return function() { that.remove(key); };
-    };
-
-
-
-

- - Queue.executeAndClear -

-
- -
-

Executes sequentially all callbacks, and removes them from the queue

-
-
-
    Queue.prototype.executeAndClear = function() {
-        var i, len;
-        i = -1;
-        len = this.queue.length;
-        for ( ; ++i < len ; ) {
-            this.queue[i]();
-        }
-    };
-
-    JSUS.extend(QUEUE);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/random.js.html b/docs/lib/random.js.html deleted file mode 100644 index a2c5f9b..0000000 --- a/docs/lib/random.js.html +++ /dev/null @@ -1,788 +0,0 @@ - - - - random.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - RANDOM -

-
- - -

Copyright(c) 2016 Stefano Balietti -MIT Licensed

-
-

Generates pseudo-random numbers

-
-
-
(function(JSUS) {
-
-    "use strict";
-
-    function RANDOM() {}
-
-
-
-

- - RANDOM.random -

-
- -
-

Generates a pseudo-random floating point number between -[a,b), a inclusive and b exclusive.

-
-
-
Params
-
- a - number - The lower limit -
-
- b - number - The upper limit -
-
Returns
-
- - number - A random floating point number in [a,b) -
-
-
-
    RANDOM.random = function(a, b) {
-        var c;
-        a = ('undefined' === typeof a) ? 0 : a;
-        b = ('undefined' === typeof b) ? 0 : b;
-        if (a === b) return a;
-
-        if (b < a) {
-            c = a;
-            a = b;
-            b = c;
-        }
-        return (Math.random() * (b - a)) + a;
-    };
-
-
-
-

- - RANDOM.randomInt -

-
- -
-

Generates a pseudo-random integer between (a,b] a exclusive, b inclusive

-
-
-
Params
-
- a - number - The lower limit -
-
- b - number - The upper limit -
-
Returns
-
- - number - A random integer in (a,b] -
-
See
-
- RANDOM.random - -
-
-
-
    RANDOM.randomInt = function(a, b) {
-        if (a === b) return a;
-        return Math.floor(RANDOM.random(a, b) + 1);
-    };
-
-
-
-

- - RANDOM.sample -

-
- -
-

Generates a randomly shuffled sequence of numbers in (a,b)

- -

Both a and b are inclued in the interval.

-
-
-
Params
-
- a - number - The lower limit -
-
- b - number - The upper limit -
-
Returns
-
- - array - The randomly shuffled sequence. -
-
See
-
- RANDOM.seq - -
-
-
-
    RANDOM.sample = function(a, b) {
-        var out;
-        out = JSUS.seq(a,b);
-        if (!out) return false;
-        return JSUS.shuffle(out);
-    };
-
-
-
-

- - RANDOM.getNormalGenerator -

-
- -
-

Returns a new generator of normally distributed pseudo random numbers

- -

The generator is independent from RANDOM.nextNormal

-
-
-
Returns
-
- - function - An independent generator -
-
See
-
- RANDOM.nextNormal - -
-
-
-
    RANDOM.getNormalGenerator = function() {
-
-        return (function() {
-
-            var oldMu, oldSigma;
-            var x2, multiplier, genReady;
-
-            return function normal(mu, sigma) {
-
-                var x1, u1, u2, v1, v2, s;
-
-                if ('number' !== typeof mu) {
-                    throw new TypeError('nextNormal: mu must be number.');
-                }
-                if ('number' !== typeof sigma) {
-                    throw new TypeError('nextNormal: sigma must be number.');
-                }
-
-                if (mu !== oldMu || sigma !== oldSigma) {
-                    genReady = false;
-                    oldMu = mu;
-                    oldSigma = sigma;
-                }
-
-                if (genReady) {
-                    genReady = false;
-                    return (sigma * x2) + mu;
-                }
-
-                u1 = Math.random();
-                u2 = Math.random();
-
-
- -
-

Normalize between -1 and +1.

-
                v1 = (2 * u1) - 1;
-                v2 = (2 * u2) - 1;
-
-                s = (v1 * v1) + (v2 * v2);
-
-
- -
-

Condition is true on average 1.27 times, -with variance equal to 0.587.

-
                if (s >= 1) {
-                    return normal(mu, sigma);
-                }
-
-                multiplier = Math.sqrt(-2 * Math.log(s) / s);
-
-                x1 = v1 * multiplier;
-                x2 = v2 * multiplier;
-
-                genReady = true;
-
-                return (sigma * x1) + mu;
-
-            };
-        })();
-    };
-
-
-
-

- - RANDOM.nextNormal -

-
- -
-

Generates random numbers with Normal Gaussian distribution.

- -

User must specify the expected mean, and standard deviation a input -parameters.

- -

Implements the Polar Method by Knuth, "The Art Of Computer -Programming", p. 117.

-
-
-
Params
-
- mu - number - The mean of the distribution -param {number} sigma The standard deviation of the distribution -
-
Returns
-
- - number - A random number following a Normal Gaussian distribution -
-
See
-
- RANDOM.getNormalGenerator - -
-
-
-
    RANDOM.nextNormal = RANDOM.getNormalGenerator();
-
-
-
-

- - RANDOM.nextLogNormal -

-
- -
-

Generates random numbers with LogNormal distribution.

- -

User must specify the expected mean, and standard deviation of the -underlying gaussian distribution as input parameters.

-
-
-
Params
-
- mu - number - The mean of the gaussian distribution -
-
- sigma - number - The standard deviation of the gaussian distribution -
-
Returns
-
- - number - A random number following a LogNormal distribution -
-
See
-
- RANDOM.nextNormal - -
-
-
-
    RANDOM.nextLogNormal = function(mu, sigma) {
-        if ('number' !== typeof mu) {
-            throw new TypeError('nextLogNormal: mu must be number.');
-        }
-        if ('number' !== typeof sigma) {
-            throw new TypeError('nextLogNormal: sigma must be number.');
-        }
-        return Math.exp(RANDOM.nextNormal(mu, sigma));
-    };
-
-
-
-

- - RANDOM.nextExponential -

-
- -
-

Generates random numbers with Exponential distribution.

- -

User must specify the lambda the rate parameter of the distribution. -The expected mean of the distribution is equal to Math.pow(lamba, -1).

-
-
-
Params
-
- lambda - number - The rate parameter -
-
Returns
-
- - number - A random number following an Exponential distribution -
-
-
-
    RANDOM.nextExponential = function(lambda) {
-        if ('number' !== typeof lambda) {
-            throw new TypeError('nextExponential: lambda must be number.');
-        }
-        if (lambda <= 0) {
-            throw new TypeError('nextExponential: ' +
-                                'lambda must be greater than 0.');
-        }
-        return - Math.log(1 - Math.random()) / lambda;
-    };
-
-
-
-

- - RANDOM.nextBinomial -

-
- -
-

Generates random numbers following the Binomial distribution.

- -

User must specify the probability of success and the number of trials.

-
-
-
Params
-
- p - number - The probability of success -
-
- trials - number - The number of trials -
-
Returns
-
- - number - The sum of successes in n trials -
-
-
-
    RANDOM.nextBinomial = function(p, trials) {
-        var counter, sum;
-
-        if ('number' !== typeof p) {
-            throw new TypeError('nextBinomial: p must be number.');
-        }
-        if ('number' !== typeof trials) {
-            throw new TypeError('nextBinomial: trials must be number.');
-        }
-        if (p < 0 || p > 1) {
-            throw new TypeError('nextBinomial: p must between 0 and 1.');
-        }
-        if (trials < 1) {
-            throw new TypeError('nextBinomial: trials must be greater than 0.');
-        }
-
-        counter = 0;
-        sum = 0;
-
-        while(counter < trials){
-            if (Math.random() < p) {
-                sum += 1;
-            }
-            counter++;
-        }
-
-        return sum;
-    };
-
-
-
-

- - RANDOM.nextGamma -

-
- -
-

Generates random numbers following the Gamma distribution.

- -

This function is experimental and untested. No documentation.

-
-
-
-
-
    RANDOM.nextGamma = function(alpha, k) {
-        var intK, kDiv, alphaDiv;
-        var u1, u2, u3;
-        var x, i, tmp;
-
-        if ('number' !== typeof alpha) {
-            throw new TypeError('nextGamma: alpha must be number.');
-        }
-        if ('number' !== typeof k) {
-            throw new TypeError('nextGamma: k must be number.');
-        }
-        if (alpha < 1) {
-            throw new TypeError('nextGamma: alpha must be greater than 1.');
-        }
-        if (k < 1) {
-            throw new TypeError('nextGamma: k must be greater than 1.');
-        }
-
-        u1 = Math.random();
-        u2 = Math.random();
-        u3 = Math.random();
-
-        intK = Math.floor(k) + 3;
-        kDiv = 1 / k;
-
-        alphaDiv = 1 / alpha;
-
-        x = 0;
-        for (i = 3 ; ++i < intK ; ) {
-            x += Math.log(Math.random());
-        }
-
-        x *= - alphaDiv;
-
-        tmp = Math.log(u3) *
-            (Math.pow(u1, kDiv) /
-             ((Math.pow(u1, kDiv) + Math.pow(u2, 1 / (1 - k)))));
-
-        tmp *=  - alphaDiv;
-
-        return x + tmp;
-    };
-
-
-
-

- - RANDOM.randomString -

-
- -
-

Creates a parametric random string

-
-
-
Params
-
- len - number - The length of string (must be > 0). Default, 6. -
-
- chars - string - A code specifying which sets of characters - to use. Available symbols (default 'a'): - - 'a': lower case letters - - 'A': upper case letters - - '1': digits - - '!': all remaining symbols (excluding spaces) - - '_': spaces (it can be followed by an integer > 0 - controlling the frequency of spaces, default = 1) -
-
- useChars - boolean - If TRUE, the characters of the chars - parameter are used as they are instead of interpreted as - special symbols. Default FALSE. -
-
Returns
-
- - string - result The random string - -Kudos to: http://stackoverflow.com/questions/10726909/ - random-alpha-numeric-string-in-javascript -
-
-
-
    RANDOM.randomString = function(len, chars, useChars) {
-        var mask, result, i, nSpaces;
-        if ('undefined' !== typeof len) {
-            if ('number' !== typeof len || len < 1) {
-                throw new Error('randomString: len must a number > 0 or ' +
-                                'undefined. Found: ' + len);
-
-            }
-        }
-        if ('undefined' !== typeof chars) {
-            if ('string' !== typeof chars || chars.trim() === '') {
-                throw new Error('randomString: chars must a non-empty string ' +
-                                'or undefined. Found: ' + chars);
-
-            }
-        }
-        else if (useChars) {
-            throw new Error('randomString: useChars is TRUE, but chars ' +
-                            'is undefined.');
-
-        }
-
-
- -
-

Defaults.

-
        len = len || 6;
-        chars = chars || 'a';
-
-
- -
-

Create/use mask from chars.

-
        mask = '';
-        if (!useChars) {
-            if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz';
-            if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
-            if (chars.indexOf('1') > -1) mask += '0123456789';
-            if (chars.indexOf('!') > -1) {
-                mask += '!~`@#$%^&*()_+-={}[]:";\'<>?,./|\\';
-            }
-
-
- -
-

Check how many spaces we should add.

-
            nSpaces = chars.indexOf('_');
-            if (nSpaces > -1) {
-                nSpaces = chars.charAt(nSpaces + 1);
-
-
- -
-

nSpaces is integer > 0 or 1.

-
                nSpaces = JSUS.isInt(nSpaces, 0) || 1;
-                if (nSpaces === 1) mask += ' ';
-                else if (nSpaces === 2) mask += '  ';
-                else if (nSpaces === 3) mask += '   ';
-                else {
-                    i = -1;
-                    for ( ; ++i < nSpaces ; ) {
-                        mask += ' ';
-                    }
-                }
-            }
-        }
-        else {
-            mask = chars;
-        }
-
-        i = -1, result = '';
-        for ( ; ++i < len ; ) {
-            result += mask[Math.floor(Math.random() * mask.length)];
-        }
-        return result;
-    };
-
-
-
-

- - RANDOM.randomEmail -

-
- -
-

Creates a random email address

-
-
-
Returns
-
- - string - result The random email -
-
-
-
    RANDOM.randomEmail = function() {
-        return RANDOM.randomString(RANDOM.randomInt(5,15), '!Aa0') + '@' +
-            RANDOM.randomString(RANDOM.randomInt(3,10))  + '.' +
-            RANDOM.randomString(RANDOM.randomInt(2,3));
-    };
-
-    JSUS.extend(RANDOM);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/lib/time.js.html b/docs/lib/time.js.html deleted file mode 100644 index 7182c3e..0000000 --- a/docs/lib/time.js.html +++ /dev/null @@ -1,301 +0,0 @@ - - - - time.js - - - - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-

- - TIME -

-
- - -

Copyright(c) 2017 Stefano Balietti -MIT Licensed

-
-

Collection of static functions related to the generation, -manipulation, and formatting of time strings in JavaScript

-
-
-
(function (JSUS) {
-
-    "use strict";
-
-    function TIME() {}
-
-
- -
-

Polyfill for Date.toISOString (IE7, IE8, IE9) -Kudos: https://developer.mozilla.org/en-US/docs/Web/ -JavaScript/Reference/Global_Objects/Date/toISOString

-
    if (!Date.prototype.toISOString) {
-        (function() {
-
-            function pad(number) {
-                return (number < 10) ? '0' + number : number;
-            }
-
-            Date.prototype.toISOString = function() {
-                var ms = (this.getUTCMilliseconds() / 1000).toFixed(3);
-                return this.getUTCFullYear() +
-                    '-' + pad(this.getUTCMonth() + 1) +
-                    '-' + pad(this.getUTCDate()) +
-                    'T' + pad(this.getUTCHours()) +
-                    ':' + pad(this.getUTCMinutes()) +
-                    ':' + pad(this.getUTCSeconds()) +
-                    '.' + ms.slice(2, 5) + 'Z';
-            };
-
-        }());
-    }
-
-
-
-

- - TIME.getDate -

-
- -
-

Returns a string representation of the current date and time (ISO)

- -

String is formatted as follows:

- -

YYYY-MM-DDTHH:mm:ss.sssZ

-
-
-
Returns
-
- - string - Formatted time string YYYY-MM-DDTHH:mm:ss.sssZ -
-
-
-
    TIME.getDate = TIME.getFullDate = function() {
-        return new Date().toISOString();
-    };
-
-
-
-

- - TIME.getTime -

-
- -
-

Returns a string representation of the current time

- -

String is ormatted as follows:

- -

hh:mm:ss

-
-
-
Returns
-
- - string - Formatted time string hh:mm:ss -
-
See
-
- TIME.getTimeM - -
-
-
-
    TIME.getTime = function() {
-        var d;
-        d = new Date();
-        return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds();
-    };
-
-
-
-

- - TIME.getTimeM -

-
- -
-

Like TIME.getTime, but with millisecondsx

- -

String is ormatted as follows:

- -

hh:mm:ss:mls

-
-
-
Returns
-
- - string - Formatted time string hh:mm:ss:mls -
-
See
-
- TIME.getTime - -
-
-
-
    TIME.getTimeM = function() {
-        var d;
-        d = new Date();
-        return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() +
-            ':' + d.getMilliseconds();
-    };
-
-
-
-

- - TIME.parseMilliseconds -

-
- -
-

Parses milliseconds into an array of days, hours, minutes and seconds

-
-
-
Params
-
- ms - number - Integer representing milliseconds -
-
Returns
-
- - array - Milleconds parsed in days, hours, minutes, and seconds -
-
-
-
    TIME.parseMilliseconds = function(ms) {
-        var result, x, seconds, minutes, hours, days;
-        if ('number' !== typeof ms) {
-            throw new TypeError('TIME.parseMilliseconds: ms must be number.');
-        }
-        result = [];
-        x = ms / 1000;
-        result[4] = x;
-        seconds = x % 60;
-        result[3] = Math.floor(seconds);
-        x = x / 60;
-        minutes = x % 60;
-        result[2] = Math.floor(minutes);
-        x = x / 60;
-        hours = x % 24;
-        result[1] = Math.floor(hours);
-        x = x / 24;
-        days = x;
-        result[1] = Math.floor(days);
-        return result;
-    };
-
-
-
-

- - TIME.now -

-
- -
-

Shortcut to Date.now (when existing), or its polyfill

-
-
-
Returns
-
- - number - The timestamp now -
-
-
-
    TIME.now = 'function' === typeof Date.now ?
-        Date.now : function() { return new Date().getTime(); }
-
-    JSUS.extend(TIME);
-
-})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);
-
-
-
- - diff --git a/docs/readme b/docs/readme new file mode 100644 index 0000000..0defebd --- /dev/null +++ b/docs/readme @@ -0,0 +1,2 @@ +Documentation temporarily removed, please refer to the project website: http://nodegame.org + diff --git a/lib/array.js b/lib/array.js index 45b6a67..7096af4 100644 --- a/lib/array.js +++ b/lib/array.js @@ -95,13 +95,15 @@ if (start === Infinity) return false; if ('number' !== typeof end) return false; if (end === Infinity) return false; - if (start === end) return [start]; - + // TODO: increment zero might be fine if start=end. Check. if (increment === 0) return false; if (!JSUS.inArray(typeof increment, ['undefined', 'number'])) { return false; } - + if (start === end) { + if (!func) return [ start ]; + return [ func(start) ]; + } increment = increment || 1; func = func || function(e) {return e;}; @@ -387,9 +389,7 @@ var start = 0; var limit = S; var extracted = []; - if (!self) { - limit = S-1; - } + if (!self) limit = S-1; for (i=0; i < N; i++) { do { @@ -545,7 +545,8 @@ * * The original array is not modified. * - * @param {array} array the array to repeat + * @param {array|mixed} array the array to repeat. If not an array, it + * it will be made an array. * @param {number} times The number of times the array must be appended * to itself * @@ -553,13 +554,12 @@ */ ARRAY.rep = function(array, times) { var i, result; - if (!array) return; + if (!ARRAY.isArray(array)) array = [ array ]; if (!times) return array.slice(0); if (times < 1) { JSUS.log('times must be greater or equal 1', 'ERR'); return; } - i = 1; result = array.slice(0); for (; i < times; i++) { diff --git a/lib/dom.js b/lib/dom.js index 00a3073..f7ac3a1 100644 --- a/lib/dom.js +++ b/lib/dom.js @@ -1,6 +1,6 @@ /** * # DOM - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2019 Stefano Balietti * MIT Licensed * * Helper library to perform generic operation with DOM elements. @@ -180,6 +180,19 @@ return content; }; + /** + * ### DOM.write2 + * + * Like `DOM.write` but with support for HTML in text (no return value) + * + * @see DOM.write + */ + DOM.write2 = function(root, text) { + if ('undefined' === typeof text) text = ""; + if (JSUS.isNode(text) || JSUS.isElement(text)) root.appendChild(text); + else root.innerHTML += text; + }; + /** * ### DOM.writeln * @@ -203,6 +216,18 @@ return content; }; + /** + * ### DOM.writeln2 + * + * Like `DOM.writeln` but with support for HTML in text (no return value) + * + * @see DOM.writeln + */ + DOM.writeln2 = function(root, text, rc) { + DOM.write2(root, text); + this.add(rc || 'br', root); + }; + /** * ### DOM.sprintf * @@ -791,17 +816,20 @@ /** * ### DOM.removeClass * - * Removes a specific class from the classNamex attribute of a given element + * Removes a specific class from the className attribute of a given element * - * @param {HTMLElement} el An HTML element + * @param {HTMLElement|object} elem An HTML element, or an object with + * a className property if force is TRUE * @param {string} className The name of a CSS class already in the element + * @param {boolean} force Optional. If TRUE, the method is applied also + * to non HTMLElements * * @return {HTMLElement|undefined} The HTML element with the removed * class, or undefined if the inputs are misspecified */ - DOM.removeClass = function(elem, className) { - var regexpr, o; - if (!DOM.isElement(elem)) { + DOM.removeClass = function(elem, className, force) { + var regexpr; + if (!force && !DOM.isElement(elem)) { throw new TypeError('DOM.removeClass: elem must be HTMLElement. ' + 'Found: ' + elem); } @@ -811,7 +839,7 @@ 'HTMLElement. Found: ' + className); } regexpr = new RegExp('(?:^|\\s)' + className + '(?!\\S)'); - o = elem.className = elem.className.replace(regexpr, '' ); + elem.className = elem.className.replace(regexpr, '' ); } return elem; }; @@ -823,14 +851,17 @@ * * Takes care not to overwrite already existing classes. * - * @param {HTMLElement} elem An HTML element + * @param {HTMLElement|object} elem An HTML element, or an object with + * a className property if force is TRUE * @param {string|array} className The name/s of CSS class/es + * @param {boolean} force Optional. If TRUE, the method is applied also + * to non HTMLElements * * @return {HTMLElement} The HTML element with the additional * class, or undefined if the inputs are misspecified */ - DOM.addClass = function(elem, className) { - if (!DOM.isElement(elem)) { + DOM.addClass = function(elem, className, force) { + if (!force && !DOM.isElement(elem)) { throw new TypeError('DOM.addClass: elem must be HTMLElement. ' + 'Found: ' + elem); } @@ -1183,7 +1214,7 @@ */ DOM.blinkTitle = (function(id) { var clearBlinkInterval, finalTitle, elem; - clearBlinkInterval = function(opts) { + clearBlinkInterval = function() { clearInterval(id); id = null; if (elem) { @@ -1355,6 +1386,56 @@ return !dim ? { x: x, y: y } : dim === 'x' ? x : y; }; + /** + * ### DOM.makeTabbable + * + * Adds the tabindex property to an HTML element + * + * @param {HTMLElement} elem The element to make tabbable + * @param {object} opts Optional. Configuration options, avalable: + * - index: the tabindex, default 0 + * - clickable: if TRUE, calls DOM.makeClickable on the element. + * Default: FALSE + * + * @return {HTMLElement} The tabbable element + */ + DOM.makeTabbable = function(elem, opts) { + opts = opts || {}; + elem.setAttribute('tabindex', opts.index || 0); + if (opts.clicklable) DOM.makeClickable(elem); + return elem; + }; + + /** + * ### DOM.makeClickable + * + * Adds a listener that clicks on the element if SPACE or ENTER are hit + * + * The kewydown event listener callback is available under `cb`. + * + * @param {HTMLElement} elem The element to make clickable + * @param {boolean} add If FALSE, the listener is removed. Default: TRUE + * + * @return {HTMLElement} The clickable element + */ + DOM.makeClickable = (function() { + function clickCb(event) { + if (event.keyCode === 32 || event.keyCode === 13) { + event.preventDefault(); + event.target.click(); + } + } + var cb; + cb = function(elem, add) { + if ('undefined' === typeof add) add = true; + if (add) elem.addEventListener('keydown', clickCb); + else elem.removeEventListener('keydown', clickCb); + return elem; + }; + cb.cb = clickCb; + return cb; + })(); + // ## Helper methods /** diff --git a/lib/fs.js b/lib/fs.js index b2a2d15..1883596 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -1,6 +1,6 @@ /** * # FS - * Copyright(c) 2016 Stefano Balietti + * Copyright(c) 2018 Stefano Balietti * MIT Licensed * * Collection of static functions related to file system operations. @@ -21,8 +21,8 @@ } var resolve = require('resolve'), - path = require('path'), - fs = require('fs') + path = require('path'), + fs = require('fs'); function FS() {} @@ -67,10 +67,10 @@ 'string or undefined. Found: ' + basedir); } // Added this line because it might fail. - if (module === 'JSUS') return path.resolve(__dirname, '..') + '/'; + if (module === 'JSUS') return path.resolve(__dirname, '..') + path.sep; str = resolve.sync(module, {basedir: basedir || __dirname}); stop = str.indexOf(module) + module.length; - return str.substr(0, stop) + '/'; + return str.substr(0, stop) + path.sep; }; /** @@ -147,7 +147,7 @@ }; } - if (dir[dir.length] !== '/') dir = dir + '/'; + if (dir[dir.length] !== path.sep) dir = dir + path.sep; fs.readdir(dir, function(err, files) { var asq, mycb; @@ -209,7 +209,7 @@ return false; } - dirOut = path.resolve(dirOut) + '/'; + dirOut = path.resolve(dirOut) + path.sep; dirs = [dirIn, dirOut]; for (i = 0; i < 2; i++) { diff --git a/lib/obj.js b/lib/obj.js index 498c66d..c2e474b 100644 --- a/lib/obj.js +++ b/lib/obj.js @@ -1,6 +1,6 @@ /** * # OBJ - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2019 Stefano Balietti * MIT Licensed * * Collection of static functions to manipulate JavaScript objects @@ -1220,14 +1220,13 @@ /** * ## OBJ.melt * - * Creates a new object with the specified combination of - * properties - values + * Creates a new object with specific combination of properties - values * * The values are assigned cyclically to the properties, so that * they do not need to have the same length. E.g. * * ```javascript - * J.createObj(['a','b','c'], [1,2]); // { a: 1, b: 2, c: 1 } + * J.melt(['a','b','c'], [1,2]); // { a: 1, b: 2, c: 1 } * ``` * @param {array} keys The names of the keys to add to the object * @param {array} values The values to associate to the keys @@ -1283,6 +1282,25 @@ return name; }; + /** + * ## OBJ.randomKey + * + * Returns a random key from an existing object + * + * @param {object} obj The object from which the key will be extracted + * + * @return {string} The random key + */ + OBJ.randomKey = function(obj) { + var keys; + if ('object' !== typeof obj) { + throw new TypeError('OBJ.randomKey: obj must be object. ' + + 'Found: ' + obj); + } + keys = Object.keys(obj); + return keys[ keys.length * Math.random() << 0]; + }; + /** * ## OBJ.augment * @@ -1406,7 +1424,8 @@ OBJ.getKeyByValue = function(obj, value, allKeys) { var key, out; if ('object' !== typeof obj) { - throw new TypeError('OBJ.getKeyByValue: obj must be object.'); + throw new TypeError('OBJ.getKeyByValue: obj must be object. ' + + 'Found: ' + obj); } if (allKeys) out = []; for (key in obj) { @@ -1420,6 +1439,40 @@ return out; }; + /** + * ## OBJ.reverseObj + * + * Returns a new object where they keys and values are switched + * + * @param {object} obj The object to reverse + * @param {function} cb Optional. A callback processing a key-value pair. + * Takes as inputs current key and value and must return an array with + * updated key and value: [ newKey, newValue ]. + * + * @return {object} The reversed object + */ + OBJ.reverseObj = function(o, cb) { + var k, res; + if (cb && 'function' !== typeof cb) { + throw new TypeError('OBJ.reverseObj: cb must be function or ' + + 'undefined. Found: ' + cb); + } + res = {}; + if (!o) return res; + for (k in o) { + if (o.hasOwnProperty(k)) { + if (cb) { + k = cb(k, o[k]); + res[k[1]] = res[k[0]]; + } + else { + res[o[k]] = k; + } + } + } + return res; + }; + JSUS.extend(OBJ); })('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS); diff --git a/lib/parse.js b/lib/parse.js index 309e972..7ef3fad 100644 --- a/lib/parse.js +++ b/lib/parse.js @@ -61,6 +61,35 @@ decodeURIComponent(results[1].replace(/\+/g, " ")); }; + /** + * ## PARSE.isMobileAgent + * + * Returns TRUE if a user agent is for a mobile device + * + * @param {string} agent Optional. The user agent to check. Default: + * navigator.userAgent + * + * @return {boolean} TRUE if a user agent is for a mobile device + */ + PARSE.isMobileAgent = function(agent) { + var rx; + if (!agent){ + if (!navigator) { + throw new Error('JSUS.isMobileAgent: agent undefined and ' + + 'no navigator. Are you in the browser?'); + } + agent = navigator.userAgent; + } + else if ('string' !== typeof agent) { + throw new TypeError('JSUS.isMobileAgent: agent must be undefined ' + + 'or string. Found: ' + agent); + } + rx = new RegExp('Android|webOS|iPhone|iPad|BlackBerry|' + + 'Windows Phone|Opera Mini|IEMobile|Mobile', 'i'); + + return rx.test(agent); + }; + /** * ## PARSE.tokenize * @@ -177,6 +206,8 @@ * encoded by `PARSE.stringify` * * @param {string} str The string to decode + * @param {function} cb Optional. A callback to apply to each decoded item + * * @return {mixed} The decoded value * * @see JSON.parse @@ -192,6 +223,8 @@ len_inf = PARSE.marker_inf.length, len_minus_inf = PARSE.marker_minus_inf.length; + var customCb; + function walker(o) { var i; if ('object' !== typeof o) return reviver(o); @@ -201,6 +234,8 @@ else o[i] = reviver(o[i]); } } + // On the full object. + if (customCb) customCb(o); return o; } @@ -233,12 +268,13 @@ return -Infinity; } - } + return value; } - return function(str) { + return function(str, cb) { + customCb = cb; return walker(JSON.parse(str)); }; @@ -254,19 +290,21 @@ * @param {mixed} n The value to check * @param {number} lower Optional. If set, n must be greater than lower * @param {number} upper Optional. If set, n must be smaller than upper + * @param {boolean} leq Optional. If TRUE, n can also be equal to lower + * @param {boolean} ueq Optional. If TRUE, n can also be equal to upper * * @return {boolean|number} The parsed integer, or FALSE if none was found * * @see PARSE.isFloat * @see PARSE.isNumber */ - PARSE.isInt = function(n, lower, upper) { + PARSE.isInt = function(n, lower, upper, leq, ueq) { var regex, i; regex = /^-?\d+$/; if (!regex.test(n)) return false; i = parseInt(n, 10); if (i !== parseFloat(n)) return false; - return PARSE.isNumber(i, lower, upper); + return PARSE.isNumber(i, lower, upper, leq, ueq); }; /** @@ -279,18 +317,20 @@ * @param {mixed} n The value to check * @param {number} lower Optional. If set, n must be greater than lower * @param {number} upper Optional. If set, n must be smaller than upper + * @param {boolean} leq Optional. If TRUE, n can also be equal to lower + * @param {boolean} ueq Optional. If TRUE, n can also be equal to upper * * @return {boolean|number} The parsed float, or FALSE if none was found * * @see PARSE.isInt * @see PARSE.isNumber */ - PARSE.isFloat = function(n, lower, upper) { + PARSE.isFloat = function(n, lower, upper, leq, ueq) { var regex; regex = /^-?\d*(\.\d+)?$/; if (!regex.test(n)) return false; if (n.toString().indexOf('.') === -1) return false; - return PARSE.isNumber(n, lower, upper); + return PARSE.isNumber(n, lower, upper, leq, ueq); }; /** @@ -303,17 +343,23 @@ * @param {mixed} n The value to check * @param {number} lower Optional. If set, n must be greater than lower * @param {number} upper Optional. If set, n must be smaller than upper + * @param {boolean} leq Optional. If TRUE, n can also be equal to lower + * @param {boolean} ueq Optional. If TRUE, n can also be equal to upper * * @return {boolean|number} The parsed number, or FALSE if none was found * * @see PARSE.isInt * @see PARSE.isFloat */ - PARSE.isNumber = function(n, lower, upper) { - if (isNaN(n) || !isFinite(n)) return false; + PARSE.isNumber = function(n, lower, upper, leq, ueq) { + if (isNaN(n) || !isFinite(n) || n === "") return false; n = parseFloat(n); - if ('number' === typeof lower && n < lower) return false; - if ('number' === typeof upper && n > upper) return false; + if ('number' === typeof lower && (leq ? n < lower : n <= lower)) { + return false; + } + if ('number' === typeof upper && (ueq ? n > upper : n >= upper)) { + return false; + } return n; }; diff --git a/lib/random.js b/lib/random.js index 9ab8bf7..cb3ed5c 100644 --- a/lib/random.js +++ b/lib/random.js @@ -36,7 +36,7 @@ } else { b = a; - a = 0; + a = 0; } } if (a === b) return a; @@ -68,6 +68,44 @@ return Math.floor(RANDOM.random(a, b) + 1); }; + /** + * ## RANDOM.randomDate + * + * Generates a pseudo-random date between + * + * @param {Date} startDate Optional. The lower date. Default: 01-01-1900. + * @param {Date} endDate Optional. The upper date. Default: today. + * + * @return {number} A random date in the chosen interval + * + * @see RANDOM.randomDate + */ + RANDOM.randomDate = (function() { + function isValidDate(date) { + return date && + Object.prototype.toString.call(date) === "[object Date]" && + !isNaN(date); + } + return function(startDate, endDate) { + if ('undefined' === typeof startDate) { + startDate = new Date("1900"); + } + else if (!isValidDate(startDate)) { + throw new TypeError('randomDate: startDate must be a valid ' + + 'date. Found: ' + startDate); + } + if ('undefined' === typeof endDate) { + endDate = new Date(); + } + else if (!isValidDate(endDate)) { + throw new TypeError('randomDate: endDate must be a valid ' + + 'date or undefined. Found: ' + endDate); + } + return new Date(startDate.getTime() + Math.random() * + (endDate.getTime() - startDate.getTime())); + }; + })(); + /** * ## RANDOM.sample * diff --git a/lib/time.js b/lib/time.js index 64e7402..d1dc4f9 100644 --- a/lib/time.js +++ b/lib/time.js @@ -1,6 +1,6 @@ /** * # TIME - * Copyright(c) 2017 Stefano Balietti + * Copyright(c) 2021 Stefano Balietti * MIT Licensed * * Collection of static functions related to the generation, @@ -12,28 +12,34 @@ function TIME() {} + function pad(number) { + return (number < 10) ? '0' + number : number; + } + + function _getTime(ms) { + var d, res; + d = new Date(); + res = pad(d.getHours()) + ':' + pad(d.getMinutes()) + ':' + + pad(d.getSeconds()); + if (ms) res += ':' + pad(d.getMilliseconds()); + return res; + } + // Polyfill for Date.toISOString (IE7, IE8, IE9) // Kudos: https://developer.mozilla.org/en-US/docs/Web/ // JavaScript/Reference/Global_Objects/Date/toISOString if (!Date.prototype.toISOString) { - (function() { - function pad(number) { - return (number < 10) ? '0' + number : number; - } - - Date.prototype.toISOString = function() { - var ms = (this.getUTCMilliseconds() / 1000).toFixed(3); - return this.getUTCFullYear() + - '-' + pad(this.getUTCMonth() + 1) + - '-' + pad(this.getUTCDate()) + - 'T' + pad(this.getUTCHours()) + - ':' + pad(this.getUTCMinutes()) + - ':' + pad(this.getUTCSeconds()) + - '.' + ms.slice(2, 5) + 'Z'; - }; - - }()); + Date.prototype.toISOString = function() { + var ms = (this.getUTCMilliseconds() / 1000).toFixed(3); + return this.getUTCFullYear() + + '-' + pad(this.getUTCMonth() + 1) + + '-' + pad(this.getUTCDate()) + + 'T' + pad(this.getUTCHours()) + + ':' + pad(this.getUTCMinutes()) + + ':' + pad(this.getUTCSeconds()) + + '.' + ms.slice(2, 5) + 'Z'; + }; } /** @@ -65,9 +71,7 @@ * @see TIME.getTimeM */ TIME.getTime = function() { - var d; - d = new Date(); - return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds(); + return _getTime(); }; /** @@ -84,10 +88,7 @@ * @see TIME.getTime */ TIME.getTimeM = function() { - var d; - d = new Date(); - return d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds() + - ':' + d.getMilliseconds(); + return _getTime(true); }; /** @@ -121,7 +122,6 @@ return result; }; - /** * ## TIME.now * diff --git a/package.json b/package.json index e3886b7..50484e4 100644 --- a/package.json +++ b/package.json @@ -1,8 +1,21 @@ { "name": "JSUS", "description": "JavaScript UtilS. Extended functional programming support. JSUS helps!", - "version": "1.0.0", - "keywords": [ "functional", "functional programming", "util", "general", "array", "eval", "time", "date", "object", "nodeGame"], + "version": "1.7.2", + "keywords": [ + "functional", + "functional programming", + "util", + "general", + "array", + "eval", + "time", + "date", + "object", + "dom", + "parse", + "nodeGame" + ], "main": "jsus.js", "author": "Stefano Balietti ", "license": "MIT", @@ -13,10 +26,12 @@ "fs-extra": "*" }, "devDependencies": { - "mocha": ">= 0.3.0", - "should": ">= 0.5.1" + "mocha": "^6.0.2", + "should": "^4.4.1" + }, + "engines": { + "node": ">=0.10.0" }, - "engines": { "node": ">=0.10.0" }, "repository": { "type": "git", "url": "https://github.com/nodeGame/JSUS.git" diff --git a/test/test.array.js b/test/test.array.js index 04c10f2..e7d0e9b 100644 --- a/test/test.array.js +++ b/test/test.array.js @@ -257,6 +257,9 @@ describe('ARRAY: ', function(){ JSUS.rep(array, 3).should.eql([1,2,3,4,5,1,2,3,4,5,1,2,3,4,5]); }); + it('should create the array and replicate it 3 times', function(){ + JSUS.rep(1, 3).should.eql([1,1,1]); + }); }); describe('#distinct()', function() { diff --git a/test/test.parse.js b/test/test.parse.js index 36bf184..d0ef3b1 100644 --- a/test/test.parse.js +++ b/test/test.parse.js @@ -321,6 +321,39 @@ describe('PARSE: ', function() { it('should parse and return int number (interval bad)', function() { JSUS.isNumber('1.1', 4, 5).should.be.false; }); + it('should parse and return int number (interval bad)', function() { + JSUS.isNumber('').should.be.false; + }); + }); + + describe('#isNumber() with ueq and leg', function() { + it('should parse and return the float number', function() { + JSUS.isNumber('1.1', 1).should.be.eql(1.1); + }); + it('should parse and return false (upper)', function() { + JSUS.isNumber('3', 0, 2).should.be.eql(false); + }); + it('should parse and return false (>upper leq)', function() { + JSUS.isNumber('3', 0, 2, true).should.be.eql(false); + }); + it('should parse and return 3 (==upper ueq), ', function() { + JSUS.isNumber('3', 0, 3, true, true).should.be.eql(3); + }); + it('should parse and return 3 (==upper ueq 2)', function() { + JSUS.isNumber('3', undefined, 3, undefined, true).should.be.eql(3); + }); }); });