UNPKG

lea.js

Version:

A Tiny Javascript Framework For Modern Browsers (And Developers)

906 lines (735 loc) 19.3 kB
(function (window) { "use strict"; /* ========================================================================== Lea.js constructor ========================================================================== */ var Lea = function (query, context) { if (context == undefined) { context = window.document; } if (this == undefined || this === window) { return new Lea(query, context); } if (query == null) { this.elements = []; return this; } if (Lea.type(query) !== "array") { query = [query]; } this.elements = []; query.forEach((function (obj) { if (Lea.isNode(obj) || obj === window || obj === document) { this.elements.push(obj); } else if (Lea.type(obj) === "string") { this.elements = this.elements.concat(Lea.toArray(context.querySelectorAll(obj))); } }).bind(this)); return this; }; /* ========================================================================== About informations ========================================================================== */ Lea.about = { version : "{{version}}", homepage : "{{homepage}}" }; /* ========================================================================== Helpers ========================================================================== */ // [OK] Add method to Lea Lea.addMethod = function (name, fn) { this.prototype[name] = fn; }; // Execute function on DOM ready Lea.ready = function (fn) { if (document.readyState != "loading") { fn(); } else { document.addEventListener("DOMContentLoaded", fn); } }; // Extend Lea.extend = function (out) { var out = out || {}; for(var i = 1; i < arguments.length; i++) { if (!arguments[i]) continue; for(var key in arguments[i]) { if (arguments[i].hasOwnProperty(key)) { out[key] = arguments[i][key]; } } } return out; }; // [OK] Convert collection to array Lea.toArray = function (coll){ return Array.prototype.slice.call(coll, 0); }; // [OK] Get object type Lea.type = function (obj) { return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, "$1").toLowerCase(); }; // [OK] Check Element Lea.isNode = function (obj) { return obj instanceof HTMLElement; }; // [OK] Camelize Lea.camelize = function (str) { if (str.charAt(0) == "-") { str = str.slice(1); } return str.replace(/-\D/g, function (match) { return match.charAt(1).toUpperCase(); }); }; // [OK] Dashize Lea.dashize = function (str) { return str.replace(/[A-Z]/g, function (match) { return ("-" + match.charAt(0).toLowerCase()); }); }; // [OK] Parse object Lea.forEach = function (obj, fn, context) { for(var key in obj) { if (obj.hasOwnProperty(key)) { fn.call(context || obj, key, obj[key]); } } }; // [OK] Convert string to node Lea.str2Node = function (str) { if (Lea.isNode(str)) { return str; } var div = document.createElement("div"); div.innerHTML = str; return Array.prototype.slice.call(div.childNodes, 0); }; // [OK] Create Html Element Lea.create = function (tag, attr) { var elt = document.createElement(tag); if (attr != undefined) { Lea.forEach(attr || {}, function (key, val) { switch(key.toLowerCase()) { case "style": elt = $(elt).css(val).get(0); break; case "html": elt.innerHTML = val; break; case "text": elt.innerText = val; break; case "class": elt.classList.add(val); break; case "event": Lea.forEach(val, function (evt, fn) { elt.addEventListener(evt, fn, false); }); break; case "data": Lea.forEach(val, function (_key, _val) { elt.dataset[_key] = _val; }); break; default: elt.setAttribute(key, val); break; } }); } return elt; }; // [OK] Get device type (tablet / phone / desktop) Lea.device = function (type) { var ua = navigator.userAgent.toLowerCase(); var device = (function () { if (/(ipad|tablet|(android(?!.*mobile))|(windows(?!.*phone)(.*touch))|kindle|playbook|silk|(puffin(?!.*(IP|AP|WP))))/.test(ua)) { return "tablet"; } else if (/(mobi|ipod|phone|blackberry|opera mini|fennec|minimo|symbian|psp|nintendo ds|archos|skyfire|puffin|blazer|bolt|gobrowser|iris|maemo|semc|teashark|uzard)/.test(ua)) { return "phone"; } else { return "desktop"; } })(); return type != undefined ? (device === type) : device; }; // Check if mobile Lea.isMobile = function () { return !Lea.device("desktop"); }; // Get URL parameters Lea.getUrlParameters = function (parameter) { var regex = /([^&=]+)=?([^&]*)/g, match, store = {}, haystack = window.location.search || window.location.hash; haystack = haystack.substring(haystack.indexOf("?") + 1, haystack.length); while ((match = regex.exec(haystack))) { store[decodeURIComponent(match[1])] = decodeURIComponent(match[2]); } return parameter != undefined ? store[parameter] || null : store; }; // Ajax Lea.ajax = function (url, options) { this.httpRequest = function () { var cb = (function(response){}).bind(this), _this = this; this.options = Lea.extend({ method: "GET", complete: cb, success: cb, error: cb, send: true, async: true, data: {}, json: false, contentType: "application/x-www-form-urlencoded" }, options || {}); this.transport = new XMLHttpRequest(); this.options.method = this.options.method.toUpperCase(); this.parameters = ""; this.transport.onreadystatechange = function () { if (this.readyState == 4) { var response = _this.options.json ? JSON.parse(this.responseText) : this.responseText; _this.options.complete.call( _this, response ); if (this.status == 200 || this.status === 0) { _this.options.success.call( _this, response ); } else { _this.options.error.call( _this, response ); } } }; this.transport.open(this.options.method, url, this.options.async); if (this.options.method == "POST") { this.transport.setRequestHeader("Content-Type", this.options.contentType); Lea.forEach(this.options.data, function (key, val) { if (_this.parameters.length) { _this.parameters += "&"; } _this.parameters += encodeURIComponent(key) + "=" + encodeURIComponent(val); }); } if (this.options.send) { this.send(); }; }; this.httpRequest.prototype = { complete: function (cb) { this.options.complete = cb.bind(this); return this; }, success: function (cb) { this.options.success = cb.bind(this); return this; }, error: function (cb) { this.options.error = cb.bind(this); return this; }, send: function () { this.transport.send( this.parameters.length ? this.parameters : null ); return this; }, abort: function () { this.transport.abort(); return this; } }; return new this.httpRequest(); }; // Ajax Get Lea.get = function (url, options) { return Lea.ajax( url, Lea.extend(options || {}, {method: "GET"}) ); }; // Ajax Post Lea.post = function (url, data, options) { return Lea.ajax( url, Lea.extend(options || {}, {method: "POST", data: data || {}}) ); }; // [OK] Debounce Lea.debounce = function (fn, delay) { var timer; return function () { var args = arguments, context = this; clearTimeout(timer); timer = setTimeout(function () { fn.apply(context, args); }, delay); } }; // [OK] Throttle Lea.throttle = function(fn, delay) { var last, timer; return function () { var context = this, now = +new Date(), args = arguments; if (last && now < last + delay) { clearTimeout(timer); timer = setTimeout(function () { last = now; fn.apply(context, args); }, delay); } else { last = now; fn.apply(context, args); } }; }; /* ========================================================================== Methods ========================================================================== */ Lea.prototype = { // [OK] Check elements hasElements: function () { return this.elements.length > 0; }, // Loop on each elements each: function (action) { var response, err = new Error("Break"); try { this.elements.forEach(function (element, index) { response = action.call(element, element, index); if (response === false) throw err; }); } catch(error) { if (error != err) throw error; } return this; }, // [OK] Get element get: function (index) { return index != undefined ? this.elements[ index ] || null : this.elements; }, // Get the first element first: function () { return $(this.hasElements() ? this.get(0) : []); }, // Get the last element last: function () { return $(this.hasElements() ? this.get(this.elements.length - 1) : []); }, // Get computed style or set style css: function (prop, value) { if (value != undefined) { this.each(function () { this.style[ Lea.camelize(prop) ] = value; }); return this; } else { if (Lea.type(prop) === "string") { return window.getComputedStyle(this.get(0), null)[ Lea.dashize(prop) ]; } else if (Lea.type(prop) === "object") { this.each(function () { var element = this; Lea.forEach(prop, function (key, val) { element.style[ Lea.camelize(key) ] = val; }); }); return this; } } }, // Get height height: function () { var element = this.elements[0]; if (element == window) { return window.innerHeight; } if (element == document) { return document.body.clientHeight; } return element.offsetHeight; }, // Get width width: function () { var element = this.elements[0]; if (element == window) { return window.innerWidth; } if (element == document) { return document.body.clientWidth; } return element.offsetWidth; }, // [OK] Get scroll offsets scroll: function () { var element = this.elements[0]; if (element == window) { return { top: element.scrollY, left: element.scrollX, width: document.body.scrollWidth, height: document.body.scrollHeight }; } else { return { top: element.scrollTop, left: element.scrollLeft, width: element.scrollWidth, height: element.scrollHeight }; } }, // [OK] Get or set value val: function (value) { if (value != undefined) { this.each(function(){ this.value = value; }); return this; } else { return this.elements[0].value || ""; } }, // [OK] Add class addClass: function (klass) { this.each(function () { this.classList.add(klass); }); return this; }, // [OK] Remove class removeClass: function (klass) { this.each(function () { this.classList.remove(klass); }); return this; }, // [OK] Check class exists hasClass: function (klass) { var bool = true; this.elements.forEach(function (element) { if (!element.classList.contains(klass)) { bool = false; return; } }); return bool; }, // [OK] Toggle class toggleClass: function (klass) { this.each(function () { var $elt = $(this); if( $elt.hasClass(klass) ) { $elt.removeClass(klass); } else { $elt.addClass(klass); } }); return this; }, // [OK] Show element show: function (display) { if (display == undefined) var display = "block"; this.each(function () { this.style.display = display; }); return this; }, // [OK] Hide element hide: function () { this.each(function () { this.style.display = "none"; }); return this; }, // Toggle display toggle: function (display) { if (display == undefined) var display = "block"; this.each(function (){ this.style.display = Lea(this).css("display") == "none" ? display : "none"; }); return this; }, // Insert or get Html from element html: function (src) { if (src == undefined) { return this.get(0).innerHTML; } else { this.each(function () { this.innerHTML = src; }); return this; } }, // Add event on: function (event, fn) { this.each(function () { this.addEventListener(event, fn, false); }, false); return this; }, // Remove event off: function (event, fn) { this.each(function (){ this.removeEventListener(event, fn, false); }); return this; }, // [OK] Live event delegate: function (selector, event, fn) { this.each(function (){ this.addEventListener(event, function (evt) { if ( Lea(evt.target).is(selector) ) { fn.call(evt.target, event); } }, false ); }); return this; }, // Fire event trigger: function (event){ var evt = document.createEvent("HTMLEvents"); evt.initEvent(event, true, true); this.each(function () { this.dispatchEvent(evt); }); return this; }, // Apply "click" event click: function (fn) { return this.on("click", fn); }, // Set or get attribute attr: function (attr, val){ if (val != undefined) { this.each(function () { this.setAttribute(attr, val); }); return this; } else { return this.elements[0].getAttribute(attr); } }, // Remove attribute removeAttr: function (attr) { this.each(function () { this.removeAttribute(attr); }); return this; }, // [OK] Set or get data data: function (data, value) { if (value != undefined) { this.each(function () { this.dataset[data] = value; }); return this; } else { return this.get(0).dataset[data]; } }, // [OK] Remove data removeData: function (data) { this.each(function () { delete this.dataset[data]; }); return this; }, // Clone node clone: function () { return this.elements[0].cloneNode(true); }, // [OK] Append element append: function (obj) { this.each(function (element) { if (Lea.isNode(obj)) { element.appendChild(obj); } else { var nodes = Lea.str2Node(obj); nodes.forEach(function (node) { element.appendChild(node); }); } }); return this; }, // [OK] Prepend element prepend: function (obj) { this.each(function (element) { if (Lea.isNode(obj)) { element.insertBefore(obj, element.firstChild); } else { var nodes = Lea.str2Node(obj); nodes.forEach(function (node) { element.insertBefore(node, element.firstChild); }); } }); return this; }, // [OK] Insert element before an other element before: function (obj){ this.each(function () { this.insertAdjacentHTML("beforebegin", obj); }); return this; }, // [OK] Insert element after an other element after: function (obj) { this.each(function () { this.insertAdjacentHTML("afterend", obj); }); return this; }, // [OK] Remove element from DOM remove: function (){ this.each(function () { this.parentNode.removeChild(this); }); return this; }, // [OK] Get parent parent: function (){ var parents = []; this.each(function () { var parent = this.parentNode; if (parent) { parents.push(parent); } }); return new Lea(parents); }, // [OK] Find elements find: function (selector) { var found = []; this.elements.forEach(function (element) { found = found.concat( Lea.toArray(element.querySelectorAll(selector)) ); }); this.elements = found; return this; }, // [OK] Get previous element prev: function () { var previous = []; this.each(function () { var prev = this.previousElementSibling; if (prev) { previous.push(prev); } }); this.elements = previous; return this; }, // [OK] Get next element next: function () { var next = []; this.each(function () { var nex = this.nextElementSibling; if (nex) { next.push(nex); } }); this.elements = next; return this; }, // [OK] Clear content clear: function () { this.each(function () { this.innerHTML = ""; }); return this; }, // [OK] Get or set text content text: function (txt) { if (txt != undefined) { this.each(function () { this.textContent = txt; }); return this; } else { return this.hasElements ? this.elements[0].innerText : ""; } }, // [OK] Check comparaison is: function (selector) { var flag = true; var matches = function (element) { //return (element.matches || element.matchesSelector || element.msMatchesSelector || element.mozMatchesSelector || element.webkitMatchesSelector || element.oMatchesSelector).call(element, selector); return (element.matches || element.matchesSelector || element.msMatchesSelector || element.webkitMatchesSelector).call(element, selector); }; this.each(function () { flag = matches(this); return flag; }); return flag; }, // [OK] Get offset offset: function () { if (!this.hasElements()) return {top:0,left:0} var element = this.elements[0], rect = element.getBoundingClientRect(); return { top: rect.top + document.body.scrollTop, left: rect.left + document.body.scrollLeft }; }, // [OK] Get position position: function () { if (!this.hasElements()) return {top:0,left:0} var rect = this.elements[0].getBoundingClientRect(); return { top: rect.top, left: rect.left }; }, // [OK] Replace from Html replaceWith: function (html) { this.each(function () { this.outerHTML = html; }); return this; }, // [OK] Serialize form serialize: function () { var form = this.elements[0], serial = {}, l, j; if (form.nodeName.toLowerCase() !== "form") { return serial; } Lea.toArray(form.elements).forEach(function (field) { if (field.name && !field.disabled && (["file", "button", "reset", "submit"]).indexOf(field.type) == -1) { if (field.type == "select-multiple") { l = form.elements[i].options.length; for (j = 0; j < l; j++) { if (field.options[j].selected) { serial[field.name] = field.options[j].value; } } } else if ( (field.type != "checkbox" && field.type != "radio") || field.checked) { serial[field.name] = field.value; } } }); return serial; }, submit: function (options) { var form = this.elements[0]; if (form.nodeName.toLowerCase() !== "form") { return false; } options = Lea.extend({ method: form.method || "GET", data: this.serialize() }, options || {}); return Lea.ajax( form.action || "#", options ); } }; window.Lea = window.$ = Lea; /* ========================================================================== AMD Compliant For Use With RequireJS ========================================================================== */ if (typeof define === "function" && define.amd) { define("lea", [], function() { return Lea; }); } console.info("Powered by Lea.js" + "\n" + "Version: " + Lea.about.version + "\n" + "Homepage:" + Lea.about.homepage); return Lea; })(window);