@sumaris-net/ngx-components 2.0.0-rc31 → 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,27 +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
- this.__moment = momentNamespace;
2561
- if (this.isEsModule(this.__moment)) {
2562
- this.__moment = this.__moment.default;
2563
- }
2564
- }
2565
- return this.__moment;
2566
- }
2567
2562
  static min(date1, date2) {
2568
2563
  return date1 && (!date2 || date1.isSameOrBefore(date2)) ? date1 : date2;
2569
2564
  }
@@ -2622,6 +2617,7 @@ class DateUtils {
2622
2617
  return momentDate.day() === weekday;
2623
2618
  }
2624
2619
  }
2620
+ DateUtils.moment = moment$1;
2625
2621
  DateUtils.toDateISOString = toDateISOString;
2626
2622
  DateUtils.fromDateISOString = fromDateISOString;
2627
2623
  DateUtils.toDuration = toDuration;
@@ -2689,7 +2685,6 @@ function toDuration(value, unit) {
2689
2685
  }
2690
2686
  return duration;
2691
2687
  }
2692
- const moment$1 = DateUtils.moment;
2693
2688
 
2694
2689
  class DateDiffDurationPipe {
2695
2690
  constructor(dateAdapter, translate) {
@@ -10540,7 +10535,6 @@ class ImagesUtils {
10540
10535
  }
10541
10536
  }
10542
10537
 
10543
- const uuidv4$1 = uuidv4Imported;
10544
10538
  class FileService {
10545
10539
  constructor(platform,
10546
10540
  //private transfer: FileTransfer,
@@ -10577,7 +10571,7 @@ class FileService {
10577
10571
  const lastSlashIndex = fileUrl.lastIndexOf('/');
10578
10572
  if (lastSlashIndex === -1)
10579
10573
  throw new Error('Invalid URL: ' + fileUrl);
10580
- const fileName = lastSlashIndex < (fileUrl.length - 1) && fileUrl.substring(lastSlashIndex + 1) || uuidv4$1();
10574
+ const fileName = lastSlashIndex < (fileUrl.length - 1) && fileUrl.substring(lastSlashIndex + 1) || v4();
10581
10575
  // Download into the file system
10582
10576
  if (outputType === 'fileUrl' && this.canUseFileSystem) {
10583
10577
  console.warn(`WARN: [file] Downloading image {${fileUrl}} in local filesystem...`);
@@ -13653,398 +13647,973 @@ function getNodeInfo(http, peer, opts) {
13653
13647
  });
13654
13648
  }
13655
13649
 
13656
- class SelectPeerModal {
13657
- constructor(modalCtrl, cd, http, environment) {
13658
- this.modalCtrl = modalCtrl;
13659
- this.cd = cd;
13660
- this.http = http;
13661
- this.environment = environment;
13662
- this._subscription = new Subscription();
13663
- this.loading = true;
13664
- this.$peers = new Subject();
13665
- this.peerMinVersion = this.environment.peerMinVersion;
13666
- this.canCancel = true;
13667
- this.allowSelectDownPeer = true;
13668
- this.onRefresh = new EventEmitter();
13669
- }
13670
- set peers(peers) {
13671
- this._subscription.add(peers.subscribe(res => this.refreshPeers(res)));
13672
- }
13673
- cancel() {
13674
- 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']);
13675
13658
  }
13676
- ngOnDestroy() {
13677
- 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;
13678
13679
  }
13679
- selectPeer(peer) {
13680
- if (this.allowSelectDownPeer || (peer.reachable && this.isCompatible(peer))) {
13681
- console.debug(`[select-peer-modal] Selected peer: {url: '${peer.url}'}`);
13682
- this.modalCtrl.dismiss(peer);
13680
+ get(fieldName) {
13681
+ if (!fieldName) {
13682
+ throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
13683
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;
13684
13710
  }
13685
13711
  /**
13686
- * Check the min pod version, defined by the app
13687
- *
13688
- * @param peer
13712
+ * @deprecated
13689
13713
  */
13690
- isCompatible(peer) {
13691
- return !this.peerMinVersion || (peer && peer.softwareVersion && VersionUtils.isCompatible(this.peerMinVersion, peer.softwareVersion));
13692
- }
13693
- refresh(event) {
13694
- this.loading = true;
13695
- this.onRefresh.emit(event);
13714
+ set _loading(value) {
13715
+ this.loadingSubject.next(value);
13696
13716
  }
13697
- /* -- protected methods -- */
13698
- refreshPeers(peers) {
13699
- return __awaiter(this, void 0, void 0, function* () {
13700
- peers = peers || [];
13701
- const data = [];
13702
- const jobs = Promise.all(peers.map((peer) => __awaiter(this, void 0, void 0, function* () {
13703
- yield this.refreshPeer(peer);
13704
- if (this._subscription.closed)
13705
- return; // component destroyed
13706
- data.push(peer);
13707
- // Sort (by reachable, then host)
13708
- data.sort((a, b) => {
13709
- if (a.reachable && !b.reachable)
13710
- return -1;
13711
- if (!a.reachable && b.reachable)
13712
- return 1;
13713
- if (a.hostAndPort < b.hostAndPort)
13714
- return -1;
13715
- if (a.hostAndPort > b.hostAndPort)
13716
- return 1;
13717
- return 0;
13718
- });
13719
- this.$peers.next(data);
13720
- return peer;
13721
- })));
13722
- this._subscription.add(this.$peers
13723
- .subscribe(() => this.cd.markForCheck()));
13724
- try {
13725
- yield jobs;
13726
- }
13727
- catch (err) {
13728
- if (!this._subscription.closed)
13729
- console.error(err);
13730
- }
13731
- this.loading = false;
13732
- this.cd.markForCheck();
13733
- });
13717
+ /**
13718
+ * @deprecated
13719
+ */
13720
+ get _loading() {
13721
+ return this.loadingSubject.value;
13734
13722
  }
13735
- refreshPeer(peer) {
13736
- return __awaiter(this, void 0, void 0, function* () {
13737
- try {
13738
- const summary = yield NetworkUtils.getNodeInfo(this.http, peer.url);
13739
- peer.status = 'UP';
13740
- peer.softwareName = summary.softwareName;
13741
- peer.softwareVersion = summary.softwareVersion;
13742
- peer.label = summary.nodeLabel;
13743
- peer.name = summary.nodeName;
13744
- }
13745
- catch (err) {
13746
- if (!this._subscription.closed) {
13747
- if (err && err.message) {
13748
- console.error('[select-peer] ' + err.message, err);
13749
- }
13750
- }
13751
- peer.status = 'DOWN';
13752
- }
13753
- return peer;
13754
- });
13723
+ /**
13724
+ * @deprecated
13725
+ */
13726
+ get _$ready() {
13727
+ return this.readySubject;
13755
13728
  }
13756
- markForCheck() {
13757
- this.cd.markForCheck();
13729
+ /**
13730
+ * @deprecated
13731
+ */
13732
+ get _$loading() {
13733
+ return this.loadingSubject;
13758
13734
  }
13759
- }
13760
- 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 });
13761
- 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 });
13762
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SelectPeerModal, decorators: [{
13763
- type: Component,
13764
- 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"] }]
13765
- }], ctorParameters: function () {
13766
- return [{ type: i2.ModalController }, { type: i0.ChangeDetectorRef }, { type: i2$5.HttpClient }, { type: undefined, decorators: [{
13767
- type: Inject,
13768
- args: [ENVIRONMENT]
13769
- }] }];
13770
- }, propDecorators: { canCancel: [{
13771
- type: Input
13772
- }], allowSelectDownPeer: [{
13773
- type: Input
13774
- }], onRefresh: [{
13775
- type: Input
13776
- }] } });
13777
-
13778
- /**
13779
- * Same as StartableService, bu with a dataSubject instead of a simple 'data' property
13780
- */
13781
- let StartableObservableService = class StartableObservableService {
13782
- constructor(prerequisiteService) {
13783
- this.dataSubject = new BehaviorSubject(null);
13784
- this.startSubject = new Subject();
13785
- this.stopSubject = new Subject();
13786
- this._debug = false;
13787
- this._startByReadyFunction = true; // should start when calling ready() ?
13788
- this._started = false;
13789
- this._startPromise = null;
13790
- this._startPrerequisite = null;
13791
- this._subscription = null;
13792
- this._startPrerequisite = prerequisiteService
13793
- ? () => prerequisiteService.ready()
13794
- : () => Promise.resolve();
13735
+ get error() {
13736
+ return this.errorSubject.value;
13795
13737
  }
13796
- start(opts) {
13797
- if (this._startPromise)
13798
- return this._startPromise;
13799
- if (this._started)
13800
- return Promise.resolve(this.dataSubject.value);
13801
- this._startPromise = this._startPrerequisite()
13802
- .then(() => this.ngOnStart(opts))
13803
- .then(data => {
13804
- this._started = true;
13805
- this._startPromise = undefined;
13806
- // Should be done AFTER 'this._started = true', because of the 'filter' operator, inside ready() function
13807
- this.dataSubject.next(data);
13808
- this.startSubject.next(data);
13809
- return data;
13810
- })
13811
- .catch(err => {
13812
- if (!this.stopped) {
13813
- console.error('Failed to start a service: ' + (err && err.message || err), err);
13814
- this._started = false;
13815
- this._startPromise = null;
13816
- }
13817
- return null;
13818
- });
13819
- return this._startPromise;
13738
+ set error(error) {
13739
+ this.setError(error);
13820
13740
  }
13821
- ready() {
13822
- if (this._started)
13823
- return Promise.resolve(this.dataSubject.value);
13824
- if (this._startPromise)
13825
- return this._startPromise;
13826
- if (this._startByReadyFunction)
13827
- return this.start();
13828
- return this.dataSubject
13829
- .pipe(takeUntil(this.stopSubject),
13830
- // Wait start() to be called, to exclude the initial 'null' value
13831
- filter(_ => this._started))
13832
- .toPromise();
13741
+ get loading() {
13742
+ return this.loadingSubject.value;
13833
13743
  }
13834
- stop() {
13835
- return __awaiter(this, void 0, void 0, function* () {
13836
- try {
13837
- this.unsubscribe();
13838
- yield this.ngOnStop();
13839
- }
13840
- catch (err) {
13841
- console.error('Failed to stop a service: ' + (err && err.message || err), err);
13842
- }
13843
- finally {
13844
- this._started = false;
13845
- this._startPromise = undefined;
13846
- this.stopSubject.next(); // Stop all running observables
13847
- this.dataSubject.next(null); // Reset data
13848
- }
13849
- });
13744
+ get loaded() {
13745
+ return !this.loadingSubject.value;
13850
13746
  }
13851
- restart(opts) {
13852
- return __awaiter(this, void 0, void 0, function* () {
13853
- if (this._startPromise)
13854
- yield this._startPromise; // Wait end of previous loading
13855
- if (this._started)
13856
- yield this.stop(); // Then stop if started
13857
- return this.start(opts); // Then start again
13858
- });
13747
+ get value() {
13748
+ return this.form.value;
13859
13749
  }
13860
- get started() {
13861
- return this._started;
13750
+ set value(data) {
13751
+ this.setValue(data);
13862
13752
  }
13863
- get starting() {
13864
- return !!this._startPromise;
13753
+ get dirty() {
13754
+ var _a;
13755
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.dirty) || false;
13865
13756
  }
13866
- get stopped() {
13867
- return !this._started && !this._startPromise;
13757
+ get invalid() {
13758
+ return !this.form || this.form.invalid;
13868
13759
  }
13869
- get data() {
13870
- return this.dataSubject.value;
13760
+ get pending() {
13761
+ return !this.form || (this.form.dirty && this.form.pending);
13871
13762
  }
13872
- set data(value) {
13873
- if (this.dataSubject.value !== value) {
13874
- this.dataSubject.next(value);
13875
- }
13763
+ get valid() {
13764
+ var _a;
13765
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
13876
13766
  }
13877
- registerSubscription(sub) {
13878
- this._subscription = this._subscription || new Subscription();
13879
- this._subscription.add(sub);
13767
+ get empty() {
13768
+ return !this.form || (!this.form.dirty && !this.form.touched);
13880
13769
  }
13881
- unregisterSubscription(sub) {
13770
+ get touched() {
13882
13771
  var _a;
13883
- (_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;
13884
13773
  }
13885
- unsubscribe() {
13886
- var _a;
13887
- (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
13888
- this._subscription = null;
13774
+ get untouched() {
13775
+ return !this.form || this.form.untouched;
13889
13776
  }
13890
- ngOnStop() {
13891
- // Can be overwritten by subclasses
13777
+ get enabled() {
13778
+ return this._enable;
13892
13779
  }
13893
- };
13894
- StartableObservableService = __decorate([
13895
- __param(0, Optional())
13896
- ], StartableObservableService);
13897
-
13898
- // Base58 encoding/decoding
13899
- // Originally written by Mike Hearn for BitcoinJ
13900
- // Copyright (c) 2011 Google Inc
13901
- // Ported to JavaScript by Stefan Thomas
13902
- // Merged Buffer refactorings from base58-native by Stephen Pair
13903
- // Copyright (c) 2013 BitPay Inc
13904
- // Rewritten in TypeScript by Ludovic Pecquot
13905
- // @dynamic
13906
- class Base58 {
13907
- static getAlphabetMap() {
13908
- if (!Base58.alphabetMap) {
13909
- this.alphabetMap = {};
13910
- for (let i = 0; i < Base58.alphabet.length; i++) {
13911
- Base58.alphabetMap[Base58.alphabet.charAt(i)] = i;
13912
- }
13913
- }
13914
- return Base58.alphabetMap;
13780
+ get disabled() {
13781
+ return !this._enable;
13915
13782
  }
13916
- static encode(buffer) {
13917
- if (buffer.length === 0)
13918
- return '';
13919
- let i;
13920
- let j;
13921
- const digits = [0];
13922
- for (i = 0; i < buffer.length; i++) {
13923
- for (j = 0; j < digits.length; j++)
13924
- digits[j] <<= 8;
13925
- digits[digits.length - 1] += buffer[i];
13926
- let carry = 0;
13927
- for (j = digits.length - 1; j >= 0; j--) {
13928
- digits[j] += carry;
13929
- carry = (digits[j] / 58) | 0;
13930
- digits[j] %= 58;
13931
- }
13932
- while (carry) {
13933
- digits.unshift(carry);
13934
- carry = (digits[0] / 58) | 0;
13935
- digits[0] %= 58;
13936
- }
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();
13937
13790
  }
13938
- // deal with leading zeros
13939
- for (i = 0; i < buffer.length - 1 && buffer[i] === 0; i++)
13940
- digits.unshift(0);
13941
- return digits.map(function (digit) { return Base58.alphabet[digit]; }).join('');
13942
13791
  }
13943
- static decode(string) {
13944
- if (string.length === 0)
13945
- return (new Uint8Array(0));
13946
- const input = string.split('').map(function (c) {
13947
- return Base58.getAlphabetMap()[c];
13948
- });
13949
- let i;
13950
- let j;
13951
- const bytes = [0];
13952
- for (i = 0; i < input.length; i++) {
13953
- for (j = 0; j < bytes.length; j++)
13954
- bytes[j] *= 58;
13955
- bytes[bytes.length - 1] += input[i];
13956
- let carry = 0;
13957
- for (j = bytes.length - 1; j >= 0; j--) {
13958
- bytes[j] += carry;
13959
- carry = bytes[j] >> 8;
13960
- bytes[j] &= 0xff;
13961
- }
13962
- while (carry) {
13963
- bytes.unshift(carry);
13964
- carry = bytes[0] >> 8;
13965
- bytes[0] &= 0xff;
13966
- }
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();
13967
13799
  }
13968
- // deal with leading zeros
13969
- for (i = 0; i < input.length - 1 && input[i] === 0; i++)
13970
- bytes.unshift(0);
13971
- return (new Uint8Array(bytes));
13972
13800
  }
13973
- }
13974
- Base58.alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
13975
-
13976
- const ED25519_SEED_LENGTH = 32; // Length of a ED25519 seed
13977
- const SCRYPT_PARAMS = {
13978
- SIMPLE: {
13979
- N: 2048,
13980
- r: 8,
13981
- p: 1
13982
- },
13983
- DEFAULT: {
13984
- N: 4096,
13985
- r: 16,
13986
- p: 1
13987
- },
13988
- SECURE: {
13989
- N: 16384,
13990
- r: 32,
13991
- p: 2
13992
- },
13993
- HARDEST: {
13994
- N: 65536,
13995
- r: 32,
13996
- p: 4
13997
- },
13998
- EXTREME: {
13999
- N: 262144,
14000
- r: 64,
14001
- p: 8
13801
+ get destroyed() {
13802
+ var _a;
13803
+ return ((_a = this.destroySubject) === null || _a === void 0 ? void 0 : _a.closed) !== false;
14002
13804
  }
14003
- };
14004
- class CryptoService {
14005
- static get started() {
14006
- return this._ready;
13805
+ set form(value) {
13806
+ this.setForm(value);
14007
13807
  }
14008
- static ready() {
14009
- return __awaiter(this, void 0, void 0, function* () {
14010
- if (this._ready)
14011
- return; // OK
14012
- yield cryptoWaitReady();
14013
- this._ready = true;
14014
- });
13808
+ get form() {
13809
+ return this._form;
14015
13810
  }
14016
- /**
14017
- * Generate a sign keypair, using scrypt, from a salt and a password
14018
- *
14019
- * @param salt
14020
- * @param password
14021
- * @param scryptParams
14022
- */
14023
- static scryptKeypair(salt, password, scryptParams) {
14024
- return __awaiter(this, void 0, void 0, function* () {
14025
- if (!this.started)
14026
- yield this.ready();
14027
- const passwordU8a = decodeUTF8(password);
14028
- const saltU8a = decodeUTF8(salt);
14029
- const result = scryptEncode(passwordU8a, saltU8a, scryptParams || SCRYPT_PARAMS.DEFAULT);
14030
- const seed = result.password.slice(0, ED25519_SEED_LENGTH);
14031
- return ed25519PairFromSeed(seed);
14032
- });
13811
+ ngOnInit() {
13812
+ this._enable ? this.enable() : this.disable();
13813
+ this.errorTranslatorOptions = this.errorTranslatorOptions || {
13814
+ controlPathTranslator: this
13815
+ };
14033
13816
  }
14034
- /**
14035
- * Sign a message, from a key pair
14036
- */
14037
- static sign(message, keypair) {
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() {
14038
13828
  return __awaiter(this, void 0, void 0, function* () {
14039
- if (!this.started)
14040
- yield this.ready();
14041
- const m = decodeUTF8(message);
14042
- const sig = ed25519Sign(m, keypair);
14043
- return encodeBase64(sig);
13829
+ this.onCancel.emit();
14044
13830
  });
14045
13831
  }
14046
13832
  /**
14047
- * Sign a message, from a key pair
13833
+ *
13834
+ * @param event
13835
+ * @param opts allow to skip validation check, using {checkValid: false}
13836
+ */
13837
+ doSubmit(event, opts) {
13838
+ return __awaiter(this, void 0, void 0, function* () {
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
+ }
14615
+ /**
14616
+ * Sign a message, from a key pair
14048
14617
  */
14049
14618
  static verify(message, signature, publicKey) {
14050
14619
  return __awaiter(this, void 0, void 0, function* () {
@@ -14108,6 +14677,7 @@ const NetworkRefreshTimerPeriod = {
14108
14677
  MOBILE: 1000 * 60 * 10 /* every 10 min */,
14109
14678
  DESKTOP: 1000 * 60 * 5 /* every 5 min */
14110
14679
  };
14680
+ const PEER_URL_REGEXP = /^(http|https):\/\/[^ "?#@]+$/;
14111
14681
  /* -- DEV only (to debug refresh timer)
14112
14682
  const NetworkRefreshTimerPeriod = {
14113
14683
  MOBILE: 1000,
@@ -14417,12 +14987,7 @@ class NetworkService extends StartableObservableService {
14417
14987
  const peers$ = $onRefresh.pipe(mergeMap((_) => this.getDefaultPeers()), map(peers => peers || []));
14418
14988
  const modal = yield this.modalCtrl.create({
14419
14989
  component: SelectPeerModal,
14420
- componentProps: {
14421
- onRefresh: $onRefresh,
14422
- peers: peers$,
14423
- canCancel: toBoolean(opts.canCancel, true),
14424
- allowSelectDownPeer: toBoolean(opts.allowSelectDownPeer, true)
14425
- },
14990
+ componentProps: Object.assign({ onRefresh: $onRefresh, peers: peers$ }, opts),
14426
14991
  keyboardClose: true,
14427
14992
  showBackdrop: true
14428
14993
  });
@@ -14985,7 +15550,6 @@ function accountToString(data) {
14985
15550
  (data.lastName || '')) || '';
14986
15551
  }
14987
15552
 
14988
- const uuidv4 = uuidv4Imported;
14989
15553
  const _global = typeof global !== 'undefined' ? global : (typeof window !== 'undefined' ? window : {});
14990
15554
  const NativeWebSocket = _global.WebSocket || _global.MozWebSocket;
14991
15555
  /**
@@ -15029,7 +15593,7 @@ function createTrackerLink(opts) {
15029
15593
  // Skip if not tracked
15030
15594
  if (!context || !context.tracked)
15031
15595
  return forward(operation);
15032
- const id = context.serializationKey || uuidv4();
15596
+ const id = context.serializationKey || v4();
15033
15597
  console.debug(`[apollo-tracker-link] Watching tracked query {${operation.operationName}#${id}}`);
15034
15598
  // Clean context, before calling JSON.stringify (remove unused attributes)
15035
15599
  const cleanContext = Object.assign(Object.assign({}, context), { optimisticResponse: null, cache: null });
@@ -19008,44 +19572,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
19008
19572
  }]
19009
19573
  }], ctorParameters: function () { return []; } });
19010
19574
 
19011
- class MatAutocompleteConfigHolder {
19012
- constructor(options) {
19013
- this.options = options;
19014
- this.fields = {};
19015
- // Store the function from options (e.g. get from user settings)
19016
- // or create a default function
19017
- this.getUserAttributes = (options === null || options === void 0 ? void 0 : options.getUserAttributes) ||
19018
- ((fieldName, defaultAttributes) => defaultAttributes || ['label', 'name']);
19019
- }
19020
- add(fieldName, options) {
19021
- if (!fieldName) {
19022
- throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
19023
- }
19024
- options = options || {};
19025
- const suggestFn = options.suggestFn
19026
- || (options.service && ((v, f) => options.service.suggest(v, f)))
19027
- || undefined;
19028
- const attributes = (this.getUserAttributes(fieldName, options.attributes) || ['label', 'name']);
19029
- // Keep original the function from options, when exists
19030
- const attributesOrFn = attributes.map((a, index) => typeof a === 'function' && options.attributes[index] || a);
19031
- const filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
19032
- const displayWith = options.displayWith || MatAutocompleteFieldUtils.createDisplayFn(attributes, options.multiple);
19033
- const equals = options.equals || MatAutocompleteFieldUtils.defaultEquals;
19034
- const config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn,
19035
- filter,
19036
- displayWith,
19037
- equals });
19038
- this.fields[fieldName] = config;
19039
- return config;
19040
- }
19041
- get(fieldName) {
19042
- if (!fieldName) {
19043
- throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
19044
- }
19045
- return this.fields[fieldName] || this.add(fieldName);
19046
- }
19047
- }
19048
-
19049
19575
  class FormFieldValuesHolder {
19050
19576
  getAsBoolean(data, definition) {
19051
19577
  const value = this.get(data, definition);
@@ -21138,6 +21664,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
21138
21664
  }]
21139
21665
  }] });
21140
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
+
21141
21701
  class AppSelectPeerModule {
21142
21702
  }
21143
21703
  AppSelectPeerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -21145,19 +21705,21 @@ AppSelectPeerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", ver
21145
21705
  // Network
21146
21706
  SelectPeerModal
21147
21707
  ], imports: [SharedModule,
21148
- HttpClientModule, i1$1.TranslateModule], exports: [TranslateModule,
21708
+ HttpClientModule, i1$1.TranslateModule, AppTextPopoverModule], exports: [TranslateModule,
21149
21709
  // Components
21150
21710
  SelectPeerModal] });
21151
21711
  AppSelectPeerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, imports: [SharedModule,
21152
21712
  HttpClientModule,
21153
- TranslateModule.forChild(), TranslateModule] });
21713
+ TranslateModule.forChild(),
21714
+ AppTextPopoverModule, TranslateModule] });
21154
21715
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, decorators: [{
21155
21716
  type: NgModule,
21156
21717
  args: [{
21157
21718
  imports: [
21158
21719
  SharedModule,
21159
21720
  HttpClientModule,
21160
- TranslateModule.forChild()
21721
+ TranslateModule.forChild(),
21722
+ AppTextPopoverModule
21161
21723
  ],
21162
21724
  declarations: [
21163
21725
  // Network
@@ -21589,577 +22151,240 @@ class AccountValidatorService extends AppValidatorService {
21589
22151
  lastName: [data && data.lastName || null, Validators.compose([Validators.required, Validators.minLength(2)])],
21590
22152
  firstName: [data && data.firstName || null, Validators.compose([Validators.required, Validators.minLength(2)])],
21591
22153
  email: [data && data.email || null, Validators.compose([Validators.required, Validators.email])],
21592
- mainProfile: [data && (data.mainProfile || PersonUtils.getMainProfile(data.profiles)) || 'GUEST', Validators.required],
21593
- statusId: [data && data.statusId || StatusIds.TEMPORARY, Validators.required],
21594
- pubkey: [data && data.pubkey || null, Validators.compose([Validators.required, SharedValidators.pubkey])]
21595
- };
21596
- // Add additional fields
21597
- this.accountService.additionalFields.forEach(field => {
21598
- //console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
21599
- formDef[field.key] = [data && data[field.key] || null, this.getValidators(field)];
21600
- });
21601
- return formDef;
21602
- }
21603
- getValidators(field) {
21604
- const validatorFns = [];
21605
- if (field.extra && field.extra.account && field.extra.account.required) {
21606
- validatorFns.push(Validators.required);
21607
- }
21608
- if (field.type === 'entity') {
21609
- validatorFns.push(SharedValidators.entity);
21610
- }
21611
- return validatorFns.length ? Validators.compose(validatorFns) : validatorFns.length === 1 ? validatorFns[0] : undefined;
21612
- }
21613
- }
21614
- 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 });
21615
- AccountValidatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, providedIn: 'root' });
21616
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, decorators: [{
21617
- type: Injectable,
21618
- args: [{ providedIn: 'root' }]
21619
- }], ctorParameters: function () { return [{ type: i1$2.UntypedFormBuilder }, { type: AccountService }]; } });
21620
-
21621
- class RegisterForm {
21622
- constructor(accountService, accountValidatorService, formBuilder, environment, settings) {
21623
- this.accountService = accountService;
21624
- this.accountValidatorService = accountValidatorService;
21625
- this.formBuilder = formBuilder;
21626
- this.environment = environment;
21627
- this.settings = settings;
21628
- this.debug = false;
21629
- this.subscriptions = [];
21630
- this.sending = false;
21631
- this.showPwd = false;
21632
- this.showConfirmPwd = false;
21633
- this.onCancel = new EventEmitter();
21634
- this.onSubmit = new EventEmitter();
21635
- this.referentialToString = referentialToString;
21636
- this.forms = [];
21637
- // Email form
21638
- this.forms.push(formBuilder.group({
21639
- email: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.email]), this.emailAvailability(this.accountService)),
21640
- confirmEmail: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('email')]))
21641
- }));
21642
- // Password form
21643
- this.forms.push(formBuilder.group({
21644
- password: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(8)])),
21645
- confirmPassword: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('password')]))
21646
- }));
21647
- // Detail form
21648
- const formDetailDef = {
21649
- lastName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)])),
21650
- firstName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)]))
21651
- };
21652
- // Prepare autocomplete settings
21653
- this.autocompleteHelper = new MatAutocompleteConfigHolder(settings && {
21654
- getUserAttributes: (a, b) => settings.getFieldDisplayAttributes(a, b)
21655
- });
21656
- // Add additional fields to details form
21657
- this.additionalFields = this.accountService.additionalFields
21658
- // Keep only required fields
21659
- .filter(field => field.extra && field.extra.registration && field.extra.registration.required);
21660
- this.additionalFields.forEach(field => {
21661
- //if (this.debug) console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
21662
- formDetailDef[field.key] = new UntypedFormControl(null, this.accountValidatorService.getValidators(field));
21663
- if (field.type === 'entity') {
21664
- field.autocomplete = this.autocompleteHelper.add(field.key, field.autocomplete);
21665
- }
21666
- });
21667
- this.forms.push(formBuilder.group(formDetailDef));
21668
- this.form = formBuilder.group({
21669
- emailStep: this.forms[0],
21670
- passwordStep: this.forms[1],
21671
- detailsStep: this.forms[2]
21672
- });
21673
- }
21674
- ngOnInit() {
21675
- // For DEV only ------------------------
21676
- if (!this.environment.production) {
21677
- this.form.setValue({
21678
- emailStep: {
21679
- email: 'contact@e-is.pro',
21680
- confirmEmail: 'contact@e-is.pro'
21681
- },
21682
- passwordStep: {
21683
- password: 'contactera',
21684
- confirmPassword: 'contactera'
21685
- },
21686
- detailsStep: {
21687
- lastName: 'Lavenier 2',
21688
- firstName: 'Benoit',
21689
- department: null
21690
- }
21691
- });
21692
- }
21693
- }
21694
- get value() {
21695
- const result = {
21696
- username: this.form.value.emailStep.email,
21697
- password: this.form.value.passwordStep.password,
21698
- account: new Account()
21699
- };
21700
- result.account.fromObject(this.form.value.detailsStep);
21701
- result.account.email = result.username;
21702
- return result;
21703
- }
21704
- get valid() {
21705
- return this.form.valid;
21706
- }
21707
- isEnd() {
21708
- return this.stepper.selectedIndex === 2;
21709
- }
21710
- isBeginning() {
21711
- return this.stepper.selectedIndex === 0;
21712
- }
21713
- slidePrev() {
21714
- return this.stepper.previous();
21715
- }
21716
- slideNext(event) {
21717
- if (event) {
21718
- event.stopPropagation();
21719
- event.preventDefault();
21720
- }
21721
- return this.stepper.next();
21722
- }
21723
- equalsValidator(otherControlName) {
21724
- return function (c) {
21725
- if (c.parent && c.value !== c.parent.value[otherControlName]) {
21726
- return {
21727
- equals: true
21728
- };
21729
- }
21730
- return null;
21731
- };
21732
- }
21733
- emailAvailability(accountService) {
21734
- return function (control) {
21735
- return timer(500).pipe(mergeMap(() => accountService.checkEmailAvailable(control.value)
21736
- .then(res => null)
21737
- .catch(err => {
21738
- console.error(err);
21739
- return { availability: true };
21740
- })));
21741
- };
21742
- }
21743
- cancel() {
21744
- this.onCancel.emit();
21745
- }
21746
- doSubmit(event) {
21747
- if (this.form.invalid)
21748
- return;
21749
- this.sending = true;
21750
- this.onSubmit.emit(this.value);
21751
- }
21752
- markAsTouched() {
21753
- this.form.markAsTouched();
21754
- }
21755
- disable() {
21756
- this.form.disable();
21757
- }
21758
- enable() {
21759
- this.form.enable();
21760
- }
21761
- }
21762
- 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 });
21763
- 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" }] });
21764
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterForm, decorators: [{
21765
- type: Component,
21766
- 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"] }]
21767
- }], ctorParameters: function () {
21768
- return [{ type: AccountService }, { type: AccountValidatorService }, { type: i1$2.UntypedFormBuilder }, { type: undefined, decorators: [{
21769
- type: Inject,
21770
- args: [ENVIRONMENT]
21771
- }] }, { type: LocalSettingsService }];
21772
- }, propDecorators: { stepper: [{
21773
- type: ViewChild,
21774
- args: ['stepper', { static: true }]
21775
- }], onCancel: [{
21776
- type: Output
21777
- }], onSubmit: [{
21778
- type: Output
21779
- }] } });
21780
-
21781
- class RegisterModal {
21782
- constructor(accountService, viewCtrl) {
21783
- this.accountService = accountService;
21784
- this.viewCtrl = viewCtrl;
21785
- this.sending = false;
21786
- }
21787
- cancel() {
21788
- console.debug('[register] cancelled');
21789
- this.viewCtrl.dismiss();
21790
- }
21791
- doSubmit(event) {
21792
- return __awaiter(this, void 0, void 0, function* () {
21793
- if (this.form.form.disabled || this.sending)
21794
- return; // Skip
21795
- if (!this.form.valid || !this.form.isEnd()) {
21796
- this.form.markAsTouched();
21797
- return;
21798
- }
21799
- this.sending = true;
21800
- const data = this.form.value;
21801
- this.form.disable();
21802
- try {
21803
- console.debug('[register] Sending registration to server...', data);
21804
- const res = yield this.accountService.register(data);
21805
- console.debug('[register] Account registered!');
21806
- yield this.viewCtrl.dismiss();
21807
- }
21808
- catch (err) {
21809
- this.form.error = err && err.message || err;
21810
- this.form.enable();
21811
- }
21812
- finally {
21813
- this.sending = false;
21814
- }
21815
- });
21816
- }
21817
- }
21818
- 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 });
21819
- 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"] }] });
21820
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterModal, decorators: [{
21821
- type: Component,
21822
- 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" }]
21823
- }], ctorParameters: function () { return [{ type: AccountService }, { type: i2.ModalController }]; }, propDecorators: { form: [{
21824
- type: ViewChild,
21825
- args: ['form', { static: true }]
21826
- }] } });
21827
-
21828
- // eslint-disable-next-line @angular-eslint/directive-class-suffix
21829
- class AppForm {
21830
- constructor(injector, form) {
21831
- this._subscription = new Subscription();
21832
- this._enable = false;
21833
- this.i18nFieldPrefix = null;
21834
- this.destroySubject = new Subject();
21835
- this.readySubject = new BehaviorSubject(false);
21836
- this.loadingSubject = new BehaviorSubject(true);
21837
- this.errorSubject = new BehaviorSubject(undefined);
21838
- this.debug = false;
21839
- this.onCancel = new EventEmitter();
21840
- this.onSubmit = new EventEmitter();
21841
- if (form)
21842
- this.setForm(form);
21843
- this.translate = injector.get(TranslateService);
21844
- this.settings = injector.get(LocalSettingsService);
21845
- this.errorTranslator = injector.get(FormErrorTranslator);
21846
- this.autocompleteHelper = new MatAutocompleteConfigHolder(this.settings && {
21847
- getUserAttributes: (a, b) => this.settings.getFieldDisplayAttributes(a, b)
21848
- });
21849
- this.autocompleteFields = this.autocompleteHelper.fields;
21850
- }
21851
- /**
21852
- * @deprecated
21853
- */
21854
- set _loading(value) {
21855
- this.loadingSubject.next(value);
21856
- }
21857
- /**
21858
- * @deprecated
21859
- */
21860
- get _loading() {
21861
- return this.loadingSubject.value;
21862
- }
21863
- /**
21864
- * @deprecated
21865
- */
21866
- get _$ready() {
21867
- return this.readySubject;
21868
- }
21869
- /**
21870
- * @deprecated
21871
- */
21872
- get _$loading() {
21873
- return this.loadingSubject;
21874
- }
21875
- get error() {
21876
- return this.errorSubject.value;
21877
- }
21878
- set error(error) {
21879
- this.setError(error);
21880
- }
21881
- get loading() {
21882
- return this.loadingSubject.value;
21883
- }
21884
- get loaded() {
21885
- return !this.loadingSubject.value;
21886
- }
21887
- get value() {
21888
- return this.form.value;
21889
- }
21890
- set value(data) {
21891
- this.setValue(data);
21892
- }
21893
- get dirty() {
21894
- var _a;
21895
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.dirty) || false;
21896
- }
21897
- get invalid() {
21898
- return !this.form || this.form.invalid;
21899
- }
21900
- get pending() {
21901
- return !this.form || (this.form.dirty && this.form.pending);
21902
- }
21903
- get valid() {
21904
- var _a;
21905
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
21906
- }
21907
- get empty() {
21908
- return !this.form || (!this.form.dirty && !this.form.touched);
21909
- }
21910
- get touched() {
21911
- var _a;
21912
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.touched) || false;
21913
- }
21914
- get untouched() {
21915
- return !this.form || this.form.untouched;
21916
- }
21917
- get enabled() {
21918
- return this._enable;
21919
- }
21920
- get disabled() {
21921
- return !this._enable;
21922
- }
21923
- disable(opts) {
21924
- var _a;
21925
- (_a = this.form) === null || _a === void 0 ? void 0 : _a.disable(opts);
21926
- if (this._enable) {
21927
- this._enable = false;
21928
- if (!opts || opts.emitEvent !== true)
21929
- this.markForCheck();
21930
- }
21931
- }
21932
- enable(opts) {
21933
- var _a;
21934
- (_a = this.form) === null || _a === void 0 ? void 0 : _a.enable(opts);
21935
- if (!this._enable) {
21936
- this._enable = true;
21937
- if (!opts || opts.emitEvent !== true)
21938
- this.markForCheck();
21939
- }
21940
- }
21941
- get destroyed() {
21942
- var _a;
21943
- return ((_a = this.destroySubject) === null || _a === void 0 ? void 0 : _a.closed) !== false;
21944
- }
21945
- set form(value) {
21946
- this.setForm(value);
21947
- }
21948
- get form() {
21949
- return this._form;
21950
- }
21951
- ngOnInit() {
21952
- this._enable ? this.enable() : this.disable();
21953
- this.errorTranslatorOptions = this.errorTranslatorOptions || {
21954
- controlPathTranslator: this
21955
- };
21956
- }
21957
- ngOnDestroy() {
21958
- this._subscription.unsubscribe();
21959
- this.readySubject.unsubscribe();
21960
- this.loadingSubject.unsubscribe();
21961
- this.errorSubject.unsubscribe();
21962
- this.onCancel.unsubscribe();
21963
- this.onSubmit.unsubscribe();
21964
- this.destroySubject.next();
21965
- this.destroySubject.unsubscribe();
21966
- }
21967
- cancel() {
21968
- return __awaiter(this, void 0, void 0, function* () {
21969
- this.onCancel.emit();
21970
- });
21971
- }
21972
- /**
21973
- *
21974
- * @param event
21975
- * @param opts allow to skip validation check, using {checkValid: false}
21976
- */
21977
- doSubmit(event, opts) {
21978
- return __awaiter(this, void 0, void 0, function* () {
21979
- if (!this._form) {
21980
- this.markAllAsTouched({ emitEvent: true });
21981
- return;
21982
- }
21983
- // Check if valid (if not disabled)
21984
- if ((!opts || opts.checkValid !== false) && !this._form.valid) {
21985
- // Wait validation end
21986
- yield AppFormUtils.waitWhilePending(this._form);
21987
- // Form is invalid: exit (+ log if debug)
21988
- if (this._form.invalid) {
21989
- this.markAllAsTouched({ emitEvent: true });
21990
- if (this.debug)
21991
- AppFormUtils.logFormErrors(this._form);
21992
- return;
21993
- }
21994
- }
21995
- // Emit event
21996
- this.onSubmit.emit(event);
21997
- });
21998
- }
21999
- setForm(form) {
22000
- if (this._form !== form) {
22001
- this._form = form;
22002
- this._subscription.add(this._form.statusChanges.subscribe(status => this.markForCheck()));
22003
- }
22004
- }
22005
- setValue(data, opts) {
22006
- if (!data) {
22007
- console.warn('[form] Trying to set an empty value to form. Skipping');
22008
- return;
22009
- }
22010
- // DEBUG
22011
- //if (this.debug) console.debug('[form] Updating form (using entity)', data);
22012
- // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
22013
- AppFormUtils.copyEntity2Form(data, this.form, Object.assign({ emitEvent: false, onlySelf: true }, opts));
22014
- if (!opts || opts.emitEvent !== true) {
22015
- this.markForCheck();
22016
- }
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;
22017
22164
  }
22018
- reset(data, opts) {
22019
- if (data) {
22020
- if (this.debug)
22021
- console.debug('[form] Resetting form (using entity)', data);
22022
- // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
22023
- const json = AppFormUtils.getFormValueFromEntity(data, this.form);
22024
- 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);
22025
22169
  }
22026
- else {
22027
- this.form.reset(null, { emitEvent: false, onlySelf: true });
22170
+ if (field.type === 'entity') {
22171
+ validatorFns.push(SharedValidators.entity);
22028
22172
  }
22029
- if (!opts || opts.emitEvent !== true)
22030
- this.markForCheck();
22173
+ return validatorFns.length ? Validators.compose(validatorFns) : validatorFns.length === 1 ? validatorFns[0] : undefined;
22031
22174
  }
22032
- markAsPristine(opts) {
22033
- this.form.markAsPristine(opts);
22034
- if (!opts || opts.emitEvent !== false)
22035
- 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
+ });
22036
22235
  }
22037
- markAsUntouched(opts) {
22038
- this.form.markAsUntouched(opts);
22039
- if (!opts || opts.emitEvent !== false)
22040
- 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
+ }
22041
22255
  }
22042
- /**
22043
- * @deprecated prefer to use markAllAsTouched()
22044
- * @param opts
22045
- */
22046
- markAsTouched(opts) {
22047
- // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
22048
- console.warn('TODO: Replace this call by markAllAsTouched() - because of changes in ngx-components >= 0.16.0');
22049
- AppFormUtils.markAsTouched(this.form, opts);
22050
- if (!opts || opts.emitEvent !== false)
22051
- 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;
22052
22265
  }
22053
- markAllAsTouched(opts) {
22054
- // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
22055
- AppFormUtils.markAllAsTouched(this.form, opts);
22056
- if (!opts || opts.emitEvent !== false)
22057
- this.markForCheck();
22266
+ get valid() {
22267
+ return this.form.valid;
22058
22268
  }
22059
- markAsDirty(opts) {
22060
- this.form.markAsDirty(opts);
22061
- if (!opts || opts.emitEvent !== false)
22062
- this.markForCheck();
22269
+ isEnd() {
22270
+ return this.stepper.selectedIndex === 2;
22063
22271
  }
22064
- markAsLoading(opts) {
22065
- this.setLoading(true, opts);
22272
+ isBeginning() {
22273
+ return this.stepper.selectedIndex === 0;
22066
22274
  }
22067
- markAsLoaded(opts) {
22068
- this.setLoading(false, opts);
22275
+ slidePrev() {
22276
+ return this.stepper.previous();
22069
22277
  }
22070
- markAsReady(opts) {
22071
- if (this.readySubject.value !== true) {
22072
- this.readySubject.next(true);
22073
- // If subclasses implements OnReady
22074
- if (typeof this['ngOnReady'] === 'function') {
22075
- this.ngOnReady();
22076
- }
22278
+ slideNext(event) {
22279
+ if (event) {
22280
+ event.stopPropagation();
22281
+ event.preventDefault();
22077
22282
  }
22283
+ return this.stepper.next();
22078
22284
  }
22079
- /**
22080
- * Wait form is ready
22081
- * @param opts
22082
- */
22083
- ready(opts) {
22084
- if (this.readySubject.value)
22085
- return Promise.resolve();
22086
- 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
+ };
22087
22294
  }
22088
- /**
22089
- * Wait form is not busy (=loaded)
22090
- * @param opts
22091
- */
22092
- waitIdle(opts) {
22093
- if (!this.loadingSubject.value)
22094
- return Promise.resolve();
22095
- 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
+ };
22096
22304
  }
22097
- updateValueAndValidity(opts) {
22098
- AppFormUtils.updateValueAndValidity(this.form, opts);
22099
- if (!opts || opts.emitEvent !== false)
22100
- this.markForCheck();
22305
+ cancel() {
22306
+ this.onCancel.emit();
22101
22307
  }
22102
- translateControlPath(path) {
22103
- var _a;
22104
- const i18nFieldName = this.getI18nFieldName(path);
22105
- 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);
22106
22313
  }
22107
- /* -- protected methods -- */
22108
- getFormError(form, opts) {
22109
- if (!form || !this.errorTranslator)
22110
- return undefined;
22111
- return this.errorTranslator.translateFormErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
22314
+ markAsTouched() {
22315
+ this.form.markAsTouched();
22112
22316
  }
22113
- getI18nFieldName(path) {
22114
- return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
22317
+ disable() {
22318
+ this.form.disable();
22115
22319
  }
22116
- registerSubscription(sub) {
22117
- this._subscription.add(sub);
22320
+ enable() {
22321
+ this.form.enable();
22118
22322
  }
22119
- unregisterSubscription(sub) {
22120
- 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;
22121
22348
  }
22122
- registerAutocompleteField(fieldName, opts) {
22123
- return this.autocompleteHelper.add(fieldName, opts);
22349
+ cancel() {
22350
+ console.debug('[register] cancelled');
22351
+ this.viewCtrl.dismiss();
22124
22352
  }
22125
- setError(value, opts) {
22126
- if (this.errorSubject.value !== value) {
22127
- this.errorSubject.next(value);
22128
- if (!opts || opts.emitEvent !== false) {
22129
- 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;
22130
22360
  }
22131
- }
22132
- }
22133
- markForCheck() {
22134
- // Should be overwritten by subclasses
22135
- console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
22136
- }
22137
- /* -- private function -- */
22138
- setLoading(value, opts) {
22139
- if (this.loadingSubject.value !== value) {
22140
- this.loadingSubject.next(value);
22141
- if (!opts || opts.emitEvent !== false) {
22142
- 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();
22143
22369
  }
22144
- }
22370
+ catch (err) {
22371
+ this.form.error = err && err.message || err;
22372
+ this.form.enable();
22373
+ }
22374
+ finally {
22375
+ this.sending = false;
22376
+ }
22377
+ });
22145
22378
  }
22146
22379
  }
22147
- 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 });
22148
- 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 });
22149
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppForm, decorators: [{
22150
- type: Directive
22151
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$2.UntypedFormGroup }]; }, propDecorators: { debug: [{
22152
- type: Input
22153
- }], tabindex: [{
22154
- type: Input
22155
- }], errorTranslatorOptions: [{
22156
- type: Input
22157
- }], form: [{
22158
- type: Input
22159
- }], onCancel: [{
22160
- type: Output
22161
- }], onSubmit: [{
22162
- 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 }]
22163
22388
  }] } });
22164
22389
 
22165
22390
  class AppAuthForm extends AppForm {
@@ -23118,8 +23343,8 @@ class SettingsPage extends AppForm {
23118
23343
  }
23119
23344
  showSelectPeerModal(opts) {
23120
23345
  return __awaiter(this, void 0, void 0, function* () {
23121
- const peer = yield this.network.showSelectPeerModal(opts);
23122
- 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) {
23123
23348
  const control = this.form.get('peerUrl');
23124
23349
  control.setValue(peer.url, { emitEvent: true, onlySelf: false });
23125
23350
  control.markAsDirty({ onlySelf: false });
@@ -23176,12 +23401,12 @@ class SettingsPage extends AppForm {
23176
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 });
23177
23402
  SettingsPage.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: SettingsPage, selector: "page-settings", providers: [
23178
23403
  { provide: ValidatorService, useExisting: LocalSettingsValidatorService },
23179
- ], 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 });
23180
23405
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SettingsPage, decorators: [{
23181
23406
  type: Component,
23182
23407
  args: [{ selector: 'page-settings', providers: [
23183
23408
  { provide: ValidatorService, useExisting: LocalSettingsValidatorService },
23184
- ], 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" }]
23185
23410
  }], ctorParameters: function () {
23186
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: [{
23187
23412
  type: Inject,
@@ -23644,197 +23869,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
23644
23869
  }]
23645
23870
  }] });
23646
23871
 
23647
- class TextForm extends AppForm {
23648
- constructor(injector, cd, formBuilder) {
23649
- super(injector);
23650
- this.injector = injector;
23651
- this.cd = cd;
23652
- this.formBuilder = formBuilder;
23653
- this.showError = true;
23654
- this.multiline = true;
23655
- this.autoHeight = false;
23656
- this.maxLength = 2000;
23657
- this.autofocus = false;
23658
- this.textAreaChanges = new EventEmitter();
23659
- }
23660
- ngOnInit() {
23661
- const form = this.formBuilder.group({
23662
- text: [null, isNotNil(this.maxLength)
23663
- ? Validators.maxLength(this.maxLength)
23664
- : undefined
23665
- ]
23666
- });
23667
- this.control = form.get('text');
23668
- this.setForm(form);
23669
- super.ngOnInit();
23670
- }
23671
- textAreaChanged(event) {
23672
- this.textAreaChanges.emit(this.control.value);
23673
- }
23674
- containerResize() {
23675
- var _a;
23676
- (_a = this.autosizeDirective) === null || _a === void 0 ? void 0 : _a.resizeToFitContent(true);
23677
- }
23678
- focusInput() {
23679
- if (this.textArea)
23680
- focusInput(this.textArea);
23681
- if (this.textInput)
23682
- focusInput(this.textInput);
23683
- }
23684
- markForCheck() {
23685
- this.cd.markForCheck();
23686
- }
23687
- }
23688
- 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 });
23689
- 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" }] });
23690
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextForm, decorators: [{
23691
- type: Component,
23692
- 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"] }]
23693
- }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i1$2.UntypedFormBuilder }]; }, propDecorators: { showError: [{
23694
- type: Input
23695
- }], placeholder: [{
23696
- type: Input
23697
- }], multiline: [{
23698
- type: Input
23699
- }], autoHeight: [{
23700
- type: Input
23701
- }], maxLength: [{
23702
- type: Input
23703
- }], autofocus: [{
23704
- type: Input
23705
- }], textAreaChanges: [{
23706
- type: Output
23707
- }], textArea: [{
23708
- type: ViewChild,
23709
- args: ['textArea']
23710
- }], textInput: [{
23711
- type: ViewChild,
23712
- args: ['textInput']
23713
- }], autosizeDirective: [{
23714
- type: ViewChild,
23715
- args: [CdkTextareaAutosize]
23716
- }] } });
23717
-
23718
- class TextPopover {
23719
- constructor(popoverController, translate) {
23720
- this.popoverController = popoverController;
23721
- this.translate = translate;
23722
- this.placeholder = '';
23723
- this.editing = true;
23724
- this.multiline = true;
23725
- this.maxLength = 2000;
23726
- this.autofocus = false;
23727
- this.subscription = new Subscription();
23728
- }
23729
- get disabled() {
23730
- return this.form.disabled;
23731
- }
23732
- get enabled() {
23733
- return this.form.enabled;
23734
- }
23735
- get valid() {
23736
- var _a;
23737
- return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
23738
- }
23739
- get value() {
23740
- var _a;
23741
- return (_a = this.form) === null || _a === void 0 ? void 0 : _a.value.text;
23742
- }
23743
- ngOnInit() {
23744
- this.enable();
23745
- }
23746
- ngAfterViewInit() {
23747
- setTimeout(() => this.form.setValue({ text: this.text }), 0);
23748
- }
23749
- onValidate(event) {
23750
- return __awaiter(this, void 0, void 0, function* () {
23751
- yield waitWhilePending(this.form);
23752
- if (!this.valid) {
23753
- logFormErrors(this.form.control);
23754
- return;
23755
- }
23756
- try {
23757
- const value = this.value;
23758
- this.disable();
23759
- yield this.popoverController.dismiss(value);
23760
- this.form.error = null;
23761
- }
23762
- catch (err) {
23763
- this.form.error = (err && err.message) || err;
23764
- this.enable();
23765
- }
23766
- });
23767
- }
23768
- disable() {
23769
- this.form.disable();
23770
- }
23771
- enable() {
23772
- if (this.editing)
23773
- this.form.enable();
23774
- }
23775
- cancel() {
23776
- this.popoverController.dismiss();
23777
- }
23778
- ngOnDestroy() {
23779
- this.subscription.unsubscribe();
23780
- }
23781
- }
23782
- 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 });
23783
- 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" }] });
23784
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextPopover, decorators: [{
23785
- type: Component,
23786
- 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" }]
23787
- }], ctorParameters: function () { return [{ type: i2.PopoverController }, { type: i1$1.TranslateService }]; }, propDecorators: { form: [{
23788
- type: ViewChild,
23789
- args: ['form', { static: true }]
23790
- }], text: [{
23791
- type: Input
23792
- }], placeholder: [{
23793
- type: Input
23794
- }], editing: [{
23795
- type: Input
23796
- }], multiline: [{
23797
- type: Input
23798
- }], maxLength: [{
23799
- type: Input
23800
- }], autofocus: [{
23801
- type: Input
23802
- }] } });
23803
-
23804
- class AppTextPopoverModule {
23805
- }
23806
- AppTextPopoverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
23807
- AppTextPopoverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, declarations: [
23808
- // Components
23809
- TextForm,
23810
- TextPopover
23811
- ], imports: [SharedModule, i1$1.TranslateModule], exports: [TranslateModule,
23812
- // Components
23813
- TextForm,
23814
- TextPopover] });
23815
- AppTextPopoverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, imports: [SharedModule,
23816
- TranslateModule.forChild(), TranslateModule] });
23817
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, decorators: [{
23818
- type: NgModule,
23819
- args: [{
23820
- imports: [
23821
- SharedModule,
23822
- TranslateModule.forChild()
23823
- ],
23824
- declarations: [
23825
- // Components
23826
- TextForm,
23827
- TextPopover
23828
- ],
23829
- exports: [
23830
- TranslateModule,
23831
- // Components
23832
- TextForm,
23833
- TextPopover
23834
- ]
23835
- }]
23836
- }] });
23837
-
23838
23872
  class EntityMetadataComponent {
23839
23873
  constructor() {
23840
23874
  this.showRecorder = true;
@@ -33236,7 +33270,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
33236
33270
  }] }];
33237
33271
  } });
33238
33272
 
33239
- const moment = momentNamespace;
33273
+ const moment = momentImported;
33240
33274
  class UserEventTestingPage {
33241
33275
  constructor(userEventService, router, alertController, translateService) {
33242
33276
  this.userEventService = userEventService;
@@ -33578,5 +33612,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
33578
33612
  * Generated bundle index. Do not edit.
33579
33613
  */
33580
33614
 
33581
- 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 };
33582
33616
  //# sourceMappingURL=sumaris-net.ngx-components.mjs.map