UNPKG

@universis/common

Version:

Universis - common directives and services

1,085 lines (1,072 loc) 269 kB
import * as i0 from '@angular/core'; import { InjectionToken, isDevMode, Injectable, Component, Input, EventEmitter, Output, Pipe, Directive, Inject, ChangeDetectorRef, Optional, NgModule, CUSTOM_ELEMENTS_SCHEMA, ViewEncapsulation, ErrorHandler, SkipSelf } from '@angular/core'; import * as i1 from '@ngx-translate/core'; import { TranslatePipe, TranslateModule } from '@ngx-translate/core'; import * as i2 from '@angular/common/http'; import { HttpErrorResponse, HttpClientModule, HttpClient } from '@angular/common/http'; import * as i1$1 from '@themost/angular'; import { DATA_CONTEXT_CONFIG, AngularDataContext, MostModule } from '@themost/angular'; import { BehaviorSubject, Observable, Subject, lastValueFrom } from 'rxjs'; import 'jquery'; import 'bootstrap/js/dist/modal'; import * as i4 from '@angular/common'; import { DecimalPipe, DatePipe, CommonModule } from '@angular/common'; import * as i2$1 from 'ngx-bootstrap/modal'; import * as _Toast from 'bootstrap/js/dist/toast'; import * as _numeral from 'numeral'; import 'numeral/locales'; import * as _ from 'lodash'; import { template, uniqBy, slice } from 'lodash'; import * as i1$2 from '@angular/router'; import { NavigationEnd, NavigationStart, DefaultUrlSerializer, PRIMARY_OUTLET, RouterModule, ActivatedRoute } from '@angular/router'; import { Args, ResponseError } from '@themost/client'; import { skip, filter, first, map, takeUntil } from 'rxjs/operators'; import { X509 } from 'jsrsasign'; import * as FileSaver from 'file-saver'; import * as XLSX from 'xlsx'; import { EventSourcePolyfill } from 'event-source-polyfill'; import { FormsModule } from '@angular/forms'; import { AES, enc, lib, SHA256, SHA1 } from 'crypto-js'; let APP_CONFIGURATION = new InjectionToken('app.configuration'); /** * * This Service is used to get or set global configuration for the project * @export * @class ConfigurationService */ class ConfigurationService { constructor(_translateService, _injector, _http) { this._translateService = _translateService; this._injector = _injector; this._http = _http; this.loaded = new BehaviorSubject(null); // } /** * * Load Configs saved in Project * @returns {Promise<any>} * @memberof ConfigurationService */ async load() { if (this.config) { return true; } // get environment const env = isDevMode() ? 'development' : 'production'; // load configuration based on environment // e.g. assets/config/app.production.json or // assets/config/app.development.json try { return await this.loadFrom(`assets/config/app.${env}.json`); } catch (err) { if (err.status === 404) { // not found // load default application configuration return await this.loadFrom(`assets/config/app.json`); } throw err; } } async loadFrom(url) { // get configuration from url this.config = await new Promise((resolve, reject) => { this._http.get(url).subscribe(result => { return resolve(result); }, err => { return reject(err); }); }); // get DATA_CONTEXT_CONFIG const dataContextConfig = this._injector.get(DATA_CONTEXT_CONFIG); // IMPORTANT: Set DATA_CONTEXT_CONFIG base URI from configuration dataContextConfig.base = this.config.settings.remote.server; // set locale for translate service this._translateService.use(this.currentLocale); // emit event for loaded configuration this.loaded.next(this.config); // return return true; } /** * Gets current application settings */ get settings() { return this.config && this.config.settings; } /** * Gets the current user language */ get currentLocale() { const currentLang = localStorage.getItem('currentLang'); if (currentLang) { return currentLang; } if (this.settings && this.settings.i18n && this.settings.i18n.defaultLocale) { // return current language return this.settings.i18n.defaultLocale; } // use fallback language return 'en'; } set currentLocale(locale) { // save current locale localStorage.setItem('currentLang', locale); // set locale for translate service this._translateService.use(locale); } } ConfigurationService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ConfigurationService, deps: [{ token: i1.TranslateService }, { token: i0.Injector }, { token: i2.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable }); ConfigurationService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ConfigurationService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ConfigurationService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1.TranslateService }, { type: i0.Injector }, { type: i2.HttpClient }]; } }); var DIALOG_BUTTONS; (function (DIALOG_BUTTONS) { DIALOG_BUTTONS[DIALOG_BUTTONS["Ok"] = 1] = "Ok"; DIALOG_BUTTONS[DIALOG_BUTTONS["Yes"] = 2] = "Yes"; DIALOG_BUTTONS[DIALOG_BUTTONS["No"] = 4] = "No"; DIALOG_BUTTONS[DIALOG_BUTTONS["Abort"] = 8] = "Abort"; DIALOG_BUTTONS[DIALOG_BUTTONS["Retry"] = 16] = "Retry"; DIALOG_BUTTONS[DIALOG_BUTTONS["Ignore"] = 32] = "Ignore"; DIALOG_BUTTONS[DIALOG_BUTTONS["Cancel"] = 64] = "Cancel"; DIALOG_BUTTONS[DIALOG_BUTTONS["YesNo"] = 6] = "YesNo"; DIALOG_BUTTONS[DIALOG_BUTTONS["AbortRetryIgnore"] = 54] = "AbortRetryIgnore"; DIALOG_BUTTONS[DIALOG_BUTTONS["OkCancel"] = 65] = "OkCancel"; DIALOG_BUTTONS[DIALOG_BUTTONS["YesNoCancel"] = 70] = "YesNoCancel"; })(DIALOG_BUTTONS || (DIALOG_BUTTONS = {})); /** * * A modal dialog component with ok and cancel buttons * @export * @class DialogComponent */ class DialogComponent { constructor(_element, _translateService) { this._element = _element; this._translateService = _translateService; this.title = ''; this.message = ''; this.buttons = DIALOG_BUTTONS.Ok; this.language = 'en'; this.language = this._translateService.currentLang; } bitwiseAnd(a, b) { return a & b; } /** * Shows modal dialog * @returns Promise<any> */ show() { return new Promise((resolve, reject) => { if (this.modalRef) { this.modalRef.one('hide.bs.modal', () => { // get related target if any const result = this.modalRef.data('result'); // return result return resolve(result); }); const modalRef = this.modalRef; modalRef.modal('show'); } else { reject('Modal element may not be empty at this context'); } }); } /** * Hides modal dialog * @param value */ hide(value) { this.modalRef.data('result', value); const modalRef = this.modalRef; modalRef.modal('hide'); } /** * Converts modal buttons classes modal-ok, modal-yes-no etc to dialog buttons * @param {Array<string>} classList */ classListToButtons(classList) { return classList.map(classListElement => { // maps each item to an array of matches (if match) return /^modal(-ok)?(-yes)?(-no)?(-abort)?(-retry)?(-ignore)?(-cancel)?/ig.exec(classListElement); }).filter(match => { // filter not matched elements return match != null; }).map((match) => { // maps each match as an array of 2 ^ k results // @ts-ignore return match.map((item, k) => { if (item && k > 0) { return Math.pow(2, k - 1); } return 0; }).reduce((a, b) => { // return a sum of results return a + b; }); }).reduce((a, b) => { // return a final sum of results return a | b; }); } async ngOnInit() { // get element classes const classList = Array.from(this._element.nativeElement.classList); // get buttons from element class list const classListButtons = this.classListToButtons(classList); // if element has button classes (modal-ok, modal-yes-no etc) if (classListButtons) { // set dialog buttons this.buttons = classListButtons; } this.modalRef = jQuery(this._element.nativeElement); // initialize modal const modalRef = this.modalRef; modalRef.modal({ backdrop: 'static', focus: true, keyboard: false, show: false }); } } DialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DialogComponent, deps: [{ token: i0.ElementRef }, { token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); DialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: DialogComponent, selector: "universis-dialog.modal", inputs: { title: "title", message: "message", theme: "theme" }, ngImport: i0, template: ` <div class="modal-dialog" [ngClass]="theme" role="document"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">{{title | translate}}</h4> </div> <div class="modal-body" [innerHTML]="message"></div> <div class="modal-footer"> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 1)" (click)="hide('ok')" class="btn btn-theme btn-ok" [translate]="'OK'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 2)" (click)="hide('yes')" class="btn btn-theme btn-yes" [translate]="'Yes'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 4)" (click)="hide('no')" class="btn btn-gray-100 btn-no" [translate]="'No'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 8)" (click)="hide('abort')" class="btn btn-danger btn-abort" [translate]="'Abort'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 16)" (click)="hide('retry')" class="btn btn-gray-100 btn-retry" [translate]="'Retry'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 32)" (click)="hide('ignore')" class="btn btn-gray-100 btn-ignore" [translate]="'Ignore'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 64)" (click)="hide('cancel')" class="btn btn-gray-100 btn-cancel" [translate]="'Cancel'"></button> </div> </div> </div> `, isInline: true, styles: [".modal-dialog .modal-body{margin-top:0;margin-bottom:0}.modal-footer{border-top:0}.btn{text-transform:uppercase;font-size:16px}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: i1.TranslatePipe, name: "translate" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: DialogComponent, decorators: [{ type: Component, args: [{ selector: 'universis-dialog.modal', template: ` <div class="modal-dialog" [ngClass]="theme" role="document"> <div class="modal-content"> <div class="modal-header"> <h4 class="modal-title">{{title | translate}}</h4> </div> <div class="modal-body" [innerHTML]="message"></div> <div class="modal-footer"> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 1)" (click)="hide('ok')" class="btn btn-theme btn-ok" [translate]="'OK'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 2)" (click)="hide('yes')" class="btn btn-theme btn-yes" [translate]="'Yes'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 4)" (click)="hide('no')" class="btn btn-gray-100 btn-no" [translate]="'No'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 8)" (click)="hide('abort')" class="btn btn-danger btn-abort" [translate]="'Abort'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 16)" (click)="hide('retry')" class="btn btn-gray-100 btn-retry" [translate]="'Retry'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 32)" (click)="hide('ignore')" class="btn btn-gray-100 btn-ignore" [translate]="'Ignore'"></button> <button [lang]="language" type="button" *ngIf="bitwiseAnd(buttons, 64)" (click)="hide('cancel')" class="btn btn-gray-100 btn-cancel" [translate]="'Cancel'"></button> </div> </div> </div> `, styles: [".modal-dialog .modal-body{margin-top:0;margin-bottom:0}.modal-footer{border-top:0}.btn{text-transform:uppercase;font-size:16px}\n"] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.TranslateService }]; }, propDecorators: { title: [{ type: Input }], message: [{ type: Input }], theme: [{ type: Input }] } }); /** * * Displays a Modal window or a type of Notification (based on choice the color changes) * @export * @class ModalService */ class ModalService { constructor(componentFactoryResolver, appRef, injector, modalService) { this.componentFactoryResolver = componentFactoryResolver; this.appRef = appRef; this.injector = injector; this.modalService = modalService; this.config = { ignoreBackdropClick: true, keyboard: false, initialState: null, class: 'modal-content-base' }; } showDialog(title, message, buttons = DIALOG_BUTTONS.Ok, extras) { const componentRef = this.componentFactoryResolver .resolveComponentFactory(DialogComponent) .create(this.injector); componentRef.instance.title = title; componentRef.instance.message = message; componentRef.instance.buttons = buttons; if (extras) { componentRef.instance.theme = extras.theme; } // attach component to the appRef so that it's inside the ng component tree this.appRef.attachView(componentRef.hostView); // get DOM element from component const modalElement = componentRef.hostView .rootNodes[0]; // append DOM element to the body document.body.appendChild(modalElement); return componentRef.instance.ngOnInit().then(() => { // show dialog return componentRef.instance.show().then(result => { // detach view this.appRef.detachView(componentRef.hostView); // destroy component ref componentRef.destroy(); // return Promise.resolve(result); }); }); } showWarningDialog(title, message, buttons = DIALOG_BUTTONS.OkCancel) { return this.showDialog('', `<div class="text-center"> <div class="icon-circle icon-circle-warning"> <i class="fa fa-exclamation"></i> </div> <div class="font-2xl font-weight-bold mt-2"> ${title} </div> <p class="mt-2"> ${message} </p> </div> `, buttons, { theme: 'modal-dialog-warning' }); } showSuccessDialog(title, message, buttons = DIALOG_BUTTONS.Ok) { return this.showDialog('', `<div class="text-center"> <div class="icon-circle icon-circle-success"> <i class="fa fa-check"></i> </div> <div class="font-2xl font-weight-bold mt-2"> ${title} </div> <p class="mt-2"> ${message} </p> </div> `, buttons, { theme: 'modal-dialog-success' }); } showErrorDialog(title, message, buttons = DIALOG_BUTTONS.Ok) { return this.showDialog('', `<div class="text-center"> <div class="icon-circle icon-circle-danger"> <i class="fa fa-times"></i> </div> <div class="font-2xl font-weight-bold mt-2"> ${title} </div> <p class="mt-2"> ${message} </p> </div> `, buttons, { theme: 'modal-dialog-danger' }); } showInfoDialog(title, message, buttons = DIALOG_BUTTONS.Ok) { return this.showDialog('', `<div class="text-center"> <div class="icon-circle icon-circle-info"> <i class="fa fa-info"></i> </div> <div class="font-2xl font-weight-bold mt-2"> ${title} </div> <p class="mt-2"> ${message} </p> </div> `, buttons, { theme: 'modal-dialog-info' }); } openModal(template, customClass) { let config; if (customClass) { config = JSON.parse(JSON.stringify(this.config)); config.class = customClass; } else { config = this.config; } return this.modalRef = this.modalService.show(template, config); } openModalComponent(template, options) { return this.modalRef = this.modalService.show(template, options); } } ModalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ModalService, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.ApplicationRef }, { token: i0.Injector }, { token: i2$1.BsModalService }], target: i0.ɵɵFactoryTarget.Injectable }); ModalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ModalService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ModalService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.ApplicationRef }, { type: i0.Injector }, { type: i2$1.BsModalService }]; } }); /** * * Component for Card-Box element with Inputs: * Usage <universis-msgbox [title]="HelloWorld" ...></universis-msgbox> * @Input() title: Title of Box * @Input() icon: Icon displayed on the left of the element * @Input() info: The Status displayed on user * @Input() message: Explanation of the status * @Input() extraMessage: Some extra guidance * @Input() actionButton: Text displayed as Text in button * @Input() actionText: Text displayed as an action * @Input() disableBut: Disable button * @export */ class MsgboxComponent { constructor() { // Default class sets the color to green, otherwise pass it the correct bootstrap class this.buttonClass = 'btn-success'; // Usage (action)="someFunction()" this.action = new EventEmitter(); } clicked() { this.action.emit(); } } MsgboxComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsgboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); MsgboxComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: MsgboxComponent, selector: "universis-msgbox", inputs: { title: "title", icon: "icon", info: "info", message: "message", extraMessage: "extraMessage", actionButton: "actionButton", actionText: "actionText", disableBut: "disableBut", buttonClass: "buttonClass" }, outputs: { action: "action" }, ngImport: i0, template: "<div class=\"card\">\n <div class=\"msgbox_main-container\">\n <div class=\"msgbox_icon\">\n <span class=\"fa-4x far {{icon}}\" style=\"color:#678898;\"></span>\n </div>\n <div class=\"msgbox_details\">\n <div *ngIf=\"title && !title.includes('title')\" class=\"msgbox_title\" id=\"title\">{{title}}</div>\n <div class=\"font pt-3 msgbox_item\" id=\"message\">{{message}}</div>\n <div class=\"pt-3 msgbox_item\" *ngIf=\"extraMessage && !extraMessage.includes('extraMessage')\">{{extraMessage}}</div>\n <div>\n <div class=\"pt-3 msgbox_item\" *ngIf=\"actionButton && !actionButton.includes('actionButton')\">\n <button type=\"button\" class=\"btn s--btn\" [ngClass]=\"buttonClass\" [disabled]=\"disableBut\" (click)=\"clicked()\">{{actionButton}}</button>\n </div>\n <div class=\"pt-3 msgbox_item\" *ngIf=\"actionText && !actionText.includes('actionText')\" id=\"text\">\n <span><span class=\"fa-1x icon-arrow-right\"></span>{{actionText}}</span>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".msgbox_main-container{display:flex;margin:30px 40px}.msgbox_title{text-transform:uppercase;color:#536c79}.msgbox_details{display:flex;flex-direction:column;justify-content:center}.msgbox_icon{padding-right:60px;padding-left:20px;display:flex;align-items:center}.msgbox_item{display:flex}@media screen and (max-width: 600px){.msgbox_main-container{flex-direction:column;align-items:center}.msgbox_title{text-align:center;justify-content:center;padding:1rem 5px 0}.msgbox_item{justify-content:center;text-align:center}.msgbox_icon{padding-right:0;padding-left:0;justify-content:center}}\n"], dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: MsgboxComponent, decorators: [{ type: Component, args: [{ selector: 'universis-msgbox', template: "<div class=\"card\">\n <div class=\"msgbox_main-container\">\n <div class=\"msgbox_icon\">\n <span class=\"fa-4x far {{icon}}\" style=\"color:#678898;\"></span>\n </div>\n <div class=\"msgbox_details\">\n <div *ngIf=\"title && !title.includes('title')\" class=\"msgbox_title\" id=\"title\">{{title}}</div>\n <div class=\"font pt-3 msgbox_item\" id=\"message\">{{message}}</div>\n <div class=\"pt-3 msgbox_item\" *ngIf=\"extraMessage && !extraMessage.includes('extraMessage')\">{{extraMessage}}</div>\n <div>\n <div class=\"pt-3 msgbox_item\" *ngIf=\"actionButton && !actionButton.includes('actionButton')\">\n <button type=\"button\" class=\"btn s--btn\" [ngClass]=\"buttonClass\" [disabled]=\"disableBut\" (click)=\"clicked()\">{{actionButton}}</button>\n </div>\n <div class=\"pt-3 msgbox_item\" *ngIf=\"actionText && !actionText.includes('actionText')\" id=\"text\">\n <span><span class=\"fa-1x icon-arrow-right\"></span>{{actionText}}</span>\n </div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".msgbox_main-container{display:flex;margin:30px 40px}.msgbox_title{text-transform:uppercase;color:#536c79}.msgbox_details{display:flex;flex-direction:column;justify-content:center}.msgbox_icon{padding-right:60px;padding-left:20px;display:flex;align-items:center}.msgbox_item{display:flex}@media screen and (max-width: 600px){.msgbox_main-container{flex-direction:column;align-items:center}.msgbox_title{text-align:center;justify-content:center;padding:1rem 5px 0}.msgbox_item{justify-content:center;text-align:center}.msgbox_icon{padding-right:0;padding-left:0;justify-content:center}}\n"] }] }], propDecorators: { title: [{ type: Input }], icon: [{ type: Input }], info: [{ type: Input }], message: [{ type: Input }], extraMessage: [{ type: Input }], actionButton: [{ type: Input }], actionText: [{ type: Input }], disableBut: [{ type: Input }], buttonClass: [{ type: Input }], action: [{ type: Output }] } }); /** * * A native spinner component * @export * @class SpinnerComponent * @implements {OnInit} */ class SpinnerComponent { constructor() { } ngOnInit() { // } } SpinnerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); SpinnerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: SpinnerComponent, selector: "universis-spinner", ngImport: i0, template: ` <div class="s--spinner"> <div class="sk-three-bounce"> <div class="sk-child sk-bounce1"></div> <div class="sk-child sk-bounce2"></div> <div class="sk-child sk-bounce3"></div> </div> </div> `, isInline: true, styles: ["@import\"spinkit/css/spinners/7-three-bounce.css\";.s--spinner{position:fixed;width:100%;height:100%;top:0;background-color:#7f7f7f80;z-index:10000;display:flex!important;justify-content:center!important;align-items:center!important}@media screen and (-ms-high-contrast: active),(-ms-high-contrast: none){.s--spinner .sk-three-bounce{display:table-cell}}.sk-three-bounce{margin:40px auto;width:80px;text-align:center}.sk-three-bounce .sk-child{width:20px;height:20px;background-color:#333;border-radius:100%;display:inline-block;animation:sk-three-bounce 1.4s ease-in-out 0s infinite both}.sk-three-bounce .sk-bounce1{animation-delay:-.32s}.sk-three-bounce .sk-bounce2{animation-delay:-.16s}@keyframes sk-three-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}\n"] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SpinnerComponent, decorators: [{ type: Component, args: [{ selector: 'universis-spinner', template: ` <div class="s--spinner"> <div class="sk-three-bounce"> <div class="sk-child sk-bounce1"></div> <div class="sk-child sk-bounce2"></div> <div class="sk-child sk-bounce3"></div> </div> </div> `, styles: ["@import\"spinkit/css/spinners/7-three-bounce.css\";.s--spinner{position:fixed;width:100%;height:100%;top:0;background-color:#7f7f7f80;z-index:10000;display:flex!important;justify-content:center!important;align-items:center!important}@media screen and (-ms-high-contrast: active),(-ms-high-contrast: none){.s--spinner .sk-three-bounce{display:table-cell}}.sk-three-bounce{margin:40px auto;width:80px;text-align:center}.sk-three-bounce .sk-child{width:20px;height:20px;background-color:#333;border-radius:100%;display:inline-block;animation:sk-three-bounce 1.4s ease-in-out 0s infinite both}.sk-three-bounce .sk-bounce1{animation-delay:-.32s}.sk-three-bounce .sk-bounce2{animation-delay:-.16s}@keyframes sk-three-bounce{0%,80%,to{transform:scale(0)}40%{transform:scale(1)}}\n"] }] }], ctorParameters: function () { return []; } }); const Toast = _Toast.default || _Toast; /** * * A native spinner component * @export * @class SpinnerComponent * @implements {OnInit} */ class ToastComponent { constructor(_element) { this._element = _element; this.autoHide = true; this.delay = 5000; this.dateCreated = new Date(); } ngOnInit() { } ngAfterViewInit() { this.toast = new Toast(this._element.nativeElement, { animation: false, autohide: this.autoHide, delay: this.delay }); return this.toast.show(); } show() { if (this.toast) { this.toast.show(); } } hide() { const container = document.body.getElementsByClassName('universis-toast-container')[0]; if (container.getElementsByClassName('show').length === 1) { container.classList.add('hidden'); } if (this.toast) { this.toast.hide(); } } } ToastComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToastComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); ToastComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "15.2.10", type: ToastComponent, selector: "universis-toast.toast", inputs: { title: "title", message: "message", autoHide: "autoHide", delay: "delay" }, ngImport: i0, template: ` <div class="toast-header d-flex p-0"> <strong class="mr-auto">{{ title }}</strong> <button type="button" class="ml-2 mb-1 align-self-start close" data-dismiss="toast" (click)="hide();" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="toast-body p-0"> <div class="toast-body-content" [innerHTML]="message"></div> </div> <div class="toast-header p-0"> <small class="toast-date">{{ dateCreated | date: 'shortTime'}}</small> </div> `, isInline: true, styles: [":host{z-index:auto}\n"], dependencies: [{ kind: "pipe", type: i4.DatePipe, name: "date" }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToastComponent, decorators: [{ type: Component, args: [{ selector: 'universis-toast.toast', template: ` <div class="toast-header d-flex p-0"> <strong class="mr-auto">{{ title }}</strong> <button type="button" class="ml-2 mb-1 align-self-start close" data-dismiss="toast" (click)="hide();" aria-label="Close"> <span aria-hidden="true">&times;</span> </button> </div> <div class="toast-body p-0"> <div class="toast-body-content" [innerHTML]="message"></div> </div> <div class="toast-header p-0"> <small class="toast-date">{{ dateCreated | date: 'shortTime'}}</small> </div> `, styles: [":host{z-index:auto}\n"] }] }], ctorParameters: function () { return [{ type: i0.ElementRef }]; }, propDecorators: { title: [{ type: Input }], message: [{ type: Input }], autoHide: [{ type: Input }], delay: [{ type: Input }] } }); /** * @export * @class ToastService */ class ToastService { constructor(componentFactoryResolver, appRef, injector) { this.componentFactoryResolver = componentFactoryResolver; this.appRef = appRef; this.injector = injector; } /** * Shows a toast message * @param {string} title A string which represents message title * @param {string} message A string which represents message body * @param {boolean=} autoHide A boolean which indicates whether a message will auto hide or not * @param {number=} delay A number which indicates the number of milliseconds before auto hide message */ show(title, message, autoHide = true, delay = 5000) { // search for toast container let container = document.body.getElementsByClassName('universis-toast-container')[0]; if (container == null) { // create toast container container = document.createElement('div'); container.classList.add('universis-toast-container', 'p-3'); // append to boyd document.body.appendChild(container); } // create a component reference for toast component const componentRef = this.componentFactoryResolver .resolveComponentFactory(ToastComponent) .create(this.injector); componentRef.instance.title = title; componentRef.instance.message = message; componentRef.instance.autoHide = autoHide; componentRef.instance.delay = delay; componentRef.location.nativeElement.classList.add('show'); // attach component to the appRef so that it's inside the ng component tree this.appRef.attachView(componentRef.hostView); // get DOM element from component const domElem = componentRef.hostView.rootNodes[0]; // append DOM element to the body container.appendChild(domElem); container.classList.remove('hidden'); setTimeout(() => { componentRef.instance.hide(); }, delay); } // noinspection JSMethodCanBeStatic /** * Clears toast messages */ clear() { // search for toast container const container = document.body.getElementsByClassName('universis-toast-container')[0]; if (container) { // remove children while (container.firstChild) { container.removeChild(container.firstChild); } } } } ToastService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToastService, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.ApplicationRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); ToastService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToastService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: ToastService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.ApplicationRef }, { type: i0.Injector }]; } }); function round(x, n) { if (typeof x !== 'number') { return 0; } if (n) { return parseFloat(x.toFixed(n)); } return Math.round(x); } class GradeScale { constructor(_locale, scale = null) { this._locale = _locale; this.scale = scale; this.formatPrecision = 2; this.scalePrecision = 2; // init decimal pipe this._formatter = new DecimalPipe(this._locale); // get decimal separator regular expression // @ts-ignore this._decimalCharRegExp = new RegExp('\\' + this._formatter.transform(0.1, '1.1-1').substr(1, 1), 'ig'); if (scale) { this.id = scale['id']; this.name = scale['name']; this.scaleType = scale['scaleType']; this.scaleFactor = scale['scaleFactor']; this.scaleBase = scale['scaleBase']; this.formatPrecision = scale['formatPrecision']; this.scalePrecision = scale['scalePrecision']; this.values = scale['values']; } } /** * Formats the specified based on this grade scale and returns the formatted value * @param {number} grade * @returns string */ format(grade) { if (this.scaleType === 0) { if (typeof this.scaleFactor !== 'number') { throw new TypeError('Grade scale factor must be a number.'); } if (this.scaleFactor <= 0) { throw new TypeError('Grade scale factor must greater than zero.'); } // arithmetic grade scale if (typeof grade === 'number') { // get final grade by applying rounding const finalGrade = round((grade / this.scaleFactor), this.formatPrecision); // return formatted value based on the current locale const result = this._formatter.transform(finalGrade, `1.${this.formatPrecision}-${this.formatPrecision}`); if (result != null) { return result; } } return ''; } else if (this.scaleType === 1 || this.scaleType === 3) { let finalValue = round(grade, this.scalePrecision); if (this.values != null) { let findValue = this.values.find(x => { return finalValue >= x.valueFrom && finalValue <= x.valueTo; }); if (findValue) { return findValue.name; } } throw new RangeError('Out of range value for grade'); } throw new Error('Not yet implemented'); } /** * Converts the given grade to the equivalent grade value base on this grade scale * @param grade */ convert(grade) { if (this.scaleType === 0) { let finalGrade; // if grade is a number if (typeof grade === 'undefined' || grade === null) { return; } else if (typeof grade === 'number') { finalGrade = grade; } else if (typeof grade === 'string') { // try to convert the given grade finalGrade = parseFloat(grade.replace(this._decimalCharRegExp, '.')); if (isNaN(finalGrade)) { return; } } if (typeof this.scaleFactor !== 'number') { throw new TypeError('Grade scale factor must be a number.'); } if (this.scaleFactor <= 0) { throw new TypeError('Grade scale factor must greater than zero.'); } // validate grade const res = round((finalGrade * this.scaleFactor), this.formatPrecision + 1); // throw error if result is greater than 1 if (res < 0 || res > 1) { throw new Error('Grade is out of range. It must be between 0 to 1.'); } return res; } else if (this.scaleType === 1 || this.scaleType === 3) { if (this.values) { let findValue = this.values.find(x => { return x.name === grade || x.alternateName === grade; }); if (findValue) { return findValue.exactValue; } } throw new RangeError('Out of range value for grade'); } throw new Error('Not yet implemented'); } } class GradeScaleService { constructor(_context, _configurationService) { this._context = _context; this._configurationService = _configurationService; // } /** * Gets all the available grade scales */ getGradeScales() { if (this._gradeScales) { return Promise.resolve(this._gradeScales); } return this._context.model('GradeScales').getItems().then(result => { const locale = this._configurationService.currentLocale; this._gradeScales = result.map(x => { return Object.assign(new GradeScale(locale), x); }); return Promise.resolve(this._gradeScales); }, (err) => { console.log(err); return null; }); } /** * Gets a grade scale based on the given identifier * @param {*} id */ getGradeScale(id) { if (this._gradeScales) { return Promise.resolve(this._gradeScales.find(value => { return value.id === id; })); } return this.getGradeScales().then(res => { if (res == null) { return; } return Promise.resolve(res.find(value => { return value.id === id; })); }); } } GradeScaleService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GradeScaleService, deps: [{ token: i1$1.AngularDataContext }, { token: ConfigurationService }], target: i0.ɵɵFactoryTarget.Injectable }); GradeScaleService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GradeScaleService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GradeScaleService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i1$1.AngularDataContext }, { type: ConfigurationService }]; } }); class GradePipe { constructor(_gradeScaleService) { this._gradeScaleService = _gradeScaleService; // } transform(value, gradeScale) { if (gradeScale instanceof GradeScale) { return Promise.resolve(gradeScale.format(value)); } return this._gradeScaleService.getGradeScale(gradeScale).then(result => { if (typeof result === 'undefined') { return Promise.reject(new Error('The specified grade scale cannot be found or is inaccessible')); } return Promise.resolve(result.format(value)); }); } } GradePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GradePipe, deps: [{ token: GradeScaleService }], target: i0.ɵɵFactoryTarget.Pipe }); GradePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: GradePipe, name: "grade" }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: GradePipe, decorators: [{ type: Pipe, args: [{ name: 'grade' }] }], ctorParameters: function () { return [{ type: GradeScaleService }]; } }); /** * * Displays Loading Spinner * @export * @class LoadingService */ class LoadingService { constructor(componentFactoryResolver, appRef, injector) { this.componentFactoryResolver = componentFactoryResolver; this.appRef = appRef; this.injector = injector; this.componentRef = null; } appendComponentToBody(component) { // do nothing if component ref already exists if (this.componentRef) { return; } // create a component reference from the component this.componentRef = this.componentFactoryResolver .resolveComponentFactory(component) .create(this.injector); // attach component to the appRef so that it's inside the ng component tree this.appRef.attachView(this.componentRef.hostView); // get DOM element from component const domElem = this.componentRef.hostView .rootNodes[0]; // append DOM element to the body document.body.appendChild(domElem); } /** * * Toggles show/hide state of spinner */ toggle() { if (this.componentRef) { this.hideLoading(); } else { this.showLoading(); } } /** * * Shows spinner */ showLoading() { if (this.componentRef == null) { this.appendComponentToBody(SpinnerComponent); } } /** * * Hides spinner */ hideLoading() { if (this.componentRef) { this.appRef.detachView(this.componentRef.hostView); this.componentRef.destroy(); this.componentRef = null; } } } LoadingService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: LoadingService, deps: [{ token: i0.ComponentFactoryResolver }, { token: i0.ApplicationRef }, { token: i0.Injector }], target: i0.ɵɵFactoryTarget.Injectable }); LoadingService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: LoadingService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: LoadingService, decorators: [{ type: Injectable }], ctorParameters: function () { return [{ type: i0.ComponentFactoryResolver }, { type: i0.ApplicationRef }, { type: i0.Injector }]; } }); /** * * Custom DatePipe representation * @export * @class LocalizedDatePipe * @implements {PipeTransform} */ class LocalizedDatePipe { constructor(translateService) { this.translateService = translateService; } /** * * Converts Date value that been passed * @param {*} value The Date that needs to be converted * @param {string} [pattern='mediumDate'] Pattern of Date * @returns {*} Converted Date * @memberof LocalizedDatePipe */ transform(value, pattern = 'mediumDate') { const datePipe = new DatePipe(this.translateService.currentLang); if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\+\d{2}$/.test(value)) { return datePipe.transform(new Date(value + ':00'), pattern); } return datePipe.transform(value, pattern); } } LocalizedDatePipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: LocalizedDatePipe, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); LocalizedDatePipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: LocalizedDatePipe, name: "localizedDate", pure: false }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: LocalizedDatePipe, decorators: [{ type: Pipe, args: [{ name: 'localizedDate', pure: false }] }], ctorParameters: function () { return [{ type: i1.TranslateService }]; } }); async function registration(_numeral) { await _numeral.register('locale', 'el', { delimiters: { thousands: '.', decimal: ',' }, abbreviations: { thousand: 'χιλ', million: 'εκ', billion: 'δισ', trillion: 'τρισ' }, ordinal: function (number) { return 'ο'; }, currency: { symbol: '€' } }); await _numeral.register('locale', 'el-gr', { delimiters: { thousands: '.', decimal: ',' }, abbreviations: { thousand: 'χιλ', million: 'εκ', billion: 'δισ', trillion: 'τρισ' }, ordinal: function (number) { return 'ο'; }, currency: { symbol: '€' } }); await _numeral.register('locale', 'cy', { delimiters: { thousands: '.', decimal: ',' }, abbreviations: { thousand: 'χιλ', million: 'εκ', billion: 'δισ', trillion: 'τρισ' }, ordinal: function (number) { return 'ο'; }, currency: { symbol: '€' } }); await _numeral.register('locale', 'cy-cy', { delimiters: { thousands: '.', decimal: ',' }, abbreviations: { thousand: 'χιλ', million: 'εκ', billion: 'δισ', trillion: 'τρισ' }, ordinal: function (number) { return 'ο'; }, currency: { symbol: '€' } }); } const numeral = _numeral.default || _numeral; class SemesterPipe { constructor(_translateService) { this._translateService = _translateService; const numeralWithLocales = numeral; if (numeralWithLocales.locales['el'] == null) { registration(numeral).then(async () => { await Promise.resolve(); }); } } transform(value, pattern = 'long') { if (typeof value === 'object') { value = value.id; } if (value >= 250) { return this._translateService.instant(`Semester.full.${value}`); } numeral.locale(this._translateService.currentLang); return this._translateService.instant(`Semester.${pattern}`, { value: value, ordinal: numeral(value).format('o') }); } } SemesterPipe.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SemesterPipe, deps: [{ token: i1.TranslateService }], target: i0.ɵɵFactoryTarget.Pipe }); SemesterPipe.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "15.2.10", ngImport: i0, type: SemesterPipe, name: "semester", pure: false }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "15.2.10", ngImport: i0, type: SemesterPipe, decorators: [{ type: Pipe, args: [{ name: 'semester', pure: false }] }], ctorParameters: function () { return [{ type: i1.TranslateService }]; } }); /** * Template Pipe is an impure pipe that can escape * HTML and inter