/** * @package Regular.js * @description A light and simple JavaScript Library * * @author Peter van Westen <info@regularlabs.com> * @link https://github.com/regularlabs/regularjs * @copyright Copyright © 2019 Regular Labs - All Rights Reserved * @license https://github.com/regularlabs/regularjs/blob/master/LICENCE MIT */ "use strict"; if (typeof window.Regular === 'undefined' || typeof Regular.version === 'undefined' || Regular.version < 1.3) { window.Regular = new function() { /** * * PUBLIC PROPERTIES * */ this.version = 1.3; /** * * PUBLIC METHODS * */ /** * Sets a global alias for the Regular class. * * @param word A string (character or word) representing the alias for the Regular class. * * @return boolean */ this.alias = function(word) { if (typeof window[word] !== 'undefined') { console.error(`Cannot set '${word}' as am alias of Regular, as it already exists.`); return false; } window[word] = $; return true; }; /** * Returns a boolean based on whether the element contains one or more of the given class names. * * @param selector A CSS selector string or a HTMLElement object. * @param classes A string or array of class names. * @param matchAll Optional boolean whether the element should have all given classes (true) or at least one (false). * * @return boolean */ this.hasClasses = function(selector, classes, matchAll = true) { if (!selector) { return false; } const element = typeof selector === 'string' ? document.querySelectorAll(selector) : selector; if (typeof classes === 'string') { classes = classes.split(' '); } let hasClass = false; for (const clss of classes) { hasClass = element.classList.contains(clss); if (matchAll && !hasClass) { return false; } if (!matchAll && hasClass) { return true; } } return hasClass; }; /** * Adds given class name(s) to the element(s). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. * @param classes A string or array of class names. */ this.addClasses = function(selector, classes) { doClasses('add', selector, classes); }; /** * Removes given class name(s) from the element(s). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. * @param classes A string or array of class names. */ this.removeClasses = function(selector, classes) { doClasses('remove', selector, classes); }; /** * Toggles given class name(s) of the element(s). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. * @param classes A string or array of class names. */ this.toggleClasses = function(selector, classes) { doClasses('toggle', selector, classes); }; /** * Shows the given element(s) (changes opacity and display attributes). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. */ this.show = function(selector) { if (!selector) { return; } const element = typeof selector === 'string' ? document.querySelectorAll(selector) : selector; if ('forEach' in element) { element.forEach(subElement => $.show(subElement)); return; } let computedDisplay = getComputedStyle(element, 'display'); if (!('origDisplay' in element)) { element.origDisplay = computedDisplay === 'none' ? getDefaultComputedStyle(element, 'display') : computedDisplay; } if (computedDisplay === 'none') { element.style.display = ('origDisplay' in element) ? element.origDisplay : ''; } computedDisplay = getComputedStyle(element, 'display'); if (computedDisplay === 'none') { element.style.display = 'block'; } element.style.visibility = 'visible'; element.style.opacity = 1; }; /** * Hides the given element(s) (changes opacity and display attributes). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. */ this.hide = function(selector) { if (!selector) { return; } const element = typeof selector === 'string' ? document.querySelectorAll(selector) : selector; if ('forEach' in element) { element.forEach(subElement => $.hide(subElement)); return; } const computedDisplay = getComputedStyle(element, 'display'); if (computedDisplay !== 'none' && !('origDisplay' in element)) { element.origDisplay = computedDisplay; } element.style.display = 'none'; element.style.visibility = 'hidden'; element.style.opacity = 0; }; /** * Fades in the the given element(s). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. * @param duration Optional duration of the effect in milliseconds. * @param oncomplete Optional callback function to execute when effect is completed. */ this.fadeIn = function(selector, duration = 250, oncomplete) { if (!selector) { return; } const element = typeof selector === 'string' ? document.querySelectorAll(selector) : selector; if ('forEach' in element) { element.forEach(subElement => $.fadeIn(subElement, duration, oncomplete)); return; } element.setAttribute('data-fading', 'in'); const wait = 50; // amount of time between steps const nr_of_steps = duration / wait; const change = 1 / nr_of_steps; // time to wait before next step element.style.opacity = getComputedStyle(element, 'opacity'); if (!element.style.opacity) { element.style.opacity = 0; } if (element.style.display === 'none') { element.style.display = 'block'; } element.style.visibility = 'visible'; (function fade() { if (element.getAttribute('data-fading') === 'out') { return; } const new_opacity = parseFloat(element.style.opacity) + change; if (new_opacity >= 1) { $.show(element); element.setAttribute('data-fading', ''); if (oncomplete) { oncomplete.call(element); } return; } element.style.opacity = new_opacity; setTimeout(function() { fade.call(); }, wait); })(); }; /** * Fades out the the given element(s). * * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. * @param duration Optional duration of the effect in milliseconds. * @param oncomplete Optional callback function to execute when effect is completed. */ this.fadeOut = function(selector, duration = 250, oncomplete) { if (!selector) { return; } const element = typeof selector === 'string' ? document.querySelectorAll(selector) : selector; if ('forEach' in element) { element.forEach(subElement => $.fadeOut(subElement, duration, oncomplete)); return; } element.setAttribute('data-fading', 'out'); const wait = 50; // amount of time between steps const nr_of_steps = duration / wait; const change = 1 / nr_of_steps; // time to wait before next step element.style.opacity = getComputedStyle(element, 'opacity'); (function fade() { if (element.getAttribute('data-fading') === 'in') { return; } const new_opacity = parseFloat(element.style.opacity) - change; if (element.style.opacity <= 0) { $.hide(element); element.setAttribute('data-fading', ''); if (oncomplete) { oncomplete.call(element); } return; } element.style.opacity = new_opacity; setTimeout(function() { fade.call(); }, wait); })(); }; /** * Runs a function when the document is loaded (on ready state). * * @param func Callback function to execute when document is ready. */ this.onReady = function(func) { document.addEventListener('DOMContentLoaded', func); }; /** * Converts a string with HTML code to 'DOM' elements. * * @param html String with HTML code. * * @return element */ this.createElementFromHTML = function(html) { return document.createRange().createContextualFragment(html); }; /** * Loads a url with optional POST data and optionally calls a function on success or fail. * * @param url String containing the url to load. * @param data Optional string representing the POST data to send along. * @param success Optional callback function to execute when the url loads successfully (status 200). * @param fail Optional callback function to execute when the url fails to load. */ this.loadUrl = function(url, data, success, fail) { const request = new XMLHttpRequest(); request.open("POST", url, true); request.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); request.onreadystatechange = function() { if (this.readyState !== 4) { return; } if (this.status === 200) { success && success.call(null, this.responseText, this.status, this); return; } fail && fail.call(null, this.responseText, this.status, this); }; request.send(data); }; /** * * ALIASES * */ this.as = this.alias; this.hasClass = this.hasClasses; this.addClass = this.addClasses; this.removeClass = this.removeClasses; this.toggleClass = this.toggleClasses; /** * * PRIVATE FUNCTIONS * */ /** * Executes an action on the element(s) to add/remove/toggle classes. * * @param action A string that identifies the action: add|remove|toggle. * @param selector A CSS selector string, a HTMLElement object or a collection of HTMLElement objects. * @param classes A string or array of class names. */ const doClasses = function(action, selector, classes) { if (!selector) { return; } const element = typeof selector === 'string' ? document.querySelectorAll(selector) : selector; if ('forEach' in element) { element.forEach(subElement => doClasses(action, subElement, classes)); return; } if (typeof classes === 'string') { classes = classes.split(' '); } element.classList[action](...classes); }; /** * Finds the computed style of an element. * * @param element A HTMLElement object. * @param property The style property that needs to be returned. * * @returns mixed */ const getComputedStyle = function(element, property) { if (!element) { return null; } return window.getComputedStyle(element).getPropertyValue(property); }; /** * Finds the default computed style of an element by its type. * * @param element A HTMLElement object. * @param property The style property that needs to be returned. * * @returns mixed */ const getDefaultComputedStyle = function(element, property) { if (!element) { return null; } const defaultElement = document.createElement(element.nodeName); document.body.append(defaultElement); let propertyValue = window.getComputedStyle(defaultElement).getPropertyValue(property); defaultElement.remove(); return propertyValue; }; /** * * PRIVATE VARIABLES * */ /** * @param $ internal shorthand for the 'this' keyword. */ const $ = this; }; }