UNPKG

@rero/ng-core

Version:

RERO angular core library.

16,324 lines 745 kB
import * as i0 from '@angular/core';
import { Injectable, inject, HostListener, Component, Pipe, Input, NgModule, input, output, effect, ViewChild, provideAppInitializer, ViewContainerRef, Directive, signal, computed, EventEmitter, Output, LOCALE_ID, model, ChangeDetectionStrategy, ChangeDetectorRef, viewChild } from '@angular/core';
import * as i1$2 from '@angular/common';
import { DatePipe, registerLocaleData, CommonModule, Location } from '@angular/common';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import * as i2$8 from '@angular/router';
import { TitleStrategy, RouterModule, Router, ActivatedRoute } from '@angular/router';
import * as i5 from '@ngx-translate/core';
import { TranslateService, TranslateModule, TranslateLoader as TranslateLoader$1, _ } from '@ngx-translate/core';
import { NgxSpinnerModule, NgxSpinnerService } from 'ngx-spinner';
import { ConfirmationService, MessageService } from 'primeng/api';
import { of, forkJoin, throwError, Subject, BehaviorSubject, catchError as catchError$1, tap as tap$1, isObservable, map as map$5, Subscription, combineLatest, switchMap as switchMap$1, merge } from 'rxjs';
import { DynamicDialogConfig, DynamicDialogRef, DialogService, DynamicDialogModule } from 'primeng/dynamicdialog';
import * as i1 from 'primeng/button';
import { ButtonModule } from 'primeng/button';
import { DomSanitizer, Title } from '@angular/platform-browser';
import { marked } from 'marked';
import * as i1$3 from 'primeng/autocomplete';
import { AutoCompleteModule } from 'primeng/autocomplete';
import * as i1$1 from 'primeng/autofocus';
import { AutoFocusModule } from 'primeng/autofocus';
import { BadgeModule } from 'primeng/badge';
import { CardModule } from 'primeng/card';
import * as i2$5 from 'primeng/checkbox';
import { CheckboxModule } from 'primeng/checkbox';
import { ConfirmDialogModule } from 'primeng/confirmdialog';
import * as i2$4 from 'primeng/datepicker';
import { DatePickerModule } from 'primeng/datepicker';
import * as i2$3 from 'primeng/divider';
import { DividerModule } from 'primeng/divider';
import * as i1$7 from 'primeng/fieldset';
import { FieldsetModule } from 'primeng/fieldset';
import * as i4 from 'primeng/inputgroup';
import { InputGroupModule } from 'primeng/inputgroup';
import * as i3 from 'primeng/inputgroupaddon';
import { InputGroupAddonModule } from 'primeng/inputgroupaddon';
import * as i3$6 from 'primeng/inputnumber';
import { InputNumberModule } from 'primeng/inputnumber';
import * as i3$1 from 'primeng/inputtext';
import { InputTextModule } from 'primeng/inputtext';
import * as i2$2 from 'primeng/listbox';
import { ListboxModule } from 'primeng/listbox';
import * as i2$7 from 'primeng/menu';
import { MenuModule } from 'primeng/menu';
import * as i2$1 from 'primeng/message';
import { MessageModule } from 'primeng/message';
import * as i1$8 from 'primeng/paginator';
import { PaginatorModule } from 'primeng/paginator';
import { PanelModule } from 'primeng/panel';
import * as i1$6 from 'primeng/radiobutton';
import { RadioButtonModule } from 'primeng/radiobutton';
import { RippleModule } from 'primeng/ripple';
import { ScrollPanelModule } from 'primeng/scrollpanel';
import * as i4$2 from 'primeng/select';
import { SelectModule } from 'primeng/select';
import * as i3$3 from 'primeng/splitbutton';
import { SplitButtonModule } from 'primeng/splitbutton';
import * as i1$9 from 'primeng/tabs';
import { TabsModule } from 'primeng/tabs';
import * as i1$5 from 'primeng/textarea';
import { TextareaModule } from 'primeng/textarea';
import * as i2$6 from 'primeng/tieredmenu';
import { TieredMenuModule } from 'primeng/tieredmenu';
import { ToastModule } from 'primeng/toast';
import * as i1$4 from 'primeng/toggleswitch';
import { ToggleSwitchModule } from 'primeng/toggleswitch';
import * as i2 from 'primeng/tooltip';
import { TooltipModule } from 'primeng/tooltip';
import { FluidModule } from 'primeng/fluid';
import { catchError, map as map$4, tap, debounceTime, first, switchMap, finalize, distinctUntilChanged } from 'rxjs/operators';
import localeDe from '@angular/common/locales/de';
import localeEn from '@angular/common/locales/en-GB';
import localeFr from '@angular/common/locales/fr';
import localeIt from '@angular/common/locales/it';
import { DateTime } from 'luxon';
import de$6 from 'primelocale/de.json';
import en$6 from 'primelocale/en.json';
import fr$6 from 'primelocale/fr.json';
import it$6 from 'primelocale/it.json';
import { PrimeNG } from 'primeng/config';
import { definePreset } from '@primeng/themes';
import Aura from '@primeng/themes/aura';
import * as i3$2 from '@angular/forms';
import { UntypedFormGroup, FormsModule, ReactiveFormsModule, FormControl } from '@angular/forms';
import { FormlyJsonschema } from '@ngx-formly/core/json-schema';
import { cloneDeep } from 'lodash-es';
import * as i4$1 from '@ngx-formly/core';
import { FieldType, FormlyModule, FieldArrayType, FieldWrapper, FORMLY_CONFIG } from '@ngx-formly/core';
import { FormlyFormFieldModule } from '@ngx-formly/primeng/form-field';
import { FormlySelectModule } from '@ngx-formly/core/select';
import * as i3$4 from 'primeng/multiselect';
import { MultiSelectModule } from 'primeng/multiselect';
import { toSignal } from '@angular/core/rxjs-interop';
import { FormlySelectModule as FormlySelectModule$1 } from '@ngx-formly/primeng/select';
import * as i3$5 from 'primeng/treeselect';
import { TreeSelectModule } from 'primeng/treeselect';
import { Clipboard, ClipboardModule } from '@angular/cdk/clipboard';
import { GeneratePassword } from 'generate-password-lite';
import { FormlyPrimeNGModule } from '@ngx-formly/primeng';
import * as i8 from 'primeng/dataview';
import { DataViewModule } from 'primeng/dataview';
import EasyMDE from 'easymde';
import { DomHandler } from 'primeng/dom';
import * as CryptoJS from 'crypto-js';

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Service for managing configuration of the application.
 */
class CoreConfigService {
    constructor() {
        this.production = false;
        this.apiBaseUrl = '';
        this.apiEndpointPrefix = '/api';
        this.schemaFormEndpoint = '/api/schemaform';
        this.languages = ['en'];
        this.defaultLanguage = 'en';
        this.secretPassphrase = 'ShERWIN53SnAggIng48rELAtiVes';
        this.translationsURLs = [];
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CoreConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CoreConfigService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CoreConfigService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Service giving information about API.
 */
class ApiService {
    constructor() {
        this.configService = inject(CoreConfigService);
        // API base URL. Ex: https://localhost:5000.
        this.baseUrl = '';
        // API prefix. Ex: /api
        this.endpointPrefix = '/';
    }
    /**
     * Returns Invenio API Endpoint corresponding to type.
     *
     * @param type Type of the resource.
     * @param absolute If absolute or relative url must be returned.
     * @return Endpoint as string.
     */
    getEndpointByType(type, absolute = false) {
        let endpoint = this.configService.apiEndpointPrefix + '/' + type;
        if (absolute === true) {
            endpoint = this.configService.apiBaseUrl + endpoint;
        }
        return endpoint;
    }
    /**
     * Returns Invenio-RERO-base API export endpoint corresponding to type.
     *
     * @param type Type of the resource.
     * @param absolute If absolute or relative url must be returned.
     * @return Endpoint as string.
     */
    getExportEndpointByType(type, absolute = false) {
        let endpoint = this.configService.apiEndpointPrefix + '/export/' + type;
        if (absolute === true) {
            endpoint = this.configService.apiBaseUrl + endpoint;
        }
        return endpoint;
    }
    /**
     * Returns $ref endpoint to resource.
     *
     * @param type Type of resource.
     * @param id Id of the record.
     * @return Ref endpoint as string.
     */
    getRefEndpoint(type, id) {
        let prefix = '';
        if (this.configService.$refPrefix) {
            prefix += this.configService.$refPrefix;
        }
        return `${prefix}${this.configService.apiEndpointPrefix}/${type}/${id}`;
    }
    /**
     * Returns invenio API FormOption Endpoint corresponding to type.
     *
     * @param type Type of the resource
     * @param absolute If absolute or relative url must be returned.
     * @return Schema form endpoint.
     */
    getSchemaFormEndpoint(type, absolute = false) {
        let endpoint = this.configService.schemaFormEndpoint + '/' + type;
        if (absolute === true) {
            endpoint = this.configService.apiBaseUrl + endpoint;
        }
        return endpoint;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApiService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ApiService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2023 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Doc: https://developer.mozilla.org/en-US/docs/Web/API/Window/beforeunload_event
 *
 * The beforeunload event is fired when the window, the document and its resources
 * are about to be unloaded. The document is still visible and the event is still
 * cancelable at this point.
 */
class AbstractCanDeactivateComponent {
    unloadNotification($event) {
        if (!this.canDeactivate) {
            $event.returnValue = true;
        }
    }
    /**
     * Can deactivate changed on editor
     * @param activate - boolean
     */
    canDeactivateChanged(activate) {
        this.canDeactivate = activate;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AbstractCanDeactivateComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: AbstractCanDeactivateComponent, isStandalone: false, selector: "ng-component", host: { listeners: { "window:beforeunload": "unloadNotification($event)" } }, ngImport: i0, template: '', isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AbstractCanDeactivateComponent, decorators: [{
            type: Component,
            args: [{
                    template: '',
                    standalone: false
                }]
        }], propDecorators: { unloadNotification: [{
                type: HostListener,
                args: ['window:beforeunload', ['$event']]
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Pipe for converting carriage returns to <br> html entities.
 */
class Nl2brPipe {
    constructor() {
        this.sanitizer = inject(DomSanitizer);
    }
    /**
     * Returns transformed value containing <br> entities.
     *
     * @param value Value to transform.
     * @return Transformed value.
     */
    transform(value) {
        if (!value) {
            return this.sanitizer.bypassSecurityTrustHtml('');
        }
        return this.sanitizer.bypassSecurityTrustHtml(value.replace(/\r\n?|\n/g, '<br>\n'));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Nl2brPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: Nl2brPipe, isStandalone: false, name: "nl2br" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: Nl2brPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'nl2br',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class DialogComponent {
    constructor() {
        this.config = inject(DynamicDialogConfig);
        this.ref = inject(DynamicDialogRef);
    }
    confirm() {
        this.ref.close(true);
    }
    cancel() {
        this.ref.close(false);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DialogComponent, isStandalone: false, selector: "ng-core-dialog", ngImport: i0, template: `
  <div class="core:flex core:flex-col core:gap-2">
    <div class="core:flex" [innerHtml]="config.data.body|nl2br"></div>
    <div class="core:flex core:justify-end core:gap-1">
      <p-button
        [label]="config.data.cancelTitleButton || 'Cancel'|translate"
        severity="danger"
        [outlined]="true"
        (onClick)="cancel()"
      />
      @if (config.data.confirmButton) {
        <p-button [label]="config.data.confirmTitleButton || 'OK'|translate" (onClick)="confirm()" />
      }
    </div>
  </div>
  `, isInline: true, dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: Nl2brPipe, name: "nl2br" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DialogComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-dialog',
                    template: `
  <div class="core:flex core:flex-col core:gap-2">
    <div class="core:flex" [innerHtml]="config.data.body|nl2br"></div>
    <div class="core:flex core:justify-end core:gap-1">
      <p-button
        [label]="config.data.cancelTitleButton || 'Cancel'|translate"
        severity="danger"
        [outlined]="true"
        (onClick)="cancel()"
      />
      @if (config.data.confirmButton) {
        <p-button [label]="config.data.confirmTitleButton || 'OK'|translate" (onClick)="confirm()" />
      }
    </div>
  </div>
  `,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Pipe for returning a default value if the given value is null or undefined.
 */
class DefaultPipe {
    /**
     * Returns a default value.
     *
     * @param value Value to check.
     * @param defaultValue Value to return if value is null.
     * @return Value or default value.
     */
    transform(value, defaultValue) {
        return value || defaultValue;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DefaultPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: DefaultPipe, isStandalone: false, name: "default" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DefaultPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'default', pure: true,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying errors.
 */
class ErrorComponent {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: ErrorComponent, isStandalone: false, selector: "ng-core-error", inputs: { error: "error" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div class=\"core:text-center core:my-8\">\n  <p class=\"core:text-4xl\">\n    <i class=\"fa fa-flash core:mr-4\"></i>\n    <span class=\"core:text-muted-color\">{{ error.status }}</span>\n    {{ error.title }}\n  </p>\n  <h5 class=\"core:mt-8\">{{ error.message | default: ('You cannot access this page.' | translate) }}</h5>\n</div>\n", dependencies: [{ kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: DefaultPipe, name: "default" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ErrorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-error', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div class=\"core:text-center core:my-8\">\n  <p class=\"core:text-4xl\">\n    <i class=\"fa fa-flash core:mr-4\"></i>\n    <span class=\"core:text-muted-color\">{{ error.status }}</span>\n    {{ error.title }}\n  </p>\n  <h5 class=\"core:mt-8\">{{ error.message | default: ('You cannot access this page.' | translate) }}</h5>\n</div>\n" }]
        }], propDecorators: { error: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2023-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * When this guard is configured, it intercepts the form output without
 * saving or undoing changes.
 *
 * Route definition configuration
 * { path: 'foo/bar', canDeactivate: [ ComponentCanDeactivateGuard ] },
 *
 * Custom editor component configuration
 * class FooComponent AbstractCanDeactivateComponent {
 *  canDeactivate: boolean = false;
 *  ...
 * }
 *
 * Template configuration (add output canDeactivateChange)
 * <ng-core-editor
 *   (canDeactivateChange)="canDeactivateChanged($event)"
 *   ...
 * ></ng-core-editor>
 */
class ComponentCanDeactivateGuard {
    constructor() {
        this.translateService = inject(TranslateService);
        this.dialogService = inject(DialogService);
    }
    /**
     * Displays a confirmation modal if the user leaves the form without
     * saving or canceling
     * @param component - AbstractCanDeactivateComponent
     * @returns Observable<boolean> or boolean
     */
    canDeactivate(component) {
        if (!component.canDeactivate) {
            this.ref = this.dialogService.open(DialogComponent, {
                header: this.translateService.instant('Quit the page'),
                data: {
                    body: this.translateService.instant('Do you want to quit the page? The changes made so far will be lost.'),
                    confirmButton: true,
                    confirmTitleButton: this.translateService.instant('Quit'),
                    cancelTitleButton: this.translateService.instant('Stay'),
                },
                dismissableMask: true,
                modal: true,
                style: { width: '25rem' }
            });
            return this.ref.onClose;
        }
        return true;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ComponentCanDeactivateGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ComponentCanDeactivateGuard }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ComponentCanDeactivateGuard, decorators: [{
            type: Injectable
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Pipe for applying a callback function to filter array items.
 */
class CallbackArrayFilterPipe {
    /**
     * Filter array items with the given callback function.
     *
     * @param items List of items.
     * @param callback Callback function to apply.
     * @return List of filtered values.
     */
    transform(items, callback) {
        if (!items && !callback) {
            return [];
        }
        if (items && !callback) {
            return items;
        }
        return items.filter(item => callback(item));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CallbackArrayFilterPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: CallbackArrayFilterPipe, isStandalone: false, name: "callbackArrayFilter" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CallbackArrayFilterPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'callbackArrayFilter',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Get human readable file size.
 */
class FilesizePipe {
    /**
     * Transform size to a human readable size.
     *
     * @param size Size of file.
     * @param precision Number of decimals.
     * @return Human readable file size.
     */
    transform(size, precision = 2) {
        let i = -1;
        const byteUnits = ['kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
        do {
            size /= 1024;
            i++;
        } while (size > 1024);
        return [Math.max(size, 0.1).toFixed(precision), byteUnits[i]].join(' ');
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FilesizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: FilesizePipe, isStandalone: false, name: "filesize" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FilesizePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'filesize',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2021-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Pipe to transform markdown to html.
 */
class MarkdownPipe {
    constructor() {
        this.sanitizer = inject(DomSanitizer);
    }
    /**
     * Transform markdown to HTML.
     *
     * @param value Markdown initial value.
     * @returns HTML corresponding to markdown.
     */
    transform(value) {
        const markValue = marked.parse(value, { gfm: true, breaks: false, async: false });
        return this.sanitizer.bypassSecurityTrustHtml(markValue);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: MarkdownPipe, isStandalone: false, name: "markdown" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'markdown',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class SanitizePipe {
    transform(value, regex = '<[^>]*>', replace = '', flag = 'g') {
        const re = new RegExp(regex, flag);
        return value.replace(re, replace);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SanitizePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: SanitizePipe, isStandalone: false, name: "sanitize" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SanitizePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'sanitize',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Source code: https://dev.to/codephobia/using-typescricore:pt-to-sort-by-keys-35ob
 */
/**
 * Error messages
 */
const ERROR_REQUIRES_AT_LEAST_ONE_KEY = 'provide at least one key to sort by';
const ERROR_KEY_LENGTH_INVALID = 'a key was provided as an empty string';
const ERROR_DESC_KEY_LENGTH_INVALID = 'a descending key was missing the key name';
const ERROR_OBJECT_DOESNT_CONTAIN_KEY = 'a key you are attempting to sort by is not on all objects';
/**
 *  Recursive function to sort values by their keys.
 */
const sortByKey = (a, b, ...keys) => {
    // Get first key in array.
    let key = keys.shift();
    // Make sure we have a valid key name.
    if (!key.length) {
        throw new Error(ERROR_KEY_LENGTH_INVALID);
    }
    // Default to ascending order.
    let desc = false;
    // Check for descending sort.
    if (key.charAt(0) === '-') {
        // Make sure key has a name as well as the minus sign.
        if (key.length < 2) {
            throw new Error(ERROR_DESC_KEY_LENGTH_INVALID);
        }
        // Remove minus from key name.
        key = key.substr(1);
        // Flag as descending order.
        desc = true;
    }
    // Make sure the objects both have the key. We make sure
    // to check this after we have removed the minus sign.
    if (!a.hasOwnProperty(key) || !b.hasOwnProperty(key)) {
        throw new Error(ERROR_OBJECT_DOESNT_CONTAIN_KEY);
    }
    // Determine checks based on asc / desc.
    const direction = (desc) ? -1 : 1;
    // Perform bubble sort based on the values.
    const authorizedSort = [-1, 1];
    if (authorizedSort.includes(a[key].localeCompare(b[key]))) {
        return a[key].localeCompare(b[key]) * direction;
    }
    // The values of the current key are equal, so if we still
    // have keys to check recursively, check the next key.
    if (keys.length) {
        return sortByKey(a, b, ...keys);
    }
    // All keys returned and no more sorting needed.
    return 0;
};
/**
 * Wrapper sort function for the recursive one.
 */
const sortByKeys = (data, ...keys) => {
    // Make sure we have at least one key to sort by.
    if (!keys.length) {
        throw new Error(ERROR_REQUIRES_AT_LEAST_ONE_KEY);
    }
    // Sort data.
    data.sort((a, b) => {
        return sortByKey(a, b, ...keys);
    });
    // Return sorted data.
    return data;
};

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Source code: https://dev.to/codephobia/using-typescript-to-sort-by-keys-35ob
 */
/**
 * Pipe for the sorting function.
 */
class SortByKeysPipe {
    /**
     * Order elements by sort key(s)
     * @param value - array of values
     * @param keys - string, sort key
     */
    transform(value, ...keys) {
        return sortByKeys(value, ...keys);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SortByKeysPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: SortByKeysPipe, isStandalone: false, name: "sortByKeys" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SortByKeysPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'sortByKeys',
                    pure: true,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Pipe for truncating text.
 */
class TruncateTextPipe {
    /**
     * Truncate text.
     *
     * @param value Text to truncate.
     * @param limit Limit after which the text is truncated.
     * @param trail Trailing chars
     * @param type Word or Char type
     * @return Truncated string
     */
    transform(value, limit = 40, trail = '…', type = 'word') {
        let result = value || '';
        if (type === 'char' && value) {
            if (value.length < limit) {
                return value;
            }
            else {
                return value.substring(0, limit) + trail;
            }
        }
        if (type === 'word' && value) {
            const words = value.split(/\s+/);
            if (words.length > Math.abs(limit)) {
                if (limit < 0) {
                    limit *= -1;
                    result =
                        trail + words.slice(words.length - limit).join(' ');
                }
                else {
                    result = words.slice(0, limit).join(' ') + trail;
                }
            }
        }
        return result;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TruncateTextPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: TruncateTextPipe, isStandalone: false, name: "truncateText" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TruncateTextPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'truncateText',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
function extractIdOnRef(ref) {
    if (ref != null) {
        const pidRegExp = new RegExp('.*/(.*)$');
        return pidRegExp.exec(ref)[1];
    }
    return null;
}
function cleanDictKeys(data) {
    // let data = _.cloneDeep(data);
    for (const key in data) {
        if (data[key] === null || data[key] === undefined || data[key].length === 0) {
            delete data[key];
        }
    }
    return data;
}
function capitalize(value) {
    return value.charAt(0).toUpperCase() + value.slice(1);
}

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Uppercase the first letter of the string.
 */
class UpperCaseFirstPipe {
    /**
     * Uppercase the first letter of the given value.
     *
     * @param value Value to transform.
     * @return Transformed value.
     */
    transform(value) {
        if (!value) {
            return value;
        }
        return capitalize(value);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpperCaseFirstPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: UpperCaseFirstPipe, isStandalone: false, name: "ucfirst" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: UpperCaseFirstPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'ucfirst',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class PrimeNgCoreModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PrimeNgCoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: PrimeNgCoreModule, exports: [AutoCompleteModule,
            AutoFocusModule,
            BadgeModule,
            ButtonModule,
            CardModule,
            CheckboxModule,
            ConfirmDialogModule,
            DatePickerModule,
            DividerModule,
            DynamicDialogModule,
            FieldsetModule,
            FluidModule,
            InputGroupAddonModule,
            InputGroupModule,
            InputNumberModule,
            InputTextModule,
            ListboxModule,
            MenuModule,
            MessageModule,
            PaginatorModule,
            PanelModule,
            RadioButtonModule,
            RippleModule,
            ScrollPanelModule,
            SelectModule,
            SplitButtonModule,
            TabsModule,
            TextareaModule,
            TieredMenuModule,
            ToastModule,
            ToggleSwitchModule,
            TooltipModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PrimeNgCoreModule, providers: [
            ConfirmationService,
            DialogService,
            MessageService
        ], imports: [AutoCompleteModule,
            AutoFocusModule,
            BadgeModule,
            ButtonModule,
            CardModule,
            CheckboxModule,
            ConfirmDialogModule,
            DatePickerModule,
            DividerModule,
            DynamicDialogModule,
            FieldsetModule,
            FluidModule,
            InputGroupAddonModule,
            InputGroupModule,
            InputNumberModule,
            InputTextModule,
            ListboxModule,
            MenuModule,
            MessageModule,
            PaginatorModule,
            PanelModule,
            RadioButtonModule,
            RippleModule,
            ScrollPanelModule,
            SelectModule,
            SplitButtonModule,
            TabsModule,
            TextareaModule,
            TieredMenuModule,
            ToastModule,
            ToggleSwitchModule,
            TooltipModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PrimeNgCoreModule, decorators: [{
            type: NgModule,
            args: [{
                    providers: [
                        ConfirmationService,
                        DialogService,
                        MessageService
                    ],
                    exports: [
                        AutoCompleteModule,
                        AutoFocusModule,
                        BadgeModule,
                        ButtonModule,
                        CardModule,
                        CheckboxModule,
                        ConfirmDialogModule,
                        DatePickerModule,
                        DividerModule,
                        DynamicDialogModule,
                        FieldsetModule,
                        FluidModule,
                        InputGroupAddonModule,
                        InputGroupModule,
                        InputNumberModule,
                        InputTextModule,
                        ListboxModule,
                        MenuModule,
                        MessageModule,
                        PaginatorModule,
                        PanelModule,
                        RadioButtonModule,
                        RippleModule,
                        ScrollPanelModule,
                        SelectModule,
                        SplitButtonModule,
                        TabsModule,
                        TextareaModule,
                        TieredMenuModule,
                        ToastModule,
                        ToggleSwitchModule,
                        TooltipModule,
                    ],
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class SearchInputComponent {
    constructor() {
        /** Input Id */
        this.inputId = input('search');
        /** Display label */
        this.displayLabel = input(false);
        /** Placeholder */
        this.placeholder = input('search');
        /** Value to search */
        this.searchText = input('');
        /** Remove trailing and leading spaces if true */
        this.trimQueryString = input(true);
        /** Disabled attribute of search input */
        this.disabled = input(false);
        /** Make the focus on field */
        this.focus = input(false);
        /** Search value event */
        this.search = output();
        effect(() => {
            if (this.focus() && this.input?.nativeElement) {
                this.input.nativeElement.focus();
            }
        });
    }
    /**
     * Start the search by pressing enter
     * or clicking on the lens.
     */
    doSearch() {
        const { value } = this.input.nativeElement;
        this.search.emit(this.trimQueryString() ? value.trim() : value);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SearchInputComponent, isStandalone: false, selector: "ng-core-search-input", inputs: { inputId: { classPropertyName: "inputId", publicName: "inputId", isSignal: true, isRequired: false, transformFunction: null }, displayLabel: { classPropertyName: "displayLabel", publicName: "displayLabel", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, searchText: { classPropertyName: "searchText", publicName: "searchText", isSignal: true, isRequired: false, transformFunction: null }, trimQueryString: { classPropertyName: "trimQueryString", publicName: "trimQueryString", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, focus: { classPropertyName: "focus", publicName: "focus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { search: "search" }, viewQueries: [{ propertyName: "input", first: true, predicate: ["searchInput"], descendants: true }], ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (displayLabel()) {\n  <label [for]=\"inputId()\" class=\"core:font-bold\">{{ placeholder() }}</label>\n}\n<p-inputGroup>\n  <input\n    #searchInput\n    [pAutoFocus]=\"focus()\"\n    pInputText\n    [disabled]=\"disabled()\"\n    [id]=\"inputId()\"\n    [placeholder]=\"!displayLabel() && placeholder() ? placeholder() : ''\"\n    [value]=\"searchText()\"\n    (keydown.enter)=\"doSearch()\"\n    attr.aria-label=\"{{ placeholder() }}\"\n  />\n  <p-inputGroupAddon>\n    <p-button\n      icon=\"fa fa-search\"\n      variant=\"text\"\n      severity=\"secondary\"\n      (click)=\"doSearch()\"\n      class=\"core:h-[2.5rem]\"\n    />\n  </p-inputGroupAddon>\n</p-inputGroup>\n", dependencies: [{ kind: "directive", type: i1$1.AutoFocus, selector: "[pAutoFocus]", inputs: ["autofocus", "pAutoFocus"] }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i3.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["style", "styleClass"] }, { kind: "directive", type: i3$1.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchInputComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-search-input', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (displayLabel()) {\n  <label [for]=\"inputId()\" class=\"core:font-bold\">{{ placeholder() }}</label>\n}\n<p-inputGroup>\n  <input\n    #searchInput\n    [pAutoFocus]=\"focus()\"\n    pInputText\n    [disabled]=\"disabled()\"\n    [id]=\"inputId()\"\n    [placeholder]=\"!displayLabel() && placeholder() ? placeholder() : ''\"\n    [value]=\"searchText()\"\n    (keydown.enter)=\"doSearch()\"\n    attr.aria-label=\"{{ placeholder() }}\"\n  />\n  <p-inputGroupAddon>\n    <p-button\n      icon=\"fa fa-search\"\n      variant=\"text\"\n      severity=\"secondary\"\n      (click)=\"doSearch()\"\n      class=\"core:h-[2.5rem]\"\n    />\n  </p-inputGroupAddon>\n</p-inputGroup>\n" }]
        }], ctorParameters: () => [], propDecorators: { input: [{
                type: ViewChild,
                args: ['searchInput']
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class PageTitleStrategy extends TitleStrategy {
    constructor() {
        super(...arguments);
        this.title = inject(Title);
        this.config = inject(CoreConfigService);
        this.translate = inject(TranslateService);
    }
    updateTitle(routerState) {
        const title = this.buildTitle(routerState);
        let projectTitle = '';
        if (this.config.projectTitle) {
            projectTitle = this.config.projectTitle;
        }
        if (projectTitle && title) {
            this.title.setTitle(`${this.translate.instant(title)} | ${projectTitle}`);
        }
        else if (projectTitle) {
            this.title.setTitle(projectTitle);
        }
        else if (title) {
            this.title.setTitle(this.translate.instant(title));
        }
        else {
            this.title.setTitle('-');
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PageTitleStrategy, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PageTitleStrategy, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PageTitleStrategy, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying a "read more" link after a text.
 */
class TextReadMoreComponent {
    constructor() {
        /** Number of parts to display (depending of the unit)  */
        this.limit = 50;
        /** "Show more" label to display */
        this.showMoreLabel = 'Show more';
        /** "Show less" label to display  */
        this.showLessLabel = 'Show less';
        /** Splitting unit [ word | character] */
        this.unit = 'word';
        /** trailing string */
        this.trailing = '…';
        /** boolean to know if initial text is expanded  */
        this.isExpanded = false;
        /** boolean to know if limit is reached */
        this.isLimitReached = true;
    }
    ngOnInit() {
        this.textToDisplay = this.sTruncateText = this._truncateText();
        if (this.text === this.textToDisplay) {
            this.isLimitReached = false;
        }
    }
    /**
     * Allow to toggle content of the field
     * @param event : Click event
     */
    toggleText(event) {
        event.preventDefault();
        this.textToDisplay = (this.isExpanded)
            ? this.sTruncateText
            : this.text;
        this.isExpanded = !this.isExpanded;
    }
    /**
     * Show the link label depending of isExpanded
     */
    get linkLabel() {
        return this.isExpanded ? this.showLessLabel : this.showMoreLabel;
    }
    /**
     * Truncate initial text using the defined limit and unit.
     */
    _truncateText() {
        if (this.text === undefined) {
            return '';
        }
        let pattern = /\s+/;
        let joinText = ' ';
        if (this.unit !== 'word') {
            pattern = '';
            joinText = '';
        }
        const parts = this.text.split(pattern);
        if (parts.length <= this.limit) {
            return this.text;
        }
        else {
            if (this.limit < 0) {
                const tmpLimit = this.limit * -1;
                return this.trailing + parts.slice(parts.length - tmpLimit, parts.length).join(joinText);
            }
            else {
                return parts.slice(0, this.limit).join(joinText) + this.trailing;
            }
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TextReadMoreComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: TextReadMoreComponent, isStandalone: false, selector: "ng-core-text-read-more", inputs: { text: "text", limit: "limit", showMoreLabel: "showMoreLabel", showLessLabel: "showLessLabel", unit: "unit", trailing: "trailing" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (isLimitReached && limit<0) {\n  <a class=\"core:pl-2\" href=\"#\" (click)=\"toggleText($event)\">{{ linkLabel }}</a>\n}\n<span [innerHTML]=\"textToDisplay | nl2br\"></span>\n@if (isLimitReached && limit>=0) {\n  <a class=\"core:pl-2\" href=\"#\" (click)=\"toggleText($event)\">{{ linkLabel }}</a>\n}\n", dependencies: [{ kind: "pipe", type: Nl2brPipe, name: "nl2br" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TextReadMoreComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-text-read-more', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (isLimitReached && limit<0) {\n  <a class=\"core:pl-2\" href=\"#\" (click)=\"toggleText($event)\">{{ linkLabel }}</a>\n}\n<span [innerHTML]=\"textToDisplay | nl2br\"></span>\n@if (isLimitReached && limit>=0) {\n  <a class=\"core:pl-2\" href=\"#\" (click)=\"toggleText($event)\">{{ linkLabel }}</a>\n}\n" }]
        }], propDecorators: { text: [{
                type: Input
            }], limit: [{
                type: Input
            }], showMoreLabel: [{
                type: Input
            }], showLessLabel: [{
                type: Input
            }], unit: [{
                type: Input
            }], trailing: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class DateTranslatePipe extends DatePipe {
    constructor() {
        super(...arguments);
        this.translateService = inject(TranslateService);
    }
    transform(value, format, timezone, locale) {
        if (!locale) {
            locale = this.translateService.currentLang;
        }
        if (locale === 'en') {
            locale = `${locale}-GB`;
        }
        return super.transform(value, format, timezone, locale);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DateTranslatePipe, deps: null, target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: DateTranslatePipe, isStandalone: false, name: "dateTranslate", pure: false }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DateTranslatePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'dateTranslate',
                    pure: false,
                    standalone: false
                }]
        }] });

var aar$3 = "Afar";
var abk$3 = "Abchasisch";
var ace$3 = "Achinesisch";
var ach$3 = "Acholi";
var ada$3 = "Dangme";
var ady$3 = "Adygeisch";
var afa$3 = "Afroasiatische Sprachen";
var afh$3 = "Afrihili";
var afr$3 = "Afrikaans";
var ain$3 = "Ainu";
var aka$3 = "Akan";
var akk$3 = "Akkadisch";
var alb$3 = "Albanisch";
var ale$3 = "Aleutisch";
var alg$3 = "Algonkin Sprachen";
var alt$3 = "Südaltaisch";
var amh$3 = "Amharisch";
var ang$3 = "Altenglisch";
var anp$3 = "Angika";
var apa$3 = "Apache Sprachen";
var ara$3 = "Arabisch";
var arc$3 = "Reichsaramäisch";
var arg$3 = "Aragonesisch";
var arm$3 = "Armenisch";
var arn$3 = "Mapudungun";
var arp$3 = "Arapaho";
var art$3 = "Konstruierte Sprachen";
var arw$3 = "Arawak";
var asm$3 = "Assamesisch";
var ast$3 = "Asturisch";
var ath$3 = "Athapaskische Sprachen";
var aus$3 = "Australische Sprachen";
var ava$3 = "Awarisch";
var ave$3 = "Avestisch";
var awa$3 = "Awadhi";
var aym$3 = "Aymara";
var aze$3 = "Aserbaidschanisch";
var bad$3 = "Banda Sprachen";
var bai$3 = "Bamileke Sprachen";
var bak$3 = "Baschkirisch";
var bal$3 = "Belutschisch";
var bam$3 = "Bambara";
var ban$3 = "Balinesisch";
var baq$3 = "Baskisch";
var bas$3 = "Basaa";
var bat$3 = "Baltische Sprachen";
var bej$3 = "Bedscha";
var bel$3 = "Weißrussisch";
var bem$3 = "Bemba";
var ben$3 = "Bengalisch";
var ber$3 = "Berbersprachen";
var bho$3 = "Bhojpuri";
var bih$3 = "Bihari";
var bik$3 = "Bikolano";
var bin$3 = "Edo";
var bis$3 = "Bislama";
var bla$3 = "Blackfoot";
var bnt$3 = "Bantusprachen";
var bos$3 = "Bosnisch";
var bra$3 = "Braj-Bhakha";
var bre$3 = "Bretonisch";
var btk$3 = "Bataksprachen";
var bua$3 = "Burjatisch";
var bug$3 = "Buginesisch";
var bul$3 = "Bulgarisch";
var bur$3 = "Birmanisch";
var byn$3 = "Blin";
var cad$3 = "Caddo";
var cai$3 = "Mesoamerikanische Sprachen";
var car$3 = "Karib";
var cat$3 = "Katalanisch";
var cau$3 = "Kaukasische Sprachen";
var ceb$3 = "Cebuano";
var cel$3 = "Keltische Sprachen";
var cha$3 = "Chamorro";
var chb$3 = "Chibcha";
var che$3 = "Tschechisch";
var chg$3 = "Tschagataisch";
var chi$3 = "chinesisch";
var chk$3 = "Chuukesisch";
var chm$3 = "Mari";
var chn$3 = "Chinook Wawa";
var cho$3 = "Choctaw";
var chp$3 = "Chipewyan";
var chr$3 = "Cherokee";
var chu$3 = "Kirchenslawisch";
var chv$3 = "Tschuwaschisch";
var chy$3 = "Cheyenne";
var cmc$3 = "Chamische Sprachen";
var cnr$3 = "Montenegrinisch";
var cop$3 = "Koptisch";
var cor$3 = "Kornisch";
var cos$3 = "Korsisch";
var cpe$3 = "Englisch-basierte Kreols und Pidgins";
var cpf$3 = "Französisch-basierte Kreols und Pidgins";
var cpp$3 = "Portugiesisch-basierte Kreols und Pidgins";
var cre$3 = "Cree";
var crh$3 = "Krimtatarisch";
var crp$3 = "Kreol- und Pidginsprachen";
var csb$3 = "Kaschubisch";
var cus$3 = "Kuschitische Sprachen";
var cze$3 = "Tschechisch";
var dak$3 = "Dakota";
var dan$3 = "Dänisch";
var dar$3 = "Darginisch";
var day$3 = "Land-Dayak-Sprachen";
var del$3 = "Delawarisch";
var den$3 = "Slavey";
var dgr$3 = "Dogrib";
var din$3 = "Dinka";
var div$3 = "Dhivehi";
var doi$3 = "Dogri";
var dra$3 = "Dravidische Sprachen";
var dsb$3 = "Niedersorbisch";
var dua$3 = "Duala";
var dum$3 = "Mittelniederländisch";
var dut$3 = "Niederländisch";
var dyu$3 = "Dioula";
var dzo$3 = "Dzongkha";
var efi$3 = "Efik";
var egy$3 = "Ägyptisch";
var eka$3 = "Ekajuk";
var elx$3 = "Elamisch";
var eng$3 = "Englisch";
var enm$3 = "Mittelenglisch";
var epo$3 = "Esperanto";
var est$3 = "Estnisch";
var ewe$3 = "Ewe";
var ewo$3 = "Ewondo";
var fan$3 = "Fang";
var fao$3 = "Färöisch";
var fat$3 = "Fante";
var fij$3 = "Fidschi";
var fil$3 = "Filipino";
var fin$3 = "Finnisch";
var fiu$3 = "Finno-ugrische Sprachen";
var fon$3 = "Fon";
var fre$3 = "Französisch";
var frm$3 = "Mittelfranzösisch";
var fro$3 = "Altfranzösisch";
var frr$3 = "Nordfriesisch";
var frs$3 = "Ostfriesisch";
var fry$3 = "Westfriesisch";
var ful$3 = "Fulfulde";
var fur$3 = "Friulian";
var gaa$3 = "Ga";
var gay$3 = "Gayo";
var gba$3 = "Gbaya";
var gem$3 = "Germanische Sprachen";
var geo$3 = "Georgisch";
var ger$3 = "Deutsch";
var gez$3 = "Geez";
var gil$3 = "Kiribatisch";
var gla$3 = "Schottisch-gälisch";
var gle$3 = "Irisch";
var glg$3 = "Galicisch";
var glv$3 = "Manx";
var gmh$3 = "Mittelhochdeutsch";
var goh$3 = "Althochdeutsch";
var gon$3 = "Gondi";
var gor$3 = "Gorontalo";
var got$3 = "Gotisch";
var grb$3 = "Grebo";
var grc$3 = "Altgriechisch";
var gre$3 = "Griechisch";
var grn$3 = "Guarani";
var gsw$3 = "Schweizerdeutsch";
var guj$3 = "Gujarati";
var gwi$3 = "Gwich'in (Sprache)";
var hai$3 = "Haida";
var hat$3 = "Haitianisch";
var hau$3 = "Hausa";
var haw$3 = "Hawaiisch";
var heb$3 = "Hebräisch";
var her$3 = "Otjiherero";
var hil$3 = "Hiligaynon";
var him$3 = "West-Paharisprachen";
var hin$3 = "Hindi";
var hit$3 = "Hethitisch";
var hmn$3 = "Hmong-Sprache";
var hmo$3 = "Hiri-Motu";
var hrv$3 = "Kroatisch";
var hsb$3 = "Obersorbisch";
var hun$3 = "Ungarisch";
var hup$3 = "Hoopa";
var iba$3 = "Iban";
var ibo$3 = "Igbo";
var ice$3 = "Isländisch";
var ido$3 = "Ido";
var iii$3 = "Yi";
var ijo$3 = "Ijo-Sprachen";
var iku$3 = "Inuktitut";
var ile$3 = "Interlingue";
var ilo$3 = "Ilokano";
var ina$3 = "Interlingua";
var inc$3 = "Indoarische Sprachen";
var ind$3 = "Indonesisch";
var ine$3 = "Indogermanische Sprachen";
var inh$3 = "Inguschisch";
var ipk$3 = "Inupiaq";
var ira$3 = "Iranische Sprachen";
var iro$3 = "Irokesische Sprachen";
var ita$3 = "Italienisch";
var jav$3 = "Javanisch";
var jbo$3 = "Lojban";
var jpn$3 = "Japanisch";
var jpr$3 = "Judäo-Persisch";
var jrb$3 = "Judäo-Arabisch";
var kaa$3 = "Karakalpakisch";
var kab$3 = "Kabylisch";
var kac$3 = "Jingpo";
var kal$3 = "Grönländisch";
var kam$3 = "Kikamba";
var kan$3 = "Kannada";
var kar$3 = "Karenische Sprachen";
var kas$3 = "Kaschmiri";
var kau$3 = "Kanuri";
var kaw$3 = "Kawi";
var kaz$3 = "Kasachisch";
var kbd$3 = "Kabardinisch";
var kha$3 = "Khasi";
var khi$3 = "Khoisansprachen";
var khm$3 = "Khmer";
var kho$3 = "Khotanesisch";
var kik$3 = "Kikuyu";
var kin$3 = "Kinyarwanda";
var kir$3 = "Kirgisisch";
var kmb$3 = "Kimbundu";
var kok$3 = "Konkani";
var kom$3 = "Komi";
var kon$3 = "Kikongo";
var kor$3 = "Koreanisch";
var kos$3 = "Kosraeanisch";
var kpe$3 = "Kpelle";
var krc$3 = "Karatschai-balkarisch";
var krl$3 = "Karelisch";
var kro$3 = "Kru-Sprachen";
var kru$3 = "Kurukh";
var kua$3 = "oshiKwanyama";
var kum$3 = "Kumykisch";
var kur$3 = "Kurdisch";
var kut$3 = "Kutanaha";
var lad$3 = "Judenspanisch";
var lah$3 = "Lahnda";
var lam$3 = "Lamba";
var lao$3 = "Laotisch";
var lat$3 = "Latein";
var lav$3 = "Lettisch";
var lez$3 = "Lesgisch";
var lim$3 = "Limburgisch";
var lin$3 = "Lingála";
var lit$3 = "Litauisch";
var lol$3 = "Lomongo";
var loz$3 = "Lozi";
var ltz$3 = "Luxemburgisch";
var lua$3 = "Tschiluba";
var lub$3 = "Kiluba";
var lug$3 = "Luganda";
var lui$3 = "Luiseño";
var lun$3 = "Chilunda";
var luo$3 = "Luo";
var lus$3 = "Mizo";
var mac$3 = "Mazedonisch";
var mad$3 = "Maduresisch";
var mag$3 = "Magadhi";
var mah$3 = "Marschallesisch";
var mai$3 = "Maithili";
var mak$3 = "Makassar";
var mal$3 = "Malayalam";
var man$3 = "Manding";
var mao$3 = "Maori";
var map$3 = "Austronesische Sprachen";
var mar$3 = "Marathi";
var mas$3 = "Maa";
var may$3 = "Malaiisch";
var mdf$3 = "Mokschanisch";
var mdr$3 = "Mandar";
var men$3 = "Mende";
var mga$3 = "Mittelirisch";
var mic$3 = "Míkmawísimk";
var min$3 = "Minangkabauisch";
var mis$3 = "Verschiedene Sprachen";
var mkh$3 = "Mon-Khmer-Sprachen";
var mlg$3 = "Malagasy";
var mlt$3 = "Maltesisch";
var mnc$3 = "Mandschurisch";
var mni$3 = "Meithei";
var mno$3 = "Manobo Sprachen";
var moh$3 = "Mohawk";
var mon$3 = "Mongolisch";
var mos$3 = "Mòoré";
var mul$3 = "Mehrsprachig";
var mun$3 = "Munda-Sprachen";
var mus$3 = "Muskogee-Sprachen";
var mwl$3 = "Mirandés";
var mwr$3 = "Marwari";
var myn$3 = "Maya Sprachen";
var myv$3 = "Ersjanisch";
var nah$3 = "Nahuatl";
var nai$3 = "Nordamerikanische Sprachen";
var nap$3 = "Neapolitanisch";
var nau$3 = "Nauruisch";
var nav$3 = "Navajo";
var nbl$3 = "Süd-Ndebele";
var nde$3 = "Nord-Ndebele";
var ndo$3 = "Ndonga";
var nds$3 = "Niederdeutsch";
var nep$3 = "Nepali";
var nia$3 = "Nias";
var nic$3 = "Niger-Kongo-Sprachen";
var niu$3 = "Niueanisch";
var nno$3 = "Nynorsk";
var nob$3 = "Bokmål";
var nog$3 = "Nogaisch";
var non$3 = "Altnordisch";
var nor$3 = "Norwegisch";
var nqo$3 = "N’Ko";
var nso$3 = "Nord-Sotho";
var nub$3 = "Nubische Sprachen";
var nwc$3 = "Klassisches Newari";
var nya$3 = "Chichewa";
var nym$3 = "Nyamwesi";
var nyn$3 = "Runyankole";
var nyo$3 = "Runyoro";
var nzi$3 = "Nzema";
var oci$3 = "Okzitanisch";
var oji$3 = "Ojibwe";
var ori$3 = "Oriya";
var orm$3 = "Oromo";
var osa$3 = "Osage";
var oss$3 = "Ossetisch";
var ota$3 = "Osmanisch";
var oto$3 = "Oto-Pame-Sprachen";
var paa$3 = "Papuasprachen";
var pag$3 = "Pangasinensisch";
var pal$3 = "Mittelpersisch";
var pam$3 = "Kapampangan";
var pan$3 = "Panjabi";
var pap$3 = "Papiamentu";
var pau$3 = "Palauisch";
var peo$3 = "Altpersisch";
var per$3 = "Persisch";
var phi$3 = "Philippinische Sprachen";
var phn$3 = "Phönizisch";
var pli$3 = "Pali";
var pol$3 = "Polnisch";
var pon$3 = "Pohnpeanisch";
var por$3 = "Portugiesisch";
var pra$3 = "Prakrit";
var pro$3 = "Altokzitanisch";
var pus$3 = "Paschtunisch";
var que$3 = "Quechua";
var raj$3 = "Rajasthani";
var rap$3 = "Rapanui";
var rar$3 = "Rarotonganisch";
var roa$3 = "Romanische Sprachen";
var roh$3 = "Bündnerromanisch";
var rom$3 = "Romani";
var rum$3 = "Rumänisch";
var run$3 = "Kirundi";
var rup$3 = "Aromunisch";
var rus$3 = "Russisch";
var sad$3 = "Sandawe";
var sag$3 = "Sango";
var sah$3 = "Jakutisch";
var sai$3 = "Südamerikanische Sprachen";
var sal$3 = "Salish-Sprachen";
var sam$3 = "Samaritanisch";
var san$3 = "Sanskrit";
var sas$3 = "Sasak";
var sat$3 = "Santali";
var scn$3 = "Sizilianisch";
var sco$3 = "Scots";
var sel$3 = "Selkupisch";
var sem$3 = "Semitische Sprachen";
var sga$3 = "Altirisch";
var sgn$3 = "Gebärdensprachen";
var shn$3 = "Shan";
var sid$3 = "Sidama";
var sin$3 = "Singhalesisch";
var sio$3 = "Sioux-Sprachen";
var sit$3 = "Sinotibetische Sprachen";
var sla$3 = "Slawische Sprachen";
var slo$3 = "Slowakisch";
var slv$3 = "Slowenisch";
var sma$3 = "Südsamisch";
var sme$3 = "Nordsamisch";
var smi$3 = "Samische Sprachen";
var smj$3 = "Lulesamisch";
var smn$3 = "Inarisamisch";
var smo$3 = "Samoanisch";
var sms$3 = "Skoltsamisch";
var sna$3 = "Shona";
var snd$3 = "Sindhi";
var snk$3 = "Soninke";
var sog$3 = "Sogdisch";
var som$3 = "Somali";
var son$3 = "Songhai-Sprachen";
var sot$3 = "Sesotho";
var spa$3 = "Spanisch";
var srd$3 = "Sardisch";
var srn$3 = "Sranantongo";
var srp$3 = "Serbisch";
var srr$3 = "Serer";
var ssa$3 = "Nilosaharanische Sprachen";
var ssw$3 = "Swahili";
var suk$3 = "Sukuma";
var sun$3 = "Sundanesisch";
var sus$3 = "Susu";
var sux$3 = "Sumerisch";
var swa$3 = "Suaheli";
var swe$3 = "Schwedisch";
var syc$3 = "Syrisch";
var syr$3 = "Nordost-Neuaramäisch";
var tah$3 = "Tahitianisch";
var tai$3 = "Tai-Sprachen";
var tam$3 = "Tamil";
var tat$3 = "Tatarisch";
var tel$3 = "Telugu";
var tem$3 = "Temne";
var ter$3 = "Terena";
var tet$3 = "Tetum";
var tgk$3 = "Tadschikisch";
var tgl$3 = "Tagalog";
var tha$3 = "Thai";
var tib$3 = "Tibetisch";
var tig$3 = "Tigre";
var tir$3 = "Tigrinya";
var tiv$3 = "Tiv";
var tkl$3 = "Tokelauisch";
var tlh$3 = "Klingonisch";
var tli$3 = "Tlingit";
var tmh$3 = "Tuareg";
var tog$3 = "ChiTonga";
var ton$3 = "Tongaisch";
var tpi$3 = "Tok Pisin";
var tsi$3 = "Tsimshian";
var tsn$3 = "Setswana";
var tso$3 = "Xitsonga";
var tuk$3 = "Turkmenisch";
var tum$3 = "Tumbuka";
var tup$3 = "Tupí-Sprachen";
var tur$3 = "Türkisch";
var tut$3 = "Altaische Sprachen";
var tvl$3 = "Tuvaluisch";
var twi$3 = "Twi";
var tyv$3 = "Tuwinisch";
var udm$3 = "Udmurtisch";
var uga$3 = "Ugaritisch";
var uig$3 = "Uigurisch";
var ukr$3 = "Ukrainisch";
var umb$3 = "Umbundu";
var und$3 = "Unbekannte Sprache";
var urd$3 = "Urdu";
var uzb$3 = "Usbekisch";
var vai$3 = "Vai";
var ven$3 = "Tshivenda";
var vie$3 = "Vietnamesisch";
var vol$3 = "Volapük";
var vot$3 = "Wotisch";
var wak$3 = "Wakash-Sprachen";
var wal$3 = "Wolaytta";
var war$3 = "Wáray-Wáray";
var was$3 = "Washo";
var wel$3 = "Walisisch";
var wen$3 = "Sorbische Sprache";
var wln$3 = "Wallonisch";
var wol$3 = "Wolof";
var xal$3 = "Kalmückisch";
var xho$3 = "IsiXhosa";
var yao$3 = "Yao";
var yap$3 = "Yapesisch";
var yid$3 = "Jiddisch";
var yor$3 = "Yoruba";
var ypk$3 = "Yupik-Sprachen";
var zap$3 = "Zapotekisch";
var zbl$3 = "Bliss-Symbole";
var zen$3 = "Zenaga";
var zha$3 = "Zhuang";
var znd$3 = "Zande-Sprachen";
var zul$3 = "isiZulu";
var zun$3 = "Zuñi";
var zxx$3 = "Keine Sprachinhalte";
var zza$3 = "Zazaisch";
var de$5 = {
	aar: aar$3,
	abk: abk$3,
	ace: ace$3,
	ach: ach$3,
	ada: ada$3,
	ady: ady$3,
	afa: afa$3,
	afh: afh$3,
	afr: afr$3,
	ain: ain$3,
	aka: aka$3,
	akk: akk$3,
	alb: alb$3,
	ale: ale$3,
	alg: alg$3,
	alt: alt$3,
	amh: amh$3,
	ang: ang$3,
	anp: anp$3,
	apa: apa$3,
	ara: ara$3,
	arc: arc$3,
	arg: arg$3,
	arm: arm$3,
	arn: arn$3,
	arp: arp$3,
	art: art$3,
	arw: arw$3,
	asm: asm$3,
	ast: ast$3,
	ath: ath$3,
	aus: aus$3,
	ava: ava$3,
	ave: ave$3,
	awa: awa$3,
	aym: aym$3,
	aze: aze$3,
	bad: bad$3,
	bai: bai$3,
	bak: bak$3,
	bal: bal$3,
	bam: bam$3,
	ban: ban$3,
	baq: baq$3,
	bas: bas$3,
	bat: bat$3,
	bej: bej$3,
	bel: bel$3,
	bem: bem$3,
	ben: ben$3,
	ber: ber$3,
	bho: bho$3,
	bih: bih$3,
	bik: bik$3,
	bin: bin$3,
	bis: bis$3,
	bla: bla$3,
	bnt: bnt$3,
	bos: bos$3,
	bra: bra$3,
	bre: bre$3,
	btk: btk$3,
	bua: bua$3,
	bug: bug$3,
	bul: bul$3,
	bur: bur$3,
	byn: byn$3,
	cad: cad$3,
	cai: cai$3,
	car: car$3,
	cat: cat$3,
	cau: cau$3,
	ceb: ceb$3,
	cel: cel$3,
	cha: cha$3,
	chb: chb$3,
	che: che$3,
	chg: chg$3,
	chi: chi$3,
	chk: chk$3,
	chm: chm$3,
	chn: chn$3,
	cho: cho$3,
	chp: chp$3,
	chr: chr$3,
	chu: chu$3,
	chv: chv$3,
	chy: chy$3,
	cmc: cmc$3,
	cnr: cnr$3,
	cop: cop$3,
	cor: cor$3,
	cos: cos$3,
	cpe: cpe$3,
	cpf: cpf$3,
	cpp: cpp$3,
	cre: cre$3,
	crh: crh$3,
	crp: crp$3,
	csb: csb$3,
	cus: cus$3,
	cze: cze$3,
	dak: dak$3,
	dan: dan$3,
	dar: dar$3,
	day: day$3,
	del: del$3,
	den: den$3,
	dgr: dgr$3,
	din: din$3,
	div: div$3,
	doi: doi$3,
	dra: dra$3,
	dsb: dsb$3,
	dua: dua$3,
	dum: dum$3,
	dut: dut$3,
	dyu: dyu$3,
	dzo: dzo$3,
	efi: efi$3,
	egy: egy$3,
	eka: eka$3,
	elx: elx$3,
	eng: eng$3,
	enm: enm$3,
	epo: epo$3,
	est: est$3,
	ewe: ewe$3,
	ewo: ewo$3,
	fan: fan$3,
	fao: fao$3,
	fat: fat$3,
	fij: fij$3,
	fil: fil$3,
	fin: fin$3,
	fiu: fiu$3,
	fon: fon$3,
	fre: fre$3,
	frm: frm$3,
	fro: fro$3,
	frr: frr$3,
	frs: frs$3,
	fry: fry$3,
	ful: ful$3,
	fur: fur$3,
	gaa: gaa$3,
	gay: gay$3,
	gba: gba$3,
	gem: gem$3,
	geo: geo$3,
	ger: ger$3,
	gez: gez$3,
	gil: gil$3,
	gla: gla$3,
	gle: gle$3,
	glg: glg$3,
	glv: glv$3,
	gmh: gmh$3,
	goh: goh$3,
	gon: gon$3,
	gor: gor$3,
	got: got$3,
	grb: grb$3,
	grc: grc$3,
	gre: gre$3,
	grn: grn$3,
	gsw: gsw$3,
	guj: guj$3,
	gwi: gwi$3,
	hai: hai$3,
	hat: hat$3,
	hau: hau$3,
	haw: haw$3,
	heb: heb$3,
	her: her$3,
	hil: hil$3,
	him: him$3,
	hin: hin$3,
	hit: hit$3,
	hmn: hmn$3,
	hmo: hmo$3,
	hrv: hrv$3,
	hsb: hsb$3,
	hun: hun$3,
	hup: hup$3,
	iba: iba$3,
	ibo: ibo$3,
	ice: ice$3,
	ido: ido$3,
	iii: iii$3,
	ijo: ijo$3,
	iku: iku$3,
	ile: ile$3,
	ilo: ilo$3,
	ina: ina$3,
	inc: inc$3,
	ind: ind$3,
	ine: ine$3,
	inh: inh$3,
	ipk: ipk$3,
	ira: ira$3,
	iro: iro$3,
	ita: ita$3,
	jav: jav$3,
	jbo: jbo$3,
	jpn: jpn$3,
	jpr: jpr$3,
	jrb: jrb$3,
	kaa: kaa$3,
	kab: kab$3,
	kac: kac$3,
	kal: kal$3,
	kam: kam$3,
	kan: kan$3,
	kar: kar$3,
	kas: kas$3,
	kau: kau$3,
	kaw: kaw$3,
	kaz: kaz$3,
	kbd: kbd$3,
	kha: kha$3,
	khi: khi$3,
	khm: khm$3,
	kho: kho$3,
	kik: kik$3,
	kin: kin$3,
	kir: kir$3,
	kmb: kmb$3,
	kok: kok$3,
	kom: kom$3,
	kon: kon$3,
	kor: kor$3,
	kos: kos$3,
	kpe: kpe$3,
	krc: krc$3,
	krl: krl$3,
	kro: kro$3,
	kru: kru$3,
	kua: kua$3,
	kum: kum$3,
	kur: kur$3,
	kut: kut$3,
	lad: lad$3,
	lah: lah$3,
	lam: lam$3,
	lao: lao$3,
	lat: lat$3,
	lav: lav$3,
	lez: lez$3,
	lim: lim$3,
	lin: lin$3,
	lit: lit$3,
	lol: lol$3,
	loz: loz$3,
	ltz: ltz$3,
	lua: lua$3,
	lub: lub$3,
	lug: lug$3,
	lui: lui$3,
	lun: lun$3,
	luo: luo$3,
	lus: lus$3,
	mac: mac$3,
	mad: mad$3,
	mag: mag$3,
	mah: mah$3,
	mai: mai$3,
	mak: mak$3,
	mal: mal$3,
	man: man$3,
	mao: mao$3,
	map: map$3,
	mar: mar$3,
	mas: mas$3,
	may: may$3,
	mdf: mdf$3,
	mdr: mdr$3,
	men: men$3,
	mga: mga$3,
	mic: mic$3,
	min: min$3,
	mis: mis$3,
	mkh: mkh$3,
	mlg: mlg$3,
	mlt: mlt$3,
	mnc: mnc$3,
	mni: mni$3,
	mno: mno$3,
	moh: moh$3,
	mon: mon$3,
	mos: mos$3,
	mul: mul$3,
	mun: mun$3,
	mus: mus$3,
	mwl: mwl$3,
	mwr: mwr$3,
	myn: myn$3,
	myv: myv$3,
	nah: nah$3,
	nai: nai$3,
	nap: nap$3,
	nau: nau$3,
	nav: nav$3,
	nbl: nbl$3,
	nde: nde$3,
	ndo: ndo$3,
	nds: nds$3,
	nep: nep$3,
	"new": "Newari",
	nia: nia$3,
	nic: nic$3,
	niu: niu$3,
	nno: nno$3,
	nob: nob$3,
	nog: nog$3,
	non: non$3,
	nor: nor$3,
	nqo: nqo$3,
	nso: nso$3,
	nub: nub$3,
	nwc: nwc$3,
	nya: nya$3,
	nym: nym$3,
	nyn: nyn$3,
	nyo: nyo$3,
	nzi: nzi$3,
	oci: oci$3,
	oji: oji$3,
	ori: ori$3,
	orm: orm$3,
	osa: osa$3,
	oss: oss$3,
	ota: ota$3,
	oto: oto$3,
	paa: paa$3,
	pag: pag$3,
	pal: pal$3,
	pam: pam$3,
	pan: pan$3,
	pap: pap$3,
	pau: pau$3,
	peo: peo$3,
	per: per$3,
	phi: phi$3,
	phn: phn$3,
	pli: pli$3,
	pol: pol$3,
	pon: pon$3,
	por: por$3,
	pra: pra$3,
	pro: pro$3,
	pus: pus$3,
	que: que$3,
	raj: raj$3,
	rap: rap$3,
	rar: rar$3,
	roa: roa$3,
	roh: roh$3,
	rom: rom$3,
	rum: rum$3,
	run: run$3,
	rup: rup$3,
	rus: rus$3,
	sad: sad$3,
	sag: sag$3,
	sah: sah$3,
	sai: sai$3,
	sal: sal$3,
	sam: sam$3,
	san: san$3,
	sas: sas$3,
	sat: sat$3,
	scn: scn$3,
	sco: sco$3,
	sel: sel$3,
	sem: sem$3,
	sga: sga$3,
	sgn: sgn$3,
	shn: shn$3,
	sid: sid$3,
	sin: sin$3,
	sio: sio$3,
	sit: sit$3,
	sla: sla$3,
	slo: slo$3,
	slv: slv$3,
	sma: sma$3,
	sme: sme$3,
	smi: smi$3,
	smj: smj$3,
	smn: smn$3,
	smo: smo$3,
	sms: sms$3,
	sna: sna$3,
	snd: snd$3,
	snk: snk$3,
	sog: sog$3,
	som: som$3,
	son: son$3,
	sot: sot$3,
	spa: spa$3,
	srd: srd$3,
	srn: srn$3,
	srp: srp$3,
	srr: srr$3,
	ssa: ssa$3,
	ssw: ssw$3,
	suk: suk$3,
	sun: sun$3,
	sus: sus$3,
	sux: sux$3,
	swa: swa$3,
	swe: swe$3,
	syc: syc$3,
	syr: syr$3,
	tah: tah$3,
	tai: tai$3,
	tam: tam$3,
	tat: tat$3,
	tel: tel$3,
	tem: tem$3,
	ter: ter$3,
	tet: tet$3,
	tgk: tgk$3,
	tgl: tgl$3,
	tha: tha$3,
	tib: tib$3,
	tig: tig$3,
	tir: tir$3,
	tiv: tiv$3,
	tkl: tkl$3,
	tlh: tlh$3,
	tli: tli$3,
	tmh: tmh$3,
	tog: tog$3,
	ton: ton$3,
	tpi: tpi$3,
	tsi: tsi$3,
	tsn: tsn$3,
	tso: tso$3,
	tuk: tuk$3,
	tum: tum$3,
	tup: tup$3,
	tur: tur$3,
	tut: tut$3,
	tvl: tvl$3,
	twi: twi$3,
	tyv: tyv$3,
	udm: udm$3,
	uga: uga$3,
	uig: uig$3,
	ukr: ukr$3,
	umb: umb$3,
	und: und$3,
	urd: urd$3,
	uzb: uzb$3,
	vai: vai$3,
	ven: ven$3,
	vie: vie$3,
	vol: vol$3,
	vot: vot$3,
	wak: wak$3,
	wal: wal$3,
	war: war$3,
	was: was$3,
	wel: wel$3,
	wen: wen$3,
	wln: wln$3,
	wol: wol$3,
	xal: xal$3,
	xho: xho$3,
	yao: yao$3,
	yap: yap$3,
	yid: yid$3,
	yor: yor$3,
	ypk: ypk$3,
	zap: zap$3,
	zbl: zbl$3,
	zen: zen$3,
	zha: zha$3,
	znd: znd$3,
	zul: zul$3,
	zun: zun$3,
	zxx: zxx$3,
	zza: zza$3
};

var aar$2 = "Afar";
var abk$2 = "Abkhaz";
var ace$2 = "Achinese";
var ach$2 = "Acoli";
var ada$2 = "Adangme";
var ady$2 = "Adygei";
var afa$2 = "Afroasiatic (Other)";
var afh$2 = "Afrihili (Artificial language)";
var afr$2 = "Afrikaans";
var ain$2 = "Ainu";
var aka$2 = "Akan";
var akk$2 = "Akkadian";
var alb$2 = "Albanian";
var ale$2 = "Aleut";
var alg$2 = "Algonquian (Other)";
var alt$2 = "Altai";
var amh$2 = "Amharic";
var ang$2 = "English, Old (ca. 450-1100)";
var anp$2 = "Angika";
var apa$2 = "Apache languages";
var ara$2 = "Arabic";
var arc$2 = "Aramaic";
var arg$2 = "Aragonese";
var arm$2 = "Armenian";
var arn$2 = "Mapuche";
var arp$2 = "Arapaho";
var art$2 = "Artificial (Other)";
var arw$2 = "Arawak";
var asm$2 = "Assamese";
var ast$2 = "Bable";
var ath$2 = "Athapascan (Other)";
var aus$2 = "Australian languages";
var ava$2 = "Avaric";
var ave$2 = "Avestan";
var awa$2 = "Awadhi";
var aym$2 = "Aymara";
var aze$2 = "Azerbaijani";
var bad$2 = "Banda languages";
var bai$2 = "Bamileke languages";
var bak$2 = "Bashkir";
var bal$2 = "Baluchi";
var bam$2 = "Bambara";
var ban$2 = "Balinese";
var baq$2 = "Basque";
var bas$2 = "Basa";
var bat$2 = "Baltic (Other)";
var bej$2 = "Beja";
var bel$2 = "Belarusian";
var bem$2 = "Bemba";
var ben$2 = "Bengali";
var ber$2 = "Berber (Other)";
var bho$2 = "Bhojpuri";
var bih$2 = "Bihari (Other)";
var bik$2 = "Bikol";
var bin$2 = "Edo";
var bis$2 = "Bislama";
var bla$2 = "Siksika";
var bnt$2 = "Bantu (Other)";
var bos$2 = "Bosnian";
var bra$2 = "Braj";
var bre$2 = "Breton";
var btk$2 = "Batak";
var bua$2 = "Buriat";
var bug$2 = "Bugis";
var bul$2 = "Bulgarian";
var bur$2 = "Burmese";
var byn$2 = "Bilin";
var cad$2 = "Caddo";
var cai$2 = "Central American Indian (Other)";
var car$2 = "Carib";
var cat$2 = "Catalan";
var cau$2 = "Caucasian (Other)";
var ceb$2 = "Cebuano";
var cel$2 = "Celtic (Other)";
var cha$2 = "Chamorro";
var chb$2 = "Chibcha";
var che$2 = "Chechen";
var chg$2 = "Chagatai";
var chi$2 = "Chinese";
var chk$2 = "Chuukese";
var chm$2 = "Mari";
var chn$2 = "Chinook jargon";
var cho$2 = "Choctaw";
var chp$2 = "Chipewyan";
var chr$2 = "Cherokee";
var chu$2 = "Church Slavic";
var chv$2 = "Chuvash";
var chy$2 = "Cheyenne";
var cmc$2 = "Chamic languages";
var cnr$2 = "Montenegrin";
var cop$2 = "Coptic";
var cor$2 = "Cornish";
var cos$2 = "Corsican";
var cpe$2 = "Creoles and Pidgins, English-based (Other)";
var cpf$2 = "Creoles and Pidgins, French-based (Other)";
var cpp$2 = "Creoles and Pidgins, Portuguese-based (Other)";
var cre$2 = "Cree";
var crh$2 = "Crimean Tatar";
var crp$2 = "Creoles and Pidgins (Other)";
var csb$2 = "Kashubian";
var cus$2 = "Cushitic (Other)";
var cze$2 = "Czech";
var dak$2 = "Dakota";
var dan$2 = "Danish";
var dar$2 = "Dargwa";
var day$2 = "Dayak";
var del$2 = "Delaware";
var den$2 = "Slavey";
var dgr$2 = "Dogrib";
var din$2 = "Dinka";
var div$2 = "Divehi";
var doi$2 = "Dogri";
var dra$2 = "Dravidian (Other)";
var dsb$2 = "Lower Sorbian";
var dua$2 = "Duala";
var dum$2 = "Dutch, Middle (ca. 1050-1350)";
var dut$2 = "Dutch";
var dyu$2 = "Dyula";
var dzo$2 = "Dzongkha";
var efi$2 = "Efik";
var egy$2 = "Egyptian";
var eka$2 = "Ekajuk";
var elx$2 = "Elamite";
var eng$2 = "English";
var enm$2 = "English, Middle (1100-1500)";
var epo$2 = "Esperanto";
var est$2 = "Estonian";
var ewe$2 = "Ewe";
var ewo$2 = "Ewondo";
var fan$2 = "Fang";
var fao$2 = "Faroese";
var fat$2 = "Fanti";
var fij$2 = "Fijian";
var fil$2 = "Filipino";
var fin$2 = "Finnish";
var fiu$2 = "Finno-Ugrian (Other)";
var fon$2 = "Fon";
var fre$2 = "French";
var frm$2 = "French, Middle (ca. 1300-1600)";
var fro$2 = "French, Old (ca. 842-1300)";
var frr$2 = "North Frisian";
var frs$2 = "East Frisian";
var fry$2 = "Frisian";
var ful$2 = "Fula";
var fur$2 = "Friulian";
var gaa$2 = "Gã";
var gay$2 = "Gayo";
var gba$2 = "Gbaya";
var gem$2 = "Germanic (Other)";
var geo$2 = "Georgian";
var ger$2 = "German";
var gez$2 = "Ethiopic";
var gil$2 = "Gilbertese";
var gla$2 = "Scottish Gaelic";
var gle$2 = "Irish";
var glg$2 = "Galician";
var glv$2 = "Manx";
var gmh$2 = "German, Middle High (ca. 1050-1500)";
var goh$2 = "German, Old High (ca. 750-1050)";
var gon$2 = "Gondi";
var gor$2 = "Gorontalo";
var got$2 = "Gothic";
var grb$2 = "Grebo";
var grc$2 = "Greek, Ancient (to 1453)";
var gre$2 = "Greek, Modern (1453- )";
var grn$2 = "Guarani";
var gsw$2 = "Swiss German";
var guj$2 = "Gujarati";
var gwi$2 = "Gwich'in";
var hai$2 = "Haida";
var hat$2 = "Haitian French Creole";
var hau$2 = "Hausa";
var haw$2 = "Hawaiian";
var heb$2 = "Hebrew";
var her$2 = "Herero";
var hil$2 = "Hiligaynon";
var him$2 = "Western Pahari languages";
var hin$2 = "Hindi";
var hit$2 = "Hittite";
var hmn$2 = "Hmong";
var hmo$2 = "Hiri Motu";
var hrv$2 = "Croatian";
var hsb$2 = "Upper Sorbian";
var hun$2 = "Hungarian";
var hup$2 = "Hupa";
var iba$2 = "Iban";
var ibo$2 = "Igbo";
var ice$2 = "Icelandic";
var ido$2 = "Ido";
var iii$2 = "Sichuan Yi";
var ijo$2 = "Ijo";
var iku$2 = "Inuktitut";
var ile$2 = "Interlingue";
var ilo$2 = "Iloko";
var ina$2 = "Interlingua (International Auxiliary Language Association)";
var inc$2 = "Indic (Other)";
var ind$2 = "Indonesian";
var ine$2 = "Indo-European (Other)";
var inh$2 = "Ingush";
var ipk$2 = "Inupiaq";
var ira$2 = "Iranian (Other)";
var iro$2 = "Iroquoian (Other)";
var ita$2 = "Italian";
var jav$2 = "Javanese";
var jbo$2 = "Lojban (Artificial language)";
var jpn$2 = "Japanese";
var jpr$2 = "Judeo-Persian";
var jrb$2 = "Judeo-Arabic";
var kaa$2 = "Kara-Kalpak";
var kab$2 = "Kabyle";
var kac$2 = "Kachin";
var kal$2 = "Kalâtdlisut";
var kam$2 = "Kamba";
var kan$2 = "Kannada";
var kar$2 = "Karen languages";
var kas$2 = "Kashmiri";
var kau$2 = "Kanuri";
var kaw$2 = "Kawi";
var kaz$2 = "Kazakh";
var kbd$2 = "Kabardian";
var kha$2 = "Khasi";
var khi$2 = "Khoisan (Other)";
var khm$2 = "Khmer";
var kho$2 = "Khotanese";
var kik$2 = "Kikuyu";
var kin$2 = "Kinyarwanda";
var kir$2 = "Kyrgyz";
var kmb$2 = "Kimbundu";
var kok$2 = "Konkani";
var kom$2 = "Komi";
var kon$2 = "Kongo";
var kor$2 = "Korean";
var kos$2 = "Kosraean";
var kpe$2 = "Kpelle";
var krc$2 = "Karachay-Balkar";
var krl$2 = "Karelian";
var kro$2 = "Kru (Other)";
var kru$2 = "Kurukh";
var kua$2 = "Kuanyama";
var kum$2 = "Kumyk";
var kur$2 = "Kurdish";
var kut$2 = "Kootenai";
var lad$2 = "Ladino";
var lah$2 = "Lahndā";
var lam$2 = "Lamba (Zambia and Congo)";
var lao$2 = "Lao";
var lat$2 = "Latin";
var lav$2 = "Latvian";
var lez$2 = "Lezgian";
var lim$2 = "Limburgish";
var lin$2 = "Lingala";
var lit$2 = "Lithuanian";
var lol$2 = "Mongo-Nkundu";
var loz$2 = "Lozi";
var ltz$2 = "Luxembourgish";
var lua$2 = "Luba-Lulua";
var lub$2 = "Luba-Katanga";
var lug$2 = "Ganda";
var lui$2 = "Luiseño";
var lun$2 = "Lunda";
var luo$2 = "Luo (Kenya and Tanzania)";
var lus$2 = "Lushai";
var mac$2 = "Macedonian";
var mad$2 = "Madurese";
var mag$2 = "Magahi";
var mah$2 = "Marshallese";
var mai$2 = "Maithili";
var mak$2 = "Makasar";
var mal$2 = "Malayalam";
var man$2 = "Mandingo";
var mao$2 = "Maori";
var map$2 = "Austronesian (Other)";
var mar$2 = "Marathi";
var mas$2 = "Maasai";
var may$2 = "Malay";
var mdf$2 = "Moksha";
var mdr$2 = "Mandar";
var men$2 = "Mende";
var mga$2 = "Irish, Middle (ca. 1100-1550)";
var mic$2 = "Micmac";
var min$2 = "Minangkabau";
var mis$2 = "Miscellaneous languages";
var mkh$2 = "Mon-Khmer (Other)";
var mlg$2 = "Malagasy";
var mlt$2 = "Maltese";
var mnc$2 = "Manchu";
var mni$2 = "Manipuri";
var mno$2 = "Manobo languages";
var moh$2 = "Mohawk";
var mon$2 = "Mongolian";
var mos$2 = "Mooré";
var mul$2 = "Multiple languages";
var mun$2 = "Munda (Other)";
var mus$2 = "Creek";
var mwl$2 = "Mirandese";
var mwr$2 = "Marwari";
var myn$2 = "Mayan languages";
var myv$2 = "Erzya";
var nah$2 = "Nahuatl";
var nai$2 = "North American Indian (Other)";
var nap$2 = "Neapolitan Italian";
var nau$2 = "Nauru";
var nav$2 = "Navajo";
var nbl$2 = "Ndebele (South Africa)";
var nde$2 = "Ndebele (Zimbabwe)";
var ndo$2 = "Ndonga";
var nds$2 = "Low German";
var nep$2 = "Nepali";
var nia$2 = "Nias";
var nic$2 = "Niger-Kordofanian (Other)";
var niu$2 = "Niuean";
var nno$2 = "Norwegian (Nynorsk)";
var nob$2 = "Norwegian (Bokmål)";
var nog$2 = "Nogai";
var non$2 = "Old Norse";
var nor$2 = "Norwegian";
var nqo$2 = "N'Ko";
var nso$2 = "Northern Sotho";
var nub$2 = "Nubian languages";
var nwc$2 = "Newari, Old";
var nya$2 = "Nyanja";
var nym$2 = "Nyamwezi";
var nyn$2 = "Nyankole";
var nyo$2 = "Nyoro";
var nzi$2 = "Nzima";
var oci$2 = "Occitan (post-1500)";
var oji$2 = "Ojibwa";
var ori$2 = "Oriya";
var orm$2 = "Oromo";
var osa$2 = "Osage";
var oss$2 = "Ossetic";
var ota$2 = "Turkish, Ottoman";
var oto$2 = "Otomian languages";
var paa$2 = "Papuan (Other)";
var pag$2 = "Pangasinan";
var pal$2 = "Pahlavi";
var pam$2 = "Pampanga";
var pan$2 = "Panjabi";
var pap$2 = "Papiamento";
var pau$2 = "Palauan";
var peo$2 = "Old Persian (ca. 600-400 B.C.)";
var per$2 = "Persian";
var phi$2 = "Philippine (Other)";
var phn$2 = "Phoenician";
var pli$2 = "Pali";
var pol$2 = "Polish";
var pon$2 = "Pohnpeian";
var por$2 = "Portuguese";
var pra$2 = "Prakrit languages";
var pro$2 = "Provençal (to 1500)";
var pus$2 = "Pushto";
var que$2 = "Quechua";
var raj$2 = "Rajasthani";
var rap$2 = "Rapanui";
var rar$2 = "Rarotongan";
var roa$2 = "Romance (Other)";
var roh$2 = "Raeto-Romance";
var rom$2 = "Romani";
var rum$2 = "Romanian";
var run$2 = "Rundi";
var rup$2 = "Aromanian";
var rus$2 = "Russian";
var sad$2 = "Sandawe";
var sag$2 = "Sango (Ubangi Creole)";
var sah$2 = "Yakut";
var sai$2 = "South American Indian (Other)";
var sal$2 = "Salishan languages";
var sam$2 = "Samaritan Aramaic";
var san$2 = "Sanskrit";
var sas$2 = "Sasak";
var sat$2 = "Santali";
var scn$2 = "Sicilian Italian";
var sco$2 = "Scots";
var sel$2 = "Selkup";
var sem$2 = "Semitic (Other)";
var sga$2 = "Irish, Old (to 1100)";
var sgn$2 = "Sign languages";
var shn$2 = "Shan";
var sid$2 = "Sidamo";
var sin$2 = "Sinhalese";
var sio$2 = "Siouan (Other)";
var sit$2 = "Sino-Tibetan (Other)";
var sla$2 = "Slavic (Other)";
var slo$2 = "Slovak";
var slv$2 = "Slovenian";
var sma$2 = "Southern Sami";
var sme$2 = "Northern Sami";
var smi$2 = "Sami";
var smj$2 = "Lule Sami";
var smn$2 = "Inari Sami";
var smo$2 = "Samoan";
var sms$2 = "Skolt Sami";
var sna$2 = "Shona";
var snd$2 = "Sindhi";
var snk$2 = "Soninke";
var sog$2 = "Sogdian";
var som$2 = "Somali";
var son$2 = "Songhai";
var sot$2 = "Sotho";
var spa$2 = "Spanish";
var srd$2 = "Sardinian";
var srn$2 = "Sranan";
var srp$2 = "Serbian";
var srr$2 = "Serer";
var ssa$2 = "Nilo-Saharan (Other)";
var ssw$2 = "Swazi";
var suk$2 = "Sukuma";
var sun$2 = "Sundanese";
var sus$2 = "Susu";
var sux$2 = "Sumerian";
var swa$2 = "Swahili";
var swe$2 = "Swedish";
var syc$2 = "Syriac";
var syr$2 = "Syriac, Modern";
var tah$2 = "Tahitian";
var tai$2 = "Tai (Other)";
var tam$2 = "Tamil";
var tat$2 = "Tatar";
var tel$2 = "Telugu";
var tem$2 = "Temne";
var ter$2 = "Terena";
var tet$2 = "Tetum";
var tgk$2 = "Tajik";
var tgl$2 = "Tagalog";
var tha$2 = "Thai";
var tib$2 = "Tibetan";
var tig$2 = "Tigré";
var tir$2 = "Tigrinya";
var tiv$2 = "Tiv";
var tkl$2 = "Tokelauan";
var tlh$2 = "Klingon (Artificial language)";
var tli$2 = "Tlingit";
var tmh$2 = "Tamashek";
var tog$2 = "Tonga (Nyasa)";
var ton$2 = "Tongan";
var tpi$2 = "Tok Pisin";
var tsi$2 = "Tsimshian";
var tsn$2 = "Tswana";
var tso$2 = "Tsonga";
var tuk$2 = "Turkmen";
var tum$2 = "Tumbuka";
var tup$2 = "Tupi languages";
var tur$2 = "Turkish";
var tut$2 = "Altaic (Other)";
var tvl$2 = "Tuvaluan";
var twi$2 = "Twi";
var tyv$2 = "Tuvinian";
var udm$2 = "Udmurt";
var uga$2 = "Ugaritic";
var uig$2 = "Uighur";
var ukr$2 = "Ukrainian";
var umb$2 = "Umbundu";
var und$2 = "Undetermined";
var urd$2 = "Urdu";
var uzb$2 = "Uzbek";
var vai$2 = "Vai";
var ven$2 = "Venda";
var vie$2 = "Vietnamese";
var vol$2 = "Volapük";
var vot$2 = "Votic";
var wak$2 = "Wakashan languages";
var wal$2 = "Wolayta";
var war$2 = "Waray";
var was$2 = "Washoe";
var wel$2 = "Welsh";
var wen$2 = "Sorbian (Other)";
var wln$2 = "Walloon";
var wol$2 = "Wolof";
var xal$2 = "Oirat";
var xho$2 = "Xhosa";
var yao$2 = "Yao (Africa)";
var yap$2 = "Yapese";
var yid$2 = "Yiddish";
var yor$2 = "Yoruba";
var ypk$2 = "Yupik languages";
var zap$2 = "Zapotec";
var zbl$2 = "Blissymbolics";
var zen$2 = "Zenaga";
var zha$2 = "Zhuang";
var znd$2 = "Zande languages";
var zul$2 = "Zulu";
var zun$2 = "Zuni";
var zxx$2 = "No linguistic content";
var zza$2 = "Zaza";
var en$5 = {
	aar: aar$2,
	abk: abk$2,
	ace: ace$2,
	ach: ach$2,
	ada: ada$2,
	ady: ady$2,
	afa: afa$2,
	afh: afh$2,
	afr: afr$2,
	ain: ain$2,
	aka: aka$2,
	akk: akk$2,
	alb: alb$2,
	ale: ale$2,
	alg: alg$2,
	alt: alt$2,
	amh: amh$2,
	ang: ang$2,
	anp: anp$2,
	apa: apa$2,
	ara: ara$2,
	arc: arc$2,
	arg: arg$2,
	arm: arm$2,
	arn: arn$2,
	arp: arp$2,
	art: art$2,
	arw: arw$2,
	asm: asm$2,
	ast: ast$2,
	ath: ath$2,
	aus: aus$2,
	ava: ava$2,
	ave: ave$2,
	awa: awa$2,
	aym: aym$2,
	aze: aze$2,
	bad: bad$2,
	bai: bai$2,
	bak: bak$2,
	bal: bal$2,
	bam: bam$2,
	ban: ban$2,
	baq: baq$2,
	bas: bas$2,
	bat: bat$2,
	bej: bej$2,
	bel: bel$2,
	bem: bem$2,
	ben: ben$2,
	ber: ber$2,
	bho: bho$2,
	bih: bih$2,
	bik: bik$2,
	bin: bin$2,
	bis: bis$2,
	bla: bla$2,
	bnt: bnt$2,
	bos: bos$2,
	bra: bra$2,
	bre: bre$2,
	btk: btk$2,
	bua: bua$2,
	bug: bug$2,
	bul: bul$2,
	bur: bur$2,
	byn: byn$2,
	cad: cad$2,
	cai: cai$2,
	car: car$2,
	cat: cat$2,
	cau: cau$2,
	ceb: ceb$2,
	cel: cel$2,
	cha: cha$2,
	chb: chb$2,
	che: che$2,
	chg: chg$2,
	chi: chi$2,
	chk: chk$2,
	chm: chm$2,
	chn: chn$2,
	cho: cho$2,
	chp: chp$2,
	chr: chr$2,
	chu: chu$2,
	chv: chv$2,
	chy: chy$2,
	cmc: cmc$2,
	cnr: cnr$2,
	cop: cop$2,
	cor: cor$2,
	cos: cos$2,
	cpe: cpe$2,
	cpf: cpf$2,
	cpp: cpp$2,
	cre: cre$2,
	crh: crh$2,
	crp: crp$2,
	csb: csb$2,
	cus: cus$2,
	cze: cze$2,
	dak: dak$2,
	dan: dan$2,
	dar: dar$2,
	day: day$2,
	del: del$2,
	den: den$2,
	dgr: dgr$2,
	din: din$2,
	div: div$2,
	doi: doi$2,
	dra: dra$2,
	dsb: dsb$2,
	dua: dua$2,
	dum: dum$2,
	dut: dut$2,
	dyu: dyu$2,
	dzo: dzo$2,
	efi: efi$2,
	egy: egy$2,
	eka: eka$2,
	elx: elx$2,
	eng: eng$2,
	enm: enm$2,
	epo: epo$2,
	est: est$2,
	ewe: ewe$2,
	ewo: ewo$2,
	fan: fan$2,
	fao: fao$2,
	fat: fat$2,
	fij: fij$2,
	fil: fil$2,
	fin: fin$2,
	fiu: fiu$2,
	fon: fon$2,
	fre: fre$2,
	frm: frm$2,
	fro: fro$2,
	frr: frr$2,
	frs: frs$2,
	fry: fry$2,
	ful: ful$2,
	fur: fur$2,
	gaa: gaa$2,
	gay: gay$2,
	gba: gba$2,
	gem: gem$2,
	geo: geo$2,
	ger: ger$2,
	gez: gez$2,
	gil: gil$2,
	gla: gla$2,
	gle: gle$2,
	glg: glg$2,
	glv: glv$2,
	gmh: gmh$2,
	goh: goh$2,
	gon: gon$2,
	gor: gor$2,
	got: got$2,
	grb: grb$2,
	grc: grc$2,
	gre: gre$2,
	grn: grn$2,
	gsw: gsw$2,
	guj: guj$2,
	gwi: gwi$2,
	hai: hai$2,
	hat: hat$2,
	hau: hau$2,
	haw: haw$2,
	heb: heb$2,
	her: her$2,
	hil: hil$2,
	him: him$2,
	hin: hin$2,
	hit: hit$2,
	hmn: hmn$2,
	hmo: hmo$2,
	hrv: hrv$2,
	hsb: hsb$2,
	hun: hun$2,
	hup: hup$2,
	iba: iba$2,
	ibo: ibo$2,
	ice: ice$2,
	ido: ido$2,
	iii: iii$2,
	ijo: ijo$2,
	iku: iku$2,
	ile: ile$2,
	ilo: ilo$2,
	ina: ina$2,
	inc: inc$2,
	ind: ind$2,
	ine: ine$2,
	inh: inh$2,
	ipk: ipk$2,
	ira: ira$2,
	iro: iro$2,
	ita: ita$2,
	jav: jav$2,
	jbo: jbo$2,
	jpn: jpn$2,
	jpr: jpr$2,
	jrb: jrb$2,
	kaa: kaa$2,
	kab: kab$2,
	kac: kac$2,
	kal: kal$2,
	kam: kam$2,
	kan: kan$2,
	kar: kar$2,
	kas: kas$2,
	kau: kau$2,
	kaw: kaw$2,
	kaz: kaz$2,
	kbd: kbd$2,
	kha: kha$2,
	khi: khi$2,
	khm: khm$2,
	kho: kho$2,
	kik: kik$2,
	kin: kin$2,
	kir: kir$2,
	kmb: kmb$2,
	kok: kok$2,
	kom: kom$2,
	kon: kon$2,
	kor: kor$2,
	kos: kos$2,
	kpe: kpe$2,
	krc: krc$2,
	krl: krl$2,
	kro: kro$2,
	kru: kru$2,
	kua: kua$2,
	kum: kum$2,
	kur: kur$2,
	kut: kut$2,
	lad: lad$2,
	lah: lah$2,
	lam: lam$2,
	lao: lao$2,
	lat: lat$2,
	lav: lav$2,
	lez: lez$2,
	lim: lim$2,
	lin: lin$2,
	lit: lit$2,
	lol: lol$2,
	loz: loz$2,
	ltz: ltz$2,
	lua: lua$2,
	lub: lub$2,
	lug: lug$2,
	lui: lui$2,
	lun: lun$2,
	luo: luo$2,
	lus: lus$2,
	mac: mac$2,
	mad: mad$2,
	mag: mag$2,
	mah: mah$2,
	mai: mai$2,
	mak: mak$2,
	mal: mal$2,
	man: man$2,
	mao: mao$2,
	map: map$2,
	mar: mar$2,
	mas: mas$2,
	may: may$2,
	mdf: mdf$2,
	mdr: mdr$2,
	men: men$2,
	mga: mga$2,
	mic: mic$2,
	min: min$2,
	mis: mis$2,
	mkh: mkh$2,
	mlg: mlg$2,
	mlt: mlt$2,
	mnc: mnc$2,
	mni: mni$2,
	mno: mno$2,
	moh: moh$2,
	mon: mon$2,
	mos: mos$2,
	mul: mul$2,
	mun: mun$2,
	mus: mus$2,
	mwl: mwl$2,
	mwr: mwr$2,
	myn: myn$2,
	myv: myv$2,
	nah: nah$2,
	nai: nai$2,
	nap: nap$2,
	nau: nau$2,
	nav: nav$2,
	nbl: nbl$2,
	nde: nde$2,
	ndo: ndo$2,
	nds: nds$2,
	nep: nep$2,
	"new": "Newari",
	nia: nia$2,
	nic: nic$2,
	niu: niu$2,
	nno: nno$2,
	nob: nob$2,
	nog: nog$2,
	non: non$2,
	nor: nor$2,
	nqo: nqo$2,
	nso: nso$2,
	nub: nub$2,
	nwc: nwc$2,
	nya: nya$2,
	nym: nym$2,
	nyn: nyn$2,
	nyo: nyo$2,
	nzi: nzi$2,
	oci: oci$2,
	oji: oji$2,
	ori: ori$2,
	orm: orm$2,
	osa: osa$2,
	oss: oss$2,
	ota: ota$2,
	oto: oto$2,
	paa: paa$2,
	pag: pag$2,
	pal: pal$2,
	pam: pam$2,
	pan: pan$2,
	pap: pap$2,
	pau: pau$2,
	peo: peo$2,
	per: per$2,
	phi: phi$2,
	phn: phn$2,
	pli: pli$2,
	pol: pol$2,
	pon: pon$2,
	por: por$2,
	pra: pra$2,
	pro: pro$2,
	pus: pus$2,
	que: que$2,
	raj: raj$2,
	rap: rap$2,
	rar: rar$2,
	roa: roa$2,
	roh: roh$2,
	rom: rom$2,
	rum: rum$2,
	run: run$2,
	rup: rup$2,
	rus: rus$2,
	sad: sad$2,
	sag: sag$2,
	sah: sah$2,
	sai: sai$2,
	sal: sal$2,
	sam: sam$2,
	san: san$2,
	sas: sas$2,
	sat: sat$2,
	scn: scn$2,
	sco: sco$2,
	sel: sel$2,
	sem: sem$2,
	sga: sga$2,
	sgn: sgn$2,
	shn: shn$2,
	sid: sid$2,
	sin: sin$2,
	sio: sio$2,
	sit: sit$2,
	sla: sla$2,
	slo: slo$2,
	slv: slv$2,
	sma: sma$2,
	sme: sme$2,
	smi: smi$2,
	smj: smj$2,
	smn: smn$2,
	smo: smo$2,
	sms: sms$2,
	sna: sna$2,
	snd: snd$2,
	snk: snk$2,
	sog: sog$2,
	som: som$2,
	son: son$2,
	sot: sot$2,
	spa: spa$2,
	srd: srd$2,
	srn: srn$2,
	srp: srp$2,
	srr: srr$2,
	ssa: ssa$2,
	ssw: ssw$2,
	suk: suk$2,
	sun: sun$2,
	sus: sus$2,
	sux: sux$2,
	swa: swa$2,
	swe: swe$2,
	syc: syc$2,
	syr: syr$2,
	tah: tah$2,
	tai: tai$2,
	tam: tam$2,
	tat: tat$2,
	tel: tel$2,
	tem: tem$2,
	ter: ter$2,
	tet: tet$2,
	tgk: tgk$2,
	tgl: tgl$2,
	tha: tha$2,
	tib: tib$2,
	tig: tig$2,
	tir: tir$2,
	tiv: tiv$2,
	tkl: tkl$2,
	tlh: tlh$2,
	tli: tli$2,
	tmh: tmh$2,
	tog: tog$2,
	ton: ton$2,
	tpi: tpi$2,
	tsi: tsi$2,
	tsn: tsn$2,
	tso: tso$2,
	tuk: tuk$2,
	tum: tum$2,
	tup: tup$2,
	tur: tur$2,
	tut: tut$2,
	tvl: tvl$2,
	twi: twi$2,
	tyv: tyv$2,
	udm: udm$2,
	uga: uga$2,
	uig: uig$2,
	ukr: ukr$2,
	umb: umb$2,
	und: und$2,
	urd: urd$2,
	uzb: uzb$2,
	vai: vai$2,
	ven: ven$2,
	vie: vie$2,
	vol: vol$2,
	vot: vot$2,
	wak: wak$2,
	wal: wal$2,
	war: war$2,
	was: was$2,
	wel: wel$2,
	wen: wen$2,
	wln: wln$2,
	wol: wol$2,
	xal: xal$2,
	xho: xho$2,
	yao: yao$2,
	yap: yap$2,
	yid: yid$2,
	yor: yor$2,
	ypk: ypk$2,
	zap: zap$2,
	zbl: zbl$2,
	zen: zen$2,
	zha: zha$2,
	znd: znd$2,
	zul: zul$2,
	zun: zun$2,
	zxx: zxx$2,
	zza: zza$2
};

var aar$1 = "afar";
var abk$1 = "abkhaze";
var ace$1 = "aceh";
var ach$1 = "acoli";
var ada$1 = "adangme";
var ady$1 = "adyguéen";
var afa$1 = "afro-asiatiques, autres langues";
var afh$1 = "afrihili";
var afr$1 = "afrikaans";
var ain$1 = "aïnou";
var aka$1 = "akan";
var akk$1 = "akkadien";
var alb$1 = "albanais";
var ale$1 = "aléoute";
var alg$1 = "algonquines, langues";
var alt$1 = "altaï du Sud";
var amh$1 = "amharique";
var ang$1 = "ancien anglais";
var anp$1 = "angika";
var apa$1 = "apaches, langues";
var ara$1 = "arabe";
var arc$1 = "araméen";
var arg$1 = "aragonais";
var arm$1 = "arménien";
var arn$1 = "mapuche";
var arp$1 = "arapaho";
var art$1 = "artificielles, autres langues";
var arw$1 = "arawak";
var asm$1 = "assamais";
var ast$1 = "asturien";
var ath$1 = "athapascanes, langues";
var aus$1 = "australiennes, langues";
var ava$1 = "avar";
var ave$1 = "avestique";
var awa$1 = "awadhi";
var aym$1 = "aymara";
var aze$1 = "azéri";
var bad$1 = "banda, langues";
var bai$1 = "bamilékés, langues";
var bak$1 = "bachkir";
var bal$1 = "baloutchi";
var bam$1 = "bambara";
var ban$1 = "balinais";
var baq$1 = "basque";
var bas$1 = "bassa";
var bat$1 = "baltes, langues";
var bej$1 = "bedja";
var bel$1 = "biélorusse";
var bem$1 = "bemba";
var ben$1 = "bengali";
var ber$1 = "berbères, autres langues";
var bho$1 = "bhodjpouri";
var bih$1 = "bihari";
var bik$1 = "bikol";
var bin$1 = "bini";
var bis$1 = "bichelamar";
var bla$1 = "siksika";
var bnt$1 = "bantoues, autres langues";
var bos$1 = "bosniaque";
var bra$1 = "braj";
var bre$1 = "breton";
var btk$1 = "batak, langues";
var bua$1 = "bouriate";
var bug$1 = "bugi";
var bul$1 = "bulgare";
var bur$1 = "birman";
var byn$1 = "blin";
var cad$1 = "caddo";
var cai$1 = "indiennes d'Amérique centrale, autres langues";
var car$1 = "caribe";
var cat$1 = "catalan";
var cau$1 = "caucasiennes, autres langues";
var ceb$1 = "cebuano";
var cel$1 = "celtique, autres langues";
var cha$1 = "chamorro";
var chb$1 = "chibcha";
var che$1 = "tchétchène";
var chg$1 = "tchaghataï";
var chi$1 = "chinois";
var chk$1 = "chuuk";
var chm$1 = "mari";
var chn$1 = "jargon chinook";
var cho$1 = "choctaw";
var chp$1 = "chipewyan";
var chr$1 = "cherokee";
var chu$1 = "slavon d’église";
var chv$1 = "tchouvache";
var chy$1 = "cheyenne";
var cmc$1 = "chamic";
var cnr$1 = "monténégrin";
var cop$1 = "copte";
var cor$1 = "cornique";
var cos$1 = "corse";
var cpe$1 = "créoles et pidgins anglais, autres";
var cpf$1 = "créoles et pidgins français, autres";
var cpp$1 = "créoles et pidgins portugais, autres";
var cre$1 = "cree";
var crh$1 = "turc de Crimée";
var crp$1 = "créoles et pidgins divers";
var csb$1 = "kachoube";
var cus$1 = "couchitiques, autres langues";
var cze$1 = "tchèque";
var dak$1 = "dakota";
var dan$1 = "danois";
var dar$1 = "dargwa";
var day$1 = "Land Dayak, langues";
var del$1 = "delaware";
var den$1 = "esclave";
var dgr$1 = "dogrib";
var din$1 = "dinka";
var div$1 = "maldivien";
var doi$1 = "dogri";
var dra$1 = "dravidiennes, langues";
var dsb$1 = "bas-sorabe";
var dua$1 = "douala";
var dum$1 = "moyen néerlandais";
var dut$1 = "néerlandais";
var dyu$1 = "dioula";
var dzo$1 = "dzongkha";
var efi$1 = "éfik";
var egy$1 = "égyptien ancien";
var eka$1 = "ékadjouk";
var elx$1 = "élamite";
var eng$1 = "anglais";
var enm$1 = "moyen anglais";
var epo$1 = "espéranto";
var est$1 = "estonien";
var ewe$1 = "éwé";
var ewo$1 = "éwondo";
var fan$1 = "fang";
var fao$1 = "féroïen";
var fat$1 = "fanti";
var fij$1 = "fidjien";
var fil$1 = "filipino";
var fin$1 = "finnois";
var fiu$1 = "finno-ougriennnes, autres langues";
var fon$1 = "fon";
var fre$1 = "français";
var frm$1 = "moyen français";
var fro$1 = "ancien français";
var frr$1 = "frison du Nord";
var frs$1 = "frison oriental";
var fry$1 = "frison occidental";
var ful$1 = "peul";
var fur$1 = "frioulan";
var gaa$1 = "ga";
var gay$1 = "gayo";
var gba$1 = "gbaya";
var gem$1 = "germaniques, autres langues";
var geo$1 = "géorgien";
var ger$1 = "allemand";
var gez$1 = "guèze";
var gil$1 = "gilbertin";
var gla$1 = "gaélique écossais";
var gle$1 = "irlandais";
var glg$1 = "galicien";
var glv$1 = "mannois";
var gmh$1 = "moyen haut-allemand";
var goh$1 = "ancien haut allemand";
var gon$1 = "gondi";
var gor$1 = "gorontalo";
var got$1 = "gotique";
var grb$1 = "grebo";
var grc$1 = "grec ancien (jusqu'à 1453)";
var gre$1 = "grec moderne (après 1453)";
var grn$1 = "guarani";
var gsw$1 = "suisse allemand";
var guj$1 = "goudjerati";
var gwi$1 = "gwichʼin";
var hai$1 = "haida";
var hat$1 = "créole haïtien";
var hau$1 = "haoussa";
var haw$1 = "hawaïen";
var heb$1 = "hébreu";
var her$1 = "héréro";
var hil$1 = "hiligaynon";
var him$1 = "himachali";
var hin$1 = "hindi";
var hit$1 = "hittite";
var hmn$1 = "hmong";
var hmo$1 = "hiri motu";
var hrv$1 = "croate";
var hsb$1 = "haut-sorabe";
var hun$1 = "hongrois";
var hup$1 = "hupa";
var iba$1 = "iban";
var ibo$1 = "igbo";
var ice$1 = "islandais";
var ido$1 = "ido";
var iii$1 = "yi du Sichuan";
var ijo$1 = "ijo, langues";
var iku$1 = "inuktitut";
var ile$1 = "interlingue";
var ilo$1 = "ilocano";
var ina$1 = "interlingua";
var inc$1 = "indo-aryennes, autres langues";
var ind$1 = "indonésien";
var ine$1 = "indo-européennes, autres langues";
var inh$1 = "ingouche";
var ipk$1 = "inupiaq";
var ira$1 = "iraniennes, autres langues";
var iro$1 = "iroquois, langues (famille)";
var ita$1 = "italien";
var jav$1 = "javanais";
var jbo$1 = "lojban";
var jpn$1 = "japonais";
var jpr$1 = "judéo-persan";
var jrb$1 = "judéo-arabe";
var kaa$1 = "karakalpak";
var kab$1 = "kabyle";
var kac$1 = "kachin";
var kal$1 = "groenlandais";
var kam$1 = "kamba";
var kan$1 = "kannada";
var kar$1 = "karen, langues";
var kas$1 = "cachemiri";
var kau$1 = "kanouri";
var kaw$1 = "kawi";
var kaz$1 = "kazakh";
var kbd$1 = "kabarde";
var kha$1 = "khasi";
var khi$1 = "khoisan, autres langues";
var khm$1 = "khmer";
var kho$1 = "khotanais";
var kik$1 = "kikuyu";
var kin$1 = "kinyarwanda";
var kir$1 = "kirghize";
var kmb$1 = "kimboundou";
var kok$1 = "konkani";
var kom$1 = "komi";
var kon$1 = "kikongo";
var kor$1 = "coréen";
var kos$1 = "kosraéen";
var kpe$1 = "kpellé";
var krc$1 = "karatchaï balkar";
var krl$1 = "carélien";
var kro$1 = "krou, langues";
var kru$1 = "kouroukh";
var kua$1 = "kuanyama";
var kum$1 = "koumyk";
var kur$1 = "kurde";
var kut$1 = "kutenai";
var lad$1 = "ladino";
var lah$1 = "lahnda";
var lam$1 = "lamba";
var lao$1 = "lao";
var lat$1 = "latin";
var lav$1 = "letton";
var lez$1 = "lezghien";
var lim$1 = "limbourgeois";
var lin$1 = "lingala";
var lit$1 = "lituanien";
var lol$1 = "mongo";
var loz$1 = "lozi";
var ltz$1 = "luxembourgeois";
var lua$1 = "luba-kasaï (ciluba)";
var lub$1 = "luba-katanga (kiluba)";
var lug$1 = "ganda";
var lui$1 = "luiseño";
var lun$1 = "lunda";
var luo$1 = "luo";
var lus$1 = "lushaï";
var mac$1 = "macédonien";
var mad$1 = "madurais";
var mag$1 = "magahi";
var mah$1 = "marshallais";
var mai$1 = "maïthili";
var mak$1 = "makassar";
var mal$1 = "malayalam";
var man$1 = "mandingue";
var mao$1 = "maori";
var map$1 = "malayo-polynésiennes, autres langues";
var mar$1 = "marathi";
var mas$1 = "maasaï";
var may$1 = "malais";
var mdf$1 = "mokcha";
var mdr$1 = "mandar";
var men$1 = "mendé";
var mga$1 = "moyen irlandais";
var mic$1 = "micmac";
var min$1 = "minangkabau";
var mis$1 = "diverses, langues";
var mkh$1 = "môn-khmer, langues";
var mlg$1 = "malgache";
var mlt$1 = "maltais";
var mnc$1 = "mandchou";
var mni$1 = "manipuri";
var mno$1 = "manobo, langues";
var moh$1 = "mohawk";
var mon$1 = "mongol";
var mos$1 = "moré";
var mul$1 = "multilingue";
var mun$1 = "mounda, langues";
var mus$1 = "muskogee";
var mwl$1 = "mirandais";
var mwr$1 = "marwarî";
var myn$1 = "maya, langues";
var myv$1 = "erzya";
var nah$1 = "nahuatl, langues";
var nai$1 = "indiennes d'Amérique du Nord, autres langues";
var nap$1 = "napolitain";
var nau$1 = "nauruan";
var nav$1 = "navajo";
var nbl$1 = "ndébélé du Sud";
var nde$1 = "ndébélé du Nord";
var ndo$1 = "ndonga";
var nds$1 = "bas-allemand";
var nep$1 = "népalais";
var nia$1 = "niha";
var nic$1 = "nigéro-congolaises,langues";
var niu$1 = "niuéen";
var nno$1 = "norvégien nynorsk";
var nob$1 = "norvégien bokmål";
var nog$1 = "nogaï";
var non$1 = "vieux norrois";
var nor$1 = "norvégien";
var nqo$1 = "n’ko";
var nso$1 = "sotho du Nord";
var nub$1 = "nubiennes, langues";
var nwc$1 = "newarî classique";
var nya$1 = "chewa";
var nym$1 = "nyamwezi";
var nyn$1 = "nyankolé";
var nyo$1 = "nyoro";
var nzi$1 = "nzema";
var oci$1 = "occitan";
var oji$1 = "ojibwa";
var ori$1 = "odia";
var orm$1 = "oromo";
var osa$1 = "osage";
var oss$1 = "ossète";
var ota$1 = "turc ottoman";
var oto$1 = "otomi, langues";
var paa$1 = "papoues, autres langues";
var pag$1 = "pangasinan";
var pal$1 = "pahlavi";
var pam$1 = "pampangan";
var pan$1 = "pendjabi";
var pap$1 = "papiamento";
var pau$1 = "palau";
var peo$1 = "persan ancien";
var per$1 = "persan";
var phi$1 = "philippin, autres langues";
var phn$1 = "phénicien";
var pli$1 = "pali";
var pol$1 = "polonais";
var pon$1 = "pohnpei";
var por$1 = "portugais";
var pra$1 = "prâkrit";
var pro$1 = "provençal ancien";
var pus$1 = "pachto";
var que$1 = "quechua";
var raj$1 = "rajasthani";
var rap$1 = "rapanui";
var rar$1 = "rarotongien";
var roa$1 = "romanes, langues";
var roh$1 = "romanche";
var rom$1 = "romani";
var rum$1 = "roumain";
var run$1 = "roundi";
var rup$1 = "aroumain";
var rus$1 = "russe";
var sad$1 = "sandawe";
var sag$1 = "sango";
var sah$1 = "iakoute";
var sai$1 = "indiennes d'Amérique du Sud, autres langues";
var sal$1 = "salish, langues";
var sam$1 = "araméen samaritain";
var san$1 = "sanskrit";
var sas$1 = "sasak";
var sat$1 = "santali";
var scn$1 = "sicilien";
var sco$1 = "écossais";
var sel$1 = "selkoupe";
var sem$1 = "sémitiques, langues";
var sga$1 = "ancien irlandais";
var sgn$1 = "langue des signes";
var shn$1 = "shan";
var sid$1 = "sidamo";
var sin$1 = "cingalais";
var sio$1 = "sioux, langues";
var sit$1 = "sino-tibétaines, autres langues";
var sla$1 = "slaves, langues";
var slo$1 = "slovaque";
var slv$1 = "slovène";
var sma$1 = "same du Sud";
var sme$1 = "same du Nord";
var smi$1 = "sâmes, langues";
var smj$1 = "same de Lule";
var smn$1 = "same d’Inari";
var smo$1 = "samoan";
var sms$1 = "same skolt";
var sna$1 = "shona";
var snd$1 = "sindhi";
var snk$1 = "soninké";
var sog$1 = "sogdien";
var som$1 = "somali";
var son$1 = "songhai";
var sot$1 = "sotho du Sud";
var spa$1 = "espagnol";
var srd$1 = "sarde";
var srn$1 = "sranan tongo";
var srp$1 = "serbe";
var srr$1 = "sérère";
var ssa$1 = "nilo-sahariennes, langues";
var ssw$1 = "swati";
var suk$1 = "soukouma";
var sun$1 = "soundanais";
var sus$1 = "soussou";
var sux$1 = "sumérien";
var swa$1 = "swahili";
var swe$1 = "suédois";
var syc$1 = "syriaque classique";
var syr$1 = "syriaque";
var tah$1 = "tahitien";
var tai$1 = "tai, langues";
var tam$1 = "tamoul";
var tat$1 = "tatar";
var tel$1 = "télougou";
var tem$1 = "timné";
var ter$1 = "tereno";
var tet$1 = "tétoum";
var tgk$1 = "tadjik";
var tgl$1 = "tagalog";
var tha$1 = "thaï";
var tib$1 = "tibétain";
var tig$1 = "tigré";
var tir$1 = "tigrigna";
var tiv$1 = "tiv";
var tkl$1 = "tokelau";
var tlh$1 = "klingon";
var tli$1 = "tlingit";
var tmh$1 = "tamacheq";
var tog$1 = "tonga nyasa";
var ton$1 = "tongien";
var tpi$1 = "tok pisin";
var tsi$1 = "tsimshian";
var tsn$1 = "tswana";
var tso$1 = "tsonga";
var tuk$1 = "turkmène";
var tum$1 = "tumbuka";
var tup$1 = "tupi, langues";
var tur$1 = "turc";
var tut$1 = "altaïques, langues";
var tvl$1 = "tuvalu";
var twi$1 = "twi";
var tyv$1 = "touvain";
var udm$1 = "oudmourte";
var uga$1 = "ougaritique";
var uig$1 = "ouïghour";
var ukr$1 = "ukrainien";
var umb$1 = "umbundu";
var und$1 = "langue indéterminée";
var urd$1 = "ourdou";
var uzb$1 = "ouzbek";
var vai$1 = "vaï";
var ven$1 = "venda";
var vie$1 = "vietnamien";
var vol$1 = "volapük";
var vot$1 = "vote";
var wak$1 = "wakashennes, langues";
var wal$1 = "walamo";
var war$1 = "waray";
var was$1 = "washo";
var wel$1 = "gallois";
var wen$1 = "sorabes, langues";
var wln$1 = "wallon";
var wol$1 = "wolof";
var xal$1 = "kalmouk";
var xho$1 = "xhosa";
var yao$1 = "yao";
var yap$1 = "yapois";
var yid$1 = "yiddish";
var yor$1 = "yoruba";
var ypk$1 = "yupik, langues";
var zap$1 = "zapotèque";
var zbl$1 = "symboles Bliss";
var zen$1 = "zenaga";
var zha$1 = "zhuang";
var znd$1 = "zandé, langues";
var zul$1 = "zoulou";
var zun$1 = "zuñi";
var zxx$1 = "sans contenu linguistique";
var zza$1 = "zazaki";
var fr$5 = {
	aar: aar$1,
	abk: abk$1,
	ace: ace$1,
	ach: ach$1,
	ada: ada$1,
	ady: ady$1,
	afa: afa$1,
	afh: afh$1,
	afr: afr$1,
	ain: ain$1,
	aka: aka$1,
	akk: akk$1,
	alb: alb$1,
	ale: ale$1,
	alg: alg$1,
	alt: alt$1,
	amh: amh$1,
	ang: ang$1,
	anp: anp$1,
	apa: apa$1,
	ara: ara$1,
	arc: arc$1,
	arg: arg$1,
	arm: arm$1,
	arn: arn$1,
	arp: arp$1,
	art: art$1,
	arw: arw$1,
	asm: asm$1,
	ast: ast$1,
	ath: ath$1,
	aus: aus$1,
	ava: ava$1,
	ave: ave$1,
	awa: awa$1,
	aym: aym$1,
	aze: aze$1,
	bad: bad$1,
	bai: bai$1,
	bak: bak$1,
	bal: bal$1,
	bam: bam$1,
	ban: ban$1,
	baq: baq$1,
	bas: bas$1,
	bat: bat$1,
	bej: bej$1,
	bel: bel$1,
	bem: bem$1,
	ben: ben$1,
	ber: ber$1,
	bho: bho$1,
	bih: bih$1,
	bik: bik$1,
	bin: bin$1,
	bis: bis$1,
	bla: bla$1,
	bnt: bnt$1,
	bos: bos$1,
	bra: bra$1,
	bre: bre$1,
	btk: btk$1,
	bua: bua$1,
	bug: bug$1,
	bul: bul$1,
	bur: bur$1,
	byn: byn$1,
	cad: cad$1,
	cai: cai$1,
	car: car$1,
	cat: cat$1,
	cau: cau$1,
	ceb: ceb$1,
	cel: cel$1,
	cha: cha$1,
	chb: chb$1,
	che: che$1,
	chg: chg$1,
	chi: chi$1,
	chk: chk$1,
	chm: chm$1,
	chn: chn$1,
	cho: cho$1,
	chp: chp$1,
	chr: chr$1,
	chu: chu$1,
	chv: chv$1,
	chy: chy$1,
	cmc: cmc$1,
	cnr: cnr$1,
	cop: cop$1,
	cor: cor$1,
	cos: cos$1,
	cpe: cpe$1,
	cpf: cpf$1,
	cpp: cpp$1,
	cre: cre$1,
	crh: crh$1,
	crp: crp$1,
	csb: csb$1,
	cus: cus$1,
	cze: cze$1,
	dak: dak$1,
	dan: dan$1,
	dar: dar$1,
	day: day$1,
	del: del$1,
	den: den$1,
	dgr: dgr$1,
	din: din$1,
	div: div$1,
	doi: doi$1,
	dra: dra$1,
	dsb: dsb$1,
	dua: dua$1,
	dum: dum$1,
	dut: dut$1,
	dyu: dyu$1,
	dzo: dzo$1,
	efi: efi$1,
	egy: egy$1,
	eka: eka$1,
	elx: elx$1,
	eng: eng$1,
	enm: enm$1,
	epo: epo$1,
	est: est$1,
	ewe: ewe$1,
	ewo: ewo$1,
	fan: fan$1,
	fao: fao$1,
	fat: fat$1,
	fij: fij$1,
	fil: fil$1,
	fin: fin$1,
	fiu: fiu$1,
	fon: fon$1,
	fre: fre$1,
	frm: frm$1,
	fro: fro$1,
	frr: frr$1,
	frs: frs$1,
	fry: fry$1,
	ful: ful$1,
	fur: fur$1,
	gaa: gaa$1,
	gay: gay$1,
	gba: gba$1,
	gem: gem$1,
	geo: geo$1,
	ger: ger$1,
	gez: gez$1,
	gil: gil$1,
	gla: gla$1,
	gle: gle$1,
	glg: glg$1,
	glv: glv$1,
	gmh: gmh$1,
	goh: goh$1,
	gon: gon$1,
	gor: gor$1,
	got: got$1,
	grb: grb$1,
	grc: grc$1,
	gre: gre$1,
	grn: grn$1,
	gsw: gsw$1,
	guj: guj$1,
	gwi: gwi$1,
	hai: hai$1,
	hat: hat$1,
	hau: hau$1,
	haw: haw$1,
	heb: heb$1,
	her: her$1,
	hil: hil$1,
	him: him$1,
	hin: hin$1,
	hit: hit$1,
	hmn: hmn$1,
	hmo: hmo$1,
	hrv: hrv$1,
	hsb: hsb$1,
	hun: hun$1,
	hup: hup$1,
	iba: iba$1,
	ibo: ibo$1,
	ice: ice$1,
	ido: ido$1,
	iii: iii$1,
	ijo: ijo$1,
	iku: iku$1,
	ile: ile$1,
	ilo: ilo$1,
	ina: ina$1,
	inc: inc$1,
	ind: ind$1,
	ine: ine$1,
	inh: inh$1,
	ipk: ipk$1,
	ira: ira$1,
	iro: iro$1,
	ita: ita$1,
	jav: jav$1,
	jbo: jbo$1,
	jpn: jpn$1,
	jpr: jpr$1,
	jrb: jrb$1,
	kaa: kaa$1,
	kab: kab$1,
	kac: kac$1,
	kal: kal$1,
	kam: kam$1,
	kan: kan$1,
	kar: kar$1,
	kas: kas$1,
	kau: kau$1,
	kaw: kaw$1,
	kaz: kaz$1,
	kbd: kbd$1,
	kha: kha$1,
	khi: khi$1,
	khm: khm$1,
	kho: kho$1,
	kik: kik$1,
	kin: kin$1,
	kir: kir$1,
	kmb: kmb$1,
	kok: kok$1,
	kom: kom$1,
	kon: kon$1,
	kor: kor$1,
	kos: kos$1,
	kpe: kpe$1,
	krc: krc$1,
	krl: krl$1,
	kro: kro$1,
	kru: kru$1,
	kua: kua$1,
	kum: kum$1,
	kur: kur$1,
	kut: kut$1,
	lad: lad$1,
	lah: lah$1,
	lam: lam$1,
	lao: lao$1,
	lat: lat$1,
	lav: lav$1,
	lez: lez$1,
	lim: lim$1,
	lin: lin$1,
	lit: lit$1,
	lol: lol$1,
	loz: loz$1,
	ltz: ltz$1,
	lua: lua$1,
	lub: lub$1,
	lug: lug$1,
	lui: lui$1,
	lun: lun$1,
	luo: luo$1,
	lus: lus$1,
	mac: mac$1,
	mad: mad$1,
	mag: mag$1,
	mah: mah$1,
	mai: mai$1,
	mak: mak$1,
	mal: mal$1,
	man: man$1,
	mao: mao$1,
	map: map$1,
	mar: mar$1,
	mas: mas$1,
	may: may$1,
	mdf: mdf$1,
	mdr: mdr$1,
	men: men$1,
	mga: mga$1,
	mic: mic$1,
	min: min$1,
	mis: mis$1,
	mkh: mkh$1,
	mlg: mlg$1,
	mlt: mlt$1,
	mnc: mnc$1,
	mni: mni$1,
	mno: mno$1,
	moh: moh$1,
	mon: mon$1,
	mos: mos$1,
	mul: mul$1,
	mun: mun$1,
	mus: mus$1,
	mwl: mwl$1,
	mwr: mwr$1,
	myn: myn$1,
	myv: myv$1,
	nah: nah$1,
	nai: nai$1,
	nap: nap$1,
	nau: nau$1,
	nav: nav$1,
	nbl: nbl$1,
	nde: nde$1,
	ndo: ndo$1,
	nds: nds$1,
	nep: nep$1,
	"new": "newari",
	nia: nia$1,
	nic: nic$1,
	niu: niu$1,
	nno: nno$1,
	nob: nob$1,
	nog: nog$1,
	non: non$1,
	nor: nor$1,
	nqo: nqo$1,
	nso: nso$1,
	nub: nub$1,
	nwc: nwc$1,
	nya: nya$1,
	nym: nym$1,
	nyn: nyn$1,
	nyo: nyo$1,
	nzi: nzi$1,
	oci: oci$1,
	oji: oji$1,
	ori: ori$1,
	orm: orm$1,
	osa: osa$1,
	oss: oss$1,
	ota: ota$1,
	oto: oto$1,
	paa: paa$1,
	pag: pag$1,
	pal: pal$1,
	pam: pam$1,
	pan: pan$1,
	pap: pap$1,
	pau: pau$1,
	peo: peo$1,
	per: per$1,
	phi: phi$1,
	phn: phn$1,
	pli: pli$1,
	pol: pol$1,
	pon: pon$1,
	por: por$1,
	pra: pra$1,
	pro: pro$1,
	pus: pus$1,
	que: que$1,
	raj: raj$1,
	rap: rap$1,
	rar: rar$1,
	roa: roa$1,
	roh: roh$1,
	rom: rom$1,
	rum: rum$1,
	run: run$1,
	rup: rup$1,
	rus: rus$1,
	sad: sad$1,
	sag: sag$1,
	sah: sah$1,
	sai: sai$1,
	sal: sal$1,
	sam: sam$1,
	san: san$1,
	sas: sas$1,
	sat: sat$1,
	scn: scn$1,
	sco: sco$1,
	sel: sel$1,
	sem: sem$1,
	sga: sga$1,
	sgn: sgn$1,
	shn: shn$1,
	sid: sid$1,
	sin: sin$1,
	sio: sio$1,
	sit: sit$1,
	sla: sla$1,
	slo: slo$1,
	slv: slv$1,
	sma: sma$1,
	sme: sme$1,
	smi: smi$1,
	smj: smj$1,
	smn: smn$1,
	smo: smo$1,
	sms: sms$1,
	sna: sna$1,
	snd: snd$1,
	snk: snk$1,
	sog: sog$1,
	som: som$1,
	son: son$1,
	sot: sot$1,
	spa: spa$1,
	srd: srd$1,
	srn: srn$1,
	srp: srp$1,
	srr: srr$1,
	ssa: ssa$1,
	ssw: ssw$1,
	suk: suk$1,
	sun: sun$1,
	sus: sus$1,
	sux: sux$1,
	swa: swa$1,
	swe: swe$1,
	syc: syc$1,
	syr: syr$1,
	tah: tah$1,
	tai: tai$1,
	tam: tam$1,
	tat: tat$1,
	tel: tel$1,
	tem: tem$1,
	ter: ter$1,
	tet: tet$1,
	tgk: tgk$1,
	tgl: tgl$1,
	tha: tha$1,
	tib: tib$1,
	tig: tig$1,
	tir: tir$1,
	tiv: tiv$1,
	tkl: tkl$1,
	tlh: tlh$1,
	tli: tli$1,
	tmh: tmh$1,
	tog: tog$1,
	ton: ton$1,
	tpi: tpi$1,
	tsi: tsi$1,
	tsn: tsn$1,
	tso: tso$1,
	tuk: tuk$1,
	tum: tum$1,
	tup: tup$1,
	tur: tur$1,
	tut: tut$1,
	tvl: tvl$1,
	twi: twi$1,
	tyv: tyv$1,
	udm: udm$1,
	uga: uga$1,
	uig: uig$1,
	ukr: ukr$1,
	umb: umb$1,
	und: und$1,
	urd: urd$1,
	uzb: uzb$1,
	vai: vai$1,
	ven: ven$1,
	vie: vie$1,
	vol: vol$1,
	vot: vot$1,
	wak: wak$1,
	wal: wal$1,
	war: war$1,
	was: was$1,
	wel: wel$1,
	wen: wen$1,
	wln: wln$1,
	wol: wol$1,
	xal: xal$1,
	xho: xho$1,
	yao: yao$1,
	yap: yap$1,
	yid: yid$1,
	yor: yor$1,
	ypk: ypk$1,
	zap: zap$1,
	zbl: zbl$1,
	zen: zen$1,
	zha: zha$1,
	znd: znd$1,
	zul: zul$1,
	zun: zun$1,
	zxx: zxx$1,
	zza: zza$1
};

var aar = "afar";
var abk = "abcaso";
var ace = "accinese";
var ach = "acioli";
var ada = "adangme";
var ady = "adyghe";
var afa = "afroasiatiche (altre)";
var afh = "afrihili";
var afr = "afrikaans";
var ain = "ainu";
var aka = "akan";
var akk = "accado";
var alb = "albanese";
var ale = "aleuto";
var alg = "lingue algonchine";
var alt = "altai meridionale";
var amh = "amarico";
var ang = "inglese antico";
var anp = "angika";
var apa = "lingue apache";
var ara = "arabo";
var arc = "aramaico";
var arg = "aragonese";
var arm = "armeno";
var arn = "mapudungun";
var arp = "arapaho";
var art = "lingua artificiale (altre)";
var arw = "aruaco";
var asm = "assamese";
var ast = "asturiano";
var ath = "lingue athabaska";
var aus = "lingue australiane aborigene";
var ava = "avaro";
var ave = "avestan";
var awa = "awadhi";
var aym = "aymara";
var aze = "azerbaigiano";
var bad = "banda";
var bai = "lingue bamileke";
var bak = "baschiro";
var bal = "beluci";
var bam = "bambara";
var ban = "balinese";
var baq = "basco";
var bas = "basa";
var bat = "lingue baltiche (altre)";
var bej = "begia";
var bel = "bielorusso";
var bem = "wemba";
var ben = "bengalese";
var ber = "lingue berbere";
var bho = "bhojpuri";
var bih = "bihari";
var bik = "bicol";
var bin = "bini";
var bis = "bislama";
var bla = "siksika";
var bnt = "bantu (altre)";
var bos = "bosniaco";
var bra = "braj";
var bre = "bretone";
var btk = "batak (indonesia)";
var bua = "buriat";
var bug = "bugi";
var bul = "bulgaro";
var bur = "birmano";
var byn = "blin";
var cad = "caddo";
var cai = "indiane centro-americane (altre)";
var car = "caribico";
var cat = "catalano";
var cau = "lingue caucasiche (altre)";
var ceb = "cebuano";
var cel = "lingue celtiche (altre)";
var cha = "chamorro";
var chb = "chibcha";
var che = "ceceno";
var chg = "ciagataico";
var chi = "cinese";
var chk = "chuukese";
var chm = "mari";
var chn = "gergo chinook";
var cho = "choctaw";
var chp = "chipewyan";
var chr = "cherokee";
var chu = "slavo della Chiesa";
var chv = "ciuvascio";
var chy = "cheyenne";
var cmc = "chamic";
var cnr = "montenegrino";
var cop = "copto";
var cor = "cornico";
var cos = "corso";
var cpe = "creoli e pidgin basati sull'inglese (altre)";
var cpf = "creoli e pidgin basati sul francese (altre)";
var cpp = "creoli e pidgin basati sul portoghese (altre)";
var cre = "cree";
var crh = "turco crimeo";
var crp = "creoli e pidgin (altre)";
var csb = "kashubian";
var cus = "lingue cushitiche (altre)";
var cze = "ceco";
var dak = "dakota";
var dan = "danese";
var dar = "dargwa";
var day = "dayak";
var del = "delaware";
var den = "slave";
var dgr = "dogrib";
var din = "dinca";
var div = "divehi";
var doi = "dogri";
var dra = "dravidiche (altre)";
var dsb = "basso sorabo";
var dua = "duala";
var dum = "olandese medio";
var dut = "olandese; fiammingo";
var dyu = "diula";
var dzo = "dzongkha";
var efi = "efik";
var egy = "egiziano antico";
var eka = "ekajuka";
var elx = "elamitico";
var eng = "inglese";
var enm = "inglese medio";
var epo = "esperanto";
var est = "estone";
var ewe = "ewe";
var ewo = "ewondo";
var fan = "fang";
var fao = "faroese";
var fat = "fanti";
var fij = "figiano";
var fil = "filippino";
var fin = "finlandese";
var fiu = "ugrofinniche (altre)";
var fon = "fon";
var fre = "francese";
var frm = "francese medio";
var fro = "francese antico";
var frr = "frisone settentrionale";
var frs = "frisone orientale";
var fry = "frisone occidentale";
var ful = "fulah";
var fur = "friulano";
var gaa = "ga";
var gay = "gayo";
var gba = "gbaya";
var gem = "lingue germaniche (altre)";
var geo = "georgiano";
var ger = "tedesco";
var gez = "geez";
var gil = "gilbertese";
var gla = "gaelico scozzese";
var gle = "irlandese";
var glg = "galiziano";
var glv = "mannese";
var gmh = "tedesco medio alto";
var goh = "tedesco antico alto";
var gon = "gondi";
var gor = "gorontalo";
var got = "gotico";
var grb = "grebo";
var grc = "greco antico";
var gre = "greco moderno (dal 1453)";
var grn = "guaraní";
var gsw = "tedesco svizzero";
var guj = "gujarati";
var gwi = "gwichʼin";
var hai = "haida";
var hat = "haitiano";
var hau = "hausa";
var haw = "hawaiano";
var heb = "ebraico";
var her = "herero";
var hil = "ilongo";
var him = "himachali";
var hin = "hindi";
var hit = "hittite";
var hmn = "hmong";
var hmo = "hiri motu";
var hrv = "croato";
var hsb = "alto sorabo";
var hun = "ungherese";
var hup = "hupa";
var iba = "iban";
var ibo = "igbo";
var ice = "islandese";
var ido = "ido";
var iii = "sichuan yi";
var ijo = "ijo";
var iku = "inuktitut";
var ile = "interlingue";
var ilo = "ilocano";
var ina = "interlingua";
var inc = "lingue indoarie (altre)";
var ind = "indonesiano";
var ine = "lingue indoeuropee (altre)";
var inh = "ingush";
var ipk = "inupiak";
var ira = "lingue iraniche (altre)";
var iro = "lingue irochesi";
var ita = "italiano";
var jav = "giavanese";
var jbo = "lojban";
var jpn = "giapponese";
var jpr = "giudeo persiano";
var jrb = "giudeo arabo";
var kaa = "kara-kalpak";
var kab = "cabilo";
var kac = "kachin";
var kal = "groenlandese";
var kam = "kamba";
var kan = "kannada";
var kar = "karen";
var kas = "kashmiri";
var kau = "kanuri";
var kaw = "kawi";
var kaz = "kazako";
var kbd = "cabardino";
var kha = "khasi";
var khi = "khoisan (altre)";
var khm = "khmer";
var kho = "khotanese";
var kik = "kikuyu";
var kin = "kinyarwanda";
var kir = "kirghiso";
var kmb = "kimbundu";
var kok = "konkani";
var kom = "komi";
var kon = "kongo";
var kor = "coreano";
var kos = "kosraean";
var kpe = "kpelle";
var krc = "karachay-Balkar";
var krl = "careliano";
var kro = "kru";
var kru = "kurukh";
var kua = "kuanyama";
var kum = "kumyk";
var kur = "curdo";
var kut = "kutenai";
var lad = "giudeo-spagnolo";
var lah = "lahnda";
var lam = "lamba";
var lao = "lao";
var lat = "latino";
var lav = "lettone";
var lez = "lesgo";
var lim = "limburghese";
var lin = "lingala";
var lit = "lituano";
var lol = "lolo bantu";
var loz = "lozi";
var ltz = "lussemburghese";
var lua = "luba-lulua";
var lub = "luba-katanga";
var lug = "ganda";
var lui = "luiseno";
var lun = "lunda";
var luo = "luo";
var lus = "lushai";
var mac = "macedone";
var mad = "madurese";
var mag = "magahi";
var mah = "marshallese";
var mai = "maithili";
var mak = "makasar";
var mal = "malayalam";
var man = "mandingo";
var mao = "maori";
var map = "austronesiano (altre)";
var mar = "marathi";
var mas = "masai";
var may = "malay";
var mdf = "moksha";
var mdr = "mandar";
var men = "mende";
var mga = "irlandese medio";
var mic = "micmac";
var min = "menangkabau";
var mis = "ainu";
var mkh = "mon-khmer (altre)";
var mlg = "malgascio";
var mlt = "maltese";
var mnc = "manchu";
var mni = "manipuri";
var mno = "lingue manobo";
var moh = "mohawk";
var mon = "mongolo";
var mos = "mossi";
var mul = "multilingua";
var mun = "lingue munda";
var mus = "creek";
var mwl = "mirandese";
var mwr = "marwari";
var myn = "maya";
var myv = "erzya";
var nah = "nahuatl";
var nai = "indiano nordamericano (altre)";
var nap = "napoletano";
var nau = "nauru";
var nav = "navajo";
var nbl = "ndebele del sud";
var nde = "ndebele del nord";
var ndo = "ndonga";
var nds = "basso tedesco";
var nep = "nepalese";
var nia = "nias";
var nic = "niger-kordofaniane (altre)";
var niu = "niue";
var nno = "norvegese nynorsk";
var nob = "norvegese bokmål";
var nog = "nogai";
var non = "norse antico";
var nor = "norvegese";
var nqo = "n’ko";
var nso = "sotho del nord";
var nub = "lingue nubiane";
var nwc = "newari classico";
var nya = "nyanja";
var nym = "nyamwezi";
var nyn = "nyankole";
var nyo = "nyoro";
var nzi = "nzima";
var oci = "occitano";
var oji = "ojibwa";
var ori = "odia";
var orm = "oromo";
var osa = "osage";
var oss = "ossetico";
var ota = "turco ottomano";
var oto = "lingue otomiane";
var paa = "papuasiche";
var pag = "pangasinan";
var pal = "pahlavi";
var pam = "pampanga";
var pan = "punjabi";
var pap = "papiamento";
var pau = "palau";
var peo = "persiano antico";
var per = "persiano";
var phi = "filippine (altre)";
var phn = "fenicio";
var pli = "pali";
var pol = "polacco";
var pon = "ponape";
var por = "portoghese";
var pra = "lingue pracrite";
var pro = "provenzale antico";
var pus = "pashto";
var que = "quechua";
var raj = "rajasthani";
var rap = "rapanui";
var rar = "rarotonga";
var roa = "lingue romanze (altre)";
var roh = "romancio";
var rom = "romani";
var rum = "romeno";
var run = "rundi";
var rup = "arumeno";
var rus = "russo";
var sad = "sandawe";
var sag = "sango";
var sah = "yakut";
var sai = "lingue indiane sudamericane (altre)";
var sal = "lingue salish";
var sam = "aramaico samaritano";
var san = "sanscrito";
var sas = "sasak";
var sat = "santali";
var scn = "siciliano";
var sco = "scozzese";
var sel = "selkup";
var sem = "lingue semitiche (altre)";
var sga = "irlandese antico";
var sgn = "lingua dei segni";
var shn = "shan";
var sid = "sidamo";
var sin = "singalese";
var sio = "lingue sioux";
var sit = "sinotibetane (altre)";
var sla = "lingue slave (altre)";
var slo = "slovacco";
var slv = "sloveno";
var sma = "sami del sud";
var sme = "sami del nord";
var smi = "lingue sami (altre)";
var smj = "sami di Lule";
var smn = "sami di Inari";
var smo = "samoano";
var sms = "sami skolt";
var sna = "shona";
var snd = "sindhi";
var snk = "soninke";
var sog = "sogdiano";
var som = "somalo";
var son = "songhai";
var sot = "sotho del sud";
var spa = "spagnolo";
var srd = "sardo";
var srn = "sranan tongo";
var srp = "serbo";
var srr = "serer";
var ssa = "lingue nilo-sahariane (altre)";
var ssw = "swati";
var suk = "sukuma";
var sun = "sundanese";
var sus = "susu";
var sux = "sumero";
var swa = "swahili";
var swe = "svedese";
var syc = "siriaco classico";
var syr = "siriaco";
var tah = "taitiano";
var tai = "thailandese (altre)";
var tam = "tamil";
var tat = "tataro";
var tel = "telugu";
var tem = "temne";
var ter = "tereno";
var tet = "tetum";
var tgk = "tagico";
var tgl = "tagalog";
var tha = "thai";
var tib = "tibetano";
var tig = "tigre";
var tir = "tigrino";
var tiv = "tiv";
var tkl = "tokelau";
var tlh = "klingon";
var tli = "tlingit";
var tmh = "tamashek";
var tog = "nyasa del Tonga";
var ton = "tongano";
var tpi = "tok pisin";
var tsi = "tsimshian";
var tsn = "tswana";
var tso = "tsonga";
var tuk = "turcomanno";
var tum = "tumbuka";
var tup = "lingue tupi";
var tur = "turco";
var tut = "altaiche (altre)";
var tvl = "tuvalu";
var twi = "ci";
var tyv = "tuvinian";
var udm = "udmurt";
var uga = "ugaritico";
var uig = "uiguro";
var ukr = "ucraino";
var umb = "mbundu";
var und = "lingua imprecisata";
var urd = "urdu";
var uzb = "uzbeco";
var vai = "vai";
var ven = "venda";
var vie = "vietnamita";
var vol = "volapük";
var vot = "voto";
var wak = "lingue wakash";
var wal = "walamo";
var war = "waray";
var was = "washo";
var wel = "gallese";
var wen = "lingue lusaziane";
var wln = "vallone";
var wol = "wolof";
var xal = "kalmyk";
var xho = "xhosa";
var yao = "yao (bantu)";
var yap = "yapese";
var yid = "yiddish";
var yor = "yoruba";
var ypk = "lingue yupik";
var zap = "zapotec";
var zbl = "blissymbol";
var zen = "zenaga";
var zha = "zhuang";
var znd = "zande";
var zul = "zulu";
var zun = "zuni";
var zxx = "nessun contenuto linguistico";
var zza = "zaza";
var it$5 = {
	aar: aar,
	abk: abk,
	ace: ace,
	ach: ach,
	ada: ada,
	ady: ady,
	afa: afa,
	afh: afh,
	afr: afr,
	ain: ain,
	aka: aka,
	akk: akk,
	alb: alb,
	ale: ale,
	alg: alg,
	alt: alt,
	amh: amh,
	ang: ang,
	anp: anp,
	apa: apa,
	ara: ara,
	arc: arc,
	arg: arg,
	arm: arm,
	arn: arn,
	arp: arp,
	art: art,
	arw: arw,
	asm: asm,
	ast: ast,
	ath: ath,
	aus: aus,
	ava: ava,
	ave: ave,
	awa: awa,
	aym: aym,
	aze: aze,
	bad: bad,
	bai: bai,
	bak: bak,
	bal: bal,
	bam: bam,
	ban: ban,
	baq: baq,
	bas: bas,
	bat: bat,
	bej: bej,
	bel: bel,
	bem: bem,
	ben: ben,
	ber: ber,
	bho: bho,
	bih: bih,
	bik: bik,
	bin: bin,
	bis: bis,
	bla: bla,
	bnt: bnt,
	bos: bos,
	bra: bra,
	bre: bre,
	btk: btk,
	bua: bua,
	bug: bug,
	bul: bul,
	bur: bur,
	byn: byn,
	cad: cad,
	cai: cai,
	car: car,
	cat: cat,
	cau: cau,
	ceb: ceb,
	cel: cel,
	cha: cha,
	chb: chb,
	che: che,
	chg: chg,
	chi: chi,
	chk: chk,
	chm: chm,
	chn: chn,
	cho: cho,
	chp: chp,
	chr: chr,
	chu: chu,
	chv: chv,
	chy: chy,
	cmc: cmc,
	cnr: cnr,
	cop: cop,
	cor: cor,
	cos: cos,
	cpe: cpe,
	cpf: cpf,
	cpp: cpp,
	cre: cre,
	crh: crh,
	crp: crp,
	csb: csb,
	cus: cus,
	cze: cze,
	dak: dak,
	dan: dan,
	dar: dar,
	day: day,
	del: del,
	den: den,
	dgr: dgr,
	din: din,
	div: div,
	doi: doi,
	dra: dra,
	dsb: dsb,
	dua: dua,
	dum: dum,
	dut: dut,
	dyu: dyu,
	dzo: dzo,
	efi: efi,
	egy: egy,
	eka: eka,
	elx: elx,
	eng: eng,
	enm: enm,
	epo: epo,
	est: est,
	ewe: ewe,
	ewo: ewo,
	fan: fan,
	fao: fao,
	fat: fat,
	fij: fij,
	fil: fil,
	fin: fin,
	fiu: fiu,
	fon: fon,
	fre: fre,
	frm: frm,
	fro: fro,
	frr: frr,
	frs: frs,
	fry: fry,
	ful: ful,
	fur: fur,
	gaa: gaa,
	gay: gay,
	gba: gba,
	gem: gem,
	geo: geo,
	ger: ger,
	gez: gez,
	gil: gil,
	gla: gla,
	gle: gle,
	glg: glg,
	glv: glv,
	gmh: gmh,
	goh: goh,
	gon: gon,
	gor: gor,
	got: got,
	grb: grb,
	grc: grc,
	gre: gre,
	grn: grn,
	gsw: gsw,
	guj: guj,
	gwi: gwi,
	hai: hai,
	hat: hat,
	hau: hau,
	haw: haw,
	heb: heb,
	her: her,
	hil: hil,
	him: him,
	hin: hin,
	hit: hit,
	hmn: hmn,
	hmo: hmo,
	hrv: hrv,
	hsb: hsb,
	hun: hun,
	hup: hup,
	iba: iba,
	ibo: ibo,
	ice: ice,
	ido: ido,
	iii: iii,
	ijo: ijo,
	iku: iku,
	ile: ile,
	ilo: ilo,
	ina: ina,
	inc: inc,
	ind: ind,
	ine: ine,
	inh: inh,
	ipk: ipk,
	ira: ira,
	iro: iro,
	ita: ita,
	jav: jav,
	jbo: jbo,
	jpn: jpn,
	jpr: jpr,
	jrb: jrb,
	kaa: kaa,
	kab: kab,
	kac: kac,
	kal: kal,
	kam: kam,
	kan: kan,
	kar: kar,
	kas: kas,
	kau: kau,
	kaw: kaw,
	kaz: kaz,
	kbd: kbd,
	kha: kha,
	khi: khi,
	khm: khm,
	kho: kho,
	kik: kik,
	kin: kin,
	kir: kir,
	kmb: kmb,
	kok: kok,
	kom: kom,
	kon: kon,
	kor: kor,
	kos: kos,
	kpe: kpe,
	krc: krc,
	krl: krl,
	kro: kro,
	kru: kru,
	kua: kua,
	kum: kum,
	kur: kur,
	kut: kut,
	lad: lad,
	lah: lah,
	lam: lam,
	lao: lao,
	lat: lat,
	lav: lav,
	lez: lez,
	lim: lim,
	lin: lin,
	lit: lit,
	lol: lol,
	loz: loz,
	ltz: ltz,
	lua: lua,
	lub: lub,
	lug: lug,
	lui: lui,
	lun: lun,
	luo: luo,
	lus: lus,
	mac: mac,
	mad: mad,
	mag: mag,
	mah: mah,
	mai: mai,
	mak: mak,
	mal: mal,
	man: man,
	mao: mao,
	map: map,
	mar: mar,
	mas: mas,
	may: may,
	mdf: mdf,
	mdr: mdr,
	men: men,
	mga: mga,
	mic: mic,
	min: min,
	mis: mis,
	mkh: mkh,
	mlg: mlg,
	mlt: mlt,
	mnc: mnc,
	mni: mni,
	mno: mno,
	moh: moh,
	mon: mon,
	mos: mos,
	mul: mul,
	mun: mun,
	mus: mus,
	mwl: mwl,
	mwr: mwr,
	myn: myn,
	myv: myv,
	nah: nah,
	nai: nai,
	nap: nap,
	nau: nau,
	nav: nav,
	nbl: nbl,
	nde: nde,
	ndo: ndo,
	nds: nds,
	nep: nep,
	"new": "newari",
	nia: nia,
	nic: nic,
	niu: niu,
	nno: nno,
	nob: nob,
	nog: nog,
	non: non,
	nor: nor,
	nqo: nqo,
	nso: nso,
	nub: nub,
	nwc: nwc,
	nya: nya,
	nym: nym,
	nyn: nyn,
	nyo: nyo,
	nzi: nzi,
	oci: oci,
	oji: oji,
	ori: ori,
	orm: orm,
	osa: osa,
	oss: oss,
	ota: ota,
	oto: oto,
	paa: paa,
	pag: pag,
	pal: pal,
	pam: pam,
	pan: pan,
	pap: pap,
	pau: pau,
	peo: peo,
	per: per,
	phi: phi,
	phn: phn,
	pli: pli,
	pol: pol,
	pon: pon,
	por: por,
	pra: pra,
	pro: pro,
	pus: pus,
	que: que,
	raj: raj,
	rap: rap,
	rar: rar,
	roa: roa,
	roh: roh,
	rom: rom,
	rum: rum,
	run: run,
	rup: rup,
	rus: rus,
	sad: sad,
	sag: sag,
	sah: sah,
	sai: sai,
	sal: sal,
	sam: sam,
	san: san,
	sas: sas,
	sat: sat,
	scn: scn,
	sco: sco,
	sel: sel,
	sem: sem,
	sga: sga,
	sgn: sgn,
	shn: shn,
	sid: sid,
	sin: sin,
	sio: sio,
	sit: sit,
	sla: sla,
	slo: slo,
	slv: slv,
	sma: sma,
	sme: sme,
	smi: smi,
	smj: smj,
	smn: smn,
	smo: smo,
	sms: sms,
	sna: sna,
	snd: snd,
	snk: snk,
	sog: sog,
	som: som,
	son: son,
	sot: sot,
	spa: spa,
	srd: srd,
	srn: srn,
	srp: srp,
	srr: srr,
	ssa: ssa,
	ssw: ssw,
	suk: suk,
	sun: sun,
	sus: sus,
	sux: sux,
	swa: swa,
	swe: swe,
	syc: syc,
	syr: syr,
	tah: tah,
	tai: tai,
	tam: tam,
	tat: tat,
	tel: tel,
	tem: tem,
	ter: ter,
	tet: tet,
	tgk: tgk,
	tgl: tgl,
	tha: tha,
	tib: tib,
	tig: tig,
	tir: tir,
	tiv: tiv,
	tkl: tkl,
	tlh: tlh,
	tli: tli,
	tmh: tmh,
	tog: tog,
	ton: ton,
	tpi: tpi,
	tsi: tsi,
	tsn: tsn,
	tso: tso,
	tuk: tuk,
	tum: tum,
	tup: tup,
	tur: tur,
	tut: tut,
	tvl: tvl,
	twi: twi,
	tyv: tyv,
	udm: udm,
	uga: uga,
	uig: uig,
	ukr: ukr,
	umb: umb,
	und: und,
	urd: urd,
	uzb: uzb,
	vai: vai,
	ven: ven,
	vie: vie,
	vol: vol,
	vot: vot,
	wak: wak,
	wal: wal,
	war: war,
	was: was,
	wel: wel,
	wen: wen,
	wln: wln,
	wol: wol,
	xal: xal,
	xho: xho,
	yao: yao,
	yap: yap,
	yid: yid,
	yor: yor,
	ypk: ypk,
	zap: zap,
	zbl: zbl,
	zen: zen,
	zha: zha,
	znd: znd,
	zul: zul,
	zun: zun,
	zxx: zxx,
	zza: zza
};

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class TranslateLanguageService {
    constructor() {
        this.translateService = inject(TranslateService);
        // Available languages (import)
        this._availableLanguages = { de: de$5, en: en$5, fr: fr$5, it: it$5 };
    }
    // List of preferred languages
    static { this.PREFERRED_LANGUAGES = ['eng', 'fre', 'ger', 'ita']; }
    /**
     * @param langCode - ISO 639-2 (3 characters)
     * @param language - ISO 639-1 (2 characters)
     * @return human language - string
     */
    translate(langCode, language) {
        const lang = language || this.translateService.currentLang;
        if (!(lang in this._availableLanguages)) {
            return langCode;
        }
        if (!(langCode in this._availableLanguages[lang])) {
            return langCode;
        }
        return this._availableLanguages[lang][langCode];
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLanguageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLanguageService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLanguageService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class TranslateLanguagePipe {
    constructor() {
        this.translateLanguage = inject(TranslateLanguageService);
    }
    /**
     * transform language code to human language
     * @param langCode - ISO 639-2 (3 characters)
     * @param language - ISO 639-1 (2 characters)
     */
    transform(langCode, language) {
        return this.translateLanguage.translate(langCode, language);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLanguagePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: TranslateLanguagePipe, isStandalone: false, name: "translateLanguage" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLanguagePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'translateLanguage',
                    standalone: false
                }]
        }] });

var Add$3 = "Hinzufügen";
var Apply$3 = "Anwenden";
var Back$3 = "Zurück";
var Cancel$3 = "Abbrechen";
var Clear$3 = "Leeren";
var Confirmation$3 = "Bestätigung";
var Confirmed$3 = "Bestätigt";
var Delete$3 = "Löschen";
var Edit$3 = "Bearbeiten";
var Forbidden$3 = "Verboten";
var Information$3 = "Information";
var Load$3 = "Laden";
var OK$3 = "OK";
var Quit$3 = "Verlassen";
var Save$3 = "Speichern";
var Show$3 = "Anzeigen";
var Stay$3 = "Bleiben";
var Template$3 = "Vorlage";
var Unauthorized$3 = "Unerlaubt";
var Use$3 = "Verwenden";
var de$3 = "Deutsch";
var en$4 = "Englisch";
var fr$4 = "Französisch";
var it$4 = "Italienisch";
var search$3 = "Suche";
var de$4 = {
	Add: Add$3,
	"Add field": "Feld hinzufügen",
	"An error occurred": "Ein Fehler ist aufgetreten",
	Apply: Apply$3,
	Back: Back$3,
	"Bad request": "Ungültige Anfrage",
	Cancel: Cancel$3,
	"Choose a name for your template": "Einen Namen für die Vorlage wählen",
	Clear: Clear$3,
	Confirmation: Confirmation$3,
	Confirmed: Confirmed$3,
	Delete: Delete$3,
	"Do you really want to delete this record?": "Möchten Sie diesen Datensatz wirklich löschen?",
	"Do you want to quit the page? The changes made so far will be lost.": "Möchten Sie die Seite verlassen? Die bisher vorgenommenen Änderungen gehen verloren.",
	Edit: Edit$3,
	"Edit mode": "Bearbeitungsmodus",
	"Enter a query to get results.": "Geben Sie eine Abfrage ein, um Ergebnisse zu erhalten.",
	"Error": "Fehler",
	"Export as": "Exportieren als",
	"Field(s) in error: ": "Fehlerhafte(s) Feld(er): ",
	Forbidden: Forbidden$3,
	"Generate a new password": "Ein neues Passwort generieren",
	Information: Information$3,
	"Jump to": "Gehe zu",
	"Last month": "Letzten Monat",
	"Last year": "Letztes Jahr",
	Load: Load$3,
	"Load from template": "Eine Vorlage laden",
	"Load template…": "Vorlage laden…",
	"Loading a template will reload the current form. All values previously encoded will be lost.": "Beim Laden einer Vorlage wird das aktuelle Formular neu geladen. Alle zuvor erfassten Werte gehen dabei verloren.",
	"My private templates": "Meine privaten Vorlagen",
	"No result": "Kein Ergebnis",
	"Not found": "Nicht gefunden",
	"Number of chars": "Anzahl der Zeichen",
	"Number of words": "Anzahl der Wörter",
	OK: OK$3,
	"Public templates": "Öffentliche Vorlagen",
	Quit: Quit$3,
	"Quit the page": "Seite verlassen",
	"Record created.": "Ressource erstellt.",
	"Record deleted.": "Datensatz gelöscht.",
	"Record updated.": "Daten aktualisiert.",
	"Result list is empty.": "Die Ergebnisliste ist leer.",
	Save: Save$3,
	"Save as template": "Als Vorlage speichern",
	"Search in": "Suchen in",
	"Select a template": "Eine Vorlage wählen",
	"Select…": "Wählen…",
	"Server error.": "Serverfehler.",
	Show: Show$3,
	"Show or hide password": "Passwort anzeigen oder verbergen",
	"Sort by": "Sortieren nach",
	Stay: Stay$3,
	Template: Template$3,
	"Template loaded": "Vorlage geladen",
	"The form contains errors.": "Das Formular enthält Fehler.",
	"The password has been copied to the clipboard.": "Das Kennwort wurde in die Zwischenablage kopiert.",
	"There are no records in this section": "In diesem Abschnitt gibt es keine Ressourcen",
	"This field is required": "Dieses Feld ist erforderlich",
	"This month": "Diesen Monat",
	"This year": "Dieses Jahr",
	"Too many items. Should be less than {{max}}.": "Zu viele Artikel. Sollte weniger als {{max}} sein.",
	Unauthorized: Unauthorized$3,
	Use: Use$3,
	"Warning!": "Achtung!",
	"You cannot access this page.": "Sie können nicht auf diese Seite zugreifen.",
	"You cannot read this record": "Sie dürfen diesen Datensatz nicht lesen",
	"You cannot update this record": "Sie dürfen diesen Datensatz nicht aktualisieren",
	"between {{min}} and {{max}}": "zwischen {{min}} und {{max}}",
	de: de$3,
	en: en$4,
	fr: fr$4,
	it: it$4,
	"less…": "Weniger…",
	"maximum {{max}}": "maximal {{max}}",
	"minimum {{min}}": "mindestens {{min}}",
	"more…": "Mehr…",
	search: search$3,
	"should NOT be longer than {{maxLength}} characters": "darf nicht länger als {{maxLength}} Zeichen sein",
	"should NOT be shorter than {{minLength}} characters": "darf nicht kürzer als {{minLength}} Zeichen sein",
	"should NOT have duplicate items": "sollte NICHT doppelt vorhanden sein",
	"should NOT have fewer than {{minItems}} items": "muss mindestens {{minItems}} Elemente haben",
	"should NOT have more than {{maxItems}} items": "darf höchstens {{maxItems}} Elemente haben",
	"should be <  {{step}}": "muss kleiner als {{step}} sein",
	"should be <=  {{max}}": "muss grösser oder gleich {{max}} sein",
	"should be >  {{step}}": "muss grösser als {{step}} sein",
	"should be >=  {{min}}": "muss kleiner oder gleich {{min}} sein",
	"should be equal to constant \"{{const}}\"": "muss gleich der Konstante \"{{const}}\" sein",
	"should be multiple of ${{step}}": "muss ein Vielfaches von ${{step}} sein",
	"should be null": "sollte null sein",
	"should have {{counter}} {{keys}}": "muss {{counter}} {{keys}} haben",
	"strictly {{counter}}": "streng {{counter}}",
	"the value is already taken": "der Wert ist bereits vergeben",
	"{{ total }} result": "{{ total }} Ergebnis",
	"{{ total }} results": "{{ total }} Ergebnisse"
};

var Add$2 = "Add";
var Apply$2 = "Apply";
var Back$2 = "Back";
var Cancel$2 = "Cancel";
var Clear$2 = "Clear";
var Confirmation$2 = "Confirmation";
var Confirmed$2 = "Confirmed";
var Delete$2 = "Delete";
var Edit$2 = "Edit";
var Forbidden$2 = "Forbidden";
var Information$2 = "Information";
var Load$2 = "Load";
var OK$2 = "OK";
var Quit$2 = "Quit";
var Save$2 = "Save";
var Show$2 = "Show";
var Stay$2 = "Stay";
var Template$2 = "Template";
var Unauthorized$2 = "Unauthorized";
var Use$2 = "Use";
var de$2 = "German";
var en$2 = "English";
var fr$3 = "French";
var it$3 = "Italian";
var search$2 = "search";
var en$3 = {
	Add: Add$2,
	"Add field": "Add field",
	"An error occurred": "An error occurred",
	Apply: Apply$2,
	Back: Back$2,
	"Bad request": "Bad request",
	Cancel: Cancel$2,
	"Choose a name for your template": "Choose a name for your template",
	Clear: Clear$2,
	Confirmation: Confirmation$2,
	Confirmed: Confirmed$2,
	Delete: Delete$2,
	"Do you really want to delete this record?": "Do you really want to delete this record?",
	"Do you want to quit the page? The changes made so far will be lost.": "Do you want to quit the page? The changes made so far will be lost.",
	Edit: Edit$2,
	"Edit mode": "Edit mode",
	"Enter a query to get results.": "Enter a query to get results.",
	"Error": "Error",
	"Export as": "Export as",
	"Field(s) in error: ": "Field(s) in error: ",
	Forbidden: Forbidden$2,
	"Generate a new password": "Generate a new password",
	Information: Information$2,
	"Jump to": "Jump to",
	"Last month": "Last month",
	"Last year": "Last year",
	Load: Load$2,
	"Load from template": "Load from template",
	"Load template…": "Load template…",
	"Loading a template will reload the current form. All values previously encoded will be lost.": "Loading a template will reload the current form. All values previously encoded will be lost.",
	"My private templates": "My private templates",
	"No result": "No result",
	"Not found": "Not found",
	"Number of chars": "Number of chars",
	"Number of words": "Number of words",
	OK: OK$2,
	"Public templates": "Public templates",
	Quit: Quit$2,
	"Quit the page": "Quit the page",
	"Record created.": "Record created.",
	"Record deleted.": "Record deleted.",
	"Record updated.": "Record updated.",
	"Result list is empty.": "Result list is empty.",
	Save: Save$2,
	"Save as template": "Save as template",
	"Search in": "Search in",
	"Select a template": "Select a template",
	"Select…": "Select…",
	"Server error.": "Server error.",
	Show: Show$2,
	"Show or hide password": "Show or hide password",
	"Sort by": "Sort by",
	Stay: Stay$2,
	Template: Template$2,
	"Template loaded": "Template loaded",
	"The form contains errors.": "The form contains errors.",
	"The password has been copied to the clipboard.": "The password has been copied to the clipboard.",
	"There are no records in this section": "There are no records in this section",
	"This field is required": "This field is required",
	"This month": "This month",
	"This year": "This year",
	"Too many items. Should be less than {{max}}.": "Too many items. Should be less than {{max}}.",
	Unauthorized: Unauthorized$2,
	Use: Use$2,
	"Warning!": "Warning!",
	"You cannot access this page.": "You cannot access this page.",
	"You cannot read this record": "You cannot read this record",
	"You cannot update this record": "You cannot update this record",
	"between {{min}} and {{max}}": "between {{min}} and {{max}}",
	de: de$2,
	en: en$2,
	fr: fr$3,
	it: it$3,
	"less…": "less…",
	"maximum {{max}}": "maximum {{max}}",
	"minimum {{min}}": "minimum {{min}}",
	"more…": "more…",
	search: search$2,
	"should NOT be longer than {{maxLength}} characters": "should NOT be longer than {{maxLength}} characters",
	"should NOT be shorter than {{minLength}} characters": "should NOT be shorter than {{minLength}} characters",
	"should NOT have duplicate items": "should NOT have duplicate items",
	"should NOT have fewer than {{minItems}} items": "should NOT have fewer than {{minItems}} items",
	"should NOT have more than {{maxItems}} items": "should NOT have more than {{maxItems}} items",
	"should be <  {{step}}": "should be < {{step}}",
	"should be <=  {{max}}": "should be <= {{max}}",
	"should be >  {{step}}": "should be > {{step}}",
	"should be >=  {{min}}": "should be >= {{min}}",
	"should be equal to constant \"{{const}}\"": "should be equal to constant \"{{const}}\"",
	"should be multiple of ${{step}}": "should be multiple of ${{step}}",
	"should be null": "should be null",
	"should have {{counter}} {{keys}}": "should have {{counter}} {{keys}}",
	"strictly {{counter}}": "strictly {{counter}}",
	"the value is already taken": "the value is already taken",
	"{{ total }} result": "{{ total }} result",
	"{{ total }} results": "{{ total }} results"
};

var Add$1 = "Ajouter";
var Apply$1 = "Appliquer";
var Back$1 = "Retour";
var Cancel$1 = "Annuler";
var Clear$1 = "Effacer";
var Confirmation$1 = "Confirmation";
var Confirmed$1 = "Confirmé";
var Delete$1 = "Supprimer";
var Edit$1 = "Modifier";
var Forbidden$1 = "Interdit";
var Information$1 = "Information";
var Load$1 = "Charger";
var OK$1 = "OK";
var Quit$1 = "Quitter";
var Save$1 = "Enregistrer";
var Show$1 = "Afficher";
var Stay$1 = "Rester";
var Template$1 = "Modèle";
var Unauthorized$1 = "Non autorisé";
var Use$1 = "Utiliser";
var de$1 = "Allemand";
var en$1 = "Anglais";
var fr$1 = "Français";
var it$2 = "Italien";
var search$1 = "recherche";
var fr$2 = {
	Add: Add$1,
	"Add field": "Ajouter un champ",
	"An error occurred": "Une erreur est survenue",
	Apply: Apply$1,
	Back: Back$1,
	"Bad request": "Requête invalide",
	Cancel: Cancel$1,
	"Choose a name for your template": "Choisir un nom pour votre modèle",
	Clear: Clear$1,
	Confirmation: Confirmation$1,
	Confirmed: Confirmed$1,
	Delete: Delete$1,
	"Do you really want to delete this record?": "Voulez-vous vraiment supprimer cet enregistrement ?",
	"Do you want to quit the page? The changes made so far will be lost.": "Voulez-vous quitter la page ? Les modifications seront perdues.",
	Edit: Edit$1,
	"Edit mode": "Mode édition",
	"Enter a query to get results.": "Entrer une requête pour obtenir des résultats.",
	"Error": "Erreur",
	"Export as": "Exporter en",
	"Field(s) in error: ": "Champ(s) en erreur : ",
	Forbidden: Forbidden$1,
	"Generate a new password": "Générer un nouveau mot de passe",
	Information: Information$1,
	"Jump to": "Aller à",
	"Last month": "Le mois dernier",
	"Last year": "L'année dernière",
	Load: Load$1,
	"Load from template": "Charger un modèle",
	"Load template…": "Charger le modèle…",
	"Loading a template will reload the current form. All values previously encoded will be lost.": "Le chargement d'un modèle va recharger le formulaire actuel. Toutes les valeurs saisies jusqu'à maintenant seront perdues.",
	"My private templates": "Mes modèles privés",
	"No result": "Aucun résultat",
	"Not found": "Non trouvé",
	"Number of chars": "Nombre de caractères",
	"Number of words": "Nombre de mots",
	OK: OK$1,
	"Public templates": "Modèles publics",
	Quit: Quit$1,
	"Quit the page": "Quitter la page",
	"Record created.": "Ressource créée.",
	"Record deleted.": "Ressource effacée.",
	"Record updated.": "Ressource mise à jour.",
	"Result list is empty.": "La liste de résultat est vide.",
	Save: Save$1,
	"Save as template": "Enregistrer en tant que modèle",
	"Search in": "Chercher dans",
	"Select a template": "Sélectionner un modèle",
	"Select…": "Sélectionner…",
	"Server error.": "Erreur serveur.",
	Show: Show$1,
	"Show or hide password": "Afficher/masquer le mot de passe",
	"Sort by": "Trier par",
	Stay: Stay$1,
	Template: Template$1,
	"Template loaded": "Modèle chargé",
	"The form contains errors.": "Le formulaire contient des erreurs.",
	"The password has been copied to the clipboard.": "Le mot de passe a été copié dans le presse-papiers.",
	"There are no records in this section": "Il n'y a pas de ressources dans cette section",
	"This field is required": "Ce champ est obligatoire",
	"This month": "Ce mois-ci",
	"This year": "Cette année",
	"Too many items. Should be less than {{max}}.": "Trop d'éléments. Le total doit être inférieur à {{max}}.",
	Unauthorized: Unauthorized$1,
	Use: Use$1,
	"Warning!": "Attention !",
	"You cannot access this page.": "Vous ne pouvez pas accéder à cette page.",
	"You cannot read this record": "Vous n'avez pas les permissions nécessaires pour afficher cette ressource",
	"You cannot update this record": "Vous n'avez pas les permissions nécessaires pour modifier cette ressource",
	"between {{min}} and {{max}}": "entre {{min}} et {{max}}",
	de: de$1,
	en: en$1,
	fr: fr$1,
	it: it$2,
	"less…": "moins…",
	"maximum {{max}}": "maximum {{max}}",
	"minimum {{min}}": "minimum {{min}}",
	"more…": "plus…",
	search: search$1,
	"should NOT be longer than {{maxLength}} characters": "Ne doit pas être plus long que {{maxLength}} caractères",
	"should NOT be shorter than {{minLength}} characters": "Ne doit pas être plus court que {{minLength}} caractères",
	"should NOT have duplicate items": "Deux éléments identiques ne sont pas autorisés",
	"should NOT have fewer than {{minItems}} items": "Doit contenir au moins {{minItems}} éléments",
	"should NOT have more than {{maxItems}} items": "Doit contenir au maximum {{maxItems}} éléments",
	"should be <  {{step}}": "Doit être plus petit que {{step}}",
	"should be <=  {{max}}": "Doit être plus petit ou égal à  {{max}}",
	"should be >  {{step}}": "Doit être plus grand que  {{step}}",
	"should be >=  {{min}}": "Doit être plus grand ou égal à  {{min}}",
	"should be equal to constant \"{{const}}\"": "Doit être égal à la constante \"{{const}}\"",
	"should be multiple of ${{step}}": "Doit être un multiple de ${{step}}",
	"should be null": "doit être vide",
	"should have {{counter}} {{keys}}": "doit contenir {{counter}} {{keys}}",
	"strictly {{counter}}": "strictement {{counter}}",
	"the value is already taken": "cette valeur est déjà utilisée",
	"{{ total }} result": "{{ total }} résultat",
	"{{ total }} results": "{{ total }} résultats"
};

var Add = "Aggiungere";
var Apply = "Applicare";
var Back = "Indietro";
var Cancel = "Annullare";
var Clear = "Cancellare";
var Confirmation = "Conferma";
var Confirmed = "Confermato";
var Delete = "Eliminare";
var Edit = "Modificare";
var Forbidden = "Vietato";
var Information = "Informazione";
var Load = "Caricare";
var OK = "OK";
var Quit = "Uscire";
var Save = "Salvare";
var Show = "Mostrare";
var Stay = "Rimanere";
var Template = "Modello";
var Unauthorized = "Non autorizzato";
var Use = "Utilizzare";
var de = "Tedesco";
var en = "Inglese";
var fr = "Francese";
var it = "Italiano";
var search = "ricerca";
var it$1 = {
	Add: Add,
	"Add field": "Aggiungere un campo",
	"An error occurred": "Si è verificato un errore",
	Apply: Apply,
	Back: Back,
	"Bad request": "Richiesta non valida",
	Cancel: Cancel,
	"Choose a name for your template": "Scegliere un nome per il modello",
	Clear: Clear,
	Confirmation: Confirmation,
	Confirmed: Confirmed,
	Delete: Delete,
	"Do you really want to delete this record?": "Si desidera veramente eliminare questa risorsa?",
	"Do you want to quit the page? The changes made so far will be lost.": "Vuoi uscire dalla pagina? Le modifiche fatte finora andranno perse.",
	Edit: Edit,
	"Edit mode": "Modalità di modifica",
	"Enter a query to get results.": "Inserisci una richiesta per ottenere dei risultati.",
	"Error": "Errore",
	"Export as": "Esportare in",
	"Field(s) in error: ": "Campo/i in errore: ",
	Forbidden: Forbidden,
	"Generate a new password": "Generare una nuova password",
	Information: Information,
	"Jump to": "Andare a",
	"Last month": "Ultimo mese",
	"Last year": "Ultimo anno",
	Load: Load,
	"Load from template": "Caricare un modello",
	"Load template…": "Caricare modello…",
	"Loading a template will reload the current form. All values previously encoded will be lost.": "Il caricamento di un modello ricaricherà il modulo corrente. Tutti i valori precedentemente inseriti andranno persi.",
	"My private templates": "I miei modelli privati",
	"No result": "Nessun risultato",
	"Not found": "Non trovato",
	"Number of chars": "Numero di caratteri",
	"Number of words": "Numero di parole",
	OK: OK,
	"Public templates": "Modelli pubblici",
	Quit: Quit,
	"Quit the page": "Uscire dalla pagina",
	"Record created.": "Record creato.",
	"Record deleted.": "Record eliminato.",
	"Record updated.": "Record aggiornato.",
	"Result list is empty.": "L'elenco dei risultati è vuoto.",
	Save: Save,
	"Save as template": "Salvare come modello",
	"Search in": "Cercare in",
	"Select a template": "Selezionare un modello",
	"Select…": "Selezionare…",
	"Server error.": "Errore del server.",
	Show: Show,
	"Show or hide password": "Mostra o nascondi la password",
	"Sort by": "Ordina per",
	Stay: Stay,
	Template: Template,
	"Template loaded": "Modello caricato",
	"The form contains errors.": "Il modulo contiene errori.",
	"The password has been copied to the clipboard.": "La password è stata copiata negli appunti.",
	"There are no records in this section": "Non ci sono risorse in questa sezione",
	"This field is required": "Questo campo è obbligatorio",
	"This month": "Questo mese",
	"This year": "Quest'anno",
	"Too many items. Should be less than {{max}}.": "Troppi elementi. Dovrebbe essere meno di {{max}}.",
	Unauthorized: Unauthorized,
	Use: Use,
	"Warning!": "Attenzione!",
	"You cannot access this page.": "Non è possibile accedere a questa pagina.",
	"You cannot read this record": "Lei non ha autorizzazioni sufficienti per vedere questa risorsa",
	"You cannot update this record": "Non è abilitato a modificare questo record",
	"between {{min}} and {{max}}": "tra {{min}} e {{max}}",
	de: de,
	en: en,
	fr: fr,
	it: it,
	"less…": "Meno…",
	"maximum {{max}}": "massimo {{max}}",
	"minimum {{min}}": "minimo {{min}}",
	"more…": "Più…",
	search: search,
	"should NOT be longer than {{maxLength}} characters": "Non deve essere più lungo di {{maxLength}} caratteri",
	"should NOT be shorter than {{minLength}} characters": "Non deve avere meno di {{minLength}} caratteri",
	"should NOT have duplicate items": "NON deve presentare due elementi identici",
	"should NOT have fewer than {{minItems}} items": "NON deve avere meno di {{minItems}} esemplari",
	"should NOT have more than {{maxItems}} items": "NON deve avere più di {{maxItems}} esemplari",
	"should be <  {{step}}": "Deve essere inferiore a  {{step}}",
	"should be <=  {{max}}": "Deve essere inferiore o uguale a {{max}}",
	"should be >  {{step}}": "Deve essere maggiore a >  {{step}}",
	"should be >=  {{min}}": "Deve essere maggiore o uguale a {{min}}",
	"should be equal to constant \"{{const}}\"": "Deve essere uguale alla costante \"{{const}}\"",
	"should be multiple of ${{step}}": "Deve essere un multiplo di ${{step}}",
	"should be null": "Deve essere vuoto",
	"should have {{counter}} {{keys}}": "deve avere {{counter}} {{keys}}",
	"strictly {{counter}}": "rigorosamente {{counter}}",
	"the value is already taken": "Il valore è già utilizzato",
	"{{ total }} result": "{{ total }} risultato",
	"{{ total }} results": "{{ total }} risultati"
};

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Loader for translations used in ngx-translate library.
 */
class TranslateLoader {
    constructor() {
        this.coreConfigService = inject(CoreConfigService);
        this.http = inject(HttpClient);
        // translations
        this.translations = {};
        // locale translations
        // with angular<9 assets are not available for libraries
        // See: https://angular.io/guide/creating-libraries#managing-assets-in-a-library
        this.coreTranslations = { de: de$4, en: en$3, fr: fr$2, it: it$1 };
    }
    /**
     * Return observable used by ngx-translate to get translations.
     * @param lang - string, language to retrieve translations from.
     */
    getTranslation(lang) {
        // Already in cache
        if (this.translations[lang] != null) {
            return of(this.translations[lang]);
        }
        const urls = this.coreConfigService.translationsURLs;
        // create the list of http requests
        const observers = urls.map(url => {
            const langURL = url.replace('${lang}', lang);
            return this.http.get(langURL).pipe(catchError(() => {
                console.log(`ERROR: Cannot load translation: ${langURL}`);
                return of([]);
            }));
        });
        // Get local and backend translations
        return forkJoin(observers).pipe(map$4((translations) => {
            // copy local translations
            if (this.coreTranslations[lang] != null) {
                this.translations[lang] = { ...this.coreTranslations[lang] };
            }
            // get remote translations
            translations.map(trans => this.translations[lang] = {
                ...this.translations[lang],
                ...trans
            });
            return this.translations[lang];
        }));
    }
}

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class NgCoreTranslateService extends TranslateService {
    constructor() {
        super(...arguments);
        this.primeNG = inject(PrimeNG);
        this.coreConfigService = inject(CoreConfigService);
        this.locales = {
            de: { angular: localeDe, primeng: de$6 },
            en: { angular: localeEn, primeng: en$6 },
            fr: { angular: localeFr, primeng: fr$6 },
            it: { angular: localeIt, primeng: it$6 }
        };
    }
    initialize() {
        for (const [key, value] of Object.entries(this.locales)) {
            registerLocaleData(value.angular, key);
        }
        const languages = this.coreConfigService.languages;
        super.addLangs(languages);
        super.onLangChange.subscribe(translation => {
            this.use(translation.lang);
        });
        super.setDefaultLang(this.coreConfigService.defaultLanguage);
        if (!super.currentLang) {
            super.use(this.coreConfigService.defaultLanguage);
        }
    }
    use(lang) {
        DateTime.locale = lang;
        this.primeNG.setTranslation(this.locales[lang].primeng[lang]);
        return super.use(lang);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreTranslateService, deps: null, target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreTranslateService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreTranslateService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class CoreModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CoreModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: CoreModule, declarations: [Nl2brPipe,
            DefaultPipe,
            TruncateTextPipe,
            UpperCaseFirstPipe,
            CallbackArrayFilterPipe,
            DateTranslatePipe,
            DialogComponent,
            SearchInputComponent,
            TranslateLanguagePipe,
            TextReadMoreComponent,
            SortByKeysPipe,
            ErrorComponent,
            FilesizePipe,
            MarkdownPipe,
            SanitizePipe], imports: [CommonModule,
            RouterModule, i5.TranslateModule, NgxSpinnerModule,
            PrimeNgCoreModule], exports: [PrimeNgCoreModule,
            CommonModule,
            TranslateModule,
            Nl2brPipe,
            DefaultPipe,
            TruncateTextPipe,
            TranslateLanguagePipe,
            UpperCaseFirstPipe,
            CallbackArrayFilterPipe,
            DateTranslatePipe,
            FilesizePipe,
            DialogComponent,
            SearchInputComponent,
            TextReadMoreComponent,
            ErrorComponent,
            SortByKeysPipe,
            NgxSpinnerModule,
            MarkdownPipe,
            SanitizePipe] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CoreModule, providers: [
            provideAppInitializer(() => {
                const translateService = inject(NgCoreTranslateService);
                translateService.initialize();
                return of(true);
            }),
            { provide: TranslateService, useClass: NgCoreTranslateService },
            { provide: TitleStrategy, useClass: PageTitleStrategy },
            ComponentCanDeactivateGuard,
            ConfirmationService,
            MessageService,
            SanitizePipe
        ], imports: [CommonModule,
            RouterModule,
            TranslateModule.forChild({
                loader: {
                    provide: TranslateLoader$1,
                    useClass: TranslateLoader,
                    deps: [CoreConfigService, HttpClient]
                }
            }),
            NgxSpinnerModule,
            PrimeNgCoreModule, PrimeNgCoreModule,
            CommonModule,
            TranslateModule,
            NgxSpinnerModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CoreModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        Nl2brPipe,
                        DefaultPipe,
                        TruncateTextPipe,
                        UpperCaseFirstPipe,
                        CallbackArrayFilterPipe,
                        DateTranslatePipe,
                        DialogComponent,
                        SearchInputComponent,
                        TranslateLanguagePipe,
                        TextReadMoreComponent,
                        SortByKeysPipe,
                        ErrorComponent,
                        FilesizePipe,
                        MarkdownPipe,
                        SanitizePipe
                    ],
                    imports: [
                        CommonModule,
                        RouterModule,
                        TranslateModule.forChild({
                            loader: {
                                provide: TranslateLoader$1,
                                useClass: TranslateLoader,
                                deps: [CoreConfigService, HttpClient]
                            }
                        }),
                        NgxSpinnerModule,
                        PrimeNgCoreModule
                    ],
                    exports: [
                        PrimeNgCoreModule,
                        CommonModule,
                        TranslateModule,
                        Nl2brPipe,
                        DefaultPipe,
                        TruncateTextPipe,
                        TranslateLanguagePipe,
                        UpperCaseFirstPipe,
                        CallbackArrayFilterPipe,
                        DateTranslatePipe,
                        FilesizePipe,
                        DialogComponent,
                        SearchInputComponent,
                        TextReadMoreComponent,
                        ErrorComponent,
                        SortByKeysPipe,
                        NgxSpinnerModule,
                        MarkdownPipe,
                        SanitizePipe
                    ],
                    providers: [
                        provideAppInitializer(() => {
                            const translateService = inject(NgCoreTranslateService);
                            translateService.initialize();
                            return of(true);
                        }),
                        { provide: TranslateService, useClass: NgCoreTranslateService },
                        { provide: TitleStrategy, useClass: PageTitleStrategy },
                        ComponentCanDeactivateGuard,
                        ConfirmationService,
                        MessageService,
                        SanitizePipe
                    ]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Initialize the Formly widget on JSONSchema
 * @param schema - object, the JSONSchema
 */
function createWidgetFormlyConfigProps(schema) {
    if (!schema.widget) {
        schema.widget = {};
    }
    if (!schema.widget.formlyConfig) {
        schema.widget.formlyConfig = {};
    }
    if (!schema.widget.formlyConfig.props) {
        schema.widget.formlyConfig.props = {};
    }
}
/**
 * Resolve $ref definition and set properties on field
 * @param schema - json schema all properties
 * @param schemaProperties - json schema level
 * @returns the updated schema
 */
function resolve$ref(schema, schemaProperties) {
    if (schemaProperties) {
        Object.keys(schemaProperties).forEach((property) => {
            let field = schemaProperties[property];
            if (field.properties) {
                resolve$ref(schema, field.properties);
            }
            // The field contains a $ref definition
            if (field.$ref) {
                const paths = field.$ref.replace('#/', '').split('/');
                let def = schema;
                paths.forEach((path) => {
                    def = def[path];
                });
                // Populate field with new definition
                Object.keys(def).forEach((defKey) => {
                    if (defKey === 'widget' && def[defKey].formlyConfig?.templateOptions) {
                        def[defKey].formlyConfig.props = def[defKey].formlyConfig.templateOptions;
                        delete def[defKey].formlyConfig.templateOptions;
                    }
                    field[defKey] = def[defKey];
                });
                // Delete reference
                delete field.$ref;
            }
        });
    }
    return schema;
}
/**
 * Process required properties on the JSONSchema.
 * @param schema - object, the JSONSchema
 * @returns object, a processed required properties JSONSchema
 */
function processRequiredJsonSchema(schema) {
    schema.required.map((key) => {
        const childSchema = schema.properties[key];
        if (childSchema) {
            createWidgetFormlyConfigProps(childSchema);
            childSchema.widget.formlyConfig.props.initialRequired = true;
        }
    });
    return schema;
}
/**
 * Process order properties on the JSONSchema
 * @param schema - object, the JSONSchema
 * @returns object, a processed order properties JSONSchema
 */
function processPropertiesOder(schema) {
    // copy the data
    schema._properties = { ...schema.properties };
    // new ordered properties
    schema.properties = {};
    // copy in the right order
    for (const property of schema.propertiesOrder) {
        schema.properties[property] = schema._properties[property];
    }
    return schema;
}
/**
 * Process JSONSchema
 * This re-order the object properties given a local defined
 * `propertiesOrder` property.
 * The process the required properties given a local defined
 * `required` property.
 * @param schema - object, the JSONSchema
 * @returns object, a converted JSONSchema
 */
function processJsonSchema(schema) {
    if (schema.properties) {
        if (schema.propertiesOrder) {
            schema = processPropertiesOder(schema);
        }
        if (schema.required) {
            schema = processRequiredJsonSchema(schema);
        }
        // recursion for objects
        for (const property of Object.keys(schema.properties)) {
            processJsonSchema(schema.properties[property]);
        }
    }
    // recursion for array
    if (schema.items) {
        processJsonSchema(schema.items);
    }
    // recursion for oneOf
    if (schema.oneOf) {
        for (const item of schema.oneOf) {
            processJsonSchema(item);
        }
    }
    // recursion for anyOf
    if (schema.anyOf) {
        for (const item of schema.anyOf) {
            processJsonSchema(item);
        }
    }
    // recursion for allOf
    if (schema.allOf) {
        for (const item of schema.allOf) {
            processJsonSchema(item);
        }
    }
    // recursion for definitions
    if (schema.definitions) {
        for (const property of Object.keys(schema.definitions)) {
            processJsonSchema(schema.definitions[property]);
        }
    }
    return schema;
}
/**
 * Replace $ref by pid
 *
 * @param schema - object, the JSONSchema
 * @param data - object, the data to be cleaned
 * @returns object, a fresh copy of the data with replacements
 */
function resolveRefs(data) {
    // array?
    if (data instanceof Array) {
        for (const d of data) {
            // recursion
            const value = resolveRefs(d);
        }
    }
    // object
    if (data instanceof Object) {
        // new object with resolved refs
        const newObject = {};
        for (const key of Object.keys(data)) {
            const value = resolveRefs(data[key]);
            if (key === '$ref') {
                newObject.pid = extractIdOnRef(value);
            }
            else {
                newObject[key] = value;
            }
        }
        return newObject;
    }
    return data;
}
/**
 * Tell if a value can be considered as empty
 * @param value - any, the value to check
 * @returns boolean, true if the value is empty
 */
function isEmpty(value) {
    return (
    // null or undefined
    value == null ||
        // has length and it's zero (array, string)
        (value.hasOwnProperty('length') && value.length === 0) ||
        // is an Object and has no keys
        (value instanceof Object && Object.keys(value).length === 0));
}
/**
 * Recursively remove the empty values
 * @param data - object, the data to be cleaned
 * @returns object, a fresh copy of the clean data
 */
function removeEmptyValues(data) {
    // array?
    if (data instanceof Array) {
        // new array with non empty values
        const newArray = [];
        for (const d of data) {
            // recursion
            const value = removeEmptyValues(d);
            if (!isEmpty(value)) {
                newArray.push(value);
            }
        }
        return newArray;
    }
    // object?
    if (data instanceof Object) {
        // new object with non empty values
        const newObject = {};
        for (const key of Object.keys(data)) {
            const value = removeEmptyValues(data[key]);
            if (!isEmpty(value)) {
                newObject[key] = value;
            }
        }
        return newObject;
    }
    return data;
}

class RecordHandleErrorService {
    constructor() {
        this.translateService = inject(TranslateService);
    }
    /**
     * handle http error
     * @param error - HttpErrorResponse
     * @returns Observable
     */
    handleError(error, resourceName) {
        return this.standardHandleError(error);
    }
    /**
     * Standard handle error (base error)
     * @param error - HttpErrorResponse
     * @returns Observable
     */
    standardHandleError(error) {
        // handle Marshmallow errors
        //   Python marshmallow library can raise ValidationError. In this case, the message is simply 'Validation error'
        //   but list of errors are passed into the `errors` fields.
        if (error.error?.errors) {
            const message = typeof (error.error.errors) === 'object'
                ? error.error.errors.message
                : error.error.errors
                    .map(err => this.translateService.instant(err.message))
                    .join('; ');
            return throwError(() => ({ status: error.status, title: message }));
        }
        // check if we have possible custom error message to display
        if (error.status === 400 && error.error.hasOwnProperty('message')) {
            let { message } = error.error;
            message = message.replace(/^Validation error: /, '').trim(); // Remove Invenio `ValidationError` header
            return throwError(() => ({ status: error.status, title: this.translateService.instant(message) }));
        }
        // If not, then return default message
        switch (error.status) {
            case 400:
                return throwError(() => ({ status: error.status, title: this.translateService.instant('Bad request') }));
            case 401:
                return throwError(() => ({ status: error.status, title: this.translateService.instant('Unauthorized') }));
            case 403:
                return throwError(() => ({ status: error.status, title: this.translateService.instant('Forbidden') }));
            case 404:
                return throwError(() => ({ status: error.status, title: this.translateService.instant('Not found') }));
            default:
                return throwError(() => ({ status: 500, title: this.translateService.instant('An error occurred') }));
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordHandleErrorService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordHandleErrorService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordHandleErrorService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordService {
    constructor() {
        this.http = inject(HttpClient);
        this.apiService = inject(ApiService);
        this.translateService = inject(TranslateService);
        this.recordHandleErrorService = inject(RecordHandleErrorService);
        /**
         * Event for record created
         */
        this.onCreate = new Subject();
        /**
         * Event for record updated
         */
        this.onUpdate = new Subject();
        /**
         * Event for record deleted
         */
        this.onDelete = new Subject();
    }
    static { this.DEFAULT_REST_RESULTS_SIZE = 10; }
    static { this.MAX_REST_RESULTS_SIZE = 9999; }
    /**
     * On create observable
     * @return onCreate Subject
     */
    get onCreate$() {
        return this.onCreate.asObservable();
    }
    /**
     * On update observable
     * @return onUpdate Subject
     */
    get onUpdate$() {
        return this.onUpdate.asObservable();
    }
    /**
     * On delete observable
     * @return onDelete Subject
     */
    get onDelete$() {
        return this.onDelete.asObservable();
    }
    /**
     * Get records filtered by given parameters.
     *
     * @param type - string, type of resource
     * @param query - string, keyword to search for
     * @param page - number, return records corresponding to this page
     * @param itemsPerPage - number, number of records to return
     * @param aggregationsFilters - list, option list of filters; usually used by
     *                              the aggregation filters.
     * @param preFilters - object, option list of additional filters.  The value can
     *                     a string or a list of string to filter with multiple values.
     * @param headers - HttpHeaders optional http header for the backend call.
     * @param sort - parameter for sorting records (eg. 'mostrecent' or '-mostrecent')
     * @param facets - list of strings, define which aggregations/facets should be included into the response.
     */
    getRecords(type, query = '', page = 1, itemsPerPage = RecordService.DEFAULT_REST_RESULTS_SIZE, aggregationsFilters = [], preFilters = {}, headers = null, sort = null, facets = []) {
        // Build query string
        let httpParams = new HttpParams().set('q', query);
        httpParams = httpParams.append('page', '' + page);
        httpParams = httpParams.append('size', '' + itemsPerPage);
        if (sort) {
            httpParams = httpParams.append('sort', sort);
        }
        // aggregationsFilters
        aggregationsFilters.map((filter) => {
            filter.values.map((value) => {
                httpParams = httpParams.append(filter.key, value);
            });
        });
        // preFilters
        for (const key of Object.keys(preFilters)) {
            const value = preFilters[key];
            if (Array.isArray(value)) {
                value.map((val) => {
                    httpParams = httpParams.append(key, val);
                });
            }
            else {
                httpParams = httpParams.append(key, value);
            }
        }
        // facets management
        //   if array `facets` is an empty array, no aggregations data will be included into response.s
        httpParams = httpParams.append('facets', facets.join(','));
        // http request with headers
        return this.http
            .get(this.apiService.getEndpointByType(type, true) + '/', {
            params: httpParams,
            headers: this._createRequestHeaders(headers),
        })
            .pipe(catchError((error) => this._handleError(error, type)));
    }
    /**
     * Delete a record.
     * @param type - string, type of record
     * @param pid - string, PID to remove
     */
    delete(type, pid) {
        return this.http
            .delete(this.apiService.getEndpointByType(type, true) + '/' + pid)
            .pipe(catchError((error) => this._handleError(error, type)), tap(() => this.onDelete.next(this._createEvent(type, { pid }))));
    }
    /**
     * Get record data
     * @param type - string, type of resource
     * @param pid - string, record PID
     */
    getRecord(type, pid, resolve = 0, headers = {}) {
        return this.http
            .get(`${this.apiService.getEndpointByType(type, true)}/${pid}?resolve=${resolve}`, {
            headers: this._createRequestHeaders(headers),
        })
            .pipe(catchError((error) => this._handleError(error, type)));
    }
    /**
     * Return the schema form to generate the form based on the resource given.
     * @param recordType - string, type of the resource
     */
    getSchemaForm(recordType) {
        let recType = recordType.replace(/ies$/, 'y');
        recType = recType.replace(/s$/, '');
        const url = this.apiService.getSchemaFormEndpoint(recordType, true);
        return this.http.get(url).pipe(catchError((e) => {
            if (e.status === 404) {
                return of(null);
            }
        }), map$4((data) => {
            return data;
        }));
    }
    /**
     * Create a new record
     * @param recordType - string, type of resource
     * @param record - object, record to create
     */
    create(recordType, record) {
        return this.http
            .post(this.apiService.getEndpointByType(recordType, true) + '/', record)
            .pipe(catchError((error) => this._handleError(error, recordType)), tap(() => this.onCreate.next(this._createEvent(recordType, { record }))));
    }
    /**
     * Update a record
     * @param recordType - string, type of resource
     * @param pid - string, record PID
     * @param record - object, record to update
     */
    update(recordType, pid, record) {
        const url = `${this.apiService.getEndpointByType(recordType, true)}/${pid}`;
        return this.http
            .put(url, record)
            .pipe(catchError((error) => this._handleError(error, recordType)), tap(() => this.onUpdate.next(this._createEvent(recordType, { record }))));
    }
    /**
     * Check if a record is already registered with the same value
     * @param recordType - string, type of record
     * @param field - string, field to check
     * @param value - string, value to check
     * @param excludePid - string, PID to ignore (normally the current record we are checking)
     */
    valueAlreadyExists(recordType, field, value, excludePid) {
        value = value.replace(/\"/g, '\\"');
        let query = `${field}:"${value}"`;
        if (excludePid) {
            query += ` NOT pid:${excludePid}`;
        }
        return this.getRecords(recordType, query, 1, 1).pipe(map$4((res) => this.totalHits(res.hits.total)), map$4((total) => (total ? { alreadyTaken: value } : null)), debounceTime(1000));
    }
    /**
     * Check if a record is already registered with the same value
     * @param field - FormlyFieldConfig, field to check
     * @param recordType - string, type of record
     * @param excludePid - string, PID to ignore (normally the current record we are checking)
     * @param term - string, the elasticsearch term to check the uniqueness, use field.key if not given
     * @param limitToValues - string[], limit the test to a given list of values
     * @param filter - string, additional es query filters
     */
    uniqueValue(field, recordType, excludePid = null, term = null, limitToValues = [], filter = null) {
        let key = field.key;
        if (term != null) {
            key = term;
        }
        let value = field.formControl.value;
        const model = resolveRefs(field.model);
        if (value == null) {
            return of(true);
        }
        if (typeof (value) === 'string') {
            value = value.replace(/\"/g, '\\"');
        }
        if (limitToValues.length > 0 && !limitToValues.some((v) => v === value)) {
            return of(true);
        }
        let query = `${key}:${value}`;
        if (typeof value === 'string') {
            query = `${key}:"${value}"`;
        }
        if (filter) {
            const filterFn = Function('model', `return ${filter};`);
            query = `${query} AND ` + filterFn(model);
        }
        if (excludePid) {
            query += ` NOT pid:${excludePid}`;
        }
        return this.getRecords(recordType, query, 1, 1).pipe(map$4((res) => this.totalHits(res.hits.total)), map$4((total) => (total ? { alreadyTaken: value } : null)), debounceTime(500));
    }
    /**
     * Transform a total value string or object representation
     * (ES compatibility v6 and v7)
     * @param total - string or object
     * @param relation - boolean
     * @return integer, text or null
     */
    totalHits(total, relation = false) {
        switch (typeof total) {
            case 'object':
                if (relation) {
                    return `${this.translateService.instant(total.relation)} ${total.value.toString()}`;
                }
                return Number(total.value);
            case 'number':
                return total;
            case 'string':
                return Number(total);
            default:
                return null;
        }
    }
    /**
     * Return the suggestions for query and field.
     *
     * @param resource Resource type.
     * @param url URL of suggestions endpoint.
     * @param field Field to search for suggestions.
     * @param q Query.
     * @returns Observable containing the list of suggestions.
     */
    suggestions(resource, url, field, q) {
        return this.http.get(`${this.apiService.baseUrl}${url}`, {
            params: { resource, field, q },
        });
    }
    /**
     * Error handling during api call process.
     * @param error - HttpErrorResponse
     * @param resourceName- Name of current resource
     * @return throwError
     */
    _handleError(error, resourceName) {
        return this.recordHandleErrorService.handleError(error, resourceName);
    }
    /**
     * Creates and returns a HttpHeader object to send to request.
     * @param headers Object containing http headers to send to request.
     */
    _createRequestHeaders(headers = {}) {
        return headers
            ? new HttpHeaders(headers)
            : new HttpHeaders({ 'Content-Type': 'application/json' });
    }
    /**
     * Create a message for event
     * @param resource - string
     * @param data - any
     */
    _createEvent(resource, data) {
        return { resource, data };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Get a record by its PID.
 */
class GetRecordPipe {
    constructor() {
        this.recordService = inject(RecordService);
    }
    /**
     * Return record data corresponding to PID.
     *
     * @param pid Record PID.
     * @param type Type of the resource.
     * @param returnType Type of data to return.
     * @param field Field to return.
     * @return Record or field record corresponding to PID.
     */
    transform(pid, type, returnType = 'object', field, headers) {
        // process $ref entrypoint
        if (pid.startsWith('http')) {
            pid = extractIdOnRef(pid);
        }
        if ('object' !== returnType) {
            returnType = 'field';
        }
        return this.recordService.getRecord(type, pid, 1, headers).pipe(map$4(data => {
            if (!data) {
                return null;
            }
            if ('object' === returnType) {
                return data;
            }
            if (field in data.metadata) {
                return data.metadata[field];
            }
            return null;
        }));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GetRecordPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: GetRecordPipe, isStandalone: false, name: "getRecord" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GetRecordPipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'getRecord',
                    standalone: false
                }]
        }] });

const primeNGConfig = {
    theme: {
        options: {
            cssLayer: {
                name: 'primeng'
            },
            darkModeSelector: false
        },
        preset: definePreset(Aura, {
            primitive: {
                borderRadius: {
                    none: "0",
                    xs: "2px",
                    sm: "4px",
                    md: "6px",
                    lg: "8px",
                    xl: "12px"
                },
                emerald: {
                    50: "#ecfdf5",
                    100: "#d1fae5",
                    200: "#a7f3d0",
                    300: "#6ee7b7",
                    400: "#34d399",
                    500: "#10b981",
                    600: "#059669",
                    700: "#047857",
                    800: "#065f46",
                    900: "#064e3b",
                    950: "#022c22"
                },
                green: {
                    50: "#f0fdf4",
                    100: "#dcfce7",
                    200: "#bbf7d0",
                    300: "#86efac",
                    400: "#4ade80",
                    500: "#22c55e",
                    600: "#16a34a",
                    700: "#15803d",
                    800: "#166534",
                    900: "#14532d",
                    950: "#052e16"
                },
                lime: {
                    50: "#f7fee7",
                    100: "#ecfccb",
                    200: "#d9f99d",
                    300: "#bef264",
                    400: "#a3e635",
                    500: "#84cc16",
                    600: "#65a30d",
                    700: "#4d7c0f",
                    800: "#3f6212",
                    900: "#365314",
                    950: "#1a2e05"
                },
                red: {
                    50: "#fef2f2",
                    100: "#fee2e2",
                    200: "#fecaca",
                    300: "#fca5a5",
                    400: "#f87171",
                    500: "#ef4444",
                    600: "#dc2626",
                    700: "#b91c1c",
                    800: "#991b1b",
                    900: "#7f1d1d",
                    950: "#450a0a"
                },
                orange: {
                    50: "#fff7ed",
                    100: "#ffedd5",
                    200: "#fed7aa",
                    300: "#fdba74",
                    400: "#fb923c",
                    500: "#f97316",
                    600: "#ea580c",
                    700: "#c2410c",
                    800: "#9a3412",
                    900: "#7c2d12",
                    950: "#431407"
                },
                amber: {
                    50: "#fffbeb",
                    100: "#fef3c7",
                    200: "#fde68a",
                    300: "#fcd34d",
                    400: "#fbbf24",
                    500: "#f59e0b",
                    600: "#d97706",
                    700: "#b45309",
                    800: "#92400e",
                    900: "#78350f",
                    950: "#451a03"
                },
                yellow: {
                    50: "#fefce8",
                    100: "#fef9c3",
                    200: "#fef08a",
                    300: "#fde047",
                    400: "#facc15",
                    500: "#eab308",
                    600: "#ca8a04",
                    700: "#a16207",
                    800: "#854d0e",
                    900: "#713f12",
                    950: "#422006"
                },
                teal: {
                    50: "#f0fdfa",
                    100: "#ccfbf1",
                    200: "#99f6e4",
                    300: "#5eead4",
                    400: "#2dd4bf",
                    500: "#14b8a6",
                    600: "#0d9488",
                    700: "#0f766e",
                    800: "#115e59",
                    900: "#134e4a",
                    950: "#042f2e"
                },
                cyan: {
                    50: "#ecfeff",
                    100: "#cffafe",
                    200: "#a5f3fc",
                    300: "#67e8f9",
                    400: "#22d3ee",
                    500: "#06b6d4",
                    600: "#0891b2",
                    700: "#0e7490",
                    800: "#155e75",
                    900: "#164e63",
                    950: "#083344"
                },
                sky: {
                    50: "#f0f9ff",
                    100: "#e0f2fe",
                    200: "#bae6fd",
                    300: "#7dd3fc",
                    400: "#38bdf8",
                    500: "#0ea5e9",
                    600: "#0284c7",
                    700: "#0369a1",
                    800: "#075985",
                    900: "#0c4a6e",
                    950: "#082f49"
                },
                blue: {
                    50: "#eff6ff",
                    100: "#dbeafe",
                    200: "#bfdbfe",
                    300: "#93c5fd",
                    400: "#60a5fa",
                    500: "#3b82f6",
                    600: "#2563eb",
                    700: "#1d4ed8",
                    800: "#1e40af",
                    900: "#1e3a8a",
                    950: "#172554"
                },
                indigo: {
                    50: "#eef2ff",
                    100: "#e0e7ff",
                    200: "#c7d2fe",
                    300: "#a5b4fc",
                    400: "#818cf8",
                    500: "#6366f1",
                    600: "#4f46e5",
                    700: "#4338ca",
                    800: "#3730a3",
                    900: "#312e81",
                    950: "#1e1b4b"
                },
                violet: {
                    50: "#f5f3ff",
                    100: "#ede9fe",
                    200: "#ddd6fe",
                    300: "#c4b5fd",
                    400: "#a78bfa",
                    500: "#8b5cf6",
                    600: "#7c3aed",
                    700: "#6d28d9",
                    800: "#5b21b6",
                    900: "#4c1d95",
                    950: "#2e1065"
                },
                purple: {
                    50: "#faf5ff",
                    100: "#f3e8ff",
                    200: "#e9d5ff",
                    300: "#d8b4fe",
                    400: "#c084fc",
                    500: "#a855f7",
                    600: "#9333ea",
                    700: "#7e22ce",
                    800: "#6b21a8",
                    900: "#581c87",
                    950: "#3b0764"
                },
                fuchsia: {
                    50: "#fdf4ff",
                    100: "#fae8ff",
                    200: "#f5d0fe",
                    300: "#f0abfc",
                    400: "#e879f9",
                    500: "#d946ef",
                    600: "#c026d3",
                    700: "#a21caf",
                    800: "#86198f",
                    900: "#701a75",
                    950: "#4a044e"
                },
                pink: {
                    50: "#fdf2f8",
                    100: "#fce7f3",
                    200: "#fbcfe8",
                    300: "#f9a8d4",
                    400: "#f472b6",
                    500: "#ec4899",
                    600: "#db2777",
                    700: "#be185d",
                    800: "#9d174d",
                    900: "#831843",
                    950: "#500724"
                },
                rose: {
                    50: "#fff1f2",
                    100: "#ffe4e6",
                    200: "#fecdd3",
                    300: "#fda4af",
                    400: "#fb7185",
                    500: "#f43f5e",
                    600: "#e11d48",
                    700: "#be123c",
                    800: "#9f1239",
                    900: "#881337",
                    950: "#4c0519"
                },
                slate: {
                    50: "#f8fafc",
                    100: "#f1f5f9",
                    200: "#e2e8f0",
                    300: "#cbd5e1",
                    400: "#94a3b8",
                    500: "#64748b",
                    600: "#475569",
                    700: "#334155",
                    800: "#1e293b",
                    900: "#0f172a",
                    950: "#020617"
                },
                gray: {
                    50: "#f9fafb",
                    100: "#f3f4f6",
                    200: "#e5e7eb",
                    300: "#d1d5db",
                    400: "#9ca3af",
                    500: "#6b7280",
                    600: "#4b5563",
                    700: "#374151",
                    800: "#1f2937",
                    900: "#111827",
                    950: "#030712"
                },
                zinc: {
                    50: "#fafafa",
                    100: "#f4f4f5",
                    200: "#e4e4e7",
                    300: "#d4d4d8",
                    400: "#a1a1aa",
                    500: "#71717a",
                    600: "#52525b",
                    700: "#3f3f46",
                    800: "#27272a",
                    900: "#18181b",
                    950: "#09090b"
                },
                neutral: {
                    50: "#fafafa",
                    100: "#f5f5f5",
                    200: "#e5e5e5",
                    300: "#d4d4d4",
                    400: "#a3a3a3",
                    500: "#737373",
                    600: "#525252",
                    700: "#404040",
                    800: "#262626",
                    900: "#171717",
                    950: "#0a0a0a"
                },
                stone: {
                    50: "#fafaf9",
                    100: "#f5f5f4",
                    200: "#e7e5e4",
                    300: "#d6d3d1",
                    400: "#a8a29e",
                    500: "#78716c",
                    600: "#57534e",
                    700: "#44403c",
                    800: "#292524",
                    900: "#1c1917",
                    950: "#0c0a09"
                }
            },
            semantic: {
                transitionDuration: "0.2s",
                focusRing: {
                    width: "1px",
                    style: "solid",
                    color: "{primary.color}",
                    offset: "2px",
                    shadow: "none"
                },
                disabledOpacity: "0.6",
                iconSize: "1rem",
                anchorGutter: "2px",
                primary: {
                    50: "#eff6ff",
                    100: "#dbeafe",
                    200: "#bfdbfe",
                    300: "#93c5fd",
                    400: "#60a5fa",
                    500: "#3b82f6",
                    600: "#2563eb",
                    700: "#1d4ed8",
                    800: "#1e40af",
                    900: "#1e3a8a",
                    950: "#172554"
                },
                formField: {
                    paddingX: "0.75rem",
                    paddingY: "0.5rem",
                    sm: {
                        fontSize: "0.875rem",
                        paddingX: "0.625rem",
                        paddingY: "0.375rem"
                    },
                    lg: {
                        fontSize: "1.125rem",
                        paddingX: "0.875rem",
                        paddingY: "0.625rem"
                    },
                    borderRadius: "{border.radius.md}",
                    focusRing: {
                        width: "0",
                        style: "none",
                        color: "transparent",
                        offset: "0",
                        shadow: "none"
                    },
                    transitionDuration: "{transition.duration}"
                },
                list: {
                    padding: "0.25rem 0.25rem",
                    gap: "2px",
                    header: {
                        padding: "0.5rem 1rem 0.25rem 1rem"
                    },
                    option: {
                        padding: "0.5rem 0.75rem",
                        borderRadius: "{border.radius.sm}"
                    },
                    optionGroup: {
                        padding: "0.5rem 0.75rem",
                        fontWeight: "600"
                    }
                },
                content: {
                    borderRadius: "{border.radius.md}"
                },
                mask: {
                    transitionDuration: "0.15s"
                },
                navigation: {
                    list: {
                        padding: "0.25rem 0.25rem",
                        gap: "2px"
                    },
                    item: {
                        padding: "0.5rem 0.75rem",
                        borderRadius: "{border.radius.sm}",
                        gap: "0.5rem"
                    },
                    submenuLabel: {
                        padding: "0.5rem 0.75rem",
                        fontWeight: "600"
                    },
                    submenuIcon: {
                        size: "0.875rem"
                    }
                },
                overlay: {
                    select: {
                        borderRadius: "{border.radius.md}",
                        shadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)"
                    },
                    popover: {
                        borderRadius: "{border.radius.md}",
                        padding: "0.75rem",
                        shadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)"
                    },
                    modal: {
                        borderRadius: "{border.radius.xl}",
                        padding: "1.25rem",
                        shadow: "0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)"
                    },
                    navigation: {
                        shadow: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)"
                    }
                },
                colorScheme: {
                    light: {
                        surface: {
                            0: "#ffffff",
                            50: "#f8fafc",
                            100: "#f1f5f9",
                            200: "#e2e8f0",
                            300: "#cbd5e1",
                            400: "#94a3b8",
                            500: "#64748b",
                            600: "#475569",
                            700: "#334155",
                            800: "#1e293b",
                            900: "#0f172a",
                            950: "#020617"
                        },
                        primary: {
                            color: "{primary.500}",
                            contrastColor: "#ffffff",
                            hoverColor: "{primary.600}",
                            activeColor: "{primary.700}"
                        },
                        highlight: {
                            background: "{primary.50}",
                            focusBackground: "{primary.100}",
                            color: "{primary.700}",
                            focusColor: "{primary.800}"
                        },
                        mask: {
                            background: "rgba(0,0,0,0.4)",
                            color: "{surface.200}"
                        },
                        formField: {
                            background: "{surface.0}",
                            disabledBackground: "{surface.200}",
                            filledBackground: "{surface.50}",
                            filledHoverBackground: "{surface.50}",
                            filledFocusBackground: "{surface.50}",
                            borderColor: "{surface.300}",
                            hoverBorderColor: "{surface.400}",
                            focusBorderColor: "{primary.color}",
                            invalidBorderColor: "{red.400}",
                            color: "{surface.700}",
                            disabledColor: "{surface.500}",
                            placeholderColor: "{surface.500}",
                            invalidPlaceholderColor: "{red.600}",
                            floatLabelColor: "{surface.500}",
                            floatLabelFocusColor: "{primary.600}",
                            floatLabelActiveColor: "{surface.500}",
                            floatLabelInvalidColor: "{form.field.invalid.placeholder.color}",
                            iconColor: "{surface.400}",
                            shadow: "0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(18, 18, 23, 0.05)"
                        },
                        text: {
                            color: "{surface.800}",
                            hoverColor: "{surface.900}",
                            mutedColor: "{surface.500}",
                            hoverMutedColor: "{surface.600}"
                        },
                        content: {
                            background: "{surface.0}",
                            hoverBackground: "{surface.100}",
                            borderColor: "{surface.200}",
                            color: "{text.color}",
                            hoverColor: "{text.hover.color}"
                        },
                        overlay: {
                            select: {
                                background: "{surface.0}",
                                borderColor: "{surface.200}",
                                color: "{text.color}"
                            },
                            popover: {
                                background: "{surface.0}",
                                borderColor: "{surface.200}",
                                color: "{text.color}"
                            },
                            modal: {
                                background: "{surface.0}",
                                borderColor: "{surface.200}",
                                color: "{text.color}"
                            }
                        },
                        list: {
                            option: {
                                focusBackground: "{surface.100}",
                                selectedBackground: "{highlight.background}",
                                selectedFocusBackground: "{highlight.focus.background}",
                                color: "{text.color}",
                                focusColor: "{text.hover.color}",
                                selectedColor: "{highlight.color}",
                                selectedFocusColor: "{highlight.focus.color}",
                                icon: {
                                    color: "{surface.400}",
                                    focusColor: "{surface.500}"
                                }
                            },
                            optionGroup: {
                                background: "transparent",
                                color: "{text.muted.color}"
                            }
                        },
                        navigation: {
                            item: {
                                focusBackground: "{surface.100}",
                                activeBackground: "{surface.100}",
                                color: "{text.color}",
                                focusColor: "{text.hover.color}",
                                activeColor: "{text.hover.color}",
                                icon: {
                                    color: "{surface.400}",
                                    focusColor: "{surface.500}",
                                    activeColor: "{surface.500}"
                                }
                            },
                            submenuLabel: {
                                background: "transparent",
                                color: "{text.muted.color}"
                            },
                            submenuIcon: {
                                color: "{surface.400}",
                                focusColor: "{surface.500}",
                                activeColor: "{surface.500}"
                            }
                        }
                    },
                    dark: {
                        surface: {
                            0: "#ffffff",
                            50: "#fafafa",
                            100: "#f4f4f5",
                            200: "#e4e4e7",
                            300: "#d4d4d8",
                            400: "#a1a1aa",
                            500: "#71717a",
                            600: "#52525b",
                            700: "#3f3f46",
                            800: "#27272a",
                            900: "#18181b",
                            950: "#09090b"
                        },
                        primary: {
                            color: "{primary.400}",
                            contrastColor: "{surface.900}",
                            hoverColor: "{primary.300}",
                            activeColor: "{primary.200}"
                        },
                        highlight: {
                            background: "color-mix(in srgb, {primary.400}, transparent 84%)",
                            focusBackground: "color-mix(in srgb, {primary.400}, transparent 76%)",
                            color: "rgba(255,255,255,.87)",
                            focusColor: "rgba(255,255,255,.87)"
                        },
                        mask: {
                            background: "rgba(0,0,0,0.6)",
                            color: "{surface.200}"
                        },
                        formField: {
                            background: "{surface.950}",
                            disabledBackground: "{surface.700}",
                            filledBackground: "{surface.800}",
                            filledHoverBackground: "{surface.800}",
                            filledFocusBackground: "{surface.800}",
                            borderColor: "{surface.600}",
                            hoverBorderColor: "{surface.500}",
                            focusBorderColor: "{primary.color}",
                            invalidBorderColor: "{red.300}",
                            color: "{surface.0}",
                            disabledColor: "{surface.400}",
                            placeholderColor: "{surface.400}",
                            invalidPlaceholderColor: "{red.400}",
                            floatLabelColor: "{surface.400}",
                            floatLabelFocusColor: "{primary.color}",
                            floatLabelActiveColor: "{surface.400}",
                            floatLabelInvalidColor: "{form.field.invalid.placeholder.color}",
                            iconColor: "{surface.400}",
                            shadow: "0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(18, 18, 23, 0.05)"
                        },
                        text: {
                            color: "{surface.0}",
                            hoverColor: "{surface.0}",
                            mutedColor: "{surface.400}",
                            hoverMutedColor: "{surface.300}"
                        },
                        content: {
                            background: "{surface.900}",
                            hoverBackground: "{surface.800}",
                            borderColor: "{surface.700}",
                            color: "{text.color}",
                            hoverColor: "{text.hover.color}"
                        },
                        overlay: {
                            select: {
                                background: "{surface.900}",
                                borderColor: "{surface.700}",
                                color: "{text.color}"
                            },
                            popover: {
                                background: "{surface.900}",
                                borderColor: "{surface.700}",
                                color: "{text.color}"
                            },
                            modal: {
                                background: "{surface.900}",
                                borderColor: "{surface.700}",
                                color: "{text.color}"
                            }
                        },
                        list: {
                            option: {
                                focusBackground: "{surface.800}",
                                selectedBackground: "{highlight.background}",
                                selectedFocusBackground: "{highlight.focus.background}",
                                color: "{text.color}",
                                focusColor: "{text.hover.color}",
                                selectedColor: "{highlight.color}",
                                selectedFocusColor: "{highlight.focus.color}",
                                icon: {
                                    color: "{surface.500}",
                                    focusColor: "{surface.400}"
                                }
                            },
                            optionGroup: {
                                background: "transparent",
                                color: "{text.muted.color}"
                            }
                        },
                        navigation: {
                            item: {
                                focusBackground: "{surface.800}",
                                activeBackground: "{surface.800}",
                                color: "{text.color}",
                                focusColor: "{text.hover.color}",
                                activeColor: "{text.hover.color}",
                                icon: {
                                    color: "{surface.500}",
                                    focusColor: "{surface.400}",
                                    activeColor: "{surface.400}"
                                }
                            },
                            submenuLabel: {
                                background: "transparent",
                                color: "{text.muted.color}"
                            },
                            submenuIcon: {
                                color: "{surface.500}",
                                focusColor: "{surface.400}",
                                activeColor: "{surface.400}"
                            }
                        }
                    }
                }
            },
            components: {
                accordion: {
                    header: {
                        borderRadius: "{content.border.radius}",
                        borderColor: "{content.border.color}",
                        background: "{surface.100}",
                        hoverBackground: "{surface.200}",
                        activeBackground: "{surface.200}",
                        activeHoverBackground: "{surface.200}"
                    },
                    content: {
                        padding: "0.5rem 0.25rem"
                    }
                },
                autocomplete: {
                    option: {
                        padding: "0.2rem 0.5rem"
                    }
                },
                card: {
                    root: {
                        background: "{surface.100}",
                    },
                    body: {
                        padding: "0",
                    }
                },
                fieldset: {
                    legend: {
                        padding: "0 0.25rem 0.25rem 0.25rem",
                    }
                },
                listbox: {
                    option: {
                        padding: "0.2rem 0.5rem"
                    }
                },
                menubar: {
                    root: {
                        borderColor: "transparent",
                    }
                },
                panel: {
                    root: {
                        background: "{surface.100}",
                    },
                    content: {
                        padding: "0"
                    }
                },
                tag: {
                    root: {
                        fontSize: "0.8rem",
                        fontWeight: "600",
                        padding: "0.15rem 0.5rem",
                        gap: "0.25rem",
                        borderRadius: "{content.border.radius}",
                        roundedBorderRadius: "{border.radius.xl}"
                    },
                    icon: {
                        size: "0.5rem"
                    },
                    colorScheme: {
                        light: {
                            primary: {
                                background: "{primary.100}",
                                color: "{primary.700}"
                            },
                            secondary: {
                                background: "{surface.500}",
                                color: "{surface.0}"
                            },
                            success: {
                                background: "{green.100}",
                                color: "{green.700}"
                            },
                            info: {
                                background: "{sky.100}",
                                color: "{sky.700}"
                            },
                            warn: {
                                background: "{orange.100}",
                                color: "{orange.700}"
                            },
                            danger: {
                                background: "{red.100}",
                                color: "{red.700}"
                            },
                            contrast: {
                                background: "{surface.950}",
                                color: "{surface.0}"
                            }
                        },
                        dark: {
                            primary: {
                                background: "color-mix(in srgb, {primary.500}, transparent 84%)",
                                color: "{primary.300}"
                            },
                            secondary: {
                                background: "{surface.800}",
                                color: "{surface.300}"
                            },
                            success: {
                                background: "color-mix(in srgb, {green.500}, transparent 84%)",
                                color: "{green.300}"
                            },
                            info: {
                                background: "color-mix(in srgb, {sky.500}, transparent 84%)",
                                color: "{sky.300}"
                            },
                            warn: {
                                background: "color-mix(in srgb, {orange.500}, transparent 84%)",
                                color: "{orange.300}"
                            },
                            danger: {
                                background: "color-mix(in srgb, {red.500}, transparent 84%)",
                                color: "{red.300}"
                            },
                            contrast: {
                                background: "{surface.0}",
                                color: "{surface.950}"
                            }
                        }
                    }
                },
                timeline: {
                    event: {
                        minHeight: "2.5rem",
                    }
                }
            }
        })
    }
};

/*
 * RERO angular core
 * Copyright (C) 2019-2023 RERO
 * Copyright (C) 2019-2023 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class DetailButtonComponent {
    constructor() {
        // Inject
        this.location = inject(Location);
        /** Record */
        this.record = input();
        /** Record type */
        this.type = input();
        /** Admin mode for CRUD operations */
        this.adminMode = input({ can: false, message: '' });
        /** Record can be used ? */
        this.useStatus = input({ can: false, message: '', url: '' });
        /** Record can be updated ? */
        this.updateStatus = input({ can: false, message: '' });
        /** Record can be deleted ? */
        this.deleteStatus = input({ can: false, message: '' });
        /** Record event */
        this.recordEvent = output();
        /** Delete record message event */
        this.deleteMessageEvent = output();
    }
    /** Use the record */
    useRecord() {
        this.recordEvent.emit({ action: 'use', url: this.updateStatus().url });
    }
    /**
     * Update record event
     * @param record - the current record
     */
    updateRecord(record) {
        this.recordEvent.emit({ action: 'update', record });
    }
    /**
     * Delete record event
     * @param record - the current record
     */
    deleteRecord(record) {
        if (this.deleteStatus().can) {
            this.recordEvent.emit({ action: 'delete', record });
        }
        else {
            this.deleteMessageEvent.emit(this.deleteStatus().message.replace(new RegExp('\n', 'g'), '<br>'));
        }
    }
    /** Go back to previous page */
    goBack() {
        this.location.back();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DetailButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DetailButtonComponent, isStandalone: false, selector: "ng-core-detail-button", inputs: { record: { classPropertyName: "record", publicName: "record", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, adminMode: { classPropertyName: "adminMode", publicName: "adminMode", isSignal: true, isRequired: false, transformFunction: null }, useStatus: { classPropertyName: "useStatus", publicName: "useStatus", isSignal: true, isRequired: false, transformFunction: null }, updateStatus: { classPropertyName: "updateStatus", publicName: "updateStatus", isSignal: true, isRequired: false, transformFunction: null }, deleteStatus: { classPropertyName: "deleteStatus", publicName: "deleteStatus", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { recordEvent: "recordEvent", deleteMessageEvent: "deleteMessageEvent" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div class=\"core:flex core:justify-between core:flex-wrap core:mb-4\">\n  <p-button\n    id=\"detail-back-button\"\n    styleClass=\"core:grow\"\n    icon=\"fa fa-arrow-left\"\n    [label]=\"'Back'|translate\"\n    severity=\"secondary\"\n    [text]=\"true\"\n    (onClick)=\"goBack()\"\n  />\n  <div class=\"core:flex core:flex-wrap core:items-center core:gap-1\">\n    <ng-content select=\"[beforeButton]\"></ng-content>\n    @if (record() && adminMode().can) {\n      @if (useStatus() && useStatus().can && useStatus().url) {\n        <p-button\n          id=\"detail-use-button\"\n          icon=\"fa fa-hand-o-right\"\n          [label]=\"'Use'|translate\"\n          (onClick)=\"useRecord()\"\n          translate\n        />\n      }\n      @if (updateStatus() && updateStatus().can) {\n        <p-button\n          id=\"detail-edit-button\"\n          icon=\"fa fa-pencil\"\n          [label]=\"'Edit'|translate\"\n          [outlined]=\"useStatus()?.can\"\n          (onClick)=\"updateRecord(record())\"\n          translate\n        />\n      }\n      @if (deleteStatus()) {\n        <p-button\n          id=\"detail-delete-button\"\n          icon=\"fa fa-trash\"\n          severity=\"danger\"\n          class=\"core:pointer-events-auto\"\n          outlined\n          (onClick)=\"deleteRecord(record())\"\n          [pTooltip]=\"tooltipContent\"\n          tooltipPosition=\"bottom\"\n          [disabled]=\"!deleteStatus().can\"\n          [label]=\"'Delete'|translate\"\n          [tooltipDisabled]=\"deleteStatus().can\"\n        />\n        <ng-template #tooltipContent>\n          <span [innerHTML]=\"deleteStatus().message\"></span>\n        </ng-template>\n      }\n    }\n    <ng-content select=\"[afterButton]\"/>\n  </div>\n</div>\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DetailButtonComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-detail-button', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div class=\"core:flex core:justify-between core:flex-wrap core:mb-4\">\n  <p-button\n    id=\"detail-back-button\"\n    styleClass=\"core:grow\"\n    icon=\"fa fa-arrow-left\"\n    [label]=\"'Back'|translate\"\n    severity=\"secondary\"\n    [text]=\"true\"\n    (onClick)=\"goBack()\"\n  />\n  <div class=\"core:flex core:flex-wrap core:items-center core:gap-1\">\n    <ng-content select=\"[beforeButton]\"></ng-content>\n    @if (record() && adminMode().can) {\n      @if (useStatus() && useStatus().can && useStatus().url) {\n        <p-button\n          id=\"detail-use-button\"\n          icon=\"fa fa-hand-o-right\"\n          [label]=\"'Use'|translate\"\n          (onClick)=\"useRecord()\"\n          translate\n        />\n      }\n      @if (updateStatus() && updateStatus().can) {\n        <p-button\n          id=\"detail-edit-button\"\n          icon=\"fa fa-pencil\"\n          [label]=\"'Edit'|translate\"\n          [outlined]=\"useStatus()?.can\"\n          (onClick)=\"updateRecord(record())\"\n          translate\n        />\n      }\n      @if (deleteStatus()) {\n        <p-button\n          id=\"detail-delete-button\"\n          icon=\"fa fa-trash\"\n          severity=\"danger\"\n          class=\"core:pointer-events-auto\"\n          outlined\n          (onClick)=\"deleteRecord(record())\"\n          [pTooltip]=\"tooltipContent\"\n          tooltipPosition=\"bottom\"\n          [disabled]=\"!deleteStatus().can\"\n          [label]=\"'Delete'|translate\"\n          [tooltipDisabled]=\"deleteStatus().can\"\n        />\n        <ng-template #tooltipContent>\n          <span [innerHTML]=\"deleteStatus().message\"></span>\n        </ng-template>\n      }\n    }\n    <ng-content select=\"[afterButton]\"/>\n  </div>\n</div>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
const CONFIG = {
    MESSAGE_LIFE: 5000, // Message lifetime in ms
    DEFAULT_SELECT_SCROLL_HEIGHT: '50vh'
};

/*
 * RERO angular core
 * Copyright (C) 2019-2024 RERO
 * Copyright (C) 2019-2023 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordUiService {
    constructor() {
        this.translateService = inject(TranslateService);
        this.recordService = inject(RecordService);
        this.router = inject(Router);
        this.confirmationService = inject(ConfirmationService);
        this.messageService = inject(MessageService);
        /** Configuration for all resources. */
        this.types = [];
    }
    /**
     * Delete a record by its PID.
     * @param type Type of resource
     * @param pid - string, PID to delete
     * @returns Observable resolving as a boolean
     */
    deleteRecord(type, pid) {
        const delete$ = new BehaviorSubject(false);
        this.confirmationService.confirm({
            acceptLabel: this.translateService.instant('Delete'),
            rejectLabel: this.translateService.instant('Cancel'),
            message: this.deleteMessage(pid, type).join('<br>'),
            header: this.translateService.instant('Confirmation'),
            icon: 'fa fa-exclamation-triangle fa-2x core:text-red-500',
            acceptButtonStyleClass: "core:bg-red-500 core:border-red-500",
            rejectButtonStyleClass: "p-button-text",
            accept: () => {
                this.recordService.delete(type, pid).subscribe({
                    next: () => {
                        delete$.next(true);
                        this.messageService.add({
                            severity: 'info',
                            summary: this.translateService.instant('Confirmed'),
                            detail: this.translateService.instant('Record deleted.'),
                            life: CONFIG.MESSAGE_LIFE
                        });
                    },
                    error: (error) => {
                        delete$.next(false);
                        this.messageService.add({
                            severity: 'error',
                            summary: this.translateService.instant('Error'),
                            detail: this.translateService.instant(error.title),
                            sticky: true,
                            closable: true
                        });
                    }
                });
            }
        });
        return delete$.asObservable();
    }
    /**
     * Show dialog with the reason why record cannot be deleted.
     * @param message Message to display
     */
    showDeleteMessage(message) {
        this.confirmationService.confirm({
            acceptLabel: this.translateService.instant('OK'),
            rejectVisible: false,
            header: this.translateService.instant('Information'),
            message: message,
            acceptIcon: "none",
        });
    }
    /**
     * Get resource configuration for given type.
     *
     * @param type Current type to find
     * @returns Object configuration for the current type
     */
    getResourceConfig(type) {
        if (this.types == null) {
            throw new Error(`Configuration not found for type "${type}"`);
        }
        const index = this.types.findIndex(item => item.key === type);
        if (index === -1) {
            throw new Error(`Configuration not found for type "${type}"`);
        }
        return this.types[index];
    }
    /**
     * Redirects after saving a resource
     * @param pid - string, pid of the record
     * @param record - object, record to save
     * @param recordType - string, Type of resource
     * @param action - string, http action: create or update
     * @param route - ActivatedRoute: the current route used
     */
    redirectAfterSave(pid, record, recordType, action, route) {
        const config = this.getResourceConfig(recordType);
        if (config.redirectUrl) {
            config.redirectUrl(record, action).subscribe((result) => {
                if (result !== null) {
                    this.router.navigateByUrl(result);
                    return;
                }
            });
        }
        else {
            // Default behavior
            if (action === 'update') {
                this.router.navigate(['../../detail', pid], { relativeTo: route, replaceUrl: true });
                return;
            }
            this.router.navigate(['../detail', pid], { relativeTo: route, replaceUrl: true });
        }
    }
    /**
     * Personalized message for delete a record
     * @param pid - record pid string
     * @param type - Type of resource
     * @returns  Observable array of string
     */
    deleteMessage(pid, type) {
        const defaultMessage = [
            this.translateService.instant('Do you really want to delete this record?')
        ];
        try {
            const config = this.getResourceConfig(type);
            return (config.deleteMessage)
                ? config.deleteMessage(pid)
                : defaultMessage;
        }
        catch {
            return defaultMessage;
        }
    }
    // ================================================================
    //    Permissions
    // ================================================================
    /**
     * Check if a record can be added
     * @param type Type of resource
     * @returns Observable resolving an object containing the result of a permission check.
     */
    canAddRecord$(type) {
        const config = this.getResourceConfig(type);
        return (config.canAdd)
            ? config.canAdd().pipe(first())
            : of({ can: true, message: '' });
    }
    /**
     * Check if a record can be updated
     * @param record - object, record to check
     * @param type Type of resource
     * @returns Observable resolving an object containing the result of a permission check.
     */
    canUpdateRecord$(record, type) {
        const config = this.getResourceConfig(type);
        // The canUpdate function takes precedence over permissions
        if (config.canUpdate) {
            return config.canUpdate(record).pipe(first());
        }
        if (config.permissions) {
            const permissions = config.permissions(record);
            return permissions.pipe(map$4((perms) => {
                if ('canUpdate' in perms) {
                    return perms.canUpdate;
                }
                else {
                    return of({ can: true, message: '' });
                }
            }));
        }
        return of({ can: true, message: '' });
    }
    /**
     * Check if a record can be deleted
     * @param record - object, record to check
     * @param type Type of resource
     * @returns Observable resolving an object containing the result of a permission check.
     */
    canDeleteRecord$(record, type) {
        const config = this.getResourceConfig(type);
        // The canDelete function takes precedence over permissions
        if (config.canDelete) {
            return config.canDelete(record).pipe(first());
        }
        if (config.permissions) {
            const permissions = config.permissions(record);
            return permissions.pipe(map$4((perms) => {
                if ('canDelete' in perms) {
                    return perms.canDelete;
                }
                else {
                    return of({ can: true, message: '' });
                }
            }));
        }
        return of({ can: true, message: '' });
    }
    /**
     * Check if a record can be read
     * @param record - object, record to check
     * @param type Type of resource
     * @returns Observable resolving an object containing the result of a permission check.
     */
    canReadRecord$(record, type) {
        const config = this.getResourceConfig(type);
        // The canRead function takes precedence over permissions
        if (config.canRead) {
            return config.canRead(record).pipe(first());
        }
        if (config.permissions) {
            const permissions = config.permissions(record);
            return permissions.pipe(map$4((perms) => {
                if ('canRead' in perms) {
                    return perms.canRead;
                }
                else {
                    return of({ can: true, message: '' });
                }
            }));
        }
        return of({ can: true, message: '' });
    }
    /**
     * Check if a record can be used (mainly used for templates)
     * @param record - object, record to check
     * @param type Type of resource
     * @returns Observable resolving an object containing the result of a permission check.
     */
    canUseRecord$(record, type) {
        const config = this.getResourceConfig(type);
        // The canUse function takes precedence over permissions
        if (config.canUse) {
            return config.canUse(record).pipe(first());
        }
        if (config.permissions) {
            const permissions = config.permissions(record);
            if ('canUse' in permissions) {
                return permissions.canUse;
            }
        }
        return of({ can: false, message: '' });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordUiService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordUiService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordUiService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Directive for displaying a record detail.
 */
class RecordDetailDirective {
    constructor() {
        this.viewContainerRef = inject(ViewContainerRef);
        /**
         * Record to display
         */
        this.record = {};
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordDetailDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
    static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.14", type: RecordDetailDirective, isStandalone: false, selector: "[ngCoreRecordDetail]", inputs: { record: "record", type: "type" }, ngImport: i0 }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordDetailDirective, decorators: [{
            type: Directive,
            args: [{
                    selector: '[ngCoreRecordDetail]',
                    standalone: false
                }]
        }], propDecorators: { record: [{
                type: Input
            }], type: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component to display a record by dumping its data to JSON.
 */
let JsonComponent$1 = class JsonComponent {
    /**
     * Component initialization.
     *
     * Subscribes to observable for getting the record.
     */
    ngOnInit() {
        this.record$.subscribe((record) => {
            this.record = record;
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JsonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: JsonComponent, isStandalone: false, selector: "ng-component", ngImport: i0, template: `
    @if (record) {
      <h1>Record of type "{{ type }}" #{{ record.id }}</h1>
      <pre>
        <div style="white-space: pre-wrap;">{{ record|json }}</div>
      </pre>
    }
  `, isInline: true, dependencies: [{ kind: "pipe", type: i1$2.JsonPipe, name: "json" }] }); }
};
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JsonComponent$1, decorators: [{
            type: Component,
            args: [{
                    template: `
    @if (record) {
      <h1>Record of type "{{ type }}" #{{ record.id }}</h1>
      <pre>
        <div style="white-space: pre-wrap;">{{ record|json }}</div>
      </pre>
    }
  `,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2023 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class DetailComponent {
    constructor() {
        this.route = inject(ActivatedRoute);
        this.router = inject(Router);
        this.location = inject(Location);
        this.recordService = inject(RecordService);
        this.recordUiService = inject(RecordUiService);
        this.translate = inject(TranslateService);
        this.spinner = inject(NgxSpinnerService);
        this.messageService = inject(MessageService);
        this.viewContainerRef = inject(ViewContainerRef);
        /** View component for displaying record */
        this.viewComponent = null;
        /** Record can be used ? */
        this.useStatus = { can: false, message: '', url: '' };
        /** Record can be updated ? */
        this.updateStatus = { can: false, message: '' };
        /** Record can be deleted ? */
        this.deleteStatus = { can: false, message: '' };
        /** Observable resolving record data */
        this.record$ = null;
        /** Record data */
        this.record = null;
        /** Admin mode for CRUD operations */
        this.adminMode = { can: true, message: '' };
        /** Object type route config */
        this.config = null;
    }
    /** On init hook */
    ngOnInit() {
        this.routeParametersSubscription = this.route.paramMap.subscribe(() => {
            this.spinner.show();
            this.loadViewComponentRef();
            const pid = this.route.snapshot.paramMap.get('pid');
            this.type = this.route.snapshot.paramMap.get('type');
            this.recordUiService.types = this.route.snapshot.data.types;
            this.config = this.recordUiService.getResourceConfig(this.type);
            const type = this.config.index || this.config.key;
            this.record$ = this.recordService.getRecord(type, pid, 1, this.config.itemHeaders || null).pipe(catchError$1((error) => {
                this.error = error;
                this.spinner.hide();
                return of(null);
            }), tap$1(record => {
                this.record = record;
                this.recordUiService.canReadRecord$(this.record, this.type).subscribe(result => {
                    if (result.can === false) {
                        this.messageService.add({
                            severity: 'error',
                            summary: this.translate.instant(this.type),
                            detail: this.translate.instant('You cannot read this record'),
                            sticky: true,
                            closable: true
                        });
                        this.location.back();
                    }
                });
                this.recordUiService.canDeleteRecord$(this.record, this.type).subscribe(result => {
                    this.deleteStatus = result;
                });
                this.recordUiService.canUpdateRecord$(this.record, this.type).subscribe(result => {
                    this.updateStatus = result;
                });
                this.recordUiService.canUseRecord$(this.record, this.type).subscribe(result => {
                    this.useStatus = result;
                });
                if (this.route.snapshot.data.adminMode) {
                    this.route.snapshot.data.adminMode().subscribe((am) => this.adminMode = am);
                }
                this.spinner.hide();
            }));
            this.loadRecordView();
        });
    }
    /**
     * Component destruction.
     *
     * Unsubscribes from the observables of the route parameters.
     * Unsubscribes from the observable for detail view.
     */
    ngOnDestroy() {
        this.routeParametersSubscription.unsubscribe();
        if (this.detailComponentSubscription) {
            this.detailComponentSubscription.unsubscribe();
        }
    }
    /**
     * Record event
     * @param event - Record event message
     */
    recordEvent(event) {
        switch (event.action) {
            case 'use':
                this.router.navigateByUrl(event.url);
                break;
            case 'update':
                this.router.navigate(['../../edit', event.record.id], { relativeTo: this.route, replaceUrl: true });
                break;
            case 'delete':
                this.deleteRecord(event.record);
                break;
            default:
                throw new Error('Missing record event action.');
        }
    }
    /**
     * Getter giving the information if file management is enabled.
     * @returns True if file management is enabled.
     */
    get filesEnabled() {
        return this.config.files && this.config.files.enabled ? this.config.files.enabled : false;
    }
    /**
     * Delete the record and go back to previous page.
     * @param event - DOM event
     * @param element - string (PID to remove) or object
     */
    deleteRecord(element) {
        const pid = typeof element === 'object' ? element.id : element;
        return this.recordUiService.deleteRecord(this.type, pid).subscribe((result) => {
            if (result === true) {
                let redirectUrl = '../..';
                const navigateOptions = { relativeTo: this.route };
                if (typeof element === 'object' && this.config.redirectUrl) {
                    this.config.redirectUrl(element, 'delete').subscribe((redirect) => {
                        if (redirect !== null) {
                            redirectUrl = redirect;
                        }
                        this.router.navigate([redirectUrl], navigateOptions);
                    });
                }
                this.router.navigate([redirectUrl], navigateOptions);
            }
        });
    }
    /**
     * Show a modal containing message given in parameter.
     * @param message - message to display into modal
     */
    showDeleteMessage(message) {
        this.recordUiService.showDeleteMessage(message);
    }
    /** Dynamically load component depending on selected resource type. */
    loadRecordView() {
        this.viewContainerRef.clear();
        const componentRef = this.viewContainerRef.createComponent(this.viewComponent || JsonComponent$1);
        componentRef.instance.record$ = this.record$;
        componentRef.instance.type = this.route.snapshot.paramMap.get('type');
    }
    /** Load component view corresponding to type */
    loadViewComponentRef() {
        if (!this.route.snapshot.data.types || this.route.snapshot.data.types.length === 0) {
            throw new Error('Configuration types not passed to component');
        }
        const type = this.route.snapshot.paramMap.get('type');
        const { types } = this.route.snapshot.data;
        const index = types.findIndex((item) => item.key === type);
        if (index === -1) {
            throw new Error(`Configuration not found for type "${type}"`);
        }
        if (types[index].detailComponent) {
            let detailComponent$ = types[index].detailComponent;
            if (isObservable(detailComponent$) === false) {
                detailComponent$ = of(detailComponent$);
            }
            this.detailComponentSubscription = detailComponent$.subscribe((component) => {
                this.viewComponent = component;
            });
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DetailComponent, isStandalone: false, selector: "ng-core-record-detail", inputs: { viewComponent: "viewComponent" }, viewQueries: [{ propertyName: "recordDetail", first: true, predicate: RecordDetailDirective, descendants: true, static: true }], ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div>\n  @if (record) {\n    <ng-core-detail-button\n      [record]=\"record\"\n      [type]=\"type\"\n      [adminMode]=\"adminMode\"\n      [useStatus]=\"useStatus\"\n      [updateStatus]=\"updateStatus\"\n      [deleteStatus]=\"deleteStatus\"\n      (recordEvent)=\"recordEvent($event)\"\n      (deleteMessageEvent)=\"showDeleteMessage($event)\"\n    />\n  }\n  @if (error) {\n    <ng-core-error [error]=\"error\"/>\n  }\n  <ng-template ngCoreRecordDetail/>\n</div>\n", dependencies: [{ kind: "component", type: ErrorComponent, selector: "ng-core-error", inputs: ["error"] }, { kind: "directive", type: RecordDetailDirective, selector: "[ngCoreRecordDetail]", inputs: ["record", "type"] }, { kind: "component", type: DetailButtonComponent, selector: "ng-core-detail-button", inputs: ["record", "type", "adminMode", "useStatus", "updateStatus", "deleteStatus"], outputs: ["recordEvent", "deleteMessageEvent"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DetailComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-record-detail', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div>\n  @if (record) {\n    <ng-core-detail-button\n      [record]=\"record\"\n      [type]=\"type\"\n      [adminMode]=\"adminMode\"\n      [useStatus]=\"useStatus\"\n      [updateStatus]=\"updateStatus\"\n      [deleteStatus]=\"deleteStatus\"\n      (recordEvent)=\"recordEvent($event)\"\n      (deleteMessageEvent)=\"showDeleteMessage($event)\"\n    />\n  }\n  @if (error) {\n    <ng-core-error [error]=\"error\"/>\n  }\n  <ng-template ngCoreRecordDetail/>\n</div>\n" }]
        }], propDecorators: { viewComponent: [{
                type: Input
            }], recordDetail: [{
                type: ViewChild,
                args: [RecordDetailDirective, { static: true }]
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RouteCollectionService {
    constructor() {
        /**
         * Collection of routes
         */
        this.collection = new Map();
    }
    /**
     * Add route on collection
     * @param route - RouteInterface
     * @return this - RouteCollectionService
     */
    addRoute(route) {
        const routeName = route.name;
        if (!this.hasRoute(routeName)) {
            this.collection.set(routeName, route);
        }
        return this;
    }
    /**
     * Delete route on collection
     * @param name - string
     * @return boolean
     */
    deleteRoute(name) {
        if (this.hasRoute(name)) {
            this.collection.delete(name);
            return true;
        }
        return false;
    }
    /**
     * Check if route is present to the collection
     * @param name - string
     * @return boolean
     */
    hasRoute(name) {
        return this.collection.has(name);
    }
    /**
     * Get route by name
     * @param name - string
     * @return mixed - RouteInterface | null
     */
    getRoute(name) {
        if (this.hasRoute(name)) {
            return this.collection.get(name);
        }
        return null;
    }
    /**
     * Get All routes
     * @return routes separated by comma
     */
    getRoutes() {
        const routes = [];
        for (const value of this.collection.values()) {
            routes.push(value.getConfiguration());
        }
        return routes;
    }
    /**
     * Return a array of route name
     * @return array
     */
    availableRoutesName() {
        const routesName = [];
        for (const route of this.collection.keys()) {
            routesName.push(route);
        }
        return routesName;
    }
    /**
     * Count available routes
     * @return number;
     */
    size() {
        return this.collection.size;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RouteCollectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RouteCollectionService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RouteCollectionService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2022 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class LoggerService {
    info(data, message) {
        console.log(message, data);
    }
    warning(data, message) {
        console.warn(message, data);
    }
    error(data, message) {
        console.error(message, data);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LoggerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LoggerService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LoggerService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class JSONSchemaService {
    constructor() {
        this.translateService = inject(TranslateService);
        this.recordService = inject(RecordService);
        this.apiService = inject(ApiService);
        // list of custom validators
        this.customValidators = [
            'valueAlreadyExists',
            'uniqueValueKeysInObject',
            'numberOfSpecificValuesInObject',
            'dateMustBeGreaterThan',
            'dateMustBeLessThan'
        ];
    }
    processField(field, jsonSchema) {
        // initial population of arrays with a minItems constraints
        if (field.type === 'array' && jsonSchema.minItems && !jsonSchema.hasOwnProperty('default')) {
            field.defaultValue = new Array(jsonSchema.minItems);
        }
        // If 'format' is defined into the jsonSchema, use it as props to try a validation on this field.
        // See: `email.validator.ts` file
        if (jsonSchema.format) {
            field.props.type = jsonSchema.format;
        }
        if (jsonSchema?.widget?.formlyConfig) {
            const { props } = jsonSchema.widget.formlyConfig;
            if (props) {
                this.setSimpleOptions(field, props);
                this.setValidation(field, props);
                this.setRemoteSelectOptions(field, props);
            }
        }
        return field;
    }
    /**
    * Populate a select options with a remote API call.
    * @param field formly field config
    * @param formOptions JSONSchema object
    */
    setRemoteSelectOptions(field, formOptions) {
        if (formOptions.remoteOptions && formOptions.remoteOptions.type) {
            field.type = 'select';
            field.hooks = {
                ...field.hooks,
                afterContentInit: (f) => {
                    const recordType = formOptions.remoteOptions.type;
                    const query = formOptions.remoteOptions.query || '';
                    f.props.options = this.recordService
                        .getRecords(recordType, query, 1, RecordService.MAX_REST_RESULTS_SIZE)
                        .pipe(map$5((data) => data.hits.hits.map((record) => {
                        return {
                            label: formOptions.remoteOptions.labelField && formOptions.remoteOptions.labelField in record.metadata
                                ? record.metadata[formOptions.remoteOptions.labelField]
                                : record.metadata.name,
                            value: this.apiService.getRefEndpoint(recordType, record.id)
                        };
                    })));
                }
            };
        }
    }
    /**
     *
     * @param field formly field config
     * @param formOptions JSONSchema object
     */
    setValidation(field, formOptions) {
        if (formOptions.validation) {
            // custom validation messages
            // TODO: use widget instead
            const { messages } = formOptions.validation;
            if (messages) {
                if (!field.validation) {
                    field.validation = {};
                }
                if (!field.validation.messages) {
                    field.validation.messages = {};
                }
                for (const key of Object.keys(messages)) {
                    const msg = messages[key];
                    // add support of key with or without Message suffix (required == requiredMessage),
                    // this is useful for backend translation extraction
                    field.validation.messages[key.replace(/Message$/, '')] = (error, f) => 
                    // translate the validation messages coming from the JSONSchema
                    // TODO: need to remove `as any` once it is fixed in ngx-formly v.5.7.2
                    this.translateService.stream(msg);
                }
            }
            // store the custom validators config
            field.props.customValidators = {};
            if (formOptions.validation && formOptions.validation.validators) {
                for (const customValidator of this.customValidators) {
                    const validatorConfig = formOptions.validation.validators[customValidator];
                    if (validatorConfig != null) {
                        field.props.customValidators[customValidator] = validatorConfig;
                    }
                }
            }
            if (formOptions.validation.validators) {
                // validators: add validator with expressions
                // TODO: use widget
                const validatorsKey = Object.keys(formOptions.validation.validators);
                validatorsKey.map(validatorKey => {
                    const validator = formOptions.validation.validators[validatorKey];
                    if ('expression' in validator && 'message' in validator) {
                        const { expression } = validator;
                        const expressionFn = Function('formControl', `return ${expression};`);
                        const validatorExpression = {
                            expression: (fc) => expressionFn(fc),
                            // translate the validation message coming form the JSONSchema
                            message: this.translateService.stream(validator.message)
                        };
                        field.validators = field.validators !== undefined ? field.validators : {};
                        field.validators[validatorKey] = validatorExpression;
                    }
                });
            }
        }
    }
    /**
     * Convert JSONSchema form options to formly field options.
     * @param field formly field config
     * @param formOptions JSONSchema object
     */
    setSimpleOptions(field, formOptions) {
        // some fields should not submit the form when enter key is pressed
        if (field.props.doNotSubmitOnEnter != null) {
            field.props.keydown = (f, event) => {
                if (event.key === 'Enter') {
                    event.preventDefault();
                }
            };
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JSONSchemaService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JSONSchemaService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JSONSchemaService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class TemplatesService {
    constructor() {
        this.recordService = inject(RecordService);
    }
    /**
     * Get all templates corresponding to a resource type
     * @param templateResourceType - string: the resource name where to find templates
     * @param resourceType - string: the resource type
     * @return an observable of template record
     */
    getTemplates(templateResourceType, resourceType) {
        const query = (resourceType !== undefined)
            ? `template_type:${resourceType}`
            : '';
        return this.recordService.getRecords(templateResourceType, query, 1, RecordService.MAX_REST_RESULTS_SIZE).pipe(map$4((data) => data.hits), map$4(hits => hits.total === 0 ? [] : hits.hits), map$4(hits => hits.map(hit => hit.metadata)));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TemplatesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TemplatesService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TemplatesService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 * Copyright (C) 2020-2023 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class LoadTemplateFormComponent {
    constructor() {
        this.dynamicDialogRef = inject(DynamicDialogRef);
        this.dynamicDialogConfig = inject(DynamicDialogConfig);
        this.recordService = inject(RecordService);
        this.templateService = inject(TemplatesService);
        this.translateService = inject(TranslateService);
        this.router = inject(Router);
        this.messageService = inject(MessageService);
        /** form group */
        this.form = new UntypedFormGroup({});
        /** fields config of the form */
        this.formFields = [];
        this.isDataFormLoaded = false;
        this.isVisible = true;
    }
    ngOnInit() {
        const { data } = this.dynamicDialogConfig;
        this.formFields.push({
            key: 'template',
            type: 'select',
            props: {
                appendTo: 'body',
                required: true,
                group: true,
                filter: true,
                scrollHeight: CONFIG.DEFAULT_SELECT_SCROLL_HEIGHT,
                options: [],
                attributes: {
                    size: 10
                }
            }
        });
        this.templateService.getTemplates(data.templateResourceType, data.resourceType)
            .subscribe((templates) => {
            const items = [];
            // private first
            const privateItems = templates.filter(template => template.visibility === 'private');
            if (privateItems?.length > 0) {
                items.push({
                    label: this.translateService.instant('My private templates'),
                    untranslatedLabel: 'My private templates',
                    items: privateItems.map(item => ({
                        label: item.name,
                        value: item.pid
                    }))
                });
            }
            // public last
            const publicItems = templates.filter(template => template.visibility === 'public');
            if (publicItems?.length > 0) {
                items.push({
                    label: this.translateService.instant('Public templates'),
                    untranslatedLabel: 'Public templates',
                    items: publicItems.map(item => ({
                        label: item.name,
                        value: item.pid
                    }))
                });
            }
            this.formFields[0].props.options = items;
            this.isDataFormLoaded = true;
        });
    }
    /**
     * Submit form hook.
     * Redirect to the same editor form url with query params related to the selected template.
     */
    onSubmitForm() {
        const formValues = this.form.value;
        this.recordService.getRecord('templates', formValues.template).subscribe({
            next: (template) => {
                this.router.navigate([], {
                    queryParams: {
                        source: 'templates',
                        pid: template.id
                    },
                    queryParamsHandling: 'merge',
                    skipLocationChange: true
                });
                this.closeDialog();
            },
            error: (error) => {
                this.messageService.add({
                    severity: 'error',
                    summary: this.translateService.instant('Error'),
                    detail: error.message,
                    sticky: true,
                    closable: true
                });
            }
        });
    }
    closeDialog() {
        this.dynamicDialogRef.close();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LoadTemplateFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: LoadTemplateFormComponent, isStandalone: false, selector: "ng-core-load-template-form", ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n  Copyright (C) 2020 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (isDataFormLoaded) {\n  <form [formGroup]=\"form\" (ngSubmit)=\"onSubmitForm()\">\n    <p-message severity=\"warn\">\n        <div class=\"core:w-full\">\n          <h4 class=\"text-error\" translate>Warning!</h4>\n          <p class=\"core:mt-1\" translate>\n            Loading a template will reload the current form. All values previously encoded will be lost.\n          </p>\n        </div>\n    </p-message>\n\n    <div class=\"core:my-1 core:font-bold\" translate>Select a template</div>\n    <formly-form [form]=\"form\" [fields]=\"formFields\" [model]=\"model\" />\n    <div class=\"core:flex core:justify-end core:gap-2 core:mt-2\">\n      <p-button [label]=\"'Cancel'|translate\" [outlined]=\"true\" severity=\"danger\" (onClick)=\"closeDialog()\" />\n      <p-button type=\"submit\" [label]=\"'Load'|translate\"  [disabled]=\"this.form.status !== 'VALID'\" />\n    </div>\n  </form>\n}\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$1.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i3$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$1.LegacyFormlyForm, selector: "formly-form" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LoadTemplateFormComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-load-template-form', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n  Copyright (C) 2020 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (isDataFormLoaded) {\n  <form [formGroup]=\"form\" (ngSubmit)=\"onSubmitForm()\">\n    <p-message severity=\"warn\">\n        <div class=\"core:w-full\">\n          <h4 class=\"text-error\" translate>Warning!</h4>\n          <p class=\"core:mt-1\" translate>\n            Loading a template will reload the current form. All values previously encoded will be lost.\n          </p>\n        </div>\n    </p-message>\n\n    <div class=\"core:my-1 core:font-bold\" translate>Select a template</div>\n    <formly-form [form]=\"form\" [fields]=\"formFields\" [model]=\"model\" />\n    <div class=\"core:flex core:justify-end core:gap-2 core:mt-2\">\n      <p-button [label]=\"'Cancel'|translate\" [outlined]=\"true\" severity=\"danger\" (onClick)=\"closeDialog()\" />\n      <p-button type=\"submit\" [label]=\"'Load'|translate\"  [disabled]=\"this.form.status !== 'VALID'\" />\n    </div>\n  </form>\n}\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 * Copyright (C) 2020-2023 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class SaveTemplateFormComponent {
    constructor() {
        this.dynamicDialogRef = inject(DynamicDialogRef);
        this.translateService = inject(TranslateService);
        /** form group */
        this.form = new UntypedFormGroup({});
        /** fields config of the form */
        this.formFields = [];
    }
    ngOnInit() {
        this.formFields.push({
            key: 'name',
            type: 'string',
            props: {
                required: true,
                placeholder: this.translateService.instant('Choose a name for your template'),
                minLength: 3,
            }
        });
    }
    /**
     * Submit the form
     */
    onSubmitForm() {
        this.closeDialog(this.form.value);
    }
    /**
     * Close the modal dialog box
     */
    closeDialog(data) {
        this.dynamicDialogRef.close(data);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SaveTemplateFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SaveTemplateFormComponent, isStandalone: false, selector: "ng-core-save-template-form", ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n  Copyright (C) 2020 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n\n<form class=\"core:w-full\" [formGroup]=\"form\" (ngSubmit)=\"onSubmitForm()\">\n    <formly-form class=\"core:w-full\" [form]=\"form\" [fields]=\"formFields\" [model]=\"model\"/>\n    <div class=\"core:flex core:justify-end core:gap-1 core:mt-2\">\n      <p-button [label]=\"'Cancel'|translate\" [outlined]=\"true\" severity=\"danger\" (onClick)=\"closeDialog()\" />\n      <p-button type=\"submit\" [label]=\"'Save'|translate\" [disabled]=\"this.form.status !== 'VALID'\" />\n    </div>\n</form>\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i3$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$1.LegacyFormlyForm, selector: "formly-form" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SaveTemplateFormComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-save-template-form', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n  Copyright (C) 2020 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n\n<form class=\"core:w-full\" [formGroup]=\"form\" (ngSubmit)=\"onSubmitForm()\">\n    <formly-form class=\"core:w-full\" [form]=\"form\" [fields]=\"formFields\" [model]=\"model\"/>\n    <div class=\"core:flex core:justify-end core:gap-1 core:mt-2\">\n      <p-button [label]=\"'Cancel'|translate\" [outlined]=\"true\" severity=\"danger\" (onClick)=\"closeDialog()\" />\n      <p-button type=\"submit\" [label]=\"'Save'|translate\" [disabled]=\"this.form.status !== 'VALID'\" />\n    </div>\n</form>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * For big editor add the possibility to display
 */
class AddFieldEditorComponent {
    constructor() {
        this.translateService = inject(TranslateService);
        this.items = signal([]);
        // Subscriptions to observables.
        this.subscriptions = new Subscription();
        this.essentialsOptions = computed(() => this.items()
            .filter(f => this.isFieldEssential(f)));
    }
    onAddField(event) {
        this.editorComponentInstance.setHide(event.value, false, true);
    }
    /** onInit hook */
    ngOnInit() {
        this.editorComponentInstance = (this.editorComponent)();
        this.subscriptions.add(this.editorComponentInstance.hiddenFields$.pipe(tap((fields) => this.fieldsTranslate(fields))).subscribe());
        this.subscriptions.add(this.translateService.onLangChange.pipe(tap(() => this.fieldsTranslate(this.items()))).subscribe());
    }
    /** onDestroy hook */
    ngOnDestroy() {
        this.subscriptions.unsubscribe();
    }
    search(event) {
        this.suggestions = this.items().filter((item) => {
            return item.props.label.toLowerCase().indexOf(event.query.toLowerCase()) > -1;
        });
    }
    onSelect(event) {
        this.editorComponentInstance.setHide(event.value, false);
        this.autocomplete.clear();
    }
    /**
     * Filter fields to display only essential ones
     * @param field - field to check
     */
    isFieldEssential(field) {
        return field.props?.navigation && field.props.navigation.essential === true;
    }
    fieldsTranslate(fields) {
        this.items.set(fields
            .map((field) => {
            field.props.label = this.translateService.instant(field.props.untranslatedLabel);
            return field;
        })
            .sort((field1, field2) => field1.props.label.localeCompare(field2.props.label)));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddFieldEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: AddFieldEditorComponent, isStandalone: false, selector: "ng-core-editor-add-field-editor", inputs: { editorComponent: "editorComponent" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: ["addField"], descendants: true }], ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n  <div>\n    <p-autoComplete\n      [dropdown]=\"true\"\n      #addField\n      optionLabel=\"props.label\"\n      [placeholder]=\"'Add field' | translate\"\n      styleClass=\"core:mb-2 core:w-full\"\n      [suggestions]=\"suggestions\"\n      (completeMethod)=\"search($event)\"\n      (onSelect)=\"onSelect($event)\"\n      [disabled]=\"items().length < 1\"\n      scrollHeight=\"400px\"\n      appendTo=\"body\"\n    />\n  </div>\n\n@if(essentialsOptions()?.length > 0) {\n  <p-listbox\n    [options]=\"essentialsOptions()\"\n    scrollHeight=\"\"\n    styleClass=\"core:mt-2\"\n    (onChange)=\"onAddField($event)\"\n  >\n    <ng-template #item let-item>\n      {{ item.props.label }}\n    </ng-template>\n  </p-listbox>\n}\n", dependencies: [{ kind: "component", type: i1$3.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "delay", "style", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "disabled", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "maxlength", "name", "required", "size", "appendTo", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "field", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "itemSize", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "variant", "fluid"], outputs: ["completeMethod", "onSelect", "onUnselect", "onFocus", "onBlur", "onDropdownClick", "onClear", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "component", type: i2$2.Listbox, selector: "p-listbox, p-listBox, p-list-box", inputs: ["id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "ariaLabel", "selectOnFocus", "searchLocale", "focusOnHover", "filterMessage", "filterFields", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "scrollHeight", "tabindex", "multiple", "style", "styleClass", "listStyle", "listStyleClass", "readonly", "disabled", "checkbox", "filter", "filterBy", "filterMatchMode", "filterLocale", "metaKeySelection", "dataKey", "showToggleAll", "optionLabel", "optionValue", "optionGroupChildren", "optionGroupLabel", "optionDisabled", "ariaFilterLabel", "filterPlaceHolder", "emptyFilterMessage", "emptyMessage", "group", "options", "filterValue", "selectAll", "striped", "highlightOnSelect", "checkmark", "dragdrop"], outputs: ["onChange", "onClick", "onDblClick", "onFilter", "onFocus", "onBlur", "onSelectAllChange", "onLazyLoad", "onDrop"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AddFieldEditorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-editor-add-field-editor', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n  <div>\n    <p-autoComplete\n      [dropdown]=\"true\"\n      #addField\n      optionLabel=\"props.label\"\n      [placeholder]=\"'Add field' | translate\"\n      styleClass=\"core:mb-2 core:w-full\"\n      [suggestions]=\"suggestions\"\n      (completeMethod)=\"search($event)\"\n      (onSelect)=\"onSelect($event)\"\n      [disabled]=\"items().length < 1\"\n      scrollHeight=\"400px\"\n      appendTo=\"body\"\n    />\n  </div>\n\n@if(essentialsOptions()?.length > 0) {\n  <p-listbox\n    [options]=\"essentialsOptions()\"\n    scrollHeight=\"\"\n    styleClass=\"core:mt-2\"\n    (onChange)=\"onAddField($event)\"\n  >\n    <ng-template #item let-item>\n      {{ item.props.label }}\n    </ng-template>\n  </p-listbox>\n}\n" }]
        }], propDecorators: { editorComponent: [{
                type: Input
            }], autocomplete: [{
                type: ViewChild,
                args: ["addField"]
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class EditorComponent extends AbstractCanDeactivateComponent {
    // current list of hidden fields
    get hiddenFields$() {
        return this._hiddenFieldsSubject.asObservable();
    }
    // Editor long mode
    get longMode() {
        return this.editorSettings.longMode;
    }
    // Editor function
    get editorComponent() {
        return () => this;
    }
    /** Constructor */
    constructor() {
        super();
        this.formlyJsonschema = inject(FormlyJsonschema);
        this.recordService = inject(RecordService);
        this.apiService = inject(ApiService);
        this.route = inject(ActivatedRoute);
        this.recordUiService = inject(RecordUiService);
        this.translateService = inject(TranslateService);
        this.location = inject(Location);
        this.routeCollectionService = inject(RouteCollectionService);
        this.loggerService = inject(LoggerService);
        this.jsonschemaService = inject(JSONSchemaService);
        this.dialogService = inject(DialogService);
        this.messageService = inject(MessageService);
        // form initial values
        this.model = null;
        // initial values changes notification
        this.modelChange = new EventEmitter();
        // editor loading state notifications
        this.loadingChange = new EventEmitter();
        // editor can deactivate change notification
        this.canDeactivateChange = new EventEmitter();
        // Can Deactivate
        this.canDeactivate = false;
        // editor settings
        this.editorSettings = {
            longMode: false, // editor long mode
            template: {
                recordType: undefined, // the resource considerate as template
                loadFromTemplate: false, // enable load from template button
                saveAsTemplate: false // allow to save the record as a template
            }
        };
        // store pid on edit mode
        this.pid = null;
        // save alternatives
        this.saveAlternatives = [];
        // current record type from the url
        this.recordType = null;
        /** Disables the save button during the action */
        this.isSaveButtonDisabled = false;
        // subscribers
        this._subscribers = new Subscription();
        // list of fields to be hidden
        this._hiddenFields = [];
        // Observable of hidden fields
        this._hiddenFieldsSubject = new BehaviorSubject([]);
        this.form = new UntypedFormGroup({});
    }
    /**
     * Component has changed
     * Called before ngOnInit() and whenever one of the input properties change.
     * @param changes: the changed properties
     */
    ngOnChanges(changes) {
        if (changes.model && !changes.model.isFirstChange()) { // Model has changed
            this._setModel(changes.model.currentValue);
            // needed to select the right value for existing data in the multi select
            // components such as oneOf
            if (this.schema) {
                this.setSchema(this.schema);
            }
        }
        if (changes.schema && changes.schema.isFirstChange()) { // Schema has changed
            this.setSchema(changes.schema.currentValue);
        }
        if (changes.pid) { // Assign pid on schema. Reload schema
            this.pid = changes.pid.currentValue;
            if (this.schema) {
                this.setSchema(this.schema);
            }
        }
    }
    /** onInit hook */
    ngOnInit() {
        this.tocFields$ = this.hiddenFields$.pipe(debounceTime(300), switchMap(() => {
            if (this.fields && this.fields.length > 0) {
                return of(this.fields[0].fieldGroup.filter(f => {
                    // hidden properties should not be in the navigation
                    if (f.hide === true) {
                        return false;
                    }
                    // properties with hide wrapper should not be in the navigation
                    if (f.props.alwaysHidden) {
                        return false;
                    }
                    return true;
                }));
            }
            return of([]);
        }));
        combineLatest([this.route.params, this.route.queryParams]).subscribe(([params, queryParams]) => {
            // uncomment for debug
            // this.form.valueChanges.subscribe(v =>
            //   console.log('model', this.model, 'v', v, 'form', this.form, 'field', this.fields)
            // );
            this.loadingChange.emit(true);
            if (!params.type) {
                this.model = {};
                this.schema = {};
                return;
            }
            this.recordType = params.type;
            this.recordUiService.types = this.route.snapshot.data.types;
            this._resourceConfig = this.recordUiService.getResourceConfig(this.recordType);
            if (this._resourceConfig.editorSettings) {
                this.editorSettings = { ...cloneDeep(this.editorSettings), ...this._resourceConfig.editorSettings };
            }
            // load template resource configuration if needed
            //   If editor allowed to use a resource as a template, we need to load the configuration
            //   of this resource and save it into `recordUIService.types` to use it when loading and saving
            if (this.editorSettings.template.recordType !== undefined) {
                const tmplResource = this.routeCollectionService.getRoute(this.editorSettings.template.recordType);
                const tmplConfiguration = tmplResource.getConfiguration();
                if (tmplConfiguration.hasOwnProperty('data')
                    && tmplConfiguration.data.hasOwnProperty('types')) {
                    this.recordUiService.types = this.recordUiService.types.concat(tmplConfiguration.data.types);
                }
            }
            // saveAlternatives construction
            //   Depending of editor configuration, it's possible to provide some alternatives save
            //   methods. Each method must defined a label and a callback function used when user choose
            //   this save method.
            this.saveAlternatives = [];
            if (this.editorSettings.template.saveAsTemplate) {
                this.saveAlternatives.push({
                    label: this.translateService.instant('Save as template') + '…',
                    command: () => this.saveAsTemplate()
                });
            }
            this.pid = params.pid;
            const schema$ = this.recordService.getSchemaForm(this.recordType);
            let record$ = of({ record: {}, result: null });
            // load from template
            //   If the url contains query arguments 'source' and 'pid' and 'source'=='templates'
            //   then we need to use the data from this template as data source to fill the form.
            if (queryParams.source === 'templates' && queryParams.pid != null) {
                record$ = this.recordService.getRecord('templates', queryParams.pid).pipe(map$4((record) => {
                    this.messageService.add({
                        severity: 'success',
                        summary: this.translateService.instant('Template'),
                        detail: this.translateService.instant('Template loaded'),
                        life: CONFIG.MESSAGE_LIFE
                    });
                    return {
                        result: true,
                        record: record.metadata.data
                    };
                }));
                // load data from existing document
                //   If the parsed url contains a 'pid' value, then user try to edit a record. Then
                //   we need to load this record and use it as data source to fill the form.
            }
            else if (this.pid) {
                record$ = this.recordService
                    .getRecord(this.recordType, this.pid)
                    .pipe(switchMap((record) => {
                    return this.recordUiService.canUpdateRecord$(record, this.recordType).pipe(map$4((result) => {
                        return {
                            result,
                            record: record.metadata
                        };
                    }));
                }));
            }
            combineLatest([schema$, record$]).subscribe({
                next: ([schemaform, data]) => {
                    // Set schema
                    this.setSchema(this._resourceConfig.recordResource
                        ? schemaform.schema.properties.metadata
                        : schemaform.schema);
                    // Check permissions and set record
                    if (data.result && data.result.can === false) {
                        this.messageService.add({
                            severity: 'error',
                            summary: this.translateService.instant(this.recordType),
                            detail: this.translateService.instant('You cannot update this record'),
                            sticky: true,
                            closable: true
                        });
                        this.location.back();
                    }
                    else {
                        this._setModel(data.record);
                    }
                    this.loadingChange.emit(false);
                },
                error: (error) => {
                    this.error = error;
                    this.loadingChange.emit(false);
                }
            });
        });
    }
    /** onDestroy hook */
    ngOnDestroy() {
        this._subscribers.unsubscribe();
    }
    /**
     * Set the model
     * @param model: The data to use as new model
     */
    _setModel(model) {
        if (this._resourceConfig != null) {
            // the parent don't know that we are editing a record
            // /!\ This will probably not work anymore with resources managed by
            // invenio-records-resources, a fix will be necessary to make it work
            // with both systems.
            if (!this._resourceConfig.recordResource &&
                this.pid != null &&
                (this.model == null || this.model.pid == null)) {
                model.pid = this.pid;
            }
            // preprocess the model before sending to formly
            this.model = this.preprocessRecord(model);
            this.modelChanged(this.model);
        }
    }
    /**
     * Emit value when model is changed.
     * @param modelValue Model.
     */
    modelChanged(modelValue) {
        this.modelChange.emit(removeEmptyValues(modelValue));
    }
    /**
     * Preprocess the record before passing it to the editor
     * @param record - Record object to preprocess
     */
    preprocessRecord(record) {
        const config = this.recordUiService.getResourceConfig(this.recordType);
        if (config.preprocessRecordEditor) {
            return config.preprocessRecordEditor(record);
        }
        return record;
    }
    /**
     * Postprocess the record before save
     * @param record - Record object to postprocess
     */
    postprocessRecord(record) {
        const config = this.recordUiService.getResourceConfig(this.recordType);
        if (config.postprocessRecordEditor) {
            return config.postprocessRecordEditor(record);
        }
        return record;
    }
    /**
     * Pre Create Record
     * @param record - Record object
     */
    preCreateRecord(record) {
        const config = this.recordUiService.getResourceConfig(this.recordType);
        if (config.preCreateRecord) {
            return config.preCreateRecord(record);
        }
        return record;
    }
    /**
     * Pre Update Record
     * @param record - Record object
     */
    preUpdateRecord(record) {
        const config = this.recordUiService.getResourceConfig(this.recordType);
        if (config.preUpdateRecord) {
            return config.preUpdateRecord(record);
        }
        return record;
    }
    /**
     * Preprocess the record before passing it to the editor
     * @param schema - object, JSONSchema
     */
    setSchema(schema) {
        // reorder all object properties
        this.schema = processJsonSchema(resolve$ref(schema, schema.properties));
        this.options = {};
        // remove hidden field list in case of a previous setSchema call
        this.clearHiddenFields();
        // form configuration
        const editorConfig = {
            pid: this.pid,
            longMode: this.longMode,
            recordType: this.recordType
        };
        const fields = [
            this.formlyJsonschema.toFieldConfig(this.schema, {
                // post process JSONSChema7 to FormlyFieldConfig conversion
                map: (field, jsonSchema) => {
                    /**** additional JSONSchema configurations *******/
                    field = this.jsonschemaService.processField(field, jsonSchema);
                    field.props.editorConfig = editorConfig;
                    field.props.getRoot = (() => this.rootField);
                    field.props.setHide = ((field, value) => this.setHide(field, value));
                    if (this._resourceConfig != null && this._resourceConfig.formFieldMap) {
                        return this._resourceConfig.formFieldMap(field, jsonSchema);
                    }
                    return field;
                }
            })
        ];
        // mark the root field
        fields[0].props.isRoot = true;
        this.fields = fields;
        // set root element
        if (this.fields) {
            this.title = this.fields[0].props?.label;
            this.description = this.fields[0].props?.description;
            this.rootField = this.fields[0];
        }
    }
    /**
     * Save the data on the server.
     */
    submit() {
        this.isSaveButtonDisabled = true;
        this.form.markAllAsTouched();
        if (this.form.valid === false) {
            const fields = [];
            Object.keys(this.form.controls).forEach((key) => {
                if (this.form.controls[key].status !== 'VALID') {
                    fields.push(this.translateService.instant(key));
                }
            });
            let errorMessage = '';
            if (fields.length > 0) {
                errorMessage += "\n" + this.translateService.instant('Field(s) in error: ');
                errorMessage += fields.join(', ');
            }
            this.messageService.add({
                severity: 'error',
                summary: this.translateService.instant(this.recordType),
                detail: this.translateService.instant('The form contains errors.') + errorMessage,
                sticky: true,
                closable: true
            });
            this.isSaveButtonDisabled = false;
            return;
        }
        this._canDeactivate();
        this.loadingChange.emit(true);
        let data = removeEmptyValues(this.model);
        data = this.postprocessRecord(data);
        // For compatibility with resources managed with invenio-records-resources
        if (this._resourceConfig.recordResource) {
            data = { metadata: data };
        }
        // The record has validation, the action `save` is set.
        if (data.metadata?.validation) {
            data.metadata.validation.action = 'save';
        }
        let recordAction$;
        if (this.pid != null) {
            recordAction$ = this.recordService.update(this.recordType, this.pid, this.preUpdateRecord(data)).pipe(catchError((error) => this._handleError(error)), map$4(record => {
                return { record, action: 'update', message: this.translateService.instant('Record updated.') };
            }), finalize(() => this.isSaveButtonDisabled = false));
        }
        else {
            recordAction$ = this.recordService.create(this.recordType, this.preCreateRecord(data)).pipe(catchError((error) => this._handleError(error)), map$4(record => {
                return { record, action: 'create', message: this.translateService.instant('Record created.') };
            }), finalize(() => this.isSaveButtonDisabled = false));
        }
        recordAction$.subscribe(result => {
            this.messageService.add({
                severity: 'success',
                summary: this.translateService.instant(this.recordType),
                detail: this.translateService.instant(result.message),
                life: CONFIG.MESSAGE_LIFE
            });
            this.recordUiService.redirectAfterSave(result.record.id, result.record, this.recordType, result.action, this.route);
            this.loadingChange.emit(true);
        });
    }
    /** Save the current editor content as a template */
    saveAsTemplate() {
        this.ref = this.dialogService.open(SaveTemplateFormComponent, {
            header: this.translateService.instant('Save as template'),
            width: '40vw',
        });
        this.ref.onClose.subscribe(data => {
            if (data) {
                let modelData = removeEmptyValues(this.model);
                modelData = this.postprocessRecord(modelData);
                let record = {
                    name: data.name,
                    data: modelData,
                    template_type: this.recordType
                };
                const tmplConfig = this.recordUiService.getResourceConfig(this.editorSettings.template.recordType);
                if (tmplConfig.preCreateRecord) {
                    record = tmplConfig.preCreateRecord(record);
                }
                this.loadingChange.emit(true);
                this.recordService.create(this.editorSettings.template.recordType, record).subscribe({
                    next: (createdRecord) => {
                        this.messageService.add({
                            severity: 'success',
                            summary: this.translateService.instant(this.editorSettings.template.recordType),
                            detail: this.translateService.instant('Record created.'),
                            life: CONFIG.MESSAGE_LIFE
                        });
                        this.recordUiService.redirectAfterSave(createdRecord.id, createdRecord, this.editorSettings.template.recordType, 'create', this.route);
                    },
                    error: (error) => {
                        this.loadingChange.emit(false);
                        this.messageService.add({
                            severity: 'error',
                            summary: this.translateService.instant(this.editorSettings.template.recordType),
                            detail: error.title,
                            sticky: true,
                            closable: true
                        });
                    }
                });
            }
        });
    }
    /**
     * Scroll the window in to the DOM element corresponding to a given config field.
     * @param event - click DOM event
     * @param field - FormlyFieldConfig, the form config corresponding to the DOM element to jump to.
     */
    setFocus(event, field) {
        event.preventDefault();
        this.setFieldFocus(field, true);
    }
    /**
     * Cancel editing and back to previous page
     */
    cancel() {
        this._canDeactivate();
        this.location.back();
    }
    /**
     * Open a modal dialog box to load a template.
     */
    showLoadTemplateDialog() {
        this.dialogService.open(LoadTemplateFormComponent, {
            header: this.translateService.instant('Load from template'),
            focusOnShow: false,
            width: '50vw',
            position: 'top',
            modal: true,
            dismissableMask: false,
            data: {
                templateResourceType: this.editorSettings.template.recordType,
                resourceType: this.recordType
            }
        });
    }
    /**
     * Can the `load template` should be visible.
     * The 'load template' button will be visible only if the corresponding setting is set and the user
     * isn't in 'edit mode' (load template is only available for new resources)
     * @return True if the button could be visible ; False otherwise
     */
    canLoadTemplate() {
        return this.editorSettings.template.loadFromTemplate && !this.pid;
    }
    /********** Form field manipulation **********/
    /**
     * Scroll to a field or fieldGroup and set focus in the first field candidate.
     * @param field: the field or fieldGroup where to search about field candidate.
     * @param scroll: is the screen should scroll to the field.
     */
    setFieldFocus(field, scroll = false) {
        if (scroll === true && field.id) {
            const el = document.getElementById(`field-${field.id}`);
            if (el != null) {
                // we need to scroll after the focus setTimeout push the action in the
                // next event loop.
                setTimeout(() => el.scrollIntoView({ behavior: 'smooth' }));
                scroll = false;
            }
        }
        if (field.fieldGroup && field.fieldGroup.length > 0) {
            const visibleFields = field.fieldGroup.filter(f => !f.hide);
            if (visibleFields.length > 0) {
                return this.setFieldFocus(visibleFields[0], scroll);
            }
        }
        field.focus = true;
        return true;
    }
    /**
     * Add a field to the hidden list
     * @param field - FormlyFieldConfig, form config to be added
     */
    addHiddenField(field) {
        if (this.isRoot(field.parent)) {
            // formly can change the reference of a field. Especially when the model
            // change such as external import.
            this._hiddenFields = this._hiddenFields.filter(f => f.id !== field.id);
            this._hiddenFields.push(field);
            this._hiddenFieldsSubject.next(this._hiddenFields);
        }
    }
    /**
     * Clear the list of the hidden fields
     */
    clearHiddenFields() {
        this._hiddenFields = [];
        this._hiddenFieldsSubject.next(this._hiddenFields);
    }
    /**
     * Remove a field to the hidden list
     * @param field - FormlyFieldConfig, form config to be removed
     */
    removeHiddenField(field) {
        if (this._hiddenFields.some(f => f.id === field.id) && this.isRoot(field.parent)) {
            // Form is touched if a field is added.
            // Required for hide field in edit mode.
            this.rootField.formControl.markAsTouched();
            this._hiddenFields = this._hiddenFields.filter(f => f.id !== field.id);
            this._hiddenFieldsSubject.next(this._hiddenFields);
        }
    }
    /**
     * Am I at the root of the form?
     * @param field - FormlyFieldConfig, the field to hide
     * @returns boolean, true if I'm the root
     */
    isRoot(field) {
        if (field == null) {
            return false;
        }
        return field.props?.isRoot || false;
    }
    /**
     * Can the field be hidden?
     * @param field - FormlyFieldConfig, the field to hide
     * @returns boolean, true if the field can be hidden
     */
    canHide(field) {
        if (!this.longMode) {
            return false;
        }
        return (!field.props.required &&
            !field.hide &&
            !('hide' in field?.expressions));
    }
    /**
     * Hide the given formly field.
     * @param field - FormlyFieldConfig, the field to hide
     */
    setHide(field, value, scroll = false) {
        if (value) {
            if (field.parent.props.isRoot) {
                this.addHiddenField(field);
            }
        }
        else {
            this.removeHiddenField(field);
            this.setFieldFocus(field, scroll);
        }
        field.hide = value;
    }
    /********************* Private  ***************************************/
    /**
     * Handle form error
     * @param error: object with status and title parameters
     * @return Observable<Error>
     */
    _handleError(error) {
        this.messageService.add({
            severity: 'error',
            summary: this.translateService.instant(error.title),
            detail: this.translateService.instant('Server error.'),
            sticky: true,
            closable: true
        });
        return throwError(() => ({ status: error.status, title: error.title }));
    }
    _canDeactivate(activate = true) {
        this.canDeactivate = activate;
        this.canDeactivateChange.next(activate);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: EditorComponent, isStandalone: false, selector: "ng-core-editor", inputs: { model: "model", schema: "schema", editorSettings: "editorSettings", pid: "pid" }, outputs: { modelChange: "modelChange", loadingChange: "loadingChange", canDeactivateChange: "canDeactivateChange" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n  <div class=\"core:flex core:flex-col core:gap-1\">\n    <div class=\"core:z-10 core:flex core:flex-col core:gap-2 core:bg-white core:sticky core:top-0 core:py-1\">\n      <div class=\"core:flex core:justify-between core:items-center\">\n        @if (rootField) {\n          <legend>\n              <span class=\"core:text-2xl\" [pTooltip]=\"description | translate\" tooltipPosition=\"top\">\n                {{ title || recordType | ucfirst | translate }}\n              </span>\n          </legend>\n        }\n        <div class=\"core:flex core:items-center core:justify-end core:gap-1\">\n          <!-- load from template button -->\n          @if (canLoadTemplate()) {\n            <p-button\n              id=\"editor-load-template-button\"\n              [label]=\"'Load template\u2026' | translate\"\n              [outlined]=\"true\"\n              icon=\"fa fa-upload\"\n              (onClick)=\"showLoadTemplateDialog()\"\n            />\n          }\n          <!-- cancel button -->\n          <p-button\n            id=\"editor-cancel-button\"\n            [label]=\"'Cancel' | translate\"\n            icon=\"fa fa-times\"\n            [outlined]=\"true\"\n            severity=\"danger\"\n            (onClick)=\"cancel()\"\n          />\n        <!-- save button -->\n          @if (saveAlternatives.length === 0) {\n          <p-button\n            id=\"editor-save-button\"\n            [label]=\"'Save' | translate\"\n            (onClick)=\"submit()\"\n            [disabled]=\"isSaveButtonDisabled\"\n          />\n          } @else {\n          <p-splitButton\n            id=\"editor-save-button-split\"\n            [label]=\"'Save' | translate\"\n            (onClick)=\"submit()\"\n            [model]=\"saveAlternatives\"\n          />\n          }\n        </div>\n      </div>\n      <p-divider class=\"core:!mt-0\" />\n    </div>\n\n    <div class=\"core:flex core:gap-2 core:**:min-w-0\">\n      <!-- add fields section -->\n      @if (editorSettings.longMode) {\n        <div class=\"core:flex core:top-18 core:sticky core:flex-[0_0_250px] core:h-[calc(100dvh-(--spacing(18)))] core:overflow-y-auto core:py-1\">\n          <ng-core-editor-add-field-editor [editorComponent]=\"editorComponent\" />\n        </div>\n      }\n\n      <!-- editor itself -->\n      <div class=\"core:grow core:flex core:gap-2\">\n        <!-- ngx-formly -->\n          <formly-form\n            class=\"core:grow\"\n            [model]=\"model\"\n            [fields]=\"fields\"\n            [options]=\"options\"\n            [form]=\"form\"\n            (modelChange)=\"modelChanged($event)\"\n          />\n        @if (editorSettings.longMode) {\n          <!-- TOC navigation -->\n          <div class=\"core:text-sm core:hidden core:lg:block core:flex core:top-18 core:sticky core:flex-[0_0_250px] core:h-[calc(100dvh-(--spacing(18)))] core:overflow-y-auto core:flex-col core:gap-2\">\n              <ng-content select=\"[beforeTableOfContent]\"></ng-content>\n              <span class=\"core:font-bold\" for=\"addField\" translate>Jump to</span>\n              <ul class=\"core:ml-2 core:pl-0 core:list-none\">\n                @for (f of tocFields$ | async; track f.key) {\n                  <li class=\"core:mb-1\">\n                    <span class=\"text-link-secondary\" (click)=\"setFocus($event, f)\">{{ f.props.label | translate }}</span>\n                  </li>\n                }\n              </ul>\n        </div>\n        }\n      </div>\n      </div>\n  </div>\n</form>\n\n@if (error) {\n  <ng-core-error [error]=\"error\" />\n}\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$3.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }, { kind: "component", type: i3$3.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "style", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ErrorComponent, selector: "ng-core-error", inputs: ["error"] }, { kind: "directive", type: i3$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i4$1.LegacyFormlyForm, selector: "formly-form" }, { kind: "component", type: AddFieldEditorComponent, selector: "ng-core-editor-add-field-editor", inputs: ["editorComponent"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: UpperCaseFirstPipe, name: "ucfirst" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: EditorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-editor', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<form [formGroup]=\"form\" (ngSubmit)=\"submit()\">\n  <div class=\"core:flex core:flex-col core:gap-1\">\n    <div class=\"core:z-10 core:flex core:flex-col core:gap-2 core:bg-white core:sticky core:top-0 core:py-1\">\n      <div class=\"core:flex core:justify-between core:items-center\">\n        @if (rootField) {\n          <legend>\n              <span class=\"core:text-2xl\" [pTooltip]=\"description | translate\" tooltipPosition=\"top\">\n                {{ title || recordType | ucfirst | translate }}\n              </span>\n          </legend>\n        }\n        <div class=\"core:flex core:items-center core:justify-end core:gap-1\">\n          <!-- load from template button -->\n          @if (canLoadTemplate()) {\n            <p-button\n              id=\"editor-load-template-button\"\n              [label]=\"'Load template\u2026' | translate\"\n              [outlined]=\"true\"\n              icon=\"fa fa-upload\"\n              (onClick)=\"showLoadTemplateDialog()\"\n            />\n          }\n          <!-- cancel button -->\n          <p-button\n            id=\"editor-cancel-button\"\n            [label]=\"'Cancel' | translate\"\n            icon=\"fa fa-times\"\n            [outlined]=\"true\"\n            severity=\"danger\"\n            (onClick)=\"cancel()\"\n          />\n        <!-- save button -->\n          @if (saveAlternatives.length === 0) {\n          <p-button\n            id=\"editor-save-button\"\n            [label]=\"'Save' | translate\"\n            (onClick)=\"submit()\"\n            [disabled]=\"isSaveButtonDisabled\"\n          />\n          } @else {\n          <p-splitButton\n            id=\"editor-save-button-split\"\n            [label]=\"'Save' | translate\"\n            (onClick)=\"submit()\"\n            [model]=\"saveAlternatives\"\n          />\n          }\n        </div>\n      </div>\n      <p-divider class=\"core:!mt-0\" />\n    </div>\n\n    <div class=\"core:flex core:gap-2 core:**:min-w-0\">\n      <!-- add fields section -->\n      @if (editorSettings.longMode) {\n        <div class=\"core:flex core:top-18 core:sticky core:flex-[0_0_250px] core:h-[calc(100dvh-(--spacing(18)))] core:overflow-y-auto core:py-1\">\n          <ng-core-editor-add-field-editor [editorComponent]=\"editorComponent\" />\n        </div>\n      }\n\n      <!-- editor itself -->\n      <div class=\"core:grow core:flex core:gap-2\">\n        <!-- ngx-formly -->\n          <formly-form\n            class=\"core:grow\"\n            [model]=\"model\"\n            [fields]=\"fields\"\n            [options]=\"options\"\n            [form]=\"form\"\n            (modelChange)=\"modelChanged($event)\"\n          />\n        @if (editorSettings.longMode) {\n          <!-- TOC navigation -->\n          <div class=\"core:text-sm core:hidden core:lg:block core:flex core:top-18 core:sticky core:flex-[0_0_250px] core:h-[calc(100dvh-(--spacing(18)))] core:overflow-y-auto core:flex-col core:gap-2\">\n              <ng-content select=\"[beforeTableOfContent]\"></ng-content>\n              <span class=\"core:font-bold\" for=\"addField\" translate>Jump to</span>\n              <ul class=\"core:ml-2 core:pl-0 core:list-none\">\n                @for (f of tocFields$ | async; track f.key) {\n                  <li class=\"core:mb-1\">\n                    <span class=\"text-link-secondary\" (click)=\"setFocus($event, f)\">{{ f.props.label | translate }}</span>\n                  </li>\n                }\n              </ul>\n        </div>\n        }\n      </div>\n      </div>\n  </div>\n</form>\n\n@if (error) {\n  <ng-core-error [error]=\"error\" />\n}\n" }]
        }], ctorParameters: () => [], propDecorators: { model: [{
                type: Input
            }], modelChange: [{
                type: Output
            }], loadingChange: [{
                type: Output
            }], canDeactivateChange: [{
                type: Output
            }], schema: [{
                type: Input
            }], editorSettings: [{
                type: Input
            }], pid: [{
                type: Input
            }] } });

class Validators {
    static datesGreaterThan(dateFirstName, dateLastName, targetField, strictMode = false) {
        return datesGreaterThanValidator(dateFirstName, dateLastName, targetField, strictMode);
    }
}
function datesGreaterThanValidator(dateFirstName, dateLastName, targetField, strict) {
    return (control) => {
        const dateFormat = 'yyyy-MM-dd';
        const dateFirst = control.parent.get(dateFirstName);
        const dateLast = control.parent.get(dateLastName);
        if (dateFirst.value?.length > 0 && dateLast.value?.length > 0) {
            const dateTimeFirst = DateTime.fromFormat(dateFirst.value, dateFormat);
            const dateTimeLast = DateTime.fromFormat(dateLast.value, dateFormat);
            const status = strict ? dateTimeFirst < dateTimeLast : dateTimeFirst <= dateTimeLast;
            if (status) {
                dateFirst.setErrors(null);
                dateLast.setErrors(null);
            }
            return status;
        }
        return true;
    };
}

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class NgCoreFormlyExtension {
    constructor() {
        this.recordService = inject(RecordService);
        // Types to apply field wrapper on
        this._fieldWrapperTypes = [
            'boolean',
            'datepicker',
            'markdown',
            'passwordGenerator',
            'radioButton',
            'remoteAutoComplete',
            'textarea'
        ];
    }
    /**
     * prePopulate Formly hook
     * @param field - FormlyFieldConfig
     */
    prePopulate(field) {
        if (field.key) {
            field.id = this._getKey(field);
        }
        this._setCustomValidators(field);
        // Set default value from expression.
        if (field.props?.defaultValueExpression) {
            const expression = field.props.defaultValueExpression;
            const expressionFn = Function('expression', `return ${expression};`);
            field.defaultValue = expressionFn();
        }
    }
    /**
     * onPopulate Formly hook
     * @param field - FormlyFieldConfig
     */
    onPopulate(field) {
        // Path of Array
        // Bug issue: https://github.com/ngx-formly/ngx-formly/issues/3914
        if (field?.parent?.type === 'array' && field.type !== 'object' && field.props.required) {
            field.props.required = false;
        }
        this._setWrappers(field);
        this._hideEmptyField(field);
        if (field.props.alwaysHidden) {
            field.props.itemCssClass = 'core:hidden';
        }
        const expressions = field?.expressions;
        if (expressions && expressions['props.required'] !== undefined) {
            field.options.fieldChanges.subscribe((changes) => {
                if (changes.type === 'expressionChanges' &&
                    changes.property === 'props.required' &&
                    changes.value === true &&
                    changes.field.hide === true) {
                    changes.field.hide = false;
                }
            });
        }
    }
    /**
     * Add formly wrappers
     * @param field - FormlyFieldConfig
     */
    _setWrappers(field) {
        // get wrappers from the props (JSONSchema)
        if (field.props) {
            field.wrappers = [...(field.props.wrappers || []), ...(field.wrappers || [])];
        }
        if (field?.props?.editorConfig?.longMode) {
            // add automatically a card wrapper for the first level fields
            const { parent } = field;
            if (parent && parent.props && parent.props.isRoot === true && !field.wrappers.includes('card') && !field.wrappers.includes('hide')) {
                field.wrappers.unshift('card');
            }
        }
        // adds form-fields for non standard field types
        if (this._fieldWrapperTypes.some((elem) => elem === field.type) && !field.wrappers.includes('card')) {
            field.wrappers = [...(field.wrappers || []), 'form-field'];
        }
        // TODO: this can be fixed in a future formly release
        // due to multiple calls (sometimes) we need to make the value unique
        field.wrappers = [...new Set(field.wrappers)];
    }
    /**
     * Create an id html attribute by joining field and parents keys
     * @param field formly field config
     * @returns array - keys to create the id html attribute
     */
    _getKey(field) {
        let parentKey = null;
        const keyParams = [];
        if (field.parent != null) {
            parentKey = this._getKey(field.parent);
            keyParams.push(parentKey);
        }
        if (parentKey != null) {
            if (field.key != null) {
                keyParams.push(field.key);
            }
            else {
                keyParams.push(field.id.replace(/.*__(\d+)$/, '$1'));
            }
            return keyParams.join('-');
        }
        return field.key;
    }
    /**
     * Check if the given field or one of his parents has a hide wrapper
     * @param field - FormlyFieldConfig
     * @return boolean - true if has a hide wrapper
     */
    _hasHideWrapper(field) {
        if (field.wrappers.includes('hide')) {
            return true;
        }
        if (field?.parent) {
            return this._hasHideWrapper(field.parent);
        }
        return false;
    }
    /**
     * Check if the given field has at least on parent marked as hidden.
     * The model should be empty.
     *
     * @param field - FormlyFieldConfig
     * @return boolean - true has a parent marked as hidden.
     */
    _hasHiddenParent(field) {
        if (field?.hide === true) {
            return this._modelIsEmpty(field);
        }
        if (field?.parent) {
            return this._hasHiddenParent(field.parent);
        }
        return false;
    }
    /**
     * Check if a field has an empty model.
     *
     * @param field formly field config
     * @returns true if the given field has an empty model.
     */
    _modelIsEmpty(field) {
        let model = field?.model;
        // for simple object the model is the parent dict
        if (field.model != null && !field.hasOwnProperty('fieldGroup')) {
            // New from ngx-formly v5.9.0
            model = field.model[Array.isArray(field.key) ? field.key[0] : field.key];
        }
        model = removeEmptyValues(model);
        return isEmpty(model);
    }
    /**
     * Hide or show field depending of the data content and the hide property
     * @param field - FormlyFieldConfig
     */
    _hideEmptyField(field) {
        if (!field.props?.editorConfig) {
            return;
        }
        const { pid, longMode } = field.props?.editorConfig;
        if (
        // only in longMode else it will not be possible to unhide a field
        !longMode ||
            // system field has not key
            !field?.key ||
            // ignore array item which as key of the form "0"
            // TODO: find a better way to identify this case
            !isNaN(Number(field.key)) ||
            // ignore field that has hide expression
            'hide' in field?.expressions ||
            // do not hide a field containing a 'hide' wrapper
            this._hasHideWrapper(field) ||
            // do not hide a field that has a parent marked as hidden and a model is empty
            (this._hasHiddenParent(field?.parent) && field.props.hide !== true)) {
            return;
        }
        // is the model empty
        const modelEmpty = this._modelIsEmpty(field);
        if (
        // do not hide field which has value in the model
        modelEmpty &&
            // do not hide required fields
            !field.props.initialRequired) {
            if (
            // hide field marked as hide
            (field.props.hide === true &&
                // do not hide field has been already manipulated
                field.hide === undefined) ||
                // in edition empty fields should be hidden
                (pid != null &&
                    // only during the editor initialization
                    !field?.props?.getRoot()?.formControl?.touched)) {
                field.props.setHide ? field.props.setHide(field, true) : (field.hide = true);
            }
        }
    }
    /**
     * Set custom validators from the props configuration.
     * @param field - FormlyFieldConfig
     */
    _setCustomValidators(field) {
        if (field.props == null || field.props.validation == null) {
            return;
        }
        const customValidators = field.props.validation.validators || {};
        // asyncValidators: valueAlreadyExists
        if (customValidators.valueAlreadyExists) {
            const { filter, limitToValues, term } = customValidators.valueAlreadyExists;
            field.asyncValidators = {
                validation: [
                    (control) => {
                        return this.recordService.uniqueValue(field, field.props.editorConfig.recordType, field.props.editorConfig.pid, term ? term : null, limitToValues ? limitToValues : [], filter ? filter : null);
                    },
                ],
            };
            delete customValidators.valueAlreadyExists;
        }
        // asyncValidators: valueKeysInObject
        //  This validator is similar to uniqueValidator but only check on some specific fields of array items.
        if (customValidators.uniqueValueKeysInObject) {
            field.validators = {
                uniqueValueKeysInObject: {
                    expression: (control) => {
                        // if value isn't an array or array contains less than 2 elements, no need to check
                        if (!(control.value instanceof Array) || control.value.length < 2) {
                            return true;
                        }
                        const keysToKeep = customValidators.uniqueValueKeysInObject.keys;
                        const uniqueItems = Array.from(new Set(control.value.map((v) => {
                            const keys = keysToKeep.reduce((acc, elt) => {
                                acc[elt] = v[elt];
                                return acc;
                            }, {});
                            return JSON.stringify(keys);
                        })));
                        return uniqueItems.length === control.value.length;
                    },
                },
            };
        }
        // asyncValidators: numberOfSpecificValuesInObject
        if (customValidators.numberOfSpecificValuesInObject) {
            field.validators = {
                numberOfSpecificValuesInObject: {
                    expression: (control) => {
                        function objIntersection(a, b) {
                            const k1 = Object.keys(a);
                            return k1.filter((k) => a[k] === b[k]);
                        }
                        const min = customValidators.numberOfSpecificValuesInObject.min || 0;
                        const max = customValidators.numberOfSpecificValuesInObject.max || Infinity;
                        const keys = customValidators.numberOfSpecificValuesInObject.keys;
                        // if value isn't an array and no minimum value is specified, no need to check.
                        if (!(control.value instanceof Array) && min === 0) {
                            return true;
                        }
                        const counter = control.value.filter((element) => objIntersection(keys, element).length > 0).length;
                        return min <= counter && counter <= max;
                    },
                },
            };
        }
        // The start date must be less than the end date.
        if (customValidators.datesGreaterThan) {
            const dateFirst = customValidators.datesGreaterThan.dateFirst;
            const dateLast = customValidators.datesGreaterThan.dateLast;
            const strict = customValidators.datesGreaterThan.strict || false;
            const updateOn = customValidators.datesGreaterThan.updateOn || 'blur';
            const fieldKey = String(field.key);
            field.validators = {
                datesGreaterThan: {
                    updateOn,
                    expression: (control) => Validators.datesGreaterThan(dateFirst, dateLast, fieldKey, strict)(control),
                    message: () => field.props.validation.messages.datesGreaterThan
                },
            };
        }
    }
}
class TranslateExtension {
    constructor() {
        this.translate = inject(TranslateService);
    }
    prePopulate(field) {
        const props = field.props || {};
        // translate only once
        if (props.translated) {
            return;
        }
        props.translated = true;
        // label / title
        if (props.label) {
            // store the untranslated label as the hidden fields are not translated
            props.untranslatedLabel = props.label;
            field.expressions = {
                ...(field.expressions || {}),
                'props.label': this.translate.stream(props.label),
            };
        }
        // description
        if (props.description) {
            field.expressions = {
                ...(field.expressions || {}),
                'props.description': this.translate.stream(props.description),
            };
        }
        // placeholder
        if (props.placeholder) {
            field.expressions = {
                ...(field.expressions || {}),
                'props.placeholder': this.translate.stream(props.placeholder),
            };
        }
        // Save untranslated string
        if (props.addonLeft) {
            props.addonLeftUntranslated = props.addonLeft;
        }
        if (props.addonRight) {
            props.addonRightUntranslated = props.addonRight;
        }
        this.processAllAddon(props);
        this.translate.onLangChange.subscribe(() => {
            this.processAllAddon(props);
        });
    }
    processAllAddon(props) {
        if (props.addonLeft) {
            props.addonLeft = this.processAddon(props.addonLeftUntranslated);
        }
        if (props.addonRight) {
            props.addonRight = this.processAddon(props.addonRightUntranslated);
        }
    }
    processAddon(addon) {
        return addon.map((label) => (label.startsWith('<') ? label : this.translate.instant(label)));
    }
}
class FormOptionsProcessExtension {
    prePopulate(field) {
        // Process options
        if (field.props?.options && !isObservable(field.props.options)) {
            field.props.options = of(this.processOptions(field.props));
        }
        // Process filter options
        if (field.props?.filters?.options && !isObservable(field.props.filters.options)) {
            field.props.filters.options = of(this.processOptions(field.props.filters));
        }
    }
    processOptions(props) {
        this.processUntranslatedLabel(props.options);
        const preferredOptions = props.options.filter((option) => option.preferred);
        if (preferredOptions.length > 0) {
            const options = [];
            props.group = true;
            const otherOptions = props.options.filter((option) => !option.preferred);
            options.push({
                label: 'group-preferred',
                untranslatedLabel: 'group-preferred',
                items: props.sort ? this.sortOptions(preferredOptions) : preferredOptions
            });
            options.push({
                label: 'group-other',
                untranslatedLabel: 'group-other',
                items: props.sort ? this.sortOptions(otherOptions) : otherOptions
            });
            return options;
        }
        else {
            return props.sort ? this.sortOptions(props.options) : props.options;
        }
    }
    processUntranslatedLabel(options) {
        options.map((option) => {
            option.untranslatedLabel = option.label;
            if (option.items) {
                this.processUntranslatedLabel(option.items);
            }
            if (option.children) {
                this.processUntranslatedLabel(option.children);
            }
        });
    }
    sortOptions(options) {
        options = options.sort((a, b) => a.label.localeCompare(b.label));
        if (options.filter((option) => option.items).length > 0) {
            options.forEach((option) => {
                if (option.items) {
                    return this.sortOptions(option.items);
                }
            });
        }
        return options;
    }
}
/**
 * To register an ngx-formly translations extension.
 *
 * @param translate ngx-translate service
 * @param recordService - ng core record service
 * @returns FormlyConfig object configuration
 */
function registerNgCoreFormlyExtension(translate, recordService) {
    return {
        // translate the default validators messages
        // widely inspired from ngx-formly example
        validationMessages: [
            {
                name: 'required',
                // use a marker to force translation extraction due to a bad detection of ngx-translate-extract
                message: () => translate.stream(_('This field is required')),
            },
            {
                name: 'null',
                message: () => translate.stream(_('should be null')),
            },
            {
                name: 'uniqueItems',
                message: () => translate.stream(_('should NOT have duplicate items')),
            },
            {
                name: 'uniqueValueKeysInObject',
                message: () => translate.stream(_('should NOT have duplicate items')),
            },
            {
                name: 'numberOfSpecificValuesInObject',
                message: (_err, field) => {
                    const validatorConfig = field.props.customValidators.numberOfSpecificValuesInObject;
                    const min = validatorConfig.min || 0;
                    const max = validatorConfig.max || Infinity;
                    const { keys } = validatorConfig;
                    // Build a string based on validators specified keys
                    // the object `{a: 'testA', b= 'testB'}` will be transform to a string `a=testA and b=testB`
                    const keysString = Object.keys(keys).map((key) => key + '=' + translate.instant(keys[key]));
                    const joinKeysString = keysString.join(' ' + translate.instant('and') + ' ');
                    // Build a string based on min/max values specified into configuration
                    // depending of min/max configuration, the message must be different
                    let counterMessage = '';
                    if (min > 0 && max < Infinity) {
                        counterMessage =
                            min === max
                                ? translate.instant(_('strictly {{counter}}'), { counter: min })
                                : translate.instant(_('between {{min}} and {{max}}'), { min, max });
                    }
                    else if (min > 0) {
                        counterMessage = translate.instant(_('minimum {{min}}'), { min });
                    }
                    else if (max < Infinity) {
                        counterMessage = translate.instant(_('maximum {{max}}'), { max });
                    }
                    // Combine string to return a full sentence
                    return translate.instant(_('should have {{counter}} {{keys}}'), {
                        counter: counterMessage,
                        keys: joinKeysString,
                    });
                },
            },
            {
                name: 'alreadyTaken',
                message: () => translate.stream(_('the value is already taken')),
            },
            {
                name: 'minLength',
                message: (_err, field) => translate.stream(_('should NOT be shorter than {{minLength}} characters'), {
                    minLength: field.props.minLength,
                }),
            },
            {
                name: 'maxLength',
                message: (_err, field) => translate.stream(_('should NOT be longer than {{maxLength}} characters'), {
                    maxLength: field.props.maxLength,
                }),
            },
            {
                name: 'minItems',
                message: (_err, field) => translate.stream(_('should NOT have fewer than {{minItems}} items'), {
                    minItems: field.props.minItems,
                }),
            },
            {
                name: 'maxItems',
                message: (_err, field) => translate.stream(_('should NOT have more than {{maxItems}} items'), {
                    maxItems: field.props.maxItems,
                }),
            },
            {
                name: 'min',
                message: (_err, field) => translate.stream(_('should be >=  {{min}}'), { min: field.props.min }),
            },
            {
                name: 'max',
                message: (_err, field) => translate.stream(_('should be <=  {{max}}'), { max: field.props.max }),
            },
            {
                name: 'exclusiveMinimum',
                message: (_err, field) => translate.stream(_('should be >  {{step}}'), { step: field.props.step }),
            },
            {
                name: 'exclusiveMaximum',
                message: (_err, field) => translate.stream(_('should be <  {{step}}'), { step: field.props.step }),
            },
            {
                name: 'multipleOf',
                message: (_err, field) => translate.stream(_('should be multiple of ${{step}}'), { step: field.props.step }),
            },
            {
                name: 'const',
                message: (_err, field) => translate.stream(_('should be equal to constant "{{const}}"'), { const: field.props.const }),
            },
        ],
        extensions: [
            {
                name: 'form-options',
                extension: new FormOptionsProcessExtension(),
                priority: 12
            },
            {
                name: 'translate',
                extension: new TranslateExtension(),
                // Execute Translate extension after ng-core extension
                priority: 11,
            },
            {
                name: 'ng-core',
                extension: new NgCoreFormlyExtension(),
                // Execute Core Formly extension after formly processing (priority low)
                // https://main.formly.dev/docs/guide/custom-formly-extension#extension-priority
                priority: 10,
            },
        ],
    };
}

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class DatePickerComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.locale = inject(LOCALE_ID);
        this.value = model();
        this.subscription = new Subscription();
        this.defaultOptions = {
            props: {
                appendTo: 'body',
                clearButtonStyleClass: 'p-button-text',
                dateFormat: 'yy-mm-dd',
                disabled: false,
                firstDayOfWeek: 0,
                fluid: true,
                inline: false,
                numberOfMonths: 1,
                panelStyleClass: 'core:!min-w-0',
                placeholder: 'Select…',
                required: false,
                showButtonBar: false,
                showIcon: true,
                showOnFocus: true,
                stepHour: 1,
                stepMinute: 1,
                stepSecond: 1,
                todayButtonStyleClass: 'p-button-text',
                view: 'date'
            },
        };
        this.defaultDate = undefined;
        this.disabledDates = undefined;
        this.maxDate = undefined;
        this.minDate = undefined;
    }
    ngOnInit() {
        this.subscription.add(this.formControl.valueChanges.subscribe((value) => {
            const date = new Date(value);
            if (this.value() !== date) {
                this.value.set(date);
            }
        }));
        let { value } = this.formControl;
        if (value) {
            this.value.set(new Date(value));
        }
        if (!this.formControl.value && this.props.defaultDate) {
            this.defaultDate = this.processDate(this.props.defaultDate);
        }
        if (this.props.disabledDates) {
            this.disabledDates = this.props.disabledDates.map((date) => this.processDate(date));
        }
        if (this.props.minDate) {
            this.minDate = this.processDate(this.props.minDate);
        }
        if (this.props.maxDate) {
            this.maxDate = this.processDate(this.props.maxDate);
        }
        this.subscription.add(this.value.subscribe((value) => {
            if (value) {
                const convertedDate = this.outputDate(value);
                if (convertedDate !== this.formControl.value) {
                    this.formControl.patchValue(convertedDate);
                }
            }
        }));
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    processDate(date) {
        return date instanceof Date ? date : new Date(date);
    }
    outputDate(value) {
        return DateTime
            .fromJSDate(this.processDate(value))
            .toFormat('yyyy-MM-dd');
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DatePickerComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.14", type: DatePickerComponent, isStandalone: false, selector: "ng-core-date-picker", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, usesInheritance: true, ngImport: i0, template: `
    <p-datepicker
      [(ngModel)]="value"
      [formlyAttributes]="field"
      [appendTo]="props.appendTo"
      [clearButtonStyleClass]="props.clearButtonStyleClass"
      [dateFormat]="props.dateFormat"
      [defaultDate]="props.defaultDate"
      [disabledDates]="disabledDates"
      [disabledDays]="props.disabledDays"
      [firstDayOfWeek]="props.firstDayOfWeek"
      [fluid]="props.fluid"
      [hourFormat]="props.hourFormat"
      [inline]="props.inline"
      [inputStyleClass]="props.inputStyleClass"
      [maxDate]="maxDate"
      [minDate]="minDate"
      [numberOfMonths]="props.numberOfMonths"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder"
      [readonlyInput]="props.readonlyInput"
      [required]="props.required"
      selectionMode="single"
      [showButtonBar]="props.showButtonBar"
      [showIcon]="props.showIcon"
      [showOnFocus]="props.showOnFocus"
      [stepHour]="props.stepHour"
      [stepMinute]="props.stepMinute"
      [stepSecond]="props.stepSecond"
      [styleClass]="props.styleClass"
      [todayButtonStyleClass]="props.todayButtonStyleClass"
      [view]="props.view"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
    />
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i2$4.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DatePickerComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-date-picker',
                    template: `
    <p-datepicker
      [(ngModel)]="value"
      [formlyAttributes]="field"
      [appendTo]="props.appendTo"
      [clearButtonStyleClass]="props.clearButtonStyleClass"
      [dateFormat]="props.dateFormat"
      [defaultDate]="props.defaultDate"
      [disabledDates]="disabledDates"
      [disabledDays]="props.disabledDays"
      [firstDayOfWeek]="props.firstDayOfWeek"
      [fluid]="props.fluid"
      [hourFormat]="props.hourFormat"
      [inline]="props.inline"
      [inputStyleClass]="props.inputStyleClass"
      [maxDate]="maxDate"
      [minDate]="minDate"
      [numberOfMonths]="props.numberOfMonths"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder"
      [readonlyInput]="props.readonlyInput"
      [required]="props.required"
      selectionMode="single"
      [showButtonBar]="props.showButtonBar"
      [showIcon]="props.showIcon"
      [showOnFocus]="props.showOnFocus"
      [stepHour]="props.stepHour"
      [stepMinute]="props.stepMinute"
      [stepSecond]="props.stepSecond"
      [styleClass]="props.styleClass"
      [todayButtonStyleClass]="props.todayButtonStyleClass"
      [view]="props.view"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
    />
  `,
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    standalone: false
                }]
        }] });
class NgCoreFormlyDatePickerModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyDatePickerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyDatePickerModule, declarations: [DatePickerComponent], imports: [CommonModule,
            DatePickerModule,
            FormsModule,
            ReactiveFormsModule, i4$1.FormlyModule], exports: [DatePickerComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyDatePickerModule, imports: [CommonModule,
            DatePickerModule,
            FormsModule,
            ReactiveFormsModule,
            FormlyModule.forChild({
                types: [
                    {
                        name: 'datePicker',
                        component: DatePickerComponent,
                        wrappers: ['form-field'],
                    },
                    {
                        name: 'dateTimePicker', // For compatibility
                        extends: 'datePicker'
                    }
                ],
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyDatePickerModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [DatePickerComponent],
                    imports: [
                        CommonModule,
                        DatePickerModule,
                        FormsModule,
                        ReactiveFormsModule,
                        FormlyModule.forChild({
                            types: [
                                {
                                    name: 'datePicker',
                                    component: DatePickerComponent,
                                    wrappers: ['form-field'],
                                },
                                {
                                    name: 'dateTimePicker', // For compatibility
                                    extends: 'datePicker'
                                }
                            ],
                        }),
                    ],
                    exports: [DatePickerComponent]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class NgCoreFormlyFieldInput extends FieldType {
    constructor() {
        super(...arguments);
        this.defaultOptions = {
            props: {
                class: 'core:w-full',
                inputStep: 'any'
            }
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyFieldInput, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: NgCoreFormlyFieldInput, isStandalone: false, selector: "ng-core-formly-field-primeng-input", usesInheritance: true, ngImport: i0, template: `
    @if (props.addonLeft || props.addonRight) {
      <p-inputgroup>
          @if (props.addonLeft) {
            @for (prop of props.addonLeft; track prop) {
              <p-inputgroup-addon [innerHTML]="prop"></p-inputgroup-addon>
            }
          }
          <ng-container
            [ngTemplateOutlet]="input"
            [ngTemplateOutletContext]="{ formControl, props, field, showError }"
          />
          @if (props.addonRight) {
            @for (prop of props.addonRight; track prop) {
              <p-inputgroup-addon [innerHTML]="prop"></p-inputgroup-addon>
            }
          }
      </p-inputgroup>
    } @else {
      <ng-container
        [ngTemplateOutlet]="input"
        [ngTemplateOutletContext]="{ formControl, props, field, showError }"
      />
    }
    <ng-template #input let-formControl="formControl" let-props="props" let-field="field" let-showError="showError">
      @if (props.type === 'number') {
        <input
          pInputText
          [class]="props.class"
          type="number"
          [attr.step]="props.inputStep"
          [formControl]="formControl"
          [formlyAttributes]="field"
          [ngClass]="{ 'ng-invalid ng-dirty': showError }"
        />
      } @else {
        <input
          pInputText
          [class]="props.class"
          [type]="props.type || 'text'"
          [formControl]="formControl"
          [formlyAttributes]="field"
          [ngClass]="{ 'ng-invalid ng-dirty': showError }"
        />
      }
    </ng-template>
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i3$1.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["style", "styleClass"] }, { kind: "component", type: i3.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyFieldInput, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-formly-field-primeng-input',
                    template: `
    @if (props.addonLeft || props.addonRight) {
      <p-inputgroup>
          @if (props.addonLeft) {
            @for (prop of props.addonLeft; track prop) {
              <p-inputgroup-addon [innerHTML]="prop"></p-inputgroup-addon>
            }
          }
          <ng-container
            [ngTemplateOutlet]="input"
            [ngTemplateOutletContext]="{ formControl, props, field, showError }"
          />
          @if (props.addonRight) {
            @for (prop of props.addonRight; track prop) {
              <p-inputgroup-addon [innerHTML]="prop"></p-inputgroup-addon>
            }
          }
      </p-inputgroup>
    } @else {
      <ng-container
        [ngTemplateOutlet]="input"
        [ngTemplateOutletContext]="{ formControl, props, field, showError }"
      />
    }
    <ng-template #input let-formControl="formControl" let-props="props" let-field="field" let-showError="showError">
      @if (props.type === 'number') {
        <input
          pInputText
          [class]="props.class"
          type="number"
          [attr.step]="props.inputStep"
          [formControl]="formControl"
          [formlyAttributes]="field"
          [ngClass]="{ 'ng-invalid ng-dirty': showError }"
        />
      } @else {
        <input
          pInputText
          [class]="props.class"
          [type]="props.type || 'text'"
          [formControl]="formControl"
          [formlyAttributes]="field"
          [ngClass]="{ 'ng-invalid ng-dirty': showError }"
        />
      }
    </ng-template>
  `,
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class NgCoreFormlyInputModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyInputModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyInputModule, declarations: [NgCoreFormlyFieldInput], imports: [CommonModule,
            ReactiveFormsModule,
            InputTextModule,
            InputNumberModule,
            InputGroupModule,
            InputGroupAddonModule,
            FormlyFormFieldModule, i4$1.FormlyModule], exports: [NgCoreFormlyFieldInput] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyInputModule, imports: [CommonModule,
            ReactiveFormsModule,
            InputTextModule,
            InputNumberModule,
            InputGroupModule,
            InputGroupAddonModule,
            FormlyFormFieldModule,
            FormlyModule.forChild({
                types: [
                    {
                        name: 'input',
                        component: NgCoreFormlyFieldInput,
                        wrappers: ['form-field'],
                    },
                    { name: 'string', extends: 'input' },
                    {
                        name: 'number',
                        extends: 'input',
                        defaultOptions: {
                            props: {
                                type: 'number',
                            },
                        },
                    },
                    {
                        name: 'integer',
                        extends: 'input',
                        defaultOptions: {
                            props: {
                                type: 'number',
                            },
                        },
                    },
                ],
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyInputModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [NgCoreFormlyFieldInput],
                    imports: [
                        CommonModule,
                        ReactiveFormsModule,
                        InputTextModule,
                        InputNumberModule,
                        InputGroupModule,
                        InputGroupAddonModule,
                        FormlyFormFieldModule,
                        FormlyModule.forChild({
                            types: [
                                {
                                    name: 'input',
                                    component: NgCoreFormlyFieldInput,
                                    wrappers: ['form-field'],
                                },
                                { name: 'string', extends: 'input' },
                                {
                                    name: 'number',
                                    extends: 'input',
                                    defaultOptions: {
                                        props: {
                                            type: 'number',
                                        },
                                    },
                                },
                                {
                                    name: 'integer',
                                    extends: 'input',
                                    defaultOptions: {
                                        props: {
                                            type: 'number',
                                        },
                                    },
                                },
                            ],
                        }),
                    ],
                    exports: [NgCoreFormlyFieldInput]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class TranslateLabelService {
    constructor() {
        this.translateService = inject(TranslateService);
    }
    translateLabel(options) {
        options.map((option) => {
            if (!option.untranslatedLabel) {
                option.untranslatedLabel = option.label;
            }
            option.label = this.translateService.instant(option.untranslatedLabel);
            if (option.items) {
                this.translateLabel(option.items);
            }
            if (option.children) {
                this.translateLabel(option.children);
            }
        });
        return options;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLabelService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLabelService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TranslateLabelService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class MultiCheckboxComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.translateService = inject(TranslateService);
        this.translateLabelService = inject(TranslateLabelService);
        this.ref = inject(ChangeDetectorRef);
        this.subscription = new Subscription();
        /** Default options */
        this.defaultOptions = {
            props: {
                style: 'stacked'
            }
        };
        this.multiCheckBoxValue = [];
    }
    ngOnInit() {
        const optionsObs = this.props.options;
        const changeObs = this.translateService.onLangChange.pipe(switchMap$1(() => this.optionValues$));
        this.optionValues$ = merge(...[optionsObs, changeObs])
            .pipe(map$5(options => {
            this.ref.markForCheck();
            return this.translateLabelService.translateLabel(options);
        }));
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    onChange(event) {
        this.field.formControl.patchValue(event.checked);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MultiCheckboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: MultiCheckboxComponent, isStandalone: false, selector: "ng-core-multi-checkbox", usesInheritance: true, ngImport: i0, template: `
    <div class="core:flex" [ngClass]="{ 'core:gap-3': props.style === 'inline', 'core:flex-col core:gap-1': props.style === 'stacked', 'p-inputtext ng-invalid ng-dirty': showError }">
    @for (option of optionValues$|async|keyvalue; track option.key) {
      @let fieldKey = field.key + '_' + option.key;
      <div class="core:flex core:items-center core:gap-2">
        <p-checkbox
          [disabled]="option.value.disabled"
          [formlyAttributes]="field"
          [inputId]="fieldKey"
          [name]="field.key"
          [ngModel]="field.formControl.value"
          [readonly]="props.readonly"
          [styleClass]="props.styleClass"
          [value]="option.value.value"
          (onChange)="onChange($event)"
        />
        <label [for]="fieldKey" [class]="props.labelStyleClass">{{ option.value.label }}</label>
      </div>
    }
    </div>
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i2$5.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$2.KeyValuePipe, name: "keyvalue" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MultiCheckboxComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-multi-checkbox',
                    template: `
    <div class="core:flex" [ngClass]="{ 'core:gap-3': props.style === 'inline', 'core:flex-col core:gap-1': props.style === 'stacked', 'p-inputtext ng-invalid ng-dirty': showError }">
    @for (option of optionValues$|async|keyvalue; track option.key) {
      @let fieldKey = field.key + '_' + option.key;
      <div class="core:flex core:items-center core:gap-2">
        <p-checkbox
          [disabled]="option.value.disabled"
          [formlyAttributes]="field"
          [inputId]="fieldKey"
          [name]="field.key"
          [ngModel]="field.formControl.value"
          [readonly]="props.readonly"
          [styleClass]="props.styleClass"
          [value]="option.value.value"
          (onChange)="onChange($event)"
        />
        <label [for]="fieldKey" [class]="props.labelStyleClass">{{ option.value.label }}</label>
      </div>
    }
    </div>
  `,
                    standalone: false
                }]
        }] });
class NgCoreFormlyMultiCheckboxModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiCheckboxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiCheckboxModule, declarations: [MultiCheckboxComponent], imports: [CommonModule,
            CheckboxModule,
            FormsModule, i5.TranslateModule, FormlySelectModule, i4$1.FormlyModule], exports: [MultiCheckboxComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiCheckboxModule, imports: [CommonModule,
            CheckboxModule,
            FormsModule,
            TranslateModule.forChild(),
            FormlySelectModule,
            FormlyModule.forChild({
                types: [
                    {
                        name: 'multi-checkbox',
                        component: MultiCheckboxComponent,
                        wrappers: ['form-field'],
                    }
                ],
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiCheckboxModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [MultiCheckboxComponent],
                    imports: [
                        CommonModule,
                        CheckboxModule,
                        FormsModule,
                        TranslateModule.forChild(),
                        FormlySelectModule,
                        FormlyModule.forChild({
                            types: [
                                {
                                    name: 'multi-checkbox',
                                    component: MultiCheckboxComponent,
                                    wrappers: ['form-field'],
                                }
                            ],
                        }),
                    ],
                    exports: [MultiCheckboxComponent]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class MultiSelectComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.translateService = inject(TranslateService);
        this.translateLabelService = inject(TranslateLabelService);
        this.ref = inject(ChangeDetectorRef);
        this.subscription = new Subscription();
        this.filter = false;
        /** Default properties */
        this.defaultOptions = {
            props: {
                display: 'comma',
                editable: false,
                filterMatchMode: 'contains',
                fluid: true,
                group: false,
                placeholder: 'Select…',
                required: false,
                scrollHeight: CONFIG.DEFAULT_SELECT_SCROLL_HEIGHT,
                sort: false,
                tooltipPosition: 'top',
                tooltipPositionStyle: 'absolute',
                variant: 'outlined',
            },
        };
    }
    ngOnInit() {
        const optionsObs = this.props.options;
        const changeObs = this.translateService.onLangChange.pipe(switchMap$1(() => this.optionValues$));
        this.optionValues$ = merge(...[optionsObs, changeObs])
            .pipe(tap$1((options) => {
            this.filter = this.enableFilter(options, 0).enabled;
        }), map$5(options => {
            this.ref.markForCheck();
            return this.translateLabelService.translateLabel(options);
        }));
    }
    /**
     * Check if the filter feature of the select should be enabled.
     *
     * This function is interrupted if the threshold is reached.
     *
     * @param options the list of options
     * @param numberOfOptions the numberOfOptions used by the recursion
     * @returns enabled: true if the filter should be enabled, the current total of detected options (used by the recursion)
     */
    enableFilter(options, numberOfOptions = 0) {
        if (!options?.length) {
            return { total: numberOfOptions, enabled: false };
        }
        // number of entries to enable the filter
        const limit = 5;
        let total = numberOfOptions + options.length;
        if (total > limit) {
            return { enabled: true, total };
        }
        for (const option of options) {
            const child = this.enableFilter(option?.items, total);
            total = child.total;
            if (total > limit) {
                return { enabled: total > limit, total };
            }
        }
        return { enabled: total > limit, total };
    }
    // Clear all validators except required.
    clearValidators() {
        const { errors } = this.formControl;
        this.formControl.setErrors(errors.required ? { required: true } : null);
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MultiSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: MultiSelectComponent, isStandalone: false, selector: "ng-core-multi-select", usesInheritance: true, ngImport: i0, template: `
    <p-multiSelect
      [appendTo]="props.appendTo"
      [class]="props.class"
      [display]="props.display"
      [dropdownIcon]="props.dropdownIcon"
      [emptyFilterMessage]="props.emptyFilterMessage"
      [emptyMessage]="props.emptyMessage"
      [filter]="filter"
      filterBy="label"
      [fluid]="props.fluid"
      [formControl]="formControl"
      [formlyAttributes]="field"
      [group]="props.group"
      [loadingIcon]="props.loadingIcon"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
      [options]="optionValues$|async"
      optionLabel="label"
      optionValue="value"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder | translate"
      [required]="props.required"
      [showClear]="!props.required"
      [styleClass]="props.styleClass"
      [tooltip]="props.tooltip"
      [tooltipPosition]="props.tooltipPosition"
      [tooltipPositionStyle]="props.tooltipPositionStyle"
      [tooltipStyleClass]="props.tooltipStyleClass"
      (onChange)="props.change && props.change(field, $event)"
      (onClear)="clearValidators()"
    >
      <ng-template #selectedItems let-items>
        @for(option of items; track option.value; let last = $last) {
          <div class="core:inline-flex core:items-center core:gap-2 core:px-1">
            <div>
              {{ option.label }}@if(!last) {, }
            </div>
          </div>
        }
        @if (!items || items.length === 0) {
          <div>{{ props.placeholder | translate }}</div>
        }
      </ng-template>
      <ng-template let-item #item>
        <span class="core:whitespace-normal">
          {{item.label}}
        </span>
      </ng-template>
      <ng-template let-group #group>
        @if (group.untranslatedLabel !== 'group-preferred' && group.untranslatedLabel !== 'group-other') {
          <div class="core:py-2 core:font-bold">{{ group.label }}</div>
        } @else if (group.label === 'group-other') {
          <div class="core:py-2"><hr></div>
        }
      </ng-template>
    </p-multiSelect>
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i3$4.MultiSelect, selector: "p-multiSelect, p-multiselect, p-multi-select", inputs: ["id", "ariaLabel", "style", "styleClass", "panelStyle", "panelStyleClass", "inputId", "disabled", "fluid", "readonly", "group", "filter", "filterPlaceHolder", "filterLocale", "overlayVisible", "tabindex", "variant", "appendTo", "dataKey", "name", "ariaLabelledBy", "displaySelectedLabel", "maxSelectedLabels", "selectionLimit", "selectedItemsLabel", "showToggleAll", "emptyFilterMessage", "emptyMessage", "resetFilterOnHide", "dropdownIcon", "chipIcon", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "showHeader", "filterBy", "scrollHeight", "lazy", "virtualScroll", "loading", "virtualScrollItemSize", "loadingIcon", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "autofocusFilter", "display", "autocomplete", "size", "showClear", "autofocus", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "defaultLabel", "placeholder", "options", "filterValue", "itemSize", "selectAll", "focusOnHover", "filterFields", "selectOnFocus", "autoOptionFocus", "highlightOnSelect"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onClear", "onPanelShow", "onPanelHide", "onLazyLoad", "onRemove", "onSelectAllChange"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MultiSelectComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-multi-select',
                    template: `
    <p-multiSelect
      [appendTo]="props.appendTo"
      [class]="props.class"
      [display]="props.display"
      [dropdownIcon]="props.dropdownIcon"
      [emptyFilterMessage]="props.emptyFilterMessage"
      [emptyMessage]="props.emptyMessage"
      [filter]="filter"
      filterBy="label"
      [fluid]="props.fluid"
      [formControl]="formControl"
      [formlyAttributes]="field"
      [group]="props.group"
      [loadingIcon]="props.loadingIcon"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
      [options]="optionValues$|async"
      optionLabel="label"
      optionValue="value"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder | translate"
      [required]="props.required"
      [showClear]="!props.required"
      [styleClass]="props.styleClass"
      [tooltip]="props.tooltip"
      [tooltipPosition]="props.tooltipPosition"
      [tooltipPositionStyle]="props.tooltipPositionStyle"
      [tooltipStyleClass]="props.tooltipStyleClass"
      (onChange)="props.change && props.change(field, $event)"
      (onClear)="clearValidators()"
    >
      <ng-template #selectedItems let-items>
        @for(option of items; track option.value; let last = $last) {
          <div class="core:inline-flex core:items-center core:gap-2 core:px-1">
            <div>
              {{ option.label }}@if(!last) {, }
            </div>
          </div>
        }
        @if (!items || items.length === 0) {
          <div>{{ props.placeholder | translate }}</div>
        }
      </ng-template>
      <ng-template let-item #item>
        <span class="core:whitespace-normal">
          {{item.label}}
        </span>
      </ng-template>
      <ng-template let-group #group>
        @if (group.untranslatedLabel !== 'group-preferred' && group.untranslatedLabel !== 'group-other') {
          <div class="core:py-2 core:font-bold">{{ group.label }}</div>
        } @else if (group.label === 'group-other') {
          <div class="core:py-2"><hr></div>
        }
      </ng-template>
    </p-multiSelect>
  `,
                    standalone: false
                }]
        }] });
class NgCoreFormlyMultiSelectModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiSelectModule, declarations: [MultiSelectComponent], imports: [CommonModule,
            ReactiveFormsModule, i5.TranslateModule, FormlySelectModule,
            MultiSelectModule, i4$1.FormlyModule], exports: [MultiSelectComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiSelectModule, imports: [CommonModule,
            ReactiveFormsModule,
            TranslateModule.forChild(),
            FormlySelectModule,
            MultiSelectModule,
            FormlyModule.forChild({
                types: [
                    {
                        name: 'multi-select',
                        component: MultiSelectComponent,
                        wrappers: ['form-field'],
                    },
                ],
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyMultiSelectModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [MultiSelectComponent],
                    imports: [
                        CommonModule,
                        ReactiveFormsModule,
                        TranslateModule.forChild(),
                        FormlySelectModule,
                        MultiSelectModule,
                        FormlyModule.forChild({
                            types: [
                                {
                                    name: 'multi-select',
                                    component: MultiSelectComponent,
                                    wrappers: ['form-field'],
                                },
                            ],
                        }),
                    ],
                    exports: [MultiSelectComponent],
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
// Override this service in your application to implement your logic
class RemoteAutocompleteService {
    getSuggestions(query, queryOptions, currentPid) {
        return of([{ label: "test" }]);
    }
    getValueAsHTML(queryOptions, item) {
        return of(item.label);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RemoteAutocompleteService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RemoteAutocompleteService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RemoteAutocompleteService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RemoteAutocomplete extends FieldType {
    constructor() {
        super(...arguments);
        this.translateService = inject(TranslateService);
        this.remoteAutocompleteService = inject(RemoteAutocompleteService);
        this.route = inject(ActivatedRoute);
        this.ref = inject(ChangeDetectorRef);
        this.query = new Subject();
        this.onValueSelect = new Subject();
        this.suggestions = toSignal(this.query.pipe(switchMap$1((data) => this.remoteAutocompleteService.getSuggestions(data.query, data.queryOptions, data.recordPid))), { initialValue: [] });
        this.valueSelected = toSignal(this.onValueSelect.pipe(switchMap$1((data) => this.remoteAutocompleteService.getValueAsHTML(data.queryOptions, data.item))));
        /** Default properties */
        this.defaultOptions = {
            props: {
                delay: 300,
                group: false,
                minLength: 3,
                scrollHeight: CONFIG.DEFAULT_SELECT_SCROLL_HEIGHT,
                queryOptions: {
                    allowAdd: false,
                    maxOfResult: 100
                }
            }
        };
        this.value = '';
    }
    ngOnInit() {
        if (this.props.filters) {
            const optionsObs = this.props.filters.options;
            const changeObs = this.translateService.onLangChange.pipe(switchMap$1(() => this.optionValues$));
            this.optionValues$ = merge(...[optionsObs, changeObs])
                .pipe(map$5(options => {
                this.ref.markForCheck();
                return this.translateLabel(options);
            }));
        }
    }
    ngAfterViewInit() {
        if (this.field.props.filters) {
            this.field.props.queryOptions.filter = this.field.props.filters.selected;
        }
        if (this.field.formControl?.value?.length > 0) {
            this.onValueSelect.next({
                item: { label: this.field.formControl.value, value: this.field.formControl.value },
                queryOptions: { ...this.field.props.queryOptions },
            });
        }
    }
    changeFilter(filter) {
        this.field.props.queryOptions.filter = filter.value;
        this.value = '';
    }
    search(event) {
        this.query.next({
            query: event.query,
            queryOptions: { ...this.field.props.queryOptions },
            recordPid: this.route.snapshot.params.pid || null
        });
    }
    onSelect(event) {
        this.onValueSelect.next({
            item: event.value,
            queryOptions: { ...this.field.props.queryOptions },
        });
        this.formControl.patchValue(event.value.value);
    }
    clear() {
        this.value = '';
        this.formControl.reset(null);
        this.field.focus = true;
    }
    translateLabel(options) {
        options.map((option) => {
            if (!option.untranslatedLabel) {
                option.untranslatedLabel = option.label;
            }
            option.label = this.translateService.instant(option.untranslatedLabel);
        });
        return options;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RemoteAutocomplete, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RemoteAutocomplete, isStandalone: false, selector: "ng-core-remote-autocomplete", usesInheritance: true, ngImport: i0, template: `
  <div style="padding-inline: 0; padding-block: 0" class="core:flex core:gap-1" [ngClass]="{ 'p-inputtext ng-invalid ng-dirty': showError }">
    @if (!field.formControl.value) {
      @if (props.filters?.options) {
        <p-select
          [options]="optionValues$|async"
          [ngModel]="props.filters.selected"
          (onChange)="changeFilter($event)"
        >
          <ng-template let-selected #selectedItem>
            {{ selected.untranslatedLabel | translate }}
          </ng-template>
        </p-select>
      }
        <p-autoComplete
          class="core:grow"
          styleClass="core:w-full"
          inputStyleClass="core:w-full"
          [scrollHeight]="props.scrollHeight"
          [minLength]="props.minLength"
          [maxlength]="props.maxLength"
          [(ngModel)]="value"
          [placeholder]="props.placeholder"
          [group]="props.group"
          [suggestions]="suggestions()"
          (completeMethod)="search($event)"
          (onSelect)="onSelect($event)"
        >
          <ng-template #item let-data>
            <div class="core:w-full">
              <div class="core:flex core:gap-2">
                <span class="core:grow" [innerHTML]="data.label"></span>
                @if (data.link) {
                  <a class="core:flex-none core:text-color-secondary" [href]="data.link" target="_blank">
                    <i class="fa fa-external-link"></i>
                  </a>
                }
              </div>
              @if (data.summary) {
                <div class="core:w-full" [innerHTML]="data.summary" [ngClass]="props.summaryClass"></div>
              }
            </div>
          </ng-template>
        </p-autoComplete>
    } @else {
      <div class="core:flex core:gap-1 core:items-center">
        <div [innerHtml]="valueSelected()"></div>
        <p-button icon="fa fa-trash" severity="secondary" [text]="true" (onClick)="clear()" />
      </div>
    }
  </div>
  `, isInline: true, dependencies: [{ kind: "component", type: i1$3.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "delay", "style", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "disabled", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "maxlength", "name", "required", "size", "appendTo", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "field", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "itemSize", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "variant", "fluid"], outputs: ["completeMethod", "onSelect", "onUnselect", "onFocus", "onBlur", "onDropdownClick", "onClear", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RemoteAutocomplete, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-remote-autocomplete',
                    standalone: false,
                    template: `
  <div style="padding-inline: 0; padding-block: 0" class="core:flex core:gap-1" [ngClass]="{ 'p-inputtext ng-invalid ng-dirty': showError }">
    @if (!field.formControl.value) {
      @if (props.filters?.options) {
        <p-select
          [options]="optionValues$|async"
          [ngModel]="props.filters.selected"
          (onChange)="changeFilter($event)"
        >
          <ng-template let-selected #selectedItem>
            {{ selected.untranslatedLabel | translate }}
          </ng-template>
        </p-select>
      }
        <p-autoComplete
          class="core:grow"
          styleClass="core:w-full"
          inputStyleClass="core:w-full"
          [scrollHeight]="props.scrollHeight"
          [minLength]="props.minLength"
          [maxlength]="props.maxLength"
          [(ngModel)]="value"
          [placeholder]="props.placeholder"
          [group]="props.group"
          [suggestions]="suggestions()"
          (completeMethod)="search($event)"
          (onSelect)="onSelect($event)"
        >
          <ng-template #item let-data>
            <div class="core:w-full">
              <div class="core:flex core:gap-2">
                <span class="core:grow" [innerHTML]="data.label"></span>
                @if (data.link) {
                  <a class="core:flex-none core:text-color-secondary" [href]="data.link" target="_blank">
                    <i class="fa fa-external-link"></i>
                  </a>
                }
              </div>
              @if (data.summary) {
                <div class="core:w-full" [innerHTML]="data.summary" [ngClass]="props.summaryClass"></div>
              }
            </div>
          </ng-template>
        </p-autoComplete>
    } @else {
      <div class="core:flex core:gap-1 core:items-center">
        <div [innerHtml]="valueSelected()"></div>
        <p-button icon="fa fa-trash" severity="secondary" [text]="true" (onClick)="clear()" />
      </div>
    }
  </div>
  `,
                }]
        }] });
class NgCoreFormlyRemoteAutocompleteModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyRemoteAutocompleteModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyRemoteAutocompleteModule, declarations: [RemoteAutocomplete], imports: [AutoCompleteModule,
            ButtonModule,
            CommonModule,
            SelectModule,
            FormsModule, i5.TranslateModule, i4$1.FormlyModule], exports: [RemoteAutocomplete] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyRemoteAutocompleteModule, imports: [AutoCompleteModule,
            ButtonModule,
            CommonModule,
            SelectModule,
            FormsModule,
            TranslateModule.forChild(),
            FormlyModule.forChild({
                types: [
                    { name: 'remoteAutoComplete', component: RemoteAutocomplete }
                ]
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyRemoteAutocompleteModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [RemoteAutocomplete],
                    imports: [
                        AutoCompleteModule,
                        ButtonModule,
                        CommonModule,
                        SelectModule,
                        FormsModule,
                        TranslateModule.forChild(),
                        FormlyModule.forChild({
                            types: [
                                { name: 'remoteAutoComplete', component: RemoteAutocomplete }
                            ]
                        }),
                    ],
                    exports: [RemoteAutocomplete]
                }]
        }] });

;

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class SelectComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.translateService = inject(TranslateService);
        this.translateLabelService = inject(TranslateLabelService);
        this.ref = inject(ChangeDetectorRef);
        this.subscription = new Subscription();
        this.filter = false;
        /** Default properties */
        this.defaultOptions = {
            props: {
                disabled: false,
                editable: false,
                filterMatchMode: 'contains',
                fluid: true,
                group: false,
                placeholder: _('Select…'),
                required: false,
                scrollHeight: CONFIG.DEFAULT_SELECT_SCROLL_HEIGHT,
                sort: false,
                tooltipPosition: 'top',
                tooltipPositionStyle: 'absolute',
            }
        };
    }
    ngOnInit() {
        const optionsObs = this.props.options;
        const changeObs = this.translateService.onLangChange.pipe(switchMap$1(() => this.optionValues$));
        if (this.field.props?.disabled) {
            this.formControl.disable();
        }
        this.optionValues$ = merge(...[optionsObs, changeObs])
            .pipe(tap$1((options) => {
            this.filter = this.enableFilter(options, 0).enabled;
        }), map$5(options => {
            this.ref.markForCheck();
            return this.translateLabelService.translateLabel(options);
        }));
    }
    /**
     * Check if the filter feature of the select should be enabled.
     *
     * This function is interrupted if the threshold is reached.
     *
     * @param options the list of options
     * @param numberOfOptions the numberOfOptions used by the recursion
     * @returns enabled: true if the filter should be enabled, the current total of detected options (used by the recursion)
     */
    enableFilter(options, numberOfOptions = 0) {
        if (!options?.length) {
            return { total: numberOfOptions, enabled: false };
        }
        // number of entries to enable the filter
        const limit = 5;
        let total = numberOfOptions + options.length;
        if (total > limit) {
            return { enabled: true, total };
        }
        for (const option of options) {
            const child = this.enableFilter(option?.items, total);
            total = child.total;
            if (total > limit) {
                return { enabled: total > limit, total };
            }
        }
        return { enabled: total > limit, total };
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    clearValidators() {
        const { errors } = this.formControl;
        this.formControl.setErrors(errors.required ? { required: true } : null);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SelectComponent, isStandalone: false, selector: "ng-core-primeng-select", usesInheritance: true, ngImport: i0, template: `
  @if(props.options) {
    <p-select
      [appendTo]="props.appendTo"
      [class]="props.class"
      [dropdownIcon]="props.dropdownIcon"
      [editable]="props.editable"
      [emptyFilterMessage]="props.emptyFilterMessage"
      [emptyMessage]="props.emptyMessage"
      [filter]="filter"
      filterBy="label"
      [filterMatchMode]="props.filterMatchMode"
      [fluid]="props.fluid"
      [formControl]="formControl"
      [formlyAttributes]="field"
      [group]="props.group"
      [loadingIcon]="props.loadingIcon"
      [scrollHeight]="props.scrollHeight"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
      [options]="optionValues$|async"
      [optionLabel]="props.group ? undefined : 'label'"
      [optionValue]="props.group ? undefined : 'value'"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder | translate"
      [required]="props.required"
      [showClear]="!props.required"
      [styleClass]="props.styleClass"
      [tooltip]="props.tooltip"
      [tooltipPosition]="props.tooltipPosition"
      [tooltipPositionStyle]="props.tooltipPositionStyle"
      [tooltipStyleClass]="props.tooltipStyleClass"
      (onChange)="props.change && props.change(field, $event)"
      (onClear)="clearValidators()"
    >
      <ng-template let-selected #selectedItem>
        {{ selected.untranslatedLabel | translate }}
      </ng-template>
      <ng-template let-item #item>
        <span class="core:whitespace-normal">
          {{item.label}}
        </span>
      </ng-template>
      <ng-template let-group #group>
        @if (group.untranslatedLabel !== 'group-preferred' && group.untranslatedLabel !== 'group-other') {
          <div class="core:py-2 core:font-bold">{{ group.label }}</div>
        } @else if (group.label === 'group-other') {
          <div class="core:py-2"><hr></div>
        }
      </ng-template>
    </p-select>
  }
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "name", "style", "panelStyle", "styleClass", "panelStyleClass", "readonly", "required", "editable", "appendTo", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "variant", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "autoDisplayFirst", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "size", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "maxlength", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "fluid", "disabled", "itemSize", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "filterValue", "options"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SelectComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-primeng-select',
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    template: `
  @if(props.options) {
    <p-select
      [appendTo]="props.appendTo"
      [class]="props.class"
      [dropdownIcon]="props.dropdownIcon"
      [editable]="props.editable"
      [emptyFilterMessage]="props.emptyFilterMessage"
      [emptyMessage]="props.emptyMessage"
      [filter]="filter"
      filterBy="label"
      [filterMatchMode]="props.filterMatchMode"
      [fluid]="props.fluid"
      [formControl]="formControl"
      [formlyAttributes]="field"
      [group]="props.group"
      [loadingIcon]="props.loadingIcon"
      [scrollHeight]="props.scrollHeight"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
      [options]="optionValues$|async"
      [optionLabel]="props.group ? undefined : 'label'"
      [optionValue]="props.group ? undefined : 'value'"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder | translate"
      [required]="props.required"
      [showClear]="!props.required"
      [styleClass]="props.styleClass"
      [tooltip]="props.tooltip"
      [tooltipPosition]="props.tooltipPosition"
      [tooltipPositionStyle]="props.tooltipPositionStyle"
      [tooltipStyleClass]="props.tooltipStyleClass"
      (onChange)="props.change && props.change(field, $event)"
      (onClear)="clearValidators()"
    >
      <ng-template let-selected #selectedItem>
        {{ selected.untranslatedLabel | translate }}
      </ng-template>
      <ng-template let-item #item>
        <span class="core:whitespace-normal">
          {{item.label}}
        </span>
      </ng-template>
      <ng-template let-group #group>
        @if (group.untranslatedLabel !== 'group-preferred' && group.untranslatedLabel !== 'group-other') {
          <div class="core:py-2 core:font-bold">{{ group.label }}</div>
        } @else if (group.label === 'group-other') {
          <div class="core:py-2"><hr></div>
        }
      </ng-template>
    </p-select>
  }
  `,
                    standalone: false
                }]
        }] });
class NgCoreFormlySelectModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlySelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlySelectModule, declarations: [SelectComponent], imports: [CommonModule,
            SelectModule,
            ReactiveFormsModule, i5.TranslateModule, FormlySelectModule, i4$1.FormlyModule], exports: [SelectComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlySelectModule, imports: [CommonModule,
            SelectModule,
            ReactiveFormsModule,
            TranslateModule.forChild(),
            FormlySelectModule,
            FormlyModule.forChild({
                types: [
                    {
                        name: 'select',
                        component: SelectComponent,
                        wrappers: ['form-field'],
                    },
                    { name: 'enum', extends: 'select' },
                ],
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlySelectModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [SelectComponent],
                    imports: [
                        CommonModule,
                        SelectModule,
                        ReactiveFormsModule,
                        TranslateModule.forChild(),
                        FormlySelectModule,
                        FormlyModule.forChild({
                            types: [
                                {
                                    name: 'select',
                                    component: SelectComponent,
                                    wrappers: ['form-field'],
                                },
                                { name: 'enum', extends: 'select' },
                            ],
                        }),
                    ],
                    exports: [SelectComponent]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class TreeSelectComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.translateService = inject(TranslateService);
        this.translateLabelService = inject(TranslateLabelService);
        this.ref = inject(ChangeDetectorRef);
        this.subscription = new Subscription();
        this.filter = false;
        /** Default properties */
        this.defaultOptions = {
            props: {
                filterBy: 'label',
                filterInputAutoFocus: true,
                fluid: true,
                placeholder: 'Select…',
                scrollHeight: CONFIG.DEFAULT_SELECT_SCROLL_HEIGHT,
                variant: 'outlined'
            }
        };
        this.nodeSelected = undefined;
        this.optionValues = [];
    }
    ngOnInit() {
        const optionsObs = this.props.options;
        const changeObs = this.translateService.onLangChange.pipe(switchMap$1(() => this.optionValues$));
        this.optionValues$ = merge(...[optionsObs, changeObs])
            .pipe(tap$1((options) => {
            this.filter = this.enableFilter(options, 0).enabled;
        }), map$5(options => {
            this.ref.markForCheck();
            return this.translateLabelService.translateLabel(options);
        }));
        this.subscription.add(this.optionValues$.subscribe((options) => {
            this.optionValues = options;
            if (this.field.formControl?.value) {
                this.nodeSelected = this.findNodeByValue(options, this.field.formControl?.value);
            }
            else {
                this.nodeSelected = null;
            }
        }));
        this.subscription.add(this.field.formControl?.valueChanges.subscribe((value) => {
            if (value) {
                this.nodeSelected = this.findNodeByValue(this.optionValues, value);
            }
            else {
                this.nodeSelected = null;
            }
        }));
    }
    /**
     * Check if the filter feature of the select should be enabled.
     *
     * This function is interrupted if the threshold is reached.
     *
     * @param options the list of options
     * @param numberOfOptions the numberOfOptions used by the recursion
     * @returns enabled: true if the filter should be enabled, the current total of detected options (used by the recursion)
     */
    enableFilter(options, numberOfOptions = 0) {
        if (!options?.length) {
            return { total: numberOfOptions, enabled: false };
        }
        // number of entries to enable the filter
        const limit = 5;
        let total = numberOfOptions + options.length;
        if (total > limit) {
            return { enabled: true, total };
        }
        for (const option of options) {
            const child = this.enableFilter(option?.children, total);
            total = child.total;
            if (total > limit) {
                return { enabled: total > limit, total };
            }
        }
        return { enabled: total > limit, total };
    }
    ngOnDestroy() {
        this.subscription.unsubscribe();
    }
    setFormValue(event) {
        this.formControl.setValue(event.node.data);
    }
    clearFormValue() {
        this.formControl.reset(null);
        const { errors } = this.formControl;
        this.formControl.setErrors(errors.required ? { required: true } : null);
    }
    findNodeByValue(node, value, data) {
        if (!data) {
            node.map((treeNode) => {
                if (treeNode.data === value) {
                    data = treeNode;
                }
                else if (treeNode.children) {
                    data = this.findNodeByValue(treeNode.children, value, data);
                }
            });
        }
        return data;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TreeSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: TreeSelectComponent, isStandalone: false, selector: "ng-core-tree-select", usesInheritance: true, ngImport: i0, template: `
    <p-treeSelect
      [class]="props.class"
      [containerStyleClass]="props.containerStyleClass"
      [disabled]="props.disabled"
      [filter]="filter"
      [filterBy]="props.filterBy"
      [filterInputAutoFocus]="props.filterInputAutoFocus"
      [filterPlaceholder]="props.filterPlaceholder"
      [fluid]="props.fluid"
      [formlyAttributes]="field"
      [ngModel]="nodeSelected"
      [options]="optionValues"
      [panelClass]="props.panelClass"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder | translate"
      [showClear]="!props.required"
      [variant]="props.variant"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
      (onNodeSelect)="setFormValue($event)"
      (onNodeUnselect)="clearFormValue()"
      (onClear)="clearFormValue()"
    >
      <ng-template let-item #item>
        <span class="core:whitespace-normal">
          {{item.label}}
        </span>
      </ng-template>
    </p-treeSelect>
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i3$5.TreeSelect, selector: "p-treeSelect, p-treeselect, p-tree-select", inputs: ["inputId", "scrollHeight", "disabled", "metaKeySelection", "variant", "display", "selectionMode", "tabindex", "ariaLabel", "ariaLabelledBy", "placeholder", "panelClass", "panelStyle", "fluid", "panelStyleClass", "containerStyle", "containerStyleClass", "labelStyle", "labelStyleClass", "overlayOptions", "emptyMessage", "appendTo", "filter", "filterBy", "filterMode", "filterPlaceholder", "filterLocale", "filterInputAutoFocus", "propagateSelectionDown", "propagateSelectionUp", "showClear", "resetFilterOnHide", "virtualScroll", "virtualScrollItemSize", "size", "virtualScrollOptions", "autofocus", "options", "showTransitionOptions", "hideTransitionOptions", "loading"], outputs: ["onNodeExpand", "onNodeCollapse", "onShow", "onHide", "onClear", "onFilter", "onFocus", "onBlur", "onNodeUnselect", "onNodeSelect"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TreeSelectComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-tree-select',
                    template: `
    <p-treeSelect
      [class]="props.class"
      [containerStyleClass]="props.containerStyleClass"
      [disabled]="props.disabled"
      [filter]="filter"
      [filterBy]="props.filterBy"
      [filterInputAutoFocus]="props.filterInputAutoFocus"
      [filterPlaceholder]="props.filterPlaceholder"
      [fluid]="props.fluid"
      [formlyAttributes]="field"
      [ngModel]="nodeSelected"
      [options]="optionValues"
      [panelClass]="props.panelClass"
      [panelStyleClass]="props.panelStyleClass"
      [placeholder]="props.placeholder | translate"
      [showClear]="!props.required"
      [variant]="props.variant"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
      (onNodeSelect)="setFormValue($event)"
      (onNodeUnselect)="clearFormValue()"
      (onClear)="clearFormValue()"
    >
      <ng-template let-item #item>
        <span class="core:whitespace-normal">
          {{item.label}}
        </span>
      </ng-template>
    </p-treeSelect>
  `,
                    standalone: false
                }]
        }] });
class NgCoreFormlyTreeSelectModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyTreeSelectModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyTreeSelectModule, declarations: [TreeSelectComponent], imports: [CommonModule,
            FormsModule,
            FormlySelectModule$1, i5.TranslateModule, TreeSelectModule, i4$1.FormlyModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyTreeSelectModule, imports: [CommonModule,
            FormsModule,
            FormlySelectModule$1,
            TranslateModule.forChild(),
            TreeSelectModule,
            FormlyModule.forChild({
                types: [
                    {
                        name: 'tree-select',
                        component: TreeSelectComponent,
                        wrappers: ['form-field'],
                    }
                ],
            })] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgCoreFormlyTreeSelectModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [TreeSelectComponent],
                    imports: [
                        CommonModule,
                        FormsModule,
                        FormlySelectModule$1,
                        TranslateModule.forChild(),
                        TreeSelectModule,
                        FormlyModule.forChild({
                            types: [
                                {
                                    name: 'tree-select',
                                    component: TreeSelectComponent,
                                    wrappers: ['form-field'],
                                }
                            ],
                        }),
                    ],
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying a label with dropdown in editor.
 */
class DropdownLabelEditorComponent {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DropdownLabelEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DropdownLabelEditorComponent, isStandalone: false, selector: "ng-core-editor-dropdown-label-editor", inputs: { field: "field", canAdd: "canAdd" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (field.props.label) {\n  <div class=\"core:flex core:gap-1 core:items-center\">\n    <span [pTooltip]=\"field.props.description\" tooltipPosition=\"top\">\n      {{ field.props.label }}\n      @if (field.props.required) {\n        &nbsp;*\n      }\n    </span>\n    <ng-content select=\"[menu]\"/>\n    <ng-content id=\"{field.id}-clone-button\" select=\"[buttons]\"/>\n  </div>\n}\n", dependencies: [{ kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DropdownLabelEditorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-editor-dropdown-label-editor', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (field.props.label) {\n  <div class=\"core:flex core:gap-1 core:items-center\">\n    <span [pTooltip]=\"field.props.description\" tooltipPosition=\"top\">\n      {{ field.props.label }}\n      @if (field.props.required) {\n        &nbsp;*\n      }\n    </span>\n    <ng-content select=\"[menu]\"/>\n    <ng-content id=\"{field.id}-clone-button\" select=\"[buttons]\"/>\n  </div>\n}\n" }]
        }], propDecorators: { field: [{
                type: Input
            }], canAdd: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class LabelComponent {
    constructor() {
        this.translateService = inject(TranslateService);
        // Subscriptions to observables.
        this.subscriptions = new Subscription();
        this.items = [];
    }
    ngOnInit() {
        this.updateItems();
        // update items when the hidden state of the children change
        const fields = this.getFieldGroup(this.field);
        if (fields?.length > 0) {
            this.subscriptions.add(merge(...fields.map((child) => child.options.fieldChanges))
                .subscribe((changes) => {
                if (changes.type === 'hidden') {
                    this.updateItems();
                }
            }));
            // update translations
            this.subscriptions.add(this.translateService.onLangChange.subscribe(() => this.updateItems()));
        }
    }
    ngOnDestroy() {
        this.subscriptions.unsubscribe();
    }
    updateItems() {
        if (this.hasMenu(this.field)) {
            this.items = [];
            this.hiddenFieldGroup(this.getFieldGroup(this.field)).map((field) => {
                if (!field.props.untranslatedLabel) {
                    field.props.untranslatedLabel = field.props.label;
                }
                this.items.push({
                    label: this.translateService.instant(field.props.untranslatedLabel),
                    command: () => this.show(field),
                });
            });
        }
    }
    /**
     * Is the dropdown menu displayed?
     * @param field - FormlyFieldConfig, the corresponding form field config
     * @returns boolean, true if the menu should be displayed
     */
    hasMenu(field) {
        if (field.fieldGroup && field.fieldGroup.length > 0 && field.fieldGroup[0].type === 'multischema') {
            return false;
        }
        if (this.field.fieldGroup == null) {
            return false;
        }
        return ((this.hiddenFieldGroup(this.getFieldGroup(this.field)).length > 0 || this.field.props.helpURL) &&
            field.props?.editorConfig?.longMode);
    }
    /** Get the current field index position in the parent array.
     *
     * @returns number - the index position in the parent array, null if the parent
     *                   is not an array.
     */
    getIndex() {
        if (this.field.parent.type === 'array') {
            return Number(this.field.key);
        }
        return null;
    }
    /** Get the list of children fields of a given field.
     *
     * This is more complicated for multischema, the formlyField should be extracted
     * from the children of children.
     *
     * @param field FormlyFieldConfig - the field to get the fieldGroup.
     * @returns Array of FormlyFieldConfig - the list of the children fields.
     */
    getFieldGroup(field) {
        let fieldGroup = [];
        // multischema has a nested structure object['enum', 'object'], enum is the oneOf select
        // and object['object'] are all the possible oneOf entries
        if (field.fieldGroup?.length > 0 && field.fieldGroup[0].type === 'multischema') {
            const multischemaFieldGroup = field.fieldGroup[0];
            // [0] is the enum i.e. (select) for the oneOf
            const multischemaEntries = multischemaFieldGroup.fieldGroup[1];
            let activeGroups = multischemaEntries.fieldGroup;
            // only the active
            activeGroups = activeGroups.filter((f) => f.hide === false);
            activeGroups.map((group) => (fieldGroup = [...group.fieldGroup, group]));
        }
        else {
            fieldGroup = field.fieldGroup;
        }
        return fieldGroup;
    }
    /**
     * Filter the fieldGroup to return the list of hidden field.
     * @param fieldGroup - FormlyFieldConfig[], the fieldGroup to filter
     * @returns FormlyFieldConfig[], the filtered list
     */
    hiddenFieldGroup(fieldGroup) {
        return fieldGroup.filter((f) => f.hide && !('hide' in f?.expressions));
    }
    /**
     * Am I at the root of the form?
     * @returns boolean, true if I'm the root
     */
    isRoot() {
        return this.field.props?.isRoot || false;
    }
    /**
     * Hide the field
     * @param field - FormlyFieldConfig, the field to hide
     */
    remove() {
        if (this.field.parent.type === 'object') {
            this.field.props.setHide ? this.field.props.setHide(this.field, true) : (this.field.hide = true);
        }
        if (this.field.parent.type === 'array') {
            this.field.parent.props.remove(this.getIndex());
        }
    }
    /**
     * Show the field
     * @param field - FormlyFieldConfig, the field to show
     */
    show(field) {
        field.props.setHide ? field.props.setHide(field, false) : (field.hide = false);
    }
    /**
     * Is the field can be hidden?
     * @returns boolean, true if the field can be hidden
     */
    canRemove() {
        switch (this.field.parent.type) {
            case 'object':
                if (!this.field.props?.editorConfig?.longMode) {
                    return false;
                }
                return !this.field.props.required && !this.field.hide;
            case 'array':
                return this.field.parent.props.canRemove();
            default:
                return false;
        }
    }
    /**
     * Is a new item can be added in an array?
     * Note that this is true only if the array does not contains items, else the
     * clone button should be used.
     * @returns boolean, true if a new item can be added
     */
    canAddItem() {
        if (this.field.type === 'array' && this.field.props.canAdd) {
            return this.field.props.canAdd() && this.field.fieldGroup.length === 0;
        }
        return false;
    }
    /**
     * Add a new item element
     * @param field - FormlyFieldConfig, the field to hide
     */
    addItem() {
        if (this.field.type === 'array') {
            return this.field.props.add(0);
        }
    }
    /**
     * Is a array item can be cloned?
     * @returns boolean, true if the field can be hidden
     */
    canAdd() {
        if (this.field.parent.type === 'array') {
            return this.field.parent.props.canAdd();
        }
        return false;
    }
    /**
     * Add a array item after the current field.
     * @param field - FormlyFieldConfig, the field to hide
     */
    add() {
        if (this.field.parent.type === 'array') {
            const index = this.getIndex() + 1;
            return this.field.parent.props.add(index);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: LabelComponent, isStandalone: false, selector: "ng-core-label-editor", inputs: { field: "field" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (field) {\n<!-- header and menu -->\n@if (!isRoot()) {\n  <ng-container *ngTemplateOutlet=\"hasMenu(field) ? menu : title; context: { f: field }\" />\n}\n\n<!-- TEMPLATES -->\n<!-- dropdown menu -->\n<ng-template #menu let-f=\"f\">\n  <ng-core-editor-dropdown-label-editor [field]=\"f\" [canAdd]=\"false\">\n    <ng-container menu>\n      <div class=\"core:flex\">\n        <p-button icon=\"fa fa-caret-down\" severity=\"secondary\" [text]=\"true\" (onClick)=\"menu.toggle($event)\" />\n        <p-tieredMenu #menu [model]=\"items\" [popup]=\"true\" appendTo=\"body\" />\n      </div>\n    </ng-container>\n    <ng-container buttons>\n      @if (canAddItem()) {\n      <p-button icon=\"fa fa-plus\" severity=\"secondary\" [text]=\"true\" (onClick)=\"addItem()\" />\n      } @if (canAdd()) {\n      <p-button\n        id=\"{{ f.id }}-clone-button\"\n        icon=\"fa fa-clone\"\n        severity=\"secondary\"\n        [text]=\"true\"\n        styleClass=\"core:mr-1\"\n        (onClick)=\"add()\"\n      />\n      }\n      <!-- hide button -->\n      @if (canRemove()) {\n      <p-button\n        id=\"{{ f.id }}-remove-button\"\n        icon=\"fa fa-trash\"\n        severity=\"secondary\"\n        [text]=\"true\"\n        (onClick)=\"remove()\"\n      />\n      }\n    </ng-container>\n  </ng-core-editor-dropdown-label-editor>\n</ng-template>\n\n<!-- section title -->\n<ng-template #title let-f=\"f\">\n  <div class=\"core:flex core:gap-1 core:items-center\">\n    @if (f.props.label) {\n    <label class=\"p-fieldset-legend-label\" [attr.for]=\"f.id\" [pTooltip]=\"f.props.description\" tooltipPosition=\"top\">\n      {{ f.props.label }}\n    </label>\n    @if (f.props.required && f.props.hideRequiredMarker !== true) { * } @if (canAddItem()) {\n    <p-button icon=\"fa fa-plus\" severity=\"secondary\" [text]=\"true\" (onClick)=\"addItem()\" />\n    } @if (canAdd()) {\n    <p-button id=\"{{ f.id }}-clone-button\" icon=\"fa fa-clone\" [text]=\"true\" severity=\"secondary\" (onClick)=\"add()\" />\n    }\n    <!-- hide button -->\n    @if (canRemove()) {\n    <p-button\n      id=\"{{ f.id }}-remove-button\"\n      icon=\"fa fa-trash\"\n      [text]=\"true\"\n      severity=\"secondary\"\n      (onClick)=\"remove()\"\n    />\n    } }\n  </div>\n</ng-template>\n}\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$6.TieredMenu, selector: "p-tieredMenu, p-tieredmenu, p-tiered-menu", inputs: ["model", "popup", "style", "styleClass", "appendTo", "breakpoint", "autoZIndex", "baseZIndex", "autoDisplay", "showTransitionOptions", "hideTransitionOptions", "id", "ariaLabel", "ariaLabelledBy", "disabled", "tabindex"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: DropdownLabelEditorComponent, selector: "ng-core-editor-dropdown-label-editor", inputs: ["field", "canAdd"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LabelComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-label-editor', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (field) {\n<!-- header and menu -->\n@if (!isRoot()) {\n  <ng-container *ngTemplateOutlet=\"hasMenu(field) ? menu : title; context: { f: field }\" />\n}\n\n<!-- TEMPLATES -->\n<!-- dropdown menu -->\n<ng-template #menu let-f=\"f\">\n  <ng-core-editor-dropdown-label-editor [field]=\"f\" [canAdd]=\"false\">\n    <ng-container menu>\n      <div class=\"core:flex\">\n        <p-button icon=\"fa fa-caret-down\" severity=\"secondary\" [text]=\"true\" (onClick)=\"menu.toggle($event)\" />\n        <p-tieredMenu #menu [model]=\"items\" [popup]=\"true\" appendTo=\"body\" />\n      </div>\n    </ng-container>\n    <ng-container buttons>\n      @if (canAddItem()) {\n      <p-button icon=\"fa fa-plus\" severity=\"secondary\" [text]=\"true\" (onClick)=\"addItem()\" />\n      } @if (canAdd()) {\n      <p-button\n        id=\"{{ f.id }}-clone-button\"\n        icon=\"fa fa-clone\"\n        severity=\"secondary\"\n        [text]=\"true\"\n        styleClass=\"core:mr-1\"\n        (onClick)=\"add()\"\n      />\n      }\n      <!-- hide button -->\n      @if (canRemove()) {\n      <p-button\n        id=\"{{ f.id }}-remove-button\"\n        icon=\"fa fa-trash\"\n        severity=\"secondary\"\n        [text]=\"true\"\n        (onClick)=\"remove()\"\n      />\n      }\n    </ng-container>\n  </ng-core-editor-dropdown-label-editor>\n</ng-template>\n\n<!-- section title -->\n<ng-template #title let-f=\"f\">\n  <div class=\"core:flex core:gap-1 core:items-center\">\n    @if (f.props.label) {\n    <label class=\"p-fieldset-legend-label\" [attr.for]=\"f.id\" [pTooltip]=\"f.props.description\" tooltipPosition=\"top\">\n      {{ f.props.label }}\n    </label>\n    @if (f.props.required && f.props.hideRequiredMarker !== true) { * } @if (canAddItem()) {\n    <p-button icon=\"fa fa-plus\" severity=\"secondary\" [text]=\"true\" (onClick)=\"addItem()\" />\n    } @if (canAdd()) {\n    <p-button id=\"{{ f.id }}-clone-button\" icon=\"fa fa-clone\" [text]=\"true\" severity=\"secondary\" (onClick)=\"add()\" />\n    }\n    <!-- hide button -->\n    @if (canRemove()) {\n    <p-button\n      id=\"{{ f.id }}-remove-button\"\n      icon=\"fa fa-trash\"\n      [text]=\"true\"\n      severity=\"secondary\"\n      (onClick)=\"remove()\"\n    />\n    } }\n  </div>\n</ng-template>\n}\n" }]
        }], propDecorators: { field: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying array fields in editor.
 */
class ArrayTypeComponent extends FieldArrayType {
    /**
     * Component initialization
     */
    ngOnInit() {
        this.props.remove = this.remove.bind(this);
        this.props.add = this.add.bind(this);
        this.props.canAdd = this.canAdd.bind(this);
        this.props.canRemove = this.canRemove.bind(this);
    }
    /**
     * Can a new element be added?
     * @returns boolean, true if a new element can be inserted in the array
     */
    canAdd() {
        const { maxItems } = this.field.props;
        if (maxItems === undefined) {
            return true;
        }
        return this.field.fieldGroup.length < maxItems;
    }
    /**
     * Can an element be removed?
     * @returns boolean, true if an element ca be removed
     */
    canRemove() {
        const { minItems } = this.field.props;
        if (minItems === undefined) {
            return true;
        }
        return this.field.fieldGroup.length > minItems;
    }
    /**
     * Remove an element from the array and hide buttons
     * @param i - number, the position to remove the element
     */
    remove(i) {
        super.remove(i);
    }
    /**
     * Add a new element in the array
     * @param i - number, the position to add the element
     */
    add(i, initialModel) {
        super.add(i, initialModel);
        this.setFocusInChildren(this.field.fieldGroup[i]);
    }
    /**
     * Set the focus to the first non object, array in children
     * Recursive.
     * @param field - FormlyFieldConfig, configuration form
     */
    setFocusInChildren(field) {
        if (field.fieldGroup && field.fieldGroup.length > 0) {
            for (const f of field.fieldGroup) {
                if (this.setFocusInChildren(f)) {
                    return true;
                }
            }
            return false;
        }
        if (!field.hide) {
            field.focus = true;
            return true;
        }
        return false;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ArrayTypeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: ArrayTypeComponent, isStandalone: false, selector: "ng-core-editor-formly-array-type", usesInheritance: true, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<!-- array title only if the array is empty -->\n\n@if (props.label && field.props.hideLabel !== true) {\n  <ng-core-label-editor [field]=\"field\" />\n}\n\n<div>\n  @if (showError) {\n    <div class=\"text-error core:my-2\">\n      <formly-validation-message [field]=\"field\"/>\n    </div>\n  }\n  <!-- for each item -->\n  <div [class]=\"props.containerCssClass\">\n    @for (f of field.fieldGroup; track f.id) { @if (!f.hide) {\n    <div class=\"{{ f.props.itemCssClass }} core:mb-1\" [id]=\"'field-' + f.id\">\n      <formly-field [field]=\"f\" />\n    </div>\n    } }\n  </div>\n</div>\n", dependencies: [{ kind: "component", type: i4$1.LegacyFormlyField, selector: "formly-field" }, { kind: "component", type: i4$1.LegacyFormlyValidationMessage, selector: "formly-validation-message" }, { kind: "component", type: LabelComponent, selector: "ng-core-label-editor", inputs: ["field"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ArrayTypeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-editor-formly-array-type', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<!-- array title only if the array is empty -->\n\n@if (props.label && field.props.hideLabel !== true) {\n  <ng-core-label-editor [field]=\"field\" />\n}\n\n<div>\n  @if (showError) {\n    <div class=\"text-error core:my-2\">\n      <formly-validation-message [field]=\"field\"/>\n    </div>\n  }\n  <!-- for each item -->\n  <div [class]=\"props.containerCssClass\">\n    @for (f of field.fieldGroup; track f.id) { @if (!f.hide) {\n    <div class=\"{{ f.props.itemCssClass }} core:mb-1\" [id]=\"'field-' + f.id\">\n      <formly-field [field]=\"f\" />\n    </div>\n    } }\n  </div>\n</div>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class MultiSchemaTypeComponent extends FieldType {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MultiSchemaTypeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: MultiSchemaTypeComponent, isStandalone: false, selector: "ng-core-editor-formly-multi-schema-type", usesInheritance: true, ngImport: i0, template: `
    <div [class]="field.parent.props.cssClass">
      @if (props.label) {
        <legend [pTooltip]="props.description" tooltipPosition="top">{{ props.label }}</legend>
      }
      @if (showError && formControl.errors) {
        <div class="text-error core:my-2">
          <formly-validation-message [field]="field" />
        </div>
      }
      @for (f of field.fieldGroup; track f.id) {
        <formly-field [field]="f"></formly-field>
      }
    </div>
  `, isInline: true, dependencies: [{ kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: i4$1.LegacyFormlyField, selector: "formly-field" }, { kind: "component", type: i4$1.LegacyFormlyValidationMessage, selector: "formly-validation-message" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MultiSchemaTypeComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-editor-formly-multi-schema-type',
                    template: `
    <div [class]="field.parent.props.cssClass">
      @if (props.label) {
        <legend [pTooltip]="props.description" tooltipPosition="top">{{ props.label }}</legend>
      }
      @if (showError && formControl.errors) {
        <div class="text-error core:my-2">
          <formly-validation-message [field]="field" />
        </div>
      }
      @for (f of field.fieldGroup; track f.id) {
        <formly-field [field]="f"></formly-field>
      }
    </div>
  `,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying an object in editor.
 */
class ObjectTypeComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.defaultOptions = {
            props: {
                containerCssClass: 'core:flex core:flex-col core:gap-2'
            }
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ObjectTypeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: ObjectTypeComponent, isStandalone: false, selector: "ng-core-editor-formly-object-type", usesInheritance: true, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (showError) {\n  <div class=\"text-error core:my-2\">\n    <formly-validation-message [field]=\"field\"/>\n  </div>\n}\n<div [class]=\"props.containerCssClass\">\n  @for (f of field.fieldGroup; track f.id) {\n    <!-- the core:scroll-mt-18 class is added for sticky -->\n    <div\n      [hidden]=\"f.hide\"\n      [class]=\"f.props.itemCssClass\"\n      [ngClass]=\"{'core:scroll-mt-18': (props.isRoot && props.editorConfig?.longMode)}\"\n      [id]=\"'field-' + f.id\"\n    >\n      <formly-field [field]=\"f\" />\n    </div>\n  }\n</div>\n", dependencies: [{ kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: i4$1.LegacyFormlyField, selector: "formly-field" }, { kind: "component", type: i4$1.LegacyFormlyValidationMessage, selector: "formly-validation-message" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ObjectTypeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-editor-formly-object-type', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (showError) {\n  <div class=\"text-error core:my-2\">\n    <formly-validation-message [field]=\"field\"/>\n  </div>\n}\n<div [class]=\"props.containerCssClass\">\n  @for (f of field.fieldGroup; track f.id) {\n    <!-- the core:scroll-mt-18 class is added for sticky -->\n    <div\n      [hidden]=\"f.hide\"\n      [class]=\"f.props.itemCssClass\"\n      [ngClass]=\"{'core:scroll-mt-18': (props.isRoot && props.editorConfig?.longMode)}\"\n      [id]=\"'field-' + f.id\"\n    >\n      <formly-field [field]=\"f\" />\n    </div>\n  }\n</div>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2022-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
;
class PasswordGeneratorTypeComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.httpClient = inject(HttpClient);
        this.clipboard = inject(Clipboard);
        this.cd = inject(ChangeDetectorRef);
        this.passwordField = viewChild('password');
        /** Default options */
        this.defaultOptions = {
            props: {
                // Allows you to edit the password
                enabledEditMode: false,
                // Minimum password size
                minLength: 8,
                // Maximum password size
                maxLength: 255,
                // Password generation with special characters (ex: $%&)
                specialChar: false,
                // The field is readonly
                readonly: true,
                // If you use the function in javascript, it is possible
                // to pass options. See the information above.
                generateOptions: {}
            }
        };
        this.hasBeenGenerated = false;
        /** Field password type (show or hide password) */
        this.type = 'password';
        /** Password Observable */
        this._password$ = new Subject();
    }
    /** OnInit hook */
    ngOnInit() {
        this._password$.pipe(tap((password) => this.formControl.setValue(password)), tap((password) => this.clipboard.copy(this.formControl.errors ? ' ' : password))).subscribe(() => {
            this.hasBeenGenerated = true;
            this.cd.markForCheck();
        });
    }
    /** Generation of the password when the button is clicked. */
    onClick() {
        if (!this.props.api) {
            this._jsGeneration();
        }
        else {
            this._callApi();
        }
    }
    /**
     * Change the password when entering.
     * @param password - string
     */
    onChange(password) {
        this._password$.next(password);
    }
    /** Hide or show password data */
    showHidePassword() {
        this.type = this.type === 'password' ? 'text' : 'password';
    }
    onEdit() {
        this.props.readonly = !this.props.readonly;
        if (!this.props.readonly) {
            this.passwordField().nativeElement.focus();
        }
    }
    /** Generate the password by javascript */
    _jsGeneration() {
        if (!this.props.generateOptions.length) {
            this.props.generateOptions.length = this.props.minLength;
        }
        if (!this.props.generateOptions.symbols) {
            this.props.generateOptions.symbols = this.props.specialChar;
        }
        this._password$.next(GeneratePassword(this.props.generateOptions));
    }
    /** Call backend api entrypoint */
    _callApi() {
        this.httpClient.get(this.props.api, {
            responseType: 'text',
            params: {
                length: this.props.minLength,
                special_char: this.props.specialChar
            }
        }).subscribe((password) => this._password$.next(password));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordGeneratorTypeComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: PasswordGeneratorTypeComponent, isStandalone: false, selector: "ng-core-editor-field-password-generator", viewQueries: [{ propertyName: "passwordField", first: true, predicate: ["password"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: `
  <p-inputGroup>
    <input
      pInputText
      #password
      id="password"
      [type]="type"
      autocomplete="off"
      [formControl]="formControl"
      (change)="onChange($event.target.value)"
      [readonly]="props.readonly"
      [class]="props.class ? props.class : props.readonly ? 'core:!bg-surface-200' : ''"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
    />
    <p-inputGroupAddon class="core:flex">
      <div class="core:flex core:justify-center core:items-center core:min-h-full core:grow core:cursor-pointer core:hover:bg-emphasis" (click)="onClick()">
        <i class="fa fa-repeat" [title]="'Generate a new password' | translate"></i>
      </div>
    </p-inputGroupAddon>
    <p-inputGroupAddon>
      <div class="core:flex core:justify-center core:items-center core:min-h-full core:grow core:cursor-pointer core:hover:bg-emphasis" (click)="showHidePassword()">
        <i class="fa" [ngClass]="{'fa-eye': type === 'password', 'fa-eye-slash': type === 'text'}" [title]="'Show or hide password' | translate"></i>
      </div>
    </p-inputGroupAddon>
    @if (props.enabledEditMode) {
    <p-inputGroupAddon>
      <div class="core:flex core:justify-center core:items-center core:min-h-full core:grow core:cursor-pointer core:hover:bg-emphasis" (click)="onEdit()">
        <i class="fa" [ngClass]="{'fa-lock': props.readonly, 'fa-unlock-alt': !props.readonly}" [title]="'Edit mode' | translate"></i>
      </div>
    </p-inputGroupAddon>
    }
  </p-inputGroup>
  @if (!showError && hasBeenGenerated) {
    <div class="core:text-muted-color core:my-4" translate>
      The password has been copied to the clipboard.
    </div>
    }
  `, isInline: true, styles: ["p-inputGroupAddon{padding:0!important}\n"], dependencies: [{ kind: "component", type: i3.InputGroupAddon, selector: "p-inputgroup-addon, p-inputGroupAddon", inputs: ["style", "styleClass"] }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["style", "styleClass"] }, { kind: "directive", type: i3$1.InputText, selector: "[pInputText]", inputs: ["variant", "fluid", "pSize"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i3$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PasswordGeneratorTypeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-editor-field-password-generator', template: `
  <p-inputGroup>
    <input
      pInputText
      #password
      id="password"
      [type]="type"
      autocomplete="off"
      [formControl]="formControl"
      (change)="onChange($event.target.value)"
      [readonly]="props.readonly"
      [class]="props.class ? props.class : props.readonly ? 'core:!bg-surface-200' : ''"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
    />
    <p-inputGroupAddon class="core:flex">
      <div class="core:flex core:justify-center core:items-center core:min-h-full core:grow core:cursor-pointer core:hover:bg-emphasis" (click)="onClick()">
        <i class="fa fa-repeat" [title]="'Generate a new password' | translate"></i>
      </div>
    </p-inputGroupAddon>
    <p-inputGroupAddon>
      <div class="core:flex core:justify-center core:items-center core:min-h-full core:grow core:cursor-pointer core:hover:bg-emphasis" (click)="showHidePassword()">
        <i class="fa" [ngClass]="{'fa-eye': type === 'password', 'fa-eye-slash': type === 'text'}" [title]="'Show or hide password' | translate"></i>
      </div>
    </p-inputGroupAddon>
    @if (props.enabledEditMode) {
    <p-inputGroupAddon>
      <div class="core:flex core:justify-center core:items-center core:min-h-full core:grow core:cursor-pointer core:hover:bg-emphasis" (click)="onEdit()">
        <i class="fa" [ngClass]="{'fa-lock': props.readonly, 'fa-unlock-alt': !props.readonly}" [title]="'Edit mode' | translate"></i>
      </div>
    </p-inputGroupAddon>
    }
  </p-inputGroup>
  @if (!showError && hasBeenGenerated) {
    <div class="core:text-muted-color core:my-4" translate>
      The password has been copied to the clipboard.
    </div>
    }
  `, standalone: false, styles: ["p-inputGroupAddon{padding:0!important}\n"] }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying a switcher in editor.
 */
class SwitchComponent extends FieldType {
    constructor() {
        super(...arguments);
        /** Default properties */
        this.defaultOptions = {
            props: {
                hideLabel: true,
            },
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SwitchComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: SwitchComponent, isStandalone: false, selector: "ng-core-editor-formly-field-switch", usesInheritance: true, ngImport: i0, template: `
    <div class="core:flex core:gap-2 core:my-2">
      <p-toggleswitch
        [ngClass]="{'ng-invalid ng-dirty': showError }"
        [formControl]="formControl"
        [formlyAttributes]="field"
      />
      <label [for]="id" [pTooltip]="props.description" tooltipPosition="top">{{ props.label }}</label>
    </div>
  `, isInline: true, dependencies: [{ kind: "component", type: i1$4.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SwitchComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-editor-formly-field-switch',
                    template: `
    <div class="core:flex core:gap-2 core:my-2">
      <p-toggleswitch
        [ngClass]="{'ng-invalid ng-dirty': showError }"
        [formControl]="formControl"
        [formlyAttributes]="field"
      />
      <label [for]="id" [pTooltip]="props.description" tooltipPosition="top">{{ props.label }}</label>
    </div>
  `,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2022-2024 RERO
 * Copyright (C) 2022 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
;
class ExportButtonComponent {
    constructor() {
        /** Export formats configuration */
        this.exportOptions = input([]);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ExportButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: ExportButtonComponent, isStandalone: false, selector: "ng-core-export-button", inputs: { exportOptions: { classPropertyName: "exportOptions", publicName: "exportOptions", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2022-2025 RERO\n  Copyright (C) 2022 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (exportOptions() && exportOptions().length > 0) {\n  <!-- check single export format -->\n   @if (exportOptions().length === 1) {\n    @if (!exportOptions()[0]?.disabled) {\n      <a\n        pButton\n        outlined\n        severity=\"secondary\"\n        [href]=\"exportOptions()[0].url\"\n        rel=\"noopener noreferrer\"\n      >\n        <i class=\"fa fa-cloud-download core:mr-1\"></i>\n        {{ 'Export as' | translate }} {{ exportOptions()[0].label }}\n      </a>\n    } @else {\n      <p-button\n        severity=\"secondary\"\n        outlined\n        label=\"{{ 'Export as' | translate }} {{ exportOptions()[0].label }}\"\n        icon=\"fa fa-cloud-download\"\n        [href]=\"exportOptions()[0].url\"\n        [disabled]=\"exportOptions()[0]?.disabled\"\n        [pTooltip]=\"exportOptions()[0]?.disabled_message\"\n        [tooltipDisabled]=\"!exportOptions()[0]?.disabled\"\n        tooltipPosition=\"top\"\n      />\n    }\n   } @else {\n      <!-- display multiple export formats as dropdown list -->\n      <p-menu #menu [model]=\"exportOptions()\" [popup]=\"true\" />\n      <p-button\n        severity=\"secondary\"\n        outlined\n        [disabled]=\"exportOptions()[0]?.disabled\"\n        [pTooltip]=\"exportOptions()[0]?.disabled_message\"\n        [tooltipDisabled]=\"!exportOptions()[0]?.disabled\"\n        tooltipPosition=\"top\"\n        (onClick)=\"menu.toggle($event)\"\n      >\n        <div class=\"core:flex core:gap-4 core:items-center\">\n          <i class=\"fa fa-download\"></i>\n          {{ 'Export as' | translate }}&nbsp;\u2026\n          <i class=\"fa fa-caret-down\"></i>\n        </div>\n      </p-button>\n   }\n}\n", dependencies: [{ kind: "directive", type: i1.ButtonDirective, selector: "[pButton]", inputs: ["iconPos", "loadingIcon", "loading", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "fluid", "label", "icon", "buttonProps"] }, { kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$7.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ExportButtonComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-export-button', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2022-2025 RERO\n  Copyright (C) 2022 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (exportOptions() && exportOptions().length > 0) {\n  <!-- check single export format -->\n   @if (exportOptions().length === 1) {\n    @if (!exportOptions()[0]?.disabled) {\n      <a\n        pButton\n        outlined\n        severity=\"secondary\"\n        [href]=\"exportOptions()[0].url\"\n        rel=\"noopener noreferrer\"\n      >\n        <i class=\"fa fa-cloud-download core:mr-1\"></i>\n        {{ 'Export as' | translate }} {{ exportOptions()[0].label }}\n      </a>\n    } @else {\n      <p-button\n        severity=\"secondary\"\n        outlined\n        label=\"{{ 'Export as' | translate }} {{ exportOptions()[0].label }}\"\n        icon=\"fa fa-cloud-download\"\n        [href]=\"exportOptions()[0].url\"\n        [disabled]=\"exportOptions()[0]?.disabled\"\n        [pTooltip]=\"exportOptions()[0]?.disabled_message\"\n        [tooltipDisabled]=\"!exportOptions()[0]?.disabled\"\n        tooltipPosition=\"top\"\n      />\n    }\n   } @else {\n      <!-- display multiple export formats as dropdown list -->\n      <p-menu #menu [model]=\"exportOptions()\" [popup]=\"true\" />\n      <p-button\n        severity=\"secondary\"\n        outlined\n        [disabled]=\"exportOptions()[0]?.disabled\"\n        [pTooltip]=\"exportOptions()[0]?.disabled_message\"\n        [tooltipDisabled]=\"!exportOptions()[0]?.disabled\"\n        tooltipPosition=\"top\"\n        (onClick)=\"menu.toggle($event)\"\n      >\n        <div class=\"core:flex core:gap-4 core:items-center\">\n          <i class=\"fa fa-download\"></i>\n          {{ 'Export as' | translate }}&nbsp;\u2026\n          <i class=\"fa fa-caret-down\"></i>\n        </div>\n      </p-button>\n   }\n}\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2023 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Class representing a record set returned by API.
 */
class Record {
}
class SearchResult {
}

function emailValidator(field) {
    // Regex pattern to check email
    const emailPattern = /^([A-Za-z0-9\._%+-]+@[A-Za-z0-9\.-]+\.[A-Z|a-z]{2,})$/;
    if (field.props?.type !== 'email' || field.validators?.email) {
        return;
    }
    field.validators = field.validators || {};
    field.validators.email = {
        expression: (control) => control.value ? (new RegExp(emailPattern)).test(control.value) : true,
        message: `This value is not a valid email.`,
    };
}

/*
 * RERO angular core
 * Copyright (C) 2021-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component to display textarea as a markdown editor.
 */
class MarkdownFieldComponent extends FieldType {
    constructor() {
        super(...arguments);
        /** Default options */
        this.defaultOptions = {
            props: {
                minHeight: '500px',
                promptURLs: true,
                spellChecker: false,
                status: false,
                toolbar: [
                    'bold',
                    'italic',
                    'heading',
                    '|',
                    'unordered-list',
                    'ordered-list',
                    '|',
                    'link',
                    'image',
                    '|',
                    'preview',
                    'fullscreen',
                    '|',
                    'guide',
                ]
            }
        };
    }
    /**
     * Markdown editor initialization and listen for changes to update the model
     * value.
     */
    ngAfterViewInit() {
        const mde = new EasyMDE({
            spellChecker: this.props.spellChecker,
            promptURLs: this.props.promptURLs,
            initialValue: this.formControl.value,
            maxHeight: this.props.maxHeight,
            minHeight: this.props.minHeight,
            toolbar: this.props.toolbar,
            element: this.textarea.nativeElement,
            status: this.props.status,
        });
        mde.codemirror.on('change', () => {
            this.formControl.patchValue(mde.value());
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: MarkdownFieldComponent, isStandalone: false, selector: "ng-core-editor-formly-field-markdown", viewQueries: [{ propertyName: "textarea", first: true, predicate: ["textarea"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
    <div style="padding-inline: 0; padding-block: 0" [ngClass]="{ 'p-inputtext ng-invalid ng-dirty': showError }">
      <textarea pTextarea #textarea></textarea>
    </div>
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$5.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MarkdownFieldComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-editor-formly-field-markdown',
                    template: `
    <div style="padding-inline: 0; padding-block: 0" [ngClass]="{ 'p-inputtext ng-invalid ng-dirty': showError }">
      <textarea pTextarea #textarea></textarea>
    </div>
  `,
                    standalone: false
                }]
        }], propDecorators: { textarea: [{
                type: ViewChild,
                args: ['textarea']
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2022-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
;
;
class RadioButtonComponent extends FieldType {
    constructor() {
        super(...arguments);
        this.defaultOptions = {
            props: {
                options: [],
                style: 'stacked'
            }
        };
    }
    get disabledControl() {
        return new FormControl({ value: this.formControl.value, disabled: true });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RadioButtonComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RadioButtonComponent, isStandalone: false, selector: "ng-core-editor-field-radio-button", usesInheritance: true, ngImport: i0, template: `
  <ng-template #radioButton let-option="option" let-class="class">
    <div class="core:flex">
      <p-radiobutton
        [inputId]="option.value"
        [formControl]="option.disabled ? disabledControl : formControl"
        [value]="option.value"
      />
      <label [for]="option.value" class="core:ml-1">{{ option.untranslatedLabel | translate }}</label>
    </div>
  </ng-template>
  @if (props.style === 'stacked') {
    @for (option of props.options | async; track option.value) {
      <ng-container [ngTemplateOutlet]="radioButton" [ngTemplateOutletContext]="{option}"/>
    }
  } @else {
    <div class="core:flex core:gap-2">
    @for (option of props.options | async; track option.value) {
      <ng-container [ngTemplateOutlet]="radioButton" [ngTemplateOutletContext]="{option}"/>
    }
    </div>
  }
  `, isInline: true, dependencies: [{ kind: "component", type: i1$6.RadioButton, selector: "p-radioButton, p-radiobutton, p-radio-button", inputs: ["value", "formControlName", "name", "disabled", "variant", "size", "tabindex", "inputId", "ariaLabelledBy", "ariaLabel", "style", "styleClass", "autofocus", "binary"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RadioButtonComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-editor-field-radio-button',
                    template: `
  <ng-template #radioButton let-option="option" let-class="class">
    <div class="core:flex">
      <p-radiobutton
        [inputId]="option.value"
        [formControl]="option.disabled ? disabledControl : formControl"
        [value]="option.value"
      />
      <label [for]="option.value" class="core:ml-1">{{ option.untranslatedLabel | translate }}</label>
    </div>
  </ng-template>
  @if (props.style === 'stacked') {
    @for (option of props.options | async; track option.value) {
      <ng-container [ngTemplateOutlet]="radioButton" [ngTemplateOutletContext]="{option}"/>
    }
  } @else {
    <div class="core:flex core:gap-2">
    @for (option of props.options | async; track option.value) {
      <ng-container [ngTemplateOutlet]="radioButton" [ngTemplateOutletContext]="{option}"/>
    }
    </div>
  }
  `,
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class TextareaFieldComponent extends FieldType {
    constructor() {
        super(...arguments);
        /** Default properties */
        this.defaultOptions = {
            props: {
                displayChars: false,
                displayWords: false,
            }
        };
    }
    /**
     * Get the number of chars.
     *
     * @returns The number of chars.
     */
    get countChars() {
        return this.formControl.value ? this.formControl.value.length : 0;
    }
    /**
     * Get the number of words.
     *
     * @returns The number of words.
     */
    get countWords() {
        return this.formControl.value ? this.formControl.value.split(/\s+/).length : 0;
    }
    /**
     * Component init.
     *
     * Adds validator for chars and words.
     * Check if the current value does not exceed the limit value for chars or words.
     */
    ngOnInit() {
        if (this.props.limitWords || this.props.limitChars) {
            this.formControl.setValidators([this.limitValidator(), this.formControl.validator]);
            this.formControl.updateValueAndValidity();
        }
    }
    /**
     * Form validator to check if the value is not greater than the limit.
     *
     * @returns A validator function returning the eventual error.
     */
    limitValidator() {
        return (control) => {
            if (this.props.limitWords && this.countWords > this.props.limitWords) {
                return { limitWords: { value: control.value } };
            }
            if (this.props.limitChars && this.countChars > this.props.limitChars) {
                return { limitChars: { value: control.value } };
            }
            return null;
        };
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TextareaFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: TextareaFieldComponent, isStandalone: false, selector: "ng-core-editor-formly-field-textarea", usesInheritance: true, ngImport: i0, template: `
    <textarea
      pTextarea
      [formControl]="formControl"
      [cols]="props.cols"
      [rows]="props.rows"
      class="core:w-full"
      [class.is-invalid]="showError"
      [formlyAttributes]="field"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
    ></textarea>
    @if (field.props.limitWords || field.props.displayWords) {
      <ng-container
        [ngTemplateOutlet]="counter"
        [ngTemplateOutletContext]="{
          limit: field.props.limitWords,
          count: countWords,
          label: 'Number of words' | translate
        }"></ng-container>
    }
    @if (field.props.limitChars || field.props.displayChars) {
      <ng-container
        [ngTemplateOutlet]="counter"
        [ngTemplateOutletContext]="{
          limit: field.props.limitChars,
          count: countChars,
          label: 'Number of chars' | translate
        }"></ng-container>
    }
    <ng-template #counter let-limit="limit" let-count="count" let-label="label">
      <span class="core:text-sm core:text-muted-color core:inline-block core:mr-4">
        {{ label }}: {{ count }}
        @if (limit) {
          / {{ limit }}
        }
      </span>
    </ng-template>
  `, isInline: true, dependencies: [{ kind: "directive", type: i1$5.Textarea, selector: "[pTextarea], [pInputTextarea]", inputs: ["autoResize", "variant", "fluid", "pSize"], outputs: ["onResize"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i4$1.LegacyFormlyAttributes, selector: "[formlyAttributes]" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: TextareaFieldComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-editor-formly-field-textarea',
                    template: `
    <textarea
      pTextarea
      [formControl]="formControl"
      [cols]="props.cols"
      [rows]="props.rows"
      class="core:w-full"
      [class.is-invalid]="showError"
      [formlyAttributes]="field"
      [ngClass]="{ 'ng-invalid ng-dirty': showError }"
    ></textarea>
    @if (field.props.limitWords || field.props.displayWords) {
      <ng-container
        [ngTemplateOutlet]="counter"
        [ngTemplateOutletContext]="{
          limit: field.props.limitWords,
          count: countWords,
          label: 'Number of words' | translate
        }"></ng-container>
    }
    @if (field.props.limitChars || field.props.displayChars) {
      <ng-container
        [ngTemplateOutlet]="counter"
        [ngTemplateOutletContext]="{
          limit: field.props.limitChars,
          count: countChars,
          label: 'Number of chars' | translate
        }"></ng-container>
    }
    <ng-template #counter let-limit="limit" let-count="count" let-label="label">
      <span class="core:text-sm core:text-muted-color core:inline-block core:mr-4">
        {{ label }}: {{ count }}
        @if (limit) {
          / {{ limit }}
        }
      </span>
    </ng-template>
  `,
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class CardWrapperComponent extends FieldWrapper {
    /** OnInit hook */
    ngOnInit() {
        // remove the field label as it is displayed by this wrapper
        this.field.props.hideLabel = true;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CardWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: CardWrapperComponent, isStandalone: false, selector: "ng-core-card-wrapper", usesInheritance: true, ngImport: i0, template: `
  @if (!props?.isRoot) {
    <p-fieldset>
      <ng-template #header>
          <ng-core-label-editor [field]="field" />
      </ng-template>
      <ng-template #fieldComponent></ng-template>
    </p-fieldset>
    } @else {
      <ng-template #fieldComponent></ng-template>
    }
  `, isInline: true, dependencies: [{ kind: "component", type: i1$7.Fieldset, selector: "p-fieldset", inputs: ["legend", "toggleable", "collapsed", "style", "styleClass", "transitionOptions"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "component", type: LabelComponent, selector: "ng-core-label-editor", inputs: ["field"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CardWrapperComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-card-wrapper',
                    template: `
  @if (!props?.isRoot) {
    <p-fieldset>
      <ng-template #header>
          <ng-core-label-editor [field]="field" />
      </ng-template>
      <ng-template #fieldComponent></ng-template>
    </p-fieldset>
    } @else {
      <ng-template #fieldComponent></ng-template>
    }
  `,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class FormFieldWrapperComponent extends FieldWrapper {
    /** Hide the field */
    remove() {
        switch (this.field.parent.type) {
            case 'object':
                this.field.props.setHide ? this.field.props.setHide(this.field, true) : this.field.hide = true;
                break;
            case 'array':
                this.field.parent.props.remove(Number(this.field.key));
                break;
        }
    }
    /**
     * Is the field can be hidden?
     * @returns boolean, true if the field can be hidden
     */
    canRemove() {
        switch (this.field.parent.type) {
            case 'object':
                if (!this.field.props?.editorConfig?.longMode) {
                    return false;
                }
                return (!this.field.props.required && !this.field.hide);
            case 'array':
                return this.field.parent.props.canRemove();
            default:
                return false;
        }
    }
    /**
     * Is the field can be hidden?
     * @returns boolean, true if the field can be hidden
     */
    canAdd() {
        if (this.field.parent.type === 'array') {
            return this.field.parent.props.canAdd();
        }
        return false;
    }
    /** Add a new element */
    add() {
        if (this.field.parent.type === 'array') {
            const index = Number(this.field.key) + 1;
            this.field.parent.props.add(index);
        }
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FormFieldWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: FormFieldWrapperComponent, isStandalone: false, selector: "ng-core-form-field-wrapper", usesInheritance: true, ngImport: i0, template: `
    <div class="core:flex core:flex-col core:gap-2" [class]="props.cssClass" [class.has-error]="showError">
      <!-- label -->
      @if (props.label && props.hideLabel !== true) {
        <div>
          <label [attr.for]="id" [pTooltip]="props.description" tooltipPosition="top">
            {{ props.label }}
            @if (props.required && props.hideRequiredMarker !== true) {
              &nbsp;*
            }
          </label>
        </div>
      }
      <div class="core:flex core:content-center core:grow core:gap-1">
        <div class="core:grow">
          <!-- field -->
          <ng-template #fieldComponent></ng-template>
        </div>
          @if (canAdd() || canRemove()) {
          <div class="core:flex core:gap-1 core:items-center">
            <!-- clone button -->
            @if (canAdd()) {
              <p-button icon="fa fa-clone" severity="secondary" [text]="true" (onClick)="add()" />
            }
            <!-- trash button -->
            @if (canRemove()) {
              <p-button icon="fa fa-trash" severity="secondary" [text]="true" (onClick)="remove()" />
            }
          </div>
          }
        </div>
      @if (showError) {
        <div class="text-error core:my-2">
          <formly-validation-message [field]="field"/>
        </div>
      }
   </div>
  `, isInline: true, dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: i4$1.LegacyFormlyValidationMessage, selector: "formly-validation-message" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: FormFieldWrapperComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-form-field-wrapper',
                    template: `
    <div class="core:flex core:flex-col core:gap-2" [class]="props.cssClass" [class.has-error]="showError">
      <!-- label -->
      @if (props.label && props.hideLabel !== true) {
        <div>
          <label [attr.for]="id" [pTooltip]="props.description" tooltipPosition="top">
            {{ props.label }}
            @if (props.required && props.hideRequiredMarker !== true) {
              &nbsp;*
            }
          </label>
        </div>
      }
      <div class="core:flex core:content-center core:grow core:gap-1">
        <div class="core:grow">
          <!-- field -->
          <ng-template #fieldComponent></ng-template>
        </div>
          @if (canAdd() || canRemove()) {
          <div class="core:flex core:gap-1 core:items-center">
            <!-- clone button -->
            @if (canAdd()) {
              <p-button icon="fa fa-clone" severity="secondary" [text]="true" (onClick)="add()" />
            }
            <!-- trash button -->
            @if (canRemove()) {
              <p-button icon="fa fa-trash" severity="secondary" [text]="true" (onClick)="remove()" />
            }
          </div>
          }
        </div>
      @if (showError) {
        <div class="text-error core:my-2">
          <formly-validation-message [field]="field"/>
        </div>
      }
   </div>
  `,
                    changeDetection: ChangeDetectionStrategy.OnPush,
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class HideWrapperComponent extends FieldWrapper {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HideWrapperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: HideWrapperComponent, isStandalone: false, selector: "ng-core-hide-wrapper", usesInheritance: true, ngImport: i0, template: '', isInline: true }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: HideWrapperComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-hide-wrapper',
                    // do not include the children
                    template: '',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Service for managing records search.
 */
class RecordSearchService {
    /**
     * Constructor, initialize aggregations filters subject.
     */
    constructor() {
        /** Aggregations filters array */
        this._aggregationsFilters = null;
        this._aggregationsFiltersSubject = new BehaviorSubject(this._aggregationsFilters);
    }
    /**
     * Returns an observable which emits aggregations filters.
     */
    get aggregationsFilters() {
        return this._aggregationsFiltersSubject.asObservable();
    }
    /**
     * Removes the given value from selected filters and removes all children
     * selected values, too.
     * @param key Aggregation key
     * @param bucket Bucket containing the value to remove
     */
    removeAggregationFilter(key, bucket) {
        this.removeFilter(key, bucket.key.toString());
        this.removeChildrenFilters(bucket);
        this.removeParentFilters(bucket);
        // Update selected aggregations filters
        this._aggregationsFiltersSubject.next(cloneDeep(this._aggregationsFilters));
    }
    /**
     * Set all aggregations filters and emit the list.
     * @param aggregationsFilters List of aggregations filters
     * @param forceRefresh Force the refresh of aggregations filters
     */
    setAggregationsFilters(aggregationsFilters, forceRefresh = false) {
        // TODO: If the filter is in a child bucket, checks if all parents are
        // selected, too. If not, adds all parents filters.
        if (!forceRefresh && JSON.stringify(this._aggregationsFilters) !== JSON.stringify(aggregationsFilters)) {
            forceRefresh = true;
        }
        if (forceRefresh) {
            this._aggregationsFilters = cloneDeep(aggregationsFilters);
            this._aggregationsFiltersSubject.next(cloneDeep(this._aggregationsFilters));
        }
    }
    /**
     * Stores selected values for an aggregation or removes it if values are empty.
     * @param term Term (aggregation key)
     * @param values Selected values
     * @param bucket The complete ElasticSearch affected bucket configuration
     */
    updateAggregationFilter(term, values, bucket = null) {
        if (this._aggregationsFilters === null) {
            this._aggregationsFilters = [];
        }
        if (bucket) {
            this.removeParentFilters(bucket);
            this.removeChildrenFilters(bucket);
        }
        if (values.length === 0) {
            // no more items selected, remove filter
            this._aggregationsFilters = this._aggregationsFilters.filter(item => item.key !== term);
        }
        else {
            const filter = this._aggregationsFilters.find(item => item.key === term);
            // In both cases values are affected with destructuring assignment, to
            // avoid values to be modified outside the service, as array are assigned
            // by reference.
            if (filter) {
                // update existing filter
                filter.values = [...values];
            }
            else {
                // add new filter
                this._aggregationsFilters.push({ key: term, values: [...values] });
            }
        }
        this._aggregationsFiltersSubject.next(cloneDeep(this._aggregationsFilters));
    }
    /**
     * Remove a filter from the current aggregations filters.
     * @param key - the filter name
     * @param value - the filter value
     * @param emit - is the `_aggregationsFiltersSubject` should be emitted
     */
    removeFilter(key, value, emit = false) {
        const filter = this._aggregationsFilters.find(item => item.key === key);
        if (filter) {
            filter.values = filter.values.filter(item => item !== value);
            // No more selected values, remove key from aggregations filters.
            if (filter.values.length === 0) {
                this._aggregationsFilters = this._aggregationsFilters.filter(item => item.key !== filter.key);
            }
        }
        if (emit) {
            this._aggregationsFiltersSubject.next(cloneDeep(this._aggregationsFilters));
        }
    }
    /**
     * Check if a given filter exist in the current aggregations filters.
     * @param key - the filter name
     * @param value - the filter value
     * @returns `true` if exists
     */
    hasFilter(key, value) {
        const filter = this._aggregationsFilters.find((a) => a.key === key);
        return !!(filter && filter.values.some(v => v === value));
    }
    /**
     * Remove the parent filters of a given bucket.
     * @param bucket - The ElasticSearch bucket
     */
    removeParentFilters(bucket) {
        if (bucket.parent) {
            this.removeParentFilters(bucket.parent);
        }
        this.removeFilter(bucket.aggregationKey, bucket.key);
    }
    /**
     * Removes children filters of a given bucket.
     * @param bucket - The ElasticSearch bucket
     */
    removeChildrenFilters(bucket) {
        for (const k of Object.keys(bucket).filter(key => bucket[key].buckets)) {
            const aggregationsKey = k;
            for (const childBucket of bucket[k].buckets) {
                this.removeFilter(aggregationsKey, childBucket.key);
                this.removeChildrenFilters(childBucket);
            }
        }
    }
    /**
     * Check if a children filter of a given bucket exists
     * @param bucket - The ElasticSearch bucket
     * @returns `true` if the bucket has children with a corresponding filter
     */
    hasChildrenFilter(bucket) {
        for (const k of Object.keys(bucket).filter(key => typeof bucket[key] === 'object' && bucket[key].buckets)) {
            const aggregationsKey = k;
            for (const childBucket of bucket[k].buckets) {
                const filter = this._aggregationsFilters.find((v) => v.key === aggregationsKey);
                if ((filter && filter.values.includes(childBucket.key)) || this.hasChildrenFilter(childBucket)) {
                    return true;
                }
            }
        }
        return false;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root',
                }]
        }], ctorParameters: () => [] });

/*
 * RERO angular core
 * Copyright (C) 2020-20224 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Component for displaying record as JSON in brief views.
 */
class JsonComponent {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JsonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: JsonComponent, isStandalone: false, selector: "ng-component", inputs: { record: "record", type: "type", detailUrl: "detailUrl" }, ngImport: i0, template: `
    {{ record|json }}
    @if (detailUrl) {
      <div class="core:my-4">
        @if (detailUrl.external === false) {
          <p-button outlined icon="pi pi-eye" [label]="'Show' | translate" [routerLink]="detailUrl.link" />
        } @else {
          <p-button outlined icon="pi pi-eye" [label]="'Show' | translate" [href]="detailUrl.link" />
        }
      </div>
    }
  `, isInline: true, dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2$8.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i1$2.JsonPipe, name: "json" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: JsonComponent, decorators: [{
            type: Component,
            args: [{
                    template: `
    {{ record|json }}
    @if (detailUrl) {
      <div class="core:my-4">
        @if (detailUrl.external === false) {
          <p-button outlined icon="pi pi-eye" [label]="'Show' | translate" [routerLink]="detailUrl.link" />
        } @else {
          <p-button outlined icon="pi pi-eye" [label]="'Show' | translate" [href]="detailUrl.link" />
        }
      </div>
    }
  `,
                    standalone: false
                }]
        }], propDecorators: { record: [{
                type: Input
            }], type: [{
                type: Input
            }], detailUrl: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2019-2024 RERO
 * Copyright (C) 2019-2023 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordSearchResultComponent {
    constructor() {
        this.changeDetectorRef = inject(ChangeDetectorRef);
        this.router = inject(Router);
        // Store current URL to come back to the same page
        this.currentUrl = null;
        // Admin mode (edit, remove, add, ...)
        this.adminMode = { can: false, message: '' };
        // Observable emitting current value of record URL.
        this.detailUrl$ = null;
        // Event emitted when a record is deleted
        this.deletedRecord = new EventEmitter();
        this.deleteMessageEvent = new EventEmitter();
    }
    // Return a message containing the reasons why the item cannot be deleted
    get deleteInfoMessage() {
        return this.deleteStatus.message;
    }
    // OnInit hook
    ngOnInit() {
        this.currentUrl = window.location.href;
        if (this.canDelete$) {
            this.canDelete$.subscribe((result) => {
                this.deleteStatus = result;
            });
        }
        if (this.canUpdate$) {
            this.canUpdate$.subscribe((result) => {
                this.updateStatus = result;
            });
        }
        if (this.canUse$) {
            this.canUse$.subscribe((result) => {
                this.useStatus = result;
            });
        }
        if (this.detailUrl$) {
            this.detailUrl$.subscribe((url) => {
                this.detailUrl = url;
            });
        }
    }
    // AfterViewInit hook
    ngAfterViewInit() {
        this.container.clear();
        const component = this.container.createComponent(this.itemViewComponent || JsonComponent);
        component.instance.record = this.record;
        component.instance.type = this.type;
        component.instance.detailUrl = this.detailUrl;
        this.changeDetectorRef.detectChanges();
    }
    /**
     * Delete a record
     * @param pid - string, pid to delete
     * @param type - string, resource type
     */
    deleteRecord(pid, type) {
        if (this.deleteStatus.can) {
            this.deletedRecord.emit({ pid, type });
        }
        else {
            this.deleteMessageEvent.emit(this.deleteStatus.message.replace(new RegExp('\n', 'g'), '<br>'));
        }
    }
    /**
     * Use a record
     */
    useRecord() {
        this.router.navigateByUrl(this.useStatus.url);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchResultComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RecordSearchResultComponent, isStandalone: false, selector: "ng-core-record-search-result", inputs: { record: "record", type: "type", itemViewComponent: "itemViewComponent", adminMode: "adminMode", canUpdate$: "canUpdate$", canDelete$: "canDelete$", canUse$: "canUse$", aggregations: "aggregations", detailUrl$: "detailUrl$" }, outputs: { deletedRecord: "deletedRecord", deleteMessageEvent: "deleteMessageEvent" }, viewQueries: [{ propertyName: "container", first: true, predicate: ["item"], descendants: true, read: ViewContainerRef }], ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2019-2024 RERO\n  Copyright (C) 2019-2023 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div class=\"core:flex core:items-start\">\n  <div class=\"core:grow\">\n    <ng-container #item></ng-container>\n  </div>\n  <div class=\"core:flex core:flex-none core:gap-1 core:justify-end core:ml-2\">\n    @if (adminMode.can) {\n        <!-- use button -->\n        @if (useStatus?.can && useStatus?.url) {\n          <p-button\n            [outlined]=\"true\"\n            [ariaLabel]=\"'Use' | translate\"\n            (onClick)=\"useRecord()\"\n            [title]=\"'Use' | translate\"\n            icon=\"fa fa-hand-o-right\"\n          />\n        }\n\n        <!-- edit button -->\n        @if (updateStatus?.can) {\n          <p-button\n            [outlined]=\"true\"\n            [ariaLabel]=\"'Edit' | translate\"\n            [routerLink]=\"updateStatus.routerLink || ['edit', record.id]\"\n            icon=\"fa fa-pencil\"\n          />\n        }\n\n        <!-- delete button -->\n        @if (deleteStatus?.can || deleteStatus?.message) {\n          <p-button\n          icon=\"fa fa-trash\"\n          severity=\"danger\"\n          class=\"core:pointer-events-auto\"\n          outlined\n          [title]=\"'Delete'|translate\"\n          (onClick)=\"deleteRecord(record.id, deleteStatus?.type)\"\n          [pTooltip]=\"tooltipContent\"\n          tooltipPosition=\"top\"\n          [disabled]=\"!deleteStatus.can\"\n          [tooltipDisabled]=\"deleteStatus.can\"\n        />\n        <ng-template #tooltipContent>\n          <span [innerHTML]=\"deleteStatus.message\"></span>\n        </ng-template>\n        }\n    }\n  </div>\n</div>\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "directive", type: i2.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "directive", type: i2$8.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchResultComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-record-search-result', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2019-2024 RERO\n  Copyright (C) 2019-2023 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<div class=\"core:flex core:items-start\">\n  <div class=\"core:grow\">\n    <ng-container #item></ng-container>\n  </div>\n  <div class=\"core:flex core:flex-none core:gap-1 core:justify-end core:ml-2\">\n    @if (adminMode.can) {\n        <!-- use button -->\n        @if (useStatus?.can && useStatus?.url) {\n          <p-button\n            [outlined]=\"true\"\n            [ariaLabel]=\"'Use' | translate\"\n            (onClick)=\"useRecord()\"\n            [title]=\"'Use' | translate\"\n            icon=\"fa fa-hand-o-right\"\n          />\n        }\n\n        <!-- edit button -->\n        @if (updateStatus?.can) {\n          <p-button\n            [outlined]=\"true\"\n            [ariaLabel]=\"'Edit' | translate\"\n            [routerLink]=\"updateStatus.routerLink || ['edit', record.id]\"\n            icon=\"fa fa-pencil\"\n          />\n        }\n\n        <!-- delete button -->\n        @if (deleteStatus?.can || deleteStatus?.message) {\n          <p-button\n          icon=\"fa fa-trash\"\n          severity=\"danger\"\n          class=\"core:pointer-events-auto\"\n          outlined\n          [title]=\"'Delete'|translate\"\n          (onClick)=\"deleteRecord(record.id, deleteStatus?.type)\"\n          [pTooltip]=\"tooltipContent\"\n          tooltipPosition=\"top\"\n          [disabled]=\"!deleteStatus.can\"\n          [tooltipDisabled]=\"deleteStatus.can\"\n        />\n        <ng-template #tooltipContent>\n          <span [innerHTML]=\"deleteStatus.message\"></span>\n        </ng-template>\n        }\n    }\n  </div>\n</div>\n" }]
        }], propDecorators: { record: [{
                type: Input
            }], type: [{
                type: Input
            }], itemViewComponent: [{
                type: Input
            }], adminMode: [{
                type: Input
            }], canUpdate$: [{
                type: Input
            }], canDelete$: [{
                type: Input
            }], canUse$: [{
                type: Input
            }], aggregations: [{
                type: Input
            }], detailUrl$: [{
                type: Input
            }], deletedRecord: [{
                type: Output
            }], deleteMessageEvent: [{
                type: Output
            }], container: [{
                type: ViewChild,
                args: ['item', { read: ViewContainerRef }]
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2019-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * To implement your translation, please do it in your application
 * by overloading this service.
 * Example:
 *
 * import { BucketNameService as CoreBucketNameService } from '@rero/ng-core';
 * import { BucketNameService } from './service/bucket-name.service';
 *
 * @NgModule({
 *     providers: [
 *         { provide: CoreBucketNameService, useClass: BucketNameService }
 *     ]
 * });
 *
 */
class BucketNameService {
    constructor() {
        this.translateService = inject(TranslateService);
    }
    /**
     * Transform aggregation name
     * @param aggregationKey - type of aggregation
     * @param value - value of current aggregation
     * @returns Observable of string
     */
    transform(aggregationKey, value) {
        let data = value;
        // Legacy: for compatibility
        switch (aggregationKey) {
            case 'language':
                data = `lang_${value}`;
                break;
        }
        // End Legacy
        return of(this.translateService.instant(data));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketNameService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketNameService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketNameService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2019-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class BucketNamePipe {
    constructor() {
        this.bucketNameService = inject(BucketNameService);
    }
    /**
     * Transform value if the type of aggregation is language
     * @param value - aggregation value
     * @param aggregationKey - aggregation type
     * @returns Observable<string>
     */
    transform(value, aggregationKey) {
        return this.bucketNameService.transform(aggregationKey, value);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
    static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: BucketNamePipe, isStandalone: false, name: "bucketName" }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketNamePipe, decorators: [{
            type: Pipe,
            args: [{
                    name: 'bucketName',
                    standalone: false
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class BucketsComponent {
    constructor() {
        this.recordSearchService = inject(RecordSearchService);
        // COMPONENT ATTRIBUTES ============================================================
        /** Buckets list for aggregation */
        this.buckets = input.required();
        /** Aggregation key */
        this.aggregationKey = input.required();
        /** Bucket size, if not null, reduce displayed items to this size. */
        this.size = input();
        /** More and less on aggregation content (facet) */
        this.moreMode = true;
        /** Current selected values for the aggregations */
        this.aggregationsFilters = [];
        /** Children of current bucket */
        this.bucketChildren = {};
    }
    // GETTERS & SETTERS =================================================================
    /** Returns selected filters for the aggregation key. */
    get aggregationFilters() {
        const aggregationFilters = this.aggregationsFilters.find((item) => item.key === this.aggregationKey());
        return aggregationFilters === undefined
            ? []
            : aggregationFilters.values;
    }
    /** Get bucket size. */
    get bucketSize() {
        const size = this.buckets().length;
        return this.size() === null || this.moreMode === false
            ? size
            : this.size();
    }
    /** Get the number of bucket items with non-zero doc_count. */
    get bucketsLength() {
        return this.buckets().reduce((acc, bucket) => (bucket.doc_count) ? acc + 1 : acc, 0);
    }
    /** Should display more or less link for a bucket ? */
    get displayMoreAndLessLink() {
        return (this.size() === null)
            ? false
            : this.bucketsLength > this.size();
    }
    /**
     * OnInit hook
     *   Subscribe to aggregations filters observable for getting the aggregations filters each time
     *   they will change.
     */
    ngOnInit() {
        this.aggregationsFiltersSubscription = this.recordSearchService
            .aggregationsFilters
            .subscribe((aggregationsFilters) => {
            if (aggregationsFilters !== null) {
                this.aggregationsFilters = aggregationsFilters;
            }
        });
    }
    /**
     * OnChanges hook
     *   Called each time an input property is modified.
     *   If buckets are changed, refresh children buckets.
     * @param changes - bucket changes
     */
    ngOnChanges(changes) {
        if (changes.buckets) {
            for (const bucket of this.buckets()) {
                this.bucketChildren[bucket.key] = this.getBucketChildren(bucket);
            }
        }
    }
    /**
     * OnDestroy hook
     *   Unsubscribes from the observable of aggregations filters.
     */
    ngOnDestroy() {
        this.aggregationsFiltersSubscription.unsubscribe();
    }
    // COMPONENT F£UNCTIONS =====================================================
    /**
     * Check if a value is present in selected filters.
     * @param value: filter value (could be string, number, ...)
     * @return `true` if value is present in the aggregation filters, `null` otherwise.
     */
    isSelected(value) {
        return this.aggregationFilters.includes(value.toString()) ? true : null;
    }
    /**
     * Do we need to display the children?
     * @return `true` if we want to display the children, `false` otherwise.
     */
    displayChildren(bucket) {
        return (this.isSelected(bucket.key) ||
            // not necessary but faster than hasChildrenFilter
            bucket.indeterminate ||
            // hasChildrenFilter is required to avoid blinks when a child is selected
            this.recordSearchService.hasChildrenFilter(bucket));
    }
    /**
     * Update selected filters by adding or removing the given value and push
     * values to service.
     * @param bucket - string: the selected bucket value (checked OR unchecked)
     */
    updateFilter(bucket) {
        const index = this.aggregationsFilters.findIndex((item) => item.key === this.aggregationKey());
        if (index === -1) {
            // No filters exist for the aggregation.
            this.recordSearchService.updateAggregationFilter(this.aggregationKey(), [bucket.key], bucket);
        }
        else {
            const aggFilter = this.aggregationsFilters[index];
            if (!aggFilter.values.includes(bucket.key.toString())) {
                // Bucket value is not yet selected, we add value to selected values.
                this.aggregationsFilters[index].values.push(bucket.key.toString());
                this.recordSearchService.updateAggregationFilter(this.aggregationKey(), this.aggregationsFilters[index].values, bucket);
            }
            else {
                // Removes value from selected values and all children selected values.
                this.recordSearchService.removeAggregationFilter(this.aggregationKey(), bucket);
            }
        }
    }
    /**
     * Get children buckets
     * @param bucket: parent bucket
     * @return Bucket children list of given bucket
     */
    getBucketChildren(bucket) {
        const children = [];
        for (const k of Object.keys(bucket).filter(key => typeof bucket[key] === 'object' && bucket[key].buckets)) {
            children.push({
                aggregationKey: k,
                bucketSize: this.bucketSize,
                key: k,
                buckets: bucket[k].buckets,
            });
        }
        return children;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: BucketsComponent, isStandalone: false, selector: "ng-core-record-search-aggregation-buckets", inputs: { buckets: { classPropertyName: "buckets", publicName: "buckets", isSignal: true, isRequired: true, transformFunction: null }, aggregationKey: { classPropertyName: "aggregationKey", publicName: "aggregationKey", isSignal: true, isRequired: true, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, usesOnChanges: true, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (buckets()) {\n  <ul class=\"core:list-none core:text-sm\">\n  @for (bucket of buckets()|slice:0:bucketSize; track bucket.key; let index = $index) {\n    <li>\n        @if (bucket.doc_count) {\n          <div class=\"core:flex core:gap-1 core:items-start core:text-link-secondary core:mb-1\">\n            <p-checkbox\n              inputId=\"{{ bucket.aggregationKey }}-{{ index }}\"\n              binary\n              [indeterminate]=\"bucket.indeterminate\"\n              variant=\"filled\"\n              [ngModel]=\"isSelected(bucket.key)\"\n              (onChange)=\"updateFilter(bucket)\"\n            />\n            <label class=\"core:grow core:overflow-hidden\" for=\"{{ bucket.aggregationKey }}-{{ index }}\">\n              @if (bucket.name) {\n                {{ bucket.name }}\n              } @else {\n                {{ bucket.key | bucketName: aggregationKey() | async }}\n              }\n            </label>\n              <div class=\"core:pl-2\">\n                {{ bucket.doc_count }}\n              </div>\n          </div>\n        }\n      <div class=\"core:ml-6\">\n        @if (displayChildren(bucket)) {\n          @for (aggregation of bucketChildren[bucket.key]; track aggregation.key) {\n            <ng-core-record-search-aggregation-buckets\n              [buckets]=\"aggregation.buckets\"\n              [size]=\"aggregation.bucketSize\"\n              [aggregationKey]=\"aggregation.key\"\n            ></ng-core-record-search-aggregation-buckets>\n          }\n        }\n      </div>\n    </li>\n  }\n  </ul>\n}\n@if (displayMoreAndLessLink) {\n  <div class=\"core:flex core:justify-end\">\n    <span class=\"text-link\" (click)=\"moreMode = !moreMode\">{{ (moreMode ? 'more\u2026' : 'less\u2026') | translate }}</span>\n  </div>\n}\n", dependencies: [{ kind: "component", type: i2$5.Checkbox, selector: "p-checkbox, p-checkBox, p-check-box", inputs: ["value", "name", "disabled", "binary", "ariaLabelledBy", "ariaLabel", "tabindex", "inputId", "style", "inputStyle", "styleClass", "inputClass", "indeterminate", "size", "formControl", "checkboxIcon", "readonly", "required", "autofocus", "trueValue", "falseValue", "variant"], outputs: ["onChange", "onFocus", "onBlur"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: BucketsComponent, selector: "ng-core-record-search-aggregation-buckets", inputs: ["buckets", "aggregationKey", "size"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$2.SlicePipe, name: "slice" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: BucketNamePipe, name: "bucketName" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: BucketsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-record-search-aggregation-buckets', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (buckets()) {\n  <ul class=\"core:list-none core:text-sm\">\n  @for (bucket of buckets()|slice:0:bucketSize; track bucket.key; let index = $index) {\n    <li>\n        @if (bucket.doc_count) {\n          <div class=\"core:flex core:gap-1 core:items-start core:text-link-secondary core:mb-1\">\n            <p-checkbox\n              inputId=\"{{ bucket.aggregationKey }}-{{ index }}\"\n              binary\n              [indeterminate]=\"bucket.indeterminate\"\n              variant=\"filled\"\n              [ngModel]=\"isSelected(bucket.key)\"\n              (onChange)=\"updateFilter(bucket)\"\n            />\n            <label class=\"core:grow core:overflow-hidden\" for=\"{{ bucket.aggregationKey }}-{{ index }}\">\n              @if (bucket.name) {\n                {{ bucket.name }}\n              } @else {\n                {{ bucket.key | bucketName: aggregationKey() | async }}\n              }\n            </label>\n              <div class=\"core:pl-2\">\n                {{ bucket.doc_count }}\n              </div>\n          </div>\n        }\n      <div class=\"core:ml-6\">\n        @if (displayChildren(bucket)) {\n          @for (aggregation of bucketChildren[bucket.key]; track aggregation.key) {\n            <ng-core-record-search-aggregation-buckets\n              [buckets]=\"aggregation.buckets\"\n              [size]=\"aggregation.bucketSize\"\n              [aggregationKey]=\"aggregation.key\"\n            ></ng-core-record-search-aggregation-buckets>\n          }\n        }\n      </div>\n    </li>\n  }\n  </ul>\n}\n@if (displayMoreAndLessLink) {\n  <div class=\"core:flex core:justify-end\">\n    <span class=\"text-link\" (click)=\"moreMode = !moreMode\">{{ (moreMode ? 'more\u2026' : 'less\u2026') | translate }}</span>\n  </div>\n}\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class AggregationSliderComponent {
    constructor() {
        this.recordSearchService = inject(RecordSearchService);
        // COMPONENT ATTRIBUTES =====================================================
        /** The aggregation key. */
        this.key = input();
        /** Buckets list */
        this.buckets = input();
        /** The minimum value */
        this.min = input(1);
        /** The maximum value */
        this.max = input(1000);
        /** gap between each value. */
        this.step = input(1);
        /** Range to search */
        this.range = null;
        /** True if route have aggregation query param. */
        this.hasQueryParam = false;
    }
    /**
     * OnInit hook
     * Subscribe to route changes for getting aggregation query parameter.
     */
    ngOnInit() {
        this.range = [this.min(), this.max()];
        this.searchServiceSubscription = this.recordSearchService
            .aggregationsFilters
            .subscribe((filters) => {
            if (!filters) {
                return;
            }
            let filter = filters.find((element) => element.key === this.key());
            if (filter) {
                filter = filter.values[0].split('--').map((item) => +item);
                this.hasQueryParam = true;
                this.range = filter;
            }
            else {
                this.range = [this.min(), this.max()];
            }
        });
    }
    /**
     * OnDestroy hook
     * Unsubscribes from search service.
     */
    ngOnDestroy() {
        this.searchServiceSubscription.unsubscribe();
    }
    // COMPONENT FUNCTIONS ======================================================
    /** Update aggregation filter. */
    updateFilter() {
        if (!this.range[0] || this.range[0] < this.min()) {
            this.range[0] = this.min();
        }
        if (!this.range[1] || this.range[1] > this.max()) {
            this.range[1] = this.max();
        }
        this.recordSearchService.updateAggregationFilter(this.key(), [
            `${this.range[0]}--${this.range[1]}`,
        ]);
    }
    /** Clear aggregation filter. */
    clearFilter() {
        this.hasQueryParam = false;
        this.recordSearchService.updateAggregationFilter(this.key(), []);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AggregationSliderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: AggregationSliderComponent, isStandalone: false, selector: "ng-core-aggregation-slider", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null }, buckets: { classPropertyName: "buckets", publicName: "buckets", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-inputGroup>\n    <p-inputNumber\n      class=\"core:mr-1\"\n      inputId=\"integeronly\"\n      [useGrouping]=\"false\"\n      [(ngModel)]=\"range[0]\"\n      [min]=\"range[0]\"\n      [max]=\"range[1]\" />\n    <p-inputNumber\n      class=\"core:ml-1\"\n      inputId=\"integeronly\"\n      [useGrouping]=\"false\"\n      [(ngModel)]=\"range[1]\"\n      [min]=\"range[0]\"\n      [max]=\"range[1]\" />\n</p-inputGroup>\n<div class=\"core:flex core:justify-end core:mt-2 core:gap-2\">\n    @if (hasQueryParam) {\n      <p-button size=\"small\" [label]=\"'Clear' | translate\" [outlined]=\"true\" (onClick)=\"$event.preventDefault(); clearFilter()\" />\n    }\n    <p-button size=\"small\" [label]=\"'Apply' | translate\" [outlined]=\"true\" (onClick)=\"$event.preventDefault(); updateFilter()\" />\n</div>\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i4.InputGroup, selector: "p-inputgroup, p-inputGroup, p-input-group", inputs: ["style", "styleClass"] }, { kind: "component", type: i3$6.InputNumber, selector: "p-inputNumber, p-inputnumber, p-input-number", inputs: ["showButtons", "format", "buttonLayout", "inputId", "styleClass", "style", "placeholder", "size", "maxlength", "tabindex", "title", "ariaLabelledBy", "ariaDescribedBy", "ariaLabel", "ariaRequired", "name", "required", "autocomplete", "min", "max", "incrementButtonClass", "decrementButtonClass", "incrementButtonIcon", "decrementButtonIcon", "readonly", "step", "allowEmpty", "locale", "localeMatcher", "mode", "currency", "currencyDisplay", "useGrouping", "variant", "minFractionDigits", "maxFractionDigits", "prefix", "suffix", "inputStyle", "inputStyleClass", "showClear", "autofocus", "disabled", "fluid"], outputs: ["onInput", "onFocus", "onBlur", "onKeyDown", "onClear"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AggregationSliderComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-aggregation-slider', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-inputGroup>\n    <p-inputNumber\n      class=\"core:mr-1\"\n      inputId=\"integeronly\"\n      [useGrouping]=\"false\"\n      [(ngModel)]=\"range[0]\"\n      [min]=\"range[0]\"\n      [max]=\"range[1]\" />\n    <p-inputNumber\n      class=\"core:ml-1\"\n      inputId=\"integeronly\"\n      [useGrouping]=\"false\"\n      [(ngModel)]=\"range[1]\"\n      [min]=\"range[0]\"\n      [max]=\"range[1]\" />\n</p-inputGroup>\n<div class=\"core:flex core:justify-end core:mt-2 core:gap-2\">\n    @if (hasQueryParam) {\n      <p-button size=\"small\" [label]=\"'Clear' | translate\" [outlined]=\"true\" (onClick)=\"$event.preventDefault(); clearFilter()\" />\n    }\n    <p-button size=\"small\" [label]=\"'Apply' | translate\" [outlined]=\"true\" (onClick)=\"$event.preventDefault(); updateFilter()\" />\n</div>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2021-2025 RERO
 * Copyright (C) 2021 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class AggregationDateRangeComponent {
    constructor() {
        this.recordSearchService = inject(RecordSearchService);
        this.translateService = inject(TranslateService);
        // COMPONENTS ATTRIBUTES ====================================================
        // Aggregation key
        this.key = input.required();
        // Components configuration
        this.config = input.required();
        // Date minimum
        this.minDate = null;
        // Date maximum
        this.maxDate = null;
        /** True if route have aggregation query param. */
        this.hasQueryParam = false;
        this.buttonConfig = [];
    }
    /** OnInit hook */
    ngOnInit() {
        // Define min/max values if not exists
        if (this.config().min) {
            this.minDate = new Date(this.config().min);
        }
        else {
            this.minDate = new Date(1900, 0, 0);
        }
        if (this.config().max) {
            this.maxDate = new Date(this.config().max);
        }
        else {
            this.maxDate = new Date();
        }
        this.dateRangeModel = [this.minDate, this.maxDate];
        this.searchServiceSubscription = this.recordSearchService.aggregationsFilters.subscribe((filters) => {
            if (!filters) {
                return;
            }
            const filter = filters.find((element) => element.key === this.key());
            this.hasQueryParam = filter !== undefined;
            this.dateRangeModel = (filter)
                ? filter.values[0].split('--').map((item) => new Date(+item)) // split filter data and transform each part into Date
                : [this.minDate, this.maxDate];
        });
        const today = new Date();
        this.buttonConfig = [
            {
                value: [new Date(new Date().setDate(today.getDate() - 31)), today],
                label: this.translateService.instant('Last month')
            }, {
                value: [new Date(new Date().setDate(today.getDate() - 366)), today],
                label: this.translateService.instant('Last year')
            }, {
                value: [new Date(today.getFullYear(), today.getMonth(), 1), new Date(today.getFullYear(), today.getMonth() + 1, 0)],
                label: this.translateService.instant('This month')
            },
            {
                value: [new Date(today.getFullYear(), 0, 1), new Date(today.getFullYear() + 1, 0, 1)],
                label: this.translateService.instant('This year')
            }
        ];
    }
    setRange(value) {
        this.dateRangeModel = value;
        this.updateFilter();
    }
    /** OnDestroy hook */
    ngOnDestroy() {
        this.searchServiceSubscription.unsubscribe();
    }
    // COMPONENTS FUNCTIONS =====================================================
    /** Update aggregation filter. */
    updateFilter() {
        if (this.dateRangeModel && this.dateRangeModel[0] && this.dateRangeModel[1]) {
            this.recordSearchService.updateAggregationFilter(this.key(), [
                `${this.dateRangeModel[0].getTime()}--${this.dateRangeModel[1].getTime()}`
            ]);
        }
    }
    /** Clear aggregation filter. */
    clearFilter() {
        this.recordSearchService.updateAggregationFilter(this.key(), []);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AggregationDateRangeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: AggregationDateRangeComponent, isStandalone: false, selector: "ng-core-aggregation-date-range", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2021-2025 RERO\n  Copyright (C) 2021 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-datepicker\n  styleClass=\"core:w-full\"\n  inputStyleClass=\"core:text-center\"\n  [(ngModel)]=\"dateRangeModel\"\n  selectionMode=\"range\"\n  showIcon\n>\n  <ng-template #footer>\n    <p-divider/>\n    <div class=\"core:grid core:grid-cols-12 core:gap-4\">\n      @for (cfg of buttonConfig; track cfg.value) {\n        <div class=\"core:col-span-6 core:flex core:justify-center\">\n          <p-button (onClick)=\"setRange(cfg.value)\" styleClass=\"core:w-full\" class=\"core:grow core:p-1\" outlined size=\"small\" [label]=\"cfg.label\" />\n        </div>\n      }\n    </div>\n  </ng-template>\n</p-datepicker>\n<div class=\"core:flex core:justify-end core:mt-2 core:gap-2\">\n  @if (hasQueryParam) {\n    <p-button size=\"small\" [label]=\"'Clear' | translate\" [outlined]=\"true\" (onClick)=\"clearFilter()\" />\n  }\n  <p-button size=\"small\" [label]=\"'Apply' | translate\" [outlined]=\"true\" (onClick)=\"updateFilter()\" />\n</div>\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$4.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "style", "styleClass", "inputStyle", "inputId", "name", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "disabled", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "fluid", "icon", "appendTo", "readonlyInput", "shortYearCutoff", "monthNavigator", "yearNavigator", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "required", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "variant", "size", "minDate", "maxDate", "disabledDates", "disabledDays", "yearRange", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "locale", "view", "defaultDate"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "component", type: i2$3.Divider, selector: "p-divider", inputs: ["style", "styleClass", "layout", "type", "align"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AggregationDateRangeComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-aggregation-date-range', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2021-2025 RERO\n  Copyright (C) 2021 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-datepicker\n  styleClass=\"core:w-full\"\n  inputStyleClass=\"core:text-center\"\n  [(ngModel)]=\"dateRangeModel\"\n  selectionMode=\"range\"\n  showIcon\n>\n  <ng-template #footer>\n    <p-divider/>\n    <div class=\"core:grid core:grid-cols-12 core:gap-4\">\n      @for (cfg of buttonConfig; track cfg.value) {\n        <div class=\"core:col-span-6 core:flex core:justify-center\">\n          <p-button (onClick)=\"setRange(cfg.value)\" styleClass=\"core:w-full\" class=\"core:grow core:p-1\" outlined size=\"small\" [label]=\"cfg.label\" />\n        </div>\n      }\n    </div>\n  </ng-template>\n</p-datepicker>\n<div class=\"core:flex core:justify-end core:mt-2 core:gap-2\">\n  @if (hasQueryParam) {\n    <p-button size=\"small\" [label]=\"'Clear' | translate\" [outlined]=\"true\" (onClick)=\"clearFilter()\" />\n  }\n  <p-button size=\"small\" [label]=\"'Apply' | translate\" [outlined]=\"true\" (onClick)=\"updateFilter()\" />\n</div>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordSearchAggregationComponent {
    constructor() {
        // COMPONENT ATTRIBUTES =====================================================
        /** Aggregation data */
        this.aggregation = input();
        /** Current selected values */
        this.aggregationsFilters = input.required();
        /** Output event when aggregation is clicked. */
        this.aggregationClicked = output();
    }
    // GETTER & SETTER ==========================================================
    /**
     * Returns aggregations filters corresponding to the aggregation key.
     * @return List of aggregation filters
     */
    get aggregationFilters() {
        const aggregationFilters = this.aggregationsFilters().find((item) => item.key === this.aggregation().key);
        return aggregationFilters === undefined ? [] : aggregationFilters.values;
    }
    /** Is the aggregation content should be displayed. */
    get isAggregationDisplayed() {
        return this.aggregation().expanded || this.aggregationFilters.length > 0;
    }
    // PUBLIC COMPONENTS ========================================================
    /**
     * Method called when the title of an aggregation is clicked.
     */
    toggleVisibility() {
        // if filters are selected, we do nothing.
        if (this.aggregationFilters.length > 0) {
            return;
        }
        // Toggle aggregation expanded attribute
        this.aggregation().expanded = !this.aggregation().expanded;
        // Emit the value to parent.
        this.aggregationClicked.emit({
            key: this.aggregation().key,
            expanded: this.aggregation().expanded,
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchAggregationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RecordSearchAggregationComponent, isStandalone: false, selector: "ng-core-record-search-aggregation", inputs: { aggregation: { classPropertyName: "aggregation", publicName: "aggregation", isSignal: true, isRequired: false, transformFunction: null }, aggregationsFilters: { classPropertyName: "aggregationsFilters", publicName: "aggregationsFilters", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { aggregationClicked: "aggregationClicked" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<!-- Aggregation with no bucket, containing only the count. -->\n@if (aggregation().doc_count) {\n  <div class=\"core:mb-4\">\n    <ng-core-record-search-aggregation-buckets\n      [buckets]=\"[{key: '1', doc_count: aggregation().doc_count, name: aggregation().key | translate }]\"\n      [aggregationKey]=\"aggregation().key\"\n      [size]=\"aggregation().bucketSize\" />\n  </div>\n} @else {\n  <p-fieldset\n    [legend]=\"(aggregation().name || aggregation().key) | translate | ucfirst\"\n    [toggleable]=\"true\"\n    [collapsed]=\"!isAggregationDisplayed\"\n    (collapsedChange)=\"toggleVisibility()\"\n  >\n  <div class=\"core:p-2\">\n  @switch (aggregation().type) {\n    @case ('range') {\n      <ng-core-aggregation-slider\n        [key]=\"aggregation().key\"\n        [min]=\"aggregation().config.min || 1\"\n        [max]=\"aggregation().config.max || 100\"\n        [step]=\"aggregation().config.step || 1\"\n        [buckets]=\"aggregation().value.buckets\" />\n    }\n    @case ('date-range') {\n      <ng-core-aggregation-date-range\n        [key]=\"aggregation().key\"\n        [config]=\"aggregation().config\" />\n    }\n    @default {\n      @if (aggregation().value.buckets.length > 0) {\n        <ng-core-record-search-aggregation-buckets\n          [buckets]=\"aggregation().value.buckets\"\n          [aggregationKey]=\"aggregation().key\"\n          [size]=\"aggregation().bucketSize\" />\n      } @else {\n        @if (aggregation().loaded) {\n          <span class=\"core:text-sm\" translate>No result</span>\n        }\n      }\n    }\n  }\n</div>\n</p-fieldset>\n}\n", dependencies: [{ kind: "component", type: i1$7.Fieldset, selector: "p-fieldset", inputs: ["legend", "toggleable", "collapsed", "style", "styleClass", "transitionOptions"], outputs: ["collapsedChange", "onBeforeToggle", "onAfterToggle"] }, { kind: "directive", type: i5.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: BucketsComponent, selector: "ng-core-record-search-aggregation-buckets", inputs: ["buckets", "aggregationKey", "size"] }, { kind: "component", type: AggregationSliderComponent, selector: "ng-core-aggregation-slider", inputs: ["key", "buckets", "min", "max", "step"] }, { kind: "component", type: AggregationDateRangeComponent, selector: "ng-core-aggregation-date-range", inputs: ["key", "config"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: UpperCaseFirstPipe, name: "ucfirst" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchAggregationComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-record-search-aggregation', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<!-- Aggregation with no bucket, containing only the count. -->\n@if (aggregation().doc_count) {\n  <div class=\"core:mb-4\">\n    <ng-core-record-search-aggregation-buckets\n      [buckets]=\"[{key: '1', doc_count: aggregation().doc_count, name: aggregation().key | translate }]\"\n      [aggregationKey]=\"aggregation().key\"\n      [size]=\"aggregation().bucketSize\" />\n  </div>\n} @else {\n  <p-fieldset\n    [legend]=\"(aggregation().name || aggregation().key) | translate | ucfirst\"\n    [toggleable]=\"true\"\n    [collapsed]=\"!isAggregationDisplayed\"\n    (collapsedChange)=\"toggleVisibility()\"\n  >\n  <div class=\"core:p-2\">\n  @switch (aggregation().type) {\n    @case ('range') {\n      <ng-core-aggregation-slider\n        [key]=\"aggregation().key\"\n        [min]=\"aggregation().config.min || 1\"\n        [max]=\"aggregation().config.max || 100\"\n        [step]=\"aggregation().config.step || 1\"\n        [buckets]=\"aggregation().value.buckets\" />\n    }\n    @case ('date-range') {\n      <ng-core-aggregation-date-range\n        [key]=\"aggregation().key\"\n        [config]=\"aggregation().config\" />\n    }\n    @default {\n      @if (aggregation().value.buckets.length > 0) {\n        <ng-core-record-search-aggregation-buckets\n          [buckets]=\"aggregation().value.buckets\"\n          [aggregationKey]=\"aggregation().key\"\n          [size]=\"aggregation().bucketSize\" />\n      } @else {\n        @if (aggregation().loaded) {\n          <span class=\"core:text-sm\" translate>No result</span>\n        }\n      }\n    }\n  }\n</div>\n</p-fieldset>\n}\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2022-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class ListFiltersComponent {
    constructor() {
        this.translateService = inject(TranslateService);
        /**
         * All aggregations
         */
        this.aggregations = input([]);
        // Selected aggregations filters
        this.aggregationsFilters = input([]);
        // Search filters
        this.searchFilters = input([]);
        /** Remove filter event */
        this.remove = output();
        // Filters to hide
        this.filtersToHide = ['simple'];
        // Filters selected
        this.filters = computed(() => this.getActiveFilters());
    }
    /**
     * Returns promised filters
     * @returns the array of IFilter
     */
    getActiveFilters() {
        const filterSet = [];
        this.searchFilters().forEach((filter) => {
            if (!filter.filters) {
                filterSet.push(filter.filter);
            }
            else {
                filter.filters.forEach((fSection) => {
                    filterSet.push(fSection.filter);
                });
            }
        });
        this.filtersToHide = [...new Set([...this.filtersToHide, ...filterSet])];
        let filters = [];
        this.aggregationsFilters().map((filter) => {
            if (!this.filtersToHide.includes(filter.key)) {
                filter.values.map((value) => {
                    if (value.includes('--')) {
                        const regex = /\d{13,}--\d{13,}/;
                        if (regex.test(value)) {
                            const [min, max] = value.split('--');
                            const dateMin = new Intl.DateTimeFormat(this.translateService.currentLang).format(+min);
                            const dateMax = new Intl.DateTimeFormat(this.translateService.currentLang).format(+max);
                            filters.push({ key: value, aggregationKey: filter.key, name: `${dateMin} - ${dateMax}` });
                        }
                        else {
                            filters.push({ key: value, aggregationKey: filter.key, name: value.replace('--', ' - ') });
                        }
                    }
                    else {
                        filters.push({ key: value, aggregationKey: filter.key });
                    }
                });
            }
        });
        if (this.aggregations()) {
            this.aggregations().map((item) => {
                this.getFilterNames(item.value.buckets, filters);
            });
        }
        return filters;
    }
    /**
     * Get displayed name of bucket
     * and fill in filters list.
     *
     * @param buckets - Bucket to get the name from.
     */
    getFilterNames(buckets, filters) {
        if (!buckets || buckets.length === 0) {
            return;
        }
        buckets.map((bucket) => {
            for (const k in bucket) {
                if (bucket[k].buckets) {
                    this.getFilterNames(bucket[k].buckets, filters);
                }
            }
            if (bucket.name) {
                const index = filters.findIndex((filter) => filter.key === bucket.key && filter.aggregationKey === bucket.aggregationKey);
                if (index > -1) {
                    filters[index].name = bucket.name;
                    filters[index] = { ...filters[index] };
                }
            }
        });
    }
    /**
     * Remove filter.
     * @param filter - the filter to remove
     */
    removeFilter(filter) {
        this.remove.emit(filter);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ListFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: ListFiltersComponent, isStandalone: false, selector: "ng-core-list-filters", inputs: { aggregations: { classPropertyName: "aggregations", publicName: "aggregations", isSignal: true, isRequired: false, transformFunction: null }, aggregationsFilters: { classPropertyName: "aggregationsFilters", publicName: "aggregationsFilters", isSignal: true, isRequired: false, transformFunction: null }, searchFilters: { classPropertyName: "searchFilters", publicName: "searchFilters", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { remove: "remove" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2022-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (filters()?.length > 0) {\n  <div class=\"core:flex core:flex-wrap core:mb-2\">\n    @for (filter of filters(); track filter.key) {\n    <p-button\n      class=\"core:mr-2 core:mb-2\"\n      [label]=\"filter.name ? filter.name : (filter.key | bucketName : filter.aggregationKey | async)\"\n      icon=\"fa fa-times\"\n      [outlined]=\"true\"\n      severity=\"secondary\"\n      (onClick)=\"removeFilter(filter)\"\n    />\n    }\n  </div>\n  }\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: BucketNamePipe, name: "bucketName" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: ListFiltersComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-list-filters', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2022-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (filters()?.length > 0) {\n  <div class=\"core:flex core:flex-wrap core:mb-2\">\n    @for (filter of filters(); track filter.key) {\n    <p-button\n      class=\"core:mr-2 core:mb-2\"\n      [label]=\"filter.name ? filter.name : (filter.key | bucketName : filter.aggregationKey | async)\"\n      icon=\"fa fa-times\"\n      [outlined]=\"true\"\n      severity=\"secondary\"\n      (onClick)=\"removeFilter(filter)\"\n    />\n    }\n  </div>\n  }\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class PaginatorComponent {
    constructor() {
        /** Input */
        this.alwaysShow = input(true);
        this.currentPage = input(1);
        this.pageLinkSize = input(5);
        this.rows = input(10);
        this.rowsPerPageOptions = input();
        this.showCurrentPageReport = input(false);
        this.showFirstLastIcon = input(false);
        this.totalRecords = input(0);
        /** Output */
        this.rowPageChange = output();
        /** Position for the current page */
        this.first = computed(() => {
            this.eventData.page = (this.currentPage() - 1);
            this.eventData.rows = this.rows();
            return this.eventData.page * this.eventData.rows;
        });
        /** Paginator Event */
        this.eventData = {
            page: 0,
            rows: 10
        };
    }
    /** Event on change page */
    onPageChange(event) {
        this.eventData.rows = event.rows;
        this.eventData.page = event.page;
        this.rowPageChange.emit(this.eventData);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PaginatorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.14", type: PaginatorComponent, isStandalone: false, selector: "ng-core-paginator", inputs: { alwaysShow: { classPropertyName: "alwaysShow", publicName: "alwaysShow", isSignal: true, isRequired: false, transformFunction: null }, currentPage: { classPropertyName: "currentPage", publicName: "currentPage", isSignal: true, isRequired: false, transformFunction: null }, pageLinkSize: { classPropertyName: "pageLinkSize", publicName: "pageLinkSize", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, rowsPerPageOptions: { classPropertyName: "rowsPerPageOptions", publicName: "rowsPerPageOptions", isSignal: true, isRequired: false, transformFunction: null }, showCurrentPageReport: { classPropertyName: "showCurrentPageReport", publicName: "showCurrentPageReport", isSignal: true, isRequired: false, transformFunction: null }, showFirstLastIcon: { classPropertyName: "showFirstLastIcon", publicName: "showFirstLastIcon", isSignal: true, isRequired: false, transformFunction: null }, totalRecords: { classPropertyName: "totalRecords", publicName: "totalRecords", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowPageChange: "rowPageChange" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-paginator\n    (onPageChange)=\"onPageChange($event)\"\n    [alwaysShow]=\"alwaysShow()\"\n    [first]=\"first()\"\n    [pageLinkSize]=\"pageLinkSize()\"\n    [rows]=\"rows()\"\n    [showCurrentPageReport]=\"showCurrentPageReport()\"\n    [showFirstLastIcon]=\"showFirstLastIcon()\"\n    [totalRecords]=\"totalRecords()\"\n    [rowsPerPageOptions]=\"rowsPerPageOptions()\" />\n", dependencies: [{ kind: "component", type: i1$8.Paginator, selector: "p-paginator", inputs: ["pageLinkSize", "style", "styleClass", "alwaysShow", "dropdownAppendTo", "templateLeft", "templateRight", "appendTo", "dropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showFirstLastIcon", "totalRecords", "rows", "rowsPerPageOptions", "showJumpToPageDropdown", "showJumpToPageInput", "jumpToPageItemTemplate", "showPageLinks", "locale", "dropdownItemTemplate", "first"], outputs: ["onPageChange"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: PaginatorComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-paginator', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-paginator\n    (onPageChange)=\"onPageChange($event)\"\n    [alwaysShow]=\"alwaysShow()\"\n    [first]=\"first()\"\n    [pageLinkSize]=\"pageLinkSize()\"\n    [rows]=\"rows()\"\n    [showCurrentPageReport]=\"showCurrentPageReport()\"\n    [showFirstLastIcon]=\"showFirstLastIcon()\"\n    [totalRecords]=\"totalRecords()\"\n    [rowsPerPageOptions]=\"rowsPerPageOptions()\" />\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2022-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class MenuSortComponent {
    constructor() {
        this.translateService = inject(TranslateService);
        this.activatedRoute = inject(ActivatedRoute);
        /** Input */
        this.config = input.required();
        this.selectedValue = input();
        this.language = toSignal(this.translateService.onLangChange);
        this.selectedOption = computed(() => this.config().find((conf) => conf.value === this.selectedValue()));
        this.options = computed(() => { this.language(); return this.sortOptions(); });
        /** Change event */
        this.onChange = output();
    }
    /** Return the sort options from config. */
    sortOptions() {
        const translations = [];
        this.config().map((option) => {
            const newOption = { ...option };
            newOption.label = this.translateService.instant(option.label);
            newOption.command = (event) => this.onChange.emit(event.item.value);
            translations.push(newOption);
        });
        return translations.sort((a, b) => a.label.localeCompare(b.label));
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MenuSortComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: MenuSortComponent, isStandalone: false, selector: "ng-core-menu-sort", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, selectedValue: { classPropertyName: "selectedValue", publicName: "selectedValue", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChange: "onChange" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2019-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (options().length > 0) {\n<p-menu #menu [model]=\"options()\" [popup]=\"true\" />\n<p-button severity=\"secondary\" outlined (onClick)=\"menu.toggle($event)\">\n  <div class=\"core:flex core:gap-4 core:items-center\">\n    @if (selectedOption()?.icon) {\n      <i [ngClass]=\"selectedOption().icon\"></i>\n    } @else if (selectedOption()) {\n      {{'Sort by' | translate }}&nbsp;:\n    }\n    @if (selectedOption()?.label) {\n      {{ selectedOption()?.label | translate }}\n    } @else {\n      {{'Sort by' | translate }}&nbsp;\u2026\n    }\n  <i class=\"fa fa-caret-down\"></i>\n</div>\n</p-button>\n}\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$7.Menu, selector: "p-menu", inputs: ["model", "popup", "style", "styleClass", "appendTo", "autoZIndex", "baseZIndex", "showTransitionOptions", "hideTransitionOptions", "ariaLabel", "ariaLabelledBy", "id", "tabindex"], outputs: ["onShow", "onHide", "onBlur", "onFocus"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: MenuSortComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-menu-sort', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2019-2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (options().length > 0) {\n<p-menu #menu [model]=\"options()\" [popup]=\"true\" />\n<p-button severity=\"secondary\" outlined (onClick)=\"menu.toggle($event)\">\n  <div class=\"core:flex core:gap-4 core:items-center\">\n    @if (selectedOption()?.icon) {\n      <i [ngClass]=\"selectedOption().icon\"></i>\n    } @else if (selectedOption()) {\n      {{'Sort by' | translate }}&nbsp;:\n    }\n    @if (selectedOption()?.label) {\n      {{ selectedOption()?.label | translate }}\n    } @else {\n      {{'Sort by' | translate }}&nbsp;\u2026\n    }\n  <i class=\"fa fa-caret-down\"></i>\n</div>\n</p-button>\n}\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class SearchFiltersComponent {
    constructor() {
        this.activatedRoute = inject(ActivatedRoute);
        // Array of filters
        this.searchFilters = input([]);
        // Resources configuration
        this.config = input.required();
        // query string
        this.query = input.required();
        // Class for section
        this.styleClassSection = input();
        // Filter event
        this.onChange = output();
    }
    /**
     * Check if a filter section
     * @param searchFilterSection - SearchFilterSection
     * @returns True if the filter is the section
     */
    showFilterSection(searchFilterSection) {
        return searchFilterSection.filters.some((filter) => this.config().allowEmptySearch
            ? true
            : (this.query() && filter.showIfQuery === true) || !filter?.showIfQuery);
    }
    /**
     * Check if a simple filter
     * @param searchFilter - SearchFilter
     * @returns True if the filter is simple.
     */
    showFilter(searchFilter) {
        if (this.config().allowEmptySearch) {
            return true;
        }
        if (!this.query()) {
            return !(searchFilter.showIfQuery === true);
        }
        else {
            return (searchFilter.showIfQuery === true || !searchFilter?.showIfQuery);
        }
    }
    /**
     * Activates the filter according to the route parameters.
     * @param filter - SearchFilter
     * @returns True, if the parameter is present nd contains a value.
     */
    isChecked(filter) {
        if (this.activatedRoute.snapshot.queryParamMap.has(filter.filter)) {
            const value = this.activatedRoute.snapshot.queryParamMap.get(filter.filter);
            if (!value) {
                return false;
            }
            if (filter.filter === 'simple') {
                return !Boolean(JSON.parse(value));
            }
            else {
                return Boolean(JSON.parse(value));
            }
        }
        return false;
    }
    /**
     * Event on switch
     * @param event - ToggleSwitchChangeEvent primeng
     * @param filter the search filter
     */
    change(event, filter) {
        this.onChange.emit({ filterKey: filter.filter, checked: event.checked });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchFiltersComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SearchFiltersComponent, isStandalone: false, selector: "ng-core-search-filters", inputs: { searchFilters: { classPropertyName: "searchFilters", publicName: "searchFilters", isSignal: true, isRequired: false, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: true, transformFunction: null }, query: { classPropertyName: "query", publicName: "query", isSignal: true, isRequired: true, transformFunction: null }, styleClassSection: { classPropertyName: "styleClassSection", publicName: "styleClassSection", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChange: "onChange" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2024-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (searchFilters().length > 0) {\n  <div class=\"core:mb-2\">\n    @for (searchFilter of searchFilters(); track searchFilter.filter) {\n      @if (searchFilter.filters) {\n        @if (showFilterSection(searchFilter)) {\n          <div [ngClass]=\"styleClassSection()\">{{ searchFilter.label | translate }}</div>\n          @for(searchFilterSection of searchFilter.filters; track searchFilterSection.filter) {\n            @if (showFilter(searchFilterSection)) {\n              <ng-container [ngTemplateOutlet]=\"searchFilterTemplate\" [ngTemplateOutletContext]=\"{filter: searchFilterSection}\"/>\n            }\n          }\n        }\n      } @else {\n        @if (showFilter(searchFilter)) {\n          <ng-container [ngTemplateOutlet]=\"searchFilterTemplate\" [ngTemplateOutletContext]=\"{filter: searchFilter}\"/>\n        }\n      }\n    }\n  </div>\n}\n\n<ng-template #searchFilterTemplate let-filter=\"filter\">\n    <div class=\"core:flex\">\n      <div class=\"core:flex core:items-center core:mr-2\">\n        <p-toggleswitch\n          [ngModel]=\"isChecked(filter)\"\n          inputId=\"customSwitch-{{ filter.filter }}\"\n          [ariaLabel]=\"filter.label | translate\"\n          (onChange)=\"change($event, filter)\"\n        />\n      </div>\n      <div class=\"core:flex core:items-center\">\n        <label for=\"customSwitch-{{ filter.filter }}\">{{ filter.label | translate }}</label>\n        @if (filter.url) {\n          @if (filter.url.external) {\n            <a class=\"core:ml-1\" [title]=\"filter.url.title\" [href]=\"filter.url.link\" [target]=\"filter.url.target\">\n              <i class=\"fa fa-info-circle \" aria-hidden=\"true\"></i>\n            </a>\n          } @else {\n            <a class=\"core:ml-1\" [title]=\"filter.url.title\" [routerLink]=\"filter.url.routerLink\">\n              <i class=\"fa fa-info-circle \" aria-hidden=\"true\"></i>\n            </a>\n          }\n        }\n      </div>\n    </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: i1$4.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2$8.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchFiltersComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-search-filters', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2024-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (searchFilters().length > 0) {\n  <div class=\"core:mb-2\">\n    @for (searchFilter of searchFilters(); track searchFilter.filter) {\n      @if (searchFilter.filters) {\n        @if (showFilterSection(searchFilter)) {\n          <div [ngClass]=\"styleClassSection()\">{{ searchFilter.label | translate }}</div>\n          @for(searchFilterSection of searchFilter.filters; track searchFilterSection.filter) {\n            @if (showFilter(searchFilterSection)) {\n              <ng-container [ngTemplateOutlet]=\"searchFilterTemplate\" [ngTemplateOutletContext]=\"{filter: searchFilterSection}\"/>\n            }\n          }\n        }\n      } @else {\n        @if (showFilter(searchFilter)) {\n          <ng-container [ngTemplateOutlet]=\"searchFilterTemplate\" [ngTemplateOutletContext]=\"{filter: searchFilter}\"/>\n        }\n      }\n    }\n  </div>\n}\n\n<ng-template #searchFilterTemplate let-filter=\"filter\">\n    <div class=\"core:flex\">\n      <div class=\"core:flex core:items-center core:mr-2\">\n        <p-toggleswitch\n          [ngModel]=\"isChecked(filter)\"\n          inputId=\"customSwitch-{{ filter.filter }}\"\n          [ariaLabel]=\"filter.label | translate\"\n          (onChange)=\"change($event, filter)\"\n        />\n      </div>\n      <div class=\"core:flex core:items-center\">\n        <label for=\"customSwitch-{{ filter.filter }}\">{{ filter.label | translate }}</label>\n        @if (filter.url) {\n          @if (filter.url.external) {\n            <a class=\"core:ml-1\" [title]=\"filter.url.title\" [href]=\"filter.url.link\" [target]=\"filter.url.target\">\n              <i class=\"fa fa-info-circle \" aria-hidden=\"true\"></i>\n            </a>\n          } @else {\n            <a class=\"core:ml-1\" [title]=\"filter.url.title\" [routerLink]=\"filter.url.routerLink\">\n              <i class=\"fa fa-info-circle \" aria-hidden=\"true\"></i>\n            </a>\n          }\n        }\n      </div>\n    </div>\n</ng-template>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
;
class SearchTabsComponent {
    constructor() {
        this.activatedRoute = inject(ActivatedRoute);
        // Resources configuration
        this.types = input.required();
        // Tab change event
        this.onChangeType = output();
        /** Tab index */
        this.currentType = model(undefined);
    }
    /** OnInit hook */
    ngOnInit() {
        this.typesInTabs = this.types().filter((item) => item.hideInTabs !== true);
        this.currentType.set(this.activatedRoute.snapshot.params.type);
        this.currentTypeSubscription = this.currentType.subscribe(typeName => this.onChangeType.emit(typeName));
    }
    ngOnDestroy() {
        this.currentTypeSubscription.unsubscribe();
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SearchTabsComponent, isStandalone: false, selector: "ng-core-search-tabs", inputs: { types: { classPropertyName: "types", publicName: "types", isSignal: true, isRequired: true, transformFunction: null }, currentType: { classPropertyName: "currentType", publicName: "currentType", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChangeType: "onChangeType", currentType: "currentTypeChange" }, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2024-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (typesInTabs.length > 1) {\n  <p-tabs [(value)]=\"currentType\">\n    <p-tablist>\n    @for (tab of typesInTabs; track tab.key) {\n      <p-tab [value]=\"tab.key\">{{ tab.label | translate }}</p-tab>\n    }\n    </p-tablist>\n  </p-tabs>\n}\n", dependencies: [{ kind: "component", type: i1$9.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i1$9.TabList, selector: "p-tablist" }, { kind: "component", type: i1$9.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchTabsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-search-tabs', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2024-2025 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (typesInTabs.length > 1) {\n  <p-tabs [(value)]=\"currentType\">\n    <p-tablist>\n    @for (tab of typesInTabs; track tab.key) {\n      <p-tab [value]=\"tab.key\">{{ tab.label | translate }}</p-tab>\n    }\n    </p-tablist>\n  </p-tabs>\n}\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2022-2025 RERO
 * Copyright (C) 2022 UCLouvain
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordSearchComponent {
    constructor() {
        this.recordService = inject(RecordService);
        this.recordUiService = inject(RecordUiService);
        this.recordSearchService = inject(RecordSearchService);
        this.translateService = inject(TranslateService);
        this.spinner = inject(NgxSpinnerService);
        this.apiService = inject(ApiService);
        this.activatedRoute = inject(ActivatedRoute);
        // COMPONENT ATTRIBUTES =====================================================
        /** Current selected resource type */
        this.currentType = null;
        /** Search query */
        this.q = '';
        /** Define the current record's page */
        this.page = 1;
        /** Define the number of records per page */
        this.size = 10;
        /** Defined the sort order */
        this.sort = null;
        /** If admin mode is disabled, no action can be performed on a record (as add, update or remove) */
        this.adminMode = { can: true, message: '' };
        /** Custom URL to notice detail */
        this.detailUrl = null;
        /** Resources types available */
        this.types = [{ key: 'documents', label: 'Documents' }];
        /** Output current state when parameters change. */
        this.parametersChanged = new EventEmitter();
        /** Output current result of records by type. */
        this.recordsSearched = new EventEmitter();
        /** Current aggregations filters applied */
        this.aggregationsFilters = [];
        /** Contain result row data */
        this.hits = [];
        /** Aggregation keys to always hide (defined into the config) */
        this.aggregationsToHide = [];
        /** Check if record can be added */
        this.addStatus = { can: true, message: '' };
        /** List of fields on which we can do a specific search. */
        this.searchFields = [];
        /** List of fields on which we can filter. */
        this.searchFilters = [];
        /** If we need to show the empty search message info. */
        this.showEmptySearchMessage = false;
        /** JSON dumping of last search parameters (used for checking if we have to do a search or not).*/
        this._searchParameters = new BehaviorSubject(null);
        /** Define if search input have to be displayed or not. */
        this._showSearchInput = true;
        /** Define if title have to be displayed or not. */
        this._showLabel = true;
        /** Subscriptions to observables. */
        this._subscriptions = new Subscription();
        /** Store configuration for type. */
        this.config = null;
        this.availableTypes = [];
        this.loaded = false;
    }
    // GETTER & SETTER ==========================================================
    /** Check if pagination have to be displayed or not. */
    get showPagination() {
        return this.total > this.size;
    }
    /** Does it require to activate the first and last button on pagination. */
    get paginationBoundaryLinks() {
        const paginationConfig = this._getResourceConfig('pagination', {});
        return 'boundaryLinks' in paginationConfig ? paginationConfig.boundaryLinks : false;
    }
    /** Get the number of pages showed on pagination. */
    get paginationMaxSize() {
        const paginationConfig = this._getResourceConfig('pagination', {});
        return 'maxSize' in paginationConfig ? paginationConfig.maxSize : 5;
    }
    /** Request result record hits. */
    get records() {
        return this.hits && this.hits.hits ? this.hits.hits : [];
    }
    /** Total records number corresponding to the request. */
    get total() {
        return this.hits && this.hits.total ? this.recordService.totalHits(this.hits.total) : 0;
    }
    /** Get the text for displaying results text. */
    get resultsText$() {
        if (this.config.resultsText) {
            return this.config.resultsText(this.hits);
        }
        return this.total <= 1
            ? this.translateService.stream('{{ total }} result', { total: this.total }) // O or 1 result
            : this.translateService.stream('{{ total }} results', { total: this.total });
    }
    /** Get showSearchInput value, given either by config or by local value. */
    get showSearchInput() {
        if (this.config.showSearchInput != null) {
            return this.config.showSearchInput;
        }
        return this._showSearchInput;
    }
    /** Setter for `showSearchInput`. */
    set showSearchInput(showSearchInput) {
        this._showSearchInput = showSearchInput;
    }
    /** Get showLabel value, given either by config or by local value. */
    get showLabel() {
        if (this.config.showLabel != null) {
            return this.config.showLabel;
        }
        return this._showLabel;
    }
    /** Setter for `showLabel`. */
    set showLabel(showLabel) {
        this._showLabel = showLabel;
    }
    /** Return the current page (used in pagination, has we cannot use `page` property directly) */
    get currentPage() {
        return this.page;
    }
    /**
     * Used only for binding with pagination.
     * Avoid side effect if "page" property is bound to pagination
     * (infinite calls to get records).
     * @param page - number, new page
     */
    set currentPage(page) {
        this.page = +page;
        this._searchParamsHasChanged(false);
    }
    /**
     * Return the list of search fields that are selected.
     * @return List of selected search fields.
     */
    get selectedSearchFields() {
        return this.searchFields.filter((field) => field.selected);
    }
    /**
     * Get the message if there's no record for the type.
     * The message can be customized with the `noRecordMessage` property in route configuration.
     * @returns A message indicating there's no record.
     */
    get emptyRecordMessage() {
        return this.config.noRecordMessage || this.translateService.instant('There are no records in this section');
    }
    /**
     * Check if the current type has no record.
     * @returns True if no record is found and no search query is done.
     */
    get hasNoRecord() {
        return this.config.showFacetsIfNoResults
            ? false
            : !this.q && this.records.length === 0 && !this.showEmptySearchMessage;
    }
    /** Return a message containing the reasons why record list cannot be exported. */
    get exportInfoMessage() {
        return this.total === 0
            ? this.translateService.instant('Result list is empty.')
            : this.translateService.instant('Too many items. Should be less than {{max}}.', {
                max: RecordService.MAX_REST_RESULTS_SIZE,
            });
    }
    get selectedSortValue() {
        const sortParam = this.activatedRoute.snapshot?.queryParamMap?.get('sort');
        return (sortParam && this.config.sortOptions)
            ? this.config.sortOptions.find((item) => item.value === sortParam)?.value
            : null;
    }
    // HOOKS ======================================================
    /**
     * OnInit hook.
     *   Subscribes to the observable emitting the aggregations filters.
     *   Loads total count of records for each resource.
     */
    ngOnInit() {
        this._subscriptions.add(this.translateService.onLangChange.subscribe((lang) => {
            this._loadSearchFields();
        }));
        this.availableTypes = this.types.filter((item) => item.hideInTabs !== true);
        // Subscribe on aggregation filters changes and do search.
        let first = true;
        // Load the possible aggregation asked to search engine and that always need to be hide.
        // DEV NOTE : These aggregation should be used by other components (using content injection)
        //            otherwise it doesn't matter to ask them.
        if (this.config.aggregationsHide) {
            this.aggregationsToHide =
                typeof this.config.aggregationsHide === 'function'
                    ? this.config.aggregationsHide()
                    : this.config.aggregationsHide;
        }
        this._subscriptions.add(this.recordSearchService.aggregationsFilters.subscribe((aggregationsFilters) => {
            // No aggregations filters are set at this time, we do nothing.
            if (aggregationsFilters === null) {
                return;
            }
            aggregationsFilters.forEach((item, key) => (aggregationsFilters[key].values = item.values.sort()));
            this.aggregationsFilters = aggregationsFilters;
            // if it's the first value emitted, the current page is kept.
            this._searchParamsHasChanged(first === false);
            // not first anymore
            first = false;
        }));
        this._subscriptions.add(this._searchParameters
            .asObservable()
            .pipe(
        // only if the patterns changed
        distinctUntilChanged((a, b) => JSON.stringify(a) === JSON.stringify(b)), 
        // cancel previous pending requests
        switchMap(() => {
            if (this.aggregations != null) {
                return of(null);
            }
            return this.config.aggregationsOrder.pipe(tap((aggregations) => {
                let aggregationsExpandCfg = this.config.aggregationsExpand;
                if (typeof aggregationsExpandCfg === 'function') {
                    aggregationsExpandCfg = aggregationsExpandCfg();
                }
                this.aggregations = aggregations.map((key) => {
                    return {
                        key: key.key || key,
                        bucketSize: this.config.aggregationsBucketSize || null,
                        value: { buckets: [] },
                        expanded: (aggregationsExpandCfg || []).includes(key),
                        included: ([...aggregationsExpandCfg, ...this.aggregationsToHide]).includes(key),
                        name: key.name || this._aggregationName(key) || null,
                    };
                });
            }));
        }), tap(() => (this.hits = [])), switchMap(() => this._getRecords()))
            .subscribe({
            next: (records) => {
                this.loaded = true;
                this.hits = records.hits;
                this.spinner.hide();
                // Apply filters
                this.aggregations$(records.aggregations).subscribe((aggregations) => {
                    for (const agg of this.aggregations) {
                        // reset aggregations
                        agg.loaded = false;
                        agg.value.buckets = [];
                        if (agg.key in aggregations) {
                            this._mapAggregation(agg, aggregations[agg.key]);
                        }
                    }
                });
                // Required to fire onChange event
                this.aggregations = [...this.aggregations];
                this._emitNewParameters();
                this.recordsSearched.emit({ type: this.currentType, records });
                // reload export options
                this.exportOptions = this._exportFormats();
            },
            error: (error) => {
                this.error = error;
                this.spinner.hide();
            }
        }));
    }
    /**
     * Methods called each time an input property is modified.
     *
     * If current type is changed, the configuration for the new type is loaded.
     *
     * The first time current type is changed, the types property is set in the
     * RecordUiServices. A better way to do that is to detect route change in the
     * service, but at this time it is done like that.
     *
     * This method does a search at the end but only if the search parameters have
     * changed. We want to avoid a double search when the following process is
     * done:
     *
     * 1. A parameter is changed in the search interface.
     * 2. Local property is updated.
     * 3. A search is done.
     * 4. The component outputs the search parameters.
     * 5. The parent component (RecordSearchPage) updates the URL
     * 6. The parent component detects route parameters changes.
     * 7. The parent component update the input value of the component.
     * 8. This method is triggered.
     *
     * @param changes Object containing all the changed properties.
     */
    ngOnChanges(changes) {
        // Current type has changed
        if (changes.currentType) {
            if (changes.currentType.firstChange) {
                // Load all configuration types, only during the first change
                this.recordUiService.types = this.types;
            }
            // if the "type" property is changed in input, but the change is not
            // triggered by clicking on a tab (which already load configuration),
            // we reload configuration.
            // If no configuration is loaded, we load it, too.
            if (this.config === null ||
                (changes.currentType.currentValue != null && changes.currentType.currentValue !== this.config.key)) {
                this._loadConfigurationForType(this.currentType);
            }
        }
        // If it's the first change, we don't do a search, it's delegated to the
        // aggregations filters subscription.
        if (changes[Object.keys(changes)[0]].firstChange === false) {
            // Get records and reset page only if page has not changed
            this._searchParamsHasChanged(!('page' in changes));
        }
    }
    /**
     * OnDestroy hook
     *  Unsubscribes from the observable of the aggregations filters.
     */
    ngOnDestroy() {
        this._subscriptions.unsubscribe();
    }
    // COMPONENT FUNCTIONS ======================================================
    /**
     * Internal notification that notify the search parameters has changed.
     * @param resetPage reset the pager to the first page
     */
    _searchParamsHasChanged(resetPage = true) {
        if (resetPage) {
            this.page = 1;
        }
        // Deep copy is sent, to avoid the reference (source object) to be
        // accidentally changed.
        this._searchParameters.next(cloneDeep(this._serializeSearchParameters()));
    }
    /** Move to the top of the page if you change page */
    pageChanged() {
        this.topScroll.nativeElement.scrollIntoView({ behavior: 'smooth' });
    }
    /**
     * Change number of items per page value.
     * @param event - Event, dom event triggered
     * @param size - number, new page size
     */
    changeSize(event, size) {
        event.preventDefault();
        this.size = size;
        this._searchParamsHasChanged();
    }
    /**
     * Change sorting.
     * @param sort sort name.
     */
    changeSorting(sort) {
        this.sort = sort;
        this._searchParamsHasChanged();
    }
    /**
     * Change query text.
     * @param event - string, new query text
     */
    searchByQuery(event) {
        // If empty search is not allowed and query is empty, the search is not processed.
        if (this.config.allowEmptySearch === false && !event) {
            this.showEmptySearchMessage = true;
            return;
        }
        this.q = event;
        this._setDefaultSort();
        this._searchParamsHasChanged();
        // Build aggregations to used.
        //   This is a combination of `defaultSearchInputFilters` and persistent aggregation filters.
        const aggregations = new Set(this._extractPersistentAggregationsFilters());
        this.aggregationsFilters.forEach((aggregation) => aggregations.add(aggregation));
        this.recordSearchService.setAggregationsFilters(Array.from(aggregations), true);
    }
    /**
     * Change type of records.
     * @param type - resource type name.
     */
    changeType(type) {
        this.currentType = type;
        this._loadConfigurationForType(this.currentType);
        this.aggregationsFilters = [];
        this._searchParamsHasChanged();
        this.recordSearchService.setAggregationsFilters([]);
    }
    /**
     * Delete a record by its PID.
     * @param event - object
     */
    deleteRecord(event) {
        const type = event.type ?? this.currentType;
        this.recordUiService
            .deleteRecord(type, event.pid)
            .pipe(switchMap((result) => {
            if (result === true) {
                this.page = 1;
                return this._getRecords();
            }
            return of(null);
        }))
            .subscribe((records) => {
            if (records != null) {
                this.hits = records.hits;
                this.spinner.hide();
            }
        });
        // update main counter
        this.config.total--;
    }
    /**
     * Show a modal containing message given in parameter.
     * @param message - message to display into modal
     */
    showDeleteMessage(message) {
        this.recordUiService.showDeleteMessage(message);
    }
    /**
     * Get component view for the current resource type.
     * @return A component for displaying result item.
     */
    getResultItemComponentView() {
        return this.config.component ? this.config.component : null;
    }
    /**
     * Get Export formats for the current resource given by configuration.
     * @return Array of export format to generate an `export as` button or an empty array.
     */
    _exportFormats() {
        if (!this.config || !this.config.exportFormats) {
            return [];
        }
        return this.config.exportFormats.map((format) => {
            return {
                label: format.label,
                url: this.getExportFormatUrl(format),
                disabled: !this.canExport(format),
                disabled_message: this.exportInfoMessage,
            };
        });
    }
    /**
     * Get export format url.
     * @param format - export format object
     * @return formatted url for an export format.
     */
    getExportFormatUrl(format) {
        const queryParams = Object.keys(this.activatedRoute.snapshot.queryParams);
        // TODO: maybe we can use URLSerializer to build query string
        const baseUrl = format.endpoint ? format.endpoint : this.apiService.getEndpointByType(this._currentIndex());
        let url = `${baseUrl}?q=${encodeURIComponent(this.q)}&format=${format.format}`;
        // check if max rest result size is disabled
        if (!format.disableMaxRestResultsSize) {
            url += `&size=${RecordService.MAX_REST_RESULTS_SIZE}`;
        }
        // preFilters
        if (this.config && this.config.preFilters) {
            for (const [key, value] of Object.entries(this.config.preFilters)) {
                // force value to an array
                const values = !Array.isArray(value) ? [value] : value;
                values.map((v) => {
                    // We check whether the parameter exists in the current url.
                    // If it does, we don't add the preFilter parameter.
                    if (!queryParams.includes(key)) {
                        url += `&${key}=${v}`;
                    }
                });
            }
        }
        // aggregations
        if (this.aggregationsFilters) {
            this.aggregationsFilters.map((filter) => {
                filter.values.map((v) => {
                    url += `&${filter.key}=${v}`;
                });
            });
        }
        return url;
    }
    /**
     * Check if a record list can be exported
     * @param format - export format object
     * @return Boolean
     */
    canExport(format) {
        return format.hasOwnProperty('disableMaxRestResultsSize') && format.disableMaxRestResultsSize
            ? this.total > 0
            : 0 < this.total && this.total < RecordService.MAX_REST_RESULTS_SIZE;
    }
    /**
     * Check if a record can be updated
     * @param record - object, record to check
     * @return Observable
     */
    canUpdateRecord$(record) {
        return this.recordUiService.canUpdateRecord$(record, this.currentType);
    }
    /**
     * Check if a record can be deleted
     * @param record - object, record to check
     * @return Observable
     */
    canDeleteRecord$(record) {
        return this.recordUiService.canDeleteRecord$(record, this.currentType);
    }
    /**
     * Check if a record can be used
     * @param record - object, record to check
     * @return Observable
     */
    canUseRecord$(record) {
        return this.recordUiService.canUseRecord$(record, this.currentType);
    }
    /**
     * Filter the aggregations with given configuration function.
     * If no configuration is given, return the original aggregations.
     * @param records - Result records
     * @return Observable containing aggregations corresponding to actual records.
     */
    aggregations$(aggregations) {
        if (this.config.aggregations) {
            return this.config.aggregations(aggregations);
        }
        else {
            return of(aggregations);
        }
    }
    /**
     * Returns an observable which emits the URL value for given record.
     * In case record cannot be read, returns null.
     * @param record - Generate detail URL for this record.
     * @return Observable emitting detail URL object
     */
    resolveDetailUrl$(record) {
        const url = { link: `detail/${record.id}`, external: false };
        if (this.detailUrl) {
            url.link = this.detailUrl.replace(':type', this._currentIndex()).replace(':pid', record.id);
            url.external = true;
        }
        if (!this.config.canRead) {
            return of(url);
        }
        return this.recordUiService.canReadRecord$(record, this.currentType).pipe(map$4((status) => {
            if (status.can === false) {
                return null;
            }
            return url;
        }));
    }
    searchInField(event, path) {
        this.searchFields = this.searchFields.map((item) => {
            if (item.path === path) {
                item.selected = event.checked;
            }
            return item;
        });
        // If query string is specified, search is processed.
        if (this.q) {
            this.searchByQuery(this.q);
        }
    }
    onChangeSearchFilter(event) {
        const values = [];
        if (event.filterKey === 'simple') {
            values.push(event.checked ? '0' : '1');
        }
        else if (event.checked) {
            values.push(String(event.checked));
        }
        this.recordSearchService.updateAggregationFilter(event.filterKey, values);
    }
    /**
     * Check if a filter is selected.
     *
     * @param filter SearchFilter
     * @returns true if the given filter is selected.
     */
    isFilterActive(filter) {
        return this.aggregationsFilters
            ? this.aggregationsFilters.some((item) => item.key === filter.filter && item.values.includes(String(filter.value)))
            : false;
    }
    /**
     * Load buckets for the given aggregation.
     * @param event - Object outputted when an aggregation is clicked.
     */
    loadAggregationBuckets(event) {
        // the aggregation is collapsed, buckets are not loaded.
        if (event.expanded === false) {
            return;
        }
        const aggregation = this.aggregations.find((item) => item.key === event.key);
        // No aggregation found or buckets are already loaded.
        if (!aggregation || aggregation.loaded) {
            return;
        }
        // Get buckets for the aggregation
        this._getRecords(1).subscribe((records) => {
            this.aggregations$(records.aggregations).subscribe((aggregations) => {
                if (aggregations[event.key]) {
                    this._mapAggregation(aggregation, aggregations[event.key]);
                }
                // Required to fire onChange event
                this.aggregations = [...this.aggregations];
                this.spinner.hide();
            });
        });
    }
    /**
     * Search for records.
     * @param size - number : force the number of records to return. If `null` the default component `size` attribute will be used.
     */
    _getRecords(size = null) {
        // Build query string
        const q = this._buildQueryString();
        // Empty search is not allowed and query is empty, search in backend is not
        // processed.
        if (this.config.allowEmptySearch === false && !q) {
            this.showEmptySearchMessage = true;
            return of({ hits: { hits: [], total: 0 }, aggregations: {} });
        }
        else {
            this.showEmptySearchMessage = false;
        }
        this.spinner.show();
        // Check remove filter from preFilters if it is already present in
        // the aggs filters.
        const preFilters = {};
        const aggsKeys = [];
        this.aggregationsFilters.map((agg) => aggsKeys.push(agg.key));
        for (const [key, value] of Object.entries(this.config.preFilters || {})) {
            if (!aggsKeys.includes(key)) {
                preFilters[key] = value;
            }
        }
        return this.recordService.getRecords(this._currentIndex(), q, this.page, size || this.size, this.aggregationsFilters || [], preFilters, this.config.listHeaders || null, this.sort, this._getFacetsParameter());
    }
    /**
     * Emit new parameters when a search is done.
     */
    _emitNewParameters() {
        this.parametersChanged.emit({
            q: this.q,
            page: this.page,
            size: this.size,
            currentType: this.config.key,
            aggregationsFilters: this.aggregationsFilters,
            sort: this.sort,
        });
    }
    /**
     * Get configuration for the current resource type.
     * @param type Type of resource
     */
    _loadConfigurationForType(type) {
        const q = this._buildQueryString();
        this.config = this.recordUiService.getResourceConfig(type);
        this.recordUiService.canAddRecord$(type).subscribe((result) => {
            this.addStatus = result;
        });
        this._loadSearchFields();
        // Build aggregations.
        if (this.config.aggregationsOrder) {
            if (!isObservable(this.config.aggregationsOrder)) {
                this.config.aggregationsOrder = of(this.config.aggregationsOrder);
            }
        }
        else {
            this.config.aggregationsOrder = of([]);
        }
        // reset aggregations
        this.aggregations = null;
        // Sort options
        this._setDefaultSort();
        // load search filters
        this.searchFilters = this.config.searchFilters || [];
        // load export options
        this.exportOptions = this._exportFormats();
        // Update filters with default search filters only if the q parameter is empty
        if ((q === null || q.trim().length === 0) && this.config.defaultSearchInputFilters) {
            this.config.defaultSearchInputFilters.forEach((filter) => {
                this.recordSearchService.updateAggregationFilter(filter.key, filter.values);
            });
        }
    }
    /**
     * Get Resource config
     * @param paramName - Name of parameter
     * @param defaultValue - Default value is returned if the parameter is not defined
     * @return A config value or the given default value instead
     */
    _getResourceConfig(paramName, defaultValue) {
        return (paramName in this.config) ? this.config[paramName] : defaultValue;
    }
    /**
     * Serialize all the search parameters with JSON.stringify method.
     * @return The serialized string.
     */
    _serializeSearchParameters() {
        return {
            currentType: this.config.key,
            index: this._currentIndex(),
            q: this.q,
            page: this.page,
            size: this.size,
            sort: this.sort,
            aggregationsFilters: this.aggregationsFilters,
            searchFields: this.searchFields,
            searchFilters: this.searchFilters,
        };
    }
    /**
     * Load search fields stored in configuration and assign to them the
     * `selected` property.
     *
     * @returns void
     */
    _loadSearchFields() {
        // No search fields, reset previous stored and return.
        if (!this.config.searchFields) {
            this.searchFields = [];
            return;
        }
        // Store search fields.
        this.searchFields = this.config.searchFields.map((field) => {
            field.label = this.translateService.instant(field.label);
            if (!field.selected) {
                field.selected = false;
            }
            return field;
        });
    }
    /**
     * Build query string with possibly search fields.
     *
     * @return Final query string.
     */
    _buildQueryString() {
        // If query is empty or no selected fields found, the initial query string
        // is returned.
        if (!this.q || this.selectedSearchFields.length === 0) {
            return this.q;
        }
        // Loop over select fields and add them to final query string.
        const queries = [];
        this.selectedSearchFields.forEach((field) => {
            queries.push(`${field.path}:(${this.q})`);
        });
        return queries.join(' ');
    }
    /**
     * Return the name of the index defined either by the index key or key.
     *
     * @return string, current index defined by keys index or key
     */
    _currentIndex() {
        if (this.config == null) {
            return null;
        }
        return this.config.index || this.config.key;
    }
    /**
     * Get personalized name for current aggregation
     * @param key - string, aggregation key
     * @return string or null
     */
    _aggregationName(key) {
        return this.config.aggregationsName && key in this.config.aggregationsName
            ? this.config.aggregationsName[key]
            : null;
    }
    /**
     * Extract persistent search filters on current url
     * @return Array of aggregations filter
     */
    _extractPersistentAggregationsFilters() {
        const persistent = [];
        this._flatSearchFilters()
            .filter((filter) => filter.persistent === true)
            .forEach((filter) => {
            if (this.activatedRoute.snapshot.queryParams.hasOwnProperty(filter.filter)) {
                const data = this.activatedRoute.snapshot.queryParams[filter.filter];
                persistent.push({
                    key: filter.filter,
                    values: Array.isArray(data) ? data : [data],
                });
            }
        });
        return persistent;
    }
    /**
     * Make all search filters on same array level
     * @returns - A filters array
     */
    _flatSearchFilters() {
        const flatFilters = [];
        this.searchFilters.forEach((searchFilter) => {
            if (searchFilter.filters) {
                searchFilter.filters.forEach((filter) => flatFilters.push(filter));
            }
            else {
                flatFilters.push(searchFilter);
            }
        });
        return flatFilters;
    }
    /**
     * Map aggregation records data to corresponding aggregation.
     *
     * @param aggregation Aggregation object.
     * @param recordsAggregation Aggregation retrieved from record.
     */
    _mapAggregation(aggregation, recordsAggregation) {
        aggregation.doc_count = recordsAggregation.doc_count || null;
        aggregation.type = recordsAggregation.type || 'terms';
        aggregation.config = recordsAggregation.config || null;
        if (!aggregation.name && recordsAggregation.name) {
            aggregation.name = recordsAggregation.name;
        }
        if (recordsAggregation.buckets) {
            aggregation.value.buckets = recordsAggregation.buckets;
            if (recordsAggregation.doc_count != null) {
                aggregation.doc_count = recordsAggregation.doc_count;
            }
            aggregation.value.buckets.map((bucket) => this.processBuckets(bucket, aggregation.key));
        }
        aggregation.loaded = true;
    }
    /**
     * Enrich the bucket with several properties: indeterminate, parent, aggregationKey.
     *
     * @param bucket elastic bucket to process
     * @param aggregationKey bucket parent key
     * @returns the indeterminate state of the bucket
     */
    processBuckets(bucket, aggregationKey) {
        // checkbox indeterminate state
        bucket.indeterminate = false;
        bucket.aggregationKey = aggregationKey;
        for (const k of Object.keys(bucket).filter((key) => bucket[key].buckets)) {
            for (const childBucket of bucket[k].buckets) {
                // store the parent: useful to remove parent filters
                childBucket.parent = bucket;
                // store the aggregation key as we re-organize the bucket structure
                bucket.indeterminate ||= this.recordSearchService.hasFilter(k, childBucket.key);
                // do not change the order of the boolean expression to force processBucket over all
                // recursion steps
                bucket.indeterminate = this.processBuckets(childBucket, k) || bucket.indeterminate;
            }
        }
        return bucket.indeterminate;
    }
    /**
     * Compile facets keys to get only 'included' facets or having a filter selected.
     * @returns List of facets.
     */
    _getFacetsParameter() {
        const facets = [];
        this.aggregations.forEach((agg) => {
            if (agg.included === true ||
                agg.expanded ||
                this.aggregationsFilters.some((filter) => filter.key === agg.key)) {
                facets.push(agg.key);
            }
        });
        return facets;
    }
    /** Set the default sort. */
    _setDefaultSort() {
        if (this.sort != null) {
            return;
        }
        if (this.config.sortOptions) {
            const defaultSortValue = this.q ? 'defaultQuery' : 'defaultNoQuery';
            this.config.sortOptions.forEach((option) => {
                if (option[defaultSortValue] === true) {
                    this.sort = option.value;
                }
            });
        }
    }
    /**
     * Show the filter's section
     * @param searchFilterSection - Collection of filter
     * @returns true if the filter's section is show
     */
    showFilterSection(searchFilterSection) {
        return searchFilterSection.filters.some((filter) => {
            return this.config.allowEmptySearch ? true : (this.q && filter.showIfQuery === true) || !filter?.showIfQuery;
        });
    }
    /**
     * Show the filter
     * @param searchFilter - search Filter
     * @returns true if the filter is show
     */
    showFilter(searchFilter) {
        if (this.config.allowEmptySearch) {
            return true;
        }
        if (!this.q) {
            return !(searchFilter.showIfQuery === true);
        }
        else {
            return searchFilter.showIfQuery === true || !searchFilter?.showIfQuery;
        }
    }
    paginatorChange(event) {
        this.page = ++event.page;
        this.size = event.rows;
        this._searchParamsHasChanged(false);
    }
    /**
     * Remove filter.
     *
     * @param filter - the filter to remove
     */
    removeFilter(filter) {
        this.recordSearchService.removeFilter(filter.aggregationKey, filter.key, true);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: RecordSearchComponent, isStandalone: false, selector: "ng-core-record-search", inputs: { currentType: "currentType", q: "q", page: "page", size: "size", sort: "sort", adminMode: "adminMode", detailUrl: "detailUrl", types: "types", showSearchInput: "showSearchInput", showLabel: "showLabel" }, outputs: { parametersChanged: "parametersChanged", recordsSearched: "recordsSearched" }, viewQueries: [{ propertyName: "topScroll", first: true, predicate: ["topScrollAnchor"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2019-2024 RERO\n  Copyright (C) 2019-2023 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (error) {\n<ng-core-error [error]=\"error\"></ng-core-error>\n} @else {\n<span #topScrollAnchor></span>\n<ng-core-search-tabs [types]=\"availableTypes\" (onChangeType)=\"changeType($event)\"/>\n<div class=\"core:flex core:flex-col core:gap-2\">\n  @if (availableTypes.length === 1 && showLabel) {\n  <h5>{{ availableTypes[0].label | translate }}</h5>\n  }\n  <ng-content select=\"[header]\"></ng-content>\n  <div class=\"core:flex core:gap-2\">\n    @if (showSearchInput) {\n    <ng-core-search-input\n      class=\"core:grow\"\n      [placeholder]=\"'search' | translate | ucfirst\"\n      [searchText]=\"q\"\n      [displayLabel]=\"false\"\n      (search)=\"searchByQuery($event)\"\n      [focus]=\"true\"\n    />\n    }\n    <ng-content select=\"[afterInputSearch]\"/>\n  </div>\n  @if (loaded && hasNoRecord) {\n    <p-message severity=\"info\">\n      {{ emptyRecordMessage }}\n    </p-message>\n    @if (adminMode.can && addStatus.can) {\n    <p-button\n      id=\"search-add-button\"\n      [label]=\"'Add' | translate\"\n      icon=\"fa fa-plus\"\n      [routerLink]=\"addStatus.routerLink || ['new']\"\n    />\n    }\n  } @else {\n  <div class=\"core:flex core:items-stretch core:w-full\">\n    @if (resultsText$ | async; as resultsText) {\n    <div class=\"core:flex core:items-center core:w-full\">\n      <strong>{{ resultsText }}</strong>\n    </div>\n    }\n    <div class=\"core:flex core:items-center core:justify-end core:w-full\">\n      @if (adminMode.can && addStatus.can) {\n      <p-button\n        id=\"search-add-button\"\n        [label]=\"'Add' | translate\"\n        icon=\"fa fa-plus\"\n        [routerLink]=\"addStatus.routerLink || ['new']\"\n      />\n      }\n      <!-- Sorting -->\n      @if (config?.sortOptions?.length > 0) {\n      <ng-core-menu-sort class=\"core:ml-1\" [selectedValue]=\"selectedSortValue\" [config]=\"config.sortOptions\" (onChange)=\"changeSorting($event)\" />\n      }\n      <!-- EXPORT BUTTON -->\n      <ng-core-export-button class=\"core:ml-1\"[exportOptions]=\"exportOptions\"/>\n      <!-- END EXPORT BUTTON -->\n    </div>\n  </div>\n  <ng-content select=\"[beforeResult]\"></ng-content>\n  <div class=\"core:grid core:grid-cols-12 core:gap-4\">\n    <ng-core-list-filters\n      [aggregations]=\"aggregations\"\n      class=\"core:col-span-12\"\n      [aggregationsFilters]=\"aggregationsFilters\"\n      [searchFilters]=\"searchFilters\"\n      (remove)=\"removeFilter($event)\"\n    />\n    <ng-content select=\"[top-search-result]\"></ng-content>\n    @if ((aggregations && aggregations.length) || searchFields.length > 0 || searchFilters.length > 0) {\n    <div class=\"core:md:col-span-5 core:lg:col-span-3 core:col-span-12\">\n      @if (searchFields.length > 0 && q) {\n        <div class=\"core:mb-4\">\n          @for (searchField of searchFields; track $index) {\n            <div class=\"core:flex core:gap-2 core:items-center\">\n              <p-toggleswitch (onChange)=\"searchInField($event, searchField.path)\" />\n              <label>{{ searchField.label | translate }}</label>\n            </div>\n          }\n        </div>\n      }\n\n      <ng-core-search-filters\n        [searchFilters]=\"searchFilters\"\n        [config]=\"config\"\n        [query]=\"q\"\n        styleClassSection=\"core:my-2\"\n        (onChange)=\"onChangeSearchFilter($event)\"\n      />\n\n      @if (!showEmptySearchMessage || q) {\n      <ng-content select=\"[top-facets]\"/>\n      @for (item of aggregations; track item.key) {\n      <div>\n        @if (!aggregationsToHide.includes(item.key)) {\n        <ng-core-record-search-aggregation\n          [aggregation]=\"item\"\n          [aggregationsFilters]=\"aggregationsFilters\"\n          (aggregationClicked)=\"loadAggregationBuckets($event)\"\n        />\n        }\n      </div>\n      } }\n    </div>\n    }\n    <div id=\"recordlist\" class=\"core:md:col-span-7 core:lg:col-span-9 core:col-span-12\">\n      @if (showEmptySearchMessage) {\n      <p-message severity=\"info\">\n        {{ 'Enter a query to get results.' | translate }}\n      </p-message>\n      }\n      <ng-content select=\"[top-result]\"/>\n      <p-dataView [value]=\"records\" [emptyMessage]=\"' '\">\n        <ng-template #list let-records>\n          <ul class=\"core:list-none\">\n            @for (record of records; track record.metadata.pid; let first = $first) {\n            <li class=\"core:py-2 core:md:py-6\" [ngClass]=\"{ 'core:border-t-1 core:border-surface': !first }\">\n              <ng-core-record-search-result\n                [adminMode]=\"adminMode\"\n                [record]=\"record\"\n                [type]=\"currentType\"\n                [itemViewComponent]=\"getResultItemComponentView()\"\n                [canUpdate$]=\"canUpdateRecord$(record)\"\n                [canDelete$]=\"canDeleteRecord$(record)\"\n                [canUse$]=\"canUseRecord$(record)\"\n                [detailUrl$]=\"resolveDetailUrl$(record)\"\n                (deletedRecord)=\"deleteRecord($event)\"\n                (deleteMessageEvent)=\"showDeleteMessage($event)\"\n              />\n            </li>\n            }\n          </ul>\n        </ng-template>\n      </p-dataView>\n\n      <ng-core-paginator\n        [alwaysShow]=\"showPagination\"\n        [currentPage]=\"currentPage\"\n        [pageLinkSize]=\"paginationMaxSize\"\n        [totalRecords]=\"total\"\n        [rows]=\"size\"\n        [rowsPerPageOptions]=\"config?.pagination?.rowsPerPageOptions || [10, 20, 50]\"\n        [showCurrentPageReport]=\"config?.pagination?.pageReport || false\"\n        [showFirstLastIcon]=\"paginationBoundaryLinks\"\n        (rowPageChange)=\"paginatorChange($event)\"\n      />\n      <ng-content select=\"[footer-result]\"/>\n      <ng-content/>\n    </div>\n  </div>\n  <ng-content select=\"[footer-search-result]\"/>\n  }\n</div>\n}\n", dependencies: [{ kind: "component", type: i1.Button, selector: "p-button", inputs: ["type", "iconPos", "icon", "badge", "label", "disabled", "loading", "loadingIcon", "raised", "rounded", "text", "plain", "severity", "outlined", "link", "tabindex", "size", "variant", "style", "styleClass", "badgeClass", "badgeSeverity", "ariaLabel", "autofocus", "fluid", "buttonProps"], outputs: ["onClick", "onFocus", "onBlur"] }, { kind: "component", type: i2$1.Message, selector: "p-message", inputs: ["severity", "text", "escape", "style", "styleClass", "closable", "icon", "closeIcon", "life", "showTransitionOptions", "hideTransitionOptions", "size", "variant"], outputs: ["onClose"] }, { kind: "component", type: i1$4.ToggleSwitch, selector: "p-toggleswitch, p-toggleSwitch, p-toggle-switch", inputs: ["style", "styleClass", "tabindex", "inputId", "name", "disabled", "readonly", "trueValue", "falseValue", "ariaLabel", "ariaLabelledBy", "autofocus"], outputs: ["onChange"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: SearchInputComponent, selector: "ng-core-search-input", inputs: ["inputId", "displayLabel", "placeholder", "searchText", "trimQueryString", "disabled", "focus"], outputs: ["search"] }, { kind: "component", type: ErrorComponent, selector: "ng-core-error", inputs: ["error"] }, { kind: "directive", type: i2$8.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i8.DataView, selector: "p-dataView, p-dataview, p-data-view", inputs: ["paginator", "rows", "totalRecords", "pageLinks", "rowsPerPageOptions", "paginatorPosition", "paginatorStyleClass", "alwaysShowPaginator", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showFirstLastIcon", "showPageLinks", "lazy", "lazyLoadOnInit", "emptyMessage", "style", "styleClass", "gridStyleClass", "trackBy", "filterBy", "filterLocale", "loading", "loadingIcon", "first", "sortField", "sortOrder", "value", "layout"], outputs: ["onLazyLoad", "onPage", "onSort", "onChangeLayout"] }, { kind: "component", type: RecordSearchResultComponent, selector: "ng-core-record-search-result", inputs: ["record", "type", "itemViewComponent", "adminMode", "canUpdate$", "canDelete$", "canUse$", "aggregations", "detailUrl$"], outputs: ["deletedRecord", "deleteMessageEvent"] }, { kind: "component", type: RecordSearchAggregationComponent, selector: "ng-core-record-search-aggregation", inputs: ["aggregation", "aggregationsFilters"], outputs: ["aggregationClicked"] }, { kind: "component", type: ExportButtonComponent, selector: "ng-core-export-button", inputs: ["exportOptions"] }, { kind: "component", type: ListFiltersComponent, selector: "ng-core-list-filters", inputs: ["aggregations", "aggregationsFilters", "searchFilters"], outputs: ["remove"] }, { kind: "component", type: PaginatorComponent, selector: "ng-core-paginator", inputs: ["alwaysShow", "currentPage", "pageLinkSize", "rows", "rowsPerPageOptions", "showCurrentPageReport", "showFirstLastIcon", "totalRecords"], outputs: ["rowPageChange"] }, { kind: "component", type: MenuSortComponent, selector: "ng-core-menu-sort", inputs: ["config", "selectedValue"], outputs: ["onChange"] }, { kind: "component", type: SearchFiltersComponent, selector: "ng-core-search-filters", inputs: ["searchFilters", "config", "query", "styleClassSection"], outputs: ["onChange"] }, { kind: "component", type: SearchTabsComponent, selector: "ng-core-search-tabs", inputs: ["types", "currentType"], outputs: ["onChangeType", "currentTypeChange"] }, { kind: "pipe", type: i1$2.AsyncPipe, name: "async" }, { kind: "pipe", type: i5.TranslatePipe, name: "translate" }, { kind: "pipe", type: UpperCaseFirstPipe, name: "ucfirst" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-record-search', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2019-2024 RERO\n  Copyright (C) 2019-2023 UCLouvain\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n@if (error) {\n<ng-core-error [error]=\"error\"></ng-core-error>\n} @else {\n<span #topScrollAnchor></span>\n<ng-core-search-tabs [types]=\"availableTypes\" (onChangeType)=\"changeType($event)\"/>\n<div class=\"core:flex core:flex-col core:gap-2\">\n  @if (availableTypes.length === 1 && showLabel) {\n  <h5>{{ availableTypes[0].label | translate }}</h5>\n  }\n  <ng-content select=\"[header]\"></ng-content>\n  <div class=\"core:flex core:gap-2\">\n    @if (showSearchInput) {\n    <ng-core-search-input\n      class=\"core:grow\"\n      [placeholder]=\"'search' | translate | ucfirst\"\n      [searchText]=\"q\"\n      [displayLabel]=\"false\"\n      (search)=\"searchByQuery($event)\"\n      [focus]=\"true\"\n    />\n    }\n    <ng-content select=\"[afterInputSearch]\"/>\n  </div>\n  @if (loaded && hasNoRecord) {\n    <p-message severity=\"info\">\n      {{ emptyRecordMessage }}\n    </p-message>\n    @if (adminMode.can && addStatus.can) {\n    <p-button\n      id=\"search-add-button\"\n      [label]=\"'Add' | translate\"\n      icon=\"fa fa-plus\"\n      [routerLink]=\"addStatus.routerLink || ['new']\"\n    />\n    }\n  } @else {\n  <div class=\"core:flex core:items-stretch core:w-full\">\n    @if (resultsText$ | async; as resultsText) {\n    <div class=\"core:flex core:items-center core:w-full\">\n      <strong>{{ resultsText }}</strong>\n    </div>\n    }\n    <div class=\"core:flex core:items-center core:justify-end core:w-full\">\n      @if (adminMode.can && addStatus.can) {\n      <p-button\n        id=\"search-add-button\"\n        [label]=\"'Add' | translate\"\n        icon=\"fa fa-plus\"\n        [routerLink]=\"addStatus.routerLink || ['new']\"\n      />\n      }\n      <!-- Sorting -->\n      @if (config?.sortOptions?.length > 0) {\n      <ng-core-menu-sort class=\"core:ml-1\" [selectedValue]=\"selectedSortValue\" [config]=\"config.sortOptions\" (onChange)=\"changeSorting($event)\" />\n      }\n      <!-- EXPORT BUTTON -->\n      <ng-core-export-button class=\"core:ml-1\"[exportOptions]=\"exportOptions\"/>\n      <!-- END EXPORT BUTTON -->\n    </div>\n  </div>\n  <ng-content select=\"[beforeResult]\"></ng-content>\n  <div class=\"core:grid core:grid-cols-12 core:gap-4\">\n    <ng-core-list-filters\n      [aggregations]=\"aggregations\"\n      class=\"core:col-span-12\"\n      [aggregationsFilters]=\"aggregationsFilters\"\n      [searchFilters]=\"searchFilters\"\n      (remove)=\"removeFilter($event)\"\n    />\n    <ng-content select=\"[top-search-result]\"></ng-content>\n    @if ((aggregations && aggregations.length) || searchFields.length > 0 || searchFilters.length > 0) {\n    <div class=\"core:md:col-span-5 core:lg:col-span-3 core:col-span-12\">\n      @if (searchFields.length > 0 && q) {\n        <div class=\"core:mb-4\">\n          @for (searchField of searchFields; track $index) {\n            <div class=\"core:flex core:gap-2 core:items-center\">\n              <p-toggleswitch (onChange)=\"searchInField($event, searchField.path)\" />\n              <label>{{ searchField.label | translate }}</label>\n            </div>\n          }\n        </div>\n      }\n\n      <ng-core-search-filters\n        [searchFilters]=\"searchFilters\"\n        [config]=\"config\"\n        [query]=\"q\"\n        styleClassSection=\"core:my-2\"\n        (onChange)=\"onChangeSearchFilter($event)\"\n      />\n\n      @if (!showEmptySearchMessage || q) {\n      <ng-content select=\"[top-facets]\"/>\n      @for (item of aggregations; track item.key) {\n      <div>\n        @if (!aggregationsToHide.includes(item.key)) {\n        <ng-core-record-search-aggregation\n          [aggregation]=\"item\"\n          [aggregationsFilters]=\"aggregationsFilters\"\n          (aggregationClicked)=\"loadAggregationBuckets($event)\"\n        />\n        }\n      </div>\n      } }\n    </div>\n    }\n    <div id=\"recordlist\" class=\"core:md:col-span-7 core:lg:col-span-9 core:col-span-12\">\n      @if (showEmptySearchMessage) {\n      <p-message severity=\"info\">\n        {{ 'Enter a query to get results.' | translate }}\n      </p-message>\n      }\n      <ng-content select=\"[top-result]\"/>\n      <p-dataView [value]=\"records\" [emptyMessage]=\"' '\">\n        <ng-template #list let-records>\n          <ul class=\"core:list-none\">\n            @for (record of records; track record.metadata.pid; let first = $first) {\n            <li class=\"core:py-2 core:md:py-6\" [ngClass]=\"{ 'core:border-t-1 core:border-surface': !first }\">\n              <ng-core-record-search-result\n                [adminMode]=\"adminMode\"\n                [record]=\"record\"\n                [type]=\"currentType\"\n                [itemViewComponent]=\"getResultItemComponentView()\"\n                [canUpdate$]=\"canUpdateRecord$(record)\"\n                [canDelete$]=\"canDeleteRecord$(record)\"\n                [canUse$]=\"canUseRecord$(record)\"\n                [detailUrl$]=\"resolveDetailUrl$(record)\"\n                (deletedRecord)=\"deleteRecord($event)\"\n                (deleteMessageEvent)=\"showDeleteMessage($event)\"\n              />\n            </li>\n            }\n          </ul>\n        </ng-template>\n      </p-dataView>\n\n      <ng-core-paginator\n        [alwaysShow]=\"showPagination\"\n        [currentPage]=\"currentPage\"\n        [pageLinkSize]=\"paginationMaxSize\"\n        [totalRecords]=\"total\"\n        [rows]=\"size\"\n        [rowsPerPageOptions]=\"config?.pagination?.rowsPerPageOptions || [10, 20, 50]\"\n        [showCurrentPageReport]=\"config?.pagination?.pageReport || false\"\n        [showFirstLastIcon]=\"paginationBoundaryLinks\"\n        (rowPageChange)=\"paginatorChange($event)\"\n      />\n      <ng-content select=\"[footer-result]\"/>\n      <ng-content/>\n    </div>\n  </div>\n  <ng-content select=\"[footer-search-result]\"/>\n  }\n</div>\n}\n" }]
        }], propDecorators: { topScroll: [{
                type: ViewChild,
                args: ['topScrollAnchor']
            }], currentType: [{
                type: Input
            }], q: [{
                type: Input
            }], page: [{
                type: Input
            }], size: [{
                type: Input
            }], sort: [{
                type: Input
            }], adminMode: [{
                type: Input
            }], detailUrl: [{
                type: Input
            }], types: [{
                type: Input
            }], parametersChanged: [{
                type: Output
            }], recordsSearched: [{
                type: Output
            }], showSearchInput: [{
                type: Input
            }], showLabel: [{
                type: Input
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordSearchPageComponent {
    constructor() {
        this.route = inject(ActivatedRoute);
        this.router = inject(Router);
        this.recordSearchService = inject(RecordSearchService);
        this.recordUiService = inject(RecordUiService);
        /**
         * Current selected resource type
         */
        this.currentType = 'documents';
        /**
         * URL to notice detail
         */
        this.detailUrl = null;
        /**
         * Display search input
         */
        this.showSearchInput = true;
        /**
         * Admin mode (edit, remove, add, ...)
         */
        this.adminMode = {
            can: true,
            message: ''
        };
        /**
         * Define the current record's page
         */
        this.page = 1;
        /**
         * Define the number of records per page
         */
        this.size = 10;
        /**
         * Search query
         */
        this.q = '';
        /**
         * Define the sort order of resulting records. It takes a string value
         * representing the property which is used to sort the records.
         * If a minus is put before the value, the sort is reversed.
         */
        this.sort = null;
        /**
         * Types of resources available
         */
        this.types = [{ key: 'documents', label: 'Documents' }];
    }
    /**
     * Component initialization.
     *
     * Subscribes to changes of route parameters and query parameters for
     * updating the search parameters and sending them to child component
     * (RecordSearchComponent).
     */
    ngOnInit() {
        this.routeParametersSubscription = combineLatest([this.route.paramMap, this.route.queryParamMap]).subscribe(([paramMap, queryParams]) => {
            // store current type of resource
            this.currentType = paramMap.get('type');
            this.recordUiService.types = this.route.snapshot.data.types;
            const config = this.recordUiService.getResourceConfig(this.currentType);
            // Stores query parameters
            this.q = queryParams.get('q') || '';
            this.size = queryParams.get('size') ? +queryParams.get('size') : 10;
            this.page = queryParams.get('page') ? +queryParams.get('page') : 1;
            this._setDefaultSort(config, queryParams.get('sort'));
            // loops over all aggregations filters and stores them.
            const aggregationsFilters = [];
            queryParams.keys.forEach((key) => {
                if (['q', 'page', 'size', 'sort'].includes(key) === false) {
                    const values = queryParams.getAll(key);
                    aggregationsFilters.push({ key, values });
                }
            });
            // Add filter parameter value
            if (config.searchFilters) {
                config.searchFilters.forEach((filter) => {
                    if (queryParams.get(filter.filter) === null && filter.disabledValue) {
                        aggregationsFilters.push({ key: filter.filter, values: [filter.disabledValue] });
                    }
                });
            }
            // update the facet filters given the URL params
            this.recordSearchService.setAggregationsFilters(aggregationsFilters);
        });
        // Store configuration data
        const { data } = this.route.snapshot;
        if (data.types) {
            this.types = data.types;
        }
        if (data.showSearchInput != null) {
            this.showSearchInput = data.showSearchInput;
        }
        if (data.adminMode) {
            data.adminMode().subscribe((as) => this.adminMode = as);
        }
        if (data.detailUrl) {
            this.detailUrl = data.detailUrl;
        }
    }
    /**
     * Component destruction.
     *
     * Unsubscribes from the observables of the route parameters.
     */
    ngOnDestroy() {
        this.routeParametersSubscription.unsubscribe();
    }
    /**
     * Update URL accordingly to parameters given.
     * @param parameters Parameters to put in url or query string
     */
    updateUrl(parameters) {
        const queryParams = {
            q: parameters.q,
            page: parameters.page,
            size: parameters.size,
            sort: parameters.sort
        };
        for (const filter of parameters.aggregationsFilters) {
            // We need to loop over each value and insert it on beginning of the array
            // instead of assign values directly. Otherwise, angular router doesn't
            // detect the changes. It's certainly a bug in angular.
            queryParams[filter.key] = [];
            for (const value of filter.values) {
                queryParams[filter.key].unshift(value);
            }
        }
        this.router.navigate([this.getCurrentUrl(parameters.currentType)], { queryParams, relativeTo: this.route });
    }
    /**
     * Return current URL after removing query parameters and updating resource type.
     *
     * @returns Updated url without query string
     */
    getCurrentUrl(type) {
        const segments = this.router.parseUrl(this.router.url).root.children.primary.segments.map(it => it.path);
        segments[segments.length - 1] = type;
        return '/' + segments.join('/');
    }
    /**
     * Sets the default sort for resource type.
     *
     * @param config Configuration object.
     */
    _setDefaultSort(config, sortParam) {
        if (sortParam) {
            this.sort = sortParam;
            return;
        }
        this.sort = null;
        if (!config.sortOptions) {
            return;
        }
        const defaultSortValue = this.q ? 'defaultQuery' : 'defaultNoQuery';
        config.sortOptions.forEach((option) => {
            if (option[defaultSortValue] === true) {
                this.sort = option.value;
            }
        });
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: RecordSearchPageComponent, isStandalone: false, selector: "ng-core-record-search-page", ngImport: i0, template: "<!--\n  RERO angular core\n  Copyright (C) 2020 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<ng-core-record-search class=\"core:my-1\" [adminMode]=\"adminMode\" [currentType]=\"currentType\" [types]=\"types\" [detailUrl]=\"detailUrl\"\n  [showSearchInput]=\"showSearchInput\" [q]=\"q\" [page]=\"page\" [size]=\"size\" [sort]=\"sort\"\n  (parametersChanged)=\"updateUrl($event)\"/>\n", dependencies: [{ kind: "component", type: RecordSearchComponent, selector: "ng-core-record-search", inputs: ["currentType", "q", "page", "size", "sort", "adminMode", "detailUrl", "types", "showSearchInput", "showLabel"], outputs: ["parametersChanged", "recordsSearched"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordSearchPageComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-record-search-page', standalone: false, template: "<!--\n  RERO angular core\n  Copyright (C) 2020 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<ng-core-record-search class=\"core:my-1\" [adminMode]=\"adminMode\" [currentType]=\"currentType\" [types]=\"types\" [detailUrl]=\"detailUrl\"\n  [showSearchInput]=\"showSearchInput\" [q]=\"q\" [page]=\"page\" [size]=\"size\" [sort]=\"sort\"\n  (parametersChanged)=\"updateUrl($event)\"/>\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
const typeResolver = (route) => {
    return route.params["type"];
};
const routes = [
    {
        path: ':type',
        title: typeResolver,
        component: RecordSearchPageComponent
    },
    {
        path: ':type/detail/:pid',
        title: typeResolver,
        component: DetailComponent
    },
    {
        path: ':type/edit/:pid',
        component: EditorComponent
    },
    {
        path: ':type/new',
        title: typeResolver,
        component: EditorComponent
    }
];
class RecordRoutingModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordRoutingModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: RecordRoutingModule, imports: [i2$8.RouterModule], exports: [RouterModule] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordRoutingModule, imports: [RouterModule.forChild(routes), RouterModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordRoutingModule, decorators: [{
            type: NgModule,
            args: [{
                    imports: [RouterModule.forChild(routes)],
                    exports: [RouterModule]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2024-2025 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
;
class SearchAutocompleteComponent {
    constructor() {
        this.recordService = inject(RecordService);
        this.sanitizePipe = inject(SanitizePipe);
        // Input
        this.delay = input(300);
        this.groupClass = input('core:text-gray-400');
        this.inputStyleClass = input('core:w-full');
        this.minLength = input(3);
        this.placeholder = input(null);
        this.recordTypes = input.required();
        this.scrollHeight = input(CONFIG.DEFAULT_SELECT_SCROLL_HEIGHT);
        this.styleClass = input('core:w-full');
        this.value = input();
        // Output
        this.onSearch = output();
        // Current value
        this.currentValue = '';
        // Whether to display options as grouped when nested options are provided.
        this.group = false;
        this.overlayOptions = {};
        // User Query
        this.query = new Subject();
        this.suggestions = toSignal(this.query.pipe(switchMap$1((query) => this.getSuggestions(query))), { initialValue: [] });
    }
    buttonClick(event) {
        this.onSearch.emit(this.currentValue);
    }
    setSuggestionQuery(event) {
        this.query.next(event.query);
    }
    onSelectValue(event) {
        this.onSearch.emit(event.value);
    }
    search(event) {
        if (event?.key === 'Enter') {
            this.onSearch.emit(this.currentValue);
        }
    }
    calculateWidth() {
        let width = 200;
        if (this.autoComplete) {
            width = DomHandler.getOuterWidth(this.autoComplete.el.nativeElement);
        }
        this.overlayOptions = {
            contentStyle: { width: width * 1 + 'px' }
        };
    }
    onResize() {
        this.calculateWidth();
    }
    ngAfterViewInit() {
        this.calculateWidth();
    }
    sanitize(value) {
        return this.sanitizePipe.transform(value);
    }
    getSuggestions(query) {
        return combineLatest(this.prepareQuery(query)).pipe(map$5((data) => {
            if (data.length > 1) {
                this.group = true;
                const suggestions = [];
                data.forEach((hits) => {
                    if (hits.length > 0) {
                        const selectedRecordType = this.recordTypes().find((type) => type.index === hits[0].index);
                        if (!('groupLabel' in selectedRecordType)) {
                            throw new Error('Missing groupLabel definition');
                        }
                        suggestions.push({
                            label: selectedRecordType.groupLabel,
                            items: hits
                        });
                    }
                });
                return suggestions;
            }
            else {
                return data[0];
            }
        }));
    }
    prepareQuery(query) {
        const suggestions = [];
        this.recordTypes().forEach((recordType) => {
            const queryParams = [];
            if ('queryParams' in recordType) {
                Object.keys(recordType.queryParams).forEach(key => {
                    queryParams.push(`${key}:${recordType.queryParams[key].replace(':', '\\:')}`);
                });
            }
            let queryRecord = `${recordType.field}:${query}`;
            if (queryParams.length > 0) {
                queryRecord += ` AND ${queryParams.join(' AND ')}`;
            }
            suggestions.push(this.recordService.getRecords(recordType.index, queryRecord, 1, recordType.maxSuggestions || 10, [], recordType.preFilters || {}, null, recordType.sort || null).pipe(map$5((data) => recordType.processSuggestions(data, query))));
        });
        return suggestions;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchAutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: SearchAutocompleteComponent, isStandalone: false, selector: "ng-core-search-autocomplete", inputs: { delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, groupClass: { classPropertyName: "groupClass", publicName: "groupClass", isSignal: true, isRequired: false, transformFunction: null }, inputStyleClass: { classPropertyName: "inputStyleClass", publicName: "inputStyleClass", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, recordTypes: { classPropertyName: "recordTypes", publicName: "recordTypes", isSignal: true, isRequired: true, transformFunction: null }, scrollHeight: { classPropertyName: "scrollHeight", publicName: "scrollHeight", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSearch: "onSearch" }, host: { listeners: { "window:resize": "onResize()" } }, viewQueries: [{ propertyName: "autoComplete", first: true, predicate: ["autoComplete"], descendants: true }], ngImport: i0, template: `
    <p-autoComplete
      #autoComplete
      [overlayOptions]="overlayOptions"
      dropdownIcon="fa fa-search"
      [dropdown]="true"
      dropdownMode="none"
      [styleClass]="styleClass()"
      [inputStyleClass]="inputStyleClass()"
      [delay]="delay()"
      [group]="group"
      [minLength]="minLength()"
      [placeholder]="placeholder()"
      [ngModel]="value()"
      (ngModelChange)="currentValue = sanitize($event)"
      [scrollHeight]="scrollHeight()"
      [suggestions]="suggestions()"
      (completeMethod)="setSuggestionQuery($event)"
      (onSelect)="onSelectValue($event)"
      (onKeyUp)="search($event)"
      (onDropdownClick)="buttonClick($event)"
      [pAutoFocus]="true"
    >
    <ng-template let-item #group>
      <div class="core:flex core:items-center" [ngClass]="groupClass()" [innerHTML]="item.label"></div>
    </ng-template>
    <ng-template let-item #item>
        @if(item.iconClass) {
          <i [ngClass]="item.iconClass"></i>&nbsp;
        }
        <span [innerHTML]="item.label" [title]="item.originalLabel ? item.originalLabel : ''"></span>
    </ng-template>
    </p-autoComplete>
  `, isInline: true, dependencies: [{ kind: "component", type: i1$3.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "delay", "style", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "disabled", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "maxlength", "name", "required", "size", "appendTo", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "field", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "itemSize", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "variant", "fluid"], outputs: ["completeMethod", "onSelect", "onUnselect", "onFocus", "onBlur", "onDropdownClick", "onClear", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i1$1.AutoFocus, selector: "[pAutoFocus]", inputs: ["autofocus", "pAutoFocus"] }, { kind: "directive", type: i1$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchAutocompleteComponent, decorators: [{
            type: Component,
            args: [{
                    selector: 'ng-core-search-autocomplete',
                    template: `
    <p-autoComplete
      #autoComplete
      [overlayOptions]="overlayOptions"
      dropdownIcon="fa fa-search"
      [dropdown]="true"
      dropdownMode="none"
      [styleClass]="styleClass()"
      [inputStyleClass]="inputStyleClass()"
      [delay]="delay()"
      [group]="group"
      [minLength]="minLength()"
      [placeholder]="placeholder()"
      [ngModel]="value()"
      (ngModelChange)="currentValue = sanitize($event)"
      [scrollHeight]="scrollHeight()"
      [suggestions]="suggestions()"
      (completeMethod)="setSuggestionQuery($event)"
      (onSelect)="onSelectValue($event)"
      (onKeyUp)="search($event)"
      (onDropdownClick)="buttonClick($event)"
      [pAutoFocus]="true"
    >
    <ng-template let-item #group>
      <div class="core:flex core:items-center" [ngClass]="groupClass()" [innerHTML]="item.label"></div>
    </ng-template>
    <ng-template let-item #item>
        @if(item.iconClass) {
          <i [ngClass]="item.iconClass"></i>&nbsp;
        }
        <span [innerHTML]="item.label" [title]="item.originalLabel ? item.originalLabel : ''"></span>
    </ng-template>
    </p-autoComplete>
  `,
                    standalone: false
                }]
        }], propDecorators: { autoComplete: [{
                type: ViewChild,
                args: ['autoComplete']
            }], onResize: [{
                type: HostListener,
                args: ['window:resize']
            }] } });

/*
 * RERO angular core
 * Copyright (C) 2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
;
class SearchFieldsComponent {
    constructor() {
        this.translate = inject(TranslateService);
        // Input
        this.searchLabel = input('Search in');
        this.resetLabel = input('Reset');
        this.searchFields = input.required();
        this.withResetAction = input(true);
        // Output
        this.onChange = output();
        // Field label
        this.label = signal(this.processLabel());
        // Field items
        this.items = [];
    }
    /** onInit hook */
    ngOnInit() {
        this.searchFields().map((field) => {
            this.items.push({
                label: field.label,
                command: () => this.select(field),
            });
        });
        if (this.withResetAction()) {
            this.items.push({ separator: true });
            this.items.push({
                label: this.translate.instant(this.resetLabel()),
                command: () => this.reset(),
            });
        }
        this.label.set(this.processLabel());
    }
    /**
     * Select a field from the menu
     * @param field - SearchField
     */
    select(field) {
        this.label.set(this.processLabel(field.label));
        this.onChange.emit({ action: 'select', field: field });
    }
    /** Reset search field */
    reset() {
        this.label.set(this.processLabel());
        this.onChange.emit({ action: 'reset' });
    }
    /**
     * Label formatting
     * @param label - The name of the field
     * @returns string, The formatted label
     */
    processLabel(label = '…') {
        return this.translate.instant(this.searchLabel()) + ' ' + label;
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchFieldsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
    static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.14", type: SearchFieldsComponent, isStandalone: false, selector: "ng-core-search-fields", inputs: { searchLabel: { classPropertyName: "searchLabel", publicName: "searchLabel", isSignal: true, isRequired: false, transformFunction: null }, resetLabel: { classPropertyName: "resetLabel", publicName: "resetLabel", isSignal: true, isRequired: false, transformFunction: null }, searchFields: { classPropertyName: "searchFields", publicName: "searchFields", isSignal: true, isRequired: true, transformFunction: null }, withResetAction: { classPropertyName: "withResetAction", publicName: "withResetAction", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onChange: "onChange" }, ngImport: i0, template: "\n<!--\n  RERO angular core\n  Copyright (C) 2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-splitButton [label]=\"label()\" [model]=\"items\" outlined />\n", dependencies: [{ kind: "component", type: i3$3.SplitButton, selector: "p-splitbutton, p-splitButton, p-split-button", inputs: ["model", "severity", "raised", "rounded", "text", "outlined", "size", "plain", "icon", "iconPos", "label", "tooltip", "tooltipOptions", "style", "styleClass", "menuStyle", "menuStyleClass", "dropdownIcon", "appendTo", "dir", "expandAriaLabel", "showTransitionOptions", "hideTransitionOptions", "buttonProps", "menuButtonProps", "autofocus", "disabled", "tabindex", "menuButtonDisabled", "buttonDisabled"], outputs: ["onClick", "onMenuHide", "onMenuShow", "onDropdownClick"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SearchFieldsComponent, decorators: [{
            type: Component,
            args: [{ selector: 'ng-core-search-fields', standalone: false, template: "\n<!--\n  RERO angular core\n  Copyright (C) 2024 RERO\n\n  This program is free software: you can redistribute it and/or modify\n  it under the terms of the GNU Affero General Public License as published by\n  the Free Software Foundation, version 3 of the License.\n\n  This program is distributed in the hope that it will be useful,\n  but WITHOUT ANY WARRANTY; without even the implied warranty of\n  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n  GNU Affero General Public License for more details.\n\n  You should have received a copy of the GNU Affero General Public License\n  along with this program.  If not, see <http://www.gnu.org/licenses/>.\n-->\n<p-splitButton [label]=\"label()\" [model]=\"items\" outlined />\n" }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class RecordModule {
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
    static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: RecordModule, declarations: [RecordSearchPageComponent,
            RecordSearchComponent,
            RecordSearchResultComponent,
            RecordSearchAggregationComponent,
            JsonComponent,
            DetailComponent,
            RecordDetailDirective,
            JsonComponent$1,
            GetRecordPipe,
            EditorComponent,
            AddFieldEditorComponent,
            DropdownLabelEditorComponent,
            ArrayTypeComponent,
            ObjectTypeComponent,
            SwitchComponent,
            MultiSchemaTypeComponent,
            BucketsComponent,
            FormFieldWrapperComponent,
            HideWrapperComponent,
            AggregationSliderComponent,
            LoadTemplateFormComponent,
            SaveTemplateFormComponent,
            CardWrapperComponent,
            LabelComponent,
            TextareaFieldComponent,
            MarkdownFieldComponent,
            AggregationDateRangeComponent,
            ExportButtonComponent,
            ListFiltersComponent,
            BucketNamePipe,
            PasswordGeneratorTypeComponent,
            DetailButtonComponent,
            RadioButtonComponent,
            PaginatorComponent,
            MenuSortComponent,
            SearchFiltersComponent,
            SearchFieldsComponent,
            SearchTabsComponent,
            SearchAutocompleteComponent], imports: [
            // NOTE : BrowserAnimationModule **should** be include in application core module.
            // BrowserAnimationsModule,
            CoreModule,
            FormsModule,
            ReactiveFormsModule,
            RecordRoutingModule,
            DatePickerModule,
            DataViewModule,
            ClipboardModule,
            RadioButtonModule,
            AutoCompleteModule,
            FormlySelectModule, i4$1.FormlyModule, FormlyPrimeNGModule,
            NgCoreFormlyDatePickerModule,
            NgCoreFormlyInputModule,
            NgCoreFormlyMultiCheckboxModule,
            NgCoreFormlyMultiSelectModule,
            NgCoreFormlyRemoteAutocompleteModule,
            NgCoreFormlySelectModule,
            NgCoreFormlyTreeSelectModule], exports: [RecordSearchComponent,
            GetRecordPipe,
            CoreModule,
            EditorComponent,
            FormlyModule,
            FormlyPrimeNGModule,
            FormlySelectModule,
            ExportButtonComponent,
            DetailButtonComponent,
            RecordDetailDirective,
            ListFiltersComponent,
            RecordSearchAggregationComponent,
            SearchFiltersComponent,
            SearchFieldsComponent,
            SearchAutocompleteComponent,
            NgCoreFormlyDatePickerModule,
            NgCoreFormlyInputModule,
            NgCoreFormlyMultiCheckboxModule,
            NgCoreFormlyRemoteAutocompleteModule,
            NgCoreFormlySelectModule,
            MenuSortComponent,
            NgCoreFormlyTreeSelectModule,
            SearchTabsComponent,
            PaginatorComponent] }); }
    static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordModule, providers: [
            {
                provide: FORMLY_CONFIG,
                multi: true,
                useFactory: registerNgCoreFormlyExtension,
                deps: [TranslateService, RecordService]
            }
        ], imports: [
            // NOTE : BrowserAnimationModule **should** be include in application core module.
            // BrowserAnimationsModule,
            CoreModule,
            FormsModule,
            ReactiveFormsModule,
            RecordRoutingModule,
            DatePickerModule,
            DataViewModule,
            ClipboardModule,
            RadioButtonModule,
            AutoCompleteModule,
            FormlySelectModule,
            FormlyModule.forRoot({
                extensions: [
                    { name: 'email', extension: { prePopulate: emailValidator } }
                ],
                extras: {
                    checkExpressionOn: 'changeDetectionCheck',
                    resetFieldOnHide: true
                },
                types: [
                    { name: 'input', component: NgCoreFormlyFieldInput },
                    { name: 'boolean', component: SwitchComponent },
                    { name: 'enum', extends: 'select' },
                    { name: 'array', component: ArrayTypeComponent, wrappers: ['card'] },
                    { name: 'object', component: ObjectTypeComponent, wrappers: ['card'] },
                    { name: 'multischema', component: MultiSchemaTypeComponent },
                    { name: 'textarea', component: TextareaFieldComponent },
                    { name: 'markdown', component: MarkdownFieldComponent },
                    { name: 'passwordGenerator', component: PasswordGeneratorTypeComponent },
                    { name: 'radioButton', component: RadioButtonComponent },
                ],
                wrappers: [
                    { name: 'form-field', component: FormFieldWrapperComponent },
                    { name: 'hide', component: HideWrapperComponent },
                    { name: 'card', component: CardWrapperComponent }
                ]
            }),
            FormlyPrimeNGModule,
            NgCoreFormlyDatePickerModule,
            NgCoreFormlyInputModule,
            NgCoreFormlyMultiCheckboxModule,
            NgCoreFormlyMultiSelectModule,
            NgCoreFormlyRemoteAutocompleteModule,
            NgCoreFormlySelectModule,
            NgCoreFormlyTreeSelectModule, CoreModule,
            FormlyModule,
            FormlyPrimeNGModule,
            FormlySelectModule,
            NgCoreFormlyDatePickerModule,
            NgCoreFormlyInputModule,
            NgCoreFormlyMultiCheckboxModule,
            NgCoreFormlyRemoteAutocompleteModule,
            NgCoreFormlySelectModule,
            NgCoreFormlyTreeSelectModule] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: RecordModule, decorators: [{
            type: NgModule,
            args: [{
                    declarations: [
                        RecordSearchPageComponent,
                        RecordSearchComponent,
                        RecordSearchResultComponent,
                        RecordSearchAggregationComponent,
                        JsonComponent,
                        DetailComponent,
                        RecordDetailDirective,
                        JsonComponent$1,
                        GetRecordPipe,
                        EditorComponent,
                        AddFieldEditorComponent,
                        DropdownLabelEditorComponent,
                        ArrayTypeComponent,
                        ObjectTypeComponent,
                        SwitchComponent,
                        MultiSchemaTypeComponent,
                        BucketsComponent,
                        FormFieldWrapperComponent,
                        HideWrapperComponent,
                        AggregationSliderComponent,
                        LoadTemplateFormComponent,
                        SaveTemplateFormComponent,
                        CardWrapperComponent,
                        LabelComponent,
                        TextareaFieldComponent,
                        MarkdownFieldComponent,
                        AggregationDateRangeComponent,
                        ExportButtonComponent,
                        ListFiltersComponent,
                        BucketNamePipe,
                        PasswordGeneratorTypeComponent,
                        DetailButtonComponent,
                        RadioButtonComponent,
                        PaginatorComponent,
                        MenuSortComponent,
                        SearchFiltersComponent,
                        SearchFieldsComponent,
                        SearchTabsComponent,
                        SearchAutocompleteComponent
                    ],
                    imports: [
                        // NOTE : BrowserAnimationModule **should** be include in application core module.
                        // BrowserAnimationsModule,
                        CoreModule,
                        FormsModule,
                        ReactiveFormsModule,
                        RecordRoutingModule,
                        DatePickerModule,
                        DataViewModule,
                        ClipboardModule,
                        RadioButtonModule,
                        AutoCompleteModule,
                        FormlySelectModule,
                        FormlyModule.forRoot({
                            extensions: [
                                { name: 'email', extension: { prePopulate: emailValidator } }
                            ],
                            extras: {
                                checkExpressionOn: 'changeDetectionCheck',
                                resetFieldOnHide: true
                            },
                            types: [
                                { name: 'input', component: NgCoreFormlyFieldInput },
                                { name: 'boolean', component: SwitchComponent },
                                { name: 'enum', extends: 'select' },
                                { name: 'array', component: ArrayTypeComponent, wrappers: ['card'] },
                                { name: 'object', component: ObjectTypeComponent, wrappers: ['card'] },
                                { name: 'multischema', component: MultiSchemaTypeComponent },
                                { name: 'textarea', component: TextareaFieldComponent },
                                { name: 'markdown', component: MarkdownFieldComponent },
                                { name: 'passwordGenerator', component: PasswordGeneratorTypeComponent },
                                { name: 'radioButton', component: RadioButtonComponent },
                            ],
                            wrappers: [
                                { name: 'form-field', component: FormFieldWrapperComponent },
                                { name: 'hide', component: HideWrapperComponent },
                                { name: 'card', component: CardWrapperComponent }
                            ]
                        }),
                        FormlyPrimeNGModule,
                        NgCoreFormlyDatePickerModule,
                        NgCoreFormlyInputModule,
                        NgCoreFormlyMultiCheckboxModule,
                        NgCoreFormlyMultiSelectModule,
                        NgCoreFormlyRemoteAutocompleteModule,
                        NgCoreFormlySelectModule,
                        NgCoreFormlyTreeSelectModule,
                    ],
                    exports: [
                        RecordSearchComponent,
                        GetRecordPipe,
                        CoreModule,
                        EditorComponent,
                        FormlyModule,
                        FormlyPrimeNGModule,
                        FormlySelectModule,
                        ExportButtonComponent,
                        DetailButtonComponent,
                        RecordDetailDirective,
                        ListFiltersComponent,
                        RecordSearchAggregationComponent,
                        SearchFiltersComponent,
                        SearchFieldsComponent,
                        SearchAutocompleteComponent,
                        NgCoreFormlyDatePickerModule,
                        NgCoreFormlyInputModule,
                        NgCoreFormlyMultiCheckboxModule,
                        NgCoreFormlyRemoteAutocompleteModule,
                        NgCoreFormlySelectModule,
                        MenuSortComponent,
                        NgCoreFormlyTreeSelectModule,
                        SearchTabsComponent,
                        PaginatorComponent
                    ],
                    providers: [
                        {
                            provide: FORMLY_CONFIG,
                            multi: true,
                            useFactory: registerNgCoreFormlyExtension,
                            deps: [TranslateService, RecordService]
                        }
                    ]
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
class CryptoJsService {
    constructor() {
        this.coreConfigService = inject(CoreConfigService);
    }
    encrypt(value) {
        const _key = this.secretPassphrase();
        return CryptoJS.AES.encrypt(value, _key, { iv: _key });
    }
    decrypt(value) {
        const _key = this.secretPassphrase();
        return CryptoJS.AES.decrypt(value, _key, { iv: _key }).toString(CryptoJS.enc.Utf8);
    }
    secretPassphrase() {
        return CryptoJS.enc.Utf8.parse(this.coreConfigService.secretPassphrase);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CryptoJsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CryptoJsService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: CryptoJsService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 * Service for managing data saved into local storage.
 */
class LocalStorageService {
    constructor() {
        this.cryptoService = inject(CryptoJsService);
        /**
         * Event for set data on local storage
         */
        this.onSet = new Subject();
        /**
         * Event for remove data on local storage
         */
        this.onRemove = new Subject();
        /**
         * Event for clear on local storage
         */
        this.onClear = new Subject();
    }
    /**
     * On set observable
     * @return onSet subject observable
     */
    get onSet$() {
        return this.onSet.asObservable();
    }
    /**
     * On remove observable
     * @return onRemove subject observable
     */
    get onRemove$() {
        return this.onRemove.asObservable();
    }
    /**
     * On clear observable
     * @return onClear subject observable
     */
    get onClear$() {
        return this.onClear.asObservable();
    }
    /**
     * Set a new key on LocalStorage
     * @param key - string
     * @param value - string
     * @return LocalStorageService
     */
    set(key, value) {
        const data = { date: new Date(), data: value };
        localStorage.setItem(key, this.cryptoService.encrypt(JSON.stringify(data)));
        this.onSet.next({ key, data });
        return this;
    }
    /**
     * Update date of current object qualified by the key
     * @param key - string
     * @return LocalStorageService;
     */
    updateDate(key) {
        const local = this.getItem(key);
        local.date = new Date();
        localStorage.setItem(key, this.cryptoService.encrypt(JSON.stringify(local)));
        return this;
    }
    /**
     * Return the status of current object qualified by the key
     * @param key - string
     * @param seconds - number of seconds session expired
     * @return boolean
     */
    isExpired(key, seconds) {
        const local = this.getItem(key);
        const today = new Date();
        const localDate = new Date(local.date);
        localDate.setSeconds(localDate.getSeconds() + seconds);
        return today > localDate;
    }
    /**
     * Return JSON content of the LocaleStorage
     * @param key - string
     * @param field - string (default: data)
     * @return JSON
     */
    get(key, field = 'data') {
        const local = this.getItem(key);
        return local ? local[field] : null;
    }
    /**
     * Remove a key of LocaleStorage
     * @param key - string
     * @return LocalStorageService
     */
    remove(key) {
        localStorage.removeItem(key);
        this.onRemove.next(null);
        return this;
    }
    /**
     * Clear LocaleStorage
     * @return LocalStorageService
     */
    clear() {
        localStorage.clear();
        this.onClear.next(null);
        return this;
    }
    /**
     * has key in LocaleStorage
     * @param key - string
     * @return Boolean
     */
    has(key) {
        return this.keys().indexOf(key) > -1;
    }
    /**
     * Get local storage with the key
     * @param key - string
     */
    getItem(key) {
        return JSON.parse(this.cryptoService.decrypt(localStorage.getItem(key)));
    }
    /**
     * Return keys of LocaleStorage
     * @return array
     */
    keys() {
        return Object.keys(localStorage);
    }
    static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocalStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
    static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocalStorageService, providedIn: 'root' }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocalStorageService, decorators: [{
            type: Injectable,
            args: [{
                    providedIn: 'root'
                }]
        }] });

// @dynamic
class TimeValidator {
    static { this.FORMAT = 'hh:mm'; }
    /**
     * Allow to control if time interval limits are well formed : the end limit should be 'older' the start limit
     * @param start: the field name where to find the start limit value
     * @param end: the field name where to find the end limit value
     */
    static greaterThanValidator(start, end) {
        return (control) => {
            if (control) {
                let isLessThan = false;
                const startTime = control.get(start);
                const endTime = control.get(end);
                const startDate = DateTime.fromFormat(startTime.value, TimeValidator.FORMAT);
                const endDate = DateTime.fromFormat(endTime.value, TimeValidator.FORMAT);
                if (startDate.toFormat(TimeValidator.FORMAT) !== '00:00' || endDate.toFormat(TimeValidator.FORMAT) !== '00:00') {
                    isLessThan = startDate.diff(endDate) >= 0;
                }
                return (isLessThan)
                    ? ({ lessThan: { value: isLessThan } })
                    : null;
            }
        };
    }
    static RangePeriodValidator() {
        return (control) => {
            if (control.value) {
                let isRangeLessThan = false;
                const times = control.get('times');
                if (control.get('is_open').value && times.value.length > 1) {
                    const firstStartDate = DateTime.fromFormat(times.at(0).get('start_time').value, TimeValidator.FORMAT);
                    const firstEndDate = DateTime.fromFormat(times.at(0).get('end_time').value, TimeValidator.FORMAT);
                    const lastStartDate = DateTime.fromFormat(times.at(1).get('start_time').value, TimeValidator.FORMAT);
                    const lastEndDate = DateTime.fromFormat(times.at(1).get('end_time').value, TimeValidator.FORMAT);
                    if (firstStartDate > lastStartDate) {
                        isRangeLessThan = firstStartDate.diff(lastStartDate) <= 0
                            || firstStartDate.diff(lastEndDate) <= 0;
                    }
                    else {
                        isRangeLessThan = lastStartDate.diff(firstEndDate) <= 0
                            || lastStartDate.diff(firstEndDate) <= 0;
                    }
                }
                return (isRangeLessThan)
                    ? ({ rangeLessThan: { value: isRangeLessThan } })
                    : null;
            }
        };
    }
}

// @dynamic
class UniqueValidator {
    static createValidator(recordService, recordType, fieldName, excludePid = null) {
        return (control) => {
            return recordService.valueAlreadyExists(recordType, fieldName, control.value, excludePid);
        };
    }
}

/*
 * RERO angular core
 * Copyright (C) 2020-2024 RERO
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Generated bundle index. Do not edit.
 */

export { AbstractCanDeactivateComponent, AddFieldEditorComponent, ApiService, ArrayTypeComponent, BucketNameService, CONFIG, CallbackArrayFilterPipe, ComponentCanDeactivateGuard, CoreConfigService, CoreModule, CryptoJsService, DatePickerComponent, DateTranslatePipe, DefaultPipe, DetailButtonComponent, DetailComponent, DialogComponent, DropdownLabelEditorComponent, EditorComponent, ErrorComponent, ExportButtonComponent, FilesizePipe, FormOptionsProcessExtension, GetRecordPipe, JSONSchemaService, ListFiltersComponent, LocalStorageService, LoggerService, MarkdownPipe, MenuSortComponent, MultiCheckboxComponent, MultiSchemaTypeComponent, MultiSelectComponent, NgCoreFormlyDatePickerModule, NgCoreFormlyExtension, NgCoreFormlyFieldInput, NgCoreFormlyInputModule, NgCoreFormlyMultiCheckboxModule, NgCoreFormlyMultiSelectModule, NgCoreFormlyRemoteAutocompleteModule, NgCoreFormlySelectModule, NgCoreFormlyTreeSelectModule, NgCoreTranslateService, Nl2brPipe, ObjectTypeComponent, PaginatorComponent, PasswordGeneratorTypeComponent, PrimeNgCoreModule, Record, RecordDetailDirective, RecordHandleErrorService, RecordModule, RecordSearchAggregationComponent, RecordSearchComponent, RecordSearchPageComponent, RecordSearchService, RecordService, RecordUiService, RemoteAutocomplete, RemoteAutocompleteService, RouteCollectionService, SanitizePipe, SearchAutocompleteComponent, SearchFieldsComponent, SearchFiltersComponent, SearchInputComponent, SearchResult, SearchTabsComponent, SelectComponent, SortByKeysPipe, SwitchComponent, TextReadMoreComponent, TimeValidator, TranslateExtension, TranslateLabelService, TranslateLanguagePipe, TranslateLanguageService, TranslateLoader, TreeSelectComponent, TruncateTextPipe, UniqueValidator, UpperCaseFirstPipe, Validators, capitalize, cleanDictKeys, datesGreaterThanValidator, extractIdOnRef, isEmpty, primeNGConfig, processJsonSchema, registerNgCoreFormlyExtension, removeEmptyValues, resolve$ref, resolveRefs, sortByKeys };
//# sourceMappingURL=rero-ng-core.mjs.map