// Utilities const characters ='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; function randomString(length) { let result = ''; const charactersLength = characters.length; for ( let i = 0; i < length; i++ ) { result += characters.charAt(Math.floor(Math.random() * charactersLength)); } return result; } // serializeObject tweak to allow '.' to nest keys, and '-' in keys /* $.extend(FormSerializer.patterns, { fixed: /^\d+$/, validate: /^[a-z][a-z0-9_-]*(?:\.[a-z0-9_-]+|\[[0-9]+\])*(?:\[\])?$/i, key: /[a-z0-9_-]+|(?=\[\])/gi, named: /^[a-z0-9_-]+$/i }); */ // deserializeObject /* jQuery.fn.populate = function (data) { if (!this.is('form')) throw "Error: ${this} is not a form"; populate(this[0], data); return this; }; */ // crypto async function digestMessage(message) { const msgUint8 = new TextEncoder().encode(message); // encode as (utf-8) Uint8Array const hashBuffer = await crypto.subtle.digest('SHA-256', msgUint8); // hash the message const hashArray = Array.from(new Uint8Array(hashBuffer)); // convert buffer to byte array const hashHex = hashArray.map((b) => b.toString(16).padStart(2, '0')).join(''); // convert bytes to hex string return hashHex; } // number formats function setDecimals() { // due to a W3C decision, "number" inputs do not expose their selection, breaking inputmask library $('input[data-decimals="0"]').inputmask({ alias: 'integer', placeholder: '0', groupSeparator: ' ' }); $('input[data-decimals="1"]').inputmask({ alias: 'numeric', placeholder: '0', groupSeparator: ' ', digits: 1 }); $('input[data-decimals="2"]').inputmask({ alias: 'numeric', placeholder: '0', groupSeparator: ' ', digits: 2 }); $('input[data-decimals="3"]').inputmask({ alias: 'numeric', placeholder: '0', groupSeparator: ' ', digits: 3 }); $('input[data-decimals="4"]').inputmask({ alias: 'numeric', placeholder: '0', groupSeparator: ' ', digits: 4 }); $('input.number:not([data-decimals]):not([data-digits])').inputmask({ alias: 'numeric', placeholder: '', groupSeparator: ' '}); $('input[data-digits="2"]').inputmask({ alias: 'currency', placeholder: '0', groupSeparator: ' ', digits: 2, digitsOptional: false }); $('input[data-digits="4"]').inputmask({ alias: 'currency', placeholder: '0', groupSeparator: ' ', digits: 4, digitsOptional: false }); } /* $(() => { setDecimals(); }); */ function populateSelect(select, list, empty = false) { select.empty(); if (empty) select.append(''); list.forEach(option => select.append(``)); } function spinner(show) { if (show) $('#backdrop').addClass('active'); else $('#backdrop').removeClass('active'); } function exportCSV(filename, content) { let body = content.map(s => [].concat(s).join(';')).join('\n'); let blob = new Blob(['\uFEFF', body], {type: 'text/csv;charset=utf-8'}); let link = document.createElement("a"); let url = URL.createObjectURL(blob); link.setAttribute("href", url); link.setAttribute("download", filename); //link.setAttribute("target", "_blank") link.style.visibility = 'hidden'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } /* modals */ NodeList.prototype.modal = function(show) { this.item(0).modal(show); return this; } Element.prototype.modal = function(show) { if (show) { document.body.addClass('dimmed'); this.addClass('active'); } else { this.removeClass('active'); document.body.removeClass('dimmed'); } return this; } /* DOM helpers */ function formValue(name) { let ctl = $(`[name="${name}"]`)[0]; let type = ctl.tagName; if ( (type === 'INPUT' && ['text', 'number'].includes(ctl.attr('type'))) || type === 'SELECT' ) { return ctl.value; } else if (type === 'INPUT' && ctl.attr('type') === 'radio') { ctl = $(`input[name="${name}"]:checked`)[0]; if (ctl) return ctl.value; } else if (type === 'INPUT' && ctl.attr('type') === 'radio') { return ctl.checked; } console.error(`unknown input name: ${name}`); return null; } function msg(id) { let ctl = $(`#${id}`)[0]; return ctl.textContent; } function spinner(show) { if (show) $('#backdrop').addClass('active'); else $('#backdrop').removeClass('active'); } onLoad(() => { /* document.on('click', e => { if (!e.target.closest('.modal')) $('.modal').hide(); }) */ $('i.close.icon').on('click', e => { let modal = e.target.closest('.modal'); if (modal) modal.modal(false); }); $('.modal .actions .cancel').on('click', e => { e.target.closest('.modal').modal(false); }); $('#dimmer').on('click', e => $('.modal').modal(false)); });