@sumaris-net/ngx-components 2.0.0-rc30 → 2.0.0-rc32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -66,10 +66,11 @@ import { Capacitor } from '@capacitor/core';
66
66
  import { Keyboard } from '@capacitor/keyboard';
67
67
  import * as i1$1 from '@ngx-translate/core';
68
68
  import { TranslateModule, TranslateService } from '@ngx-translate/core';
69
- import * as momentNamespace from 'moment';
69
+ import * as momentImported from 'moment';
70
70
  import { isMoment, locale } from 'moment';
71
71
  import * as i1 from '@angular/material-moment-adapter';
72
72
  import { MatMomentDateModule } from '@angular/material-moment-adapter';
73
+ import 'moment-timezone';
73
74
  import * as i11$1 from 'angular2-text-mask';
74
75
  import { TextMaskModule } from 'angular2-text-mask';
75
76
  import * as i10$1 from '@angular/material/datepicker';
@@ -91,7 +92,7 @@ import { Haptics } from '@capacitor/haptics';
91
92
  import { NativeAudio } from '@capacitor-community/native-audio';
92
93
  import * as i1$4 from '@angular/platform-browser';
93
94
  import { HammerGestureConfig, HammerModule } from '@angular/platform-browser';
94
- import * as uuidv4Imported from 'uuid/v4';
95
+ import { v4 } from 'uuid';
95
96
  import { DragDropModule } from '@angular/cdk/drag-drop';
96
97
  import * as i6$4 from 'ngx-markdown';
97
98
  import { MarkdownModule } from 'ngx-markdown';
@@ -107,6 +108,8 @@ import { Browser } from '@capacitor/browser';
107
108
  import * as i2$7 from '@angular/cdk/platform';
108
109
  import * as i3 from '@ionic/storage-angular';
109
110
  import { IonicStorageModule } from '@ionic/storage-angular';
111
+ import * as i4 from '@angular/cdk/text-field';
112
+ import { CdkTextareaAutosize } from '@angular/cdk/text-field';
110
113
  import * as i7$2 from '@awesome-cordova-plugins/network/ngx';
111
114
  import { Connection } from '@awesome-cordova-plugins/network/ngx';
112
115
  import { scryptEncode } from '@polkadot/util-crypto/scrypt/encode';
@@ -137,9 +140,6 @@ import { isDataSource, SelectionModel } from '@angular/cdk/collections';
137
140
  import { Camera, CameraResultType } from '@capacitor/camera';
138
141
  import * as i3$2 from '@e-is/ngx-material-table';
139
142
  import { ValidatorService, TableDataSource } from '@e-is/ngx-material-table';
140
- import * as i4 from '@angular/cdk/text-field';
141
- import { CdkTextareaAutosize } from '@angular/cdk/text-field';
142
- import 'moment-timezone';
143
143
 
144
144
  const ENVIRONMENT = new InjectionToken('ENV');
145
145
  class Environment {
@@ -2543,29 +2543,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
2543
2543
  type: Input
2544
2544
  }] } });
2545
2545
 
2546
+ function isESModule(value) {
2547
+ return value && value['__esModule'] === true;
2548
+ }
2549
+ function unwrapESModule(value) {
2550
+ return isESModule(value) ? value.default : value;
2551
+ }
2552
+ function requireCommonJS(moduleName) {
2553
+ const module = require(moduleName);
2554
+ return unwrapESModule(module);
2555
+ }
2556
+
2546
2557
  const DATE_UNIX_TIMESTAMP = 'X';
2547
2558
  const DATE_UNIX_MS_TIMESTAMP = 'x';
2548
2559
  const MOMENT_NO_TIME_PROPERTY = '_hasNoTime';
2560
+ const moment$1 = unwrapESModule(momentImported);
2549
2561
  class DateUtils {
2550
- static isEsModule(value) {
2551
- return value && value['__esModule'] === true;
2552
- }
2553
- static set moment(value) {
2554
- this.__moment = value;
2555
- }
2556
- static get moment() {
2557
- // Resolve moment, if was wrapped into a ES module
2558
- if (!this.__moment) {
2559
- console.log('Resolving moment...');
2560
- if (this.isEsModule(momentNamespace)) {
2561
- this.__moment = momentNamespace.default;
2562
- }
2563
- if (typeof momentNamespace['isMoment'] === 'function') {
2564
- this.__moment = momentNamespace;
2565
- }
2566
- }
2567
- return this.__moment;
2568
- }
2569
2562
  static min(date1, date2) {
2570
2563
  return date1 && (!date2 || date1.isSameOrBefore(date2)) ? date1 : date2;
2571
2564
  }
@@ -2624,6 +2617,7 @@ class DateUtils {
2624
2617
  return momentDate.day() === weekday;
2625
2618
  }
2626
2619
  }
2620
+ DateUtils.moment = moment$1;
2627
2621
  DateUtils.toDateISOString = toDateISOString;
2628
2622
  DateUtils.fromDateISOString = fromDateISOString;
2629
2623
  DateUtils.toDuration = toDuration;
@@ -2691,7 +2685,6 @@ function toDuration(value, unit) {
2691
2685
  }
2692
2686
  return duration;
2693
2687
  }
2694
- const moment$1 = DateUtils.moment;
2695
2688
 
2696
2689
  class DateDiffDurationPipe {
2697
2690
  constructor(dateAdapter, translate) {
@@ -10542,7 +10535,6 @@ class ImagesUtils {
10542
10535
  }
10543
10536
  }
10544
10537
 
10545
- const uuidv4$1 = uuidv4Imported;
10546
10538
  class FileService {
10547
10539
  constructor(platform,
10548
10540
  //private transfer: FileTransfer,
@@ -10579,7 +10571,7 @@ class FileService {
10579
10571
  const lastSlashIndex = fileUrl.lastIndexOf('/');
10580
10572
  if (lastSlashIndex === -1)
10581
10573
  throw new Error('Invalid URL: ' + fileUrl);
10582
- const fileName = lastSlashIndex < (fileUrl.length - 1) && fileUrl.substring(lastSlashIndex + 1) || uuidv4$1();
10574
+ const fileName = lastSlashIndex < (fileUrl.length - 1) && fileUrl.substring(lastSlashIndex + 1) || v4();
10583
10575
  // Download into the file system
10584
10576
  if (outputType === 'fileUrl' && this.canUseFileSystem) {
10585
10577
  console.warn(`WARN: [file] Downloading image {${fileUrl}} in local filesystem...`);
@@ -13655,396 +13647,971 @@ function getNodeInfo(http, peer, opts) {
13655
13647
  });
13656
13648
  }
13657
13649
 
13658
- class SelectPeerModal {
13659
- constructor(modalCtrl, cd, http, environment) {
13660
- this.modalCtrl = modalCtrl;
13661
- this.cd = cd;
13662
- this.http = http;
13663
- this.environment = environment;
13664
- this._subscription = new Subscription();
13665
- this.loading = true;
13666
- this.$peers = new Subject();
13667
- this.peerMinVersion = this.environment.peerMinVersion;
13668
- this.canCancel = true;
13669
- this.allowSelectDownPeer = true;
13670
- this.onRefresh = new EventEmitter();
13671
- }
13672
- set peers(peers) {
13673
- this._subscription.add(peers.subscribe(res => this.refreshPeers(res)));
13674
- }
13675
- cancel() {
13676
- this.modalCtrl.dismiss();
13650
+ class MatAutocompleteConfigHolder {
13651
+ constructor(options) {
13652
+ this.options = options;
13653
+ this.fields = {};
13654
+ // Store the function from options (e.g. get from user settings)
13655
+ // or create a default function
13656
+ this.getUserAttributes = (options === null || options === void 0 ? void 0 : options.getUserAttributes) ||
13657
+ ((fieldName, defaultAttributes) => defaultAttributes || ['label', 'name']);
13677
13658
  }
13678
- ngOnDestroy() {
13679
- this._subscription.unsubscribe();
13659
+ add(fieldName, options) {
13660
+ if (!fieldName) {
13661
+ throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
13662
+ }
13663
+ options = options || {};
13664
+ const suggestFn = options.suggestFn
13665
+ || (options.service && ((v, f) => options.service.suggest(v, f)))
13666
+ || undefined;
13667
+ const attributes = (this.getUserAttributes(fieldName, options.attributes) || ['label', 'name']);
13668
+ // Keep original the function from options, when exists
13669
+ const attributesOrFn = attributes.map((a, index) => typeof a === 'function' && options.attributes[index] || a);
13670
+ const filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
13671
+ const displayWith = options.displayWith || MatAutocompleteFieldUtils.createDisplayFn(attributes, options.multiple);
13672
+ const equals = options.equals || MatAutocompleteFieldUtils.defaultEquals;
13673
+ const config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn,
13674
+ filter,
13675
+ displayWith,
13676
+ equals });
13677
+ this.fields[fieldName] = config;
13678
+ return config;
13680
13679
  }
13681
- selectPeer(peer) {
13682
- if (this.allowSelectDownPeer || (peer.reachable && this.isCompatible(peer))) {
13683
- console.debug(`[select-peer-modal] Selected peer: {url: '${peer.url}'}`);
13684
- this.modalCtrl.dismiss(peer);
13680
+ get(fieldName) {
13681
+ if (!fieldName) {
13682
+ throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
13685
13683
  }
13684
+ return this.fields[fieldName] || this.add(fieldName);
13685
+ }
13686
+ }
13687
+
13688
+ // eslint-disable-next-line @angular-eslint/directive-class-suffix
13689
+ class AppForm {
13690
+ constructor(injector, form) {
13691
+ this._subscription = new Subscription();
13692
+ this._enable = false;
13693
+ this.i18nFieldPrefix = null;
13694
+ this.destroySubject = new Subject();
13695
+ this.readySubject = new BehaviorSubject(false);
13696
+ this.loadingSubject = new BehaviorSubject(true);
13697
+ this.errorSubject = new BehaviorSubject(undefined);
13698
+ this.debug = false;
13699
+ this.onCancel = new EventEmitter();
13700
+ this.onSubmit = new EventEmitter();
13701
+ if (form)
13702
+ this.setForm(form);
13703
+ this.translate = injector.get(TranslateService);
13704
+ this.settings = injector.get(LocalSettingsService);
13705
+ this.errorTranslator = injector.get(FormErrorTranslator);
13706
+ this.autocompleteHelper = new MatAutocompleteConfigHolder(this.settings && {
13707
+ getUserAttributes: (a, b) => this.settings.getFieldDisplayAttributes(a, b)
13708
+ });
13709
+ this.autocompleteFields = this.autocompleteHelper.fields;
13686
13710
  }
13687
13711
  /**
13688
- * Check the min pod version, defined by the app
13689
- *
13690
- * @param peer
13712
+ * @deprecated
13691
13713
  */
13692
- isCompatible(peer) {
13693
- return !this.peerMinVersion || (peer && peer.softwareVersion && VersionUtils.isCompatible(this.peerMinVersion, peer.softwareVersion));
13694
- }
13695
- refresh(event) {
13696
- this.loading = true;
13697
- this.onRefresh.emit(event);
13714
+ set _loading(value) {
13715
+ this.loadingSubject.next(value);
13698
13716
  }
13699
- /* -- protected methods -- */
13700
- refreshPeers(peers) {
13701
- return __awaiter(this, void 0, void 0, function* () {
13702
- peers = peers || [];
13703
- const data = [];
13704
- const jobs = Promise.all(peers.map((peer) => __awaiter(this, void 0, void 0, function* () {
13705
- yield this.refreshPeer(peer);
13706
- if (this._subscription.closed)
13707
- return; // component destroyed
13708
- data.push(peer);
13709
- // Sort (by reachable, then host)
13710
- data.sort((a, b) => {
13711
- if (a.reachable && !b.reachable)
13712
- return -1;
13713
- if (!a.reachable && b.reachable)
13714
- return 1;
13715
- if (a.hostAndPort < b.hostAndPort)
13716
- return -1;
13717
- if (a.hostAndPort > b.hostAndPort)
13718
- return 1;
13719
- return 0;
13720
- });
13721
- this.$peers.next(data);
13722
- return peer;
13723
- })));
13724
- this._subscription.add(this.$peers
13725
- .subscribe(() => this.cd.markForCheck()));
13726
- try {
13727
- yield jobs;
13728
- }
13729
- catch (err) {
13730
- if (!this._subscription.closed)
13731
- console.error(err);
13732
- }
13733
- this.loading = false;
13734
- this.cd.markForCheck();
13735
- });
13717
+ /**
13718
+ * @deprecated
13719
+ */
13720
+ get _loading() {
13721
+ return this.loadingSubject.value;
13736
13722
  }
13737
- refreshPeer(peer) {
13738
- return __awaiter(this, void 0, void 0, function* () {
13739
- try {
13740
- const summary = yield NetworkUtils.getNodeInfo(this.http, peer.url);
13741
- peer.status = 'UP';
13742
- peer.softwareName = summary.softwareName;
13743
- peer.softwareVersion = summary.softwareVersion;
13744
- peer.label = summary.nodeLabel;
13745
- peer.name = summary.nodeName;
13746
- }
13747
- catch (err) {
13748
- if (!this._subscription.closed) {
13749
- if (err && err.message) {
13750
- console.error('[select-peer] ' + err.message, err);
13751
- }
13752
- }
13753
- peer.status = 'DOWN';
13754
- }
13755
- return peer;
13756
- });
13723
+ /**
13724
+ * @deprecated
13725
+ */
13726
+ get _$ready() {
13727
+ return this.readySubject;
13757
13728
  }
13758
- markForCheck() {
13759
- this.cd.markForCheck();
13729
+ /**
13730
+ * @deprecated
13731
+ */
13732
+ get _$loading() {
13733
+ return this.loadingSubject;
13760
13734
  }
13761
- }
13762
- SelectPeerModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SelectPeerModal, deps: [{ token: i2.ModalController }, { token: i0.ChangeDetectorRef }, { token: i2$5.HttpClient }, { token: ENVIRONMENT }], target: i0.ɵɵFactoryTarget.Component });
13763
- SelectPeerModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: SelectPeerModal, selector: "select-peer-modal", inputs: { canCancel: "canCancel", allowSelectDownPeer: "allowSelectDownPeer", onRefresh: "onRefresh" }, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"cancel()\" *ngIf=\"canCancel\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{'NETWORK.PEER.SELECT_MODAL.TITLE'|translate}}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button *ngIf=\"onRefresh.observers | isNotEmptyArray\"\n [matTooltip]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"refresh($event)\">\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <ion-list>\n\n <ion-list-header>\n <ion-label class=\"ion-text-wrap\">\n <p translate>NETWORK.PEER.SELECT_MODAL.HELP</p>\n </ion-label>\n </ion-list-header>\n\n <ion-item *ngFor=\"let peer of $peers | async\"\n tappable\n (click)=\"selectPeer(peer)\"\n detail\n @fadeInAnimation>\n\n <!-- icon -->\n <ion-avatar slot=\"start\" *ngIf=\"peer.reachable\" >\n <ion-img [src]=\"peer.favicon || (peer.url + '/api/favicon')\"></ion-img>\n </ion-avatar>\n <ion-icon slot=\"start\" *ngIf=\"!peer.reachable\" name=\"desktop\" color=\"medium\" class=\"ion-text-center\"></ion-icon>\n\n <!-- Peer is UP -->\n <ion-grid *ngIf=\"peer.reachable\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"dark\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4>{{peer.label}}</h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap ion-text-center\" color=\"medium\">\n <h3>{{peer.softwareName}}</h3>\n <h4 *ngIf=\"!peerMinVersion || isCompatible(peer); else invalidVersion\">\n <small>v{{peer.softwareVersion}}</small>\n </h4>\n <ng-template #invalidVersion>\n <ion-text color=\"danger\" [matTooltip]=\"'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP'|translate: {version: peerMinVersion} \">\n <h4 class=\"ion-color-danger\">\n <small><mat-icon>warning</mat-icon>v{{peer.softwareVersion}}</small>\n </h4>\n </ion-text>\n </ng-template>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Peer is DOWN -->\n <ion-label class=\"ion-text-wrap\" *ngIf=\"!peer.reachable\">\n <ion-text color=\"medium\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small><ion-icon size=\"small\" name=\"close-circle\"></ion-icon></small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n </ion-item>\n </ion-list>\n\n</ion-content>\n\n\n<ion-footer *ngIf=\"canCancel\" hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n", styles: ["ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i2.IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i2.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i2.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i6$3.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "pipe", type: i2$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }], animations: [fadeInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush });
13764
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SelectPeerModal, decorators: [{
13765
- type: Component,
13766
- args: [{ selector: 'select-peer-modal', changeDetection: ChangeDetectionStrategy.OnPush, animations: [fadeInAnimation], template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"cancel()\" *ngIf=\"canCancel\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{'NETWORK.PEER.SELECT_MODAL.TITLE'|translate}}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button *ngIf=\"onRefresh.observers | isNotEmptyArray\"\n [matTooltip]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"refresh($event)\">\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <ion-list>\n\n <ion-list-header>\n <ion-label class=\"ion-text-wrap\">\n <p translate>NETWORK.PEER.SELECT_MODAL.HELP</p>\n </ion-label>\n </ion-list-header>\n\n <ion-item *ngFor=\"let peer of $peers | async\"\n tappable\n (click)=\"selectPeer(peer)\"\n detail\n @fadeInAnimation>\n\n <!-- icon -->\n <ion-avatar slot=\"start\" *ngIf=\"peer.reachable\" >\n <ion-img [src]=\"peer.favicon || (peer.url + '/api/favicon')\"></ion-img>\n </ion-avatar>\n <ion-icon slot=\"start\" *ngIf=\"!peer.reachable\" name=\"desktop\" color=\"medium\" class=\"ion-text-center\"></ion-icon>\n\n <!-- Peer is UP -->\n <ion-grid *ngIf=\"peer.reachable\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"dark\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4>{{peer.label}}</h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap ion-text-center\" color=\"medium\">\n <h3>{{peer.softwareName}}</h3>\n <h4 *ngIf=\"!peerMinVersion || isCompatible(peer); else invalidVersion\">\n <small>v{{peer.softwareVersion}}</small>\n </h4>\n <ng-template #invalidVersion>\n <ion-text color=\"danger\" [matTooltip]=\"'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP'|translate: {version: peerMinVersion} \">\n <h4 class=\"ion-color-danger\">\n <small><mat-icon>warning</mat-icon>v{{peer.softwareVersion}}</small>\n </h4>\n </ion-text>\n </ng-template>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Peer is DOWN -->\n <ion-label class=\"ion-text-wrap\" *ngIf=\"!peer.reachable\">\n <ion-text color=\"medium\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small><ion-icon size=\"small\" name=\"close-circle\"></ion-icon></small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n </ion-item>\n </ion-list>\n\n</ion-content>\n\n\n<ion-footer *ngIf=\"canCancel\" hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n", styles: ["ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}\n"] }]
13767
- }], ctorParameters: function () {
13768
- return [{ type: i2.ModalController }, { type: i0.ChangeDetectorRef }, { type: i2$5.HttpClient }, { type: undefined, decorators: [{
13769
- type: Inject,
13770
- args: [ENVIRONMENT]
13771
- }] }];
13772
- }, propDecorators: { canCancel: [{
13773
- type: Input
13774
- }], allowSelectDownPeer: [{
13775
- type: Input
13776
- }], onRefresh: [{
13777
- type: Input
13778
- }] } });
13779
-
13780
- /**
13781
- * Same as StartableService, bu with a dataSubject instead of a simple 'data' property
13782
- */
13783
- let StartableObservableService = class StartableObservableService {
13784
- constructor(prerequisiteService) {
13785
- this.dataSubject = new BehaviorSubject(null);
13786
- this.startSubject = new Subject();
13787
- this.stopSubject = new Subject();
13788
- this._debug = false;
13789
- this._startByReadyFunction = true; // should start when calling ready() ?
13790
- this._started = false;
13791
- this._startPromise = null;
13792
- this._startPrerequisite = null;
13793
- this._subscription = null;
13794
- this._startPrerequisite = prerequisiteService
13795
- ? () => prerequisiteService.ready()
13796
- : () => Promise.resolve();
13735
+ get error() {
13736
+ return this.errorSubject.value;
13797
13737
  }
13798
- start(opts) {
13799
- if (this._startPromise)
13800
- return this._startPromise;
13801
- if (this._started)
13802
- return Promise.resolve(this.dataSubject.value);
13803
- this._startPromise = this._startPrerequisite()
13804
- .then(() => this.ngOnStart(opts))
13805
- .then(data => {
13806
- this._started = true;
13807
- this._startPromise = undefined;
13808
- // Should be done AFTER 'this._started = true', because of the 'filter' operator, inside ready() function
13809
- this.dataSubject.next(data);
13810
- this.startSubject.next(data);
13811
- return data;
13812
- })
13813
- .catch(err => {
13814
- if (!this.stopped) {
13815
- console.error('Failed to start a service: ' + (err && err.message || err), err);
13816
- this._started = false;
13817
- this._startPromise = null;
13818
- }
13819
- return null;
13820
- });
13821
- return this._startPromise;
13738
+ set error(error) {
13739
+ this.setError(error);
13822
13740
  }
13823
- ready() {
13824
- if (this._started)
13825
- return Promise.resolve(this.dataSubject.value);
13826
- if (this._startPromise)
13827
- return this._startPromise;
13828
- if (this._startByReadyFunction)
13829
- return this.start();
13830
- return this.dataSubject
13831
- .pipe(takeUntil(this.stopSubject),
13832
- // Wait start() to be called, to exclude the initial 'null' value
13833
- filter(_ => this._started))
13834
- .toPromise();
13741
+ get loading() {
13742
+ return this.loadingSubject.value;
13835
13743
  }
13836
- stop() {
13837
- return __awaiter(this, void 0, void 0, function* () {
13838
- try {
13839
- this.unsubscribe();
13840
- yield this.ngOnStop();
13841
- }
13842
- catch (err) {
13843
- console.error('Failed to stop a service: ' + (err && err.message || err), err);
13844
- }
13845
- finally {
13846
- this._started = false;
13847
- this._startPromise = undefined;
13848
- this.stopSubject.next(); // Stop all running observables
13849
- this.dataSubject.next(null); // Reset data
13850
- }
13851
- });
13744
+ get loaded() {
13745
+ return !this.loadingSubject.value;
13852
13746
  }
13853
- restart(opts) {
13854
- return __awaiter(this, void 0, void 0, function* () {
13855
- if (this._startPromise)
13856
- yield this._startPromise; // Wait end of previous loading
13857
- if (this._started)
13858
- yield this.stop(); // Then stop if started
13859
- return this.start(opts); // Then start again
13860
- });
13747
+ get value() {
13748
+ return this.form.value;
13861
13749
  }
13862
- get started() {
13863
- return this._started;
13750
+ set value(data) {
13751
+ this.setValue(data);
13864
13752
  }
13865
- get starting() {
13866
- return !!this._startPromise;
13753
+ get dirty() {
13754
+ var _a;
13755
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.dirty) || false;
13867
13756
  }
13868
- get stopped() {
13869
- return !this._started && !this._startPromise;
13757
+ get invalid() {
13758
+ return !this.form || this.form.invalid;
13870
13759
  }
13871
- get data() {
13872
- return this.dataSubject.value;
13760
+ get pending() {
13761
+ return !this.form || (this.form.dirty && this.form.pending);
13873
13762
  }
13874
- set data(value) {
13875
- if (this.dataSubject.value !== value) {
13876
- this.dataSubject.next(value);
13877
- }
13763
+ get valid() {
13764
+ var _a;
13765
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
13878
13766
  }
13879
- registerSubscription(sub) {
13880
- this._subscription = this._subscription || new Subscription();
13881
- this._subscription.add(sub);
13767
+ get empty() {
13768
+ return !this.form || (!this.form.dirty && !this.form.touched);
13882
13769
  }
13883
- unregisterSubscription(sub) {
13770
+ get touched() {
13884
13771
  var _a;
13885
- (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.remove(sub);
13772
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.touched) || false;
13886
13773
  }
13887
- unsubscribe() {
13888
- var _a;
13889
- (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
13890
- this._subscription = null;
13774
+ get untouched() {
13775
+ return !this.form || this.form.untouched;
13891
13776
  }
13892
- ngOnStop() {
13893
- // Can be overwritten by subclasses
13777
+ get enabled() {
13778
+ return this._enable;
13894
13779
  }
13895
- };
13896
- StartableObservableService = __decorate([
13897
- __param(0, Optional())
13898
- ], StartableObservableService);
13899
-
13900
- // Base58 encoding/decoding
13901
- // Originally written by Mike Hearn for BitcoinJ
13902
- // Copyright (c) 2011 Google Inc
13903
- // Ported to JavaScript by Stefan Thomas
13904
- // Merged Buffer refactorings from base58-native by Stephen Pair
13905
- // Copyright (c) 2013 BitPay Inc
13906
- // Rewritten in TypeScript by Ludovic Pecquot
13907
- // @dynamic
13908
- class Base58 {
13909
- static getAlphabetMap() {
13910
- if (!Base58.alphabetMap) {
13911
- this.alphabetMap = {};
13912
- for (let i = 0; i < Base58.alphabet.length; i++) {
13913
- Base58.alphabetMap[Base58.alphabet.charAt(i)] = i;
13914
- }
13915
- }
13916
- return Base58.alphabetMap;
13780
+ get disabled() {
13781
+ return !this._enable;
13917
13782
  }
13918
- static encode(buffer) {
13919
- if (buffer.length === 0)
13920
- return '';
13921
- let i;
13922
- let j;
13923
- const digits = [0];
13924
- for (i = 0; i < buffer.length; i++) {
13925
- for (j = 0; j < digits.length; j++)
13926
- digits[j] <<= 8;
13927
- digits[digits.length - 1] += buffer[i];
13928
- let carry = 0;
13929
- for (j = digits.length - 1; j >= 0; j--) {
13930
- digits[j] += carry;
13931
- carry = (digits[j] / 58) | 0;
13932
- digits[j] %= 58;
13933
- }
13934
- while (carry) {
13935
- digits.unshift(carry);
13936
- carry = (digits[0] / 58) | 0;
13937
- digits[0] %= 58;
13938
- }
13783
+ disable(opts) {
13784
+ var _a;
13785
+ (_a = this.form) === null || _a === void 0 ? void 0 : _a.disable(opts);
13786
+ if (this._enable) {
13787
+ this._enable = false;
13788
+ if (!opts || opts.emitEvent !== true)
13789
+ this.markForCheck();
13939
13790
  }
13940
- // deal with leading zeros
13941
- for (i = 0; i < buffer.length - 1 && buffer[i] === 0; i++)
13942
- digits.unshift(0);
13943
- return digits.map(function (digit) { return Base58.alphabet[digit]; }).join('');
13944
13791
  }
13945
- static decode(string) {
13946
- if (string.length === 0)
13947
- return (new Uint8Array(0));
13948
- const input = string.split('').map(function (c) {
13949
- return Base58.getAlphabetMap()[c];
13950
- });
13951
- let i;
13952
- let j;
13953
- const bytes = [0];
13954
- for (i = 0; i < input.length; i++) {
13955
- for (j = 0; j < bytes.length; j++)
13956
- bytes[j] *= 58;
13957
- bytes[bytes.length - 1] += input[i];
13958
- let carry = 0;
13959
- for (j = bytes.length - 1; j >= 0; j--) {
13960
- bytes[j] += carry;
13961
- carry = bytes[j] >> 8;
13962
- bytes[j] &= 0xff;
13963
- }
13964
- while (carry) {
13965
- bytes.unshift(carry);
13966
- carry = bytes[0] >> 8;
13967
- bytes[0] &= 0xff;
13968
- }
13792
+ enable(opts) {
13793
+ var _a;
13794
+ (_a = this.form) === null || _a === void 0 ? void 0 : _a.enable(opts);
13795
+ if (!this._enable) {
13796
+ this._enable = true;
13797
+ if (!opts || opts.emitEvent !== true)
13798
+ this.markForCheck();
13969
13799
  }
13970
- // deal with leading zeros
13971
- for (i = 0; i < input.length - 1 && input[i] === 0; i++)
13972
- bytes.unshift(0);
13973
- return (new Uint8Array(bytes));
13974
13800
  }
13975
- }
13976
- Base58.alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
13977
-
13978
- const ED25519_SEED_LENGTH = 32; // Length of a ED25519 seed
13979
- const SCRYPT_PARAMS = {
13980
- SIMPLE: {
13981
- N: 2048,
13982
- r: 8,
13983
- p: 1
13984
- },
13985
- DEFAULT: {
13986
- N: 4096,
13987
- r: 16,
13988
- p: 1
13989
- },
13990
- SECURE: {
13991
- N: 16384,
13992
- r: 32,
13993
- p: 2
13994
- },
13995
- HARDEST: {
13996
- N: 65536,
13997
- r: 32,
13998
- p: 4
13999
- },
14000
- EXTREME: {
14001
- N: 262144,
14002
- r: 64,
14003
- p: 8
13801
+ get destroyed() {
13802
+ var _a;
13803
+ return ((_a = this.destroySubject) === null || _a === void 0 ? void 0 : _a.closed) !== false;
14004
13804
  }
14005
- };
14006
- class CryptoService {
14007
- static get started() {
14008
- return this._ready;
13805
+ set form(value) {
13806
+ this.setForm(value);
14009
13807
  }
14010
- static ready() {
14011
- return __awaiter(this, void 0, void 0, function* () {
14012
- if (this._ready)
14013
- return; // OK
14014
- yield cryptoWaitReady();
14015
- this._ready = true;
14016
- });
13808
+ get form() {
13809
+ return this._form;
14017
13810
  }
14018
- /**
14019
- * Generate a sign keypair, using scrypt, from a salt and a password
14020
- *
14021
- * @param salt
14022
- * @param password
14023
- * @param scryptParams
14024
- */
14025
- static scryptKeypair(salt, password, scryptParams) {
13811
+ ngOnInit() {
13812
+ this._enable ? this.enable() : this.disable();
13813
+ this.errorTranslatorOptions = this.errorTranslatorOptions || {
13814
+ controlPathTranslator: this
13815
+ };
13816
+ }
13817
+ ngOnDestroy() {
13818
+ this._subscription.unsubscribe();
13819
+ this.readySubject.unsubscribe();
13820
+ this.loadingSubject.unsubscribe();
13821
+ this.errorSubject.unsubscribe();
13822
+ this.onCancel.unsubscribe();
13823
+ this.onSubmit.unsubscribe();
13824
+ this.destroySubject.next();
13825
+ this.destroySubject.unsubscribe();
13826
+ }
13827
+ cancel() {
14026
13828
  return __awaiter(this, void 0, void 0, function* () {
14027
- if (!this.started)
14028
- yield this.ready();
14029
- const passwordU8a = decodeUTF8(password);
14030
- const saltU8a = decodeUTF8(salt);
14031
- const result = scryptEncode(passwordU8a, saltU8a, scryptParams || SCRYPT_PARAMS.DEFAULT);
14032
- const seed = result.password.slice(0, ED25519_SEED_LENGTH);
14033
- return ed25519PairFromSeed(seed);
13829
+ this.onCancel.emit();
14034
13830
  });
14035
13831
  }
14036
13832
  /**
14037
- * Sign a message, from a key pair
13833
+ *
13834
+ * @param event
13835
+ * @param opts allow to skip validation check, using {checkValid: false}
14038
13836
  */
14039
- static sign(message, keypair) {
13837
+ doSubmit(event, opts) {
14040
13838
  return __awaiter(this, void 0, void 0, function* () {
14041
- if (!this.started)
14042
- yield this.ready();
14043
- const m = decodeUTF8(message);
14044
- const sig = ed25519Sign(m, keypair);
14045
- return encodeBase64(sig);
14046
- });
14047
- }
13839
+ if (!this._form) {
13840
+ this.markAllAsTouched({ emitEvent: true });
13841
+ return;
13842
+ }
13843
+ // Check if valid (if not disabled)
13844
+ if ((!opts || opts.checkValid !== false) && !this._form.valid) {
13845
+ // Wait validation end
13846
+ yield AppFormUtils.waitWhilePending(this._form);
13847
+ // Form is invalid: exit (+ log if debug)
13848
+ if (this._form.invalid) {
13849
+ this.markAllAsTouched({ emitEvent: true });
13850
+ if (this.debug)
13851
+ AppFormUtils.logFormErrors(this._form);
13852
+ return;
13853
+ }
13854
+ }
13855
+ // Emit event
13856
+ this.onSubmit.emit(event);
13857
+ });
13858
+ }
13859
+ setForm(form) {
13860
+ if (this._form !== form) {
13861
+ this._form = form;
13862
+ this._subscription.add(this._form.statusChanges.subscribe(status => this.markForCheck()));
13863
+ }
13864
+ }
13865
+ setValue(data, opts) {
13866
+ if (!data) {
13867
+ console.warn('[form] Trying to set an empty value to form. Skipping');
13868
+ return;
13869
+ }
13870
+ // DEBUG
13871
+ //if (this.debug) console.debug('[form] Updating form (using entity)', data);
13872
+ // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
13873
+ AppFormUtils.copyEntity2Form(data, this.form, Object.assign({ emitEvent: false, onlySelf: true }, opts));
13874
+ if (!opts || opts.emitEvent !== true) {
13875
+ this.markForCheck();
13876
+ }
13877
+ }
13878
+ reset(data, opts) {
13879
+ if (data) {
13880
+ if (this.debug)
13881
+ console.debug('[form] Resetting form (using entity)', data);
13882
+ // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
13883
+ const json = AppFormUtils.getFormValueFromEntity(data, this.form);
13884
+ this.form.reset(json, { emitEvent: false, onlySelf: true });
13885
+ }
13886
+ else {
13887
+ this.form.reset(null, { emitEvent: false, onlySelf: true });
13888
+ }
13889
+ if (!opts || opts.emitEvent !== true)
13890
+ this.markForCheck();
13891
+ }
13892
+ markAsPristine(opts) {
13893
+ this.form.markAsPristine(opts);
13894
+ if (!opts || opts.emitEvent !== false)
13895
+ this.markForCheck();
13896
+ }
13897
+ markAsUntouched(opts) {
13898
+ this.form.markAsUntouched(opts);
13899
+ if (!opts || opts.emitEvent !== false)
13900
+ this.markForCheck();
13901
+ }
13902
+ /**
13903
+ * @deprecated prefer to use markAllAsTouched()
13904
+ * @param opts
13905
+ */
13906
+ markAsTouched(opts) {
13907
+ // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
13908
+ console.warn('TODO: Replace this call by markAllAsTouched() - because of changes in ngx-components >= 0.16.0');
13909
+ AppFormUtils.markAsTouched(this.form, opts);
13910
+ if (!opts || opts.emitEvent !== false)
13911
+ this.markForCheck();
13912
+ }
13913
+ markAllAsTouched(opts) {
13914
+ // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
13915
+ AppFormUtils.markAllAsTouched(this.form, opts);
13916
+ if (!opts || opts.emitEvent !== false)
13917
+ this.markForCheck();
13918
+ }
13919
+ markAsDirty(opts) {
13920
+ this.form.markAsDirty(opts);
13921
+ if (!opts || opts.emitEvent !== false)
13922
+ this.markForCheck();
13923
+ }
13924
+ markAsLoading(opts) {
13925
+ this.setLoading(true, opts);
13926
+ }
13927
+ markAsLoaded(opts) {
13928
+ this.setLoading(false, opts);
13929
+ }
13930
+ markAsReady(opts) {
13931
+ if (this.readySubject.value !== true) {
13932
+ this.readySubject.next(true);
13933
+ // If subclasses implements OnReady
13934
+ if (typeof this['ngOnReady'] === 'function') {
13935
+ this.ngOnReady();
13936
+ }
13937
+ }
13938
+ }
13939
+ /**
13940
+ * Wait form is ready
13941
+ * @param opts
13942
+ */
13943
+ ready(opts) {
13944
+ if (this.readySubject.value)
13945
+ return Promise.resolve();
13946
+ return waitForTrue(this.readySubject, opts);
13947
+ }
13948
+ /**
13949
+ * Wait form is not busy (=loaded)
13950
+ * @param opts
13951
+ */
13952
+ waitIdle(opts) {
13953
+ if (!this.loadingSubject.value)
13954
+ return Promise.resolve();
13955
+ return waitForFalse(this.loadingSubject, opts);
13956
+ }
13957
+ updateValueAndValidity(opts) {
13958
+ AppFormUtils.updateValueAndValidity(this.form, opts);
13959
+ if (!opts || opts.emitEvent !== false)
13960
+ this.markForCheck();
13961
+ }
13962
+ translateControlPath(path) {
13963
+ var _a;
13964
+ const i18nFieldName = this.getI18nFieldName(path);
13965
+ return ((_a = this.translate) === null || _a === void 0 ? void 0 : _a.instant(i18nFieldName)) || i18nFieldName;
13966
+ }
13967
+ /* -- protected methods -- */
13968
+ getFormError(form, opts) {
13969
+ if (!form || !this.errorTranslator)
13970
+ return undefined;
13971
+ return this.errorTranslator.translateFormErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
13972
+ }
13973
+ getI18nFieldName(path) {
13974
+ return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
13975
+ }
13976
+ registerSubscription(sub) {
13977
+ this._subscription.add(sub);
13978
+ }
13979
+ unregisterSubscription(sub) {
13980
+ this._subscription.remove(sub);
13981
+ }
13982
+ registerAutocompleteField(fieldName, opts) {
13983
+ return this.autocompleteHelper.add(fieldName, opts);
13984
+ }
13985
+ setError(value, opts) {
13986
+ if (this.errorSubject.value !== value) {
13987
+ this.errorSubject.next(value);
13988
+ if (!opts || opts.emitEvent !== false) {
13989
+ this.markForCheck();
13990
+ }
13991
+ }
13992
+ }
13993
+ markForCheck() {
13994
+ // Should be overwritten by subclasses
13995
+ console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
13996
+ }
13997
+ /* -- private function -- */
13998
+ setLoading(value, opts) {
13999
+ if (this.loadingSubject.value !== value) {
14000
+ this.loadingSubject.next(value);
14001
+ if (!opts || opts.emitEvent !== false) {
14002
+ this.markForCheck();
14003
+ }
14004
+ }
14005
+ }
14006
+ }
14007
+ AppForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppForm, deps: [{ token: i0.Injector }, { token: i1$2.UntypedFormGroup }], target: i0.ɵɵFactoryTarget.Directive });
14008
+ AppForm.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.8", type: AppForm, inputs: { debug: "debug", tabindex: "tabindex", errorTranslatorOptions: "errorTranslatorOptions", form: "form" }, outputs: { onCancel: "onCancel", onSubmit: "onSubmit" }, ngImport: i0 });
14009
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppForm, decorators: [{
14010
+ type: Directive
14011
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$2.UntypedFormGroup }]; }, propDecorators: { debug: [{
14012
+ type: Input
14013
+ }], tabindex: [{
14014
+ type: Input
14015
+ }], errorTranslatorOptions: [{
14016
+ type: Input
14017
+ }], form: [{
14018
+ type: Input
14019
+ }], onCancel: [{
14020
+ type: Output
14021
+ }], onSubmit: [{
14022
+ type: Output
14023
+ }] } });
14024
+
14025
+ class TextForm extends AppForm {
14026
+ constructor(injector, cd, formBuilder) {
14027
+ super(injector);
14028
+ this.injector = injector;
14029
+ this.cd = cd;
14030
+ this.formBuilder = formBuilder;
14031
+ this.showError = true;
14032
+ this.multiline = true;
14033
+ this.autoHeight = false;
14034
+ this.maxLength = 2000;
14035
+ this.autofocus = false;
14036
+ this.validator = null;
14037
+ this.textAreaChanges = new EventEmitter();
14038
+ }
14039
+ ngOnInit() {
14040
+ // Compute validators
14041
+ const validators = isNotNil(this.maxLength) && this.maxLength > 0 ? [Validators.maxLength(this.maxLength)] : [];
14042
+ if (this.validator)
14043
+ validators.push(this.validator);
14044
+ // Create the form
14045
+ const form = this.formBuilder.group({
14046
+ text: [null, validators.length ? Validators.compose(validators) : null]
14047
+ });
14048
+ this.control = form.get('text');
14049
+ this.setForm(form);
14050
+ super.ngOnInit();
14051
+ }
14052
+ textAreaChanged(event) {
14053
+ this.textAreaChanges.emit(this.control.value);
14054
+ }
14055
+ containerResize() {
14056
+ var _a;
14057
+ (_a = this.autosizeDirective) === null || _a === void 0 ? void 0 : _a.resizeToFitContent(true);
14058
+ }
14059
+ focusInput() {
14060
+ if (this.textArea)
14061
+ focusInput(this.textArea);
14062
+ if (this.textInput)
14063
+ focusInput(this.textInput);
14064
+ }
14065
+ markForCheck() {
14066
+ this.cd.markForCheck();
14067
+ }
14068
+ }
14069
+ TextForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextForm, deps: [{ token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i1$2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component });
14070
+ TextForm.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: TextForm, selector: "app-text-form", inputs: { showError: "showError", placeholder: "placeholder", multiline: "multiline", autoHeight: "autoHeight", maxLength: "maxLength", autofocus: "autofocus", validator: "validator" }, outputs: { textAreaChanges: "textAreaChanges" }, viewQueries: [{ propertyName: "textArea", first: true, predicate: ["textArea"], descendants: true }, { propertyName: "textInput", first: true, predicate: ["textInput"], descendants: true }, { propertyName: "autosizeDirective", first: true, predicate: CdkTextareaAutosize, descendants: true }], usesInheritance: true, ngImport: i0, template: "<form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n <mat-form-field *ngIf=\"multiline; else monoline\">\n <textarea\n #textArea\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"control.disabled\"\n [class.fixed-height]=\"!autoHeight\"\n [cdkTextareaAutosize]=\"autoHeight\"\n (keyup)=\"textAreaChanged($event)\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n [autofocus]=\"autofocus\"\n ></textarea>\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textArea.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n <ng-template #monoline>\n <mat-form-field>\n <input\n #textInput\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"disabled\"\n [appAutofocus]=\"autofocus\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n />\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-error *ngIf=\"control.hasError('pattern')\">\n {{ 'ERROR.FIELD_INVALID' | translate }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textInput.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n </ng-template>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}\n"], dependencies: [{ kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
14071
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextForm, decorators: [{
14072
+ type: Component,
14073
+ args: [{ selector: 'app-text-form', template: "<form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n <mat-form-field *ngIf=\"multiline; else monoline\">\n <textarea\n #textArea\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"control.disabled\"\n [class.fixed-height]=\"!autoHeight\"\n [cdkTextareaAutosize]=\"autoHeight\"\n (keyup)=\"textAreaChanged($event)\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n [autofocus]=\"autofocus\"\n ></textarea>\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textArea.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n <ng-template #monoline>\n <mat-form-field>\n <input\n #textInput\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"disabled\"\n [appAutofocus]=\"autofocus\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n />\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-error *ngIf=\"control.hasError('pattern')\">\n {{ 'ERROR.FIELD_INVALID' | translate }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textInput.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n </ng-template>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}\n"] }]
14074
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i1$2.UntypedFormBuilder }]; }, propDecorators: { showError: [{
14075
+ type: Input
14076
+ }], placeholder: [{
14077
+ type: Input
14078
+ }], multiline: [{
14079
+ type: Input
14080
+ }], autoHeight: [{
14081
+ type: Input
14082
+ }], maxLength: [{
14083
+ type: Input
14084
+ }], autofocus: [{
14085
+ type: Input
14086
+ }], validator: [{
14087
+ type: Input
14088
+ }], textAreaChanges: [{
14089
+ type: Output
14090
+ }], textArea: [{
14091
+ type: ViewChild,
14092
+ args: ['textArea']
14093
+ }], textInput: [{
14094
+ type: ViewChild,
14095
+ args: ['textInput']
14096
+ }], autosizeDirective: [{
14097
+ type: ViewChild,
14098
+ args: [CdkTextareaAutosize]
14099
+ }] } });
14100
+
14101
+ class TextPopover {
14102
+ constructor(popoverController, translate) {
14103
+ this.popoverController = popoverController;
14104
+ this.translate = translate;
14105
+ this.placeholder = '';
14106
+ this.editing = true;
14107
+ this.multiline = true;
14108
+ this.maxLength = 2000;
14109
+ this.autofocus = false;
14110
+ this.validator = null;
14111
+ this.subscription = new Subscription();
14112
+ }
14113
+ get disabled() {
14114
+ return this.form.disabled;
14115
+ }
14116
+ get enabled() {
14117
+ return this.form.enabled;
14118
+ }
14119
+ get valid() {
14120
+ var _a;
14121
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
14122
+ }
14123
+ get value() {
14124
+ var _a;
14125
+ return (_a = this.form) === null || _a === void 0 ? void 0 : _a.value.text;
14126
+ }
14127
+ ngOnInit() {
14128
+ this.enable();
14129
+ }
14130
+ ngAfterViewInit() {
14131
+ setTimeout(() => this.form.setValue({ text: this.text }), 0);
14132
+ }
14133
+ onValidate(event) {
14134
+ return __awaiter(this, void 0, void 0, function* () {
14135
+ yield waitWhilePending(this.form);
14136
+ if (!this.valid) {
14137
+ logFormErrors(this.form.control);
14138
+ return;
14139
+ }
14140
+ try {
14141
+ const value = this.value;
14142
+ this.disable();
14143
+ yield this.popoverController.dismiss(value);
14144
+ this.form.error = null;
14145
+ }
14146
+ catch (err) {
14147
+ this.form.error = (err && err.message) || err;
14148
+ this.enable();
14149
+ }
14150
+ });
14151
+ }
14152
+ disable() {
14153
+ this.form.disable();
14154
+ }
14155
+ enable() {
14156
+ if (this.editing)
14157
+ this.form.enable();
14158
+ }
14159
+ cancel() {
14160
+ this.popoverController.dismiss();
14161
+ }
14162
+ ngOnDestroy() {
14163
+ this.subscription.unsubscribe();
14164
+ }
14165
+ }
14166
+ TextPopover.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextPopover, deps: [{ token: i2.PopoverController }, { token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
14167
+ TextPopover.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: TextPopover, selector: "app-text-popover", inputs: { text: "text", placeholder: "placeholder", editing: "editing", multiline: "multiline", maxLength: "maxLength", autofocus: "autofocus", validator: "validator" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "\n<ion-content class=\"ion-padding\" cdkTrapFocus [cdkTrapFocusAutoCapture]=\"true\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error|translate\"></ion-label>\n </ion-item>\n\n <app-text-form #form [placeholder]=\"placeholder\"\n [multiline]=\"multiline\"\n [maxLength]=\"maxLength\"\n [autofocus]=\"editing && autofocus\"\n [validator]=\"validator\"\n (onSubmit)=\"onValidate($event)\"\n ></app-text-form>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n\n </ion-col>\n\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n <ion-button\n [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onValidate($event)\"\n (keyup.enter)=\"onValidate($event)\"\n color=\"tertiary\"\n [disabled]=\"disabled\"\n [title]=\"'COMMON.BTN_VALIDATE_WITH_SHORTCUT_HELP'|translate\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "component", type: TextForm, selector: "app-text-form", inputs: ["showError", "placeholder", "multiline", "autoHeight", "maxLength", "autofocus", "validator"], outputs: ["textAreaChanges"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
14168
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextPopover, decorators: [{
14169
+ type: Component,
14170
+ args: [{ selector: 'app-text-popover', template: "\n<ion-content class=\"ion-padding\" cdkTrapFocus [cdkTrapFocusAutoCapture]=\"true\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error|translate\"></ion-label>\n </ion-item>\n\n <app-text-form #form [placeholder]=\"placeholder\"\n [multiline]=\"multiline\"\n [maxLength]=\"maxLength\"\n [autofocus]=\"editing && autofocus\"\n [validator]=\"validator\"\n (onSubmit)=\"onValidate($event)\"\n ></app-text-form>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n\n </ion-col>\n\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n <ion-button\n [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onValidate($event)\"\n (keyup.enter)=\"onValidate($event)\"\n color=\"tertiary\"\n [disabled]=\"disabled\"\n [title]=\"'COMMON.BTN_VALIDATE_WITH_SHORTCUT_HELP'|translate\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n" }]
14171
+ }], ctorParameters: function () { return [{ type: i2.PopoverController }, { type: i1$1.TranslateService }]; }, propDecorators: { form: [{
14172
+ type: ViewChild,
14173
+ args: ['form', { static: true }]
14174
+ }], text: [{
14175
+ type: Input
14176
+ }], placeholder: [{
14177
+ type: Input
14178
+ }], editing: [{
14179
+ type: Input
14180
+ }], multiline: [{
14181
+ type: Input
14182
+ }], maxLength: [{
14183
+ type: Input
14184
+ }], autofocus: [{
14185
+ type: Input
14186
+ }], validator: [{
14187
+ type: Input
14188
+ }] } });
14189
+
14190
+ class SelectPeerModal {
14191
+ constructor(modalCtrl, popoverController, translate, http, cd, environment) {
14192
+ this.modalCtrl = modalCtrl;
14193
+ this.popoverController = popoverController;
14194
+ this.translate = translate;
14195
+ this.http = http;
14196
+ this.cd = cd;
14197
+ this.environment = environment;
14198
+ this._subscription = new Subscription();
14199
+ this.loading = true;
14200
+ this.$peers = new Subject();
14201
+ this.peerMinVersion = this.environment.peerMinVersion;
14202
+ this.canCancel = true;
14203
+ this.allowSelectDownPeer = true;
14204
+ this.onRefresh = new EventEmitter();
14205
+ this.showSetManuallyButton = true;
14206
+ this.mobile = isMobile(window);
14207
+ }
14208
+ set peers(peers) {
14209
+ this._subscription.add(peers.subscribe(res => this.refreshPeers(res)));
14210
+ }
14211
+ cancel() {
14212
+ this.modalCtrl.dismiss();
14213
+ }
14214
+ ngOnDestroy() {
14215
+ this._subscription.unsubscribe();
14216
+ }
14217
+ selectPeer(peer) {
14218
+ if (this.allowSelectDownPeer || (peer.reachable && this.isCompatible(peer))) {
14219
+ console.debug(`[select-peer-modal] Selected peer: {url: '${peer.url}'}`);
14220
+ this.modalCtrl.dismiss(peer);
14221
+ }
14222
+ }
14223
+ /**
14224
+ * Check the min pod version, defined by the app
14225
+ *
14226
+ * @param peer
14227
+ */
14228
+ isCompatible(peer) {
14229
+ return !this.peerMinVersion || (peer && peer.softwareVersion && VersionUtils.isCompatible(this.peerMinVersion, peer.softwareVersion));
14230
+ }
14231
+ refresh(event) {
14232
+ this.loading = true;
14233
+ this.onRefresh.emit(event);
14234
+ }
14235
+ clickSetManually(event) {
14236
+ return __awaiter(this, void 0, void 0, function* () {
14237
+ const peerUrl = yield this.openPeerUrlPopover(event);
14238
+ if (peerUrl) {
14239
+ const peer = Peer.parseUrl(peerUrl);
14240
+ yield this.refreshPeer(peer);
14241
+ this.selectPeer(peer);
14242
+ }
14243
+ });
14244
+ }
14245
+ /* -- protected methods -- */
14246
+ refreshPeers(peers) {
14247
+ return __awaiter(this, void 0, void 0, function* () {
14248
+ peers = peers || [];
14249
+ const data = [];
14250
+ const jobs = Promise.all(peers.map((peer) => __awaiter(this, void 0, void 0, function* () {
14251
+ yield this.refreshPeer(peer);
14252
+ if (this._subscription.closed)
14253
+ return; // component destroyed
14254
+ data.push(peer);
14255
+ // Sort (by reachable, then host)
14256
+ data.sort((a, b) => {
14257
+ if (a.reachable && !b.reachable)
14258
+ return -1;
14259
+ if (!a.reachable && b.reachable)
14260
+ return 1;
14261
+ if (a.hostAndPort < b.hostAndPort)
14262
+ return -1;
14263
+ if (a.hostAndPort > b.hostAndPort)
14264
+ return 1;
14265
+ return 0;
14266
+ });
14267
+ this.$peers.next(data);
14268
+ return peer;
14269
+ })));
14270
+ this._subscription.add(this.$peers
14271
+ .subscribe(() => this.cd.markForCheck()));
14272
+ try {
14273
+ yield jobs;
14274
+ }
14275
+ catch (err) {
14276
+ if (!this._subscription.closed)
14277
+ console.error(err);
14278
+ }
14279
+ this.loading = false;
14280
+ this.cd.markForCheck();
14281
+ });
14282
+ }
14283
+ refreshPeer(peer) {
14284
+ return __awaiter(this, void 0, void 0, function* () {
14285
+ try {
14286
+ const summary = yield NetworkUtils.getNodeInfo(this.http, peer.url);
14287
+ peer.status = 'UP';
14288
+ peer.softwareName = summary.softwareName;
14289
+ peer.softwareVersion = summary.softwareVersion;
14290
+ peer.label = summary.nodeLabel;
14291
+ peer.name = summary.nodeName;
14292
+ }
14293
+ catch (err) {
14294
+ if (!this._subscription.closed) {
14295
+ if (err && err.message) {
14296
+ console.error('[select-peer] ' + err.message, err);
14297
+ }
14298
+ }
14299
+ peer.status = 'DOWN';
14300
+ }
14301
+ return peer;
14302
+ });
14303
+ }
14304
+ openPeerUrlPopover(event, opts) {
14305
+ return __awaiter(this, void 0, void 0, function* () {
14306
+ const modal = yield this.popoverController.create({
14307
+ component: TextPopover,
14308
+ componentProps: Object.assign({ placeholder: this.translate.instant('SETTINGS.PEER_URL'), multiline: false, autofocus: !this.mobile, autocomplete: false, validator: Validators.pattern(PEER_URL_REGEXP), maxLength: null }, opts),
14309
+ backdropDismiss: false,
14310
+ keyboardClose: false,
14311
+ event,
14312
+ translucent: true,
14313
+ cssClass: 'popover-large',
14314
+ });
14315
+ yield modal.present();
14316
+ const { data, role } = yield modal.onDidDismiss();
14317
+ if (data) {
14318
+ console.info('Popover result: ', data);
14319
+ return data;
14320
+ }
14321
+ });
14322
+ }
14323
+ markForCheck() {
14324
+ this.cd.markForCheck();
14325
+ }
14326
+ }
14327
+ SelectPeerModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SelectPeerModal, deps: [{ token: i2.ModalController }, { token: i2.PopoverController }, { token: i1$1.TranslateService }, { token: i2$5.HttpClient }, { token: i0.ChangeDetectorRef }, { token: ENVIRONMENT }], target: i0.ɵɵFactoryTarget.Component });
14328
+ SelectPeerModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: SelectPeerModal, selector: "select-peer-modal", inputs: { canCancel: "canCancel", allowSelectDownPeer: "allowSelectDownPeer", onRefresh: "onRefresh", showSetManuallyButton: "showSetManuallyButton" }, ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"cancel()\" *ngIf=\"canCancel\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{'NETWORK.PEER.SELECT_MODAL.TITLE'|translate}}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button *ngIf=\"onRefresh.observers | isNotEmptyArray\"\n [matTooltip]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"refresh($event)\">\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <ion-list>\n\n <ion-list-header>\n <ion-label class=\"ion-text-wrap\">\n <p translate>NETWORK.PEER.SELECT_MODAL.HELP</p>\n </ion-label>\n </ion-list-header>\n\n <ion-item *ngFor=\"let peer of $peers | async\"\n tappable\n (click)=\"selectPeer(peer)\"\n detail\n @fadeInAnimation>\n\n <!-- icon -->\n <ion-avatar slot=\"start\" *ngIf=\"peer.reachable\" >\n <ion-img [src]=\"peer.favicon || (peer.url + '/api/favicon')\"></ion-img>\n </ion-avatar>\n <ion-icon slot=\"start\" *ngIf=\"!peer.reachable\" name=\"desktop\" color=\"medium\" class=\"ion-text-center\"></ion-icon>\n\n <!-- Peer is UP -->\n <ion-grid *ngIf=\"peer.reachable\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"dark\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4>{{peer.label}}</h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap ion-text-center\" color=\"medium\">\n <h3>{{peer.softwareName}}</h3>\n <h4 *ngIf=\"!peerMinVersion || isCompatible(peer); else invalidVersion\">\n <small>v{{peer.softwareVersion}}</small>\n </h4>\n <ng-template #invalidVersion>\n <ion-text color=\"danger\" [matTooltip]=\"'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP'|translate: {version: peerMinVersion} \">\n <h4 class=\"ion-color-danger\">\n <small><mat-icon>warning</mat-icon>v{{peer.softwareVersion}}</small>\n </h4>\n </ion-text>\n </ng-template>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Peer is DOWN -->\n <ion-label class=\"ion-text-wrap\" *ngIf=\"!peer.reachable\">\n <ion-text color=\"medium\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small><ion-icon size=\"small\" name=\"close-circle\"></ion-icon></small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n </ion-item>\n </ion-list>\n\n</ion-content>\n\n\n<ion-footer *ngIf=\"canCancel\" hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\" *ngIf=\"showSetManuallyButton\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"clickSetManually($event)\">\n <ion-label translate>NETWORK.PEER.SELECT_MODAL.BTN_SET_MANUALLY</ion-label>\n </ion-button>\n </ion-col>\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n", styles: ["ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonAvatar, selector: "ion-avatar" }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonImg, selector: "ion-img", inputs: ["alt", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }, { kind: "component", type: i2.IonListHeader, selector: "ion-list-header", inputs: ["color", "lines", "mode"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i2.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "component", type: i2.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i6$3.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { kind: "pipe", type: i2$1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: NotEmptyArrayPipe, name: "isNotEmptyArray" }], animations: [fadeInAnimation], changeDetection: i0.ChangeDetectionStrategy.OnPush });
14329
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SelectPeerModal, decorators: [{
14330
+ type: Component,
14331
+ args: [{ selector: 'select-peer-modal', changeDetection: ChangeDetectionStrategy.OnPush, animations: [fadeInAnimation], template: "<ion-header>\n <ion-toolbar color=\"light\">\n <ion-buttons slot=\"start\">\n <ion-button (click)=\"cancel()\" *ngIf=\"canCancel\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title>\n {{'NETWORK.PEER.SELECT_MODAL.TITLE'|translate}}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button *ngIf=\"onRefresh.observers | isNotEmptyArray\"\n [matTooltip]=\"'COMMON.BTN_REFRESH'|translate\"\n (click)=\"refresh($event)\">\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <ion-list>\n\n <ion-list-header>\n <ion-label class=\"ion-text-wrap\">\n <p translate>NETWORK.PEER.SELECT_MODAL.HELP</p>\n </ion-label>\n </ion-list-header>\n\n <ion-item *ngFor=\"let peer of $peers | async\"\n tappable\n (click)=\"selectPeer(peer)\"\n detail\n @fadeInAnimation>\n\n <!-- icon -->\n <ion-avatar slot=\"start\" *ngIf=\"peer.reachable\" >\n <ion-img [src]=\"peer.favicon || (peer.url + '/api/favicon')\"></ion-img>\n </ion-avatar>\n <ion-icon slot=\"start\" *ngIf=\"!peer.reachable\" name=\"desktop\" color=\"medium\" class=\"ion-text-center\"></ion-icon>\n\n <!-- Peer is UP -->\n <ion-grid *ngIf=\"peer.reachable\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap\">\n <ion-text color=\"dark\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"primary\">\n <h4>{{peer.label}}</h4>\n </ion-text>\n </ion-label>\n </ion-col>\n <ion-col class=\"ion-no-padding\">\n <ion-label class=\"ion-text-wrap ion-text-center\" color=\"medium\">\n <h3>{{peer.softwareName}}</h3>\n <h4 *ngIf=\"!peerMinVersion || isCompatible(peer); else invalidVersion\">\n <small>v{{peer.softwareVersion}}</small>\n </h4>\n <ng-template #invalidVersion>\n <ion-text color=\"danger\" [matTooltip]=\"'NETWORK.PEER.SELECT_MODAL.NOT_COMPATIBLE_HELP'|translate: {version: peerMinVersion} \">\n <h4 class=\"ion-color-danger\">\n <small><mat-icon>warning</mat-icon>v{{peer.softwareVersion}}</small>\n </h4>\n </ion-text>\n </ng-template>\n </ion-label>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Peer is DOWN -->\n <ion-label class=\"ion-text-wrap\" *ngIf=\"!peer.reachable\">\n <ion-text color=\"medium\">\n <h3>{{peer.hostAndPort}}{{peer.path}}</h3>\n </ion-text>\n <ion-text color=\"danger\">\n <h4>\n <small><ion-icon size=\"small\" name=\"close-circle\"></ion-icon></small>\n <span translate>NETWORK.PEER.OFFLINE</span>\n </h4>\n </ion-text>\n </ion-label>\n </ion-item>\n </ion-list>\n\n</ion-content>\n\n\n<ion-footer *ngIf=\"canCancel\" hidden-xs hidden-sm hidden-mobile>\n\n <ion-toolbar>\n\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col></ion-col>\n\n <!-- buttons -->\n <ion-col size=\"auto\" *ngIf=\"showSetManuallyButton\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"clickSetManually($event)\">\n <ion-label translate>NETWORK.PEER.SELECT_MODAL.BTN_SET_MANUALLY</ion-label>\n </ion-button>\n </ion-col>\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n", styles: ["ion-item h4 ion-icon,ion-item h4 mat-icon{height:14px;width:14px;font-size:14px;line-height:14px}ion-item h4 small ion-icon,ion-item h4 small mat-icon{height:12px;width:12px;font-size:12px;line-height:12px}\n"] }]
14332
+ }], ctorParameters: function () {
14333
+ return [{ type: i2.ModalController }, { type: i2.PopoverController }, { type: i1$1.TranslateService }, { type: i2$5.HttpClient }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
14334
+ type: Inject,
14335
+ args: [ENVIRONMENT]
14336
+ }] }];
14337
+ }, propDecorators: { canCancel: [{
14338
+ type: Input
14339
+ }], allowSelectDownPeer: [{
14340
+ type: Input
14341
+ }], onRefresh: [{
14342
+ type: Input
14343
+ }], showSetManuallyButton: [{
14344
+ type: Input
14345
+ }] } });
14346
+
14347
+ /**
14348
+ * Same as StartableService, bu with a dataSubject instead of a simple 'data' property
14349
+ */
14350
+ let StartableObservableService = class StartableObservableService {
14351
+ constructor(prerequisiteService) {
14352
+ this.dataSubject = new BehaviorSubject(null);
14353
+ this.startSubject = new Subject();
14354
+ this.stopSubject = new Subject();
14355
+ this._debug = false;
14356
+ this._startByReadyFunction = true; // should start when calling ready() ?
14357
+ this._started = false;
14358
+ this._startPromise = null;
14359
+ this._startPrerequisite = null;
14360
+ this._subscription = null;
14361
+ this._startPrerequisite = prerequisiteService
14362
+ ? () => prerequisiteService.ready()
14363
+ : () => Promise.resolve();
14364
+ }
14365
+ start(opts) {
14366
+ if (this._startPromise)
14367
+ return this._startPromise;
14368
+ if (this._started)
14369
+ return Promise.resolve(this.dataSubject.value);
14370
+ this._startPromise = this._startPrerequisite()
14371
+ .then(() => this.ngOnStart(opts))
14372
+ .then(data => {
14373
+ this._started = true;
14374
+ this._startPromise = undefined;
14375
+ // Should be done AFTER 'this._started = true', because of the 'filter' operator, inside ready() function
14376
+ this.dataSubject.next(data);
14377
+ this.startSubject.next(data);
14378
+ return data;
14379
+ })
14380
+ .catch(err => {
14381
+ if (!this.stopped) {
14382
+ console.error('Failed to start a service: ' + (err && err.message || err), err);
14383
+ this._started = false;
14384
+ this._startPromise = null;
14385
+ }
14386
+ return null;
14387
+ });
14388
+ return this._startPromise;
14389
+ }
14390
+ ready() {
14391
+ if (this._started)
14392
+ return Promise.resolve(this.dataSubject.value);
14393
+ if (this._startPromise)
14394
+ return this._startPromise;
14395
+ if (this._startByReadyFunction)
14396
+ return this.start();
14397
+ return this.dataSubject
14398
+ .pipe(takeUntil(this.stopSubject),
14399
+ // Wait start() to be called, to exclude the initial 'null' value
14400
+ filter(_ => this._started))
14401
+ .toPromise();
14402
+ }
14403
+ stop() {
14404
+ return __awaiter(this, void 0, void 0, function* () {
14405
+ try {
14406
+ this.unsubscribe();
14407
+ yield this.ngOnStop();
14408
+ }
14409
+ catch (err) {
14410
+ console.error('Failed to stop a service: ' + (err && err.message || err), err);
14411
+ }
14412
+ finally {
14413
+ this._started = false;
14414
+ this._startPromise = undefined;
14415
+ this.stopSubject.next(); // Stop all running observables
14416
+ this.dataSubject.next(null); // Reset data
14417
+ }
14418
+ });
14419
+ }
14420
+ restart(opts) {
14421
+ return __awaiter(this, void 0, void 0, function* () {
14422
+ if (this._startPromise)
14423
+ yield this._startPromise; // Wait end of previous loading
14424
+ if (this._started)
14425
+ yield this.stop(); // Then stop if started
14426
+ return this.start(opts); // Then start again
14427
+ });
14428
+ }
14429
+ get started() {
14430
+ return this._started;
14431
+ }
14432
+ get starting() {
14433
+ return !!this._startPromise;
14434
+ }
14435
+ get stopped() {
14436
+ return !this._started && !this._startPromise;
14437
+ }
14438
+ get data() {
14439
+ return this.dataSubject.value;
14440
+ }
14441
+ set data(value) {
14442
+ if (this.dataSubject.value !== value) {
14443
+ this.dataSubject.next(value);
14444
+ }
14445
+ }
14446
+ registerSubscription(sub) {
14447
+ this._subscription = this._subscription || new Subscription();
14448
+ this._subscription.add(sub);
14449
+ }
14450
+ unregisterSubscription(sub) {
14451
+ var _a;
14452
+ (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.remove(sub);
14453
+ }
14454
+ unsubscribe() {
14455
+ var _a;
14456
+ (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
14457
+ this._subscription = null;
14458
+ }
14459
+ ngOnStop() {
14460
+ // Can be overwritten by subclasses
14461
+ }
14462
+ };
14463
+ StartableObservableService = __decorate([
14464
+ __param(0, Optional())
14465
+ ], StartableObservableService);
14466
+
14467
+ // Base58 encoding/decoding
14468
+ // Originally written by Mike Hearn for BitcoinJ
14469
+ // Copyright (c) 2011 Google Inc
14470
+ // Ported to JavaScript by Stefan Thomas
14471
+ // Merged Buffer refactorings from base58-native by Stephen Pair
14472
+ // Copyright (c) 2013 BitPay Inc
14473
+ // Rewritten in TypeScript by Ludovic Pecquot
14474
+ // @dynamic
14475
+ class Base58 {
14476
+ static getAlphabetMap() {
14477
+ if (!Base58.alphabetMap) {
14478
+ this.alphabetMap = {};
14479
+ for (let i = 0; i < Base58.alphabet.length; i++) {
14480
+ Base58.alphabetMap[Base58.alphabet.charAt(i)] = i;
14481
+ }
14482
+ }
14483
+ return Base58.alphabetMap;
14484
+ }
14485
+ static encode(buffer) {
14486
+ if (buffer.length === 0)
14487
+ return '';
14488
+ let i;
14489
+ let j;
14490
+ const digits = [0];
14491
+ for (i = 0; i < buffer.length; i++) {
14492
+ for (j = 0; j < digits.length; j++)
14493
+ digits[j] <<= 8;
14494
+ digits[digits.length - 1] += buffer[i];
14495
+ let carry = 0;
14496
+ for (j = digits.length - 1; j >= 0; j--) {
14497
+ digits[j] += carry;
14498
+ carry = (digits[j] / 58) | 0;
14499
+ digits[j] %= 58;
14500
+ }
14501
+ while (carry) {
14502
+ digits.unshift(carry);
14503
+ carry = (digits[0] / 58) | 0;
14504
+ digits[0] %= 58;
14505
+ }
14506
+ }
14507
+ // deal with leading zeros
14508
+ for (i = 0; i < buffer.length - 1 && buffer[i] === 0; i++)
14509
+ digits.unshift(0);
14510
+ return digits.map(function (digit) { return Base58.alphabet[digit]; }).join('');
14511
+ }
14512
+ static decode(string) {
14513
+ if (string.length === 0)
14514
+ return (new Uint8Array(0));
14515
+ const input = string.split('').map(function (c) {
14516
+ return Base58.getAlphabetMap()[c];
14517
+ });
14518
+ let i;
14519
+ let j;
14520
+ const bytes = [0];
14521
+ for (i = 0; i < input.length; i++) {
14522
+ for (j = 0; j < bytes.length; j++)
14523
+ bytes[j] *= 58;
14524
+ bytes[bytes.length - 1] += input[i];
14525
+ let carry = 0;
14526
+ for (j = bytes.length - 1; j >= 0; j--) {
14527
+ bytes[j] += carry;
14528
+ carry = bytes[j] >> 8;
14529
+ bytes[j] &= 0xff;
14530
+ }
14531
+ while (carry) {
14532
+ bytes.unshift(carry);
14533
+ carry = bytes[0] >> 8;
14534
+ bytes[0] &= 0xff;
14535
+ }
14536
+ }
14537
+ // deal with leading zeros
14538
+ for (i = 0; i < input.length - 1 && input[i] === 0; i++)
14539
+ bytes.unshift(0);
14540
+ return (new Uint8Array(bytes));
14541
+ }
14542
+ }
14543
+ Base58.alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
14544
+
14545
+ const ED25519_SEED_LENGTH = 32; // Length of a ED25519 seed
14546
+ const SCRYPT_PARAMS = {
14547
+ SIMPLE: {
14548
+ N: 2048,
14549
+ r: 8,
14550
+ p: 1
14551
+ },
14552
+ DEFAULT: {
14553
+ N: 4096,
14554
+ r: 16,
14555
+ p: 1
14556
+ },
14557
+ SECURE: {
14558
+ N: 16384,
14559
+ r: 32,
14560
+ p: 2
14561
+ },
14562
+ HARDEST: {
14563
+ N: 65536,
14564
+ r: 32,
14565
+ p: 4
14566
+ },
14567
+ EXTREME: {
14568
+ N: 262144,
14569
+ r: 64,
14570
+ p: 8
14571
+ }
14572
+ };
14573
+ class CryptoService {
14574
+ static get started() {
14575
+ return this._ready;
14576
+ }
14577
+ static ready() {
14578
+ return __awaiter(this, void 0, void 0, function* () {
14579
+ if (this._ready)
14580
+ return; // OK
14581
+ yield cryptoWaitReady();
14582
+ this._ready = true;
14583
+ });
14584
+ }
14585
+ /**
14586
+ * Generate a sign keypair, using scrypt, from a salt and a password
14587
+ *
14588
+ * @param salt
14589
+ * @param password
14590
+ * @param scryptParams
14591
+ */
14592
+ static scryptKeypair(salt, password, scryptParams) {
14593
+ return __awaiter(this, void 0, void 0, function* () {
14594
+ if (!this.started)
14595
+ yield this.ready();
14596
+ const passwordU8a = decodeUTF8(password);
14597
+ const saltU8a = decodeUTF8(salt);
14598
+ const result = scryptEncode(passwordU8a, saltU8a, scryptParams || SCRYPT_PARAMS.DEFAULT);
14599
+ const seed = result.password.slice(0, ED25519_SEED_LENGTH);
14600
+ return ed25519PairFromSeed(seed);
14601
+ });
14602
+ }
14603
+ /**
14604
+ * Sign a message, from a key pair
14605
+ */
14606
+ static sign(message, keypair) {
14607
+ return __awaiter(this, void 0, void 0, function* () {
14608
+ if (!this.started)
14609
+ yield this.ready();
14610
+ const m = decodeUTF8(message);
14611
+ const sig = ed25519Sign(m, keypair);
14612
+ return encodeBase64(sig);
14613
+ });
14614
+ }
14048
14615
  /**
14049
14616
  * Sign a message, from a key pair
14050
14617
  */
@@ -14110,6 +14677,7 @@ const NetworkRefreshTimerPeriod = {
14110
14677
  MOBILE: 1000 * 60 * 10 /* every 10 min */,
14111
14678
  DESKTOP: 1000 * 60 * 5 /* every 5 min */
14112
14679
  };
14680
+ const PEER_URL_REGEXP = /^(http|https):\/\/[^ "?#@]+$/;
14113
14681
  /* -- DEV only (to debug refresh timer)
14114
14682
  const NetworkRefreshTimerPeriod = {
14115
14683
  MOBILE: 1000,
@@ -14419,12 +14987,7 @@ class NetworkService extends StartableObservableService {
14419
14987
  const peers$ = $onRefresh.pipe(mergeMap((_) => this.getDefaultPeers()), map(peers => peers || []));
14420
14988
  const modal = yield this.modalCtrl.create({
14421
14989
  component: SelectPeerModal,
14422
- componentProps: {
14423
- onRefresh: $onRefresh,
14424
- peers: peers$,
14425
- canCancel: toBoolean(opts.canCancel, true),
14426
- allowSelectDownPeer: toBoolean(opts.allowSelectDownPeer, true)
14427
- },
14990
+ componentProps: Object.assign({ onRefresh: $onRefresh, peers: peers$ }, opts),
14428
14991
  keyboardClose: true,
14429
14992
  showBackdrop: true
14430
14993
  });
@@ -14987,7 +15550,6 @@ function accountToString(data) {
14987
15550
  (data.lastName || '')) || '';
14988
15551
  }
14989
15552
 
14990
- const uuidv4 = uuidv4Imported;
14991
15553
  const _global = typeof global !== 'undefined' ? global : (typeof window !== 'undefined' ? window : {});
14992
15554
  const NativeWebSocket = _global.WebSocket || _global.MozWebSocket;
14993
15555
  /**
@@ -15031,7 +15593,7 @@ function createTrackerLink(opts) {
15031
15593
  // Skip if not tracked
15032
15594
  if (!context || !context.tracked)
15033
15595
  return forward(operation);
15034
- const id = context.serializationKey || uuidv4();
15596
+ const id = context.serializationKey || v4();
15035
15597
  console.debug(`[apollo-tracker-link] Watching tracked query {${operation.operationName}#${id}}`);
15036
15598
  // Clean context, before calling JSON.stringify (remove unused attributes)
15037
15599
  const cleanContext = Object.assign(Object.assign({}, context), { optimisticResponse: null, cache: null });
@@ -19010,44 +19572,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
19010
19572
  }]
19011
19573
  }], ctorParameters: function () { return []; } });
19012
19574
 
19013
- class MatAutocompleteConfigHolder {
19014
- constructor(options) {
19015
- this.options = options;
19016
- this.fields = {};
19017
- // Store the function from options (e.g. get from user settings)
19018
- // or create a default function
19019
- this.getUserAttributes = (options === null || options === void 0 ? void 0 : options.getUserAttributes) ||
19020
- ((fieldName, defaultAttributes) => defaultAttributes || ['label', 'name']);
19021
- }
19022
- add(fieldName, options) {
19023
- if (!fieldName) {
19024
- throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
19025
- }
19026
- options = options || {};
19027
- const suggestFn = options.suggestFn
19028
- || (options.service && ((v, f) => options.service.suggest(v, f)))
19029
- || undefined;
19030
- const attributes = (this.getUserAttributes(fieldName, options.attributes) || ['label', 'name']);
19031
- // Keep original the function from options, when exists
19032
- const attributesOrFn = attributes.map((a, index) => typeof a === 'function' && options.attributes[index] || a);
19033
- const filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
19034
- const displayWith = options.displayWith || MatAutocompleteFieldUtils.createDisplayFn(attributes, options.multiple);
19035
- const equals = options.equals || MatAutocompleteFieldUtils.defaultEquals;
19036
- const config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn,
19037
- filter,
19038
- displayWith,
19039
- equals });
19040
- this.fields[fieldName] = config;
19041
- return config;
19042
- }
19043
- get(fieldName) {
19044
- if (!fieldName) {
19045
- throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
19046
- }
19047
- return this.fields[fieldName] || this.add(fieldName);
19048
- }
19049
- }
19050
-
19051
19575
  class FormFieldValuesHolder {
19052
19576
  getAsBoolean(data, definition) {
19053
19577
  const value = this.get(data, definition);
@@ -21140,6 +21664,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
21140
21664
  }]
21141
21665
  }] });
21142
21666
 
21667
+ class AppTextPopoverModule {
21668
+ }
21669
+ AppTextPopoverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
21670
+ AppTextPopoverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, declarations: [
21671
+ // Components
21672
+ TextForm,
21673
+ TextPopover
21674
+ ], imports: [SharedModule, i1$1.TranslateModule], exports: [TranslateModule,
21675
+ // Components
21676
+ TextForm,
21677
+ TextPopover] });
21678
+ AppTextPopoverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, imports: [SharedModule,
21679
+ TranslateModule.forChild(), TranslateModule] });
21680
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, decorators: [{
21681
+ type: NgModule,
21682
+ args: [{
21683
+ imports: [
21684
+ SharedModule,
21685
+ TranslateModule.forChild()
21686
+ ],
21687
+ declarations: [
21688
+ // Components
21689
+ TextForm,
21690
+ TextPopover
21691
+ ],
21692
+ exports: [
21693
+ TranslateModule,
21694
+ // Components
21695
+ TextForm,
21696
+ TextPopover
21697
+ ]
21698
+ }]
21699
+ }] });
21700
+
21143
21701
  class AppSelectPeerModule {
21144
21702
  }
21145
21703
  AppSelectPeerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -21147,19 +21705,21 @@ AppSelectPeerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", ver
21147
21705
  // Network
21148
21706
  SelectPeerModal
21149
21707
  ], imports: [SharedModule,
21150
- HttpClientModule, i1$1.TranslateModule], exports: [TranslateModule,
21708
+ HttpClientModule, i1$1.TranslateModule, AppTextPopoverModule], exports: [TranslateModule,
21151
21709
  // Components
21152
21710
  SelectPeerModal] });
21153
21711
  AppSelectPeerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, imports: [SharedModule,
21154
21712
  HttpClientModule,
21155
- TranslateModule.forChild(), TranslateModule] });
21713
+ TranslateModule.forChild(),
21714
+ AppTextPopoverModule, TranslateModule] });
21156
21715
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, decorators: [{
21157
21716
  type: NgModule,
21158
21717
  args: [{
21159
21718
  imports: [
21160
21719
  SharedModule,
21161
21720
  HttpClientModule,
21162
- TranslateModule.forChild()
21721
+ TranslateModule.forChild(),
21722
+ AppTextPopoverModule
21163
21723
  ],
21164
21724
  declarations: [
21165
21725
  // Network
@@ -21591,577 +22151,240 @@ class AccountValidatorService extends AppValidatorService {
21591
22151
  lastName: [data && data.lastName || null, Validators.compose([Validators.required, Validators.minLength(2)])],
21592
22152
  firstName: [data && data.firstName || null, Validators.compose([Validators.required, Validators.minLength(2)])],
21593
22153
  email: [data && data.email || null, Validators.compose([Validators.required, Validators.email])],
21594
- mainProfile: [data && (data.mainProfile || PersonUtils.getMainProfile(data.profiles)) || 'GUEST', Validators.required],
21595
- statusId: [data && data.statusId || StatusIds.TEMPORARY, Validators.required],
21596
- pubkey: [data && data.pubkey || null, Validators.compose([Validators.required, SharedValidators.pubkey])]
21597
- };
21598
- // Add additional fields
21599
- this.accountService.additionalFields.forEach(field => {
21600
- //console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
21601
- formDef[field.key] = [data && data[field.key] || null, this.getValidators(field)];
21602
- });
21603
- return formDef;
21604
- }
21605
- getValidators(field) {
21606
- const validatorFns = [];
21607
- if (field.extra && field.extra.account && field.extra.account.required) {
21608
- validatorFns.push(Validators.required);
21609
- }
21610
- if (field.type === 'entity') {
21611
- validatorFns.push(SharedValidators.entity);
21612
- }
21613
- return validatorFns.length ? Validators.compose(validatorFns) : validatorFns.length === 1 ? validatorFns[0] : undefined;
21614
- }
21615
- }
21616
- AccountValidatorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, deps: [{ token: i1$2.UntypedFormBuilder }, { token: AccountService }], target: i0.ɵɵFactoryTarget.Injectable });
21617
- AccountValidatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, providedIn: 'root' });
21618
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, decorators: [{
21619
- type: Injectable,
21620
- args: [{ providedIn: 'root' }]
21621
- }], ctorParameters: function () { return [{ type: i1$2.UntypedFormBuilder }, { type: AccountService }]; } });
21622
-
21623
- class RegisterForm {
21624
- constructor(accountService, accountValidatorService, formBuilder, environment, settings) {
21625
- this.accountService = accountService;
21626
- this.accountValidatorService = accountValidatorService;
21627
- this.formBuilder = formBuilder;
21628
- this.environment = environment;
21629
- this.settings = settings;
21630
- this.debug = false;
21631
- this.subscriptions = [];
21632
- this.sending = false;
21633
- this.showPwd = false;
21634
- this.showConfirmPwd = false;
21635
- this.onCancel = new EventEmitter();
21636
- this.onSubmit = new EventEmitter();
21637
- this.referentialToString = referentialToString;
21638
- this.forms = [];
21639
- // Email form
21640
- this.forms.push(formBuilder.group({
21641
- email: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.email]), this.emailAvailability(this.accountService)),
21642
- confirmEmail: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('email')]))
21643
- }));
21644
- // Password form
21645
- this.forms.push(formBuilder.group({
21646
- password: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(8)])),
21647
- confirmPassword: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('password')]))
21648
- }));
21649
- // Detail form
21650
- const formDetailDef = {
21651
- lastName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)])),
21652
- firstName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)]))
21653
- };
21654
- // Prepare autocomplete settings
21655
- this.autocompleteHelper = new MatAutocompleteConfigHolder(settings && {
21656
- getUserAttributes: (a, b) => settings.getFieldDisplayAttributes(a, b)
21657
- });
21658
- // Add additional fields to details form
21659
- this.additionalFields = this.accountService.additionalFields
21660
- // Keep only required fields
21661
- .filter(field => field.extra && field.extra.registration && field.extra.registration.required);
21662
- this.additionalFields.forEach(field => {
21663
- //if (this.debug) console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
21664
- formDetailDef[field.key] = new UntypedFormControl(null, this.accountValidatorService.getValidators(field));
21665
- if (field.type === 'entity') {
21666
- field.autocomplete = this.autocompleteHelper.add(field.key, field.autocomplete);
21667
- }
21668
- });
21669
- this.forms.push(formBuilder.group(formDetailDef));
21670
- this.form = formBuilder.group({
21671
- emailStep: this.forms[0],
21672
- passwordStep: this.forms[1],
21673
- detailsStep: this.forms[2]
21674
- });
21675
- }
21676
- ngOnInit() {
21677
- // For DEV only ------------------------
21678
- if (!this.environment.production) {
21679
- this.form.setValue({
21680
- emailStep: {
21681
- email: 'contact@e-is.pro',
21682
- confirmEmail: 'contact@e-is.pro'
21683
- },
21684
- passwordStep: {
21685
- password: 'contactera',
21686
- confirmPassword: 'contactera'
21687
- },
21688
- detailsStep: {
21689
- lastName: 'Lavenier 2',
21690
- firstName: 'Benoit',
21691
- department: null
21692
- }
21693
- });
21694
- }
21695
- }
21696
- get value() {
21697
- const result = {
21698
- username: this.form.value.emailStep.email,
21699
- password: this.form.value.passwordStep.password,
21700
- account: new Account()
21701
- };
21702
- result.account.fromObject(this.form.value.detailsStep);
21703
- result.account.email = result.username;
21704
- return result;
21705
- }
21706
- get valid() {
21707
- return this.form.valid;
21708
- }
21709
- isEnd() {
21710
- return this.stepper.selectedIndex === 2;
21711
- }
21712
- isBeginning() {
21713
- return this.stepper.selectedIndex === 0;
21714
- }
21715
- slidePrev() {
21716
- return this.stepper.previous();
21717
- }
21718
- slideNext(event) {
21719
- if (event) {
21720
- event.stopPropagation();
21721
- event.preventDefault();
21722
- }
21723
- return this.stepper.next();
21724
- }
21725
- equalsValidator(otherControlName) {
21726
- return function (c) {
21727
- if (c.parent && c.value !== c.parent.value[otherControlName]) {
21728
- return {
21729
- equals: true
21730
- };
21731
- }
21732
- return null;
21733
- };
21734
- }
21735
- emailAvailability(accountService) {
21736
- return function (control) {
21737
- return timer(500).pipe(mergeMap(() => accountService.checkEmailAvailable(control.value)
21738
- .then(res => null)
21739
- .catch(err => {
21740
- console.error(err);
21741
- return { availability: true };
21742
- })));
21743
- };
21744
- }
21745
- cancel() {
21746
- this.onCancel.emit();
21747
- }
21748
- doSubmit(event) {
21749
- if (this.form.invalid)
21750
- return;
21751
- this.sending = true;
21752
- this.onSubmit.emit(this.value);
21753
- }
21754
- markAsTouched() {
21755
- this.form.markAsTouched();
21756
- }
21757
- disable() {
21758
- this.form.disable();
21759
- }
21760
- enable() {
21761
- this.form.enable();
21762
- }
21763
- }
21764
- RegisterForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterForm, deps: [{ token: AccountService }, { token: AccountValidatorService }, { token: i1$2.UntypedFormBuilder }, { token: ENVIRONMENT }, { token: LocalSettingsService }], target: i0.ɵɵFactoryTarget.Component });
21765
- RegisterForm.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: RegisterForm, selector: "app-register-form", outputs: { onCancel: "onCancel", onSubmit: "onSubmit" }, viewQueries: [{ propertyName: "stepper", first: true, predicate: ["stepper"], descendants: true, static: true }], ngImport: i0, template: "<mat-horizontal-stepper linear #stepper=\"matHorizontalStepper\">\n\n <!-- Step 1: Username -->\n <mat-step [stepControl]=\"forms[0]\" *ngIf=\"forms[0].controls; let controls\">\n\n <form [formGroup]=\"forms[0]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n <ng-template matStepLabel>{{'REGISTER.STEP_EMAIL'|translate}}</ng-template>\n\n <!-- Email -->\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\" [autofocusDelay]=\"500\" [placeholder]=\"'USER.EMAIL'|translate\"\n formControlName=\"email\" autocomplete=\"off\" required>\n <mat-error *ngIf=\"controls.email.hasError('required') && controls.email.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.email.hasError('email') && !controls.email.hasError('required') && controls.email.touched\">\n <span>{{'ERROR.FIELD_NOT_VALID_EMAIL' | translate }}</span>\n </mat-error>\n <mat-error *ngIf=\"controls.email.hasError('availability') && controls.email.touched\" translate>REGISTER.ERROR.EMAIL_ALREADY_REGISTERED</mat-error>\n\n </mat-form-field>\n\n <!-- Confirm Email -->\n <mat-form-field>\n <input matInput autocomplete=\"off\" matFormFieldControl [placeholder]=\"'REGISTER.CONFIRM_EMAIL'|translate\" formControlName=\"confirmEmail\">\n <mat-error *ngIf=\"controls.confirmEmail.hasError('required') && controls.confirmEmail.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmEmail.hasError('equals') && controls.confirmEmail.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_EMAIL' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 2: Password -->\n <mat-step [stepControl]=\"forms[1]\" *ngIf=\"forms[1].controls; let controls\">\n\n <form [formGroup]=\"forms[1]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_PASSWORD'|translate}}</ng-template>\n\n <!-- Password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.PASSWORD'|translate\"\n formControlName=\"password\"\n autocomplete=\"section-red new-password\"\n [type]=\"showPwd ? 'text' : 'password'\"\n required>\n <button matSuffix mat-icon-button\n type=\"button\"\n (click)=\"showPwd = !showPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.password.hasError('required') && controls.password.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.password.hasError('minlength') && controls.password.touched\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 8} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Confirm password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'REGISTER.CONFIRM_PASSWORD'|translate\"\n formControlName=\"confirmPassword\"\n autocomplete=\"section-red new-password\"\n [type]=\"showConfirmPwd ? 'text' : 'password'\"\n required>\n <button mat-icon-button matSuffix\n (click)=\"showConfirmPwd = !showConfirmPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showConfirmPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('required') && controls.confirmPassword.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('equals') && controls.confirmPassword.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_PASSWORD' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 3: user details -->\n <mat-step [stepControl]=\"forms[2]\" *ngIf=\"forms[2].controls; let controls\">\n\n <form [formGroup]=\"forms[2]\" (ngSubmit)=\"doSubmit($event)\" class=\"form-container ion-padding\" (keyup.enter)=\"doSubmit()\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_USER_DETAILS'|translate}}</ng-template>\n\n <!-- error -->\n <ion-item *ngIf=\"error && !sending\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <!-- Last name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.LAST_NAME'|translate\" formControlName=\"lastName\" autocomplete=\"section-blue family-name\"\n required>\n <mat-error *ngIf=\"controls.lastName.hasError('required') && controls.lastName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.lastName.hasError('minlength') && controls.lastName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- First name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.FIRST_NAME'|translate\" formControlName=\"firstName\" autocomplete=\"section-blue given-name\"\n required>\n <mat-error *ngIf=\"controls.firstName.hasError('required') && controls.firstName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.firstName.hasError('minlength') && controls.firstName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Additional fields -->\n <app-form-field *ngFor=\"let field of additionalFields\"\n [definition]=\"field\"\n [formControlName]=\"field.key\"\n [required]=\"true\">\n </app-form-field>\n\n </form>\n </mat-step>\n</mat-horizontal-stepper>\n", styles: ["form ion-toolbar.toolbar-buttons .toolbar-content{text-align:right}form ion-toolbar.toolbar-buttons .toolbar-background{border:0;background:inherit!important}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatSuffix, selector: "[matSuffix]" }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i11.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i12$1.MatStep, selector: "mat-step", inputs: ["color"], exportAs: ["matStep"] }, { kind: "directive", type: i12$1.MatStepLabel, selector: "[matStepLabel]" }, { kind: "component", type: i12$1.MatStepper, selector: "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", inputs: ["selectedIndex", "disableRipple", "color", "labelPosition", "headerPosition", "animationDuration"], outputs: ["animationDone"], exportAs: ["matStepper", "matVerticalStepper", "matHorizontalStepper"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "component", type: AppFormField, selector: "app-form-field", inputs: ["definition", "required", "readonly", "disabled", "formControl", "formControlName", "placeholder", "compact", "floatLabel", "tabindex", "autofocus", "chipColor", "class"], outputs: ["keyup.enter"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
21766
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterForm, decorators: [{
21767
- type: Component,
21768
- args: [{ selector: 'app-register-form', template: "<mat-horizontal-stepper linear #stepper=\"matHorizontalStepper\">\n\n <!-- Step 1: Username -->\n <mat-step [stepControl]=\"forms[0]\" *ngIf=\"forms[0].controls; let controls\">\n\n <form [formGroup]=\"forms[0]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n <ng-template matStepLabel>{{'REGISTER.STEP_EMAIL'|translate}}</ng-template>\n\n <!-- Email -->\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\" [autofocusDelay]=\"500\" [placeholder]=\"'USER.EMAIL'|translate\"\n formControlName=\"email\" autocomplete=\"off\" required>\n <mat-error *ngIf=\"controls.email.hasError('required') && controls.email.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.email.hasError('email') && !controls.email.hasError('required') && controls.email.touched\">\n <span>{{'ERROR.FIELD_NOT_VALID_EMAIL' | translate }}</span>\n </mat-error>\n <mat-error *ngIf=\"controls.email.hasError('availability') && controls.email.touched\" translate>REGISTER.ERROR.EMAIL_ALREADY_REGISTERED</mat-error>\n\n </mat-form-field>\n\n <!-- Confirm Email -->\n <mat-form-field>\n <input matInput autocomplete=\"off\" matFormFieldControl [placeholder]=\"'REGISTER.CONFIRM_EMAIL'|translate\" formControlName=\"confirmEmail\">\n <mat-error *ngIf=\"controls.confirmEmail.hasError('required') && controls.confirmEmail.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmEmail.hasError('equals') && controls.confirmEmail.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_EMAIL' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 2: Password -->\n <mat-step [stepControl]=\"forms[1]\" *ngIf=\"forms[1].controls; let controls\">\n\n <form [formGroup]=\"forms[1]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_PASSWORD'|translate}}</ng-template>\n\n <!-- Password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.PASSWORD'|translate\"\n formControlName=\"password\"\n autocomplete=\"section-red new-password\"\n [type]=\"showPwd ? 'text' : 'password'\"\n required>\n <button matSuffix mat-icon-button\n type=\"button\"\n (click)=\"showPwd = !showPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.password.hasError('required') && controls.password.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.password.hasError('minlength') && controls.password.touched\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 8} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Confirm password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'REGISTER.CONFIRM_PASSWORD'|translate\"\n formControlName=\"confirmPassword\"\n autocomplete=\"section-red new-password\"\n [type]=\"showConfirmPwd ? 'text' : 'password'\"\n required>\n <button mat-icon-button matSuffix\n (click)=\"showConfirmPwd = !showConfirmPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showConfirmPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('required') && controls.confirmPassword.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('equals') && controls.confirmPassword.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_PASSWORD' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 3: user details -->\n <mat-step [stepControl]=\"forms[2]\" *ngIf=\"forms[2].controls; let controls\">\n\n <form [formGroup]=\"forms[2]\" (ngSubmit)=\"doSubmit($event)\" class=\"form-container ion-padding\" (keyup.enter)=\"doSubmit()\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_USER_DETAILS'|translate}}</ng-template>\n\n <!-- error -->\n <ion-item *ngIf=\"error && !sending\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <!-- Last name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.LAST_NAME'|translate\" formControlName=\"lastName\" autocomplete=\"section-blue family-name\"\n required>\n <mat-error *ngIf=\"controls.lastName.hasError('required') && controls.lastName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.lastName.hasError('minlength') && controls.lastName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- First name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.FIRST_NAME'|translate\" formControlName=\"firstName\" autocomplete=\"section-blue given-name\"\n required>\n <mat-error *ngIf=\"controls.firstName.hasError('required') && controls.firstName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.firstName.hasError('minlength') && controls.firstName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Additional fields -->\n <app-form-field *ngFor=\"let field of additionalFields\"\n [definition]=\"field\"\n [formControlName]=\"field.key\"\n [required]=\"true\">\n </app-form-field>\n\n </form>\n </mat-step>\n</mat-horizontal-stepper>\n", styles: ["form ion-toolbar.toolbar-buttons .toolbar-content{text-align:right}form ion-toolbar.toolbar-buttons .toolbar-background{border:0;background:inherit!important}\n"] }]
21769
- }], ctorParameters: function () {
21770
- return [{ type: AccountService }, { type: AccountValidatorService }, { type: i1$2.UntypedFormBuilder }, { type: undefined, decorators: [{
21771
- type: Inject,
21772
- args: [ENVIRONMENT]
21773
- }] }, { type: LocalSettingsService }];
21774
- }, propDecorators: { stepper: [{
21775
- type: ViewChild,
21776
- args: ['stepper', { static: true }]
21777
- }], onCancel: [{
21778
- type: Output
21779
- }], onSubmit: [{
21780
- type: Output
21781
- }] } });
21782
-
21783
- class RegisterModal {
21784
- constructor(accountService, viewCtrl) {
21785
- this.accountService = accountService;
21786
- this.viewCtrl = viewCtrl;
21787
- this.sending = false;
21788
- }
21789
- cancel() {
21790
- console.debug('[register] cancelled');
21791
- this.viewCtrl.dismiss();
21792
- }
21793
- doSubmit(event) {
21794
- return __awaiter(this, void 0, void 0, function* () {
21795
- if (this.form.form.disabled || this.sending)
21796
- return; // Skip
21797
- if (!this.form.valid || !this.form.isEnd()) {
21798
- this.form.markAsTouched();
21799
- return;
21800
- }
21801
- this.sending = true;
21802
- const data = this.form.value;
21803
- this.form.disable();
21804
- try {
21805
- console.debug('[register] Sending registration to server...', data);
21806
- const res = yield this.accountService.register(data);
21807
- console.debug('[register] Account registered!');
21808
- yield this.viewCtrl.dismiss();
21809
- }
21810
- catch (err) {
21811
- this.form.error = err && err.message || err;
21812
- this.form.enable();
21813
- }
21814
- finally {
21815
- this.sending = false;
21816
- }
21817
- });
21818
- }
21819
- }
21820
- RegisterModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterModal, deps: [{ token: AccountService }, { token: i2.ModalController }], target: i0.ɵɵFactoryTarget.Component });
21821
- RegisterModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: RegisterModal, selector: "app-register-modal", viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button *ngIf=\"form.isBeginning()\" (click)=\"cancel()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n <ion-button *ngIf=\"!form.isBeginning()\" (click)=\"form.slidePrev()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title translate>REGISTER.TITLE</ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-spinner *ngIf=\"sending\"></ion-spinner>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\"\n visible-xs visible-sm visible-mobile>\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd() && !sending\" (click)=\"doSubmit()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <app-register-form #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\">\n </app-register-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <!-- buttons -->\n <ion-toolbar>\n\n <ion-row>\n <ion-col></ion-col>\n <ion-col size=\"auto\">\n <ion-button *ngIf=\"form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"form.slidePrev()\" [disabled]=\"sending\">\n <ion-icon slot=\"start\" name=\"arrow-back\"></ion-icon>\n <ion-label translate>COMMON.BTN_BACK</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\" fill=\"solid\" color=\"tertiary\">\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd()\" (click)=\"doSubmit()\" fill=\"solid\" [disabled]=\"sending\" color=\"tertiary\">\n <span translate>COMMON.BTN_SEND</span>\n <ion-icon slot=\"end\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i2.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: RegisterForm, selector: "app-register-form", outputs: ["onCancel", "onSubmit"] }] });
21822
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterModal, decorators: [{
21823
- type: Component,
21824
- args: [{ selector: 'app-register-modal', template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button *ngIf=\"form.isBeginning()\" (click)=\"cancel()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n <ion-button *ngIf=\"!form.isBeginning()\" (click)=\"form.slidePrev()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title translate>REGISTER.TITLE</ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-spinner *ngIf=\"sending\"></ion-spinner>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\"\n visible-xs visible-sm visible-mobile>\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd() && !sending\" (click)=\"doSubmit()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <app-register-form #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\">\n </app-register-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <!-- buttons -->\n <ion-toolbar>\n\n <ion-row>\n <ion-col></ion-col>\n <ion-col size=\"auto\">\n <ion-button *ngIf=\"form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"form.slidePrev()\" [disabled]=\"sending\">\n <ion-icon slot=\"start\" name=\"arrow-back\"></ion-icon>\n <ion-label translate>COMMON.BTN_BACK</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\" fill=\"solid\" color=\"tertiary\">\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd()\" (click)=\"doSubmit()\" fill=\"solid\" [disabled]=\"sending\" color=\"tertiary\">\n <span translate>COMMON.BTN_SEND</span>\n <ion-icon slot=\"end\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n" }]
21825
- }], ctorParameters: function () { return [{ type: AccountService }, { type: i2.ModalController }]; }, propDecorators: { form: [{
21826
- type: ViewChild,
21827
- args: ['form', { static: true }]
21828
- }] } });
21829
-
21830
- // eslint-disable-next-line @angular-eslint/directive-class-suffix
21831
- class AppForm {
21832
- constructor(injector, form) {
21833
- this._subscription = new Subscription();
21834
- this._enable = false;
21835
- this.i18nFieldPrefix = null;
21836
- this.destroySubject = new Subject();
21837
- this.readySubject = new BehaviorSubject(false);
21838
- this.loadingSubject = new BehaviorSubject(true);
21839
- this.errorSubject = new BehaviorSubject(undefined);
21840
- this.debug = false;
21841
- this.onCancel = new EventEmitter();
21842
- this.onSubmit = new EventEmitter();
21843
- if (form)
21844
- this.setForm(form);
21845
- this.translate = injector.get(TranslateService);
21846
- this.settings = injector.get(LocalSettingsService);
21847
- this.errorTranslator = injector.get(FormErrorTranslator);
21848
- this.autocompleteHelper = new MatAutocompleteConfigHolder(this.settings && {
21849
- getUserAttributes: (a, b) => this.settings.getFieldDisplayAttributes(a, b)
21850
- });
21851
- this.autocompleteFields = this.autocompleteHelper.fields;
21852
- }
21853
- /**
21854
- * @deprecated
21855
- */
21856
- set _loading(value) {
21857
- this.loadingSubject.next(value);
21858
- }
21859
- /**
21860
- * @deprecated
21861
- */
21862
- get _loading() {
21863
- return this.loadingSubject.value;
21864
- }
21865
- /**
21866
- * @deprecated
21867
- */
21868
- get _$ready() {
21869
- return this.readySubject;
21870
- }
21871
- /**
21872
- * @deprecated
21873
- */
21874
- get _$loading() {
21875
- return this.loadingSubject;
21876
- }
21877
- get error() {
21878
- return this.errorSubject.value;
21879
- }
21880
- set error(error) {
21881
- this.setError(error);
21882
- }
21883
- get loading() {
21884
- return this.loadingSubject.value;
21885
- }
21886
- get loaded() {
21887
- return !this.loadingSubject.value;
21888
- }
21889
- get value() {
21890
- return this.form.value;
21891
- }
21892
- set value(data) {
21893
- this.setValue(data);
21894
- }
21895
- get dirty() {
21896
- var _a;
21897
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.dirty) || false;
21898
- }
21899
- get invalid() {
21900
- return !this.form || this.form.invalid;
21901
- }
21902
- get pending() {
21903
- return !this.form || (this.form.dirty && this.form.pending);
21904
- }
21905
- get valid() {
21906
- var _a;
21907
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
21908
- }
21909
- get empty() {
21910
- return !this.form || (!this.form.dirty && !this.form.touched);
21911
- }
21912
- get touched() {
21913
- var _a;
21914
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.touched) || false;
21915
- }
21916
- get untouched() {
21917
- return !this.form || this.form.untouched;
21918
- }
21919
- get enabled() {
21920
- return this._enable;
21921
- }
21922
- get disabled() {
21923
- return !this._enable;
21924
- }
21925
- disable(opts) {
21926
- var _a;
21927
- (_a = this.form) === null || _a === void 0 ? void 0 : _a.disable(opts);
21928
- if (this._enable) {
21929
- this._enable = false;
21930
- if (!opts || opts.emitEvent !== true)
21931
- this.markForCheck();
21932
- }
21933
- }
21934
- enable(opts) {
21935
- var _a;
21936
- (_a = this.form) === null || _a === void 0 ? void 0 : _a.enable(opts);
21937
- if (!this._enable) {
21938
- this._enable = true;
21939
- if (!opts || opts.emitEvent !== true)
21940
- this.markForCheck();
21941
- }
21942
- }
21943
- get destroyed() {
21944
- var _a;
21945
- return ((_a = this.destroySubject) === null || _a === void 0 ? void 0 : _a.closed) !== false;
21946
- }
21947
- set form(value) {
21948
- this.setForm(value);
21949
- }
21950
- get form() {
21951
- return this._form;
21952
- }
21953
- ngOnInit() {
21954
- this._enable ? this.enable() : this.disable();
21955
- this.errorTranslatorOptions = this.errorTranslatorOptions || {
21956
- controlPathTranslator: this
21957
- };
21958
- }
21959
- ngOnDestroy() {
21960
- this._subscription.unsubscribe();
21961
- this.readySubject.unsubscribe();
21962
- this.loadingSubject.unsubscribe();
21963
- this.errorSubject.unsubscribe();
21964
- this.onCancel.unsubscribe();
21965
- this.onSubmit.unsubscribe();
21966
- this.destroySubject.next();
21967
- this.destroySubject.unsubscribe();
21968
- }
21969
- cancel() {
21970
- return __awaiter(this, void 0, void 0, function* () {
21971
- this.onCancel.emit();
21972
- });
21973
- }
21974
- /**
21975
- *
21976
- * @param event
21977
- * @param opts allow to skip validation check, using {checkValid: false}
21978
- */
21979
- doSubmit(event, opts) {
21980
- return __awaiter(this, void 0, void 0, function* () {
21981
- if (!this._form) {
21982
- this.markAllAsTouched({ emitEvent: true });
21983
- return;
21984
- }
21985
- // Check if valid (if not disabled)
21986
- if ((!opts || opts.checkValid !== false) && !this._form.valid) {
21987
- // Wait validation end
21988
- yield AppFormUtils.waitWhilePending(this._form);
21989
- // Form is invalid: exit (+ log if debug)
21990
- if (this._form.invalid) {
21991
- this.markAllAsTouched({ emitEvent: true });
21992
- if (this.debug)
21993
- AppFormUtils.logFormErrors(this._form);
21994
- return;
21995
- }
21996
- }
21997
- // Emit event
21998
- this.onSubmit.emit(event);
21999
- });
22000
- }
22001
- setForm(form) {
22002
- if (this._form !== form) {
22003
- this._form = form;
22004
- this._subscription.add(this._form.statusChanges.subscribe(status => this.markForCheck()));
22005
- }
22006
- }
22007
- setValue(data, opts) {
22008
- if (!data) {
22009
- console.warn('[form] Trying to set an empty value to form. Skipping');
22010
- return;
22011
- }
22012
- // DEBUG
22013
- //if (this.debug) console.debug('[form] Updating form (using entity)', data);
22014
- // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
22015
- AppFormUtils.copyEntity2Form(data, this.form, Object.assign({ emitEvent: false, onlySelf: true }, opts));
22016
- if (!opts || opts.emitEvent !== true) {
22017
- this.markForCheck();
22018
- }
22154
+ mainProfile: [data && (data.mainProfile || PersonUtils.getMainProfile(data.profiles)) || 'GUEST', Validators.required],
22155
+ statusId: [data && data.statusId || StatusIds.TEMPORARY, Validators.required],
22156
+ pubkey: [data && data.pubkey || null, Validators.compose([Validators.required, SharedValidators.pubkey])]
22157
+ };
22158
+ // Add additional fields
22159
+ this.accountService.additionalFields.forEach(field => {
22160
+ //console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
22161
+ formDef[field.key] = [data && data[field.key] || null, this.getValidators(field)];
22162
+ });
22163
+ return formDef;
22019
22164
  }
22020
- reset(data, opts) {
22021
- if (data) {
22022
- if (this.debug)
22023
- console.debug('[form] Resetting form (using entity)', data);
22024
- // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
22025
- const json = AppFormUtils.getFormValueFromEntity(data, this.form);
22026
- this.form.reset(json, { emitEvent: false, onlySelf: true });
22165
+ getValidators(field) {
22166
+ const validatorFns = [];
22167
+ if (field.extra && field.extra.account && field.extra.account.required) {
22168
+ validatorFns.push(Validators.required);
22027
22169
  }
22028
- else {
22029
- this.form.reset(null, { emitEvent: false, onlySelf: true });
22170
+ if (field.type === 'entity') {
22171
+ validatorFns.push(SharedValidators.entity);
22030
22172
  }
22031
- if (!opts || opts.emitEvent !== true)
22032
- this.markForCheck();
22173
+ return validatorFns.length ? Validators.compose(validatorFns) : validatorFns.length === 1 ? validatorFns[0] : undefined;
22033
22174
  }
22034
- markAsPristine(opts) {
22035
- this.form.markAsPristine(opts);
22036
- if (!opts || opts.emitEvent !== false)
22037
- this.markForCheck();
22175
+ }
22176
+ AccountValidatorService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, deps: [{ token: i1$2.UntypedFormBuilder }, { token: AccountService }], target: i0.ɵɵFactoryTarget.Injectable });
22177
+ AccountValidatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, providedIn: 'root' });
22178
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, decorators: [{
22179
+ type: Injectable,
22180
+ args: [{ providedIn: 'root' }]
22181
+ }], ctorParameters: function () { return [{ type: i1$2.UntypedFormBuilder }, { type: AccountService }]; } });
22182
+
22183
+ class RegisterForm {
22184
+ constructor(accountService, accountValidatorService, formBuilder, environment, settings) {
22185
+ this.accountService = accountService;
22186
+ this.accountValidatorService = accountValidatorService;
22187
+ this.formBuilder = formBuilder;
22188
+ this.environment = environment;
22189
+ this.settings = settings;
22190
+ this.debug = false;
22191
+ this.subscriptions = [];
22192
+ this.sending = false;
22193
+ this.showPwd = false;
22194
+ this.showConfirmPwd = false;
22195
+ this.onCancel = new EventEmitter();
22196
+ this.onSubmit = new EventEmitter();
22197
+ this.referentialToString = referentialToString;
22198
+ this.forms = [];
22199
+ // Email form
22200
+ this.forms.push(formBuilder.group({
22201
+ email: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.email]), this.emailAvailability(this.accountService)),
22202
+ confirmEmail: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('email')]))
22203
+ }));
22204
+ // Password form
22205
+ this.forms.push(formBuilder.group({
22206
+ password: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(8)])),
22207
+ confirmPassword: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('password')]))
22208
+ }));
22209
+ // Detail form
22210
+ const formDetailDef = {
22211
+ lastName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)])),
22212
+ firstName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)]))
22213
+ };
22214
+ // Prepare autocomplete settings
22215
+ this.autocompleteHelper = new MatAutocompleteConfigHolder(settings && {
22216
+ getUserAttributes: (a, b) => settings.getFieldDisplayAttributes(a, b)
22217
+ });
22218
+ // Add additional fields to details form
22219
+ this.additionalFields = this.accountService.additionalFields
22220
+ // Keep only required fields
22221
+ .filter(field => field.extra && field.extra.registration && field.extra.registration.required);
22222
+ this.additionalFields.forEach(field => {
22223
+ //if (this.debug) console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
22224
+ formDetailDef[field.key] = new UntypedFormControl(null, this.accountValidatorService.getValidators(field));
22225
+ if (field.type === 'entity') {
22226
+ field.autocomplete = this.autocompleteHelper.add(field.key, field.autocomplete);
22227
+ }
22228
+ });
22229
+ this.forms.push(formBuilder.group(formDetailDef));
22230
+ this.form = formBuilder.group({
22231
+ emailStep: this.forms[0],
22232
+ passwordStep: this.forms[1],
22233
+ detailsStep: this.forms[2]
22234
+ });
22038
22235
  }
22039
- markAsUntouched(opts) {
22040
- this.form.markAsUntouched(opts);
22041
- if (!opts || opts.emitEvent !== false)
22042
- this.markForCheck();
22236
+ ngOnInit() {
22237
+ // For DEV only ------------------------
22238
+ if (!this.environment.production) {
22239
+ this.form.setValue({
22240
+ emailStep: {
22241
+ email: 'contact@e-is.pro',
22242
+ confirmEmail: 'contact@e-is.pro'
22243
+ },
22244
+ passwordStep: {
22245
+ password: 'contactera',
22246
+ confirmPassword: 'contactera'
22247
+ },
22248
+ detailsStep: {
22249
+ lastName: 'Lavenier 2',
22250
+ firstName: 'Benoit',
22251
+ department: null
22252
+ }
22253
+ });
22254
+ }
22043
22255
  }
22044
- /**
22045
- * @deprecated prefer to use markAllAsTouched()
22046
- * @param opts
22047
- */
22048
- markAsTouched(opts) {
22049
- // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
22050
- console.warn('TODO: Replace this call by markAllAsTouched() - because of changes in ngx-components >= 0.16.0');
22051
- AppFormUtils.markAsTouched(this.form, opts);
22052
- if (!opts || opts.emitEvent !== false)
22053
- this.markForCheck();
22256
+ get value() {
22257
+ const result = {
22258
+ username: this.form.value.emailStep.email,
22259
+ password: this.form.value.passwordStep.password,
22260
+ account: new Account()
22261
+ };
22262
+ result.account.fromObject(this.form.value.detailsStep);
22263
+ result.account.email = result.username;
22264
+ return result;
22054
22265
  }
22055
- markAllAsTouched(opts) {
22056
- // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
22057
- AppFormUtils.markAllAsTouched(this.form, opts);
22058
- if (!opts || opts.emitEvent !== false)
22059
- this.markForCheck();
22266
+ get valid() {
22267
+ return this.form.valid;
22060
22268
  }
22061
- markAsDirty(opts) {
22062
- this.form.markAsDirty(opts);
22063
- if (!opts || opts.emitEvent !== false)
22064
- this.markForCheck();
22269
+ isEnd() {
22270
+ return this.stepper.selectedIndex === 2;
22065
22271
  }
22066
- markAsLoading(opts) {
22067
- this.setLoading(true, opts);
22272
+ isBeginning() {
22273
+ return this.stepper.selectedIndex === 0;
22068
22274
  }
22069
- markAsLoaded(opts) {
22070
- this.setLoading(false, opts);
22275
+ slidePrev() {
22276
+ return this.stepper.previous();
22071
22277
  }
22072
- markAsReady(opts) {
22073
- if (this.readySubject.value !== true) {
22074
- this.readySubject.next(true);
22075
- // If subclasses implements OnReady
22076
- if (typeof this['ngOnReady'] === 'function') {
22077
- this.ngOnReady();
22078
- }
22278
+ slideNext(event) {
22279
+ if (event) {
22280
+ event.stopPropagation();
22281
+ event.preventDefault();
22079
22282
  }
22283
+ return this.stepper.next();
22080
22284
  }
22081
- /**
22082
- * Wait form is ready
22083
- * @param opts
22084
- */
22085
- ready(opts) {
22086
- if (this.readySubject.value)
22087
- return Promise.resolve();
22088
- return waitForTrue(this.readySubject, opts);
22285
+ equalsValidator(otherControlName) {
22286
+ return function (c) {
22287
+ if (c.parent && c.value !== c.parent.value[otherControlName]) {
22288
+ return {
22289
+ equals: true
22290
+ };
22291
+ }
22292
+ return null;
22293
+ };
22089
22294
  }
22090
- /**
22091
- * Wait form is not busy (=loaded)
22092
- * @param opts
22093
- */
22094
- waitIdle(opts) {
22095
- if (!this.loadingSubject.value)
22096
- return Promise.resolve();
22097
- return waitForFalse(this.loadingSubject, opts);
22295
+ emailAvailability(accountService) {
22296
+ return function (control) {
22297
+ return timer(500).pipe(mergeMap(() => accountService.checkEmailAvailable(control.value)
22298
+ .then(res => null)
22299
+ .catch(err => {
22300
+ console.error(err);
22301
+ return { availability: true };
22302
+ })));
22303
+ };
22098
22304
  }
22099
- updateValueAndValidity(opts) {
22100
- AppFormUtils.updateValueAndValidity(this.form, opts);
22101
- if (!opts || opts.emitEvent !== false)
22102
- this.markForCheck();
22305
+ cancel() {
22306
+ this.onCancel.emit();
22103
22307
  }
22104
- translateControlPath(path) {
22105
- var _a;
22106
- const i18nFieldName = this.getI18nFieldName(path);
22107
- return ((_a = this.translate) === null || _a === void 0 ? void 0 : _a.instant(i18nFieldName)) || i18nFieldName;
22308
+ doSubmit(event) {
22309
+ if (this.form.invalid)
22310
+ return;
22311
+ this.sending = true;
22312
+ this.onSubmit.emit(this.value);
22108
22313
  }
22109
- /* -- protected methods -- */
22110
- getFormError(form, opts) {
22111
- if (!form || !this.errorTranslator)
22112
- return undefined;
22113
- return this.errorTranslator.translateFormErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
22314
+ markAsTouched() {
22315
+ this.form.markAsTouched();
22114
22316
  }
22115
- getI18nFieldName(path) {
22116
- return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
22317
+ disable() {
22318
+ this.form.disable();
22117
22319
  }
22118
- registerSubscription(sub) {
22119
- this._subscription.add(sub);
22320
+ enable() {
22321
+ this.form.enable();
22120
22322
  }
22121
- unregisterSubscription(sub) {
22122
- this._subscription.remove(sub);
22323
+ }
22324
+ RegisterForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterForm, deps: [{ token: AccountService }, { token: AccountValidatorService }, { token: i1$2.UntypedFormBuilder }, { token: ENVIRONMENT }, { token: LocalSettingsService }], target: i0.ɵɵFactoryTarget.Component });
22325
+ RegisterForm.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: RegisterForm, selector: "app-register-form", outputs: { onCancel: "onCancel", onSubmit: "onSubmit" }, viewQueries: [{ propertyName: "stepper", first: true, predicate: ["stepper"], descendants: true, static: true }], ngImport: i0, template: "<mat-horizontal-stepper linear #stepper=\"matHorizontalStepper\">\n\n <!-- Step 1: Username -->\n <mat-step [stepControl]=\"forms[0]\" *ngIf=\"forms[0].controls; let controls\">\n\n <form [formGroup]=\"forms[0]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n <ng-template matStepLabel>{{'REGISTER.STEP_EMAIL'|translate}}</ng-template>\n\n <!-- Email -->\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\" [autofocusDelay]=\"500\" [placeholder]=\"'USER.EMAIL'|translate\"\n formControlName=\"email\" autocomplete=\"off\" required>\n <mat-error *ngIf=\"controls.email.hasError('required') && controls.email.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.email.hasError('email') && !controls.email.hasError('required') && controls.email.touched\">\n <span>{{'ERROR.FIELD_NOT_VALID_EMAIL' | translate }}</span>\n </mat-error>\n <mat-error *ngIf=\"controls.email.hasError('availability') && controls.email.touched\" translate>REGISTER.ERROR.EMAIL_ALREADY_REGISTERED</mat-error>\n\n </mat-form-field>\n\n <!-- Confirm Email -->\n <mat-form-field>\n <input matInput autocomplete=\"off\" matFormFieldControl [placeholder]=\"'REGISTER.CONFIRM_EMAIL'|translate\" formControlName=\"confirmEmail\">\n <mat-error *ngIf=\"controls.confirmEmail.hasError('required') && controls.confirmEmail.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmEmail.hasError('equals') && controls.confirmEmail.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_EMAIL' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 2: Password -->\n <mat-step [stepControl]=\"forms[1]\" *ngIf=\"forms[1].controls; let controls\">\n\n <form [formGroup]=\"forms[1]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_PASSWORD'|translate}}</ng-template>\n\n <!-- Password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.PASSWORD'|translate\"\n formControlName=\"password\"\n autocomplete=\"section-red new-password\"\n [type]=\"showPwd ? 'text' : 'password'\"\n required>\n <button matSuffix mat-icon-button\n type=\"button\"\n (click)=\"showPwd = !showPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.password.hasError('required') && controls.password.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.password.hasError('minlength') && controls.password.touched\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 8} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Confirm password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'REGISTER.CONFIRM_PASSWORD'|translate\"\n formControlName=\"confirmPassword\"\n autocomplete=\"section-red new-password\"\n [type]=\"showConfirmPwd ? 'text' : 'password'\"\n required>\n <button mat-icon-button matSuffix\n (click)=\"showConfirmPwd = !showConfirmPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showConfirmPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('required') && controls.confirmPassword.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('equals') && controls.confirmPassword.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_PASSWORD' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 3: user details -->\n <mat-step [stepControl]=\"forms[2]\" *ngIf=\"forms[2].controls; let controls\">\n\n <form [formGroup]=\"forms[2]\" (ngSubmit)=\"doSubmit($event)\" class=\"form-container ion-padding\" (keyup.enter)=\"doSubmit()\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_USER_DETAILS'|translate}}</ng-template>\n\n <!-- error -->\n <ion-item *ngIf=\"error && !sending\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <!-- Last name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.LAST_NAME'|translate\" formControlName=\"lastName\" autocomplete=\"section-blue family-name\"\n required>\n <mat-error *ngIf=\"controls.lastName.hasError('required') && controls.lastName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.lastName.hasError('minlength') && controls.lastName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- First name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.FIRST_NAME'|translate\" formControlName=\"firstName\" autocomplete=\"section-blue given-name\"\n required>\n <mat-error *ngIf=\"controls.firstName.hasError('required') && controls.firstName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.firstName.hasError('minlength') && controls.firstName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Additional fields -->\n <app-form-field *ngFor=\"let field of additionalFields\"\n [definition]=\"field\"\n [formControlName]=\"field.key\"\n [required]=\"true\">\n </app-form-field>\n\n </form>\n </mat-step>\n</mat-horizontal-stepper>\n", styles: ["form ion-toolbar.toolbar-buttons .toolbar-content{text-align:right}form ion-toolbar.toolbar-buttons .toolbar-background{border:0;background:inherit!important}\n"], dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatSuffix, selector: "[matSuffix]" }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i11.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i12$1.MatStep, selector: "mat-step", inputs: ["color"], exportAs: ["matStep"] }, { kind: "directive", type: i12$1.MatStepLabel, selector: "[matStepLabel]" }, { kind: "component", type: i12$1.MatStepper, selector: "mat-stepper, mat-vertical-stepper, mat-horizontal-stepper, [matStepper]", inputs: ["selectedIndex", "disableRipple", "color", "labelPosition", "headerPosition", "animationDuration"], outputs: ["animationDone"], exportAs: ["matStepper", "matVerticalStepper", "matHorizontalStepper"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "component", type: AppFormField, selector: "app-form-field", inputs: ["definition", "required", "readonly", "disabled", "formControl", "formControlName", "placeholder", "compact", "floatLabel", "tabindex", "autofocus", "chipColor", "class"], outputs: ["keyup.enter"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
22326
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterForm, decorators: [{
22327
+ type: Component,
22328
+ args: [{ selector: 'app-register-form', template: "<mat-horizontal-stepper linear #stepper=\"matHorizontalStepper\">\n\n <!-- Step 1: Username -->\n <mat-step [stepControl]=\"forms[0]\" *ngIf=\"forms[0].controls; let controls\">\n\n <form [formGroup]=\"forms[0]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n <ng-template matStepLabel>{{'REGISTER.STEP_EMAIL'|translate}}</ng-template>\n\n <!-- Email -->\n <mat-form-field>\n <input matInput\n [appAutofocus]=\"true\" [autofocusDelay]=\"500\" [placeholder]=\"'USER.EMAIL'|translate\"\n formControlName=\"email\" autocomplete=\"off\" required>\n <mat-error *ngIf=\"controls.email.hasError('required') && controls.email.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.email.hasError('email') && !controls.email.hasError('required') && controls.email.touched\">\n <span>{{'ERROR.FIELD_NOT_VALID_EMAIL' | translate }}</span>\n </mat-error>\n <mat-error *ngIf=\"controls.email.hasError('availability') && controls.email.touched\" translate>REGISTER.ERROR.EMAIL_ALREADY_REGISTERED</mat-error>\n\n </mat-form-field>\n\n <!-- Confirm Email -->\n <mat-form-field>\n <input matInput autocomplete=\"off\" matFormFieldControl [placeholder]=\"'REGISTER.CONFIRM_EMAIL'|translate\" formControlName=\"confirmEmail\">\n <mat-error *ngIf=\"controls.confirmEmail.hasError('required') && controls.confirmEmail.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmEmail.hasError('equals') && controls.confirmEmail.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_EMAIL' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 2: Password -->\n <mat-step [stepControl]=\"forms[1]\" *ngIf=\"forms[1].controls; let controls\">\n\n <form [formGroup]=\"forms[1]\" class=\"form-container ion-padding\" (keyup.enter)=\"slideNext($event)\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_PASSWORD'|translate}}</ng-template>\n\n <!-- Password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.PASSWORD'|translate\"\n formControlName=\"password\"\n autocomplete=\"section-red new-password\"\n [type]=\"showPwd ? 'text' : 'password'\"\n required>\n <button matSuffix mat-icon-button\n type=\"button\"\n (click)=\"showPwd = !showPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.password.hasError('required') && controls.password.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.password.hasError('minlength') && controls.password.touched\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 8} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Confirm password -->\n <mat-form-field>\n <input matInput [placeholder]=\"'REGISTER.CONFIRM_PASSWORD'|translate\"\n formControlName=\"confirmPassword\"\n autocomplete=\"section-red new-password\"\n [type]=\"showConfirmPwd ? 'text' : 'password'\"\n required>\n <button mat-icon-button matSuffix\n (click)=\"showConfirmPwd = !showConfirmPwd\"\n tabindex=\"-1\">\n <mat-icon>{{showConfirmPwd ? 'visibility_off' : 'visibility'}}</mat-icon>\n </button>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('required') && controls.confirmPassword.touched\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.confirmPassword.hasError('equals') && controls.confirmPassword.touched\">\n <span>{{'REGISTER.ERROR.NOT_SAME_PASSWORD' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n </form>\n </mat-step>\n\n\n <!-- Step 3: user details -->\n <mat-step [stepControl]=\"forms[2]\" *ngIf=\"forms[2].controls; let controls\">\n\n <form [formGroup]=\"forms[2]\" (ngSubmit)=\"doSubmit($event)\" class=\"form-container ion-padding\" (keyup.enter)=\"doSubmit()\">\n\n <ng-template matStepLabel>{{'REGISTER.STEP_USER_DETAILS'|translate}}</ng-template>\n\n <!-- error -->\n <ion-item *ngIf=\"error && !sending\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <!-- Last name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.LAST_NAME'|translate\" formControlName=\"lastName\" autocomplete=\"section-blue family-name\"\n required>\n <mat-error *ngIf=\"controls.lastName.hasError('required') && controls.lastName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.lastName.hasError('minlength') && controls.lastName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- First name -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.FIRST_NAME'|translate\" formControlName=\"firstName\" autocomplete=\"section-blue given-name\"\n required>\n <mat-error *ngIf=\"controls.firstName.hasError('required') && controls.firstName.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"controls.firstName.hasError('minlength') && controls.firstName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n <!-- Additional fields -->\n <app-form-field *ngFor=\"let field of additionalFields\"\n [definition]=\"field\"\n [formControlName]=\"field.key\"\n [required]=\"true\">\n </app-form-field>\n\n </form>\n </mat-step>\n</mat-horizontal-stepper>\n", styles: ["form ion-toolbar.toolbar-buttons .toolbar-content{text-align:right}form ion-toolbar.toolbar-buttons .toolbar-background{border:0;background:inherit!important}\n"] }]
22329
+ }], ctorParameters: function () {
22330
+ return [{ type: AccountService }, { type: AccountValidatorService }, { type: i1$2.UntypedFormBuilder }, { type: undefined, decorators: [{
22331
+ type: Inject,
22332
+ args: [ENVIRONMENT]
22333
+ }] }, { type: LocalSettingsService }];
22334
+ }, propDecorators: { stepper: [{
22335
+ type: ViewChild,
22336
+ args: ['stepper', { static: true }]
22337
+ }], onCancel: [{
22338
+ type: Output
22339
+ }], onSubmit: [{
22340
+ type: Output
22341
+ }] } });
22342
+
22343
+ class RegisterModal {
22344
+ constructor(accountService, viewCtrl) {
22345
+ this.accountService = accountService;
22346
+ this.viewCtrl = viewCtrl;
22347
+ this.sending = false;
22123
22348
  }
22124
- registerAutocompleteField(fieldName, opts) {
22125
- return this.autocompleteHelper.add(fieldName, opts);
22349
+ cancel() {
22350
+ console.debug('[register] cancelled');
22351
+ this.viewCtrl.dismiss();
22126
22352
  }
22127
- setError(value, opts) {
22128
- if (this.errorSubject.value !== value) {
22129
- this.errorSubject.next(value);
22130
- if (!opts || opts.emitEvent !== false) {
22131
- this.markForCheck();
22353
+ doSubmit(event) {
22354
+ return __awaiter(this, void 0, void 0, function* () {
22355
+ if (this.form.form.disabled || this.sending)
22356
+ return; // Skip
22357
+ if (!this.form.valid || !this.form.isEnd()) {
22358
+ this.form.markAsTouched();
22359
+ return;
22132
22360
  }
22133
- }
22134
- }
22135
- markForCheck() {
22136
- // Should be overwritten by subclasses
22137
- console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
22138
- }
22139
- /* -- private function -- */
22140
- setLoading(value, opts) {
22141
- if (this.loadingSubject.value !== value) {
22142
- this.loadingSubject.next(value);
22143
- if (!opts || opts.emitEvent !== false) {
22144
- this.markForCheck();
22361
+ this.sending = true;
22362
+ const data = this.form.value;
22363
+ this.form.disable();
22364
+ try {
22365
+ console.debug('[register] Sending registration to server...', data);
22366
+ const res = yield this.accountService.register(data);
22367
+ console.debug('[register] Account registered!');
22368
+ yield this.viewCtrl.dismiss();
22145
22369
  }
22146
- }
22370
+ catch (err) {
22371
+ this.form.error = err && err.message || err;
22372
+ this.form.enable();
22373
+ }
22374
+ finally {
22375
+ this.sending = false;
22376
+ }
22377
+ });
22147
22378
  }
22148
22379
  }
22149
- AppForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppForm, deps: [{ token: i0.Injector }, { token: i1$2.UntypedFormGroup }], target: i0.ɵɵFactoryTarget.Directive });
22150
- AppForm.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.2.8", type: AppForm, inputs: { debug: "debug", tabindex: "tabindex", errorTranslatorOptions: "errorTranslatorOptions", form: "form" }, outputs: { onCancel: "onCancel", onSubmit: "onSubmit" }, ngImport: i0 });
22151
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppForm, decorators: [{
22152
- type: Directive
22153
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$2.UntypedFormGroup }]; }, propDecorators: { debug: [{
22154
- type: Input
22155
- }], tabindex: [{
22156
- type: Input
22157
- }], errorTranslatorOptions: [{
22158
- type: Input
22159
- }], form: [{
22160
- type: Input
22161
- }], onCancel: [{
22162
- type: Output
22163
- }], onSubmit: [{
22164
- type: Output
22380
+ RegisterModal.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterModal, deps: [{ token: AccountService }, { token: i2.ModalController }], target: i0.ɵɵFactoryTarget.Component });
22381
+ RegisterModal.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: RegisterModal, selector: "app-register-modal", viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button *ngIf=\"form.isBeginning()\" (click)=\"cancel()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n <ion-button *ngIf=\"!form.isBeginning()\" (click)=\"form.slidePrev()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title translate>REGISTER.TITLE</ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-spinner *ngIf=\"sending\"></ion-spinner>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\"\n visible-xs visible-sm visible-mobile>\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd() && !sending\" (click)=\"doSubmit()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <app-register-form #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\">\n </app-register-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <!-- buttons -->\n <ion-toolbar>\n\n <ion-row>\n <ion-col></ion-col>\n <ion-col size=\"auto\">\n <ion-button *ngIf=\"form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"form.slidePrev()\" [disabled]=\"sending\">\n <ion-icon slot=\"start\" name=\"arrow-back\"></ion-icon>\n <ion-label translate>COMMON.BTN_BACK</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\" fill=\"solid\" color=\"tertiary\">\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd()\" (click)=\"doSubmit()\" fill=\"solid\" [disabled]=\"sending\" color=\"tertiary\">\n <span translate>COMMON.BTN_SEND</span>\n <ion-icon slot=\"end\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonSpinner, selector: "ion-spinner", inputs: ["color", "duration", "name", "paused"] }, { kind: "component", type: i2.IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: RegisterForm, selector: "app-register-form", outputs: ["onCancel", "onSubmit"] }] });
22382
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterModal, decorators: [{
22383
+ type: Component,
22384
+ args: [{ selector: 'app-register-modal', template: "<ion-header>\n <ion-toolbar color=\"secondary\">\n <ion-buttons slot=\"start\">\n <ion-button *ngIf=\"form.isBeginning()\" (click)=\"cancel()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n <ion-button *ngIf=\"!form.isBeginning()\" (click)=\"form.slidePrev()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title translate>REGISTER.TITLE</ion-title>\n\n <ion-buttons slot=\"end\">\n <ion-spinner *ngIf=\"sending\"></ion-spinner>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\"\n visible-xs visible-sm visible-mobile>\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd() && !sending\" (click)=\"doSubmit()\"\n visible-xs visible-sm visible-mobile>\n <ion-icon slot=\"icon-only\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n <app-register-form #form\n (onSubmit)=\"doSubmit()\"\n (onCancel)=\"cancel()\">\n </app-register-form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <!-- buttons -->\n <ion-toolbar>\n\n <ion-row>\n <ion-col></ion-col>\n <ion-col size=\"auto\">\n <ion-button *ngIf=\"form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isBeginning()\" fill=\"clear\" color=\"dark\" (click)=\"form.slidePrev()\" [disabled]=\"sending\">\n <ion-icon slot=\"start\" name=\"arrow-back\"></ion-icon>\n <ion-label translate>COMMON.BTN_BACK</ion-label>\n </ion-button>\n\n <ion-button *ngIf=\"!form.isEnd()\" (click)=\"form.slideNext()\" fill=\"solid\" color=\"tertiary\">\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <ion-button *ngIf=\"form.isEnd()\" (click)=\"doSubmit()\" fill=\"solid\" [disabled]=\"sending\" color=\"tertiary\">\n <span translate>COMMON.BTN_SEND</span>\n <ion-icon slot=\"end\" name=\"send\"></ion-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n\n </ion-toolbar>\n</ion-footer>\n" }]
22385
+ }], ctorParameters: function () { return [{ type: AccountService }, { type: i2.ModalController }]; }, propDecorators: { form: [{
22386
+ type: ViewChild,
22387
+ args: ['form', { static: true }]
22165
22388
  }] } });
22166
22389
 
22167
22390
  class AppAuthForm extends AppForm {
@@ -23120,8 +23343,8 @@ class SettingsPage extends AppForm {
23120
23343
  }
23121
23344
  showSelectPeerModal(opts) {
23122
23345
  return __awaiter(this, void 0, void 0, function* () {
23123
- const peer = yield this.network.showSelectPeerModal(opts);
23124
- if (peer && peer.url) {
23346
+ const peer = yield this.network.showSelectPeerModal(Object.assign({ showSetManuallyButton: true }, opts));
23347
+ if (peer === null || peer === void 0 ? void 0 : peer.url) {
23125
23348
  const control = this.form.get('peerUrl');
23126
23349
  control.setValue(peer.url, { emitEvent: true, onlySelf: false });
23127
23350
  control.markAsDirty({ onlySelf: false });
@@ -23178,12 +23401,12 @@ class SettingsPage extends AppForm {
23178
23401
  SettingsPage.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SettingsPage, deps: [{ token: i0.Injector }, { token: PlatformService }, { token: i1$5.Router }, { token: LocalSettingsValidatorService }, { token: i2.AlertController }, { token: i1$1.TranslateService }, { token: i1$2.UntypedFormBuilder }, { token: AccountService }, { token: LocalSettingsService }, { token: i0.ChangeDetectorRef }, { token: NetworkService }, { token: APP_LOCALES }], target: i0.ɵɵFactoryTarget.Component });
23179
23402
  SettingsPage.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: SettingsPage, selector: "page-settings", providers: [
23180
23403
  { provide: ValidatorService, useExisting: LocalSettingsValidatorService },
23181
- ], usesInheritance: true, ngImport: i0, template: "<app-toolbar [title]=\"'SETTINGS.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"dirty && !saving\"\n [hasClose]=\"!dirty && !saving\"\n (onValidate)=\"save($event)\"\n (onClose)=\"close($event)\">\n\n <ion-buttons slot=\"end\">\n <!-- options menu -->\n <ion-button [matMenuTriggerFor]=\"optionsMenu\"\n *ngIf=\"!saving\"\n [disabled]=\"saving\">\n <mat-icon slot=\"icon-only\">more_vert</mat-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Options menu -->\n<mat-menu #optionsMenu=\"matMenu\">\n <!-- Clear cache -->\n <button mat-menu-item (click)=\"clearCache($event)\">\n <ion-label translate>SETTINGS.BTN_CLEAR_CACHE</ion-label>\n </button>\n\n <!-- Reset -->\n <button mat-menu-item\n [disabled]=\"!dirty\"\n (click)=\"cancel($event)\">\n <ion-label>\n <mat-icon><ion-icon slot=\"start\" name=\"refresh\"></ion-icon></mat-icon>&nbsp;\n <span translate>COMMON.BTN_RESET</span>\n </ion-label>\n </button>\n</mat-menu>\n\n<ion-content>\n\n <form [formGroup]=\"form\" novalidate (ngSubmit)=\"save($event)\" class=\"form-container\">\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n\n <!-- left margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n\n <ion-col class=\"ion-padding\">\n\n <!-- error -->\n <ion-item *ngIf=\"error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <p [innerHTML]=\"'SETTINGS.DESCRIPTION'|translate\"></p>\n\n <!-- account inheritance (desktop) -->\n <mat-form-field [hidden]=\"!isLogin\" *ngIf=\"!mobile; else accountInheritanceMobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- check box (if desktop) -->\n <mat-checkbox\n *ngIf=\"!mobile; else accountInheritanceMobile\"\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n <span translate>SETTINGS.INHERIT_FROM_ACCOUNT</span>\n </mat-checkbox>\n\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- account inheritance (if mobile) -->\n <ng-template #accountInheritanceMobile>\n <mat-form-field [hidden]=\"!isLogin\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.INHERIT_FROM_ACCOUNT</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n\n </mat-slide-toggle>\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </ng-template>\n\n <!-- locale -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LOCALE'|translate\" formControlName=\"locale\" required>\n <mat-option *ngFor=\"let item of locales\" [value]=\"item.key\">\n {{item.value}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.locale.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- Network entry -->\n <h3>\n <ion-text translate>SETTINGS.NETWORK_DIVIDER</ion-text>\n </h3>\n\n <!-- Peer address -->\n <mat-form-field>\n <input matInput type=\"text\" [placeholder]=\"'SETTINGS.PEER_URL'|translate\" formControlName=\"peerUrl\"\n required>\n\n <button mat-icon-button type=\"button\" matSuffix (click)=\"showSelectPeerModal()\" tabindex=\"-1\"\n [title]=\"'SETTINGS.BTN_CHANGE_PEER'|translate\">\n <mat-icon>search</mat-icon>\n </button>\n\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerAlive')\"\n translate>SETTINGS.ERROR.PEER_NOT_REACHABLE\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerNotCompatible')\"\n translate>SETTINGS.ERROR.PEER_NOT_COMPATIBLE\n </mat-error>\n </mat-form-field>\n\n <!-- Offline mode (if mobile) -->\n <mat-form-field *ngIf=\"mobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.OFFLINE_MODE</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"network.setForceOffline($event.checked)\"\n [checked]=\"network.offline\">\n\n </mat-slide-toggle>\n </mat-form-field>\n\n <!-- Data entry -->\n <h3>\n <ion-text translate>SETTINGS.DATA_ENTRY_DIVIDER</ion-text>\n </h3>\n\n <!-- Usage mode -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.USAGE_MODE'|translate\" formControlName=\"usageMode\"\n required>\n <mat-option *ngFor=\"let item of usageModes\" [value]=\"item\">\n {{'SETTINGS.USAGE_MODES.'+item|translate}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.usageMode.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- lat/long format-->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LAT_LONG_FORMAT'|translate\" formControlName=\"latLongFormat\"\n required>\n <mat-option *ngFor=\"let item of latLongFormats\" [value]=\"item\">\n {{'COMMON.LAT_LONG.'+item+'_PLACEHOLDER'|translate}}\n </mat-option>\n </mat-select>\n <mat-error\n *ngIf=\"form.controls.latLongFormat.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- fields options -->\n <ion-grid formArrayName=\"properties\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding ion-align-self-end\" size=\"12\">\n <span class=\"toolbar-spacer\"></span>\n\n <!-- Show more options -->\n <ion-button color=\"light\" *ngIf=\"propertiesForm?.length === 0\"\n [title]=\"'SETTINGS.BTN_SHOW_MORE_HELP'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n <!-- Fields options -->\n <ng-container *ngFor=\"let propertyForm of propertiesForm?.controls; let i=index\">\n <ion-row class=\"ion-no-padding\" [formGroupName]=\"i\">\n\n <!-- property key -->\n <ion-col class=\"ion-no-padding\">\n <mat-form-field>\n <mat-select formControlName=\"key\"\n [placeholder]=\" 'SETTINGS.PROPERTY_KEY'|translate\">\n <mat-option *ngFor=\"let item of propertyDefinitions\" [value]=\"item.key\">{{ item.label | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n\n <!-- property value -->\n <ion-col class=\"ion-no-padding\" padding-left>\n <app-form-field *ngIf=\"getPropertyDefinition(i); let definition\"\n floatLabel=\"never\"\n [definition]=\"definition\"\n [formControl]=\"propertyForm|formGetControl:'value'\"\n [placeholder]=\"'SETTINGS.PROPERTY_VALUE' | translate\"\n [required]=\"true\">\n </app-form-field>\n </ion-col>\n <ion-col size=\"2\" class=\"ion-no-padding\">\n <button type=\"button\" mat-icon-button color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'COMMON.BTN_DELETE'|translate\"\n (click)=\"removePropertyAt(i)\">\n <mat-icon>close</mat-icon>\n </button>\n <button *ngIf=\"propertiesFormHelper.isLast(i)\"\n type=\"button\"\n mat-icon-button\n color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'SETTINGS.BTN_ADD_PROPERTY'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <mat-icon>add</mat-icon>\n </button>\n </ion-col>\n </ion-row>\n </ng-container>\n </ion-grid>\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n </ion-row>\n </ion-grid>\n\n\n </form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <app-form-buttons-bar (onCancel)=\"cancel()\" (onSave)=\"save($event)\" [disabled]=\"!form.dirty || saving\"></app-form-buttons-bar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatSuffix, selector: "[matSuffix]" }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i6$2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i11.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i11$3.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i11$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i11$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { kind: "component", type: i2$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i14.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: ToolbarComponent, selector: "app-toolbar", inputs: ["title", "color", "class", "backHref", "defaultBackHref", "hasValidate", "hasClose", "hasSearch", "canGoBack", "canShowMenu"], outputs: ["onValidate", "onClose", "onValidateAndClose", "onBackClick", "onSearch"] }, { kind: "component", type: AppFormField, selector: "app-form-field", inputs: ["definition", "required", "readonly", "disabled", "formControl", "formControlName", "placeholder", "compact", "floatLabel", "tabindex", "autofocus", "chipColor", "class"], outputs: ["keyup.enter"] }, { kind: "component", type: FormButtonsBarComponent, selector: "app-form-buttons-bar", inputs: ["disabled", "disabledCancel", "classList"], outputs: ["onCancel", "onSave", "onNext", "onBack"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: FormGetControlPipe, name: "formGetControl" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23404
+ ], usesInheritance: true, ngImport: i0, template: "<app-toolbar [title]=\"'SETTINGS.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"dirty && !saving\"\n [hasClose]=\"!dirty && !saving\"\n (onValidate)=\"save($event)\"\n (onClose)=\"close($event)\">\n\n <ion-buttons slot=\"end\">\n <!-- options menu -->\n <ion-button [matMenuTriggerFor]=\"optionsMenu\"\n *ngIf=\"!saving\"\n [disabled]=\"saving\">\n <mat-icon slot=\"icon-only\">more_vert</mat-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Options menu -->\n<mat-menu #optionsMenu=\"matMenu\">\n <!-- Clear cache -->\n <button mat-menu-item (click)=\"clearCache($event)\">\n <ion-label translate>SETTINGS.BTN_CLEAR_CACHE</ion-label>\n </button>\n\n <!-- Reset -->\n <button mat-menu-item\n [disabled]=\"!dirty\"\n (click)=\"cancel($event)\">\n <ion-label>\n <mat-icon><ion-icon slot=\"start\" name=\"refresh\"></ion-icon></mat-icon>&nbsp;\n <span translate>COMMON.BTN_RESET</span>\n </ion-label>\n </button>\n</mat-menu>\n\n<ion-content>\n\n <form [formGroup]=\"form\" novalidate (ngSubmit)=\"save($event)\" class=\"form-container\">\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n\n <!-- left margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n\n <ion-col class=\"ion-padding\">\n\n <!-- error -->\n <ion-item *ngIf=\"error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <p [innerHTML]=\"'SETTINGS.DESCRIPTION'|translate\"></p>\n\n <!-- account inheritance (desktop) -->\n <mat-form-field [hidden]=\"!isLogin\" *ngIf=\"!mobile; else accountInheritanceMobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- check box (if desktop) -->\n <mat-checkbox\n *ngIf=\"!mobile; else accountInheritanceMobile\"\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n <span translate>SETTINGS.INHERIT_FROM_ACCOUNT</span>\n </mat-checkbox>\n\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- account inheritance (if mobile) -->\n <ng-template #accountInheritanceMobile>\n <mat-form-field [hidden]=\"!isLogin\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.INHERIT_FROM_ACCOUNT</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n\n </mat-slide-toggle>\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </ng-template>\n\n <!-- locale -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LOCALE'|translate\" formControlName=\"locale\" required>\n <mat-option *ngFor=\"let item of locales\" [value]=\"item.key\">\n {{item.value}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.locale.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- Network entry -->\n <h3>\n <ion-text translate>SETTINGS.NETWORK_DIVIDER</ion-text>\n </h3>\n\n <!-- Peer address -->\n <mat-form-field>\n <input matInput type=\"text\" [placeholder]=\"'SETTINGS.PEER_URL'|translate\"\n formControlName=\"peerUrl\"\n required>\n\n <button mat-icon-button type=\"button\" matSuffix (click)=\"showSelectPeerModal()\" tabindex=\"-1\"\n [title]=\"'SETTINGS.BTN_CHANGE_PEER'|translate\">\n <mat-icon>search</mat-icon>\n </button>\n\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerAlive')\"\n translate>SETTINGS.ERROR.PEER_NOT_REACHABLE\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerNotCompatible')\"\n translate>SETTINGS.ERROR.PEER_NOT_COMPATIBLE\n </mat-error>\n </mat-form-field>\n\n <!-- Offline mode (if mobile) -->\n <mat-form-field *ngIf=\"mobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.OFFLINE_MODE</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"network.setForceOffline($event.checked)\"\n [checked]=\"network.offline\">\n\n </mat-slide-toggle>\n </mat-form-field>\n\n <!-- Data entry -->\n <h3>\n <ion-text translate>SETTINGS.DATA_ENTRY_DIVIDER</ion-text>\n </h3>\n\n <!-- Usage mode -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.USAGE_MODE'|translate\" formControlName=\"usageMode\"\n required>\n <mat-option *ngFor=\"let item of usageModes\" [value]=\"item\">\n {{'SETTINGS.USAGE_MODES.'+item|translate}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.usageMode.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- lat/long format-->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LAT_LONG_FORMAT'|translate\" formControlName=\"latLongFormat\"\n required>\n <mat-option *ngFor=\"let item of latLongFormats\" [value]=\"item\">\n {{'COMMON.LAT_LONG.'+item+'_PLACEHOLDER'|translate}}\n </mat-option>\n </mat-select>\n <mat-error\n *ngIf=\"form.controls.latLongFormat.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- fields options -->\n <ion-grid formArrayName=\"properties\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding ion-align-self-end\" size=\"12\">\n <span class=\"toolbar-spacer\"></span>\n\n <!-- Show more options -->\n <ion-button color=\"light\" *ngIf=\"propertiesForm?.length === 0\"\n [title]=\"'SETTINGS.BTN_SHOW_MORE_HELP'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n <!-- Fields options -->\n <ng-container *ngFor=\"let propertyForm of propertiesForm?.controls; let i=index\">\n <ion-row class=\"ion-no-padding\" [formGroupName]=\"i\">\n\n <!-- property key -->\n <ion-col class=\"ion-no-padding\">\n <mat-form-field>\n <mat-select formControlName=\"key\"\n [placeholder]=\" 'SETTINGS.PROPERTY_KEY'|translate\">\n <mat-option *ngFor=\"let item of propertyDefinitions\" [value]=\"item.key\">{{ item.label | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n\n <!-- property value -->\n <ion-col class=\"ion-no-padding\" padding-left>\n <app-form-field *ngIf=\"getPropertyDefinition(i); let definition\"\n floatLabel=\"never\"\n [definition]=\"definition\"\n [formControl]=\"propertyForm|formGetControl:'value'\"\n [placeholder]=\"'SETTINGS.PROPERTY_VALUE' | translate\"\n [required]=\"true\">\n </app-form-field>\n </ion-col>\n <ion-col size=\"2\" class=\"ion-no-padding\">\n <button type=\"button\" mat-icon-button color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'COMMON.BTN_DELETE'|translate\"\n (click)=\"removePropertyAt(i)\">\n <mat-icon>close</mat-icon>\n </button>\n <button *ngIf=\"propertiesFormHelper.isLast(i)\"\n type=\"button\"\n mat-icon-button\n color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'SETTINGS.BTN_ADD_PROPERTY'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <mat-icon>add</mat-icon>\n </button>\n </ion-col>\n </ion-row>\n </ng-container>\n </ion-grid>\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n </ion-row>\n </ion-grid>\n\n\n </form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <app-form-buttons-bar (onCancel)=\"cancel()\" (onSave)=\"save($event)\" [disabled]=\"!form.dirty || saving\"></app-form-buttons-bar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i2$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonGrid, selector: "ion-grid", inputs: ["fixed"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonText, selector: "ion-text", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i1$2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i1$2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatSuffix, selector: "[matSuffix]" }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i6$2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }, { kind: "component", type: i10.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i11.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i11$3.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i11$3.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i11$3.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { kind: "component", type: i2$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i14.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: ToolbarComponent, selector: "app-toolbar", inputs: ["title", "color", "class", "backHref", "defaultBackHref", "hasValidate", "hasClose", "hasSearch", "canGoBack", "canShowMenu"], outputs: ["onValidate", "onClose", "onValidateAndClose", "onBackClick", "onSearch"] }, { kind: "component", type: AppFormField, selector: "app-form-field", inputs: ["definition", "required", "readonly", "disabled", "formControl", "formControlName", "placeholder", "compact", "floatLabel", "tabindex", "autofocus", "chipColor", "class"], outputs: ["keyup.enter"] }, { kind: "component", type: FormButtonsBarComponent, selector: "app-form-buttons-bar", inputs: ["disabled", "disabledCancel", "classList"], outputs: ["onCancel", "onSave", "onNext", "onBack"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }, { kind: "pipe", type: FormGetControlPipe, name: "formGetControl" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
23182
23405
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SettingsPage, decorators: [{
23183
23406
  type: Component,
23184
23407
  args: [{ selector: 'page-settings', providers: [
23185
23408
  { provide: ValidatorService, useExisting: LocalSettingsValidatorService },
23186
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<app-toolbar [title]=\"'SETTINGS.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"dirty && !saving\"\n [hasClose]=\"!dirty && !saving\"\n (onValidate)=\"save($event)\"\n (onClose)=\"close($event)\">\n\n <ion-buttons slot=\"end\">\n <!-- options menu -->\n <ion-button [matMenuTriggerFor]=\"optionsMenu\"\n *ngIf=\"!saving\"\n [disabled]=\"saving\">\n <mat-icon slot=\"icon-only\">more_vert</mat-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Options menu -->\n<mat-menu #optionsMenu=\"matMenu\">\n <!-- Clear cache -->\n <button mat-menu-item (click)=\"clearCache($event)\">\n <ion-label translate>SETTINGS.BTN_CLEAR_CACHE</ion-label>\n </button>\n\n <!-- Reset -->\n <button mat-menu-item\n [disabled]=\"!dirty\"\n (click)=\"cancel($event)\">\n <ion-label>\n <mat-icon><ion-icon slot=\"start\" name=\"refresh\"></ion-icon></mat-icon>&nbsp;\n <span translate>COMMON.BTN_RESET</span>\n </ion-label>\n </button>\n</mat-menu>\n\n<ion-content>\n\n <form [formGroup]=\"form\" novalidate (ngSubmit)=\"save($event)\" class=\"form-container\">\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n\n <!-- left margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n\n <ion-col class=\"ion-padding\">\n\n <!-- error -->\n <ion-item *ngIf=\"error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <p [innerHTML]=\"'SETTINGS.DESCRIPTION'|translate\"></p>\n\n <!-- account inheritance (desktop) -->\n <mat-form-field [hidden]=\"!isLogin\" *ngIf=\"!mobile; else accountInheritanceMobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- check box (if desktop) -->\n <mat-checkbox\n *ngIf=\"!mobile; else accountInheritanceMobile\"\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n <span translate>SETTINGS.INHERIT_FROM_ACCOUNT</span>\n </mat-checkbox>\n\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- account inheritance (if mobile) -->\n <ng-template #accountInheritanceMobile>\n <mat-form-field [hidden]=\"!isLogin\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.INHERIT_FROM_ACCOUNT</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n\n </mat-slide-toggle>\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </ng-template>\n\n <!-- locale -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LOCALE'|translate\" formControlName=\"locale\" required>\n <mat-option *ngFor=\"let item of locales\" [value]=\"item.key\">\n {{item.value}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.locale.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- Network entry -->\n <h3>\n <ion-text translate>SETTINGS.NETWORK_DIVIDER</ion-text>\n </h3>\n\n <!-- Peer address -->\n <mat-form-field>\n <input matInput type=\"text\" [placeholder]=\"'SETTINGS.PEER_URL'|translate\" formControlName=\"peerUrl\"\n required>\n\n <button mat-icon-button type=\"button\" matSuffix (click)=\"showSelectPeerModal()\" tabindex=\"-1\"\n [title]=\"'SETTINGS.BTN_CHANGE_PEER'|translate\">\n <mat-icon>search</mat-icon>\n </button>\n\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerAlive')\"\n translate>SETTINGS.ERROR.PEER_NOT_REACHABLE\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerNotCompatible')\"\n translate>SETTINGS.ERROR.PEER_NOT_COMPATIBLE\n </mat-error>\n </mat-form-field>\n\n <!-- Offline mode (if mobile) -->\n <mat-form-field *ngIf=\"mobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.OFFLINE_MODE</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"network.setForceOffline($event.checked)\"\n [checked]=\"network.offline\">\n\n </mat-slide-toggle>\n </mat-form-field>\n\n <!-- Data entry -->\n <h3>\n <ion-text translate>SETTINGS.DATA_ENTRY_DIVIDER</ion-text>\n </h3>\n\n <!-- Usage mode -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.USAGE_MODE'|translate\" formControlName=\"usageMode\"\n required>\n <mat-option *ngFor=\"let item of usageModes\" [value]=\"item\">\n {{'SETTINGS.USAGE_MODES.'+item|translate}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.usageMode.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- lat/long format-->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LAT_LONG_FORMAT'|translate\" formControlName=\"latLongFormat\"\n required>\n <mat-option *ngFor=\"let item of latLongFormats\" [value]=\"item\">\n {{'COMMON.LAT_LONG.'+item+'_PLACEHOLDER'|translate}}\n </mat-option>\n </mat-select>\n <mat-error\n *ngIf=\"form.controls.latLongFormat.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- fields options -->\n <ion-grid formArrayName=\"properties\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding ion-align-self-end\" size=\"12\">\n <span class=\"toolbar-spacer\"></span>\n\n <!-- Show more options -->\n <ion-button color=\"light\" *ngIf=\"propertiesForm?.length === 0\"\n [title]=\"'SETTINGS.BTN_SHOW_MORE_HELP'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n <!-- Fields options -->\n <ng-container *ngFor=\"let propertyForm of propertiesForm?.controls; let i=index\">\n <ion-row class=\"ion-no-padding\" [formGroupName]=\"i\">\n\n <!-- property key -->\n <ion-col class=\"ion-no-padding\">\n <mat-form-field>\n <mat-select formControlName=\"key\"\n [placeholder]=\" 'SETTINGS.PROPERTY_KEY'|translate\">\n <mat-option *ngFor=\"let item of propertyDefinitions\" [value]=\"item.key\">{{ item.label | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n\n <!-- property value -->\n <ion-col class=\"ion-no-padding\" padding-left>\n <app-form-field *ngIf=\"getPropertyDefinition(i); let definition\"\n floatLabel=\"never\"\n [definition]=\"definition\"\n [formControl]=\"propertyForm|formGetControl:'value'\"\n [placeholder]=\"'SETTINGS.PROPERTY_VALUE' | translate\"\n [required]=\"true\">\n </app-form-field>\n </ion-col>\n <ion-col size=\"2\" class=\"ion-no-padding\">\n <button type=\"button\" mat-icon-button color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'COMMON.BTN_DELETE'|translate\"\n (click)=\"removePropertyAt(i)\">\n <mat-icon>close</mat-icon>\n </button>\n <button *ngIf=\"propertiesFormHelper.isLast(i)\"\n type=\"button\"\n mat-icon-button\n color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'SETTINGS.BTN_ADD_PROPERTY'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <mat-icon>add</mat-icon>\n </button>\n </ion-col>\n </ion-row>\n </ng-container>\n </ion-grid>\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n </ion-row>\n </ion-grid>\n\n\n </form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <app-form-buttons-bar (onCancel)=\"cancel()\" (onSave)=\"save($event)\" [disabled]=\"!form.dirty || saving\"></app-form-buttons-bar>\n</ion-footer>\n" }]
23409
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<app-toolbar [title]=\"'SETTINGS.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"dirty && !saving\"\n [hasClose]=\"!dirty && !saving\"\n (onValidate)=\"save($event)\"\n (onClose)=\"close($event)\">\n\n <ion-buttons slot=\"end\">\n <!-- options menu -->\n <ion-button [matMenuTriggerFor]=\"optionsMenu\"\n *ngIf=\"!saving\"\n [disabled]=\"saving\">\n <mat-icon slot=\"icon-only\">more_vert</mat-icon>\n </ion-button>\n </ion-buttons>\n</app-toolbar>\n\n<!-- Options menu -->\n<mat-menu #optionsMenu=\"matMenu\">\n <!-- Clear cache -->\n <button mat-menu-item (click)=\"clearCache($event)\">\n <ion-label translate>SETTINGS.BTN_CLEAR_CACHE</ion-label>\n </button>\n\n <!-- Reset -->\n <button mat-menu-item\n [disabled]=\"!dirty\"\n (click)=\"cancel($event)\">\n <ion-label>\n <mat-icon><ion-icon slot=\"start\" name=\"refresh\"></ion-icon></mat-icon>&nbsp;\n <span translate>COMMON.BTN_RESET</span>\n </ion-label>\n </button>\n</mat-menu>\n\n<ion-content>\n\n <form [formGroup]=\"form\" novalidate (ngSubmit)=\"save($event)\" class=\"form-container\">\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n\n <!-- left margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n\n <ion-col class=\"ion-padding\">\n\n <!-- error -->\n <ion-item *ngIf=\"error\" lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"error|translate\"></ion-label>\n </ion-item>\n\n <p [innerHTML]=\"'SETTINGS.DESCRIPTION'|translate\"></p>\n\n <!-- account inheritance (desktop) -->\n <mat-form-field [hidden]=\"!isLogin\" *ngIf=\"!mobile; else accountInheritanceMobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- check box (if desktop) -->\n <mat-checkbox\n *ngIf=\"!mobile; else accountInheritanceMobile\"\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n <span translate>SETTINGS.INHERIT_FROM_ACCOUNT</span>\n </mat-checkbox>\n\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- account inheritance (if mobile) -->\n <ng-template #accountInheritanceMobile>\n <mat-form-field [hidden]=\"!isLogin\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.INHERIT_FROM_ACCOUNT</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"setAccountInheritance($event.checked)\"\n [checked]=\"accountInheritance\">\n\n </mat-slide-toggle>\n <mat-error *ngIf=\"form.controls.accountInheritance.hasError('required')\" translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n </ng-template>\n\n <!-- locale -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LOCALE'|translate\" formControlName=\"locale\" required>\n <mat-option *ngFor=\"let item of locales\" [value]=\"item.key\">\n {{item.value}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.locale.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- Network entry -->\n <h3>\n <ion-text translate>SETTINGS.NETWORK_DIVIDER</ion-text>\n </h3>\n\n <!-- Peer address -->\n <mat-form-field>\n <input matInput type=\"text\" [placeholder]=\"'SETTINGS.PEER_URL'|translate\"\n formControlName=\"peerUrl\"\n required>\n\n <button mat-icon-button type=\"button\" matSuffix (click)=\"showSelectPeerModal()\" tabindex=\"-1\"\n [title]=\"'SETTINGS.BTN_CHANGE_PEER'|translate\">\n <mat-icon>search</mat-icon>\n </button>\n\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerAlive')\"\n translate>SETTINGS.ERROR.PEER_NOT_REACHABLE\n </mat-error>\n <mat-error *ngIf=\"form.controls.peerUrl.hasError('peerNotCompatible')\"\n translate>SETTINGS.ERROR.PEER_NOT_COMPATIBLE\n </mat-error>\n </mat-form-field>\n\n <!-- Offline mode (if mobile) -->\n <mat-form-field *ngIf=\"mobile\">\n <input matInput hidden formControlName=\"accountInheritance\" type=\"text\">\n\n <!-- slide toggle -->\n <ion-text translate>SETTINGS.OFFLINE_MODE</ion-text>\n <mat-slide-toggle matSuffix\n (change)=\"network.setForceOffline($event.checked)\"\n [checked]=\"network.offline\">\n\n </mat-slide-toggle>\n </mat-form-field>\n\n <!-- Data entry -->\n <h3>\n <ion-text translate>SETTINGS.DATA_ENTRY_DIVIDER</ion-text>\n </h3>\n\n <!-- Usage mode -->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.USAGE_MODE'|translate\" formControlName=\"usageMode\"\n required>\n <mat-option *ngFor=\"let item of usageModes\" [value]=\"item\">\n {{'SETTINGS.USAGE_MODES.'+item|translate}}\n </mat-option>\n </mat-select>\n <mat-error *ngIf=\"form.controls.usageMode.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- lat/long format-->\n <mat-form-field>\n <mat-select [placeholder]=\"'SETTINGS.LAT_LONG_FORMAT'|translate\" formControlName=\"latLongFormat\"\n required>\n <mat-option *ngFor=\"let item of latLongFormats\" [value]=\"item\">\n {{'COMMON.LAT_LONG.'+item+'_PLACEHOLDER'|translate}}\n </mat-option>\n </mat-select>\n <mat-error\n *ngIf=\"form.controls.latLongFormat.hasError('required')\"\n translate>ERROR.FIELD_REQUIRED\n </mat-error>\n </mat-form-field>\n\n <!-- fields options -->\n <ion-grid formArrayName=\"properties\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding ion-align-self-end\" size=\"12\">\n <span class=\"toolbar-spacer\"></span>\n\n <!-- Show more options -->\n <ion-button color=\"light\" *ngIf=\"propertiesForm?.length === 0\"\n [title]=\"'SETTINGS.BTN_SHOW_MORE_HELP'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-col>\n </ion-row>\n\n <!-- Fields options -->\n <ng-container *ngFor=\"let propertyForm of propertiesForm?.controls; let i=index\">\n <ion-row class=\"ion-no-padding\" [formGroupName]=\"i\">\n\n <!-- property key -->\n <ion-col class=\"ion-no-padding\">\n <mat-form-field>\n <mat-select formControlName=\"key\"\n [placeholder]=\" 'SETTINGS.PROPERTY_KEY'|translate\">\n <mat-option *ngFor=\"let item of propertyDefinitions\" [value]=\"item.key\">{{ item.label | translate }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n\n <!-- property value -->\n <ion-col class=\"ion-no-padding\" padding-left>\n <app-form-field *ngIf=\"getPropertyDefinition(i); let definition\"\n floatLabel=\"never\"\n [definition]=\"definition\"\n [formControl]=\"propertyForm|formGetControl:'value'\"\n [placeholder]=\"'SETTINGS.PROPERTY_VALUE' | translate\"\n [required]=\"true\">\n </app-form-field>\n </ion-col>\n <ion-col size=\"2\" class=\"ion-no-padding\">\n <button type=\"button\" mat-icon-button color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'COMMON.BTN_DELETE'|translate\"\n (click)=\"removePropertyAt(i)\">\n <mat-icon>close</mat-icon>\n </button>\n <button *ngIf=\"propertiesFormHelper.isLast(i)\"\n type=\"button\"\n mat-icon-button\n color=\"light\"\n [disabled]=\"loading\"\n [title]=\"'SETTINGS.BTN_ADD_PROPERTY'|translate\"\n (click)=\"propertiesFormHelper.add()\">\n <mat-icon>add</mat-icon>\n </button>\n </ion-col>\n </ion-row>\n </ng-container>\n </ion-grid>\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"2\">&nbsp;\n </ion-col>\n </ion-row>\n </ion-grid>\n\n\n </form>\n</ion-content>\n\n<ion-footer hidden-xs hidden-sm hidden-mobile>\n <app-form-buttons-bar (onCancel)=\"cancel()\" (onSave)=\"save($event)\" [disabled]=\"!form.dirty || saving\"></app-form-buttons-bar>\n</ion-footer>\n" }]
23187
23410
  }], ctorParameters: function () {
23188
23411
  return [{ type: i0.Injector }, { type: PlatformService }, { type: i1$5.Router }, { type: LocalSettingsValidatorService }, { type: i2.AlertController }, { type: i1$1.TranslateService }, { type: i1$2.UntypedFormBuilder }, { type: AccountService }, { type: LocalSettingsService }, { type: i0.ChangeDetectorRef }, { type: NetworkService }, { type: undefined, decorators: [{
23189
23412
  type: Inject,
@@ -23646,197 +23869,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
23646
23869
  }]
23647
23870
  }] });
23648
23871
 
23649
- class TextForm extends AppForm {
23650
- constructor(injector, cd, formBuilder) {
23651
- super(injector);
23652
- this.injector = injector;
23653
- this.cd = cd;
23654
- this.formBuilder = formBuilder;
23655
- this.showError = true;
23656
- this.multiline = true;
23657
- this.autoHeight = false;
23658
- this.maxLength = 2000;
23659
- this.autofocus = false;
23660
- this.textAreaChanges = new EventEmitter();
23661
- }
23662
- ngOnInit() {
23663
- const form = this.formBuilder.group({
23664
- text: [null, isNotNil(this.maxLength)
23665
- ? Validators.maxLength(this.maxLength)
23666
- : undefined
23667
- ]
23668
- });
23669
- this.control = form.get('text');
23670
- this.setForm(form);
23671
- super.ngOnInit();
23672
- }
23673
- textAreaChanged(event) {
23674
- this.textAreaChanges.emit(this.control.value);
23675
- }
23676
- containerResize() {
23677
- var _a;
23678
- (_a = this.autosizeDirective) === null || _a === void 0 ? void 0 : _a.resizeToFitContent(true);
23679
- }
23680
- focusInput() {
23681
- if (this.textArea)
23682
- focusInput(this.textArea);
23683
- if (this.textInput)
23684
- focusInput(this.textInput);
23685
- }
23686
- markForCheck() {
23687
- this.cd.markForCheck();
23688
- }
23689
- }
23690
- TextForm.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextForm, deps: [{ token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i1$2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component });
23691
- TextForm.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: TextForm, selector: "app-text-form", inputs: { showError: "showError", placeholder: "placeholder", multiline: "multiline", autoHeight: "autoHeight", maxLength: "maxLength", autofocus: "autofocus" }, outputs: { textAreaChanges: "textAreaChanges" }, viewQueries: [{ propertyName: "textArea", first: true, predicate: ["textArea"], descendants: true }, { propertyName: "textInput", first: true, predicate: ["textInput"], descendants: true }, { propertyName: "autosizeDirective", first: true, predicate: CdkTextareaAutosize, descendants: true }], usesInheritance: true, ngImport: i0, template: "<form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n <mat-form-field *ngIf=\"multiline; else monoline\">\n <textarea\n #textArea\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"control.disabled\"\n [class.fixed-height]=\"!autoHeight\"\n [cdkTextareaAutosize]=\"autoHeight\"\n (keyup)=\"textAreaChanged($event)\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n [autofocus]=\"autofocus\"\n ></textarea>\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textArea.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n <ng-template #monoline>\n <mat-form-field>\n <input\n #textInput\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"disabled\"\n [appAutofocus]=\"autofocus\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n />\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textInput.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n </ng-template>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}\n"], dependencies: [{ kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$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: i1$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i6$1.MatError, selector: "mat-error", inputs: ["id"] }, { kind: "component", type: i6$1.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i6$1.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i4.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "directive", type: i7.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
23692
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextForm, decorators: [{
23693
- type: Component,
23694
- args: [{ selector: 'app-text-form', template: "<form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n <mat-form-field *ngIf=\"multiline; else monoline\">\n <textarea\n #textArea\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"control.disabled\"\n [class.fixed-height]=\"!autoHeight\"\n [cdkTextareaAutosize]=\"autoHeight\"\n (keyup)=\"textAreaChanged($event)\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n [autofocus]=\"autofocus\"\n ></textarea>\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textArea.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n <ng-template #monoline>\n <mat-form-field>\n <input\n #textInput\n matInput\n [formControl]=\"control\"\n [placeholder]=\"placeholder\"\n [readonly]=\"disabled\"\n [appAutofocus]=\"autofocus\"\n (keydown.control.enter)=\"onSubmit.emit($event)\"\n />\n <mat-error *ngIf=\"control.hasError('maxlength')\">\n {{ 'ERROR.FIELD_MAX_LENGTH' | translate: control.errors['maxlength'] }}\n </mat-error>\n <mat-hint *ngIf=\"maxLength\" align=\"end\">\n {{ 'INFO.TEXT_PROGRESS' | translate: { current: textInput.value?.length || 0, max: maxLength } }}\n </mat-hint>\n </mat-form-field>\n </ng-template>\n</form>\n", styles: ["textarea.fixed-height{height:11.5em}\n"] }]
23695
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i1$2.UntypedFormBuilder }]; }, propDecorators: { showError: [{
23696
- type: Input
23697
- }], placeholder: [{
23698
- type: Input
23699
- }], multiline: [{
23700
- type: Input
23701
- }], autoHeight: [{
23702
- type: Input
23703
- }], maxLength: [{
23704
- type: Input
23705
- }], autofocus: [{
23706
- type: Input
23707
- }], textAreaChanges: [{
23708
- type: Output
23709
- }], textArea: [{
23710
- type: ViewChild,
23711
- args: ['textArea']
23712
- }], textInput: [{
23713
- type: ViewChild,
23714
- args: ['textInput']
23715
- }], autosizeDirective: [{
23716
- type: ViewChild,
23717
- args: [CdkTextareaAutosize]
23718
- }] } });
23719
-
23720
- class TextPopover {
23721
- constructor(popoverController, translate) {
23722
- this.popoverController = popoverController;
23723
- this.translate = translate;
23724
- this.placeholder = '';
23725
- this.editing = true;
23726
- this.multiline = true;
23727
- this.maxLength = 2000;
23728
- this.autofocus = false;
23729
- this.subscription = new Subscription();
23730
- }
23731
- get disabled() {
23732
- return this.form.disabled;
23733
- }
23734
- get enabled() {
23735
- return this.form.enabled;
23736
- }
23737
- get valid() {
23738
- var _a;
23739
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
23740
- }
23741
- get value() {
23742
- var _a;
23743
- return (_a = this.form) === null || _a === void 0 ? void 0 : _a.value.text;
23744
- }
23745
- ngOnInit() {
23746
- this.enable();
23747
- }
23748
- ngAfterViewInit() {
23749
- setTimeout(() => this.form.setValue({ text: this.text }), 0);
23750
- }
23751
- onValidate(event) {
23752
- return __awaiter(this, void 0, void 0, function* () {
23753
- yield waitWhilePending(this.form);
23754
- if (!this.valid) {
23755
- logFormErrors(this.form.control);
23756
- return;
23757
- }
23758
- try {
23759
- const value = this.value;
23760
- this.disable();
23761
- yield this.popoverController.dismiss(value);
23762
- this.form.error = null;
23763
- }
23764
- catch (err) {
23765
- this.form.error = (err && err.message) || err;
23766
- this.enable();
23767
- }
23768
- });
23769
- }
23770
- disable() {
23771
- this.form.disable();
23772
- }
23773
- enable() {
23774
- if (this.editing)
23775
- this.form.enable();
23776
- }
23777
- cancel() {
23778
- this.popoverController.dismiss();
23779
- }
23780
- ngOnDestroy() {
23781
- this.subscription.unsubscribe();
23782
- }
23783
- }
23784
- TextPopover.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextPopover, deps: [{ token: i2.PopoverController }, { token: i1$1.TranslateService }], target: i0.ɵɵFactoryTarget.Component });
23785
- TextPopover.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: TextPopover, selector: "app-text-popover", inputs: { text: "text", placeholder: "placeholder", editing: "editing", multiline: "multiline", maxLength: "maxLength", autofocus: "autofocus" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["form"], descendants: true, static: true }], ngImport: i0, template: "\n<ion-content class=\"ion-padding\" cdkTrapFocus [cdkTrapFocusAutoCapture]=\"true\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error|translate\"></ion-label>\n </ion-item>\n\n <app-text-form #form [placeholder]=\"placeholder\"\n [multiline]=\"multiline\"\n [maxLength]=\"maxLength\"\n [autofocus]=\"editing && autofocus\"\n (onSubmit)=\"onValidate($event)\"\n ></app-text-form>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n\n </ion-col>\n\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n <ion-button\n [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onValidate($event)\"\n (keyup.enter)=\"onValidate($event)\"\n color=\"tertiary\"\n [disabled]=\"disabled\"\n [title]=\"'COMMON.BTN_VALIDATE_WITH_SHORTCUT_HELP'|translate\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n", dependencies: [{ kind: "directive", type: i2$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: i2.IonCol, selector: "ion-col", inputs: ["offset", "offsetLg", "offsetMd", "offsetSm", "offsetXl", "offsetXs", "pull", "pullLg", "pullMd", "pullSm", "pullXl", "pullXs", "push", "pushLg", "pushMd", "pushSm", "pushXl", "pushXs", "size", "sizeLg", "sizeMd", "sizeSm", "sizeXl", "sizeXs"] }, { kind: "component", type: i2.IonContent, selector: "ion-content", inputs: ["color", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: i2.IonFooter, selector: "ion-footer", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: i2.IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: i2.IonItem, selector: "ion-item", inputs: ["button", "color", "counter", "counterFormatter", "detail", "detailIcon", "disabled", "download", "fill", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "shape", "target", "type"] }, { kind: "component", type: i2.IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: i2.IonRow, selector: "ion-row" }, { kind: "component", type: i2.IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "directive", type: i1$1.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "directive", type: i1$3.CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "directive", type: AutofocusDirective, selector: "[autofocus], input[appAutofocus]", inputs: ["appAutofocus", "autofocusDelay"] }, { kind: "component", type: TextForm, selector: "app-text-form", inputs: ["showError", "placeholder", "multiline", "autoHeight", "maxLength", "autofocus"], outputs: ["textAreaChanges"] }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] });
23786
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextPopover, decorators: [{
23787
- type: Component,
23788
- args: [{ selector: 'app-text-popover', template: "\n<ion-content class=\"ion-padding\" cdkTrapFocus [cdkTrapFocusAutoCapture]=\"true\">\n <ion-item *ngIf=\"form.error\" visible-xs visible-sm visible-mobile lines=\"none\">\n <ion-icon color=\"danger\" slot=\"start\" name=\"alert-circle\"></ion-icon>\n <ion-label color=\"danger\" class=\"error\" [innerHTML]=\"form.error|translate\"></ion-label>\n </ion-item>\n\n <app-text-form #form [placeholder]=\"placeholder\"\n [multiline]=\"multiline\"\n [maxLength]=\"maxLength\"\n [autofocus]=\"editing && autofocus\"\n (onSubmit)=\"onValidate($event)\"\n ></app-text-form>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n\n </ion-col>\n\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n <ion-button\n [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onValidate($event)\"\n (keyup.enter)=\"onValidate($event)\"\n color=\"tertiary\"\n [disabled]=\"disabled\"\n [title]=\"'COMMON.BTN_VALIDATE_WITH_SHORTCUT_HELP'|translate\">\n <ion-label translate>COMMON.BTN_VALIDATE</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n" }]
23789
- }], ctorParameters: function () { return [{ type: i2.PopoverController }, { type: i1$1.TranslateService }]; }, propDecorators: { form: [{
23790
- type: ViewChild,
23791
- args: ['form', { static: true }]
23792
- }], text: [{
23793
- type: Input
23794
- }], placeholder: [{
23795
- type: Input
23796
- }], editing: [{
23797
- type: Input
23798
- }], multiline: [{
23799
- type: Input
23800
- }], maxLength: [{
23801
- type: Input
23802
- }], autofocus: [{
23803
- type: Input
23804
- }] } });
23805
-
23806
- class AppTextPopoverModule {
23807
- }
23808
- AppTextPopoverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
23809
- AppTextPopoverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, declarations: [
23810
- // Components
23811
- TextForm,
23812
- TextPopover
23813
- ], imports: [SharedModule, i1$1.TranslateModule], exports: [TranslateModule,
23814
- // Components
23815
- TextForm,
23816
- TextPopover] });
23817
- AppTextPopoverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, imports: [SharedModule,
23818
- TranslateModule.forChild(), TranslateModule] });
23819
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, decorators: [{
23820
- type: NgModule,
23821
- args: [{
23822
- imports: [
23823
- SharedModule,
23824
- TranslateModule.forChild()
23825
- ],
23826
- declarations: [
23827
- // Components
23828
- TextForm,
23829
- TextPopover
23830
- ],
23831
- exports: [
23832
- TranslateModule,
23833
- // Components
23834
- TextForm,
23835
- TextPopover
23836
- ]
23837
- }]
23838
- }] });
23839
-
23840
23872
  class EntityMetadataComponent {
23841
23873
  constructor() {
23842
23874
  this.showRecorder = true;
@@ -33238,7 +33270,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
33238
33270
  }] }];
33239
33271
  } });
33240
33272
 
33241
- const moment = momentNamespace;
33273
+ const moment = momentImported;
33242
33274
  class UserEventTestingPage {
33243
33275
  constructor(userEventService, router, alertController, translateService) {
33244
33276
  this.userEventService = userEventService;
@@ -33580,5 +33612,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
33580
33612
  * Generated bundle index. Do not edit.
33581
33613
  */
33582
33614
 
33583
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_JOB_PROGRESSION_SERVICE, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_MENU_OPTIONS, APP_STORAGE, APP_TESTING_PAGES, APP_USER_EVENT_SERVICE, AboutModal, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, AdminUsersModule, Alerts, AndroidOsEnvironment, AnimationState, AppAboutModalModule, AppAccountModule, AppAuthForm, AppAuthModal, AppAuthModule, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppEntityFormModule, AppForm, AppFormButtonsBarModule, AppFormField, AppFormModule, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppHomePageModule, AppIconComponent, AppIconModule, AppImageGalleryComponent, AppInMemoryTable, AppInstallUpgradeCard, AppInstallUpgradeCardModule, AppListForm, AppListFormModule, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppPropertiesFormModule, AppRegisterModule, AppSelectPeerModule, AppSettingsPageModule, AppTabEditor, AppTabEditorOptions, AppTable, AppTableModule, AppTableUtils, AppTextPopoverModule, AppUpdateOfflineModeCard, AppUpdateOfflineModeCardModule, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayJoinPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AudioTestingModule, AudioTestingPage, AuthGuardService, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, BadgeDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTestPage, DateTimeTestPage, DateUtils, DebugComponent, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ED25519_SEED_LENGTH, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments, GalleryTestPage, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, IMAGE_DEFAULTS, ImageAttachment, ImageAttachmentFilter, ImageAttachmentService, ImageGalleryModule, ImageGalleryTestingModule, ImageModule, ImageService, ImagesUtils, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, Job, JobModule, JobProgression, JobProgressionIcon, JobProgressionList, JobProgressionService, JobProgressionTestService, JobProgressionTestingPage, JobTestingModule, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MOMENT_NO_TIME_PROPERTY, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatAutocompleteFieldUtils, MatBooleanField, MatChipsField, MatColorPipe, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuOptions, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, NumpadTestPage, ObservableTestPage, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertiesFormTestPage, PropertiesFormTestingModule, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, RegisterForm, RegisterModal, ResizableComponent, ResizableDirective, ResizableModule, SCRYPT_PARAMS, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SOCIAL_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedBadgeModule, SharedDebugModule, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedToolbarModule, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, SocialTestingModule, Software, StartableService, StatusById, StatusIds, StatusList, StorageDrivers, StorageService, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, ToastTestingModule, ToastTestingPage, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEventModule, UserEventNotificationIcon, UserEventTestService, UserEventTestingModule, UserEventTestingPage, UserSettings, UsersPage, ZERO_PLACEHOLDER_CHAR, accountToString, adaptValueToControl, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isCapacitor, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$1 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, patchValueInArray, propertiesPathComparator, propertyComparator, propertyPathComparator, pushValueInArray, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
33615
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_JOB_PROGRESSION_SERVICE, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_MENU_OPTIONS, APP_STORAGE, APP_TESTING_PAGES, APP_USER_EVENT_SERVICE, AboutModal, AbstractUserEventService, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, AdminUsersModule, Alerts, AndroidOsEnvironment, AnimationState, AppAboutModalModule, AppAccountModule, AppAuthForm, AppAuthModal, AppAuthModule, AppEditor, AppEditorOptions, AppEntityEditor, AppEntityEditorModal, AppEntityEditorModalOptions, AppEntityFormModule, AppForm, AppFormButtonsBarModule, AppFormField, AppFormModule, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppHomePageModule, AppIconComponent, AppIconModule, AppImageGalleryComponent, AppInMemoryTable, AppInstallUpgradeCard, AppInstallUpgradeCardModule, AppListForm, AppListFormModule, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppPropertiesFormModule, AppRegisterModule, AppSelectPeerModule, AppSettingsPageModule, AppTabEditor, AppTabEditorOptions, AppTable, AppTableModule, AppTableUtils, AppTextPopoverModule, AppUpdateOfflineModeCard, AppUpdateOfflineModeCardModule, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayJoinPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AudioTestingModule, AudioTestingPage, AuthGuardService, AutoTitleDirective, AutocompleteTestPage, AutofocusDirective, BadgeDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, CsvUtils, DATE_ISO_PATTERN, DATE_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTestPage, DateTimeTestPage, DateUtils, DebugComponent, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ED25519_SEED_LENGTH, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, ErrorCodes, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments, GalleryTestPage, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, IMAGE_DEFAULTS, ImageAttachment, ImageAttachmentFilter, ImageAttachmentService, ImageGalleryModule, ImageGalleryTestingModule, ImageModule, ImageService, ImagesUtils, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, Job, JobModule, JobProgression, JobProgressionIcon, JobProgressionList, JobProgressionService, JobProgressionTestService, JobProgressionTestingPage, JobTestingModule, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MOMENT_NO_TIME_PROPERTY, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatAutocompleteFieldUtils, MatBooleanField, MatChipsField, MatColorPipe, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuOptions, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageModule, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, NumpadTestPage, ObservableTestPage, OddPipe, PEER_URL_REGEXP, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertiesFormTestPage, PropertiesFormTestingModule, PropertyFormatPipe, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, RegisterForm, RegisterModal, ResizableComponent, ResizableDirective, ResizableModule, SCRYPT_PARAMS, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SOCIAL_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, ServerErrorCodes, SettingsPage, SharedAsyncValidators, SharedBadgeModule, SharedDebugModule, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedToolbarModule, SharedValidators, SocialErrorCodes, SocialModule, SocialModuleOptionsToken, SocialTestingModule, Software, StartableService, StatusById, StatusIds, StatusList, StorageDrivers, StorageService, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, ToastTestingModule, ToastTestingPage, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEventModule, UserEventNotificationIcon, UserEventTestService, UserEventTestingModule, UserEventTestingPage, UserSettings, UsersPage, ZERO_PLACEHOLDER_CHAR, accountToString, adaptValueToControl, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isCapacitor, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$1 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, patchValueInArray, propertiesPathComparator, propertyComparator, propertyPathComparator, pushValueInArray, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForFalse, waitForTrue, waitIdle, waitWhilePending };
33584
33616
  //# sourceMappingURL=sumaris-net.ngx-components.mjs.map