@sumaris-net/ngx-components 1.4.4 → 1.5.1

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.
@@ -511,9 +511,7 @@
511
511
  return value.replace(/([a-z])([A-Z])/g, '$1_$2').toLowerCase();
512
512
  }
513
513
  function removeDiacritics(text) {
514
- return text.normalize('NFD')
515
- //
516
- .replace(/[\u0300-\u036f]/g, '');
514
+ return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
517
515
  }
518
516
  function suggestFromArray(items, value, opts) {
519
517
  var _this = this;
@@ -1268,7 +1266,6 @@
1268
1266
  this.debounceTime = null;
1269
1267
  this.i18nPrefix = 'REFERENTIAL.';
1270
1268
  this.noResultMessage = 'COMMON.NO_RESULT';
1271
- this.matAutocompletePosition = 'auto';
1272
1269
  this.multiple = false;
1273
1270
  this.itemSize = '48px';
1274
1271
  this.fetchMoreThreshold = '15%';
@@ -1435,6 +1432,7 @@
1435
1432
  this.debounceTime = toNumber(this.debounceTime, 250);
1436
1433
  this.highlightAccent = toBoolean(this.highlightAccent, false);
1437
1434
  this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
1435
+ this.matAutocompletePosition = this.matAutocompletePosition || (this.mobile && this.searchable ? 'above' : 'auto'); // On mobile, set position to above (because of bottom keyboard)
1438
1436
  // No suggestFn: filter on the given items
1439
1437
  if (!this.suggestFn) {
1440
1438
  var suggestFromArrayFn_1 = function (value, filter) { return __awaiter(_this, void 0, void 0, function () {
@@ -1486,9 +1484,10 @@
1486
1484
  // Filter if not enough character
1487
1485
  operators.filter(function (value) { return value.length >= _this.suggestLengthThreshold; }),
1488
1486
  // Wait a debounce time
1489
- operators.debounceTime(this.debounceTime),
1487
+ operators.debounceTime(this.debounceTime)
1490
1488
  // DEBUG
1491
- operators.tap(function (value) { return console.debug(_this.logPrefix + ' Search text changes:', value); })),
1489
+ //tap((value) => console.debug(this.logPrefix + ' Search text changes:', value)),
1490
+ ),
1492
1491
  // Object set: use it (no distinctUntilChanged() pipe need)
1493
1492
  this.formControl.valueChanges
1494
1493
  .pipe(operators.startWith(this.formControl.value), operators.filter(function (value) { return (_this.searchable && isNotNil(value) && typeof value === 'object'); }), operators.tap(function (value) {
@@ -1503,9 +1502,10 @@
1503
1502
  _this.matInputText.nativeElement.value = _this.displayValue;
1504
1503
  }
1505
1504
  }
1506
- }),
1505
+ })
1507
1506
  // DEBUG
1508
- operators.tap(function (value) { return console.debug(_this.logPrefix + ' Received an object value: ', value); })),
1507
+ //tap(value => console.debug(this.logPrefix + ' Received an object value: ', value))
1508
+ ),
1509
1509
  // Merge some observables, with a common distinctUntilChanged() pipe, and NO debounceTime
1510
1510
  rxjs.merge(
1511
1511
  // Focus or click => Load all
@@ -1514,16 +1514,12 @@
1514
1514
  // On dropdown button click
1515
1515
  this.onDropButtonClick
1516
1516
  .pipe(operators.filter(function (event) { return _this.enabled && _this.searchable && (!event || !event.defaultPrevented); }), operators.map(function (_) { return _this.showAllOnFocus ? '*' : _this.formControl.value; })), rxjs.merge(this.$inputItems, this._filter$)
1517
- .pipe(operators.filter(function (event) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.formControl.value; }),
1518
- // DEBUG
1519
- operators.tap(function (value) { return console.debug(_this.logPrefix + ' Received $inputItems or filter event: ', value); })))
1517
+ .pipe(operators.filter(function (event) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.formControl.value; })))
1520
1518
  .pipe(
1521
1519
  // If value is a string (and is not = '*'), filter if not enough character
1522
1520
  operators.filter(function (value) { return value === '*' || !(typeof value === 'string') || value.length >= _this.suggestLengthThreshold; }),
1523
1521
  // Distinguish changes
1524
- operators.distinctUntilChanged(),
1525
- // DEBUG
1526
- operators.tap(function (value) { return console.debug(_this.logPrefix + ' Received update event: ', value); })))
1522
+ operators.distinctUntilChanged()))
1527
1523
  .pipe(
1528
1524
  // Suggest values
1529
1525
  operators.mergeMap(function (value) { return _this.suggest(value, _this.filter); }),
@@ -1687,7 +1683,7 @@
1687
1683
  // If combo is empty, or if has content but should force to show panel on focus
1688
1684
  if (!hasContent || (this.showPanelOnFocus && this.showAllOnFocus)) {
1689
1685
  // DEBUG
1690
- console.debug(this.logPrefix + ' Emit focus event');
1686
+ //console.debug(this.logPrefix + ' Emit focus event');
1691
1687
  this.onFocus.emit(event);
1692
1688
  return true;
1693
1689
  }
@@ -12150,6 +12146,14 @@
12150
12146
  this._storageKey = ENTITIES_STORAGE_KEY_PREFIX + '#' + name;
12151
12147
  this._mapToLightEntity = this.createLightEntityMapFn(this.policy);
12152
12148
  }
12149
+ Object.defineProperty(EntityStore.prototype, "length", {
12150
+ get: function () {
12151
+ var _a;
12152
+ return ((_a = this._cache) === null || _a === void 0 ? void 0 : _a.length) || 0;
12153
+ },
12154
+ enumerable: false,
12155
+ configurable: true
12156
+ });
12153
12157
  Object.defineProperty(EntityStore.prototype, "cache", {
12154
12158
  get: function () {
12155
12159
  return this._cache;
@@ -12188,12 +12192,12 @@
12188
12192
  };
12189
12193
  EntityStore.prototype.load = function (id, opts) {
12190
12194
  return __awaiter(this, void 0, void 0, function () {
12191
- return __generator(this, function (_a) {
12192
- switch (_a.label) {
12195
+ return __generator(this, function (_b) {
12196
+ switch (_b.label) {
12193
12197
  case 0:
12194
12198
  if (!(this._mapToLightEntity && (!opts || opts.fullLoad !== false))) return [3 /*break*/, 2];
12195
12199
  return [4 /*yield*/, this.loadFullEntity(id, opts)];
12196
- case 1: return [2 /*return*/, _a.sent()];
12200
+ case 1: return [2 /*return*/, _b.sent()];
12197
12201
  case 2: return [2 /*return*/, this.loadCachedEntity(id, opts)];
12198
12202
  }
12199
12203
  });
@@ -12233,20 +12237,20 @@
12233
12237
  */
12234
12238
  EntityStore.prototype.loadAll = function (variables, opts) {
12235
12239
  return __awaiter(this, void 0, void 0, function () {
12236
- var res, _a;
12240
+ var res, _b;
12237
12241
  var _this = this;
12238
- return __generator(this, function (_b) {
12239
- switch (_b.label) {
12242
+ return __generator(this, function (_c) {
12243
+ switch (_c.label) {
12240
12244
  case 0:
12241
12245
  res = this.reduceAndSort(this._cache, variables);
12242
12246
  if (!(this._mapToLightEntity && isNotEmptyArray(res.data) && (opts && opts.fullLoad === true))) return [3 /*break*/, 2];
12243
12247
  // Load full entities, one by one
12244
- _a = res;
12248
+ _b = res;
12245
12249
  return [4 /*yield*/, chainPromises((res.data || []).map(function (e) { return function () { return _this.load(e.id); }; }))];
12246
12250
  case 1:
12247
12251
  // Load full entities, one by one
12248
- _a.data = _b.sent();
12249
- _b.label = 2;
12252
+ _b.data = _c.sent();
12253
+ _c.label = 2;
12250
12254
  case 2: return [2 /*return*/, res];
12251
12255
  }
12252
12256
  });
@@ -12363,8 +12367,8 @@
12363
12367
  return __awaiter(this, void 0, void 0, function () {
12364
12368
  var dirtyIndexes, entities;
12365
12369
  var _this = this;
12366
- return __generator(this, function (_a) {
12367
- switch (_a.label) {
12370
+ return __generator(this, function (_b) {
12371
+ switch (_b.label) {
12368
12372
  case 0:
12369
12373
  opts = Object.assign({ skipIfPristine: this.policy.skipNonLocalEntities }, opts);
12370
12374
  // Skip is not dirty
@@ -12388,7 +12392,7 @@
12388
12392
  return [4 /*yield*/, this.storage.remove(this._storageKey)];
12389
12393
  case 1:
12390
12394
  // Clean the local storage
12391
- _a.sent();
12395
+ _b.sent();
12392
12396
  return [3 /*break*/, 7];
12393
12397
  case 2:
12394
12398
  if (!this.isByIdMode) return [3 /*break*/, 5];
@@ -12396,7 +12400,7 @@
12396
12400
  return [4 /*yield*/, this.storage.set(this.storageKeyById, entities.filter(isNotNil).map(function (e) { return e.id; }))];
12397
12401
  case 3:
12398
12402
  // Save ids
12399
- _a.sent();
12403
+ _b.sent();
12400
12404
  // Saved dirty entities
12401
12405
  return [4 /*yield*/, Promise.all(dirtyIndexes
12402
12406
  .map(function (index) {
@@ -12406,15 +12410,15 @@
12406
12410
  }))];
12407
12411
  case 4:
12408
12412
  // Saved dirty entities
12409
- _a.sent();
12413
+ _b.sent();
12410
12414
  console.info("[entity-storage] Persisting " + dirtyIndexes.length + "/" + entities.length + " " + this.name + "(s)...");
12411
12415
  return [3 /*break*/, 7];
12412
12416
  case 5:
12413
12417
  console.info("[entity-storage] Persisting " + entities.length + " " + this.name + "(s)...");
12414
12418
  return [4 /*yield*/, this.storage.set(this._storageKey, entities)];
12415
12419
  case 6:
12416
- _a.sent();
12417
- _a.label = 7;
12420
+ _b.sent();
12421
+ _b.label = 7;
12418
12422
  case 7: return [2 /*return*/, entities.length];
12419
12423
  }
12420
12424
  });
@@ -12424,14 +12428,14 @@
12424
12428
  return __awaiter(this, void 0, void 0, function () {
12425
12429
  var entities, res, values, ids, migration, oldKeysToClean, storageKeys, storageKeys, err_1;
12426
12430
  var _this = this;
12427
- return __generator(this, function (_a) {
12428
- switch (_a.label) {
12431
+ return __generator(this, function (_b) {
12432
+ switch (_b.label) {
12429
12433
  case 0: return [4 /*yield*/, Promise.all([
12430
12434
  this.storage.get(this._storageKey),
12431
12435
  this.storage.get(this.storageKeyById)
12432
12436
  ])];
12433
12437
  case 1:
12434
- res = _a.sent();
12438
+ res = _b.sent();
12435
12439
  values = res[0] && Array.isArray(res[0]) ? res[0] : null;
12436
12440
  ids = res[1] && Array.isArray(res[1]) ? res[1] : null;
12437
12441
  migration = false;
@@ -12440,7 +12444,7 @@
12440
12444
  storageKeys = ids.map(function (id) { return _this._storageKey + '#' + id; });
12441
12445
  return [4 /*yield*/, chainPromises(storageKeys.map(function (key) { return function () { return _this.storage.get(key); }; }))];
12442
12446
  case 2:
12443
- entities = _a.sent();
12447
+ entities = _b.sent();
12444
12448
  return [3 /*break*/, 4];
12445
12449
  case 3:
12446
12450
  if (isNotNil(values)) {
@@ -12448,7 +12452,7 @@
12448
12452
  migration = true;
12449
12453
  oldKeysToClean = [this._storageKey];
12450
12454
  }
12451
- _a.label = 4;
12455
+ _b.label = 4;
12452
12456
  case 4: return [3 /*break*/, 8];
12453
12457
  case 5:
12454
12458
  if (!isNotNil(values)) return [3 /*break*/, 6];
@@ -12460,10 +12464,10 @@
12460
12464
  return [4 /*yield*/, chainPromises(storageKeys.map(function (key) { return function () { return _this.storage.get(key); }; }))];
12461
12465
  case 7:
12462
12466
  // Load entity by id (one by one)
12463
- entities = _a.sent();
12467
+ entities = _b.sent();
12464
12468
  migration = true;
12465
12469
  oldKeysToClean = __spread(storageKeys, [this.storageKeyById]);
12466
- _a.label = 8;
12470
+ _b.label = 8;
12467
12471
  case 8:
12468
12472
  // OK, there is something in storage...
12469
12473
  if (isNotEmptyArray(entities)) {
@@ -12478,23 +12482,23 @@
12478
12482
  this.setEntities(entities || [], Object.assign(Object.assign({}, opts), { emitEvent: false }));
12479
12483
  this._dirty = false;
12480
12484
  if (!migration) return [3 /*break*/, 14];
12481
- _a.label = 9;
12485
+ _b.label = 9;
12482
12486
  case 9:
12483
- _a.trys.push([9, 13, , 14]);
12487
+ _b.trys.push([9, 13, , 14]);
12484
12488
  console.warn("[entity-storage] - Migrate " + this.name + " into {mode: '" + this.policy.mode + "'}...");
12485
12489
  // Force to persist, using the new mode
12486
12490
  return [4 /*yield*/, this.persist({ skipIfPristine: false /* force persist using the new mode */ })];
12487
12491
  case 10:
12488
12492
  // Force to persist, using the new mode
12489
- _a.sent();
12493
+ _b.sent();
12490
12494
  if (!isNotEmptyArray(oldKeysToClean)) return [3 /*break*/, 12];
12491
12495
  return [4 /*yield*/, chainPromises(oldKeysToClean.map(function (key) { return function () { return _this.storage.remove(key); }; }))];
12492
12496
  case 11:
12493
- _a.sent();
12494
- _a.label = 12;
12497
+ _b.sent();
12498
+ _b.label = 12;
12495
12499
  case 12: return [3 /*break*/, 14];
12496
12500
  case 13:
12497
- err_1 = _a.sent();
12501
+ err_1 = _b.sent();
12498
12502
  console.error(err_1);
12499
12503
  throw { code: ErrorCodes$2.ENTITY_STORAGE_MIGRATION_FAILED, message: 'ERROR.ENTITY_STORAGE_MIGRATION_FAILED', details: err_1 };
12500
12504
  case 14:
@@ -12515,10 +12519,10 @@
12515
12519
  }
12516
12520
  };
12517
12521
  EntityStore.prototype.markAsPristine = function (opts) {
12518
- var e_1, _a;
12522
+ var e_1, _b;
12519
12523
  try {
12520
- for (var _b = __values(this._statusById.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
12521
- var s = _c.value;
12524
+ for (var _c = __values(this._statusById.values()), _d = _c.next(); !_d.done; _d = _c.next()) {
12525
+ var s = _d.value;
12522
12526
  if (isNotNil(s)) {
12523
12527
  s.dirty = false;
12524
12528
  }
@@ -12527,7 +12531,7 @@
12527
12531
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
12528
12532
  finally {
12529
12533
  try {
12530
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
12534
+ if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
12531
12535
  }
12532
12536
  finally { if (e_1) throw e_1.error; }
12533
12537
  }
@@ -12548,8 +12552,8 @@
12548
12552
  EntityStore.prototype.loadFullEntity = function (id, opts) {
12549
12553
  return __awaiter(this, void 0, void 0, function () {
12550
12554
  var status, index, fullData;
12551
- return __generator(this, function (_a) {
12552
- switch (_a.label) {
12555
+ return __generator(this, function (_b) {
12556
+ switch (_b.label) {
12553
12557
  case 0:
12554
12558
  status = this._statusById.get(id);
12555
12559
  index = status && status.index;
@@ -12559,10 +12563,10 @@
12559
12563
  console.debug("[entity-storage] Full reloading " + this.name + "#" + id + "...");
12560
12564
  return [4 /*yield*/, this.storage.get(this._storageKey + '#' + id)];
12561
12565
  case 1:
12562
- fullData = _a.sent();
12566
+ fullData = _b.sent();
12563
12567
  if (fullData)
12564
12568
  return [2 /*return*/, fullData];
12565
- _a.label = 2;
12569
+ _b.label = 2;
12566
12570
  case 2:
12567
12571
  // Load from the cache, if dirty OR if storage is not splited by id
12568
12572
  return [2 /*return*/, this._cache[index]];
@@ -13229,11 +13233,17 @@
13229
13233
  console.warn("[entities-storage] Persisting " + entityName + ": store not found!");
13230
13234
  return;
13231
13235
  }
13232
- return entityStore.persist()
13236
+ // SKip store if not dirty
13237
+ if (!entityStore.dirty)
13238
+ return Promise.resolve(); // Skip
13239
+ // Persist store
13240
+ return (entityStore.dirty ? entityStore.persist() : Promise.resolve(entityStore.length))
13233
13241
  .then(function (count) {
13234
13242
  // If no entity found, remove from the entity names array
13235
13243
  if (!count) {
13236
- entityNames.splice(entityNames.findIndex(function (e) { return e === entityName; }), 1);
13244
+ var entityNameIndex = entityNames.findIndex(function (e) { return e === entityName; });
13245
+ if (entityNameIndex !== -1)
13246
+ entityNames.splice(entityNameIndex, 1);
13237
13247
  }
13238
13248
  });
13239
13249
  }; }))
@@ -19629,6 +19639,9 @@
19629
19639
  AppForm.prototype.registerSubscription = function (sub) {
19630
19640
  return this._subscription.add(sub);
19631
19641
  };
19642
+ AppForm.prototype.unregisterSubscription = function (sub) {
19643
+ this._subscription.remove(sub);
19644
+ };
19632
19645
  AppForm.prototype.registerAutocompleteField = function (fieldName, opts) {
19633
19646
  return this.autocompleteHelper.add(fieldName, opts);
19634
19647
  };
@@ -20466,13 +20479,14 @@
20466
20479
  { type: AccountService }
20467
20480
  ]; };
20468
20481
 
20469
- var AccountPage = /** @class */ (function (_super) {
20470
- __extends(AccountPage, _super);
20471
- function AccountPage(injector, router, formBuilder, accountService, validatorService, settingsValidatorService, translate, settings, cd, locales) {
20472
- var _this = _super.call(this, injector, validatorService.getFormGroup(accountService.account)) || this;
20473
- _this.router = router;
20482
+ var AccountPage = /** @class */ (function (_super_1) {
20483
+ __extends(AccountPage, _super_1);
20484
+ function AccountPage(injector, formBuilder, accountService, network, router, validatorService, settingsValidatorService, translate, settings, cd, locales) {
20485
+ var _this = _super_1.call(this, injector, validatorService.getFormGroup(accountService.account)) || this;
20474
20486
  _this.formBuilder = formBuilder;
20475
20487
  _this.accountService = accountService;
20488
+ _this.network = network;
20489
+ _this.router = router;
20476
20490
  _this.validatorService = validatorService;
20477
20491
  _this.settingsValidatorService = settingsValidatorService;
20478
20492
  _this.translate = translate;
@@ -20513,21 +20527,38 @@
20513
20527
  return _this;
20514
20528
  }
20515
20529
  AccountPage.prototype.ngOnDestroy = function () {
20516
- _super.prototype.ngOnDestroy.call(this);
20530
+ var _a;
20531
+ _super_1.prototype.ngOnDestroy.call(this);
20517
20532
  this.stopListenChanges();
20533
+ (_a = this.networkSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
20518
20534
  };
20519
20535
  AccountPage.prototype.onLogin = function (account) {
20536
+ var _this = this;
20537
+ var _a;
20520
20538
  console.debug('[account] Logged account: ', account);
20521
20539
  this.isLogin = true;
20522
20540
  this.setValue(account);
20523
20541
  this.email.confirmed = account && account.email && (account.statusId !== StatusIds.TEMPORARY);
20524
20542
  this.email.notConfirmed = account && account.email && (!account.statusId || account.statusId === StatusIds.TEMPORARY);
20525
- this.enable();
20526
- this.markAsPristine();
20527
- this.startListenChanges();
20528
- this.markAsLoaded();
20543
+ (_a = this.networkSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
20544
+ this.networkSubscription = this.network.onNetworkStatusChanges
20545
+ .pipe(operators.map(function (connectionType) { return connectionType !== 'none'; }))
20546
+ .subscribe(function (online) {
20547
+ if (online) {
20548
+ _this.enable();
20549
+ _this.markAsPristine();
20550
+ _this.startListenChanges();
20551
+ }
20552
+ else {
20553
+ _this.disable();
20554
+ _this.markAsPristine();
20555
+ _this.stopListenChanges();
20556
+ }
20557
+ _this.markAsLoaded();
20558
+ });
20529
20559
  };
20530
20560
  AccountPage.prototype.onLogout = function () {
20561
+ var _a;
20531
20562
  this.isLogin = false;
20532
20563
  this.email.confirmed = false;
20533
20564
  this.email.notConfirmed = false;
@@ -20535,13 +20566,14 @@
20535
20566
  this.email.error = undefined;
20536
20567
  this.form.reset();
20537
20568
  this.disable();
20569
+ (_a = this.networkSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
20538
20570
  this.stopListenChanges();
20539
20571
  // Back to home
20540
20572
  this.router.navigateByUrl('/');
20541
20573
  };
20542
20574
  AccountPage.prototype.refresh = function (event) {
20543
20575
  return __awaiter(this, void 0, void 0, function () {
20544
- return __generator(this, function (_a) {
20576
+ return __generator(this, function (_b) {
20545
20577
  this.disable();
20546
20578
  this.markAsLoading();
20547
20579
  return [2 /*return*/, this.accountService.refresh()];
@@ -20562,8 +20594,8 @@
20562
20594
  AccountPage.prototype.sendConfirmationEmail = function (event) {
20563
20595
  return __awaiter(this, void 0, void 0, function () {
20564
20596
  var json, err_1;
20565
- return __generator(this, function (_a) {
20566
- switch (_a.label) {
20597
+ return __generator(this, function (_b) {
20598
+ switch (_b.label) {
20567
20599
  case 0:
20568
20600
  json = this.form.value;
20569
20601
  json.email = this.form.controls['email'].value;
@@ -20573,17 +20605,17 @@
20573
20605
  }
20574
20606
  this.email.sending = true;
20575
20607
  console.debug('[account] Sending confirmation email...');
20576
- _a.label = 1;
20608
+ _b.label = 1;
20577
20609
  case 1:
20578
- _a.trys.push([1, 3, , 4]);
20610
+ _b.trys.push([1, 3, , 4]);
20579
20611
  return [4 /*yield*/, this.accountService.sendConfirmationEmail(json.email, json.settings && json.settings.locale || this.translate.currentLang)];
20580
20612
  case 2:
20581
- _a.sent();
20613
+ _b.sent();
20582
20614
  console.debug('[account] Confirmation email sent.');
20583
20615
  this.email.sending = false;
20584
20616
  return [3 /*break*/, 4];
20585
20617
  case 3:
20586
- err_1 = _a.sent();
20618
+ err_1 = _b.sent();
20587
20619
  this.email.sending = false;
20588
20620
  this.email.error = err_1 && err_1.message || err_1;
20589
20621
  return [3 /*break*/, 4];
@@ -20595,41 +20627,41 @@
20595
20627
  AccountPage.prototype.save = function (event) {
20596
20628
  return __awaiter(this, void 0, void 0, function () {
20597
20629
  var newAccount, err_2;
20598
- return __generator(this, function (_a) {
20599
- switch (_a.label) {
20630
+ return __generator(this, function (_b) {
20631
+ switch (_b.label) {
20600
20632
  case 0:
20601
20633
  if (this.saving)
20602
- return [2 /*return*/];
20634
+ return [2 /*return*/, false];
20603
20635
  if (!!this.form.valid) return [3 /*break*/, 2];
20604
20636
  return [4 /*yield*/, AppFormUtils.waitWhilePending(this.form)];
20605
20637
  case 1:
20606
- _a.sent();
20638
+ _b.sent();
20607
20639
  if (this.form.invalid) {
20608
20640
  AppFormUtils.logFormErrors(this.form);
20609
20641
  this.form.markAllAsTouched();
20610
- return [2 /*return*/];
20642
+ return [2 /*return*/, false];
20611
20643
  }
20612
- _a.label = 2;
20644
+ _b.label = 2;
20613
20645
  case 2:
20614
20646
  this.submitted = true;
20615
20647
  this.saving = true;
20616
20648
  this.error = undefined;
20617
20649
  newAccount = exports.Account.fromObject(Object.assign(Object.assign({}, (this.accountService.account.asObject())), (this.form.value)));
20618
20650
  console.debug('[account] Saving account...', newAccount);
20619
- _a.label = 3;
20651
+ _b.label = 3;
20620
20652
  case 3:
20621
- _a.trys.push([3, 5, 6, 7]);
20653
+ _b.trys.push([3, 5, 6, 7]);
20622
20654
  this.disable();
20623
20655
  return [4 /*yield*/, this.accountService.save(newAccount)];
20624
20656
  case 4:
20625
- _a.sent();
20657
+ _b.sent();
20626
20658
  this.markAsPristine();
20627
- return [3 /*break*/, 7];
20659
+ return [2 /*return*/, true];
20628
20660
  case 5:
20629
- err_2 = _a.sent();
20661
+ err_2 = _b.sent();
20630
20662
  console.error(err_2);
20631
20663
  this.error = err_2 && err_2.message || err_2;
20632
- return [3 /*break*/, 7];
20664
+ return [2 /*return*/, false];
20633
20665
  case 6:
20634
20666
  this.saving = false;
20635
20667
  this.enable();
@@ -20641,7 +20673,7 @@
20641
20673
  };
20642
20674
  AccountPage.prototype.enable = function () {
20643
20675
  var _this = this;
20644
- _super.prototype.enable.call(this);
20676
+ _super_1.prototype.enable.call(this);
20645
20677
  // Some fields are always disable
20646
20678
  this.form.controls.email.disable();
20647
20679
  this.form.controls.mainProfile.disable();
@@ -20654,6 +20686,17 @@
20654
20686
  });
20655
20687
  this.markForCheck();
20656
20688
  };
20689
+ AccountPage.prototype.cancel = function () {
20690
+ var _super = Object.create(null, {
20691
+ cancel: { get: function () { return _super_1.prototype.cancel; } }
20692
+ });
20693
+ return __awaiter(this, void 0, void 0, function () {
20694
+ return __generator(this, function (_b) {
20695
+ _super.cancel.call(this);
20696
+ return [2 /*return*/];
20697
+ });
20698
+ });
20699
+ };
20657
20700
  AccountPage.prototype.markForCheck = function () {
20658
20701
  this.cd.markForCheck();
20659
20702
  };
@@ -20662,16 +20705,17 @@
20662
20705
  AccountPage.decorators = [
20663
20706
  { type: i0.Component, args: [{
20664
20707
  selector: 'app-page-account',
20665
- template: "<app-toolbar [title]=\"'ACCOUNT.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"form.dirty && !saving\"\n (onValidate)=\"save($event)\"\n [canGoBack]=\"false\">\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading || saving; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button -->\n <ion-button [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</app-toolbar>\n\n<ion-content>\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 <form [formGroup]=\"form\" novalidate (ngSubmit)=\"save($event)\" class=\"form-container\">\n\n <mat-tab-group>\n\n <!-- TAB: user details -->\n <mat-tab label=\"{{'ACCOUNT.USER_DETAILS.TITLE'|translate}}\" class=\"ion-padding\">\n <ng-template mat-tab-label>\n <mat-icon>\n <ion-icon matPrefix slot=\"start\" name=\"person-circle\"></ion-icon>\n </mat-icon>\n <ion-label>{{'ACCOUNT.USER_DETAILS.TITLE'|translate}}</ion-label>\n <ion-icon slot=\"end\" name=\"alert-circle\" color=\"danger\" *ngIf=\"submitted && form.invalid\"></ion-icon>\n </ng-template>\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=\"3\">&nbsp;</ion-col>\n\n <ion-col class=\"ion-padding\">\n <p [innerHTML]=\"'ACCOUNT.USER_DETAILS.DESCRIPTION'|translate\"></p>\n\n <!--h1>Identit\u00E9</h1-->\n\n <!-- Email -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.EMAIL'|translate\"\n formControlName=\"email\" autocomplete=\"section-red email\">\n <mat-error *ngIf=\"form.controls.email.hasError('required') && form.controls.email.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.email.hasError('email') && form.controls.email.dirty\">\n <span>{{'ERROR.FIELD_NOT_VALID_EMAIL' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n <ion-grid *ngIf=\"email.notConfirmed\" class=\"ion-no-padding ion-padding-bottom\">\n <ion-row>\n <ion-col color=\"danger\">\n <ion-icon slot=\"start\" color=\"danger\" name=\"alert-circle\" color=\"danger\"></ion-icon>\n <ion-text [innerHTML]=\"'ACCOUNT.EMAIL_NOT_CONFIRMED_LABEL'|translate\"></ion-text>\n </ion-col>\n </ion-row>\n\n <ion-row style=\"height: 51px;\">\n <ion-col style=\"text-align: right;\">\n <ion-text>\n <small [innerHTML]=\"'ACCOUNT.EMAIL_NOT_RECEIVED_QUESTION'|translate\"></small>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ion-button fill=\"solid\" color=\"secondary\" *ngIf=\"!email.sending\" (click)=\"sendConfirmationEmail($event)\">\n {{'ACCOUNT.BTN_RESEND'|translate}}\n </ion-button>\n <ion-spinner class=\"ion-no-padding\" *ngIf=\"email.sending\"></ion-spinner>\n </ion-col>\n </ion-row>\n\n <ion-row *ngIf=\"email.error && !email.sending\">\n <ion-col>\n <span *ngIf=\"email.error && !email.sending\" [innerHTML]=\"email.error|translate\"></span>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Last name -->\n <mat-form-field>\n <input matInput [appAutofocus]=\"true\" [autofocusDelay]=\"500\" [placeholder]=\"'USER.LAST_NAME'|translate\"\n formControlName=\"lastName\"\n autocomplete=\"section-blue family-name\"\n required>\n <mat-error *ngIf=\"form.controls.lastName.hasError('required') && form.controls.lastName.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.lastName.hasError('minlength') && form.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=\"form.controls.firstName.hasError('required') && form.controls.firstName.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.firstName.hasError('minlength') && form.controls.firstName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n\n <!-- Additional fields -->\n <ng-container *ngFor=\"let definition of additionalFields\">\n <app-form-field [definition]=\"definition\"\n [formControlName]=\"definition.key\"\n [required]=\"definition.extra && definition.extra.account && definition.extra.account.required || false\">\n </app-form-field>\n </ng-container>\n\n <h3 translate>ACCOUNT.USER_DETAILS.TECHNICAL_DIVIDER</h3>\n\n <!-- profile -->\n <mat-form-field>\n <input matInput hidden readonly=\"true\" [placeholder]=\"'ACCOUNT.USER_DETAILS.PROFILE'|translate\"\n formControlName=\"mainProfile\" required>\n <span>{{'USER.PROFILE_ENUM.'+form.controls.mainProfile.value | translate}}</span>\n <mat-error *ngIf=\"form.controls.firstName.hasError('mainProfile') && form.controls.mainProfile.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- pubkey -->\n <mat-form-field>\n <input matInput readonly=\"true\" [placeholder]=\"'ACCOUNT.USER_DETAILS.PUBKEY'|translate\" formControlName=\"pubkey\"\n required>\n <mat-error *ngIf=\"form.controls.firstName.hasError('pubkey') && form.controls.firstName.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.firstName.hasError('pubkey') && form.controls.firstName.dirty\">\n <span translate>ERROR.FIELD_NOT_VALID_PUBKEY</span>\n </mat-error>\n </mat-form-field>\n\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"3\">&nbsp;</ion-col>\n </ion-row>\n </ion-grid>\n </mat-tab>\n\n <!-- TAB: settings -->\n <mat-tab label=\"{{'ACCOUNT.SETTINGS.TITLE'|translate}}\" formGroupName=\"settings\">\n <ng-template mat-tab-label>\n <mat-icon>\n <ion-icon matPrefix slot=\"start\" name=\"settings\"></ion-icon>\n </mat-icon>\n <ion-label translate>ACCOUNT.SETTINGS.TITLE</ion-label>\n </ng-template>\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=\"3\">&nbsp;\n </ion-col>\n\n <ion-col class=\"ion-padding\">\n\n <p [innerHTML]=\"'ACCOUNT.SETTINGS.DESCRIPTION'|translate\"></p>\n\n <mat-form-field>\n <mat-select [placeholder]=\"'ACCOUNT.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=\"settingsForm.controls.locale.hasError('required') && settingsForm.controls.locale.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- lat/long format-->\n <mat-form-field>\n <mat-select [placeholder]=\"'ACCOUNT.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 *ngIf=\"settingsForm.controls.latLongFormat.hasError('required') && settingsForm.controls.latLongFormat.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <form formGroupName=\"content\">\n\n\n </form>\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"3\">&nbsp;\n </ion-col>\n </ion-row>\n </ion-grid>\n </mat-tab>\n </mat-tab-group>\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",
20708
+ template: "<app-toolbar [title]=\"'ACCOUNT.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"form.dirty && !saving\"\n (onValidate)=\"save($event)\"\n [canGoBack]=\"false\">\n\n <ion-buttons slot=\"end\">\n <!-- loader -->\n <ion-spinner *ngIf=\"loading || saving; else endButtons\"></ion-spinner>\n\n <ng-template #endButtons>\n <!-- refresh button (if online) -->\n <ion-button [matTooltip]=\"'COMMON.BTN_REFRESH'|translate\"\n *ngIf=\"network.online\"\n (click)=\"refresh($event)\">\n <mat-icon slot=\"icon-only\">refresh</mat-icon>\n </ion-button>\n </ng-template>\n </ion-buttons>\n</app-toolbar>\n\n<ion-content>\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 <form [formGroup]=\"form\" novalidate (ngSubmit)=\"save($event)\" class=\"form-container\">\n\n <mat-tab-group>\n\n <!-- TAB: user details -->\n <mat-tab label=\"{{'ACCOUNT.USER_DETAILS.TITLE'|translate}}\" class=\"ion-padding\">\n <ng-template mat-tab-label>\n <mat-icon>\n <ion-icon matPrefix slot=\"start\" name=\"person-circle\"></ion-icon>\n </mat-icon>\n <ion-label>{{'ACCOUNT.USER_DETAILS.TITLE'|translate}}</ion-label>\n <ion-icon slot=\"end\" name=\"alert-circle\" color=\"danger\" *ngIf=\"submitted && form.invalid\"></ion-icon>\n </ng-template>\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=\"3\">&nbsp;</ion-col>\n\n <ion-col class=\"ion-padding\">\n <p [innerHTML]=\"'ACCOUNT.USER_DETAILS.DESCRIPTION'|translate\"></p>\n\n <!--h1>Identit\u00E9</h1-->\n\n <!-- Email -->\n <mat-form-field>\n <input matInput [placeholder]=\"'USER.EMAIL'|translate\"\n formControlName=\"email\" autocomplete=\"section-red email\">\n <mat-error *ngIf=\"form.controls.email.hasError('required') && form.controls.email.dirty\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.email.hasError('email') && form.controls.email.dirty\">\n <span>{{'ERROR.FIELD_NOT_VALID_EMAIL' | translate }}</span>\n </mat-error>\n </mat-form-field>\n\n <ion-grid *ngIf=\"email.notConfirmed\" class=\"ion-no-padding ion-padding-bottom\">\n <ion-row>\n <ion-col color=\"danger\">\n <ion-icon slot=\"start\" color=\"danger\" name=\"alert-circle\" color=\"danger\"></ion-icon>\n <ion-text [innerHTML]=\"'ACCOUNT.EMAIL_NOT_CONFIRMED_LABEL'|translate\"></ion-text>\n </ion-col>\n </ion-row>\n\n <ion-row style=\"height: 51px;\">\n <ion-col style=\"text-align: right;\">\n <ion-text>\n <small [innerHTML]=\"'ACCOUNT.EMAIL_NOT_RECEIVED_QUESTION'|translate\"></small>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ion-button fill=\"solid\" color=\"secondary\" *ngIf=\"!email.sending\" (click)=\"sendConfirmationEmail($event)\">\n {{'ACCOUNT.BTN_RESEND'|translate}}\n </ion-button>\n <ion-spinner class=\"ion-no-padding\" *ngIf=\"email.sending\"></ion-spinner>\n </ion-col>\n </ion-row>\n\n <ion-row *ngIf=\"email.error && !email.sending\">\n <ion-col>\n <span *ngIf=\"email.error && !email.sending\" [innerHTML]=\"email.error|translate\"></span>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Last name -->\n <mat-form-field>\n <input matInput [appAutofocus]=\"true\" [autofocusDelay]=\"500\" [placeholder]=\"'USER.LAST_NAME'|translate\"\n formControlName=\"lastName\"\n autocomplete=\"section-blue family-name\"\n required>\n <mat-error *ngIf=\"form.controls.lastName.hasError('required') && form.controls.lastName.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.lastName.hasError('minlength') && form.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=\"form.controls.firstName.hasError('required') && form.controls.firstName.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.firstName.hasError('minlength') && form.controls.firstName.dirty\">\n <span>{{'ERROR.FIELD_MIN_LENGTH' | translate: {minLength: 2} }}</span>\n </mat-error>\n </mat-form-field>\n\n\n <!-- Additional fields -->\n <ng-container *ngFor=\"let definition of additionalFields\">\n <app-form-field [definition]=\"definition\"\n [formControlName]=\"definition.key\"\n [required]=\"definition.extra && definition.extra.account && definition.extra.account.required || false\">\n </app-form-field>\n </ng-container>\n\n <h3 translate>ACCOUNT.USER_DETAILS.TECHNICAL_DIVIDER</h3>\n\n <!-- profile -->\n <mat-form-field>\n <input matInput hidden readonly=\"true\" [placeholder]=\"'ACCOUNT.USER_DETAILS.PROFILE'|translate\"\n formControlName=\"mainProfile\" required>\n <span>{{'USER.PROFILE_ENUM.'+form.controls.mainProfile.value | translate}}</span>\n <mat-error *ngIf=\"form.controls.firstName.hasError('mainProfile') && form.controls.mainProfile.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- pubkey -->\n <mat-form-field>\n <input matInput readonly=\"true\" [placeholder]=\"'ACCOUNT.USER_DETAILS.PUBKEY'|translate\" formControlName=\"pubkey\"\n required>\n <mat-error *ngIf=\"form.controls.firstName.hasError('pubkey') && form.controls.firstName.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"form.controls.firstName.hasError('pubkey') && form.controls.firstName.dirty\">\n <span translate>ERROR.FIELD_NOT_VALID_PUBKEY</span>\n </mat-error>\n </mat-form-field>\n\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"3\">&nbsp;</ion-col>\n </ion-row>\n </ion-grid>\n </mat-tab>\n\n <!-- TAB: settings -->\n <mat-tab label=\"{{'ACCOUNT.SETTINGS.TITLE'|translate}}\" formGroupName=\"settings\">\n <ng-template mat-tab-label>\n <mat-icon>\n <ion-icon matPrefix slot=\"start\" name=\"settings\"></ion-icon>\n </mat-icon>\n <ion-label translate>ACCOUNT.SETTINGS.TITLE</ion-label>\n </ng-template>\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=\"3\">&nbsp;\n </ion-col>\n\n <ion-col class=\"ion-padding\">\n\n <p [innerHTML]=\"'ACCOUNT.SETTINGS.DESCRIPTION'|translate\"></p>\n\n <mat-form-field>\n <mat-select [placeholder]=\"'ACCOUNT.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=\"settingsForm.controls.locale.hasError('required') && settingsForm.controls.locale.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- lat/long format-->\n <mat-form-field>\n <mat-select [placeholder]=\"'ACCOUNT.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 *ngIf=\"settingsForm.controls.latLongFormat.hasError('required') && settingsForm.controls.latLongFormat.dirty\"\n translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <form formGroupName=\"content\">\n\n\n </form>\n </ion-col>\n\n <!-- right margin -->\n <ion-col size=\"0\" size-lg=\"3\">&nbsp;\n </ion-col>\n </ion-row>\n </ion-grid>\n </mat-tab>\n </mat-tab-group>\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",
20666
20709
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
20667
20710
  styles: ["mat-tab-group .mat-tab-body-content{padding:var(--ion-grid-padding);display:grid}form,form mat-form-field{width:100%}"]
20668
20711
  },] }
20669
20712
  ];
20670
20713
  AccountPage.ctorParameters = function () { return [
20671
20714
  { type: i0.Injector },
20672
- { type: i3.Router },
20673
20715
  { type: i1.FormBuilder },
20674
20716
  { type: AccountService },
20717
+ { type: NetworkService },
20718
+ { type: i3.Router },
20675
20719
  { type: AccountValidatorService },
20676
20720
  { type: UserSettingsValidatorService },
20677
20721
  { type: i1$2.TranslateService },
@@ -21219,6 +21263,7 @@
21219
21263
  if (this.saving)
21220
21264
  return [2 /*return*/]; // Skip
21221
21265
  event === null || event === void 0 ? void 0 : event.preventDefault();
21266
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
21222
21267
  // Remove all empty controls
21223
21268
  this.propertiesFormHelper.removeAllEmpty();
21224
21269
  if (!!this.form.valid) return [3 /*break*/, 2];
@@ -21423,7 +21468,7 @@
21423
21468
  SettingsPage.decorators = [
21424
21469
  { type: i0.Component, args: [{
21425
21470
  selector: 'page-settings',
21426
- template: "<app-toolbar [title]=\"'SETTINGS.TITLE'|translate\" color=\"primary\"\n [hasValidate]=\"form.dirty && !saving\"\n [hasClose]=\"!form.dirty && !saving\"\n (onValidate)=\"save($event)\"\n (onClose)=\"close($event)\">\n\n <ion-buttons slot=\"end\">\n <!-- options menu -->\n <ion-button [matMenuTriggerFor]=\"optionsMenu\" [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.controls.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",
21471
+ 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\" [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.controls.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",
21427
21472
  providers: [
21428
21473
  { provide: ngxMaterialTable.ValidatorService, useExisting: LocalSettingsValidatorService },
21429
21474
  ],