@sumaris-net/ngx-components 1.19.2 → 1.19.5-rc1
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.
- package/bundles/sumaris-net.ngx-components.umd.js +457 -376
- package/bundles/sumaris-net.ngx-components.umd.js.map +1 -1
- package/bundles/sumaris-net.ngx-components.umd.min.js +2 -2
- package/bundles/sumaris-net.ngx-components.umd.min.js.map +1 -1
- package/doc/changelog.md +3 -0
- package/esm2015/src/app/core/auth/form/form-auth.js +26 -20
- package/esm2015/src/app/core/form/form.class.js +27 -7
- package/esm2015/src/app/core/install/install-upgrade-card.component.js +7 -23
- package/esm2015/src/app/core/services/platform.service.js +30 -15
- package/esm2015/src/app/core/table/entities-table-datasource.class.js +5 -3
- package/esm2015/src/app/shared/files.js +26 -1
- package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +11 -2
- package/fesm2015/sumaris-net.ngx-components.js +288 -229
- package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
- package/package.json +1 -1
- package/src/app/core/auth/form/form-auth.d.ts +1 -1
- package/src/app/core/form/form.class.d.ts +8 -1
- package/src/app/core/install/install-upgrade-card.component.d.ts +0 -1
- package/src/app/shared/files.d.ts +10 -0
- package/sumaris-net.ngx-components.metadata.json +1 -1
|
@@ -17888,6 +17888,252 @@
|
|
|
17888
17888
|
]; };
|
|
17889
17889
|
var templateObject_1$1, templateObject_2$1, templateObject_3$1, templateObject_4$1, templateObject_5$1;
|
|
17890
17890
|
|
|
17891
|
+
var UploadFile = /** @class */ (function (_super) {
|
|
17892
|
+
__extends(UploadFile, _super);
|
|
17893
|
+
function UploadFile() {
|
|
17894
|
+
return _super !== null && _super.apply(this, arguments) || this;
|
|
17895
|
+
}
|
|
17896
|
+
return UploadFile;
|
|
17897
|
+
}(File));
|
|
17898
|
+
var FileResponse = /** @class */ (function () {
|
|
17899
|
+
function FileResponse(init) {
|
|
17900
|
+
this.type = i2$1.HttpEventType.Response;
|
|
17901
|
+
this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
|
|
17902
|
+
this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
|
|
17903
|
+
this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
|
|
17904
|
+
}
|
|
17905
|
+
return FileResponse;
|
|
17906
|
+
}());
|
|
17907
|
+
function isProgressEvent(event) {
|
|
17908
|
+
return event && (event.type === i2$1.HttpEventType.UploadProgress
|
|
17909
|
+
|| event.type === i2$1.HttpEventType.DownloadProgress);
|
|
17910
|
+
}
|
|
17911
|
+
function isResponseEvent(event) {
|
|
17912
|
+
return event && event.type === i2$1.HttpEventType.Response;
|
|
17913
|
+
}
|
|
17914
|
+
|
|
17915
|
+
var UploadFilePopover = /** @class */ (function () {
|
|
17916
|
+
function UploadFilePopover(popoverController, translate, cd) {
|
|
17917
|
+
this.popoverController = popoverController;
|
|
17918
|
+
this.translate = translate;
|
|
17919
|
+
this.cd = cd;
|
|
17920
|
+
this.uniqueFile = false;
|
|
17921
|
+
this.instantUpload = false;
|
|
17922
|
+
this.importing = false;
|
|
17923
|
+
}
|
|
17924
|
+
Object.defineProperty(UploadFilePopover.prototype, "files", {
|
|
17925
|
+
get: function () {
|
|
17926
|
+
return this.uploader.files;
|
|
17927
|
+
},
|
|
17928
|
+
enumerable: false,
|
|
17929
|
+
configurable: true
|
|
17930
|
+
});
|
|
17931
|
+
Object.defineProperty(UploadFilePopover.prototype, "disabled", {
|
|
17932
|
+
get: function () {
|
|
17933
|
+
return this.importing || isEmptyArray(this.files);
|
|
17934
|
+
},
|
|
17935
|
+
enumerable: false,
|
|
17936
|
+
configurable: true
|
|
17937
|
+
});
|
|
17938
|
+
Object.defineProperty(UploadFilePopover.prototype, "valid", {
|
|
17939
|
+
get: function () {
|
|
17940
|
+
return isNotEmptyArray(this.files);
|
|
17941
|
+
},
|
|
17942
|
+
enumerable: false,
|
|
17943
|
+
configurable: true
|
|
17944
|
+
});
|
|
17945
|
+
UploadFilePopover.prototype.onValidate = function (event) {
|
|
17946
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
17947
|
+
var files, errors, err_1;
|
|
17948
|
+
return __generator(this, function (_a) {
|
|
17949
|
+
switch (_a.label) {
|
|
17950
|
+
case 0:
|
|
17951
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
17952
|
+
// Avoid multiple call
|
|
17953
|
+
if (this.importing)
|
|
17954
|
+
return [2 /*return*/];
|
|
17955
|
+
console.debug('[upload-file-popover] Validate form: will upload all files...');
|
|
17956
|
+
_a.label = 1;
|
|
17957
|
+
case 1:
|
|
17958
|
+
_a.trys.push([1, , 8, 9]);
|
|
17959
|
+
this.importing = true;
|
|
17960
|
+
this.resetError();
|
|
17961
|
+
_a.label = 2;
|
|
17962
|
+
case 2:
|
|
17963
|
+
_a.trys.push([2, 6, , 7]);
|
|
17964
|
+
// Wait processing files finished
|
|
17965
|
+
return [4 /*yield*/, this.uploader.waitIdle()];
|
|
17966
|
+
case 3:
|
|
17967
|
+
// Wait processing files finished
|
|
17968
|
+
_a.sent();
|
|
17969
|
+
// upload all files
|
|
17970
|
+
return [4 /*yield*/, this.uploader.uploadFiles()];
|
|
17971
|
+
case 4:
|
|
17972
|
+
// upload all files
|
|
17973
|
+
_a.sent();
|
|
17974
|
+
files = (this.uploader.processedFiles || [])
|
|
17975
|
+
.filter(function (file) { return !file.deleting; });
|
|
17976
|
+
// Nothing to upload: close popover
|
|
17977
|
+
if (isEmptyArray(files))
|
|
17978
|
+
return [2 /*return*/, this.cancel()];
|
|
17979
|
+
errors = files.map(function (file) { return file.error; }).filter(isNotNilOrBlank);
|
|
17980
|
+
// If error: stop
|
|
17981
|
+
if (errors.length) {
|
|
17982
|
+
errors.forEach(function (error) { return console.error(error); });
|
|
17983
|
+
throw { message: 'FILE.UPLOAD.ERROR' };
|
|
17984
|
+
}
|
|
17985
|
+
// return files
|
|
17986
|
+
return [4 /*yield*/, this.popoverController.dismiss(files)];
|
|
17987
|
+
case 5:
|
|
17988
|
+
// return files
|
|
17989
|
+
_a.sent();
|
|
17990
|
+
return [3 /*break*/, 7];
|
|
17991
|
+
case 6:
|
|
17992
|
+
err_1 = _a.sent();
|
|
17993
|
+
this.error = (err_1 && err_1.message) || err_1;
|
|
17994
|
+
return [3 /*break*/, 7];
|
|
17995
|
+
case 7: return [3 /*break*/, 9];
|
|
17996
|
+
case 8:
|
|
17997
|
+
this.importing = false;
|
|
17998
|
+
this.cd.markForCheck();
|
|
17999
|
+
return [7 /*endfinally*/];
|
|
18000
|
+
case 9: return [2 /*return*/];
|
|
18001
|
+
}
|
|
18002
|
+
});
|
|
18003
|
+
});
|
|
18004
|
+
};
|
|
18005
|
+
UploadFilePopover.prototype.cancel = function () {
|
|
18006
|
+
return this.popoverController.dismiss();
|
|
18007
|
+
};
|
|
18008
|
+
UploadFilePopover.prototype.resetError = function () {
|
|
18009
|
+
if (this.error) {
|
|
18010
|
+
this.error = null;
|
|
18011
|
+
this.cd.markForCheck();
|
|
18012
|
+
}
|
|
18013
|
+
};
|
|
18014
|
+
return UploadFilePopover;
|
|
18015
|
+
}());
|
|
18016
|
+
UploadFilePopover.decorators = [
|
|
18017
|
+
{ type: i0.Component, args: [{
|
|
18018
|
+
selector: 'app-upload-file-popover',
|
|
18019
|
+
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 <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",
|
|
18020
|
+
encapsulation: i0.ViewEncapsulation.None,
|
|
18021
|
+
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
18022
|
+
styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
|
|
18023
|
+
},] }
|
|
18024
|
+
];
|
|
18025
|
+
UploadFilePopover.ctorParameters = function () { return [
|
|
18026
|
+
{ type: i1$5.PopoverController },
|
|
18027
|
+
{ type: i1$2.TranslateService },
|
|
18028
|
+
{ type: i0.ChangeDetectorRef }
|
|
18029
|
+
]; };
|
|
18030
|
+
UploadFilePopover.propDecorators = {
|
|
18031
|
+
uploader: [{ type: i0.ViewChild, args: ['uploader', { static: true },] }],
|
|
18032
|
+
fileExtension: [{ type: i0.Input }],
|
|
18033
|
+
title: [{ type: i0.Input }],
|
|
18034
|
+
uniqueFile: [{ type: i0.Input }],
|
|
18035
|
+
instantUpload: [{ type: i0.Input }],
|
|
18036
|
+
uploadFn: [{ type: i0.Input }],
|
|
18037
|
+
deleteFn: [{ type: i0.Input }],
|
|
18038
|
+
maxParallelUpload: [{ type: i0.Input }]
|
|
18039
|
+
};
|
|
18040
|
+
|
|
18041
|
+
var MimeTypes = Object.freeze({
|
|
18042
|
+
ANDROID_APK: 'application/vnd.android.package-archive'
|
|
18043
|
+
});
|
|
18044
|
+
var FilesUtils = /** @class */ (function () {
|
|
18045
|
+
function FilesUtils() {
|
|
18046
|
+
}
|
|
18047
|
+
FilesUtils.showUploadPopover = function (popoverController, event, opts) {
|
|
18048
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
18049
|
+
var modal, _a, data, role;
|
|
18050
|
+
return __generator(this, function (_b) {
|
|
18051
|
+
switch (_b.label) {
|
|
18052
|
+
case 0: return [4 /*yield*/, popoverController.create({
|
|
18053
|
+
component: UploadFilePopover,
|
|
18054
|
+
componentProps: opts,
|
|
18055
|
+
backdropDismiss: false,
|
|
18056
|
+
keyboardClose: false,
|
|
18057
|
+
event: event,
|
|
18058
|
+
translucent: true,
|
|
18059
|
+
cssClass: 'popover-large',
|
|
18060
|
+
})];
|
|
18061
|
+
case 1:
|
|
18062
|
+
modal = _b.sent();
|
|
18063
|
+
return [4 /*yield*/, modal.present()];
|
|
18064
|
+
case 2:
|
|
18065
|
+
_b.sent();
|
|
18066
|
+
return [4 /*yield*/, modal.onDidDismiss()];
|
|
18067
|
+
case 3:
|
|
18068
|
+
_a = _b.sent(), data = _a.data, role = _a.role;
|
|
18069
|
+
return [2 /*return*/, {
|
|
18070
|
+
role: role,
|
|
18071
|
+
data: data ? data : undefined
|
|
18072
|
+
}];
|
|
18073
|
+
}
|
|
18074
|
+
});
|
|
18075
|
+
});
|
|
18076
|
+
};
|
|
18077
|
+
FilesUtils.readAsText = function (file, encoding) {
|
|
18078
|
+
var $progress = new rxjs.Subject();
|
|
18079
|
+
var reader = new FileReader();
|
|
18080
|
+
encoding = (encoding || 'UTF-8').toLowerCase();
|
|
18081
|
+
// Listen progress
|
|
18082
|
+
reader.onprogress = function (e) {
|
|
18083
|
+
var total = e.total || 1;
|
|
18084
|
+
var loaded = e.total || 0;
|
|
18085
|
+
if (loaded < total)
|
|
18086
|
+
$progress.next({ type: i2$1.HttpEventType.UploadProgress, loaded: loaded, total: total });
|
|
18087
|
+
};
|
|
18088
|
+
// Listen end
|
|
18089
|
+
reader.onloadend = function (e) {
|
|
18090
|
+
var body = reader.result;
|
|
18091
|
+
if (typeof body === 'string') {
|
|
18092
|
+
$progress.next(new FileResponse({ body: body }));
|
|
18093
|
+
$progress.complete();
|
|
18094
|
+
}
|
|
18095
|
+
else {
|
|
18096
|
+
console.error("Cannot read file '" + file.name + "' as text");
|
|
18097
|
+
$progress.error("Cannot read file as text");
|
|
18098
|
+
}
|
|
18099
|
+
};
|
|
18100
|
+
// Listen error
|
|
18101
|
+
reader.onerror = function (event) {
|
|
18102
|
+
console.error('[files] Error while reading file:', event);
|
|
18103
|
+
$progress.error(event);
|
|
18104
|
+
};
|
|
18105
|
+
// Start reading the file
|
|
18106
|
+
reader.readAsText(file, encoding);
|
|
18107
|
+
return $progress.asObservable();
|
|
18108
|
+
};
|
|
18109
|
+
return FilesUtils;
|
|
18110
|
+
}());
|
|
18111
|
+
var UriUtils = /** @class */ (function () {
|
|
18112
|
+
function UriUtils() {
|
|
18113
|
+
}
|
|
18114
|
+
/**
|
|
18115
|
+
* Extract the filename, from an uri (using the last slash)
|
|
18116
|
+
* @param uri
|
|
18117
|
+
*/
|
|
18118
|
+
UriUtils.getFilename = function (uri) {
|
|
18119
|
+
if (!uri)
|
|
18120
|
+
return uri;
|
|
18121
|
+
var filename = uri.trim();
|
|
18122
|
+
// Get last part (or all string, if no '/')
|
|
18123
|
+
var lastSlashIndex = filename.lastIndexOf('/');
|
|
18124
|
+
if (lastSlashIndex !== -1 && lastSlashIndex !== uri.length - 1) {
|
|
18125
|
+
filename = filename.substring(lastSlashIndex + 1);
|
|
18126
|
+
}
|
|
18127
|
+
// Remove query params
|
|
18128
|
+
var queryParamIndex = filename.indexOf('?');
|
|
18129
|
+
if (queryParamIndex !== -1) {
|
|
18130
|
+
filename = filename.substring(0, queryParamIndex);
|
|
18131
|
+
}
|
|
18132
|
+
return filename;
|
|
18133
|
+
};
|
|
18134
|
+
return UriUtils;
|
|
18135
|
+
}());
|
|
18136
|
+
|
|
17891
18137
|
var moment$4 = momentImported__namespace;
|
|
17892
18138
|
var AndroidOsEnvironment = Object.freeze({
|
|
17893
18139
|
DIRECTORY_DOWNLOADS: 'Download',
|
|
@@ -18083,34 +18329,48 @@
|
|
|
18083
18329
|
};
|
|
18084
18330
|
PlatformService.prototype.download = function (request) {
|
|
18085
18331
|
var _this = this;
|
|
18332
|
+
var _a, _b;
|
|
18086
18333
|
if (!request || !request.uri)
|
|
18087
18334
|
throw new Error('Missing argument \'request\' or \'request.uri\'');
|
|
18088
18335
|
if (this._android && this.downloader) {
|
|
18089
18336
|
// Check if not already downloading file
|
|
18090
|
-
var
|
|
18091
|
-
if (
|
|
18092
|
-
return
|
|
18093
|
-
|
|
18094
|
-
|
|
18337
|
+
var job$ = this._downloadingJobs.get(request.uri);
|
|
18338
|
+
if (job$)
|
|
18339
|
+
return job$;
|
|
18340
|
+
// Compute subPath (final filename)
|
|
18341
|
+
var subPath = ((_a = request.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.subPath) || ((_b = request.destinationInExternalFilesDir) === null || _b === void 0 ? void 0 : _b.subPath)
|
|
18342
|
+
|| request.filename || UriUtils.getFilename(request.uri)
|
|
18343
|
+
|| request.title || 'download';
|
|
18344
|
+
subPath = subPath.toLowerCase()
|
|
18345
|
+
// Remove spaces
|
|
18346
|
+
.replace(/\s+/g, '-');
|
|
18347
|
+
// Force APK to finish with '.apk'
|
|
18348
|
+
if (request.mimeType === MimeTypes.ANDROID_APK && !subPath.toLowerCase().endsWith('.apk')) {
|
|
18349
|
+
subPath += '.apk';
|
|
18350
|
+
}
|
|
18351
|
+
var downloadRequest_1 = Object.assign(Object.assign({ visibleInDownloadsUi: true, notificationVisibility: ngx$6.NotificationVisibility.VisibleNotifyCompleted }, request), { filename: undefined, destinationInExternalPublicDir: !request.destinationInExternalFilesDir
|
|
18352
|
+
? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalPublicDir), { subPath: subPath }) : undefined, destinationInExternalFilesDir: request.destinationInExternalFilesDir
|
|
18353
|
+
? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalFilesDir), { subPath: subPath }) : undefined });
|
|
18095
18354
|
// Start download
|
|
18096
|
-
|
|
18355
|
+
console.debug('[platform] Downloading, using request: ' + JSON.stringify(downloadRequest_1));
|
|
18356
|
+
job$ = rxjs.from(this.downloader.download(downloadRequest_1));
|
|
18097
18357
|
// Remember this request uri
|
|
18098
|
-
this._downloadingJobs.set(
|
|
18099
|
-
return
|
|
18358
|
+
this._downloadingJobs.set(downloadRequest_1.uri, job$);
|
|
18359
|
+
return job$
|
|
18100
18360
|
.pipe(operators.tap(function (location) {
|
|
18101
18361
|
console.info('[platform] File successfully downloaded at:' + location);
|
|
18102
|
-
// Forget
|
|
18103
|
-
_this._downloadingJobs.delete(
|
|
18362
|
+
// Forget job
|
|
18363
|
+
_this._downloadingJobs.delete(downloadRequest_1.uri);
|
|
18104
18364
|
return location;
|
|
18105
18365
|
}), operators.catchError(function (err) {
|
|
18106
18366
|
var _a;
|
|
18107
18367
|
console.error('[platform] Unable to download: ' + (err && err.message || err));
|
|
18108
18368
|
// Forget the request
|
|
18109
|
-
_this._downloadingJobs.delete(
|
|
18369
|
+
_this._downloadingJobs.delete(downloadRequest_1.uri);
|
|
18110
18370
|
// Retry with another location - issue in older Android version
|
|
18111
|
-
if (((_a =
|
|
18112
|
-
|
|
18113
|
-
return _this.download(
|
|
18371
|
+
if (((_a = downloadRequest_1.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.dirType) === AndroidOsEnvironment.DIRECTORY_DOWNLOADS) {
|
|
18372
|
+
downloadRequest_1.destinationInExternalPublicDir.dirType = AndroidOsEnvironment.DIRECTORY_DOWNLOADS_OLD;
|
|
18373
|
+
return _this.download(downloadRequest_1);
|
|
18114
18374
|
}
|
|
18115
18375
|
throw err;
|
|
18116
18376
|
}));
|
|
@@ -18526,30 +18786,6 @@
|
|
|
18526
18786
|
{ type: i1$2.TranslateService }
|
|
18527
18787
|
]; };
|
|
18528
18788
|
|
|
18529
|
-
var UploadFile = /** @class */ (function (_super) {
|
|
18530
|
-
__extends(UploadFile, _super);
|
|
18531
|
-
function UploadFile() {
|
|
18532
|
-
return _super !== null && _super.apply(this, arguments) || this;
|
|
18533
|
-
}
|
|
18534
|
-
return UploadFile;
|
|
18535
|
-
}(File));
|
|
18536
|
-
var FileResponse = /** @class */ (function () {
|
|
18537
|
-
function FileResponse(init) {
|
|
18538
|
-
this.type = i2$1.HttpEventType.Response;
|
|
18539
|
-
this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
|
|
18540
|
-
this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
|
|
18541
|
-
this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
|
|
18542
|
-
}
|
|
18543
|
-
return FileResponse;
|
|
18544
|
-
}());
|
|
18545
|
-
function isProgressEvent(event) {
|
|
18546
|
-
return event && (event.type === i2$1.HttpEventType.UploadProgress
|
|
18547
|
-
|| event.type === i2$1.HttpEventType.DownloadProgress);
|
|
18548
|
-
}
|
|
18549
|
-
function isResponseEvent(event) {
|
|
18550
|
-
return event && event.type === i2$1.HttpEventType.Response;
|
|
18551
|
-
}
|
|
18552
|
-
|
|
18553
18789
|
var UploadFileComponent = /** @class */ (function () {
|
|
18554
18790
|
function UploadFileComponent(cd, translate) {
|
|
18555
18791
|
this.cd = cd;
|
|
@@ -18668,235 +18904,109 @@
|
|
|
18668
18904
|
// Start upload
|
|
18669
18905
|
if (this.instantUpload) {
|
|
18670
18906
|
this.uploadFiles(items);
|
|
18671
|
-
}
|
|
18672
|
-
};
|
|
18673
|
-
/**
|
|
18674
|
-
* Execute upload
|
|
18675
|
-
*/
|
|
18676
|
-
UploadFileComponent.prototype.uploadFiles = function (files) {
|
|
18677
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
18678
|
-
var $processingFileCountChange, $changes, jobs;
|
|
18679
|
-
var _this = this;
|
|
18680
|
-
return __generator(this, function (_b) {
|
|
18681
|
-
if (!files) {
|
|
18682
|
-
console.info('[upload-file] Uploading all files...');
|
|
18683
|
-
files = this.files;
|
|
18684
|
-
}
|
|
18685
|
-
$processingFileCountChange = new rxjs.BehaviorSubject(this.processingFilesCount);
|
|
18686
|
-
$changes = new rxjs.Subject();
|
|
18687
|
-
$changes.subscribe(function (_) {
|
|
18688
|
-
_this.cd.markForCheck();
|
|
18689
|
-
$processingFileCountChange.next(_this.processingFilesCount);
|
|
18690
|
-
});
|
|
18691
|
-
jobs = files
|
|
18692
|
-
.map(function (f) { return f; })
|
|
18693
|
-
.filter(function (file) { return file && isNil(file.progress) && !file.error; }) // Skip if already started or in error
|
|
18694
|
-
.map(function (file, i) {
|
|
18695
|
-
// Wait if need
|
|
18696
|
-
if (isNotNil(_this.maxParallelUpload)) {
|
|
18697
|
-
return $processingFileCountChange.pipe(operators.debounceTime(i), // call of filter() must be different for waiting job
|
|
18698
|
-
operators.filter(function (count) { return count < _this.maxParallelUpload; }), operators.map(function (_) {
|
|
18699
|
-
// Start uploading
|
|
18700
|
-
if (isNil(file.progress))
|
|
18701
|
-
file.progress = 0;
|
|
18702
|
-
$changes.next();
|
|
18703
|
-
return file;
|
|
18704
|
-
}), operators.first());
|
|
18705
|
-
}
|
|
18706
|
-
// Start uploading
|
|
18707
|
-
if (isNil(file.progress))
|
|
18708
|
-
file.progress = 0;
|
|
18709
|
-
return rxjs.of(file);
|
|
18710
|
-
})
|
|
18711
|
-
.map(function (file$) { return file$.pipe(operators.filter(isNotNil),
|
|
18712
|
-
// Log
|
|
18713
|
-
operators.tap(function (file) { return console.debug("[upload-file] " + file.name + ": uploading..."); }),
|
|
18714
|
-
// Start uploading
|
|
18715
|
-
operators.switchMap(function (file) { return _this.uploadFn(file)
|
|
18716
|
-
.pipe(operators.filter(isNotNil), operators.map(function (event) {
|
|
18717
|
-
// Progress event
|
|
18718
|
-
if (isProgressEvent(event)) {
|
|
18719
|
-
if (isNotNil(event.loaded) && event.loaded >= 0) {
|
|
18720
|
-
file.progress = Math.min(1, event.loaded / (event.total || 1));
|
|
18721
|
-
}
|
|
18722
|
-
else {
|
|
18723
|
-
file.progress = -1; // Indeterminate progression
|
|
18724
|
-
}
|
|
18725
|
-
}
|
|
18726
|
-
// Response event
|
|
18727
|
-
else if (isResponseEvent(event)) {
|
|
18728
|
-
file.progress = 1;
|
|
18729
|
-
file.response = event;
|
|
18730
|
-
console.debug("[upload-file] " + file.name + ": " + (event.statusText || 'OK'), file.response);
|
|
18731
|
-
}
|
|
18732
|
-
// Other events: ignore
|
|
18733
|
-
else {
|
|
18734
|
-
// DEBUG
|
|
18735
|
-
console.debug('[upload-file] Ignoring a file event: ', event);
|
|
18736
|
-
}
|
|
18737
|
-
return file;
|
|
18738
|
-
}), operators.catchError(function (err) {
|
|
18739
|
-
var _a;
|
|
18740
|
-
console.error(err);
|
|
18741
|
-
file.error = err && (err.message || ((_a = err.error) === null || _a === void 0 ? void 0 : _a.message)) || 'FILE.UPLOAD.ERROR';
|
|
18742
|
-
return rxjs.of(file);
|
|
18743
|
-
}), operators.tap(function () {
|
|
18744
|
-
$changes.next();
|
|
18745
|
-
_this.cd.markForCheck();
|
|
18746
|
-
})); })); });
|
|
18747
|
-
// Wait jobs to finish
|
|
18748
|
-
return [2 /*return*/, rxjs.forkJoin(jobs)
|
|
18749
|
-
.pipe(operators.tap(function (_) { return $changes.complete(); }))
|
|
18750
|
-
.toPromise()];
|
|
18751
|
-
});
|
|
18752
|
-
});
|
|
18753
|
-
};
|
|
18754
|
-
UploadFileComponent.prototype.waitIdle = function (opts) {
|
|
18755
|
-
var _this = this;
|
|
18756
|
-
return waitFor(function () { return _this.processingFilesCount === 0; }, opts);
|
|
18757
|
-
};
|
|
18758
|
-
return UploadFileComponent;
|
|
18759
|
-
}());
|
|
18760
|
-
UploadFileComponent.decorators = [
|
|
18761
|
-
{ type: i0.Component, args: [{
|
|
18762
|
-
selector: 'app-upload-file',
|
|
18763
|
-
template: "<div *ngIf=\"!uniqueFile || files.length === 0\"\n class=\"container\"\n appDragAndDrop (fileDropped)=\"onFileDropped($event)\">\n <input\n type=\"file\"\n #fileDropRef\n id=\"fileDropRef\"\n multiple\n [accept]=\"fileExtension\"\n (change)=\"fileBrowseHandler($any($event.target).files)\"\n />\n <mat-icon style=\"font-size: xx-large\" color=\"accent\">file_upload</mat-icon>\n <ion-label\n [innerHTML]=\"\n 'FILE.UPLOAD.DRAG_AND_DROP' | translate: { extension: !fileExtension ? '' : ' (' + fileExtension + ')' }\n \"\n ></ion-label>\n <ion-button>{{ 'FILE.UPLOAD.BROWSE' | translate }}</ion-button>\n</div>\n<div class=\"files-list\">\n <div *ngFor=\"let file of files; index as i\"\n class=\"single-file\"\n [class.deleting]=\"file.deleting\">\n <mat-icon>description</mat-icon>\n <div class=\"info\">\n <h4 class=\"name\">\n {{ file.name }}\n </h4>\n <p class=\"size\">\n {{ file.size | fileSize }}\n </p>\n <ion-progress-bar *ngIf=\"!file.error\"\n [value]=\"file.progress||0\"\n [type]=\"(file.deleting || file.progress === -1) ? 'indeterminate' : 'determinate'\"></ion-progress-bar>\n <ion-label *ngIf=\"file.error\" color=\"danger\" [innerHTML]=\"file.error | translate\"></ion-label>\n </div>\n <!-- remote from list (before importation) -->\n <button *ngIf=\"!(file.progress) || file.error\" mat-icon-button (click)=\"deleteFile(i)\">\n <mat-icon>clear</mat-icon>\n </button>\n <!-- delete file (remotely - after importation) -->\n <button *ngIf=\"file.progress === 1 && !!deleteFn && !file.deleting\" mat-icon-button (click)=\"deleteFile(i)\">\n <mat-icon>clear</mat-icon>\n </button>\n </div>\n</div>\n",
|
|
18764
|
-
styles: [".container{width:calc(100% - 3rem);min-height:200px;padding:2rem;text-align:center;border:1px dashed #979797;position:relative;margin:1.5rem}.container input{opacity:0;position:absolute;z-index:2;width:100%;height:100%;top:0;left:0;cursor:pointer}.container ion-label{display:block;font-size:20px;font-weight:600;color:#38424c}.container label{display:inline-block;color:#fff;width:183px;height:44px;border-radius:21.5px;background-color:#db202f;padding:8px 16px}.fileover{-webkit-animation:shake 1s;animation:shake 1s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.files-list{max-height:300px;overflow:auto}.files-list .single-file{display:flex;flex-grow:1;padding:.5rem;justify-content:space-between;align-items:center;border:1px dashed #979797;margin-bottom:1rem}.files-list .single-file.deleting .name{color:grey!important;font-style:italic!important}.files-list .single-file .name{font-size:14px;font-weight:500;color:#353f4a;margin:0}.files-list .single-file .size{font-size:12px;font-weight:500;color:#a4a4a4;margin:0 0 .25rem}.files-list .single-file .info{width:100%}@-webkit-keyframes shake{0%{transform:translate(1px,1px) rotate(0deg)}10%{transform:translate(-1px,-2px) rotate(-1deg)}20%{transform:translate(-3px) rotate(1deg)}30%{transform:translate(3px,2px) rotate(0deg)}40%{transform:translate(1px,-1px) rotate(1deg)}50%{transform:translate(-1px,2px) rotate(-1deg)}60%{transform:translate(-3px,1px) rotate(0deg)}70%{transform:translate(3px,1px) rotate(-1deg)}80%{transform:translate(-1px,-1px) rotate(1deg)}90%{transform:translate(1px,2px) rotate(0deg)}to{transform:translate(1px,-2px) rotate(-1deg)}}@keyframes shake{0%{transform:translate(1px,1px) rotate(0deg)}10%{transform:translate(-1px,-2px) rotate(-1deg)}20%{transform:translate(-3px) rotate(1deg)}30%{transform:translate(3px,2px) rotate(0deg)}40%{transform:translate(1px,-1px) rotate(1deg)}50%{transform:translate(-1px,2px) rotate(-1deg)}60%{transform:translate(-3px,1px) rotate(0deg)}70%{transform:translate(3px,1px) rotate(-1deg)}80%{transform:translate(-1px,-1px) rotate(1deg)}90%{transform:translate(1px,2px) rotate(0deg)}to{transform:translate(1px,-2px) rotate(-1deg)}}"]
|
|
18765
|
-
},] }
|
|
18766
|
-
];
|
|
18767
|
-
UploadFileComponent.ctorParameters = function () { return [
|
|
18768
|
-
{ type: i0.ChangeDetectorRef },
|
|
18769
|
-
{ type: i1$2.TranslateService }
|
|
18770
|
-
]; };
|
|
18771
|
-
UploadFileComponent.propDecorators = {
|
|
18772
|
-
fileDropEl: [{ type: i0.ViewChild, args: ['fileDropRef', { static: false },] }],
|
|
18773
|
-
fileExtension: [{ type: i0.Input }],
|
|
18774
|
-
uniqueFile: [{ type: i0.Input }],
|
|
18775
|
-
instantUpload: [{ type: i0.Input }],
|
|
18776
|
-
uploadFn: [{ type: i0.Input }],
|
|
18777
|
-
deleteFn: [{ type: i0.Input }],
|
|
18778
|
-
maxParallelUpload: [{ type: i0.Input }]
|
|
18779
|
-
};
|
|
18780
|
-
|
|
18781
|
-
var UploadFilePopover = /** @class */ (function () {
|
|
18782
|
-
function UploadFilePopover(popoverController, translate, cd) {
|
|
18783
|
-
this.popoverController = popoverController;
|
|
18784
|
-
this.translate = translate;
|
|
18785
|
-
this.cd = cd;
|
|
18786
|
-
this.uniqueFile = false;
|
|
18787
|
-
this.instantUpload = false;
|
|
18788
|
-
this.importing = false;
|
|
18789
|
-
}
|
|
18790
|
-
Object.defineProperty(UploadFilePopover.prototype, "files", {
|
|
18791
|
-
get: function () {
|
|
18792
|
-
return this.uploader.files;
|
|
18793
|
-
},
|
|
18794
|
-
enumerable: false,
|
|
18795
|
-
configurable: true
|
|
18796
|
-
});
|
|
18797
|
-
Object.defineProperty(UploadFilePopover.prototype, "disabled", {
|
|
18798
|
-
get: function () {
|
|
18799
|
-
return this.importing || isEmptyArray(this.files);
|
|
18800
|
-
},
|
|
18801
|
-
enumerable: false,
|
|
18802
|
-
configurable: true
|
|
18803
|
-
});
|
|
18804
|
-
Object.defineProperty(UploadFilePopover.prototype, "valid", {
|
|
18805
|
-
get: function () {
|
|
18806
|
-
return isNotEmptyArray(this.files);
|
|
18807
|
-
},
|
|
18808
|
-
enumerable: false,
|
|
18809
|
-
configurable: true
|
|
18810
|
-
});
|
|
18811
|
-
UploadFilePopover.prototype.onValidate = function (event) {
|
|
18812
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
18813
|
-
var files, errors, err_1;
|
|
18814
|
-
return __generator(this, function (_a) {
|
|
18815
|
-
switch (_a.label) {
|
|
18816
|
-
case 0:
|
|
18817
|
-
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
18818
|
-
// Avoid multiple call
|
|
18819
|
-
if (this.importing)
|
|
18820
|
-
return [2 /*return*/];
|
|
18821
|
-
console.debug('[upload-file-popover] Validate form: will upload all files...');
|
|
18822
|
-
_a.label = 1;
|
|
18823
|
-
case 1:
|
|
18824
|
-
_a.trys.push([1, , 8, 9]);
|
|
18825
|
-
this.importing = true;
|
|
18826
|
-
this.resetError();
|
|
18827
|
-
_a.label = 2;
|
|
18828
|
-
case 2:
|
|
18829
|
-
_a.trys.push([2, 6, , 7]);
|
|
18830
|
-
// Wait processing files finished
|
|
18831
|
-
return [4 /*yield*/, this.uploader.waitIdle()];
|
|
18832
|
-
case 3:
|
|
18833
|
-
// Wait processing files finished
|
|
18834
|
-
_a.sent();
|
|
18835
|
-
// upload all files
|
|
18836
|
-
return [4 /*yield*/, this.uploader.uploadFiles()];
|
|
18837
|
-
case 4:
|
|
18838
|
-
// upload all files
|
|
18839
|
-
_a.sent();
|
|
18840
|
-
files = (this.uploader.processedFiles || [])
|
|
18841
|
-
.filter(function (file) { return !file.deleting; });
|
|
18842
|
-
// Nothing to upload: close popover
|
|
18843
|
-
if (isEmptyArray(files))
|
|
18844
|
-
return [2 /*return*/, this.cancel()];
|
|
18845
|
-
errors = files.map(function (file) { return file.error; }).filter(isNotNilOrBlank);
|
|
18846
|
-
// If error: stop
|
|
18847
|
-
if (errors.length) {
|
|
18848
|
-
errors.forEach(function (error) { return console.error(error); });
|
|
18849
|
-
throw { message: 'FILE.UPLOAD.ERROR' };
|
|
18850
|
-
}
|
|
18851
|
-
// return files
|
|
18852
|
-
return [4 /*yield*/, this.popoverController.dismiss(files)];
|
|
18853
|
-
case 5:
|
|
18854
|
-
// return files
|
|
18855
|
-
_a.sent();
|
|
18856
|
-
return [3 /*break*/, 7];
|
|
18857
|
-
case 6:
|
|
18858
|
-
err_1 = _a.sent();
|
|
18859
|
-
this.error = (err_1 && err_1.message) || err_1;
|
|
18860
|
-
return [3 /*break*/, 7];
|
|
18861
|
-
case 7: return [3 /*break*/, 9];
|
|
18862
|
-
case 8:
|
|
18863
|
-
this.importing = false;
|
|
18864
|
-
this.cd.markForCheck();
|
|
18865
|
-
return [7 /*endfinally*/];
|
|
18866
|
-
case 9: return [2 /*return*/];
|
|
18907
|
+
}
|
|
18908
|
+
};
|
|
18909
|
+
/**
|
|
18910
|
+
* Execute upload
|
|
18911
|
+
*/
|
|
18912
|
+
UploadFileComponent.prototype.uploadFiles = function (files) {
|
|
18913
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
18914
|
+
var $processingFileCountChange, $changes, jobs;
|
|
18915
|
+
var _this = this;
|
|
18916
|
+
return __generator(this, function (_b) {
|
|
18917
|
+
if (!files) {
|
|
18918
|
+
console.info('[upload-file] Uploading all files...');
|
|
18919
|
+
files = this.files;
|
|
18867
18920
|
}
|
|
18921
|
+
$processingFileCountChange = new rxjs.BehaviorSubject(this.processingFilesCount);
|
|
18922
|
+
$changes = new rxjs.Subject();
|
|
18923
|
+
$changes.subscribe(function (_) {
|
|
18924
|
+
_this.cd.markForCheck();
|
|
18925
|
+
$processingFileCountChange.next(_this.processingFilesCount);
|
|
18926
|
+
});
|
|
18927
|
+
jobs = files
|
|
18928
|
+
.map(function (f) { return f; })
|
|
18929
|
+
.filter(function (file) { return file && isNil(file.progress) && !file.error; }) // Skip if already started or in error
|
|
18930
|
+
.map(function (file, i) {
|
|
18931
|
+
// Wait if need
|
|
18932
|
+
if (isNotNil(_this.maxParallelUpload)) {
|
|
18933
|
+
return $processingFileCountChange.pipe(operators.debounceTime(i), // call of filter() must be different for waiting job
|
|
18934
|
+
operators.filter(function (count) { return count < _this.maxParallelUpload; }), operators.map(function (_) {
|
|
18935
|
+
// Start uploading
|
|
18936
|
+
if (isNil(file.progress))
|
|
18937
|
+
file.progress = 0;
|
|
18938
|
+
$changes.next();
|
|
18939
|
+
return file;
|
|
18940
|
+
}), operators.first());
|
|
18941
|
+
}
|
|
18942
|
+
// Start uploading
|
|
18943
|
+
if (isNil(file.progress))
|
|
18944
|
+
file.progress = 0;
|
|
18945
|
+
return rxjs.of(file);
|
|
18946
|
+
})
|
|
18947
|
+
.map(function (file$) { return file$.pipe(operators.filter(isNotNil),
|
|
18948
|
+
// Log
|
|
18949
|
+
operators.tap(function (file) { return console.debug("[upload-file] " + file.name + ": uploading..."); }),
|
|
18950
|
+
// Start uploading
|
|
18951
|
+
operators.switchMap(function (file) { return _this.uploadFn(file)
|
|
18952
|
+
.pipe(operators.filter(isNotNil), operators.map(function (event) {
|
|
18953
|
+
// Progress event
|
|
18954
|
+
if (isProgressEvent(event)) {
|
|
18955
|
+
if (isNotNil(event.loaded) && event.loaded >= 0) {
|
|
18956
|
+
file.progress = Math.min(1, event.loaded / (event.total || 1));
|
|
18957
|
+
}
|
|
18958
|
+
else {
|
|
18959
|
+
file.progress = -1; // Indeterminate progression
|
|
18960
|
+
}
|
|
18961
|
+
}
|
|
18962
|
+
// Response event
|
|
18963
|
+
else if (isResponseEvent(event)) {
|
|
18964
|
+
file.progress = 1;
|
|
18965
|
+
file.response = event;
|
|
18966
|
+
console.debug("[upload-file] " + file.name + ": " + (event.statusText || 'OK'), file.response);
|
|
18967
|
+
}
|
|
18968
|
+
// Other events: ignore
|
|
18969
|
+
else {
|
|
18970
|
+
// DEBUG
|
|
18971
|
+
console.debug('[upload-file] Ignoring a file event: ', event);
|
|
18972
|
+
}
|
|
18973
|
+
return file;
|
|
18974
|
+
}), operators.catchError(function (err) {
|
|
18975
|
+
var _a;
|
|
18976
|
+
console.error(err);
|
|
18977
|
+
file.error = err && (err.message || ((_a = err.error) === null || _a === void 0 ? void 0 : _a.message)) || 'FILE.UPLOAD.ERROR';
|
|
18978
|
+
return rxjs.of(file);
|
|
18979
|
+
}), operators.tap(function () {
|
|
18980
|
+
$changes.next();
|
|
18981
|
+
_this.cd.markForCheck();
|
|
18982
|
+
})); })); });
|
|
18983
|
+
// Wait jobs to finish
|
|
18984
|
+
return [2 /*return*/, rxjs.forkJoin(jobs)
|
|
18985
|
+
.pipe(operators.tap(function (_) { return $changes.complete(); }))
|
|
18986
|
+
.toPromise()];
|
|
18868
18987
|
});
|
|
18869
18988
|
});
|
|
18870
18989
|
};
|
|
18871
|
-
|
|
18872
|
-
|
|
18873
|
-
|
|
18874
|
-
UploadFilePopover.prototype.resetError = function () {
|
|
18875
|
-
if (this.error) {
|
|
18876
|
-
this.error = null;
|
|
18877
|
-
this.cd.markForCheck();
|
|
18878
|
-
}
|
|
18990
|
+
UploadFileComponent.prototype.waitIdle = function (opts) {
|
|
18991
|
+
var _this = this;
|
|
18992
|
+
return waitFor(function () { return _this.processingFilesCount === 0; }, opts);
|
|
18879
18993
|
};
|
|
18880
|
-
return
|
|
18994
|
+
return UploadFileComponent;
|
|
18881
18995
|
}());
|
|
18882
|
-
|
|
18996
|
+
UploadFileComponent.decorators = [
|
|
18883
18997
|
{ type: i0.Component, args: [{
|
|
18884
|
-
selector: 'app-upload-file
|
|
18885
|
-
template: "\n
|
|
18886
|
-
|
|
18887
|
-
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
18888
|
-
styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
|
|
18998
|
+
selector: 'app-upload-file',
|
|
18999
|
+
template: "<div *ngIf=\"!uniqueFile || files.length === 0\"\n class=\"container\"\n appDragAndDrop (fileDropped)=\"onFileDropped($event)\">\n <input\n type=\"file\"\n #fileDropRef\n id=\"fileDropRef\"\n multiple\n [accept]=\"fileExtension\"\n (change)=\"fileBrowseHandler($any($event.target).files)\"\n />\n <mat-icon style=\"font-size: xx-large\" color=\"accent\">file_upload</mat-icon>\n <ion-label\n [innerHTML]=\"\n 'FILE.UPLOAD.DRAG_AND_DROP' | translate: { extension: !fileExtension ? '' : ' (' + fileExtension + ')' }\n \"\n ></ion-label>\n <ion-button>{{ 'FILE.UPLOAD.BROWSE' | translate }}</ion-button>\n</div>\n<div class=\"files-list\">\n <div *ngFor=\"let file of files; index as i\"\n class=\"single-file\"\n [class.deleting]=\"file.deleting\">\n <mat-icon>description</mat-icon>\n <div class=\"info\">\n <h4 class=\"name\">\n {{ file.name }}\n </h4>\n <p class=\"size\">\n {{ file.size | fileSize }}\n </p>\n <ion-progress-bar *ngIf=\"!file.error\"\n [value]=\"file.progress||0\"\n [type]=\"(file.deleting || file.progress === -1) ? 'indeterminate' : 'determinate'\"></ion-progress-bar>\n <ion-label *ngIf=\"file.error\" color=\"danger\" [innerHTML]=\"file.error | translate\"></ion-label>\n </div>\n <!-- remote from list (before importation) -->\n <button *ngIf=\"!(file.progress) || file.error\" mat-icon-button (click)=\"deleteFile(i)\">\n <mat-icon>clear</mat-icon>\n </button>\n <!-- delete file (remotely - after importation) -->\n <button *ngIf=\"file.progress === 1 && !!deleteFn && !file.deleting\" mat-icon-button (click)=\"deleteFile(i)\">\n <mat-icon>clear</mat-icon>\n </button>\n </div>\n</div>\n",
|
|
19000
|
+
styles: [".container{width:calc(100% - 3rem);min-height:200px;padding:2rem;text-align:center;border:1px dashed #979797;position:relative;margin:1.5rem}.container input{opacity:0;position:absolute;z-index:2;width:100%;height:100%;top:0;left:0;cursor:pointer}.container ion-label{display:block;font-size:20px;font-weight:600;color:#38424c}.container label{display:inline-block;color:#fff;width:183px;height:44px;border-radius:21.5px;background-color:#db202f;padding:8px 16px}.fileover{-webkit-animation:shake 1s;animation:shake 1s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.files-list{max-height:300px;overflow:auto}.files-list .single-file{display:flex;flex-grow:1;padding:.5rem;justify-content:space-between;align-items:center;border:1px dashed #979797;margin-bottom:1rem}.files-list .single-file.deleting .name{color:grey!important;font-style:italic!important}.files-list .single-file .name{font-size:14px;font-weight:500;color:#353f4a;margin:0}.files-list .single-file .size{font-size:12px;font-weight:500;color:#a4a4a4;margin:0 0 .25rem}.files-list .single-file .info{width:100%}@-webkit-keyframes shake{0%{transform:translate(1px,1px) rotate(0deg)}10%{transform:translate(-1px,-2px) rotate(-1deg)}20%{transform:translate(-3px) rotate(1deg)}30%{transform:translate(3px,2px) rotate(0deg)}40%{transform:translate(1px,-1px) rotate(1deg)}50%{transform:translate(-1px,2px) rotate(-1deg)}60%{transform:translate(-3px,1px) rotate(0deg)}70%{transform:translate(3px,1px) rotate(-1deg)}80%{transform:translate(-1px,-1px) rotate(1deg)}90%{transform:translate(1px,2px) rotate(0deg)}to{transform:translate(1px,-2px) rotate(-1deg)}}@keyframes shake{0%{transform:translate(1px,1px) rotate(0deg)}10%{transform:translate(-1px,-2px) rotate(-1deg)}20%{transform:translate(-3px) rotate(1deg)}30%{transform:translate(3px,2px) rotate(0deg)}40%{transform:translate(1px,-1px) rotate(1deg)}50%{transform:translate(-1px,2px) rotate(-1deg)}60%{transform:translate(-3px,1px) rotate(0deg)}70%{transform:translate(3px,1px) rotate(-1deg)}80%{transform:translate(-1px,-1px) rotate(1deg)}90%{transform:translate(1px,2px) rotate(0deg)}to{transform:translate(1px,-2px) rotate(-1deg)}}"]
|
|
18889
19001
|
},] }
|
|
18890
19002
|
];
|
|
18891
|
-
|
|
18892
|
-
{ type:
|
|
18893
|
-
{ type: i1$2.TranslateService }
|
|
18894
|
-
{ type: i0.ChangeDetectorRef }
|
|
19003
|
+
UploadFileComponent.ctorParameters = function () { return [
|
|
19004
|
+
{ type: i0.ChangeDetectorRef },
|
|
19005
|
+
{ type: i1$2.TranslateService }
|
|
18895
19006
|
]; };
|
|
18896
|
-
|
|
18897
|
-
|
|
19007
|
+
UploadFileComponent.propDecorators = {
|
|
19008
|
+
fileDropEl: [{ type: i0.ViewChild, args: ['fileDropRef', { static: false },] }],
|
|
18898
19009
|
fileExtension: [{ type: i0.Input }],
|
|
18899
|
-
title: [{ type: i0.Input }],
|
|
18900
19010
|
uniqueFile: [{ type: i0.Input }],
|
|
18901
19011
|
instantUpload: [{ type: i0.Input }],
|
|
18902
19012
|
uploadFn: [{ type: i0.Input }],
|
|
@@ -19663,12 +19773,41 @@
|
|
|
19663
19773
|
AppForm.prototype.cancel = function () {
|
|
19664
19774
|
this.onCancel.emit();
|
|
19665
19775
|
};
|
|
19666
|
-
|
|
19667
|
-
|
|
19668
|
-
|
|
19669
|
-
|
|
19670
|
-
|
|
19671
|
-
|
|
19776
|
+
/**
|
|
19777
|
+
*
|
|
19778
|
+
* @param event
|
|
19779
|
+
* @param opts allow to skip validation check, using {checkValid: false}
|
|
19780
|
+
*/
|
|
19781
|
+
AppForm.prototype.doSubmit = function (event, opts) {
|
|
19782
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
19783
|
+
return __generator(this, function (_b) {
|
|
19784
|
+
switch (_b.label) {
|
|
19785
|
+
case 0:
|
|
19786
|
+
if (!this._form) {
|
|
19787
|
+
this.markAllAsTouched({ emitEvent: true });
|
|
19788
|
+
return [2 /*return*/];
|
|
19789
|
+
}
|
|
19790
|
+
if (!((!opts || opts.checkValid !== false) && !this._form.valid)) return [3 /*break*/, 2];
|
|
19791
|
+
// Wait validation end
|
|
19792
|
+
return [4 /*yield*/, AppFormUtils.waitWhilePending(this._form)];
|
|
19793
|
+
case 1:
|
|
19794
|
+
// Wait validation end
|
|
19795
|
+
_b.sent();
|
|
19796
|
+
// Form is invalid: exit (+ log if debug)
|
|
19797
|
+
if (this._form.invalid) {
|
|
19798
|
+
this.markAllAsTouched({ emitEvent: true });
|
|
19799
|
+
if (this.debug)
|
|
19800
|
+
AppFormUtils.logFormErrors(this._form);
|
|
19801
|
+
return [2 /*return*/];
|
|
19802
|
+
}
|
|
19803
|
+
_b.label = 2;
|
|
19804
|
+
case 2:
|
|
19805
|
+
// Emit event
|
|
19806
|
+
this.onSubmit.emit(event);
|
|
19807
|
+
return [2 /*return*/];
|
|
19808
|
+
}
|
|
19809
|
+
});
|
|
19810
|
+
});
|
|
19672
19811
|
};
|
|
19673
19812
|
AppForm.prototype.setForm = function (form) {
|
|
19674
19813
|
var _this = this;
|
|
@@ -20469,74 +20608,6 @@
|
|
|
20469
20608
|
return JobUtils;
|
|
20470
20609
|
}());
|
|
20471
20610
|
|
|
20472
|
-
var FilesUtils = /** @class */ (function () {
|
|
20473
|
-
function FilesUtils() {
|
|
20474
|
-
}
|
|
20475
|
-
FilesUtils.showUploadPopover = function (popoverController, event, opts) {
|
|
20476
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
20477
|
-
var modal, _a, data, role;
|
|
20478
|
-
return __generator(this, function (_b) {
|
|
20479
|
-
switch (_b.label) {
|
|
20480
|
-
case 0: return [4 /*yield*/, popoverController.create({
|
|
20481
|
-
component: UploadFilePopover,
|
|
20482
|
-
componentProps: opts,
|
|
20483
|
-
backdropDismiss: false,
|
|
20484
|
-
keyboardClose: false,
|
|
20485
|
-
event: event,
|
|
20486
|
-
translucent: true,
|
|
20487
|
-
cssClass: 'popover-large',
|
|
20488
|
-
})];
|
|
20489
|
-
case 1:
|
|
20490
|
-
modal = _b.sent();
|
|
20491
|
-
return [4 /*yield*/, modal.present()];
|
|
20492
|
-
case 2:
|
|
20493
|
-
_b.sent();
|
|
20494
|
-
return [4 /*yield*/, modal.onDidDismiss()];
|
|
20495
|
-
case 3:
|
|
20496
|
-
_a = _b.sent(), data = _a.data, role = _a.role;
|
|
20497
|
-
return [2 /*return*/, {
|
|
20498
|
-
role: role,
|
|
20499
|
-
data: data ? data : undefined
|
|
20500
|
-
}];
|
|
20501
|
-
}
|
|
20502
|
-
});
|
|
20503
|
-
});
|
|
20504
|
-
};
|
|
20505
|
-
FilesUtils.readAsText = function (file, encoding) {
|
|
20506
|
-
var $progress = new rxjs.Subject();
|
|
20507
|
-
var reader = new FileReader();
|
|
20508
|
-
encoding = (encoding || 'UTF-8').toLowerCase();
|
|
20509
|
-
// Listen progress
|
|
20510
|
-
reader.onprogress = function (e) {
|
|
20511
|
-
var total = e.total || 1;
|
|
20512
|
-
var loaded = e.total || 0;
|
|
20513
|
-
if (loaded < total)
|
|
20514
|
-
$progress.next({ type: i2$1.HttpEventType.UploadProgress, loaded: loaded, total: total });
|
|
20515
|
-
};
|
|
20516
|
-
// Listen end
|
|
20517
|
-
reader.onloadend = function (e) {
|
|
20518
|
-
var body = reader.result;
|
|
20519
|
-
if (typeof body === 'string') {
|
|
20520
|
-
$progress.next(new FileResponse({ body: body }));
|
|
20521
|
-
$progress.complete();
|
|
20522
|
-
}
|
|
20523
|
-
else {
|
|
20524
|
-
console.error("Cannot read file '" + file.name + "' as text");
|
|
20525
|
-
$progress.error("Cannot read file as text");
|
|
20526
|
-
}
|
|
20527
|
-
};
|
|
20528
|
-
// Listen error
|
|
20529
|
-
reader.onerror = function (event) {
|
|
20530
|
-
console.error('[files] Error while reading file:', event);
|
|
20531
|
-
$progress.error(event);
|
|
20532
|
-
};
|
|
20533
|
-
// Start reading the file
|
|
20534
|
-
reader.readAsText(file, encoding);
|
|
20535
|
-
return $progress.asObservable();
|
|
20536
|
-
};
|
|
20537
|
-
return FilesUtils;
|
|
20538
|
-
}());
|
|
20539
|
-
|
|
20540
20611
|
/**
|
|
20541
20612
|
* Define here theme colors
|
|
20542
20613
|
*/
|
|
@@ -20953,25 +21024,41 @@
|
|
|
20953
21024
|
this.onCancel.emit();
|
|
20954
21025
|
};
|
|
20955
21026
|
AuthForm.prototype.doSubmit = function (event) {
|
|
20956
|
-
|
|
20957
|
-
|
|
20958
|
-
|
|
20959
|
-
|
|
20960
|
-
|
|
20961
|
-
|
|
20962
|
-
|
|
20963
|
-
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
20967
|
-
|
|
20968
|
-
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
|
|
20974
|
-
|
|
21027
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
21028
|
+
var data;
|
|
21029
|
+
var _this = this;
|
|
21030
|
+
return __generator(this, function (_a) {
|
|
21031
|
+
switch (_a.label) {
|
|
21032
|
+
case 0:
|
|
21033
|
+
if (event) {
|
|
21034
|
+
event.preventDefault();
|
|
21035
|
+
event.stopPropagation();
|
|
21036
|
+
}
|
|
21037
|
+
if (this.loading)
|
|
21038
|
+
return [2 /*return*/];
|
|
21039
|
+
if (!!this.form.valid) return [3 /*break*/, 2];
|
|
21040
|
+
return [4 /*yield*/, AppFormUtils.waitWhilePending(this.form)];
|
|
21041
|
+
case 1:
|
|
21042
|
+
_a.sent();
|
|
21043
|
+
if (this.form.invalid) {
|
|
21044
|
+
AppFormUtils.logFormErrors(this.form);
|
|
21045
|
+
return [2 /*return*/]; // Skip if invalid
|
|
21046
|
+
}
|
|
21047
|
+
_a.label = 2;
|
|
21048
|
+
case 2:
|
|
21049
|
+
this.markAsLoading();
|
|
21050
|
+
data = this.form.value;
|
|
21051
|
+
this.showPwd = false; // Hide password
|
|
21052
|
+
this.error = null; // Reset error
|
|
21053
|
+
setTimeout(function () { return _this.onSubmit.emit({
|
|
21054
|
+
username: data.username,
|
|
21055
|
+
password: data.password,
|
|
21056
|
+
offline: data.offline
|
|
21057
|
+
}); });
|
|
21058
|
+
return [2 /*return*/];
|
|
21059
|
+
}
|
|
21060
|
+
});
|
|
21061
|
+
});
|
|
20975
21062
|
};
|
|
20976
21063
|
AuthForm.prototype.register = function () {
|
|
20977
21064
|
var _this = this;
|
|
@@ -23170,9 +23257,6 @@
|
|
|
23170
23257
|
{ type: i0.Injectable, args: [{ providedIn: 'root' },] }
|
|
23171
23258
|
];
|
|
23172
23259
|
|
|
23173
|
-
var MimeTypes = Object.freeze({
|
|
23174
|
-
ANDROID_APK: 'application/vnd.android.package-archive'
|
|
23175
|
-
});
|
|
23176
23260
|
var AppInstallUpgradeCard = /** @class */ (function () {
|
|
23177
23261
|
function AppInstallUpgradeCard(modalCtrl, configService, toastController, alertController, translate, cd, platform, network, environment) {
|
|
23178
23262
|
this.modalCtrl = modalCtrl;
|
|
@@ -23419,10 +23503,10 @@
|
|
|
23419
23503
|
var title = void 0;
|
|
23420
23504
|
var mimeType = void 0;
|
|
23421
23505
|
// Get file name
|
|
23422
|
-
var filename =
|
|
23506
|
+
var filename = UriUtils.getFilename(url);
|
|
23423
23507
|
var version = minVersion || 'latest';
|
|
23424
23508
|
// OK, this is a downloadable APK file (e.g. NOT a link to a playstore)
|
|
23425
|
-
if (filename === null || filename === void 0 ? void 0 : filename.endsWith('.apk')) {
|
|
23509
|
+
if (filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.apk')) {
|
|
23426
23510
|
// Define mime type
|
|
23427
23511
|
mimeType = MimeTypes.ANDROID_APK;
|
|
23428
23512
|
// Get the file version (if any)
|
|
@@ -23433,11 +23517,9 @@
|
|
|
23433
23517
|
filename = (name + "-v" + version + ".apk").toLowerCase();
|
|
23434
23518
|
title = name + " v" + version;
|
|
23435
23519
|
}
|
|
23436
|
-
|
|
23437
|
-
|
|
23438
|
-
|
|
23439
|
-
filename = filename.replace('latest', version);
|
|
23440
|
-
}
|
|
23520
|
+
// Replace 'latest' with the app version, if present in the filename
|
|
23521
|
+
else if (filename.indexOf('latest') && version !== 'latest') {
|
|
23522
|
+
filename = filename.replace('latest', version);
|
|
23441
23523
|
}
|
|
23442
23524
|
}
|
|
23443
23525
|
result.push({ name: name, url: url, platform: 'android', version: version, filename: filename, title: title, mimeType: mimeType });
|
|
@@ -23449,18 +23531,6 @@
|
|
|
23449
23531
|
//}
|
|
23450
23532
|
return result;
|
|
23451
23533
|
};
|
|
23452
|
-
AppInstallUpgradeCard.prototype.getFilename = function (url) {
|
|
23453
|
-
if (!url)
|
|
23454
|
-
return;
|
|
23455
|
-
// Get last part (or all string, if no '/')
|
|
23456
|
-
var filename = url.substring(url.lastIndexOf('/') + 1);
|
|
23457
|
-
var queryParamIndex = filename.indexOf('?');
|
|
23458
|
-
if (queryParamIndex !== -1) {
|
|
23459
|
-
// Remove query params
|
|
23460
|
-
return filename.substring(0, queryParamIndex);
|
|
23461
|
-
}
|
|
23462
|
-
return filename;
|
|
23463
|
-
};
|
|
23464
23534
|
AppInstallUpgradeCard.prototype.listenDownloadJobs = function () {
|
|
23465
23535
|
var _this = this;
|
|
23466
23536
|
// Listening downloading promise, if exists
|
|
@@ -25221,7 +25291,7 @@
|
|
|
25221
25291
|
updateDatasource: { get: function () { return _super_1.prototype.updateDatasource; } }
|
|
25222
25292
|
});
|
|
25223
25293
|
return __awaiter(this, void 0, void 0, function () {
|
|
25224
|
-
var res, existingData;
|
|
25294
|
+
var fetchMoreFn, res, existingData;
|
|
25225
25295
|
return __generator(this, function (_a) {
|
|
25226
25296
|
switch (_a.label) {
|
|
25227
25297
|
case 0:
|
|
@@ -25231,9 +25301,9 @@
|
|
|
25231
25301
|
console.warn('Cannot fetch more because still editing row');
|
|
25232
25302
|
return [2 /*return*/];
|
|
25233
25303
|
}
|
|
25234
|
-
|
|
25235
|
-
this._fetchMoreFn = null;
|
|
25236
|
-
return [4 /*yield*/,
|
|
25304
|
+
fetchMoreFn = this._fetchMoreFn;
|
|
25305
|
+
this._fetchMoreFn = null;
|
|
25306
|
+
return [4 /*yield*/, fetchMoreFn()];
|
|
25237
25307
|
case 1:
|
|
25238
25308
|
res = _a.sent();
|
|
25239
25309
|
// Skip if empty (no more data)
|
|
@@ -30276,6 +30346,7 @@
|
|
|
30276
30346
|
missingEntity: [null, SharedValidators.entity],
|
|
30277
30347
|
disableEntity: [null, SharedValidators.entity],
|
|
30278
30348
|
entities: [null, SharedFormArrayValidators.requiredArrayMinLength(1)],
|
|
30349
|
+
farEntity: [null, SharedValidators.entity]
|
|
30279
30350
|
});
|
|
30280
30351
|
this.form.get('disableEntity').disable();
|
|
30281
30352
|
}
|
|
@@ -30314,6 +30385,13 @@
|
|
|
30314
30385
|
attributes: ['label', 'name', 'description', 'comments'],
|
|
30315
30386
|
displayWith: this.entityToString
|
|
30316
30387
|
});
|
|
30388
|
+
// Far entity, in the list
|
|
30389
|
+
this.autocompleteFields.add('entity-far', {
|
|
30390
|
+
suggestFn: function (value, filter) { return _this.suggest(value, filter); },
|
|
30391
|
+
attributes: ['label', 'name'],
|
|
30392
|
+
displayWith: this.entityToString,
|
|
30393
|
+
showAllOnFocus: true
|
|
30394
|
+
});
|
|
30317
30395
|
// For mutliple value
|
|
30318
30396
|
this.autocompleteFields.add('entities-items-filter', {
|
|
30319
30397
|
service: {
|
|
@@ -30333,6 +30411,7 @@
|
|
|
30333
30411
|
return __generator(this, function (_a) {
|
|
30334
30412
|
data = {
|
|
30335
30413
|
entity: deepCopy(FAKE_ENTITIES)[0],
|
|
30414
|
+
farEntity: deepCopy(FAKE_ENTITIES)[2],
|
|
30336
30415
|
// This item is NOT in the items list => i should be displayed anyway
|
|
30337
30416
|
missingEntity: {
|
|
30338
30417
|
id: -1, label: '??', name: 'Missing item'
|
|
@@ -30428,7 +30507,7 @@
|
|
|
30428
30507
|
AutocompleteTestPage.decorators = [
|
|
30429
30508
|
{ type: i0.Component, args: [{
|
|
30430
30509
|
selector: 'app-autocomplete-test',
|
|
30431
|
-
template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable<any[]></pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) => any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [clearable]=\"true\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<any>\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-mobile-suggestLengthThreshold]'\"\n required\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"true\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter(filterChangeField, 'entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\" #filterChangeField\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Fullscreen\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-mobile-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<any></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-suggest]'\">\n </mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<any>\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggestLengthThreshold]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"false\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
|
|
30510
|
+
template: "<ion-header>\n <ion-toolbar color=\"primary\">\n\n <ion-buttons slot=\"start\">\n <ion-back-button></ion-back-button>\n </ion-buttons>\n\n <ion-title>Autocomplete field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content>\n\n <!-- Tab nav - mobile/desktop mode -->\n <nav mat-tab-nav-bar>\n <a mat-tab-link\n [active]=\"mode==='mobile'\"\n (click)=\"toggleMode('mobile')\">\n <mat-label>Mobile</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='desktop'\"\n (click)=\"toggleMode('desktop')\">\n <mat-label>Desktop</mat-label>\n </a>\n <a mat-tab-link [active]=\"mode==='memory'\"\n (click)=\"toggleMode('memory')\">\n <mat-label>Memory leak debug</mat-label>\n </a>\n <a mat-tab-link\n [active]=\"mode==='temp'\"\n (click)=\"toggleMode('temp')\">\n <mat-label>Temporary</mat-label>\n </a>\n </nav>\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!--<ion-grid *ngIf=\"mode === 'temp'\">\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>items: Observable<any[]></pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [compareWith]=\"compareWithFn\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n </ion-row>\n\n\n </ion-grid>-->\n\n\n <ion-grid *ngIf=\"mode === 'memory'\">\n\n <!-- debugging memory leak -->\n <ion-row>\n <ion-col>\n <ion-text><h4>Debug memory leak</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Items type\">\n <mat-select (selectionChange)=\"memoryAutocompleteFieldName=$event.value\" [value]=\"memoryAutocompleteFieldName\">\n <mat-option value=\"entity-$items\">Observable</mat-option>\n <mat-option value=\"entity-suggestFn\">Suggest function</mat-option>\n </mat-select>\n </mat-form-field>\n </ion-col>\n <ion-col size=\"1\" class=\"ion-no-padding\">\n <mat-form-field floatLabel=\"always\">\n <input matInput type=\"text\" hidden placeholder=\"Mobile ?\">\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [checked]=\"memoryMobile\">\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\" color=\"tertiary\">Start</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\" color=\"tertiary\">Stop</ion-button>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\"\n *ngIf=\"!memoryHide && memoryAutocompleteFieldName\"\n [config]=\"autocompleteFields.get(memoryAutocompleteFieldName)\"\n [mobile]=\"memoryMobile\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-memory-leak]'\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n <!-- Mobile mode -->\n <ion-grid *ngIf=\"mode === 'mobile'\">\n\n <ion-row>\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) => any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"farEntity\"\n [config]=\"autocompleteFields.get('entity-far')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-far]'\"\n [required]=\"true\"\n placeholder=\"Far entity (in the list)\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Suggest() function\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, suggestFn: (searchText, filter) => any[]</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-suggestFn')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-1]'\"\n [required]=\"true\"\n placeholder=\"Suggest field\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Items is an Observable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-observable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>mobile: true, items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [clearable]=\"true\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<any>\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-mobile-suggestLengthThreshold]'\"\n required\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"true\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-2]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Change filter\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <ion-button (click)=\"updateFilter(filterChangeField, 'entity-items-filter')\">Filter on: {{autocompleteFields.get('entity-items-filter').filter?.searchAttribute }}</ion-button>\n </ion-col>\n <ion-col>\n <mat-autocomplete-field formControlName=\"entity\" #filterChangeField\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-filter]'\"\n ></mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"min-width-large\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"true\"\n class=\"min-width-large\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Fullscreen\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"true\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-mobile-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Desktop mode -->\n <ion-grid *ngIf=\"mode === 'desktop'\">\n <ion-row>\n <ion-col>\n <ion-text><h4>Desktop mode</h4></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n items from suggest function\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<any></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-suggest]'\">\n </mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n search with a suggestLengthThreshold\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>suggest: (value, filter) => LoadResult<any>\nsuggestLengthThreshold: '3'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n suggestLengthThreshold=\"3\"\n [logPrefix]=\"'[combo-desktop-suggestLengthThreshold]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an array\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: [], value: {{stringify(form.controls.entity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items')\"\n [logPrefix]=\"'[combo-desktop-array-1]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Items is an Observable\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [logPrefix]=\"'[combo-desktop-2]'\"\n [equals]=\"equals\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Multiple value\n </ion-text>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>multiple: true</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entities\"\n [config]=\"autocompleteFields.get('entities-items-filter')\"\n [placeholder]=\"'Multiple'\"\n mobile=\"false\"\n multiple=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-multiple]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Control value if missing in items\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>items: Observable<any[]></pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"missingEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-missing]'\"\n [mobile]=\"false\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size panel\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class: 'mat-autocomplete-panel-full-size'</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [class]=\"'mat-autocomplete-panel-full-size'\"\n [matAutocompletePosition]=\"'above'\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n [debug]=\"true\"\n [showAllOnFocus]=\"true\"\n [showPanelOnFocus]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disabled control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"disableEntity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-disable]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly control\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-$items')\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n <ion-row>\n <ion-col size=\"9\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Full size combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>class=\"mat-autocomplete-panel-full-size\"</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n class=\"mat-autocomplete-panel-full-size\"\n panelWidth=\"100vw\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-full-size]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"3\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Large combo\n </ion-label>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre>panelWidth: string</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-large')\"\n [mobile]=\"false\"\n panelWidth=\"400px\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-large]'\"\n ></mat-autocomplete-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <ion-col size=\"6\">\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-text color=\"primary\">\n Readonly toggle\n </ion-text>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n <ion-grid>\n <ion-row>\n <ion-col size=\"3\">\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n Readonly ?\n </mat-checkbox>\n </ion-col>\n <ion-col size=\"3\">\n <mat-checkbox #showIcons [checked]=\"false\">\n Icons ?\n </mat-checkbox>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <mat-autocomplete-field #readonlyField formControlName=\"entity\"\n [config]=\"autocompleteFields.get('entity-items-filter')\"\n [placeholder]=\"'Entity'\"\n [mobile]=\"false\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-desktop-readonly]'\"\n [readonly]=\"true\"\n [clearable]=\"!readonlyField.readonly\">\n <mat-icon matPrefix *ngIf=\"showIcons.checked\">keyboard_arrow_right</mat-icon>\n <mat-icon matSuffix *ngIf=\"showIcons.checked\">keyboard_arrow_left</mat-icon>\n </mat-autocomplete-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </form>\n\n</ion-content>\n"
|
|
30432
30511
|
},] }
|
|
30433
30512
|
];
|
|
30434
30513
|
AutocompleteTestPage.ctorParameters = function () { return [
|
|
@@ -31920,6 +31999,7 @@
|
|
|
31920
31999
|
exports.MessageService = MessageService;
|
|
31921
32000
|
exports.MessageTypeList = MessageTypeList;
|
|
31922
32001
|
exports.MessageTypes = MessageTypes;
|
|
32002
|
+
exports.MimeTypes = MimeTypes;
|
|
31923
32003
|
exports.ModalToolbarComponent = ModalToolbarComponent;
|
|
31924
32004
|
exports.NetworkService = NetworkService;
|
|
31925
32005
|
exports.NgInitDirective = NgInitDirective;
|
|
@@ -32004,6 +32084,7 @@
|
|
|
32004
32084
|
exports.UploadFilePopover = UploadFilePopover;
|
|
32005
32085
|
exports.UploadFileTestingModule = UploadFileTestingModule;
|
|
32006
32086
|
exports.UploadFileTestingPage = UploadFileTestingPage;
|
|
32087
|
+
exports.UriUtils = UriUtils;
|
|
32007
32088
|
exports.UserEventFragments = UserEventFragments;
|
|
32008
32089
|
exports.UserEventService = UserEventService;
|
|
32009
32090
|
exports.UserEventTypes = UserEventTypes;
|