wacom
Version:
Module which has common services and components which can be used on all projects.
1 lines • 330 kB
Source Map (JSON)
{"version":3,"file":"wacom.mjs","sources":["../../../projects/wacom/src/lib/interfaces/config.ts","../../../projects/wacom/src/lib/interfaces/alert.interface.ts","../../../projects/wacom/src/lib/interfaces/modal.interface.ts","../../../projects/wacom/src/lib/services/meta.service.ts","../../../projects/wacom/src/lib/guard/meta.guard.ts","../../../projects/wacom/src/lib/components/alert/alert.component.ts","../../../projects/wacom/src/lib/components/alert/alert.component.html","../../../projects/wacom/src/lib/components/modal/modal.component.ts","../../../projects/wacom/src/lib/components/modal/modal.component.html","../../../projects/wacom/src/lib/components/loader/loader.component.ts","../../../projects/wacom/src/lib/components/loader/loader.component.html","../../../projects/wacom/src/lib/components/base.component.ts","../../../projects/wacom/src/lib/components/alert/wrapper/wrapper.component.ts","../../../projects/wacom/src/lib/components/alert/wrapper/wrapper.component.html","../../../projects/wacom/src/lib/services/dom.service.ts","../../../projects/wacom/src/lib/services/alert.service.ts","../../../projects/wacom/src/lib/services/core.service.ts","../../../projects/wacom/src/lib/components/crud.component.ts","../../../projects/wacom/src/lib/directives/click-outside.directive.ts","../../../projects/wacom/src/lib/pipes/arr.pipe.ts","../../../projects/wacom/src/lib/pipes/mongodate.pipe.ts","../../../projects/wacom/src/lib/pipes/pagination.pipe.ts","../../../projects/wacom/src/lib/pipes/safe.pipe.ts","../../../projects/wacom/src/lib/pipes/search.pipe.ts","../../../projects/wacom/src/lib/pipes/splice.pipe.ts","../../../projects/wacom/src/lib/pipes/split.pipe.ts","../../../projects/wacom/src/lib/pipes/number.pipe.ts","../../../projects/wacom/src/lib/services/base.service.ts","../../../projects/wacom/src/lib/services/store.service.ts","../../../projects/wacom/src/lib/services/http.service.ts","../../../projects/wacom/src/lib/services/crud.service.ts","../../../projects/wacom/src/lib/services/mongo.service.ts","../../../projects/wacom/src/lib/services/render.service.ts","../../../projects/wacom/src/lib/services/hash.service.ts","../../../projects/wacom/src/lib/services/loader.service.ts","../../../projects/wacom/src/lib/services/socket.service.ts","../../../projects/wacom/src/lib/services/modal.service.ts","../../../projects/wacom/src/lib/components/files/files.component.ts","../../../projects/wacom/src/lib/components/files/files.component.html","../../../projects/wacom/src/lib/services/file.service.ts","../../../projects/wacom/src/lib/services/ui.service.ts","../../../projects/wacom/src/lib/services/time.service.ts","../../../projects/wacom/src/lib/services/rtc.service.ts","../../../projects/wacom/src/lib/wacom.module.ts","../../../projects/wacom/src/public-api.ts","../../../projects/wacom/src/wacom.ts"],"sourcesContent":["import { InjectionToken } from '@angular/core';\nexport interface Any {\n\t[key: string]: string;\n}\nexport interface Config {\n\tmeta?: {\n\t\tuseTitleSuffix?: boolean;\n\t\twarnMissingGuard?: boolean;\n\t\tdefaults?: {\n\t\t\ttitle?: string;\n\t\t\ttitleSuffix?: string;\n\t\t} & { [key: string]: string | undefined };\n\t};\n\talert?: {\n\t\talerts?: object;\n\t\ttext?: string;\n\t\ttype?: string;\n\t\ticon?: string;\n\t\tclass?: string;\n\t\tunique?: string;\n\t\tprogress?: boolean;\n\t\tposition?: string;\n\t\ttimeout?: number;\n\t\tclose?: any;\n\t\tbuttons?: any;\n\t};\n\tmodal?: {\n\t\tsize?: any;\n\t\ttimeout?: any;\n\t\ttimestart?: any;\n\t\tclass?: string;\n\t\tmodals?: object;\n\t\tposition?: string;\n\t\tclosable?: boolean;\n\t\tunique?: string;\n\t};\n\tpopup?: {\n\t\tpopups?: object;\n\t};\n\tloader?: {\n\t\tloaders?: object;\n\t};\n\tsocket?: any;\n\tio?: any;\n\thttp?: {\n\t\theaders?: any;\n\t\turl?: string;\n\t};\n\tstore?: {\n\t\tprefix?: string;\n\t\tset?: (\n\t\t\thold: any,\n\t\t\tvalue: any,\n\t\t\tcb?: () => void,\n\t\t\terrCb?: () => void\n\t\t) => Promise<boolean>;\n\t\tget?: (\n\t\t\thold: any,\n\t\t\tcb?: (value: string) => void,\n\t\t\terrCb?: () => void\n\t\t) => Promise<string>;\n\t\tremove?: (\n\t\t\thold: any,\n\t\t\tcb?: () => void,\n\t\t\terrCb?: () => void\n\t\t) => Promise<boolean>;\n\t\tclear?: (cb?: () => void, errCb?: () => void) => Promise<boolean>;\n\t};\n}\nexport const CONFIG_TOKEN = new InjectionToken<Config>('config');\nexport const DEFAULT_CONFIG: Config = {\n\tmeta: {\n\t\tuseTitleSuffix: false,\n\t\twarnMissingGuard: true,\n\t\tdefaults: {},\n\t},\n\tsocket: false,\n\thttp: {\n\t\turl: '',\n\t\theaders: {},\n\t},\n\tstore: {\n\t\tprefix: '',\n\t},\n};\n","import { InjectionToken } from '@angular/core';\n\nexport interface Alert {\n\tonClose?: any;\n\talerts?: object;\n\tcomponent?: any;\n\ttext?: string;\n\ticon?: string;\n\ttype?: string;\n\tclass?: string;\n\tunique?: string;\n\tprogress?: boolean;\n\tposition?: string;\n\ttimeout?: any;\n\tclosable?: boolean;\n\tclose?: any;\n\tbuttons?: any;\n\t[x: string]: any;\n}\nexport const DEFAULT_Alert: Alert = {\n\talerts: {},\n\ttext: '',\n\ttype: 'info',\n\tclass: '',\n\tprogress: true,\n\tposition: 'bottomRight',\n\ttimeout: 5000,\n\tclosable: true,\n\tbuttons: [],\n};\n","import { InjectionToken } from '@angular/core';\n\nexport interface Modal {\n\tonOpen?: any;\n\tonClose?: any;\n\tonClickOutside?: any;\n\tid?: number;\n\tclose?: any;\n\tcomponent?: any;\n\tsize?: any;\n\ttimeout?: any;\n\ttimestart?: any;\n\tclass?: string;\n\tmodals?: object;\n\tposition?: string;\n\tclosable?: boolean;\n\tunique?: string;\n\t[x: string]: any;\n}\nexport const DEFAULT_Modal: Modal = {\n\tsize: 'mid',\n\ttimeout: 0,\n\ttimestart: 0,\n\tclass: '',\n\tmodals: {},\n\tposition: 'tc',\n\tclosable: true,\n};\n","import { Inject, Injectable, Optional } from '@angular/core';\nimport { Title, Meta } from '@angular/platform-browser';\nimport { Router, Route } from '@angular/router';\nimport { CONFIG_TOKEN, Config, DEFAULT_CONFIG } from '../interfaces/config';\n\nconst isDefined = (val: any) => typeof val !== 'undefined';\n\n@Injectable({\n\tprovidedIn: 'root',\n})\nexport class MetaService {\n\tprivate _meta: any;\n\n\tconstructor(\n\t\tprivate router: Router,\n\t\tprivate meta: Meta,\n\t\tprivate titleService: Title,\n\t\t@Inject(CONFIG_TOKEN) @Optional() private config: Config\n\t) {\n\t\tthis.config = this.config || DEFAULT_CONFIG;\n\t\tthis._meta = this.config.meta || {};\n\t\tthis._warnMissingGuard();\n\t}\n\n\t/**\n\t * Sets the default meta tags.\n\t *\n\t * @param defaults - The default meta tags.\n\t */\n\tsetDefaults(defaults: { [key: string]: string }): void {\n\t\tthis._meta.defaults = defaults;\n\t}\n\n\t/**\n\t * Sets the title and optional title suffix.\n\t *\n\t * @param title - The title to set.\n\t * @param titleSuffix - The title suffix to append.\n\t * @returns The MetaService instance.\n\t */\n\tsetTitle(title?: string, titleSuffix?: string): MetaService {\n\t\tlet titleContent = isDefined(title)\n\t\t\t? title\n\t\t\t: this._meta.defaults['title'] || '';\n\t\tif (this._meta.useTitleSuffix) {\n\t\t\ttitleContent += isDefined(titleSuffix)\n\t\t\t\t? titleSuffix\n\t\t\t\t: this._meta.defaults['titleSuffix'] || '';\n\t\t}\n\t\tthis._updateMetaTag('title', titleContent);\n\t\tthis._updateMetaTag('og:title', titleContent);\n\t\tthis.titleService.setTitle(titleContent);\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets link tags.\n\t *\n\t * @param links - The links to set.\n\t * @returns The MetaService instance.\n\t */\n\tsetLink(links: { [key: string]: string }): MetaService {\n\t\tObject.keys(links).forEach((rel) => {\n\t\t\tlet link: HTMLLinkElement = document.createElement('link');\n\t\t\tlink.setAttribute('rel', rel);\n\t\t\tlink.setAttribute('href', links[rel]);\n\t\t\tdocument.head.appendChild(link);\n\t\t});\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets a meta tag.\n\t *\n\t * @param tag - The meta tag name.\n\t * @param value - The meta tag value.\n\t * @param prop - The meta tag property.\n\t * @returns The MetaService instance.\n\t */\n\tsetTag(tag: string, value: string, prop?: string): MetaService {\n\t\tif (tag === 'title' || tag === 'titleSuffix') {\n\t\t\tthrow new Error(\n\t\t\t\t`Attempt to set ${tag} through 'setTag': 'title' and 'titleSuffix' are reserved tag names. Please use 'MetaService.setTitle' instead`\n\t\t\t);\n\t\t}\n\t\tconst content = isDefined(value)\n\t\t\t? value\n\t\t\t: this._meta.defaults[tag] || '';\n\t\tthis._updateMetaTag(tag, content, prop);\n\t\tif (tag === 'description') {\n\t\t\tthis._updateMetaTag('og:description', content, prop);\n\t\t\tthis._updateMetaTag('twitter:description', content, prop);\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Updates a meta tag.\n\t *\n\t * @param tag - The meta tag name.\n\t * @param value - The meta tag value.\n\t * @param prop - The meta tag property.\n\t */\n\tprivate _updateMetaTag(tag: string, value: string, prop?: string): void {\n\t\tprop =\n\t\t\tprop ||\n\t\t\t(tag.startsWith('og:') || tag.startsWith('twitter:')\n\t\t\t\t? 'property'\n\t\t\t\t: 'name');\n\t\tthis.meta.updateTag({ [prop]: tag, content: value });\n\t}\n\n\t/**\n\t * Removes a meta tag.\n\t *\n\t * @param tag - The meta tag name.\n\t * @param prop - The meta tag property.\n\t */\n\tremoveTag(tag: string, prop?: string): void {\n\t\tprop =\n\t\t\tprop ||\n\t\t\t(tag.startsWith('og:') || tag.startsWith('twitter:')\n\t\t\t\t? 'property'\n\t\t\t\t: 'name');\n\t\tthis.meta.removeTag(`${prop}=\"${tag}\"`);\n\t}\n\n\t/**\n\t * Warns about missing meta guards in routes.\n\t */\n\tprivate _warnMissingGuard(): void {\n\t\tif (\n\t\t\tisDefined(this._meta.warnMissingGuard) &&\n\t\t\t!this._meta.warnMissingGuard\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tconst hasDefaultMeta = !!Object.keys(this._meta.defaults).length;\n\t\tconst hasMetaGuardInArr = (it: any) =>\n\t\t\tit && it.IDENTIFIER === 'MetaGuard';\n\t\tlet hasShownWarnings = false;\n\t\tthis.router.config.forEach((route: Route) => {\n\t\t\tconst hasRouteMeta = route.data && route.data['meta'];\n\t\t\tconst showWarning =\n\t\t\t\t!isDefined(route.redirectTo) &&\n\t\t\t\t(hasDefaultMeta || hasRouteMeta) &&\n\t\t\t\t!(route.canActivate || []).some(hasMetaGuardInArr);\n\t\t\tif (showWarning) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Route with path \"${route.path}\" has ${\n\t\t\t\t\t\thasRouteMeta ? '' : 'default '\n\t\t\t\t\t}meta tags, but does not use MetaGuard. Please add MetaGuard to the canActivate array in your route configuration`\n\t\t\t\t);\n\t\t\t\thasShownWarnings = true;\n\t\t\t}\n\t\t});\n\t\tif (hasShownWarnings) {\n\t\t\tconsole.warn(\n\t\t\t\t`To disable these warnings, set metaConfig.warnMissingGuard: false in your MetaConfig passed to MetaModule.forRoot()`\n\t\t\t);\n\t\t}\n\t}\n}\n","import { Injectable, Inject, Optional } from '@angular/core';\nimport { ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';\nimport { MetaService } from '../services/meta.service';\nimport { CONFIG_TOKEN, Config, DEFAULT_CONFIG } from '../interfaces/config';\n\n@Injectable()\nexport class MetaGuard {\n\tpublic static IDENTIFIER = 'MetaGuard';\n\tprivate _meta: any;\n\tpublic constructor(\n\t\tprivate metaService: MetaService,\n\t\t@Inject(CONFIG_TOKEN) @Optional() private config: Config\n\t) {\n\t\tthis._meta = config.meta;\n\t\tif (!this.config) this.config = DEFAULT_CONFIG;\n\t}\n\tpublic canActivate(\n\t\troute: ActivatedRouteSnapshot,\n\t\tstate: RouterStateSnapshot\n\t): boolean {\n\t\tthis._processRouteMetaTags(route.data && route.data['meta']);\n\t\treturn true;\n\t}\n\tprivate _processRouteMetaTags(meta: any = {}) {\n\t\tif (meta.disableUpdate) {\n\t\t\treturn;\n\t\t}\n\t\tif (meta.title) {\n\t\t\tthis.metaService.setTitle(meta.title, meta.titleSuffix);\n\t\t}\n\t\tif (Array.isArray(meta.links)) {\n\t\t\tthis.metaService.setLink(meta.links);\n\t\t} else if (typeof meta.links === 'string') {\n\t\t\tthis.metaService.setLink(meta.links.split(' '));\n\t\t}\n\t\tif (Array.isArray(this._meta.defaults?.links)) {\n\t\t\tthis.metaService.setLink(this._meta.defaults?.links);\n\t\t} else if (typeof this._meta.defaults?.links === 'string') {\n\t\t\tthis.metaService.setLink(this._meta.defaults?.links.split(' '));\n\t\t}\n\t\tObject.keys(meta).forEach((prop) => {\n\t\t\tif (\n\t\t\t\tprop === 'title' ||\n\t\t\t\tprop === 'titleSuffix' ||\n\t\t\t\tprop === 'links'\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tObject.keys(meta[prop]).forEach((key) => {\n\t\t\t\tthis.metaService.setTag(key, meta[prop][key], prop);\n\t\t\t});\n\t\t});\n\t\tObject.keys(this._meta.defaults).forEach((key) => {\n\t\t\tif (\n\t\t\t\tkey in meta ||\n\t\t\t\tkey === 'title' ||\n\t\t\t\tkey === 'titleSuffix' ||\n\t\t\t\tkey === 'links'\n\t\t\t) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.metaService.setTag(key, this._meta.defaults[key]);\n\t\t});\n\t}\n}\n","import { Component, ViewChild } from '@angular/core';\n\n@Component({\n\tselector: 'alert',\n\ttemplateUrl: './alert.component.html',\n\tstyleUrls: ['./alert.component.scss'],\n\tstandalone: false,\n})\nexport class AlertComponent {\n\t@ViewChild('alert', { static: false }) alert: any;\n\tcomponent: any;\n\ttext: string = '';\n\tclass: string = '';\n\ttype: string = 'info';\n\tprogress: boolean = true;\n\tposition: string = 'bottomRight'; // [bottomRight, bottomLeft, topRight, topLeft, topCenter, bottomCenter or center]\n\ticon: string = '';\n\ttimeout: any = 5000;\n\tclose: any;\n\tclosable: any = true;\n\tbuttons: any = []; /*[{text, callback}]*/\n\n\tconstructor() {\n\t\tsetTimeout(() => {\n\t\t\tif (this.timeout) {\n\t\t\t\tlet remaining = JSON.parse(JSON.stringify(this.timeout));\n\n\t\t\t\tlet timer = setTimeout(() => {\n\t\t\t\t\tthis.remove();\n\t\t\t\t}, remaining);\n\n\t\t\t\tlet start = new Date();\n\n\t\t\t\tthis.alert.nativeElement.addEventListener(\n\t\t\t\t\t'mouseenter',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tclearTimeout(timer);\n\n\t\t\t\t\t\tremaining -= new Date().getTime() - start.getTime();\n\t\t\t\t\t},\n\t\t\t\t\tfalse\n\t\t\t\t);\n\t\t\t\tthis.alert.nativeElement.addEventListener(\n\t\t\t\t\t'mouseleave',\n\t\t\t\t\t() => {\n\t\t\t\t\t\tstart = new Date();\n\n\t\t\t\t\t\tclearTimeout(timer);\n\n\t\t\t\t\t\ttimer = window.setTimeout(() => {\n\t\t\t\t\t\t\tthis.remove();\n\t\t\t\t\t\t}, remaining);\n\t\t\t\t\t},\n\t\t\t\t\tfalse\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\tpublic delete_animation = false;\n\tremove() {\n\t\tthis.delete_animation = true;\n\t\tsetTimeout(() => {\n\t\t\tthis.close();\n\t\t\tthis.delete_animation = false;\n\t\t}, 350);\n\t}\n}\n","<div\n\t*ngIf=\"text\"\n\t[ngClass]=\"class\"\n\tclass=\"waw-alert-container height\"\n\t[class._close]=\"delete_animation\"\n>\n\t<div\n\t\t[class.waw-alert-color-blue]=\"type == 'info'\"\n\t\t[class.waw-alert-color-red]=\"type == 'error'\"\n\t\t[class.waw-alert-color-green]=\"type == 'success'\"\n\t\t[class.waw-alert-color-orange]=\"type == 'warning'\"\n\t\t[class.waw-alert-color-yellow]=\"type == 'question'\"\n\t\tclass=\"waw-alert bounceInUp waw-alert-theme-light waw-alert-animateInside waw-alert-opened\"\n\t\t#alert\n\t>\n\t\t<div class=\"waw-alert__progress\" *ngIf=\"progress\">\n\t\t\t<span\n\t\t\t\t[ngStyle]=\"{\n\t\t\t\t\t'animation-duration': (timeout + 350) / 1000 + 's'\n\t\t\t\t}\"\n\t\t\t></span>\n\t\t</div>\n\t\t<div class=\"waw-alert-body\">\n\t\t\t<div *ngIf=\"!component\" class=\"waw-alert-texts\">\n\t\t\t\t<div *ngIf=\"icon\" class=\"{{ icon }}\"></div>\n\t\t\t\t<div class=\"waw-alert-message slideIn\">{{ text }}</div>\n\t\t\t</div>\n\t\t\t<div *ngIf=\"!component && type == 'question'\">\n\t\t\t\t<button\n\t\t\t\t\tclass=\"alert-btn\"\n\t\t\t\t\t*ngFor=\"let b of buttons\"\n\t\t\t\t\t(click)=\"remove(); b.callback && b.callback()\"\n\t\t\t\t>\n\t\t\t\t\t{{ b.text }}\n\t\t\t\t</button>\n\t\t\t</div>\n\t\t\t<div\n\t\t\t\tclass=\"waw-alert__close\"\n\t\t\t\t*ngIf=\"closable\"\n\t\t\t\t(click)=\"remove()\"\n\t\t\t></div>\n\t\t</div>\n\t</div>\n</div>\n","import { Component, OnInit } from '@angular/core';\n\n@Component({\n\tselector: 'lib-modal',\n\ttemplateUrl: './modal.component.html',\n\tstyleUrls: ['./modal.component.scss'],\n\tstandalone: false,\n})\nexport class ModalComponent implements OnInit {\n\tclass: string = '';\n\tsize: string = 'flex';\n\tclosable: boolean = true;\n\tclose: any;\n\tonOpen: any;\n\ttimestart: any;\n\ttimeout: any;\n\tshowModal = false;\n\tallowClose = true;\n\tonClickOutside: any;\n\tngOnInit() {\n\t\tif (typeof this.onClickOutside !== 'function') {\n\t\t\tthis.onClickOutside = this.close;\n\t\t\t// this.onClickOutside = () => {\n\t\t\t// \tif (this.allowClose) {\n\t\t\t// \t\tthis.close();\n\t\t\t// \t}\n\n\t\t\t// \tthis.allowClose = true;\n\t\t\t// };\n\t\t}\n\n\t\tif (typeof this.onOpen == 'function') this.onOpen();\n\n\t\twindow.addEventListener('popstate', this.popStateListener.bind(this));\n\t}\n\n\tngAfterViewInit() {\n\t\tsetTimeout(() => {\n\t\t\tthis.showModal = true;\n\t\t}, this.timestart || 0);\n\t}\n\n\tngOnDestroy(): void {\n\t\twindow.removeEventListener(\n\t\t\t'popstate',\n\t\t\tthis.popStateListener.bind(this)\n\t\t);\n\t}\n\n\tpopStateListener(e: Event) {\n\t\tthis.close();\n\t}\n}\n","<div\n\t[hidden]=\"!showModal\"\n\tclass=\"modal\"\n\t[ngClass]=\"class + ' ' + size\"\n\t(click)=\"onClickOutside()\"\n>\n\t<!-- (click)=\"$event.stopPropagation()\" -->\n\t<!-- <div class=\"modal-content\" (mousedown)=\"allowClose = false\"> -->\n\t<div class=\"modal-content\" (click)=\"$event.stopPropagation()\">\n\t\t<div><!-- Content Will Drop Here --></div>\n\t\t<span class=\"close\" (click)=\"close()\" *ngIf=\"closable\">×</span>\n\t</div>\n</div>\n","import { Component, ViewChild } from '@angular/core';\n\n@Component({\n\tselector: 'lib-loader',\n\ttemplateUrl: './loader.component.html',\n\tstyleUrls: ['./loader.component.scss'],\n\tstandalone: false,\n})\nexport class LoaderComponent {\n\t@ViewChild('loader', { static: false }) loader: any;\n\tpublic text: string = 'Loading';\n\tpublic class: string = '';\n\tpublic progress: boolean = true;\n\tpublic timeout: number = 5000;\n\tpublic close: any;\n\tpublic closable: any = true;\n\tconstructor() {}\n\tngOnInit() {\n\t\tif (this.timeout) {\n\t\t\tsetTimeout(() => {\n\t\t\t\tthis.close();\n\t\t\t}, this.timeout);\n\t\t}\n\t}\n}\n","<div\n\tstyle=\"\n\t\tposition: fixed;\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tleft: 0;\n\t\ttop: 0;\n\t\tbackground-color: #334d6e;\n\t\tdisplay: flex;\n\t\tjustify-content: center;\n\t\talign-items: center;\n\t\tz-index: 999999;\n\t\"\n\t#loader\n>\n\t<span class=\"close\" (click)=\"close()\" *ngIf=\"closable\">×</span>\n\t<span style=\"font-size: 30px; color: white\">\n\t\t{{ text }}\n\t</span>\n</div>\n","/**\n * BaseComponent is an abstract class that provides basic functionality for managing the current timestamp.\n */\nexport abstract class BaseComponent {\n\t/**\n\t * The current timestamp in milliseconds since the Unix epoch.\n\t */\n\tnow = new Date().getTime();\n\n\t/**\n\t * Refreshes the `now` property with the current timestamp.\n\t */\n\trefreshNow(): void {\n\t\tthis.now = new Date().getTime();\n\t}\n}\n","import { Component } from '@angular/core';\n\n@Component({\n\tselector: 'lib-wrapper',\n\ttemplateUrl: './wrapper.component.html',\n\tstyleUrls: ['./wrapper.component.scss'],\n\tstandalone: false,\n})\nexport class WrapperComponent {\n\tconstructor() {}\n}\n","<div>\n\t<div\n\t\tclass=\"waw-alert-wrapper waw-alert-wrapper-bottomRight\"\n\t\tid=\"bottomRight\"\n\t></div>\n\t<div\n\t\tclass=\"waw-alert-wrapper waw-alert-wrapper-bottomLeft\"\n\t\tid=\"bottomLeft\"\n\t></div>\n\t<div\n\t\tclass=\"waw-alert-wrapper waw-alert-wrapper-topRight\"\n\t\tid=\"topRight\"\n\t></div>\n\t<div class=\"waw-alert-wrapper waw-alert-wrapper-topLeft\" id=\"topLeft\"></div>\n\t<div\n\t\tclass=\"waw-alert-wrapper waw-alert-wrapper-topCenter\"\n\t\tid=\"topCenter\"\n\t></div>\n\t<div\n\t\tclass=\"waw-alert-wrapper waw-alert-wrapper-bottomCenter\"\n\t\tid=\"bottomCenter\"\n\t></div>\n\t<div class=\"waw-alert-wrapper waw-alert-wrapper-center\" id=\"center\"></div>\n</div>\n","import {\n\tInjectable,\n\tInjector,\n\tComponentFactoryResolver,\n\tComponentRef,\n\tEmbeddedViewRef,\n\tApplicationRef,\n} from '@angular/core';\n\n@Injectable({\n\tprovidedIn: 'root',\n})\nexport class DomService {\n\tprivate providedIn: Record<string, boolean> = {};\n\n\tconstructor(\n\t\tprivate componentFactoryResolver: ComponentFactoryResolver,\n\t\tprivate appRef: ApplicationRef,\n\t\tprivate injector: Injector\n\t) {}\n\n\t/**\n\t * Appends a component to a specified element by ID.\n\t *\n\t * @param component - The component to append.\n\t * @param options - The options to project into the component.\n\t * @param id - The ID of the element to append the component to.\n\t * @returns An object containing the native element and the component reference.\n\t */\n\tappendById(\n\t\tcomponent: any,\n\t\toptions: any = {},\n\t\tid: string\n\t): { nativeElement: HTMLElement; componentRef: ComponentRef<any> } {\n\t\tconst componentRef = this.componentFactoryResolver\n\t\t\t.resolveComponentFactory(component)\n\t\t\t.create(this.injector);\n\n\t\tthis.projectComponentInputs(componentRef, options);\n\t\tthis.appRef.attachView(componentRef.hostView);\n\t\tconst domElem = (componentRef.hostView as EmbeddedViewRef<any>)\n\t\t\t.rootNodes[0] as HTMLElement;\n\t\tconst element = document.getElementById(id);\n\t\tif (element && typeof element.appendChild === 'function') {\n\t\t\telement.appendChild(domElem);\n\t\t}\n\t\treturn {\n\t\t\tnativeElement: domElem,\n\t\t\tcomponentRef: componentRef,\n\t\t};\n\t}\n\n\t/**\n\t * Appends a component to a specified element or to the body.\n\t *\n\t * @param component - The component to append.\n\t * @param options - The options to project into the component.\n\t * @param element - The element to append the component to. Defaults to body.\n\t * @returns An object containing the native element and the component reference.\n\t */\n\tappendComponent(\n\t\tcomponent: any,\n\t\toptions: any = {},\n\t\telement: HTMLElement = document.body\n\t): { nativeElement: HTMLElement; componentRef: ComponentRef<any> } | void {\n\t\tif (options.providedIn) {\n\t\t\tif (this.providedIn[options.providedIn]) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.providedIn[options.providedIn] = true;\n\t\t}\n\n\t\tconst componentRef = this.componentFactoryResolver\n\t\t\t.resolveComponentFactory(component)\n\t\t\t.create(this.injector);\n\t\tthis.projectComponentInputs(componentRef, options);\n\t\tthis.appRef.attachView(componentRef.hostView);\n\t\tconst domElem = (componentRef.hostView as EmbeddedViewRef<any>)\n\t\t\t.rootNodes[0] as HTMLElement;\n\t\tif (element && typeof element.appendChild === 'function') {\n\t\t\telement.appendChild(domElem);\n\t\t}\n\t\treturn {\n\t\t\tnativeElement: domElem,\n\t\t\tcomponentRef: componentRef,\n\t\t};\n\t}\n\n\t/**\n\t * Gets a reference to a dynamically created component.\n\t *\n\t * @param component - The component to create.\n\t * @param options - The options to project into the component.\n\t * @returns The component reference.\n\t */\n\tgetComponentRef(component: any, options: any = {}): ComponentRef<any> {\n\t\tconst componentRef = this.componentFactoryResolver\n\t\t\t.resolveComponentFactory(component)\n\t\t\t.create(this.injector);\n\n\t\tthis.projectComponentInputs(componentRef, options);\n\t\tthis.appRef.attachView(componentRef.hostView);\n\n\t\treturn componentRef;\n\t}\n\n\t/**\n\t * Projects the inputs onto the component.\n\t *\n\t * @param component - The component reference.\n\t * @param options - The options to project into the component.\n\t * @returns The component reference with the projected inputs.\n\t */\n\tprivate projectComponentInputs(\n\t\tcomponent: ComponentRef<any>,\n\t\toptions: any\n\t): ComponentRef<any> {\n\t\tif (options) {\n\t\t\tconst props = Object.getOwnPropertyNames(options);\n\t\t\tfor (const prop of props) {\n\t\t\t\tcomponent.instance[prop] = options[prop];\n\t\t\t}\n\t\t}\n\t\treturn component;\n\t}\n}\n\n/*\nhttps://stackoverflow.com/questions/39857222/angular2-dynamic-component-injection-in-root/40687392#40687392\nhttps://gist.github.com/reed-lawrence/1f6b7c328ad3886e60dc2b0adcf75a97\n*/\n","import { Injectable, Inject, Optional } from '@angular/core';\nimport { CONFIG_TOKEN, Config, DEFAULT_CONFIG } from '../interfaces/config';\nimport { AlertComponent } from '../components/alert/alert.component';\nimport { WrapperComponent } from '../components/alert/wrapper/wrapper.component';\nimport { DomService } from './dom.service';\nimport { Alert, DEFAULT_Alert } from '../interfaces/alert.interface';\n\n@Injectable({\n\tprovidedIn: 'root',\n})\nexport class AlertService {\n\tprivate alert: any;\n\tprivate _container: any;\n\tconstructor(\n\t\tprivate dom: DomService,\n\t\t@Inject(CONFIG_TOKEN) @Optional() private config: Config\n\t) {\n\t\tif (!this.config) this.config = DEFAULT_CONFIG;\n\t\tthis.alert = this.config.alert;\n\t\tif (!this.alert) {\n\t\t\tthis.alert = DEFAULT_Alert;\n\t\t} else {\n\t\t\tfor (let each in DEFAULT_Alert) {\n\t\t\t\tif (this.alert[each]) continue;\n\t\t\t\tthis.alert[each] = DEFAULT_Alert[each];\n\t\t\t}\n\t\t}\n\t\tthis._container = this.dom.appendComponent(WrapperComponent);\n\t}\n\tprivate uniques: any = {};\n\tprivate shortcuts: any = {\n\t\ttl: 'topLeft',\n\t\ttc: 'topCenter',\n\t\ttr: 'topRight',\n\t\tr: 'right',\n\t\tbr: 'bottomRight',\n\t\tbc: 'bottomCenter',\n\t\tbl: 'bottomLeft',\n\t\tl: 'left',\n\t\tc: 'center',\n\t};\n\tprivate positionNumber: any = {\n\t\ttopLeft: 3,\n\t\ttopCenter: 4,\n\t\ttopRight: 2,\n\t\tright: '',\n\t\tbottomRight: 0,\n\t\tbottomCenter: 5,\n\t\tbottomLeft: 1,\n\t\tleft: '',\n\t\tcenter: 6,\n\t};\n\n\tshow(opts: any | Alert) {\n\t\tif (typeof opts === 'string') {\n\t\t\topts = {\n\t\t\t\ttext: opts,\n\t\t\t};\n\t\t}\n\t\tif (!opts) opts = {};\n\t\tif (!opts['type']) opts['type'] = 'info';\n\t\tfor (let each in this.alert) {\n\t\t\tif (each == 'class')\n\t\t\t\topts[each] = opts[each] + ' ' + this.alert[each];\n\t\t\telse if (typeof opts[each] == 'undefined')\n\t\t\t\topts[each] = this.alert[each];\n\t\t}\n\t\tif (this.shortcuts[opts.position])\n\t\t\topts.position = this.shortcuts[opts.position];\n\t\tif (!opts.position) opts.position = 'bottomRight';\n\t\tvar content: any;\n\t\topts.close = () => {\n\t\t\tif (content) content.componentRef.destroy();\n\t\t\topts.component.nativeElement.remove();\n\t\t\tif (typeof (opts as Alert).onClose == 'function')\n\t\t\t\t(opts as Alert).onClose();\n\t\t};\n\t\t// let component = this.dom.appendById(AlertComponent, opts, opts.position);\n\t\tlet customElement = false;\n\n\t\tif (\n\t\t\ttypeof opts.component == 'string' &&\n\t\t\tthis.alert.alerts[opts.component]\n\t\t) {\n\t\t\topts.component = this.alert.alerts[opts.component];\n\t\t\tcustomElement = true;\n\t\t} else {\n\t\t\topts.component = this.dom.appendById(\n\t\t\t\tAlertComponent,\n\t\t\t\topts,\n\t\t\t\topts.position\n\t\t\t);\n\t\t}\n\n\t\tif (typeof opts.component === 'function') {\n\t\t\tcontent = this.dom.appendComponent(\n\t\t\t\topts.component,\n\t\t\t\topts,\n\t\t\t\tthis._container.nativeElement.children[0].children[\n\t\t\t\t\tthis.positionNumber[opts.position] || 0\n\t\t\t\t]\n\t\t\t\t// component.nativeElement.children[0].children[0].children[0] as HTMLElement\n\t\t\t);\n\t\t}\n\n\t\tif (opts.unique) {\n\t\t\tif (this.uniques[opts.unique]) this.uniques[opts.unique].remove();\n\t\t\tthis.uniques[opts.unique] = opts.component.nativeElement;\n\t\t}\n\n\t\tif (typeof opts.timeout !== 'number') {\n\t\t\topts.timeout = 2000;\n\t\t}\n\n\t\tif (opts.timeout) {\n\t\t\tsetTimeout(() => {\n\t\t\t\topts.close();\n\t\t\t}, opts.timeout);\n\t\t}\n\n\t\treturn opts.component.nativeElement;\n\t}\n\n\topen(opts: Alert) {\n\t\tthis.show(opts);\n\t}\n\n\tinfo(opts: Alert) {\n\t\topts['type'] = 'info';\n\t\tthis.show(opts);\n\t}\n\n\tsuccess(opts: Alert) {\n\t\topts['type'] = 'success';\n\t\tthis.show(opts);\n\t}\n\n\twarning(opts: Alert) {\n\t\topts['type'] = 'warning';\n\t\tthis.show(opts);\n\t}\n\n\terror(opts: Alert) {\n\t\topts['type'] = 'error';\n\t\tthis.show(opts);\n\t}\n\n\tquestion(opts: Alert) {\n\t\topts['type'] = 'question';\n\t\tthis.show(opts);\n\t}\n\n\tdestroy() {\n\t\t[\n\t\t\t'bottomRight',\n\t\t\t'bottomLeft',\n\t\t\t'bottomCenter',\n\t\t\t'topRight',\n\t\t\t'topLeft',\n\t\t\t'topCenter',\n\t\t\t'center',\n\t\t].forEach((id) => {\n\t\t\tconst el = document.getElementById(id);\n\n\t\t\tif (el) el.innerHTML = '';\n\t\t});\n\t}\n}\n","import {\n\tInjectable,\n\tInject,\n\tPLATFORM_ID,\n\tSignal,\n\tWritableSignal,\n\tsignal,\n} from '@angular/core';\nimport { Subject, Observable } from 'rxjs';\nimport { Selectitem } from '../interfaces/select.item.interface';\n\n// Add capitalize method to String prototype if it doesn't already exist\nif (!String.prototype.capitalize) {\n\tString.prototype.capitalize = function (): string {\n\t\tif (this.length > 0) {\n\t\t\treturn this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();\n\t\t}\n\t\treturn '';\n\t};\n}\n\n// Extend the String interface to include the new method\ndeclare global {\n\tinterface String {\n\t\tcapitalize(): string;\n\t}\n}\n\n@Injectable({\n\tprovidedIn: 'root',\n})\nexport class CoreService {\n\tdeviceID =\n\t\tlocalStorage.getItem('deviceID') ||\n\t\t(typeof crypto?.randomUUID === 'function'\n\t\t\t? crypto.randomUUID()\n\t\t\t: this.UUID());\n\n\tconstructor(@Inject(PLATFORM_ID) private platformId: boolean) {\n\t\tlocalStorage.setItem('deviceID', this.deviceID);\n\n\t\tthis.detectDevice();\n\t}\n\n\t/**\n\t * Generates a UUID (Universally Unique Identifier) version 4.\n\t *\n\t * This implementation uses `Math.random()` to generate random values,\n\t * making it suitable for general-purpose identifiers, but **not** for\n\t * cryptographic or security-sensitive use cases.\n\t *\n\t * The format follows the UUID v4 standard: `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`\n\t * where:\n\t * - `x` is a random hexadecimal digit (0–f)\n\t * - `4` indicates UUID version 4\n\t * - `y` is one of 8, 9, A, or B\n\t *\n\t * Example: `f47ac10b-58cc-4372-a567-0e02b2c3d479`\n\t *\n\t * @returns A string containing a UUID v4.\n\t */\n\tUUID(): string {\n\t\treturn 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(\n\t\t\t/[xy]/g,\n\t\t\t(c: string) => {\n\t\t\t\tconst r = (Math.random() * 16) | 0;\n\t\t\t\tconst v = c === 'x' ? r : (r & 0x3) | 0x8;\n\t\t\t\treturn v.toString(16);\n\t\t\t}\n\t\t);\n\t}\n\n\t/**\n\t * Converts an object to an array. Optionally holds keys instead of values.\n\t *\n\t * @param {any} obj - The object to be converted.\n\t * @param {boolean} [holder=false] - If true, the keys will be held in the array; otherwise, the values will be held.\n\t * @returns {any[]} The resulting array.\n\t */\n\tota(obj: any, holder: boolean = false): any[] {\n\t\tif (Array.isArray(obj)) return obj;\n\t\tif (typeof obj !== 'object' || obj === null) return [];\n\t\tconst arr = [];\n\t\tfor (const each in obj) {\n\t\t\tif (\n\t\t\t\tobj.hasOwnProperty(each) &&\n\t\t\t\t(obj[each] ||\n\t\t\t\t\ttypeof obj[each] === 'number' ||\n\t\t\t\t\ttypeof obj[each] === 'boolean')\n\t\t\t) {\n\t\t\t\tif (holder) {\n\t\t\t\t\tarr.push(each);\n\t\t\t\t} else {\n\t\t\t\t\tarr.push(obj[each]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn arr;\n\t}\n\n\t/**\n\t * Removes elements from `fromArray` that are present in `removeArray` based on a comparison field.\n\t *\n\t * @param {any[]} removeArray - The array of elements to remove.\n\t * @param {any[]} fromArray - The array from which to remove elements.\n\t * @param {string} [compareField='_id'] - The field to use for comparison.\n\t * @returns {any[]} The modified `fromArray` with elements removed.\n\t */\n\tsplice(\n\t\tremoveArray: any[],\n\t\tfromArray: any[],\n\t\tcompareField: string = '_id'\n\t): any[] {\n\t\tif (!Array.isArray(removeArray) || !Array.isArray(fromArray)) {\n\t\t\treturn fromArray;\n\t\t}\n\n\t\tconst removeSet = new Set(\n\t\t\tremoveArray.map((item) => item[compareField])\n\t\t);\n\t\treturn fromArray.filter((item) => !removeSet.has(item[compareField]));\n\t}\n\n\t/**\n\t * Unites multiple _id values into a single unique _id.\n\t * The resulting _id is unique regardless of the order of the input _id values.\n\t *\n\t * @param {...string[]} args - The _id values to be united.\n\t * @returns {string} The unique combined _id.\n\t */\n\tids2id(...args: string[]): string {\n\t\targs.sort((a, b) => {\n\t\t\tif (\n\t\t\t\tNumber(a.toString().substring(0, 8)) >\n\t\t\t\tNumber(b.toString().substring(0, 8))\n\t\t\t) {\n\t\t\t\treturn 1;\n\t\t\t}\n\t\t\treturn -1;\n\t\t});\n\n\t\treturn args.join();\n\t}\n\n\t// After While\n\tprivate _afterWhile: Record<string, number> = {};\n\t/**\n\t * Delays the execution of a callback function for a specified amount of time.\n\t * If called again within that time, the timer resets.\n\t *\n\t * @param {string | object | (() => void)} doc - A unique identifier for the timer, an object to host the timer, or the callback function.\n\t * @param {() => void} [cb] - The callback function to execute after the delay.\n\t * @param {number} [time=1000] - The delay time in milliseconds.\n\t */\n\tafterWhile(\n\t\tdoc: string | object | (() => void),\n\t\tcb?: () => void,\n\t\ttime: number = 1000\n\t): void {\n\t\tif (typeof doc === 'function') {\n\t\t\tcb = doc as () => void;\n\t\t\tdoc = 'common';\n\t\t}\n\n\t\tif (typeof cb === 'function' && typeof time === 'number') {\n\t\t\tif (typeof doc === 'string') {\n\t\t\t\tclearTimeout(this._afterWhile[doc]);\n\t\t\t\tthis._afterWhile[doc] = window.setTimeout(cb, time);\n\t\t\t} else if (typeof doc === 'object') {\n\t\t\t\tclearTimeout((doc as { __afterWhile: number }).__afterWhile);\n\t\t\t\t(doc as { __afterWhile: number }).__afterWhile =\n\t\t\t\t\twindow.setTimeout(cb, time);\n\t\t\t} else {\n\t\t\t\tconsole.warn('badly configured after while');\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Recursively copies properties from one object to another.\n\t * Handles nested objects, arrays, and Date instances appropriately.\n\t *\n\t * @param from - The source object from which properties are copied.\n\t * @param to - The target object to which properties are copied.\n\t */\n\tcopy(from: any, to: any) {\n\t\tfor (const each in from) {\n\t\t\tif (\n\t\t\t\ttypeof from[each] !== 'object' ||\n\t\t\t\tfrom[each] instanceof Date ||\n\t\t\t\tArray.isArray(from[each]) ||\n\t\t\t\tfrom[each] === null\n\t\t\t) {\n\t\t\t\tto[each] = from[each];\n\t\t\t} else {\n\t\t\t\tif (\n\t\t\t\t\ttypeof to[each] !== 'object' ||\n\t\t\t\t\tto[each] instanceof Date ||\n\t\t\t\t\tArray.isArray(to[each]) ||\n\t\t\t\t\tto[each] === null\n\t\t\t\t) {\n\t\t\t\t\tto[each] = {};\n\t\t\t\t}\n\n\t\t\t\tthis.copy(from[each], to[each]);\n\t\t\t}\n\t\t}\n\t}\n\n\t// Device management\n\tdevice = '';\n\t/**\n\t * Detects the device type based on the user agent.\n\t */\n\tdetectDevice(): void {\n\t\tconst userAgent =\n\t\t\tnavigator.userAgent || navigator.vendor || (window as any).opera;\n\t\tif (/windows phone/i.test(userAgent)) {\n\t\t\tthis.device = 'Windows Phone';\n\t\t} else if (/android/i.test(userAgent)) {\n\t\t\tthis.device = 'Android';\n\t\t} else if (\n\t\t\t/iPad|iPhone|iPod/.test(userAgent) &&\n\t\t\t!(window as any).MSStream\n\t\t) {\n\t\t\tthis.device = 'iOS';\n\t\t} else {\n\t\t\tthis.device = 'Web';\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the device is a mobile device.\n\t * @returns {boolean} - Returns true if the device is a mobile device.\n\t */\n\tisMobile(): boolean {\n\t\treturn (\n\t\t\tthis.device === 'Windows Phone' ||\n\t\t\tthis.device === 'Android' ||\n\t\t\tthis.device === 'iOS'\n\t\t);\n\t}\n\n\t/**\n\t * Checks if the device is a tablet.\n\t * @returns {boolean} - Returns true if the device is a tablet.\n\t */\n\tisTablet(): boolean {\n\t\treturn this.device === 'iOS' && /iPad/.test(navigator.userAgent);\n\t}\n\n\t/**\n\t * Checks if the device is a web browser.\n\t * @returns {boolean} - Returns true if the device is a web browser.\n\t */\n\tisWeb(): boolean {\n\t\treturn this.device === 'Web';\n\t}\n\n\t/**\n\t * Checks if the device is an Android device.\n\t * @returns {boolean} - Returns true if the device is an Android device.\n\t */\n\tisAndroid(): boolean {\n\t\treturn this.device === 'Android';\n\t}\n\n\t/**\n\t * Checks if the device is an iOS device.\n\t * @returns {boolean} - Returns true if the device is an iOS device.\n\t */\n\tisIos(): boolean {\n\t\treturn this.device === 'iOS';\n\t}\n\n\t// Version management\n\tversion = '1.0.0';\n\n\tappVersion = '';\n\n\tdateVersion = '';\n\n\t/**\n\t * Sets the combined version string based on appVersion and dateVersion.\n\t */\n\tsetVersion(): void {\n\t\tthis.version = this.appVersion || '';\n\n\t\tthis.version += this.version && this.dateVersion ? ' ' : '';\n\n\t\tthis.version += this.dateVersion || '';\n\t}\n\n\t/**\n\t * Sets the app version and updates the combined version string.\n\t *\n\t * @param {string} appVersion - The application version to set.\n\t */\n\tsetAppVersion(appVersion: string): void {\n\t\tthis.appVersion = appVersion;\n\n\t\tthis.setVersion();\n\t}\n\n\t/**\n\t * Sets the date version and updates the combined version string.\n\t *\n\t * @param {string} dateVersion - The date version to set.\n\t */\n\tsetDateVersion(dateVersion: string): void {\n\t\tthis.dateVersion = dateVersion;\n\n\t\tthis.setVersion();\n\t}\n\n\t// Signal management\n\tprivate _signals: Record<string, Subject<any>> = {};\n\n\t/**\n\t * Emits a signal, optionally passing data to the listeners.\n\t * @param signal - The name of the signal to emit.\n\t * @param data - Optional data to pass to the listeners.\n\t */\n\temit(signal: string, data?: any): void {\n\t\tif (!this._signals[signal]) {\n\t\t\tthis._signals[signal] = new Subject<any>();\n\t\t}\n\n\t\tthis._signals[signal].next(data);\n\t}\n\n\t/**\n\t * Returns an Observable that emits values when the specified signal is emitted.\n\t * Multiple components or services can subscribe to this Observable to be notified of the signal.\n\t * @param signal - The name of the signal to listen for.\n\t * @returns An Observable that emits when the signal is emitted.\n\t */\n\ton(signal: string): Observable<any> {\n\t\tif (!this._signals[signal]) {\n\t\t\tthis._signals[signal] = new Subject<any>();\n\t\t}\n\n\t\treturn this._signals[signal].asObservable();\n\t}\n\n\t/**\n\t * Completes the Subject for a specific signal, effectively stopping any future emissions.\n\t * This also unsubscribes all listeners for the signal.\n\t * @param signal - The name of the signal to stop.\n\t */\n\toff(signal: string): void {\n\t\tif (!this._signals[signal]) return;\n\t\tthis._signals[signal].complete();\n\t\tdelete this._signals[signal];\n\t}\n\n\t// Await management\n\tprivate _completed: Record<string, unknown> = {};\n\n\tprivate _completeResolvers: Record<string, ((doc: unknown) => void)[]> = {};\n\n\t/**\n\t * Marks a task as complete.\n\t * @param task - The task to mark as complete, identified by a string.\n\t */\n\tcomplete(task: string, document: unknown = true): void {\n\t\tthis._completed[task] = document;\n\n\t\tif (this._completeResolvers[task]) {\n\t\t\tthis._completeResolvers[task].forEach((resolve) =>\n\t\t\t\tresolve(document)\n\t\t\t);\n\n\t\t\tthis._completeResolvers[task] = [];\n\t\t}\n\t}\n\n\t/**\n\t * Waits for one or more tasks to be marked as complete.\n\t *\n\t * @param {string | string[]} tasks - The task or array of tasks to wait for.\n\t * @returns {Promise<unknown>} A promise that resolves when all specified tasks are complete.\n\t * - If a single task is provided, resolves with its completion result.\n\t * - If multiple tasks are provided, resolves with an array of results in the same order.\n\t *\n\t * @remarks\n\t * If any task is not yet completed, a resolver is attached. The developer is responsible for managing\n\t * resolver cleanup if needed. Resolvers remain after resolution and are not removed automatically.\n\t */\n\tonComplete(tasks: string | string[]): Promise<unknown> {\n\t\tif (typeof tasks === 'string') {\n\t\t\ttasks = [tasks];\n\t\t}\n\n\t\tif (this._isCompleted(tasks)) {\n\t\t\treturn Promise.resolve(\n\t\t\t\ttasks.length > 1\n\t\t\t\t\t? tasks.map((task) => this._completed[task])\n\t\t\t\t\t: this._completed[tasks[0]]\n\t\t\t);\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tfor (const task of tasks) {\n\t\t\t\tif (!this._completeResolvers[task]) {\n\t\t\t\t\tthis._completeResolvers[task] = [];\n\t\t\t\t}\n\n\t\t\t\tthis._completeResolvers[task].push(\n\t\t\t\t\tthis._allCompleted(tasks, resolve)\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Returns a resolver function that checks if all given tasks are completed,\n\t * and if so, calls the provided resolve function with their results.\n\t *\n\t * @param {string[]} tasks - The list of task names to monitor for completion.\n\t * @param {(value: unknown) => void} resolve - The resolver function to call once all tasks are complete.\n\t * @returns {(doc: unknown) => void} A function that can be registered as a resolver for each task.\n\t *\n\t * @remarks\n\t * This function does not manage or clean up resolvers. It assumes the developer handles any potential duplicates or memory concerns.\n\t */\n\tprivate _allCompleted(\n\t\ttasks: string[],\n\t\tresolve: (value: unknown) => void\n\t): (doc: unknown) => void {\n\t\treturn (doc: unknown) => {\n\t\t\tif (this._isCompleted(tasks)) {\n\t\t\t\tresolve(\n\t\t\t\t\ttasks.length > 1\n\t\t\t\t\t\t? tasks.map((task) => this._completed[task])\n\t\t\t\t\t\t: this._completed[tasks[0]]\n\t\t\t\t);\n\t\t\t}\n\t\t};\n\t}\n\n\t/**\n\t * Checks whether all specified tasks have been marked as completed.\n\t *\n\t * @param {string[]} tasks - The array of task names to check.\n\t * @returns {boolean} `true` if all tasks are completed, otherwise `false`.\n\t */\n\tprivate _isCompleted(tasks: string[]): boolean {\n\t\tfor (const task of tasks) {\n\t\t\tif (!this._completed[task]) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Checks if a task is completed.\n\t * @param task - The task to check, identified by a string.\n\t * @returns True if the task is completed, false otherwise.\n\t */\n\tcompleted(task: string): unknown {\n\t\treturn this._completed[task];\n\t}\n\n\t/**\n\t * Clears the completed state for a specific task.\n\t *\n\t * This removes the task from the internal `_completed` store,\n\t * allowing it to be awaited again in the future if needed.\n\t * It does not affect pending resolvers or trigger any callbacks.\n\t *\n\t * @param task - The task identifier to clear from completed state.\n\t */\n\tclearCompleted(task: string) {\n\t\tdelete this._completed[task];\n\t}\n\n\t// Locking management\n\tprivate _locked: Record<string, boolean> = {};\n\tprivate _unlockResolvers: Record<string, (() => void)[]> = {};\n\n\t/**\n\t * Locks a resource to prevent concurrent access.\n\t * @param which - The resource to lock, identified by a string.\n\t */\n\tlock(which: string): void {\n\t\tthis._locked[which] = true;\n\n\t\tif (!this._unlockResolvers[which]) {\n\t\t\tthis._unlockResolvers[which] = [];\n\t\t}\n\t}\n\n\t/**\n\t * Unlocks a resource, allowing access.\n\t * @param which - The resource to unlock, identified by a string.\n\t */\n\tunlock(which: string): void {\n\t\tthis._locked[which] = false;\n\n\t\tif (this._unlockResolvers[which]) {\n\t\t\tthis._unlockResolvers[which].forEach((resolve) => resolve());\n\n\t\t\tthis._unlockResolvers[which] = [];\n\t\t}\n\t}\n\n\t/**\n\t * Returns a Promise that resolves when the specified resource is unlocked.\n\t * @param which - The resource to watch for unlocking, identified by a string.\n\t * @returns A Promise that resolves when the resource is unlocked.\n\t */\n\tonUnlock(which: string): Promise<void> {\n\t\tif (!this._locked[which]) {\n\t\t\treturn Promise.resolve();\n\t\t}\n\n\t\treturn new Promise((resolve) => {\n\t\t\tif (!this._unlockResolvers[which]) {\n\t\t\t\tthis._unlockResolvers[which] = [];\n\t\t\t}\n\n\t\t\tthis._unlockResolvers[which].push(resolve);\n\t\t});\n\t}\n\n\t/**\n\t * Checks if a resource is locked.\n\t * @param which - The resource to check, identified by a string.\n\t * @returns True if the resource is locked, false otherwise.\n\t */\n\tlocked(which: string): boolean {\n\t\treturn !!this._locked[which];\n\t}\n\n\t// Linking management\n\tlinkCollections: string[] = [];\n\tlinkRealCollectionName: Record<string, string> = {};\n\tlinkIds: Record<string, Selectitem[]> = {};\n\n\taddLink(name: string, reset: () => Selectitem[], realName = ''): void {\n\t\tthis.linkCollections.push(name);\n\n\t\tthis.linkRealCollectionName[name] = realName || name;\n\n\t\tthis.onComplete(name.toLowerCase() + '_loaded').then(() => {\n\t\t\tthis.linkIds[name] = reset();\n\t\t});\n\n\t\tthis.on(name.toLowerCase() + '_changed').subscribe(() => {\n\t\t\tthis.linkIds[name].splice(0, this.linkIds[name].length);\n\n\t\t\tthis.linkIds[name].push(...reset());\n\t\t});\n\t}\n\n\t// Angular Signals //\n\t/**\n\t * Converts a plain object into a signal-wrapped object.\n\t * Optionally wraps specific fields of the object as individual signals,\n\t * and merges them into the returned signal for fine-grained reactivity.\n\t *\n\t * @template Document - The type of the object being wrapped.\n\t * @param {Document} document - The plain object to wrap into a signal.\n\t * @param {Record<string, (doc: Document) => unknown>} [signalFields={}] -\n\t * Optional map where each key is a field name and the value is a function\n\t * to extract the initial value for that field. These fields will be wrapped\n\t * as separate signals and embedded in the returned object.\n\t *\n\t * @returns {Signal<Document>} A signal-wrapped object, possibly containing\n\t * nested field signals for more granular control.\n\t *\n\t * @example\n\t * const user = { _id: '1', name: 'Alice', score: 42 };\n\t * const sig = toSignal(user, { score: (u) => u.score });\n\t * console.log(sig().name); // 'Alice'\n\t * console.log(sig().score()); // 42 — field is now a signal\n\t */\n\ttoSignal<Document>(\n\t\tdocument: Document,\n\t\tsignalFields: Record<string, (doc: Document) => unknown> = {}\n\t): Signal<Document> {\n\t\tif (Object.keys(signalFields).length) {\n\t\t\tconst fields: Record<string, Signal<unknown>> = {};\n\n\t\t\tfor (const key in signalFields) {\n\t\t\t\tfields[key] = signal(signalFields[key](document));\n\t\t\t}\n\n\t\t\treturn signal({ ...document, ...fields });\n\t\t} else {\n\t\t\treturn signal(document);\n\t\t}\n\t}\n\n\t/**\n\t * Converts an array of objects into an array of Angular signals.\n\t * Optionally wraps specific fields of each object as individual signals.\n\t *\n\t * @template Document - The type of each object in the array.\n\t * @param {Document[]} arr - Array of plain objects to convert into signals.\n\t * @param {Record<string, (doc: Document) => unknown>} [signalFields={}] -\n\t * Optional map where keys are field names and values are functions that extract the initial value\n\t * from the object. These fields will be turned into separate signals.\n\t *\n\t * @returns {Signal<Document>[]} An array where each item is a signal-wrapped object,\n\t * optionally with individual fields also wrapped in signals.\n\t *\n\t * @example\n\t * toSignalsArray(users, {\n\t * name: (u) => u.name,\n\t * score: (u) => u.score,\n\t * });\n\t */\n\ttoSignalsArray<Document>(\n\t\tarr: Document[],\n\t\tsignalFields: Record<string, (doc: Document) => unknown> = {}\n\t): Signal<Document>[] {\n\t\treturn arr.map((obj) => this.toSignal(obj, signalFields));\n\t}\n\n\t/**\n\t * Adds a new object to the signals array.\n\t * Optionally wraps specific fields of the object as individual signals before wrapping the whole object.\n\t *\n\t * @template Document - The type of the object being added.\n\t * @param {Signal<Document>[]} signals - The signals array to append to.\n\t * @param {Document} item - The object to wrap and push as a signal.\n\t * @param {Record<string, (doc: Document) => unknown>} [signalFields={}] -\n\t * Optional map of fields to be wrapped as signals within the object.\n\t *\n\t * @returns {void}\n\t */\n\tpushSignal<Document>(\n\t\tsignals: Signal<Document>[],\n\t\titem: Document,\n\t\tsignalFields: Record<string, (doc: Document) => unknown> = {}\n\t): void {\n\t\tsignals.push(this.toSignal(item, signalFields));\n\t}\n\n\t/**\n\t * Removes the first signal from the array whose object's field matches the provided value.\n\t * @template Document\n\t * @param {WritableSignal<Document>[]} signals - The signals array to modify.\n\t * @param {unknown} value - The value to match.\n\t * @param {string} [field='_id'] - The object field to match against.\n\t * @returns {void}\n\t */\n\tremoveSignalByField<Document extends Record<string, unknown>>(\n\t\tsignals: WritableSignal<Document>[],\n\t\tvalue: unknown,\n\t\tfield: string = '_id'\n\t): void {\n\t\tconst idx = signals.findIndex((sig) => sig()[field] === value);\n\n\t\tif (idx > -1) signals.splice(idx, 1);\n\t}\n\n\t/**\n\t * Returns a generic trackBy function for *ngFor, tracking by the specified object field.\n\t * @template Document\n\t * @param {string} field - The object field to use for tracking (e.g., '_id').\n\t * @returns {(index: number, sig: Signal<Document>) => unknown} TrackBy function for Angular.\n\t */\n\ttrackBySignalField<Document extends Record<string, unknown>>(\n\t\tfield: string\n\t) {\n\t\treturn (_: number, sig: Signal<Document>) => sig()[field];\n\t}\n\n\t/**\n\t * Finds the first signal in the array whose object's field matches the provided value.\n\t * @template Document\n\t * @param {Signal<Document>[]} signals - Array of signals to search.\n\t * @param {unknown} value - The value to match.\n\t * @param {string} [field='_id'] - The object field to match against.\n\t * @returns {Signal<Document> | undefined} The found signal or undefined if not found.\n\t */\n\tfindSignalByField<Document extends Record<string, unknown>>(\n\t\tsignals: Signal<Document>[],\n\t\tvalue: unkno