@sumaris-net/ngx-components 2.0.0-rc31 → 2.0.0-rc33

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.
Files changed (26) hide show
  1. package/esm2020/src/app/core/form/text-popover/text-form.component.mjs +12 -7
  2. package/esm2020/src/app/core/form/text-popover/text-popover.component.mjs +6 -3
  3. package/esm2020/src/app/core/graphql/graphql.service.mjs +8 -4
  4. package/esm2020/src/app/core/graphql/graphql.utils.mjs +2 -3
  5. package/esm2020/src/app/core/peer/select-peer.modal.mjs +54 -10
  6. package/esm2020/src/app/core/peer/select-peer.module.mjs +7 -4
  7. package/esm2020/src/app/core/services/config.service.mjs +1 -1
  8. package/esm2020/src/app/core/services/network.service.mjs +3 -3
  9. package/esm2020/src/app/core/settings/settings.page.mjs +8 -5
  10. package/esm2020/src/app/shared/dates.mjs +8 -21
  11. package/esm2020/src/app/shared/file/file.service.mjs +2 -3
  12. package/esm2020/src/app/shared/modules.mjs +11 -0
  13. package/fesm2015/sumaris-net.ngx-components.mjs +1213 -1174
  14. package/fesm2015/sumaris-net.ngx-components.mjs.map +1 -1
  15. package/fesm2020/sumaris-net.ngx-components.mjs +7655 -7605
  16. package/fesm2020/sumaris-net.ngx-components.mjs.map +1 -1
  17. package/package.json +1 -1
  18. package/src/app/core/form/text-popover/text-form.component.d.ts +3 -2
  19. package/src/app/core/form/text-popover/text-popover.component.d.ts +4 -1
  20. package/src/app/core/peer/select-peer.modal.d.ts +19 -5
  21. package/src/app/core/peer/select-peer.module.d.ts +2 -1
  22. package/src/app/core/services/network.service.d.ts +3 -4
  23. package/src/app/core/settings/settings.page.d.ts +2 -4
  24. package/src/app/shared/dates.d.ts +3 -11
  25. package/src/app/shared/modules.d.ts +8 -0
  26. package/src/assets/i18n/fr.json +1 -0
@@ -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 * as momentTZImported from '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';
@@ -121,9 +124,9 @@ import { CacheModule } from 'ionic-cache';
121
124
  import { ApolloLink, NetworkStatus, InMemoryCache, ApolloClient, gql } from '@apollo/client/core';
122
125
  import { getMainDefinition } from '@apollo/client/utilities';
123
126
  import { RetryLink } from '@apollo/client/link/retry';
124
- import QueueLink from 'apollo-link-queue';
125
- import SerializingLink from 'apollo-link-serialize';
126
- import loggerLink from 'apollo-link-logger';
127
+ import * as queueLinkImported from 'apollo-link-queue';
128
+ import * as serializingLinkImported from 'apollo-link-serialize';
129
+ import * as loggerLinkImported from 'apollo-link-logger';
127
130
  import { persistCache } from 'apollo3-cache-persist';
128
131
  import { GraphQLWsLink } from '@apollo/client/link/subscriptions';
129
132
  import { createClient } from 'graphql-ws';
@@ -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,23 @@ 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 && !!value['default'];
2548
+ }
2549
+ /**
2550
+ * Workaround need for CommonJS library (eg. moment), because of packagr's issue - see https://github.com/ng-packagr/ng-packagr/issues/2215
2551
+ * @param commonJSModule
2552
+ */
2553
+ function unwrapESModule(commonJSModule) {
2554
+ return isESModule(commonJSModule) ? commonJSModule.default : commonJSModule;
2555
+ }
2556
+
2557
+ const moment$1 = unwrapESModule(momentImported);
2558
+ const momentTZ = unwrapESModule(momentTZImported);
2546
2559
  const DATE_UNIX_TIMESTAMP = 'X';
2547
2560
  const DATE_UNIX_MS_TIMESTAMP = 'x';
2548
2561
  const MOMENT_NO_TIME_PROPERTY = '_hasNoTime';
2549
2562
  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
2563
  static min(date1, date2) {
2568
2564
  return date1 && (!date2 || date1.isSameOrBefore(date2)) ? date1 : date2;
2569
2565
  }
@@ -2622,6 +2618,8 @@ class DateUtils {
2622
2618
  return momentDate.day() === weekday;
2623
2619
  }
2624
2620
  }
2621
+ DateUtils.moment = moment$1;
2622
+ DateUtils.momentTZ = momentTZ;
2625
2623
  DateUtils.toDateISOString = toDateISOString;
2626
2624
  DateUtils.fromDateISOString = fromDateISOString;
2627
2625
  DateUtils.toDuration = toDuration;
@@ -2689,7 +2687,6 @@ function toDuration(value, unit) {
2689
2687
  }
2690
2688
  return duration;
2691
2689
  }
2692
- const moment$1 = DateUtils.moment;
2693
2690
 
2694
2691
  class DateDiffDurationPipe {
2695
2692
  constructor(dateAdapter, translate) {
@@ -10540,7 +10537,6 @@ class ImagesUtils {
10540
10537
  }
10541
10538
  }
10542
10539
 
10543
- const uuidv4$1 = uuidv4Imported;
10544
10540
  class FileService {
10545
10541
  constructor(platform,
10546
10542
  //private transfer: FileTransfer,
@@ -10577,7 +10573,7 @@ class FileService {
10577
10573
  const lastSlashIndex = fileUrl.lastIndexOf('/');
10578
10574
  if (lastSlashIndex === -1)
10579
10575
  throw new Error('Invalid URL: ' + fileUrl);
10580
- const fileName = lastSlashIndex < (fileUrl.length - 1) && fileUrl.substring(lastSlashIndex + 1) || uuidv4$1();
10576
+ const fileName = lastSlashIndex < (fileUrl.length - 1) && fileUrl.substring(lastSlashIndex + 1) || v4();
10581
10577
  // Download into the file system
10582
10578
  if (outputType === 'fileUrl' && this.canUseFileSystem) {
10583
10579
  console.warn(`WARN: [file] Downloading image {${fileUrl}} in local filesystem...`);
@@ -13653,400 +13649,975 @@ function getNodeInfo(http, peer, opts) {
13653
13649
  });
13654
13650
  }
13655
13651
 
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();
13652
+ class MatAutocompleteConfigHolder {
13653
+ constructor(options) {
13654
+ this.options = options;
13655
+ this.fields = {};
13656
+ // Store the function from options (e.g. get from user settings)
13657
+ // or create a default function
13658
+ this.getUserAttributes = (options === null || options === void 0 ? void 0 : options.getUserAttributes) ||
13659
+ ((fieldName, defaultAttributes) => defaultAttributes || ['label', 'name']);
13675
13660
  }
13676
- ngOnDestroy() {
13677
- this._subscription.unsubscribe();
13661
+ add(fieldName, options) {
13662
+ if (!fieldName) {
13663
+ throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
13664
+ }
13665
+ options = options || {};
13666
+ const suggestFn = options.suggestFn
13667
+ || (options.service && ((v, f) => options.service.suggest(v, f)))
13668
+ || undefined;
13669
+ const attributes = (this.getUserAttributes(fieldName, options.attributes) || ['label', 'name']);
13670
+ // Keep original the function from options, when exists
13671
+ const attributesOrFn = attributes.map((a, index) => typeof a === 'function' && options.attributes[index] || a);
13672
+ const filter = Object.assign({ searchAttribute: attributes.length === 1 ? attributes[0] : undefined, searchAttributes: attributes.length > 1 ? attributes : undefined }, options.filter);
13673
+ const displayWith = options.displayWith || MatAutocompleteFieldUtils.createDisplayFn(attributes, options.multiple);
13674
+ const equals = options.equals || MatAutocompleteFieldUtils.defaultEquals;
13675
+ const config = Object.assign(Object.assign({}, options), { attributes: attributesOrFn, suggestFn,
13676
+ filter,
13677
+ displayWith,
13678
+ equals });
13679
+ this.fields[fieldName] = config;
13680
+ return config;
13678
13681
  }
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);
13682
+ get(fieldName) {
13683
+ if (!fieldName) {
13684
+ throw new Error('Unable to add config, with name: ' + (fieldName || 'undefined'));
13683
13685
  }
13686
+ return this.fields[fieldName] || this.add(fieldName);
13687
+ }
13688
+ }
13689
+
13690
+ // eslint-disable-next-line @angular-eslint/directive-class-suffix
13691
+ class AppForm {
13692
+ constructor(injector, form) {
13693
+ this._subscription = new Subscription();
13694
+ this._enable = false;
13695
+ this.i18nFieldPrefix = null;
13696
+ this.destroySubject = new Subject();
13697
+ this.readySubject = new BehaviorSubject(false);
13698
+ this.loadingSubject = new BehaviorSubject(true);
13699
+ this.errorSubject = new BehaviorSubject(undefined);
13700
+ this.debug = false;
13701
+ this.onCancel = new EventEmitter();
13702
+ this.onSubmit = new EventEmitter();
13703
+ if (form)
13704
+ this.setForm(form);
13705
+ this.translate = injector.get(TranslateService);
13706
+ this.settings = injector.get(LocalSettingsService);
13707
+ this.errorTranslator = injector.get(FormErrorTranslator);
13708
+ this.autocompleteHelper = new MatAutocompleteConfigHolder(this.settings && {
13709
+ getUserAttributes: (a, b) => this.settings.getFieldDisplayAttributes(a, b)
13710
+ });
13711
+ this.autocompleteFields = this.autocompleteHelper.fields;
13684
13712
  }
13685
13713
  /**
13686
- * Check the min pod version, defined by the app
13687
- *
13688
- * @param peer
13714
+ * @deprecated
13689
13715
  */
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);
13716
+ set _loading(value) {
13717
+ this.loadingSubject.next(value);
13696
13718
  }
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
- });
13719
+ /**
13720
+ * @deprecated
13721
+ */
13722
+ get _loading() {
13723
+ return this.loadingSubject.value;
13734
13724
  }
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
- });
13725
+ /**
13726
+ * @deprecated
13727
+ */
13728
+ get _$ready() {
13729
+ return this.readySubject;
13755
13730
  }
13756
- markForCheck() {
13757
- this.cd.markForCheck();
13731
+ /**
13732
+ * @deprecated
13733
+ */
13734
+ get _$loading() {
13735
+ return this.loadingSubject;
13758
13736
  }
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();
13737
+ get error() {
13738
+ return this.errorSubject.value;
13795
13739
  }
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;
13740
+ set error(error) {
13741
+ this.setError(error);
13820
13742
  }
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();
13743
+ get loading() {
13744
+ return this.loadingSubject.value;
13833
13745
  }
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
- });
13746
+ get loaded() {
13747
+ return !this.loadingSubject.value;
13850
13748
  }
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
- });
13749
+ get value() {
13750
+ return this.form.value;
13859
13751
  }
13860
- get started() {
13861
- return this._started;
13752
+ set value(data) {
13753
+ this.setValue(data);
13862
13754
  }
13863
- get starting() {
13864
- return !!this._startPromise;
13755
+ get dirty() {
13756
+ var _a;
13757
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.dirty) || false;
13865
13758
  }
13866
- get stopped() {
13867
- return !this._started && !this._startPromise;
13759
+ get invalid() {
13760
+ return !this.form || this.form.invalid;
13868
13761
  }
13869
- get data() {
13870
- return this.dataSubject.value;
13762
+ get pending() {
13763
+ return !this.form || (this.form.dirty && this.form.pending);
13871
13764
  }
13872
- set data(value) {
13873
- if (this.dataSubject.value !== value) {
13874
- this.dataSubject.next(value);
13875
- }
13765
+ get valid() {
13766
+ var _a;
13767
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
13876
13768
  }
13877
- registerSubscription(sub) {
13878
- this._subscription = this._subscription || new Subscription();
13879
- this._subscription.add(sub);
13769
+ get empty() {
13770
+ return !this.form || (!this.form.dirty && !this.form.touched);
13880
13771
  }
13881
- unregisterSubscription(sub) {
13772
+ get touched() {
13882
13773
  var _a;
13883
- (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.remove(sub);
13774
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.touched) || false;
13884
13775
  }
13885
- unsubscribe() {
13886
- var _a;
13887
- (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
13888
- this._subscription = null;
13776
+ get untouched() {
13777
+ return !this.form || this.form.untouched;
13889
13778
  }
13890
- ngOnStop() {
13891
- // Can be overwritten by subclasses
13779
+ get enabled() {
13780
+ return this._enable;
13892
13781
  }
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;
13782
+ get disabled() {
13783
+ return !this._enable;
13915
13784
  }
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
- }
13785
+ disable(opts) {
13786
+ var _a;
13787
+ (_a = this.form) === null || _a === void 0 ? void 0 : _a.disable(opts);
13788
+ if (this._enable) {
13789
+ this._enable = false;
13790
+ if (!opts || opts.emitEvent !== true)
13791
+ this.markForCheck();
13937
13792
  }
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
13793
  }
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
- }
13794
+ enable(opts) {
13795
+ var _a;
13796
+ (_a = this.form) === null || _a === void 0 ? void 0 : _a.enable(opts);
13797
+ if (!this._enable) {
13798
+ this._enable = true;
13799
+ if (!opts || opts.emitEvent !== true)
13800
+ this.markForCheck();
13967
13801
  }
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
13802
  }
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
13803
+ get destroyed() {
13804
+ var _a;
13805
+ return ((_a = this.destroySubject) === null || _a === void 0 ? void 0 : _a.closed) !== false;
14002
13806
  }
14003
- };
14004
- class CryptoService {
14005
- static get started() {
14006
- return this._ready;
13807
+ set form(value) {
13808
+ this.setForm(value);
14007
13809
  }
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
- });
13810
+ get form() {
13811
+ return this._form;
14015
13812
  }
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
- });
13813
+ ngOnInit() {
13814
+ this._enable ? this.enable() : this.disable();
13815
+ this.errorTranslatorOptions = this.errorTranslatorOptions || {
13816
+ controlPathTranslator: this
13817
+ };
14033
13818
  }
14034
- /**
14035
- * Sign a message, from a key pair
14036
- */
14037
- static sign(message, keypair) {
13819
+ ngOnDestroy() {
13820
+ this._subscription.unsubscribe();
13821
+ this.readySubject.unsubscribe();
13822
+ this.loadingSubject.unsubscribe();
13823
+ this.errorSubject.unsubscribe();
13824
+ this.onCancel.unsubscribe();
13825
+ this.onSubmit.unsubscribe();
13826
+ this.destroySubject.next();
13827
+ this.destroySubject.unsubscribe();
13828
+ }
13829
+ cancel() {
14038
13830
  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);
13831
+ this.onCancel.emit();
14044
13832
  });
14045
13833
  }
14046
13834
  /**
14047
- * Sign a message, from a key pair
13835
+ *
13836
+ * @param event
13837
+ * @param opts allow to skip validation check, using {checkValid: false}
14048
13838
  */
14049
- static verify(message, signature, publicKey) {
13839
+ doSubmit(event, opts) {
13840
+ return __awaiter(this, void 0, void 0, function* () {
13841
+ if (!this._form) {
13842
+ this.markAllAsTouched({ emitEvent: true });
13843
+ return;
13844
+ }
13845
+ // Check if valid (if not disabled)
13846
+ if ((!opts || opts.checkValid !== false) && !this._form.valid) {
13847
+ // Wait validation end
13848
+ yield AppFormUtils.waitWhilePending(this._form);
13849
+ // Form is invalid: exit (+ log if debug)
13850
+ if (this._form.invalid) {
13851
+ this.markAllAsTouched({ emitEvent: true });
13852
+ if (this.debug)
13853
+ AppFormUtils.logFormErrors(this._form);
13854
+ return;
13855
+ }
13856
+ }
13857
+ // Emit event
13858
+ this.onSubmit.emit(event);
13859
+ });
13860
+ }
13861
+ setForm(form) {
13862
+ if (this._form !== form) {
13863
+ this._form = form;
13864
+ this._subscription.add(this._form.statusChanges.subscribe(status => this.markForCheck()));
13865
+ }
13866
+ }
13867
+ setValue(data, opts) {
13868
+ if (!data) {
13869
+ console.warn('[form] Trying to set an empty value to form. Skipping');
13870
+ return;
13871
+ }
13872
+ // DEBUG
13873
+ //if (this.debug) console.debug('[form] Updating form (using entity)', data);
13874
+ // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
13875
+ AppFormUtils.copyEntity2Form(data, this.form, Object.assign({ emitEvent: false, onlySelf: true }, opts));
13876
+ if (!opts || opts.emitEvent !== true) {
13877
+ this.markForCheck();
13878
+ }
13879
+ }
13880
+ reset(data, opts) {
13881
+ if (data) {
13882
+ if (this.debug)
13883
+ console.debug('[form] Resetting form (using entity)', data);
13884
+ // Convert object to json, then apply it to form (e.g. convert 'undefined' into 'null')
13885
+ const json = AppFormUtils.getFormValueFromEntity(data, this.form);
13886
+ this.form.reset(json, { emitEvent: false, onlySelf: true });
13887
+ }
13888
+ else {
13889
+ this.form.reset(null, { emitEvent: false, onlySelf: true });
13890
+ }
13891
+ if (!opts || opts.emitEvent !== true)
13892
+ this.markForCheck();
13893
+ }
13894
+ markAsPristine(opts) {
13895
+ this.form.markAsPristine(opts);
13896
+ if (!opts || opts.emitEvent !== false)
13897
+ this.markForCheck();
13898
+ }
13899
+ markAsUntouched(opts) {
13900
+ this.form.markAsUntouched(opts);
13901
+ if (!opts || opts.emitEvent !== false)
13902
+ this.markForCheck();
13903
+ }
13904
+ /**
13905
+ * @deprecated prefer to use markAllAsTouched()
13906
+ * @param opts
13907
+ */
13908
+ markAsTouched(opts) {
13909
+ // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
13910
+ console.warn('TODO: Replace this call by markAllAsTouched() - because of changes in ngx-components >= 0.16.0');
13911
+ AppFormUtils.markAsTouched(this.form, opts);
13912
+ if (!opts || opts.emitEvent !== false)
13913
+ this.markForCheck();
13914
+ }
13915
+ markAllAsTouched(opts) {
13916
+ // this.form.markAllAsTouched() // This is not working well (e.g. in TripForm)
13917
+ AppFormUtils.markAllAsTouched(this.form, opts);
13918
+ if (!opts || opts.emitEvent !== false)
13919
+ this.markForCheck();
13920
+ }
13921
+ markAsDirty(opts) {
13922
+ this.form.markAsDirty(opts);
13923
+ if (!opts || opts.emitEvent !== false)
13924
+ this.markForCheck();
13925
+ }
13926
+ markAsLoading(opts) {
13927
+ this.setLoading(true, opts);
13928
+ }
13929
+ markAsLoaded(opts) {
13930
+ this.setLoading(false, opts);
13931
+ }
13932
+ markAsReady(opts) {
13933
+ if (this.readySubject.value !== true) {
13934
+ this.readySubject.next(true);
13935
+ // If subclasses implements OnReady
13936
+ if (typeof this['ngOnReady'] === 'function') {
13937
+ this.ngOnReady();
13938
+ }
13939
+ }
13940
+ }
13941
+ /**
13942
+ * Wait form is ready
13943
+ * @param opts
13944
+ */
13945
+ ready(opts) {
13946
+ if (this.readySubject.value)
13947
+ return Promise.resolve();
13948
+ return waitForTrue(this.readySubject, opts);
13949
+ }
13950
+ /**
13951
+ * Wait form is not busy (=loaded)
13952
+ * @param opts
13953
+ */
13954
+ waitIdle(opts) {
13955
+ if (!this.loadingSubject.value)
13956
+ return Promise.resolve();
13957
+ return waitForFalse(this.loadingSubject, opts);
13958
+ }
13959
+ updateValueAndValidity(opts) {
13960
+ AppFormUtils.updateValueAndValidity(this.form, opts);
13961
+ if (!opts || opts.emitEvent !== false)
13962
+ this.markForCheck();
13963
+ }
13964
+ translateControlPath(path) {
13965
+ var _a;
13966
+ const i18nFieldName = this.getI18nFieldName(path);
13967
+ return ((_a = this.translate) === null || _a === void 0 ? void 0 : _a.instant(i18nFieldName)) || i18nFieldName;
13968
+ }
13969
+ /* -- protected methods -- */
13970
+ getFormError(form, opts) {
13971
+ if (!form || !this.errorTranslator)
13972
+ return undefined;
13973
+ return this.errorTranslator.translateFormErrors(this.form, Object.assign({ controlPathTranslator: this }, opts));
13974
+ }
13975
+ getI18nFieldName(path) {
13976
+ return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
13977
+ }
13978
+ registerSubscription(sub) {
13979
+ this._subscription.add(sub);
13980
+ }
13981
+ unregisterSubscription(sub) {
13982
+ this._subscription.remove(sub);
13983
+ }
13984
+ registerAutocompleteField(fieldName, opts) {
13985
+ return this.autocompleteHelper.add(fieldName, opts);
13986
+ }
13987
+ setError(value, opts) {
13988
+ if (this.errorSubject.value !== value) {
13989
+ this.errorSubject.next(value);
13990
+ if (!opts || opts.emitEvent !== false) {
13991
+ this.markForCheck();
13992
+ }
13993
+ }
13994
+ }
13995
+ markForCheck() {
13996
+ // Should be overwritten by subclasses
13997
+ console.warn('markForCheck() has been called, but is not overwritten by component ' + this.constructor.name);
13998
+ }
13999
+ /* -- private function -- */
14000
+ setLoading(value, opts) {
14001
+ if (this.loadingSubject.value !== value) {
14002
+ this.loadingSubject.next(value);
14003
+ if (!opts || opts.emitEvent !== false) {
14004
+ this.markForCheck();
14005
+ }
14006
+ }
14007
+ }
14008
+ }
14009
+ 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 });
14010
+ 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 });
14011
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppForm, decorators: [{
14012
+ type: Directive
14013
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i1$2.UntypedFormGroup }]; }, propDecorators: { debug: [{
14014
+ type: Input
14015
+ }], tabindex: [{
14016
+ type: Input
14017
+ }], errorTranslatorOptions: [{
14018
+ type: Input
14019
+ }], form: [{
14020
+ type: Input
14021
+ }], onCancel: [{
14022
+ type: Output
14023
+ }], onSubmit: [{
14024
+ type: Output
14025
+ }] } });
14026
+
14027
+ class TextForm extends AppForm {
14028
+ constructor(injector, cd, formBuilder) {
14029
+ super(injector);
14030
+ this.injector = injector;
14031
+ this.cd = cd;
14032
+ this.formBuilder = formBuilder;
14033
+ this.showError = true;
14034
+ this.multiline = true;
14035
+ this.autoHeight = false;
14036
+ this.maxLength = 2000;
14037
+ this.autofocus = false;
14038
+ this.validator = null;
14039
+ this.textAreaChanges = new EventEmitter();
14040
+ }
14041
+ ngOnInit() {
14042
+ // Compute validators
14043
+ const validators = isNotNil(this.maxLength) && this.maxLength > 0 ? [Validators.maxLength(this.maxLength)] : [];
14044
+ if (this.validator)
14045
+ validators.push(this.validator);
14046
+ // Create the form
14047
+ const form = this.formBuilder.group({
14048
+ text: [null, validators.length ? Validators.compose(validators) : null]
14049
+ });
14050
+ this.control = form.get('text');
14051
+ this.setForm(form);
14052
+ super.ngOnInit();
14053
+ }
14054
+ textAreaChanged(event) {
14055
+ this.textAreaChanges.emit(this.control.value);
14056
+ }
14057
+ containerResize() {
14058
+ var _a;
14059
+ (_a = this.autosizeDirective) === null || _a === void 0 ? void 0 : _a.resizeToFitContent(true);
14060
+ }
14061
+ focusInput() {
14062
+ if (this.textArea)
14063
+ focusInput(this.textArea);
14064
+ if (this.textInput)
14065
+ focusInput(this.textInput);
14066
+ }
14067
+ markForCheck() {
14068
+ this.cd.markForCheck();
14069
+ }
14070
+ }
14071
+ 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 });
14072
+ 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" }] });
14073
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextForm, decorators: [{
14074
+ type: Component,
14075
+ 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"] }]
14076
+ }], ctorParameters: function () { return [{ type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i1$2.UntypedFormBuilder }]; }, propDecorators: { showError: [{
14077
+ type: Input
14078
+ }], placeholder: [{
14079
+ type: Input
14080
+ }], multiline: [{
14081
+ type: Input
14082
+ }], autoHeight: [{
14083
+ type: Input
14084
+ }], maxLength: [{
14085
+ type: Input
14086
+ }], autofocus: [{
14087
+ type: Input
14088
+ }], validator: [{
14089
+ type: Input
14090
+ }], textAreaChanges: [{
14091
+ type: Output
14092
+ }], textArea: [{
14093
+ type: ViewChild,
14094
+ args: ['textArea']
14095
+ }], textInput: [{
14096
+ type: ViewChild,
14097
+ args: ['textInput']
14098
+ }], autosizeDirective: [{
14099
+ type: ViewChild,
14100
+ args: [CdkTextareaAutosize]
14101
+ }] } });
14102
+
14103
+ class TextPopover {
14104
+ constructor(popoverController, translate) {
14105
+ this.popoverController = popoverController;
14106
+ this.translate = translate;
14107
+ this.placeholder = '';
14108
+ this.editing = true;
14109
+ this.multiline = true;
14110
+ this.maxLength = 2000;
14111
+ this.autofocus = false;
14112
+ this.validator = null;
14113
+ this.subscription = new Subscription();
14114
+ }
14115
+ get disabled() {
14116
+ return this.form.disabled;
14117
+ }
14118
+ get enabled() {
14119
+ return this.form.enabled;
14120
+ }
14121
+ get valid() {
14122
+ var _a;
14123
+ return ((_a = this.form) === null || _a === void 0 ? void 0 : _a.valid) || false;
14124
+ }
14125
+ get value() {
14126
+ var _a;
14127
+ return (_a = this.form) === null || _a === void 0 ? void 0 : _a.value.text;
14128
+ }
14129
+ ngOnInit() {
14130
+ this.enable();
14131
+ }
14132
+ ngAfterViewInit() {
14133
+ setTimeout(() => this.form.setValue({ text: this.text }), 0);
14134
+ }
14135
+ onValidate(event) {
14136
+ return __awaiter(this, void 0, void 0, function* () {
14137
+ yield waitWhilePending(this.form);
14138
+ if (!this.valid) {
14139
+ logFormErrors(this.form.control);
14140
+ return;
14141
+ }
14142
+ try {
14143
+ const value = this.value;
14144
+ this.disable();
14145
+ yield this.popoverController.dismiss(value);
14146
+ this.form.error = null;
14147
+ }
14148
+ catch (err) {
14149
+ this.form.error = (err && err.message) || err;
14150
+ this.enable();
14151
+ }
14152
+ });
14153
+ }
14154
+ disable() {
14155
+ this.form.disable();
14156
+ }
14157
+ enable() {
14158
+ if (this.editing)
14159
+ this.form.enable();
14160
+ }
14161
+ cancel() {
14162
+ this.popoverController.dismiss();
14163
+ }
14164
+ ngOnDestroy() {
14165
+ this.subscription.unsubscribe();
14166
+ }
14167
+ }
14168
+ 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 });
14169
+ 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" }] });
14170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: TextPopover, decorators: [{
14171
+ type: Component,
14172
+ 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" }]
14173
+ }], ctorParameters: function () { return [{ type: i2.PopoverController }, { type: i1$1.TranslateService }]; }, propDecorators: { form: [{
14174
+ type: ViewChild,
14175
+ args: ['form', { static: true }]
14176
+ }], text: [{
14177
+ type: Input
14178
+ }], placeholder: [{
14179
+ type: Input
14180
+ }], editing: [{
14181
+ type: Input
14182
+ }], multiline: [{
14183
+ type: Input
14184
+ }], maxLength: [{
14185
+ type: Input
14186
+ }], autofocus: [{
14187
+ type: Input
14188
+ }], validator: [{
14189
+ type: Input
14190
+ }] } });
14191
+
14192
+ class SelectPeerModal {
14193
+ constructor(modalCtrl, popoverController, translate, http, cd, environment) {
14194
+ this.modalCtrl = modalCtrl;
14195
+ this.popoverController = popoverController;
14196
+ this.translate = translate;
14197
+ this.http = http;
14198
+ this.cd = cd;
14199
+ this.environment = environment;
14200
+ this._subscription = new Subscription();
14201
+ this.loading = true;
14202
+ this.$peers = new Subject();
14203
+ this.peerMinVersion = this.environment.peerMinVersion;
14204
+ this.canCancel = true;
14205
+ this.allowSelectDownPeer = true;
14206
+ this.onRefresh = new EventEmitter();
14207
+ this.showSetManuallyButton = true;
14208
+ this.mobile = isMobile(window);
14209
+ }
14210
+ set peers(peers) {
14211
+ this._subscription.add(peers.subscribe(res => this.refreshPeers(res)));
14212
+ }
14213
+ cancel() {
14214
+ this.modalCtrl.dismiss();
14215
+ }
14216
+ ngOnDestroy() {
14217
+ this._subscription.unsubscribe();
14218
+ }
14219
+ selectPeer(peer) {
14220
+ if (this.allowSelectDownPeer || (peer.reachable && this.isCompatible(peer))) {
14221
+ console.debug(`[select-peer-modal] Selected peer: {url: '${peer.url}'}`);
14222
+ this.modalCtrl.dismiss(peer);
14223
+ }
14224
+ }
14225
+ /**
14226
+ * Check the min pod version, defined by the app
14227
+ *
14228
+ * @param peer
14229
+ */
14230
+ isCompatible(peer) {
14231
+ return !this.peerMinVersion || (peer && peer.softwareVersion && VersionUtils.isCompatible(this.peerMinVersion, peer.softwareVersion));
14232
+ }
14233
+ refresh(event) {
14234
+ this.loading = true;
14235
+ this.onRefresh.emit(event);
14236
+ }
14237
+ clickSetManually(event) {
14238
+ return __awaiter(this, void 0, void 0, function* () {
14239
+ const peerUrl = yield this.openPeerUrlPopover(event);
14240
+ if (peerUrl) {
14241
+ const peer = Peer.parseUrl(peerUrl);
14242
+ yield this.refreshPeer(peer);
14243
+ this.selectPeer(peer);
14244
+ }
14245
+ });
14246
+ }
14247
+ /* -- protected methods -- */
14248
+ refreshPeers(peers) {
14249
+ return __awaiter(this, void 0, void 0, function* () {
14250
+ peers = peers || [];
14251
+ const data = [];
14252
+ const jobs = Promise.all(peers.map((peer) => __awaiter(this, void 0, void 0, function* () {
14253
+ yield this.refreshPeer(peer);
14254
+ if (this._subscription.closed)
14255
+ return; // component destroyed
14256
+ data.push(peer);
14257
+ // Sort (by reachable, then host)
14258
+ data.sort((a, b) => {
14259
+ if (a.reachable && !b.reachable)
14260
+ return -1;
14261
+ if (!a.reachable && b.reachable)
14262
+ return 1;
14263
+ if (a.hostAndPort < b.hostAndPort)
14264
+ return -1;
14265
+ if (a.hostAndPort > b.hostAndPort)
14266
+ return 1;
14267
+ return 0;
14268
+ });
14269
+ this.$peers.next(data);
14270
+ return peer;
14271
+ })));
14272
+ this._subscription.add(this.$peers
14273
+ .subscribe(() => this.cd.markForCheck()));
14274
+ try {
14275
+ yield jobs;
14276
+ }
14277
+ catch (err) {
14278
+ if (!this._subscription.closed)
14279
+ console.error(err);
14280
+ }
14281
+ this.loading = false;
14282
+ this.cd.markForCheck();
14283
+ });
14284
+ }
14285
+ refreshPeer(peer) {
14286
+ return __awaiter(this, void 0, void 0, function* () {
14287
+ try {
14288
+ const summary = yield NetworkUtils.getNodeInfo(this.http, peer.url);
14289
+ peer.status = 'UP';
14290
+ peer.softwareName = summary.softwareName;
14291
+ peer.softwareVersion = summary.softwareVersion;
14292
+ peer.label = summary.nodeLabel;
14293
+ peer.name = summary.nodeName;
14294
+ }
14295
+ catch (err) {
14296
+ if (!this._subscription.closed) {
14297
+ if (err && err.message) {
14298
+ console.error('[select-peer] ' + err.message, err);
14299
+ }
14300
+ }
14301
+ peer.status = 'DOWN';
14302
+ }
14303
+ return peer;
14304
+ });
14305
+ }
14306
+ openPeerUrlPopover(event, opts) {
14307
+ return __awaiter(this, void 0, void 0, function* () {
14308
+ const modal = yield this.popoverController.create({
14309
+ component: TextPopover,
14310
+ 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),
14311
+ backdropDismiss: false,
14312
+ keyboardClose: false,
14313
+ event,
14314
+ translucent: true,
14315
+ cssClass: 'popover-large',
14316
+ });
14317
+ yield modal.present();
14318
+ const { data, role } = yield modal.onDidDismiss();
14319
+ if (data) {
14320
+ console.info('Popover result: ', data);
14321
+ return data;
14322
+ }
14323
+ });
14324
+ }
14325
+ markForCheck() {
14326
+ this.cd.markForCheck();
14327
+ }
14328
+ }
14329
+ 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 });
14330
+ 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 });
14331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SelectPeerModal, decorators: [{
14332
+ type: Component,
14333
+ 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"] }]
14334
+ }], ctorParameters: function () {
14335
+ return [{ type: i2.ModalController }, { type: i2.PopoverController }, { type: i1$1.TranslateService }, { type: i2$5.HttpClient }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
14336
+ type: Inject,
14337
+ args: [ENVIRONMENT]
14338
+ }] }];
14339
+ }, propDecorators: { canCancel: [{
14340
+ type: Input
14341
+ }], allowSelectDownPeer: [{
14342
+ type: Input
14343
+ }], onRefresh: [{
14344
+ type: Input
14345
+ }], showSetManuallyButton: [{
14346
+ type: Input
14347
+ }] } });
14348
+
14349
+ /**
14350
+ * Same as StartableService, bu with a dataSubject instead of a simple 'data' property
14351
+ */
14352
+ let StartableObservableService = class StartableObservableService {
14353
+ constructor(prerequisiteService) {
14354
+ this.dataSubject = new BehaviorSubject(null);
14355
+ this.startSubject = new Subject();
14356
+ this.stopSubject = new Subject();
14357
+ this._debug = false;
14358
+ this._startByReadyFunction = true; // should start when calling ready() ?
14359
+ this._started = false;
14360
+ this._startPromise = null;
14361
+ this._startPrerequisite = null;
14362
+ this._subscription = null;
14363
+ this._startPrerequisite = prerequisiteService
14364
+ ? () => prerequisiteService.ready()
14365
+ : () => Promise.resolve();
14366
+ }
14367
+ start(opts) {
14368
+ if (this._startPromise)
14369
+ return this._startPromise;
14370
+ if (this._started)
14371
+ return Promise.resolve(this.dataSubject.value);
14372
+ this._startPromise = this._startPrerequisite()
14373
+ .then(() => this.ngOnStart(opts))
14374
+ .then(data => {
14375
+ this._started = true;
14376
+ this._startPromise = undefined;
14377
+ // Should be done AFTER 'this._started = true', because of the 'filter' operator, inside ready() function
14378
+ this.dataSubject.next(data);
14379
+ this.startSubject.next(data);
14380
+ return data;
14381
+ })
14382
+ .catch(err => {
14383
+ if (!this.stopped) {
14384
+ console.error('Failed to start a service: ' + (err && err.message || err), err);
14385
+ this._started = false;
14386
+ this._startPromise = null;
14387
+ }
14388
+ return null;
14389
+ });
14390
+ return this._startPromise;
14391
+ }
14392
+ ready() {
14393
+ if (this._started)
14394
+ return Promise.resolve(this.dataSubject.value);
14395
+ if (this._startPromise)
14396
+ return this._startPromise;
14397
+ if (this._startByReadyFunction)
14398
+ return this.start();
14399
+ return this.dataSubject
14400
+ .pipe(takeUntil(this.stopSubject),
14401
+ // Wait start() to be called, to exclude the initial 'null' value
14402
+ filter(_ => this._started))
14403
+ .toPromise();
14404
+ }
14405
+ stop() {
14406
+ return __awaiter(this, void 0, void 0, function* () {
14407
+ try {
14408
+ this.unsubscribe();
14409
+ yield this.ngOnStop();
14410
+ }
14411
+ catch (err) {
14412
+ console.error('Failed to stop a service: ' + (err && err.message || err), err);
14413
+ }
14414
+ finally {
14415
+ this._started = false;
14416
+ this._startPromise = undefined;
14417
+ this.stopSubject.next(); // Stop all running observables
14418
+ this.dataSubject.next(null); // Reset data
14419
+ }
14420
+ });
14421
+ }
14422
+ restart(opts) {
14423
+ return __awaiter(this, void 0, void 0, function* () {
14424
+ if (this._startPromise)
14425
+ yield this._startPromise; // Wait end of previous loading
14426
+ if (this._started)
14427
+ yield this.stop(); // Then stop if started
14428
+ return this.start(opts); // Then start again
14429
+ });
14430
+ }
14431
+ get started() {
14432
+ return this._started;
14433
+ }
14434
+ get starting() {
14435
+ return !!this._startPromise;
14436
+ }
14437
+ get stopped() {
14438
+ return !this._started && !this._startPromise;
14439
+ }
14440
+ get data() {
14441
+ return this.dataSubject.value;
14442
+ }
14443
+ set data(value) {
14444
+ if (this.dataSubject.value !== value) {
14445
+ this.dataSubject.next(value);
14446
+ }
14447
+ }
14448
+ registerSubscription(sub) {
14449
+ this._subscription = this._subscription || new Subscription();
14450
+ this._subscription.add(sub);
14451
+ }
14452
+ unregisterSubscription(sub) {
14453
+ var _a;
14454
+ (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.remove(sub);
14455
+ }
14456
+ unsubscribe() {
14457
+ var _a;
14458
+ (_a = this._subscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
14459
+ this._subscription = null;
14460
+ }
14461
+ ngOnStop() {
14462
+ // Can be overwritten by subclasses
14463
+ }
14464
+ };
14465
+ StartableObservableService = __decorate([
14466
+ __param(0, Optional())
14467
+ ], StartableObservableService);
14468
+
14469
+ // Base58 encoding/decoding
14470
+ // Originally written by Mike Hearn for BitcoinJ
14471
+ // Copyright (c) 2011 Google Inc
14472
+ // Ported to JavaScript by Stefan Thomas
14473
+ // Merged Buffer refactorings from base58-native by Stephen Pair
14474
+ // Copyright (c) 2013 BitPay Inc
14475
+ // Rewritten in TypeScript by Ludovic Pecquot
14476
+ // @dynamic
14477
+ class Base58 {
14478
+ static getAlphabetMap() {
14479
+ if (!Base58.alphabetMap) {
14480
+ this.alphabetMap = {};
14481
+ for (let i = 0; i < Base58.alphabet.length; i++) {
14482
+ Base58.alphabetMap[Base58.alphabet.charAt(i)] = i;
14483
+ }
14484
+ }
14485
+ return Base58.alphabetMap;
14486
+ }
14487
+ static encode(buffer) {
14488
+ if (buffer.length === 0)
14489
+ return '';
14490
+ let i;
14491
+ let j;
14492
+ const digits = [0];
14493
+ for (i = 0; i < buffer.length; i++) {
14494
+ for (j = 0; j < digits.length; j++)
14495
+ digits[j] <<= 8;
14496
+ digits[digits.length - 1] += buffer[i];
14497
+ let carry = 0;
14498
+ for (j = digits.length - 1; j >= 0; j--) {
14499
+ digits[j] += carry;
14500
+ carry = (digits[j] / 58) | 0;
14501
+ digits[j] %= 58;
14502
+ }
14503
+ while (carry) {
14504
+ digits.unshift(carry);
14505
+ carry = (digits[0] / 58) | 0;
14506
+ digits[0] %= 58;
14507
+ }
14508
+ }
14509
+ // deal with leading zeros
14510
+ for (i = 0; i < buffer.length - 1 && buffer[i] === 0; i++)
14511
+ digits.unshift(0);
14512
+ return digits.map(function (digit) { return Base58.alphabet[digit]; }).join('');
14513
+ }
14514
+ static decode(string) {
14515
+ if (string.length === 0)
14516
+ return (new Uint8Array(0));
14517
+ const input = string.split('').map(function (c) {
14518
+ return Base58.getAlphabetMap()[c];
14519
+ });
14520
+ let i;
14521
+ let j;
14522
+ const bytes = [0];
14523
+ for (i = 0; i < input.length; i++) {
14524
+ for (j = 0; j < bytes.length; j++)
14525
+ bytes[j] *= 58;
14526
+ bytes[bytes.length - 1] += input[i];
14527
+ let carry = 0;
14528
+ for (j = bytes.length - 1; j >= 0; j--) {
14529
+ bytes[j] += carry;
14530
+ carry = bytes[j] >> 8;
14531
+ bytes[j] &= 0xff;
14532
+ }
14533
+ while (carry) {
14534
+ bytes.unshift(carry);
14535
+ carry = bytes[0] >> 8;
14536
+ bytes[0] &= 0xff;
14537
+ }
14538
+ }
14539
+ // deal with leading zeros
14540
+ for (i = 0; i < input.length - 1 && input[i] === 0; i++)
14541
+ bytes.unshift(0);
14542
+ return (new Uint8Array(bytes));
14543
+ }
14544
+ }
14545
+ Base58.alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
14546
+
14547
+ const ED25519_SEED_LENGTH = 32; // Length of a ED25519 seed
14548
+ const SCRYPT_PARAMS = {
14549
+ SIMPLE: {
14550
+ N: 2048,
14551
+ r: 8,
14552
+ p: 1
14553
+ },
14554
+ DEFAULT: {
14555
+ N: 4096,
14556
+ r: 16,
14557
+ p: 1
14558
+ },
14559
+ SECURE: {
14560
+ N: 16384,
14561
+ r: 32,
14562
+ p: 2
14563
+ },
14564
+ HARDEST: {
14565
+ N: 65536,
14566
+ r: 32,
14567
+ p: 4
14568
+ },
14569
+ EXTREME: {
14570
+ N: 262144,
14571
+ r: 64,
14572
+ p: 8
14573
+ }
14574
+ };
14575
+ class CryptoService {
14576
+ static get started() {
14577
+ return this._ready;
14578
+ }
14579
+ static ready() {
14580
+ return __awaiter(this, void 0, void 0, function* () {
14581
+ if (this._ready)
14582
+ return; // OK
14583
+ yield cryptoWaitReady();
14584
+ this._ready = true;
14585
+ });
14586
+ }
14587
+ /**
14588
+ * Generate a sign keypair, using scrypt, from a salt and a password
14589
+ *
14590
+ * @param salt
14591
+ * @param password
14592
+ * @param scryptParams
14593
+ */
14594
+ static scryptKeypair(salt, password, scryptParams) {
14595
+ return __awaiter(this, void 0, void 0, function* () {
14596
+ if (!this.started)
14597
+ yield this.ready();
14598
+ const passwordU8a = decodeUTF8(password);
14599
+ const saltU8a = decodeUTF8(salt);
14600
+ const result = scryptEncode(passwordU8a, saltU8a, scryptParams || SCRYPT_PARAMS.DEFAULT);
14601
+ const seed = result.password.slice(0, ED25519_SEED_LENGTH);
14602
+ return ed25519PairFromSeed(seed);
14603
+ });
14604
+ }
14605
+ /**
14606
+ * Sign a message, from a key pair
14607
+ */
14608
+ static sign(message, keypair) {
14609
+ return __awaiter(this, void 0, void 0, function* () {
14610
+ if (!this.started)
14611
+ yield this.ready();
14612
+ const m = decodeUTF8(message);
14613
+ const sig = ed25519Sign(m, keypair);
14614
+ return encodeBase64(sig);
14615
+ });
14616
+ }
14617
+ /**
14618
+ * Sign a message, from a key pair
14619
+ */
14620
+ static verify(message, signature, publicKey) {
14050
14621
  return __awaiter(this, void 0, void 0, function* () {
14051
14622
  if (!this.started)
14052
14623
  yield this.ready();
@@ -14108,6 +14679,7 @@ const NetworkRefreshTimerPeriod = {
14108
14679
  MOBILE: 1000 * 60 * 10 /* every 10 min */,
14109
14680
  DESKTOP: 1000 * 60 * 5 /* every 5 min */
14110
14681
  };
14682
+ const PEER_URL_REGEXP = /^(http|https):\/\/[^ "?#@]+$/;
14111
14683
  /* -- DEV only (to debug refresh timer)
14112
14684
  const NetworkRefreshTimerPeriod = {
14113
14685
  MOBILE: 1000,
@@ -14417,12 +14989,7 @@ class NetworkService extends StartableObservableService {
14417
14989
  const peers$ = $onRefresh.pipe(mergeMap((_) => this.getDefaultPeers()), map(peers => peers || []));
14418
14990
  const modal = yield this.modalCtrl.create({
14419
14991
  component: SelectPeerModal,
14420
- componentProps: {
14421
- onRefresh: $onRefresh,
14422
- peers: peers$,
14423
- canCancel: toBoolean(opts.canCancel, true),
14424
- allowSelectDownPeer: toBoolean(opts.allowSelectDownPeer, true)
14425
- },
14992
+ componentProps: Object.assign({ onRefresh: $onRefresh, peers: peers$ }, opts),
14426
14993
  keyboardClose: true,
14427
14994
  showBackdrop: true
14428
14995
  });
@@ -14985,7 +15552,6 @@ function accountToString(data) {
14985
15552
  (data.lastName || '')) || '';
14986
15553
  }
14987
15554
 
14988
- const uuidv4 = uuidv4Imported;
14989
15555
  const _global = typeof global !== 'undefined' ? global : (typeof window !== 'undefined' ? window : {});
14990
15556
  const NativeWebSocket = _global.WebSocket || _global.MozWebSocket;
14991
15557
  /**
@@ -15029,7 +15595,7 @@ function createTrackerLink(opts) {
15029
15595
  // Skip if not tracked
15030
15596
  if (!context || !context.tracked)
15031
15597
  return forward(operation);
15032
- const id = context.serializationKey || uuidv4();
15598
+ const id = context.serializationKey || v4();
15033
15599
  console.debug(`[apollo-tracker-link] Watching tracked query {${operation.operationName}#${id}}`);
15034
15600
  // Clean context, before calling JSON.stringify (remove unused attributes)
15035
15601
  const cleanContext = Object.assign(Object.assign({}, context), { optimisticResponse: null, cache: null });
@@ -15099,6 +15665,9 @@ class StorageServiceWrapper {
15099
15665
  }
15100
15666
  }
15101
15667
 
15668
+ const QueueLink = unwrapESModule(queueLinkImported);
15669
+ const SerializingLink = unwrapESModule(serializingLinkImported);
15670
+ const loggerLink = unwrapESModule(loggerLinkImported);
15102
15671
  const APP_GRAPHQL_TYPE_POLICIES = new InjectionToken('graphqlTypePolicies');
15103
15672
  class GraphqlService extends StartableService {
15104
15673
  constructor(platform, apollo, httpLink, network, storage, cryptoService, environment, typePolicies) {
@@ -19008,44 +19577,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
19008
19577
  }]
19009
19578
  }], ctorParameters: function () { return []; } });
19010
19579
 
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
19580
  class FormFieldValuesHolder {
19050
19581
  getAsBoolean(data, definition) {
19051
19582
  const value = this.get(data, definition);
@@ -21138,6 +21669,40 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
21138
21669
  }]
21139
21670
  }] });
21140
21671
 
21672
+ class AppTextPopoverModule {
21673
+ }
21674
+ AppTextPopoverModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
21675
+ AppTextPopoverModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, declarations: [
21676
+ // Components
21677
+ TextForm,
21678
+ TextPopover
21679
+ ], imports: [SharedModule, i1$1.TranslateModule], exports: [TranslateModule,
21680
+ // Components
21681
+ TextForm,
21682
+ TextPopover] });
21683
+ AppTextPopoverModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, imports: [SharedModule,
21684
+ TranslateModule.forChild(), TranslateModule] });
21685
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppTextPopoverModule, decorators: [{
21686
+ type: NgModule,
21687
+ args: [{
21688
+ imports: [
21689
+ SharedModule,
21690
+ TranslateModule.forChild()
21691
+ ],
21692
+ declarations: [
21693
+ // Components
21694
+ TextForm,
21695
+ TextPopover
21696
+ ],
21697
+ exports: [
21698
+ TranslateModule,
21699
+ // Components
21700
+ TextForm,
21701
+ TextPopover
21702
+ ]
21703
+ }]
21704
+ }] });
21705
+
21141
21706
  class AppSelectPeerModule {
21142
21707
  }
21143
21708
  AppSelectPeerModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
@@ -21145,19 +21710,21 @@ AppSelectPeerModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", ver
21145
21710
  // Network
21146
21711
  SelectPeerModal
21147
21712
  ], imports: [SharedModule,
21148
- HttpClientModule, i1$1.TranslateModule], exports: [TranslateModule,
21713
+ HttpClientModule, i1$1.TranslateModule, AppTextPopoverModule], exports: [TranslateModule,
21149
21714
  // Components
21150
21715
  SelectPeerModal] });
21151
21716
  AppSelectPeerModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, imports: [SharedModule,
21152
21717
  HttpClientModule,
21153
- TranslateModule.forChild(), TranslateModule] });
21718
+ TranslateModule.forChild(),
21719
+ AppTextPopoverModule, TranslateModule] });
21154
21720
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AppSelectPeerModule, decorators: [{
21155
21721
  type: NgModule,
21156
21722
  args: [{
21157
21723
  imports: [
21158
21724
  SharedModule,
21159
21725
  HttpClientModule,
21160
- TranslateModule.forChild()
21726
+ TranslateModule.forChild(),
21727
+ AppTextPopoverModule
21161
21728
  ],
21162
21729
  declarations: [
21163
21730
  // Network
@@ -21589,577 +22156,240 @@ class AccountValidatorService extends AppValidatorService {
21589
22156
  lastName: [data && data.lastName || null, Validators.compose([Validators.required, Validators.minLength(2)])],
21590
22157
  firstName: [data && data.firstName || null, Validators.compose([Validators.required, Validators.minLength(2)])],
21591
22158
  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
- }
22159
+ mainProfile: [data && (data.mainProfile || PersonUtils.getMainProfile(data.profiles)) || 'GUEST', Validators.required],
22160
+ statusId: [data && data.statusId || StatusIds.TEMPORARY, Validators.required],
22161
+ pubkey: [data && data.pubkey || null, Validators.compose([Validators.required, SharedValidators.pubkey])]
22162
+ };
22163
+ // Add additional fields
22164
+ this.accountService.additionalFields.forEach(field => {
22165
+ //console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
22166
+ formDef[field.key] = [data && data[field.key] || null, this.getValidators(field)];
22167
+ });
22168
+ return formDef;
22017
22169
  }
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 });
22170
+ getValidators(field) {
22171
+ const validatorFns = [];
22172
+ if (field.extra && field.extra.account && field.extra.account.required) {
22173
+ validatorFns.push(Validators.required);
22025
22174
  }
22026
- else {
22027
- this.form.reset(null, { emitEvent: false, onlySelf: true });
22175
+ if (field.type === 'entity') {
22176
+ validatorFns.push(SharedValidators.entity);
22028
22177
  }
22029
- if (!opts || opts.emitEvent !== true)
22030
- this.markForCheck();
22178
+ return validatorFns.length ? Validators.compose(validatorFns) : validatorFns.length === 1 ? validatorFns[0] : undefined;
22031
22179
  }
22032
- markAsPristine(opts) {
22033
- this.form.markAsPristine(opts);
22034
- if (!opts || opts.emitEvent !== false)
22035
- this.markForCheck();
22180
+ }
22181
+ 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 });
22182
+ AccountValidatorService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, providedIn: 'root' });
22183
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: AccountValidatorService, decorators: [{
22184
+ type: Injectable,
22185
+ args: [{ providedIn: 'root' }]
22186
+ }], ctorParameters: function () { return [{ type: i1$2.UntypedFormBuilder }, { type: AccountService }]; } });
22187
+
22188
+ class RegisterForm {
22189
+ constructor(accountService, accountValidatorService, formBuilder, environment, settings) {
22190
+ this.accountService = accountService;
22191
+ this.accountValidatorService = accountValidatorService;
22192
+ this.formBuilder = formBuilder;
22193
+ this.environment = environment;
22194
+ this.settings = settings;
22195
+ this.debug = false;
22196
+ this.subscriptions = [];
22197
+ this.sending = false;
22198
+ this.showPwd = false;
22199
+ this.showConfirmPwd = false;
22200
+ this.onCancel = new EventEmitter();
22201
+ this.onSubmit = new EventEmitter();
22202
+ this.referentialToString = referentialToString;
22203
+ this.forms = [];
22204
+ // Email form
22205
+ this.forms.push(formBuilder.group({
22206
+ email: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.email]), this.emailAvailability(this.accountService)),
22207
+ confirmEmail: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('email')]))
22208
+ }));
22209
+ // Password form
22210
+ this.forms.push(formBuilder.group({
22211
+ password: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(8)])),
22212
+ confirmPassword: new UntypedFormControl(null, Validators.compose([Validators.required, this.equalsValidator('password')]))
22213
+ }));
22214
+ // Detail form
22215
+ const formDetailDef = {
22216
+ lastName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)])),
22217
+ firstName: new UntypedFormControl(null, Validators.compose([Validators.required, Validators.minLength(2)]))
22218
+ };
22219
+ // Prepare autocomplete settings
22220
+ this.autocompleteHelper = new MatAutocompleteConfigHolder(settings && {
22221
+ getUserAttributes: (a, b) => settings.getFieldDisplayAttributes(a, b)
22222
+ });
22223
+ // Add additional fields to details form
22224
+ this.additionalFields = this.accountService.additionalFields
22225
+ // Keep only required fields
22226
+ .filter(field => field.extra && field.extra.registration && field.extra.registration.required);
22227
+ this.additionalFields.forEach(field => {
22228
+ //if (this.debug) console.debug("[register-form] Add additional field {" + field.name + "} to form", field);
22229
+ formDetailDef[field.key] = new UntypedFormControl(null, this.accountValidatorService.getValidators(field));
22230
+ if (field.type === 'entity') {
22231
+ field.autocomplete = this.autocompleteHelper.add(field.key, field.autocomplete);
22232
+ }
22233
+ });
22234
+ this.forms.push(formBuilder.group(formDetailDef));
22235
+ this.form = formBuilder.group({
22236
+ emailStep: this.forms[0],
22237
+ passwordStep: this.forms[1],
22238
+ detailsStep: this.forms[2]
22239
+ });
22036
22240
  }
22037
- markAsUntouched(opts) {
22038
- this.form.markAsUntouched(opts);
22039
- if (!opts || opts.emitEvent !== false)
22040
- this.markForCheck();
22241
+ ngOnInit() {
22242
+ // For DEV only ------------------------
22243
+ if (!this.environment.production) {
22244
+ this.form.setValue({
22245
+ emailStep: {
22246
+ email: 'contact@e-is.pro',
22247
+ confirmEmail: 'contact@e-is.pro'
22248
+ },
22249
+ passwordStep: {
22250
+ password: 'contactera',
22251
+ confirmPassword: 'contactera'
22252
+ },
22253
+ detailsStep: {
22254
+ lastName: 'Lavenier 2',
22255
+ firstName: 'Benoit',
22256
+ department: null
22257
+ }
22258
+ });
22259
+ }
22041
22260
  }
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();
22261
+ get value() {
22262
+ const result = {
22263
+ username: this.form.value.emailStep.email,
22264
+ password: this.form.value.passwordStep.password,
22265
+ account: new Account()
22266
+ };
22267
+ result.account.fromObject(this.form.value.detailsStep);
22268
+ result.account.email = result.username;
22269
+ return result;
22052
22270
  }
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();
22271
+ get valid() {
22272
+ return this.form.valid;
22058
22273
  }
22059
- markAsDirty(opts) {
22060
- this.form.markAsDirty(opts);
22061
- if (!opts || opts.emitEvent !== false)
22062
- this.markForCheck();
22274
+ isEnd() {
22275
+ return this.stepper.selectedIndex === 2;
22063
22276
  }
22064
- markAsLoading(opts) {
22065
- this.setLoading(true, opts);
22277
+ isBeginning() {
22278
+ return this.stepper.selectedIndex === 0;
22066
22279
  }
22067
- markAsLoaded(opts) {
22068
- this.setLoading(false, opts);
22280
+ slidePrev() {
22281
+ return this.stepper.previous();
22069
22282
  }
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
- }
22283
+ slideNext(event) {
22284
+ if (event) {
22285
+ event.stopPropagation();
22286
+ event.preventDefault();
22077
22287
  }
22288
+ return this.stepper.next();
22078
22289
  }
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);
22290
+ equalsValidator(otherControlName) {
22291
+ return function (c) {
22292
+ if (c.parent && c.value !== c.parent.value[otherControlName]) {
22293
+ return {
22294
+ equals: true
22295
+ };
22296
+ }
22297
+ return null;
22298
+ };
22087
22299
  }
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);
22300
+ emailAvailability(accountService) {
22301
+ return function (control) {
22302
+ return timer(500).pipe(mergeMap(() => accountService.checkEmailAvailable(control.value)
22303
+ .then(res => null)
22304
+ .catch(err => {
22305
+ console.error(err);
22306
+ return { availability: true };
22307
+ })));
22308
+ };
22096
22309
  }
22097
- updateValueAndValidity(opts) {
22098
- AppFormUtils.updateValueAndValidity(this.form, opts);
22099
- if (!opts || opts.emitEvent !== false)
22100
- this.markForCheck();
22310
+ cancel() {
22311
+ this.onCancel.emit();
22101
22312
  }
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;
22313
+ doSubmit(event) {
22314
+ if (this.form.invalid)
22315
+ return;
22316
+ this.sending = true;
22317
+ this.onSubmit.emit(this.value);
22106
22318
  }
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));
22319
+ markAsTouched() {
22320
+ this.form.markAsTouched();
22112
22321
  }
22113
- getI18nFieldName(path) {
22114
- return (this.i18nFieldPrefix || '') + changeCaseToUnderscore(path).toUpperCase();
22322
+ disable() {
22323
+ this.form.disable();
22115
22324
  }
22116
- registerSubscription(sub) {
22117
- this._subscription.add(sub);
22325
+ enable() {
22326
+ this.form.enable();
22118
22327
  }
22119
- unregisterSubscription(sub) {
22120
- this._subscription.remove(sub);
22328
+ }
22329
+ 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 });
22330
+ 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" }] });
22331
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterForm, decorators: [{
22332
+ type: Component,
22333
+ 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"] }]
22334
+ }], ctorParameters: function () {
22335
+ return [{ type: AccountService }, { type: AccountValidatorService }, { type: i1$2.UntypedFormBuilder }, { type: undefined, decorators: [{
22336
+ type: Inject,
22337
+ args: [ENVIRONMENT]
22338
+ }] }, { type: LocalSettingsService }];
22339
+ }, propDecorators: { stepper: [{
22340
+ type: ViewChild,
22341
+ args: ['stepper', { static: true }]
22342
+ }], onCancel: [{
22343
+ type: Output
22344
+ }], onSubmit: [{
22345
+ type: Output
22346
+ }] } });
22347
+
22348
+ class RegisterModal {
22349
+ constructor(accountService, viewCtrl) {
22350
+ this.accountService = accountService;
22351
+ this.viewCtrl = viewCtrl;
22352
+ this.sending = false;
22121
22353
  }
22122
- registerAutocompleteField(fieldName, opts) {
22123
- return this.autocompleteHelper.add(fieldName, opts);
22354
+ cancel() {
22355
+ console.debug('[register] cancelled');
22356
+ this.viewCtrl.dismiss();
22124
22357
  }
22125
- setError(value, opts) {
22126
- if (this.errorSubject.value !== value) {
22127
- this.errorSubject.next(value);
22128
- if (!opts || opts.emitEvent !== false) {
22129
- this.markForCheck();
22358
+ doSubmit(event) {
22359
+ return __awaiter(this, void 0, void 0, function* () {
22360
+ if (this.form.form.disabled || this.sending)
22361
+ return; // Skip
22362
+ if (!this.form.valid || !this.form.isEnd()) {
22363
+ this.form.markAsTouched();
22364
+ return;
22130
22365
  }
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();
22366
+ this.sending = true;
22367
+ const data = this.form.value;
22368
+ this.form.disable();
22369
+ try {
22370
+ console.debug('[register] Sending registration to server...', data);
22371
+ const res = yield this.accountService.register(data);
22372
+ console.debug('[register] Account registered!');
22373
+ yield this.viewCtrl.dismiss();
22143
22374
  }
22144
- }
22375
+ catch (err) {
22376
+ this.form.error = err && err.message || err;
22377
+ this.form.enable();
22378
+ }
22379
+ finally {
22380
+ this.sending = false;
22381
+ }
22382
+ });
22145
22383
  }
22146
22384
  }
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
22385
+ 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 });
22386
+ 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"] }] });
22387
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: RegisterModal, decorators: [{
22388
+ type: Component,
22389
+ 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" }]
22390
+ }], ctorParameters: function () { return [{ type: AccountService }, { type: i2.ModalController }]; }, propDecorators: { form: [{
22391
+ type: ViewChild,
22392
+ args: ['form', { static: true }]
22163
22393
  }] } });
22164
22394
 
22165
22395
  class AppAuthForm extends AppForm {
@@ -23118,8 +23348,8 @@ class SettingsPage extends AppForm {
23118
23348
  }
23119
23349
  showSelectPeerModal(opts) {
23120
23350
  return __awaiter(this, void 0, void 0, function* () {
23121
- const peer = yield this.network.showSelectPeerModal(opts);
23122
- if (peer && peer.url) {
23351
+ const peer = yield this.network.showSelectPeerModal(Object.assign({ showSetManuallyButton: true }, opts));
23352
+ if (peer === null || peer === void 0 ? void 0 : peer.url) {
23123
23353
  const control = this.form.get('peerUrl');
23124
23354
  control.setValue(peer.url, { emitEvent: true, onlySelf: false });
23125
23355
  control.markAsDirty({ onlySelf: false });
@@ -23176,12 +23406,12 @@ class SettingsPage extends AppForm {
23176
23406
  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
23407
  SettingsPage.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.2.8", type: SettingsPage, selector: "page-settings", providers: [
23178
23408
  { 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 });
23409
+ ], 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
23410
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImport: i0, type: SettingsPage, decorators: [{
23181
23411
  type: Component,
23182
23412
  args: [{ selector: 'page-settings', providers: [
23183
23413
  { 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" }]
23414
+ ], 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
23415
  }], ctorParameters: function () {
23186
23416
  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
23417
  type: Inject,
@@ -23644,197 +23874,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
23644
23874
  }]
23645
23875
  }] });
23646
23876
 
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
23877
  class EntityMetadataComponent {
23839
23878
  constructor() {
23840
23879
  this.showRecorder = true;
@@ -33236,7 +33275,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
33236
33275
  }] }];
33237
33276
  } });
33238
33277
 
33239
- const moment = momentNamespace;
33278
+ const moment = momentImported;
33240
33279
  class UserEventTestingPage {
33241
33280
  constructor(userEventService, router, alertController, translateService) {
33242
33281
  this.userEventService = userEventService;
@@ -33578,5 +33617,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.2.8", ngImpor
33578
33617
  * Generated bundle index. Do not edit.
33579
33618
  */
33580
33619
 
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 };
33620
+ 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, 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
33621
  //# sourceMappingURL=sumaris-net.ngx-components.mjs.map