UNPKG

@igo2/utils

Version:
1,085 lines (1,064 loc) 37.7 kB
import { Observable, Subject } from 'rxjs'; import { distinctUntilChanged } from 'rxjs/operators'; /* eslint-disable */ const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; class Base64 { static PADCHAR = '='; static ALPHA = ALPHA; static getByte(s, i) { const x = s.charCodeAt(i); return x; } static getByte64(s, i) { const idx = this.ALPHA.indexOf(s.charAt(i)); return idx; } static decode(s) { let pads = 0, i, b10, imax = s.length, x = []; s = String(s); if (imax === 0) { return s; } if (s.charAt(imax - 1) === this.PADCHAR) { pads = 1; if (s.charAt(imax - 2) === this.PADCHAR) { pads = 2; } imax -= 4; } for (i = 0; i < imax; i += 4) { b10 = (this.getByte64(s, i) << 18) | (this.getByte64(s, i + 1) << 12) | (this.getByte64(s, i + 2) << 6) | this.getByte64(s, i + 3); x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255, b10 & 255)); } switch (pads) { case 1: b10 = (this.getByte64(s, i) << 18) | (this.getByte64(s, i + 1) << 12) | (this.getByte64(s, i + 2) << 6); x.push(String.fromCharCode(b10 >> 16, (b10 >> 8) & 255)); break; case 2: b10 = (this.getByte64(s, i) << 18) | (this.getByte64(s, i + 1) << 12); x.push(String.fromCharCode(b10 >> 16)); break; } return x.join(''); } static encode(s) { s = String(s); let i, b10, x = [], imax = s.length - (s.length % 3); if (s.length === 0) { return s; } for (i = 0; i < imax; i += 3) { b10 = (this.getByte(s, i) << 16) | (this.getByte(s, i + 1) << 8) | this.getByte(s, i + 2); x.push(this.ALPHA.charAt(b10 >> 18)); x.push(this.ALPHA.charAt((b10 >> 12) & 63)); x.push(this.ALPHA.charAt((b10 >> 6) & 63)); x.push(this.ALPHA.charAt(b10 & 63)); } switch (s.length - imax) { case 1: b10 = this.getByte(s, i) << 16; x.push(this.ALPHA.charAt(b10 >> 18) + this.ALPHA.charAt((b10 >> 12) & 63) + this.PADCHAR + this.PADCHAR); break; case 2: b10 = (this.getByte(s, i) << 16) | (this.getByte(s, i + 1) << 8); x.push(this.ALPHA.charAt(b10 >> 18) + this.ALPHA.charAt((b10 >> 12) & 63) + this.ALPHA.charAt((b10 >> 6) & 63) + this.PADCHAR); break; } return x.join(''); } } function customCacheHasher(parameters) { return parameters.map((param) => { if (typeof param === 'object' && param != null && typeof param.toString === 'function') { return param.toString(); } return param !== undefined ? JSON.parse(JSON.stringify(param)) : param; }); } function getNumber(v, endposition, length) { const mask = (1 << length) - 1; return (v >> endposition) & mask; } class Compression { base64Index = new Map(); indexBase64 = new Map(); constructor() { this.generateBase64Index(); } generateBase64Index() { // https://fr.wikipedia.org/wiki/Base64 // A-Z => [0, 25] for (let i = 0; i < 26; i++) { this.base64Index.set(String.fromCharCode('A'.charCodeAt(0) + i), i); this.indexBase64.set(i, String.fromCharCode('A'.charCodeAt(0) + i)); } // a-z => [26, 51] for (let i = 0; i < 26; i++) { this.base64Index.set(String.fromCharCode('a'.charCodeAt(0) + i), i + 26); this.indexBase64.set(i + 26, String.fromCharCode('a'.charCodeAt(0) + i)); } // 0-9 => [52, 61] for (let i = 0; i < 10; i++) { this.base64Index.set(String.fromCharCode('0'.charCodeAt(0) + i), i + 52); this.indexBase64.set(i + 52, String.fromCharCode('0'.charCodeAt(0) + i)); } // + / => [62, 63] this.base64Index.set('+', 62); this.base64Index.set('/', 63); this.indexBase64.set(62, '+'); this.indexBase64.set(63, '/'); } compressBlob(blob) { if (!blob) { return; } const observable = new Observable((observer) => { const reader = new FileReader(); reader.readAsDataURL(blob); reader.onload = () => { const base64 = reader.result.valueOf(); const text64 = base64.substr(base64.indexOf(',') + 1); const compressed = this.compressStringBase64(text64); const compressedData = { length: text64.length, type: blob.type, object: compressed }; observer.next(compressedData); }; }); return observable; } decompressBlob(compressedData) { const object = compressedData.object; const length = compressedData.length; const decompressed = this.decompressStringBase64(object, length); const byteCharacters = atob(decompressed); const byteNumbers = new Array(byteCharacters.length); for (let i = 0; i < byteCharacters.length; i++) { byteNumbers[i] = byteCharacters.charCodeAt(i); } const byteArray = new Uint8Array(byteNumbers); const blob = new Blob([byteArray], { type: compressedData.type }); return blob; } compressStringBase64(s) { let out = ''; let bits = 16; let chr = 0; let rem = 0; for (const c of s) { const value = this.base64Index.get(c); if (bits > 6) { bits -= 6; chr += value << bits; } else { rem = 6 - bits; chr += value >> rem; out += String.fromCharCode(chr); chr = value << (16 - rem); bits = 16 - rem; } } if (s.length % 8 !== 0) { out += String.fromCharCode(chr); } return String.fromCharCode(9731) + out; } decompressStringBase64(c, length) { if (!c) { return; } if (c.charCodeAt(0) !== 9731) { return c; } let chr = 0; let rem = 0; let bits = 16; let out = ''; let j = 1; let value = c.charCodeAt(j); for (let i = 0; i < length; i++) { if (bits > 6) { bits -= 6; chr = getNumber(value, bits, 6); out += this.indexBase64.get(chr); } else { rem = 6 - bits; chr = getNumber(value, 0, bits) << rem; value = c.charCodeAt(++j); chr += getNumber(value, 16 - rem, rem); out += this.indexBase64.get(chr); bits = 16 - rem; } } return out; } } var ChangeType; (function (ChangeType) { ChangeType["ADDED"] = "added"; ChangeType["DELETED"] = "deleted"; ChangeType["MODIFIED"] = "modified"; })(ChangeType || (ChangeType = {})); class StringUtils { static diff(s1, s2, p = 4) { if (!s1 && !s2) { return ''; } if (!s1) { return '<span class="inserted">' + s2 + '</span>'; } if (!s2) { return '<span class="deleted">' + s1 + '</span>'; } s1 = s1.toString(); s2 = s2.toString(); const changeData = StringUtils.getChanges(s1, s2, '', p); const nextS = s2.slice(changeData.mtc.length + changeData.ins.length + changeData.sbs.length); // remaining part of "s" const nextThis = s1.slice(changeData.mtc.length + changeData.del.length + changeData.sbs.length); // remaining part of "this" let result = ''; // the glorious result if (changeData.del.length > 0) { changeData.del = '<span class="deleted">' + changeData.del + '</span>'; } if (changeData.ins.length > 0) { changeData.ins = '<span class="inserted">' + changeData.ins + '</span>'; } result = changeData.mtc + changeData.del + changeData.ins + changeData.sbs; result += nextThis !== '' || nextS !== '' ? StringUtils.diff(nextThis, nextS, p) : ''; return result; } static getMatchingSubstring(s, l, m) { // returns the first matching substring in-between the two strings let i = 0; let match = false; const slen = s.length; const o = { fis: slen, mtc: m, sbs: '' }; // temporary object used to construct the cd (change data) object while (i < slen) { // eslint-disable-next-line @typescript-eslint/no-unused-expressions l[i] === s[i] ? match ? (o.sbs += s[i]) // o.sbs holds the matching substring itsef : ((match = true), (o.fis = i), (o.sbs = s[i])) : match ? (i = slen) // stop after the first found substring : // eslint-disable-next-line no-self-assign (i = i); ++i; } return o; } static getChanges(s1, s2, m, p) { const isThisLonger = s1.length >= s1.length ? true : false; let [longer, shorter] = isThisLonger ? [s1, s2] : [s2, s1]; // assignment of longer and shorter by es6 destructuring let bi = 0; // base index designating the index of first mismacthing character in both strings while (shorter[bi] === longer[bi] && bi < shorter.length) { ++bi; } // make bi the index of first mismatching character longer = longer.split('').slice(bi); // as the longer string will be rotated it is converted into array shorter = shorter.slice(bi); // shorter and longer now starts from the first mismatching character const len = longer.length; // length of the longer string let cd = { fis: shorter.length, // the index of matching string in the shorter string fil: len, // the index of matching string in the longer string sbs: '', // the matching substring itself mtc: m + s2.slice(0, bi) }; // if exists mtc holds the matching string at the front let sub = { sbs: '' }; // returned substring per 1 character rotation of the longer string if (shorter !== '') { for (let rc = 0; rc < len && sub.sbs.length < p; rc++) { // rc -> rotate count, p -> precision factor sub = StringUtils.getMatchingSubstring(shorter, StringUtils.rotateArray(longer, rc), cd.mtc); // rotate longer string 1 char and get substring sub.fil = rc < len - sub.fis ? sub.fis + rc // mismatch is longer than the mismatch in short : sub.fis - len + rc; // mismatch is shorter than the mismatch in short if (sub.sbs.length > cd.sbs.length) { cd = sub; // only keep the one with the longest substring. } } } // insert the mismatching delete subsrt and insert substr to the cd object and attach the previous substring [cd.del, cd.ins] = isThisLonger ? [longer.slice(0, cd.fil).join(''), shorter.slice(0, cd.fis)] : [shorter.slice(0, cd.fis), longer.slice(0, cd.fil).join('')]; return cd.del.indexOf(' ') === -1 || cd.ins.indexOf(' ') === -1 || cd.del === '' || cd.ins === '' || cd.sbs === '' ? cd : StringUtils.getChanges(cd.del, cd.ins, cd.mtc, p); } static rotateArray(array, n) { const len = array.length; const res = new Array(array.length); if (n % len === 0) { return array.slice(); } else { for (let i = 0; i < len; i++) { res[i] = array[(i + (len + (n % len))) % len]; } } return res; } static isValidNumber(value) { return !isNaN(Number(value)); } static isOctalNumber(value) { return (StringUtils.isValidNumber(value) && value.startsWith('0') && value.length > 1); } } class ChangeUtils { static findChanges(obj1, obj2, ignoreKeys = []) { const items = { added: [], deleted: [], modified: [] }; if (!obj1 || !obj2) { return items; } const obj1Clone = [...obj1]; const obj2Clone = [...obj2]; for (const fromItem of obj1Clone) { const index = obj2Clone.findIndex((s) => s.id === fromItem.id); if (index === -1) { items.deleted.push({ change: { type: ChangeType.DELETED }, value: fromItem }); continue; } const toItem = obj2Clone.splice(index, 1)[0]; const fromItemClone = JSON.parse(JSON.stringify(fromItem)); const toItemClone = JSON.parse(JSON.stringify(toItem)); const keysChanged = ChangeUtils.compareObject(fromItemClone, toItemClone, undefined, ignoreKeys); if (keysChanged.length) { items.modified.push({ change: { type: ChangeType.MODIFIED, keysChanged }, value: fromItemClone, oldValue: fromItem, newValue: toItem }); } } items.added = obj2Clone.map((itemAdded) => { return { change: { type: ChangeType.ADDED }, value: itemAdded }; }); return items; } static compareObject(fromItem, toItem, baseKey, ignoreKeys = []) { const fromItemClone = JSON.parse(JSON.stringify(fromItem)); const toItemClone = JSON.parse(JSON.stringify(toItem)); const keys = new Set([ ...Object.keys(fromItem), ...Object.keys(toItem) ]); let keysChanged = []; keys.forEach((key) => { const keyString = baseKey ? `${baseKey}.${key}` : key; if (ignoreKeys.indexOf(keyString) !== -1) { return; } if (Array.isArray(fromItem[key])) { fromItem[key] = fromItem[key].join(',<br>'); } if (Array.isArray(toItem[key])) { toItem[key] = toItem[key].join(',<br>'); } if (typeof fromItem[key] === 'object' && typeof toItem[key] === 'object' && fromItem[key] !== null && toItem[key] !== null) { keysChanged = keysChanged.concat(this.compareObject(fromItem[key], toItem[key], keyString)); } else { if (fromItem[key] !== toItem[key]) { keysChanged.push({ key: keyString, oldValue: fromItemClone[key], newValue: toItemClone[key] }); fromItem[key] = StringUtils.diff(fromItem[key], toItem[key]); } } }); return keysChanged; } } const ISO8601_REGEX = new RegExp('(d{4}-[01]d-[0-3]dT[0-2]d:[0-5]d:[0-5]d.d+)|(d{4}-[01]d-[0-3]dT[0-2]d:[0-5]d:[0-5]d)|(d{4}-[01]d-[0-3]dT[0-2]d:[0-5]d)'); const ISO8601_UTCTIME_REGEX = new RegExp('(-?(?:[1-9][0-9]*)?[0-9]{4})-(1[0-2]|0[1-9])-(3[01]|0[1-9]|[12][0-9])T(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.[0-9]+)?(Z)?'); function isIsoDate(value) { if (!ISO8601_REGEX.test(value) && !ISO8601_UTCTIME_REGEX.test(value)) { return false; } const d = new Date(value); return d instanceof Date && !isNaN(d.getTime()); } class DomUtils { static create(doc, tagName, options) { const el = doc.createElement(tagName); for (const key in options) { el[key] = options[key]; } return el; } static remove(node) { if (!node.parentNode) { return; } node.parentNode.removeChild(node); } } async function createExcelWorkBook(workSheet, workSheetName) { const { utils } = await import('xlsx'); return utils.book_new(workSheet, workSheetName); } async function addExcelSheetToWorkBook(title, rows, workBook, opts) { const { utils } = await import('xlsx'); const worksheet = utils.json_to_sheet(rows, opts?.json2SheetOpts); /* calculate column width */ if (rows?.length) { worksheet['!cols'] = getColumnsInfo(rows); } const SHEET_NAME_MAX_LENGTH = 31; let sheetName = title.length >= SHEET_NAME_MAX_LENGTH ? title.substring(0, SHEET_NAME_MAX_LENGTH) : title; if (workBook.SheetNames.includes(sheetName)) { sheetName = `${sheetName.substring(0, SHEET_NAME_MAX_LENGTH - 3)}_${workBook.SheetNames.length}`; } utils.book_append_sheet(workBook, worksheet, sheetName, opts?.bookAppendSheetOpts?.roll); } async function writeExcelFile(workBook, filename, opts) { const cleanedFileName = filename.toLowerCase().endsWith('.xlsx') ? filename.slice(0, -5) : filename; const { writeFile } = await import('xlsx'); writeFile(workBook, `${cleanedFileName}.xlsx`, opts); } function getColumnsInfo(rows) { const columns = Object.keys(rows[0]); return columns.map((column) => ({ wch: getColumnMaxWidth(column, rows) })); } function getColumnMaxWidth(column, rows) { return rows.reduce((width, row) => Math.max(width, row[column]?.toString().length ?? 0), column.length); } /** * Trigger download of a file * * @param content File content * @param mimeType File mime type * @param fileName File name */ function downloadContent(content, mimeType, fileName) { const uri = `data:${mimeType},${encodeURIComponent(content)}`; downloadFromUri(uri, fileName); } function downloadBlob(blob, fileName) { const url = window.URL.createObjectURL(blob); downloadFromUri(url, fileName); } /** * Trigger download of a file * * @param content File content * @param mimeType File mime type * @param fileName File name */ function downloadFromUri(uri, fileName) { const element = document.createElement('a'); element.setAttribute('href', uri); element.setAttribute('download', fileName); element.style.display = 'none'; document.body.appendChild(element); element.click(); document.body.removeChild(element); } /** * Validate if string is valid json object * @param jsonString * @return boolean */ function isValidJSON(jsonString) { try { return JSON.parse(jsonString) && !!jsonString; } catch { return false; } } /* eslint-disable no-prototype-builtins */ class ObjectUtils { static resolve(obj, key) { const keysArray = key.replace(/\[/g, '.').replace(/\]/g, '').split('.'); let current = obj; while (keysArray.length) { if (typeof current !== 'object') { return undefined; } current = current[keysArray.shift()]; } return current; } static isObject(item) { return (item && typeof item === 'object' && !Array.isArray(item) && item !== null && !(item instanceof Date)); } static mergeDeep(target, source, ignoreUndefined = false) { const output = Object.assign({}, target); if (ObjectUtils.isObject(target) && ObjectUtils.isObject(source)) { Object.keys(source) .filter((key) => !ignoreUndefined || source[key] !== undefined) .forEach((key) => { if (ObjectUtils.isObject(source[key])) { if (!(key in target)) { Object.assign(output, { [key]: source[key] }); } else { output[key] = ObjectUtils.mergeDeep(target[key], source[key], ignoreUndefined); } } else { Object.assign(output, { [key]: source[key] }); } }); } return output; } static copyDeep(src) { const target = Array.isArray(src) ? [] : {}; for (const prop in src) { if (src.hasOwnProperty(prop)) { const value = src[prop]; if (value && typeof value === 'object') { target[prop] = this.copyDeep(value); } else { target[prop] = value; } } } return target; } static removeDuplicateCaseInsensitive(obj) { const summaryCapitalizeObject = {}; const capitalizeObject = {}; const upperCaseCount = []; for (const property in obj) { if (obj.hasOwnProperty(property)) { const upperCaseProperty = property.toUpperCase(); if (!summaryCapitalizeObject.hasOwnProperty(upperCaseProperty)) { summaryCapitalizeObject[upperCaseProperty] = [ { [property]: obj[property] } ]; } else { summaryCapitalizeObject[upperCaseProperty].push({ [property]: obj[property] }); } // counting the number of uppercase lettersMna upperCaseCount.push({ key: property, count: property.replace(/[^A-Z]/g, '').length }); } } for (const capitalizedProperty in summaryCapitalizeObject) { if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) { if (summaryCapitalizeObject.hasOwnProperty(capitalizedProperty)) { const capitalizedPropertyObject = summaryCapitalizeObject[capitalizedProperty]; if (capitalizedPropertyObject.length === 1) { // for single params (no duplicates) const singlePossibility = capitalizedPropertyObject[0]; capitalizeObject[capitalizedProperty] = singlePossibility[Object.keys(singlePossibility)[0]]; } else if (capitalizedPropertyObject.length > 1) { // defining the closest to lowercase property const paramClosestToLowercase = upperCaseCount .filter((f) => f.key.toLowerCase() === capitalizedProperty.toLowerCase()) .reduce((prev, current) => { return prev.y < current.y ? prev : current; }); capitalizeObject[paramClosestToLowercase.key.toUpperCase()] = obj[paramClosestToLowercase.key]; } } } } for (const property in obj) { if (obj.hasOwnProperty(property)) { delete obj[property]; } } for (const property in capitalizeObject) { if (capitalizeObject.hasOwnProperty(property)) { obj[property] = capitalizeObject[property]; } } } static removeUndefined(obj) { const output = {}; if (ObjectUtils.isObject(obj)) { Object.keys(obj) .filter((key) => obj[key] !== undefined) .forEach((key) => { if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) { output[key] = ObjectUtils.removeUndefined(obj[key]); } else { output[key] = obj[key]; } }); return output; } if (Array.isArray(obj)) { return obj.map((o) => ObjectUtils.removeUndefined(o)); } return obj; } static removeNull(obj) { const output = {}; if (ObjectUtils.isObject(obj)) { Object.keys(obj) .filter((key) => obj[key] !== null) .forEach((key) => { if (ObjectUtils.isObject(obj[key]) || Array.isArray(obj[key])) { output[key] = ObjectUtils.removeNull(obj[key]); } else { output[key] = obj[key]; } }); return output; } if (Array.isArray(obj)) { return obj.map((o) => ObjectUtils.removeNull(o)); } return obj; } static naturalCompare(a, b, direction = 'asc', nullsFirst) { if (direction === 'desc') { b = [a, (a = b)][0]; } // nullsFirst = undefined : end if direction = 'asc', first if direction = 'desc' // nullsFirst = true : always first // nullsFirst = false : always end if (a === null || a === '' || a === undefined || b === null || b === '' || b === undefined) { const nullScore = a === b ? 0 : a === undefined ? 3 : b === undefined ? -3 : a === null ? 2 : b === null ? -2 : a === '' ? 1 : -1; if (direction === 'desc') { return nullsFirst !== false ? nullScore : nullScore * -1; } return nullsFirst === true ? nullScore * -1 : nullScore; } const ax = []; const bx = []; a = '' + a; b = '' + b; a.replace(/(\d+)|(\D+)/g, (_, $1, $2) => { ax.push([$1 || Infinity, $2 || '']); }); b.replace(/(\d+)|(\D+)/g, (_, $1, $2) => { bx.push([$1 || Infinity, $2 || '']); }); while (ax.length && bx.length) { const an = ax.shift(); const bn = bx.shift(); const nn = an[0] - bn[0] || an[1].localeCompare(bn[1]); if (nn) { return nn; } } return ax.length - bx.length; } /** * Return true if two object are equivalent. * Objects are considered equivalent if they have the same properties and * if all of their properties (first-level only) share the same value. * @param obj1 First object * @param obj2 Second object * @returns Whether two objects arer equivalent */ static objectsAreEquivalent(obj1, obj2) { if (obj1 === obj2) { return true; } const obj1Props = Object.getOwnPropertyNames(obj1); const obj2Props = Object.getOwnPropertyNames(obj2); if (obj1Props.length !== obj2Props.length) { return false; } for (const prop of obj1Props) { if (obj1[prop] !== obj2[prop]) { return false; } } return true; } /** * Return a new object with an array of keys removed * @param obj Source object * @param keys Keys to remove * @returns A new object */ static removeKeys(obj, keys) { const newObj = Object.keys(obj) .filter((key) => keys.indexOf(key) < 0) .reduce((_obj, key) => { _obj[key] = obj[key]; return _obj; }, {}); return newObj; } static isEmpty(obj) { return Object.keys(obj).length === 0; } } class NumberUtils { static roundToNDecimal(num, decimal = 3) { const roundFactor = Math.pow(10, decimal); return Math.round(num * roundFactor) / roundFactor; } } /** Utility function to create a K:V from a list of strings */ function strEnum(o) { return o.reduce((res, key) => { res[key] = key; return res; }, Object.create(null)); } const PATH_PREBUILT_THEMES = 'assets/igo2/core/theming/prebuilt-themes'; const LINK_ID = 'theme-styles'; function loadTheme(doc, themeName, path = PATH_PREBUILT_THEMES) { const src = `${path}/${themeName}.css`; const head = doc.getElementsByTagName('head')[0]; const themeLink = doc.getElementById(LINK_ID); if (themeLink) { themeLink.href = src; } else { createHtmlLink(doc, src, head); } } function createHtmlLink(doc, src, parent) { const element = DomUtils.create(doc, 'link', { id: LINK_ID, rel: 'stylesheet', href: src }); parent.appendChild(element); } const TREE_SEPERATOR = '.'; class Tree { config; _data; getChildren; getId; getLevel; constructor(initialData, config) { this.config = config; this.getChildren = config.getChildren; this.getId = config.getId; this.getLevel = config.getLevel; this._data = this.sortDeep(initialData); } get data() { return this._data; } get flattened() { return this.flatten([...this.data]); } add(...nodes) { this.sortDeep(nodes); this._data.unshift(...nodes); return nodes; } addBefore(beforeId, ...nodes) { this.sortDeep(nodes); this._addBefore(beforeId, this._data, ...nodes); } remove(...nodes) { return this._remove(...nodes); } clear() { this._data = []; } exist(node) { const id = this.getId(node); return this.flattened.some((layer) => this.getId(layer) === id); } /** * Move a node to a different position * @param node * @param beforeTo The position of index into the tree. If -1 move at the end */ moveTo(beforeTo, ...nodes) { const clonedBeforeTo = [...beforeTo]; const lastIndex = clonedBeforeTo.pop(); const recipient = this.getAncestorAtPosition(clonedBeforeTo); const beforeId = lastIndex === -1 || lastIndex >= recipient.length ? null : this.getId(recipient[lastIndex]); const nodesToMove = nodes.filter((node) => beforeId !== this.getId(node)); return this.move(beforeId, recipient, ...nodesToMove); } getPosition(node) { const id = this.getId(node); return this._getPosition(id); } _addBefore(beforeId, recipient = this._data, ...nodes) { if (!beforeId) { recipient.push(...nodes); return nodes; } const beforeIndex = this.getIndex(beforeId, recipient); recipient.splice(beforeIndex, 0, ...nodes); return nodes; } _remove(...nodes) { return nodes.reduce((acc, node) => { const ancestor = this.getNodeAncestor(node); if (!ancestor) { return; } const index = this.getIndex(this.getId(node), ancestor); if (index === -1) { return; } ancestor.splice(index, 1); return acc.concat(node); }, []); } /** * Move an node before an id * @param node Node to be move * @param recipient * @param beforeId */ move(beforeId, recipient, ...nodes) { this._remove(...nodes); return this._addBefore(beforeId, recipient, ...nodes); } _getPosition(id, ancestorsIndex = [], values = this._data) { let indexList; values.some((value, index) => { if (this.getId(value) === id) { indexList = ancestorsIndex.concat(index); return true; } const children = this.getChildren(value); if (children) { const groupIndexList = this._getPosition(id, ancestorsIndex.concat(index), children); if (groupIndexList) { indexList = groupIndexList; return true; } } return false; }); return indexList; } getAncestorAtPosition(position) { if (!position.length) { return this._data; } const node = this.getNodeByPosition(position); return this.getChildren(node); } /** Recursive */ sortDeep(data = this._data) { data.forEach((node) => { const children = this.getChildren(node); if (children) { this.sortDeep(children); } }); return this.sort(data); } sort(children) { const sorted = children.sort((a, b) => this.getLevel(a) - this.getLevel(b)); return this.config.reverse ? sorted.reverse() : sorted; } /** Recursive */ _getNodeById(id, data = this._data) { let node; data.some((item) => { if (this.getId(item) === id) { node = item; return true; } const children = this.getChildren(item); if (children) { node = this._getNodeById(id, children); if (node) { return true; } } return false; }); return node; } getNodeByPosition(indexes) { if (indexes.length > 1) { return indexes.reduce((previousValue, index) => { const ancestor = previousValue ? this.getChildren(previousValue) : this._data; return this._getByIndex(index, ancestor); }, null); } else { return this._getByIndex(indexes[0]); } } _getByIndex(index, ancestor = this._data) { return ancestor[index]; } getNodeAncestor(node) { const id = this.getId(node); return this.getAncestorById(id); } /** Recursive */ getAncestorById(id, data = this._data) { let ancestor; data.some((item) => { if (this.getId(item) === id) { ancestor = data; return true; } const children = this.getChildren(item); if (children) { ancestor = this.getAncestorById(id, children); if (ancestor) { return true; } } return false; }); return ancestor; } /** Recursive */ flatten(nodes) { return nodes.reduce((list, node) => { const children = this.getChildren(node); if (children) { const flattened = this.flatten(children); list.push(node, ...flattened); } else { list.push(node); } return list; }, []); } getIndex(id, ancestor) { return ancestor.findIndex((node) => this.getId(node) === id); } } function S4() { return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); } function uuid() { const id = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`; return id.toLowerCase(); } var SubjectStatus; (function (SubjectStatus) { SubjectStatus[SubjectStatus["Error"] = 0] = "Error"; SubjectStatus[SubjectStatus["Done"] = 1] = "Done"; SubjectStatus[SubjectStatus["Working"] = 2] = "Working"; SubjectStatus[SubjectStatus["Waiting"] = 3] = "Waiting"; })(SubjectStatus || (SubjectStatus = {})); class Watcher { status$ = new Subject(); status$$; get status() { return this._status; } set status(value) { this._status = value; this.status$.next(value); } _status; // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type subscribe(callback, scope) { this.watch(); this.status$$ = this.status$.pipe(distinctUntilChanged()).subscribe(() => { callback.call(scope, this); }); } unsubscribe() { this.unwatch(); if (this.status$$ !== undefined) { this.status$$.unsubscribe(); this.status$$ = undefined; } this.status = SubjectStatus.Waiting; } } /* * Public API Surface of utils */ /** * Generated bundle index. Do not edit. */ export { Base64, ChangeType, ChangeUtils, Compression, DomUtils, NumberUtils, ObjectUtils, S4, StringUtils, SubjectStatus, TREE_SEPERATOR, Tree, Watcher, addExcelSheetToWorkBook, createExcelWorkBook, customCacheHasher, downloadBlob, downloadContent, downloadFromUri, isIsoDate, isValidJSON, loadTheme, strEnum, uuid, writeExcelFile }; //# sourceMappingURL=igo2-utils.mjs.map