/**
* @module basiq.utils
* @version 1.0
* @authors: @smorcuend, @jmanuel_rosa
* @title basiq (Basic JS library)
* @description Prototyping without query selector section
*/
'use strict';
/** @namespace */
var $ = require('./basiq.core');
/**
* Extend the Basiq object.
* Merge the contents of an object onto the basiq prototype to provide new basiq instance methods.
* params[0] = target object | boolean (deep copy)
*/
$.extend = function(objTarget, objExtra) {
var source = {};
var obj = objTarget;
if (objExtra) {
source = objTarget;
obj = objExtra;
}
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
source[prop] = obj[prop];
}
}
return source;
};
/**
* [clone description]
* @date 2014-07-07
* @anotherdate 2014-07-07T14:57:43+0100
* @param {Object} obj [description]
* @return {Object} [description]
*/
$.clone = function(obj) {
// if (!$.isPlainObject(obj)) return obj;
function cloneArrayDeeply() {
var target = [];
obj.forEach(function(item) {
target.push($.clone(item));
});
return target;
}
if (Array.isArray(obj)) {
return cloneArrayDeeply();
}
return $.extend(obj, {});
};
/**
* [isPlainObject description]
* @date 2014-07-07
* @anotherdate 2014-07-07T14:57:49+0100
* @param {Object} [description]
* @return {Boolean} [description]
*/
$.isPlainObject = function(o) {
return Object(o) === o && Object.getPrototypeOf(o) === Object.prototype;
};
/**
* [resize event with propagation control]
*/
$.resize = function(callback) {
var _resizeThrottler = function() {
// ignore resize events as long as an actualResizeHandler execution is in the queue
if (!resizeTimeout) {
resizeTimeout = setTimeout(function() {
resizeTimeout = null;
callback();
}, 500); // The actualResizeHandler will execute at a rate of 2fps (1/timer * 1000)
}
};
window.addEventListener('resize', _resizeThrottler, false);
var resizeTimeout;
};
/*
* Generate custom events - Modern browsers
* @returns {Event}
*/
$.customEvent = function(name, data) {
//old-fashioned way - For old versions of IE
if (!document.createEvent) {
// Create the event
var event = document.createEvent('Event');
// Define that the event name is 'build'.
event.initEvent('build', true, true);
return event;
} else {
return (!data) ? new Event(name) : new CustomEvent(name, data);
}
};
/**
* Check Support for some functionality or property
* @date 2014-04-16
* @anotherdate 2014-04-16T13:21:07+0100
* @return {boolean}
*/
$.supports = (function() {
var div = document.createElement('div'),
vendors = 'Ms Moz Webkit'.split(' '),
len = vendors.length;
return function(prop) {
if (prop in div.style) {
return true;
}
prop = prop.replace(/^[a-z]/, function(val) {
return val.toUpperCase();
});
var lenCheck = len;
while (lenCheck--) {
if (vendors[lenCheck] + prop in div.style) {
return true;
}
}
return false;
};
})();
/* Network functions:
* ajax ( url, type, data, async, arrayHeaders )
* @returns Promise
*/
$.ajax = function(url, type, data, async, arrayHeaders, responseType) {
// Return a new promise.
return new Promise(function(resolve, reject) {
try {
var req = new XMLHttpRequest();
async = !async ? true: async;
type = !type ? 'GET' : type;
req.open(type, url, async);
if (responseType) {
req.responseType = responseType;
} else {
req.responseType = 'text';
}
req.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
if (arrayHeaders) {
for (var item in arrayHeaders) {
req.setRequestHeader(item, arrayHeaders[item]);
}
}
//In order to include cookies as part of the request, you need to set the XHR’s .withCredentials property to true
if ('withCredentials' in req) {
req.withCredentials = true;
}
req.onload = function() {
//Check the status
if (req.status === 200) {
// var dataParsed = null;
// if (req.responseType !== 'json' && req.getResponseHeader('Content-Type') === 'application/json') {
// dataParsed = JSON.parse(req.response);
// } else {
// dataParsed = req.response;
// }
//resolve(dataParsed);
resolve(req);
} else {
reject(req);
}
};
// Handle network errors
req.onerror = function() {
reject(Error('Network Error'));
};
// Make the request
if (data) {
req.send(data);
} else {
req.send();
}
} catch (e) {
throw new Error(e);
}
});
};
/*
* runLater -> Force event added to the browser bucket event
* @returns {callback}
*/
$.runLater = function(callback, delay) {
if (!callback) {
return false;
}
setTimeout(callback, delay || 0);
};
/* Base64 function
* @returns {log}
*/
$.base64 = {
encode: function(string) {
window.btoa(window.unescape(encodeURIComponent(string)));
},
decode: function(string, mode) {
if (mode === 'url') {
// var modulus = string.length % 4;
switch (string) {
case 1:
throw new Error('$.base64: Invalid token');
case 2:
string += '=';
break;
case 3:
string += '=';
break;
default:
break;
}
}
return JSON.parse(decodeURIComponent(window.escape(window.atob(string))));
}
};
/**
*
*/
/* addStylesheetRules([
['h2', // Also accepts a second argument as an array of arrays instead
['color', 'red'],
['background-color', 'green', true] // 'true' for !important rules
],
['.myClass',
['background-color', 'yellow']
]
]);
type: false, internal
*/
$.addStylesheetRules = function(rules, dom, type, identifier) {
function _insertContent(styleEl, rules) {
if (typeof rules === 'string') {
styleEl.innerHTML = rules;
return;
}
//var s = styleEl.sheet;
styleEl.innerHTML = '';
for (var i = 0, rl = rules.length; i < rl; i++) {
var j = 1,
rule = rules[i],
selector = rule[0],
propStr = '';
// If the second argument of a rule is an array of arrays, correct our variables.
// if (Object.prototype.toString.call(rule[1][0]) === '[object Array]') {
// rule = rule[1];
// j = 0;
// }
for (var pl = rule.length; j < pl; j++) {
var prop = rule[j];
//s.insertRule(selector, prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : ''), 0);
propStr += prop[0] + ':' + prop[1] + (prop[2] ? ' !important' : '') + ';\n';
}
styleEl.innerHTML += selector + ' {' + propStr + '}\n';
//s.insertRule(selector + ' {' + propStr + '} ', 0);
}
}
if (undefined !== type && 'DOM' !== type && 'internal' !== type) {
return false;
}
if (undefined === type || 'internal' === type) {
var doc = dom || document;
var styleEl = null;
if ($(identifier, doc).length === 0) {
styleEl = doc.createElement('style');
styleEl.type = 'text/css';
styleEl.id = identifier;
doc.head.appendChild(styleEl);
// Apparently some version of Safari needs the following line? I dunno.
//styleEl.appendChild(doc.createTextNode(''));
_insertContent(styleEl, rules);
return true;
} else {
return false;
}
}
return false;
};
/**
* undefined: Se devuelve cuando los argumentos son incorrectos
* false: Cuando no se cumplen las condiciones necesarias de los métodos
* true: todo ha ido de forma correcta
*/
$.storage = {
set: function(key, data) {
// Los argumentos son obligatorios
if (undefined === key || 0 === key.length || undefined === data || 0 === data.length) {
return undefined;
}
// Si la clave ya existía, avisa de ello devolviendo falso
if (false === this.get(key)) {
return false;
}
localStorage.setItem(key, data);
return true;
},
get: function(key) {
if (undefined === key) {
return undefined;
}
return localStorage.getItem(key);
},
remove: function(key) {
if (undefined === key || 0 === key.length) {
return undefined;
}
if (false === this.get(key)) {
return false;
}
localStorage.removeItem(key);
return true;
},
modify: function(key, data) {
if (undefined === key || 0 === key.length || undefined === data || 0 === data.length) {
return undefined;
}
localStorage.setItem(key, data);
return true;
}
};
/**
* Find deeply nested objects by attrs = {property: value}
*/
$.findProp = function(items, attrs) {
function match(value) {
for (var key in attrs) {
if (attrs[key] !== value[key]) {
return false;
}
}
return true;
}
function traverse(val) {
var result;
val.forEach(function(val) {
if (match(val)) {
result = val;
return false;
}
if (val instanceof Object || Array.isArray(val)) {
result = traverse(val);
}
if (result) {
return false;
}
});
return result;
}
return traverse(items);
};
/**
* [contentLoaded description]
* @param {Window} win [description]
* @param {Function} fn [description]
* @return {void} [description]
*/
$.contentLoaded = function(win, fn) {
var done = false,
top = true,
doc = win.document,
root = doc.documentElement,
add = doc.addEventListener ? 'addEventListener' : 'attachEvent',
rem = doc.addEventListener ? 'removeEventListener' : 'detachEvent',
pre = doc.addEventListener ? '' : 'on',
init = function(e) {
if (e.type === 'readystatechange' && doc.readyState !== 'complete') {
return;
}
(e.type === 'load' ? win : doc)[rem](pre + e.type, init, false);
if (!done && (done = true)) {
fn.call(win, e.type || e);
}
},
poll = function() {
try {
root.doScroll('left');
} catch (e) {
setTimeout(poll, 50);
return;
}
init('poll');
};
if (doc.readyState === 'complete') {
fn.call(win, 'lazy');
} else {
if (doc.createEventObject && root.doScroll) {
try {
top = !win.frameElement;
} catch (e) {}
if (top) {
poll();
}
}
doc[add](pre + 'DOMContentLoaded', init, false);
doc[add](pre + 'readystatechange', init, false);
win[add](pre + 'load', init, false);
}
};
/**
* [getObjectType description]
* @date 2014-07-04
* @anotherdate 2014-07-04T13:14:58+0100
* @param {Object} obj [description]
* @return {String} [description]
*/
$.getObjectType = function(obj) {
return Object.prototype.toString.call(obj);
};
/**
* [getIndex description]
* @date 2014-07-22
* @anotherdate 2014-07-22T14:53:39+0100
* @param {NodeObject} node [description]
* @return {int} [description]
*/
$.getIndex = function(node) {
var n = 0;
node = node.previousSibling;
while (node) {
node = node.previousSibling;
n++;
}
return n;
};
/**
* [getNodeFromIndex description]
* @date 2014-07-23
* @anotherdate 2014-07-23T11:28:19+0100
* @param {NodeObject} parentNode [description]
* @param {int} index [number [1-length]]
* @return {Node} [return node]
*/
$.getNodeFromIndex = function(parentNode, index) {
return parentNode.childNodes[index - 1];
};