UNPKG

ark-js-util

Version:

simple library with basic funcs for my convenience

450 lines (428 loc) 19.7 kB
/** * ark-js-util * https://github.com/immi5556/immanuel.npm/tree/master/Immanuel.a7.npm/Immanuel.ark/ark-util * * @version 1.1.2 * @date 2021-05-10 * * @version 1.1.3 * @date 2023-10-18 * * @version 1.1.9 * @date 2023-11-11 * * @version 1.2.0 * @date 2023-12-16 * From this release, only ark_util is supported and util is deprecated, because of conflicts * * @version 1.2.2 * @date 2024-01-15 * jquery equivalent methods included on etc, also group exposed functions * * @version 1.2.3 * @date 2024-01-15 * fixing loadScript with right approach * * @version 1.2.4 * @date 2025-03-22 * implementing debounce * * @version 1.2.5 * @date 2025-06-03 * new timeformat '00:00' * * @version 1.2.6 * @date 2025-06-06 * dom class name fix * * @copyright (c) 2015-2025 Immanuel R, https://www.immanuel.co * */ var ark_util = (function () { var appendhtml = (parent, selector, content, append) => { var ele = parent.querySelector(selector); if (!ele) return; if (append) ele.innerHTML = ele.innerHTML + '<br>' + content; else ele.innerHTML = content; } textToDom = (txt) => { var div = document.createElement('template'); div.innerHTML = (txt || '').trim(); return div.content.firstChild; } function toDomClassName(input) { if (typeof input !== 'string' || input.length === 0) return ''; // Convert to lowercase let className = input.toLowerCase(); // Replace spaces and underscores with hyphens className = className.replace(/[\s_]+/g, '-'); // Remove any remaining invalid characters className = className.replace(/[^a-z0-9-]/g, ''); // Ensure it starts with a letter or underscore if (!/^[a-z_]/.test(className)) { className = 'c-' + className; } // Remove consecutive hyphens className = className.replace(/-+/g, '-'); // Remove leading/trailing hyphens className = className.replace(/^-+|-+$/g, ''); return className; } // Example usage: //console.log(toDomClass("User Profile")); // "user-profile" //console.log(toDomClass("Active Item!!")); // "active-item" //console.log(toDomClass("123Main")); // "c-123main" //console.log(toDomClass("__special__")); // "__special__" //console.log(toDomClass("multiple spaces")); // "multiple-spaces" //console.log(toDomClass("CamelCaseString")); // "camelcasestring" extend = (...arg) => { var extended = {}; var deep = false; var i = 0; var args = arg; var length = args.length; if (Object.prototype.toString.call(args[0]) === '[object Boolean]') { deep = args[0]; i++; } var merge = function (obj) { for (var prop in obj) { if (Object.prototype.hasOwnProperty.call(obj, prop)) { if (deep && Object.prototype.toString.call(obj[prop]) === '[object Object]') { extended[prop] = extend(true, extended[prop], obj[prop]); } else { extended[prop] = obj[prop]; } } } }; for (; i < length; i++) { var obj = args[i]; merge(obj); } return extended; } //support dynamic dom event binding as in $.on, parent: is already available in dom loaded var onEvent = (selector, event_type, parent, handler) => { parent.addEventListener(event_type, (evt) => { if (evt.target.closest(selector)) { handler(evt); } }); }; //on('#test', 'click', document, (event) => console.log('click')); deepClone = (obj, hash = new WeakMap()) => { if (Object(obj) !== obj) return obj; // primitives if (hash.has(obj)) return hash.get(obj); // cyclic reference const result = obj instanceof Set ? new Set(obj) // See note about this! : obj instanceof Map ? new Map(Array.from(obj, ([key, val]) => [key, deepClone(val, hash)])) : obj instanceof Date ? new Date(obj) : obj instanceof RegExp ? new RegExp(obj.source, obj.flags) // ... add here any specific treatment for other classes ... // and finally a catch-all: : obj.constructor ? new obj.constructor() : Object.create(null); hash.set(obj, result); return Object.assign(result, ...Object.keys(obj).map( key => ({ [key]: deepClone(obj[key], hash) }))); } function formatBytes(bytes, decimals = 2) { if (bytes === 0) return '0 Bytes'; const k = 1024; const dm = decimals < 0 ? 0 : decimals; const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; } //output: 2025-08-04 (compatible for data control) function formatToYYYYMMDD(date) { const year = date.getFullYear(); // Month is 0-indexed, so add 1 and pad with '0' if single digit const month = String(date.getMonth() + 1).padStart(2, '0'); // Day of the month, pad with '0' if single digit const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } function toDate(input) { // format1: input = 20250807.124828.215.+05:30 const datePart = input.slice(0, 8); // "20250807" const timePart = input.slice(9, 15); // "124828" const millisPart = input.slice(16, 19); // "215" const tzOffset = input.slice(20); // "+05:30" const formatted = `${datePart.slice(0, 4)}-${datePart.slice(4, 6)}-${datePart.slice(6, 8)}T` + `${timePart.slice(0, 2)}:${timePart.slice(2, 4)}:${timePart.slice(4, 6)}.` + `${millisPart}${tzOffset}`; var jsDate = new Date(formatted); if (isDate(jsDate)) return jsDate; //TO DO: add diff formatters here return null; } function getTimeHHMM(date) { const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${hours}:${minutes}`; } function formatTime(second) { var sec_num = parseInt(second, 10); // don't forget the second param var hours = Math.floor(sec_num / 3600); var minutes = Math.floor((sec_num - (hours * 3600)) / 60); var seconds = sec_num - (hours * 3600) - (minutes * 60); if (hours < 10) { hours = "0" + hours; } if (minutes < 10) { minutes = "0" + minutes; } if (seconds < 10) { seconds = "0" + seconds; } return hours + ':' + minutes + ':' + seconds; } var formatTimeHHMMAMPM = (dte) => { return (dte || new Date()).toLocaleTimeString('en-US', { hour: 'numeric', hour12: true, minute: 'numeric' }); } var logger = (function () { let enabledebug = false; const getvalue = (msg) => typeof (msg || {}) == 'object' ? JSON.stringify(msg) : msg; const clearStyles = ''; const largeText = 'font-size: 20px;'; const yellowText = 'color: yellow;'; const largeRedText = 'font-size: 20px; color: red;'; const largeGreenText = 'font-size: 20px; color: green;'; const logwarn = (msg) => enabledebug && console.log(`%c [Warn] ${new Date()}] ${getvalue(msg)}`, yellowText + largeText); const logerror = (msg) => enabledebug && console.log(`%c [Errr- ${new Date()}] ${getvalue(msg)}`, largeRedText); const loginfo = (msg) => enabledebug && console.log(`%c [Info- ${new Date()}] ${getvalue(msg)}`, largeText); const logsuccess = (msg) => enabledebug && console.log(`%c [Succ- ${new Date()}] ${getvalue(msg)}`, largeGreenText); return { disabledebug: () => enabledebug = false, enabledebug: () => enabledebug = true, logerror: logerror, logwarn: logwarn, loginfo: loginfo, logsuccess: logsuccess } })(); function isDate(d) { return d instanceof Date && !isNaN(d); } function addDays(date, days) { var result = new Date(date); result.setDate(result.getDate() + days); return result; } var removeNode = function (elem) { elem.parentNode.removeChild(elem); } var addMinutes = (dt, mins) => { return new Date(dt.getTime() + mins * 60000); } var getMinutesDiff = (end, start) => { let mins = 0; mins = ((end.valueOf() - start.valueOf()) / (1000 * 60)); return mins; } function convertLocalDateToUTCIgnoringTimezone(date) { const timestamp = Date.UTC( date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds(), ); return new Date(timestamp); } function convertUTCToLocalDateIgnoringTimezone(utcDate) { return new Date( utcDate.getUTCFullYear(), utcDate.getUTCMonth(), utcDate.getUTCDate(), utcDate.getUTCHours(), utcDate.getUTCMinutes(), utcDate.getUTCSeconds(), utcDate.getUTCMilliseconds(), ); } var getUniqueTimestamp = function(){ var now = new Date(); var timestamp = now.getFullYear().toString(); timestamp += (now.getMonth() < 9 ? '0' : '') + now.getMonth().toString(); timestamp += ((now.getDate() < 10) ? '0' : '') + now.getDate().toString(); timestamp += ((now.getHours() < 10) ? '0' : '') + now.getHours().toString(); timestamp += ((now.getMinutes() < 10) ? '0' : '') + now.getMinutes().toString(); timestamp += ((now.getSeconds() < 10) ? '0' : '') + now.getSeconds().toString(); timestamp += ((now.getMilliseconds() < 10) ? '0' : '') + now.getMilliseconds().toString(); return timestamp; } var toLocalTime = (utc) => { var rz = convertLocalDateToUTCIgnoringTimezone(utc); return rz.toLocaleString(); } var loadScript = function (url, dom) { var scriptTag = document.createElement("script") scriptTag.src = url; (dom || document.body).append(scriptTag); } var randomDate = (start, end, startHour, endHour) => { var date = new Date(+start + Math.random() * (end - start)); var hour = startHour + Math.random() * (endHour - startHour) | 0; date.setHours(hour); return date; } var randomNumber = (begin, end) => { return Math.floor((Math.random() * end) + begin); } var randomAlphaNumber = len => Array(len || 8).fill(0).map(x => Math.random().toString(36).charAt(2)).join(''); var cookie = { get: (name) => { var v = document.cookie.match('(^|;) ?' + name + '=([^;]*)(;|$)'); return v ? decodeURIComponent(v[2]) : null; }, set: (name, value, days) => { var d = new Date; d.setTime(d.getTime() + 24 * 60 * 60 * 1000 * days); document.cookie = name + "=" + encodeURIComponent(value) + ";path=/;expires=" + d.toGMTString(); }, delete: (name) => { cookie.set(name, '', -1); } } const getRange = (end, start) => { start = start || 0; if (start > end) { console.warn(`range error, start > end, fixing it`); start = start + end - (end = start); } return Array.from({ length: end - start + 1 }, (_, i) => start + i); } var extractValue = (obj, path) => (path || '').split('.').reduce((p, c) => p && p[c] || null, obj); var downloadJson = (json, filename) => { var dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(json)); download(dataStr, (filename || 'download.json')); } var download = (dataurl, filename) => { var a = document.createElement("a"); a.href = dataurl; a.setAttribute("download", filename); a.click(); } var trim = (chr) => { //",,g,,,dfdsf,,,,".replace(/^,+|,+$/g, ''); Array.from((chr || '').toString()).reduce((accm, cv) => { }, ''); } function getQueryStringParams() { const queryParams = new URLSearchParams(window.location.search); const params = {}; for (const [key, value] of queryParams.entries()) { const lowercaseKey = key.toLowerCase(); params[lowercaseKey] = value; } return params; } const getWeekday = date => ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()]; const getMonth = date => ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][date.getMonth()]; const getDateWWWddMMM = date => `${getWeekday(date)}, ${date.getDate()} ${getMonth(date)}` const getDateWWWddMMMHHMMAMPM = (date, delimiter) => `${getWeekday(date)}, ${date.getDate()} ${getMonth(date)} ${(delimiter || '|')} ${formatTimeHHMMAMPM(date)}`; const sanitizeFilename = (fn) => { return (fn || '').replace(/[&\/\\#, +()$~%.'":*?<>{}@!^\[\]=`;]/g, '_'); //test case: "sd+==a :'?><sd@# !@#$%^&*(){}[]fs ~`*;df".replace(/[&\/\\#, +()$~%.'":*?<>{}@!^\[\]=`;]/g, '_') } const getTimeIn0000Format = (date) => { const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); return `${hours}:${minutes}`; } function isFunction(functionToCheck) { return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]'; } function isArray(arr) { return Object.prototype.toString.call(arr) === '[object Array]'; } var is_mobile = function () { let is_mob = false; (function (a) { if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true; })(navigator.userAgent || navigator.vendor || window.opera); return is_mob; }; //use: const wrap_func = debounce(functobcalled, 300); // wrap_func(arg1, arg2) function debounce(func, delay) { let timeoutId; return function (...args) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { func.apply(this, args); }, delay); }; } function ceilToNearest(num, interval = 1000) { if (interval <= 0) throw new Error("Interval must be a positive number"); if (interval % 2 !== 0) throw new Error("Interval must be an even number"); return Math.ceil(num / interval) * interval; } // Example usage: //console.log(ceilToNearest(1234)); // 2000 (default 1000) //console.log(ceilToNearest(1234, 500)); // 1500 //console.log(ceilToNearest(1234, 250)); // 1250 //console.log(ceilToNearest(1234, 100)); // 1300 //console.log(ceilToNearest(1234, 50)); // 1250 //console.log(ceilToNearest(1234, 1)); // 1234 (rounds to nearest 1) return { appendHtml: appendhtml, textToDom: textToDom, deepClone: deepClone, extend: extend, formatBytes: formatBytes, logger: logger, removeNode: removeNode, loadScript: loadScript, randomNumber: randomNumber, range: getRange, randomText: randomAlphaNumber, cookie: cookie, extractValue: extractValue, dom: { appendHtml: appendhtml, textToDom: textToDom, remove: removeNode, on: onEvent }, download: { json: downloadJson }, qs: getQueryStringParams, dater: { isDate: isDate, toDate: toDate, randomDate: randomDate, formatTimeHHMMAMPM: formatTimeHHMMAMPM, formatTime: formatTime, getTimeHHMM: getTimeHHMM, getMinutesDiff: getMinutesDiff, addMinutes: addMinutes, addDays: addDays, toLocalTime: toLocalTime, getUniqueTimestamp: getUniqueTimestamp, getWeekday: getWeekday, getMonth: getMonth, getDateWWWddMMM: getDateWWWddMMM, getDateWWWddMMMHHMMAMPM: getDateWWWddMMMHHMMAMPM, getTimeIn0000Format: getTimeIn0000Format, formatToYYYYMMDD: formatToYYYYMMDD }, sanitizeFilename: sanitizeFilename, isFunction: isFunction, isMobile: is_mobile, isArray: isArray, debounce: debounce, ceilToNearest: ceilToNearest } })(); //Array utils Array.prototype.sum = function (prop) { var total = 0 for (var i = 0, _len = this.length; i < _len; i++) { if (!isNaN(this[i][prop])) total += this[i][prop] } return total } Array.prototype.unique = function (prop) { return [...new Set(this.map(item => item[prop]))]; }