UNPKG

design-angular-kit-lombardia

Version:

Un toolkit Angular conforme alle linee guida di design per i servizi web della Regione Lombardia

922 lines (907 loc) 534 kB
import * as i0 from '@angular/core'; import { inject, Renderer2, ElementRef, ChangeDetectorRef, EventEmitter, Output, Input, Component, Injectable, signal, DestroyRef, NgZone, Injector, afterNextRender, ViewChild, ChangeDetectionStrategy, ViewEncapsulation, booleanAttribute, InjectionToken, ContentChildren, NgModule, TemplateRef, HostBinding, Directive, DOCUMENT, HostListener, ViewChildren, Pipe, HostAttributeToken, provideAppInitializer, importProvidersFrom, makeEnvironmentProviders } from '@angular/core'; import { NgTemplateOutlet, NgClass, AsyncPipe, LowerCasePipe, DatePipe, NgOptimizedImage, TitleCasePipe, Location, JsonPipe, ViewportScroller } from '@angular/common'; import { takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop'; import { tap, delay, startWith, Subject, filter, debounceTime, distinctUntilChanged, switchMap, of, merge, map, Observable, take, forkJoin, BehaviorSubject, shareReplay, combineLatest, skip, AsyncSubject, withLatestFrom, timer, takeWhile } from 'rxjs'; import videojs from 'video.js'; import * as i1 from '@ngx-translate/core'; import { TranslateService, TranslateModule, TranslatePipe, TranslateLoader } from '@ngx-translate/core'; import { initYoutubePlugin } from 'bootstrap-lombardia/dist/plugins/util/youtube-video.js'; import { Collapse, Alert, Dropdown, Carousel, Modal, Notification, Popover, Tab, Tooltip, InputPassword, ProgressDonut, SelectAutocomplete, BackToTop, NavBarCollapsible, HeaderSticky, loadFonts } from 'bootstrap-lombardia'; import { RouterLink, RouterLinkActive, Router, NavigationEnd, Scroll, RouterLinkWithHref, ActivatedRoute } from '@angular/router'; import { trigger, transition, style, animate } from '@angular/animations'; import * as i1$1 from '@angular/forms'; import { NgControl, ControlContainer, FormControl, FormGroup, Validators, ReactiveFormsModule, NgModel, FormControlName } from '@angular/forms'; import { DomSanitizer } from '@angular/platform-browser'; import { provideHttpClient, HttpClient } from '@angular/common/http'; import { provideAnimationsAsync } from '@angular/platform-browser/animations/async'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { map as map$1 } from 'rxjs/operators'; class ItAbstractComponent { /** * Counter of active instances * @private */ static { this.instances = 0; } constructor() { /** * The element ID */ this.id = this.getDefaultId(); this._renderer = inject(Renderer2); this._elementRef = inject(ElementRef); this._changeDetectorRef = inject(ChangeDetectorRef); this.valueChanges = new EventEmitter(); } ngAfterViewInit() { this._renderer.removeAttribute(this._elementRef.nativeElement, 'id'); } // eslint-disable-next-line @typescript-eslint/no-unused-vars ngOnChanges(changes) { this.valueChanges.next(); // The inputs were changed } /** * Generate unique id for components * @private */ getDefaultId() { const name = this.constructor.name.replace('Component', ''); const kebabName = name.replace(/[A-Z]+(?![a-z])|[A-Z]/g, ($, ofs) => (ofs ? '-' : '') + $.toLowerCase()); return `${kebabName}-${ItAbstractComponent.instances++}`; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItAbstractComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: ItAbstractComponent, isStandalone: false, selector: "ng-component", inputs: { id: "id" }, outputs: { valueChanges: "valueChanges" }, usesOnChanges: true, ngImport: i0, template: '', isInline: true }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItAbstractComponent, decorators: [{ type: Component, args: [{ template: '', standalone: false, }] }], ctorParameters: () => [], propDecorators: { id: [{ type: Input }], valueChanges: [{ type: Output }] } }); class VideoPlayerI18nService { #translate = inject(TranslateService); init(player, destroyRef) { this.#translate.onLangChange .pipe(takeUntilDestroyed(destroyRef), tap({ next: e => { const language = e.lang; videojs.addLanguage(language, this.getTranslations()); player.language(language); }, })) .subscribe(x => { console.log('onLangChange', x); }); } getLanguage() { const language = this.#translate.currentLang ?? 'it'; return { languages: { [language]: mapToVideoJsTranslation(this.#translate.instant('it.video-player')) }, language, }; } getTranslations() { return mapToVideoJsTranslation(this.#translate.instant('it.video-player')); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: VideoPlayerI18nService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: VideoPlayerI18nService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: VideoPlayerI18nService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); function mapToVideoJsTranslation(translations) { return { 'Audio Player': translations['audio-player'], 'Video Player': translations['video-player'], Play: translations.play, Pause: translations.pause, Replay: translations.replay, 'Current Time': translations['current-time'], Duration: translations.duration, 'Remaining Time': translations['remaining-time'], 'Stream Type': translations['stream-type'], LIVE: translations.live, Loaded: translations.loaded, Progress: translations.progress, 'Progress Bar': translations['progress-bar'], 'progress bar timing: currentTime={1} duration={2}': translations['progress-bar-timing:-currenttime={1}-duration={2}'], Fullscreen: translations.fullscreen, 'Exit Fullscreen': translations['exit-fullscreen'], Mute: translations.mute, Unmute: translations.unmute, 'Playback Rate': translations['playback-rate'], Subtitles: translations.subtitles, 'subtitles off': translations['subtitles-off'], Captions: translations.captions, 'captions off': translations['captions-off'], Chapters: translations.chapters, Descriptions: translations.descriptions, 'descriptions off': translations['descriptions-off'], 'Audio Track': translations['audio-track'], 'Volume Level': translations['volume-level'], 'You aborted the media playback': translations['you-aborted-the-media-playback'], 'A network error caused the media download to fail part-way.': translations['a-network-error-caused-the-media-download-to-fail-part-way.'], 'The media could not be loaded, either because the server or network failed or because the format is not supported.': translations['the-media-could-not-be-loaded,-either-because-the-server-or-network-failed-or-because-the-format-is-not-supported.'], 'The media playback was aborted due to a corruption problem or because the media used features your browser did not support.': translations['the-media-playback-was-aborted-due-to-a-corruption-problem-or-because-the-media-used-features-your-browser-did-not-support.'], 'No compatible source was found for this media.': translations['no-compatible-source-was-found-for-this-media.'], 'The media is encrypted and we do not have the keys to decrypt it.': translations['the-media-is-encrypted-and-we-do-not-have-the-keys-to-decrypt-it.'], 'Play Video': translations['play-video'], Close: translations.close, 'Close Modal Dialog': translations['close-modal-dialog'], 'Modal Window': translations['modal-window'], 'This is a modal window': translations['this-is-a-modal-window'], 'This modal can be closed by pressing the Escape key or activating the close button.': translations['this-modal-can-be-closed-by-pressing-the-escape-key-or-activating-the-close-button.'], ', opens captions settings dialog': translations[',-opens-captions-settings-dialog'], ', opens subtitles settings dialog': translations[',-opens-subtitles-settings-dialog'], ', opens descriptions settings dialog': translations[',-opens-descriptions-settings-dialog'], ', selected': translations[',-selected'], 'captions settings': translations['captions-settings'], 'subtitles settings': translations['subtitles-settings'], 'descriptions settings': translations['descriptions-settings'], Text: translations.text, White: translations.white, Black: translations.black, Red: translations.red, Green: translations.green, Blue: translations.blue, Yellow: translations.yellow, Magenta: translations.magenta, Cyan: translations.cyan, Background: translations.background, Window: translations.window, Transparent: translations.transparent, 'Semi-Transparent': translations['semi-transparent'], Opaque: translations.opaque, 'Font Size': translations['font-size'], 'Text Edge Style': translations['text-edge-style'], None: translations.none, Uniform: translations.uniform, 'Drop shadow': translations['drop-shadow'], 'Font Family': translations['font-family'], 'Proportional Sans-Serif': translations['proportional-sans-serif'], 'Monospace Sans-Serif': translations['monospace-sans-serif'], 'Proportional Serif': translations['proportional-serif'], 'Monospace Serif': translations['monospace-serif'], 'Small Caps': translations['small-caps'], Reset: translations.reset, 'restore all settings to the default values': translations['restore-all-settings-to-the-default-values'], Done: translations.done, 'Caption Settings Dialog': translations['caption-settings-dialog'], 'Beginning of dialog window. Escape will cancel and close the window.': translations['beginning-of-dialog-window.-escape-will-cancel-and-close-the-window.'], 'End of dialog window.': translations['end-of-dialog-window.'], '{1} is loading.': translations['{1}-is-loading.'], 'Exit Picture-in-Picture': translations['exit-picture-in-picture'], 'Picture-in-Picture': translations['picture-in-picture'], Color: translations.color, Opacity: translations.opacity, 'Text Background': translations['text-background'], 'Caption Area Background': translations['caption-area-background'], 'Skip forward {1} seconds': translations['skip-forward-{1}-seconds'], 'Skip backward {1} seconds': translations['skip-backward-{1}-seconds'], }; } const hasYoutubeVideo = (options) => options.source?.type === 'video/youtube'; class VideoPlayerConfigService { #languageService = inject(VideoPlayerI18nService); async configureTech({ tech }) { if (tech === 'youtube') { initYoutubePlugin(videojs); } } mergeConfig(o) { const options = o; const captions = options.captions ? options.captions.map(c => ({ ...c, kind: 'captions' })) : []; const chapters = options.chapters ? options.chapters.map(c => ({ ...c, kind: 'chapters' })) : []; const isYoutubeVideo = hasYoutubeVideo(options); const DEFAULT_CONFIG = this.#languageService.getLanguage(); const tech = isYoutubeVideo ? 'youtube' : 'html5'; const techOrder = [tech]; //https://developer.mozilla.org/en-US/docs/Web/HTML/Element/video#preload const preload = options.preload ?? 'metadata'; const config = { ...DEFAULT_CONFIG, ...options, preload, techOrder, tracks: [...captions, ...chapters], tech: 'html5' }; return isYoutubeVideo ? { ...config, sources: [o.source], tech: 'youtube', youtube: { ytControls: 2, rel: 0, fs: 0, modestbranding: 1 }, } : config; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: VideoPlayerConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: VideoPlayerConfigService, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: VideoPlayerConfigService, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }] }); const preferencesMap = { ck3: {} }; const STORAGE_KEY = 'bs-ck3'; /* Possible choices: false => Accept once true => Accept always */ const rememberChoice = (service, remember) => { preferencesMap.ck3[service] = remember; localStorage.setItem(STORAGE_KEY, JSON.stringify(preferencesMap.ck3)); }; const isChoiceRemembered = (service) => { preferencesMap.ck3 = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}'); return Boolean(preferencesMap.ck3[service]) || false; }; const clearAllRememberedChoices = () => { localStorage.removeItem(STORAGE_KEY); }; const cookies = { rememberChoice, isChoiceRemembered, clearAllRememberedChoices, }; var ViewType; (function (ViewType) { ViewType["Default"] = "DEFAULT"; ViewType["Overlay"] = "OVERLAY"; })(ViewType || (ViewType = {})); /** * Video Player * @description Component that allows playing a video. */ class ItVideoPlayerComponent extends ItAbstractComponent { #destroyRef; constructor() { super(); this.config = inject(VideoPlayerConfigService); this.player = null; this.viewTypes = ViewType; this.viewType = signal(undefined, ...(ngDevMode ? [{ debugName: "viewType" }] : [])); this.cookieAccepted = signal(false, ...(ngDevMode ? [{ debugName: "cookieAccepted" }] : [])); this.i18nService = inject(VideoPlayerI18nService); this.#destroyRef = inject(DestroyRef); this.ngZone = inject(NgZone); this.injector = inject(Injector); afterNextRender(() => { if (this.viewType() === ViewType.Overlay && cookies.isChoiceRemembered('youtube.com')) { this.hideOverlay(); } }); this.#destroyRef.onDestroy(() => this.player?.dispose()); } async ngOnInit() { const config = this.config.mergeConfig(this.options); this.setViewType(config); // Avoid running change detections while the script is being loaded. await this.ngZone.runOutsideAngular(() => this.config.configureTech(config)); if (!this.videoPlayerRef) { // Note: No need to pipe with `takeUntilDestroyed`; `toObservable` is // completed by Angular when the `DestroyRef` from the injector is destroyed. toObservable(this.cookieAccepted, { injector: this.injector }) .pipe(delay(0)) .subscribe(value => { if (value && !this.player) { this.initVideoPlayer(); } }); return; } this.initVideoPlayer(); } acceptCookieHandler() { this.rememberHandler(); this.hideOverlay(); this.cookieAccepted.set(true); } initVideoPlayer() { const config = this.config.mergeConfig(this.options); this.setVideoAttributes(config); this.setVideoPlayer(); } setVideoPlayer() { const config = this.config.mergeConfig(this.options); const onPlayerReadyCb = () => { if (!this.player) { return; } this.i18nService.init(this.player, this.#destroyRef); }; const element = this.videoPlayerRef?.nativeElement; if (!element) { throw Error('videoPlayerRef is undefined'); } this.player = this.ngZone.runOutsideAngular(() => videojs(element, config, onPlayerReadyCb)); } setViewType(config) { this.viewType.set(config.tech === 'youtube' ? ViewType.Overlay : ViewType.Default); this.cookieAccepted.set(this.viewType() === ViewType.Overlay && cookies.isChoiceRemembered('youtube.com')); } hideOverlay() { if (!this.acceptOverlayableRef) { return; } const classes = ['show']; this.acceptOverlayableRef.nativeElement.classList.remove(...classes); if (!this.acceptOveralyRef) { return; } this.acceptOveralyRef.nativeElement.classList.remove(...classes); this.acceptOveralyRef.nativeElement.setAttribute('aria-hidden', 'true'); } rememberHandler() { if (!this.chrRememberRef) { return; } const remember = this.chrRememberRef.nativeElement.checked; cookies.rememberChoice('youtube.com', remember); } setVideoAttributes(options) { if (!this.videoPlayerRef) { return; } const v = this.videoPlayerRef.nativeElement; const { autoplay, controls, loop, muted, poster, fluid } = options; if (autoplay) { v.setAttribute('autoplay', autoplay.toString()); } if (controls) { v.setAttribute('controls', ''); } if (loop) { v.setAttribute('loop', ''); } if (muted) { v.setAttribute('muted', ''); } if (poster) { v.setAttribute('poster', poster); } if (fluid) { v.setAttribute('fluid', ''); } v.setAttribute('preload', 'none'); v.setAttribute('playsinline', ''); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItVideoPlayerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ItVideoPlayerComponent, isStandalone: true, selector: "it-video-player", inputs: { options: "options" }, viewQueries: [{ propertyName: "videoPlayerRef", first: true, predicate: ["videoPlayer"], descendants: true }, { propertyName: "acceptOveralyRef", first: true, predicate: ["acceptOveraly"], descendants: true }, { propertyName: "acceptOverlayableRef", first: true, predicate: ["acceptOverlayable"], descendants: true }, { propertyName: "chrRememberRef", first: true, predicate: ["chkRemember"], descendants: true }], usesInheritance: true, ngImport: i0, template: `@switch (viewType()) { @case (viewTypes.Default) { <div class="row"> <ng-container *ngTemplateOutlet="videoTemplate"></ng-container> <ng-container *ngTemplateOutlet="transcriptionTemplate"></ng-container> </div> } @case (viewTypes.Overlay) { <div #acceptOverlayable class="acceptoverlayable show"> <div #acceptOveraly class="acceptoverlay acceptoverlay-primary fade show"> <div class="acceptoverlay-inner"> <div class="acceptoverlay-icon"> <svg class="icon icon-xl"><use href="/bootstrap-lombardia/dist/svg/sprites.svg#it-video"></use></svg> </div> <p> Accetta i cookie di YouTube per vedere il video. Puoi gestire le preferenze nella <a href="#" class="text-white">cookie policy</a>. </p> <div class="acceptoverlay-buttons bg-dark"> <button type="button" class="btn btn-primary" (click)="acceptCookieHandler()">Accetta</button> <div class="form-check"> <input id="chk-remember{{ id }}" type="checkbox" #chkRemember /> <label for="chk-remember{{ id }}">Ricorda per tutti i video</label> </div> </div> </div> </div> @if (cookieAccepted()) { <div> <ng-container *ngTemplateOutlet="videoTemplate"></ng-container> <ng-container *ngTemplateOutlet="transcriptionTemplate"></ng-container> </div> } </div> } @default { <h1>No video provider</h1> } } <ng-template #videoTemplate> <div> <video #videoPlayer class="video-js vjs-theme-bootstrap-lombardia vjs-fluid vjs-big-play-centered"></video> </div> </ng-template> <ng-template #transcriptionTemplate> <div class="vjs-transcription accordion"> <div class="accordion-item"> <h2 class="accordion-header " id="transcription-{{ id }}-head"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" [attr.data-bs-target]="'#transcription-' + id" [attr.aria-controls]="'transcription-' + id" aria-expanded="true"> <ng-content select="[transcriptionTitle]">Trascrizione</ng-content> </button> </h2> <div id="transcription-{{ id }}" class="accordion-collapse collapse" role="region" [attr.aria-labelledby]="'transcription-' + id + '-head'"> <div class="accordion-body"> <ng-content select="[transcriptionText]">-</ng-content> </div> </div> </div> </div> </ng-template> `, isInline: true, dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItVideoPlayerComponent, decorators: [{ type: Component, args: [{ standalone: true, selector: 'it-video-player', template: `@switch (viewType()) { @case (viewTypes.Default) { <div class="row"> <ng-container *ngTemplateOutlet="videoTemplate"></ng-container> <ng-container *ngTemplateOutlet="transcriptionTemplate"></ng-container> </div> } @case (viewTypes.Overlay) { <div #acceptOverlayable class="acceptoverlayable show"> <div #acceptOveraly class="acceptoverlay acceptoverlay-primary fade show"> <div class="acceptoverlay-inner"> <div class="acceptoverlay-icon"> <svg class="icon icon-xl"><use href="/bootstrap-lombardia/dist/svg/sprites.svg#it-video"></use></svg> </div> <p> Accetta i cookie di YouTube per vedere il video. Puoi gestire le preferenze nella <a href="#" class="text-white">cookie policy</a>. </p> <div class="acceptoverlay-buttons bg-dark"> <button type="button" class="btn btn-primary" (click)="acceptCookieHandler()">Accetta</button> <div class="form-check"> <input id="chk-remember{{ id }}" type="checkbox" #chkRemember /> <label for="chk-remember{{ id }}">Ricorda per tutti i video</label> </div> </div> </div> </div> @if (cookieAccepted()) { <div> <ng-container *ngTemplateOutlet="videoTemplate"></ng-container> <ng-container *ngTemplateOutlet="transcriptionTemplate"></ng-container> </div> } </div> } @default { <h1>No video provider</h1> } } <ng-template #videoTemplate> <div> <video #videoPlayer class="video-js vjs-theme-bootstrap-lombardia vjs-fluid vjs-big-play-centered"></video> </div> </ng-template> <ng-template #transcriptionTemplate> <div class="vjs-transcription accordion"> <div class="accordion-item"> <h2 class="accordion-header " id="transcription-{{ id }}-head"> <button class="accordion-button collapsed" type="button" data-bs-toggle="collapse" [attr.data-bs-target]="'#transcription-' + id" [attr.aria-controls]="'transcription-' + id" aria-expanded="true"> <ng-content select="[transcriptionTitle]">Trascrizione</ng-content> </button> </h2> <div id="transcription-{{ id }}" class="accordion-collapse collapse" role="region" [attr.aria-labelledby]="'transcription-' + id + '-head'"> <div class="accordion-body"> <ng-content select="[transcriptionText]">-</ng-content> </div> </div> </div> </div> </ng-template> `, imports: [NgTemplateOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, }] }], ctorParameters: () => [], propDecorators: { options: [{ type: Input }], videoPlayerRef: [{ type: ViewChild, args: ['videoPlayer', { static: false }] }], acceptOveralyRef: [{ type: ViewChild, args: ['acceptOveraly', { static: false }] }], acceptOverlayableRef: [{ type: ViewChild, args: ['acceptOverlayable', { static: false }] }], chrRememberRef: [{ type: ViewChild, args: ['chkRemember', { static: false }] }] } }); /** * Transforms a value (typically a string) to a boolean. * Intended to be used as a transform function of an input. * * @usageNotes * ```typescript * @Input({ transform: booleanAttribute }) status?: boolean; * ``` * @param {BooleanInput} value Value to be transformed. * * @publicApi */ function inputToBoolean(value) { // Wrap `@angular/core` function to force value type, for ide hits return booleanAttribute(value); } class ItCollapseComponent extends ItAbstractComponent { constructor() { super(...arguments); /** * Custom class */ this.class = ''; /** * This event fires immediately when the show method is called. */ this.showEvent = new EventEmitter(); /** * This event is triggered when the tooltip has been made visible to the user (it will wait for the CSS transitions to complete). */ this.shownEvent = new EventEmitter(); /** * This event fires immediately when the hide method is called. */ this.hideEvent = new EventEmitter(); /** * This event is raised when the tooltip has finished being hidden from the user (it will wait for the CSS transitions to complete). */ this.hiddenEvent = new EventEmitter(); this.open = false; } ngAfterViewInit() { super.ngAfterViewInit(); this._renderer.removeAttribute(this._elementRef.nativeElement, 'class'); if (this.collapseDiv) { const element = this.collapseDiv.nativeElement; this.collapse = Collapse.getOrCreateInstance(element, { toggle: this.opened, }); element.addEventListener('show.bs.collapse', event => { this.open = true; this.showEvent.emit(event); }); element.addEventListener('shown.bs.collapse', event => { this.open = true; this.shownEvent.emit(event); }); element.addEventListener('hide.bs.collapse', event => { this.open = false; this.hideEvent.emit(event); }); element.addEventListener('hidden.bs.collapse', event => { this.open = false; this.hiddenEvent.emit(event); }); } } /** * Shows if collapse is open or not */ isOpen() { return this.open; } /** * Shows a resealable item * NOTE: Returns to the caller before the collapsable element has actually been shown (onShown event). */ show() { this.collapse?.show(); } /** * Hides a resealable item * NOTE: Returns to the caller before the collapsable element has actually been hidden (onHidden Event) */ hide() { this.collapse?.hide(); } /** * Toggle a collapsible item to show or hide it. * NOTE: Returns to the caller before the collapsable element has actually been shown or hidden (onShown and onHidden events) */ toggle() { this.collapse?.toggle(); } /** * Eliminates the possibility of an item being resealable */ dispose() { this.collapse?.dispose(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItCollapseComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.10", type: ItCollapseComponent, isStandalone: true, selector: "it-collapse", inputs: { multi: ["multi", "multi", inputToBoolean], opened: ["opened", "opened", inputToBoolean], class: "class" }, outputs: { showEvent: "showEvent", shownEvent: "shownEvent", hideEvent: "hideEvent", hiddenEvent: "hiddenEvent" }, viewQueries: [{ propertyName: "collapseDiv", first: true, predicate: ["collapse"], descendants: true }], exportAs: ["itCollapse"], usesInheritance: true, ngImport: i0, template: "<div [id]=\"id\" class=\"collapse {{ class }}\" [class.multi-collapse]=\"multi\" #collapse>\n <ng-content></ng-content>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItCollapseComponent, decorators: [{ type: Component, args: [{ selector: 'it-collapse', exportAs: 'itCollapse', changeDetection: ChangeDetectionStrategy.OnPush, imports: [], template: "<div [id]=\"id\" class=\"collapse {{ class }}\" [class.multi-collapse]=\"multi\" #collapse>\n <ng-content></ng-content>\n</div>\n" }] }], propDecorators: { multi: [{ type: Input, args: [{ transform: inputToBoolean }] }], opened: [{ type: Input, args: [{ transform: inputToBoolean }] }], class: [{ type: Input }], showEvent: [{ type: Output }], shownEvent: [{ type: Output }], hideEvent: [{ type: Output }], hiddenEvent: [{ type: Output }], collapseDiv: [{ type: ViewChild, args: ['collapse'] }] } }); /** * Accordion * @description Build vertically collapsible accordions based on Collapse. */ class ItAccordionComponent extends ItCollapseComponent { constructor() { super(...arguments); this.isCollapsed = true; } ngAfterViewInit() { super.ngAfterViewInit(); this._renderer.removeAttribute(this._elementRef.nativeElement, 'title'); this.isCollapsed = !this.opened; this.hideEvent.subscribe(() => { this.isCollapsed = true; this._changeDetectorRef.detectChanges(); }); this.showEvent.subscribe(() => { this.isCollapsed = false; this._changeDetectorRef.detectChanges(); }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItAccordionComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.10", type: ItAccordionComponent, isStandalone: true, selector: "it-accordion", inputs: { title: "title" }, viewQueries: [{ propertyName: "collapseDiv", first: true, predicate: ["collapse"], descendants: true }], exportAs: ["itAccordion"], usesInheritance: true, ngImport: i0, template: "<div class=\"accordion\">\n <div class=\"accordion-item\">\n <h2 class=\"accordion-header\" id=\"collapse-{{ id }}-heading\">\n <button\n class=\"accordion-button\"\n type=\"button\"\n data-bs-toggle=\"collapse\"\n [class.collapsed]=\"isCollapsed\"\n [attr.data-bs-target]=\"'#collapse-' + id\"\n [attr.aria-controls]=\"'collapse-' + id\"\n [attr.aria-expanded]=\"opened ? 'true' : 'false'\">\n {{ title }}\n </button>\n </h2>\n\n <div\n #collapse\n id=\"collapse-{{ id }}\"\n role=\"region\"\n class=\"accordion-collapse collapse {{ class }}\"\n [attr.aria-labelledby]=\"'collapse-' + id + '-heading'\">\n <div class=\"accordion-body\">\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n</div>\n", changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItAccordionComponent, decorators: [{ type: Component, args: [{ selector: 'it-accordion', exportAs: 'itAccordion', changeDetection: ChangeDetectionStrategy.OnPush, imports: [], template: "<div class=\"accordion\">\n <div class=\"accordion-item\">\n <h2 class=\"accordion-header\" id=\"collapse-{{ id }}-heading\">\n <button\n class=\"accordion-button\"\n type=\"button\"\n data-bs-toggle=\"collapse\"\n [class.collapsed]=\"isCollapsed\"\n [attr.data-bs-target]=\"'#collapse-' + id\"\n [attr.aria-controls]=\"'collapse-' + id\"\n [attr.aria-expanded]=\"opened ? 'true' : 'false'\">\n {{ title }}\n </button>\n </h2>\n\n <div\n #collapse\n id=\"collapse-{{ id }}\"\n role=\"region\"\n class=\"accordion-collapse collapse {{ class }}\"\n [attr.aria-labelledby]=\"'collapse-' + id + '-heading'\">\n <div class=\"accordion-body\">\n <ng-content></ng-content>\n </div>\n </div>\n </div>\n</div>\n" }] }], propDecorators: { title: [{ type: Input, args: [{ required: true }] }], collapseDiv: [{ type: ViewChild, args: ['collapse'] }] } }); /** * The bootstrap-italia asset folder path * @default ./bootstrap-italia */ const IT_ASSET_BASE_PATH = new InjectionToken('it-asset-base-path'); class ItIconComponent { /** * Return the icon href */ get iconHref() { return `${this.assetBasePath}/dist/svg/sprites.svg#it-${this.name}`; } /** * Return the icon class */ get iconClass() { let iconClass = 'icon'; if (this.size) { iconClass += ` icon-${this.size}`; } if (this.color) { iconClass += ` icon-${this.color}`; } if (this.padded) { iconClass += ` icon-padded`; } if (this.svgClass) { iconClass += ` ${this.svgClass}`; } return iconClass; } get isAriaHidden() { return this.labelWaria == undefined && this.title == undefined; } get role() { return this.labelWaria == undefined && this.title == undefined ? null : 'img'; } constructor() { this.assetBasePath = inject(IT_ASSET_BASE_PATH); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ItIconComponent, isStandalone: true, selector: "it-icon", inputs: { name: "name", size: "size", color: "color", padded: ["padded", "padded", inputToBoolean], svgClass: "svgClass", title: "title", labelWaria: "labelWaria" }, ngImport: i0, template: "<svg [attr.role]=\"role\" [attr.aria-hidden]=\"isAriaHidden\" [attr.aria-label]=\"title || labelWaria\" [class]=\"iconClass\">\n @if (title || labelWaria) {\n <title>{{ title || labelWaria }}</title>\n }\n <use [attr.href]=\"iconHref\" [attr.xlink:href]=\"iconHref\"></use>\n</svg>\n", styles: [":host{display:contents}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItIconComponent, decorators: [{ type: Component, args: [{ selector: 'it-icon', changeDetection: ChangeDetectionStrategy.OnPush, imports: [], template: "<svg [attr.role]=\"role\" [attr.aria-hidden]=\"isAriaHidden\" [attr.aria-label]=\"title || labelWaria\" [class]=\"iconClass\">\n @if (title || labelWaria) {\n <title>{{ title || labelWaria }}</title>\n }\n <use [attr.href]=\"iconHref\" [attr.xlink:href]=\"iconHref\"></use>\n</svg>\n", styles: [":host{display:contents}\n"] }] }], ctorParameters: () => [], propDecorators: { name: [{ type: Input, args: [{ required: true }] }], size: [{ type: Input }], color: [{ type: Input }], padded: [{ type: Input, args: [{ transform: inputToBoolean }] }], svgClass: [{ type: Input }], title: [{ type: Input }], labelWaria: [{ type: Input }] } }); /** * Alert * @description You can provide feedback to the user via alert messages. */ class ItAlertComponent extends ItAbstractComponent { constructor() { super(...arguments); /** * The alert color * @default info */ this.color = 'info'; /** * This event fires immediately when the instance's close method is called. */ this.closeEvent = new EventEmitter(); /** * This event fires when the alert has been closed (it will wait for CSS transitions to complete). */ this.closedEvent = new EventEmitter(); } ngAfterViewInit() { super.ngAfterViewInit(); if (this.alertElement) { const element = this.alertElement.nativeElement; this.alert = Alert.getOrCreateInstance(element); element.addEventListener('close.bs.alert', event => this.closeEvent.emit(event)); element.addEventListener('closed.bs.alert', event => this.closedEvent.emit(event)); } } /** * Close an alert by removing it from the DOM. * If the `.fade` and `.show` classes are present in the element, the alert will be closed with a disappearing effect. */ close() { this.alert?.close(); } /** * The alert is removed */ dispose() { this.alert?.dispose(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItAlertComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ItAlertComponent, isStandalone: true, selector: "it-alert", inputs: { color: "color", dismissible: ["dismissible", "dismissible", inputToBoolean] }, outputs: { closeEvent: "closeEvent", closedEvent: "closedEvent" }, viewQueries: [{ propertyName: "alertElement", first: true, predicate: ["alertElement"], descendants: true }], exportAs: ["itAlert"], usesInheritance: true, ngImport: i0, template: "<div\n #alertElement\n class=\"alert alert-{{ color }}\"\n [class.alert-dismissible]=\"dismissible\"\n [class.fade]=\"dismissible\"\n [class.show]=\"dismissible\"\n role=\"alert\">\n <h4 class=\"alert-heading\">\n <ng-content select=\"[heading]\"></ng-content>\n </h4>\n\n <ng-content></ng-content>\n\n @if (dismissible) {\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" [attr.aria-label]=\"'it.core.close-alert' | translate\">\n <it-icon name=\"close\"></it-icon>\n </button>\n }\n</div>\n", styles: [".alert-heading:empty{display:none}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "component", type: ItIconComponent, selector: "it-icon", inputs: ["name", "size", "color", "padded", "svgClass", "title", "labelWaria"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItAlertComponent, decorators: [{ type: Component, args: [{ selector: 'it-alert', exportAs: 'itAlert', changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslateModule, ItIconComponent], template: "<div\n #alertElement\n class=\"alert alert-{{ color }}\"\n [class.alert-dismissible]=\"dismissible\"\n [class.fade]=\"dismissible\"\n [class.show]=\"dismissible\"\n role=\"alert\">\n <h4 class=\"alert-heading\">\n <ng-content select=\"[heading]\"></ng-content>\n </h4>\n\n <ng-content></ng-content>\n\n @if (dismissible) {\n <button type=\"button\" class=\"btn-close\" data-bs-dismiss=\"alert\" [attr.aria-label]=\"'it.core.close-alert' | translate\">\n <it-icon name=\"close\"></it-icon>\n </button>\n }\n</div>\n", styles: [".alert-heading:empty{display:none}\n"] }] }], propDecorators: { color: [{ type: Input }], dismissible: [{ type: Input, args: [{ transform: inputToBoolean }] }], closeEvent: [{ type: Output }], closedEvent: [{ type: Output }], alertElement: [{ type: ViewChild, args: ['alertElement'] }] } }); class ItLinkComponent extends ItAbstractComponent { constructor() { super(...arguments); /** * Custom class */ this.class = ''; } ngAfterViewInit() { super.ngAfterViewInit(); this._renderer.removeAttribute(this._elementRef.nativeElement, 'class'); } ngOnChanges(changes) { super.ngOnChanges(changes); if (changes['class']) { this._changeDetectorRef.markForCheck(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItLinkComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ItLinkComponent, isStandalone: true, selector: "it-link", inputs: { href: "href", externalLink: ["externalLink", "externalLink", inputToBoolean], disabled: ["disabled", "disabled", inputToBoolean], class: "class" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "@if (!externalLink) {\n <a [id]=\"id\" [class]=\"class\" [routerLinkActive]=\"'active'\" [routerLink]=\"(disabled ? null : href)!\">\n <ng-container *ngTemplateOutlet=\"linkContent\"></ng-container>\n </a>\n} @else {\n <a [id]=\"id\" [class]=\"class\" [attr.href]=\"disabled ? null : href\">\n <ng-container *ngTemplateOutlet=\"linkContent\"></ng-container>\n </a>\n}\n\n<ng-template #linkContent>\n <ng-content></ng-content>\n</ng-template>\n", dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItLinkComponent, decorators: [{ type: Component, args: [{ selector: 'it-link', changeDetection: ChangeDetectionStrategy.OnPush, imports: [RouterLink, RouterLinkActive, NgTemplateOutlet], template: "@if (!externalLink) {\n <a [id]=\"id\" [class]=\"class\" [routerLinkActive]=\"'active'\" [routerLink]=\"(disabled ? null : href)!\">\n <ng-container *ngTemplateOutlet=\"linkContent\"></ng-container>\n </a>\n} @else {\n <a [id]=\"id\" [class]=\"class\" [attr.href]=\"disabled ? null : href\">\n <ng-container *ngTemplateOutlet=\"linkContent\"></ng-container>\n </a>\n}\n\n<ng-template #linkContent>\n <ng-content></ng-content>\n</ng-template>\n" }] }], propDecorators: { href: [{ type: Input }], externalLink: [{ type: Input, args: [{ transform: inputToBoolean }] }], disabled: [{ type: Input, args: [{ transform: inputToBoolean }] }], class: [{ type: Input }] } }); class ItDropdownItemComponent extends ItLinkComponent { constructor() { super(...arguments); /** * The icon position * @default right */ this.iconPosition = 'right'; /** * Dropdown mode */ this.mode = 'button'; /** * Change icon color if menu is dark * @default false */ this.isDark = false; this.elRef = inject(ElementRef); this.isHostElement = false; } get linkClass() { let linkClass = `list-item ${this.active ? 'active' : 'dropdown-item'}`; if (this.mode === 'nav') { linkClass += ' nav-link'; } if (this.disabled) { linkClass += ' disabled'; } if (this.large) { linkClass += ' large'; } if (this.iconName) { linkClass += ` ${this.iconPosition === 'right' ? 'right-icon' : 'left-icon'}`; } return linkClass; } ngOnInit() { this.isHostElement = this.elRef.nativeElement.tagName.toLowerCase() === 'li'; if (!this.isHostElement) { console.warn(`L'utilizzo del componente attraverso il selettore it-dropdown-item verrà deprecato in quanto non accessibile. Usa il selettore itDropdownItem invece. Consulta la documentazione del component Dropdown.`); } } setDark(dark) { if (this.isDark !== dark) { this.isDark = dark; this._changeDetectorRef.detectChanges(); } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.10", ngImport: i0, type: ItDropdownItemComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.10", type: ItDropdownItemComponent, isStandalone: true, selector: "it-dropdown-item, li[itDropdownItem]", inputs: { divider: ["divider", "divider", inputToBoolean], active: ["active", "active", inputToBoolean], large: ["large", "large", inputToBoolean], iconName: "iconName", iconPosition: "iconPosition", mode: "mode" }, usesInheritance: true, ngImport: i0, template: "@if (isHostElement) {\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n} @else {\n <li>\n <ng-container *ngTemplateOutlet=\"content\"></ng-container>\n </li>\n}\n\n<ng-template #content>\n @if (divider) {\n <span class=\"divider\"></span>\n } @else {\n <it-link [class]=\"linkClass\" [id]=\"id\" [href]=\"href\" [externalLink]=\"externalLink\" [disabled]=\"disabled\">\n @if (iconName && iconPosition === 'left') {\n <it-icon size=\"sm\" [name]=\"iconName\" [color]=\"isDark ? 'light' : 'primary'\" [svgClass]=\"iconPosition\"></it-icon>\n }\n <span><ng-content></ng-content></span>\n @if (iconName && iconPosition === 'right') {\n <it-icon size=\"sm\" [name]=\"iconName\" [color]=\"isDark ? 'light' : 'primary'\" [svgClass]=\"iconPosition\"></it-icon>\n }\n @if (active) {\n <span class=\"visually-hidden\">{{ 'it.core.active' | translate }}</span>\n }\n </it-link>\n }\n</ng-template>\n", styles: [".list-item.disabled{pointer-events:none;cursor:default}\n"], dependencies: [{ kind: "component", type: ItIconComponent, selector: "it-icon", inputs: ["name", "size", "color", "padded", "svgClass", "title", "labelWaria"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: ItLinkComponent, selector: "it-link", inputs: ["href", "externalLink", "disabled", "class"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); } } i0.ɵɵngDeclareClassMetada