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
JavaScript
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