valtech-components 2.0.325 → 2.0.328
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.
- package/esm2022/lib/components/atoms/button/button.component.mjs +18 -18
- package/esm2022/lib/components/atoms/display/display.component.mjs +13 -16
- package/esm2022/lib/components/atoms/text/text.component.mjs +19 -19
- package/esm2022/lib/components/atoms/title/title.component.mjs +7 -7
- package/esm2022/lib/components/atoms/title/types.mjs +6 -2
- package/esm2022/lib/components/molecules/alert-box/alert-box.component.mjs +6 -6
- package/esm2022/lib/components/molecules/language-selector/language-selector.component.mjs +6 -17
- package/esm2022/lib/components/organisms/form/form.component.mjs +1 -1
- package/esm2022/lib/services/lang-provider/lang-provider.service.mjs +198 -2
- package/esm2022/lib/shared/utils/simple-content.mjs +119 -0
- package/esm2022/public-api.mjs +3 -4
- package/fesm2022/valtech-components.mjs +520 -837
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/components/atoms/button/button.component.d.ts +3 -3
- package/lib/components/atoms/display/display.component.d.ts +2 -3
- package/lib/components/atoms/text/text.component.d.ts +3 -3
- package/lib/components/atoms/title/title.component.d.ts +1 -2
- package/lib/components/atoms/title/types.d.ts +10 -4
- package/lib/components/molecules/alert-box/alert-box.component.d.ts +3 -3
- package/lib/components/molecules/language-selector/language-selector.component.d.ts +1 -3
- package/lib/services/lang-provider/lang-provider.service.d.ts +108 -1
- package/lib/shared/utils/simple-content.d.ts +120 -0
- package/package.json +1 -1
- package/public-api.d.ts +1 -3
- package/esm2022/lib/services/content-loader.service.mjs +0 -185
- package/esm2022/lib/services/content.service.mjs +0 -327
- package/esm2022/lib/shared/utils/reactive-content.mjs +0 -117
- package/lib/services/content-loader.service.d.ts +0 -98
- package/lib/services/content.service.d.ts +0 -296
- package/lib/shared/utils/reactive-content.d.ts +0 -109
|
@@ -5,7 +5,7 @@ import * as i1 from '@angular/common';
|
|
|
5
5
|
import { CommonModule, NgStyle, AsyncPipe, NgFor, NgClass } from '@angular/common';
|
|
6
6
|
import { addIcons } from 'ionicons';
|
|
7
7
|
import { addOutline, addCircleOutline, alertOutline, alertCircleOutline, arrowBackOutline, arrowForwardOutline, arrowDownOutline, checkmarkCircleOutline, ellipsisHorizontalOutline, notificationsOutline, openOutline, closeOutline, chatbubblesOutline, shareOutline, heart, heartOutline, homeOutline, eyeOffOutline, eyeOutline, scanOutline, chevronDownOutline, chevronForwardOutline, checkmarkOutline, clipboardOutline, copyOutline, filterOutline, locationOutline, calendarOutline, businessOutline, logoTwitter, logoInstagram, logoLinkedin, logoYoutube, logoTiktok, logoFacebook, createOutline, trashOutline, playOutline, refreshOutline, documentTextOutline, lockClosedOutline, informationCircleOutline, logoNpm, chevronDown, language, globe, chevronBackOutline } from 'ionicons/icons';
|
|
8
|
-
import {
|
|
8
|
+
import { BehaviorSubject, distinctUntilChanged, shareReplay, map, Subscription, of, combineLatest } from 'rxjs';
|
|
9
9
|
import { Router, RouterLink } from '@angular/router';
|
|
10
10
|
import { Browser } from '@capacitor/browser';
|
|
11
11
|
import * as i1$1 from '@angular/platform-browser';
|
|
@@ -219,6 +219,125 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
219
219
|
type: Output
|
|
220
220
|
}] } });
|
|
221
221
|
|
|
222
|
+
/**
|
|
223
|
+
* Simplified content utilities for the new LangService-only system.
|
|
224
|
+
* This replaces the old reactive-content.ts with a much simpler approach.
|
|
225
|
+
*/
|
|
226
|
+
/**
|
|
227
|
+
* Helper function to determine if component should use reactive content.
|
|
228
|
+
* @param metadata Component metadata
|
|
229
|
+
* @returns True if component should use reactive content
|
|
230
|
+
*/
|
|
231
|
+
function shouldUseReactiveContent(metadata) {
|
|
232
|
+
return !metadata.content && !!(metadata.contentKey && metadata.contentClass);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Extract content configuration from metadata.
|
|
236
|
+
* @param metadata Component metadata
|
|
237
|
+
* @returns Content configuration for LangService
|
|
238
|
+
*/
|
|
239
|
+
function extractContentConfig(metadata) {
|
|
240
|
+
return {
|
|
241
|
+
className: metadata.contentClass || '',
|
|
242
|
+
key: metadata.contentKey || '',
|
|
243
|
+
fallback: metadata.contentFallback,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Create reactive content metadata with defaults.
|
|
248
|
+
* @param config Partial content configuration
|
|
249
|
+
* @returns Complete reactive content metadata
|
|
250
|
+
*/
|
|
251
|
+
function createReactiveContentMetadata(config) {
|
|
252
|
+
return {
|
|
253
|
+
content: config.content,
|
|
254
|
+
contentKey: config.contentKey,
|
|
255
|
+
contentClass: config.contentClass,
|
|
256
|
+
contentFallback: config.contentFallback,
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Interpolate content string with values.
|
|
261
|
+
* Replaces placeholders like {{key}} or {key} with actual values.
|
|
262
|
+
*
|
|
263
|
+
* @param content - Content string with placeholders
|
|
264
|
+
* @param values - Values to interpolate
|
|
265
|
+
* @returns Interpolated string
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* ```typescript
|
|
269
|
+
* interpolateContent('Hello {{name}}!', { name: 'World' })
|
|
270
|
+
* // Returns: 'Hello World!'
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
function interpolateContent$1(content, values) {
|
|
274
|
+
if (!values || !content) {
|
|
275
|
+
return content;
|
|
276
|
+
}
|
|
277
|
+
return content.replace(/\{\{?(\w+)\}?\}/g, (match, key) => {
|
|
278
|
+
const value = values[key];
|
|
279
|
+
return value !== undefined ? String(value) : match;
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Check if component should use reactive content with interpolation.
|
|
284
|
+
* @param metadata Component metadata with interpolation
|
|
285
|
+
* @returns True if component should use reactive content with interpolation
|
|
286
|
+
*/
|
|
287
|
+
function shouldUseReactiveContentWithInterpolation(metadata) {
|
|
288
|
+
return shouldUseReactiveContent(metadata) && !!metadata.contentInterpolation;
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Extract content configuration with interpolation from metadata.
|
|
292
|
+
* @param metadata Component metadata with interpolation
|
|
293
|
+
* @returns Content configuration for LangService with interpolation data
|
|
294
|
+
*/
|
|
295
|
+
function extractContentConfigWithInterpolation(metadata) {
|
|
296
|
+
return {
|
|
297
|
+
className: metadata.contentClass || '',
|
|
298
|
+
key: metadata.contentKey || '',
|
|
299
|
+
fallback: metadata.contentFallback,
|
|
300
|
+
interpolation: metadata.contentInterpolation,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Helper function to get reactive content with interpolation using LangService.
|
|
305
|
+
* This provides a unified way to get reactive, interpolated content.
|
|
306
|
+
*
|
|
307
|
+
* @param langService - The LangService instance
|
|
308
|
+
* @param metadata - Component metadata with interpolation
|
|
309
|
+
* @returns Observable that emits interpolated content
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* ```typescript
|
|
313
|
+
* const content$ = fromContentWithInterpolation(this.langService, {
|
|
314
|
+
* contentClass: 'MyComponent',
|
|
315
|
+
* contentKey: 'greeting',
|
|
316
|
+
* contentInterpolation: { name: 'World' }
|
|
317
|
+
* });
|
|
318
|
+
* ```
|
|
319
|
+
*/
|
|
320
|
+
function fromContentWithInterpolation$1(langService, // LangService type would cause circular dependency
|
|
321
|
+
metadata) {
|
|
322
|
+
// Observable<string> but avoiding import
|
|
323
|
+
const config = extractContentConfigWithInterpolation(metadata);
|
|
324
|
+
if (!config.className || !config.key) {
|
|
325
|
+
throw new Error('fromContentWithInterpolation requires both contentClass and contentKey');
|
|
326
|
+
}
|
|
327
|
+
return langService.getContentWithInterpolation(config.className, config.key, config.interpolation, config.fallback);
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Helper function to get static content with interpolation.
|
|
331
|
+
* This provides interpolation for static content strings.
|
|
332
|
+
*
|
|
333
|
+
* @param content - Static content string
|
|
334
|
+
* @param interpolationData - Values to interpolate
|
|
335
|
+
* @returns Interpolated string
|
|
336
|
+
*/
|
|
337
|
+
function interpolateStaticContent(content, interpolationData) {
|
|
338
|
+
return interpolateContent$1(content, interpolationData);
|
|
339
|
+
}
|
|
340
|
+
|
|
222
341
|
const ENABLED = 'ENABLED';
|
|
223
342
|
const DISABLED = 'DISABLED';
|
|
224
343
|
const WORKING = 'WORKING';
|
|
@@ -434,191 +553,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
434
553
|
}]
|
|
435
554
|
}], ctorParameters: () => [] });
|
|
436
555
|
|
|
437
|
-
/**
|
|
438
|
-
* Create a reactive content observable from a content key.
|
|
439
|
-
* This is the primary utility for the `fromContent` pattern with unified support
|
|
440
|
-
* for both simple content and content with interpolation.
|
|
441
|
-
*
|
|
442
|
-
* @param langService - The language service instance
|
|
443
|
-
* @param config - Content configuration with optional interpolation
|
|
444
|
-
* @returns Observable that emits the content string and updates on language change
|
|
445
|
-
*
|
|
446
|
-
* @example Simple content:
|
|
447
|
-
* ```typescript
|
|
448
|
-
* // Component-specific content
|
|
449
|
-
* this.title$ = fromContent(this.langService, {
|
|
450
|
-
* className: 'HeaderComponent',
|
|
451
|
-
* key: 'title',
|
|
452
|
-
* fallback: 'Default Title'
|
|
453
|
-
* });
|
|
454
|
-
*
|
|
455
|
-
* // Global content (no className needed)
|
|
456
|
-
* this.saveButton$ = fromContent(this.langService, {
|
|
457
|
-
* key: 'save'
|
|
458
|
-
* });
|
|
459
|
-
* ```
|
|
460
|
-
*
|
|
461
|
-
* @example Content with interpolation:
|
|
462
|
-
* ```typescript
|
|
463
|
-
* // Content: "Hello {name}, you have {count} messages"
|
|
464
|
-
* this.greeting$ = fromContent(this.langService, {
|
|
465
|
-
* className: 'WelcomeComponent',
|
|
466
|
-
* key: 'greeting',
|
|
467
|
-
* interpolation: { name: 'John', count: 5 }
|
|
468
|
-
* });
|
|
469
|
-
* // Results in: "Hello John, you have 5 messages"
|
|
470
|
-
* ```
|
|
471
|
-
*/
|
|
472
|
-
function fromContent(langService, config) {
|
|
473
|
-
// Use _global as default className if not provided
|
|
474
|
-
const finalClassName = config.className || '_global';
|
|
475
|
-
const contentObservable = langService.getContent(finalClassName, config.key, config.fallback);
|
|
476
|
-
// If interpolation is provided, apply it
|
|
477
|
-
if (config.interpolation) {
|
|
478
|
-
return contentObservable.pipe(map(content => interpolateContent(content, config.interpolation)));
|
|
479
|
-
}
|
|
480
|
-
return contentObservable;
|
|
481
|
-
}
|
|
482
|
-
/**
|
|
483
|
-
* Create a reactive content observable with interpolation support.
|
|
484
|
-
*
|
|
485
|
-
* @deprecated Use fromContent() with interpolation property instead.
|
|
486
|
-
* This method is kept for backward compatibility.
|
|
487
|
-
*
|
|
488
|
-
* @param langService - The language service instance
|
|
489
|
-
* @param config - Interpolated content configuration
|
|
490
|
-
* @returns Observable that emits the interpolated content string
|
|
491
|
-
*
|
|
492
|
-
* @example Migration:
|
|
493
|
-
* ```typescript
|
|
494
|
-
* // OLD (deprecated):
|
|
495
|
-
* this.greeting$ = fromContentWithInterpolation(this.langService, {
|
|
496
|
-
* className: 'WelcomeComponent',
|
|
497
|
-
* key: 'greeting',
|
|
498
|
-
* interpolation: { name: 'John', count: 5 }
|
|
499
|
-
* });
|
|
500
|
-
*
|
|
501
|
-
* // NEW (recommended):
|
|
502
|
-
* this.greeting$ = fromContent(this.langService, {
|
|
503
|
-
* className: 'WelcomeComponent',
|
|
504
|
-
* key: 'greeting',
|
|
505
|
-
* interpolation: { name: 'John', count: 5 }
|
|
506
|
-
* });
|
|
507
|
-
* ```
|
|
508
|
-
*/
|
|
509
|
-
function fromContentWithInterpolation(langService, config) {
|
|
510
|
-
// Delegate to the unified fromContent method
|
|
511
|
-
return fromContent(langService, config);
|
|
512
|
-
}
|
|
513
|
-
/**
|
|
514
|
-
* Create multiple reactive content observables at once.
|
|
515
|
-
* Useful when a component needs several content strings.
|
|
516
|
-
*
|
|
517
|
-
* @param langService - The language service instance
|
|
518
|
-
* @param className - The component class name
|
|
519
|
-
* @param keys - Array of content keys to retrieve
|
|
520
|
-
* @returns Observable that emits an object with all requested content
|
|
521
|
-
*
|
|
522
|
-
* @example
|
|
523
|
-
* ```typescript
|
|
524
|
-
* this.content$ = fromMultipleContent(this.langService, 'FormComponent', [
|
|
525
|
-
* 'title', 'submitButton', 'cancelButton'
|
|
526
|
-
* ]);
|
|
527
|
-
*
|
|
528
|
-
* // In template
|
|
529
|
-
* <ng-container *ngIf="content$ | async as content">
|
|
530
|
-
* <h2>{{ content.title }}</h2>
|
|
531
|
-
* <button>{{ content.submitButton }}</button>
|
|
532
|
-
* <button>{{ content.cancelButton }}</button>
|
|
533
|
-
* </ng-container>
|
|
534
|
-
* ```
|
|
535
|
-
*/
|
|
536
|
-
function fromMultipleContent(langService, className, keys) {
|
|
537
|
-
return langService.getMultipleContent(className, keys);
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* Helper function to interpolate values into a content string.
|
|
541
|
-
* Replaces placeholders in the format {key} with corresponding values.
|
|
542
|
-
*
|
|
543
|
-
* @param content - The content string with placeholders
|
|
544
|
-
* @param values - Object with values to interpolate
|
|
545
|
-
* @returns The interpolated string
|
|
546
|
-
*
|
|
547
|
-
* @example
|
|
548
|
-
* ```typescript
|
|
549
|
-
* const result = interpolateContent("Hello {name}!", { name: "World" });
|
|
550
|
-
* // Returns: "Hello World!"
|
|
551
|
-
* ```
|
|
552
|
-
*/
|
|
553
|
-
function interpolateContent(content, values) {
|
|
554
|
-
if (!values)
|
|
555
|
-
return content;
|
|
556
|
-
return Object.entries(values).reduce((result, [key, value]) => {
|
|
557
|
-
return result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
|
|
558
|
-
}, content);
|
|
559
|
-
}
|
|
560
|
-
/**
|
|
561
|
-
* Factory function to create a content helper bound to a specific component class.
|
|
562
|
-
* This creates a more convenient API for components that need multiple content strings.
|
|
563
|
-
*
|
|
564
|
-
* @param langService - The language service instance
|
|
565
|
-
* @param className - The component class name
|
|
566
|
-
* @returns Object with convenient methods for content retrieval
|
|
567
|
-
*
|
|
568
|
-
* @example
|
|
569
|
-
* ```typescript
|
|
570
|
-
* export class MyComponent {
|
|
571
|
-
* private content = createContentHelper(this.langService, 'MyComponent');
|
|
572
|
-
*
|
|
573
|
-
* constructor(private langService: LangService) {}
|
|
574
|
-
*
|
|
575
|
-
* ngOnInit() {
|
|
576
|
-
* this.title$ = this.content.get('title');
|
|
577
|
-
* this.allContent$ = this.content.getMultiple(['title', 'description']);
|
|
578
|
-
* }
|
|
579
|
-
* }
|
|
580
|
-
* ```
|
|
581
|
-
*/
|
|
582
|
-
function createContentHelper(langService, className) {
|
|
583
|
-
return {
|
|
584
|
-
/**
|
|
585
|
-
* Get a single content string reactively.
|
|
586
|
-
*/
|
|
587
|
-
get(key, fallback) {
|
|
588
|
-
return fromContent(langService, { className, key, fallback });
|
|
589
|
-
},
|
|
590
|
-
/**
|
|
591
|
-
* Get multiple content strings reactively.
|
|
592
|
-
*/
|
|
593
|
-
getMultiple(keys) {
|
|
594
|
-
return fromMultipleContent(langService, className, keys);
|
|
595
|
-
},
|
|
596
|
-
/**
|
|
597
|
-
* Get content with interpolation.
|
|
598
|
-
*/
|
|
599
|
-
getWithInterpolation(key, interpolation, fallback) {
|
|
600
|
-
return fromContentWithInterpolation(langService, {
|
|
601
|
-
className,
|
|
602
|
-
key,
|
|
603
|
-
interpolation,
|
|
604
|
-
fallback,
|
|
605
|
-
});
|
|
606
|
-
},
|
|
607
|
-
/**
|
|
608
|
-
* Get a single content string synchronously (current language only).
|
|
609
|
-
*/
|
|
610
|
-
getText(key, fallback) {
|
|
611
|
-
return langService.getText(className, key, fallback);
|
|
612
|
-
},
|
|
613
|
-
/**
|
|
614
|
-
* Check if a content key exists.
|
|
615
|
-
*/
|
|
616
|
-
hasContent(key) {
|
|
617
|
-
return langService.hasContent(className, key);
|
|
618
|
-
},
|
|
619
|
-
};
|
|
620
|
-
}
|
|
621
|
-
|
|
622
556
|
const LANG = 'LANG';
|
|
623
557
|
const THEME = 'THEME';
|
|
624
558
|
|
|
@@ -991,348 +925,221 @@ class LangService {
|
|
|
991
925
|
const targetContent = classContent.Content[lang] || {};
|
|
992
926
|
return Object.keys(referenceContent).filter(key => !targetContent[key] || typeof targetContent[key] !== 'string');
|
|
993
927
|
}
|
|
994
|
-
// Legacy getters/setters for backward compatibility
|
|
995
|
-
get Lang() {
|
|
996
|
-
return this.currentLang;
|
|
997
|
-
}
|
|
998
|
-
set Lang(lang) {
|
|
999
|
-
this.setLang(lang);
|
|
1000
|
-
}
|
|
1001
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, deps: [{ token: ValtechConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1002
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, providedIn: 'root' }); }
|
|
1003
|
-
}
|
|
1004
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, decorators: [{
|
|
1005
|
-
type: Injectable,
|
|
1006
|
-
args: [{
|
|
1007
|
-
providedIn: 'root',
|
|
1008
|
-
}]
|
|
1009
|
-
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1010
|
-
type: Inject,
|
|
1011
|
-
args: [ValtechConfigService]
|
|
1012
|
-
}] }] });
|
|
1013
|
-
|
|
1014
|
-
/**
|
|
1015
|
-
* ContentService - High-level reactive content management service.
|
|
1016
|
-
*
|
|
1017
|
-
* This service provides a clean, convenient API for reactive content management
|
|
1018
|
-
* without requiring direct interaction with LangService. It acts as a facade
|
|
1019
|
-
* that simplifies the most common content operations.
|
|
1020
|
-
*
|
|
1021
|
-
* @example Basic usage:
|
|
1022
|
-
* ```typescript
|
|
1023
|
-
* @Component({})
|
|
1024
|
-
* export class MyComponent {
|
|
1025
|
-
* content = inject(ContentService);
|
|
1026
|
-
*
|
|
1027
|
-
* title$ = this.content.fromContent({
|
|
1028
|
-
* className: 'MyComponent',
|
|
1029
|
-
* key: 'title'
|
|
1030
|
-
* });
|
|
1031
|
-
*
|
|
1032
|
-
* constructor() {}
|
|
1033
|
-
* }
|
|
1034
|
-
* ```
|
|
1035
|
-
*/
|
|
1036
|
-
class ContentService {
|
|
1037
|
-
constructor(langService) {
|
|
1038
|
-
this.langService = langService;
|
|
1039
|
-
}
|
|
1040
|
-
/**
|
|
1041
|
-
* Get current language as an observable stream.
|
|
1042
|
-
* Emits whenever the language changes.
|
|
1043
|
-
*/
|
|
1044
|
-
get currentLang$() {
|
|
1045
|
-
return this.langService.currentLang$;
|
|
1046
|
-
}
|
|
1047
|
-
/**
|
|
1048
|
-
* Get current language synchronously.
|
|
1049
|
-
*/
|
|
1050
|
-
get currentLang() {
|
|
1051
|
-
return this.langService.currentLang;
|
|
1052
|
-
}
|
|
1053
928
|
/**
|
|
1054
|
-
*
|
|
1055
|
-
* This
|
|
929
|
+
* Register or update content for a component dynamically.
|
|
930
|
+
* This allows registering content at runtime without APP_INITIALIZER.
|
|
1056
931
|
*
|
|
1057
|
-
* @param
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
this.langService.setLang(lang);
|
|
1061
|
-
}
|
|
1062
|
-
/**
|
|
1063
|
-
* Create a reactive content observable from a content key.
|
|
1064
|
-
* This is the primary method for reactive content with unified support
|
|
1065
|
-
* for both simple content and content with interpolation.
|
|
1066
|
-
*
|
|
1067
|
-
* @param config - Content configuration with optional interpolation. If className is omitted, searches in global content.
|
|
1068
|
-
* @returns Observable that emits the content string and updates on language change
|
|
1069
|
-
*
|
|
1070
|
-
* @example Simple global content:
|
|
1071
|
-
* ```typescript
|
|
1072
|
-
* // Searches in global content (no className needed)
|
|
1073
|
-
* okButton$ = this.content.fromContent({
|
|
1074
|
-
* key: 'ok',
|
|
1075
|
-
* fallback: 'OK'
|
|
1076
|
-
* });
|
|
1077
|
-
* ```
|
|
1078
|
-
*
|
|
1079
|
-
* @example Component-specific content:
|
|
1080
|
-
* ```typescript
|
|
1081
|
-
* title$ = this.content.fromContent({
|
|
1082
|
-
* className: 'HeaderComponent',
|
|
1083
|
-
* key: 'title',
|
|
1084
|
-
* fallback: 'Default Title'
|
|
1085
|
-
* });
|
|
1086
|
-
* ```
|
|
932
|
+
* @param className - The component class name
|
|
933
|
+
* @param content - The multilingual content object
|
|
934
|
+
* @param merge - Whether to merge with existing content (default: true)
|
|
1087
935
|
*
|
|
1088
|
-
* @example
|
|
936
|
+
* @example
|
|
1089
937
|
* ```typescript
|
|
1090
|
-
*
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
* interpolation: { itemName: 'archivo' }
|
|
1094
|
-
* });
|
|
1095
|
-
*
|
|
1096
|
-
* // Component content with interpolation
|
|
1097
|
-
* greeting$ = this.content.fromContent({
|
|
1098
|
-
* className: 'WelcomeComponent',
|
|
1099
|
-
* key: 'greeting',
|
|
1100
|
-
* interpolation: { name: 'John', count: 5 }
|
|
938
|
+
* this.langService.registerContent('MyComponent', {
|
|
939
|
+
* [LANGUAGES.ES]: { title: 'Título', description: 'Descripción' },
|
|
940
|
+
* [LANGUAGES.EN]: { title: 'Title', description: 'Description' }
|
|
1101
941
|
* });
|
|
1102
942
|
* ```
|
|
1103
943
|
*/
|
|
1104
|
-
|
|
1105
|
-
|
|
944
|
+
registerContent(className, content, merge = true) {
|
|
945
|
+
if (!className) {
|
|
946
|
+
console.error('LangService: className is required for registerContent');
|
|
947
|
+
return;
|
|
948
|
+
}
|
|
949
|
+
if (!content || typeof content !== 'object') {
|
|
950
|
+
console.error('LangService: Invalid content provided for registerContent');
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
console.log(`LangService: Registering content for "${className}"`, {
|
|
954
|
+
merge,
|
|
955
|
+
languages: Object.keys(content),
|
|
956
|
+
});
|
|
957
|
+
// Initialize component content if it doesn't exist
|
|
958
|
+
if (!this.content[className]) {
|
|
959
|
+
this.content[className] = new TextContent({});
|
|
960
|
+
}
|
|
961
|
+
// Merge or replace content for each language
|
|
962
|
+
Object.entries(content).forEach(([lang, langContent]) => {
|
|
963
|
+
if (!langContent || typeof langContent !== 'object') {
|
|
964
|
+
console.warn(`LangService: Invalid content for language "${lang}" in "${className}"`);
|
|
965
|
+
return;
|
|
966
|
+
}
|
|
967
|
+
if (!this.content[className].Content[lang]) {
|
|
968
|
+
this.content[className].Content[lang] = {};
|
|
969
|
+
}
|
|
970
|
+
if (merge) {
|
|
971
|
+
this.content[className].Content[lang] = {
|
|
972
|
+
...this.content[className].Content[lang],
|
|
973
|
+
...langContent,
|
|
974
|
+
};
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
this.content[className].Content[lang] = { ...langContent };
|
|
978
|
+
}
|
|
979
|
+
});
|
|
980
|
+
// Update available languages
|
|
981
|
+
this.detectAvailableLanguages();
|
|
982
|
+
console.log(`LangService: Content registered successfully for "${className}"`);
|
|
1106
983
|
}
|
|
1107
984
|
/**
|
|
1108
|
-
*
|
|
985
|
+
* Update multiple content registrations at once.
|
|
1109
986
|
*
|
|
1110
|
-
* @
|
|
1111
|
-
*
|
|
987
|
+
* @param contentMap - Map of className to content
|
|
988
|
+
* @param merge - Whether to merge with existing content (default: true)
|
|
1112
989
|
*
|
|
1113
|
-
* @
|
|
1114
|
-
* @returns Observable that emits the interpolated content string
|
|
1115
|
-
*
|
|
1116
|
-
* @example Migration:
|
|
990
|
+
* @example
|
|
1117
991
|
* ```typescript
|
|
1118
|
-
*
|
|
1119
|
-
*
|
|
1120
|
-
*
|
|
1121
|
-
* key: 'greeting',
|
|
1122
|
-
* interpolation: { name: 'John', count: 5 }
|
|
1123
|
-
* });
|
|
1124
|
-
*
|
|
1125
|
-
* // NEW (recommended):
|
|
1126
|
-
* greeting$ = this.content.fromContent({
|
|
1127
|
-
* className: 'WelcomeComponent',
|
|
1128
|
-
* key: 'greeting',
|
|
1129
|
-
* interpolation: { name: 'John', count: 5 }
|
|
992
|
+
* this.langService.registerMultipleContent({
|
|
993
|
+
* 'Component1': { [LANGUAGES.ES]: { key1: 'valor1' } },
|
|
994
|
+
* 'Component2': { [LANGUAGES.EN]: { key2: 'value2' } }
|
|
1130
995
|
* });
|
|
1131
996
|
* ```
|
|
1132
997
|
*/
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
998
|
+
registerMultipleContent(contentMap, merge = true) {
|
|
999
|
+
if (!contentMap || typeof contentMap !== 'object') {
|
|
1000
|
+
console.error('LangService: Invalid contentMap provided for registerMultipleContent');
|
|
1001
|
+
return;
|
|
1002
|
+
}
|
|
1003
|
+
console.log('LangService: Registering multiple content entries', {
|
|
1004
|
+
classes: Object.keys(contentMap),
|
|
1005
|
+
merge,
|
|
1006
|
+
});
|
|
1007
|
+
Object.entries(contentMap).forEach(([className, content]) => {
|
|
1008
|
+
this.registerContent(className, content, merge);
|
|
1009
|
+
});
|
|
1010
|
+
console.log('LangService: Multiple content registration completed');
|
|
1136
1011
|
}
|
|
1137
1012
|
/**
|
|
1138
|
-
*
|
|
1139
|
-
* Useful when a component needs several content strings.
|
|
1140
|
-
*
|
|
1141
|
-
* @param className - The component class name
|
|
1142
|
-
* @param keys - Array of content keys to retrieve
|
|
1143
|
-
* @returns Observable that emits an object with all requested content
|
|
1144
|
-
*
|
|
1145
|
-
* @example
|
|
1146
|
-
* ```typescript
|
|
1147
|
-
* content$ = this.content.fromMultipleContent('FormComponent', [
|
|
1148
|
-
* 'title', 'submitButton', 'cancelButton'
|
|
1149
|
-
* ]);
|
|
1013
|
+
* Remove content for a specific component.
|
|
1150
1014
|
*
|
|
1151
|
-
*
|
|
1152
|
-
* <ng-container *ngIf="content$ | async as content">
|
|
1153
|
-
* <h2>{{ content['title'] }}</h2>
|
|
1154
|
-
* <button>{{ content['submitButton'] }}</button>
|
|
1155
|
-
* <button>{{ content['cancelButton'] }}</button>
|
|
1156
|
-
* </ng-container>
|
|
1157
|
-
* ```
|
|
1015
|
+
* @param className - The component class name to remove
|
|
1158
1016
|
*/
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
if (
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1017
|
+
removeContent(className) {
|
|
1018
|
+
if (!className) {
|
|
1019
|
+
console.error('LangService: className is required for removeContent');
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
if (this.content[className]) {
|
|
1023
|
+
delete this.content[className];
|
|
1024
|
+
this.detectAvailableLanguages();
|
|
1025
|
+
console.log(`LangService: Content removed for "${className}"`);
|
|
1168
1026
|
}
|
|
1169
1027
|
else {
|
|
1170
|
-
|
|
1171
|
-
return this.langService.getText(classNameOrKey, keyOrFallback, fallback);
|
|
1028
|
+
console.warn(`LangService: No content found for "${className}" to remove`);
|
|
1172
1029
|
}
|
|
1173
1030
|
}
|
|
1174
1031
|
/**
|
|
1175
|
-
* Get a
|
|
1176
|
-
* This is a convenience method that's equivalent to getText(key, fallback).
|
|
1032
|
+
* Get a list of all registered component classes.
|
|
1177
1033
|
*
|
|
1178
|
-
* @
|
|
1179
|
-
|
|
1180
|
-
|
|
1034
|
+
* @returns Array of registered class names
|
|
1035
|
+
*/
|
|
1036
|
+
getRegisteredClasses() {
|
|
1037
|
+
return Object.keys(this.content);
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Get the complete content configuration (for debugging purposes).
|
|
1041
|
+
* Returns a deep copy to prevent accidental mutations.
|
|
1181
1042
|
*
|
|
1182
|
-
* @
|
|
1183
|
-
* ```typescript
|
|
1184
|
-
* const okText = this.content.getGlobalText('ok');
|
|
1185
|
-
* const cancelText = this.content.getGlobalText('cancel', 'Cancel');
|
|
1186
|
-
* ```
|
|
1043
|
+
* @returns Complete content configuration
|
|
1187
1044
|
*/
|
|
1188
|
-
|
|
1189
|
-
return
|
|
1045
|
+
getContentConfiguration() {
|
|
1046
|
+
return JSON.parse(JSON.stringify(this.content));
|
|
1190
1047
|
}
|
|
1191
1048
|
/**
|
|
1192
|
-
*
|
|
1049
|
+
* Clear all content and reset to initial state.
|
|
1050
|
+
* Useful for testing or complete reinitialization.
|
|
1051
|
+
*/
|
|
1052
|
+
clearAllContent() {
|
|
1053
|
+
console.log('LangService: Clearing all content');
|
|
1054
|
+
this.content = {};
|
|
1055
|
+
this.availableLanguages = [LANGUAGES.ES]; // Reset to default
|
|
1056
|
+
this.warnedMissingLanguages.clear();
|
|
1057
|
+
console.log('LangService: All content cleared');
|
|
1058
|
+
}
|
|
1059
|
+
/**
|
|
1060
|
+
* Get content with interpolation support.
|
|
1061
|
+
* Retrieves content and replaces placeholders with provided values.
|
|
1193
1062
|
*
|
|
1194
1063
|
* @param className - The component class name
|
|
1195
1064
|
* @param key - The text key
|
|
1196
|
-
* @
|
|
1197
|
-
*
|
|
1198
|
-
* @
|
|
1199
|
-
* ```typescript
|
|
1200
|
-
* if (this.content.hasContent('MyComponent', 'optionalText')) {
|
|
1201
|
-
* // Show optional content
|
|
1202
|
-
* }
|
|
1203
|
-
* ```
|
|
1065
|
+
* @param interpolationData - Object with values to interpolate
|
|
1066
|
+
* @param fallback - Optional fallback text if key is not found
|
|
1067
|
+
* @returns Text with interpolated values
|
|
1204
1068
|
*/
|
|
1205
|
-
|
|
1206
|
-
|
|
1069
|
+
getTextWithInterpolation(className, key, interpolationData, fallback) {
|
|
1070
|
+
const content = this.getText(className, key, fallback);
|
|
1071
|
+
return this.interpolateString(content, interpolationData);
|
|
1207
1072
|
}
|
|
1208
1073
|
/**
|
|
1209
|
-
*
|
|
1210
|
-
*
|
|
1211
|
-
*
|
|
1212
|
-
* @param content - The content string with placeholders
|
|
1213
|
-
* @param values - Object with values to interpolate
|
|
1214
|
-
* @returns The interpolated string
|
|
1074
|
+
* Get reactive content with interpolation support.
|
|
1075
|
+
* Returns an Observable that emits interpolated content when language changes.
|
|
1215
1076
|
*
|
|
1216
|
-
* @
|
|
1217
|
-
*
|
|
1218
|
-
*
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1077
|
+
* @param className - The component class name
|
|
1078
|
+
* @param key - The text key
|
|
1079
|
+
* @param interpolationData - Object with values to interpolate
|
|
1080
|
+
* @param fallback - Optional fallback text if key is not found
|
|
1081
|
+
* @returns Observable that emits interpolated text
|
|
1221
1082
|
*/
|
|
1222
|
-
|
|
1223
|
-
return
|
|
1083
|
+
getContentWithInterpolation(className, key, interpolationData, fallback) {
|
|
1084
|
+
return this.getContent(className, key, fallback).pipe(map(content => this.interpolateString(content, interpolationData)));
|
|
1224
1085
|
}
|
|
1225
1086
|
/**
|
|
1226
|
-
*
|
|
1227
|
-
*
|
|
1087
|
+
* Interpolate a string with provided values.
|
|
1088
|
+
* Replaces placeholders like {{key}} or {key} with actual values.
|
|
1228
1089
|
*
|
|
1229
|
-
* @param
|
|
1230
|
-
* @
|
|
1090
|
+
* @param content - Content string with placeholders
|
|
1091
|
+
* @param values - Values to interpolate
|
|
1092
|
+
* @returns Interpolated string
|
|
1231
1093
|
*
|
|
1232
1094
|
* @example
|
|
1233
1095
|
* ```typescript
|
|
1234
|
-
*
|
|
1235
|
-
*
|
|
1236
|
-
*
|
|
1237
|
-
* ngOnInit() {
|
|
1238
|
-
* this.title$ = this.contentHelper.get('title');
|
|
1239
|
-
* this.allContent$ = this.contentHelper.getMultiple(['title', 'description']);
|
|
1240
|
-
* }
|
|
1241
|
-
*
|
|
1242
|
-
* constructor(private content: ContentService) {}
|
|
1243
|
-
* }
|
|
1096
|
+
* interpolateString('Hello {{name}}!', { name: 'World' })
|
|
1097
|
+
* // Returns: 'Hello World!'
|
|
1244
1098
|
* ```
|
|
1245
1099
|
*/
|
|
1246
|
-
|
|
1247
|
-
|
|
1100
|
+
interpolateString(content, values) {
|
|
1101
|
+
if (!values || !content) {
|
|
1102
|
+
return content;
|
|
1103
|
+
}
|
|
1104
|
+
return content.replace(/\{\{?(\w+)\}?\}/g, (match, key) => {
|
|
1105
|
+
const value = values[key];
|
|
1106
|
+
return value !== undefined ? String(value) : match;
|
|
1107
|
+
});
|
|
1248
1108
|
}
|
|
1249
1109
|
/**
|
|
1250
|
-
*
|
|
1251
|
-
*
|
|
1110
|
+
* Legacy function equivalent to the old fromContentWithInterpolation.
|
|
1111
|
+
* Provides reactive content with interpolation support for backward compatibility.
|
|
1252
1112
|
*
|
|
1253
1113
|
* @param className - The component class name
|
|
1254
|
-
* @
|
|
1255
|
-
*
|
|
1256
|
-
* @
|
|
1257
|
-
*
|
|
1258
|
-
* export class MyComponent {
|
|
1259
|
-
* private content = inject(ContentService).forComponent('MyComponent');
|
|
1260
|
-
*
|
|
1261
|
-
* // Simple content
|
|
1262
|
-
* title$ = this.content.get('title');
|
|
1263
|
-
*
|
|
1264
|
-
* // Content with interpolation
|
|
1265
|
-
* greeting$ = this.content.get('greeting', {
|
|
1266
|
-
* interpolation: { name: 'John' }
|
|
1267
|
-
* });
|
|
1268
|
-
*
|
|
1269
|
-
* // Content with fallback
|
|
1270
|
-
* subtitle$ = this.content.get('subtitle', {
|
|
1271
|
-
* fallback: 'Default Subtitle'
|
|
1272
|
-
* });
|
|
1273
|
-
*
|
|
1274
|
-
* // Multiple texts
|
|
1275
|
-
* allTexts$ = this.content.getMultiple(['title', 'subtitle', 'description']);
|
|
1114
|
+
* @param key - The text key
|
|
1115
|
+
* @param interpolationData - Object with values to interpolate
|
|
1116
|
+
* @param fallback - Optional fallback text if key is not found
|
|
1117
|
+
* @returns Observable that emits interpolated text
|
|
1276
1118
|
*
|
|
1277
|
-
*
|
|
1278
|
-
* }
|
|
1279
|
-
* ```
|
|
1119
|
+
* @deprecated Use getContentWithInterpolation instead
|
|
1280
1120
|
*/
|
|
1281
|
-
|
|
1282
|
-
return
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
get: (key, options) => {
|
|
1288
|
-
return this.fromContent({
|
|
1289
|
-
className,
|
|
1290
|
-
key,
|
|
1291
|
-
fallback: options?.fallback,
|
|
1292
|
-
interpolation: options?.interpolation,
|
|
1293
|
-
});
|
|
1294
|
-
},
|
|
1295
|
-
/**
|
|
1296
|
-
* Get content with interpolation for this component.
|
|
1297
|
-
* @deprecated Use get() with interpolation option instead.
|
|
1298
|
-
*/
|
|
1299
|
-
getWithInterpolation: (key, interpolation, fallback) => {
|
|
1300
|
-
return this.fromContent({
|
|
1301
|
-
className,
|
|
1302
|
-
key,
|
|
1303
|
-
interpolation,
|
|
1304
|
-
fallback,
|
|
1305
|
-
});
|
|
1306
|
-
},
|
|
1307
|
-
/**
|
|
1308
|
-
* Get multiple content strings for this component.
|
|
1309
|
-
*/
|
|
1310
|
-
getMultiple: (keys) => {
|
|
1311
|
-
return this.fromMultipleContent(className, keys);
|
|
1312
|
-
},
|
|
1313
|
-
/**
|
|
1314
|
-
* Get a single content string synchronously for this component.
|
|
1315
|
-
*/
|
|
1316
|
-
getText: (key, fallback) => {
|
|
1317
|
-
return this.getText(className, key, fallback);
|
|
1318
|
-
},
|
|
1319
|
-
/**
|
|
1320
|
-
* Check if a content key exists for this component.
|
|
1321
|
-
*/
|
|
1322
|
-
hasContent: (key) => {
|
|
1323
|
-
return this.hasContent(className, key);
|
|
1324
|
-
},
|
|
1325
|
-
};
|
|
1121
|
+
fromContentWithInterpolation(className, key, interpolationData, fallback) {
|
|
1122
|
+
return this.getContentWithInterpolation(className, key, interpolationData, fallback);
|
|
1123
|
+
}
|
|
1124
|
+
// Legacy getters/setters for backward compatibility
|
|
1125
|
+
get Lang() {
|
|
1126
|
+
return this.currentLang;
|
|
1326
1127
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1128
|
+
set Lang(lang) {
|
|
1129
|
+
this.setLang(lang);
|
|
1130
|
+
}
|
|
1131
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, deps: [{ token: ValtechConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1132
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, providedIn: 'root' }); }
|
|
1329
1133
|
}
|
|
1330
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type:
|
|
1134
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LangService, decorators: [{
|
|
1331
1135
|
type: Injectable,
|
|
1332
1136
|
args: [{
|
|
1333
1137
|
providedIn: 'root',
|
|
1334
1138
|
}]
|
|
1335
|
-
}], ctorParameters: () => [{ type:
|
|
1139
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1140
|
+
type: Inject,
|
|
1141
|
+
args: [ValtechConfigService]
|
|
1142
|
+
}] }] });
|
|
1336
1143
|
|
|
1337
1144
|
/**
|
|
1338
1145
|
* val-button
|
|
@@ -1376,10 +1183,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1376
1183
|
* @output onClick - Emits when the button is clicked
|
|
1377
1184
|
*/
|
|
1378
1185
|
class ButtonComponent {
|
|
1379
|
-
constructor(download, icon, navigation,
|
|
1186
|
+
constructor(download, icon, navigation, langService) {
|
|
1380
1187
|
this.download = download;
|
|
1381
1188
|
this.navigation = navigation;
|
|
1382
|
-
this.
|
|
1189
|
+
this.langService = langService;
|
|
1383
1190
|
this.states = ComponentStates;
|
|
1384
1191
|
this.subscriptions = new Subscription();
|
|
1385
1192
|
/**
|
|
@@ -1401,26 +1208,25 @@ class ButtonComponent {
|
|
|
1401
1208
|
setupDisplayText() {
|
|
1402
1209
|
if (this.props.text) {
|
|
1403
1210
|
// Static text takes precedence
|
|
1404
|
-
|
|
1211
|
+
if (this.props.contentInterpolation) {
|
|
1212
|
+
// Static text with interpolation
|
|
1213
|
+
const interpolatedText = interpolateStaticContent(this.props.text, this.props.contentInterpolation);
|
|
1214
|
+
this.displayText$ = of(interpolatedText);
|
|
1215
|
+
}
|
|
1216
|
+
else {
|
|
1217
|
+
// Simple static text
|
|
1218
|
+
this.displayText$ = of(this.props.text);
|
|
1219
|
+
}
|
|
1405
1220
|
}
|
|
1406
1221
|
else if (this.props.contentKey && this.props.contentClass) {
|
|
1407
1222
|
// Reactive content from language service
|
|
1408
1223
|
if (this.props.contentInterpolation) {
|
|
1409
1224
|
// With interpolation
|
|
1410
|
-
this.displayText$ = this.
|
|
1411
|
-
className: this.props.contentClass,
|
|
1412
|
-
key: this.props.contentKey,
|
|
1413
|
-
fallback: this.props.contentFallback,
|
|
1414
|
-
interpolation: this.props.contentInterpolation,
|
|
1415
|
-
});
|
|
1225
|
+
this.displayText$ = this.langService.getContentWithInterpolation(this.props.contentClass, this.props.contentKey, this.props.contentInterpolation, this.props.contentFallback);
|
|
1416
1226
|
}
|
|
1417
1227
|
else {
|
|
1418
1228
|
// Simple reactive content
|
|
1419
|
-
this.displayText$ = this.
|
|
1420
|
-
className: this.props.contentClass,
|
|
1421
|
-
key: this.props.contentKey,
|
|
1422
|
-
fallback: this.props.contentFallback,
|
|
1423
|
-
});
|
|
1229
|
+
this.displayText$ = this.langService.getContent(this.props.contentClass, this.props.contentKey, this.props.contentFallback);
|
|
1424
1230
|
}
|
|
1425
1231
|
}
|
|
1426
1232
|
else {
|
|
@@ -1444,7 +1250,7 @@ class ButtonComponent {
|
|
|
1444
1250
|
}
|
|
1445
1251
|
this.onClick.emit(this.props.token);
|
|
1446
1252
|
}
|
|
1447
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ButtonComponent, deps: [{ token: DownloadService }, { token: IconService }, { token: NavigationService }, { token:
|
|
1253
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ButtonComponent, deps: [{ token: DownloadService }, { token: IconService }, { token: NavigationService }, { token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1448
1254
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: ButtonComponent, isStandalone: true, selector: "val-button", inputs: { props: "props" }, outputs: { onClick: "onClick" }, ngImport: i0, template: `
|
|
1449
1255
|
<ion-button
|
|
1450
1256
|
[type]="props.type"
|
|
@@ -1486,7 +1292,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1486
1292
|
<ion-text *ngIf="props.state !== states.WORKING">{{ displayText$ | async }}</ion-text>
|
|
1487
1293
|
</ion-button>
|
|
1488
1294
|
`, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}ion-button{font-family:var(--ion-default-font),Arial,sans-serif;min-width:6.25rem;margin:0}ion-button.small{--padding-bottom: 12px;--padding-end: 14px;--padding-start: 14px;--padding-top: 12px}ion-button.button-clear{padding:0;margin:0}\n"] }]
|
|
1489
|
-
}], ctorParameters: () => [{ type: DownloadService }, { type: IconService }, { type: NavigationService }, { type:
|
|
1295
|
+
}], ctorParameters: () => [{ type: DownloadService }, { type: IconService }, { type: NavigationService }, { type: LangService }], propDecorators: { props: [{
|
|
1490
1296
|
type: Input
|
|
1491
1297
|
}], onClick: [{
|
|
1492
1298
|
type: Output
|
|
@@ -1763,9 +1569,9 @@ const SecondarySolidBlockIconHrefButton = (text, icon, href, target) => {
|
|
|
1763
1569
|
* @input props: DisplayMetadata - Configuration for the display (content/contentConfig, color, size)
|
|
1764
1570
|
*/
|
|
1765
1571
|
class DisplayComponent {
|
|
1766
|
-
constructor(
|
|
1767
|
-
this.contentService = contentService;
|
|
1572
|
+
constructor() {
|
|
1768
1573
|
this.subscriptions = new Subscription();
|
|
1574
|
+
this.langService = inject(LangService);
|
|
1769
1575
|
}
|
|
1770
1576
|
ngOnInit() {
|
|
1771
1577
|
this.initializeDisplayContent();
|
|
@@ -1781,18 +1587,15 @@ class DisplayComponent {
|
|
|
1781
1587
|
}
|
|
1782
1588
|
// Use reactive content if configured
|
|
1783
1589
|
if (this.props.contentConfig) {
|
|
1784
|
-
this.displayContent$ = this.
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
fallback: this.props.contentConfig.fallback || this.props.contentConfig.key,
|
|
1788
|
-
interpolation: this.props.contentConfig.interpolation,
|
|
1789
|
-
});
|
|
1590
|
+
this.displayContent$ = this.langService.getContent(this.props.contentConfig.className || '_global', this.props.contentConfig.key, this.props.contentConfig.fallback || this.props.contentConfig.key
|
|
1591
|
+
// interpolation: this.props.contentConfig.interpolation,
|
|
1592
|
+
);
|
|
1790
1593
|
return;
|
|
1791
1594
|
}
|
|
1792
1595
|
// No content configured - use empty string
|
|
1793
1596
|
this.displayContent$ = of('');
|
|
1794
1597
|
}
|
|
1795
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DisplayComponent, deps: [
|
|
1598
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DisplayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1796
1599
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: DisplayComponent, isStandalone: true, selector: "val-display", inputs: { props: "props" }, ngImport: i0, template: `
|
|
1797
1600
|
<ion-text [color]="props.color">
|
|
1798
1601
|
<p [class]="props.size">
|
|
@@ -1810,7 +1613,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
1810
1613
|
</p>
|
|
1811
1614
|
</ion-text>
|
|
1812
1615
|
`, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.small{font-size:1.5rem;line-height:2rem;font-weight:800}@media (min-width: 768px){.small{font-size:2rem;line-height:2.5rem}}.medium{font-size:2rem;line-height:2.5rem;font-weight:800}@media (min-width: 768px){.medium{font-size:2.5rem;line-height:3rem}}.large{font-size:2.5rem;line-height:3rem;font-weight:800}@media (min-width: 768px){.large{font-size:3rem;line-height:3.5rem}}.xlarge{font-size:3rem;line-height:2.5rem;font-weight:800}@media (min-width: 768px){.xlarge{font-size:4.375rem;line-height:4.125rem}}\n"] }]
|
|
1813
|
-
}], ctorParameters: () => [
|
|
1616
|
+
}], ctorParameters: () => [], propDecorators: { props: [{
|
|
1814
1617
|
type: Input
|
|
1815
1618
|
}] } });
|
|
1816
1619
|
/**
|
|
@@ -2592,8 +2395,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2592
2395
|
* @input props: TextMetadata - Configuration for the text (content, styling, and reactive content options)
|
|
2593
2396
|
*/
|
|
2594
2397
|
class TextComponent {
|
|
2595
|
-
constructor(
|
|
2596
|
-
this.
|
|
2398
|
+
constructor(langService, linkProcessor) {
|
|
2399
|
+
this.langService = langService;
|
|
2597
2400
|
this.linkProcessor = linkProcessor;
|
|
2598
2401
|
this.subscription = new Subscription();
|
|
2599
2402
|
}
|
|
@@ -2610,26 +2413,25 @@ class TextComponent {
|
|
|
2610
2413
|
setupDisplayContent() {
|
|
2611
2414
|
if (this.props.content) {
|
|
2612
2415
|
// Static content takes precedence
|
|
2613
|
-
|
|
2416
|
+
if (this.props.contentInterpolation) {
|
|
2417
|
+
// Static content with interpolation
|
|
2418
|
+
const interpolatedContent = interpolateStaticContent(this.props.content, this.props.contentInterpolation);
|
|
2419
|
+
this.displayContent$ = of(interpolatedContent);
|
|
2420
|
+
}
|
|
2421
|
+
else {
|
|
2422
|
+
// Simple static content
|
|
2423
|
+
this.displayContent$ = of(this.props.content);
|
|
2424
|
+
}
|
|
2614
2425
|
}
|
|
2615
|
-
else if (this.props
|
|
2426
|
+
else if (shouldUseReactiveContent(this.props)) {
|
|
2616
2427
|
// Reactive content from language service
|
|
2617
2428
|
if (this.props.contentInterpolation) {
|
|
2618
2429
|
// With interpolation
|
|
2619
|
-
this.displayContent$ = this.
|
|
2620
|
-
className: this.props.contentClass,
|
|
2621
|
-
key: this.props.contentKey,
|
|
2622
|
-
fallback: this.props.contentFallback,
|
|
2623
|
-
interpolation: this.props.contentInterpolation,
|
|
2624
|
-
});
|
|
2430
|
+
this.displayContent$ = this.langService.getContentWithInterpolation(this.props.contentClass, this.props.contentKey, this.props.contentInterpolation, this.props.contentFallback);
|
|
2625
2431
|
}
|
|
2626
2432
|
else {
|
|
2627
2433
|
// Simple reactive content
|
|
2628
|
-
this.displayContent$ = this.
|
|
2629
|
-
className: this.props.contentClass,
|
|
2630
|
-
key: this.props.contentKey,
|
|
2631
|
-
fallback: this.props.contentFallback,
|
|
2632
|
-
});
|
|
2434
|
+
this.displayContent$ = this.langService.getContent(this.props.contentClass, this.props.contentKey, this.props.contentFallback);
|
|
2633
2435
|
}
|
|
2634
2436
|
}
|
|
2635
2437
|
else {
|
|
@@ -2654,7 +2456,7 @@ class TextComponent {
|
|
|
2654
2456
|
processedContent = processedContent.replace(/<strong>(.*?)<\/strong>/gi, '<span class="partial-bold">$1</span>');
|
|
2655
2457
|
return processedContent;
|
|
2656
2458
|
}
|
|
2657
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TextComponent, deps: [{ token:
|
|
2459
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: TextComponent, deps: [{ token: LangService }, { token: LinkProcessorService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2658
2460
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: TextComponent, isStandalone: true, selector: "val-text", inputs: { props: "props" }, ngImport: i0, template: `
|
|
2659
2461
|
<ion-text [color]="props.color">
|
|
2660
2462
|
@if (props.processLinks) {
|
|
@@ -2694,7 +2496,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2694
2496
|
}
|
|
2695
2497
|
</ion-text>
|
|
2696
2498
|
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.small{font-size:.75rem;line-height:1.25rem;font-weight:400}.small.bold{font-size:.75rem;line-height:1.25rem;font-weight:700}.medium{font-size:.875rem;line-height:1.5rem;font-weight:400}@media (min-width: 768px){.medium{font-size:1rem;line-height:1.5rem}}.medium.bold{font-size:.875rem;line-height:1.5rem;font-weight:700}@media (min-width: 768px){.medium.bold{font-size:1rem;line-height:1.5rem}}.large{font-size:1rem;line-height:1.5rem;font-weight:400}@media (min-width: 768px){.large{font-size:1.125rem;line-height:1.5rem}}.large.bold{font-size:1rem;line-height:1.5rem;font-weight:700}@media (min-width: 768px){.large.bold{font-size:1.125rem;line-height:1.5rem}}.xlarge{font-size:1.125rem;line-height:1.5rem;font-weight:400}@media (min-width: 768px){.xlarge{font-size:1.5rem;line-height:2rem}}.xlarge.bold{font-size:1.125rem;line-height:1.5rem;font-weight:700}@media (min-width: 768px){.xlarge.bold{font-size:1.5rem;line-height:2rem}}:host ::ng-deep .partial-bold{font-weight:700}\n"] }]
|
|
2697
|
-
}], ctorParameters: () => [{ type:
|
|
2499
|
+
}], ctorParameters: () => [{ type: LangService }, { type: LinkProcessorService }], propDecorators: { props: [{
|
|
2698
2500
|
type: Input
|
|
2699
2501
|
}] } });
|
|
2700
2502
|
/**
|
|
@@ -2750,123 +2552,6 @@ function createTextProps(contentConfig, styleConfig = {}) {
|
|
|
2750
2552
|
};
|
|
2751
2553
|
}
|
|
2752
2554
|
|
|
2753
|
-
/**
|
|
2754
|
-
* Enhanced content utilities for multi-language component support.
|
|
2755
|
-
* Extends the base content utilities to provide specialized helpers for different component patterns.
|
|
2756
|
-
*/
|
|
2757
|
-
/**
|
|
2758
|
-
* Helper class for managing reactive content in components.
|
|
2759
|
-
*/
|
|
2760
|
-
class ComponentContentHelper {
|
|
2761
|
-
constructor(contentService, defaultClassName) {
|
|
2762
|
-
this.contentService = contentService;
|
|
2763
|
-
this.defaultClassName = defaultClassName;
|
|
2764
|
-
}
|
|
2765
|
-
/**
|
|
2766
|
-
* Resolves content based on hybrid configuration (static vs reactive).
|
|
2767
|
-
*/
|
|
2768
|
-
resolveContent(config) {
|
|
2769
|
-
// Static content takes precedence
|
|
2770
|
-
if (config.content !== undefined) {
|
|
2771
|
-
return config.content;
|
|
2772
|
-
}
|
|
2773
|
-
// Use reactive content if configured
|
|
2774
|
-
if (config.contentConfig) {
|
|
2775
|
-
return this.contentService.fromContent({
|
|
2776
|
-
className: config.contentConfig.className || this.defaultClassName || '_global',
|
|
2777
|
-
key: config.contentConfig.key,
|
|
2778
|
-
fallback: config.contentConfig.fallback,
|
|
2779
|
-
interpolation: config.contentConfig.interpolation,
|
|
2780
|
-
});
|
|
2781
|
-
}
|
|
2782
|
-
// No content configured
|
|
2783
|
-
return '';
|
|
2784
|
-
}
|
|
2785
|
-
/**
|
|
2786
|
-
* Resolves multiple text properties for components with multiple text fields.
|
|
2787
|
-
*/
|
|
2788
|
-
resolveMultipleTexts(config) {
|
|
2789
|
-
const result = {};
|
|
2790
|
-
Object.entries(config.textConfigs).forEach(([property, contentConfig]) => {
|
|
2791
|
-
result[property] = this.contentService.fromContent({
|
|
2792
|
-
className: contentConfig.className || this.defaultClassName || '_global',
|
|
2793
|
-
key: contentConfig.key,
|
|
2794
|
-
fallback: contentConfig.fallback,
|
|
2795
|
-
interpolation: contentConfig.interpolation,
|
|
2796
|
-
});
|
|
2797
|
-
});
|
|
2798
|
-
return result;
|
|
2799
|
-
}
|
|
2800
|
-
/**
|
|
2801
|
-
* Creates a reactive content configuration for array items.
|
|
2802
|
-
* Useful for list components where items might have translatable text.
|
|
2803
|
-
*/
|
|
2804
|
-
createArrayItemConfig(baseKey, index, fallback) {
|
|
2805
|
-
return {
|
|
2806
|
-
className: this.defaultClassName || '_global',
|
|
2807
|
-
key: `${baseKey}.${index}`,
|
|
2808
|
-
fallback: fallback,
|
|
2809
|
-
};
|
|
2810
|
-
}
|
|
2811
|
-
/**
|
|
2812
|
-
* Helper for button/action text that commonly needs translation.
|
|
2813
|
-
*/
|
|
2814
|
-
createActionConfig(actionKey, fallback) {
|
|
2815
|
-
return {
|
|
2816
|
-
className: '_global',
|
|
2817
|
-
key: actionKey,
|
|
2818
|
-
fallback: fallback,
|
|
2819
|
-
};
|
|
2820
|
-
}
|
|
2821
|
-
}
|
|
2822
|
-
/**
|
|
2823
|
-
* Factory function to create content helpers for components.
|
|
2824
|
-
*/
|
|
2825
|
-
function createComponentContentHelper(contentService, componentClassName) {
|
|
2826
|
-
return new ComponentContentHelper(contentService, componentClassName);
|
|
2827
|
-
}
|
|
2828
|
-
/**
|
|
2829
|
-
* Utility function to determine if content should be reactive.
|
|
2830
|
-
*/
|
|
2831
|
-
function shouldUseReactiveContent(config) {
|
|
2832
|
-
return config.content === undefined && config.contentConfig !== undefined;
|
|
2833
|
-
}
|
|
2834
|
-
/**
|
|
2835
|
-
* Enhanced props factory for components that support reactive content.
|
|
2836
|
-
*/
|
|
2837
|
-
function createReactiveProps(contentHelper, staticProps, contentConfig) {
|
|
2838
|
-
return {
|
|
2839
|
-
...staticProps,
|
|
2840
|
-
...contentConfig,
|
|
2841
|
-
};
|
|
2842
|
-
}
|
|
2843
|
-
/**
|
|
2844
|
-
* Helper for list components that need to mix static and reactive content.
|
|
2845
|
-
*/
|
|
2846
|
-
class ListContentHelper {
|
|
2847
|
-
constructor(contentHelper) {
|
|
2848
|
-
this.contentHelper = contentHelper;
|
|
2849
|
-
}
|
|
2850
|
-
/**
|
|
2851
|
-
* Resolves a list configuration into final items.
|
|
2852
|
-
*/
|
|
2853
|
-
resolveListItems(config) {
|
|
2854
|
-
const items = [];
|
|
2855
|
-
// Add static items first
|
|
2856
|
-
if (config.staticItems) {
|
|
2857
|
-
items.push(...config.staticItems);
|
|
2858
|
-
}
|
|
2859
|
-
// Add reactive items
|
|
2860
|
-
if (config.reactiveItems) {
|
|
2861
|
-
for (let i = 0; i < config.reactiveItems.count; i++) {
|
|
2862
|
-
const item = config.reactiveItems.itemTemplate(this.contentHelper, i);
|
|
2863
|
-
items.push(item);
|
|
2864
|
-
}
|
|
2865
|
-
}
|
|
2866
|
-
return items;
|
|
2867
|
-
}
|
|
2868
|
-
}
|
|
2869
|
-
|
|
2870
2555
|
/**
|
|
2871
2556
|
* val-title
|
|
2872
2557
|
*
|
|
@@ -2906,14 +2591,14 @@ class ListContentHelper {
|
|
|
2906
2591
|
*/
|
|
2907
2592
|
class TitleComponent {
|
|
2908
2593
|
constructor() {
|
|
2909
|
-
this.
|
|
2594
|
+
this.langService = inject(LangService);
|
|
2910
2595
|
}
|
|
2911
2596
|
ngOnInit() {
|
|
2912
|
-
this.contentHelper = createComponentContentHelper(this.contentService);
|
|
2913
2597
|
// Always convert to Observable for consistent template handling
|
|
2914
2598
|
if (shouldUseReactiveContent(this.props)) {
|
|
2915
|
-
// Use reactive content
|
|
2916
|
-
|
|
2599
|
+
// Use reactive content with LangService
|
|
2600
|
+
const config = extractContentConfig(this.props);
|
|
2601
|
+
this.displayContent$ = this.langService.getContent(config.className, config.key, config.fallback);
|
|
2917
2602
|
}
|
|
2918
2603
|
else {
|
|
2919
2604
|
// Convert static content to Observable
|
|
@@ -2978,7 +2663,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2978
2663
|
* ```typescript
|
|
2979
2664
|
* const props = createTitleProps(
|
|
2980
2665
|
* { size: 'large', color: 'primary', bold: true },
|
|
2981
|
-
* {
|
|
2666
|
+
* {
|
|
2667
|
+
* contentKey: 'pageTitle',
|
|
2668
|
+
* contentClass: 'MyComponent',
|
|
2669
|
+
* contentFallback: 'Default Title'
|
|
2670
|
+
* }
|
|
2982
2671
|
* );
|
|
2983
2672
|
* ```
|
|
2984
2673
|
*/
|
|
@@ -3013,8 +2702,8 @@ class AlertBoxComponent {
|
|
|
3013
2702
|
getLegacyTextProps() {
|
|
3014
2703
|
return this.props.text;
|
|
3015
2704
|
}
|
|
3016
|
-
constructor(
|
|
3017
|
-
this.
|
|
2705
|
+
constructor(langService) {
|
|
2706
|
+
this.langService = langService;
|
|
3018
2707
|
this.subscriptions = new Subscription();
|
|
3019
2708
|
}
|
|
3020
2709
|
ngOnInit() {
|
|
@@ -3043,7 +2732,7 @@ class AlertBoxComponent {
|
|
|
3043
2732
|
this.computedTextProps.contentConfig = reactiveProps.textConfig;
|
|
3044
2733
|
}
|
|
3045
2734
|
}
|
|
3046
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlertBoxComponent, deps: [{ token:
|
|
2735
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AlertBoxComponent, deps: [{ token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3047
2736
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AlertBoxComponent, isStandalone: true, selector: "val-alert-box", inputs: { props: "props" }, ngImport: i0, template: `
|
|
3048
2737
|
<val-box [props]="props.box">
|
|
3049
2738
|
<div class="content-container" body>
|
|
@@ -3073,7 +2762,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3073
2762
|
</div>
|
|
3074
2763
|
</val-box>
|
|
3075
2764
|
`, styles: [":root{--ion-color-primary: #7026df;--ion-color-primary-rgb: 112, 38, 223;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #6321c4;--ion-color-primary-tint: #7e3ce2;--ion-color-secondary: #e2ccff;--ion-color-secondary-rgb: 226, 204, 255;--ion-color-secondary-contrast: #000000;--ion-color-secondary-contrast-rgb: 0, 0, 0;--ion-color-secondary-shade: #c7b4e0;--ion-color-secondary-tint: #e5d1ff;--ion-color-texti: #354c69;--ion-color-texti-rgb: 53, 76, 105;--ion-color-texti-contrast: #ffffff;--ion-color-texti-contrast-rgb: 255, 255, 255;--ion-color-texti-shade: #2f435c;--ion-color-texti-tint: #495e78;--ion-color-darki: #090f1b;--ion-color-darki-rgb: 9, 15, 27;--ion-color-darki-contrast: #ffffff;--ion-color-darki-contrast-rgb: 255, 255, 255;--ion-color-darki-shade: #080d18;--ion-color-darki-tint: #222732;--ion-color-medium: #9e9e9e;--ion-color-medium-rgb: 158, 158, 158;--ion-color-medium-contrast: #000000;--ion-color-medium-contrast-rgb: 0, 0, 0;--ion-color-medium-shade: #8b8b8b;--ion-color-medium-tint: #a8a8a8;--swiper-pagination-color: var(--ion-color-primary);--swiper-navigation-color: var(--ion-color-primary);--swiper-pagination-bullet-inactive-color: var(--ion-color-medium)}@media (prefers-color-scheme: dark){:root{--ion-color-texti: #8fc1ff;--ion-color-texti-rgb: 143, 193, 255;--ion-color-texti-contrast: #000000;--ion-color-texti-contrast-rgb: 0, 0, 0;--ion-color-texti-shade: #7eaae0;--ion-color-texti-tint: #9ac7ff;--ion-color-darki: #ffffff;--ion-color-darki-rgb: 255, 255, 255;--ion-color-darki-contrast: #000000;--ion-color-darki-contrast-rgb: 0, 0, 0;--ion-color-darki-shade: #e0e0e0;--ion-color-darki-tint: #ffffff;--ion-color-primary: #8f49f8;--ion-color-primary-rgb: 143, 73, 248;--ion-color-primary-contrast: #ffffff;--ion-color-primary-contrast-rgb: 255, 255, 255;--ion-color-primary-shade: #7e40da;--ion-color-primary-tint: #9a5bf9}}.ion-color-texti{--ion-color-base: var(--ion-color-texti);--ion-color-base-rgb: var(--ion-color-texti-rgb);--ion-color-contrast: var(--ion-color-texti-contrast);--ion-color-contrast-rgb: var(--ion-color-texti-contrast-rgb);--ion-color-shade: var(--ion-color-texti-shade);--ion-color-tint: var(--ion-color-texti-tint)}.ion-color-darki{--ion-color-base: var(--ion-color-darki);--ion-color-base-rgb: var(--ion-color-darki-rgb);--ion-color-contrast: var(--ion-color-darki-contrast);--ion-color-contrast-rgb: var(--ion-color-darki-contrast-rgb);--ion-color-shade: var(--ion-color-darki-shade);--ion-color-tint: var(--ion-color-darki-tint)}.text{margin-left:.25rem}.content-container{display:flex;align-items:flex-start}\n"] }]
|
|
3076
|
-
}], ctorParameters: () => [{ type:
|
|
2765
|
+
}], ctorParameters: () => [{ type: LangService }], propDecorators: { props: [{
|
|
3077
2766
|
type: Input
|
|
3078
2767
|
}] } });
|
|
3079
2768
|
|
|
@@ -4271,9 +3960,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
4271
3960
|
* @output languageChange: EventEmitter<string> - Emitted when language changes
|
|
4272
3961
|
*/
|
|
4273
3962
|
class LanguageSelectorComponent {
|
|
4274
|
-
constructor(langService
|
|
3963
|
+
constructor(langService) {
|
|
4275
3964
|
this.langService = langService;
|
|
4276
|
-
this.contentService = contentService;
|
|
4277
3965
|
/**
|
|
4278
3966
|
* Language selector configuration object.
|
|
4279
3967
|
* @type {LanguageSelectorMetadata}
|
|
@@ -4337,20 +4025,11 @@ class LanguageSelectorComponent {
|
|
|
4337
4025
|
}
|
|
4338
4026
|
else if (this.props.labelConfig) {
|
|
4339
4027
|
// Reactive label
|
|
4340
|
-
this.label$ = this.
|
|
4341
|
-
className: this.props.labelConfig.className || '_global',
|
|
4342
|
-
key: this.props.labelConfig.key,
|
|
4343
|
-
fallback: this.props.labelConfig.fallback || 'Language',
|
|
4344
|
-
interpolation: this.props.labelConfig.interpolation,
|
|
4345
|
-
});
|
|
4028
|
+
this.label$ = this.langService.getContent(this.props.labelConfig.className || '_global', this.props.labelConfig.key, this.props.labelConfig.fallback || 'Language');
|
|
4346
4029
|
}
|
|
4347
4030
|
else {
|
|
4348
4031
|
// Default label from global content
|
|
4349
|
-
this.label$ = this.
|
|
4350
|
-
className: '_global',
|
|
4351
|
-
key: 'language',
|
|
4352
|
-
fallback: 'Idioma',
|
|
4353
|
-
});
|
|
4032
|
+
this.label$ = this.langService.getContent('_global', 'language', 'Idioma');
|
|
4354
4033
|
}
|
|
4355
4034
|
}
|
|
4356
4035
|
initializePopoverProps() {
|
|
@@ -4431,7 +4110,7 @@ class LanguageSelectorComponent {
|
|
|
4431
4110
|
this.languageChange.emit(selectedLanguage);
|
|
4432
4111
|
}
|
|
4433
4112
|
}
|
|
4434
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LanguageSelectorComponent, deps: [{ token: LangService }
|
|
4113
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LanguageSelectorComponent, deps: [{ token: LangService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4435
4114
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: LanguageSelectorComponent, isStandalone: true, selector: "val-language-selector", inputs: { props: "props" }, outputs: { languageChange: "languageChange" }, ngImport: i0, template: `
|
|
4436
4115
|
<val-popover-selector [props]="popoverProps" (selectionChange)="onLanguageChange($event)"> </val-popover-selector>
|
|
4437
4116
|
`, isInline: true, styles: [":host{display:inline-block;width:auto}val-popover-selector .popover-selector-container{display:inline-block;width:auto}val-popover-selector .selector-trigger .trigger-text{display:inline-flex;align-items:center;gap:8px;font-weight:700}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.2em;line-height:1;filter:drop-shadow(0 1px 2px rgba(0,0,0,.1));transition:transform .2s ease}val-popover-selector .selector-trigger.has-flag .trigger-text{letter-spacing:.025em}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1)}val-popover-selector .option-content{gap:10px;padding:8px 0}val-popover-selector .option-content .flag-emoji{font-size:1.1em;filter:drop-shadow(0 1px 2px rgba(0,0,0,.08))}val-popover-selector .option-content span{font-weight:600;letter-spacing:.01em}.language-flag{font-size:1.2em;margin-right:6px;vertical-align:middle;line-height:1;filter:drop-shadow(0 1px 3px rgba(0,0,0,.1));transition:all .2s ease}@media (max-width: 768px){val-popover-selector .selector-trigger .trigger-text{font-size:13px;gap:6px}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.1em}}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1) rotate(3deg);transition:transform .25s cubic-bezier(.4,0,.2,1)}val-popover-selector .selector-trigger:active .trigger-text .flag-emoji{transform:scale(1.05)}val-popover-selector .language-changing .flag-emoji{animation:languageSwitch .4s ease-in-out}@keyframes languageSwitch{0%{transform:scale(1)}50%{transform:scale(1.15) rotate(8deg)}to{transform:scale(1)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: PopoverSelectorComponent, selector: "val-popover-selector", inputs: ["props"], outputs: ["selectionChange"] }] }); }
|
|
@@ -4441,7 +4120,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
4441
4120
|
args: [{ selector: 'val-language-selector', standalone: true, imports: [CommonModule, PopoverSelectorComponent], template: `
|
|
4442
4121
|
<val-popover-selector [props]="popoverProps" (selectionChange)="onLanguageChange($event)"> </val-popover-selector>
|
|
4443
4122
|
`, styles: [":host{display:inline-block;width:auto}val-popover-selector .popover-selector-container{display:inline-block;width:auto}val-popover-selector .selector-trigger .trigger-text{display:inline-flex;align-items:center;gap:8px;font-weight:700}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.2em;line-height:1;filter:drop-shadow(0 1px 2px rgba(0,0,0,.1));transition:transform .2s ease}val-popover-selector .selector-trigger.has-flag .trigger-text{letter-spacing:.025em}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1)}val-popover-selector .option-content{gap:10px;padding:8px 0}val-popover-selector .option-content .flag-emoji{font-size:1.1em;filter:drop-shadow(0 1px 2px rgba(0,0,0,.08))}val-popover-selector .option-content span{font-weight:600;letter-spacing:.01em}.language-flag{font-size:1.2em;margin-right:6px;vertical-align:middle;line-height:1;filter:drop-shadow(0 1px 3px rgba(0,0,0,.1));transition:all .2s ease}@media (max-width: 768px){val-popover-selector .selector-trigger .trigger-text{font-size:13px;gap:6px}val-popover-selector .selector-trigger .trigger-text .flag-emoji{font-size:1.1em}}val-popover-selector .selector-trigger:hover:not([disabled]) .trigger-text .flag-emoji{transform:scale(1.1) rotate(3deg);transition:transform .25s cubic-bezier(.4,0,.2,1)}val-popover-selector .selector-trigger:active .trigger-text .flag-emoji{transform:scale(1.05)}val-popover-selector .language-changing .flag-emoji{animation:languageSwitch .4s ease-in-out}@keyframes languageSwitch{0%{transform:scale(1)}50%{transform:scale(1.15) rotate(8deg)}to{transform:scale(1)}}\n"] }]
|
|
4444
|
-
}], ctorParameters: () => [{ type: LangService }
|
|
4123
|
+
}], ctorParameters: () => [{ type: LangService }], propDecorators: { props: [{
|
|
4445
4124
|
type: Input
|
|
4446
4125
|
}], languageChange: [{
|
|
4447
4126
|
type: Output
|
|
@@ -8109,187 +7788,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
8109
7788
|
type: Output
|
|
8110
7789
|
}] } });
|
|
8111
7790
|
|
|
8112
|
-
/**
|
|
8113
|
-
* ContentLoader Service - Dynamic content loading system.
|
|
8114
|
-
*
|
|
8115
|
-
* REFACTORED: Now uses ValtechConfigService properly instead of hacking LangService.
|
|
8116
|
-
* This provides a clean, maintainable way to register content dynamically.
|
|
8117
|
-
*
|
|
8118
|
-
* @example Basic usage:
|
|
8119
|
-
* ```typescript
|
|
8120
|
-
* // user-page.content.ts
|
|
8121
|
-
* export const UserPageContent = {
|
|
8122
|
-
* es: { title: 'Mi Página de Usuario', welcome: 'Bienvenido {{name}}' },
|
|
8123
|
-
* en: { title: 'My User Page', welcome: 'Welcome {{name}}' }
|
|
8124
|
-
* };
|
|
8125
|
-
*
|
|
8126
|
-
* // In component
|
|
8127
|
-
* import { UserPageContent } from './user-page.content';
|
|
8128
|
-
* registerContent('UserPage', UserPageContent);
|
|
8129
|
-
* ```
|
|
8130
|
-
*/
|
|
8131
|
-
class ContentLoaderService {
|
|
8132
|
-
constructor() {
|
|
8133
|
-
this.valtechConfig = inject(ValtechConfigService);
|
|
8134
|
-
this.registeredContent = new Map();
|
|
8135
|
-
}
|
|
8136
|
-
/**
|
|
8137
|
-
* Register content for a specific component/page class.
|
|
8138
|
-
* ✅ CLEAN: Uses proper ValtechConfigService API instead of hacking LangService
|
|
8139
|
-
*/
|
|
8140
|
-
registerContent(className, content) {
|
|
8141
|
-
// Store locally for tracking
|
|
8142
|
-
this.registeredContent.set(className, content);
|
|
8143
|
-
// Update the configuration properly
|
|
8144
|
-
this.addContentToProvider(className, content);
|
|
8145
|
-
console.log(`✅ ContentLoader: Registered content for "${className}"`);
|
|
8146
|
-
}
|
|
8147
|
-
/**
|
|
8148
|
-
* Register multiple content modules at once.
|
|
8149
|
-
*/
|
|
8150
|
-
loadContent(contentModules) {
|
|
8151
|
-
console.log(`🔄 ContentLoader: Loading ${contentModules.length} content modules...`);
|
|
8152
|
-
contentModules.forEach(module => {
|
|
8153
|
-
this.registerContent(module.className, module.content);
|
|
8154
|
-
});
|
|
8155
|
-
console.log('✅ ContentLoader: All content modules loaded successfully');
|
|
8156
|
-
}
|
|
8157
|
-
/**
|
|
8158
|
-
* Check if content is registered for a class.
|
|
8159
|
-
*/
|
|
8160
|
-
hasContentFor(className) {
|
|
8161
|
-
return this.registeredContent.has(className);
|
|
8162
|
-
}
|
|
8163
|
-
/**
|
|
8164
|
-
* Get all registered class names.
|
|
8165
|
-
*/
|
|
8166
|
-
getRegisteredClasses() {
|
|
8167
|
-
return Array.from(this.registeredContent.keys());
|
|
8168
|
-
}
|
|
8169
|
-
/**
|
|
8170
|
-
* Get registered content for a specific class.
|
|
8171
|
-
*/
|
|
8172
|
-
getContentFor(className) {
|
|
8173
|
-
return this.registeredContent.get(className);
|
|
8174
|
-
}
|
|
8175
|
-
/**
|
|
8176
|
-
* Remove content registration for a class.
|
|
8177
|
-
*/
|
|
8178
|
-
unregisterContent(className) {
|
|
8179
|
-
const existed = this.registeredContent.has(className);
|
|
8180
|
-
this.registeredContent.delete(className);
|
|
8181
|
-
// Also remove from the provider
|
|
8182
|
-
if (existed && this.valtechConfig.content) {
|
|
8183
|
-
const updatedContent = { ...this.valtechConfig.content };
|
|
8184
|
-
delete updatedContent[className];
|
|
8185
|
-
this.valtechConfig.content = updatedContent;
|
|
8186
|
-
console.log(`🗑️ ContentLoader: Unregistered content for "${className}"`);
|
|
8187
|
-
}
|
|
8188
|
-
return existed;
|
|
8189
|
-
}
|
|
8190
|
-
/**
|
|
8191
|
-
* Clear all registered content.
|
|
8192
|
-
*/
|
|
8193
|
-
clearAllContent() {
|
|
8194
|
-
this.registeredContent.clear();
|
|
8195
|
-
console.log('🧹 ContentLoader: Cleared all registered content');
|
|
8196
|
-
}
|
|
8197
|
-
/**
|
|
8198
|
-
* Get current content provider state.
|
|
8199
|
-
* Useful for debugging.
|
|
8200
|
-
*/
|
|
8201
|
-
getContentProvider() {
|
|
8202
|
-
return this.valtechConfig.content;
|
|
8203
|
-
}
|
|
8204
|
-
/**
|
|
8205
|
-
* ✅ CLEAN: Add content to provider using proper API
|
|
8206
|
-
* @private
|
|
8207
|
-
*/
|
|
8208
|
-
addContentToProvider(className, content) {
|
|
8209
|
-
try {
|
|
8210
|
-
// Get current content provider
|
|
8211
|
-
const currentContent = this.valtechConfig.content || {};
|
|
8212
|
-
// Create TextContent instance
|
|
8213
|
-
const textContent = new TextContent(content);
|
|
8214
|
-
// Update the content provider properly
|
|
8215
|
-
const updatedContent = {
|
|
8216
|
-
...currentContent,
|
|
8217
|
-
[className]: textContent,
|
|
8218
|
-
};
|
|
8219
|
-
// Set the updated content - this is the clean way
|
|
8220
|
-
this.valtechConfig.content = updatedContent;
|
|
8221
|
-
console.log(`📝 ContentLoader: Added "${className}" to content provider`);
|
|
8222
|
-
}
|
|
8223
|
-
catch (error) {
|
|
8224
|
-
console.error(`❌ ContentLoader: Error adding content for "${className}":`, error);
|
|
8225
|
-
}
|
|
8226
|
-
}
|
|
8227
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
8228
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentLoaderService, providedIn: 'root' }); }
|
|
8229
|
-
}
|
|
8230
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ContentLoaderService, decorators: [{
|
|
8231
|
-
type: Injectable,
|
|
8232
|
-
args: [{
|
|
8233
|
-
providedIn: 'root',
|
|
8234
|
-
}]
|
|
8235
|
-
}] });
|
|
8236
|
-
/**
|
|
8237
|
-
* Helper function to create a content module.
|
|
8238
|
-
*/
|
|
8239
|
-
function createContentModule(className, content) {
|
|
8240
|
-
return { className, content };
|
|
8241
|
-
}
|
|
8242
|
-
/**
|
|
8243
|
-
* ✅ CLEAN: Global registry using proper array instead of globalThis hack
|
|
8244
|
-
*/
|
|
8245
|
-
const globalContentRegistry = [];
|
|
8246
|
-
/**
|
|
8247
|
-
* Simple function to register content directly.
|
|
8248
|
-
* ✅ IMPROVED: Cleaner global registry management
|
|
8249
|
-
*/
|
|
8250
|
-
function registerContent(className, content) {
|
|
8251
|
-
// Add to global registry
|
|
8252
|
-
globalContentRegistry.push({ className, content });
|
|
8253
|
-
console.log(`📝 registerContent: Queued "${className}" for registration`);
|
|
8254
|
-
}
|
|
8255
|
-
/**
|
|
8256
|
-
* Load all content from the global registry.
|
|
8257
|
-
* ✅ IMPROVED: Better error handling and logging
|
|
8258
|
-
*/
|
|
8259
|
-
function loadRegisteredContent(contentLoader) {
|
|
8260
|
-
if (globalContentRegistry.length === 0) {
|
|
8261
|
-
console.log('ℹ️ ContentLoader: No content registered to load');
|
|
8262
|
-
return;
|
|
8263
|
-
}
|
|
8264
|
-
console.log(`🚀 ContentLoader: Loading ${globalContentRegistry.length} registered content modules...`);
|
|
8265
|
-
try {
|
|
8266
|
-
// Load all content
|
|
8267
|
-
contentLoader.loadContent([...globalContentRegistry]);
|
|
8268
|
-
// Clear the registry after loading
|
|
8269
|
-
globalContentRegistry.length = 0;
|
|
8270
|
-
console.log('🎉 ContentLoader: All registered content loaded and registry cleared');
|
|
8271
|
-
}
|
|
8272
|
-
catch (error) {
|
|
8273
|
-
console.error('❌ ContentLoader: Error loading registered content:', error);
|
|
8274
|
-
}
|
|
8275
|
-
}
|
|
8276
|
-
/**
|
|
8277
|
-
* ✅ NEW: Debugging helper
|
|
8278
|
-
* Get current global registry state
|
|
8279
|
-
*/
|
|
8280
|
-
function getRegisteredContentQueue() {
|
|
8281
|
-
return [...globalContentRegistry];
|
|
8282
|
-
}
|
|
8283
|
-
/**
|
|
8284
|
-
* ✅ NEW: Debugging helper
|
|
8285
|
-
* Clear the global registry without loading
|
|
8286
|
-
*/
|
|
8287
|
-
function clearRegisteredContentQueue() {
|
|
8288
|
-
const count = globalContentRegistry.length;
|
|
8289
|
-
globalContentRegistry.length = 0;
|
|
8290
|
-
console.log(`🧹 ContentLoader: Cleared ${count} items from registration queue`);
|
|
8291
|
-
}
|
|
8292
|
-
|
|
8293
7791
|
const text = {
|
|
8294
7792
|
es: {
|
|
8295
7793
|
spanish: 'Español',
|
|
@@ -8456,6 +7954,191 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
8456
7954
|
}]
|
|
8457
7955
|
}], ctorParameters: () => [{ type: i2.ToastController }] });
|
|
8458
7956
|
|
|
7957
|
+
/**
|
|
7958
|
+
* Create a reactive content observable from a content key.
|
|
7959
|
+
* This is the primary utility for the `fromContent` pattern with unified support
|
|
7960
|
+
* for both simple content and content with interpolation.
|
|
7961
|
+
*
|
|
7962
|
+
* @param langService - The language service instance
|
|
7963
|
+
* @param config - Content configuration with optional interpolation
|
|
7964
|
+
* @returns Observable that emits the content string and updates on language change
|
|
7965
|
+
*
|
|
7966
|
+
* @example Simple content:
|
|
7967
|
+
* ```typescript
|
|
7968
|
+
* // Component-specific content
|
|
7969
|
+
* this.title$ = fromContent(this.langService, {
|
|
7970
|
+
* className: 'HeaderComponent',
|
|
7971
|
+
* key: 'title',
|
|
7972
|
+
* fallback: 'Default Title'
|
|
7973
|
+
* });
|
|
7974
|
+
*
|
|
7975
|
+
* // Global content (no className needed)
|
|
7976
|
+
* this.saveButton$ = fromContent(this.langService, {
|
|
7977
|
+
* key: 'save'
|
|
7978
|
+
* });
|
|
7979
|
+
* ```
|
|
7980
|
+
*
|
|
7981
|
+
* @example Content with interpolation:
|
|
7982
|
+
* ```typescript
|
|
7983
|
+
* // Content: "Hello {name}, you have {count} messages"
|
|
7984
|
+
* this.greeting$ = fromContent(this.langService, {
|
|
7985
|
+
* className: 'WelcomeComponent',
|
|
7986
|
+
* key: 'greeting',
|
|
7987
|
+
* interpolation: { name: 'John', count: 5 }
|
|
7988
|
+
* });
|
|
7989
|
+
* // Results in: "Hello John, you have 5 messages"
|
|
7990
|
+
* ```
|
|
7991
|
+
*/
|
|
7992
|
+
function fromContent(langService, config) {
|
|
7993
|
+
// Use _global as default className if not provided
|
|
7994
|
+
const finalClassName = config.className || '_global';
|
|
7995
|
+
const contentObservable = langService.getContent(finalClassName, config.key, config.fallback);
|
|
7996
|
+
// If interpolation is provided, apply it
|
|
7997
|
+
if (config.interpolation) {
|
|
7998
|
+
return contentObservable.pipe(map(content => interpolateContent(content, config.interpolation)));
|
|
7999
|
+
}
|
|
8000
|
+
return contentObservable;
|
|
8001
|
+
}
|
|
8002
|
+
/**
|
|
8003
|
+
* Create a reactive content observable with interpolation support.
|
|
8004
|
+
*
|
|
8005
|
+
* @deprecated Use fromContent() with interpolation property instead.
|
|
8006
|
+
* This method is kept for backward compatibility.
|
|
8007
|
+
*
|
|
8008
|
+
* @param langService - The language service instance
|
|
8009
|
+
* @param config - Interpolated content configuration
|
|
8010
|
+
* @returns Observable that emits the interpolated content string
|
|
8011
|
+
*
|
|
8012
|
+
* @example Migration:
|
|
8013
|
+
* ```typescript
|
|
8014
|
+
* // OLD (deprecated):
|
|
8015
|
+
* this.greeting$ = fromContentWithInterpolation(this.langService, {
|
|
8016
|
+
* className: 'WelcomeComponent',
|
|
8017
|
+
* key: 'greeting',
|
|
8018
|
+
* interpolation: { name: 'John', count: 5 }
|
|
8019
|
+
* });
|
|
8020
|
+
*
|
|
8021
|
+
* // NEW (recommended):
|
|
8022
|
+
* this.greeting$ = fromContent(this.langService, {
|
|
8023
|
+
* className: 'WelcomeComponent',
|
|
8024
|
+
* key: 'greeting',
|
|
8025
|
+
* interpolation: { name: 'John', count: 5 }
|
|
8026
|
+
* });
|
|
8027
|
+
* ```
|
|
8028
|
+
*/
|
|
8029
|
+
function fromContentWithInterpolation(langService, config) {
|
|
8030
|
+
// Delegate to the unified fromContent method
|
|
8031
|
+
return fromContent(langService, config);
|
|
8032
|
+
}
|
|
8033
|
+
/**
|
|
8034
|
+
* Create multiple reactive content observables at once.
|
|
8035
|
+
* Useful when a component needs several content strings.
|
|
8036
|
+
*
|
|
8037
|
+
* @param langService - The language service instance
|
|
8038
|
+
* @param className - The component class name
|
|
8039
|
+
* @param keys - Array of content keys to retrieve
|
|
8040
|
+
* @returns Observable that emits an object with all requested content
|
|
8041
|
+
*
|
|
8042
|
+
* @example
|
|
8043
|
+
* ```typescript
|
|
8044
|
+
* this.content$ = fromMultipleContent(this.langService, 'FormComponent', [
|
|
8045
|
+
* 'title', 'submitButton', 'cancelButton'
|
|
8046
|
+
* ]);
|
|
8047
|
+
*
|
|
8048
|
+
* // In template
|
|
8049
|
+
* <ng-container *ngIf="content$ | async as content">
|
|
8050
|
+
* <h2>{{ content.title }}</h2>
|
|
8051
|
+
* <button>{{ content.submitButton }}</button>
|
|
8052
|
+
* <button>{{ content.cancelButton }}</button>
|
|
8053
|
+
* </ng-container>
|
|
8054
|
+
* ```
|
|
8055
|
+
*/
|
|
8056
|
+
function fromMultipleContent(langService, className, keys) {
|
|
8057
|
+
return langService.getMultipleContent(className, keys);
|
|
8058
|
+
}
|
|
8059
|
+
/**
|
|
8060
|
+
* Helper function to interpolate values into a content string.
|
|
8061
|
+
* Replaces placeholders in the format {key} with corresponding values.
|
|
8062
|
+
*
|
|
8063
|
+
* @param content - The content string with placeholders
|
|
8064
|
+
* @param values - Object with values to interpolate
|
|
8065
|
+
* @returns The interpolated string
|
|
8066
|
+
*
|
|
8067
|
+
* @example
|
|
8068
|
+
* ```typescript
|
|
8069
|
+
* const result = interpolateContent("Hello {name}!", { name: "World" });
|
|
8070
|
+
* // Returns: "Hello World!"
|
|
8071
|
+
* ```
|
|
8072
|
+
*/
|
|
8073
|
+
function interpolateContent(content, values) {
|
|
8074
|
+
if (!values)
|
|
8075
|
+
return content;
|
|
8076
|
+
return Object.entries(values).reduce((result, [key, value]) => {
|
|
8077
|
+
return result.replace(new RegExp(`\\{${key}\\}`, 'g'), String(value));
|
|
8078
|
+
}, content);
|
|
8079
|
+
}
|
|
8080
|
+
/**
|
|
8081
|
+
* Factory function to create a content helper bound to a specific component class.
|
|
8082
|
+
* This creates a more convenient API for components that need multiple content strings.
|
|
8083
|
+
*
|
|
8084
|
+
* @param langService - The language service instance
|
|
8085
|
+
* @param className - The component class name
|
|
8086
|
+
* @returns Object with convenient methods for content retrieval
|
|
8087
|
+
*
|
|
8088
|
+
* @example
|
|
8089
|
+
* ```typescript
|
|
8090
|
+
* export class MyComponent {
|
|
8091
|
+
* private content = createContentHelper(this.langService, 'MyComponent');
|
|
8092
|
+
*
|
|
8093
|
+
* constructor(private langService: LangService) {}
|
|
8094
|
+
*
|
|
8095
|
+
* ngOnInit() {
|
|
8096
|
+
* this.title$ = this.content.get('title');
|
|
8097
|
+
* this.allContent$ = this.content.getMultiple(['title', 'description']);
|
|
8098
|
+
* }
|
|
8099
|
+
* }
|
|
8100
|
+
* ```
|
|
8101
|
+
*/
|
|
8102
|
+
function createContentHelper(langService, className) {
|
|
8103
|
+
return {
|
|
8104
|
+
/**
|
|
8105
|
+
* Get a single content string reactively.
|
|
8106
|
+
*/
|
|
8107
|
+
get(key, fallback) {
|
|
8108
|
+
return fromContent(langService, { className, key, fallback });
|
|
8109
|
+
},
|
|
8110
|
+
/**
|
|
8111
|
+
* Get multiple content strings reactively.
|
|
8112
|
+
*/
|
|
8113
|
+
getMultiple(keys) {
|
|
8114
|
+
return fromMultipleContent(langService, className, keys);
|
|
8115
|
+
},
|
|
8116
|
+
/**
|
|
8117
|
+
* Get content with interpolation.
|
|
8118
|
+
*/
|
|
8119
|
+
getWithInterpolation(key, interpolation, fallback) {
|
|
8120
|
+
return fromContentWithInterpolation(langService, {
|
|
8121
|
+
className,
|
|
8122
|
+
key,
|
|
8123
|
+
interpolation,
|
|
8124
|
+
fallback,
|
|
8125
|
+
});
|
|
8126
|
+
},
|
|
8127
|
+
/**
|
|
8128
|
+
* Get a single content string synchronously (current language only).
|
|
8129
|
+
*/
|
|
8130
|
+
getText(key, fallback) {
|
|
8131
|
+
return langService.getText(className, key, fallback);
|
|
8132
|
+
},
|
|
8133
|
+
/**
|
|
8134
|
+
* Check if a content key exists.
|
|
8135
|
+
*/
|
|
8136
|
+
hasContent(key) {
|
|
8137
|
+
return langService.hasContent(className, key);
|
|
8138
|
+
},
|
|
8139
|
+
};
|
|
8140
|
+
}
|
|
8141
|
+
|
|
8459
8142
|
/*
|
|
8460
8143
|
* Public API Surface of valtech-components
|
|
8461
8144
|
*/
|
|
@@ -8464,5 +8147,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
8464
8147
|
* Generated bundle index. Do not edit.
|
|
8465
8148
|
*/
|
|
8466
8149
|
|
|
8467
|
-
export { ARTICLE_SPACING, ActionType, AlertBoxComponent, ArticleBuilder, ArticleComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent,
|
|
8150
|
+
export { ARTICLE_SPACING, ActionType, AlertBoxComponent, ArticleBuilder, ArticleComponent, AvatarComponent, BannerComponent, BaseDefault, BoxComponent, ButtonComponent, ButtonGroupComponent, CardComponent, CardSection, CardType, CheckInputComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CommentInputComponent, ComponentStates, ContentLoaderComponent, DateInputComponent, DisplayComponent, DividerComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FileInputComponent, FooterComponent, FormComponent, FormFooterComponent, GlobalContent, HeaderComponent, HintComponent, HourInputComponent, HrefComponent, Icon, IconComponent, IconService, ImageComponent, InAppBrowserService, InputType, ItemListComponent, LANGUAGES, LangService, LanguageSelectorComponent, LayeredCardComponent, LayoutComponent, LinkComponent, LinkProcessorService, LinksCakeComponent, LocalStorageService, MOTION, NavigationService, NoContentComponent, NotesBoxComponent, NumberInputComponent, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PasswordInputComponent, PinInputComponent, PopoverSelectorComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProgressBarComponent, ProgressStatusComponent, PrompterComponent, RadioInputComponent, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SelectSearchComponent, SimpleComponent, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, TextComponent, TextContent, TextInputComponent, ThemeOption, ThemeService, TitleBlockComponent, TitleComponent, ToastService, ToolbarActionType, ToolbarComponent, ValtechConfigService, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, content, createButtonProps, createContentHelper, createDisplayProps, createReactiveContentMetadata, createTextProps, createTitleProps, extractContentConfig, extractContentConfigWithInterpolation, fromContent, fromContentWithInterpolation, fromMultipleContent, globalContentData, goToTop, interpolateContent, interpolateStaticContent, isAtEnd, maxLength, replaceSpecialChars, resolveColor, resolveInputDefaultValue, shouldUseReactiveContent, shouldUseReactiveContentWithInterpolation };
|
|
8468
8151
|
//# sourceMappingURL=valtech-components.mjs.map
|