@sumaris-net/ngx-components 1.4.6 → 1.5.2

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%';
@@ -1399,7 +1396,7 @@
1399
1396
  this.displayWith = this.displayWith || this.config.displayWith;
1400
1397
  this.mobile = toBoolean(this.mobile, this.config.mobile);
1401
1398
  this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold || 0);
1402
- this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold === 0));
1399
+ this.showAllOnFocus = toBoolean(this.showAllOnFocus, toBoolean(this.config.showAllOnFocus, this.suggestLengthThreshold <= 0));
1403
1400
  this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, toBoolean(this.config.showPanelOnFocus));
1404
1401
  this.classList = this.classList || this.config.class;
1405
1402
  this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
@@ -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 () {
@@ -1518,8 +1516,16 @@
1518
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$)
1519
1517
  .pipe(operators.filter(function (event) { return _this.enabled && _this.searchable; }), operators.map(function (_) { return _this.formControl.value; })))
1520
1518
  .pipe(
1521
- // If value is a string (and is not = '*'), filter if not enough character
1522
- operators.filter(function (value) { return value === '*' || !(typeof value === 'string') || value.length >= _this.suggestLengthThreshold; }),
1519
+ // Start to suggest when :
1520
+ // - '*'
1521
+ // - is nil, and there is no min length threshold
1522
+ // - is not nil and not a string type (e.g. object)
1523
+ // - is not nil and is a string, and has enough character
1524
+ operators.filter(function (value) { return value === '*'
1525
+ || (isNil(value)
1526
+ ? (_this.suggestLengthThreshold <= 0)
1527
+ : (!(typeof value === 'string')
1528
+ || value.length >= _this.suggestLengthThreshold)); }),
1523
1529
  // Distinguish changes
1524
1530
  operators.distinctUntilChanged()))
1525
1531
  .pipe(
@@ -10832,9 +10838,9 @@
10832
10838
  LocalSettingsService.prototype.ngOnStart = function () {
10833
10839
  console.info('[settings] Starting service...');
10834
10840
  // Restoring local settings
10835
- this._data.mobile = isNotNil(this._data.mobile) ? this._data.mobile : this.platform.is('mobile');
10841
+ this._data.mobile = toBoolean(this._data.mobile, this.platform.is('mobile'));
10836
10842
  this._data.touchUi = this._data.mobile || this.platform.is('phablet') || this.platform.is('tablet');
10837
- this._data.usageMode = this.platform.is('android') ? 'FIELD' : 'DESK'; // FIELD by default if Android
10843
+ this._data.usageMode = this.platform.is('android') || this.platform.is('ios') ? 'FIELD' : 'DESK'; // FIELD by default if Android or iOs
10838
10844
  // Restoring local settings
10839
10845
  return this.restoreLocally();
10840
10846
  };
@@ -12148,6 +12154,14 @@
12148
12154
  this._storageKey = ENTITIES_STORAGE_KEY_PREFIX + '#' + name;
12149
12155
  this._mapToLightEntity = this.createLightEntityMapFn(this.policy);
12150
12156
  }
12157
+ Object.defineProperty(EntityStore.prototype, "length", {
12158
+ get: function () {
12159
+ var _a;
12160
+ return ((_a = this._cache) === null || _a === void 0 ? void 0 : _a.length) || 0;
12161
+ },
12162
+ enumerable: false,
12163
+ configurable: true
12164
+ });
12151
12165
  Object.defineProperty(EntityStore.prototype, "cache", {
12152
12166
  get: function () {
12153
12167
  return this._cache;
@@ -12186,12 +12200,12 @@
12186
12200
  };
12187
12201
  EntityStore.prototype.load = function (id, opts) {
12188
12202
  return __awaiter(this, void 0, void 0, function () {
12189
- return __generator(this, function (_a) {
12190
- switch (_a.label) {
12203
+ return __generator(this, function (_b) {
12204
+ switch (_b.label) {
12191
12205
  case 0:
12192
12206
  if (!(this._mapToLightEntity && (!opts || opts.fullLoad !== false))) return [3 /*break*/, 2];
12193
12207
  return [4 /*yield*/, this.loadFullEntity(id, opts)];
12194
- case 1: return [2 /*return*/, _a.sent()];
12208
+ case 1: return [2 /*return*/, _b.sent()];
12195
12209
  case 2: return [2 /*return*/, this.loadCachedEntity(id, opts)];
12196
12210
  }
12197
12211
  });
@@ -12231,20 +12245,20 @@
12231
12245
  */
12232
12246
  EntityStore.prototype.loadAll = function (variables, opts) {
12233
12247
  return __awaiter(this, void 0, void 0, function () {
12234
- var res, _a;
12248
+ var res, _b;
12235
12249
  var _this = this;
12236
- return __generator(this, function (_b) {
12237
- switch (_b.label) {
12250
+ return __generator(this, function (_c) {
12251
+ switch (_c.label) {
12238
12252
  case 0:
12239
12253
  res = this.reduceAndSort(this._cache, variables);
12240
12254
  if (!(this._mapToLightEntity && isNotEmptyArray(res.data) && (opts && opts.fullLoad === true))) return [3 /*break*/, 2];
12241
12255
  // Load full entities, one by one
12242
- _a = res;
12256
+ _b = res;
12243
12257
  return [4 /*yield*/, chainPromises((res.data || []).map(function (e) { return function () { return _this.load(e.id); }; }))];
12244
12258
  case 1:
12245
12259
  // Load full entities, one by one
12246
- _a.data = _b.sent();
12247
- _b.label = 2;
12260
+ _b.data = _c.sent();
12261
+ _c.label = 2;
12248
12262
  case 2: return [2 /*return*/, res];
12249
12263
  }
12250
12264
  });
@@ -12361,8 +12375,8 @@
12361
12375
  return __awaiter(this, void 0, void 0, function () {
12362
12376
  var dirtyIndexes, entities;
12363
12377
  var _this = this;
12364
- return __generator(this, function (_a) {
12365
- switch (_a.label) {
12378
+ return __generator(this, function (_b) {
12379
+ switch (_b.label) {
12366
12380
  case 0:
12367
12381
  opts = Object.assign({ skipIfPristine: this.policy.skipNonLocalEntities }, opts);
12368
12382
  // Skip is not dirty
@@ -12386,7 +12400,7 @@
12386
12400
  return [4 /*yield*/, this.storage.remove(this._storageKey)];
12387
12401
  case 1:
12388
12402
  // Clean the local storage
12389
- _a.sent();
12403
+ _b.sent();
12390
12404
  return [3 /*break*/, 7];
12391
12405
  case 2:
12392
12406
  if (!this.isByIdMode) return [3 /*break*/, 5];
@@ -12394,7 +12408,7 @@
12394
12408
  return [4 /*yield*/, this.storage.set(this.storageKeyById, entities.filter(isNotNil).map(function (e) { return e.id; }))];
12395
12409
  case 3:
12396
12410
  // Save ids
12397
- _a.sent();
12411
+ _b.sent();
12398
12412
  // Saved dirty entities
12399
12413
  return [4 /*yield*/, Promise.all(dirtyIndexes
12400
12414
  .map(function (index) {
@@ -12404,15 +12418,15 @@
12404
12418
  }))];
12405
12419
  case 4:
12406
12420
  // Saved dirty entities
12407
- _a.sent();
12421
+ _b.sent();
12408
12422
  console.info("[entity-storage] Persisting " + dirtyIndexes.length + "/" + entities.length + " " + this.name + "(s)...");
12409
12423
  return [3 /*break*/, 7];
12410
12424
  case 5:
12411
12425
  console.info("[entity-storage] Persisting " + entities.length + " " + this.name + "(s)...");
12412
12426
  return [4 /*yield*/, this.storage.set(this._storageKey, entities)];
12413
12427
  case 6:
12414
- _a.sent();
12415
- _a.label = 7;
12428
+ _b.sent();
12429
+ _b.label = 7;
12416
12430
  case 7: return [2 /*return*/, entities.length];
12417
12431
  }
12418
12432
  });
@@ -12422,14 +12436,14 @@
12422
12436
  return __awaiter(this, void 0, void 0, function () {
12423
12437
  var entities, res, values, ids, migration, oldKeysToClean, storageKeys, storageKeys, err_1;
12424
12438
  var _this = this;
12425
- return __generator(this, function (_a) {
12426
- switch (_a.label) {
12439
+ return __generator(this, function (_b) {
12440
+ switch (_b.label) {
12427
12441
  case 0: return [4 /*yield*/, Promise.all([
12428
12442
  this.storage.get(this._storageKey),
12429
12443
  this.storage.get(this.storageKeyById)
12430
12444
  ])];
12431
12445
  case 1:
12432
- res = _a.sent();
12446
+ res = _b.sent();
12433
12447
  values = res[0] && Array.isArray(res[0]) ? res[0] : null;
12434
12448
  ids = res[1] && Array.isArray(res[1]) ? res[1] : null;
12435
12449
  migration = false;
@@ -12438,7 +12452,7 @@
12438
12452
  storageKeys = ids.map(function (id) { return _this._storageKey + '#' + id; });
12439
12453
  return [4 /*yield*/, chainPromises(storageKeys.map(function (key) { return function () { return _this.storage.get(key); }; }))];
12440
12454
  case 2:
12441
- entities = _a.sent();
12455
+ entities = _b.sent();
12442
12456
  return [3 /*break*/, 4];
12443
12457
  case 3:
12444
12458
  if (isNotNil(values)) {
@@ -12446,7 +12460,7 @@
12446
12460
  migration = true;
12447
12461
  oldKeysToClean = [this._storageKey];
12448
12462
  }
12449
- _a.label = 4;
12463
+ _b.label = 4;
12450
12464
  case 4: return [3 /*break*/, 8];
12451
12465
  case 5:
12452
12466
  if (!isNotNil(values)) return [3 /*break*/, 6];
@@ -12458,10 +12472,10 @@
12458
12472
  return [4 /*yield*/, chainPromises(storageKeys.map(function (key) { return function () { return _this.storage.get(key); }; }))];
12459
12473
  case 7:
12460
12474
  // Load entity by id (one by one)
12461
- entities = _a.sent();
12475
+ entities = _b.sent();
12462
12476
  migration = true;
12463
12477
  oldKeysToClean = __spread(storageKeys, [this.storageKeyById]);
12464
- _a.label = 8;
12478
+ _b.label = 8;
12465
12479
  case 8:
12466
12480
  // OK, there is something in storage...
12467
12481
  if (isNotEmptyArray(entities)) {
@@ -12476,23 +12490,23 @@
12476
12490
  this.setEntities(entities || [], Object.assign(Object.assign({}, opts), { emitEvent: false }));
12477
12491
  this._dirty = false;
12478
12492
  if (!migration) return [3 /*break*/, 14];
12479
- _a.label = 9;
12493
+ _b.label = 9;
12480
12494
  case 9:
12481
- _a.trys.push([9, 13, , 14]);
12495
+ _b.trys.push([9, 13, , 14]);
12482
12496
  console.warn("[entity-storage] - Migrate " + this.name + " into {mode: '" + this.policy.mode + "'}...");
12483
12497
  // Force to persist, using the new mode
12484
12498
  return [4 /*yield*/, this.persist({ skipIfPristine: false /* force persist using the new mode */ })];
12485
12499
  case 10:
12486
12500
  // Force to persist, using the new mode
12487
- _a.sent();
12501
+ _b.sent();
12488
12502
  if (!isNotEmptyArray(oldKeysToClean)) return [3 /*break*/, 12];
12489
12503
  return [4 /*yield*/, chainPromises(oldKeysToClean.map(function (key) { return function () { return _this.storage.remove(key); }; }))];
12490
12504
  case 11:
12491
- _a.sent();
12492
- _a.label = 12;
12505
+ _b.sent();
12506
+ _b.label = 12;
12493
12507
  case 12: return [3 /*break*/, 14];
12494
12508
  case 13:
12495
- err_1 = _a.sent();
12509
+ err_1 = _b.sent();
12496
12510
  console.error(err_1);
12497
12511
  throw { code: ErrorCodes$2.ENTITY_STORAGE_MIGRATION_FAILED, message: 'ERROR.ENTITY_STORAGE_MIGRATION_FAILED', details: err_1 };
12498
12512
  case 14:
@@ -12513,10 +12527,10 @@
12513
12527
  }
12514
12528
  };
12515
12529
  EntityStore.prototype.markAsPristine = function (opts) {
12516
- var e_1, _a;
12530
+ var e_1, _b;
12517
12531
  try {
12518
- for (var _b = __values(this._statusById.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
12519
- var s = _c.value;
12532
+ for (var _c = __values(this._statusById.values()), _d = _c.next(); !_d.done; _d = _c.next()) {
12533
+ var s = _d.value;
12520
12534
  if (isNotNil(s)) {
12521
12535
  s.dirty = false;
12522
12536
  }
@@ -12525,7 +12539,7 @@
12525
12539
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
12526
12540
  finally {
12527
12541
  try {
12528
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
12542
+ if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
12529
12543
  }
12530
12544
  finally { if (e_1) throw e_1.error; }
12531
12545
  }
@@ -12546,8 +12560,8 @@
12546
12560
  EntityStore.prototype.loadFullEntity = function (id, opts) {
12547
12561
  return __awaiter(this, void 0, void 0, function () {
12548
12562
  var status, index, fullData;
12549
- return __generator(this, function (_a) {
12550
- switch (_a.label) {
12563
+ return __generator(this, function (_b) {
12564
+ switch (_b.label) {
12551
12565
  case 0:
12552
12566
  status = this._statusById.get(id);
12553
12567
  index = status && status.index;
@@ -12557,10 +12571,10 @@
12557
12571
  console.debug("[entity-storage] Full reloading " + this.name + "#" + id + "...");
12558
12572
  return [4 /*yield*/, this.storage.get(this._storageKey + '#' + id)];
12559
12573
  case 1:
12560
- fullData = _a.sent();
12574
+ fullData = _b.sent();
12561
12575
  if (fullData)
12562
12576
  return [2 /*return*/, fullData];
12563
- _a.label = 2;
12577
+ _b.label = 2;
12564
12578
  case 2:
12565
12579
  // Load from the cache, if dirty OR if storage is not splited by id
12566
12580
  return [2 /*return*/, this._cache[index]];
@@ -13227,14 +13241,17 @@
13227
13241
  console.warn("[entities-storage] Persisting " + entityName + ": store not found!");
13228
13242
  return;
13229
13243
  }
13244
+ // SKip store if not dirty
13230
13245
  if (!entityStore.dirty)
13231
- return;
13246
+ return Promise.resolve(); // Skip
13232
13247
  // Persist store
13233
- return entityStore.persist()
13248
+ return (entityStore.dirty ? entityStore.persist() : Promise.resolve(entityStore.length))
13234
13249
  .then(function (count) {
13235
13250
  // If no entity found, remove from the entity names array
13236
13251
  if (!count) {
13237
- entityNames.splice(entityNames.findIndex(function (e) { return e === entityName; }), 1);
13252
+ var entityNameIndex = entityNames.findIndex(function (e) { return e === entityName; });
13253
+ if (entityNameIndex !== -1)
13254
+ entityNames.splice(entityNameIndex, 1);
13238
13255
  }
13239
13256
  });
13240
13257
  }; }))
@@ -19630,6 +19647,9 @@
19630
19647
  AppForm.prototype.registerSubscription = function (sub) {
19631
19648
  return this._subscription.add(sub);
19632
19649
  };
19650
+ AppForm.prototype.unregisterSubscription = function (sub) {
19651
+ this._subscription.remove(sub);
19652
+ };
19633
19653
  AppForm.prototype.registerAutocompleteField = function (fieldName, opts) {
19634
19654
  return this.autocompleteHelper.add(fieldName, opts);
19635
19655
  };
@@ -20467,13 +20487,14 @@
20467
20487
  { type: AccountService }
20468
20488
  ]; };
20469
20489
 
20470
- var AccountPage = /** @class */ (function (_super) {
20471
- __extends(AccountPage, _super);
20472
- function AccountPage(injector, router, formBuilder, accountService, validatorService, settingsValidatorService, translate, settings, cd, locales) {
20473
- var _this = _super.call(this, injector, validatorService.getFormGroup(accountService.account)) || this;
20474
- _this.router = router;
20490
+ var AccountPage = /** @class */ (function (_super_1) {
20491
+ __extends(AccountPage, _super_1);
20492
+ function AccountPage(injector, formBuilder, accountService, network, router, validatorService, settingsValidatorService, translate, settings, cd, locales) {
20493
+ var _this = _super_1.call(this, injector, validatorService.getFormGroup(accountService.account)) || this;
20475
20494
  _this.formBuilder = formBuilder;
20476
20495
  _this.accountService = accountService;
20496
+ _this.network = network;
20497
+ _this.router = router;
20477
20498
  _this.validatorService = validatorService;
20478
20499
  _this.settingsValidatorService = settingsValidatorService;
20479
20500
  _this.translate = translate;
@@ -20514,21 +20535,38 @@
20514
20535
  return _this;
20515
20536
  }
20516
20537
  AccountPage.prototype.ngOnDestroy = function () {
20517
- _super.prototype.ngOnDestroy.call(this);
20538
+ var _a;
20539
+ _super_1.prototype.ngOnDestroy.call(this);
20518
20540
  this.stopListenChanges();
20541
+ (_a = this.networkSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
20519
20542
  };
20520
20543
  AccountPage.prototype.onLogin = function (account) {
20544
+ var _this = this;
20545
+ var _a;
20521
20546
  console.debug('[account] Logged account: ', account);
20522
20547
  this.isLogin = true;
20523
20548
  this.setValue(account);
20524
20549
  this.email.confirmed = account && account.email && (account.statusId !== StatusIds.TEMPORARY);
20525
20550
  this.email.notConfirmed = account && account.email && (!account.statusId || account.statusId === StatusIds.TEMPORARY);
20526
- this.enable();
20527
- this.markAsPristine();
20528
- this.startListenChanges();
20529
- this.markAsLoaded();
20551
+ (_a = this.networkSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
20552
+ this.networkSubscription = this.network.onNetworkStatusChanges
20553
+ .pipe(operators.map(function (connectionType) { return connectionType !== 'none'; }))
20554
+ .subscribe(function (online) {
20555
+ if (online) {
20556
+ _this.enable();
20557
+ _this.markAsPristine();
20558
+ _this.startListenChanges();
20559
+ }
20560
+ else {
20561
+ _this.disable();
20562
+ _this.markAsPristine();
20563
+ _this.stopListenChanges();
20564
+ }
20565
+ _this.markAsLoaded();
20566
+ });
20530
20567
  };
20531
20568
  AccountPage.prototype.onLogout = function () {
20569
+ var _a;
20532
20570
  this.isLogin = false;
20533
20571
  this.email.confirmed = false;
20534
20572
  this.email.notConfirmed = false;
@@ -20536,13 +20574,14 @@
20536
20574
  this.email.error = undefined;
20537
20575
  this.form.reset();
20538
20576
  this.disable();
20577
+ (_a = this.networkSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
20539
20578
  this.stopListenChanges();
20540
20579
  // Back to home
20541
20580
  this.router.navigateByUrl('/');
20542
20581
  };
20543
20582
  AccountPage.prototype.refresh = function (event) {
20544
20583
  return __awaiter(this, void 0, void 0, function () {
20545
- return __generator(this, function (_a) {
20584
+ return __generator(this, function (_b) {
20546
20585
  this.disable();
20547
20586
  this.markAsLoading();
20548
20587
  return [2 /*return*/, this.accountService.refresh()];
@@ -20563,8 +20602,8 @@
20563
20602
  AccountPage.prototype.sendConfirmationEmail = function (event) {
20564
20603
  return __awaiter(this, void 0, void 0, function () {
20565
20604
  var json, err_1;
20566
- return __generator(this, function (_a) {
20567
- switch (_a.label) {
20605
+ return __generator(this, function (_b) {
20606
+ switch (_b.label) {
20568
20607
  case 0:
20569
20608
  json = this.form.value;
20570
20609
  json.email = this.form.controls['email'].value;
@@ -20574,17 +20613,17 @@
20574
20613
  }
20575
20614
  this.email.sending = true;
20576
20615
  console.debug('[account] Sending confirmation email...');
20577
- _a.label = 1;
20616
+ _b.label = 1;
20578
20617
  case 1:
20579
- _a.trys.push([1, 3, , 4]);
20618
+ _b.trys.push([1, 3, , 4]);
20580
20619
  return [4 /*yield*/, this.accountService.sendConfirmationEmail(json.email, json.settings && json.settings.locale || this.translate.currentLang)];
20581
20620
  case 2:
20582
- _a.sent();
20621
+ _b.sent();
20583
20622
  console.debug('[account] Confirmation email sent.');
20584
20623
  this.email.sending = false;
20585
20624
  return [3 /*break*/, 4];
20586
20625
  case 3:
20587
- err_1 = _a.sent();
20626
+ err_1 = _b.sent();
20588
20627
  this.email.sending = false;
20589
20628
  this.email.error = err_1 && err_1.message || err_1;
20590
20629
  return [3 /*break*/, 4];
@@ -20596,41 +20635,41 @@
20596
20635
  AccountPage.prototype.save = function (event) {
20597
20636
  return __awaiter(this, void 0, void 0, function () {
20598
20637
  var newAccount, err_2;
20599
- return __generator(this, function (_a) {
20600
- switch (_a.label) {
20638
+ return __generator(this, function (_b) {
20639
+ switch (_b.label) {
20601
20640
  case 0:
20602
20641
  if (this.saving)
20603
- return [2 /*return*/];
20642
+ return [2 /*return*/, false];
20604
20643
  if (!!this.form.valid) return [3 /*break*/, 2];
20605
20644
  return [4 /*yield*/, AppFormUtils.waitWhilePending(this.form)];
20606
20645
  case 1:
20607
- _a.sent();
20646
+ _b.sent();
20608
20647
  if (this.form.invalid) {
20609
20648
  AppFormUtils.logFormErrors(this.form);
20610
20649
  this.form.markAllAsTouched();
20611
- return [2 /*return*/];
20650
+ return [2 /*return*/, false];
20612
20651
  }
20613
- _a.label = 2;
20652
+ _b.label = 2;
20614
20653
  case 2:
20615
20654
  this.submitted = true;
20616
20655
  this.saving = true;
20617
20656
  this.error = undefined;
20618
20657
  newAccount = exports.Account.fromObject(Object.assign(Object.assign({}, (this.accountService.account.asObject())), (this.form.value)));
20619
20658
  console.debug('[account] Saving account...', newAccount);
20620
- _a.label = 3;
20659
+ _b.label = 3;
20621
20660
  case 3:
20622
- _a.trys.push([3, 5, 6, 7]);
20661
+ _b.trys.push([3, 5, 6, 7]);
20623
20662
  this.disable();
20624
20663
  return [4 /*yield*/, this.accountService.save(newAccount)];
20625
20664
  case 4:
20626
- _a.sent();
20665
+ _b.sent();
20627
20666
  this.markAsPristine();
20628
- return [3 /*break*/, 7];
20667
+ return [2 /*return*/, true];
20629
20668
  case 5:
20630
- err_2 = _a.sent();
20669
+ err_2 = _b.sent();
20631
20670
  console.error(err_2);
20632
20671
  this.error = err_2 && err_2.message || err_2;
20633
- return [3 /*break*/, 7];
20672
+ return [2 /*return*/, false];
20634
20673
  case 6:
20635
20674
  this.saving = false;
20636
20675
  this.enable();
@@ -20642,7 +20681,7 @@
20642
20681
  };
20643
20682
  AccountPage.prototype.enable = function () {
20644
20683
  var _this = this;
20645
- _super.prototype.enable.call(this);
20684
+ _super_1.prototype.enable.call(this);
20646
20685
  // Some fields are always disable
20647
20686
  this.form.controls.email.disable();
20648
20687
  this.form.controls.mainProfile.disable();
@@ -20655,6 +20694,17 @@
20655
20694
  });
20656
20695
  this.markForCheck();
20657
20696
  };
20697
+ AccountPage.prototype.cancel = function () {
20698
+ var _super = Object.create(null, {
20699
+ cancel: { get: function () { return _super_1.prototype.cancel; } }
20700
+ });
20701
+ return __awaiter(this, void 0, void 0, function () {
20702
+ return __generator(this, function (_b) {
20703
+ _super.cancel.call(this);
20704
+ return [2 /*return*/];
20705
+ });
20706
+ });
20707
+ };
20658
20708
  AccountPage.prototype.markForCheck = function () {
20659
20709
  this.cd.markForCheck();
20660
20710
  };
@@ -20663,16 +20713,17 @@
20663
20713
  AccountPage.decorators = [
20664
20714
  { type: i0.Component, args: [{
20665
20715
  selector: 'app-page-account',
20666
- 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",
20716
+ 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",
20667
20717
  changeDetection: i0.ChangeDetectionStrategy.OnPush,
20668
20718
  styles: ["mat-tab-group .mat-tab-body-content{padding:var(--ion-grid-padding);display:grid}form,form mat-form-field{width:100%}"]
20669
20719
  },] }
20670
20720
  ];
20671
20721
  AccountPage.ctorParameters = function () { return [
20672
20722
  { type: i0.Injector },
20673
- { type: i3.Router },
20674
20723
  { type: i1.FormBuilder },
20675
20724
  { type: AccountService },
20725
+ { type: NetworkService },
20726
+ { type: i3.Router },
20676
20727
  { type: AccountValidatorService },
20677
20728
  { type: UserSettingsValidatorService },
20678
20729
  { type: i1$2.TranslateService },
@@ -21220,6 +21271,7 @@
21220
21271
  if (this.saving)
21221
21272
  return [2 /*return*/]; // Skip
21222
21273
  event === null || event === void 0 ? void 0 : event.preventDefault();
21274
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
21223
21275
  // Remove all empty controls
21224
21276
  this.propertiesFormHelper.removeAllEmpty();
21225
21277
  if (!!this.form.valid) return [3 /*break*/, 2];
@@ -21424,7 +21476,7 @@
21424
21476
  SettingsPage.decorators = [
21425
21477
  { type: i0.Component, args: [{
21426
21478
  selector: 'page-settings',
21427
- 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",
21479
+ 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",
21428
21480
  providers: [
21429
21481
  { provide: ngxMaterialTable.ValidatorService, useExisting: LocalSettingsValidatorService },
21430
21482
  ],