@tilde-nlp/ngx-common 8.1.42 → 8.1.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, EventEmitter, Component, Input, ViewChild, Output, NgModule, Optional, Inject, Pipe, inject, Directive, HostListener, HostBinding, ViewChildren, input, effect, ElementRef, ContentChild, ContentChildren, InjectionToken, signal, output, computed, makeEnvironmentProviders, provideAppInitializer } from '@angular/core';
2
+ import { Injectable, EventEmitter, Component, Input, ViewChild, Output, NgModule, Optional, Inject, Pipe, inject, Directive, HostListener, HostBinding, ViewChildren, input, effect, ElementRef, ContentChild, ContentChildren, InjectionToken, signal, output, computed, makeEnvironmentProviders } from '@angular/core';
3
3
  import * as i2 from '@angular/material/icon';
4
4
  import { MatIconModule, MatIcon } from '@angular/material/icon';
5
5
  import * as i2$1 from '@angular/platform-browser';
6
6
  import { Title } from '@angular/platform-browser';
7
- import { Subject, map, Observable, of, take, BehaviorSubject, tap, forkJoin, takeUntil, finalize, catchError, fromEvent, debounceTime, ReplaySubject, filter, first } from 'rxjs';
7
+ import { Subject, map, Observable, of, take, BehaviorSubject, tap, forkJoin, takeUntil, finalize, catchError, fromEvent, debounceTime } from 'rxjs';
8
8
  import * as i1$1 from '@angular/common';
9
9
  import { CommonModule, TitleCasePipe, AsyncPipe, DatePipe } from '@angular/common';
10
10
  import { FlexLayoutModule } from '@ngbracket/ngx-layout';
@@ -1913,7 +1913,7 @@ function InlineMessageComponent_span_1_Template(rf, ctx) { if (rf & 1) {
1913
1913
  i0.ɵɵclassProp("order-end", ctx_r0.message.iconPosition === ctx_r0.END_ICON_POSITION);
1914
1914
  i0.ɵɵproperty("matTooltip", ctx_r0.message.iconTooltip ? i0.ɵɵpipeBind2(1, 4, ctx_r0.message.iconTooltip, ctx_r0.message.localizationParams) : "");
1915
1915
  i0.ɵɵadvance(2);
1916
- i0.ɵɵtextInterpolate(ctx_r0.iconName);
1916
+ i0.ɵɵtextInterpolate(ctx_r0.message.icon || ctx_r0.iconName);
1917
1917
  } }
1918
1918
  function InlineMessageComponent_section_2_div_1_Template(rf, ctx) { if (rf & 1) {
1919
1919
  i0.ɵɵelement(0, "div", 5);
@@ -1953,14 +1953,14 @@ class InlineMessageComponent {
1953
1953
  } if (rf & 2) {
1954
1954
  i0.ɵɵclassMap(i0.ɵɵinterpolate1("tld-inline-message ", ctx.message.type));
1955
1955
  i0.ɵɵadvance();
1956
- i0.ɵɵproperty("ngIf", ctx.iconName);
1956
+ i0.ɵɵproperty("ngIf", ctx.message.icon || ctx.iconName);
1957
1957
  i0.ɵɵadvance();
1958
1958
  i0.ɵɵproperty("ngIf", ctx.message);
1959
- } }, dependencies: [i1$1.NgIf, i2$3.MatTooltip, i1.TranslatePipe], styles: ["[_nghost-%COMP%]{display:block}.tld-inline-message[_ngcontent-%COMP%]{display:flex;flex-direction:row}.tld-inline-message.error[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{color:var(--error-dark)}.tld-inline-message.info[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{color:var(--base-40)}.tld-inline-message.warning[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{color:var(--warning-dark)}.tld-inline-message[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{font-size:16px;margin-right:.5rem;display:inline-block}.tld-inline-message[_ngcontent-%COMP%] .material-icons.order-end[_ngcontent-%COMP%]{order:2}.tld-inline-message[_ngcontent-%COMP%] .title[_ngcontent-%COMP%], .tld-inline-message[_ngcontent-%COMP%] .description[_ngcontent-%COMP%]{margin:0}.tld-inline-message[_ngcontent-%COMP%] .title[_ngcontent-%COMP%] + .description[_ngcontent-%COMP%]{margin-top:.5rem}"] }); }
1959
+ } }, dependencies: [i1$1.NgIf, i2$3.MatTooltip, i1.TranslatePipe], styles: ["[_nghost-%COMP%]{display:block}.tld-inline-message[_ngcontent-%COMP%]{display:flex;flex-direction:row;align-items:center}.tld-inline-message.error[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{color:var(--error-dark)}.tld-inline-message.info[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{color:var(--base-40)}.tld-inline-message.warning[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{color:var(--warning-dark)}.tld-inline-message.success[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%], .tld-inline-message.success[_ngcontent-%COMP%]{color:var(--success-dark)}.tld-inline-message[_ngcontent-%COMP%] .material-icons[_ngcontent-%COMP%]{font-size:16px;margin-right:.5rem;display:inline-block}.tld-inline-message[_ngcontent-%COMP%] .material-icons.order-end[_ngcontent-%COMP%]{order:2}.tld-inline-message[_ngcontent-%COMP%] .title[_ngcontent-%COMP%], .tld-inline-message[_ngcontent-%COMP%] .description[_ngcontent-%COMP%]{margin:0}.tld-inline-message[_ngcontent-%COMP%] .title[_ngcontent-%COMP%] + .description[_ngcontent-%COMP%]{margin-top:.5rem}"] }); }
1960
1960
  }
1961
1961
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(InlineMessageComponent, [{
1962
1962
  type: Component,
1963
- args: [{ selector: 'lib-inline-message', standalone: false, template: "<div class=\"tld-inline-message {{message.type}}\">\r\n <span class=\"material-icons\" [class.order-end]=\"message.iconPosition === END_ICON_POSITION\"\r\n [matTooltip]=\"message.iconTooltip? (message.iconTooltip | translate: message.localizationParams) : ''\" *ngIf=\"iconName\">{{iconName}}</span>\r\n <section *ngIf=\"message\">\r\n <div class=\"text-s-semi-bold title\" *ngIf=\"message.title\"\r\n [innerHtml]=\"message.title | translate: message.localizationParams\">\r\n </div>\r\n <p class=\"text-s description\" *ngIf=\"message.description\" [innerHtml]=\"message.description | translate:\r\n message.localizationParams\"></p>\r\n </section>\r\n</div>", styles: [":host{display:block}.tld-inline-message{display:flex;flex-direction:row}.tld-inline-message.error .material-icons{color:var(--error-dark)}.tld-inline-message.info .material-icons{color:var(--base-40)}.tld-inline-message.warning .material-icons{color:var(--warning-dark)}.tld-inline-message .material-icons{font-size:16px;margin-right:.5rem;display:inline-block}.tld-inline-message .material-icons.order-end{order:2}.tld-inline-message .title,.tld-inline-message .description{margin:0}.tld-inline-message .title+.description{margin-top:.5rem}\n"] }]
1963
+ args: [{ selector: 'lib-inline-message', standalone: false, template: "<div class=\"tld-inline-message {{message.type}}\">\r\n <span class=\"material-icons\" [class.order-end]=\"message.iconPosition === END_ICON_POSITION\"\r\n [matTooltip]=\"message.iconTooltip? (message.iconTooltip | translate: message.localizationParams) : ''\" *ngIf=\"message.icon || iconName\">{{ message.icon || iconName }}</span>\r\n <section *ngIf=\"message\">\r\n <div class=\"text-s-semi-bold title\" *ngIf=\"message.title\"\r\n [innerHtml]=\"message.title | translate: message.localizationParams\">\r\n </div>\r\n <p class=\"text-s description\" *ngIf=\"message.description\" [innerHtml]=\"message.description | translate:\r\n message.localizationParams\"></p>\r\n </section>\r\n</div>", styles: [":host{display:block}.tld-inline-message{display:flex;flex-direction:row;align-items:center}.tld-inline-message.error .material-icons{color:var(--error-dark)}.tld-inline-message.info .material-icons{color:var(--base-40)}.tld-inline-message.warning .material-icons{color:var(--warning-dark)}.tld-inline-message.success .material-icons,.tld-inline-message.success{color:var(--success-dark)}.tld-inline-message .material-icons{font-size:16px;margin-right:.5rem;display:inline-block}.tld-inline-message .material-icons.order-end{order:2}.tld-inline-message .title,.tld-inline-message .description{margin:0}.tld-inline-message .title+.description{margin-top:.5rem}\n"] }]
1964
1964
  }], null, { iconName: [{
1965
1965
  type: Input
1966
1966
  }], message: [{
@@ -2000,6 +2000,7 @@ var InlineMessageType;
2000
2000
  InlineMessageType["INFO"] = "info";
2001
2001
  InlineMessageType["WARNING"] = "warning";
2002
2002
  InlineMessageType["ERROR"] = "error";
2003
+ InlineMessageType["SUCCESS"] = "success";
2003
2004
  })(InlineMessageType || (InlineMessageType = {}));
2004
2005
 
2005
2006
  class ClickOutsideDirective {
@@ -2947,7 +2948,7 @@ class ExtensionDialogModule {
2947
2948
  MatIconModule,
2948
2949
  CloseButtonModule], exports: [OpenExtensionDialogComponent] }); })();
2949
2950
 
2950
- const FILE_UPLOAD_ICON = `<svg width="23" height="22" viewBox="0 0 23 22" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19.4999 15V19H3.49992V15H0.833252V19C0.833252 20.4666 2.03325 21.6666 3.49992 21.6666H19.4999C20.9666 21.6666 22.1666 20.4666 22.1666 19V15H19.4999ZM4.83325 6.99998L6.71325 8.87998L10.1666 5.43998V16.3333H12.8333V5.43998L16.2866 8.87998L18.1666 6.99998L11.4999 0.333313L4.83325 6.99998Z" fill="black"/></svg>`;
2951
+ const FILE_UPLOAD_ICON = `<svg width="23" height="22" viewBox="0 0 23 22" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M19.4999 15V19H3.49992V15H0.833252V19C0.833252 20.4666 2.03325 21.6666 3.49992 21.6666H19.4999C20.9666 21.6666 22.1666 20.4666 22.1666 19V15H19.4999ZM4.83325 6.99998L6.71325 8.87998L10.1666 5.43998V16.3333H12.8333V5.43998L16.2866 8.87998L18.1666 6.99998L11.4999 0.333313L4.83325 6.99998Z" fill="currentColor"/></svg>`;
2951
2952
 
2952
2953
  const _c0$b = ["fileInput"];
2953
2954
  const _c1$5 = ["*", [["", "customLimits", ""]]];
@@ -4416,7 +4417,7 @@ class MultiFunctionalTableComponent {
4416
4417
  }], tableElementRef: [{
4417
4418
  type: ViewChild,
4418
4419
  args: [MatTable, { read: ElementRef }]
4419
- }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: false }] }] }); })();
4420
+ }] }); })();
4420
4421
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MultiFunctionalTableComponent, { className: "MultiFunctionalTableComponent", filePath: "lib/multi-functional-table/multi-functional-table.component.ts", lineNumber: 27 }); })();
4421
4422
 
4422
4423
  class StatusDisplayModule {
@@ -8519,7 +8520,7 @@ class SubscriptionComponent {
8519
8520
  CommonModule,
8520
8521
  MatButtonModule
8521
8522
  ], template: "@if(token()){\r\n <!-- narrow type to non null property -->\r\n @let userToken = token()!;\r\n\r\n <h3 class=\"subscription-section-title text-l-semi-bold\">{{ \"SUBSCRIPTION.USER_INFO\" | translate }}</h3>\r\n\r\n <div class=\"subscription-data-row\">\r\n <div class=\"subscription-label\">\r\n <span class=\"label\">{{ \"SUBSCRIPTION.LABEL_NAME\" | translate }}</span>\r\n </div>\r\n\r\n <div class=\"subscription-data\">\r\n <span>{{ userToken.name }}</span>\r\n </div>\r\n </div>\r\n\r\n <div class=\"subscription-data-row\">\r\n <div class=\"subscription-label\">\r\n <span class=\"label\">{{ \"SUBSCRIPTION.LABEL_EMAIL\" | translate }}</span>\r\n </div>\r\n\r\n <div class=\"subscription-data\">\r\n <span>{{ userToken.email }}</span>\r\n </div>\r\n </div>\r\n}\r\n\r\n@if(subscription()){\r\n @let currentSubscription = subscription()!;\r\n\r\n <div fxLayout=\"row\" class=\"subscription-data-row\">\r\n <div class=\"subscription-label\">\r\n <span class=\"label\">{{ \"SUBSCRIPTION.LABEL_SUBSCRIPTION_PLAN_ID\" | translate }}</span>\r\n </div>\r\n\r\n <div class=\"subscription-data\">\r\n <ng-container>\r\n <span>\r\n {{ currentSubscription.Label ? currentSubscription.Label : currentSubscription.PlanId }}\r\n\r\n @switch (subscriptionState()) {\r\n @case(subscriptionStates.TRIAL){\r\n <span> ({{ \"SUBSCRIPTION.TRIAL_END_DATE\" | translate: { date: currentSubscription.EndDate | date: \"dd.MM.yyyy.\" } }}) </span>\r\n }\r\n @case (subscriptionStates.ACTIVE) {\r\n @if(currentSubscription.EndDate){\r\n <span> ({{ \"SUBSCRIPTION.END_DATE\" | translate: { date: currentSubscription.EndDate | date: \"dd.MM.yyyy.\" } }}) </span>\r\n }\r\n }\r\n @case (subscriptionStates.ENDED) {\r\n ({{ \"SUBSCRIPTION.END_DATE\" | translate: { date: currentSubscription.EndDate | date: \"dd.MM.yyyy.\" } }})\r\n }\r\n }\r\n </span>\r\n </ng-container>\r\n </div>\r\n </div>\r\n\r\n @if(currentSubscription.EndDate){\r\n <div class=\"subscription-data-row\">\r\n <div class=\"subscription-label\">\r\n <span class=\"label\">{{ \"SUBSCRIPTION.LABEL_SUBSCRIPTION_END_DATE\" | translate }}</span>\r\n </div>\r\n\r\n <div class=\"subscription-data\">\r\n <ng-container>\r\n <span>{{currentSubscription.EndDate | date: \"dd.MM.yyyy\"}}</span>\r\n </ng-container>\r\n </div>\r\n </div>\r\n }\r\n\r\n @if(currentSubscription.Addons?.length){\r\n <div fxLayout=\"row\" class=\"subscription-data-row\">\r\n <div class=\"subscription-label\">\r\n <span class=\"label\">{{ \"SUBSCRIPTION.ADDITIONS_PLUGINS\" | translate }}</span>\r\n </div>\r\n\r\n <div class=\"subscription-data\">\r\n @for (item of currentSubscription.Addons; track $index; let i = $index) {\r\n <span>{{ item.id }}</span>\r\n @if(item.qt>1){\r\n <span> ({{item.qt}})</span>\r\n }\r\n <span> {{ currentSubscription.Addons!.length - 1 > i ? \",\" : \"\" }} </span>\r\n }\r\n </div>\r\n </div>\r\n }\r\n}\r\n\r\n@if(visibleQuotas().length){\r\n <h3 class=\"subscription-section-title text-l-semi-bold\">{{ \"SUBSCRIPTION.LIMITS\" | translate }}</h3>\r\n\r\n @for (currentQuota of visibleQuotas(); track $index) {\r\n <div class=\"subscription-limit-wrapper\">\r\n <mat-progress-bar [value]=\"currentQuota.percentUsed\"></mat-progress-bar>\r\n <div class=\"subscription-limit\">\r\n <span class=\"text-l-semi-bold\">\r\n {{ (\"QUOTA.\" + (currentQuota.quotaType.toString() | uppercase) + (currentQuota.isUnlimited? \"_UNLIMITED\": \"\")) | translate: { used: currentQuota.convertedUsed, limit: currentQuota.convertedLimit, percent: currentQuota.percentUsed} }}\r\n </span>\r\n </div>\r\n </div>\r\n }\r\n}\r\n\r\n<!-- Add some extra info, such as disclaimer etc -->\r\n <ng-content></ng-content>\r\n\r\n<div class=\"subscription-actions-wrapper\">\r\n @if(chargebeeSettings()){\r\n <a mat-flat-button color=\"accent\" class=\"manage-sub-btn button-row-element\" href=\"javascript:void(0)\" data-cb-type=\"portal\" (click)=\"manageClicked()\">\r\n {{ \"SUBSCRIPTION.MANAGE\" | translate }}\r\n </a>\r\n }\r\n @if(contactUsUrl()){\r\n <a mat-stroked-button [attr.href]=\"contactUsUrl()\" target=\"_blank\" color=\"accent\" (click)=\"contactUsClicked()\">{{\"SUBSCRIPTION.CONTACT\" | translate}}</a>\r\n }\r\n</div>\r\n", styles: [":host{display:block}mat-card{margin:1.5rem}.subscription-container:not(.mobile){margin:16px 32px}.subscription-section-title{margin:32px 0 18px}.subscription-data-row{border-bottom:2px solid var(--base-70);margin-bottom:18px;flex-direction:row;display:flex}.subscription-data{color:var(--base-30);word-wrap:break-word;margin-left:.5rem}.subscription-limit-wrapper,.subscription-limit{margin-top:16px}.subscription-actions-wrapper{padding:32px 0 18px;display:flex;flex-direction:row;gap:24px}.subscription-manage-link{text-decoration:none}.subscription-container:not(.mobile,.empty){width:75%}.subscription-label:not(.mobile,.empty){width:35%}.subscription-data:not(.mobile,.empty){width:65%}.untranslated-files-disclaimer{margin-top:16px;margin-bottom:10px;color:var(--base-40)}.no-subscription-message{margin-top:32px;color:var(--base-40)}.contact-sales-btn{text-align:center}.contact-sales-btn:hover{text-decoration:none}\n"] }]
8522
- }], null, { token: [{ type: i0.Input, args: [{ isSignal: true, alias: "token", required: true }] }], subscription: [{ type: i0.Input, args: [{ isSignal: true, alias: "subscription", required: true }] }], quota: [{ type: i0.Input, args: [{ isSignal: true, alias: "quota", required: true }] }], visibleQuotaTypes: [{ type: i0.Input, args: [{ isSignal: true, alias: "visibleQuotaTypes", required: false }] }], contactUsUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "contactUsUrl", required: false }] }], chargebeeSettings: [{ type: i0.Input, args: [{ isSignal: true, alias: "chargebeeSettings", required: false }] }], manageClick: [{ type: i0.Output, args: ["manageClick"] }], contactUsClick: [{ type: i0.Output, args: ["contactUsClick"] }] }); })();
8523
+ }], null, null); })();
8523
8524
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SubscriptionComponent, { className: "SubscriptionComponent", filePath: "lib/subscription/subscription.component.ts", lineNumber: 26 }); })();
8524
8525
 
8525
8526
  var AccessibilityFontSizes;
@@ -9459,14 +9460,22 @@ class CookieConsentComponent {
9459
9460
  this.destroy.complete();
9460
9461
  }
9461
9462
  resolveInitialConsentState() {
9462
- this.isCookieConsentConfigured()
9463
- .pipe(tap((isConfigured) => {
9464
- if (isConfigured) {
9465
- this.isClosed = true;
9466
- return;
9467
- }
9468
- this.setupTranslations();
9469
- })).subscribe();
9463
+ const configured = this.isCookieConsentConfigured();
9464
+ if (this.isPromise(configured)) {
9465
+ configured.then((isConfigured) => {
9466
+ if (isConfigured) {
9467
+ this.isClosed = true;
9468
+ return;
9469
+ }
9470
+ this.setupTranslations();
9471
+ });
9472
+ return;
9473
+ }
9474
+ if (configured) {
9475
+ this.isClosed = true;
9476
+ return;
9477
+ }
9478
+ this.setupTranslations();
9470
9479
  }
9471
9480
  injectConsentScript() {
9472
9481
  if (!this.script || typeof document === 'undefined') {
@@ -9493,19 +9502,24 @@ class CookieConsentComponent {
9493
9502
  return translations[key] ? key : 'en';
9494
9503
  }
9495
9504
  isCookieConsentConfigured() {
9496
- if (!this.#storage) {
9497
- return of(false);
9505
+ const snapshot = this.#storage?.snapshot();
9506
+ if (snapshot) {
9507
+ return this.applyStoredConsent(snapshot);
9498
9508
  }
9499
- return this.#storage?.read().pipe(map((config) => {
9500
- return this.hasUserHandledConsent(config ?? null);
9501
- }));
9509
+ const stored = this.#storage?.read();
9510
+ if (this.isPromise(stored)) {
9511
+ return stored.then((config) => this.applyStoredConsent(config));
9512
+ }
9513
+ return this.applyStoredConsent(stored ?? null);
9502
9514
  }
9503
- hasUserHandledConsent(config) {
9515
+ applyStoredConsent(config) {
9504
9516
  const consent = config?.cookieConsent;
9505
9517
  if (!consent?.updatedAt) {
9506
9518
  return false;
9507
9519
  }
9508
- this.#analytics.cookieConsentGiven(true);
9520
+ if (consent.accepted) {
9521
+ this.#analytics.cookieConsentGiven(true);
9522
+ }
9509
9523
  return true;
9510
9524
  }
9511
9525
  persistConsent(accepted) {
@@ -9518,7 +9532,10 @@ class CookieConsentComponent {
9518
9532
  accepted,
9519
9533
  updatedAt: now,
9520
9534
  },
9521
- }).subscribe();
9535
+ });
9536
+ }
9537
+ isPromise(value) {
9538
+ return !!value && typeof value.then === 'function';
9522
9539
  }
9523
9540
  static { this.ɵfac = function CookieConsentComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CookieConsentComponent)(); }; }
9524
9541
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CookieConsentComponent, selectors: [["lib-cookie-consent"]], inputs: { script: "script", privacyPolicyUrl: "privacyPolicyUrl" }, decls: 1, vars: 1, consts: [[1, "cookie-consent-container"], [1, "cookie-consent-content"], [1, "cookie-consent-description", 3, "innerHTML"], [1, "cookie-consent-actions"], ["mat-flat-button", "", 3, "click"], ["mat-stroked-button", "", 3, "click"], [1, "cookie-consent-info"], [1, "cookie-consent-info--privacy", 3, "href"], [1, "cookie-consent-info--details", 3, "click"], [1, "spin"], [1, "cookie-consent--details"]], template: function CookieConsentComponent_Template(rf, ctx) { if (rf & 1) {
@@ -9582,132 +9599,134 @@ const USER_CONFIG_MESSAGE_UPDATE = 'ngx-user-config:update';
9582
9599
  const DEFAULT_USER_CONFIG_OPTIONS = {
9583
9600
  strategy: UserConfigStrategy.Local,
9584
9601
  iframeUrl: DEFAULT_USER_CONFIG_IFRAME_URL,
9585
- defaultConfig: DEFAULT_USER_CONFIG
9586
9602
  };
9587
9603
 
9588
- const USER_CONFIG_OPTIONS = new InjectionToken('USER_CONFIG_OPTIONS');
9604
+ const USER_CONFIG_STORAGE_KEY = 'ngx_common_user_config';
9589
9605
 
9590
- const mergeSection = (defaults, override) => ({
9591
- ...defaults,
9592
- ...(override ?? {}),
9593
- });
9594
- const mergeConfigSections = (base, override = {}) => ({
9595
- accessibility: mergeSection(base.accessibility, override.accessibility),
9596
- cookieConsent: mergeSection(base.cookieConsent, override.cookieConsent),
9597
- language: mergeSection(base.language, override.language),
9598
- metadata: mergeSection(base.metadata, override.metadata),
9599
- });
9600
- function createDefaultUserConfig(options) {
9601
- const override = options.defaultConfig ?? {};
9602
- return mergeConfigSections(DEFAULT_USER_CONFIG, override);
9603
- }
9604
- function mergeUserConfig(current, update, options) {
9605
- const base = current ?? createDefaultUserConfig(options);
9606
- const merged = mergeConfigSections(base, update);
9607
- return {
9608
- ...merged,
9609
- metadata: {
9610
- ...merged.metadata,
9611
- updatedAt: new Date().toISOString(),
9612
- },
9613
- };
9614
- }
9606
+ const USER_CONFIG_OPTIONS = new InjectionToken('USER_CONFIG_OPTIONS');
9615
9607
 
9616
- class BaseStorageStrategy {
9617
- constructor(options) {
9618
- this.options = options;
9608
+ class IframeStorageStrategy {
9609
+ #dom;
9610
+ #options;
9611
+ #iframe;
9612
+ #messageHandler;
9613
+ constructor() {
9614
+ this.#dom = inject(DOMService);
9615
+ this.#options = inject(USER_CONFIG_OPTIONS);
9619
9616
  this.snapshot = signal(null, ...(ngDevMode ? [{ debugName: "snapshot" }] : []));
9620
- /** Tracks when the initial data has been fetched from the source */
9621
- this.isReady$ = new ReplaySubject(1);
9617
+ this.#ensureIframe();
9618
+ const win = this.#dom.window;
9619
+ if (!win) {
9620
+ return;
9621
+ }
9622
+ this.#messageHandler = (event) => this.#handleMessage(event);
9623
+ win.addEventListener('message', this.#messageHandler);
9624
+ const cached = this.#readCache();
9625
+ if (cached) {
9626
+ this.snapshot.set(cached);
9627
+ }
9622
9628
  }
9623
- /**
9624
- * Returns an Observable that waits for the source to be ready,
9625
- * then emits the current snapshot.
9626
- */
9627
9629
  read() {
9628
- return this.isReady$.pipe(filter((ready) => ready), first(), map(() => {
9629
- return this.snapshot();
9630
- }));
9630
+ return this.#readCache();
9631
9631
  }
9632
- /**
9633
- * Waits for readiness, performs a deep merge, updates the local signal,
9634
- * and triggers the implementation-specific persistence.
9635
- */
9636
9632
  write(config) {
9637
- return this.isReady$.pipe(filter((ready) => ready), first(), map(() => {
9638
- const merged = this.mergeWithBase(config);
9639
- this.snapshot.set(merged);
9640
- this.saveToSource(merged);
9641
- return merged;
9642
- }));
9643
- }
9644
- initialize() {
9645
- return this.isReady$.pipe(filter((ready) => ready), first(), map(() => null));
9646
- }
9647
- mergeWithBase(update) {
9648
- return mergeUserConfig(this.snapshot(), update, this.options);
9649
- }
9650
- createDefaultConfig() {
9651
- return createDefaultUserConfig(this.options);
9652
- }
9653
- static { this.ɵfac = function BaseStorageStrategy_Factory(__ngFactoryType__) { i0.ɵɵinvalidFactory(); }; }
9654
- static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: BaseStorageStrategy, factory: BaseStorageStrategy.ɵfac }); }
9655
- }
9656
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(BaseStorageStrategy, [{
9657
- type: Injectable
9658
- }], () => [{ type: undefined }], null); })();
9659
-
9660
- class IframeStorageStrategy extends BaseStorageStrategy {
9661
- #dom = inject(DOMService);
9662
- #options = inject(USER_CONFIG_OPTIONS);
9663
- #iframe;
9664
- #messageHandler;
9665
- constructor() {
9666
- super(inject(USER_CONFIG_OPTIONS));
9667
- this.#init();
9668
- }
9669
- saveToSource(config) {
9670
- this.#postToBridge({ type: USER_CONFIG_MESSAGE_UPDATE, payload: config });
9633
+ const merged = this.#mergeWithBase(config);
9634
+ this.#writeCache(merged);
9635
+ this.#postToBridge({ type: USER_CONFIG_MESSAGE_UPDATE, payload: merged });
9636
+ this.snapshot.set(merged);
9671
9637
  }
9672
9638
  ngOnDestroy() {
9673
9639
  if (this.#messageHandler && this.#dom.window) {
9674
9640
  this.#dom.window.removeEventListener('message', this.#messageHandler);
9675
9641
  }
9676
9642
  }
9677
- #init() {
9678
- const window = this.#dom.window;
9679
- if (!window) {
9643
+ #ensureIframe() {
9644
+ if (this.#iframe) {
9645
+ return;
9646
+ }
9647
+ const win = this.#dom.window;
9648
+ const doc = win?.document;
9649
+ if (!doc) {
9680
9650
  return;
9681
9651
  }
9682
- ;
9683
- this.#messageHandler = (event) => this.#handleMessage(event);
9684
- window.addEventListener('message', this.#messageHandler);
9685
- const doc = window.document;
9686
9652
  const iframe = doc.createElement('iframe');
9687
9653
  iframe.style.display = 'none';
9688
9654
  iframe.name = USER_CONFIG_IFRAME_NAME;
9689
9655
  iframe.src = this.#options?.iframeUrl ?? DEFAULT_USER_CONFIG_IFRAME_URL;
9690
9656
  iframe.setAttribute('aria-hidden', 'true');
9691
- iframe.addEventListener('load', () => {
9692
- this.#postToBridge({ type: USER_CONFIG_MESSAGE_REQUEST });
9693
- });
9657
+ iframe.addEventListener('load', () => this.#postToBridge({ type: USER_CONFIG_MESSAGE_REQUEST }));
9694
9658
  doc.body?.appendChild(iframe);
9695
9659
  this.#iframe = iframe;
9696
9660
  }
9697
9661
  #handleMessage(event) {
9698
- if (event.source !== this.#iframe?.contentWindow) {
9662
+ if (!this.#iframe || event.source !== this.#iframe.contentWindow) {
9699
9663
  return;
9700
9664
  }
9701
- const messageData = event.data;
9702
- if (messageData?.type !== USER_CONFIG_MESSAGE_SNAPSHOT) {
9703
- return;
9665
+ const data = event.data;
9666
+ if (data?.type === USER_CONFIG_MESSAGE_SNAPSHOT && data.payload) {
9667
+ const snapshot = data.payload;
9668
+ this.#writeCache(snapshot);
9669
+ this.snapshot.set(snapshot);
9704
9670
  }
9705
- const data = messageData?.payload ?? this.createDefaultConfig();
9706
- this.snapshot.set(data);
9707
- this.isReady$.next(true);
9708
9671
  }
9709
9672
  #postToBridge(message) {
9710
- this.#iframe?.contentWindow?.postMessage(message, USER_CONFIG_IFRAME_TARGET_ORIGIN);
9673
+ if (!this.#iframe?.contentWindow) {
9674
+ return;
9675
+ }
9676
+ this.#iframe.contentWindow.postMessage(message, USER_CONFIG_IFRAME_TARGET_ORIGIN);
9677
+ }
9678
+ #readCache() {
9679
+ const store = this.#dom.localStorage;
9680
+ if (!store) {
9681
+ return null;
9682
+ }
9683
+ return this.#parse(store.getItem(USER_CONFIG_STORAGE_KEY));
9684
+ }
9685
+ #writeCache(config) {
9686
+ const store = this.#dom.localStorage;
9687
+ if (!store) {
9688
+ return;
9689
+ }
9690
+ try {
9691
+ store.setItem(USER_CONFIG_STORAGE_KEY, JSON.stringify(config));
9692
+ }
9693
+ catch {
9694
+ /* noop */
9695
+ }
9696
+ }
9697
+ #parse(raw) {
9698
+ if (!raw) {
9699
+ return null;
9700
+ }
9701
+ try {
9702
+ return JSON.parse(raw);
9703
+ }
9704
+ catch {
9705
+ return DEFAULT_USER_CONFIG;
9706
+ }
9707
+ }
9708
+ #mergeWithBase(update) {
9709
+ const base = this.snapshot() ?? this.read() ?? DEFAULT_USER_CONFIG;
9710
+ const mergedMetadata = {
9711
+ ...base.metadata,
9712
+ ...update.metadata,
9713
+ updatedAt: new Date().toISOString(),
9714
+ };
9715
+ return {
9716
+ accessibility: {
9717
+ ...base.accessibility,
9718
+ ...update.accessibility,
9719
+ },
9720
+ cookieConsent: {
9721
+ ...base.cookieConsent,
9722
+ ...update.cookieConsent,
9723
+ },
9724
+ language: {
9725
+ ...base.language,
9726
+ ...update.language,
9727
+ },
9728
+ metadata: mergedMetadata,
9729
+ };
9711
9730
  }
9712
9731
  static { this.ɵfac = function IframeStorageStrategy_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IframeStorageStrategy)(); }; }
9713
9732
  static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: IframeStorageStrategy, factory: IframeStorageStrategy.ɵfac, providedIn: 'root' }); }
@@ -9717,60 +9736,91 @@ class IframeStorageStrategy extends BaseStorageStrategy {
9717
9736
  args: [{ providedIn: 'root' }]
9718
9737
  }], () => [], null); })();
9719
9738
 
9720
- const USER_CONFIG_STORAGE_KEY = 'ngx_common_user_config';
9721
-
9722
- class LocalStorageStrategy extends BaseStorageStrategy {
9723
- #dom = inject(DOMService);
9739
+ class LocalStorageStrategy {
9740
+ #dom;
9724
9741
  #storageListener;
9725
9742
  constructor() {
9726
- super(inject(USER_CONFIG_OPTIONS));
9727
- this.#init();
9728
- }
9729
- saveToSource(config) {
9730
- const store = this.#dom.localStorage;
9731
- if (store) {
9732
- try {
9733
- store.setItem(USER_CONFIG_STORAGE_KEY, JSON.stringify(config));
9743
+ this.#dom = inject(DOMService);
9744
+ this.snapshot = signal(null, ...(ngDevMode ? [{ debugName: "snapshot" }] : []));
9745
+ const win = this.#dom.window;
9746
+ if (!win) {
9747
+ return;
9748
+ }
9749
+ this.#storageListener = (event) => {
9750
+ if (event.key !== USER_CONFIG_STORAGE_KEY || !event.newValue) {
9751
+ return;
9734
9752
  }
9735
- catch (exception) {
9736
- console.error('Failed to save user config to localStorage', exception);
9753
+ const parsed = this.#parse(event.newValue);
9754
+ if (parsed) {
9755
+ this.snapshot.set(parsed);
9737
9756
  }
9757
+ };
9758
+ win.addEventListener('storage', this.#storageListener);
9759
+ const current = this.read();
9760
+ if (current) {
9761
+ this.snapshot.set(current);
9738
9762
  }
9739
9763
  }
9740
- ngOnDestroy() {
9741
- if (this.#storageListener && this.#dom.window) {
9742
- this.#dom.window.removeEventListener('storage', this.#storageListener);
9764
+ read() {
9765
+ const store = this.#dom.localStorage;
9766
+ if (!store) {
9767
+ return null;
9743
9768
  }
9769
+ return this.#parse(store.getItem(USER_CONFIG_STORAGE_KEY));
9744
9770
  }
9745
- #init() {
9746
- const win = this.#dom.window;
9771
+ write(config) {
9747
9772
  const store = this.#dom.localStorage;
9748
- if (win) {
9749
- this.#storageListener = (event) => {
9750
- if (event.key === USER_CONFIG_STORAGE_KEY && event.newValue) {
9751
- this.snapshot.set(this.#parse(event.newValue));
9752
- }
9753
- };
9754
- win.addEventListener('storage', this.#storageListener);
9773
+ if (!store) {
9774
+ return;
9755
9775
  }
9756
- if (store) {
9757
- const raw = store.getItem(USER_CONFIG_STORAGE_KEY);
9758
- this.snapshot.set(this.#parse(raw));
9776
+ const merged = this.#mergeWithBase(config);
9777
+ try {
9778
+ store.setItem(USER_CONFIG_STORAGE_KEY, JSON.stringify(merged));
9779
+ this.snapshot.set(merged);
9780
+ }
9781
+ catch {
9782
+ /* noop */
9783
+ }
9784
+ }
9785
+ ngOnDestroy() {
9786
+ if (this.#storageListener && this.#dom.window) {
9787
+ this.#dom.window.removeEventListener('storage', this.#storageListener);
9759
9788
  }
9760
- // LocalStorage is available immediately
9761
- this.isReady$.next(true);
9762
9789
  }
9763
9790
  #parse(raw) {
9764
9791
  if (!raw) {
9765
- return this.createDefaultConfig();
9792
+ return null;
9766
9793
  }
9767
9794
  try {
9768
9795
  return JSON.parse(raw);
9769
9796
  }
9770
9797
  catch {
9771
- return this.createDefaultConfig();
9798
+ return DEFAULT_USER_CONFIG;
9772
9799
  }
9773
9800
  }
9801
+ #mergeWithBase(update) {
9802
+ const base = this.snapshot() ?? this.read() ?? DEFAULT_USER_CONFIG;
9803
+ const mergedMetadata = {
9804
+ ...base.metadata,
9805
+ ...update.metadata,
9806
+ updatedAt: new Date().toISOString(),
9807
+ };
9808
+ return {
9809
+ accessibility: {
9810
+ ...base.accessibility,
9811
+ ...update.accessibility,
9812
+ },
9813
+ cookieConsent: {
9814
+ ...base.cookieConsent,
9815
+ ...update.cookieConsent,
9816
+ },
9817
+ language: {
9818
+ ...base.language,
9819
+ ...update.language,
9820
+ },
9821
+ metadata: mergedMetadata,
9822
+ };
9823
+ }
9774
9824
  static { this.ɵfac = function LocalStorageStrategy_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || LocalStorageStrategy)(); }; }
9775
9825
  static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: LocalStorageStrategy, factory: LocalStorageStrategy.ɵfac, providedIn: 'root' }); }
9776
9826
  }
@@ -9813,10 +9863,6 @@ function provideUserConfig(options = {}) {
9813
9863
  useFactory: userConfigStorageFactory,
9814
9864
  deps: [USER_CONFIG_OPTIONS],
9815
9865
  },
9816
- provideAppInitializer(() => {
9817
- const storage = inject(USER_CONFIG_STORAGE);
9818
- return storage.initialize();
9819
- })
9820
9866
  ]);
9821
9867
  }
9822
9868