@smartsoft001-mobilems/angular 2.9.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,18 @@
1
1
  import { __decorate, __metadata } from 'tslib';
2
2
  import * as i0 from '@angular/core';
3
- import { Injectable, inject, signal, Component, Directive, effect, contentChild, HostListener, Inject, APP_INITIALIZER, NgModule } from '@angular/core';
4
- import { DomSanitizer } from '@angular/platform-browser';
5
- import { ReduxAction, AppBaseComponent, PageBaseComponent, BaseComponent } from '@smartsoft001/angular';
3
+ import { Injectable, inject, PLATFORM_ID, signal, effect, computed, Component, Directive, contentChild, HostListener, Inject, ElementRef, input, APP_INITIALIZER, NgModule } from '@angular/core';
4
+ import { Meta, Title, DomSanitizer } from '@angular/platform-browser';
5
+ import { StyleService as StyleService$1, ReduxAction, AppBaseComponent, PageBaseComponent, BaseComponent } from '@smartsoft001/angular';
6
6
  import { HttpClient } from '@angular/common/http';
7
7
  import * as moment from 'moment';
8
8
  import { lastValueFrom, combineLatest, firstValueFrom, of, throwError } from 'rxjs';
9
- import { map, catchError } from 'rxjs/operators';
9
+ import { map, filter, catchError } from 'rxjs/operators';
10
+ import { isPlatformBrowser, DOCUMENT } from '@angular/common';
11
+ import { Router, ActivatedRoute, NavigationEnd, RouterOutlet, RouterModule } from '@angular/router';
12
+ import { TranslateService } from '@ngx-translate/core';
10
13
  import { CrudService, CrudFacade } from '@smartsoft001/crud-shell-angular';
11
- import { RouterOutlet, RouterModule } from '@angular/router';
12
14
  import * as _ from 'lodash';
13
15
  import { Debounce } from 'lodash-decorators';
14
- import { DOCUMENT } from '@angular/common';
15
16
 
16
17
  function setTranslationsAndLang(service) {
17
18
  const map = {
@@ -35,11 +36,57 @@ const TRANSLATE_DATA_PL = {
35
36
  const environment = {
36
37
  production: false,
37
38
  apiUrl: '',
39
+ multimediaUrl: '',
40
+ mainLogoPath: '/assets/gfx/logo/main-logo.png',
38
41
  };
39
42
 
43
+ class AuthStorageService {
44
+ constructor() {
45
+ this.STORAGE_KEY = 'user';
46
+ }
47
+ setUser(user) {
48
+ if (typeof localStorage !== 'undefined') {
49
+ localStorage.setItem(this.STORAGE_KEY, JSON.stringify(user));
50
+ }
51
+ }
52
+ getUser() {
53
+ if (typeof localStorage !== 'undefined') {
54
+ const item = localStorage.getItem(this.STORAGE_KEY);
55
+ if (item) {
56
+ try {
57
+ return JSON.parse(item);
58
+ }
59
+ catch (error) {
60
+ console.error('Failed to parse user from localStorage', error);
61
+ return null;
62
+ }
63
+ }
64
+ }
65
+ return null;
66
+ }
67
+ removeUser() {
68
+ if (typeof localStorage !== 'undefined') {
69
+ localStorage.removeItem(this.STORAGE_KEY);
70
+ }
71
+ }
72
+ hasUser() {
73
+ return this.getUser() !== null;
74
+ }
75
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: AuthStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
76
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: AuthStorageService, providedIn: 'root' }); }
77
+ }
78
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: AuthStorageService, decorators: [{
79
+ type: Injectable,
80
+ args: [{
81
+ providedIn: 'root',
82
+ }]
83
+ }] });
84
+
40
85
  class SharedConfig {
41
86
  constructor() {
42
87
  this.apiUrl = '';
88
+ this.multimediaUrl = '';
89
+ this.mainLogoPath = '/assets/gfx/logo/main-logo.png';
43
90
  }
44
91
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SharedConfig, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
45
92
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SharedConfig }); }
@@ -87,6 +134,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
87
134
  }]
88
135
  }] });
89
136
 
137
+ const DEFAULT_COLORS = {
138
+ black: 'black',
139
+ yellow: 'yellow',
140
+ white: 'white',
141
+ transparentBlack: 'rgba(0, 0, 0, 0.9)',
142
+ wcagColor1: '#F4B735',
143
+ wcagColor2: '#1B1B1B',
144
+ };
145
+ class ContrastService {
146
+ constructor() {
147
+ this.platformId = inject(PLATFORM_ID);
148
+ this.isBrowser = isPlatformBrowser(this.platformId);
149
+ this.isActive = signal(false, ...(ngDevMode ? [{ debugName: "isActive" }] : []));
150
+ // Apply contrast changes to DOM
151
+ effect(() => {
152
+ if (this.isBrowser) {
153
+ this.applyContrast(this.isActive());
154
+ }
155
+ });
156
+ }
157
+ changeTheme(active) {
158
+ this.isActive.set(active);
159
+ }
160
+ toggle() {
161
+ this.isActive.update((value) => !value);
162
+ }
163
+ applyContrast(active) {
164
+ if (!this.isBrowser)
165
+ return;
166
+ const docElement = document.documentElement;
167
+ if (active) {
168
+ this.setProperties(docElement);
169
+ docElement.classList.add('cv');
170
+ }
171
+ else {
172
+ this.removeProperties(docElement);
173
+ docElement.classList.remove('cv');
174
+ }
175
+ }
176
+ setProperties(element) {
177
+ element.style.setProperty('--cv-black', DEFAULT_COLORS.black);
178
+ element.style.setProperty('--cv-yellow', DEFAULT_COLORS.yellow);
179
+ element.style.setProperty('--cv-white', DEFAULT_COLORS.white);
180
+ element.style.setProperty('--cv-black-transparent', DEFAULT_COLORS.transparentBlack);
181
+ element.style.setProperty('--cv-wcag-color-1', DEFAULT_COLORS.wcagColor1);
182
+ element.style.setProperty('--cv-wcag-color-2', DEFAULT_COLORS.wcagColor2);
183
+ }
184
+ removeProperties(element) {
185
+ element.style.removeProperty('--cv-black');
186
+ element.style.removeProperty('--cv-yellow');
187
+ element.style.removeProperty('--cv-white');
188
+ element.style.removeProperty('--cv-black-transparent');
189
+ element.style.removeProperty('--cv-wcag-color-1');
190
+ element.style.removeProperty('--cv-wcag-color-2');
191
+ }
192
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ContrastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
193
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ContrastService, providedIn: 'root' }); }
194
+ }
195
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ContrastService, decorators: [{
196
+ type: Injectable,
197
+ args: [{
198
+ providedIn: 'root',
199
+ }]
200
+ }], ctorParameters: () => [] });
201
+
90
202
  class DictionaryService {
91
203
  constructor() {
92
204
  this.httpClient = inject(HttpClient);
@@ -126,6 +238,561 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
126
238
  }]
127
239
  }] });
128
240
 
241
+ class FileUrlService {
242
+ constructor() {
243
+ this.config = inject(SharedConfig);
244
+ }
245
+ get(fileOrPath, mode = 'cache', noImagePlaceholder = 'assets/no-image.svg') {
246
+ const multimediaUrl = this.config.multimediaUrl;
247
+ if (!multimediaUrl) {
248
+ return noImagePlaceholder;
249
+ }
250
+ let path;
251
+ if (typeof fileOrPath === 'string') {
252
+ path = fileOrPath;
253
+ }
254
+ else {
255
+ if (!fileOrPath || !fileOrPath.filePath) {
256
+ return noImagePlaceholder;
257
+ }
258
+ // Check if it's an upload path (direct URL)
259
+ if (fileOrPath.filePath.indexOf('upload') === -1) {
260
+ return (multimediaUrl + this.getPath(mode) + this.getFileName(fileOrPath));
261
+ }
262
+ path = fileOrPath.filePath;
263
+ }
264
+ // Remove leading slash if present
265
+ if (path[0] === '/') {
266
+ path = path.substring(1);
267
+ }
268
+ return multimediaUrl + path;
269
+ }
270
+ getFileName(file) {
271
+ if (file.filePath &&
272
+ file.extension &&
273
+ file.filePath.indexOf(file.extension) > -1) {
274
+ return file.filePath;
275
+ }
276
+ return file.filePath + '.' + file.extension;
277
+ }
278
+ getPath(mode) {
279
+ switch (mode) {
280
+ case 'big':
281
+ return 'upload/cache/multimedia_big/';
282
+ case 'cache':
283
+ return 'upload/cache/multimedia_detail/';
284
+ case 'noCache':
285
+ return 'upload/multimedia/';
286
+ }
287
+ }
288
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FileUrlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
289
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FileUrlService, providedIn: 'root' }); }
290
+ }
291
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: FileUrlService, decorators: [{
292
+ type: Injectable,
293
+ args: [{
294
+ providedIn: 'root',
295
+ }]
296
+ }] });
297
+
298
+ class GlobalService {
299
+ constructor() {
300
+ this.showHeader = signal(true, ...(ngDevMode ? [{ debugName: "showHeader" }] : []));
301
+ this.showFooter = signal(true, ...(ngDevMode ? [{ debugName: "showFooter" }] : []));
302
+ }
303
+ setHeaderVisibility(visible) {
304
+ this.showHeader.set(visible);
305
+ }
306
+ setFooterVisibility(visible) {
307
+ this.showFooter.set(visible);
308
+ }
309
+ hexToRgb(hex) {
310
+ if (!hex)
311
+ return null;
312
+ // Remove # if present
313
+ let cleanHex = hex.replace(/^#/, '');
314
+ // Expand 3-character hex to 6-character (#abc -> #aabbcc)
315
+ if (cleanHex.length === 3) {
316
+ cleanHex = cleanHex
317
+ .split('')
318
+ .map((char) => char + char)
319
+ .join('');
320
+ }
321
+ // Parse 6-character hex
322
+ const result = cleanHex.match(/.{2}/g);
323
+ if (!result || result.length !== 3)
324
+ return null;
325
+ return result.map((x) => parseInt(x, 16));
326
+ }
327
+ rgbToHex(r, g, b) {
328
+ return ('#' +
329
+ [r, g, b]
330
+ .map((x) => {
331
+ const hex = x.toString(16);
332
+ return hex.length === 1 ? '0' + hex : hex;
333
+ })
334
+ .join(''));
335
+ }
336
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GlobalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
337
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GlobalService, providedIn: 'root' }); }
338
+ }
339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: GlobalService, decorators: [{
340
+ type: Injectable,
341
+ args: [{
342
+ providedIn: 'root',
343
+ }]
344
+ }] });
345
+
346
+ const TRANSLATION_CONFIG_KEY = 'TRANSLATION_CONFIG';
347
+ class TranslationService {
348
+ constructor() {
349
+ this.translateService = inject(TranslateService);
350
+ this._config = signal({
351
+ language: this.getInitialLanguage(),
352
+ }, ...(ngDevMode ? [{ debugName: "_config" }] : []));
353
+ this.config = this._config.asReadonly();
354
+ this.config$ = this.translateService.onLangChange.pipe();
355
+ this.currentLanguage = computed(() => this._config().language, ...(ngDevMode ? [{ debugName: "currentLanguage" }] : []));
356
+ }
357
+ getInitialLanguage() {
358
+ if (typeof localStorage !== 'undefined') {
359
+ const stored = localStorage.getItem(TRANSLATION_CONFIG_KEY);
360
+ if (stored) {
361
+ try {
362
+ const parsed = JSON.parse(stored);
363
+ return parsed.language;
364
+ }
365
+ catch (error) {
366
+ console.warn('Failed to parse translation config', error);
367
+ }
368
+ }
369
+ }
370
+ return this.translateService.getBrowserLang() || 'en';
371
+ }
372
+ get(key, params) {
373
+ return this.translateService.instant(key, params);
374
+ }
375
+ async init(defaultLang = 'en', availableLangs = ['en', 'pl']) {
376
+ this.translateService.setDefaultLang(defaultLang);
377
+ this.translateService.addLangs(availableLangs);
378
+ let lang = this._config().language;
379
+ if (!availableLangs.includes(lang)) {
380
+ lang = defaultLang;
381
+ this._config.set({ language: lang });
382
+ }
383
+ await this.translateService.use(lang).toPromise();
384
+ }
385
+ setLanguage(language) {
386
+ this._config.set({ language });
387
+ this.save();
388
+ this.translateService.use(language);
389
+ }
390
+ save() {
391
+ if (typeof localStorage !== 'undefined') {
392
+ localStorage.setItem(TRANSLATION_CONFIG_KEY, JSON.stringify(this._config()));
393
+ }
394
+ }
395
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: TranslationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
396
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: TranslationService, providedIn: 'root' }); }
397
+ }
398
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: TranslationService, decorators: [{
399
+ type: Injectable,
400
+ args: [{
401
+ providedIn: 'root',
402
+ }]
403
+ }] });
404
+
405
+ class MetaService {
406
+ constructor() {
407
+ this.meta = inject(Meta);
408
+ this.title = inject(Title);
409
+ this.translationService = inject(TranslationService);
410
+ this.router = inject(Router);
411
+ this.activatedRoute = inject(ActivatedRoute);
412
+ this.config = inject(SharedConfig);
413
+ this.resetMetadata();
414
+ }
415
+ keepUpdatingPageTitle(onRouteChange) {
416
+ if (onRouteChange) {
417
+ this.routerSubscription = this.router.events
418
+ .pipe(filter((event) => event instanceof NavigationEnd), map(() => this.getRouteTitle()))
419
+ .subscribe((dynamicTitle) => {
420
+ if (dynamicTitle) {
421
+ this.setTitle(dynamicTitle);
422
+ }
423
+ });
424
+ return this.routerSubscription;
425
+ }
426
+ else {
427
+ const dynamicTitle = this.getRouteTitle();
428
+ if (dynamicTitle) {
429
+ this.setTitle(dynamicTitle);
430
+ }
431
+ }
432
+ }
433
+ setPageMetadata(title = '', description = '') {
434
+ if (title) {
435
+ this.setTitle(title);
436
+ }
437
+ if (description) {
438
+ this.setDescription(description);
439
+ }
440
+ }
441
+ setObjectMetadata(objectData) {
442
+ if (objectData.image) {
443
+ this.setImageMetadata(objectData.image, objectData.title, objectData.type);
444
+ }
445
+ if (objectData.title) {
446
+ this.setTitle(objectData.title);
447
+ }
448
+ if (objectData.description) {
449
+ this.setDescription(objectData.description);
450
+ }
451
+ }
452
+ setImageMetadata(image, imageAlt, type) {
453
+ const multimediaUrl = this.config.multimediaUrl;
454
+ if (!multimediaUrl || !image?.filePath) {
455
+ return;
456
+ }
457
+ try {
458
+ const imageUrl = this.buildImageUrl(multimediaUrl, image, type);
459
+ this.meta.updateTag({ property: 'og:image', content: imageUrl });
460
+ this.meta.updateTag({ property: 'og:image:type', content: 'image/jpeg' });
461
+ this.meta.updateTag({ property: 'og:image:width', content: '600' });
462
+ this.meta.updateTag({ property: 'og:image:height', content: '600' });
463
+ if (imageAlt) {
464
+ this.meta.updateTag({
465
+ property: 'og:image:alt',
466
+ content: this.removeHtmlTags(imageAlt),
467
+ });
468
+ }
469
+ else {
470
+ this.meta.removeTag("property='og:image:alt'");
471
+ }
472
+ }
473
+ catch (error) {
474
+ console.warn('Failed to set image metadata', error);
475
+ }
476
+ }
477
+ resetMetadata() {
478
+ const baseTitle = this.translationService.get('base-portal-title') || 'Portal';
479
+ this.meta.updateTag({ property: 'og:type', content: 'website' });
480
+ this.meta.updateTag({ property: 'og:title', content: baseTitle });
481
+ this.meta.updateTag({ property: 'og:description', content: '' });
482
+ this.meta.updateTag({ name: 'description', content: '' });
483
+ this.meta.updateTag({
484
+ property: 'og:image',
485
+ content: 'assets/gfx/no-img/no-img-header.jpg',
486
+ });
487
+ this.meta.updateTag({ property: 'og:image:alt', content: baseTitle });
488
+ this.meta.updateTag({ property: 'og:image:type', content: 'image/jpeg' });
489
+ this.meta.updateTag({ property: 'og:image:width', content: '250' });
490
+ this.meta.updateTag({ property: 'og:image:height', content: '250' });
491
+ }
492
+ updateTag(tag) {
493
+ this.meta.updateTag(tag);
494
+ }
495
+ setTitle(titleText) {
496
+ const plainTitle = this.removeHtmlTags(titleText);
497
+ this.title.setTitle(plainTitle);
498
+ this.meta.updateTag({ property: 'og:title', content: plainTitle });
499
+ }
500
+ setDescription(description) {
501
+ const plainDesc = this.removeHtmlTags(description);
502
+ this.meta.updateTag({ property: 'og:description', content: plainDesc });
503
+ this.meta.updateTag({ name: 'description', content: plainDesc });
504
+ }
505
+ destroy() {
506
+ this.routerSubscription?.unsubscribe();
507
+ }
508
+ buildImageUrl(baseUrl, image, type) {
509
+ const cleanBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
510
+ if (type === 'object' && image.filePath) {
511
+ return `${cleanBaseUrl}/${image.filePath}.jpg`;
512
+ }
513
+ return `${cleanBaseUrl}/${image.filePath}`;
514
+ }
515
+ removeHtmlTags(value) {
516
+ if (!value)
517
+ return '';
518
+ return value
519
+ .replace(/<.*?>/g, '')
520
+ .replace(/&nbsp;/g, ' ')
521
+ .replace(/&hyphen;/g, '-')
522
+ .replace(/&ndash;/g, '-')
523
+ .replace(/&mdash;/g, '-')
524
+ .replace(/&#8211;/g, '-')
525
+ .replace(/&#8212;/g, '-')
526
+ .replace(/&bdquo;/g, '"')
527
+ .replace(/&oacute;/g, 'ó')
528
+ .replace(/&rdquo;/g, '"')
529
+ .replace(/&quot;/g, '"');
530
+ }
531
+ getRouteTitle() {
532
+ let child = this.activatedRoute.firstChild;
533
+ while (child?.firstChild) {
534
+ child = child.firstChild;
535
+ }
536
+ if (!child)
537
+ return '';
538
+ const snapshot = child.snapshot;
539
+ if (snapshot.data['subtitle']) {
540
+ return snapshot.data['subtitle'];
541
+ }
542
+ if (snapshot.data['title']) {
543
+ return snapshot.data['title'];
544
+ }
545
+ return '';
546
+ }
547
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: MetaService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
548
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: MetaService, providedIn: 'root' }); }
549
+ }
550
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: MetaService, decorators: [{
551
+ type: Injectable,
552
+ args: [{
553
+ providedIn: 'root',
554
+ }]
555
+ }], ctorParameters: () => [] });
556
+
557
+ class SeoService {
558
+ constructor() {
559
+ this.title = inject(Title);
560
+ this.meta = inject(Meta);
561
+ }
562
+ updateTitle(titleText) {
563
+ const decodedTitle = this.decodeHtml(titleText);
564
+ if (decodedTitle) {
565
+ this.title.setTitle(decodedTitle);
566
+ }
567
+ }
568
+ updateMetaTags(metaTags) {
569
+ metaTags.forEach((tag) => this.meta.updateTag(tag));
570
+ }
571
+ updateDescription(description) {
572
+ const decodedDesc = this.decodeHtml(description);
573
+ if (decodedDesc) {
574
+ this.meta.updateTag({ name: 'description', content: decodedDesc });
575
+ }
576
+ }
577
+ updateOgTags(title, description, image, url) {
578
+ const tags = [];
579
+ if (title) {
580
+ tags.push({
581
+ property: 'og:title',
582
+ content: this.decodeHtml(title) || title,
583
+ });
584
+ }
585
+ if (description) {
586
+ tags.push({
587
+ property: 'og:description',
588
+ content: this.decodeHtml(description) || description,
589
+ });
590
+ }
591
+ if (image) {
592
+ tags.push({ property: 'og:image', content: image });
593
+ }
594
+ if (url) {
595
+ tags.push({ property: 'og:url', content: url });
596
+ }
597
+ this.updateMetaTags(tags);
598
+ }
599
+ decodeHtml(encodedStr) {
600
+ if (!encodedStr)
601
+ return encodedStr;
602
+ try {
603
+ const parser = new DOMParser();
604
+ const doc = parser.parseFromString(encodedStr, 'text/html');
605
+ return doc.documentElement.textContent;
606
+ }
607
+ catch (error) {
608
+ console.warn('Failed to decode HTML', error);
609
+ return encodedStr;
610
+ }
611
+ }
612
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SeoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
613
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SeoService, providedIn: 'root' }); }
614
+ }
615
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SeoService, decorators: [{
616
+ type: Injectable,
617
+ args: [{
618
+ providedIn: 'root',
619
+ }]
620
+ }] });
621
+
622
+ class SettingsService {
623
+ constructor() {
624
+ this.translationService = inject(TranslationService);
625
+ this.config = inject(SharedConfig);
626
+ }
627
+ getMediaUrl() {
628
+ const multimediaUrl = this.config.multimediaUrl;
629
+ if (!multimediaUrl) {
630
+ return '';
631
+ }
632
+ // Remove trailing slash if present
633
+ return multimediaUrl.endsWith('/')
634
+ ? multimediaUrl.substring(0, multimediaUrl.length - 1)
635
+ : multimediaUrl;
636
+ }
637
+ getBaseTitle() {
638
+ return this.translationService.get('base-portal-title');
639
+ }
640
+ getCanLink() {
641
+ // Could be extended with preview mode config in the future
642
+ return true;
643
+ }
644
+ getMainLogo() {
645
+ return this.config.mainLogoPath;
646
+ }
647
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
648
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SettingsService, providedIn: 'root' }); }
649
+ }
650
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: SettingsService, decorators: [{
651
+ type: Injectable,
652
+ args: [{
653
+ providedIn: 'root',
654
+ }]
655
+ }] });
656
+
657
+ class StyleService {
658
+ constructor() {
659
+ this.smartStyleService = inject(StyleService$1);
660
+ this.config = inject(SharedConfig);
661
+ }
662
+ init(elementRef, customVariables) {
663
+ const variables = {
664
+ ...this.config.styleVariables,
665
+ ...customVariables,
666
+ };
667
+ this.smartStyleService.init(elementRef, variables);
668
+ }
669
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: StyleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
670
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: StyleService, providedIn: 'root' }); }
671
+ }
672
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: StyleService, decorators: [{
673
+ type: Injectable,
674
+ args: [{
675
+ providedIn: 'root',
676
+ }]
677
+ }] });
678
+
679
+ const WCAG_CONFIG_KEY = 'WCAG_CONFIG';
680
+ const DEFAULT_CONFIG = {
681
+ contrast: 'normal',
682
+ text: 'normal',
683
+ letterSpacing: 'small',
684
+ wordSpacing: 'small',
685
+ };
686
+ class WcagService {
687
+ constructor() {
688
+ this.translationService = inject(TranslationService);
689
+ this.platformId = inject(PLATFORM_ID);
690
+ this.isBrowser = isPlatformBrowser(this.platformId);
691
+ this._config = signal(this.loadConfig(), ...(ngDevMode ? [{ debugName: "_config" }] : []));
692
+ this.config = this._config.asReadonly();
693
+ this.wordSpacingValue = computed(() => this.getSpacingValue(this._config().wordSpacing), ...(ngDevMode ? [{ debugName: "wordSpacingValue" }] : []));
694
+ this.letterSpacingValue = computed(() => this.getSpacingValue(this._config().letterSpacing), ...(ngDevMode ? [{ debugName: "letterSpacingValue" }] : []));
695
+ // Apply config changes to DOM
696
+ effect(() => {
697
+ const config = this._config();
698
+ this.applyConfigToDOM(config);
699
+ });
700
+ }
701
+ async init() {
702
+ // Config is already loaded in constructor
703
+ // This method kept for backward compatibility
704
+ }
705
+ setContrast(value) {
706
+ this._config.update((config) => ({ ...config, contrast: value }));
707
+ this.announceChange('setContrast', value);
708
+ this.save();
709
+ }
710
+ setText(value) {
711
+ this._config.update((config) => ({ ...config, text: value }));
712
+ this.announceChange('setText', value);
713
+ this.save();
714
+ }
715
+ setLetterSpacing(value) {
716
+ this._config.update((config) => ({ ...config, letterSpacing: value }));
717
+ this.announceChange('setLetterSpacing', value);
718
+ this.save();
719
+ }
720
+ setWordSpacing(value) {
721
+ this._config.update((config) => ({ ...config, wordSpacing: value }));
722
+ this.announceChange('setWordSpacing', value);
723
+ this.save();
724
+ }
725
+ reset() {
726
+ this._config.set(DEFAULT_CONFIG);
727
+ this.save();
728
+ }
729
+ getSpacingValue(spacing) {
730
+ switch (spacing) {
731
+ case 'normal':
732
+ return 1;
733
+ case 'large':
734
+ return 2;
735
+ default:
736
+ return 0;
737
+ }
738
+ }
739
+ loadConfig() {
740
+ if (this.isBrowser && typeof localStorage !== 'undefined') {
741
+ const stored = localStorage.getItem(WCAG_CONFIG_KEY);
742
+ if (stored) {
743
+ try {
744
+ const parsed = JSON.parse(stored);
745
+ return { ...DEFAULT_CONFIG, ...parsed };
746
+ }
747
+ catch (error) {
748
+ console.warn('Failed to parse WCAG config', error);
749
+ }
750
+ }
751
+ }
752
+ return DEFAULT_CONFIG;
753
+ }
754
+ save() {
755
+ if (this.isBrowser && typeof localStorage !== 'undefined') {
756
+ localStorage.setItem(WCAG_CONFIG_KEY, JSON.stringify(this._config()));
757
+ }
758
+ }
759
+ applyConfigToDOM(config) {
760
+ if (!this.isBrowser)
761
+ return;
762
+ const body = document.getElementsByTagName('body')[0];
763
+ if (!body)
764
+ return;
765
+ body.className = '';
766
+ body.className += ` contrast-${config.contrast}`;
767
+ body.className += ` text-${config.text}`;
768
+ body.className += ` letter-spacing-${config.letterSpacing}`;
769
+ body.className += ` word-spacing-${config.wordSpacing}`;
770
+ }
771
+ announceChange(type, value) {
772
+ if (!this.isBrowser)
773
+ return;
774
+ let announceElement = document.getElementById('wcag-change');
775
+ if (!announceElement) {
776
+ announceElement = document.createElement('span');
777
+ announceElement.id = 'wcag-change';
778
+ announceElement.className = 'sr-only';
779
+ announceElement.setAttribute('aria-atomic', 'true');
780
+ announceElement.setAttribute('aria-live', 'polite');
781
+ document.body.appendChild(announceElement);
782
+ }
783
+ const translationKey = `WCAG.${type}.${value}`;
784
+ announceElement.innerHTML = this.translationService.get(translationKey);
785
+ }
786
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: WcagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
787
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: WcagService, providedIn: 'root' }); }
788
+ }
789
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: WcagService, decorators: [{
790
+ type: Injectable,
791
+ args: [{
792
+ providedIn: 'root',
793
+ }]
794
+ }], ctorParameters: () => [] });
795
+
129
796
  class CrudBaseService extends CrudService {
130
797
  downloadPdf(name, id) {
131
798
  return fetch(this.config.apiUrl + this.getUrlNameForDetails() + '/' + id + '/pdf')
@@ -210,7 +877,21 @@ class CrudBaseService extends CrudService {
210
877
  }
211
878
  }
212
879
 
213
- const SERVICES = [DictionaryService, ConfigsService, ConfigsFacade];
880
+ const SERVICES = [
881
+ DictionaryService,
882
+ ConfigsService,
883
+ ConfigsFacade,
884
+ AuthStorageService,
885
+ TranslationService,
886
+ GlobalService,
887
+ FileUrlService,
888
+ SettingsService,
889
+ WcagService,
890
+ ContrastService,
891
+ MetaService,
892
+ SeoService,
893
+ StyleService,
894
+ ];
214
895
 
215
896
  class ConfigsFacade {
216
897
  constructor() {
@@ -652,6 +1333,161 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImpor
652
1333
 
653
1334
  const COMPONENTS = [AppComponent];
654
1335
 
1336
+ /**
1337
+ * Directive that adds a "hover" CSS class to the host element on mouse enter
1338
+ * and removes it on mouse leave.
1339
+ *
1340
+ * @example
1341
+ * ```html
1342
+ * <div smartHover>Hover me</div>
1343
+ * ```
1344
+ */
1345
+ class HoverDirective {
1346
+ constructor() {
1347
+ this.el = inject(ElementRef);
1348
+ }
1349
+ /**
1350
+ * Adds the "hover" class when the mouse enters the element
1351
+ */
1352
+ onMouseEnter() {
1353
+ this.el.nativeElement.classList.add('hover');
1354
+ }
1355
+ /**
1356
+ * Removes the "hover" class when the mouse leaves the element
1357
+ */
1358
+ onMouseLeave() {
1359
+ this.el.nativeElement.classList.remove('hover');
1360
+ }
1361
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: HoverDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1362
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.1.0", type: HoverDirective, isStandalone: true, selector: "[smartHover]", host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, ngImport: i0 }); }
1363
+ }
1364
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: HoverDirective, decorators: [{
1365
+ type: Directive,
1366
+ args: [{
1367
+ selector: '[smartHover]',
1368
+ standalone: true,
1369
+ }]
1370
+ }], propDecorators: { onMouseEnter: [{
1371
+ type: HostListener,
1372
+ args: ['mouseenter']
1373
+ }], onMouseLeave: [{
1374
+ type: HostListener,
1375
+ args: ['mouseleave']
1376
+ }] } });
1377
+
1378
+ /**
1379
+ * Directive that provides programmatic scrolling and overflow detection
1380
+ * for horizontally or vertically scrollable containers.
1381
+ *
1382
+ * @example
1383
+ * ```html
1384
+ * <div smartScrollable [scrollUnit]="200" #scroll="smartScrollable">
1385
+ * <!-- scrollable content -->
1386
+ * </div>
1387
+ * <button (click)="scroll.scrollHorizontal(1)" [disabled]="!scroll.canScrollEndHorizontal">
1388
+ * Next →
1389
+ * </button>
1390
+ * ```
1391
+ */
1392
+ class ScrollableDirective {
1393
+ constructor() {
1394
+ this.el = inject(ElementRef);
1395
+ /**
1396
+ * The number of pixels to scroll per unit when using scroll methods.
1397
+ * Can be updated dynamically to change scroll behavior.
1398
+ */
1399
+ this.scrollUnit = input.required(...(ngDevMode ? [{ debugName: "scrollUnit" }] : []));
1400
+ /** Indicates if the container can scroll further to the right */
1401
+ this.canScrollEndHorizontal = signal(false, ...(ngDevMode ? [{ debugName: "canScrollEndHorizontal" }] : []));
1402
+ /** Indicates if the container can scroll further to the left */
1403
+ this.canScrollStartHorizontal = signal(false, ...(ngDevMode ? [{ debugName: "canScrollStartHorizontal" }] : []));
1404
+ /** Indicates if the container can scroll further down */
1405
+ this.canScrollEndVertical = signal(false, ...(ngDevMode ? [{ debugName: "canScrollEndVertical" }] : []));
1406
+ /** Indicates if the container can scroll further up */
1407
+ this.canScrollStartVertical = signal(false, ...(ngDevMode ? [{ debugName: "canScrollStartVertical" }] : []));
1408
+ /** Current horizontal scroll position */
1409
+ this.scrollLeftPosition = signal(0, ...(ngDevMode ? [{ debugName: "scrollLeftPosition" }] : []));
1410
+ /** Current vertical scroll position */
1411
+ this.scrollTopPosition = signal(0, ...(ngDevMode ? [{ debugName: "scrollTopPosition" }] : []));
1412
+ // Update overflow detection when scrollUnit changes
1413
+ effect(() => {
1414
+ this.scrollUnit();
1415
+ this.updateOverflow();
1416
+ });
1417
+ }
1418
+ ngOnInit() {
1419
+ this.updateOverflow();
1420
+ this.addScrollListener();
1421
+ this.addResizeListener();
1422
+ }
1423
+ /**
1424
+ * Scrolls the container horizontally by the specified number of units.
1425
+ * @param units Number of scroll units (can be negative for backward scroll)
1426
+ */
1427
+ scrollHorizontal(units) {
1428
+ const element = this.el.nativeElement;
1429
+ const scrollAmount = units * this.scrollUnit();
1430
+ element.scrollLeft += scrollAmount;
1431
+ this.updateOverflow();
1432
+ }
1433
+ /**
1434
+ * Scrolls the container vertically by the specified number of units.
1435
+ * @param units Number of scroll units (can be negative for upward scroll)
1436
+ */
1437
+ scrollVertical(units) {
1438
+ const element = this.el.nativeElement;
1439
+ const scrollAmount = units * this.scrollUnit();
1440
+ element.scrollTop += scrollAmount;
1441
+ this.updateOverflow();
1442
+ }
1443
+ /**
1444
+ * Updates all overflow detection signals based on current scroll position
1445
+ */
1446
+ updateOverflow() {
1447
+ const element = this.el.nativeElement;
1448
+ // Horizontal overflow detection
1449
+ const scrollLeft = element.scrollLeft;
1450
+ const scrollWidth = element.scrollWidth;
1451
+ const clientWidth = element.clientWidth;
1452
+ this.scrollLeftPosition.set(scrollLeft);
1453
+ this.canScrollStartHorizontal.set(scrollLeft > 0);
1454
+ this.canScrollEndHorizontal.set(scrollLeft + clientWidth < scrollWidth);
1455
+ // Vertical overflow detection
1456
+ const scrollTop = element.scrollTop;
1457
+ const scrollHeight = element.scrollHeight;
1458
+ const clientHeight = element.clientHeight;
1459
+ this.scrollTopPosition.set(scrollTop);
1460
+ this.canScrollStartVertical.set(scrollTop > 0);
1461
+ this.canScrollEndVertical.set(scrollTop + clientHeight < scrollHeight);
1462
+ }
1463
+ /**
1464
+ * Adds scroll event listener to track scroll position changes
1465
+ */
1466
+ addScrollListener() {
1467
+ this.el.nativeElement.addEventListener('scroll', () => {
1468
+ this.updateOverflow();
1469
+ });
1470
+ }
1471
+ /**
1472
+ * Adds window resize listener to recalculate overflow on resize
1473
+ */
1474
+ addResizeListener() {
1475
+ window.addEventListener('resize', () => {
1476
+ this.updateOverflow();
1477
+ });
1478
+ }
1479
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ScrollableDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1480
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.1.0", type: ScrollableDirective, isStandalone: true, selector: "[smartScrollable]", inputs: { scrollUnit: { classPropertyName: "scrollUnit", publicName: "scrollUnit", isSignal: true, isRequired: true, transformFunction: null } }, exportAs: ["smartScrollable"], ngImport: i0 }); }
1481
+ }
1482
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.0", ngImport: i0, type: ScrollableDirective, decorators: [{
1483
+ type: Directive,
1484
+ args: [{
1485
+ selector: '[smartScrollable]',
1486
+ standalone: true,
1487
+ exportAs: 'smartScrollable',
1488
+ }]
1489
+ }], ctorParameters: () => [] });
1490
+
655
1491
  const DIRECTIVES = [];
656
1492
 
657
1493
  function initializeApp(configsFacade) {
@@ -724,5 +1560,5 @@ class ImageBox {
724
1560
  * Generated bundle index. Do not edit.
725
1561
  */
726
1562
 
727
- export { AppComponent, COMPONENTS, ConfigsFacade, ConfigsService, CrudBaseService, DictionaryService, FiltersBaseComponent, FiltersContext, GameType, ImageBox, ListMode, PageComponent, SERVICES, ScrollTopComponent, SharedConfig, SharedModule, TRANSLATE_DATA_PL, environment, setTranslationsAndLang };
1563
+ export { AppComponent, AuthStorageService, COMPONENTS, ConfigsFacade, ConfigsService, ContrastService, CrudBaseService, DIRECTIVES, DictionaryService, FileUrlService, FiltersBaseComponent, FiltersContext, GameType, GlobalService, HoverDirective, ImageBox, ListMode, MetaService, PageComponent, SERVICES, ScrollTopComponent, ScrollableDirective, SeoService, SettingsService, SharedConfig, SharedModule, StyleService, TRANSLATE_DATA_PL, TranslationService, WcagService, environment, setTranslationsAndLang };
728
1564
  //# sourceMappingURL=smartsoft001-mobilems-angular.mjs.map