UNPKG

teseract-utilesjs

Version:

UtilesJS is a set of javascript utilities to facilitate the manipulation and use of some javascript elements and the DOM

1,245 lines (1,077 loc) 45.2 kB
// @ts-check /** * This function orders an array by string, date or number according to the attribute and in both ascending and descending order * * @param {Array} array * */ export const arrayOrderBy = (array) => { if (typeof array != 'object') throw new Error('The argument "array" must be an array'); return { /** * @param {string} attr name of attribute * @param {'asc'|'desc'} order * * @return {array} */ string: (attr, order) => { if (typeof attr != 'string') throw new Error('The argument "attr" must be a string'); if (typeof order != 'string') throw new Error('The argument "order" must be a string'); if(!['asc', 'desc'].includes(order)) throw new Error('The attribute "order" must be "asc" or "desc"'); array.sort(function (a,b) { return order == 'asc' ? ((a[attr] == b[attr]) ? 0 : ((a[attr] < b[attr]) ? 1 : -1 )): ((a[attr] == b[attr]) ? 0 : ((a[attr] > b[attr]) ? 1 : -1 )); }); return array; }, /** * @param {string} attr name of attribute * @param {'asc'|'desc'} order * * @return {array} */ date: (attr, order) => { if (typeof attr != 'string') throw new Error('The argument "attr" must be a string'); if (typeof order != 'string') throw new Error('The argument "order" must be a string'); if(!['asc', 'desc'].includes(order)) throw new Error('The attribute "order" must be "asc" or "desc"'); array.sort(function (a, b) { let v1 = new Date(a[attr]); let v2 = new Date(b[attr]); let sort1 = v1, sort2 = v2; // @ts-ignore return order == 'asc' ? sort2 - sort1 : sort1 - sort2; }); return array; }, /** * @param {string} attr name of attribute * @param {'asc'|'desc'} order * * @return {array} */ number: (attr, order) => { if (typeof attr != 'string') throw new Error('The argument "attr" must be a string'); if (typeof order != 'string') throw new Error('The argument "order" must be a string'); if(!['asc', 'desc'].includes(order)) throw new Error('The attribute "order" must be "asc" or "desc"'); array.sort(function (a, b) { let v1 = a[attr]; let v2 = b[attr]; let sort1 = v1, sort2 = v2; return order == 'asc' ? sort2 - sort1 : sort1 - sort2; }); return array; } } } /** * This function groups an array by category/attribute. * Just work in a new variable. * * @param {Array} arr array * @param {string} attribute attribute name to group * * @return {Array} new array grouped by attribute */ export const arrayGroupBy = (arr, attribute) => { if (typeof arr != 'object') throw new Error('The argument "arr" must be an array'); if (typeof attribute != 'string') throw new Error('The argument "attribute" must be a string'); // @ts-ignore return arr.reduce((group, array) => { group[array[attribute]] = group[array[attribute]] ?? []; group[array[attribute]].push(array); return group; }, {}); } /** * This function merges arrays and groups them based on the value of an attribute that matches between them. * Just work in a new variable. Ex: var array2 = Utiles().arrayFusionByAttribute([array1, array2], 'date') * * @param {Array} arrays * @param {string} attribute * * @returns {Array} */ export const arrayFusionByAttribute = (arrays, attribute) => { if (typeof arrays != 'object') throw new Error('The argument "arrays" must be an object'); if (typeof attribute != 'string') throw new Error('The argument "attribute" must be a string'); let newArray = []; let finalArray = []; arrays.forEach(element => { let obj = arrayGroupBy(element, attribute); newArray.push(obj); }); newArray.forEach(element => { for(const [key, value] of Object.entries(element)){ switch (finalArray.hasOwnProperty(key)) { case false: finalArray[key] = value[0]; break; case true: for (const [key2, value2] of Object.entries(value[0])) { if(!finalArray[key].hasOwnProperty(key2)){ finalArray[key][key2] = value2; } } break; } } }); return finalArray; } /** * This function removes the elements of an array based on their index, respecting the initial order * * @param {Array} array * @param {Array} indexes [1,2,...] */ export const arrayRemoveItemsByIndex = (array, indexes) => { if (typeof array != 'object') throw new Error('The argument "array" must be an object'); if (typeof indexes != 'object') throw new Error('The argument "indexes" must be an object'); indexes.sort((a, b) => b - a); for (let index of indexes) { array.splice(index, 1); } } /** * This function indexes the elements of an array based on the value of a parameter * * @param {Array<Object>} array * @param {String} prop * @returns */ export const arrayIndexBy = (array, prop) => { return array.reduce((acc, item) => { acc[item[prop]] = item; return acc }, {}) } /** * * @param {Array} array * * @returns {Array} */ export const arrayClone = (array) => { return [...array]; } /** Strings */ /** * This function converts the first letter of a string to uppercase * * @param {string} str * * @returns {string} */ export const capFirstLetter = (str) => { if (typeof str != 'string') throw new Error('The argument "str" must be a string'); return str.charAt(0).toUpperCase() + str.slice(1); } /** * This function generates line breaks based on the number of characters specified * * @param {string} text * @param {number} charactersPerLine * * @returns {string} text with line break */ export const addLineBreak = (text, charactersPerLine) => { if (typeof text != 'string') throw new Error('The argument "text" must be a string'); if (typeof charactersPerLine != 'number') throw new Error('The argument "charactersPerLine" must be a number'); var words = text.split(' '); var formattedText = ''; var counter = 0; for (var i = 0; i < words.length; i++) { var currentWord = words[i]; if (counter + currentWord.length > charactersPerLine) { formattedText += '<br>'; counter = 0; } formattedText += currentWord + ' '; counter += currentWord.length + 1; } return formattedText.trim(); } /** * This function validates the format of the mail * * @param {string} email email to validate * * @returns {boolean} TRUE if the email is valid, otherwise FALSE */ export const validateEmail = (email) => { if (typeof email != 'string') throw new Error('The argument "email" must be a string'); const validRegex = /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/; if (email.match(validRegex)) { return true; } else { return false; } } /** * This function validates the format of the rut * * @param {string} rut rut to validate * * @returns {boolean} TRUE if the rut is valid, otherwise FALSE */ export const validateRut = (rut) => { if (typeof rut != 'string') throw new Error('The argument "rut" must be a string'); var dashCheck = rut.match(/-/g) if(dashCheck == null || dashCheck.length > 1) return false rut = rut.replace(/\./g, "").replace(/-/g, "") var checkDigit = rut.charAt(rut.length - 1) var rutWithoutDigit = rut.slice(0, -1) var sum = 0 var multiplier = 2 for (var i = rutWithoutDigit.length - 1; i >= 0; i--) { sum += multiplier * parseInt(rutWithoutDigit.charAt(i), 10) multiplier = multiplier < 7 ? multiplier + 1 : 2 } /** @type {string|number} */ var expectedDigit = 11 - (sum % 11) expectedDigit = (expectedDigit === 11) ? "0" : (expectedDigit === 10) ? "K" : expectedDigit.toString() return checkDigit === expectedDigit } /** Numbers */ /** * This function add thousand points to prices * @param {number} price * * @returns {string} price with thousand points (1.000, 10.000, etc.) */ export const formatPrice = (price) => { if (typeof price != 'number') throw new Error('The argument "price" must be a number'); return new Intl.NumberFormat("de-DE").format(price); } /** * This function round prices in base 10 * @param {number} price * * @returns {number} price rounded to base 10 */ export const roundPrice = (price) => { if (typeof price != 'number') throw new Error('The argument "price" must be a number'); let total = price; let round = parseInt(total.toString().charAt(total.toString().length - 1)); if(round != 0){ if(round >= 6){ round = 10 - round; }else if(round <= 5){ round = round * -1; } } total = total + round; return total; } /** * This function get the discounted price * * @param {number} price * @param {number} discount discount percentage * * @returns {number} price */ export const discountPrice = (price, discount) => { if (typeof price != 'number') throw new Error('The argument "price" must be a number'); if (typeof discount != 'number') throw new Error('The argument "discount" must be a number'); let newPrice = 0; newPrice = price - (price * (discount / 100)); return newPrice; } /** * This function calculates the percentage difference between one number and another * * @param {number} num1 previous value * @param {number} num2 current value * @param {true|null} absVal if the return will be an absolute value or not * * @returns {number|boolean} if the num2 is 0, return false */ export const percentDiff = (num1, num2, absVal = null) => { if(num2 == 0) return false let diff = num2 - num1 let percent = (diff / num2) * 100 let roundedPercent = parseFloat(percent.toFixed(2)) // @ts-ignore let result = roundedPercent % 1 === 0 ? parseInt(roundedPercent) : roundedPercent if(absVal) return Math.abs(result) return result } /** * This function divides a number into parts and adjusts the parts * * @param {Number} number * @param {Number} divider * @returns */ export const divideAndAdjust = (number, divider) => { const base = Math.floor(number / divider) const rest = number % divider const parts = [] for (let i = 0; i < divider; i++){ parts.push(base) } for (let i = 0; i < rest; i++) { parts[i] += 1 } return parts } /** DOM */ /** * This function get the selected option text from a select element * * @param {Object|string} select element or id element * * @returns {string} text of selected option */ export const getTextOfSelect = (select) => { if(!['string', 'object'].includes(typeof select)) throw new Error('The type of the "select" argument must be string or object'); if(typeof select == 'string' && document.querySelector(`#${select}`) == undefined) throw new Error(`The element with id "${select}" is undefined`); if(typeof select == 'object' && select.nodeName != 'SELECT') throw new Error('The element type of the "select" argument must be a select'); // @ts-ignore if(typeof select == 'string') select = document.querySelector(`#${select}`); // @ts-ignore return select.options[select.selectedIndex].text; } /** * This function get the value of an attribute of the selected option of select element * * @param {Object|string} select element or id element * @param {string} attribute attribute name to retrieve * * @returns {string} attribute value of selected option */ export const getDataOfSelect = (select, attribute) => { if(!['string', 'object'].includes(typeof select)) throw new Error('The type of the "select" argument must be string or object'); if(typeof select == 'string' && document.querySelector(`#${select}`) == undefined) throw new Error(`The element with id "${select}" is undefined`); if(typeof select == 'object' && select.nodeName != 'SELECT') throw new Error('The element type of the "select" argument must be a select'); if(typeof attribute != 'string') throw new Error('The argument "attribute" must be a string'); // @ts-ignore if(typeof select == 'string') select = document.querySelector(`#${select}`); // @ts-ignore return select.options[select.selectedIndex].getAttribute(attribute); } /** * This function get all attributes values of the selected options of a select element * * @param {Object|string} select element or id element * * @returns {array} array with attributes of selected options */ export const getAllDataOfSelect = (select) => { if(!['string', 'object'].includes(typeof select)) throw new Error('The type of the "select" argument must be string or object'); if(typeof select == 'string' && document.querySelector(`#${select}`) == undefined) throw new Error(`The element with id "${select}" is undefined`); if(typeof select == 'object' && select.nodeName != 'SELECT') throw new Error('The element type of the "select" argument must be a select'); // @ts-ignore if(typeof select == 'string') select = document.querySelector(`#${select}`); let array = {}; // @ts-ignore for (const option of select.options) { if (option.selected == true) { array[option.text] = {}; for (const attr of option.attributes) { array[option.text][attr.name] = attr.value; } } } // @ts-ignore return array; } /** * This function get selected options values of a select multiple * * @param {Object|string} select element or id element * * @returns {array} array with selected options values */ export const getValuesSelectMultiple = (select) => { if(!['string', 'object'].includes(typeof select)) throw new Error('The type of the "select" argument must be string or object'); if(typeof select == 'string' && document.querySelector(`#${select}`) == undefined) throw new Error(`The element with id "${select}" is undefined`); if(typeof select == 'object' && select.nodeName != 'SELECT') throw new Error('The element type of the "select" argument must be a select'); if(typeof select == 'string') select = document.querySelector(`#${select}`); let values = []; let options = select.selectedOptions; for (const option of options) { values.push(option.value); } return values; } /** * This function change the value of a select element * * @param {Object|string} select element or id element * @param {string | number} value value to assign in the select */ export const setValueOfSelect = (select, value) => { if(!['string', 'object'].includes(typeof select)) throw new Error('The type of the "select" argument must be string or object'); if(typeof select == 'string' && document.querySelector(`#${select}`) == undefined) throw new Error(`The element with id "${select}" is undefined`); if(typeof select == 'object' && select.nodeName != 'SELECT') throw new Error('The element type of the "select" argument must be a select'); if(!['string', 'number'].includes(typeof value)) throw new Error('The type of the "value" argument must be string or number'); if(typeof select == 'string') select = document.querySelector(`#${select}`); const eventChange = new Event("change"); select.value = value; select.dispatchEvent(eventChange); } /** * This function assign values to a select multiple * * @param {Object|string} select element or id element * @param {Object|array} data object with attributes or array with values * @param {string|null} attribute attribute name of object in array to assign values to the select multiple */ export const setValuesSelectMultiple = (select, data, attribute = null) => { if(!['string', 'object'].includes(typeof select)) throw new Error('The type of the "select" argument must be string or object'); if(typeof select == 'string' && document.querySelector(`#${select}`) == undefined) throw new Error(`The element with id "${select}" is undefined`); if(typeof select == 'object' && select.nodeName != 'SELECT') throw new Error('The element type of the "select" argument must be a select'); if(!['object'].includes(typeof data)) throw new Error('The type of the "data" argument must be an object'); if(attribute != null && typeof attribute != 'string') throw new Error('The type of the "attribute" argument must be an object'); if(typeof select == 'string') select = document.querySelector(`#${select}`); function getTypeOf(obj) { for (const o of obj) { if (typeof o == 'object') { return 'object'; } } return 'array'; } const event = new Event("change"); let values = []; switch (getTypeOf(data)) { case 'object': for(const object of data){ // @ts-ignore values.push(object[attribute]); } break; case 'array': values = data; break; } values = values.map(i => String(i)); for (const option of select.options) { if (values.includes(option.value)) { option.selected = true; }else{ option.selected = false; } } select.dispatchEvent(event); } /** * This function add a row to an HTML table in a designed position * * @param {Object|string} table element or id element * @param {string} row HTML of the row to be added * @param {'first'|'last'|number} position 'first' | 'last' | number -> position of the row in the table * @param {Object|null} object object of values to add to the new row */ export const addRowToTable = (table, row, position, object = null) => { if(!['string', 'object'].includes(typeof table)) throw new Error('The type of the "table" argument must be string or object'); if(typeof table == 'string' && document.querySelector(`#${table}`) == undefined) throw new Error(`The element with id "${table}" is undefined`); if(typeof row != 'string') throw new Error('The type of the "row" argument must be a string'); if(!['string','number'].includes(typeof position)) throw new Error('The type of the "position" argument must be a string or a number'); if(typeof position == 'string' && !['first','last'].includes(position)) throw new Error('The strings of the "position" argument must be "first" or "last"'); if(object != null && !['object'].includes(typeof object)) throw new Error('The type of the "object" argument must be an object'); if(typeof table == 'object') table = table.id; let tableRef = document.querySelector(`#${table} tbody`); let newRow; switch (position) { case 'first': // @ts-ignore newRow = tableRef.insertRow(0); break; case 'last': // @ts-ignore newRow = tableRef.insertRow(tableRef.rows.length) break; default: // @ts-ignore newRow = tableRef.insertRow(position); break; } if(object != null){ for(const [key, value] of Object.entries(object)){ newRow[key] = value; } } newRow.innerHTML = row; } /** * This function delete a row from an HTML table * * @param {HTMLTableRowElement|string} row tr element from a table */ export const deleteRowOfTable = (row) => { if(!['string', 'object'].includes(typeof row)) throw new Error('The type of the "row" argument must be string or object'); // @ts-ignore if(typeof row == 'string') row = document.querySelector(`#${row}`); // @ts-ignore row.parentNode.removeChild(row); } /** * This function get a URL parameter * * @param {string} parameter name of the URL parameter * * @returns {string} URL parameter value */ export const getParamUrl = (parameter) => { if(typeof parameter != 'string') throw new Error('The type of the "parameter" argument must be a string'); let url = new URL(window.location.href); let param = url.searchParams.get(parameter); // @ts-ignore return param; } /** * This function adds parameters to the url (this reloads the page to take effect) * * @param {string} parameter name of parameter * @param {string} value value of parameter */ export const setParamUrl = (parameter, value) => { if(typeof parameter != 'string') throw new Error('The type of the "parameter" argument must be a string'); if(typeof value != 'string') throw new Error('The type of the "value" argument must be a string'); let url = new URL(window.location.href); let params = new URLSearchParams(url.search); params.set(parameter, value); // @ts-ignore document.location.search = params; } /** * This function removes a parameter from the url (if 'parameters' is empty, all parameters are removed) * * @param {array} parameters name of parameter */ export const deleteParamUrl = (parameters= []) => { // Obtener la URL actual const url = new URL(window.location.href); if (parameters.length === 0) { // Si no se especifican parámetros, eliminar todos url.search = ''; } else { // Eliminar solo los parámetros especificados parameters.forEach(param => url.searchParams.delete(param)); } // Actualizar la URL en la barra de direcciones sin recargar la página window.history.replaceState({}, '', url); } /** * This function gets the current hash of the url * * @returns hash of url */ export const getHashUrl = () => { return window.location.hash; } /** * This function add a hash in the url * @param {string} hash */ export const setHashUrl = (hash) => { if(typeof hash != 'string') throw new Error('The type of the "hash" argument must be a string'); window.location.hash = `#${hash}`; } /** * This function removes the hash in the url */ export const deleteHashUrl = () => { history.pushState("", "", `${location.pathname}${location.search}`); } /** * This function filters the page using parameters in the url * * @param {string} elClass filter element class * @param {string} page url name of actual page * @param {number|null} numPage number of page to filter */ export const filterPage = (elClass, page, numPage = null) => { const filters = document.querySelectorAll(elClass); let url = `${page}?`; filters.forEach((element, index) => { if(index == 0){ // @ts-ignore url += `${element.id}=${element.value}`; } if(index != 0){ if(element.id == 'page' && numPage != null){ url += `&${element.id}=${numPage}`; }else{ // @ts-ignore url += `&${element.id}=${element.value}`; } } }); url += `${getHashUrl()}`; window.location.href = url; } /** * This function filters the page by pressing enter in filter inputs * * @param {string} elClass filter element class * @param {string} page url name of actual page */ export const listenerInputsFilter = (elClass, page) => { const filtros = document.querySelectorAll(elClass); Array.from(filtros).forEach(function(element) { element.addEventListener('keyup', function(e){ e.preventDefault(); // @ts-ignore if(e.keyCode == 13) { filterPage(elClass, page, 1); } }); }); } /** * This function filters the page by clicking on the page number (links) * * @param {string} classLink class of the link element * @param {string} classFilter filter input class * @param {string} url url name of actual page * @param {string} idPageInput input page id */ export const listenerNumberPage = (classLink, classFilter, url, idPageInput) => { const links = document.querySelectorAll(classLink); const page = document.querySelector(idPageInput); Array.from(links).forEach(function(element) { element.addEventListener('click', function(e){ e.preventDefault(); if(this.text != undefined){ let rel = this.getAttribute('rel'); if (rel != null) { if (rel == 'next') { // @ts-ignore page.value = parseInt(page.value) + 1 }else if(rel == 'prev') { // @ts-ignore page.value = parseInt(page.value) - 1 } }else{ // @ts-ignore page.value = parseInt(this.text); } } // @ts-ignore filterPage(classFilter, url, page.value); }); }); } // Animations /** * This function simulates that the user is pressing a key and writes the character in the input * * @param {string} elementId id of input element * @param {string|number} value value to write to input */ export const simulateKeyPress = (elementId, value) => { let inputElement = document.querySelector(`#${elementId}`); let event = new Event('keypress'); let text = value.toString(); let index = 0; setInterval(addCharacter, 100); function addCharacter() { if (index < text.length) { var currentChar = text.charAt(index); // @ts-ignore inputElement.value += currentChar; // @ts-ignore inputElement.dispatchEvent(event); index++; } else { // @ts-ignore clearInterval(); } } } /** * This function displays a transition between a range of numbers in a DOM element * * @param {Object} element DOM element * @param {number} start number to start the count * @param {number} end number to end the count * @param {string} textBefore text to show before the number * @param {string} textAfter text to show after the number */ export const animateValue = (element, start, end, textBefore = '', textAfter = '') => { let current = start; let step = end / 70; let increment = step; let timer = setInterval(function() { current += increment; element.innerHTML = `${textBefore}${Math.floor(current).toLocaleString('de-DE')}`; if (current >= end) { // @ts-ignore clearInterval(timer); element.innerHTML = `${textBefore}${end.toLocaleString('de-DE')}${textAfter}`; } }, 10); } /** ATTENTION! this function just work with transition.css * This function make a transition for show or hide a element * * @param {Object|Array} element div, span, select, etc. * @param {'show'|'hide'} action */ export const elementTransition = (element, action) => { switch (action) { case 'show': if(typeof element == 'object' && typeof element[Symbol.iterator] === 'function'){ for (const el of element) { el.removeAttribute('hidden'); } setTimeout(() => { for (const el of element) { el.classList.remove('div-hide'); el.classList.add('div-show'); } }, 200); }else{ element.removeAttribute('hidden'); setTimeout(() => { element.classList.remove('div-hide'); element.classList.add('div-show'); }, 200); } break; case 'hide': if(typeof element == 'object' && typeof element[Symbol.iterator] === 'function'){ for (const el of element) { el.classList.remove('div-show'); el.classList.add('div-hide'); } setTimeout(() => { for (const el of element) { el.setAttribute('hidden', 'hidden'); } }, 400); }else{ element.classList.remove('div-show'); element.classList.add('div-hide'); setTimeout(() => { element.setAttribute('hidden', 'hidden'); }, 400); } break; } } /** * This function disable a button or "a" element and displays a custom text next to a spinner based on button text * * @param {Object|string} btn element | id of element * @param {'start' | 'stop'} action action of element * @param {object} [opts] element style options * @param {string|null} [opts.text] [text = ''] - button text * @param {number|null} [opts.width=0.8] [width = 0.8] - spinner width * @param {number|null} [opts.height=0.8] [height = 0.8] - spinner height * @param {string|null} [opts.spinnerClass='spinner-loading'] [spinnerClass = 'spinner-loading'] - class in span of spinner */ export const loadingButton = (btn, action, opts) => { let text = '', spinnerClass = 'spinner-loading'; let width = 0.8, height = 0.8; if(!['string', 'object'].includes(typeof btn)) throw new Error('The type of the "btn" argument must be string or object'); if(!['start', 'stop'].includes(action)) throw new Error('The strings of the "action" argument must be "start" or "stop"'); if(typeof btn == 'string' && document.querySelector(`#${btn}`) == undefined) throw new Error(`The element with id "${btn}" is undefined`); if(opts){ if(opts.text && typeof opts.text != 'string') throw new Error('The type of the "text" property of the opts argument must be string'); if(opts.spinnerClass && typeof opts.spinnerClass != 'string') throw new Error('The type of the "spinnerClass" property of the opts argument must be string'); if(opts.width && typeof opts.width != 'number') throw new Error('The type of the "width" property of the opts argument must be number'); if(opts.height && typeof opts.height != 'number') throw new Error('The type of the "height" property of the opts argument must be number'); text = opts.text ?? text; width = opts.width ?? width; height = opts.height ?? height; spinnerClass = opts.spinnerClass ?? spinnerClass; } // @ts-ignore if(typeof btn == 'string') btn = document.querySelector(`#${btn}`); switch (action) { case 'start': // @ts-ignore btn.setAttribute('data-btn-text', btn.innerHTML); let span = document.createElement('span'); span.classList.add(`${spinnerClass}`); span.style.width = `${width}rem`; span.style.height = `${height}rem`; // @ts-ignore btn.innerHTML = `${span.outerHTML} ${text}`; // @ts-ignore btn.nodeName == 'A' ? btn.classList.add("disabled") : btn.disabled = true; break; case 'stop': // @ts-ignore btn.innerHTML = btn.getAttribute('data-btn-text'); // @ts-ignore btn.nodeName == 'A' ? btn.classList.remove("disabled") : btn.disabled = false; break; } } // Events /** * This function formats the RUT to the text of an input in format 11111111-1 * It is recommended to use the function on input with onkeyup * * @param {Object} input */ export const formatRut = (input) =>{ if(typeof input != 'object') throw new Error('The type of the "input" argument must be an object'); let text = input.value.replace('.', ''); text = text.replace('-', ''); if(text.length > 2){ let body = text.slice(0, -1); let dv = text.slice(-1).toUpperCase(); input.value = `${body}-${dv}`; } } /** * This function controls the maximum number of characters in an input, useful with type="number" inputs * It is recommended to use the function on input with onkeypress * * @param {Object} input */ export const maxLengthCheck = (input) =>{ if(typeof input != 'object') throw new Error('The type of the "input" argument must be an object'); let value = input.value.toString(); if(value.length < input.maxLength){ return true; }else{ return false; } } /** * This function validates the keys pressed * It is recommended to use the function on input with onkeypress * * @param {Event} event * @param {Array<"letters"|"capitalLetters"|"accentMarkLetters"|"accentMarkCapitalLetters"| * "numbers"|"space"|"plus"|"minus"|"k"|"capitalK"|"dot"|"comma"|"specials">} validation type of validation */ export const checkKeys = (event, validation) => { if(typeof event != 'object') throw new Error('The type of the "event" argument must be an object'); if(typeof validation != 'object') throw new Error('The type of the "validation" argument must be an object'); // @ts-ignore let key = event.key; let keys = []; let array = []; const keyValidate = { letters: ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "ñ", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"], capitalLetters: ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "Ñ", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"], accentMarkLetters: ["á", "é", "í", "ó", "ú"], accentMarkCapitalLetters: ["Á", "É", "Í", "Ó", "Ú"], numbers: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"], space: [" "], plus: ["+"], minus: ["-"], k: ["k"], capitalK: ["K"], dot: ["."], comma: [","], specials: ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")", "-", "_", "+", "=", "[", "]", "{", "}", ";", ":", "'", "\"", ",", ".", "<", ">", "/", "?", "|", "\\"] } for (const val of validation) { let keyValidateAttr = keyValidate[val]; if(array.length == 0){ array = keyValidateAttr; }else{ array = array.concat(keyValidateAttr); } } keys = array; if(!keys.includes(key)){ event.preventDefault(); } } /** * This function filters by text an html table * * @param {Object|string} input element | id of element * @param {Object|string} table element | id of element */ export const filterTable = (input, table) => { if(!['string', 'object'].includes(typeof table)) throw new Error('The type of the "table" argument must be string or object'); if(!['string', 'object'].includes(typeof input)) throw new Error('The type of the "input" argument must be string or object'); if(typeof table == 'string' && document.querySelector(`#${table}`) == undefined) throw new Error(`The element with id "${table}" is undefined`); if(typeof input == 'string' && document.querySelector(`#${input}`) == undefined) throw new Error(`The element with id "${input}" is undefined`); // @ts-ignore if(typeof table == 'string') table = document.querySelector(`#${table}`); // @ts-ignore if(typeof input == 'string') input = document.querySelector(`#${input}`); // @ts-ignore let rows = table.getElementsByTagName("TR"); // @ts-ignore let filter = input.value.toUpperCase(); let coincidence = false; let count = 0; for (let row of rows) { if(count > 0){ let celdas = row.getElementsByTagName("TD"); for (let celda of celdas) { if (celda.textContent.toUpperCase().indexOf(filter) > -1) { coincidence = true; break; } } if (coincidence) { row.style.display = ""; } else { row.style.display = "none"; } coincidence = false; } count++; } } /** * This function does the same as the "sticky" css property, but you can define which will be the "tops" of both the top and bottom element, * together with the space between each one and the focus in the scroll of an element or window. * * @param {Object} opts Function configuration object * @param {string} opts.elementToMove id of element to move. * @param {'window'|string} opts.scrollFocusElement id or name of scroll focus element ('window' or 'elementID'). * @param {string|null} opts.topElement id of upper stop element (null is the top of the window). * @param {string|null} opts.bottomElement id of bottom stop element (with null there is no bottom stop). * @param {number} opts.topSeparation spacing size with top element in px. * @param {number} opts.bottomSeparation spacing size with bottom element in px. */ export const scrollTransition = (opts) => { if(typeof opts != 'object') throw new Error('The type of the "opts" argument must be an object'); if(typeof opts.elementToMove != 'string') throw new Error('The type of the "elementToMove" property of the opts argument must be string'); if(typeof opts.scrollFocusElement != 'string') throw new Error('The type of the "scrollFocusElement" property of the opts argument must be string'); if(opts.scrollFocusElement != 'window' && document.querySelector(`#${opts.scrollFocusElement}`) == undefined) throw new Error(`The element with id "${opts.scrollFocusElement}" is undefined`); if(typeof opts.topSeparation != 'number') throw new Error('The type of the "topSeparation" property of the opts argument must be number'); if(typeof opts.bottomSeparation != 'number') throw new Error('The type of the "bottomSeparation" property of the opts argument must be number'); if(opts.topElement){ if(typeof opts.topElement != 'string') throw new Error('The type of the "topElement" property of the opts argument must be string'); } if(opts.bottomElement){ if(typeof opts.bottomElement != 'string') throw new Error('The type of the "bottomElement" property of the opts argument must be string'); } var scrollY = window.scrollY; var diffWidth = 0; var addHeight = 0; var addBottom = 0; var topElementId = null; var bottomElementId = null; var elementId = opts.elementToMove; topElementId = opts.topElement ?? null; bottomElementId = opts.bottomElement ?? null; if(opts.scrollFocusElement == 'window'){ addHeight = opts.topSeparation ?? 7; // @ts-ignore addBottom = opts.bottomSeparation * -1 ?? -55; window.addEventListener('scroll', () => { setPositions(); }); }else{ let elementListener = document.querySelector(`#${opts.scrollFocusElement}`); addHeight = opts.topSeparation ?? 35; addBottom = opts.bottomSeparation ?? 20; // @ts-ignore elementListener.addEventListener('scroll', function() { diffWidth = 0.15; setPositions(); }); } function setPositions(){ const element = document.querySelector(`#${elementId}`); // @ts-ignore const parentElement = element.parentNode; // @ts-ignore const elementRect = parentElement.getBoundingClientRect(); // @ts-ignore const elementTop = parentElement.getBoundingClientRect().top + scrollY; // @ts-ignore const elementStyle = getComputedStyle(parentElement); const widthScreen = window.innerWidth; /** Top element limit */ let topElement; let topElementStyle; let heightTopElement; let topElementRect; /** Bottom element limit */ let bottomElement; let bottomElementStyle; let bottomElementRect; let bottomBottomElement; if(topElementId){ topElement = document.querySelector(`#${topElementId}`); // @ts-ignore topElementStyle = getComputedStyle(topElement); heightTopElement = parseFloat(topElementStyle.getPropertyValue("height")) + addHeight; // @ts-ignore topElementRect = topElement.getBoundingClientRect(); } if(bottomElementId){ bottomElement = document.querySelector(`#${bottomElementId}`); // @ts-ignore bottomElementStyle = getComputedStyle(bottomElement); bottomBottomElement = parseFloat(bottomElementStyle.getPropertyValue("bottom")); // @ts-ignore bottomElementRect = bottomElement.getBoundingClientRect(); } let widthWithPadding = elementStyle.getPropertyValue("width"); let paddingLeft = parseFloat(elementStyle.getPropertyValue("padding-left")); let paddingRight = parseFloat(elementStyle.getPropertyValue("padding-right")); let realWidth = parseFloat(widthWithPadding) - (paddingLeft + paddingRight); let totalWidth = ((realWidth * 100) / widthScreen) + 0.15 - diffWidth; if(topElementId){ if(bottomElementId){ // @ts-ignore if (topElementRect.bottom <= elementRect.top) { cleanElement(); // @ts-ignore } else if(topElementRect.bottom >= elementRect.top){ // @ts-ignore if(bottomElementRect.height - addBottom >= elementRect.bottom || (bottomElementRect.height - addBottom - elementRect.bottom) >= ((element.offsetHeight * -1) + 32)){ setPropElement('sticky', `${bottomBottomElement}px`, ''); }else{ setPropElement('fixed', `${heightTopElement}px`, `${totalWidth}%`); } } }else{ // @ts-ignore if (topElementRect.bottom <= elementRect.top) { cleanElement(); // @ts-ignore } else if(topElementRect.bottom >= elementRect.top){ setPropElement('fixed', `${heightTopElement}px`, `${totalWidth}%`); } } }else if(bottomElementId){ if (scrollY <= elementTop) { cleanElement(); } else if(scrollY >= elementRect.top){ if(scrollY >= elementRect.bottom){ setPropElement('sticky', '5px', ''); }else{ setPropElement('fixed', '5px', `${totalWidth}%`); } } }else{ // @ts-ignore if (scrollY >= elementTop && scrollY <= elementTop + parentElement.offsetHeight) { setPropElement('fixed', '5px', `${totalWidth}%`); } else { cleanElement(); } } function cleanElement(){ // @ts-ignore element.style.position = 'sticky'; // @ts-ignore element.style.top = ''; // @ts-ignore element.style.width = ''; } function setPropElement(pos, top, width){ // @ts-ignore element.style.position = pos; // @ts-ignore element.style.top = top; // @ts-ignore element.style.width = width; } } }