@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,
|
|
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(/ /g, ' ')
|
|
521
|
+
.replace(/‐/g, '-')
|
|
522
|
+
.replace(/–/g, '-')
|
|
523
|
+
.replace(/—/g, '-')
|
|
524
|
+
.replace(/–/g, '-')
|
|
525
|
+
.replace(/—/g, '-')
|
|
526
|
+
.replace(/„/g, '"')
|
|
527
|
+
.replace(/ó/g, 'ó')
|
|
528
|
+
.replace(/”/g, '"')
|
|
529
|
+
.replace(/"/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 = [
|
|
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
|