Permalink
Browse files

adds appJS

  • Loading branch information...
1 parent 3c7fd48 commit 6731d497807e01d1b5ad682f430f22292b0a08b8 @Gloorian committed Aug 25, 2012
Showing with 3,079 additions and 0 deletions.
  1. +521 −0 app.array.js
  2. +72 −0 app.class.js
  3. +110 −0 app.css.js
  4. +1,377 −0 app.dom.js
  5. +179 −0 app.js
  6. +245 −0 app.number.js
  7. +67 −0 app.prefs.js
  8. +129 −0 app.request.js
  9. +245 −0 app.string.js
  10. +134 −0 app.translate.js
View
521 app.array.js
@@ -0,0 +1,521 @@
+//v2.0
+(function() {
+ /**
+ *This module provides many functions related to the Array Object
+ *@module appJS
+ *@submodule Array
+ *@class Array
+ *@static
+ **/
+
+ appJS.array = appJS.array || {};
+
+ /**
+ *Alias for compatibility with {{#crossLink "Core/forEach"}}appJS.forEach{{/crossLink}}
+ *@method forEach
+ **/
+ appJS.array.forEach = function(array, cb, bind) {
+ appJS.forEach(array, cb, bind);
+ };
+
+ /**
+ *Clones an array
+ *@method clone
+ *@return {array} The clone of the array
+ *@param array {array} The array to be cloned
+ *@example
+ * appJS.array.clone(['sandwich', 'beurre']); //['sandwich', 'beurre']
+ **/
+ appJS.array.clone = function(array) {
+ if(appJS.isArray(array)) {
+ var retour = [];
+ appJS.array.forEach(array, function(el) {
+ retour.push(el);
+ });
+ return retour;
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Returns true if the callback returns true for every item
+ *@method every
+ *@return {boolean} True if the callback returns true for every item, false otherwise
+ *@param array {array} Array to be traversed
+ *@param cb {function|regexp|any} Function to be called for each item. Can be a regexp or a simple value to compare.
+ * @param cb.value {any} Value of the Element being traversed
+ * @param cb.index {number} Index of the element being traversed
+ * @param cb.array {array} Array being traversed
+ *@param [bind] {object} Value of this in the function
+ *@example
+ * appJS.array.every(['sandwich', 3], function(item) { return appJS.isNumber(item); }); //false
+ * appJS.array.every(['sandwich', 3], /^\d+$/); //false. Same as above.
+ * appJS.array.every(['sandwich', 'sandstorm'], function(item) { return appJS.isString(item); }); //true
+ **/
+ appJS.array.every = function(array, cb, bind) {
+ var t;
+ if(bind) {
+ t = bind;
+ }
+ if(appJS.isArray(array)) {
+ var trues = 0;
+ var func;
+ if(appJS.isFunction(cb)) {
+ func = function(item, index, arr) {
+ return cb.call(t, item, index, array) === true;
+ };
+ } else if (appJS.isRegExp(cb)) {
+ func = function(item) {
+ return cb.test(item);
+ };
+ } else {
+ func = function(item) {
+ return cb === item;
+ };
+ }
+ appJS.array.forEach(array, function(item, index, arr) {
+ var retour = func(item, index, arr);
+ if(retour === true) {
+ trues++;
+ }
+ });
+ return (trues === array.length);
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Returns an array of all the value that return true when called with the cb.
+ *@method filter
+ *@return {array|null} Array of value that returns true in the callback, null if none corresponds
+ *@param array {array} Array to be traversed
+ *@param cb {function|any} Function to be called for each item. If not a function, will compare the value.
+ * @param cb.value {any} Value of the Element being traversed
+ * @param cb.index {number} Index of the element being traversed
+ * @param cb.array {array} Array being traversed
+ *@param [bind] {object} Value of this in the function
+ *@example
+ * appJS.array.filter([3, 'sandwich', null], function(item) { return appJS.isNumber(item); }); //[3]
+ * appJS.array.filter([3, 'sandwich', null], function(item) { return item == null; }); //[null]
+ * appJS.array.filter([3, 'sandwich', null], /^(.[^\d])+$/); //['sandwich', null]
+ **/
+ appJS.array.filter = function(array, cb, bind) {
+ if(appJS.isArray(array)) {
+ var retourFunc;
+ if(appJS.isFunction(cb)) {
+ retourFunc = function(item) {
+ return cb(item) === true;
+ };
+ } else if (appJS.isRegexp(cb)) {
+ retourFunc = function(item) {
+ return cb.test(item);
+ };
+ } else {
+ retourFunc = function(item) {
+ return cb === item;
+ };
+ }
+ var retour = [];
+ appJS.array.forEach(array, function(item, index, array) {
+ if(func(item, index, array)) {
+ retour.push(item);
+ }
+ });
+ return retour || null;
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Returns the index of the element found in an array.
+ *@method indexOf
+ *@param array {array} Array where to search
+ *@param item {any} What to search in the array. Can be a function with each values of the array as parameter, a regexp or a value that will be compared.
+ *@param [from=0] {number} Where to search from. Corresponds to the first index where to search.
+ *@return {number} index of the match or -1 if no match.
+ *@example
+ * appJS.array.indexOf(['sandwich', 'jambon'], 'sandwich'); //0
+ * appJS.array.indexOf(['sandwich', 'jambon'], 'sandwich', 1); //-1
+ * appJS.array.indexOf(['sandwich', 'jambon'], /j/); //0
+ * appJS.array.indexOf(['sandwich', 'jambon'], function(item) { return appJS.isNumber(item); }); //-1
+ **/
+ appJS.array.indexOf = function(array, item, from) {
+ if(appJS.isArray(array)) {
+ var f = 0,
+ position = -1;
+ if(from) {
+ if(appJS.isNumber(from) && from < array.length && from >= 0) {
+ f = from;
+ } else {
+ throw new Error('if from is specified, must be a number between 0 and array.length');
+ }
+ }
+ var retourFunc;
+ if(appJS.isFunction(item)) {
+ retourFunc = function(el) { return item(el) === true; };
+ } else if (appJS.isRegexp(item)) {
+ retourFunc = function(el) { return item.test(el) === true; };
+ } else {
+ retourFunc = function(el) { return item === el; };
+ }
+ appJS.array.forEach(array, function(el, index, array) {
+ if(retourFunc(el) && position === -1 && index >= f) {
+ position = index;
+ }
+ });
+ return position;
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Returns an array with all the indexes of the element matching to the search.
+ *@method indexOfAll
+ *@param array {array} Array where to search
+ *@param item {any} What to search in the array. Can be a function with each values of the array as parameter, a regexp or a value that will be compared.
+ *@param [from=0] {number} Where to search from. Corresponds to the first index where to search.
+ *@return {array|number} Returns an array made of the indexes of the matches or -1 if no match.
+ *@example
+ * appJS.array.indexOfAll(['sandwich', 'jambon', 'sodebo'], /s/); //[0, 2]
+ * appJS.array.indexOfAll(['sandwich', 'jambon'], 'sandwich', 1); //-1
+ * appJS.array.indexOfAll(['sandwich', 'jambon', 'jam'], /j/); //[1, 2]
+ * appJS.array.indexOfAll(['sandwich', 'jambon'], function(item) { return appJS.isString(item) && item.length > 2; }); //[0, 1]
+ **/
+ appJS.array.indexOfAll = function(array, item, from) {
+ if(appJS.isArray(array)) {
+ var f = 0,
+ position = [];
+ if(from) {
+ if(appJS.isNumber(from) && from < array.length && from >= 0) {
+ f = from;
+ } else {
+ throw new Error('if from is specified, must be a number between 0 and array.length');
+ }
+ }
+ var retourFunc;
+ if(appJS.isFunction(item)) {
+ retourFunc = function(el) { return item(el) === true; };
+ } else if (appJS.isRegexp(item)) {
+ retourFunc = function(el) { return item.test(el) === true; };
+ } else {
+ retourFunc = function(el) { return item === el; };
+ }
+ appJS.array.forEach(array, function(el, index, array) {
+ if(retourFunc(el) && index >= f) {
+ position.push(index);
+ }
+ });
+ return (position.length !== 0) ? position : -1;
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Creates a new array with the results of calling a provided function on every element in the array.
+ *@method map
+ *@param array {array} Array where to call the function on.
+ *@param cb {function|any} Function to be called for each item. If cb is anything else than a function, the map will look for array[cb].
+ * @param cb.value {any} Value of the Element being traversed
+ * @param cb.index {number} Index of the element being traversed
+ * @param cb.array {array} Array being traversed
+ *@param [bind] {object} Value of this in the function
+ *@return {array} Array of items
+ *@example
+ * appJS.array.map([1, 2, 3], function(item, index) { return item * index; }); //[0, 2, 6]
+ **/
+ appJS.array.map = function(array, cb, bind) {
+ var b = bind ? bind : undefined;
+ if(appJS.isArray(array)) {
+ var retour = [];
+ appJS.array.forEach(array, function(item, index, array) {
+ if(appJS.isFunction(cb)) {
+ retour.push(cb.call(bind, item, index, array));
+ } else {
+ if(typeof array[cb] !== 'undefined') {
+ retour.push(array[cb]);
+ } else {
+ retour.push(null);
+ }
+ }
+ });
+ return retour;
+ } else {
+ throw new Error('array is not an Array');
+ }
+ };
+ /**
+ *Returns true if at least one element in the array satisfies the provided testing function.
+ *@method some
+ *@param array {array} Array where to call the function on.
+ *@param cb {function} Function to be called for each item. Can be a regexp or a simple value to compare.
+ * @param cb.value {any} Value of the Element being traversed
+ * @param cb.index {number} Index of the element being traversed
+ * @param cb.array {array} Array being traversed
+ *@param [bind] {object} Value of this in the function
+ *@return {boolean} True if one item satisfies the function, false otherwise.
+ *@example
+ * appJS.array.some(['sandwich', 3, 'beurre'], /\d/); //true
+ * appJS.array.some(['sandwich', 3, 'beurre'], function(item, index) { return typeof item === typeof index; }); //true
+ * appJS.array.some(['sandwich', 3, 'beurre'], function(item) { return appJS.isDate(item); });; //false
+ **/
+ appJS.array.some = function(array, cb, bind) {
+ var b = bind ? bind : undefined;
+ if(appJS.isArray(array)) {
+ var func;
+ if(appJS.isFunction(cb)) {
+ func = function(item, index, arr) {
+ return cb.call(t, item, index, array) === true;
+ };
+ } else if (appJS.isRegExp(cb)) {
+ func = function(item) {
+ return cb.test(item);
+ };
+ } else {
+ func = function(item) {
+ return cb === item;
+ };
+ }
+ var retour = 0;
+ appJS.array.forEach(array, function(item, index, array) {
+ if(func(item, index, array) === true) {
+ retour++;
+ }
+ });
+ return (retour > 0) ? true : false;
+ } else {
+ throw new Error('array is not an Array');
+ }
+ };
+ /**
+ *Exclude all the elements of an array that matches the function, regexp or value.
+ *@method exclude
+ *@param array {array} Array where to call the function on.
+ *@param cb {function|regexp|any} Function to be called for each item. or regex or any value.
+ *@param cb.item {any} If cb is a function, it takes one parameter.
+ *@return {array} Array without the element removed
+ *@example
+ * appJS.array.exclude([3, 'sandwich', null], function(item) { return appJS.isNumber(item); }); //['sandwich', null]
+ * appJS.array.exclude([3, 'sandwich', null], function(item) { return item === null; }); //[3, 'sandwich']
+ * appJS.array.exclude([3, 'sandwich', null], /^(.[^\d])+$/); //[3]
+ *
+ **/
+ appJS.array.exclude = function(array, cb) {
+ if(appJS.isArray(array)) {
+ var retour = [],
+ retourFunc;
+ if(appJS.isFunction(cb)) {
+ retourFunc = function(item) {
+ return cb(item) === true;
+ };
+ } else if (appJS.isRegexp(cb)) {
+ retourFunc = function(item) {
+ return cb.test(item);
+ };
+ } else {
+ retourFunc = function(item) {
+ return cb === item;
+ };
+ }
+ appJS.forEach(array, function(item) {
+ if(!retourFunc(item)) {
+ retour.push(item);
+ }
+ });
+ return retour;
+ } else {
+ throw new TypeError('array must be an Array');
+ }
+ };
+ /*
+ *Creates an object with key-value pairs based on the array of keywords passed in and the current content of the array.
+ *@method associate
+ *@param array {array} Its items will be used as values in the object returned
+ *@param array2 {array} Its items will be used as keys in the object returned
+ *@return {object} New associated object
+ *@beta
+ */
+ appJS.array.associate = function(array, array2) {
+ if(appJS.isArray(array)) {
+ if(appJS.isArray(array2)) {
+ if(array.length === array2.length) {
+ var retour = {};
+ for(var i = 0, t = array.length ; i < t ; i++) {
+ retour[array2[i]] = array[i];
+ }
+ return retour;
+ } else {
+ throw new Error('Both arrays must have the same length');
+ }
+ } else {
+ throw new Error('array2 must be an Array');
+ }
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Tests an array for the presence of an item
+ *@method contains
+ *@param array {array} Array where to search
+ *@param item {any} What to search in the array
+ *@return {boolean} True if the array contains the item, otherwise false.
+ *@example
+ * appJS.array.contains(['sandwich', 'beurre'], 'sandwich'); //true
+ * appJS.array.contains(['sandwich', 'beurre'], /s/); //true
+ **/
+ appJS.array.contains = function(array, item) {
+ return (appJS.array.indexOf(array, item) === -1) ? false : true;
+ };
+ /**
+ *Appends the content of an array at the end of another one.
+ *@method append
+ *@param array {array} Array where append
+ *@param array2 {array} Array whose content will be appended
+ *@return {array} Result of the appending
+ *@example
+ * appJS.array.append(['sandwich', 'beurre'], ['jambon', 3]); //['sandwich', 'beurre', 'jambon', 3]
+ **/
+ appJS.array.append = function(array, array2) {
+ if(appJS.isArray(array)) {
+ if(appJS.isArray(array2)) {
+ appJS.array.forEach(array2, function(item, index, arr) {
+ array.push(item);
+ });
+ return array;
+ } else {
+ throw new Error('array2 must be an array');
+ }
+ } else {
+ throw new Error('array must be an array');
+ }
+ };
+ /**
+ *Returns a random item in an array
+ *@method getRand
+ *@param array {array} Source
+ *@return {any} Random value from the source
+ *@example
+ * appJS.array.getRand(['sandwich', 'beurre', 'jambon']); //'sandwich'
+ * appJS.array.getRand(['sandwich', 'beurre', 'jambon']); //'beurre'
+ **/
+ appJS.array.getRand = function(array) {
+ if(appJS.isArray(array)) {
+ if(array.length === 0) { return null; }
+ var number = Math.floor(Math.random() * array.length);
+ return array[number];
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Adds an item only if it is not already present
+ *@method includes
+ *@param array {array} The array source
+ *@param item {any} The item to add
+ *@return {array} Source with, if not present before, the item
+ *@example
+ * appJS.array.includes(['sandwich', 'jambon'], 4); //['sandwich', 'jambon']
+ * appJS.array.includes(['sandwich', 'jambon'], 'sandwich'); //['sandwich', 'jambon']
+ **/
+ appJS.array.includes = function(array, item) {
+ if(appJS.isArray(array)) {
+ if(!appJS.array.contains(array, item)) {
+ array.push(item);
+ return array;
+ } else {
+ return array;
+ }
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Combine two arrays but doesn't allow duplicates
+ *@method combine
+ *@param array {array} First array to combine
+ *@param array2 {array} Second array to combine
+ *@return {array} Mix of the two array provided
+ *@example
+ * appJS.array.combine(['sandwich', 'jambon'], ['jambon', 3]); //['sandwich', 'jambon', 3]
+ **/
+ appJS.array.combine = function(array, array2) {
+ if(appJS.isArray(array)) {
+ if(appJS.isArray(array2)) {
+ appJS.array.forEach(array2, function(item, index, arr) {
+ if(!appJS.array.contains(array, item)) {
+ array.push(item);
+ }
+ });
+ return array;
+ } else {
+ throw new Error('array2 must be an array');
+ }
+ } else {
+ throw new Error('array must be an array');
+ }
+ };
+ /**
+ *Returns the first defined value of an array, or null
+ *@method pick
+ *@param array {array} Array source where to search
+ *@return {any} First defined value
+ *@example
+ * appJS.array.pick([null, 3]); //3
+ **/
+ appJS.array.pick = function(array) {
+ if(appJS.isArray(array)) {
+ var good;
+ appJS.array.forEach(array, function(item) {
+ if(typeof item !== 'undefined' && item !== null && typeof good === 'undefined') {
+ good = item;
+ }
+ });
+ return typeof good !== 'undefined' ? good : null;
+ } else {
+ throw new Error('array must be an Array');
+ }
+ };
+ /**
+ *Removes undefined or null parts of an array (or all parts that are false if all is set to true)
+ *@method compact
+ *@param array {Array} Array to apply the function
+ *@param all {boolean} If set to true, all falsy part will be removed (false for object that are == true)
+ *@return {array|null} Array of value or null if all are removed
+ *@example
+ * appJS.array.compact([3, null, 'sandwich', '', undefined]); //[3, 'sandwich', '']
+ * appJS.array.compact([null, undefined]); //null
+ * appJS.array.compact([false, null, 'sandwich', '', undefined], true); //['sandwich']
+ **/
+ appJS.array.compact = function(array, all) {
+ if(!appJS.isArray(array)) { throw new TypeError('array must be an Array'); }
+ var a = typeof all !== 'undefined' && all === true ? true : false,
+ retour = [],
+ func = function(el) {
+ if(typeof el !== 'undefined' && el !== null) {
+ if(!a) {
+ retour.push(el);
+ } else if (a && el) {
+ retour.push(el);
+ }
+ }
+ };
+ appJS.forEach(array, function(item) {
+ func(item);
+ });
+ return retour.length > 0 ? retour : null;
+ };
+ /**
+ *Returns the number of times an item appears
+ *@method count
+ *@param array {Array} Array to apply the function
+ *@param item {any} Pattern to search
+ *@return {number} Number of times the pattern is matched
+ *@example
+ * appJS.array.count(['sandwich', 'sandstorm'], 'sand'); //0
+ * appJS.array.count(['sandwich', 'sandstorm'], /sand/); //2
+ **/
+ appJS.array.count = function(array, item) {
+ var retour = appJS.array.indexOfAll(array, item);
+ return retour === - 1 ? 0 : retour.length;
+ };
+})();
View
72 app.class.js
@@ -0,0 +1,72 @@
+//v2.0
+(function() {
+ /**
+ *This module provides a simple way to create classes and make them inherit between each other.
+ *@module appJS
+ *@submodule Class
+ *@class Class
+ *@static
+ **/
+ appJS['class'] = appJS['class'] || {};
+
+ /**
+ *Simplifies the class creation in javascript
+ *@method class
+ *@param properties {object} Object of properties to apply to the class
+ *@param [properties.extends] {class} A class to extend.
+ *@param [properties.inherit] {class} A class to inherit properties.
+ *@param [properties.initialize] {function} The constructor to add to the class.
+ *@return {class} Returns a class
+ *@beta
+ *@chainable
+ **/
+ appJS['class'] = function(properties) {
+ if(typeof properties === 'object') {
+ var newClass = function() {};
+ var values = {
+ 'extends': function(classToExtend) {
+ if(classToExtend.prototype) {
+ newClass.prototype = Object.create ? Object.create(classToExtend.prototype) : new classToExtend();
+ } else {
+ throw new Error('classToExtend must be a Class');
+ }
+ },
+ inherit: function(classToInherit) {
+ for(var o in classToInherit) {
+ if(classToInherit.hasOwnProperty(o)) {
+ newClass.prototype[o] = classToInherit.prototype[o];
+ }
+ }
+ },
+ initialize: function(cons) {
+ if(appJS.isFunction(cons)) {
+ newClass.prototype.constructor = cons;
+ } else {
+ throw new Error('Constructor must be a function');
+ }
+ }
+ };
+ for(var i in properties) {
+ if(properties.hasOwnProperty(i)) {
+ if(values.hasOwnProperty(i)) {
+ values[i](properties[i]);
+ } else {
+ newClass.prototype[i] = properties[i];
+ }
+ newClass.prototype.add = function(obj) {
+ if(typeof obj === 'object') {
+ for(var e in obj) {
+ if(obj.hasOwnProperty(e)) {
+ this[e] = obj[e];
+ }
+ }
+ }
+ };
+ }
+ }
+ return newClass;
+ } else {
+ throw new Error('properties must be an Object');
+ }
+ };
+})();
View
110 app.css.js
@@ -0,0 +1,110 @@
+//v2.0
+(function() {
+ /**
+ *This module provides a new way to add css to a page.
+ *@requires DOM
+ *@module appJS
+ *@submodule CSS
+ *@class CSS
+ *@static
+ **/
+
+ /**
+ *@method css
+ *@beta
+ *@param obj {object} CSS object.
+ *@param param {object} Variables object.
+ *@example
+ * appJS.css({
+ 'body a': {
+ 'background-color': 'red',
+ 'color': 'blue',
+ '[href]': 'http://âpp.com',
+ 'span': {
+ 'color': '%colorSpan%'
+ }
+ }
+ }, {
+ 'colorSpan': 'yellow'
+ });
+ //body a { background-color: red; color: blue; } body a span { color: yellow; }
+ **/
+ appJS.css = function(obj, param) {
+ var isNotNode = (typeof module === 'undefined' || (typeof window !== 'undefined' && this === window));
+ if(typeof obj !== 'object') { throw new TypeError('obj must be an object'); }
+ var vendor = [
+ '-o-',
+ '-webkit-',
+ '-moz-',
+ '-ms-',
+ ''
+ ];
+ var func = function(obj, par) {
+ var isPar = typeof par !== "undefined",
+ wholeString = '';
+ for(var i in obj) {
+ if(obj.hasOwnProperty(i)) {
+ if(i[0] === '[') {
+ if(isPar && isNotNode) {
+ appJS.dom.queryAll(par).set(i.substring(1, i.length - 1), obj[i]);
+ }
+ } else if (typeof obj[i] === 'object') {
+ if(isPar) {
+ wholeString += ' } ';
+ if(i[0] === ':') {
+ wholeString += par + i + ' { ';
+ } else {
+ wholeString += par + ' ' + i + ' { ';
+ }
+ wholeString += func(obj[i], par + ' ' + i);
+ } else {
+ wholeString += i + ' { ';
+ wholeString += func(obj[i], i);
+ wholeString += ' } ';
+ }
+ } else {
+ if(i.substring(0, 9) === '--vendor-') {
+ var part = i.substring(9, part.length);
+ appJS.forEach(vendor, function(item) {
+ wholeString += item + part + ': ' + obj[i] + '; ';
+ });
+ } else {
+ wholeString += i + ': ' + obj[i] + '; ';
+ }
+ }
+ }
+ }
+ if (!isPar) {
+ if(typeof param !== 'undefined' && appJS.isObject(param)) {
+ var reg = /([\\\/'*+?|()\[\]{}.\^$])/g;
+ for(var e in param) {
+ if(param.hasOwnProperty(e)) {
+ var re = new RegExp('%' + e.replace(reg, '\\$1') + '%', 'g');
+ wholeString = wholeString.replace(re, param[e]);
+ }
+ }
+ }
+ }
+ if(!isPar && isNotNode) {
+ if (document.styleSheets.length === 0 || !document.styleSheets[0].insertRule) {
+ appJS.dom.create({
+ 'style': {
+ 'text': wholeString,
+ 'children': {}
+ }
+ }, [appJS.dom.query('head'), 'append']);
+ } else {
+ var arrayOf = wholeString.split('}');
+ appJS.forEach(arrayOf, function(item) {
+ if(item !== '') {
+ document.styleSheets[0].insertRule(item + '}', document.styleSheets[0].cssRules.length);
+ }
+ });
+ }
+ }
+ return wholeString;
+ };
+ var string = func(obj);
+ return string;
+ };
+})();
View
1,377 app.dom.js
@@ -0,0 +1,1377 @@
+//v2.0
+(function() {
+ /**
+ *This module provides many functions to manipulate the DOM.
+ *@module appJS
+ *@submodule Dom
+ *@class Dom
+ *@static
+ **/
+ appJS.dom = appJS.dom || {};
+ /**
+ *Gets the first element in the DOM corresponding to a css selector
+ *@method query
+ *@param CSSSelector {string} CSS Selector used to find the node
+ *@param [HTMLelement] {HTMLElement|appJS.dom.Element} If specified, research will be on this node. Otherwise, it will be done over the whole document
+ *@return {appJS.dom.Element|null} Returns the element or null if not found
+ *@chainable
+ *@example
+ * <html><!-- No head, it's a short example -->
+ * <body><div><a href="link">A big Link></a></div></body>
+ * </html>
+ * appJS.dom.query('a[href="link"]'); //An instance of appJS.dom.Element corresponding
+ **/
+ appJS.dom.query = function(string, HTMLelement) {
+ if (appJS.isString(string)) {
+ var element;
+ if (HTMLelement) {
+ if (HTMLelement instanceof appJS.dom.Element) {
+ element = HTMLelement.query(string);
+ } else if (HTMLelement.nodeType && HTMLelement.nodeType === 1) {
+ element = HTMLelement.querySelector(string);
+ } else {
+ throw new Error('HTMLelement must be HTMLElement or AppJs Element');
+ }
+ } else {
+ element = document.querySelector(string);
+ }
+ if (element === null) {
+ return null;
+ }
+ return new appJS.dom.Element(element);
+ } else {
+ throw new Error('First parameter of query must be a string !');
+ }
+ };
+ /**
+ *Same as query, but gets all the results into an appJS.dom.Elements
+ *@method queryAll
+
+ *@chainable
+ *@param CSSSelector {string} CSS Selector used to find the node
+ *@param [HTMLelement] {HTMLElement|appJS.dom.Element} If specified, research will be on this node. Otherwise, it will be done over the whole document
+ *@return {appJS.dom.Elements|null} All the elements or null if not found
+ **/
+ appJS.dom.queryAll = function(string, HTMLelement) {
+ if (appJS.isString(string)) {
+ var elements;
+ if (HTMLelement) {
+ if (HTMLelement instanceof appJS.dom.Element) {
+ elements = HTMLelement.queryAll(string);
+ } else if (HTMLelement.nodeType && HTMLelement.nodeType === 1) {
+ elements = HTMLelement.querySelectorAll(string);
+ } else {
+ throw new Error('HTMLelement must be HTMLElement or AppJs Element');
+ }
+ } else {
+ elements = document.querySelectorAll(string);
+ }
+ if (elements === null) {
+ return null;
+ }
+ return new appJS.dom.Elements(elements);
+ } else {
+ throw new Error('First parameter of query must be a string !');
+ }
+ };
+ /**
+ *Gets an element from its id. Same as appJS.dom.query('#id');
+ *@method byId
+
+ *@chainable
+ *@param id {string} Id to be looked for
+ *@return {appJS.dom.Element|null} The element with the id matching or null if not found
+ **/
+ appJS.dom.byId = function(id) {
+ return appJS.dom.query('#' + id);
+ };
+ /**
+ *Gets an element from its id. Same as appJS.dom.query('#id'); Alias for app.dom.byId for compatibility.
+ *@method getById
+
+ *@chainable
+ *@param id {string} Id to be looked for
+ *@return {appJS.dom.Element|null} The element with the id matching or null if not found
+ **/
+ appJS.dom.getById = function(id) {
+ return appJS.dom.byId(id);
+ };
+ /**
+ *Gets an element from its class. Same as appJS.dom.query('.class');
+ *@method byClass
+
+ *@chainable
+ *@param classname {string} class to be looked for
+ *@param bool {boolean} Returns all the elements or just one
+ *@return {appJS.dom.Element|appJS.dom.Elements|null} The element(s) with the class matching or null if not found
+ **/
+ appJS.dom.byClass = function(classname, bool) {
+ var meth = bool ? 'queryAll' : 'query';
+ return appJS.dom[meth]('.' + classname);
+ };
+ /**
+ *Gets an element from its class. Same as appJS.dom.query('.class'); Compatibility with byClass
+ *@method getByClass
+
+ *@chainable
+ *@param classname {string} class to be looked for
+ *@param bool {boolean} Returns all the elements or just one
+ *@return {appJS.dom.Element|appJS.dom.Elements|null} The element(s) with the class matching or null if not found
+ **/
+ appJS.dom.getByClass = function(classname, bool) {
+ return appJS.dom.byClass(classname, bool);
+ };
+ /**
+ *Gets elements from their class. Same as appJS.dom.queryAll('.class');
+ *@method byClassAll
+
+ *@chainable
+ *@param className {string} class to be looked for
+ *@return {appJS.dom.Elements|null} Elements with the class matching or null if not found
+ **/
+ appJS.dom.byClassAll = function(className) {
+ return appJS.dom.byClass('.' + className, true);
+ };
+ /**
+ *Gets elements from their class. Same as appJS.dom.queryAll('.class'); Compatibility with byClassAll
+ *@method getByClassAll
+
+ *@chainable
+ *@param className {string} class to be looked for
+ *@return {appJS.dom.Elements|null} Elements with the class matching or null if not found
+ **/
+ appJS.dom.getByClassAll = function(classname) {
+ return appJS.dom.byClassAll(classname);
+ };
+ /**
+ *Creates a node or nodes with a special syntax. See the example.
+ *@method create
+
+ *@param options {string|object} If string, will create an empty element. The string will be the tag name.
+ *If it is only an element with some text, give an object like this:
+ {
+ "a": "hehe"
+ }
+ *If there are many elements unrelated, give this
+ {
+ "span": {
+ //stuff },
+ "a": {
+ //stuff
+ }
+ }
+ }
+ *If element has children, give this
+ {
+ "div":
+ {
+ "a": {
+ //stuff
+ },
+ "p": {
+ //stuff
+ }
+ }
+ }
+ *If element has attributes, give this (always a children property, even if he doesn't have any)
+ {
+ "a": {
+ "href: "link",
+ "id": "sandwich",
+ "children": {}
+ }
+ }
+ *Text elements are done with #text tag: don't try to use any attributes, it won't work
+ {
+ "#text": "sandwich"
+ }
+ *You can also give a number as property when there are numerous tags (tagname is required)
+ {
+ 0: {
+ tagname: 'a',
+ href: 'link',
+ children: {}
+ },
+ 1: {
+ tagname: '#text',
+ text: 'sandwich'
+ }
+ }
+ *(for the text element, use a `text` property and don't add any children property)
+ *@param [parents] {array} Can be two types of array: [parent, 'append'] or [parent, 'insertBefore', which]. Here, parent and which are HTMLElement or appJS.dom.Element instance.
+ *@return {appJS.dom.Element|appJS.dom.Elements} The element(s) created
+ *@example
+ * appJS.dom.create({
+ * div: {
+ * p: {
+ * id: "sandwich",
+ * children: {
+ * a: {
+ * href: "link",
+ * text: "Link",
+ * children: {}
+ * }
+ * }
+ * }
+ * }
+ * }, [appJS.dom.body, 'append']);
+ * //Will give
+ * <body>
+ * <div>
+ * <p id="sandwich">
+ * <a href="link">Link</a>
+ * </p>
+ * </div>
+ * </body>
+ */
+ appJS.dom.create = function(options, parents) {
+ if (options) {
+ var retour = [];
+ if (appJS.isString(options) && options !== '#text') {
+ retour[0] = new appJS.dom.Element(document.createElement(options));
+ } else if (appJS.isObject(options)) {
+ for (var i in options) {
+ if (options.hasOwnProperty(i)) {
+ var element;
+ if (!isNaN(parseInt(i, 10))) {
+ if (options[i].tagname === '#text') {
+ element = new appJS.dom.NodeText(document.createTextNode(options[i].text));
+ } else {
+ element = new appJS.dom.Element(document.createElement(options[i].tagname));
+ }
+ } else {
+ if (i === '#text' && typeof options[i] === 'string') {
+ element = new appJS.dom.NodeText(document.createTextNode(options[i]));
+ } else {
+ element = new appJS.dom.Element(document.createElement(i));
+ }
+ }
+ if (typeof options[i] === 'string') {
+ if (i !== '#text') {
+ element.set('text', options[i]);
+ }
+ } else if (typeof options[i] === 'object') {
+ var e, options_tmp;
+ if (options[i].children) {
+ for (var a in options[i]) {
+ if (options[i].hasOwnProperty(a)) {
+ if (a !== 'tagname') {
+ if (a !== 'children') {
+ element.set(a, options[i][a]);
+ } else {
+ for (e in options[i].children) {
+ if (options[i].children.hasOwnProperty(e)) {
+ options_tmp = {};
+ options_tmp[e] = options[i].children[e];
+ appJS.dom.create(options_tmp, [element, 'append']);
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (options[i].tagname && options[i].tagname === '#text') {
+ element.nodeValue = options[i].text;
+ } else {
+ for (e in options[i]) {
+ if (options[i].hasOwnProperty(e)) {
+ if (e !== 'tagname') {
+ options_tmp = {};
+ options_tmp[e] = options[i][e];
+ appJS.dom.create(options_tmp, [element, 'append']);
+ }
+ }
+ }
+ }
+ }
+ retour.push(element);
+ }
+ }
+ }
+ if (parents) {
+ if (appJS.isArray(parents)) {
+ if (parents[0] instanceof appJS.dom.Element) {
+ if (parents[1] === 'append') {
+ appJS.forEach(retour, function(value, index, array) {
+ parents[0].append(array[index]);
+ });
+ } else if (parents[1] === 'insertBefore') {
+ if (parents[2]) {
+ appJS.forEach(retour, function(value, index, array) {
+ parents[0].insertBefore(array[index], parents[2]);
+ });
+ } else {
+ throw new Error('parents[2] must be specified with insertBefore');
+ }
+ }
+ } else if (parents[0].nodeType && parents[0].nodeType === 1) {
+ parents[0] = new appJS.dom.Element(parents[0]);
+ if (parents[1] === 'append') {
+ appJS.forEach(retour, function(value, index, array) {
+ parents[0].append(array[index]);
+ });
+ } else if (parents[1] === 'insertBefore') {
+ if (parents[2]) {
+ appJS.forEach(retour, function(value, index, array) {
+ parents[0].insertBefore(array[index], parents[2]);
+ });
+ } else {
+ throw new Error('parents[2] must be specified with insertBefore');
+ }
+ }
+ } else {
+ throw new Error('Parent must be an HTMLElement or an appJS.dom.Element instance');
+ }
+ } else {
+ throw new Error('parents must be array');
+ }
+ }
+ if (retour.length === 1) {
+ return retour[0];
+ } else if (retour.length === 0) {
+ return null;
+ } else {
+ return new appJS.dom.Elements(retour);
+ }
+ } else {
+ throw new Error('Options must be specified');
+ }
+ };
+ /**
+ * Creates appJS.dom.Element from html string
+ * @method fromHTML
+ * @param { string } html html string
+ * @final
+ * @return {appJS.dom.Element|appJS.dom.Elements} Elements created from html
+ **/
+ appJS.dom.fromHTML = function(html) {
+ if(appJS.isString(html) && html !== '') {
+ var div = appJS.dom.create({
+ 'div': {
+ 'html': html,
+ 'children': {}
+ }
+ });
+ var childs = div.getChild();
+ if(childs.array.length > 1) {
+ return childs;
+ } else {
+ return childs.item(0);
+ }
+ } else {
+ throw new TypeError('html must be a string');
+ }
+ };
+ /**
+ *Adds an event listener on an Element
+ *@method addEvent
+
+ *@param element {HTMLElement|appJS.dom.NodeText} The element on which you want to add the event listener
+ *@param event {string} The event to listen
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener
+ *@param callback {callback} Function called every time the event is fired
+ *@param callback.e {object} Object, same as parameter of the callback of HTMLElement.addEventlistener with other methods
+ *@param callback.e.stop {function} Stops the default handling of the event (stop submiting a form for example)
+ *@async
+ **/
+ appJS.dom.addEvent = function(element, event, boil, callback) {
+ if (appJS.isFunction(boil)) {
+ callback = boil;
+ boil = false;
+ }
+ var boil_var = boil ? true : false;
+ if (element.nodeType) {
+ appJS.dom.addEvent(new appJS.dom.Element(element), event, boil, callback);
+ } else if (element instanceof appJS.dom.Element) {
+ if (element.element.addEventListener) {
+ element.element.addEventListener(event, function(e) {
+ e.stop = function() {
+ this.preventDefault();
+ };
+ callback.call(element, e);
+ }, boil_var);
+ } else if (element.element.attachEvent) {
+ element.element.attachEvent('on' + event, function() {
+ var e = window.event;
+ e.stop = function() {
+ this.returnValue = false;
+ };
+ callback.call(element, e);
+ });
+ }
+ }
+ };
+ /**
+ *Removes an event. Needs the same callback that had been given has a parameter when adding the event listener
+ *@method removeEvent
+
+ *@param element {HTMLElement} The element on which you want to add the event listener
+ *@param event {string} The event to listen
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener
+ *@param callback {callback} Function called every time the event is fired
+ *@param callback.e {object} Object, same as parameter of the callback of HTMLElement.addEventlistener with other methods
+ *@param callback.e.stop {function} Stops the default handling of the event (stop submiting a form for example)
+ *@async
+ **/
+ appJS.dom.removeEvent = function(element, event, boil, callback) {
+ if (appJS.appJS.isFunction(boil)) {
+ callback = boil;
+ boil = false;
+ }
+ var boil_var = boil ? true : false;
+ if (element.nodeType) {
+ appJS.dom.addEvent(new appJS.dom.Element(element), event, boil, callback);
+ } else if (element instanceof appJS.dom.Element) {
+ if (element.element.removeEventListener) {
+ element.element.removeEventListener(event, function(e) {
+ e.stop = function() {
+ this.preventDefault();
+ };
+ callback.call(element, e);
+ }, boil_var);
+ } else if (element.element.detachEvent) {
+ element.element.detachEvent('on' + event, function() {
+ var e = window.event;
+ e.stop = function() {
+ this.returnValue = false;
+ };
+ callback.call(element, e);
+ });
+ }
+ }
+ };
+ /**
+ * @method fire
+ * @param {HTMLElement|appJS.dom.Element|appJS.dom.NodeText} element Element on which the event will be triggered
+ * @param {string} event The event to trigger
+ * @param {object} [options] The options to add to the event and accessible by e.options.
+ */
+ appJS.dom.fire = function(element, event, options) {
+ if (element.nodeType) {
+ if (appJS.isString(event)) {
+ var onevent = 'on' + event;
+ if (typeof element[onevent] === 'function') {
+ element[onevent]();
+ } else if (typeof element[event] === 'function') {
+ element[event]();
+ } else {
+ var eventMade;
+ if (document.createEvent) {
+ eventMade = document.createEvent('HTMLEvents');
+ eventMade.initEvent(event, true, true);
+ } else {
+ eventMade = document.createEventObject();
+ eventMade.eventType = event;
+ }
+ eventMade.options = options || {};
+ if (document.createEvent) {
+ return element.dispatchEvent(eventMade);
+ } else {
+ return element.fireEvent('on' + eventType, event);
+ }
+ }
+ } else {
+ throw new Error('event must be a string');
+ }
+ } else if (element instanceof appJS.dom.Element) {
+ return appJS.dom.fire(element.element, event, options);
+ } else if (element instanceof appJS.dom.NodeText) {
+ return appJS.dom.fire(element.nodeText, event, options);
+ } else {
+ throw new Error('element must be an HTMLElement, an appJS.dom.Element or an appJS.dom.NodeText instance');
+ }
+ };
+ /**
+ *Convert an HTMLElement to an appJS.dom.Element or the contrary
+ *@method convert
+ *@param element {HTMLElement|appJS.dom.Element} The element converted
+ *@return {HTMLElement|appJS.dom.Element} The result of the conversion
+ **/
+ appJS.dom.convert = function(element) {
+ if (element instanceof appJS.dom.Element) {
+ return element.element;
+ } else if (element.nodeType && element.nodeType === 1) {
+ return new appJS.dom.Element(element);
+ } else {
+ throw new Error('element must be an HTMLElement or an appJS.dom.Element instance');
+ }
+ };
+ /**
+ *Element class, wraps HTMLElement to add methods and properties
+ *@class Dom Element
+
+ *@requires Core
+ *@requires Dom
+ *@constructor
+ *@param element {HTMLElement} The HTMLElement to be wrapped in the class
+
+ **/
+ appJS.dom.Element = function(element) {
+ /**
+ *`this` acessible form all the methods
+ *@property this_
+ *@private
+ *@type appJS.dom.Element
+
+ **/
+ var this_ = this;
+ /**
+ *Element stored into a property
+ *@property element
+ *@public
+ *@type HTMLElement
+
+ **/
+ this.element = null;
+ if (element.nodeType && element.nodeType === 1) {
+ this.element = element;
+ } else {
+ throw new Error('element must be an HTMLElement');
+ }
+ /**
+ *Name of the tag
+ *@property tagName
+ *@public
+ *@type String
+
+ **/
+ this.tagName = this.element.tagName.toLowerCase();
+ /**
+ *Object of attributes of the Element, for those who prefer to access to attributes via element.attributes.attribute
+ *@property attributes
+ *@public
+ *@type Object
+
+ **/
+ this.attributes = this.element.attributes;
+ /**
+ *Object of styles of the Element, for those who prefer to access to the style via element.style.property
+ *@property style
+ *@public
+ *@type Object
+
+ **/
+ this.style = this.element.style;
+ /**
+ *Does an appJS.dom.query from the element: same as appJS.dom.query(string, element); where the element is here this.element
+ *@method query
+ *@param string {string} CSS Selector to search with.
+ *@return {appJS.dom.Element} The element matching the CSS selector
+
+ *@chainable
+ **/
+ this.query = function(string) {
+ return appJS.dom.query(string, this_.element);
+ };
+ /**
+ *Does an appJS.dom.queryAll from the element: same as appJS.dom.query(string, element); where the element is here this.element
+ *@method queryAll
+ *@param string {string} CSS Selector to search with.
+ *@return {appJS.dom.Elements} The elements matching the CSS selector
+
+ *@chainable
+ **/
+ this.queryAll = function(string) {
+ return appJS.dom.queryAll(string, this_.element);
+ };
+ /**
+ *Does an appJS.dom.query from the element: same as appJS.dom.query('#string', element); where the element is here this.element. Alias for byId for compatiblity.
+ *@method getByyId
+ *@param id {string} Id to search with.
+ *@return {appJS.dom.Element} The element matching the id
+
+ *@chainable
+ **/
+ this.getById = function(id) {
+ return this_.byId(id);
+ };
+ /**
+ *Does an appJS.dom.query from the element: same as appJS.dom.query('#string', element); where the element is here this.element
+ *@method byId
+ *@param id {string} Id to search with.
+ *@return {appJS.dom.Element} The element matching the id
+
+ *@chainable
+ **/
+ this.byId = function(id) {
+ return this_.query('#' + id);
+ };
+
+ /**
+ *Does an appJS.dom.query from the element: same as appJS.dom.query('.string', element); where the element is here this.element
+ *@method byClass
+
+ *@chainable
+ *@param classname {string} class to be looked for
+ *@param bool {boolean} Returns all the elements or just one
+ *@return {appJS.dom.Element|appJS.dom.Elements|null} The element(s) with the class matching or null if not found
+ **/
+ this.byClass = function(classname, bool) {
+ var meth = bool ? 'queryAll' : 'query';
+ return this_[meth]('.' + classname, this_.element);
+ };
+ /**
+ *Does an appJS.dom.query from the element: same as appJS.dom.query('.string', element); where the element is here this.element Compatibility with byClass
+ *@method getByClass
+
+ *@chainable
+ *@param classname {string} class to be looked for
+ *@param bool {boolean} Returns all the elements or just one
+ *@return {appJS.dom.Element|appJS.dom.Elements|null} The element(s) with the class matching or null if not found
+ **/
+ this.getByClass = function(classname, bool) {
+ return this_.byClass(classname, bool);
+ };
+ /**
+ *Does an appJS.dom.queryAll from the element: same as appJS.dom.queryAll('.string', element); where the element is here this.element
+ *@method byClassAll
+
+ *@chainable
+ *@param className {string} class to be looked for
+ *@return {appJS.dom.Elements|null} Elements with the class matching or null if not found
+ **/
+ this.byClassAll = function(className) {
+ return this_.byClass('.' + className, true);
+ };
+ /**
+ *Does an appJS.dom.queryAll from the element: same as appJS.dom.queryAll('.string', element); where the element is here this.element Compatibility with byClassAll
+ *@method getByClassAll
+
+ *@chainable
+ *@param className {string} class to be looked for
+ *@return {appJS.dom.Elements|null} Elements with the class matching or null if not found
+ **/
+ this.getByClassAll = function(classname) {
+ return this_.byClassAll(classname);
+ };
+ /**
+ *Empty the element
+ *@method empty
+
+ *@example
+ * <div id="sandwich"><span>hehe</span></div>
+ * appJS.dom.getById('sandwich').empty();
+ * <div id="sandwich"></div>
+ **/
+ this.empty = function() {
+ this_.element.innerHTML = '';
+ };
+ /**
+ *Gets appJS.dom.Element.element
+ *@method getDOMElement
+
+ *@return {appJS.dom.Element} The property element
+ **/
+ this.getDOMElement = function() {
+ return this_.element;
+ };
+ /**
+ *Destroy the Element
+ *@method destroy
+
+ **/
+ this.destroy = function() {
+ this_.element.parentNode.removeChild(this_.element);
+ };
+ /**
+ *@method parent
+ *@return {appJS.dom.Element} Parent of the Element
+
+ **/
+ this.parent = function() {
+ return new appJS.dom.Element(this.element.parentNode);
+ };
+ /**
+ *Gets any child of the Element but only elements. It uses appJS.dom.Element.element.childNodes.
+ *@method getChild
+
+ *@chainable
+ *@param [option] {number} Option is the number where the child is.
+ *@return {appJS.dom.Element|appJS.dom.Elements} The nth child HTMLElement as an appJS.dom.Element or all the elements if option not specified;
+ **/
+ this.getChild = function(option) {
+ if (this_.element.hasChildNodes()) {
+ var index = 0,
+ t,
+ i,
+ retour;
+ if (appJS.isNumber(option)) {
+ retour = null;
+ for(i = 0, t = this_.element.childNodes.length ; i < t ; i++) {
+ if(this_.element.childNodes[i].nodeType === 1) {
+ if(index === option) {
+ retour = new appJS.dom.Element(this_.element.childNodes[i]);
+ break;
+ }
+ index++;
+ }
+ }
+ return retour;
+ } else if (typeof option === 'undefined') {
+ retour = [];
+ for(i = 0, t = this_.element.childNodes.length ; i < t ; i++) {
+ if(this_.element.childNodes[i].nodeType === 1) {
+ retour.push(new appJS.dom.Element(this_.element.childNodes[i]));
+ }
+ }
+ return new appJS.dom.Elements(retour);
+ } else {
+ throw new Error('Option must be a number');
+ }
+ }
+ };
+ /**
+ *Gets any text child of the Element. It uses appJS.dom.Element.element.childNodes.
+ *@method getChild
+
+ *@chainable
+ *@param [option] {number} Option is the numeber where the child is.
+ *@return {appJS.dom.NodeText} The nth child nodetext or all the text elements if option not specified.
+ **/
+ this.getTextChild = function(option) {
+ if (this_.element.hasChildNodes()) {
+ var index = 0,
+ t,
+ i,
+ retour;
+ if (appJS.isNumber(option)) {
+ retour = null;
+ for(i = 0, t = this_.element.childNodes.length ; i < t ; i++) {
+ if(this_.element.childNodes[i].nodeType === 3) {
+ index++;
+ }
+ if(index === option) {
+ retour = new appJS.dom.NodeText(this_.element.childNodes[i]);
+ break;
+ }
+ }
+ return retour;
+ } else if (typeof option === 'undefined') {
+ retour = [];
+ for(i = 0, t = this_.element.childNodes.length ; i < t ; i++) {
+ if(this_.element.childNodes[i].nodeType === 1) {
+ retour.push(new appJS.dom.NodeText(this_.element.childNodes[i]));
+ }
+ }
+ return retour.length >= 0 ? new appJS.dom.Elements(retour) : null;
+ } else {
+ throw new Error('Option must be a number');
+ }
+ }
+ };
+ /**
+ *Gets the the structure of the tag. Same as HTMLElement.outerHTML.
+ *@method tagComplete
+
+ *@return {string} The structure of the tag. Ideal to use with innerHTML in some cases
+ *@example
+ * <span id="sandwich"></span>
+ * console.log(appJS.dom.getById('sandwich').tagComplete()); //'<span id="sandwich"></span>'
+ **/
+ this.tagComplete = function() {
+ return this_.element.outerHTML;
+ };
+ /**
+ *Adds an event to the element. Same as appJS.dom.addEvent(element, event, boil, callback); where element is appJS.dom.Element.element
+ *@method addEvent
+
+ *@param event {string} Name of the event. Form: 'click', not 'onclick'
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener. False is default.
+ *@param callack {callback} Callback to call when event is fired.
+ *@param callback.e {object} Event object, same as in addEventListener, but with new methods. See appJS.dom.addEvent for further information;
+ *@async
+ **/
+ this.addEvent = function(event, boil, callback) {
+ if (appJS.isFunction(boil)) {
+ callback = boil;
+ boil = false;
+ }
+ appJS.dom.addEvent(this_.element, event, boil, callback);
+ };
+ /**
+ *Remove an event. Needs the same function that had be used to add the event;
+ *@method removeEvent
+
+ *@param event {string} Name of the event. Form: 'click', not 'onclick'
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener. False is default.
+ *@param callack {callback} Callback to call when event is fired.
+ *@param callback.e {object} Event object, same as in addEventListener, but with new methods. See appJS.dom.addEvent for further information;
+ *@async
+ **/
+ this.removeEvent = function(event, boil, callback) {
+ if (appJS.isFunction(boil)) {
+ callback = boil;
+ boil = false;
+ }
+ appJS.dom.removeEvent(this_.element, event, boil, callback);
+ };
+ /**
+ *Shortcut for appJS.dom.fire
+ *@method fire
+ *@param {string} event Event to trigger
+ *@param {object} [options] Options accessible by e.options
+ */
+ this.fire = function(event, options) {
+ return appJS.dom.fire(this_.element, event, options);
+ };
+ /**
+ *Sets attributes, style, and others
+ *@method set
+
+ *@param option {string|object} The name of the attribute. Can be text to set the text, style to set a style, styles to set styles, html to set the innerHTML and events to set multiple events at once.
+ *If option is an object, method will call itself for every properties. For events, it will call addEvent. For others, it will look into properties.
+ *@param value {any} The value to set to every attributes. For styles, must be an object of property: value, for events, must be either an array [event, boil, callback] or an object of {event: [boil, callback]}
+ *For events, can also be an object of event: callback and boil will be false. Look appJS.dom.Element.addEvent for further information. If you have multiple function for the same events, you can give an object of {event: [[boil, callback], [boil, callback]]}
+ **/
+ this.set = function(option, value) {
+ var set = {
+ text: function(value) {
+ if (this_.element.innerText !== undefined) {
+ this_.element.innerText = value;
+ } else {
+ this_.element.textContent = value;
+ }
+ },
+ style: function(value) {
+ if (appJS.isArray(value)) {
+ this_.element.style[value[0]] = value[1];
+ } else {
+ throw new Error('When setting style, value must be an array [property, value]');
+ }
+ },
+ styles: function(value) {
+ if (typeof value === 'object') {
+ for (var property in value) {
+ if (value.hasOwnProperty(property)) {
+ this_.element.style[property] = value[property];
+ }
+ }
+ } else {
+ throw new Error('When setting styles, value must be an object with {property: value}');
+ }
+ },
+ html: function(value) {
+ this_.element.innerHTML = value;
+ },
+ events: function(value) {
+ if (appJS.isArray(value)) {
+ if (typeof value[0] === 'string' && typeof value[1] === 'boolean' && typeof value[2] === 'function') {
+ this_.addEvent(value[0], value[1], value[2]);
+ } else {
+ throw new Error('options must be an array: [string, boolean, function]');
+ }
+ } else if (typeof value === 'object') {
+ for (var e in value) {
+ if (value.hasOwnProperty(e)) {
+ if (appJS.isArray(value[e])) {
+ if (appJS.isArray(value[e][0])) {
+ appJS.forEach(value[e], function(el) {
+ var object = {};
+ object[e] = el;
+ this_.set('events', object);
+ });
+ } else {
+ this_.addEvent(e, value[e][0], value[e][1]);
+ }
+ } else if (typeof value[e] === 'function') {
+ this_.addEvent(e, false, value[e]);
+ } else {
+ throw new Error('value[e] must be an array or a function');
+ }
+ }
+ }
+ }
+ }
+ };
+ var defaut = function(option, value) {
+ if(value === false) {
+ this_.element.removeAttribute(option);
+ } else {
+ if (this_.element.hasOwnProperty(option)) {
+ this_.element[option] = value;
+ } else {
+ this_.element.setAttribute(option, value);
+ }
+ }
+ };
+ if (appJS.isString(option)) {
+ if (set.hasOwnProperty(option)) {
+ return set[option](value);
+ } else {
+ return defaut(option, value);
+ }
+ } else if (typeof option === 'object') {
+ for (var i in option) {
+ if (option.hasOwnProperty(i)) {
+ return this_.element.set(i, option[i]);
+ }
+ }
+ } else {
+ throw new Error('Option must be a string or an object');
+ }
+ };
+ /**
+ *Shortcut for appJS.dom.Element.set('style', [property, value]);
+ *@method setStyle
+ *@param property {string} Property of the style
+ *@param value {string} Value of the property
+
+ **/
+ this.setStyle = function(property, value) {
+ this_.set('style', [property, value]);
+ };
+ /**
+ *Shortcut for appJS.dom.Element.set('styles', {
+ property: value,
+ property: value
+ });
+ *@method setStyles
+ *@param style {object} Same as the second parameter of appJS.dom.Element.set('styles', values); Type of {property: value}
+
+ **/
+ this.setStyles = function(styles) {
+ this_.set('styles', styles);
+ };
+ /**
+ *Appends an element by doing an appendChild
+ *@method append
+ *@param element {HTMLElement|appJS.dom.Element|Elements} Element to append. If it is an appJS.dom.Elements, all elements will be appened.
+
+ **/
+ this.append = function(element) {
+ if (element.nodeType && element.nodeType === 1) {
+ this_.element.appendChild(element);
+ } else if (element instanceof appJS.dom.Element) {
+ this_.element.appendChild(element.element);
+ } else if (element instanceof appJS.dom.Elements) {
+ appJS.forEach(element.array, function(value, index, array) {
+ this_.append(value);
+ });
+ } else if (element instanceof appJS.dom.NodeText) {
+ this_.element.appendChild(element.nodeText);
+ } else {
+ throw new Error('element must be an HTMLElement, an appJS Elements, an appJS NodeText or a AppJS Element. It can also be an array of one of both above.');
+ }
+ };
+ /**
+ *Gets any attribute or style.
+ *@method get
+
+ *@param option {string} The name of the property. Can be text for the text, styles for styles, style for a style and html for innerHTML. For others, use the regular name
+ *@param [cssvalues] {string|array} Required only when option is style or styles. For style, it corresponds to the name of the property and to styles, it is an array of properties.
+ *@return {any} The content of the propertie(s) of attribute(s)
+ **/
+ this.get = function(option, cssvalues) {
+ var get = {
+ text: function() {
+ return this_.element.textContent || this_.element.innerText || '';
+ },
+ styles: function(cssvalues) {
+ if (appJS.isArray(cssvalues)) {
+ var object;
+ for (var i in cssvalues) {
+ if (cssvalues.hasOwnProperty(i)) {
+ if (this_.element.style.hasOwnProperty(i)) {
+ object.push(this_.element.style[i]);
+ } else {
+ return null;
+ }
+ }
+ }
+ return object;
+ } else {
+ throw new Error('cssvalues must be an array of properties');
+ }
+ },
+ style: function(cssvalues) {
+ if (appJS.isString(cssvalues)) {
+ if (this_.element.style.hasOwnProperty(cssvalues)) {
+ return this_.element.style[cssvalues];
+ } else {
+ return null;
+ }
+ } else {
+ throw new Error('When getting style, cssvalues must be a string');
+ }
+ },
+ html: function() {
+ return this_.element.innerHTML;
+ }
+ };
+ var defaut = function(option) {
+ if (typeof this_.element[option] !== 'undefined') {
+ return this_.element[option];
+ } else {
+ return this_.element.getAttribute(option);
+ }
+ };
+ if (get.hasOwnProperty(option)) {
+ return get[option](cssvalues);
+ } else {
+ return defaut(option);
+ }
+ };
+ /**
+ *Shortcut for appJS.dom.Element.get('style', style);
+ *@method getStyle
+
+ *@param style {string} Name of the property
+ *@return {string} Content of the property
+ **/
+ this.getStyle = function(style) {
+ return this.get('style', style);
+ };
+ /**
+ *Shortcut for appJS.dom.Element.get('styles', styles);
+ *@method getStyles
+
+ *@param styles {array} Array of properties
+ *@return {array} Array of the content of the properties
+ **/
+ this.getStyles = function(styles) {
+ return this.get('styles', styles);
+ };
+ this.getCompStyles = function(cssvalues) {
+ if (appJS.isArray(cssvalues)) {
+ var object;
+ for (var i in cssvalues) {
+ if (cssvalues.hasOwnProperty(i)) {
+ if (getComputedStyle) {
+ if (getComputedStyle(this_.element, null)[i]) {
+ object.push(getComputedStyle(this_.element, null)[i]);
+ } else {
+ object.push(null);
+ }
+ } else if (this_.element.currenStyle) {
+ if (this_.element.currentStyle[i]) {
+ object.push(this_.element.currentStyle[i]);
+ } else {
+ object.push(null);
+ }
+ }
+ }
+ }
+ return object;
+ } else {
+ throw new Error('cssvalues must be an array of values');
+ }
+ };
+ this.getCompStyle = function(cssvalues) {
+ if (appJS.isString(cssvalues)) {
+ if (getComputedStyle) {
+ if (getComputedStyle(this_.element, null)[cssvalues]) {
+ return getComputedStyle(this_.element, null)[cssvalues];
+ } else {
+ return null;
+ }
+ } else if (this_.element.currentStyle) {
+ if (this_.element.currentStyle[cssvalues]) {
+ return this_.element.currentStyle[cssvalues];
+ } else {
+ return null;
+ }
+ }
+ } else {
+ throw new Error('When getting style, cssvalues must be a string');
+ }
+ };
+ /**
+ *Inserts an element before an other as a child of the current element.
+ *@method insertBefore
+
+ *@param who {HTMLElement|appJS.dom.Element} The element inserted.
+ *@param which [HTMLElement|appJS.dom.Element] The element inserted is inserted before it.
+ **/
+ this.insertBefore = function(who, which) {
+ if (who instanceof appJS.dom.Element) {
+ who = who.element;
+ } else if (who.nodeType && who.nodeType === 1) {
+ who = who;
+ } else {
+ throw new Error('Who parts must be an HTMLElement or an AppJs Element');
+ }
+
+ if (which instanceof appJS.dom.Element) {
+ which = which.element;
+ } else if (which.nodeType && which.nodeType === 1) {
+ whichIs = which;
+ } else if (appJS.isString(which)) {
+ which = appJS.query(string).element;
+ } else {
+ throw new Error('which parts must be an array, an HTMLElement or an AppJs Element');
+ }
+
+ return this_.element.insertBefore(who, which);
+ };
+ /**
+ *Shortcut for appJS.dom.create(options, [appJS.dom.Element.element, 'append']). See appJS.dom.create for further information.
+ *@method create
+
+ *@param options {string|object} See appJS.dom.create for a complete explanation of this parameter.
+ *@return {appJS.dom.Element|appJS.dom.Elements} The element(s) created
+ *@chainable
+ **/
+ this.create = function(options) {
+ return appJS.dom.create(options, [this_.element, 'append']);
+ };
+ };
+ /**
+ *Elements class, wraps appJS.dom.Element to add methods and properties
+ *@class Dom Elements
+ *@requires Core
+ *@requires Dom
+ *@constructor
+ *@param array {array} Array of HTMLElement, NodeText or appJS.dom.Element
+ *@return {array} The array given as a parameter and stored as a property. This array only contains appJS.dom.Element instances.
+ **/
+ appJS.dom.Elements = function(array) {
+ if (appJS.isArray(array) || Object.prototype.toString.call(array) === '[object NodeList]') {
+ /**
+ *Where array is stored
+ *@property array
+ *@type array
+ *@public
+
+ **/
+ this.array = [];
+ /**
+ *This accessible for every methods
+ *@property this_
+ *@type appJS.dom.Elements
+ *@private
+
+ **/
+ var this_ = this;
+ //this fills this.array by converting every HTMLElement
+ appJS.forEach(array, function(value, index, array) {
+ if(index !== 'length') {
+ if (value instanceof appJS.dom.Element) {
+ this_.array.push(value);
+ } else if (value.nodeType && [1, 3].indexOf(value.nodeType) !== -1) {
+ if (value.nodeType === 3) {
+ this_.array.push(new appJS.dom.NodeText(value));
+ } else {
+ this_.array.push(new appJS.dom.Element(value));
+ }
+ } else {
+ throw new Error('Array parts must be HTMLElement, NodeText or AppJS Element');
+ }
+ }
+ });
+ this.item = function(number) {
+ if(appJS.isNumber(number)) {
+ if(number < this.array.length - 1 && number > 0) {
+ return this.array[number];
+ } else {
+ throw new Error('number must be between 0 and the array.length - 1');
+ }
+ } else {
+ throw new TypeError('number must be a number');
+ }
+ };
+ /**
+ *Does appJS.dom.Element.query to every element of appJS.dom.Elements
+ *@method query
+ *@param string {string} CSS Selector to search with.
+ *@return {appJS.dom.Element} The element matching the CSS selector
+
+ *@chainable
+ **/
+ this.query = function(string) {
+ var retour = [];
+ appJS.forEach(this_.array, function(value, index, array) {
+ retour.push(value.query(string));
+ });
+ return retour;
+ };
+ /**
+ *Does appJS.dom.Element.queryAll to every element of appJS.dom.Elements
+ *@method queryAll
+ *@param string {string} CSS Selector to search with.
+ *@return {appJS.dom.Elements} The elements matching the CSS selector
+
+ *@chainable
+ **/
+ this.queryAll = function(string) {
+ var retour = [];
+ appJS.forEach(this_.array, function(value, index, array) {
+ retour.push(value.queryAll(string));
+ });
+ return retour;
+ };
+ /**
+ *Empty every appJS.dom.Element
+ *@method empty
+
+ **/
+ this.empty = function() {
+ appJS.forEach(this_.array, function(value, index, array) {
+ value.empty();
+ });
+ };
+ /**
+ *Adds event to every appJS.dom.Element
+ *@method addEvent
+
+ *@param event {string} Name of the event. Form: 'click', not 'onclick'
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener. False is default.
+ *@param callack {callback} Callback to call when event is fired.
+ *@param callback.e {object} Event object, same as in addEventListener, but with new methods. See appJS.dom.addEvent for further information;
+ *@async
+ **/
+ this.addEvent = function(event, boil, callback) {
+ appJS.forEach(this_.array, function(value, index, array) {
+ value.addEvent(event, boil, callback);
+ });
+ };
+ /**
+ *Remove an event for every appJS.dom.Element
+ *@method removeEvent
+
+ *@param event {string} Name of the event. Form: 'click', not 'onclick'
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener. False is default.
+ *@param callack {callback} Callback to call when event is fired.
+ *@param callback.e {object} Event object, same as in addEventListener, but with new methods. See appJS.dom.addEvent for further information;
+ *@async
+ **/
+ this.removeEvent = function(event, boil, callback) {
+ appJS.forEach(this_.array, function(value, index, array) {
+ value.removeEvent(event, boil, callback);
+ });
+ };
+ /**
+ *Sets attributes, style, and others for every appJS.dom.Element
+ *@method set
+
+ *@param option {string|object} The name of the attribute. Can be text to set the text, style to set a style, styles to set styles, html to set the innerHTML and events to set multiple events at once.
+ *If option is an object, method will call itself for every properties. For events, it will call addEvent. For others, it will look into properties.
+ *@param value {any} The value to set to every attributes. For styles, must be an object of property: value, for events, must be either an array [event, boil, callback] or an object of {event: [boil, callback]}
+ *For events, can also be an object of event: callback and boil will be false. Look appJS.dom.Element.addEvent for further information. If you have multiple function for the same events, you can give an object of {event: [[boil, callback], [boil, callback]]}
+ **/
+ this.set = function(option, value) {
+ appJS.forEach(this_.array, function(el, index, array) {
+ el.set(option, value);
+ });
+ };
+ /**
+ *Shortcut for appJS.dom.Element.set('style', [property, value]); for every appJS.dom.Element
+ *@method setStyle
+ *@param property {string} Property of the style
+ *@param value {string} Value of the property
+
+ **/
+ this.setStyle = function(property, value) {
+ appJS.forEach(this_.array, function(el, index, array) {
+ el.setStyle(property, value);
+ });
+ };
+ /**
+ *Shortcut for appJS.dom.Element.set('styles', {
+ property: value,
+ property: value
+ }); for every appJS.dom.Element
+ *@method setStyles
+ *@param style {object} Same as the second parameter of appJS.dom.Element.set('styles', values); Type of {property: value}
+
+ **/
+ this.setStyles = function(styles) {
+ appJS.forEach(this_.array, function(value, index, array) {
+ value.setStyles(styles);
+ });
+ };
+ /**
+ *Appends an element by doing an appendChild for every appJS.dom.Element
+ *@method append
+ *@param element {HTMLElement|appJS.dom.Element|Elements} Element to append. If it is an appJS.dom.Elements, all elements will be appened.
+
+ **/
+ this.append = function(element) {
+ appJS.forEach(this_.array, function(value, index, array) {
+ value.append(element);
+ });
+ };
+ } else {
+ throw new Error('Array must be an array');
+ }
+ };
+ /**
+ *@class Dom NodeText
+ *@requires Core
+ *@requires Dom
+ *@constructor
+ *@param nodeText {Text} a nodeText
+ **/
+ appJS.dom.NodeText = function(nodeText) {
+ var this_ = this;
+ /**
+ *@property nodeText
+ *@type Text
+ *@public
+
+ **/
+ this.nodeText = (nodeText.nodeType && nodeText.nodeType === 3) ? nodeText : null;
+ this.nodeValue = this.nodeText.nodeValue ? this.nodeText.nodeValue : '';
+ /**
+ *Destroy the Element
+ *@method destroy
+
+ **/
+ this.destroy = function() {
+ var element = this_.element;
+ element.parentNode.removeChild(element);
+ };
+ /**
+ *@property parent
+ *@type appJS.dom.Element
+ *@public
+
+ **/
+ this.parent = null;
+ if (this.parentNode && !this.parentNode.doctype) {
+ this.parent = new appJS.dom.Element(this.element.parentNode);
+ }
+ /**
+ *Adds an event to the element. Same as appJS.dom.addEvent(element, event, boil, callback); where element is appJS.dom.Element.element
+ *@method addEvent
+
+ *@param event {string} Name of the event. Form: 'click', not 'onclick'
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener. False is default.
+ *@param callack {callback} Callback to call when event is fired.
+ *@param callback.e {object} Event object, same as in addEventListener, but with new methods. See appJS.dom.addEvent for further information;
+ *@async
+ **/
+ this.addEvent = function(event, boil, callback) {
+ if (appJS.isFunction(boil)) {
+ callback = boil;
+ boil = false;
+ }
+ appJS.dom.addEvent(this_.element, event, boil, callback);
+ };
+ /**
+ *Remove an event. Needs the same function that had be used to add the event;
+ *@method removeEvent
+
+ *@param event {string} Name of the event. Form: 'click', not 'onclick'
+ *@param [boil=false] {boolean} Corresponds to the third parameter of HTMLElement.addEventListener. False is default.
+ *@param callack {callback} Callback to call when event is fired.
+ *@param callback.e {object} Event object, same as in addEventListener, but with new methods. See appJS.dom.addEvent for further information;
+ *@async
+ **/
+ this.removeEvent = function(event, boil, callback) {
+ if (appJS.isFunction(boil)) {
+ callback = boil;
+ boil = false;
+ }
+ appJS.dom.removeEvent(this_.element, event, boil, callback);
+ };
+ };
+ /**
+ *Shortcut for appJS.dom.query('body'). Can be useful.
+ *@for Dom
+ *@property body
+ *@type appJS.dom.Element
+ *@public
+
+ **/
+ appJS.dom.body = new appJS.dom.Element(document.body);
+})();
View
179 app.js
@@ -0,0 +1,179 @@
+//v2.0
+(function() {
+
+ /**
+ *@module appJS
+ *@main appJS
+ *@class Core
+ *@static
+ **/
+ var appJS = {};
+ if(typeof window !== 'undefined') {
+ window.appJS = appJS;
+ } else {
+ module.exports = appJS;
+ }
+ /**
+ *Tells wether the object given as a parameter has keys or not
+ *@method isEmptyObject
+ *@return {boolean} true if object is empty or not object, false otherwise
+ *@param object {object} Object to be tested
+ *@example
+ * appJS.isEmptyObject({}); //true
+ * appJS.isArray({'key': 'value'}); //false
+ **/
+ appJS.isEmptyObject = function(object) {
+ return Object.keys(object).length === 0 || typeof object !== 'object';
+ };
+ /**
+ *Loops over an array or an object executing the callback passed as parameter to each elements.
+ *@method forEach
+ *@param object {array|object} The array or object to iterate through.
+ *@param cb {function} The function to be called with three parameters. Return false to stop the loop.
+ * @param cb.value {any} The value of the element being traversed.
+ * @param cb.index {number|string} The index of the element being traversed.
+ * @param cb.array {array|object} The array or object being traversed.
+ *@param [bind] {object} Object to used as “this” while traversing.
+ *@example
+ * appJS.forEach(['sandwich', 'tarte', 'glace'], function(element, index, array) {
+ * alert(element + ' corresponds to ' + index);
+ * });
+ * //returns "sandwich corresponds to 0", "tarte corresponds to 1", "glace corresponds to 2"
+ **/
+ appJS.forEach = function(object, cb, bind ) {
+ var T = bind ? bind : undefined,
+ retour = true;
+ if(object === null || typeof object === 'undefined') {
+ throw new TypeError('object must be defined and not null');
+ }
+ if(typeof cb !== 'function') {
+ throw new TypeError('cb must be a function and defined');
+ }
+ var keys = Object.keys(object),
+ k = 0,
+ len = keys.length >>> 0;
+ while(k < len) {
+ var kValue,
+ key = k.toString() === keys[k] ? k : keys[k];
+ kValue = object[key];
+ retour = cb.call(T, kValue, key, object);
+ if(retour === false) {
+ break;
+ }
+ k++;
+ }
+ };
+ /**
+ *Tells wether a object is from a class or not
+ *@method isClass
+ *@return {boolean} true if obj corresponds to the class.
+ *@param obj {any} Object to test
+ *@param str {string} Name of the class
+ *@example
+ * var body = document.body;
+ * appJS.isClass(body, 'HtmlBodyElement'); //true
+ * appJS.isClass(body, 'String'); //false
+ **/
+ appJS.isClass = function(obj, str) {
+ return Object.prototype.toString.call(obj) === '[object ' + str + ']';
+ };
+ var change = [
+ 'Array',
+ 'Boolean',
+ 'Date',
+ 'Function',
+ 'Number',
+ 'String',
+ 'RegExp'
+ ];
+ var buildFunction = function(num) {
+ return function(obj) {
+ return appJS.isClass(obj, num);
+ };
+ };
+
+ /**
+ *Tells wether the parameter given is an array or not.
+ *@method isArray
+ *@return {boolean} true if object is an array, false otherwise.
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isArray(['hoho', 'hehe']); //true
+ * appJS.isArray(3); //false
+ **/
+ appJS.isArray = buildFunction(change[0]);
+ /**
+ *Tells wether the parameter given is a boolean or not.
+ *@method isBoolean
+ *@return {boolean} true if object is a boolean, false otherwise.
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isBoolean(true); //true
+ * appJS.isBoolean(3); //false
+ **/
+ appJS.isBoolean = buildFunction(change[1]);
+ /**
+ *Tells wether the parameter given is a date or not
+ *@method isDate
+ *@return {boolean} true if object is a date, false otherwise
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isDate(new Date()); //true
+ * appJS.isDate(3); //false
+ **/
+ appJS.isDate = buildFunction(change[2]);
+ /**
+ *Tells wether the parameter given is a function or not
+ *@method isFunction
+ *@return {boolean} true if object is a function, false otherwise
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isFunction(function() { console.log('this is a function') ; }); //true
+ * appJS.isFunction(3); //false
+ **/
+ appJS.isFunction = buildFunction(change[3]);
+ /**
+ *Tells wether the parameter given is a number or not
+ *@method isNumber
+ *@return {boolean} true if object is a number, false otherwise
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isNumber(['hoho', 'hehe']); //false
+ * appJS.isNumber('3'); //false
+ * appJS.isNumber(3); //true
+ **/
+ appJS.isNumber = buildFunction(change[4]);
+ /**
+ *Tells wether the parameter given is a string or not
+ *@method isString
+ *@return {boolean} true if object is a string, false otherwise
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isString('3'); //true
+ * appJS.isNumber(3); //false
+ **/
+ appJS.isString = buildFunction(change[5]);
+ /**
+ *Tells wether the parameter given is a regexp or not
+ *@method isRegexp
+ *@return {boolean} true if object is a regexp, false otherwise
+ *@param object {any} Object to be tested
+ *@example
+ * appJS.isRegexp(/\w/); //true
+ * appJS.isNumber(3); //false
+ **/
+ appJS.isRegexp = buildFunction(change[6]);
+ /**
+ *Tells wether the parameter given is an object or not
+ *@method isObject
+ *@return {boolean} true if object is an object, false otherwise
+ *@param object {any} Object to be tested
+ **/
+ appJS.isObject = function(obj) {
+ return obj && typeof obj === 'object';
+ };
+
+})();
+
+
+
View
245 app.number.js
@@ -0,0 +1,245 @@
+//v2.0
+(function() {
+ /**
+ *This module provides many functions to handle numbers easier than before.
+ *@module appJS
+ *@submodule Number
+ *@class Number
+ *@static
+ **/
+
+ appJS.number = appJS.number || {};
+
+ /**
+ *Returns the provided parameter into a number or null if not a number. Part of Number object.
+ *@method from
+ *@param number {any} Number provided.
+ *@return {number|null} Number from the param, null if not a number.
+ **/
+ appJS.number.from = function(number) {
+ if(isNaN(parseInt(number, 10))) {
+ return null;
+ } else {
+ return parseInt(number, 10);
+ }
+ };
+
+
+ /**
+ *Returns a random number between min and max. Part of Number object.
+ *@method random
+ *@param min {any} Minimum. If not passed, then result will be either 0 or 1.
+ *@param max {any} Maximum. If not passed, then minimum will be 0 and maximum will be minimum.
+ *@return {number} Random number between min and max.
+ *@beta
+ **/
+ appJS.number.random = function(min, max) {
+ if(typeof min === 'undefined' || !appJS.isNumber(min)) {
+ min = 0;
+ max = 1;
+ } else if (typeof max === 'undefined' || !appJS.isNumber(max)) {
+ max = min;
+ min = 0;
+ }
+ return Math.floor(Math.random() * (max - min + 1) + min);
+ };
+ /**
+ *Limits a number with two other numbers. Part of Number prototype object.
+ *@method limit
+ *@param number {any} Number to limit. If not a number, appJS.number.from will be used.
+ *@param min {any} Minimum of the limit. If not a number, appJS.number.from will be used.
+ *@param max {any} Maximum of the limit. If not a number, appJS.number.from will be used.
+ *@return {number} If number > max, returns max. If number < min, returns min. Otherwise, returns number.
+ **/
+ appJS.number.limit = function(number, min, max) {
+ if(appJS.isNumber(min) && appJS.isNumber(max) && appJS.isNumber(number)) {
+ if(number > max) {
+ return max;
+ } else if (number < min) {
+ return min;
+ } else {
+ return number;
+ }
+ } else {
+ number = appJS.number.from(number);
+ min = appJS.number.from(min);
+ max = appJS.number.from(max);
+ if(max === null || min === null) {
+ throw new Error('min, number and max must be numbers');
+ } else {
+ return appJS.number.limit(number, min, max);
+ }
+ }
+ };
+
+ /**
+ *Calls a function x times where x is number. Also present in Number Prototype.
+ *@method times
+ *@param number {number} Number of times the function has to be called.
+ *@param cb {function} Function to call. The only parameter is the iteration.
+ *@param [bind] {object} Value of this into the function.
+ *@return
+ **/
+ appJS.number.times = function(number, cb, bind) {
+ for(var i = 0 ; i < number ; i++) {
+ cb.call(bind, i);
+ }
+ };
+ /**
+ *Returns an int with from the parameter provided. Part of the Number object.
+ *@method toInt
+ *@param number {any} Number to convert
+ *@param [base=10] {number} Base on which to convert
+ *@return {number} Result of the conversion
+ *@beta
+ **/
+ appJS.number.toInt = function(number, base) {
+ if(!base || !appJS.isNumber(base)) {
+ base = 10;
+ }
+ var result = parseInt(number, base);
+ if(isNaN(result)) {
+ return null;
+ } else {
+ return result;
+ }
+ };
+ /**
+ *Returns an array containing numbers from num down to limit.
+ *@method downto
+ *@param num {number} Number to start with.
+ *@param [limit] {number} Limit to stop. If not defined, not a number, or greater or equal than num, the function will return an empty array.
+ *@param [fn] {function} Function to apply to every number. Accept one parameter, the current number.