@sumaris-net/ngx-components 1.19.4 → 1.19.5-rc3

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.
@@ -47,7 +47,7 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
47
47
  import { MatDividerModule } from '@angular/material/divider';
48
48
  import { MatTooltipModule } from '@angular/material/tooltip';
49
49
  import { MatChipsModule } from '@angular/material/chips';
50
- import { Router, ActivatedRoute, RouterModule, RouteReuseStrategy } from '@angular/router';
50
+ import { ActivatedRoute, Router, RouterModule, RouteReuseStrategy } from '@angular/router';
51
51
  import { HammerGestureConfig, EventManager } from '@angular/platform-browser';
52
52
  import { HttpResponse, HttpClient, HttpHeaders, HttpEventType, HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
53
53
  import { ColorPickerModule } from 'ngx-color-picker';
@@ -8276,7 +8276,8 @@ AppGestureConfig.decorators = [
8276
8276
  class ToolbarToken {
8277
8277
  }
8278
8278
  class ToolbarComponent {
8279
- constructor(router, routerOutlet, cd, progressBarService) {
8279
+ constructor(route, router, routerOutlet, cd, progressBarService) {
8280
+ this.route = route;
8280
8281
  this.router = router;
8281
8282
  this.routerOutlet = routerOutlet;
8282
8283
  this.cd = cd;
@@ -8362,15 +8363,28 @@ class ToolbarComponent {
8362
8363
  return __awaiter(this, void 0, void 0, function* () {
8363
8364
  console.debug('[toolbar] calling goBack()');
8364
8365
  if (this._backHref) {
8365
- yield this.router.navigateByUrl(this._backHref);
8366
+ const replaceUrl = !this.routerOutlet.canGoBack();
8367
+ // Relative href
8368
+ if (this._backHref.startsWith('.')) {
8369
+ yield this.router.navigate([this._backHref], { relativeTo: this.route, replaceUrl });
8370
+ }
8371
+ else {
8372
+ yield this.router.navigateByUrl(this._backHref, { replaceUrl });
8373
+ }
8366
8374
  }
8367
8375
  else if (this.routerOutlet.canGoBack()) {
8368
8376
  yield this.routerOutlet.pop();
8369
8377
  }
8370
8378
  else if (this._defaultBackHref) {
8371
- yield this.router.navigateByUrl(this._defaultBackHref, {
8372
- replaceUrl: true
8373
- });
8379
+ // Relative href
8380
+ if (this._backHref.startsWith('.')) {
8381
+ yield this.router.navigate([this._backHref], { relativeTo: this.route, replaceUrl: true });
8382
+ }
8383
+ else {
8384
+ yield this.router.navigateByUrl(this._defaultBackHref, {
8385
+ replaceUrl: true
8386
+ });
8387
+ }
8374
8388
  }
8375
8389
  else {
8376
8390
  console.error('[toolbar] Cannot go back. Missing attribute \'defaultBackHref\' or \'backHref\'');
@@ -8429,7 +8443,7 @@ class ToolbarComponent {
8429
8443
  ToolbarComponent.decorators = [
8430
8444
  { type: Component, args: [{
8431
8445
  selector: 'app-toolbar',
8432
- template: "<ion-header [class]=\"class\">\n <ion-toolbar [color]=\"color\">\n\n <ion-buttons slot=\"start\">\n\n <!-- back button -->\n <ion-button class=\"back-button\"\n *ngIf=\"canGoBack\"\n (click)=\"doBackClick($event)\"\n routerDirection=\"back\" >\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n\n <!-- show menu button -->\n <ion-menu-toggle [hidden]=\"canGoBack || !canShowMenu\">\n <ion-button>\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n\n <ng-content select=\"[slot=start]\"></ng-content>\n </ion-buttons>\n\n <ion-title [innerHTML]=\"title\"></ion-title>\n\n <ng-content select=\"ion-title\"></ng-content>\n\n <ng-content select=\"ion-buttons[slot=end]\"></ng-content>\n\n <ion-buttons slot=\"end\" collapse=\"true\">\n\n <ng-content select=\"[slot=end]\"></ng-content>\n\n <!-- search bar -->\n <ion-searchbar #searchbar animated\n type=\"search\"\n *ngIf=\"hasSearch\"\n [class.cdk-visually-hidden]=\"!showSearchBar\"\n show-cancel-button=\"always\"\n (ionChange)=\"onSearch.emit($event)\"\n (ionCancel)=\"toggleSearchBar()\">\n </ion-searchbar>\n\n <!-- search button -->\n <ion-button (click)=\"toggleSearchBar()\"\n *ngIf=\"hasSearch && !showSearchBar\">\n <ion-icon slot=\"icon-only\" name=\"search\"></ion-icon>\n </ion-button>\n\n <!-- close button -->\n <ion-button *ngIf=\"hasClose\"\n (tap)=\"tapClose($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n\n <!-- validate button -->\n <ion-button *ngIf=\"hasValidate\"\n (tap)=\"tapValidate($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"save\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n\n <!-- progress bar -->\n <mat-progress-bar [color]=\"color\" [mode]=\"progressBarMode$ | async\">\n </mat-progress-bar>\n</ion-header>\n",
8446
+ template: "<ion-header [class]=\"class\">\n <ion-toolbar [color]=\"color\">\n\n <ion-buttons slot=\"start\">\n\n <!-- back button -->\n <ion-button class=\"back-button\"\n *ngIf=\"canGoBack\"\n (click)=\"doBackClick($event)\"\n routerDirection=\"back\" >\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n\n <!-- show menu button -->\n <ion-button *ngIf=\"!canGoBack && canShowMenu\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n<!--\n <ion-menu-toggle [hidden]=\"canGoBack || !canShowMenu\">\n </ion-menu-toggle>\n-->\n\n <ng-content select=\"[slot=start]\"></ng-content>\n </ion-buttons>\n\n <ion-title [innerHTML]=\"title\"></ion-title>\n\n <ng-content select=\"ion-title\"></ng-content>\n\n <ng-content select=\"ion-buttons[slot=end]\"></ng-content>\n\n <ion-buttons slot=\"end\" collapse=\"true\">\n\n <ng-content select=\"[slot=end]\"></ng-content>\n\n <!-- search bar -->\n <ion-searchbar #searchbar animated\n type=\"search\"\n *ngIf=\"hasSearch\"\n [class.cdk-visually-hidden]=\"!showSearchBar\"\n show-cancel-button=\"always\"\n (ionChange)=\"onSearch.emit($event)\"\n (ionCancel)=\"toggleSearchBar()\">\n </ion-searchbar>\n\n <!-- search button -->\n <ion-button (click)=\"toggleSearchBar()\"\n *ngIf=\"hasSearch && !showSearchBar\">\n <ion-icon slot=\"icon-only\" name=\"search\"></ion-icon>\n </ion-button>\n\n <!-- close button -->\n <ion-button *ngIf=\"hasClose\"\n (tap)=\"tapClose($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n\n <!-- validate button -->\n <ion-button *ngIf=\"hasValidate\"\n (tap)=\"tapValidate($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"save\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n\n <!-- progress bar -->\n <mat-progress-bar [color]=\"color\" [mode]=\"progressBarMode$ | async\">\n </mat-progress-bar>\n</ion-header>\n",
8433
8447
  providers: [
8434
8448
  { provide: ToolbarToken, useExisting: ToolbarComponent }
8435
8449
  ],
@@ -8438,6 +8452,7 @@ ToolbarComponent.decorators = [
8438
8452
  },] }
8439
8453
  ];
8440
8454
  ToolbarComponent.ctorParameters = () => [
8455
+ { type: ActivatedRoute },
8441
8456
  { type: Router },
8442
8457
  { type: IonRouterOutlet },
8443
8458
  { type: ChangeDetectorRef },
@@ -15680,6 +15695,196 @@ ConfigService.ctorParameters = () => [
15680
15695
  { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [APP_CONFIG_OPTIONS,] }] }
15681
15696
  ];
15682
15697
 
15698
+ class UploadFile extends File {
15699
+ }
15700
+ class FileResponse {
15701
+ constructor(init) {
15702
+ this.type = HttpEventType.Response;
15703
+ this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
15704
+ this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
15705
+ this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
15706
+ }
15707
+ }
15708
+ function isProgressEvent(event) {
15709
+ return event && (event.type === HttpEventType.UploadProgress
15710
+ || event.type === HttpEventType.DownloadProgress);
15711
+ }
15712
+ function isResponseEvent(event) {
15713
+ return event && event.type === HttpEventType.Response;
15714
+ }
15715
+
15716
+ class UploadFilePopover {
15717
+ constructor(popoverController, translate, cd) {
15718
+ this.popoverController = popoverController;
15719
+ this.translate = translate;
15720
+ this.cd = cd;
15721
+ this.uniqueFile = false;
15722
+ this.instantUpload = false;
15723
+ this.importing = false;
15724
+ }
15725
+ get files() {
15726
+ return this.uploader.files;
15727
+ }
15728
+ get disabled() {
15729
+ return this.importing || isEmptyArray(this.files);
15730
+ }
15731
+ get valid() {
15732
+ return isNotEmptyArray(this.files);
15733
+ }
15734
+ onValidate(event) {
15735
+ return __awaiter(this, void 0, void 0, function* () {
15736
+ event === null || event === void 0 ? void 0 : event.stopPropagation();
15737
+ // Avoid multiple call
15738
+ if (this.importing)
15739
+ return;
15740
+ console.debug('[upload-file-popover] Validate form: will upload all files...');
15741
+ try {
15742
+ this.importing = true;
15743
+ this.resetError();
15744
+ try {
15745
+ // Wait processing files finished
15746
+ yield this.uploader.waitIdle();
15747
+ // upload all files
15748
+ yield this.uploader.uploadFiles();
15749
+ const files = (this.uploader.processedFiles || [])
15750
+ .filter(file => !file.deleting); // Remove deleting file (deletion in progress)
15751
+ // Nothing to upload: close popover
15752
+ if (isEmptyArray(files))
15753
+ return this.cancel();
15754
+ // check errors
15755
+ const errors = files.map(file => file.error).filter(isNotNilOrBlank);
15756
+ // If error: stop
15757
+ if (errors.length) {
15758
+ errors.forEach((error) => console.error(error));
15759
+ throw { message: 'FILE.UPLOAD.ERROR' };
15760
+ }
15761
+ // return files
15762
+ yield this.popoverController.dismiss(files);
15763
+ }
15764
+ catch (err) {
15765
+ this.error = (err && err.message) || err;
15766
+ }
15767
+ }
15768
+ finally {
15769
+ this.importing = false;
15770
+ this.cd.markForCheck();
15771
+ }
15772
+ });
15773
+ }
15774
+ cancel() {
15775
+ return this.popoverController.dismiss();
15776
+ }
15777
+ resetError() {
15778
+ if (this.error) {
15779
+ this.error = null;
15780
+ this.cd.markForCheck();
15781
+ }
15782
+ }
15783
+ }
15784
+ UploadFilePopover.decorators = [
15785
+ { type: Component, args: [{
15786
+ selector: 'app-upload-file-popover',
15787
+ template: "\n<ion-content class=\"ion-no-padding\" scrollY=\"false\">\n <div class=\"modal-content\">\n <app-upload-file\n #uploader\n [uploadFn]=\"uploadFn\"\n [deleteFn]=\"deleteFn\"\n [fileExtension]=\"fileExtension\"\n [instantUpload]=\"instantUpload\"\n [uniqueFile]=\"uniqueFile\"\n [maxParallelUpload]=\"maxParallelUpload\"\n ></app-upload-file>\n </div>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <div *ngIf=\"importing\" class=\"importing-info\">\n <ion-text color=\"medium\"><small translate>FILE.UPLOAD.IMPORTING</small></ion-text>\n &nbsp;<ion-spinner name=\"dots\" color=\"accent\"></ion-spinner>\n </div>\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=\"ion-text-wrap\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n </ion-col>\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n <ion-button\n [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onValidate($event)\"\n (keyup.enter)=\"onValidate($event)\"\n color=\"tertiary\"\n [disabled]=\"disabled\"\n >\n <ion-label translate>COMMON.BTN_IMPORT</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n",
15788
+ encapsulation: ViewEncapsulation.None,
15789
+ changeDetection: ChangeDetectionStrategy.OnPush,
15790
+ styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
15791
+ },] }
15792
+ ];
15793
+ UploadFilePopover.ctorParameters = () => [
15794
+ { type: PopoverController },
15795
+ { type: TranslateService },
15796
+ { type: ChangeDetectorRef }
15797
+ ];
15798
+ UploadFilePopover.propDecorators = {
15799
+ uploader: [{ type: ViewChild, args: ['uploader', { static: true },] }],
15800
+ fileExtension: [{ type: Input }],
15801
+ title: [{ type: Input }],
15802
+ uniqueFile: [{ type: Input }],
15803
+ instantUpload: [{ type: Input }],
15804
+ uploadFn: [{ type: Input }],
15805
+ deleteFn: [{ type: Input }],
15806
+ maxParallelUpload: [{ type: Input }]
15807
+ };
15808
+
15809
+ const MimeTypes = Object.freeze({
15810
+ ANDROID_APK: 'application/vnd.android.package-archive'
15811
+ });
15812
+ class FilesUtils {
15813
+ static showUploadPopover(popoverController, event, opts) {
15814
+ return __awaiter(this, void 0, void 0, function* () {
15815
+ const modal = yield popoverController.create({
15816
+ component: UploadFilePopover,
15817
+ componentProps: opts,
15818
+ backdropDismiss: false,
15819
+ keyboardClose: false,
15820
+ event,
15821
+ translucent: true,
15822
+ cssClass: 'popover-large',
15823
+ });
15824
+ yield modal.present();
15825
+ const { data, role } = yield modal.onDidDismiss();
15826
+ return {
15827
+ role,
15828
+ data: data ? data : undefined
15829
+ };
15830
+ });
15831
+ }
15832
+ static readAsText(file, encoding) {
15833
+ const $progress = new Subject();
15834
+ const reader = new FileReader();
15835
+ encoding = (encoding || 'UTF-8').toLowerCase();
15836
+ // Listen progress
15837
+ reader.onprogress = (e) => {
15838
+ const total = e.total || 1;
15839
+ const loaded = e.total || 0;
15840
+ if (loaded < total)
15841
+ $progress.next({ type: HttpEventType.UploadProgress, loaded, total });
15842
+ };
15843
+ // Listen end
15844
+ reader.onloadend = (e) => {
15845
+ const body = reader.result;
15846
+ if (typeof body === 'string') {
15847
+ $progress.next(new FileResponse({ body }));
15848
+ $progress.complete();
15849
+ }
15850
+ else {
15851
+ console.error(`Cannot read file '${file.name}' as text`);
15852
+ $progress.error(`Cannot read file as text`);
15853
+ }
15854
+ };
15855
+ // Listen error
15856
+ reader.onerror = (event) => {
15857
+ console.error('[files] Error while reading file:', event);
15858
+ $progress.error(event);
15859
+ };
15860
+ // Start reading the file
15861
+ reader.readAsText(file, encoding);
15862
+ return $progress.asObservable();
15863
+ }
15864
+ }
15865
+ class UriUtils {
15866
+ /**
15867
+ * Extract the filename, from an uri (using the last slash)
15868
+ * @param uri
15869
+ */
15870
+ static getFilename(uri) {
15871
+ if (!uri)
15872
+ return uri;
15873
+ let filename = uri.trim();
15874
+ // Get last part (or all string, if no '/')
15875
+ const lastSlashIndex = filename.lastIndexOf('/');
15876
+ if (lastSlashIndex !== -1 && lastSlashIndex !== uri.length - 1) {
15877
+ filename = filename.substring(lastSlashIndex + 1);
15878
+ }
15879
+ // Remove query params
15880
+ const queryParamIndex = filename.indexOf('?');
15881
+ if (queryParamIndex !== -1) {
15882
+ filename = filename.substring(0, queryParamIndex);
15883
+ }
15884
+ return filename;
15885
+ }
15886
+ }
15887
+
15683
15888
  const moment$4 = momentImported;
15684
15889
  const AndroidOsEnvironment = Object.freeze({
15685
15890
  DIRECTORY_DOWNLOADS: 'Download',
@@ -15840,34 +16045,48 @@ class PlatformService extends StartableService {
15840
16045
  return this._downloadingJobs.get(uri);
15841
16046
  }
15842
16047
  download(request) {
16048
+ var _a, _b;
15843
16049
  if (!request || !request.uri)
15844
16050
  throw new Error('Missing argument \'request\' or \'request.uri\'');
15845
16051
  if (this._android && this.downloader) {
15846
16052
  // Check if not already downloading file
15847
- let location$ = this._downloadingJobs.get(request.uri);
15848
- if (location$)
15849
- return location$;
15850
- request = Object.assign(Object.assign({ visibleInDownloadsUi: true, notificationVisibility: NotificationVisibility.VisibleNotifyCompleted, title: request.title || request.filename }, request), { destinationInExternalPublicDir: Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS, subPath: request.filename || request.title || '' }, request.destinationInExternalPublicDir) });
15851
- console.debug('[platform] Downloading, using request: ' + JSON.stringify(request));
16053
+ let job$ = this._downloadingJobs.get(request.uri);
16054
+ if (job$)
16055
+ return job$;
16056
+ // Compute subPath (final filename)
16057
+ let subPath = ((_a = request.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.subPath) || ((_b = request.destinationInExternalFilesDir) === null || _b === void 0 ? void 0 : _b.subPath)
16058
+ || request.filename || UriUtils.getFilename(request.uri)
16059
+ || request.title || 'download';
16060
+ subPath = subPath.toLowerCase()
16061
+ // Remove spaces
16062
+ .replace(/\s+/g, '-');
16063
+ // Force APK to finish with '.apk'
16064
+ if (request.mimeType === MimeTypes.ANDROID_APK && !subPath.toLowerCase().endsWith('.apk')) {
16065
+ subPath += '.apk';
16066
+ }
16067
+ const downloadRequest = Object.assign(Object.assign({ visibleInDownloadsUi: true, notificationVisibility: NotificationVisibility.VisibleNotifyCompleted }, request), { filename: undefined, destinationInExternalPublicDir: !request.destinationInExternalFilesDir
16068
+ ? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalPublicDir), { subPath }) : undefined, destinationInExternalFilesDir: request.destinationInExternalFilesDir
16069
+ ? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalFilesDir), { subPath }) : undefined });
15852
16070
  // Start download
15853
- location$ = from(this.downloader.download(request));
16071
+ console.debug('[platform] Downloading, using request: ' + JSON.stringify(downloadRequest));
16072
+ job$ = from(this.downloader.download(downloadRequest));
15854
16073
  // Remember this request uri
15855
- this._downloadingJobs.set(request.uri, location$);
15856
- return location$
16074
+ this._downloadingJobs.set(downloadRequest.uri, job$);
16075
+ return job$
15857
16076
  .pipe(tap(location => {
15858
16077
  console.info('[platform] File successfully downloaded at:' + location);
15859
- // Forget the request
15860
- this._downloadingJobs.delete(request.uri);
16078
+ // Forget job
16079
+ this._downloadingJobs.delete(downloadRequest.uri);
15861
16080
  return location;
15862
16081
  }), catchError(err => {
15863
16082
  var _a;
15864
16083
  console.error('[platform] Unable to download: ' + (err && err.message || err));
15865
16084
  // Forget the request
15866
- this._downloadingJobs.delete(request.uri);
16085
+ this._downloadingJobs.delete(downloadRequest.uri);
15867
16086
  // Retry with another location - issue in older Android version
15868
- if (((_a = request.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.dirType) === AndroidOsEnvironment.DIRECTORY_DOWNLOADS) {
15869
- request.destinationInExternalPublicDir.dirType = AndroidOsEnvironment.DIRECTORY_DOWNLOADS_OLD;
15870
- return this.download(request);
16087
+ if (((_a = downloadRequest.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.dirType) === AndroidOsEnvironment.DIRECTORY_DOWNLOADS) {
16088
+ downloadRequest.destinationInExternalPublicDir.dirType = AndroidOsEnvironment.DIRECTORY_DOWNLOADS_OLD;
16089
+ return this.download(downloadRequest);
15871
16090
  }
15872
16091
  throw err;
15873
16092
  }));
@@ -16219,24 +16438,6 @@ MatStepperI18n.ctorParameters = () => [
16219
16438
  { type: TranslateService }
16220
16439
  ];
16221
16440
 
16222
- class UploadFile extends File {
16223
- }
16224
- class FileResponse {
16225
- constructor(init) {
16226
- this.type = HttpEventType.Response;
16227
- this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
16228
- this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
16229
- this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
16230
- }
16231
- }
16232
- function isProgressEvent(event) {
16233
- return event && (event.type === HttpEventType.UploadProgress
16234
- || event.type === HttpEventType.DownloadProgress);
16235
- }
16236
- function isResponseEvent(event) {
16237
- return event && event.type === HttpEventType.Response;
16238
- }
16239
-
16240
16441
  class UploadFileComponent {
16241
16442
  constructor(cd, translate) {
16242
16443
  this.cd = cd;
@@ -16431,99 +16632,6 @@ UploadFileComponent.propDecorators = {
16431
16632
  maxParallelUpload: [{ type: Input }]
16432
16633
  };
16433
16634
 
16434
- class UploadFilePopover {
16435
- constructor(popoverController, translate, cd) {
16436
- this.popoverController = popoverController;
16437
- this.translate = translate;
16438
- this.cd = cd;
16439
- this.uniqueFile = false;
16440
- this.instantUpload = false;
16441
- this.importing = false;
16442
- }
16443
- get files() {
16444
- return this.uploader.files;
16445
- }
16446
- get disabled() {
16447
- return this.importing || isEmptyArray(this.files);
16448
- }
16449
- get valid() {
16450
- return isNotEmptyArray(this.files);
16451
- }
16452
- onValidate(event) {
16453
- return __awaiter(this, void 0, void 0, function* () {
16454
- event === null || event === void 0 ? void 0 : event.stopPropagation();
16455
- // Avoid multiple call
16456
- if (this.importing)
16457
- return;
16458
- console.debug('[upload-file-popover] Validate form: will upload all files...');
16459
- try {
16460
- this.importing = true;
16461
- this.resetError();
16462
- try {
16463
- // Wait processing files finished
16464
- yield this.uploader.waitIdle();
16465
- // upload all files
16466
- yield this.uploader.uploadFiles();
16467
- const files = (this.uploader.processedFiles || [])
16468
- .filter(file => !file.deleting); // Remove deleting file (deletion in progress)
16469
- // Nothing to upload: close popover
16470
- if (isEmptyArray(files))
16471
- return this.cancel();
16472
- // check errors
16473
- const errors = files.map(file => file.error).filter(isNotNilOrBlank);
16474
- // If error: stop
16475
- if (errors.length) {
16476
- errors.forEach((error) => console.error(error));
16477
- throw { message: 'FILE.UPLOAD.ERROR' };
16478
- }
16479
- // return files
16480
- yield this.popoverController.dismiss(files);
16481
- }
16482
- catch (err) {
16483
- this.error = (err && err.message) || err;
16484
- }
16485
- }
16486
- finally {
16487
- this.importing = false;
16488
- this.cd.markForCheck();
16489
- }
16490
- });
16491
- }
16492
- cancel() {
16493
- return this.popoverController.dismiss();
16494
- }
16495
- resetError() {
16496
- if (this.error) {
16497
- this.error = null;
16498
- this.cd.markForCheck();
16499
- }
16500
- }
16501
- }
16502
- UploadFilePopover.decorators = [
16503
- { type: Component, args: [{
16504
- selector: 'app-upload-file-popover',
16505
- template: "\n<ion-content class=\"ion-no-padding\" scrollY=\"false\">\n <div class=\"modal-content\">\n <app-upload-file\n #uploader\n [uploadFn]=\"uploadFn\"\n [deleteFn]=\"deleteFn\"\n [fileExtension]=\"fileExtension\"\n [instantUpload]=\"instantUpload\"\n [uniqueFile]=\"uniqueFile\"\n [maxParallelUpload]=\"maxParallelUpload\"\n ></app-upload-file>\n </div>\n</ion-content>\n\n<ion-footer>\n <ion-toolbar>\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <div *ngIf=\"importing\" class=\"importing-info\">\n <ion-text color=\"medium\"><small translate>FILE.UPLOAD.IMPORTING</small></ion-text>\n &nbsp;<ion-spinner name=\"dots\" color=\"accent\"></ion-spinner>\n </div>\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=\"ion-text-wrap\" [innerHTML]=\"error | translate\"></ion-label>\n </ion-item>\n </ion-col>\n <ion-col size=\"auto\">\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"cancel()\">\n <ion-label translate>COMMON.BTN_CANCEL</ion-label>\n </ion-button>\n <ion-button\n [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onValidate($event)\"\n (keyup.enter)=\"onValidate($event)\"\n color=\"tertiary\"\n [disabled]=\"disabled\"\n >\n <ion-label translate>COMMON.BTN_IMPORT</ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-toolbar>\n</ion-footer>\n",
16506
- encapsulation: ViewEncapsulation.None,
16507
- changeDetection: ChangeDetectionStrategy.OnPush,
16508
- styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
16509
- },] }
16510
- ];
16511
- UploadFilePopover.ctorParameters = () => [
16512
- { type: PopoverController },
16513
- { type: TranslateService },
16514
- { type: ChangeDetectorRef }
16515
- ];
16516
- UploadFilePopover.propDecorators = {
16517
- uploader: [{ type: ViewChild, args: ['uploader', { static: true },] }],
16518
- fileExtension: [{ type: Input }],
16519
- title: [{ type: Input }],
16520
- uniqueFile: [{ type: Input }],
16521
- instantUpload: [{ type: Input }],
16522
- uploadFn: [{ type: Input }],
16523
- deleteFn: [{ type: Input }],
16524
- maxParallelUpload: [{ type: Input }]
16525
- };
16526
-
16527
16635
  const APP_TESTING_PAGES = new InjectionToken('testingPages');
16528
16636
  class SharedTestsPage {
16529
16637
  constructor(route, router, translate, pages) {
@@ -17859,60 +17967,6 @@ class JobUtils {
17859
17967
  }
17860
17968
  }
17861
17969
 
17862
- class FilesUtils {
17863
- static showUploadPopover(popoverController, event, opts) {
17864
- return __awaiter(this, void 0, void 0, function* () {
17865
- const modal = yield popoverController.create({
17866
- component: UploadFilePopover,
17867
- componentProps: opts,
17868
- backdropDismiss: false,
17869
- keyboardClose: false,
17870
- event,
17871
- translucent: true,
17872
- cssClass: 'popover-large',
17873
- });
17874
- yield modal.present();
17875
- const { data, role } = yield modal.onDidDismiss();
17876
- return {
17877
- role,
17878
- data: data ? data : undefined
17879
- };
17880
- });
17881
- }
17882
- static readAsText(file, encoding) {
17883
- const $progress = new Subject();
17884
- const reader = new FileReader();
17885
- encoding = (encoding || 'UTF-8').toLowerCase();
17886
- // Listen progress
17887
- reader.onprogress = (e) => {
17888
- const total = e.total || 1;
17889
- const loaded = e.total || 0;
17890
- if (loaded < total)
17891
- $progress.next({ type: HttpEventType.UploadProgress, loaded, total });
17892
- };
17893
- // Listen end
17894
- reader.onloadend = (e) => {
17895
- const body = reader.result;
17896
- if (typeof body === 'string') {
17897
- $progress.next(new FileResponse({ body }));
17898
- $progress.complete();
17899
- }
17900
- else {
17901
- console.error(`Cannot read file '${file.name}' as text`);
17902
- $progress.error(`Cannot read file as text`);
17903
- }
17904
- };
17905
- // Listen error
17906
- reader.onerror = (event) => {
17907
- console.error('[files] Error while reading file:', event);
17908
- $progress.error(event);
17909
- };
17910
- // Start reading the file
17911
- reader.readAsText(file, encoding);
17912
- return $progress.asObservable();
17913
- }
17914
- }
17915
-
17916
17970
  /**
17917
17971
  * Define here theme colors
17918
17972
  */
@@ -20141,9 +20195,6 @@ PersonToStringPipe.decorators = [
20141
20195
  { type: Injectable, args: [{ providedIn: 'root' },] }
20142
20196
  ];
20143
20197
 
20144
- const MimeTypes = Object.freeze({
20145
- ANDROID_APK: 'application/vnd.android.package-archive'
20146
- });
20147
20198
  class AppInstallUpgradeCard {
20148
20199
  constructor(modalCtrl, configService, toastController, alertController, translate, cd, platform, network, environment) {
20149
20200
  this.modalCtrl = modalCtrl;
@@ -20156,7 +20207,6 @@ class AppInstallUpgradeCard {
20156
20207
  this.network = network;
20157
20208
  this.environment = environment;
20158
20209
  this._subscription = new Subscription();
20159
- this._showUpdateOfflineFeature = false;
20160
20210
  this.loading = true;
20161
20211
  this.hasDownloader = false;
20162
20212
  this.downloading = false;
@@ -20164,16 +20214,6 @@ class AppInstallUpgradeCard {
20164
20214
  this.showUpgradeWarning = true;
20165
20215
  this.showOfflineWarning = true;
20166
20216
  this.showInstallButton = false;
20167
- this.onUpdateOfflineModeClick = new EventEmitter();
20168
- }
20169
- set showUpdateOfflineFeature(value) {
20170
- if (value === this._showUpdateOfflineFeature)
20171
- return; // Skip
20172
- this._showUpdateOfflineFeature = value;
20173
- this.markForCheck();
20174
- }
20175
- get showUpdateOfflineFeature() {
20176
- return this._showUpdateOfflineFeature;
20177
20217
  }
20178
20218
  ngOnInit() {
20179
20219
  this.offline = this.network.offline;
@@ -20197,7 +20237,6 @@ class AppInstallUpgradeCard {
20197
20237
  ngOnDestroy() {
20198
20238
  this._subscription.unsubscribe();
20199
20239
  this._subscription = null;
20200
- this.onUpdateOfflineModeClick.complete();
20201
20240
  this.installLinks = null;
20202
20241
  this.upgradeLinks = null;
20203
20242
  }
@@ -20348,10 +20387,10 @@ class AppInstallUpgradeCard {
20348
20387
  let title;
20349
20388
  let mimeType;
20350
20389
  // Get file name
20351
- let filename = this.getFilename(url);
20390
+ let filename = UriUtils.getFilename(url);
20352
20391
  let version = minVersion || 'latest';
20353
20392
  // OK, this is a downloadable APK file (e.g. NOT a link to a playstore)
20354
- if (filename === null || filename === void 0 ? void 0 : filename.endsWith('.apk')) {
20393
+ if (filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.apk')) {
20355
20394
  // Define mime type
20356
20395
  mimeType = MimeTypes.ANDROID_APK;
20357
20396
  // Get the file version (if any)
@@ -20362,11 +20401,9 @@ class AppInstallUpgradeCard {
20362
20401
  filename = `${name}-v${version}.apk`.toLowerCase();
20363
20402
  title = `${name} v${version}`;
20364
20403
  }
20365
- else {
20366
- // Replace 'latest' with the app version, if present
20367
- if (filename.indexOf('latest')) {
20368
- filename = filename.replace('latest', version);
20369
- }
20404
+ // Replace 'latest' with the app version, if present in the filename
20405
+ else if (filename.indexOf('latest') && version !== 'latest') {
20406
+ filename = filename.replace('latest', version);
20370
20407
  }
20371
20408
  }
20372
20409
  result.push({ name, url, platform: 'android', version, filename, title, mimeType });
@@ -20378,18 +20415,6 @@ class AppInstallUpgradeCard {
20378
20415
  //}
20379
20416
  return result;
20380
20417
  }
20381
- getFilename(url) {
20382
- if (!url)
20383
- return;
20384
- // Get last part (or all string, if no '/')
20385
- let filename = url.substring(url.lastIndexOf('/') + 1);
20386
- const queryParamIndex = filename.indexOf('?');
20387
- if (queryParamIndex !== -1) {
20388
- // Remove query params
20389
- return filename.substring(0, queryParamIndex);
20390
- }
20391
- return filename;
20392
- }
20393
20418
  listenDownloadJobs() {
20394
20419
  // Listening downloading promise, if exists
20395
20420
  (this.upgradeLinks || []).forEach(link => {
@@ -20487,7 +20512,7 @@ class AppInstallUpgradeCard {
20487
20512
  AppInstallUpgradeCard.decorators = [
20488
20513
  { type: Component, args: [{
20489
20514
  selector: 'app-install-upgrade-card',
20490
- template: "\n\n<!-- Offline mode card-->\n<ion-card *ngIf=\"showOfflineWarning && (!loading && offline || waitingNetwork)\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" *ngIf=\"!waitingNetwork; else waitingNetworkText\">\n <h4>\n <b *ngIf=\"isLogin; else notLogin\" [innerHTML]=\"'NETWORK.INFO.OFFLINE_OR_UNAUTHORIZED'| translate\"></b>\n <ng-template #notLogin>\n <b [innerHTML]=\"'NETWORK.INFO.OFFLINE'| translate\"></b>\n </ng-template>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.OFFLINE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n <ng-template #waitingNetworkText>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"'NETWORK.INFO.RETRY_TO_CONNECT'| translate\"></ion-text>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button *ngIf=\"!waitingNetwork; else waitingSpinner\" color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"tryOnline()\">\n <span translate>NETWORK.BTN_CHECK_ALIVE</span>\n </ion-button>\n\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Upgrade links -->\n<ion-card *ngIf=\"showUpgradeWarning && !loading && !offline && upgradeLinks\"\n color=\"accent\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of upgradeLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3>\n <span *ngIf=\"link.version\" [innerHTML]=\"'INFO.UPDATE_APP_TO_VERSION'| translate: link\"></span>\n <span *ngIf=\"!link.version\" [innerHTML]=\"'INFO.UPDATE_APP'| translate: link\"></span>\n </h3>\n <h4>\n <small *ngIf=\"last\" [innerHTML]=\"'INFO.UPDATE_APP_HELP'|translate\"></small>\n </h4>\n </ion-text>\n </ion-col>\n\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Install links -->\n<ion-card *ngIf=\"showInstallButton && !loading && !offline && installLinks\"\n color=\"secondary\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of installLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3 [innerHTML]=\"'INFO.DOWNLOAD_APP_TITLE'| translate: {name: link.name, platform: getPlatformName(link.platform) }\"></h3>\n <h4><small *ngIf=\"last\" [innerHTML]=\"'INFO.DOWNLOAD_APP_HELP'|translate\"></small></h4>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Update offline feature card-->\n<ion-card *ngIf=\"showUpdateOfflineFeature && !loading && !offline\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h4>\n <b [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE'| translate\"></b>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"onUpdateOfflineModeClick.emit($event)\">\n <span translate>NETWORK.BTN_UPDATE</span>\n </ion-button>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Display a download button, depending on the link URL, and the device platform -->\n<ng-template #downloadButton let-link>\n\n <ng-container *ngIf=\"link.filename; else redirectButton\">\n\n <ng-container *ngIf=\"hasDownloader; else webDownloadButton\">\n <!-- Download using platform -->\n <ion-button (click)=\"download($event, asLink(link))\"\n *ngIf=\"!link.location; else openButton\"\n [disabled]=\"link.downloading\"\n color=\"tertiary\" class=\"ion-float-end\">\n <ion-icon slot=\"start\" *ngIf=\"!link.downloading\" name=\"download\"></ion-icon>\n <ion-spinner slot=\"start\" class=\"ion-no-padding\" *ngIf=\"link.downloading\"></ion-spinner>\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n\n <!-- Open APK button -->\n <ng-template #openButton>\n <ion-button *ngIf=\"link.location\"\n (click)=\"openFile($event, link)\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_INSTALL</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web download button -->\n <ng-template #webDownloadButton>\n <ion-button [download]=\"link.downloadFilename\"\n [href]=\"link.url\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web redirect button -->\n <ng-template #redirectButton>\n <ion-button [href]=\"link.url\" rel=\"external\" color=\"tertiary\" class=\"ion-float-end\" target=\"_blank\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n </ion-button>\n </ng-template>\n</ng-template>\n\n\n<!-- Waiting spinner -->\n<ng-template #waitingSpinner>\n <ion-spinner color=\"light\"></ion-spinner>\n</ng-template>\n",
20515
+ template: "\n\n<!-- Offline mode card-->\n<ion-card *ngIf=\"showOfflineWarning && (!loading && offline || waitingNetwork)\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" *ngIf=\"!waitingNetwork; else waitingNetworkText\">\n <h4>\n <b *ngIf=\"isLogin; else notLogin\" [innerHTML]=\"'NETWORK.INFO.OFFLINE_OR_UNAUTHORIZED'| translate\"></b>\n <ng-template #notLogin>\n <b [innerHTML]=\"'NETWORK.INFO.OFFLINE'| translate\"></b>\n </ng-template>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.OFFLINE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n <ng-template #waitingNetworkText>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"'NETWORK.INFO.RETRY_TO_CONNECT'| translate\"></ion-text>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button *ngIf=\"!waitingNetwork; else waitingSpinner\" color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"tryOnline()\">\n <span translate>NETWORK.BTN_CHECK_ALIVE</span>\n </ion-button>\n\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Upgrade links -->\n<ion-card *ngIf=\"showUpgradeWarning && !loading && !offline && upgradeLinks\"\n color=\"accent\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of upgradeLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3>\n <span *ngIf=\"link.version\" [innerHTML]=\"'INFO.UPDATE_APP_TO_VERSION'| translate: link\"></span>\n <span *ngIf=\"!link.version\" [innerHTML]=\"'INFO.UPDATE_APP'| translate: link\"></span>\n </h3>\n <h4>\n <small *ngIf=\"last\" [innerHTML]=\"'INFO.UPDATE_APP_HELP'|translate\"></small>\n </h4>\n </ion-text>\n </ion-col>\n\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Install links -->\n<ion-card *ngIf=\"showInstallButton && !loading && !offline && installLinks\"\n color=\"secondary\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of installLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3 [innerHTML]=\"'INFO.DOWNLOAD_APP_TITLE'| translate: {name: link.name, platform: getPlatformName(link.platform) }\"></h3>\n <h4><small *ngIf=\"last\" [innerHTML]=\"'INFO.DOWNLOAD_APP_HELP'|translate\"></small></h4>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Display a download button, depending on the link URL, and the device platform -->\n<ng-template #downloadButton let-link>\n\n <ng-container *ngIf=\"link.filename; else redirectButton\">\n\n <ng-container *ngIf=\"hasDownloader; else webDownloadButton\">\n <!-- Download using platform -->\n <ion-button (click)=\"download($event, asLink(link))\"\n *ngIf=\"!link.location; else openButton\"\n [disabled]=\"link.downloading\"\n color=\"tertiary\" class=\"ion-float-end\">\n <ion-icon slot=\"start\" *ngIf=\"!link.downloading\" name=\"download\"></ion-icon>\n <ion-spinner slot=\"start\" class=\"ion-no-padding\" *ngIf=\"link.downloading\"></ion-spinner>\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n\n <!-- Open APK button -->\n <ng-template #openButton>\n <ion-button *ngIf=\"link.location\"\n (click)=\"openFile($event, link)\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_INSTALL</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web download button -->\n <ng-template #webDownloadButton>\n <ion-button [download]=\"link.downloadFilename\"\n [href]=\"link.url\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web redirect button -->\n <ng-template #redirectButton>\n <ion-button [href]=\"link.url\" rel=\"external\" color=\"tertiary\" class=\"ion-float-end\" target=\"_blank\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n </ion-button>\n </ng-template>\n</ng-template>\n\n\n<!-- Waiting spinner -->\n<ng-template #waitingSpinner>\n <ion-spinner color=\"light\"></ion-spinner>\n</ng-template>\n",
20491
20516
  changeDetection: ChangeDetectionStrategy.OnPush,
20492
20517
  animations: [slideUpDownAnimation],
20493
20518
  styles: ["ion-text small{font-size:85%}"]
@@ -20508,9 +20533,7 @@ AppInstallUpgradeCard.propDecorators = {
20508
20533
  isLogin: [{ type: Input }],
20509
20534
  showUpgradeWarning: [{ type: Input }],
20510
20535
  showOfflineWarning: [{ type: Input }],
20511
- showInstallButton: [{ type: Input }],
20512
- showUpdateOfflineFeature: [{ type: Input }],
20513
- onUpdateOfflineModeClick: [{ type: Output }]
20536
+ showInstallButton: [{ type: Input }]
20514
20537
  };
20515
20538
 
20516
20539
  class IsLoginAccountPipe {
@@ -20954,6 +20977,30 @@ AppIconComponent.propDecorators = {
20954
20977
  ref: [{ type: Input }]
20955
20978
  };
20956
20979
 
20980
+ class AppUpdateOfflineModeCard {
20981
+ constructor() {
20982
+ this.onUpdateClick = new EventEmitter();
20983
+ }
20984
+ ngOnDestroy() {
20985
+ this.onUpdateClick.complete();
20986
+ }
20987
+ }
20988
+ AppUpdateOfflineModeCard.decorators = [
20989
+ { type: Component, args: [{
20990
+ selector: 'app-update-offline-mode-card',
20991
+ template: "\n<!-- Update offline feature card-->\n<ion-card color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngIf=\"!progressionValue; else progression\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\" >\n <h4>\n <b [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE'| translate\"></b>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n </ion-col>\n\n <!-- Update button -->\n <ion-col size=\"auto\">\n <ion-button color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"onUpdateClick.emit($event)\">\n <span translate>NETWORK.BTN_UPDATE</span>\n </ion-button>\n </ion-col>\n </ion-row>\n\n <ng-template #progression>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"progressionMessage\"></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-progress-bar [value]=\"progressionValue / 100\"></ion-progress-bar>\n </ion-col>\n </ion-row>\n </ng-template>\n </ion-grid>\n\n\n </ion-card-content>\n</ion-card>\n",
20992
+ changeDetection: ChangeDetectionStrategy.OnPush,
20993
+ animations: [slideUpDownAnimation],
20994
+ styles: ["ion-text small{font-size:85%}"]
20995
+ },] }
20996
+ ];
20997
+ AppUpdateOfflineModeCard.ctorParameters = () => [];
20998
+ AppUpdateOfflineModeCard.propDecorators = {
20999
+ progressionMessage: [{ type: Input }],
21000
+ progressionValue: [{ type: Input }],
21001
+ onUpdateClick: [{ type: Output }]
21002
+ };
21003
+
20957
21004
  class CoreModule {
20958
21005
  static forRoot() {
20959
21006
  console.info('[core] Creating module (root)');
@@ -21000,6 +21047,7 @@ CoreModule.decorators = [
21000
21047
  // Network
21001
21048
  SelectPeerModal,
21002
21049
  AppInstallUpgradeCard,
21050
+ AppUpdateOfflineModeCard,
21003
21051
  // Other components
21004
21052
  TableSelectColumnsComponent,
21005
21053
  ActionsColumnComponent,
@@ -21035,6 +21083,7 @@ CoreModule.decorators = [
21035
21083
  AppPropertiesForm,
21036
21084
  AppListForm,
21037
21085
  AppInstallUpgradeCard,
21086
+ AppUpdateOfflineModeCard,
21038
21087
  DepartmentToStringPipe,
21039
21088
  AppIconComponent,
21040
21089
  TextPopover,
@@ -21877,9 +21926,11 @@ class EntitiesTableDataSource extends TableDataSource {
21877
21926
  console.warn('Cannot fetch more because still editing row');
21878
21927
  return;
21879
21928
  }
21929
+ // Forget the fetchMore function, to avoid multiple call
21930
+ const fetchMoreFn = this._fetchMoreFn;
21931
+ this._fetchMoreFn = null;
21880
21932
  // Fetch next page
21881
- this._fetchMoreFn = null; // Avoid multiple call
21882
- const res = yield this._fetchMoreFn();
21933
+ const res = yield fetchMoreFn();
21883
21934
  // Skip if empty (no more data)
21884
21935
  if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
21885
21936
  return false;
@@ -27502,5 +27553,5 @@ CoreTestingModule.decorators = [
27502
27553
  * Generated bundle index. Do not edit.
27503
27554
  */
27504
27555
 
27505
- export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageService, MessageTypeList, MessageTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UserEvent, UserEventFilter, UserEventFragments, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppIconComponent as ɵi, DateTestPage as ɵj, NumpadTestPage as ɵk, MatBadgeIconTestPage as ɵl, ToastTestingModule as ɵm, ToastTestingPage as ɵn };
27556
+ export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEvent, UserEventFilter, UserEventFragments, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppUpdateOfflineModeCard as ɵi, AppIconComponent as ɵj, DateTestPage as ɵk, NumpadTestPage as ɵl, MatBadgeIconTestPage as ɵm, ToastTestingModule as ɵn, ToastTestingPage as ɵo };
27506
27557
  //# sourceMappingURL=sumaris-net.ngx-components.js.map