@sumaris-net/ngx-components 1.20.0-rc5 → 1.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/bundles/sumaris-net.ngx-components.umd.js +1502 -1316
- 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 +50 -2
- package/esm2015/src/app/admin/services/person.service.js +3 -3
- package/esm2015/src/app/admin/users/list/users.js +1 -5
- package/esm2015/src/app/core/account/account.js +19 -6
- package/esm2015/src/app/core/core.module.js +4 -3
- package/esm2015/src/app/core/form/entity-editor.class.js +33 -11
- package/esm2015/src/app/core/form/form-buttons-bar.component.js +8 -5
- package/esm2015/src/app/core/form/list.form.js +1 -1
- package/esm2015/src/app/core/home/home.js +2 -2
- package/esm2015/src/app/core/install/install-upgrade-card.component.js +10 -40
- package/esm2015/src/app/core/menu/menu.component.js +77 -28
- package/esm2015/src/app/core/menu/menu.service.js +37 -12
- package/esm2015/src/app/core/offline/update-offline-mode-card.component.js +26 -0
- package/esm2015/src/app/core/services/account.service.js +2 -2
- package/esm2015/src/app/core/services/model/entity.model.js +3 -5
- package/esm2015/src/app/core/services/model/filter.model.js +1 -1
- package/esm2015/src/app/core/services/model/referential.model.js +1 -4
- package/esm2015/src/app/core/services/platform.service.js +44 -17
- package/esm2015/src/app/core/services/storage/entities-storage.service.js +36 -35
- package/esm2015/src/app/core/services/storage/entity-store.class.js +4 -5
- package/esm2015/src/app/core/table/entities-table-datasource.class.js +129 -193
- package/esm2015/src/app/core/table/memory-table.class.js +3 -3
- package/esm2015/src/app/core/table/table.class.js +96 -95
- package/esm2015/src/app/core/text-popover/text-form.component.js +1 -1
- package/esm2015/src/app/shared/dates.js +4 -8
- package/esm2015/src/app/shared/files.js +26 -1
- package/esm2015/src/app/shared/form/field.component.js +2 -2
- package/esm2015/src/app/shared/functions.js +5 -2
- package/esm2015/src/app/shared/guard/component-dirty.guard.js +3 -3
- package/esm2015/src/app/shared/material/autocomplete/material.autocomplete.js +82 -58
- package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +24 -9
- package/esm2015/src/app/shared/material/chips/material.chips.js +3 -2
- package/esm2015/src/app/shared/material/datetime/material.date.js +2 -2
- package/esm2015/src/app/shared/material/datetime/material.dateshort.js +2 -2
- package/esm2015/src/app/shared/material/datetime/material.datetime.js +7 -8
- package/esm2015/src/app/shared/material/datetime/testing/mat-date-time.test.js +6 -4
- package/esm2015/src/app/shared/material/latlong/latlong.utils.js +1 -1
- package/esm2015/src/app/shared/material/latlong/material.latlong.js +57 -51
- package/esm2015/src/app/shared/material/latlong/testing/latlong.test.js +2 -2
- package/esm2015/src/app/shared/material/swipe/material.swipe.js +7 -6
- package/esm2015/src/app/shared/pipes/form.pipes.js +86 -23
- package/esm2015/src/app/shared/pipes/latlong-format.pipe.js +17 -24
- package/esm2015/src/app/shared/pipes/number-format.pipe.js +6 -3
- package/esm2015/src/app/shared/pipes/pipes.module.js +6 -4
- package/esm2015/src/app/shared/platforms.js +2 -1
- package/esm2015/src/app/shared/services/job.utils.js +4 -3
- package/esm2015/src/app/shared/toolbar/toolbar.js +25 -9
- package/esm2015/src/app/shared/validator/validators.js +9 -4
- package/esm2015/src/app/vendor.js +7 -1
- package/esm2015/sumaris-net.ngx-components.js +8 -7
- package/fesm2015/sumaris-net.ngx-components.js +1054 -833
- package/fesm2015/sumaris-net.ngx-components.js.map +1 -1
- package/package.json +2 -2
- package/src/app/core/form/entity-editor.class.d.ts +2 -1
- package/src/app/core/form/form-buttons-bar.component.d.ts +3 -1
- package/src/app/core/install/install-upgrade-card.component.d.ts +1 -6
- package/src/app/core/menu/menu.component.d.ts +12 -7
- package/src/app/core/menu/menu.service.d.ts +15 -6
- package/src/app/core/offline/update-offline-mode-card.component.d.ts +8 -0
- package/src/app/core/services/model/entity.model.d.ts +0 -1
- package/src/app/core/services/model/filter.model.d.ts +1 -1
- package/src/app/core/services/model/referential.model.d.ts +3 -4
- package/src/app/core/services/platform.service.d.ts +1 -0
- package/src/app/core/services/storage/entities-storage.service.d.ts +10 -6
- package/src/app/core/services/storage/entity-store.class.d.ts +2 -2
- package/src/app/core/table/entities-table-datasource.class.d.ts +28 -26
- package/src/app/core/table/table.class.d.ts +2 -2
- package/src/app/shared/dates.d.ts +3 -3
- package/src/app/shared/files.d.ts +10 -0
- package/src/app/shared/functions.d.ts +1 -0
- package/src/app/shared/material/autocomplete/material.autocomplete.d.ts +2 -1
- package/src/app/shared/material/autocomplete/testing/autocomplete.test.d.ts +4 -2
- package/src/app/shared/material/chips/material.chips.d.ts +2 -1
- package/src/app/shared/material/latlong/latlong.utils.d.ts +2 -2
- package/src/app/shared/material/latlong/material.latlong.d.ts +15 -10
- package/src/app/shared/material/swipe/material.swipe.d.ts +4 -3
- package/src/app/shared/pipes/form.pipes.d.ts +20 -4
- package/src/app/shared/pipes/latlong-format.pipe.d.ts +6 -4
- package/src/app/shared/pipes/number-format.pipe.d.ts +3 -1
- package/src/app/shared/toolbar/toolbar.d.ts +5 -2
- package/src/app/shared/validator/validators.d.ts +6 -1
- package/src/app/vendor.d.ts +5 -0
- package/src/assets/i18n/en-US.json +2 -1
- package/src/assets/i18n/en.json +2 -1
- package/src/assets/i18n/fr.json +4 -1
- package/src/theme/_ngx-components.globals.scss +1 -0
- package/src/theme/_ngx-components.scss +32 -20
- package/sumaris-net.ngx-components.d.ts +7 -6
- package/sumaris-net.ngx-components.metadata.json +1 -1
|
@@ -32,14 +32,13 @@ import { MatAutocomplete, MatAutocompleteTrigger, MatAutocompleteModule, MAT_AUT
|
|
|
32
32
|
import { __awaiter, __decorate } from 'tslib';
|
|
33
33
|
import { Validators, NG_VALUE_ACCESSOR, FormGroupDirective, AbstractControl, FormGroup, FormArray, FormControl, ReactiveFormsModule, FormBuilder } from '@angular/forms';
|
|
34
34
|
import { timer, merge, fromEvent, BehaviorSubject, Subscription, Subject, isObservable, from, of, noop as noop$9, Observable, defer, forkJoin, combineLatest, EMPTY } from 'rxjs';
|
|
35
|
-
import { filter, first, map, takeUntil, switchMap,
|
|
35
|
+
import { filter, first, map, takeUntil, switchMap, tap, debounceTime, startWith, distinctUntilChanged, mergeMap, catchError, throttleTime, skip } from 'rxjs/operators';
|
|
36
36
|
import { trigger, transition, style, animate, state } from '@angular/animations';
|
|
37
37
|
import { TranslateService, TranslateModule } from '@ngx-translate/core';
|
|
38
38
|
import { IonicModule, Platform, IonRouterOutlet, ModalController, PopoverController, IonicSafeString, createAnimation, ToastController, AlertController, IonicRouteStrategy, NavParams, MenuController, IonContent, IonInfiniteScroll } from '@ionic/angular';
|
|
39
39
|
import * as momentImported from 'moment';
|
|
40
40
|
import { isMoment } from 'moment';
|
|
41
41
|
import { MomentDateAdapter, MatMomentDateModule } from '@angular/material-moment-adapter';
|
|
42
|
-
import * as momentTZImported from 'moment-timezone';
|
|
43
42
|
import { Keyboard } from '@ionic-native/keyboard/ngx';
|
|
44
43
|
import { TextMaskModule } from 'angular2-text-mask';
|
|
45
44
|
import { NgxMaterialTimepickerModule } from 'ngx-material-timepicker';
|
|
@@ -47,7 +46,7 @@ import { MatDatepickerModule } from '@angular/material/datepicker';
|
|
|
47
46
|
import { MatDividerModule } from '@angular/material/divider';
|
|
48
47
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
|
49
48
|
import { MatChipsModule } from '@angular/material/chips';
|
|
50
|
-
import {
|
|
49
|
+
import { ActivatedRoute, Router, RouterModule, RouteReuseStrategy } from '@angular/router';
|
|
51
50
|
import { HammerGestureConfig, EventManager } from '@angular/platform-browser';
|
|
52
51
|
import { HttpResponse, HttpClient, HttpHeaders, HttpEventType, HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
|
53
52
|
import { ColorPickerModule } from 'ngx-color-picker';
|
|
@@ -94,6 +93,7 @@ import { NgxJdenticonModule } from 'ngx-jdenticon';
|
|
|
94
93
|
import 'tweetnacl-util';
|
|
95
94
|
import 'scrypt-async';
|
|
96
95
|
import 'hammerjs';
|
|
96
|
+
import * as momentTZImported from 'moment-timezone';
|
|
97
97
|
|
|
98
98
|
const ENVIRONMENT = new InjectionToken('ENV');
|
|
99
99
|
class Environment {
|
|
@@ -222,6 +222,9 @@ function replaceAll(value, searchString, replacement) {
|
|
|
222
222
|
}
|
|
223
223
|
return value;
|
|
224
224
|
}
|
|
225
|
+
function escapeRegExp(value) {
|
|
226
|
+
return value.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
227
|
+
}
|
|
225
228
|
function removeEnd(value, end) {
|
|
226
229
|
return (value === null || value === void 0 ? void 0 : value.endsWith(end || '')) ? value.substr(0, value.length - end.length) : value;
|
|
227
230
|
}
|
|
@@ -251,7 +254,7 @@ function suggestFromArray(items, value, opts) {
|
|
|
251
254
|
if (isNotNilOrBlank(value)) {
|
|
252
255
|
// If wildcard, search using regexp
|
|
253
256
|
if (value.indexOf('*') !== -1) {
|
|
254
|
-
value = value.replace(
|
|
257
|
+
value = value.replace(/[*]+/g, '.*');
|
|
255
258
|
filteredItems = filteredItems.filter(v => keys.findIndex(key => matchUpperCase(getPropertyByPathAsString(v, key), value)) !== -1);
|
|
256
259
|
}
|
|
257
260
|
// Else (no wildcard), search using startsWith
|
|
@@ -1089,6 +1092,7 @@ const isMobile = (win) => {
|
|
|
1089
1092
|
if (_cache.mobile === null || _cache.mobile === undefined) {
|
|
1090
1093
|
_cache.mobile = isCordova(window)
|
|
1091
1094
|
|| isAndroid(win) || isIOS(window)
|
|
1095
|
+
// Workaround, for MS Windows touch screen (detected as mobile, but forced as desktop)
|
|
1092
1096
|
|| (isTouchUi(win) && !isWindows(win));
|
|
1093
1097
|
}
|
|
1094
1098
|
return _cache.mobile;
|
|
@@ -1250,7 +1254,7 @@ class MatAutocompleteField {
|
|
|
1250
1254
|
return isNil(this.$filteredItems.value);
|
|
1251
1255
|
}
|
|
1252
1256
|
get desktop() {
|
|
1253
|
-
return !this.mobile;
|
|
1257
|
+
return !this.mobile && !this.multiple;
|
|
1254
1258
|
}
|
|
1255
1259
|
ngOnInit() {
|
|
1256
1260
|
var _a, _b;
|
|
@@ -1271,9 +1275,9 @@ class MatAutocompleteField {
|
|
|
1271
1275
|
this.equals = this.equals || this.config.equals;
|
|
1272
1276
|
this.multiple = toBoolean(this.multiple, this.config.multiple);
|
|
1273
1277
|
this.mobile = toBoolean(this.mobile, this.config.mobile);
|
|
1274
|
-
this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold
|
|
1275
|
-
this.showAllOnFocus = toBoolean(this.showAllOnFocus,
|
|
1276
|
-
this.showPanelOnFocus = toBoolean(this.showPanelOnFocus,
|
|
1278
|
+
this.suggestLengthThreshold = toNumber(this.suggestLengthThreshold, this.config.suggestLengthThreshold);
|
|
1279
|
+
this.showAllOnFocus = toBoolean(this.showAllOnFocus, this.config.showAllOnFocus);
|
|
1280
|
+
this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, this.config.showPanelOnFocus);
|
|
1277
1281
|
this.classList = this.classList || this.config.class;
|
|
1278
1282
|
this.debounceTime = toNumber(this.debounceTime, this.config.debounceTime);
|
|
1279
1283
|
this.highlightAccent = toBoolean(this.highlightAccent, toBoolean(this.config.highlightAccent));
|
|
@@ -1302,10 +1306,11 @@ class MatAutocompleteField {
|
|
|
1302
1306
|
|| (classList.includes('min-width-large') && '400px')
|
|
1303
1307
|
|| (classList.includes('min-width-xlarge') && '450px')
|
|
1304
1308
|
|| (classList.includes('mat-autocomplete-panel-full-size') && '100vw')));
|
|
1309
|
+
this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
|
|
1310
|
+
this.showAllOnFocus = toBoolean(this.showAllOnFocus, this.mobile && this.suggestLengthThreshold <= 0);
|
|
1305
1311
|
this.showPanelOnFocus = toBoolean(this.showPanelOnFocus, true);
|
|
1306
1312
|
this.debounceTime = toNumber(this.debounceTime, this.mobile ? 650 : 250);
|
|
1307
1313
|
this.highlightAccent = toBoolean(this.highlightAccent, false);
|
|
1308
|
-
this.suggestLengthThreshold = this.suggestLengthThreshold || 0;
|
|
1309
1314
|
this.matAutocompletePosition = this.matAutocompletePosition || 'auto';
|
|
1310
1315
|
// No suggestFn: filter on the given items
|
|
1311
1316
|
if (!this.suggestFn) {
|
|
@@ -1327,24 +1332,29 @@ class MatAutocompleteField {
|
|
|
1327
1332
|
return this.suggestFn(value, filter); // Loop
|
|
1328
1333
|
});
|
|
1329
1334
|
}
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
+
// Suggest + mobile
|
|
1336
|
+
// => Manually fill input items, from the given suggest function
|
|
1337
|
+
else if (this.mobile || this.multiple) {
|
|
1338
|
+
/*this._subscription.add(
|
|
1339
|
+
this._$filter.pipe(
|
|
1340
|
+
startWith<any, any>(this.filter),
|
|
1341
|
+
debounceTime(250),
|
|
1342
|
+
filter(_ => this.suggestLengthThreshold <= 0),
|
|
1343
|
+
switchMap((filter) => this.suggest('*', filter))
|
|
1344
|
+
)
|
|
1345
|
+
.subscribe(items => this.$inputItems.next(items))
|
|
1346
|
+
);*/
|
|
1335
1347
|
}
|
|
1336
1348
|
// Send value to suggest when :
|
|
1337
1349
|
// - is nil and '*', and no min length threshold
|
|
1338
1350
|
// - is not nil and not a string type (e.g. object)
|
|
1339
1351
|
// - is not nil and is a string, and has enough character
|
|
1340
|
-
const thresholdFilterFn = (value) => (
|
|
1341
|
-
|
|
1342
|
-
: (!(typeof value === 'string')
|
|
1343
|
-
|| value.length >= this.suggestLengthThreshold));
|
|
1352
|
+
const thresholdFilterFn = (value) => this.suggestLengthThreshold <= 0 || (isNotNil(value) && (!(typeof value === 'string')
|
|
1353
|
+
|| (value !== '*' && value.trim().length >= this.suggestLengthThreshold)));
|
|
1344
1354
|
const filteredItemsChanges = merge(
|
|
1345
1355
|
// Reload event (no distinctUntilChanged() pipe, to force reload even if same value)
|
|
1346
1356
|
this._reload$
|
|
1347
|
-
.pipe(filter(thresholdFilterFn)),
|
|
1357
|
+
.pipe(filter(() => this.enabled), filter(thresholdFilterFn), tap(_ => this.showLoadingSpinner && this.markAsLoading())),
|
|
1348
1358
|
// Search text (no distinctUntilChanged() because of the debounceTime() pipe)
|
|
1349
1359
|
this.formControl.valueChanges
|
|
1350
1360
|
.pipe(filter(value => this.enabled && isNotNilString(value)),
|
|
@@ -1352,11 +1362,12 @@ class MatAutocompleteField {
|
|
|
1352
1362
|
tap(_ => this.showLoadingSpinner && this.markAsLoading()),
|
|
1353
1363
|
// Filter if not enough character
|
|
1354
1364
|
filter(value => {
|
|
1355
|
-
if (value.length
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1365
|
+
if (value.length <= this.suggestLengthThreshold) {
|
|
1366
|
+
// Update display value, to enable the message "not enough characters"
|
|
1367
|
+
this.displayValue = value;
|
|
1368
|
+
return false;
|
|
1369
|
+
}
|
|
1370
|
+
return true;
|
|
1360
1371
|
}),
|
|
1361
1372
|
// Wait a debounce time
|
|
1362
1373
|
debounceTime(this.debounceTime)
|
|
@@ -1365,9 +1376,9 @@ class MatAutocompleteField {
|
|
|
1365
1376
|
),
|
|
1366
1377
|
// Object set: use it (no distinctUntilChanged() pipe need)
|
|
1367
1378
|
this.formControl.valueChanges
|
|
1368
|
-
.pipe(startWith(this.formControl.value), filter(value => (
|
|
1379
|
+
.pipe(startWith(this.formControl.value), filter(value => (isNotNil(value) && typeof value === 'object')), tap(value => {
|
|
1369
1380
|
// DEBUG
|
|
1370
|
-
//if (this.debug) console.debug(this.logPrefix + ' object changes:', value)
|
|
1381
|
+
//if (this.debug) console.debug(this.logPrefix + ' control object changes:', value);
|
|
1371
1382
|
var _a;
|
|
1372
1383
|
// Update the display value (if need)
|
|
1373
1384
|
const displayValue = this.displayWith(value) || '';
|
|
@@ -1377,30 +1388,39 @@ class MatAutocompleteField {
|
|
|
1377
1388
|
if ((_a = this.matInputText) === null || _a === void 0 ? void 0 : _a.nativeElement) {
|
|
1378
1389
|
this.matInputText.nativeElement.value = this.displayValue;
|
|
1379
1390
|
}
|
|
1391
|
+
this.markForCheck();
|
|
1380
1392
|
}
|
|
1381
|
-
})
|
|
1382
|
-
//
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
//
|
|
1386
|
-
|
|
1387
|
-
|
|
1393
|
+
}),
|
|
1394
|
+
// If multiple: do not recompute items (only for the first time, when loading)
|
|
1395
|
+
// when formControl value changes
|
|
1396
|
+
filter(() => !this.multiple || this.loading), map(value => this.showAllOnFocus && this.suggestLengthThreshold <= 0 ? '*' : value)
|
|
1397
|
+
// DEBUG
|
|
1398
|
+
//,tap(value => this.debug && console.debug(this.logPrefix + ' Received an control object value: ', value))
|
|
1399
|
+
),
|
|
1400
|
+
// Merge some observables, with a common distinctUntilChanged() pipe
|
|
1388
1401
|
merge(
|
|
1389
|
-
//
|
|
1390
|
-
|
|
1391
|
-
.pipe(filter(
|
|
1402
|
+
// On dropdown button click (no debounceTime)
|
|
1403
|
+
this.dropButtonClick
|
|
1404
|
+
.pipe(filter(event => (!event || !event.defaultPrevented))),
|
|
1405
|
+
// Focus or click => Load all (no debounceTime)
|
|
1406
|
+
merge(this.focused, this.clicked),
|
|
1392
1407
|
// DEBUG
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
filter
|
|
1408
|
+
//.pipe(tap(_ => this.debug && console.debug(this.logPrefix + ' Received focused or clicked event'))),
|
|
1409
|
+
// Input items or filter changes
|
|
1410
|
+
merge(this.$inputItems, this._$filter)
|
|
1411
|
+
// DEBUG
|
|
1412
|
+
.pipe(filter(_ => !this.loading)
|
|
1413
|
+
//,tap(_ => this.debug && console.debug(this.logPrefix + ' Received $inputItems or filter event'))
|
|
1414
|
+
))
|
|
1415
|
+
.pipe(filter(_ => this.enabled), map(_ => this.showAllOnFocus ? '*' : this.formControl.value),
|
|
1399
1416
|
// Distinguish changes
|
|
1400
|
-
|
|
1401
|
-
|
|
1417
|
+
distinctUntilChanged((v1, v2) =>
|
|
1418
|
+
// If loading (not loaded yet), simulate that value changed to force load
|
|
1419
|
+
this.loading ? false : (v1 === v2 || this.equals(v1, v2))),
|
|
1420
|
+
// Make sure there is enough characters
|
|
1421
|
+
filter(thresholdFilterFn)
|
|
1402
1422
|
// DEBUG
|
|
1403
|
-
//,tap(value => this.debug && console.debug(this.logPrefix + ' Received update event: ', value))
|
|
1423
|
+
//,tap(value => this.debug && console.debug(this.logPrefix + ' Received update event from observables: ', value))
|
|
1404
1424
|
))
|
|
1405
1425
|
.pipe(
|
|
1406
1426
|
// Suggest values
|
|
@@ -1408,7 +1428,7 @@ class MatAutocompleteField {
|
|
|
1408
1428
|
// DEBUG
|
|
1409
1429
|
//tap(items => this.debug && console.debug(this.logPrefix + ' Received from suggest: ', items)),
|
|
1410
1430
|
// Store implicit value (will use it onBlur if not other value selected)
|
|
1411
|
-
tap(items => this.updateImplicitValue(items)));
|
|
1431
|
+
tap(items => !this.multiple && !this.mobile && this.updateImplicitValue(items)));
|
|
1412
1432
|
// Fetch more events
|
|
1413
1433
|
const fetchMoreItemsChanges = this._fetchMore$
|
|
1414
1434
|
.pipe(tap(event => event === null || event === void 0 ? void 0 : event.preventDefault()), // Avoid to close the mat-select
|
|
@@ -1425,7 +1445,7 @@ class MatAutocompleteField {
|
|
|
1425
1445
|
fetchMoreItemsChanges)
|
|
1426
1446
|
.subscribe(items => {
|
|
1427
1447
|
// Make sure control value is inside (mat-select)
|
|
1428
|
-
if (items && this.mobile) {
|
|
1448
|
+
if (items && (this.mobile || this.multiple)) {
|
|
1429
1449
|
const value = this.formControl.value;
|
|
1430
1450
|
// If form value is missing: append to list
|
|
1431
1451
|
if (isNotNil(value)) {
|
|
@@ -1443,11 +1463,11 @@ class MatAutocompleteField {
|
|
|
1443
1463
|
// Applying implicit value, on blur
|
|
1444
1464
|
this._subscription.add(this.blurred
|
|
1445
1465
|
.pipe(
|
|
1446
|
-
// Skip if
|
|
1447
|
-
filter(_ => !this.mobile
|
|
1466
|
+
// Skip if multiple (no implicit value) or disable
|
|
1467
|
+
filter(_ => !this.multiple && !this.mobile && this.enabled),
|
|
1448
1468
|
// DEBUG
|
|
1449
|
-
//,tap(
|
|
1450
|
-
)
|
|
1469
|
+
//,tap(_ => this.debug && console.debug(this.logPrefix + ' Received blurred event')),
|
|
1470
|
+
map(_ => this.formControl.value))
|
|
1451
1471
|
.subscribe(value => {
|
|
1452
1472
|
// When leave component without object, use implicit value if :
|
|
1453
1473
|
// - an explicit value
|
|
@@ -1465,16 +1485,14 @@ class MatAutocompleteField {
|
|
|
1465
1485
|
this.formControl.markAsPending({ emitEvent: false, onlySelf: true });
|
|
1466
1486
|
this.formControl.updateValueAndValidity({ emitEvent: false, onlySelf: true });
|
|
1467
1487
|
this.checkIfTouched();
|
|
1468
|
-
this
|
|
1488
|
+
this.markAsLoading();
|
|
1469
1489
|
}
|
|
1470
1490
|
this._implicitValue = null; // reset the implicit value
|
|
1471
1491
|
this.closePanel(); // Clone panel
|
|
1472
1492
|
}));
|
|
1473
1493
|
// Listen form control status change
|
|
1474
1494
|
this._subscription.add(this.formControl.statusChanges
|
|
1475
|
-
.pipe(
|
|
1476
|
-
//filter(() => this.enabled),
|
|
1477
|
-
distinctUntilChanged())
|
|
1495
|
+
.pipe(distinctUntilChanged())
|
|
1478
1496
|
// Update component state
|
|
1479
1497
|
.subscribe(() => this.checkIfTouched()));
|
|
1480
1498
|
this._subscription.add(this.keydownEscape.subscribe(event => {
|
|
@@ -1529,8 +1547,10 @@ class MatAutocompleteField {
|
|
|
1529
1547
|
* Allow to reload content. Useful when filter has been changed but not detected
|
|
1530
1548
|
*/
|
|
1531
1549
|
reloadItems(value) {
|
|
1550
|
+
// DEBUG
|
|
1551
|
+
//if (this.debug) console.debug(this.logPrefix + " Asking to reloadItems()");
|
|
1532
1552
|
// Force a refresh
|
|
1533
|
-
this._reload$.next(value || '*');
|
|
1553
|
+
this._reload$.next(value || (this.showAllOnFocus && this.suggestLengthThreshold <= 0 ? '*' : this.formControl.value));
|
|
1534
1554
|
// Clear the search bar (if hidden)
|
|
1535
1555
|
if (this.mobile && !this.matSelect.panelOpen && this.ionSearchbar) {
|
|
1536
1556
|
this.ionSearchbar.value = null;
|
|
@@ -1541,6 +1561,7 @@ class MatAutocompleteField {
|
|
|
1541
1561
|
// if (this.debug) console.debug(this.logPrefix + ' Writing value: ', value);
|
|
1542
1562
|
if (value !== this.formControl.value) {
|
|
1543
1563
|
this.formControl.patchValue(value, { emitEvent: false });
|
|
1564
|
+
this.displayValue = this.displayWith(value);
|
|
1544
1565
|
this._onChangeCallback(value);
|
|
1545
1566
|
}
|
|
1546
1567
|
}
|
|
@@ -1642,8 +1663,10 @@ class MatAutocompleteField {
|
|
|
1642
1663
|
return;
|
|
1643
1664
|
// DEBUG
|
|
1644
1665
|
// console.debug(this.logPrefix + " Received <mat-select> blur event", event);
|
|
1666
|
+
if (event.relatedTarget instanceof HTMLElement && (
|
|
1645
1667
|
// Ignore event from mat-option
|
|
1646
|
-
|
|
1668
|
+
(event.relatedTarget.tagName === 'MAT-OPTION')
|
|
1669
|
+
|| (event.relatedTarget.tagName === 'INPUT') && event.relatedTarget.classList.contains('searchbar-input'))) {
|
|
1647
1670
|
event.preventDefault();
|
|
1648
1671
|
if (event.stopPropagation)
|
|
1649
1672
|
event.stopPropagation();
|
|
@@ -1658,6 +1681,10 @@ class MatAutocompleteField {
|
|
|
1658
1681
|
clearValue(event) {
|
|
1659
1682
|
this.writeValue(null);
|
|
1660
1683
|
event.stopPropagation();
|
|
1684
|
+
if (this.ionSearchbar) {
|
|
1685
|
+
this.ionSearchbar.value = null;
|
|
1686
|
+
}
|
|
1687
|
+
this.markAsLoading();
|
|
1661
1688
|
}
|
|
1662
1689
|
_initAutocompleteInfiniteScroll(threshold) {
|
|
1663
1690
|
if (!this.autocomplete)
|
|
@@ -1724,7 +1751,7 @@ class MatAutocompleteField {
|
|
|
1724
1751
|
// Call suggestion function
|
|
1725
1752
|
let res = yield this.suggestFn(value, filter);
|
|
1726
1753
|
// DEBUG
|
|
1727
|
-
//console.debug(this.logPrefix + ' Filtered items by suggestFn:', value, res);
|
|
1754
|
+
//if (this.debug) console.debug(this.logPrefix + ' Filtered items by suggestFn:', value, res);
|
|
1728
1755
|
if (!res) {
|
|
1729
1756
|
this._itemCount = 0;
|
|
1730
1757
|
this._onFetchMoreCallback = undefined;
|
|
@@ -1762,7 +1789,7 @@ class MatAutocompleteField {
|
|
|
1762
1789
|
});
|
|
1763
1790
|
}
|
|
1764
1791
|
updateImplicitValue(items) {
|
|
1765
|
-
if (!this.
|
|
1792
|
+
if (!this.multiple) {
|
|
1766
1793
|
// Store implicit value (will use it onBlur if not other value selected)
|
|
1767
1794
|
if (items && items.length === 1) {
|
|
1768
1795
|
this._implicitValue = items[0];
|
|
@@ -1815,7 +1842,7 @@ MatAutocompleteField.decorators = [
|
|
|
1815
1842
|
{ type: Component, args: [{
|
|
1816
1843
|
// eslint-disable-next-line @angular-eslint/component-selector
|
|
1817
1844
|
selector: 'mat-autocomplete-field',
|
|
1818
|
-
template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <!-- readonly -->\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Mobile or Mutliple (use <mat-select>) -->\n <mat-select #matSelect\n *ngIf=\"mobile || multiple; else desktopTemplate\"\n [disableRipple]=\"true\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [typeaheadDebounceInterval]=\"debounceTime * 10\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- Search bar -->\n <ion-searchbar *ngIf=\"showSearchBar\" #ionSearchbar\n class=\"mat-select-header\"\n [class.ion-searchbar-sticky]=\"stickySearchBar\"\n inputmode=\"search\"\n autocomplete=\"off\"\n animated=\"true\"\n showClearButton\n [debounce]=\"debounceTime\"\n (ionClear)=\"markAsLoading()\"\n (ionInput)=\"markAsLoading()\"\n (ionChange)=\"ionSearchBarChanged($event, $event.detail.value)\"\n [placeholder]=\"'COMMON.BTN_SEARCH'|translate\"\n ></ion-searchbar>\n\n <!-- Headers -->\n <ion-row class=\"mat-select-header column ion-no-padding\"\n [class.multiple]=\"multiple\"\n [class.ion-searchbar-sticky]=\"showSearchBar && stickySearchBar\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required && !multiple && !clearable\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async as items; else loadingTemplate\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <!-- Options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- footer -->\n <ion-row *ngIf=\"itemCount as count\"\n class=\"mat-autocomplete-footer ion-no-padding\">\n <ion-col>\n <ion-text class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(displayValue | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #desktopTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n <!-- Headers -->\n <ion-row class=\"mat-autocomplete-header column ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- Options -->\n <ng-container *ngIf=\"$filteredItems | async as items; else loadingTemplate\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(displayValue | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n\n <!-- footer -->\n <ion-row *ngIf=\"itemCount; let count\" class=\"mat-autocomplete-footer ion-no-padding\">\n <ion-col>\n <ion-text class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"desktop\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n\n<ng-template #headers>\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n</ng-template>\n\n<ng-template #options>\n\n\n</ng-template>\n\n",
|
|
1845
|
+
template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <!-- readonly -->\n <mat-form-field *ngIf=\"_readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n [appearance]=\"appearance\"\n [title]=\"displayValue\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\" readonly>\n <ion-text>{{displayWith(value)}}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n </mat-form-field>\n\n <ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"disabled\"\n [title]=\"displayValue\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <!-- Mobile or Multiple (use <mat-select>) -->\n <mat-select #matSelect\n *ngIf=\"mobile || multiple; else desktopTemplate\"\n [disableRipple]=\"true\"\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\"\n [tabindex]=\"_tabindex\"\n [panelClass]=\"classList\"\n [style.width]=\"panelWidth\"\n (focus)=\"filterMatSelectFocusEvent($event)\"\n (blur)=\"filterMatSelectBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n [compareWith]=\"equals\"\n [multiple]=\"multiple\"\n [typeaheadDebounceInterval]=\"debounceTime * 10\"\n [required]=\"required\">\n <mat-select-trigger>{{ displayWith(value) }}</mat-select-trigger>\n\n <!-- Search bar -->\n <mat-option class=\"mat-select-searchbar\" *ngIf=\"showSearchBar\"\n [class.mat-select-searchbar-sticky]=\"stickySearchBar\"\n disabled>\n <ion-searchbar #ionSearchbar\n inputmode=\"search\"\n autocomplete=\"off\"\n animated=\"true\"\n showClearButton=\"true\"\n [debounce]=\"debounceTime\"\n (ionClear)=\"markAsLoading()\"\n (ionInput)=\"markAsLoading()\"\n (ionChange)=\"ionSearchBarChanged($event, $event.detail.value)\"\n [placeholder]=\"'COMMON.BTN_SEARCH'|translate\"\n ></ion-searchbar>\n </mat-option>\n\n <!-- Headers -->\n <ion-row class=\"mat-select-header column ion-no-padding\"\n [class.multiple]=\"multiple\"\n [class.mat-select-searchbar-sticky]=\"showSearchBar && stickySearchBar\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- None option -->\n <mat-option *ngIf=\"!required && !multiple && !clearable\" class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding\">\n <ion-col class=\"ion-no-padding\">\n <ion-label><i translate>COMMON.EMPTY_OPTION</i></ion-label>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <ng-container *ngIf=\"$filteredItems | async as items; else loadingTemplate\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <!-- Options -->\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initMatSelectInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- footer -->\n <mat-option *ngIf=\"itemCount as count\" class=\"mat-option-footer mat-autocomplete-footer ion-no-padding\" disabled>\n <ion-text class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </mat-option>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(displayValue | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-select>\n\n\n <!--\n NOTE :\n - \"selectInputContent($event) || onFocus.emit($event)\" : call onFocus only when to the input is empty (nothing to select)\n -->\n <ng-template #desktopTemplate>\n <input matInput #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\">\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n <!-- Headers -->\n <ion-row class=\"mat-autocomplete-header column ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <!-- Options -->\n <ng-container *ngIf=\"$filteredItems | async as items; else loadingTemplate\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label><i>{{noResultMessage | translate}}</i></ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: formControl.value, withAccent: highlightAccent }\"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(displayValue | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n\n <!-- footer -->\n <ion-row *ngIf=\"itemCount; let count\" class=\"mat-autocomplete-footer ion-no-padding\">\n <ion-col>\n <ion-text class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n </mat-autocomplete>\n\n </ng-template>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"!mobile && !multiple\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n\n<ng-template #headers>\n <ion-row class=\"mat-autocomplete-header ion-no-padding\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n</ng-template>\n\n<ng-template #options>\n\n\n</ng-template>\n\n",
|
|
1819
1846
|
providers: [{
|
|
1820
1847
|
provide: NG_VALUE_ACCESSOR,
|
|
1821
1848
|
multi: true,
|
|
@@ -1836,6 +1863,7 @@ MatAutocompleteField.propDecorators = {
|
|
|
1836
1863
|
formControl: [{ type: Input }],
|
|
1837
1864
|
formControlName: [{ type: Input }],
|
|
1838
1865
|
floatLabel: [{ type: Input }],
|
|
1866
|
+
appearance: [{ type: Input }],
|
|
1839
1867
|
placeholder: [{ type: Input }],
|
|
1840
1868
|
suggestFn: [{ type: Input }],
|
|
1841
1869
|
required: [{ type: Input }],
|
|
@@ -2222,52 +2250,49 @@ function roundFloat(input, maxDecimals) {
|
|
|
2222
2250
|
return input;
|
|
2223
2251
|
}
|
|
2224
2252
|
|
|
2225
|
-
/**
|
|
2226
|
-
* @deprecated use 'latitudeFormat' or 'longitudeFormat' instead
|
|
2227
|
-
*/
|
|
2228
|
-
class LatLongFormatPipe {
|
|
2229
|
-
transform(value, args) {
|
|
2230
|
-
return ((!args.type || args.type !== 'latitude') ? formatLongitude : formatLatitude)(value, args);
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2233
|
-
LatLongFormatPipe.ɵprov = ɵɵdefineInjectable({ factory: function LatLongFormatPipe_Factory() { return new LatLongFormatPipe(); }, token: LatLongFormatPipe, providedIn: "root" });
|
|
2234
|
-
LatLongFormatPipe.decorators = [
|
|
2235
|
-
{ type: Pipe, args: [{
|
|
2236
|
-
name: 'latLongFormat'
|
|
2237
|
-
},] },
|
|
2238
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
2239
|
-
];
|
|
2240
2253
|
class LatitudeFormatPipe {
|
|
2241
2254
|
constructor() {
|
|
2242
2255
|
this.transform = formatLatitude;
|
|
2243
2256
|
}
|
|
2244
2257
|
}
|
|
2245
|
-
LatitudeFormatPipe.ɵprov = ɵɵdefineInjectable({ factory: function LatitudeFormatPipe_Factory() { return new LatitudeFormatPipe(); }, token: LatitudeFormatPipe, providedIn: "root" });
|
|
2246
2258
|
LatitudeFormatPipe.decorators = [
|
|
2247
2259
|
{ type: Pipe, args: [{
|
|
2248
2260
|
name: 'latitudeFormat'
|
|
2249
|
-
},] }
|
|
2250
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
2261
|
+
},] }
|
|
2251
2262
|
];
|
|
2252
2263
|
class LongitudeFormatPipe {
|
|
2253
2264
|
constructor() {
|
|
2254
2265
|
this.transform = formatLongitude;
|
|
2255
2266
|
}
|
|
2256
2267
|
}
|
|
2257
|
-
LongitudeFormatPipe.ɵprov = ɵɵdefineInjectable({ factory: function LongitudeFormatPipe_Factory() { return new LongitudeFormatPipe(); }, token: LongitudeFormatPipe, providedIn: "root" });
|
|
2258
2268
|
LongitudeFormatPipe.decorators = [
|
|
2259
2269
|
{ type: Pipe, args: [{
|
|
2260
2270
|
name: 'longitudeFormat'
|
|
2261
|
-
},] }
|
|
2262
|
-
|
|
2271
|
+
},] }
|
|
2272
|
+
];
|
|
2273
|
+
/**
|
|
2274
|
+
* @deprecated use 'latitudeFormat' or 'longitudeFormat' instead
|
|
2275
|
+
*/
|
|
2276
|
+
class LatLongFormatPipe {
|
|
2277
|
+
transform(value, opts) {
|
|
2278
|
+
return ((!opts || (opts === null || opts === void 0 ? void 0 : opts.type) !== 'latitude') ? formatLongitude : formatLatitude)(value, opts);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
LatLongFormatPipe.decorators = [
|
|
2282
|
+
{ type: Pipe, args: [{
|
|
2283
|
+
name: 'latLongFormat'
|
|
2284
|
+
},] }
|
|
2263
2285
|
];
|
|
2264
2286
|
|
|
2265
2287
|
class NumberFormatPipe {
|
|
2266
|
-
transform(val,
|
|
2288
|
+
transform(val, opts) {
|
|
2267
2289
|
// Format the output to display any way you want here.
|
|
2268
2290
|
// For instance:
|
|
2269
2291
|
if (val !== undefined && val !== null) {
|
|
2270
|
-
|
|
2292
|
+
if (opts === null || opts === void 0 ? void 0 : opts.fixedDecimals) {
|
|
2293
|
+
return val.toFixed(opts.fixedDecimals);
|
|
2294
|
+
}
|
|
2295
|
+
return val.toLocaleString(undefined, opts);
|
|
2271
2296
|
}
|
|
2272
2297
|
else {
|
|
2273
2298
|
return '';
|
|
@@ -2380,15 +2405,9 @@ FileSizePipe.decorators = [
|
|
|
2380
2405
|
];
|
|
2381
2406
|
|
|
2382
2407
|
const moment$1 = momentImported;
|
|
2383
|
-
const tz = momentTZImported;
|
|
2384
2408
|
const DATE_UNIX_TIMESTAMP = 'X';
|
|
2385
2409
|
const DATE_UNIX_MS_TIMESTAMP = 'x';
|
|
2386
2410
|
class DateUtils {
|
|
2387
|
-
constructor() {
|
|
2388
|
-
this.toDateISOString = toDateISOString;
|
|
2389
|
-
this.fromDateISOString = fromDateISOString;
|
|
2390
|
-
this.toDuration = toDuration;
|
|
2391
|
-
}
|
|
2392
2411
|
static min(date1, date2) {
|
|
2393
2412
|
return date1 && (!date2 || date1.isSameOrBefore(date2)) ? date1 : date2;
|
|
2394
2413
|
}
|
|
@@ -2438,6 +2457,9 @@ class DateUtils {
|
|
|
2438
2457
|
return date.day() === weekday;
|
|
2439
2458
|
}
|
|
2440
2459
|
}
|
|
2460
|
+
DateUtils.toDateISOString = toDateISOString;
|
|
2461
|
+
DateUtils.fromDateISOString = fromDateISOString;
|
|
2462
|
+
DateUtils.toDuration = toDuration;
|
|
2441
2463
|
function toDateISOString(value) {
|
|
2442
2464
|
if (!value)
|
|
2443
2465
|
return undefined;
|
|
@@ -2908,7 +2930,7 @@ const moment$2 = momentImported;
|
|
|
2908
2930
|
// @dynamic
|
|
2909
2931
|
class SharedValidators {
|
|
2910
2932
|
static getDoubleRegexp(maxDecimals) {
|
|
2911
|
-
if (isNil(maxDecimals)
|
|
2933
|
+
if (isNil(maxDecimals))
|
|
2912
2934
|
return this._REGEXP_CACHE.DOUBLE_BY_MAX_DECIMALS.NO_LIMIT;
|
|
2913
2935
|
if (maxDecimals < 0)
|
|
2914
2936
|
throw new Error(`Invalid maxDecimals value: ${maxDecimals}`);
|
|
@@ -2969,7 +2991,7 @@ class SharedValidators {
|
|
|
2969
2991
|
}
|
|
2970
2992
|
return null;
|
|
2971
2993
|
}
|
|
2972
|
-
static
|
|
2994
|
+
static decimal(opts) {
|
|
2973
2995
|
const regexp = this.getDoubleRegexp(opts === null || opts === void 0 ? void 0 : opts.maxDecimals);
|
|
2974
2996
|
return (control) => {
|
|
2975
2997
|
let value = control.value;
|
|
@@ -2978,7 +3000,7 @@ class SharedValidators {
|
|
|
2978
3000
|
return null;
|
|
2979
3001
|
}
|
|
2980
3002
|
if (isNotNil(value) && value !== '' && !regexp.test(value)) {
|
|
2981
|
-
return
|
|
3003
|
+
return isNotNil(opts === null || opts === void 0 ? void 0 : opts.maxDecimals) ? { maxDecimals: { maxDecimals: opts.maxDecimals } } : { decimal: true };
|
|
2982
3004
|
}
|
|
2983
3005
|
return null;
|
|
2984
3006
|
};
|
|
@@ -3110,6 +3132,7 @@ SharedValidators.I18N_ERROR_KEYS = {
|
|
|
3110
3132
|
dateMinDuration: 'ERROR.FIELD_NOT_VALID_DATE_MIN_DURATION',
|
|
3111
3133
|
dateMaxDuration: 'ERROR.FIELD_NOT_VALID_DATE_MAX_DURATION',
|
|
3112
3134
|
maxDecimals: 'ERROR.FIELD_MAXIMUM_DECIMALS',
|
|
3135
|
+
double: 'ERROR.FIELD_NOT_VALID_DOUBLE',
|
|
3113
3136
|
integer: 'ERROR.FIELD_NOT_VALID_INTEGER',
|
|
3114
3137
|
email: 'ERROR.FIELD_NOT_VALID_EMAIL',
|
|
3115
3138
|
latitude: 'ERROR.FIELD_NOT_VALID_LATITUDE',
|
|
@@ -3118,6 +3141,10 @@ SharedValidators.I18N_ERROR_KEYS = {
|
|
|
3118
3141
|
unique: 'ERROR.FIELD_NOT_UNIQUE',
|
|
3119
3142
|
entity: 'ERROR.FIELD_INVALID'
|
|
3120
3143
|
};
|
|
3144
|
+
/**
|
|
3145
|
+
* @deprecated use decimal
|
|
3146
|
+
*/
|
|
3147
|
+
SharedValidators.double = SharedValidators.decimal;
|
|
3121
3148
|
// @dynamic
|
|
3122
3149
|
class SharedFormGroupValidators {
|
|
3123
3150
|
static dateRange(startDateField, endDateField, msg) {
|
|
@@ -4132,8 +4159,8 @@ class FormErrorTranslatePipe {
|
|
|
4132
4159
|
// if there is a subscription to onLangChange, clean it
|
|
4133
4160
|
this._dispose();
|
|
4134
4161
|
// subscribe to onTranslationChange event, in case the translations change
|
|
4135
|
-
if (!this.
|
|
4136
|
-
this.
|
|
4162
|
+
if (!this._onFormStatusChanges) {
|
|
4163
|
+
this._onFormStatusChanges = form.statusChanges.subscribe((status) => {
|
|
4137
4164
|
this._updateValue(form, opts, status);
|
|
4138
4165
|
});
|
|
4139
4166
|
}
|
|
@@ -4156,9 +4183,9 @@ class FormErrorTranslatePipe {
|
|
|
4156
4183
|
* Clean any existing subscription to change events
|
|
4157
4184
|
*/
|
|
4158
4185
|
_dispose() {
|
|
4159
|
-
if (typeof this.
|
|
4160
|
-
this.
|
|
4161
|
-
this.
|
|
4186
|
+
if (typeof this._onFormStatusChanges !== 'undefined') {
|
|
4187
|
+
this._onFormStatusChanges.unsubscribe();
|
|
4188
|
+
this._onFormStatusChanges = undefined;
|
|
4162
4189
|
}
|
|
4163
4190
|
}
|
|
4164
4191
|
}
|
|
@@ -4177,48 +4204,112 @@ class FormGetPipe {
|
|
|
4177
4204
|
return form.get(path);
|
|
4178
4205
|
}
|
|
4179
4206
|
}
|
|
4180
|
-
FormGetPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetPipe_Factory() { return new FormGetPipe(); }, token: FormGetPipe, providedIn: "root" });
|
|
4181
4207
|
FormGetPipe.decorators = [
|
|
4182
4208
|
{ type: Pipe, args: [{
|
|
4183
4209
|
name: 'formGet'
|
|
4184
|
-
},] }
|
|
4185
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
4210
|
+
},] }
|
|
4186
4211
|
];
|
|
4187
4212
|
class FormGetControlPipe {
|
|
4188
4213
|
transform(form, path) {
|
|
4189
|
-
return form.get(path);
|
|
4214
|
+
return (form && path && form.get(path) || form);
|
|
4190
4215
|
}
|
|
4191
4216
|
}
|
|
4192
|
-
FormGetControlPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetControlPipe_Factory() { return new FormGetControlPipe(); }, token: FormGetControlPipe, providedIn: "root" });
|
|
4193
4217
|
FormGetControlPipe.decorators = [
|
|
4194
4218
|
{ type: Pipe, args: [{
|
|
4195
4219
|
name: 'formGetControl'
|
|
4196
|
-
},] }
|
|
4197
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
4220
|
+
},] }
|
|
4198
4221
|
];
|
|
4199
4222
|
class FormGetArrayPipe {
|
|
4200
4223
|
transform(form, path) {
|
|
4201
|
-
return form.get(path);
|
|
4224
|
+
return (form && path && form.get(path) || form);
|
|
4202
4225
|
}
|
|
4203
4226
|
}
|
|
4204
|
-
FormGetArrayPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetArrayPipe_Factory() { return new FormGetArrayPipe(); }, token: FormGetArrayPipe, providedIn: "root" });
|
|
4205
4227
|
FormGetArrayPipe.decorators = [
|
|
4206
4228
|
{ type: Pipe, args: [{
|
|
4207
4229
|
name: 'formGetArray'
|
|
4208
|
-
},] }
|
|
4209
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
4230
|
+
},] }
|
|
4210
4231
|
];
|
|
4211
4232
|
class FormGetGroupPipe {
|
|
4212
4233
|
transform(form, path) {
|
|
4213
|
-
return form.get(path);
|
|
4234
|
+
return (form && path && form.get(path) || form);
|
|
4214
4235
|
}
|
|
4215
4236
|
}
|
|
4216
|
-
FormGetGroupPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetGroupPipe_Factory() { return new FormGetGroupPipe(); }, token: FormGetGroupPipe, providedIn: "root" });
|
|
4217
4237
|
FormGetGroupPipe.decorators = [
|
|
4218
4238
|
{ type: Pipe, args: [{
|
|
4219
4239
|
name: 'formGetGroup'
|
|
4220
|
-
},] }
|
|
4221
|
-
|
|
4240
|
+
},] }
|
|
4241
|
+
];
|
|
4242
|
+
class FormGetValuePipe {
|
|
4243
|
+
constructor(adapter, _ref) {
|
|
4244
|
+
this.adapter = adapter;
|
|
4245
|
+
this._ref = _ref;
|
|
4246
|
+
this.value = undefined;
|
|
4247
|
+
this._lastControl = null;
|
|
4248
|
+
}
|
|
4249
|
+
transform(form, path, listenStatusChanges = false) {
|
|
4250
|
+
if (!form) {
|
|
4251
|
+
this._dispose();
|
|
4252
|
+
return undefined;
|
|
4253
|
+
}
|
|
4254
|
+
// if we ask another time for the same form and opts, return the last value
|
|
4255
|
+
if (form === this._lastControl && equals(path, this._lastPath)) {
|
|
4256
|
+
return this.value;
|
|
4257
|
+
}
|
|
4258
|
+
// store the query, in case it changes
|
|
4259
|
+
this._lastControl = form;
|
|
4260
|
+
// store the params, in case they change
|
|
4261
|
+
this._lastPath = path;
|
|
4262
|
+
// set the value
|
|
4263
|
+
const control = path ? form.get(path) : form;
|
|
4264
|
+
this.value = control === null || control === void 0 ? void 0 : control.value;
|
|
4265
|
+
// if there is a subscription to onLangChange, clean it
|
|
4266
|
+
this._dispose();
|
|
4267
|
+
// subscribe to valueChanges event, in case control value change
|
|
4268
|
+
if (!this._onControlValueChanges && control) {
|
|
4269
|
+
this._onControlValueChanges = control.valueChanges.subscribe((value) => {
|
|
4270
|
+
if (value !== this.value) {
|
|
4271
|
+
this.value = value;
|
|
4272
|
+
this._ref.markForCheck();
|
|
4273
|
+
}
|
|
4274
|
+
});
|
|
4275
|
+
}
|
|
4276
|
+
if (listenStatusChanges && !this._onControlStatusChanges && control) {
|
|
4277
|
+
this._onControlStatusChanges = control.statusChanges.subscribe((status) => {
|
|
4278
|
+
const value = control.value;
|
|
4279
|
+
if (value !== this.value) {
|
|
4280
|
+
this.value = value;
|
|
4281
|
+
this._ref.markForCheck();
|
|
4282
|
+
}
|
|
4283
|
+
});
|
|
4284
|
+
}
|
|
4285
|
+
return this.value;
|
|
4286
|
+
}
|
|
4287
|
+
ngOnDestroy() {
|
|
4288
|
+
this._dispose();
|
|
4289
|
+
}
|
|
4290
|
+
/**
|
|
4291
|
+
* Clean any existing subscription to change events
|
|
4292
|
+
*/
|
|
4293
|
+
_dispose() {
|
|
4294
|
+
if (typeof this._onControlValueChanges !== 'undefined') {
|
|
4295
|
+
this._onControlValueChanges.unsubscribe();
|
|
4296
|
+
this._onControlValueChanges = undefined;
|
|
4297
|
+
}
|
|
4298
|
+
if (typeof this._onControlStatusChanges !== 'undefined') {
|
|
4299
|
+
this._onControlStatusChanges.unsubscribe();
|
|
4300
|
+
this._onControlStatusChanges = undefined;
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
FormGetValuePipe.decorators = [
|
|
4305
|
+
{ type: Pipe, args: [{
|
|
4306
|
+
name: 'formGetValue',
|
|
4307
|
+
pure: false
|
|
4308
|
+
},] }
|
|
4309
|
+
];
|
|
4310
|
+
FormGetValuePipe.ctorParameters = () => [
|
|
4311
|
+
{ type: FormErrorTranslator },
|
|
4312
|
+
{ type: ChangeDetectorRef }
|
|
4222
4313
|
];
|
|
4223
4314
|
|
|
4224
4315
|
class SharedPipesModule {
|
|
@@ -4267,7 +4358,8 @@ SharedPipesModule.decorators = [
|
|
|
4267
4358
|
FormGetPipe,
|
|
4268
4359
|
FormGetControlPipe,
|
|
4269
4360
|
FormGetArrayPipe,
|
|
4270
|
-
FormGetGroupPipe
|
|
4361
|
+
FormGetGroupPipe,
|
|
4362
|
+
FormGetValuePipe
|
|
4271
4363
|
],
|
|
4272
4364
|
exports: [
|
|
4273
4365
|
PropertyGetPipe,
|
|
@@ -4306,7 +4398,8 @@ SharedPipesModule.decorators = [
|
|
|
4306
4398
|
FormGetPipe,
|
|
4307
4399
|
FormGetControlPipe,
|
|
4308
4400
|
FormGetArrayPipe,
|
|
4309
|
-
FormGetGroupPipe
|
|
4401
|
+
FormGetGroupPipe,
|
|
4402
|
+
FormGetValuePipe
|
|
4310
4403
|
]
|
|
4311
4404
|
},] }
|
|
4312
4405
|
];
|
|
@@ -4583,10 +4676,10 @@ class MatLatLongField {
|
|
|
4583
4676
|
this.disabling = false;
|
|
4584
4677
|
this.writing = false;
|
|
4585
4678
|
this._readonly = false;
|
|
4679
|
+
this.required = false;
|
|
4680
|
+
this.floatLabel = 'auto';
|
|
4586
4681
|
this.maxDecimals = LAT_LONG_DEFAULT_MAX_DECIMALS;
|
|
4587
4682
|
this.placeholderChar = DEFAULT_PLACEHOLDER_CHAR;
|
|
4588
|
-
this.floatLabel = 'auto';
|
|
4589
|
-
this.required = false;
|
|
4590
4683
|
this.onBlur = new EventEmitter();
|
|
4591
4684
|
this.onFocus = new EventEmitter();
|
|
4592
4685
|
}
|
|
@@ -4601,7 +4694,6 @@ class MatLatLongField {
|
|
|
4601
4694
|
return this._readonly;
|
|
4602
4695
|
}
|
|
4603
4696
|
ngOnInit() {
|
|
4604
|
-
this.mobile = isNotNil(this.mobile) ? this.mobile : isMobile(window);
|
|
4605
4697
|
this.type = this.type || 'latitude';
|
|
4606
4698
|
this.pattern = this.pattern || 'DDMM';
|
|
4607
4699
|
this.mask = MASKS[this.type] && MASKS[this.type][this.pattern];
|
|
@@ -4632,8 +4724,8 @@ class MatLatLongField {
|
|
|
4632
4724
|
this.maxDecimals = DEFAULT_MAX_DECIMALS;
|
|
4633
4725
|
}
|
|
4634
4726
|
this.showSignControl = this.pattern !== 'DD';
|
|
4635
|
-
this.
|
|
4636
|
-
this.
|
|
4727
|
+
this._formatFn = this.type === 'latitude' ? formatLatitude : formatLongitude;
|
|
4728
|
+
this._formatOptions = { pattern: this.pattern, maxDecimals: this.maxDecimals, hideSign: this.showSignControl };
|
|
4637
4729
|
this.inputPlaceholder = 'COMMON.LAT_LONG.' + (this.type === 'longitude' && 'D' || '') + this.pattern + '_PLACEHOLDER';
|
|
4638
4730
|
this.textFormControl = this.formBuilder.control(this.required ? [null, Validators.required] : [null]);
|
|
4639
4731
|
this.textMaskConfig = { mask: this.mask, keepCharPositions: true, placeholderChar: this.placeholderChar };
|
|
@@ -4667,7 +4759,7 @@ class MatLatLongField {
|
|
|
4667
4759
|
return;
|
|
4668
4760
|
this.value = (typeof obj === 'string') ? parseFloat(obj.replace(/,/g, '.')) : obj;
|
|
4669
4761
|
this.writing = true;
|
|
4670
|
-
const strValue = this.
|
|
4762
|
+
const strValue = this._formatFn(this.value, Object.assign(Object.assign({}, this._formatOptions), { placeholderChar: this.placeholderChar }));
|
|
4671
4763
|
const sign = isNotNil(this.value) ? (this.value < 0 ? -1 : 1) :
|
|
4672
4764
|
// Use default sign, if any
|
|
4673
4765
|
(this.defaultSign ? (this.defaultSign === '-' ? -1 : 1) : null);
|
|
@@ -4700,41 +4792,13 @@ class MatLatLongField {
|
|
|
4700
4792
|
this.disabling = false;
|
|
4701
4793
|
this.markForCheck();
|
|
4702
4794
|
}
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
4709
|
-
|
|
4710
|
-
this.writing = false;
|
|
4711
|
-
return;
|
|
4712
|
-
}
|
|
4713
|
-
const parsedValue = isNotNilOrBlank(strValue) ? parseLatitudeOrLongitude(strValue, this.pattern, 7 /*=precision of the converted double value */, this.placeholderChar) : null;
|
|
4714
|
-
// DEBUG
|
|
4715
|
-
//console.debug('parsedValue=', parsedValue);
|
|
4716
|
-
if (isNaN(parsedValue)) {
|
|
4717
|
-
this.formControl.markAsPending();
|
|
4718
|
-
this.formControl.setErrors(this.type === 'latitude' ? { latitude: true } : { longitude: true });
|
|
4719
|
-
this.writing = false;
|
|
4720
|
-
return;
|
|
4721
|
-
}
|
|
4722
|
-
const sign = (this.pattern === 'DD') ? 1 /*ignore sign*/ : (this.signFormControl.value || 1);
|
|
4723
|
-
this.value = isNotNil(parsedValue) ? sign * parsedValue : null;
|
|
4724
|
-
// Get the model value
|
|
4725
|
-
//console.debug("[mat-latlon] Setting value {" + this.value + "} parsed from {" + strValue + "}");
|
|
4726
|
-
this.formControl.patchValue(this.value, { emitEvent: false });
|
|
4727
|
-
this.writing = false;
|
|
4728
|
-
this.markForCheck();
|
|
4729
|
-
this._onChangeCallback(this.value);
|
|
4730
|
-
}
|
|
4731
|
-
checkIfTouched() {
|
|
4732
|
-
if (this.formControl.touched || this.textFormControl.touched) {
|
|
4733
|
-
this.markForCheck();
|
|
4734
|
-
this._onTouchedCallback();
|
|
4735
|
-
return true;
|
|
4736
|
-
}
|
|
4737
|
-
return false;
|
|
4795
|
+
/**
|
|
4796
|
+
* Format value to display as string (no placeholder char, and show sign)
|
|
4797
|
+
* @param value
|
|
4798
|
+
* @param opts
|
|
4799
|
+
*/
|
|
4800
|
+
_format(value, opts) {
|
|
4801
|
+
return this._formatFn(value, Object.assign(Object.assign({}, this._formatOptions), { hideSign: false, placeholderChar: '' }));
|
|
4738
4802
|
}
|
|
4739
4803
|
_onFocus(event) {
|
|
4740
4804
|
// Apply the default sign, when pattern is DD and field is empty
|
|
@@ -4743,7 +4807,8 @@ class MatLatLongField {
|
|
|
4743
4807
|
// Compute the text value, using the default sign
|
|
4744
4808
|
const defaultSign = this.defaultSign === '-' ? -1 : 1;
|
|
4745
4809
|
if (this.pattern === 'DD') {
|
|
4746
|
-
let valueStr = this.
|
|
4810
|
+
let valueStr = this._formatFn(defaultSign, Object.assign(Object.assign({}, this._formatOptions), { placeholderChar: this.placeholderChar }));
|
|
4811
|
+
// Keep only the sign ('+' or '-') and placeholder chars, but NOT the '1'
|
|
4747
4812
|
valueStr = valueStr && valueStr.replace('1', this.placeholderChar);
|
|
4748
4813
|
// Wait end of focus animation (label should move to top)
|
|
4749
4814
|
setTimeout(() => {
|
|
@@ -4843,6 +4908,42 @@ class MatLatLongField {
|
|
|
4843
4908
|
}
|
|
4844
4909
|
}
|
|
4845
4910
|
}
|
|
4911
|
+
onFormChange(strValue) {
|
|
4912
|
+
if (this.writing)
|
|
4913
|
+
return; // Skip if call by self
|
|
4914
|
+
this.writing = true;
|
|
4915
|
+
if (this.textFormControl.invalid || this.signFormControl.invalid) {
|
|
4916
|
+
this.formControl.markAsPending();
|
|
4917
|
+
this.formControl.setErrors(Object.assign(Object.assign(Object.assign({}, this.formControl.errors), this.textFormControl.errors), this.signFormControl.errors));
|
|
4918
|
+
this.writing = false;
|
|
4919
|
+
return;
|
|
4920
|
+
}
|
|
4921
|
+
const parsedValue = isNotNilOrBlank(strValue) ? parseLatitudeOrLongitude(strValue, this.pattern, 7 /*=precision of the converted double value */, this.placeholderChar) : null;
|
|
4922
|
+
// DEBUG
|
|
4923
|
+
//console.debug('parsedValue=', parsedValue);
|
|
4924
|
+
if (isNaN(parsedValue)) {
|
|
4925
|
+
this.formControl.markAsPending();
|
|
4926
|
+
this.formControl.setErrors(this.type === 'latitude' ? { latitude: true } : { longitude: true });
|
|
4927
|
+
this.writing = false;
|
|
4928
|
+
return;
|
|
4929
|
+
}
|
|
4930
|
+
const sign = (this.pattern === 'DD') ? 1 /*ignore sign*/ : (this.signFormControl.value || 1);
|
|
4931
|
+
this.value = isNotNil(parsedValue) ? sign * parsedValue : null;
|
|
4932
|
+
// Get the model value
|
|
4933
|
+
//console.debug("[mat-latlon] Setting value {" + this.value + "} parsed from {" + strValue + "}");
|
|
4934
|
+
this.formControl.patchValue(this.value, { emitEvent: false });
|
|
4935
|
+
this.writing = false;
|
|
4936
|
+
this.markForCheck();
|
|
4937
|
+
this._onChangeCallback(this.value);
|
|
4938
|
+
}
|
|
4939
|
+
checkIfTouched() {
|
|
4940
|
+
if (this.formControl.touched || this.textFormControl.touched) {
|
|
4941
|
+
this.markForCheck();
|
|
4942
|
+
this._onTouchedCallback();
|
|
4943
|
+
return true;
|
|
4944
|
+
}
|
|
4945
|
+
return false;
|
|
4946
|
+
}
|
|
4846
4947
|
markForCheck() {
|
|
4847
4948
|
this.cd.markForCheck();
|
|
4848
4949
|
}
|
|
@@ -4850,7 +4951,7 @@ class MatLatLongField {
|
|
|
4850
4951
|
MatLatLongField.decorators = [
|
|
4851
4952
|
{ type: Component, args: [{
|
|
4852
4953
|
selector: 'mat-latlong-field',
|
|
4853
|
-
template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n readonly\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\">\n <ion-text>{{
|
|
4954
|
+
template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n readonly\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\">\n <ion-text>{{_format(value) }}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n</mat-form-field>\n\n<!-- writable -->\n<ng-template #writable>\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row class=\"ion-no-padding no-wrap\">\n <ion-col class=\"text ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\"\n [class.mat-form-field-disabled]=\"formControl.disabled\"\n [class.mat-form-field-invalid]=\"formControl.touched && formControl.invalid\">\n\n <mat-label *ngIf=\"placeholder\">{{placeholder}}</mat-label>\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput #inputElement\n type=\"text\"\n autocomplete=\"off\"\n [textMask]=\"textMaskConfig\"\n [formControl]=\"textFormControl\"\n [placeholder]=\"inputPlaceholder|translate\"\n (keypress)=\"onKeypress($event)\"\n (keydown.tab)=\"moveCaretToSeparator($event, true)\"\n (keydown.shift.tab)=\"moveCaretToSeparator($event, false)\"\n (focus)=\"_onFocus($event)\"\n (blur)=\"_onBlur($event)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\">\n\n <div matSuffix *ngIf=\"!showSignControl\">\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <div class=\"mat-form-field-subscript mat-form-field-subscript-wrapper\">\n\n <!-- errors -->\n <ng-container *ngIf=\"formControl.touched && formControl.errors|mapKeys|arrayFirst; let errorKey\" [ngSwitch]=\"errorKey\">\n <mat-error *ngSwitchCase=\"'required'\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngSwitchCase=\"'latitude'\" translate>ERROR.FIELD_NOT_VALID_LATITUDE</mat-error>\n <mat-error *ngSwitchCase=\"'longitude'\" translate>ERROR.FIELD_NOT_VALID_LONGITUDE</mat-error>\n <mat-error *ngSwitchCase=\"'min'\">{{'ERROR.FIELD_MIN_COMPACT'|translate: {min: _format(formControl.errors.min.min) } }}</mat-error>\n <mat-error *ngSwitchCase=\"'max'\">{{'ERROR.FIELD_MAX_COMPACT'|translate: {max: _format(formControl.errors.max.max) } }}</mat-error>\n <mat-error *ngSwitchCase=\"'msg'\">{{(formControl.errors.msg?.key || formControl.errors.msg) | translate: formControl.errors.msg?.params}}</mat-error>\n </ng-container>\n <ng-content select=\"mat-error\"></ng-content>\n\n <!-- mat hint -->\n <div class=\"mat-form-field-hint-wrapper\" [class.cdk-visually-hidden]=\"formControl.invalid\">\n <div class=\"mat-form-field-hint-spacer\"></div>\n <ng-content select=\"mat-hint\"></ng-content>\n </div>\n </div>\n </mat-form-field>\n </ion-col>\n\n <!-- sign -->\n <ion-col class=\"sign ion-no-padding\" [ngSwitch]=\"type\" *ngIf=\"showSignControl\">\n\n <!-- sign on latitude -->\n <mat-form-field *ngSwitchCase=\"'latitude'\"\n floatLabel=\"never\"\n [class.mat-form-field-invalid]=\"formControl.touched && signFormControl.invalid\">\n <mat-label *ngIf=\"placeholder && floatLabel != 'never'\" translate>COMMON.LAT_LONG.LAT_SIGN_PLACEHOLDER</mat-label>\n <mat-select [formControl]=\"signFormControl\"\n [tabindex]=\"tabindex+1\">\n <mat-option [value]=\"1\">{{'COMMON.LAT_LONG.LAT_SIGN_N'|translate}}</mat-option>\n <mat-option [value]=\"-1\" >{{'COMMON.LAT_LONG.LAT_SIGN_S'|translate}}</mat-option>\n </mat-select>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n\n <!-- sign on longitude -->\n <mat-form-field floatLabel=\"never\"\n *ngSwitchCase=\"'longitude'\"\n [class.mat-form-field-invalid]=\"formControl.touched && signFormControl.invalid\">\n <mat-label *ngIf=\"placeholder && floatLabel != 'never'\" translate>COMMON.LAT_LONG.LONG_SIGN_PLACEHOLDER</mat-label>\n <mat-select [formControl]=\"signFormControl\"\n [tabindex]=\"tabindex+2\">\n <mat-option [value]=\"1\" translate>{{'COMMON.LAT_LONG.LONG_SIGN_E'|translate}}</mat-option>\n <mat-option [value]=\"-1\" translate>{{'COMMON.LAT_LONG.LONG_SIGN_W'|translate}}</mat-option>\n </mat-select>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n</ng-template>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
|
|
4854
4955
|
providers: [
|
|
4855
4956
|
{
|
|
4856
4957
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -4859,7 +4960,7 @@ MatLatLongField.decorators = [
|
|
|
4859
4960
|
}
|
|
4860
4961
|
],
|
|
4861
4962
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
4862
|
-
styles: [":host{display:inline-block;width:100%;min-width:140px;position:relative;--ion-grid-column-padding:0}mat-form-field .datetime-md{padding:0!important}ion-row{flex-wrap:nowrap}ion-row ion-col.text{min-width:80px}ion-row ion-col.sign{min-width:
|
|
4963
|
+
styles: [":host{display:inline-block;width:100%;min-width:140px;position:relative;--ion-grid-column-padding:0}mat-form-field .datetime-md{padding:0!important}ion-row{flex-wrap:nowrap}ion-row ion-col.text{min-width:80px}ion-row ion-col.sign{min-width:40px;max-width:55px}mat-form-field{width:100%}mat-form-field .mat-form-field-subscript-wrapper{overflow:visible;white-space:nowrap;top:100%}mat-form-field .mat-form-field-subscript-wrapper .mat-form-field-hint-wrapper{display:flex}mat-form-field .mat-form-field-subscript-wrapper .mat-form-field-hint-wrapper .mat-form-field-hint-spacer{flex:1 0 1em}mat-error{text-align:right;width:100%}"]
|
|
4863
4964
|
},] }
|
|
4864
4965
|
];
|
|
4865
4966
|
MatLatLongField.ctorParameters = () => [
|
|
@@ -4869,19 +4970,18 @@ MatLatLongField.ctorParameters = () => [
|
|
|
4869
4970
|
{ type: FormGroupDirective, decorators: [{ type: Optional }] }
|
|
4870
4971
|
];
|
|
4871
4972
|
MatLatLongField.propDecorators = {
|
|
4872
|
-
mobile: [{ type: Input }],
|
|
4873
4973
|
formControl: [{ type: Input }],
|
|
4874
4974
|
formControlName: [{ type: Input }],
|
|
4875
|
-
placeholder: [{ type: Input }],
|
|
4876
4975
|
type: [{ type: Input }],
|
|
4877
4976
|
pattern: [{ type: Input, args: ['latLongPattern',] }],
|
|
4977
|
+
required: [{ type: Input }],
|
|
4978
|
+
floatLabel: [{ type: Input }],
|
|
4979
|
+
placeholder: [{ type: Input }],
|
|
4980
|
+
tabindex: [{ type: Input }],
|
|
4878
4981
|
defaultSign: [{ type: Input }],
|
|
4879
4982
|
maxDecimals: [{ type: Input }],
|
|
4880
4983
|
placeholderChar: [{ type: Input }],
|
|
4881
|
-
floatLabel: [{ type: Input }],
|
|
4882
4984
|
readonly: [{ type: Input }],
|
|
4883
|
-
required: [{ type: Input }],
|
|
4884
|
-
tabindex: [{ type: Input }],
|
|
4885
4985
|
onBlur: [{ type: Output }],
|
|
4886
4986
|
onFocus: [{ type: Output }],
|
|
4887
4987
|
inputElement: [{ type: ViewChild, args: ['inputElement',] }]
|
|
@@ -5234,7 +5334,7 @@ class MatDate {
|
|
|
5234
5334
|
MatDate.decorators = [
|
|
5235
5335
|
{ type: Component, args: [{
|
|
5236
5336
|
selector: 'mat-date-field',
|
|
5237
|
-
template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n readonly\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\">\n <ion-text>{{formControl.value|dateFormat: {pattern: datePattern} }}</ion-text>\n</mat-form-field>\n\n<!-- writable -->\n<ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\">\n\n <mat-label>{{placeholder}}</mat-label>\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"!mobile\"\n [formControl]=\"textControl\"\n [textMask]=\"{mask: mask, keepCharPositions: true, placeholderChar: placeholderChar}\"\n [placeholder]=\"'COMMON.DATE_PLACEHOLDER'|translate\"\n (blur)=\"checkIfTouched()\"\n (keyup.arrowdown)=\"openDatePicker($event, datePicker)\"\n (keyup.escape)=\"preventEvent($event)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n [appAutofocus]=\"autofocus\">\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"mobile\"\n [formControl]=\"textControl\"\n (click)=\"openDatePickerIfMobile($event, datePicker)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n readonly>\n\n <!-- Hide the final input -->\n <input matInput type=\"text\" [formControl]=\"formControl\"\n hidden\n [matDatepicker]=\"datePicker\"\n [matDatepickerFilter]=\"datePickerFilter\"\n (dateChange)=\"onDatePickerChange($event)\">\n\n <button type=\"button\" mat-icon-button tabindex=\"-1\" matSuffix\n (click)=\"openDatePicker($event, datePicker)\"\n [disabled]=\"formControl.disabled\">\n <div *ngIf=\"mobile; then iconDate; else iconDesktop\"></div>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clear()\"\n [hidden]=\"formControl.disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <!-- errors -->\n <
|
|
5337
|
+
template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly; else writable\"\n [floatLabel]=\"floatLabel\"\n class=\"mat-form-field-disabled\">\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\"\n readonly\n [placeholder]=\"placeholder\"\n [formControl]=\"formControl\">\n <ion-text>{{formControl.value|dateFormat: {pattern: datePattern} }}</ion-text>\n</mat-form-field>\n\n<!-- writable -->\n<ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\">\n\n <mat-label>{{placeholder}}</mat-label>\n\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"!mobile\"\n [formControl]=\"textControl\"\n [textMask]=\"{mask: mask, keepCharPositions: true, placeholderChar: placeholderChar}\"\n [placeholder]=\"'COMMON.DATE_PLACEHOLDER'|translate\"\n (blur)=\"checkIfTouched()\"\n (keyup.arrowdown)=\"openDatePicker($event, datePicker)\"\n (keyup.escape)=\"preventEvent($event)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n [appAutofocus]=\"autofocus\">\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"mobile\"\n [formControl]=\"textControl\"\n (click)=\"openDatePickerIfMobile($event, datePicker)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n readonly>\n\n <!-- Hide the final input -->\n <input matInput type=\"text\" [formControl]=\"formControl\"\n hidden\n [matDatepicker]=\"datePicker\"\n [matDatepickerFilter]=\"datePickerFilter\"\n (dateChange)=\"onDatePickerChange($event)\">\n\n <button type=\"button\" mat-icon-button tabindex=\"-1\" matSuffix\n (click)=\"openDatePicker($event, datePicker)\"\n [disabled]=\"formControl.disabled\">\n <div *ngIf=\"mobile; then iconDate; else iconDesktop\"></div>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clear()\"\n [hidden]=\"formControl.disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <!-- errors -->\n <ng-container *ngIf=\"formControl.touched && formControl.errors|mapKeys|arrayFirst; let errorKey\" [ngSwitch]=\"errorKey\">\n <mat-error *ngSwitchCase=\"'required'\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngSwitchCase=\"'validDate'\" translate>ERROR.FIELD_NOT_VALID_DATE</mat-error>\n <mat-error *ngSwitchCase=\"'dateIsAfter'\">{{'ERROR.FIELD_NOT_VALID_DATE_AFTER' | translate: formControl.errors.dateIsAfter }}</mat-error>\n <mat-error *ngSwitchCase=\"'dateIsBefore'\">{{'ERROR.FIELD_NOT_VALID_DATE_BEFORE' | translate: formControl.errors.dateIsBefore }}</mat-error>\n <mat-error *ngSwitchCase=\"'dateRange'\" translate>ERROR.FIELD_NOT_VALID_DATE_RANGE</mat-error>\n <mat-error *ngSwitchCase=\"'dateMaxDuration'\" translate>ERROR.FIELD_NOT_VALID_DATE_MAX_DURATION</mat-error>\n <mat-error *ngSwitchCase=\"'dateMinDuration'\" translate>ERROR.FIELD_NOT_VALID_DATE_MIN_DURATION</mat-error>\n <mat-error *ngSwitchCase=\"'msg'\">{{(formControl.errors.msg?.key || formControl.errors.msg) | translate: formControl.errors.msg?.params}}</mat-error>\n </ng-container>\n <ng-content select=\"mat-error\"></ng-content>\n\n <!-- mat hint -->\n <div class=\"mat-form-field-hint-wrapper\" [class.cdk-visually-hidden]=\"formControl.invalid\">\n <div class=\"mat-form-field-hint-spacer\"></div>\n <ng-content select=\"mat-hint\"></ng-content>\n </div>\n </mat-form-field>\n\n <mat-datepicker #datePicker\n [touchUi]=\"mobile\"\n [disabled]=\"formControl.disabled\"\n [startAt]=\"startDate\"\n ></mat-datepicker>\n\n\n\n</ng-template>\n\n<ng-template #iconDesktop>\n <mat-icon>keyboard_arrow_down</mat-icon>\n</ng-template>\n\n<ng-template #iconDate>\n <mat-icon>date_range</mat-icon>\n</ng-template>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n",
|
|
5238
5338
|
providers: [
|
|
5239
5339
|
DEFAULT_VALUE_ACCESSOR,
|
|
5240
5340
|
],
|
|
@@ -5331,7 +5431,7 @@ class MatDateTime {
|
|
|
5331
5431
|
// Workaround because ion-datetime has issue (do not returned a ISO date)
|
|
5332
5432
|
this._keyboardHideDelay = this.mobile && KEYBOARD_HIDE_DELAY_MS || 0;
|
|
5333
5433
|
this.required = isNotNilBoolean(this.required) ? this.required : (this.formControl.validator === Validators.required || isBlankString(this.required));
|
|
5334
|
-
// Add 'validDate' validator (when existing validator are null or required, to be sure to keep
|
|
5434
|
+
// Add 'validDate' validator (when existing validator are null or required, to be sure to keep)
|
|
5335
5435
|
if (!this.formControl.validator || this.formControl.validator === Validators.required) {
|
|
5336
5436
|
this.formControl.setValidators(this.required ? [Validators.required, SharedValidators.validDate] : SharedValidators.validDate);
|
|
5337
5437
|
}
|
|
@@ -5340,12 +5440,9 @@ class MatDateTime {
|
|
|
5340
5440
|
[this.formControl.validator, SharedValidators.validDate]);
|
|
5341
5441
|
}
|
|
5342
5442
|
// Create the day control
|
|
5343
|
-
this.dayControl = this.formBuilder.control(null
|
|
5443
|
+
this.dayControl = this.formBuilder.control(null);
|
|
5344
5444
|
// Create the hour control
|
|
5345
|
-
|
|
5346
|
-
(this.mobile ? Validators.required : Validators.compose([Validators.required, Validators.pattern(HOUR_REGEXP)])) :
|
|
5347
|
-
(this.mobile ? null : Validators.pattern(HOUR_REGEXP));
|
|
5348
|
-
this.hourControl = this.formBuilder.control(null, timeValidator);
|
|
5445
|
+
this.hourControl = this.formBuilder.control(null, this.mobile ? null : Validators.pattern(HOUR_REGEXP));
|
|
5349
5446
|
// Get patterns to display date and date+time
|
|
5350
5447
|
this._subscription.add(this.translate.get(['COMMON.DATE_PATTERN', 'COMMON.DATE_TIME_PATTERN'])
|
|
5351
5448
|
.subscribe((patterns) => this.updatePattern(patterns)));
|
|
@@ -5528,7 +5625,9 @@ class MatDateTime {
|
|
|
5528
5625
|
if (incompleteValue || this.dayControl.invalid || this.hourControl.invalid) {
|
|
5529
5626
|
this.formControl.markAsPending({ onlySelf: true });
|
|
5530
5627
|
this.formControl.setErrors(Object.assign(Object.assign(Object.assign({ validDate: incompleteValue }, this.formControl.errors), this.dayControl.errors), this.hourControl.errors));
|
|
5531
|
-
this.
|
|
5628
|
+
if (this.dayControl.dirty || this.hourControl.dirty) {
|
|
5629
|
+
this.formControl.markAsDirty();
|
|
5630
|
+
}
|
|
5532
5631
|
this._writing = false;
|
|
5533
5632
|
return;
|
|
5534
5633
|
}
|
|
@@ -5907,7 +6006,7 @@ class MatDateShort {
|
|
|
5907
6006
|
MatDateShort.decorators = [
|
|
5908
6007
|
{ type: Component, args: [{
|
|
5909
6008
|
selector: 'mat-date-short-field',
|
|
5910
|
-
template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly else writable\">\n <input matInput hidden type=\"text\" readonly=\"true\" [formControl]=\"formControl\">\n <ion-text>{{formControl.value|dateFormat: {pattern: displayPattern} }}</ion-text>\n</mat-form-field>\n\n<ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\">\n\n <mat-label>{{placeholder}}</mat-label>\n\n <div matPrefix><ng-content select=\"[matPrefix]\"></ng-content></div>\n\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"!mobile\"\n [formControl]=\"dayControl\"\n [textMask]=\"{mask: dayMask, keepCharPositions: true, placeholderChar: placeholderChar}\"\n [placeholder]=\"'COMMON.DATE_YEAR_PLACEHOLDER'|translate\"\n (blur)=\"checkIfTouched()\"\n (keyup.arrowdown)=\"openDatePicker($event, datePicker1)\"\n (keyup.escape)=\"preventEvent($event)\"\n (click)=\"matInput.select()\"\n [required]=\"required\"\n [tabindex]=\"tabindex\">\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"mobile\"\n [formControl]=\"dayControl\"\n (click)=\"openDatePickerIfMobile($event, datePicker1)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n readonly>\n\n <!-- Hide the final control -->\n <input matInput type=\"text\"\n [formControl]=\"formControl\"\n hidden\n [matDatepicker]=\"datePicker1\"\n (dateChange)=\"onDatePickerChange($event)\">\n\n\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n (click)=\"openDatePicker($event, datePicker1)\"\n [disabled]=\"formControl.disabled\">\n <div *ngIf=\"mobile; then iconDate; else iconDesktop\"></div>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"writeValue(null)\"\n [hidden]=\"formControl.disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <
|
|
6009
|
+
template: "<!-- readonly -->\n<mat-form-field *ngIf=\"readonly else writable\">\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n\n <input matInput hidden type=\"text\" readonly=\"true\" [formControl]=\"formControl\">\n <ion-text>{{formControl.value|dateFormat: {pattern: displayPattern} }}</ion-text>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n</mat-form-field>\n\n<ng-template #writable>\n <mat-form-field [floatLabel]=\"floatLabel\">\n\n <mat-label>{{placeholder}}</mat-label>\n\n <div matPrefix><ng-content select=\"[matPrefix]\"></ng-content></div>\n\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"!mobile\"\n [formControl]=\"dayControl\"\n [textMask]=\"{mask: dayMask, keepCharPositions: true, placeholderChar: placeholderChar}\"\n [placeholder]=\"'COMMON.DATE_YEAR_PLACEHOLDER'|translate\"\n (blur)=\"checkIfTouched()\"\n (keyup.arrowdown)=\"openDatePicker($event, datePicker1)\"\n (keyup.escape)=\"preventEvent($event)\"\n (click)=\"matInput.select()\"\n [required]=\"required\"\n [tabindex]=\"tabindex\">\n <input matInput #matInput autocomplete=\"off\" type=\"text\"\n *ngIf=\"mobile\"\n [formControl]=\"dayControl\"\n (click)=\"openDatePickerIfMobile($event, datePicker1)\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n readonly>\n\n <!-- Hide the final control -->\n <input matInput type=\"text\"\n [formControl]=\"formControl\"\n hidden\n [matDatepicker]=\"datePicker1\"\n (dateChange)=\"onDatePickerChange($event)\">\n\n\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n (click)=\"openDatePicker($event, datePicker1)\"\n [disabled]=\"formControl.disabled\">\n <div *ngIf=\"mobile; then iconDate; else iconDesktop\"></div>\n </button>\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"writeValue(null)\"\n [hidden]=\"formControl.disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n\n <ng-container *ngIf=\"formControl.touched && formControl.errors|mapKeys|arrayFirst; let errorKey\" [ngSwitch]=\"errorKey\">\n <mat-error *ngSwitchCase=\"'required'\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngSwitchCase=\"'validDate'\" translate>ERROR.FIELD_NOT_VALID_DATE</mat-error>\n <mat-error *ngSwitchCase=\"'dateIsAfter'\">{{'ERROR.FIELD_NOT_VALID_DATE_AFTER' | translate: formControl.errors.dateIsAfter }}</mat-error>\n <mat-error *ngSwitchCase=\"'dateRange'\" translate>ERROR.FIELD_NOT_VALID_DATE_RANGE</mat-error>\n <mat-error *ngSwitchCase=\"'dateMaxDuration'\" translate>ERROR.FIELD_NOT_VALID_DATE_MAX_DURATION</mat-error>\n <mat-error *ngSwitchCase=\"'dateMinDuration'\" translate>ERROR.FIELD_NOT_VALID_DATE_MIN_DURATION</mat-error>\n <mat-error *ngSwitchCase=\"'msg'\">{{(formControl.errors.msg?.key || formControl.errors.msg) | translate: formControl.errors.msg?.params}}</mat-error>\n </ng-container>\n <ng-content select=\"mat-error\"></ng-content>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n </mat-form-field>\n\n <mat-datepicker #datePicker1\n startView=\"multi-year\"\n [touchUi]=\"mobile\"\n [disabled]=\"formControl.disabled\"\n (yearSelected)=\"closeDatePicker($event, datePicker1)\"\n [startAt]=\"startDate\"></mat-datepicker>\n\n <ng-template #iconDesktop>\n <mat-icon>keyboard_arrow_down</mat-icon>\n </ng-template>\n\n <ng-template #iconDate>\n <mat-icon>date_range</mat-icon>\n </ng-template>\n\n</ng-template>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n<ng-template #matSuffixTemplate>\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
|
|
5911
6010
|
providers: [
|
|
5912
6011
|
DEFAULT_VALUE_ACCESSOR$2,
|
|
5913
6012
|
],
|
|
@@ -7045,8 +7144,8 @@ class MatSwipeField {
|
|
|
7045
7144
|
this.required = false;
|
|
7046
7145
|
this.clearable = false;
|
|
7047
7146
|
this.onClick = new EventEmitter();
|
|
7048
|
-
this.
|
|
7049
|
-
this.
|
|
7147
|
+
this.blurred = new EventEmitter();
|
|
7148
|
+
this.focused = new EventEmitter();
|
|
7050
7149
|
this.selectInputContent = selectInputContent;
|
|
7051
7150
|
}
|
|
7052
7151
|
set tabindex(value) {
|
|
@@ -7286,7 +7385,7 @@ class MatSwipeField {
|
|
|
7286
7385
|
MatSwipeField.decorators = [
|
|
7287
7386
|
{ type: Component, args: [{
|
|
7288
7387
|
selector: 'mat-swipe-field',
|
|
7289
|
-
template: "<mat-form-field [floatLabel]=\"showSlides && (!floatLabel || floatLabel === 'auto') ? 'always': floatLabel\"\n [class]=\"classList\"\n [class.mat-form-field-disabled]=\"disabled\">\n <mat-label *ngIf=\"placeholder && floatLabel!=='never'\">\n {{placeholder}}\n </mat-label>\n <input matInput #fakeInput type=\"text\"\n [formControl]=\"formControl\"\n [readonly]=\"true\"\n (focus)=\"_onFocusFakeInput($event)\"\n [required]=\"required\"\n [class.cdk-visually-hidden]=\"showSlides\"\n [tabindex]=\"tabindex\">\n\n <div class=\"slides-container\" [class.hidden]=\"!showSlides\">\n <ion-slides #slides\n [options]=\"slidesOptions\"\n (ionSlidesDidLoad)=\"slidesLoaded()\"\n (ionSlideReachStart)=\"reachStart(true)\"\n (ionSlideReachEnd)=\"reachEnd(true)\"\n (ionSlideNextEnd)=\"reachStart(false)\"\n (ionSlidePrevEnd)=\"reachEnd(false)\"\n (ionSlideDidChange)=\"slideChanged()\"\n >\n <ion-slide *ngFor=\"let item of $items | async\">\n <ion-label>{{ displayWith(item) }}</ion-label>\n </ion-slide>\n\n </ion-slides>\n </div>\n\n <button #prevButton\n mat-icon-button\n type=\"button\"\n class=\"button-prev\"\n [hidden]=\"!showSlides\"\n [disabled]=\"previousDisabled\"\n (click)=\"previous()\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button #nextButton\n mat-icon-button\n type=\"button\"\n class=\"button-next\"\n [hidden]=\"!showSlides\"\n [disabled]=\"nextDisabled\"\n (click)=\"next()\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n\n</mat-form-field>\n",
|
|
7388
|
+
template: "<mat-form-field [floatLabel]=\"showSlides && (!floatLabel || floatLabel === 'auto') ? 'always': floatLabel\"\n [appearance]=\"appearance\"\n [class]=\"classList\"\n [class.mat-form-field-disabled]=\"disabled\">\n <mat-label *ngIf=\"placeholder && floatLabel!=='never'\">\n {{placeholder}}\n </mat-label>\n <input matInput #fakeInput type=\"text\"\n [formControl]=\"formControl\"\n [readonly]=\"true\"\n (focus)=\"_onFocusFakeInput($event)\"\n [required]=\"required\"\n [class.cdk-visually-hidden]=\"showSlides\"\n [tabindex]=\"tabindex\">\n\n <div class=\"slides-container\" [class.hidden]=\"!showSlides\">\n <ion-slides #slides\n [options]=\"slidesOptions\"\n (ionSlidesDidLoad)=\"slidesLoaded()\"\n (ionSlideReachStart)=\"reachStart(true)\"\n (ionSlideReachEnd)=\"reachEnd(true)\"\n (ionSlideNextEnd)=\"reachStart(false)\"\n (ionSlidePrevEnd)=\"reachEnd(false)\"\n (ionSlideDidChange)=\"slideChanged()\"\n >\n <ion-slide *ngFor=\"let item of $items | async\">\n <ion-label>{{ displayWith(item) }}</ion-label>\n </ion-slide>\n\n </ion-slides>\n </div>\n\n <button #prevButton\n mat-icon-button\n type=\"button\"\n class=\"button-prev\"\n [hidden]=\"!showSlides\"\n [disabled]=\"previousDisabled\"\n (click)=\"previous()\">\n <mat-icon>chevron_left</mat-icon>\n </button>\n <button #nextButton\n mat-icon-button\n type=\"button\"\n class=\"button-next\"\n [hidden]=\"!showSlides\"\n [disabled]=\"nextDisabled\"\n (click)=\"next()\">\n <mat-icon>chevron_right</mat-icon>\n </button>\n\n <button matSuffix mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('entity')\" translate>ERROR.FIELD_INVALID</mat-error>\n\n</mat-form-field>\n",
|
|
7290
7389
|
providers: [DEFAULT_VALUE_ACCESSOR$5],
|
|
7291
7390
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
7292
7391
|
styles: [":host{display:inline-block;width:100%;position:relative}input.hidden{display:none}.slides-container .swiper-slide{font-size:16px!important}.slides-container.hidden{visibility:hidden;height:0!important}.button-next,.button-prev{position:absolute;top:calc(50% - 20px);z-index:10}.button-prev{left:0;right:auto}.button-next{left:auto;right:0}"]
|
|
@@ -7301,6 +7400,7 @@ MatSwipeField.propDecorators = {
|
|
|
7301
7400
|
formControl: [{ type: Input }],
|
|
7302
7401
|
formControlName: [{ type: Input }],
|
|
7303
7402
|
floatLabel: [{ type: Input }],
|
|
7403
|
+
appearance: [{ type: Input }],
|
|
7304
7404
|
placeholder: [{ type: Input }],
|
|
7305
7405
|
debug: [{ type: Input }],
|
|
7306
7406
|
required: [{ type: Input }],
|
|
@@ -7314,8 +7414,8 @@ MatSwipeField.propDecorators = {
|
|
|
7314
7414
|
tabindex: [{ type: Input }],
|
|
7315
7415
|
items: [{ type: Input }],
|
|
7316
7416
|
onClick: [{ type: Output, args: ['click',] }],
|
|
7317
|
-
|
|
7318
|
-
|
|
7417
|
+
blurred: [{ type: Output, args: ['blur',] }],
|
|
7418
|
+
focused: [{ type: Output, args: ['focus',] }],
|
|
7319
7419
|
fakeInput: [{ type: ViewChild, args: ['fakeInput',] }],
|
|
7320
7420
|
slides: [{ type: ViewChild, args: ['slides', { static: true },] }],
|
|
7321
7421
|
prevButton: [{ type: ViewChild, args: ['prevButton',] }],
|
|
@@ -7907,7 +8007,7 @@ MatChipsField.decorators = [
|
|
|
7907
8007
|
{ type: Component, args: [{
|
|
7908
8008
|
// eslint-disable-next-line @angular-eslint/component-selector
|
|
7909
8009
|
selector: 'mat-chips-field',
|
|
7910
|
-
template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\"
|
|
8010
|
+
template: "<ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col class=\"ion-no-padding\">\n <mat-form-field [floatLabel]=\"floatLabel\"\n [appearance]=\"appearance\"\n class=\"material-chips\" [class.mat-form-field-disabled]=\"disabled\">\n <div matPrefix>\n <ng-container *ngTemplateOutlet=\"matPrefixTemplate\"></ng-container>\n </div>\n <mat-label>{{placeholder}}</mat-label>\n <mat-chip-list #chipList\n (focus)=\"filterChipsFocusEvent($event)\" >\n <mat-chip\n *ngFor=\"let item of value\"\n [selectable]=\"false\"\n [removable]=\"!disabled\"\n (removed)=\"remove(item)\"\n [color]=\"chipColor\"\n >\n {{displayWith(item)}}\n <mat-icon matChipRemove *ngIf=\"!disabled\">cancel</mat-icon>\n </mat-chip>\n\n <input #matInputText type=\"text\"\n [matAutocomplete]=\"autocomplete\"\n [matAutocompletePosition]=\"matAutocompletePosition\"\n [formControl]=\"inputControl\"\n [appAutofocus]=\"autofocus\"\n [tabindex]=\"_tabindex\"\n [readonly]=\"disabled\"\n [hidden]=\"disabled\"\n [required]=\"required\"\n (click)=\"clicked.emit($event)\"\n (focus)=\"filterInputTextFocusEvent($event)\"\n (blur)=\"filterInputTextBlurEvent($event)\"\n (keydown.escape)=\"keydownEscape.emit($event)\"\n (keyup.enter)=\"keyupEnter.emit($event)\"\n (keyup.arrowdown)=\"!autocomplete.showPanel && dropButtonClick.emit($event)\"\n [matChipInputFor]=\"chipList\"\n >\n </mat-chip-list>\n\n <!-- autocomplete -->\n <mat-autocomplete #autocomplete=\"matAutocomplete\"\n (optionSelected)=\"add($event)\"\n autoActiveFirstOption\n [displayWith]=\"displayWith\"\n [class]=\"classList\"\n [panelWidth]=\"panelWidth\">\n <ion-row class=\"mat-autocomplete-header ion-no-padding column\">\n <ion-col *ngFor=\"let attr of displayAttributes; index as i\" [size]=\"displayColumnSizes[i]\">\n <ion-label [innerHTML]=\"displayColumnNames[i] | translate\"></ion-label>\n </ion-col>\n </ion-row>\n\n <ng-container *ngIf=\"$filteredItems | async as items; else loadingTemplate\">\n <!-- No item option -->\n <mat-option *ngIf=\"items | isEmptyArray\" class=\"ion-padding text-italic\" disabled>\n <ion-label>{{noResultMessage | translate}}</ion-label>\n </mat-option>\n\n <mat-option *ngFor=\"let item of items\" [value]=\"item\" class=\"ion-no-padding\">\n <ion-row [classList]=\"item.classList\">\n <ion-col *ngFor=\"let path of displayAttributes; index as i;\"\n [size]=\"displayColumnSizes[i]\">\n <ion-text [innerHTML]=\"item | propertyGet: path | highlight: { search: inputControl.value, withAccent: highlightAccent } \"></ion-text>\n </ion-col>\n </ion-row>\n </mat-option>\n\n <!-- More item -->\n <mat-option *ngIf=\"_moreItemsCount\" (ngInit)=\"_initAutocompleteInfiniteScroll()\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-container>\n\n <!-- footer -->\n <ion-row *ngIf=\"itemCount as count\"\n class=\"mat-autocomplete-footer ion-no-padding\">\n <ion-col>\n <ion-text class=\"ion-float-end ion-padding-end\"><i>{{'COMMON.RESULT_COUNT'|translate: {count: count} }}</i></ion-text>\n </ion-col>\n </ion-row>\n\n <!-- Loading spinner -->\n <ng-template #loadingTemplate>\n <mat-option *ngIf=\"(matInputText.value | strLength) >= suggestLengthThreshold; else waitMoreCharacterTemplate\"\n class=\"ion-padding\" disabled>\n <ion-skeleton-text [animated]=\"true\" style=\"width: 100%\"></ion-skeleton-text>\n </mat-option>\n </ng-template>\n\n <!-- Need more characters -->\n <ng-template #waitMoreCharacterTemplate>\n <mat-option class=\"ion-padding text-italic\" disabled>\n <ion-label>\n {{'INFO.PLEASE_TYPE_MORE_CHARACTERS'|translate:{minLength: suggestLengthThreshold} }}\n </ion-label>\n </mat-option>\n </ng-template>\n </mat-autocomplete>\n\n <div matSuffix>\n <ng-container *ngTemplateOutlet=\"matSuffixTemplate\"></ng-container>\n </div>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <ng-content select=\"[matError]\"></ng-content>\n\n </mat-form-field>\n\n </ion-col>\n <ion-col size=\"auto\" class=\"ion-align-self-center\">\n <ng-content select=\"[matAfter]\"></ng-content>\n </ion-col>\n </ion-row>\n</ion-grid>\n\n<ng-template #matPrefixTemplate>\n <ng-content select=\"[matPrefix]\"></ng-content>\n</ng-template>\n\n\n<ng-template #matSuffixTemplate>\n <button mat-icon-button tabindex=\"-1\"\n type=\"button\"\n (click)=\"dropButtonClick.emit($event)\"\n [hidden]=\"disabled\">\n <mat-icon class=\"large select-arrow\">arrow_drop_down</mat-icon>\n </button>\n <button mat-icon-button tabindex=\"-1\"\n type=\"button\"\n *ngIf=\"clearable\"\n (click)=\"clearValue($event)\"\n [hidden]=\"disabled || !formControl.value\">\n <mat-icon>close</mat-icon>\n </button>\n\n <ng-content select=\"[matSuffix]\"></ng-content>\n</ng-template>\n",
|
|
7911
8011
|
providers: [{
|
|
7912
8012
|
provide: NG_VALUE_ACCESSOR,
|
|
7913
8013
|
multi: true,
|
|
@@ -7928,6 +8028,7 @@ MatChipsField.propDecorators = {
|
|
|
7928
8028
|
formControl: [{ type: Input }],
|
|
7929
8029
|
formControlName: [{ type: Input }],
|
|
7930
8030
|
floatLabel: [{ type: Input }],
|
|
8031
|
+
appearance: [{ type: Input }],
|
|
7931
8032
|
placeholder: [{ type: Input }],
|
|
7932
8033
|
suggestFn: [{ type: Input }],
|
|
7933
8034
|
required: [{ type: Input }],
|
|
@@ -8276,7 +8377,8 @@ AppGestureConfig.decorators = [
|
|
|
8276
8377
|
class ToolbarToken {
|
|
8277
8378
|
}
|
|
8278
8379
|
class ToolbarComponent {
|
|
8279
|
-
constructor(router, routerOutlet, cd, progressBarService) {
|
|
8380
|
+
constructor(route, router, routerOutlet, cd, progressBarService) {
|
|
8381
|
+
this.route = route;
|
|
8280
8382
|
this.router = router;
|
|
8281
8383
|
this.routerOutlet = routerOutlet;
|
|
8282
8384
|
this.cd = cd;
|
|
@@ -8362,15 +8464,28 @@ class ToolbarComponent {
|
|
|
8362
8464
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8363
8465
|
console.debug('[toolbar] calling goBack()');
|
|
8364
8466
|
if (this._backHref) {
|
|
8365
|
-
|
|
8467
|
+
const replaceUrl = !this.routerOutlet.canGoBack();
|
|
8468
|
+
// Relative href
|
|
8469
|
+
if (this._backHref.startsWith('.')) {
|
|
8470
|
+
yield this.router.navigate([this._backHref], { relativeTo: this.route, replaceUrl });
|
|
8471
|
+
}
|
|
8472
|
+
else {
|
|
8473
|
+
yield this.router.navigateByUrl(this._backHref, { replaceUrl });
|
|
8474
|
+
}
|
|
8366
8475
|
}
|
|
8367
8476
|
else if (this.routerOutlet.canGoBack()) {
|
|
8368
8477
|
yield this.routerOutlet.pop();
|
|
8369
8478
|
}
|
|
8370
8479
|
else if (this._defaultBackHref) {
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8480
|
+
// Relative href
|
|
8481
|
+
if (this._defaultBackHref.startsWith('.')) {
|
|
8482
|
+
yield this.router.navigate([this._defaultBackHref], { relativeTo: this.route, replaceUrl: true });
|
|
8483
|
+
}
|
|
8484
|
+
else {
|
|
8485
|
+
yield this.router.navigateByUrl(this._defaultBackHref, {
|
|
8486
|
+
replaceUrl: true
|
|
8487
|
+
});
|
|
8488
|
+
}
|
|
8374
8489
|
}
|
|
8375
8490
|
else {
|
|
8376
8491
|
console.error('[toolbar] Cannot go back. Missing attribute \'defaultBackHref\' or \'backHref\'');
|
|
@@ -8429,7 +8544,7 @@ class ToolbarComponent {
|
|
|
8429
8544
|
ToolbarComponent.decorators = [
|
|
8430
8545
|
{ type: Component, args: [{
|
|
8431
8546
|
selector: 'app-toolbar',
|
|
8432
|
-
template: "<ion-header [class]=\"class\">\n <ion-toolbar [color]=\"color\">\n\n <ion-buttons slot=\"start\">\n\n <!-- back button -->\n <ion-button class=\"back-button\"\n *ngIf=\"canGoBack\"\n (click)=\"doBackClick($event)\"\n routerDirection=\"back\" >\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n\n <!-- show menu button -->\n <ion-menu-toggle [hidden]=\"canGoBack || !canShowMenu\">\n <ion-button>\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n\n <ng-content select=\"[slot=start]\"></ng-content>\n </ion-buttons>\n\n <ion-title [innerHTML]=\"title\"></ion-title>\n\n <ng-content select=\"ion-title\"></ng-content>\n\n <ng-content select=\"ion-buttons[slot=end]\"></ng-content>\n\n <ion-buttons slot=\"end\" collapse=\"true\">\n\n <ng-content select=\"[slot=end]\"></ng-content>\n\n <!-- search bar -->\n <ion-searchbar #searchbar animated\n type=\"search\"\n *ngIf=\"hasSearch\"\n [class.cdk-visually-hidden]=\"!showSearchBar\"\n show-cancel-button=\"always\"\n (ionChange)=\"onSearch.emit($event)\"\n (ionCancel)=\"toggleSearchBar()\">\n </ion-searchbar>\n\n <!-- search button -->\n <ion-button (click)=\"toggleSearchBar()\"\n *ngIf=\"hasSearch && !showSearchBar\">\n <ion-icon slot=\"icon-only\" name=\"search\"></ion-icon>\n </ion-button>\n\n <!-- close button -->\n <ion-button *ngIf=\"hasClose\"\n (tap)=\"tapClose($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n\n <!-- validate button -->\n <ion-button *ngIf=\"hasValidate\"\n (tap)=\"tapValidate($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"save\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n\n <!-- progress bar -->\n <mat-progress-bar [color]=\"color\" [mode]=\"progressBarMode$ | async\">\n </mat-progress-bar>\n</ion-header>\n",
|
|
8547
|
+
template: "<ion-header [class]=\"class\">\n <ion-toolbar [color]=\"color\">\n\n <ion-buttons slot=\"start\">\n\n <!-- back button -->\n <ion-button class=\"back-button\"\n *ngIf=\"canGoBack\"\n (click)=\"doBackClick($event)\"\n routerDirection=\"back\" >\n <ion-icon slot=\"icon-only\" name=\"arrow-back\"></ion-icon>\n </ion-button>\n\n <!-- show menu button -->\n <ion-menu-toggle [menu]=\"'left'\"\n [class.cdk-visually-hidden]=\"canGoBack || !canShowMenu\">\n <ion-button>\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n\n <ng-content select=\"[slot=start]\"></ng-content>\n </ion-buttons>\n\n <ion-title [innerHTML]=\"title\"></ion-title>\n\n <ng-content select=\"ion-title\"></ng-content>\n\n <ng-content select=\"ion-buttons[slot=end]\"></ng-content>\n\n <ion-buttons slot=\"end\" collapse=\"true\">\n\n <ng-content select=\"[slot=end]\"></ng-content>\n\n <!-- search bar -->\n <ion-searchbar #searchbar animated\n type=\"search\"\n *ngIf=\"hasSearch\"\n [class.cdk-visually-hidden]=\"!showSearchBar\"\n show-cancel-button=\"always\"\n (ionChange)=\"onSearch.emit($event)\"\n (ionCancel)=\"toggleSearchBar()\">\n </ion-searchbar>\n\n <!-- search button -->\n <ion-button (click)=\"toggleSearchBar()\"\n *ngIf=\"hasSearch && !showSearchBar\">\n <ion-icon slot=\"icon-only\" name=\"search\"></ion-icon>\n </ion-button>\n\n <!-- close button -->\n <ion-button *ngIf=\"hasClose\"\n (tap)=\"tapClose($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"close\"></ion-icon>\n </ion-button>\n\n <!-- validate button -->\n <ion-button *ngIf=\"hasValidate\"\n (tap)=\"tapValidate($event)\"\n class=\"visible-xs visible-sm visible-mobile\">\n <ion-icon slot=\"icon-only\" name=\"save\"></ion-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n\n <!-- progress bar -->\n <mat-progress-bar [color]=\"color\" [mode]=\"progressBarMode$ | async\">\n </mat-progress-bar>\n</ion-header>\n",
|
|
8433
8548
|
providers: [
|
|
8434
8549
|
{ provide: ToolbarToken, useExisting: ToolbarComponent }
|
|
8435
8550
|
],
|
|
@@ -8438,6 +8553,7 @@ ToolbarComponent.decorators = [
|
|
|
8438
8553
|
},] }
|
|
8439
8554
|
];
|
|
8440
8555
|
ToolbarComponent.ctorParameters = () => [
|
|
8556
|
+
{ type: ActivatedRoute },
|
|
8441
8557
|
{ type: Router },
|
|
8442
8558
|
{ type: IonRouterOutlet },
|
|
8443
8559
|
{ type: ChangeDetectorRef },
|
|
@@ -8459,7 +8575,8 @@ ToolbarComponent.propDecorators = {
|
|
|
8459
8575
|
onValidateAndClose: [{ type: Output }],
|
|
8460
8576
|
onBackClick: [{ type: Output }],
|
|
8461
8577
|
onSearch: [{ type: Output }],
|
|
8462
|
-
searchbar: [{ type: ViewChild, args: ['searchbar', { static: true },] }]
|
|
8578
|
+
searchbar: [{ type: ViewChild, args: ['searchbar', { static: true },] }],
|
|
8579
|
+
menuToggle: [{ type: ViewChild, args: ['menuToggle', { static: true },] }]
|
|
8463
8580
|
};
|
|
8464
8581
|
|
|
8465
8582
|
class MatPaginatorI18n extends MatPaginatorIntl {
|
|
@@ -8746,7 +8863,7 @@ class AppFormField {
|
|
|
8746
8863
|
AppFormField.decorators = [
|
|
8747
8864
|
{ type: Component, args: [{
|
|
8748
8865
|
selector: 'app-form-field',
|
|
8749
|
-
template: "<ng-container [ngSwitch]=\"type\">\n\n <!-- integer -->\n <mat-form-field *ngSwitchCase=\"'integer'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n <input matInput #matInput\n type=\"number\"\n autocomplete=\"off\"\n [readonly]=\"readonly\"\n [min]=\"definition.minValue\"\n [max]=\"definition.maxValue\"\n pattern=\"-?[0-9]*\"\n step=\"1\"\n [appAutofocus]=\"autofocus\"\n [placeholder]=\"placeholder\"\n (keyup.enter)=\"onKeyupEnter.emit($event)\"\n (keypress)=\"filterNumberInput($event, false)\"\n [formControl]=\"formControl\"\n [required]=\"required\"\n [tabIndex]=\"tabindex\"\n (click)=\"selectInputContent($event)\">\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('min')\">\n {{(compact ? 'ERROR.FIELD_MIN_COMPACT' : 'ERROR.FIELD_MIN') | translate:formControl.errors['min'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('max')\">\n {{(compact ? 'ERROR.FIELD_MAX_COMPACT' : 'ERROR.FIELD_MAX') | translate:formControl.errors['max'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('pattern')\">\n {{'ERROR.FIELD_NOT_VALID_INTEGER'| translate }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('integer')\">\n {{'ERROR.FIELD_NOT_VALID_INTEGER'| translate }}</mat-error>\n\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-form-field>\n\n <!-- double -->\n <mat-form-field *ngSwitchCase=\"'double'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n\n <input matInput #matInput\n type=\"number\"\n decimal=\"true\"\n autocomplete=\"off\"\n [min]=\"definition.minValue\"\n [max]=\"definition.maxValue\"\n [appAutofocus]=\"autofocus\"\n [readonly]=\"readonly\"\n [placeholder]=\"placeholder\"\n [step]=\"numberInputStep\"\n (keypress)=\"filterNumberInput($event, true)\"\n [formControl]=\"formControl\"\n [required]=\"required\"\n [tabIndex]=\"tabindex\"\n (click)=\"selectInputContent($event)\">\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('min')\">\n {{ (compact ? 'ERROR.FIELD_MIN_COMPACT' : 'ERROR.FIELD_MIN')| translate:formControl.errors['min'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('max')\">\n {{(compact ? 'ERROR.FIELD_MAX_COMPACT' : 'ERROR.FIELD_MAX') | translate:formControl.errors['max'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('maxDecimals')\">\n {{ (compact ? 'ERROR.FIELD_MAXIMUM_DECIMALS_COMPACT' : 'ERROR.FIELD_MAXIMUM_DECIMALS')| translate:{
|
|
8866
|
+
template: "<ng-container [ngSwitch]=\"type\">\n\n <!-- integer -->\n <mat-form-field *ngSwitchCase=\"'integer'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n <input matInput #matInput\n type=\"number\"\n autocomplete=\"off\"\n [readonly]=\"readonly\"\n [min]=\"definition.minValue\"\n [max]=\"definition.maxValue\"\n pattern=\"-?[0-9]*\"\n step=\"1\"\n [appAutofocus]=\"autofocus\"\n [placeholder]=\"placeholder\"\n (keyup.enter)=\"onKeyupEnter.emit($event)\"\n (keypress)=\"filterNumberInput($event, false)\"\n [formControl]=\"formControl\"\n [required]=\"required\"\n [tabIndex]=\"tabindex\"\n (click)=\"selectInputContent($event)\">\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('min')\">\n {{(compact ? 'ERROR.FIELD_MIN_COMPACT' : 'ERROR.FIELD_MIN') | translate:formControl.errors['min'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('max')\">\n {{(compact ? 'ERROR.FIELD_MAX_COMPACT' : 'ERROR.FIELD_MAX') | translate:formControl.errors['max'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('pattern')\">\n {{'ERROR.FIELD_NOT_VALID_INTEGER'| translate }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('integer')\">\n {{'ERROR.FIELD_NOT_VALID_INTEGER'| translate }}</mat-error>\n\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-form-field>\n\n <!-- double -->\n <mat-form-field *ngSwitchCase=\"'double'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n\n <input matInput #matInput\n type=\"number\"\n decimal=\"true\"\n autocomplete=\"off\"\n [min]=\"definition.minValue\"\n [max]=\"definition.maxValue\"\n [appAutofocus]=\"autofocus\"\n [readonly]=\"readonly\"\n [placeholder]=\"placeholder\"\n [step]=\"numberInputStep\"\n (keypress)=\"filterNumberInput($event, true)\"\n [formControl]=\"formControl\"\n [required]=\"required\"\n [tabIndex]=\"tabindex\"\n (click)=\"selectInputContent($event)\">\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <mat-error *ngIf=\"formControl.hasError('decimal')\" translate>ERROR.FIELD_NOT_VALID_DECIMAL</mat-error>\n <mat-error *ngIf=\"formControl.hasError('min')\">\n {{ (compact ? 'ERROR.FIELD_MIN_COMPACT' : 'ERROR.FIELD_MIN')| translate:formControl.errors['min'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('max')\">\n {{(compact ? 'ERROR.FIELD_MAX_COMPACT' : 'ERROR.FIELD_MAX') | translate:formControl.errors['max'] }}</mat-error>\n <mat-error *ngIf=\"formControl.hasError('maxDecimals')\">\n {{ (compact ? 'ERROR.FIELD_MAXIMUM_DECIMALS_COMPACT' : 'ERROR.FIELD_MAXIMUM_DECIMALS')| translate:{maxDecimals:\n definition.maximumNumberDecimals} }}</mat-error>\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-form-field>\n\n <!-- boolean -->\n <mat-boolean-field *ngSwitchCase=\"'boolean'\" #matInput\n [class]=\"classList\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [floatLabel]=\"floatLabel\"\n [required]=\"required\"\n [compact]=\"compact\"\n [tabindex]=\"tabindex\"\n [readonly]=\"readonly\">\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-boolean-field>\n\n <!-- date -->\n <mat-date-field *ngSwitchCase=\"'date'\" #matInput\n [class]=\"classList\"\n [formControl]=\"formControl\"\n [placeholder]=\"compact ? ('COMMON.DATE_PLACEHOLDER'|translate): placeholder\"\n [floatLabel]=\"floatLabel\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [compact]=\"compact\"\n [tabindex]=\"tabindex\"\n [autofocus]=\"autofocus\">\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-date-field>\n\n <!-- date time -->\n <mat-date-time-field *ngSwitchCase=\"'dateTime'\" #matInput\n [class]=\"classList\"\n [formControl]=\"formControl\"\n [placeholder]=\"compact ? ('COMMON.DATE_TIME_PLACEHOLDER'|translate): placeholder\"\n [floatLabel]=\"floatLabel\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [compact]=\"compact\"\n [tabindex]=\"tabindex\"\n [autofocus]=\"autofocus\">\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-date-time-field>\n\n <!-- enum -->\n <mat-form-field *ngSwitchCase=\"'enum'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n <mat-select [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [tabindex]=\"tabindex\"\n (keyup.enter)=\"onKeyupEnter.emit($event)\">\n <mat-option *ngFor=\"let item of definition.values\" [value]=\"item.key || item\">{{ (item.value || item) | translate }}</mat-option>\n </mat-select>\n\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-form-field>\n\n <!-- color -->\n <mat-form-field *ngSwitchCase=\"'color'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n\n <ion-icon margin-right name=\"color-fill\" matPrefix></ion-icon>\n\n <input matInput autocomplete=\"off\"\n [appAutofocus]=\"autofocus\"\n [formControl]=\"formControl\"\n [style.color]=\"getColorContrast(formControl.value)\"\n [style.background]=\"formControl.value\"\n [colorPicker]=\"formControl.value\"\n (colorPickerChange)=\"writeValue($event)\"\n [cpSaveClickOutside]=\"true\"\n cpPosition=\"top\"\n cpOutputFormat=\"hex\"\n [cpOKButton]=\"false\"\n [required]=\"required\"/>\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n </mat-form-field>\n\n <!-- string -->\n <mat-form-field *ngSwitchCase=\"'string'\" [floatLabel]=\"floatLabel\" [class]=\"classList\">\n <input matInput #matInput\n autocomplete=\"off\"\n [appAutofocus]=\"autofocus\"\n [formControl]=\"formControl\"\n [placeholder]=\"placeholder\"\n [required]=\"required\"\n [readonly]=\"readonly\"\n [tabIndex]=\"tabindex\"\n (click)=\"selectInputContent($event)\"\n (keypress)=\"filterAlphanumericalInput($event)\"\n (keyup.enter)=\"onKeyupEnter.emit($event)\">\n <mat-error *ngIf=\"formControl.hasError('required')\" translate>ERROR.FIELD_REQUIRED</mat-error>\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </mat-form-field>\n\n <!-- auto-complete -->\n <mat-autocomplete-field *ngSwitchCase=\"'entity'\"\n [class]=\"classList\"\n [autofocus]=\"autofocus\"\n [placeholder]=\"placeholder\"\n [floatLabel]=\"floatLabel\"\n [formControl]=\"formControl\"\n [config]=\"definition.autocomplete\"\n [required]=\"required\"\n [displayWith]=\"getDisplayValueFn(definition)\">\n <ng-content select=\"[matPrefix]\"></ng-content>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </mat-autocomplete-field>\n\n <!-- multi auto-complete -->\n <mat-chips-field *ngSwitchCase=\"'entities'\"\n [class]=\"classList\"\n [placeholder]=\"placeholder\"\n [floatLabel]=\"floatLabel\"\n [formControl]=\"formControl\"\n [config]=\"definition.autocomplete\"\n [required]=\"required\"\n [displayWith]=\"getDisplayValueFn(definition)\">\n <ng-content select=\"[matPrefix]\"></ng-content>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </mat-chips-field>\n\n <!-- other -->\n <div *ngSwitchDefault>\n <mat-error *ngIf=\"type\">Unknown type {{type}} for option {{definition.key}}. Please report this error.</mat-error>\n <mat-error *ngIf=\"!type\">Error on option field. Please check console log for details.</mat-error>\n <div matSuffix>\n <ng-content select=\"[matSuffix]\"></ng-content>\n </div>\n </div>\n\n</ng-container>\n",
|
|
8750
8867
|
providers: [
|
|
8751
8868
|
{
|
|
8752
8869
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -9730,10 +9847,6 @@ class EntityUtils {
|
|
|
9730
9847
|
return isNotNil(obj.__typename) && (typeof obj.fromObject === 'function') && (typeof obj.asObject === 'function');
|
|
9731
9848
|
}
|
|
9732
9849
|
// Check that the object has a NOT nil attribute (ID by default)
|
|
9733
|
-
static isNotEntity(obj) {
|
|
9734
|
-
return isNil(obj.__typename) || (typeof obj.fromObject !== 'function') || (typeof obj.asObject !== 'function');
|
|
9735
|
-
}
|
|
9736
|
-
// Check that the object has a NOT nil attribute (ID by default)
|
|
9737
9850
|
static isNotEmpty(obj, checkedAttribute) {
|
|
9738
9851
|
return !!obj && obj[checkedAttribute] !== null && obj[checkedAttribute] !== undefined;
|
|
9739
9852
|
}
|
|
@@ -9813,6 +9926,8 @@ class EntityUtils {
|
|
|
9813
9926
|
(items || []).forEach(EntityUtils.cleanIdAndUpdateDate);
|
|
9814
9927
|
}
|
|
9815
9928
|
static sort(data, sortBy, sortDirection) {
|
|
9929
|
+
if (!data || data.length <= 1 || !sortBy)
|
|
9930
|
+
return data;
|
|
9816
9931
|
return data.sort(this.sortComparator(sortBy, sortDirection));
|
|
9817
9932
|
}
|
|
9818
9933
|
static sortComparator(sortBy, sortDirection) {
|
|
@@ -11837,11 +11952,10 @@ class EntityStore {
|
|
|
11837
11952
|
/**
|
|
11838
11953
|
*
|
|
11839
11954
|
* @param opts
|
|
11840
|
-
* opts.
|
|
11955
|
+
* opts.skipIfPristine = false persist all entities, even if not dirty
|
|
11841
11956
|
*/
|
|
11842
|
-
persist(opts) {
|
|
11957
|
+
persist(opts = { skipIfPristine: true }) {
|
|
11843
11958
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11844
|
-
opts = Object.assign({ skipIfPristine: this.policy.skipNonLocalEntities }, opts);
|
|
11845
11959
|
// Skip is not dirty
|
|
11846
11960
|
if (opts.skipIfPristine && !this._dirty) {
|
|
11847
11961
|
console.debug(`[entity-storage] Persisting ${this.name} not need. Skip`);
|
|
@@ -12051,7 +12165,7 @@ class EntityStore {
|
|
|
12051
12165
|
if (variables.size === 0)
|
|
12052
12166
|
return { data: [], total };
|
|
12053
12167
|
// Sort by
|
|
12054
|
-
if (
|
|
12168
|
+
if (variables.sortBy) {
|
|
12055
12169
|
EntityUtils.sort(data, variables.sortBy, variables.sortDirection);
|
|
12056
12170
|
}
|
|
12057
12171
|
// Slice in a page (using offset and size)
|
|
@@ -12124,6 +12238,33 @@ class EntitiesStorage extends StartableService {
|
|
|
12124
12238
|
get dirty() {
|
|
12125
12239
|
return this._dirty || Object.values(this._data).some(store => store.dirty);
|
|
12126
12240
|
}
|
|
12241
|
+
ngOnStart() {
|
|
12242
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12243
|
+
const now = Date.now();
|
|
12244
|
+
console.info(`[entities-storage] Starting entity storage...`);
|
|
12245
|
+
// Restore stores
|
|
12246
|
+
yield this.restoreLocally();
|
|
12247
|
+
// Start a save timer
|
|
12248
|
+
this.registerSubscription(merge(this._$save, timer(this._saveTimerPeriod, this._saveTimerPeriod))
|
|
12249
|
+
.pipe(
|
|
12250
|
+
// Avoid to many call (e.g. when $save AND timer are triggered
|
|
12251
|
+
throttleTime(this._saveTimerPeriod))
|
|
12252
|
+
.subscribe(() => this.storeLocally({ skipIfPristine: true })));
|
|
12253
|
+
// Save, when platform is in pause
|
|
12254
|
+
this.registerSubscription(this.platform.pause.subscribe(() => __awaiter(this, void 0, void 0, function* () {
|
|
12255
|
+
console.warn(`[entities-storage] Platform will pause: saving...`);
|
|
12256
|
+
yield this.storeLocally({ skipIfPristine: true });
|
|
12257
|
+
console.warn(`[entities-storage] Platform will pause: saving [OK]`);
|
|
12258
|
+
})));
|
|
12259
|
+
console.info(`[entities-storage] Starting [OK] in ${Date.now() - now}ms`);
|
|
12260
|
+
return this._data;
|
|
12261
|
+
});
|
|
12262
|
+
}
|
|
12263
|
+
ngOnStop() {
|
|
12264
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12265
|
+
yield this.storeLocally({ skipIfPristine: true });
|
|
12266
|
+
});
|
|
12267
|
+
}
|
|
12127
12268
|
watchAll(entityName, variables, opts) {
|
|
12128
12269
|
// Make sure store is ready
|
|
12129
12270
|
if (!this.started) {
|
|
@@ -12389,34 +12530,8 @@ class EntitiesStorage extends StartableService {
|
|
|
12389
12530
|
this._$save.emit();
|
|
12390
12531
|
});
|
|
12391
12532
|
}
|
|
12392
|
-
persist() {
|
|
12393
|
-
|
|
12394
|
-
return this.storeLocally();
|
|
12395
|
-
}
|
|
12396
|
-
return Promise.resolve();
|
|
12397
|
-
}
|
|
12398
|
-
ngOnStart() {
|
|
12399
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
12400
|
-
const now = Date.now();
|
|
12401
|
-
console.info(`[entities-storage] Starting entity storage...`);
|
|
12402
|
-
// Restore sequences
|
|
12403
|
-
yield this.restoreLocally();
|
|
12404
|
-
// Start a save timer
|
|
12405
|
-
this.registerSubscription(merge(this._$save, timer(this._saveTimerPeriod, this._saveTimerPeriod))
|
|
12406
|
-
.pipe(
|
|
12407
|
-
// Avoid to many call (e.g. when $save AND timer are triggered
|
|
12408
|
-
throttleTime(this._saveTimerPeriod))
|
|
12409
|
-
.subscribe(() => this.storeLocally()));
|
|
12410
|
-
console.info(`[entities-storage] Starting [OK] in ${Date.now() - now}ms`);
|
|
12411
|
-
return this._data;
|
|
12412
|
-
});
|
|
12413
|
-
}
|
|
12414
|
-
ngOnStop() {
|
|
12415
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
12416
|
-
if (this.dirty) {
|
|
12417
|
-
yield this.storeLocally();
|
|
12418
|
-
}
|
|
12419
|
-
});
|
|
12533
|
+
persist(opts = { skipIfPristine: true }) {
|
|
12534
|
+
return this.storeLocally(opts);
|
|
12420
12535
|
}
|
|
12421
12536
|
/* -- protected methods -- */
|
|
12422
12537
|
getEntityStore(name, opts) {
|
|
@@ -12455,9 +12570,9 @@ class EntitiesStorage extends StartableService {
|
|
|
12455
12570
|
console.debug(`[entities-storage] Restoring entities [OK] ${entitiesCount} entities found in ${Date.now() - now}ms`);
|
|
12456
12571
|
});
|
|
12457
12572
|
}
|
|
12458
|
-
storeLocally() {
|
|
12573
|
+
storeLocally(opts = { skipIfPristine: true }) {
|
|
12459
12574
|
return __awaiter(this, void 0, void 0, function* () {
|
|
12460
|
-
if (!this.dirty)
|
|
12575
|
+
if (opts.skipIfPristine && !this.dirty)
|
|
12461
12576
|
return; // skip
|
|
12462
12577
|
// Saving progress: report this save later
|
|
12463
12578
|
if (this._saving) {
|
|
@@ -12481,11 +12596,11 @@ class EntitiesStorage extends StartableService {
|
|
|
12481
12596
|
console.warn(`[entities-storage] Persisting ${entityName}: store not found!`);
|
|
12482
12597
|
return;
|
|
12483
12598
|
}
|
|
12484
|
-
// SKip store if
|
|
12485
|
-
if (!entityStore.dirty)
|
|
12486
|
-
return Promise.resolve();
|
|
12599
|
+
// SKip store if pristine
|
|
12600
|
+
if (opts.skipIfPristine && !entityStore.dirty)
|
|
12601
|
+
return Promise.resolve();
|
|
12487
12602
|
// Persist store
|
|
12488
|
-
return
|
|
12603
|
+
return entityStore.persist(opts)
|
|
12489
12604
|
.then(count => {
|
|
12490
12605
|
// If no entity found, remove from the entity names array
|
|
12491
12606
|
if (!count) {
|
|
@@ -12734,9 +12849,6 @@ class ReferentialUtils {
|
|
|
12734
12849
|
// A referential entity should always have a 'id' filled (can be negative is local and temporary)
|
|
12735
12850
|
return EntityUtils.isNotEmpty(obj, 'id');
|
|
12736
12851
|
}
|
|
12737
|
-
static isNotEmptyReferential(obj) {
|
|
12738
|
-
return EntityUtils.isNotEmpty(obj, 'id');
|
|
12739
|
-
}
|
|
12740
12852
|
static isEmpty(obj) {
|
|
12741
12853
|
return EntityUtils.isEmpty(obj, 'id');
|
|
12742
12854
|
}
|
|
@@ -14637,7 +14749,7 @@ class AccountService extends BaseGraphqlService {
|
|
|
14637
14749
|
return this._$additionalFields.getValue();
|
|
14638
14750
|
}
|
|
14639
14751
|
get $additionalFields() {
|
|
14640
|
-
return this._$additionalFields;
|
|
14752
|
+
return this._$additionalFields.asObservable();
|
|
14641
14753
|
}
|
|
14642
14754
|
getAdditionalField(key) {
|
|
14643
14755
|
return this._$additionalFields.getValue().find(f => f.key === key);
|
|
@@ -15684,6 +15796,196 @@ ConfigService.ctorParameters = () => [
|
|
|
15684
15796
|
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [APP_CONFIG_OPTIONS,] }] }
|
|
15685
15797
|
];
|
|
15686
15798
|
|
|
15799
|
+
class UploadFile extends File {
|
|
15800
|
+
}
|
|
15801
|
+
class FileResponse {
|
|
15802
|
+
constructor(init) {
|
|
15803
|
+
this.type = HttpEventType.Response;
|
|
15804
|
+
this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
|
|
15805
|
+
this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
|
|
15806
|
+
this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
|
|
15807
|
+
}
|
|
15808
|
+
}
|
|
15809
|
+
function isProgressEvent(event) {
|
|
15810
|
+
return event && (event.type === HttpEventType.UploadProgress
|
|
15811
|
+
|| event.type === HttpEventType.DownloadProgress);
|
|
15812
|
+
}
|
|
15813
|
+
function isResponseEvent(event) {
|
|
15814
|
+
return event && event.type === HttpEventType.Response;
|
|
15815
|
+
}
|
|
15816
|
+
|
|
15817
|
+
class UploadFilePopover {
|
|
15818
|
+
constructor(popoverController, translate, cd) {
|
|
15819
|
+
this.popoverController = popoverController;
|
|
15820
|
+
this.translate = translate;
|
|
15821
|
+
this.cd = cd;
|
|
15822
|
+
this.uniqueFile = false;
|
|
15823
|
+
this.instantUpload = false;
|
|
15824
|
+
this.importing = false;
|
|
15825
|
+
}
|
|
15826
|
+
get files() {
|
|
15827
|
+
return this.uploader.files;
|
|
15828
|
+
}
|
|
15829
|
+
get disabled() {
|
|
15830
|
+
return this.importing || isEmptyArray(this.files);
|
|
15831
|
+
}
|
|
15832
|
+
get valid() {
|
|
15833
|
+
return isNotEmptyArray(this.files);
|
|
15834
|
+
}
|
|
15835
|
+
onValidate(event) {
|
|
15836
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15837
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
15838
|
+
// Avoid multiple call
|
|
15839
|
+
if (this.importing)
|
|
15840
|
+
return;
|
|
15841
|
+
console.debug('[upload-file-popover] Validate form: will upload all files...');
|
|
15842
|
+
try {
|
|
15843
|
+
this.importing = true;
|
|
15844
|
+
this.resetError();
|
|
15845
|
+
try {
|
|
15846
|
+
// Wait processing files finished
|
|
15847
|
+
yield this.uploader.waitIdle();
|
|
15848
|
+
// upload all files
|
|
15849
|
+
yield this.uploader.uploadFiles();
|
|
15850
|
+
const files = (this.uploader.processedFiles || [])
|
|
15851
|
+
.filter(file => !file.deleting); // Remove deleting file (deletion in progress)
|
|
15852
|
+
// Nothing to upload: close popover
|
|
15853
|
+
if (isEmptyArray(files))
|
|
15854
|
+
return this.cancel();
|
|
15855
|
+
// check errors
|
|
15856
|
+
const errors = files.map(file => file.error).filter(isNotNilOrBlank);
|
|
15857
|
+
// If error: stop
|
|
15858
|
+
if (errors.length) {
|
|
15859
|
+
errors.forEach((error) => console.error(error));
|
|
15860
|
+
throw { message: 'FILE.UPLOAD.ERROR' };
|
|
15861
|
+
}
|
|
15862
|
+
// return files
|
|
15863
|
+
yield this.popoverController.dismiss(files);
|
|
15864
|
+
}
|
|
15865
|
+
catch (err) {
|
|
15866
|
+
this.error = (err && err.message) || err;
|
|
15867
|
+
}
|
|
15868
|
+
}
|
|
15869
|
+
finally {
|
|
15870
|
+
this.importing = false;
|
|
15871
|
+
this.cd.markForCheck();
|
|
15872
|
+
}
|
|
15873
|
+
});
|
|
15874
|
+
}
|
|
15875
|
+
cancel() {
|
|
15876
|
+
return this.popoverController.dismiss();
|
|
15877
|
+
}
|
|
15878
|
+
resetError() {
|
|
15879
|
+
if (this.error) {
|
|
15880
|
+
this.error = null;
|
|
15881
|
+
this.cd.markForCheck();
|
|
15882
|
+
}
|
|
15883
|
+
}
|
|
15884
|
+
}
|
|
15885
|
+
UploadFilePopover.decorators = [
|
|
15886
|
+
{ type: Component, args: [{
|
|
15887
|
+
selector: 'app-upload-file-popover',
|
|
15888
|
+
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",
|
|
15889
|
+
encapsulation: ViewEncapsulation.None,
|
|
15890
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
15891
|
+
styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
|
|
15892
|
+
},] }
|
|
15893
|
+
];
|
|
15894
|
+
UploadFilePopover.ctorParameters = () => [
|
|
15895
|
+
{ type: PopoverController },
|
|
15896
|
+
{ type: TranslateService },
|
|
15897
|
+
{ type: ChangeDetectorRef }
|
|
15898
|
+
];
|
|
15899
|
+
UploadFilePopover.propDecorators = {
|
|
15900
|
+
uploader: [{ type: ViewChild, args: ['uploader', { static: true },] }],
|
|
15901
|
+
fileExtension: [{ type: Input }],
|
|
15902
|
+
title: [{ type: Input }],
|
|
15903
|
+
uniqueFile: [{ type: Input }],
|
|
15904
|
+
instantUpload: [{ type: Input }],
|
|
15905
|
+
uploadFn: [{ type: Input }],
|
|
15906
|
+
deleteFn: [{ type: Input }],
|
|
15907
|
+
maxParallelUpload: [{ type: Input }]
|
|
15908
|
+
};
|
|
15909
|
+
|
|
15910
|
+
const MimeTypes = Object.freeze({
|
|
15911
|
+
ANDROID_APK: 'application/vnd.android.package-archive'
|
|
15912
|
+
});
|
|
15913
|
+
class FilesUtils {
|
|
15914
|
+
static showUploadPopover(popoverController, event, opts) {
|
|
15915
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15916
|
+
const modal = yield popoverController.create({
|
|
15917
|
+
component: UploadFilePopover,
|
|
15918
|
+
componentProps: opts,
|
|
15919
|
+
backdropDismiss: false,
|
|
15920
|
+
keyboardClose: false,
|
|
15921
|
+
event,
|
|
15922
|
+
translucent: true,
|
|
15923
|
+
cssClass: 'popover-large',
|
|
15924
|
+
});
|
|
15925
|
+
yield modal.present();
|
|
15926
|
+
const { data, role } = yield modal.onDidDismiss();
|
|
15927
|
+
return {
|
|
15928
|
+
role,
|
|
15929
|
+
data: data ? data : undefined
|
|
15930
|
+
};
|
|
15931
|
+
});
|
|
15932
|
+
}
|
|
15933
|
+
static readAsText(file, encoding) {
|
|
15934
|
+
const $progress = new Subject();
|
|
15935
|
+
const reader = new FileReader();
|
|
15936
|
+
encoding = (encoding || 'UTF-8').toLowerCase();
|
|
15937
|
+
// Listen progress
|
|
15938
|
+
reader.onprogress = (e) => {
|
|
15939
|
+
const total = e.total || 1;
|
|
15940
|
+
const loaded = e.total || 0;
|
|
15941
|
+
if (loaded < total)
|
|
15942
|
+
$progress.next({ type: HttpEventType.UploadProgress, loaded, total });
|
|
15943
|
+
};
|
|
15944
|
+
// Listen end
|
|
15945
|
+
reader.onloadend = (e) => {
|
|
15946
|
+
const body = reader.result;
|
|
15947
|
+
if (typeof body === 'string') {
|
|
15948
|
+
$progress.next(new FileResponse({ body }));
|
|
15949
|
+
$progress.complete();
|
|
15950
|
+
}
|
|
15951
|
+
else {
|
|
15952
|
+
console.error(`Cannot read file '${file.name}' as text`);
|
|
15953
|
+
$progress.error(`Cannot read file as text`);
|
|
15954
|
+
}
|
|
15955
|
+
};
|
|
15956
|
+
// Listen error
|
|
15957
|
+
reader.onerror = (event) => {
|
|
15958
|
+
console.error('[files] Error while reading file:', event);
|
|
15959
|
+
$progress.error(event);
|
|
15960
|
+
};
|
|
15961
|
+
// Start reading the file
|
|
15962
|
+
reader.readAsText(file, encoding);
|
|
15963
|
+
return $progress.asObservable();
|
|
15964
|
+
}
|
|
15965
|
+
}
|
|
15966
|
+
class UriUtils {
|
|
15967
|
+
/**
|
|
15968
|
+
* Extract the filename, from an uri (using the last slash)
|
|
15969
|
+
* @param uri
|
|
15970
|
+
*/
|
|
15971
|
+
static getFilename(uri) {
|
|
15972
|
+
if (!uri)
|
|
15973
|
+
return uri;
|
|
15974
|
+
let filename = uri.trim();
|
|
15975
|
+
// Get last part (or all string, if no '/')
|
|
15976
|
+
const lastSlashIndex = filename.lastIndexOf('/');
|
|
15977
|
+
if (lastSlashIndex !== -1 && lastSlashIndex !== uri.length - 1) {
|
|
15978
|
+
filename = filename.substring(lastSlashIndex + 1);
|
|
15979
|
+
}
|
|
15980
|
+
// Remove query params
|
|
15981
|
+
const queryParamIndex = filename.indexOf('?');
|
|
15982
|
+
if (queryParamIndex !== -1) {
|
|
15983
|
+
filename = filename.substring(0, queryParamIndex);
|
|
15984
|
+
}
|
|
15985
|
+
return filename;
|
|
15986
|
+
}
|
|
15987
|
+
}
|
|
15988
|
+
|
|
15687
15989
|
const moment$4 = momentImported;
|
|
15688
15990
|
const AndroidOsEnvironment = Object.freeze({
|
|
15689
15991
|
DIRECTORY_DOWNLOADS: 'Download',
|
|
@@ -15720,7 +16022,7 @@ class PlatformService extends StartableService {
|
|
|
15720
16022
|
switch (platformName) {
|
|
15721
16023
|
case 'mobile':
|
|
15722
16024
|
case 'mobileweb':
|
|
15723
|
-
// Exclude Windows touch screens - see
|
|
16025
|
+
// Exclude Windows touch screens - see sumaris-app issues #323 and #346
|
|
15724
16026
|
return this.platform.is(platformName) && !isWindows(window);
|
|
15725
16027
|
default:
|
|
15726
16028
|
return this.platform.is(platformName);
|
|
@@ -15774,6 +16076,7 @@ class PlatformService extends StartableService {
|
|
|
15774
16076
|
this._cordova = this.is('cordova');
|
|
15775
16077
|
this._android = this.is('android');
|
|
15776
16078
|
this._ios = this.is('ios');
|
|
16079
|
+
this.configureClassList(this._mobile);
|
|
15777
16080
|
this.configureCordovaPlugins();
|
|
15778
16081
|
// Force some settings
|
|
15779
16082
|
this.settings.mobile = this._mobile;
|
|
@@ -15808,7 +16111,7 @@ class PlatformService extends StartableService {
|
|
|
15808
16111
|
this.accountService.tokenType = tokenType;
|
|
15809
16112
|
});
|
|
15810
16113
|
// Hide the splashscreen (if mobile) - after 1s - and play start sound
|
|
15811
|
-
if (this.
|
|
16114
|
+
if (this._mobile) {
|
|
15812
16115
|
setTimeout(() => {
|
|
15813
16116
|
var _a;
|
|
15814
16117
|
(_a = this.splashScreen) === null || _a === void 0 ? void 0 : _a.hide();
|
|
@@ -15844,34 +16147,48 @@ class PlatformService extends StartableService {
|
|
|
15844
16147
|
return this._downloadingJobs.get(uri);
|
|
15845
16148
|
}
|
|
15846
16149
|
download(request) {
|
|
16150
|
+
var _a, _b;
|
|
15847
16151
|
if (!request || !request.uri)
|
|
15848
16152
|
throw new Error('Missing argument \'request\' or \'request.uri\'');
|
|
15849
16153
|
if (this._android && this.downloader) {
|
|
15850
16154
|
// Check if not already downloading file
|
|
15851
|
-
let
|
|
15852
|
-
if (
|
|
15853
|
-
return
|
|
15854
|
-
|
|
15855
|
-
|
|
16155
|
+
let job$ = this._downloadingJobs.get(request.uri);
|
|
16156
|
+
if (job$)
|
|
16157
|
+
return job$;
|
|
16158
|
+
// Compute subPath (final filename)
|
|
16159
|
+
let subPath = ((_a = request.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.subPath) || ((_b = request.destinationInExternalFilesDir) === null || _b === void 0 ? void 0 : _b.subPath)
|
|
16160
|
+
|| request.filename || UriUtils.getFilename(request.uri)
|
|
16161
|
+
|| request.title || 'download';
|
|
16162
|
+
subPath = subPath.toLowerCase()
|
|
16163
|
+
// Remove spaces
|
|
16164
|
+
.replace(/\s+/g, '-');
|
|
16165
|
+
// Force APK to finish with '.apk'
|
|
16166
|
+
if (request.mimeType === MimeTypes.ANDROID_APK && !subPath.toLowerCase().endsWith('.apk')) {
|
|
16167
|
+
subPath += '.apk';
|
|
16168
|
+
}
|
|
16169
|
+
const downloadRequest = Object.assign(Object.assign({ visibleInDownloadsUi: true, notificationVisibility: NotificationVisibility.VisibleNotifyCompleted }, request), { filename: undefined, destinationInExternalPublicDir: !request.destinationInExternalFilesDir
|
|
16170
|
+
? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalPublicDir), { subPath }) : undefined, destinationInExternalFilesDir: request.destinationInExternalFilesDir
|
|
16171
|
+
? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalFilesDir), { subPath }) : undefined });
|
|
15856
16172
|
// Start download
|
|
15857
|
-
|
|
16173
|
+
console.debug('[platform] Downloading, using request: ' + JSON.stringify(downloadRequest));
|
|
16174
|
+
job$ = from(this.downloader.download(downloadRequest));
|
|
15858
16175
|
// Remember this request uri
|
|
15859
|
-
this._downloadingJobs.set(
|
|
15860
|
-
return
|
|
16176
|
+
this._downloadingJobs.set(downloadRequest.uri, job$);
|
|
16177
|
+
return job$
|
|
15861
16178
|
.pipe(tap(location => {
|
|
15862
16179
|
console.info('[platform] File successfully downloaded at:' + location);
|
|
15863
|
-
// Forget
|
|
15864
|
-
this._downloadingJobs.delete(
|
|
16180
|
+
// Forget job
|
|
16181
|
+
this._downloadingJobs.delete(downloadRequest.uri);
|
|
15865
16182
|
return location;
|
|
15866
16183
|
}), catchError(err => {
|
|
15867
16184
|
var _a;
|
|
15868
16185
|
console.error('[platform] Unable to download: ' + (err && err.message || err));
|
|
15869
16186
|
// Forget the request
|
|
15870
|
-
this._downloadingJobs.delete(
|
|
16187
|
+
this._downloadingJobs.delete(downloadRequest.uri);
|
|
15871
16188
|
// Retry with another location - issue in older Android version
|
|
15872
|
-
if (((_a =
|
|
15873
|
-
|
|
15874
|
-
return this.download(
|
|
16189
|
+
if (((_a = downloadRequest.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.dirType) === AndroidOsEnvironment.DIRECTORY_DOWNLOADS) {
|
|
16190
|
+
downloadRequest.destinationInExternalPublicDir.dirType = AndroidOsEnvironment.DIRECTORY_DOWNLOADS_OLD;
|
|
16191
|
+
return this.download(downloadRequest);
|
|
15875
16192
|
}
|
|
15876
16193
|
throw err;
|
|
15877
16194
|
}));
|
|
@@ -15896,6 +16213,17 @@ class PlatformService extends StartableService {
|
|
|
15896
16213
|
//}
|
|
15897
16214
|
}
|
|
15898
16215
|
/* -- protected methods -- */
|
|
16216
|
+
configureClassList(mobile, win = window) {
|
|
16217
|
+
var _a, _b;
|
|
16218
|
+
if (mobile)
|
|
16219
|
+
return; // Nothing to do
|
|
16220
|
+
// Workaround, for MS Windows touch screen (detected as mobile, but forced as desktop)
|
|
16221
|
+
if (!mobile && (((_a = win.document.documentElement) === null || _a === void 0 ? void 0 : _a.classList.contains('plt-mobile')) || ((_b = win.document.documentElement.classList) === null || _b === void 0 ? void 0 : _b.contains('plt-mobileweb')))) {
|
|
16222
|
+
console.warn('[platform] Force class list to: <html class="plt-desktop">. Workaround for Windows touch screen.');
|
|
16223
|
+
win.document.documentElement.classList.remove('plt-mobile', 'plt-mobileweb');
|
|
16224
|
+
win.document.documentElement.classList.add('plt-desktop');
|
|
16225
|
+
}
|
|
16226
|
+
}
|
|
15899
16227
|
configureCordovaPlugins() {
|
|
15900
16228
|
console.info('[platform] Configuring Cordova plugins...');
|
|
15901
16229
|
if (this.statusBar) {
|
|
@@ -16223,24 +16551,6 @@ MatStepperI18n.ctorParameters = () => [
|
|
|
16223
16551
|
{ type: TranslateService }
|
|
16224
16552
|
];
|
|
16225
16553
|
|
|
16226
|
-
class UploadFile extends File {
|
|
16227
|
-
}
|
|
16228
|
-
class FileResponse {
|
|
16229
|
-
constructor(init) {
|
|
16230
|
-
this.type = HttpEventType.Response;
|
|
16231
|
-
this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
|
|
16232
|
-
this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
|
|
16233
|
-
this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
|
|
16234
|
-
}
|
|
16235
|
-
}
|
|
16236
|
-
function isProgressEvent(event) {
|
|
16237
|
-
return event && (event.type === HttpEventType.UploadProgress
|
|
16238
|
-
|| event.type === HttpEventType.DownloadProgress);
|
|
16239
|
-
}
|
|
16240
|
-
function isResponseEvent(event) {
|
|
16241
|
-
return event && event.type === HttpEventType.Response;
|
|
16242
|
-
}
|
|
16243
|
-
|
|
16244
16554
|
class UploadFileComponent {
|
|
16245
16555
|
constructor(cd, translate) {
|
|
16246
16556
|
this.cd = cd;
|
|
@@ -16435,99 +16745,6 @@ UploadFileComponent.propDecorators = {
|
|
|
16435
16745
|
maxParallelUpload: [{ type: Input }]
|
|
16436
16746
|
};
|
|
16437
16747
|
|
|
16438
|
-
class UploadFilePopover {
|
|
16439
|
-
constructor(popoverController, translate, cd) {
|
|
16440
|
-
this.popoverController = popoverController;
|
|
16441
|
-
this.translate = translate;
|
|
16442
|
-
this.cd = cd;
|
|
16443
|
-
this.uniqueFile = false;
|
|
16444
|
-
this.instantUpload = false;
|
|
16445
|
-
this.importing = false;
|
|
16446
|
-
}
|
|
16447
|
-
get files() {
|
|
16448
|
-
return this.uploader.files;
|
|
16449
|
-
}
|
|
16450
|
-
get disabled() {
|
|
16451
|
-
return this.importing || isEmptyArray(this.files);
|
|
16452
|
-
}
|
|
16453
|
-
get valid() {
|
|
16454
|
-
return isNotEmptyArray(this.files);
|
|
16455
|
-
}
|
|
16456
|
-
onValidate(event) {
|
|
16457
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
16458
|
-
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
16459
|
-
// Avoid multiple call
|
|
16460
|
-
if (this.importing)
|
|
16461
|
-
return;
|
|
16462
|
-
console.debug('[upload-file-popover] Validate form: will upload all files...');
|
|
16463
|
-
try {
|
|
16464
|
-
this.importing = true;
|
|
16465
|
-
this.resetError();
|
|
16466
|
-
try {
|
|
16467
|
-
// Wait processing files finished
|
|
16468
|
-
yield this.uploader.waitIdle();
|
|
16469
|
-
// upload all files
|
|
16470
|
-
yield this.uploader.uploadFiles();
|
|
16471
|
-
const files = (this.uploader.processedFiles || [])
|
|
16472
|
-
.filter(file => !file.deleting); // Remove deleting file (deletion in progress)
|
|
16473
|
-
// Nothing to upload: close popover
|
|
16474
|
-
if (isEmptyArray(files))
|
|
16475
|
-
return this.cancel();
|
|
16476
|
-
// check errors
|
|
16477
|
-
const errors = files.map(file => file.error).filter(isNotNilOrBlank);
|
|
16478
|
-
// If error: stop
|
|
16479
|
-
if (errors.length) {
|
|
16480
|
-
errors.forEach((error) => console.error(error));
|
|
16481
|
-
throw { message: 'FILE.UPLOAD.ERROR' };
|
|
16482
|
-
}
|
|
16483
|
-
// return files
|
|
16484
|
-
yield this.popoverController.dismiss(files);
|
|
16485
|
-
}
|
|
16486
|
-
catch (err) {
|
|
16487
|
-
this.error = (err && err.message) || err;
|
|
16488
|
-
}
|
|
16489
|
-
}
|
|
16490
|
-
finally {
|
|
16491
|
-
this.importing = false;
|
|
16492
|
-
this.cd.markForCheck();
|
|
16493
|
-
}
|
|
16494
|
-
});
|
|
16495
|
-
}
|
|
16496
|
-
cancel() {
|
|
16497
|
-
return this.popoverController.dismiss();
|
|
16498
|
-
}
|
|
16499
|
-
resetError() {
|
|
16500
|
-
if (this.error) {
|
|
16501
|
-
this.error = null;
|
|
16502
|
-
this.cd.markForCheck();
|
|
16503
|
-
}
|
|
16504
|
-
}
|
|
16505
|
-
}
|
|
16506
|
-
UploadFilePopover.decorators = [
|
|
16507
|
-
{ type: Component, args: [{
|
|
16508
|
-
selector: 'app-upload-file-popover',
|
|
16509
|
-
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",
|
|
16510
|
-
encapsulation: ViewEncapsulation.None,
|
|
16511
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
16512
|
-
styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
|
|
16513
|
-
},] }
|
|
16514
|
-
];
|
|
16515
|
-
UploadFilePopover.ctorParameters = () => [
|
|
16516
|
-
{ type: PopoverController },
|
|
16517
|
-
{ type: TranslateService },
|
|
16518
|
-
{ type: ChangeDetectorRef }
|
|
16519
|
-
];
|
|
16520
|
-
UploadFilePopover.propDecorators = {
|
|
16521
|
-
uploader: [{ type: ViewChild, args: ['uploader', { static: true },] }],
|
|
16522
|
-
fileExtension: [{ type: Input }],
|
|
16523
|
-
title: [{ type: Input }],
|
|
16524
|
-
uniqueFile: [{ type: Input }],
|
|
16525
|
-
instantUpload: [{ type: Input }],
|
|
16526
|
-
uploadFn: [{ type: Input }],
|
|
16527
|
-
deleteFn: [{ type: Input }],
|
|
16528
|
-
maxParallelUpload: [{ type: Input }]
|
|
16529
|
-
};
|
|
16530
|
-
|
|
16531
16748
|
const APP_TESTING_PAGES = new InjectionToken('testingPages');
|
|
16532
16749
|
class SharedTestsPage {
|
|
16533
16750
|
constructor(route, router, translate, pages) {
|
|
@@ -16910,8 +17127,8 @@ class ComponentDirtyGuard {
|
|
|
16910
17127
|
}
|
|
16911
17128
|
canDeactivate(component, currentRoute, currentState, nextState) {
|
|
16912
17129
|
return __awaiter(this, void 0, void 0, function* () {
|
|
16913
|
-
const dirty = component.dirty;
|
|
16914
|
-
const valid = component.valid;
|
|
17130
|
+
const dirty = component === null || component === void 0 ? void 0 : component.dirty;
|
|
17131
|
+
const valid = component === null || component === void 0 ? void 0 : component.valid;
|
|
16915
17132
|
let can = {
|
|
16916
17133
|
confirmed: !dirty,
|
|
16917
17134
|
save: false,
|
|
@@ -17791,6 +18008,7 @@ class JobUtils {
|
|
|
17791
18008
|
return progression;
|
|
17792
18009
|
}
|
|
17793
18010
|
static fetchAllPages(loadPageFn, opts) {
|
|
18011
|
+
var _a, _b;
|
|
17794
18012
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17795
18013
|
const maxProgression = toNumber(opts === null || opts === void 0 ? void 0 : opts.maxProgression, 100);
|
|
17796
18014
|
const progression = opts === null || opts === void 0 ? void 0 : opts.progression;
|
|
@@ -17823,7 +18041,7 @@ class JobUtils {
|
|
|
17823
18041
|
progressionStep = maxProgression / pageCount;
|
|
17824
18042
|
// DEBUG
|
|
17825
18043
|
if (opts && opts.logPrefix)
|
|
17826
|
-
console.debug(`${opts.logPrefix} {pageCount: ${pageCount},
|
|
18044
|
+
console.debug(`${opts.logPrefix} {pageCount: ${pageCount}, progress: ${(_a = progression.value) === null || _a === void 0 ? void 0 : _a.toFixed(2)}, pageProgressStep: ${progressionStep === null || progressionStep === void 0 ? void 0 : progressionStep.toFixed(1)}}`);
|
|
17827
18045
|
}
|
|
17828
18046
|
}
|
|
17829
18047
|
// Increment progression on each iteration (if possible)
|
|
@@ -17850,7 +18068,7 @@ class JobUtils {
|
|
|
17850
18068
|
}
|
|
17851
18069
|
// DEBUG
|
|
17852
18070
|
if (opts && opts.logPrefix)
|
|
17853
|
-
console.debug(`${opts.logPrefix} All pages fetched - {
|
|
18071
|
+
console.debug(`${opts.logPrefix} All pages fetched - {progress: ${(_b = progression.value) === null || _b === void 0 ? void 0 : _b.toFixed(2)}, lastProgressStep: ${progressionStep === null || progressionStep === void 0 ? void 0 : progressionStep.toFixed(1)}`);
|
|
17854
18072
|
// Final increment
|
|
17855
18073
|
if (progression && progressionStep > 0) {
|
|
17856
18074
|
progression.next(progression.value + progressionStep);
|
|
@@ -17863,60 +18081,6 @@ class JobUtils {
|
|
|
17863
18081
|
}
|
|
17864
18082
|
}
|
|
17865
18083
|
|
|
17866
|
-
class FilesUtils {
|
|
17867
|
-
static showUploadPopover(popoverController, event, opts) {
|
|
17868
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
17869
|
-
const modal = yield popoverController.create({
|
|
17870
|
-
component: UploadFilePopover,
|
|
17871
|
-
componentProps: opts,
|
|
17872
|
-
backdropDismiss: false,
|
|
17873
|
-
keyboardClose: false,
|
|
17874
|
-
event,
|
|
17875
|
-
translucent: true,
|
|
17876
|
-
cssClass: 'popover-large',
|
|
17877
|
-
});
|
|
17878
|
-
yield modal.present();
|
|
17879
|
-
const { data, role } = yield modal.onDidDismiss();
|
|
17880
|
-
return {
|
|
17881
|
-
role,
|
|
17882
|
-
data: data ? data : undefined
|
|
17883
|
-
};
|
|
17884
|
-
});
|
|
17885
|
-
}
|
|
17886
|
-
static readAsText(file, encoding) {
|
|
17887
|
-
const $progress = new Subject();
|
|
17888
|
-
const reader = new FileReader();
|
|
17889
|
-
encoding = (encoding || 'UTF-8').toLowerCase();
|
|
17890
|
-
// Listen progress
|
|
17891
|
-
reader.onprogress = (e) => {
|
|
17892
|
-
const total = e.total || 1;
|
|
17893
|
-
const loaded = e.total || 0;
|
|
17894
|
-
if (loaded < total)
|
|
17895
|
-
$progress.next({ type: HttpEventType.UploadProgress, loaded, total });
|
|
17896
|
-
};
|
|
17897
|
-
// Listen end
|
|
17898
|
-
reader.onloadend = (e) => {
|
|
17899
|
-
const body = reader.result;
|
|
17900
|
-
if (typeof body === 'string') {
|
|
17901
|
-
$progress.next(new FileResponse({ body }));
|
|
17902
|
-
$progress.complete();
|
|
17903
|
-
}
|
|
17904
|
-
else {
|
|
17905
|
-
console.error(`Cannot read file '${file.name}' as text`);
|
|
17906
|
-
$progress.error(`Cannot read file as text`);
|
|
17907
|
-
}
|
|
17908
|
-
};
|
|
17909
|
-
// Listen error
|
|
17910
|
-
reader.onerror = (event) => {
|
|
17911
|
-
console.error('[files] Error while reading file:', event);
|
|
17912
|
-
$progress.error(event);
|
|
17913
|
-
};
|
|
17914
|
-
// Start reading the file
|
|
17915
|
-
reader.readAsText(file, encoding);
|
|
17916
|
-
return $progress.asObservable();
|
|
17917
|
-
}
|
|
17918
|
-
}
|
|
17919
|
-
|
|
17920
18084
|
/**
|
|
17921
18085
|
* Define here theme colors
|
|
17922
18086
|
*/
|
|
@@ -18723,7 +18887,7 @@ HomePage.decorators = [
|
|
|
18723
18887
|
{ type: Component, args: [{
|
|
18724
18888
|
moduleId: module.id.toString(),
|
|
18725
18889
|
selector: 'app-page-home',
|
|
18726
|
-
template: "<app-toolbar [canGoBack]=\"false\"\n visible-xs visible-sm visible-mobile>\n\n <!-- change locale button -->\n <ion-button slot=\"end\" *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\"> {{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n</app-toolbar>\n\n<!-- change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <button *ngFor=\"let item of locales\"\n mat-menu-item\n (click)=\"changeLanguage(item.key)\">\n <ion-label>{{item.value}}</ion-label>\n </button>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" no-padding-xs>\n\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!loading\">\n <div class=\"spinner\" *ngIf=\"loading && showSpinner\">\n <p
|
|
18890
|
+
template: "<app-toolbar [canGoBack]=\"false\"\n visible-xs visible-sm visible-mobile>\n\n <!-- change locale button -->\n <ion-button slot=\"end\" *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\"> {{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n</app-toolbar>\n\n<!-- change locale menu -->\n<mat-menu #localeMenu=\"matMenu\">\n <button *ngFor=\"let item of locales\"\n mat-menu-item\n (click)=\"changeLanguage(item.key)\">\n <ion-label>{{item.value}}</ion-label>\n </button>\n</mat-menu>\n\n<ion-content [ngStyle]=\"contentStyle\" no-padding-xs>\n\n <!-- loading spinner -->\n <div class=\"loading-page\" [class.cdk-visually-hidden]=\"!loading\">\n <div class=\"spinner\" *ngIf=\"loading && showSpinner\">\n <p [innerHTML]=\"'COMMON.LOADING_DOTS'|translate\"></p>\n <div class=\"sk-cube1 sk-cube\"></div>\n <div class=\"sk-cube2 sk-cube\"></div>\n <div class=\"sk-cube4 sk-cube\"></div>\n <div class=\"sk-cube3 sk-cube\"></div>\n </div>\n </div>\n\n <!-- Desktop: translucent top toolbar -->\n <div hidden-xs hidden-sm hidden-mobile>\n <ion-toolbar translucent>\n <ion-buttons slot=\"start\">\n <ion-menu-toggle>\n <ion-button color=\"light\" fill=\"clear\">\n <ion-icon slot=\"icon-only\" name=\"menu\"></ion-icon>\n </ion-button>\n </ion-menu-toggle>\n </ion-buttons>\n\n <ion-buttons slot=\"end\">\n <!-- change locale button -->\n <ion-button color=\"secondary\" fill=\"solid\"\n *ngIf=\"currentLocaleCode; let code\"\n [matMenuTriggerFor]=\"localeMenu\">\n <ion-label class=\"ion-text-uppercase\"> {{ code }}</ion-label>\n <mat-icon slot=\"end\">arrow_drop_down</mat-icon>\n </ion-button>\n </ion-buttons>\n </ion-toolbar>\n </div>\n\n <!-- Install (and upgrade) card -->\n <app-install-upgrade-card [isLogin]=\"isLogin\"\n showInstallButton=\"true\">\n </app-install-upgrade-card>\n\n <!-- Welcome card -->\n <ion-card *ngIf=\"!loading\"\n class=\"main welcome ion-padding ion-text-center ion-align-self-center\"\n @fadeInAnimation>\n <ion-card-header>\n <ion-card-title class=\"ion-text-center\">\n <span *ngIf=\"isWeb\" [innerHTML]=\"'HOME.WELCOME_WEB'|translate: {appName: appName}\"></span>\n <span *ngIf=\"!isWeb\" [innerHTML]=\"'HOME.WELCOME_APP'|translate: {appName: appName}\"></span>\n </ion-card-title>\n <ion-card-subtitle [innerHTML]=\"description\">\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content class=\"ion-no-padding\">\n <ion-text color=\"primary\">\n <img class=\"logo\" *ngIf=\"logo\" src=\"{{ logo }}\">\n </ion-text>\n <!-- register help text -->\n <ion-text *ngIf=\"!isLogin && canRegister\">\n <br/>\n <span translate>HOME.REGISTER_HELP</span>\n </ion-text>\n </ion-card-content>\n\n <ion-footer class=\"ion-padding-top\">\n\n <!-- If NOT login -->\n <ng-container *ngIf=\"!isLogin; else loginButtons;\">\n\n <ion-button *ngIf=\"canRegister\" expand=\"block\" color=\"tertiary\" (click)=\"register()\">\n <span translate>HOME.BTN_REGISTER</span>\n </ion-button>\n <ion-button expand=\"block\" color=\"light\" [routerLink]=\"['/']\" (click)=\"login()\">\n <span translate>AUTH.BTN_LOGIN</span>\n </ion-button>\n\n </ng-container>\n\n <!-- If user login -->\n <ng-template #loginButtons>\n\n <!-- Feature buttons -->\n <ng-container *ngIf=\"$filteredButtons | async as buttons\">\n <ng-container *ngFor=\"let item of buttons\">\n <ion-button *ngIf=\"item.path\"\n expand=\"block\" color=\"tertiary\"\n [class]=\"item.cssClass\"\n [routerLink]=\"item.path\"\n routerDirection=\"root\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" class=\"ion-float-start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-text>{{'HOME.BTN_DATA_ENTRY'|translate: {name: (item.title | translate) } }}</ion-text>\n </ion-button>\n\n <!-- divider -->\n <div *ngIf=\"!item.path && !item.action\" [class]=\"item.cssClass\">\n <ion-label translate>{{item.title}} </ion-label>\n </div>\n </ng-container>\n\n <!--<p *ngIf=\"buttons.length\" class=\"visible-mobile\"> </p>-->\n </ng-container>\n\n <ion-button *ngIf=\"showAccountButton\" expand=\"block\" color=\"secondary\" [routerLink]=\"['/account']\">\n <ion-icon slot=\"start\" class=\"ion-float-start\" name=\"person-circle\"></ion-icon>\n <ion-text translate>HOME.BTN_MY_ACCOUNT</ion-text>\n </ion-button>\n\n <p hidden-xs hidden-sm hidden-mobile>\n <ion-text [innerHTML]=\"'HOME.NOT_THIS_ACCOUNT_QUESTION' | translate: {displayName: accountName }\"></ion-text>\n <br/>\n <ion-text>\n <a href=\"#\" (click)=\"logout($event)\">\n <span translate>HOME.BTN_DISCONNECT</span>\n </a>\n </ion-text>\n </p>\n\n\n </ng-template>\n\n </ion-footer>\n </ion-card>\n\n <!-- Page history -->\n <ion-grid *ngIf=\"!loading && isLogin && pageHistory.length; else bottomBanner\"\n class=\"history-container ion-align-self-center\">\n <ion-row>\n <ion-col size=\"12\" size-xl=\"\" *ngFor=\"let page of pageHistory; trackBy: getPagePath\"\n class=\"ion-text-center\">\n <ion-card class=\"ion-align-self-start ion-text-start\" @fadeInAnimation>\n <ion-card-header class=\"ion-no-padding\">\n <!-- top bar -->\n <ion-card-subtitle>\n <button type=\"button\" tabindex=\"-1\"\n (click)=\"settings.removePageHistory(page.path)\"\n mat-icon-button class=\"ion-float-start ion-no-margin\">\n <mat-icon>close</mat-icon>\n </button>\n <ion-label [innerHTML]=\"page.subtitle|translate\"></ion-label>\n <ion-text class=\"ion-float-end\" [title]=\"page.time|dateFormat:{time: true}\">\n <small><ion-icon name=\"time-outline\"></ion-icon> {{ page.time|dateFromNow }}</small> \n </ion-text>\n </ion-card-subtitle>\n\n <!-- main page -->\n <ion-card-title class=\"ion-no-margin ion-no-padding\">\n <ion-item detail=\"true\"\n tappable class=\"text-1x\"\n [routerLink]=\"page.path\"\n routerDirection=\"root\" lines=\"none\">\n <!-- page icon-->\n <ion-icon *ngIf=\"page.icon\" slot=\"start\" [name]=\"page.icon\"></ion-icon>\n <mat-icon *ngIf=\"page.matIcon\" slot=\"start\">{{page.matIcon}}</mat-icon>\n\n <ion-label color=\"primary\" [innerHTML]=\"page.title\"></ion-label>\n </ion-item>\n </ion-card-title>\n </ion-card-header>\n\n <!-- children pages -->\n <ion-card-content class=\"ion-no-padding ion-padding-start\" *ngIf=\"page.children?.length\">\n <ion-list class=\"ion-no-padding\">\n <ion-item detail=\"true\"\n *ngFor=\"let childPage of page.children\"\n tappable class=\"text-1x\"\n [routerLink]=\"childPage.path\"\n routerDirection=\"root\">\n <!-- page icon-->\n <ion-icon *ngIf=\"childPage.icon\" slot=\"start\" color=\"dark\" [name]=\"childPage.icon\"></ion-icon>\n <mat-icon *ngIf=\"childPage.matIcon\" slot=\"start\" color=\"dark\">{{childPage.matIcon}}</mat-icon>\n\n <ion-label color=\"dark\" [innerHTML]=\"childPage.title\"></ion-label>\n </ion-item>\n </ion-list>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n\n <!-- Display configured Departments logos -->\n <ng-template #bottomBanner>\n <div class=\"bottom-banner ion-text-center ion-padding\" *ngIf=\"!loadingBanner\" @fadeInAnimation>\n <a href=\"{{ item.siteUrl }}\" *ngFor=\"let item of $partners | async \">\n <img class=\"logo\" src=\"{{ item.logo }}\" alt=\"{{item.label}}\" [title]=\"item.label\" />\n </a>\n </div>\n </ng-template>\n\n\n</ion-content>\n",
|
|
18727
18891
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
18728
18892
|
animations: [fadeInAnimation, slideUpDownAnimation],
|
|
18729
18893
|
styles: ["h1,h2,h3,h4,h5{white-space:normal}.center,ion-content ion-card.welcome img{text-align:center;display:inline-block}ion-content{--background:transparent;background-size:cover;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;display:inline-block;padding:15px}ion-content,ion-content .loading-page{background-color:var(--ion-color-primary)}ion-content .loading-page{display:block;height:100%;width:100%;position:absolute;z-index:5;transition:background .5s linear;-webkit-transition:background 1.5s linear}ion-content .loading-page.hidden{background-color:rgba(var(--ion-color-primary),0)}ion-content ion-card{z-index:9}ion-content ion-card ion-card-header{display:block}ion-content ion-card ion-card-header ion-card-subtitle,ion-content ion-card ion-card-header ion-card-title{display:block;width:100%}ion-content ion-card.main{min-width:240px;max-width:400px;margin-left:auto;margin-right:auto}ion-content ion-card.welcome{background-color:hsla(0,0%,100%,.7)}ion-content ion-card.welcome button{margin-top:16px}ion-content ion-card.welcome img{max-width:250px}ion-content .history-container{margin-left:auto;margin-right:auto}ion-content .history-container ion-card{display:inline-block;box-sizing:border-box;z-index:8;min-width:240px;max-width:400px;width:100%;margin-left:auto;margin-right:auto;background-color:hsla(0,0%,100%,.7)}ion-content .history-container ion-card ion-card-header ion-card-subtitle{height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle button[float-start]{z-index:99;margin:0}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label{line-height:40px}ion-content .history-container ion-card ion-card-header ion-card-subtitle ion-label[float-end]{padding-right:16px;font-weight:400}ion-content .history-container ion-card ion-card-header ion-card-title ion-item{--ion-item-background:$transparent;--ion-item-icon-color:var(--ion-color-primary);--ion-item-text-color:var(--ion-color-primary)}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-header ion-card-title ion-item mat-icon[slot=start]{margin-right:unset;-webkit-margin-end:16px!important;margin-inline-end:16px!important;color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-label,ion-content .history-container ion-card ion-card-header ion-card-title ion-item ion-text{color:var(--ion-item-text-color)!important;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%}ion-content .history-container ion-card ion-card-content ion-list{--ion-item-background:var(--ion-color-transparent)}ion-content .history-container ion-card ion-card-content ion-list ion-item{--ion-item-icon-color:var(--ion-color-dark);--ion-item-text-color:var(--ion-color-dark)}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-icon[slot=start],ion-content .history-container ion-card ion-card-content ion-list ion-item mat-icon[slot=start]{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor;margin-right:unset;-webkit-margin-end:16px!important;margin-inline-end:16px!important}ion-content .history-container ion-card ion-card-content ion-list ion-item ion-label,ion-content .history-container ion-card ion-card-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-content .bottom-banner{background-color:hsla(0,0%,100%,.7);min-width:240px;z-index:0;position:absolute;left:16px;right:16px;bottom:16px}ion-content .bottom-banner img.logo{max-height:50px;margin-left:8px}ion-content ion-text{text-align:center}@media screen and (max-width:575px){ion-content ion-card{min-width:160px;width:calc(100% - 20px);max-width:100%;margin-left:10px;margin-right:10px}ion-content ion-card h1{margin-top:0;font-size:20px}ion-content ion-card ion-card-content ion-button{margin-top:8px}ion-content .bottom-banner{display:block;position:unset}ion-content .bottom-banner img.logo{max-height:30px}}@media screen and (max-width:767px) and (min-width:576px){ion-content{min-height:555px}ion-content .bottom-banner img.logo{max-height:40px}}@media screen and (min-width:768px){ion-content{min-height:calc(100% - 100px)}}"]
|
|
@@ -18970,8 +19134,9 @@ class AccountPage extends AppForm {
|
|
|
18970
19134
|
this.setValue(this.accountService.account);
|
|
18971
19135
|
this.markAsPristine();
|
|
18972
19136
|
}));
|
|
18973
|
-
this.registerSubscription(this.accountService.$additionalFields
|
|
18974
|
-
|
|
19137
|
+
this.registerSubscription(this.accountService.$additionalFields
|
|
19138
|
+
.subscribe((additionalFields) => {
|
|
19139
|
+
this.additionalFields = additionalFields.slice(); // Copy
|
|
18975
19140
|
if (accountService.isLogin()) {
|
|
18976
19141
|
this.onLogin(this.accountService.account);
|
|
18977
19142
|
}
|
|
@@ -19105,9 +19270,21 @@ class AccountPage extends AppForm {
|
|
|
19105
19270
|
this.form.controls.pubkey.disable();
|
|
19106
19271
|
// Always disable some additional fields
|
|
19107
19272
|
this.additionalFields
|
|
19108
|
-
.filter(field => field.extra && field.extra.account && field.extra.account.disabled || false)
|
|
19109
19273
|
.forEach(field => {
|
|
19110
|
-
|
|
19274
|
+
var _a, _b;
|
|
19275
|
+
const control = this.form.controls[field.key];
|
|
19276
|
+
if (!control)
|
|
19277
|
+
return; // Skip
|
|
19278
|
+
const disabled = ((_a = field.extra) === null || _a === void 0 ? void 0 : _a.account) && field.extra.account.disabled || false;
|
|
19279
|
+
if (disabled && control.enabled) {
|
|
19280
|
+
control.disable();
|
|
19281
|
+
}
|
|
19282
|
+
const required = ((_b = field.extra) === null || _b === void 0 ? void 0 : _b.account) && field.extra.account.required || false;
|
|
19283
|
+
if (!field.required && required) {
|
|
19284
|
+
control.setValidators(control.validator
|
|
19285
|
+
? Validators.compose([control.validator, Validators.required])
|
|
19286
|
+
: Validators.required);
|
|
19287
|
+
}
|
|
19111
19288
|
});
|
|
19112
19289
|
this.markForCheck();
|
|
19113
19290
|
}
|
|
@@ -19164,11 +19341,62 @@ EntityMetadataComponent.propDecorators = {
|
|
|
19164
19341
|
showRecorder: [{ type: Input }]
|
|
19165
19342
|
};
|
|
19166
19343
|
|
|
19344
|
+
const DEFAULT_MENU_SHOW_WHEN = 'lg';
|
|
19345
|
+
class MenuService {
|
|
19346
|
+
constructor() {
|
|
19347
|
+
this._$toggled = new Subject();
|
|
19348
|
+
this._$opened = new Subject();
|
|
19349
|
+
this._$splitPaneWhen = new BehaviorSubject(DEFAULT_MENU_SHOW_WHEN);
|
|
19350
|
+
this._$enabled = new BehaviorSubject(true);
|
|
19351
|
+
}
|
|
19352
|
+
get opened() {
|
|
19353
|
+
return this._$opened.asObservable();
|
|
19354
|
+
}
|
|
19355
|
+
get splitPaneWhen() {
|
|
19356
|
+
return this._$splitPaneWhen.asObservable();
|
|
19357
|
+
}
|
|
19358
|
+
get enabled() {
|
|
19359
|
+
return this._$enabled.asObservable();
|
|
19360
|
+
}
|
|
19361
|
+
toggle() {
|
|
19362
|
+
this._$toggled.next();
|
|
19363
|
+
}
|
|
19364
|
+
enable(value) {
|
|
19365
|
+
this._$enabled.next(value);
|
|
19366
|
+
}
|
|
19367
|
+
setSplitPaneShowWhen(value) {
|
|
19368
|
+
if (this._$splitPaneWhen.value !== value) {
|
|
19369
|
+
this._$splitPaneWhen.next(value);
|
|
19370
|
+
}
|
|
19371
|
+
}
|
|
19372
|
+
toggleSplitPaneWhen() {
|
|
19373
|
+
if (this._$splitPaneWhen.value !== false) {
|
|
19374
|
+
this._$splitPaneWhen.next(false);
|
|
19375
|
+
}
|
|
19376
|
+
else {
|
|
19377
|
+
this._$splitPaneWhen.next(DEFAULT_MENU_SHOW_WHEN);
|
|
19378
|
+
}
|
|
19379
|
+
}
|
|
19380
|
+
_markAsOpened() {
|
|
19381
|
+
this._$opened.next(true);
|
|
19382
|
+
}
|
|
19383
|
+
_markAsClosed() {
|
|
19384
|
+
this._$opened.next(false);
|
|
19385
|
+
}
|
|
19386
|
+
}
|
|
19387
|
+
MenuService.ɵprov = ɵɵdefineInjectable({ factory: function MenuService_Factory() { return new MenuService(); }, token: MenuService, providedIn: "root" });
|
|
19388
|
+
MenuService.decorators = [
|
|
19389
|
+
{ type: Injectable, args: [{
|
|
19390
|
+
providedIn: 'root'
|
|
19391
|
+
},] }
|
|
19392
|
+
];
|
|
19393
|
+
|
|
19167
19394
|
class FormButtonsBarToken {
|
|
19168
19395
|
}
|
|
19169
19396
|
class FormButtonsBarComponent {
|
|
19170
|
-
constructor(hotkeys) {
|
|
19397
|
+
constructor(hotkeys, menu) {
|
|
19171
19398
|
this.hotkeys = hotkeys;
|
|
19399
|
+
this.menu = menu;
|
|
19172
19400
|
this._subscription = new Subscription();
|
|
19173
19401
|
this.disabled = false;
|
|
19174
19402
|
this.disabledCancel = false;
|
|
@@ -19200,15 +19428,16 @@ class FormButtonsBarComponent {
|
|
|
19200
19428
|
FormButtonsBarComponent.decorators = [
|
|
19201
19429
|
{ type: Component, args: [{
|
|
19202
19430
|
selector: 'app-form-buttons-bar',
|
|
19203
|
-
template: "<ion-toolbar [class]=\"classList\">\n <ion-row class=\"ion-no-padding\" nowrap>\n <ion-col>\n <ng-content></ng-content>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <!-- close (go back) -->\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"onBack.emit($event)\"\n (keyup.enter)=\"onBack.emit($event)\"\n *ngIf=\"onBack.observers | isNotEmptyArray\">\n <ion-label translate>COMMON.BTN_CLOSE</ion-label>\n </ion-button>\n\n <!-- reload -->\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"onCancel.emit($event)\"\n (keyup.enter)=\"onCancel.emit($event)\"\n [disabled]=\"disabledCancel\">\n <ion-icon slot=\"start\" name=\"refresh\"></ion-icon>\n <ion-label translate>COMMON.BTN_RESET</ion-label>\n </ion-button>\n\n <!-- next -->\n <ion-button fill=\"solid\" (click)=\"onNext.emit($event)\" (keyup.enter)=\"onNext.emit($event)\" *ngIf=\"onNext.observers | isNotEmptyArray\">\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <!-- save -->\n <ion-button [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onSave.emit($event)\"\n (keyup.enter)=\"onSave.emit($event)\" color=\"danger\"\n [disabled]=\"disabled\">\n <ion-label [innerHTML]=\"'COMMON.BTN_SAVE_WITH_SHORTCUT'|translate\" [title]=\"'COMMON.BTN_SAVE_WITH_SHORTCUT_HELP'|translate\"></ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n</ion-toolbar>\n",
|
|
19431
|
+
template: "\n<ion-toolbar [class]=\"classList\">\n <ion-row class=\"ion-no-padding\" nowrap>\n <!-- show menu button -->\n <ion-col size=\"auto\" class=\"hidden-xs hidden-sm\">\n <ion-menu-toggle>\n <button\n mat-icon-button\n color=\"accent\"\n [title]=\"'COMMON.BTN_SHOW_MENU' | translate\"\n (click)=\"menu.toggleSplitPaneWhen()\">\n <mat-icon><span>»</span></mat-icon>\n </button>\n </ion-menu-toggle>\n </ion-col>\n\n <ion-col>\n <ng-content></ng-content>\n </ion-col>\n\n <ion-col size=\"auto\">\n\n <!-- close (go back) -->\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"onBack.emit($event)\"\n (keyup.enter)=\"onBack.emit($event)\"\n *ngIf=\"onBack.observers | isNotEmptyArray\">\n <ion-label translate>COMMON.BTN_CLOSE</ion-label>\n </ion-button>\n\n <!-- reload -->\n <ion-button fill=\"clear\" color=\"dark\" (click)=\"onCancel.emit($event)\"\n (keyup.enter)=\"onCancel.emit($event)\"\n [disabled]=\"disabledCancel\">\n <ion-icon slot=\"start\" name=\"refresh\"></ion-icon>\n <ion-label translate>COMMON.BTN_RESET</ion-label>\n </ion-button>\n\n <!-- next -->\n <ion-button fill=\"solid\" (click)=\"onNext.emit($event)\" (keyup.enter)=\"onNext.emit($event)\" *ngIf=\"onNext.observers | isNotEmptyArray\">\n <ion-label translate>COMMON.BTN_NEXT</ion-label>\n <ion-icon slot=\"end\" name=\"arrow-forward\"></ion-icon>\n </ion-button>\n\n <!-- save -->\n <ion-button [fill]=\"disabled ? 'clear' : 'solid'\"\n (click)=\"onSave.emit($event)\"\n (keyup.enter)=\"onSave.emit($event)\" color=\"danger\"\n [disabled]=\"disabled\">\n <ion-label [innerHTML]=\"'COMMON.BTN_SAVE_WITH_SHORTCUT'|translate\" [title]=\"'COMMON.BTN_SAVE_WITH_SHORTCUT_HELP'|translate\"></ion-label>\n </ion-button>\n </ion-col>\n </ion-row>\n</ion-toolbar>\n",
|
|
19204
19432
|
providers: [
|
|
19205
19433
|
{ provide: FormButtonsBarToken, useExisting: FormButtonsBarComponent }
|
|
19206
19434
|
],
|
|
19207
|
-
styles: [":host{width:100%}:host ion-toolbar{height:var(--app-form-buttons-bar-height);padding:0 6px}:host ion-col{padding:0}"]
|
|
19435
|
+
styles: [":host{width:100%}:host ion-toolbar{height:var(--app-form-buttons-bar-height);padding:0 6px}:host ion-col{padding:0}ion-menu-toggle button{top:4px}"]
|
|
19208
19436
|
},] }
|
|
19209
19437
|
];
|
|
19210
19438
|
FormButtonsBarComponent.ctorParameters = () => [
|
|
19211
|
-
{ type: Hotkeys }
|
|
19439
|
+
{ type: Hotkeys },
|
|
19440
|
+
{ type: MenuService }
|
|
19212
19441
|
];
|
|
19213
19442
|
FormButtonsBarComponent.propDecorators = {
|
|
19214
19443
|
disabled: [{ type: Input }],
|
|
@@ -20084,7 +20313,7 @@ AppListForm.decorators = [
|
|
|
20084
20313
|
selector: 'app-list-form',
|
|
20085
20314
|
template: "\n<ng-container *ngIf=\"!loading; else listSkeleton\">\n\n <!-- List -->\n <ion-list class=\"ion-no-padding\" >\n\n <ng-container *ngFor=\"let itemControl of itemControls; index as i; last as last\">\n <ion-item *ngIf=\"itemControl.value; let item\"\n [class.disabled]=\"disabled\" tappable\n (click)=\"onItemClick($event, item)\"\n [color]=\"selection.isSelected(item) ? 'secondary100' : undefined\"\n [button]=\"selectionChanges.observers.length > 0\">\n <ion-label>{{displayWith(item)}}</ion-label>\n\n <!-- buttons -->\n <ion-buttons slot=\"end\" *ngIf=\"enabled\" class=\"action-buttons\">\n <ion-button fill=\"clear\" (click)=\"removeAt(i)\">\n <ion-icon slot=\"icon-only\" name=\"trash\"></ion-icon>\n </ion-button>\n\n <ion-button *ngFor=\"let button of options.buttons\"\n fill=\"clear\" [color]=\"button.color\"\n [class.cdk-visually-hidden]=\"button.disabled|async\"\n (click)=\"onItemButtonClick(button, $event, item, i)\"\n [title]=\"(button.title || '')|translate\">\n <ion-icon slot=\"icon-only\" [name]=\"button.icon\"></ion-icon>\n </ion-button>\n\n </ion-buttons>\n </ion-item>\n </ng-container>\n </ion-list>\n\n <!-- Add button -->\n <ion-button color=\"tertiary\" fill=\"clear\"\n *ngIf=\"enabled && onNewItem.observers.length; else emptyText\"\n [title]=\"'COMMON.BTN_ADD'|translate\"\n (click)=\"onNewClick($event)\" >\n <ion-icon slot=\"start\" name=\"add\"></ion-icon>\n <ion-label translate>COMMON.BTN_ADD</ion-label>\n </ion-button>\n\n <!-- Empty (if readonly) -->\n <ng-template #emptyText>\n <ion-text *ngIf=\"!length\" color=\"medium\"><i translate>COMMON.EMPTY_OPTION</i></ion-text>\n </ng-template>\n</ng-container>\n\n<ng-template #listSkeleton>\n\n <ion-list>\n <ng-container *ngTemplateOutlet=\"itemSkeleton\"></ng-container>\n <ng-container *ngTemplateOutlet=\"itemSkeleton\"></ng-container>\n <ng-container *ngTemplateOutlet=\"itemSkeleton\"></ng-container>\n </ion-list>\n\n</ng-template>\n\n<ng-template #itemSkeleton>\n\n <ion-item>\n <ion-label>\n <ion-skeleton-text animated style=\"width: 60%\"></ion-skeleton-text>\n </ion-label>\n </ion-item>\n\n</ng-template>\n",
|
|
20086
20315
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20087
|
-
styles: [":host{--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-
|
|
20316
|
+
styles: [":host{--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-color-selected:var(--ion-color-secondary100-contrast)}ion-item.disabled ion-label{color:var(--ion-color-medium-shade,grey)}ion-item{--min-height:48px;background-color:var(--ion-item-background)}ion-item ion-label,ion-item ion-text{color:var(--ion-item-color)}ion-item .action-buttons{visibility:hidden;display:none}ion-item:hover{height:var(--min-height);--ion-item-background-color:var(--ion-color-light);--ion-item-color:var(--ion-color-light-contrast)}ion-item:hover .action-buttons{margin-top:-1px;visibility:visible;display:block}ion-item.selected{--ion-item-background-color-hover:var(--ion-item-background-selected)!important;--ion-item-color-hover:var(--ion-item-color-selected)!important}"]
|
|
20088
20317
|
},] }
|
|
20089
20318
|
];
|
|
20090
20319
|
AppListForm.ctorParameters = () => [
|
|
@@ -20145,9 +20374,6 @@ PersonToStringPipe.decorators = [
|
|
|
20145
20374
|
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
20146
20375
|
];
|
|
20147
20376
|
|
|
20148
|
-
const MimeTypes = Object.freeze({
|
|
20149
|
-
ANDROID_APK: 'application/vnd.android.package-archive'
|
|
20150
|
-
});
|
|
20151
20377
|
class AppInstallUpgradeCard {
|
|
20152
20378
|
constructor(modalCtrl, configService, toastController, alertController, translate, cd, platform, network, environment) {
|
|
20153
20379
|
this.modalCtrl = modalCtrl;
|
|
@@ -20160,7 +20386,6 @@ class AppInstallUpgradeCard {
|
|
|
20160
20386
|
this.network = network;
|
|
20161
20387
|
this.environment = environment;
|
|
20162
20388
|
this._subscription = new Subscription();
|
|
20163
|
-
this._showUpdateOfflineFeature = false;
|
|
20164
20389
|
this.loading = true;
|
|
20165
20390
|
this.hasDownloader = false;
|
|
20166
20391
|
this.downloading = false;
|
|
@@ -20168,16 +20393,6 @@ class AppInstallUpgradeCard {
|
|
|
20168
20393
|
this.showUpgradeWarning = true;
|
|
20169
20394
|
this.showOfflineWarning = true;
|
|
20170
20395
|
this.showInstallButton = false;
|
|
20171
|
-
this.onUpdateOfflineModeClick = new EventEmitter();
|
|
20172
|
-
}
|
|
20173
|
-
set showUpdateOfflineFeature(value) {
|
|
20174
|
-
if (value === this._showUpdateOfflineFeature)
|
|
20175
|
-
return; // Skip
|
|
20176
|
-
this._showUpdateOfflineFeature = value;
|
|
20177
|
-
this.markForCheck();
|
|
20178
|
-
}
|
|
20179
|
-
get showUpdateOfflineFeature() {
|
|
20180
|
-
return this._showUpdateOfflineFeature;
|
|
20181
20396
|
}
|
|
20182
20397
|
ngOnInit() {
|
|
20183
20398
|
this.offline = this.network.offline;
|
|
@@ -20201,7 +20416,6 @@ class AppInstallUpgradeCard {
|
|
|
20201
20416
|
ngOnDestroy() {
|
|
20202
20417
|
this._subscription.unsubscribe();
|
|
20203
20418
|
this._subscription = null;
|
|
20204
|
-
this.onUpdateOfflineModeClick.complete();
|
|
20205
20419
|
this.installLinks = null;
|
|
20206
20420
|
this.upgradeLinks = null;
|
|
20207
20421
|
}
|
|
@@ -20352,10 +20566,10 @@ class AppInstallUpgradeCard {
|
|
|
20352
20566
|
let title;
|
|
20353
20567
|
let mimeType;
|
|
20354
20568
|
// Get file name
|
|
20355
|
-
let filename =
|
|
20569
|
+
let filename = UriUtils.getFilename(url);
|
|
20356
20570
|
let version = minVersion || 'latest';
|
|
20357
20571
|
// OK, this is a downloadable APK file (e.g. NOT a link to a playstore)
|
|
20358
|
-
if (filename === null || filename === void 0 ? void 0 : filename.endsWith('.apk')) {
|
|
20572
|
+
if (filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.apk')) {
|
|
20359
20573
|
// Define mime type
|
|
20360
20574
|
mimeType = MimeTypes.ANDROID_APK;
|
|
20361
20575
|
// Get the file version (if any)
|
|
@@ -20366,11 +20580,9 @@ class AppInstallUpgradeCard {
|
|
|
20366
20580
|
filename = `${name}-v${version}.apk`.toLowerCase();
|
|
20367
20581
|
title = `${name} v${version}`;
|
|
20368
20582
|
}
|
|
20369
|
-
|
|
20370
|
-
|
|
20371
|
-
|
|
20372
|
-
filename = filename.replace('latest', version);
|
|
20373
|
-
}
|
|
20583
|
+
// Replace 'latest' with the app version, if present in the filename
|
|
20584
|
+
else if (filename.indexOf('latest') && version !== 'latest') {
|
|
20585
|
+
filename = filename.replace('latest', version);
|
|
20374
20586
|
}
|
|
20375
20587
|
}
|
|
20376
20588
|
result.push({ name, url, platform: 'android', version, filename, title, mimeType });
|
|
@@ -20382,18 +20594,6 @@ class AppInstallUpgradeCard {
|
|
|
20382
20594
|
//}
|
|
20383
20595
|
return result;
|
|
20384
20596
|
}
|
|
20385
|
-
getFilename(url) {
|
|
20386
|
-
if (!url)
|
|
20387
|
-
return;
|
|
20388
|
-
// Get last part (or all string, if no '/')
|
|
20389
|
-
let filename = url.substring(url.lastIndexOf('/') + 1);
|
|
20390
|
-
const queryParamIndex = filename.indexOf('?');
|
|
20391
|
-
if (queryParamIndex !== -1) {
|
|
20392
|
-
// Remove query params
|
|
20393
|
-
return filename.substring(0, queryParamIndex);
|
|
20394
|
-
}
|
|
20395
|
-
return filename;
|
|
20396
|
-
}
|
|
20397
20597
|
listenDownloadJobs() {
|
|
20398
20598
|
// Listening downloading promise, if exists
|
|
20399
20599
|
(this.upgradeLinks || []).forEach(link => {
|
|
@@ -20491,7 +20691,7 @@ class AppInstallUpgradeCard {
|
|
|
20491
20691
|
AppInstallUpgradeCard.decorators = [
|
|
20492
20692
|
{ type: Component, args: [{
|
|
20493
20693
|
selector: 'app-install-upgrade-card',
|
|
20494
|
-
template: "\n\n<!-- Offline mode card-->\n<ion-card *ngIf=\"showOfflineWarning && (!loading && offline || waitingNetwork)\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" *ngIf=\"!waitingNetwork; else waitingNetworkText\">\n <h4>\n <b *ngIf=\"isLogin; else notLogin\" [innerHTML]=\"'NETWORK.INFO.OFFLINE_OR_UNAUTHORIZED'| translate\"></b>\n <ng-template #notLogin>\n <b [innerHTML]=\"'NETWORK.INFO.OFFLINE'| translate\"></b>\n </ng-template>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.OFFLINE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n <ng-template #waitingNetworkText>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"'NETWORK.INFO.RETRY_TO_CONNECT'| translate\"></ion-text>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button *ngIf=\"!waitingNetwork; else waitingSpinner\" color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"tryOnline()\">\n <span translate>NETWORK.BTN_CHECK_ALIVE</span>\n </ion-button>\n\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Upgrade links -->\n<ion-card *ngIf=\"showUpgradeWarning && !loading && !offline && upgradeLinks\"\n color=\"accent\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of upgradeLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3>\n <span *ngIf=\"link.version\" [innerHTML]=\"'INFO.UPDATE_APP_TO_VERSION'| translate: link\"></span>\n <span *ngIf=\"!link.version\" [innerHTML]=\"'INFO.UPDATE_APP'| translate: link\"></span>\n </h3>\n <h4>\n <small *ngIf=\"last\" [innerHTML]=\"'INFO.UPDATE_APP_HELP'|translate\"></small>\n </h4>\n </ion-text>\n </ion-col>\n\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Install links -->\n<ion-card *ngIf=\"showInstallButton && !loading && !offline && installLinks\"\n color=\"secondary\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of installLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3 [innerHTML]=\"'INFO.DOWNLOAD_APP_TITLE'| translate: {name: link.name, platform: getPlatformName(link.platform) }\"></h3>\n <h4><small *ngIf=\"last\" [innerHTML]=\"'INFO.DOWNLOAD_APP_HELP'|translate\"></small></h4>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!--
|
|
20694
|
+
template: "\n\n<!-- Offline mode card-->\n<ion-card *ngIf=\"showOfflineWarning && (!loading && offline || waitingNetwork)\"\n color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" *ngIf=\"!waitingNetwork; else waitingNetworkText\">\n <h4>\n <b *ngIf=\"isLogin; else notLogin\" [innerHTML]=\"'NETWORK.INFO.OFFLINE_OR_UNAUTHORIZED'| translate\"></b>\n <ng-template #notLogin>\n <b [innerHTML]=\"'NETWORK.INFO.OFFLINE'| translate\"></b>\n </ng-template>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.OFFLINE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n <ng-template #waitingNetworkText>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"'NETWORK.INFO.RETRY_TO_CONNECT'| translate\"></ion-text>\n </ng-template>\n </ion-col>\n <ion-col size=\"auto\">\n\n <!-- Retry button -->\n <ion-button *ngIf=\"!waitingNetwork; else waitingSpinner\" color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"tryOnline()\">\n <span translate>NETWORK.BTN_CHECK_ALIVE</span>\n </ion-button>\n\n </ion-col>\n </ion-row>\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Upgrade links -->\n<ion-card *ngIf=\"showUpgradeWarning && !loading && !offline && upgradeLinks\"\n color=\"accent\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of upgradeLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3>\n <span *ngIf=\"link.version\" [innerHTML]=\"'INFO.UPDATE_APP_TO_VERSION'| translate: link\"></span>\n <span *ngIf=\"!link.version\" [innerHTML]=\"'INFO.UPDATE_APP'| translate: link\"></span>\n </h3>\n <h4>\n <small *ngIf=\"last\" [innerHTML]=\"'INFO.UPDATE_APP_HELP'|translate\"></small>\n </h4>\n </ion-text>\n </ion-col>\n\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Install links -->\n<ion-card *ngIf=\"showInstallButton && !loading && !offline && installLinks\"\n color=\"secondary\"\n class=\"ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngFor=\"let link of installLinks; last as last\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\">\n <h3 [innerHTML]=\"'INFO.DOWNLOAD_APP_TITLE'| translate: {name: link.name, platform: getPlatformName(link.platform) }\"></h3>\n <h4><small *ngIf=\"last\" [innerHTML]=\"'INFO.DOWNLOAD_APP_HELP'|translate\"></small></h4>\n </ion-text>\n </ion-col>\n <ion-col size=\"auto\">\n <ng-container *ngTemplateOutlet=\"downloadButton; context: { $implicit: link }\"></ng-container>\n </ion-col>\n </ion-row>\n\n </ion-grid>\n\n </ion-card-content>\n</ion-card>\n\n<!-- Display a download button, depending on the link URL, and the device platform -->\n<ng-template #downloadButton let-link>\n\n <ng-container *ngIf=\"link.filename; else redirectButton\">\n\n <ng-container *ngIf=\"hasDownloader; else webDownloadButton\">\n <!-- Download using platform -->\n <ion-button (click)=\"download($event, asLink(link))\"\n *ngIf=\"!link.location; else openButton\"\n [disabled]=\"link.downloading\"\n color=\"tertiary\" class=\"ion-float-end\">\n <ion-icon slot=\"start\" *ngIf=\"!link.downloading\" name=\"download\"></ion-icon>\n <ion-spinner slot=\"start\" class=\"ion-no-padding\" *ngIf=\"link.downloading\"></ion-spinner>\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n\n <!-- Open APK button -->\n <ng-template #openButton>\n <ion-button *ngIf=\"link.location\"\n (click)=\"openFile($event, link)\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_INSTALL</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web download button -->\n <ng-template #webDownloadButton>\n <ion-button [download]=\"link.downloadFilename\"\n [href]=\"link.url\"\n color=\"tertiary\" class=\"ion-float-end\" >\n <ion-label translate>COMMON.BTN_DOWNLOAD</ion-label>\n </ion-button>\n </ng-template>\n </ng-container>\n\n <!-- Web redirect button -->\n <ng-template #redirectButton>\n <ion-button [href]=\"link.url\" rel=\"external\" color=\"tertiary\" class=\"ion-float-end\" target=\"_blank\">\n <ion-label translate>COMMON.BTN_SHOW_MORE</ion-label>\n </ion-button>\n </ng-template>\n</ng-template>\n\n\n<!-- Waiting spinner -->\n<ng-template #waitingSpinner>\n <ion-spinner color=\"light\"></ion-spinner>\n</ng-template>\n",
|
|
20495
20695
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20496
20696
|
animations: [slideUpDownAnimation],
|
|
20497
20697
|
styles: ["ion-text small{font-size:85%}"]
|
|
@@ -20512,9 +20712,7 @@ AppInstallUpgradeCard.propDecorators = {
|
|
|
20512
20712
|
isLogin: [{ type: Input }],
|
|
20513
20713
|
showUpgradeWarning: [{ type: Input }],
|
|
20514
20714
|
showOfflineWarning: [{ type: Input }],
|
|
20515
|
-
showInstallButton: [{ type: Input }]
|
|
20516
|
-
showUpdateOfflineFeature: [{ type: Input }],
|
|
20517
|
-
onUpdateOfflineModeClick: [{ type: Output }]
|
|
20715
|
+
showInstallButton: [{ type: Input }]
|
|
20518
20716
|
};
|
|
20519
20717
|
|
|
20520
20718
|
class IsLoginAccountPipe {
|
|
@@ -20627,33 +20825,7 @@ ActionsColumnComponent.propDecorators = {
|
|
|
20627
20825
|
forward: [{ type: Output }]
|
|
20628
20826
|
};
|
|
20629
20827
|
|
|
20630
|
-
class MenuService {
|
|
20631
|
-
constructor() {
|
|
20632
|
-
this._toggledSubject = new Subject();
|
|
20633
|
-
this._visibleSubject = new Subject();
|
|
20634
|
-
}
|
|
20635
|
-
get menuToggled$() {
|
|
20636
|
-
return this._toggledSubject.asObservable();
|
|
20637
|
-
}
|
|
20638
|
-
get menuVisible$() {
|
|
20639
|
-
return this._visibleSubject.asObservable();
|
|
20640
|
-
}
|
|
20641
|
-
toggleMenu() {
|
|
20642
|
-
this._toggledSubject.next();
|
|
20643
|
-
}
|
|
20644
|
-
menuVisible(value) {
|
|
20645
|
-
this._visibleSubject.next(value);
|
|
20646
|
-
}
|
|
20647
|
-
}
|
|
20648
|
-
MenuService.ɵprov = ɵɵdefineInjectable({ factory: function MenuService_Factory() { return new MenuService(); }, token: MenuService, providedIn: "root" });
|
|
20649
|
-
MenuService.decorators = [
|
|
20650
|
-
{ type: Injectable, args: [{
|
|
20651
|
-
providedIn: 'root'
|
|
20652
|
-
},] }
|
|
20653
|
-
];
|
|
20654
|
-
|
|
20655
20828
|
const APP_MENU_ITEMS = new InjectionToken('menuItems');
|
|
20656
|
-
const SPLIT_PANE_SHOW_WHEN = 'lg';
|
|
20657
20829
|
class MenuComponent {
|
|
20658
20830
|
constructor(platformService, accountService, router, menu, modalCtrl, alertController, translate, configService, cd, menuService, environment, items) {
|
|
20659
20831
|
this.platformService = platformService;
|
|
@@ -20672,28 +20844,35 @@ class MenuComponent {
|
|
|
20672
20844
|
this.loading = true;
|
|
20673
20845
|
this.isLogin = false;
|
|
20674
20846
|
this.$items = new BehaviorSubject(undefined);
|
|
20675
|
-
this.
|
|
20847
|
+
this.id = 'menu';
|
|
20848
|
+
this.menuId = 'left';
|
|
20676
20849
|
this.side = 'left';
|
|
20850
|
+
this.contentId = 'menu-content';
|
|
20851
|
+
this.appVersion = this.environment.version;
|
|
20677
20852
|
this._debug = !environment.production;
|
|
20678
20853
|
}
|
|
20679
20854
|
ngOnInit() {
|
|
20680
20855
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20681
|
-
this.
|
|
20682
|
-
this.splitPane.when = SPLIT_PANE_SHOW_WHEN;
|
|
20856
|
+
this.splitPane.when = yield firstNotNilPromise(this.menuService.splitPaneWhen);
|
|
20683
20857
|
// Wait platform started
|
|
20684
20858
|
yield this.platformService.ready();
|
|
20685
|
-
this.splitPaneOpened = true;
|
|
20686
20859
|
// Listen to menu service event
|
|
20687
|
-
this.menuService.
|
|
20688
|
-
.subscribe(() => this.
|
|
20860
|
+
this.menuService.splitPaneWhen
|
|
20861
|
+
.subscribe((value) => this.setSplitPaneWhen(value));
|
|
20862
|
+
this.menuService.enabled
|
|
20863
|
+
.subscribe((value) => this.enable(value));
|
|
20864
|
+
this.menuService.opened
|
|
20865
|
+
// Avoid duplicated events
|
|
20866
|
+
.pipe(distinctUntilChanged())
|
|
20867
|
+
.subscribe((value) => value ? this.open() : this.close());
|
|
20689
20868
|
// Update component when refresh is need (=login events or config changed)
|
|
20690
20869
|
this._subscription.add(merge(this.accountService.onLogin, this.accountService.onLogout, this.configService.config
|
|
20691
20870
|
.pipe(tap(config => this._config = config)))
|
|
20692
20871
|
.pipe(
|
|
20693
20872
|
// Wait account service ready (can be restarted)
|
|
20694
|
-
mergeMap(() => this.accountService.ready()))
|
|
20695
|
-
.subscribe(
|
|
20696
|
-
if (
|
|
20873
|
+
mergeMap(() => this.accountService.ready()), map(() => this.accountService.isLogin()), distinctUntilChanged())
|
|
20874
|
+
.subscribe(login => {
|
|
20875
|
+
if (login) {
|
|
20697
20876
|
this.onLogin(this.accountService.account);
|
|
20698
20877
|
}
|
|
20699
20878
|
else {
|
|
@@ -20721,8 +20900,6 @@ class MenuComponent {
|
|
|
20721
20900
|
if (!skipRedirect)
|
|
20722
20901
|
console.debug('[menu] logout');
|
|
20723
20902
|
this.isLogin = false;
|
|
20724
|
-
//this.splitPaneOpened = false;
|
|
20725
|
-
//this.splitPane.when = false;
|
|
20726
20903
|
this.accountAvatar = null;
|
|
20727
20904
|
this.accountEmail = null;
|
|
20728
20905
|
this.accountName = null;
|
|
@@ -20751,7 +20928,8 @@ class MenuComponent {
|
|
|
20751
20928
|
text: translations['COMMON.BTN_CANCEL'],
|
|
20752
20929
|
role: 'cancel',
|
|
20753
20930
|
cssClass: 'secondary'
|
|
20754
|
-
},
|
|
20931
|
+
},
|
|
20932
|
+
{
|
|
20755
20933
|
text: translations['AUTH.LOGOUT.BTN_CONFIRM'],
|
|
20756
20934
|
cssClass: 'ion-color-primary',
|
|
20757
20935
|
handler: () => {
|
|
@@ -20766,9 +20944,40 @@ class MenuComponent {
|
|
|
20766
20944
|
yield alert.present();
|
|
20767
20945
|
});
|
|
20768
20946
|
}
|
|
20769
|
-
|
|
20947
|
+
enable(value) {
|
|
20948
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20949
|
+
const enabled = yield this.menu.isEnabled(this.menuId);
|
|
20950
|
+
if (enabled !== value) {
|
|
20951
|
+
yield this.menu.enable(value, this.menuId);
|
|
20952
|
+
if (!value)
|
|
20953
|
+
yield this.close();
|
|
20954
|
+
}
|
|
20955
|
+
});
|
|
20956
|
+
}
|
|
20957
|
+
open() {
|
|
20958
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20959
|
+
console.debug('[menu] Checking open event...');
|
|
20960
|
+
const opened = yield this.menu.isOpen(this.menuId);
|
|
20961
|
+
if (!opened) {
|
|
20962
|
+
console.debug('[menu] Opening menu');
|
|
20963
|
+
yield this.menu.open(this.menuId);
|
|
20964
|
+
// Propage to service
|
|
20965
|
+
this.menuService._markAsOpened();
|
|
20966
|
+
}
|
|
20967
|
+
return true;
|
|
20968
|
+
});
|
|
20969
|
+
}
|
|
20970
|
+
close() {
|
|
20770
20971
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20771
|
-
|
|
20972
|
+
console.debug('[menu] Checking close event...');
|
|
20973
|
+
const opened = yield this.menu.isOpen(this.menuId);
|
|
20974
|
+
if (opened) {
|
|
20975
|
+
console.debug('[menu] Closing menu');
|
|
20976
|
+
yield this.menu.close(this.menuId);
|
|
20977
|
+
// Propage to service
|
|
20978
|
+
this.menuService._markAsClosed();
|
|
20979
|
+
}
|
|
20980
|
+
return true;
|
|
20772
20981
|
});
|
|
20773
20982
|
}
|
|
20774
20983
|
openAboutModal(event) {
|
|
@@ -20777,24 +20986,33 @@ class MenuComponent {
|
|
|
20777
20986
|
return modal.present();
|
|
20778
20987
|
});
|
|
20779
20988
|
}
|
|
20780
|
-
|
|
20989
|
+
setSplitPaneWhen(value) {
|
|
20990
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20991
|
+
console.debug('[menu] Checking splitPane when...');
|
|
20992
|
+
if (this.splitPane.when !== value) {
|
|
20993
|
+
console.debug('[menu] Set splitPane when to ' + value);
|
|
20994
|
+
this.splitPane.when = value;
|
|
20995
|
+
this.detectChanges();
|
|
20996
|
+
// Propagate to the menu service
|
|
20997
|
+
setTimeout(() => this.menuService.setSplitPaneShowWhen(value), 200);
|
|
20998
|
+
}
|
|
20999
|
+
});
|
|
21000
|
+
}
|
|
21001
|
+
toggleSplitPaneShow(event) {
|
|
20781
21002
|
if (event && event.defaultPrevented)
|
|
20782
21003
|
return;
|
|
20783
21004
|
if (event)
|
|
20784
21005
|
event.preventDefault();
|
|
20785
|
-
this.
|
|
20786
|
-
|
|
20787
|
-
this.splitPane.when = false;
|
|
21006
|
+
if (this.splitPane.when === false) {
|
|
21007
|
+
return this.setSplitPaneWhen(DEFAULT_MENU_SHOW_WHEN);
|
|
20788
21008
|
}
|
|
20789
21009
|
else {
|
|
20790
|
-
this.
|
|
21010
|
+
return this.setSplitPaneWhen(false);
|
|
20791
21011
|
}
|
|
20792
|
-
this.menuService.menuVisible(this.splitPaneOpened);
|
|
20793
|
-
this.detectChanges();
|
|
20794
21012
|
}
|
|
20795
21013
|
doAction(action, event) {
|
|
20796
21014
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20797
|
-
this.
|
|
21015
|
+
this.close();
|
|
20798
21016
|
switch (action) {
|
|
20799
21017
|
case 'logout':
|
|
20800
21018
|
yield this.logout();
|
|
@@ -20880,7 +21098,7 @@ class MenuComponent {
|
|
|
20880
21098
|
MenuComponent.decorators = [
|
|
20881
21099
|
{ type: Component, args: [{
|
|
20882
21100
|
selector: 'app-menu',
|
|
20883
|
-
template: "<ion-split-pane #splitPane contentId=\"
|
|
21101
|
+
template: "<ion-split-pane #splitPane [contentId]=\"contentId\" (swiperight)=\"onSwipeRight($event)\">\n\n <ion-menu [id]=\"id\" [menuId]=\"menuId\" contentId=\"menu-content\">\n <ion-header>\n\n <ion-toolbar @fadeInAnimation *ngIf=\"isLogin; else notLogin\" class=\"ion-toolbar-top\">\n <ion-grid>\n <ion-row>\n <ion-col size=\"4\">\n <button type=\"button\" mat-flat-button\n class=\"user-avatar\" [class.primary]=\"!accountAvatar\"\n [style.background-image]=\"'url('+(accountAvatar||'./assets/img/person.png')+')'\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n </button>\n </ion-col>\n <ion-col size=\"8\" class=\"user-logo\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"108px;\"/>\n <span *ngIf=\"!logo\" width=\"108px;\">{{appName}}</span>\n </ion-col>\n </ion-row>\n <ion-row class=\"ion-no-padding\">\n\n <button mat-button type=\"button\"\n [routerLink]=\"['/account']\"\n routerDirection=\"root\"\n routerLinkActive=\"ion-color-primary\"\n (click)=\"close()\">\n <ion-label color=\"primary\" class=\"ion-text-wrap ion-text-start\">\n <h3 class=\"no-margin username\">\n <b>{{accountName}}</b>\n </h3>\n <h4>{{accountEmail}}</h4>\n </ion-label>\n </button>\n\n </ion-row>\n </ion-grid>\n\n </ion-toolbar>\n\n <!-- User not logged -->\n <ng-template #notLogin>\n <mat-toolbar class=\"ion-padding\" @fadeInAnimation\n style=\"height: unset; display: block; margin: auto; text-align: center;\">\n <img *ngIf=\"logo\" src=\"{{logo}}\" [title]=\"'APP_NAME'|translate: {appName: appName}\" width=\"150px;\">\n <span *ngIf=\"!logo\" style=\"width: 150px\">{{appName}}</span>\n </mat-toolbar>\n </ng-template>\n </ion-header>\n\n <ion-content [class.has-user-header]=\"isLogin\">\n\n <ion-list lines=\"none\">\n <ion-menu-toggle auto-hide=\"false\"\n [class.flex-spacer]=\"item.cssClass == 'flex-spacer'\"\n *ngFor=\"let item of $items | async\">\n\n <!-- link -->\n <ion-item *ngIf=\"!loading && item.path\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n [routerLink]=\"item.path\"\n routerDirection=\"root\"\n routerLinkActive=\"selected\"\n [routerLinkActiveOptions]=\"{exact: (item.path === '/')}\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- action -->\n <ion-item *ngIf=\"!loading && item.action\"\n @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}} text-1x\"\n tappable\n (click)=\"doAction(item.action, $event)\">\n <ion-icon slot=\"start\" *ngIf=\"item.icon\" [name]=\"item.icon\"></ion-icon>\n <mat-icon slot=\"start\" *ngIf=\"item.matIcon\">{{item.matIcon}}</mat-icon>\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item>\n\n <!-- divider -->\n <ion-item-divider @fadeInAnimation\n class=\"{{item.cssClass}} {{item.color}}\"\n *ngIf=\"!loading && !item.path && !item.action\">\n <ion-label translate>{{item.title}}</ion-label>\n </ion-item-divider>\n\n </ion-menu-toggle>\n </ion-list>\n </ion-content>\n\n <ion-footer class=\"hidden-xs hidden-sm\">\n <ion-toolbar>\n\n <ion-buttons slot=\"start\">\n <ion-button mat-icon-button color=\"accent\" (click)=\"openAboutModal($event)\">\n <mat-icon slot=\"icon-only\">help_outline</mat-icon>\n </ion-button>\n </ion-buttons>\n\n <ion-title (click)=\"openAboutModal($event)\" color=\"medium\">\n {{'MENU.FOOTER_VERSION_ABOUT'| translate: {version: appVersion} }}\n </ion-title>\n\n <ion-buttons slot=\"end\">\n <button mat-icon-button color=\"accent\" (click)=\"toggleSplitPaneShow($event)\"\n class=\"hidden-xs hidden-sm hidden-md\"\n [title]=\"(splitPane.when ? 'COMMON.BTN_HIDE_MENU' : 'COMMON.BTN_SHOW_MENU') |translate\">\n <mat-icon><span>{{splitPane.when ? '«' : '»'}}</span></mat-icon>\n </button>\n </ion-buttons>\n </ion-toolbar>\n </ion-footer>\n\n </ion-menu>\n\n <ng-content></ng-content>\n\n</ion-split-pane>\n",
|
|
20884
21102
|
animations: [fadeInAnimation],
|
|
20885
21103
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20886
21104
|
styles: ["ion-menu{--ion-item-background:transparent;--ion-item-divider-background:transparent;--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint);--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-text-color-selected:var(--ion-color-primary);--ion-item-icon-color-selected:var(--ion-color-primary);--ion-item-text-color-disable:var(--ion-color-medium);--ion-item-icon-color-disable:var(--ion-color-medium)}ion-menu ion-header ion-text{color:var(--ion-color-primary)}ion-menu ion-header .user-avatar{background-size:cover;background-repeat:no-repeat;background-position:50%;background-color:var(--ion-color-secondary);border:1px solid var(--ion-color-primary);overflow:hidden!important;font-size:var(--avatar-size,60px)!important;line-height:var(--avatar-size,60px);height:var(--avatar-size,60px)!important;width:var(--avatar-size,60px)!important;border-radius:50%;display:inline-block}ion-menu ion-header .user-logo{text-align:right}ion-menu ion-header .user-logo img{max-width:120px;max-height:var(--avatar-size,60px);width:auto}ion-menu ion-header .username{padding-top:0;margin-top:0;margin-bottom:0;width:100%;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}ion-menu ion-header button[mat-button]{padding:0;text-align:start!important;width:100%}ion-menu .scroll-content{margin-top:79px!important}ion-menu .has-user-header .scroll-content{margin-top:188px!important}ion-menu ion-content.has-profile-header{--offset-top:188px}ion-menu ion-content.no-profile-header{--offset-top:79px}ion-menu ion-content ion-list{min-height:100%;display:flex;flex-direction:column;justify-content:flex-start}ion-menu ion-content ion-list ion-menu-toggle.flex-spacer{flex:1 1 auto;display:flex;flex-direction:column;justify-content:flex-end}ion-menu ion-content ion-list ion-item.primary{--ion-item-icon-color:var(--ion-color-primary-tint);--ion-item-text-color:var(--ion-color-primary-tint)}ion-menu ion-content ion-list ion-item.secondary{--ion-item-icon-color:var(--ion-color-secondary-tint);--ion-item-text-color:var(--ion-color-secondary-tint)}ion-menu ion-content ion-list ion-item.tertiary{--ion-item-icon-color:var(--ion-color-tertiary-tint);--ion-item-text-color:var(--ion-color-tertiary-tint)}ion-menu ion-content ion-list ion-item.danger{--ion-item-icon-color:var(--ion-color-danger-tint);--ion-item-text-color:var(--ion-color-danger-tint)}ion-menu ion-content ion-list ion-item.medium{--ion-item-icon-color:var(--ion-color-medium-shade);--ion-item-text-color:var(--ion-color-medium-shade)}ion-menu ion-content ion-list ion-item.dark{--ion-item-icon-color:var(--ion-color-dark-tint);--ion-item-text-color:var(--ion-color-dark-tint)}ion-menu ion-content ion-list ion-item ion-icon,ion-menu ion-content ion-list ion-item mat-icon{color:var(--ion-item-icon-color)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item ion-label,ion-menu ion-content ion-list ion-item ion-text{color:var(--ion-item-text-color)!important}ion-menu ion-content ion-list ion-item.selected{background-color:var(--ion-item-background-selected)!important;--color-hover:var(--ion-item-background-selected)!important}ion-menu ion-content ion-list ion-item.selected ion-icon,ion-menu ion-content ion-list ion-item.selected mat-icon{color:var(--ion-item-icon-color-selected)!important;fill:currentColor;stroke:currentColor}ion-menu ion-content ion-list ion-item.selected ion-label,ion-menu ion-content ion-list ion-item.selected ion-text{color:var(--ion-item-text-color-selected)!important}ion-menu ion-content ion-list ion-item.selected:hover{--color-hover:var(--ion-item-background-selected)!important;--ion-item-icon-color-selected:var(--ion-item-icon-color)!important;--ion-item-text-color-selected:var(--ion-item-text-color)!important}ion-menu ion-footer{display:block!important}ion-menu ion-footer ion-toolbar ion-title{cursor:pointer;font-size:12pt;font-weight:400;text-align:center;padding:0 8px}ion-menu ion-footer ion-toolbar ion-button{--width:40px}@media screen and (max-width:767px){ion-menu ion-footer{display:none!important;visibility:hidden!important}}@media screen and (min-width:768px){ion-menu ion-scroll{overflow-y:auto!important}ion-menu .user-avatar{font-size:var(--avatar-size,80px)!important;line-height:var(--avatar-size,80px);height:var(--avatar-size,80px)!important;width:var(--avatar-size,80px)!important}ion-menu .user-logo img{max-height:var(--avatar-size,80px)}}"]
|
|
@@ -20901,10 +21119,13 @@ MenuComponent.ctorParameters = () => [
|
|
|
20901
21119
|
{ type: Array, decorators: [{ type: Optional }, { type: Inject, args: [APP_MENU_ITEMS,] }] }
|
|
20902
21120
|
];
|
|
20903
21121
|
MenuComponent.propDecorators = {
|
|
21122
|
+
id: [{ type: Input }],
|
|
21123
|
+
menuId: [{ type: Input }],
|
|
21124
|
+
side: [{ type: Input }],
|
|
21125
|
+
contentId: [{ type: Input }],
|
|
20904
21126
|
logo: [{ type: Input }],
|
|
20905
21127
|
appName: [{ type: Input }],
|
|
20906
21128
|
appVersion: [{ type: Input }],
|
|
20907
|
-
side: [{ type: Input }],
|
|
20908
21129
|
splitPane: [{ type: ViewChild, args: ['splitPane', { static: true },] }]
|
|
20909
21130
|
};
|
|
20910
21131
|
|
|
@@ -20958,6 +21179,30 @@ AppIconComponent.propDecorators = {
|
|
|
20958
21179
|
ref: [{ type: Input }]
|
|
20959
21180
|
};
|
|
20960
21181
|
|
|
21182
|
+
class AppUpdateOfflineModeCard {
|
|
21183
|
+
constructor() {
|
|
21184
|
+
this.onUpdateClick = new EventEmitter();
|
|
21185
|
+
}
|
|
21186
|
+
ngOnDestroy() {
|
|
21187
|
+
this.onUpdateClick.complete();
|
|
21188
|
+
}
|
|
21189
|
+
}
|
|
21190
|
+
AppUpdateOfflineModeCard.decorators = [
|
|
21191
|
+
{ type: Component, args: [{
|
|
21192
|
+
selector: 'app-update-offline-mode-card',
|
|
21193
|
+
template: "\n<!-- Update offline feature card-->\n<ion-card color=\"accent\"\n class=\"main ion-no-margin\"\n @slideUpDownAnimation>\n <ion-card-content class=\"ion-no-padding\">\n <ion-grid>\n <ion-row *ngIf=\"!progressionValue; else progression\">\n <ion-col>\n <ion-text class=\"ion-text-wrap\" >\n <h4>\n <b [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE'| translate\"></b>\n </h4>\n <h3>\n <small [innerHTML]=\"'NETWORK.INFO.UPDATE_OFFLINE_MODE_HELP'|translate\"></small>\n </h3>\n </ion-text>\n </ion-col>\n\n <!-- Update button -->\n <ion-col size=\"auto\">\n <ion-button color=\"tertiary\" class=\"ion-float-end\"\n (click)=\"onUpdateClick.emit($event)\">\n <span translate>NETWORK.BTN_UPDATE</span>\n </ion-button>\n </ion-col>\n </ion-row>\n\n <ng-template #progression>\n <ion-row>\n <ion-col>\n <ion-text class=\"ion-text-wrap\" [innerHTML]=\"progressionMessage\"></ion-text>\n </ion-col>\n </ion-row>\n <ion-row>\n <ion-col>\n <ion-progress-bar [value]=\"progressionValue / 100\"></ion-progress-bar>\n </ion-col>\n </ion-row>\n </ng-template>\n </ion-grid>\n\n\n </ion-card-content>\n</ion-card>\n",
|
|
21194
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21195
|
+
animations: [slideUpDownAnimation],
|
|
21196
|
+
styles: ["ion-text small{font-size:85%}"]
|
|
21197
|
+
},] }
|
|
21198
|
+
];
|
|
21199
|
+
AppUpdateOfflineModeCard.ctorParameters = () => [];
|
|
21200
|
+
AppUpdateOfflineModeCard.propDecorators = {
|
|
21201
|
+
progressionMessage: [{ type: Input }],
|
|
21202
|
+
progressionValue: [{ type: Input }],
|
|
21203
|
+
onUpdateClick: [{ type: Output }]
|
|
21204
|
+
};
|
|
21205
|
+
|
|
20961
21206
|
class CoreModule {
|
|
20962
21207
|
static forRoot() {
|
|
20963
21208
|
console.info('[core] Creating module (root)');
|
|
@@ -20978,7 +21223,6 @@ CoreModule.decorators = [
|
|
|
20978
21223
|
CacheModule,
|
|
20979
21224
|
IonicStorageModule,
|
|
20980
21225
|
NgxJdenticonModule,
|
|
20981
|
-
TranslateModule.forChild(),
|
|
20982
21226
|
// Sub modules
|
|
20983
21227
|
AppGraphQLModule,
|
|
20984
21228
|
AppMenuModule
|
|
@@ -21005,6 +21249,7 @@ CoreModule.decorators = [
|
|
|
21005
21249
|
// Network
|
|
21006
21250
|
SelectPeerModal,
|
|
21007
21251
|
AppInstallUpgradeCard,
|
|
21252
|
+
AppUpdateOfflineModeCard,
|
|
21008
21253
|
// Other components
|
|
21009
21254
|
TableSelectColumnsComponent,
|
|
21010
21255
|
ActionsColumnComponent,
|
|
@@ -21040,6 +21285,7 @@ CoreModule.decorators = [
|
|
|
21040
21285
|
AppPropertiesForm,
|
|
21041
21286
|
AppListForm,
|
|
21042
21287
|
AppInstallUpgradeCard,
|
|
21288
|
+
AppUpdateOfflineModeCard,
|
|
21043
21289
|
DepartmentToStringPipe,
|
|
21044
21290
|
AppIconComponent,
|
|
21045
21291
|
TextPopover,
|
|
@@ -21048,6 +21294,9 @@ CoreModule.decorators = [
|
|
|
21048
21294
|
},] }
|
|
21049
21295
|
];
|
|
21050
21296
|
|
|
21297
|
+
const moment$5 = momentImported;
|
|
21298
|
+
const tz = momentTZImported;
|
|
21299
|
+
|
|
21051
21300
|
class AuthGuardService {
|
|
21052
21301
|
constructor(accountService, modalCtrl, router, environment) {
|
|
21053
21302
|
this.accountService = accountService;
|
|
@@ -21567,6 +21816,8 @@ class AppTableUtils {
|
|
|
21567
21816
|
}
|
|
21568
21817
|
}
|
|
21569
21818
|
|
|
21819
|
+
class AppTableDataSourceOptions {
|
|
21820
|
+
}
|
|
21570
21821
|
// @dynamic
|
|
21571
21822
|
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
|
21572
21823
|
class EntitiesTableDataSource extends TableDataSource {
|
|
@@ -21575,27 +21826,34 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21575
21826
|
*
|
|
21576
21827
|
* @param dataService A service to load and save data
|
|
21577
21828
|
* @param dataType Type of data contained by the Table. If not specified, then `data` with at least one element must be specified.
|
|
21829
|
+
* @param environment
|
|
21578
21830
|
* @param validatorService Service that create instances of the FormGroup used to validate row fields.
|
|
21579
21831
|
* @param config Additional configuration for table.
|
|
21580
21832
|
*/
|
|
21581
21833
|
constructor(dataType, dataService, validatorService, config) {
|
|
21582
|
-
super([], dataType, validatorService,
|
|
21834
|
+
super([], dataType, validatorService, config);
|
|
21583
21835
|
this.dataService = dataService;
|
|
21584
21836
|
this._creating = false;
|
|
21585
21837
|
this._saving = false;
|
|
21838
|
+
this._useValidator = false;
|
|
21586
21839
|
this._stopWatching$ = new Subject();
|
|
21587
21840
|
this._editingRowCount = 0;
|
|
21588
21841
|
this._fetchMoreFn = null;
|
|
21589
21842
|
this.loadingSubject = new BehaviorSubject(undefined);
|
|
21843
|
+
this._options = Object.assign({ dataServiceOptions: {}, debug: config && config.suppressErrors === false, keepOriginalDataAfterConfirm: false }, config);
|
|
21844
|
+
this._useValidator = isNotNil(validatorService);
|
|
21590
21845
|
this._logTypeName = removeEnd((new dataType()).__typename || 'UnknownVO', 'VO');
|
|
21591
21846
|
// For DEV ONLY
|
|
21592
|
-
this._debug = this.
|
|
21847
|
+
this._debug = this._options.debug === true;
|
|
21593
21848
|
}
|
|
21594
21849
|
get serviceOptions() {
|
|
21595
|
-
return this.
|
|
21850
|
+
return this._options.dataServiceOptions;
|
|
21596
21851
|
}
|
|
21597
21852
|
set serviceOptions(value) {
|
|
21598
|
-
this.
|
|
21853
|
+
this._options.dataServiceOptions = value;
|
|
21854
|
+
}
|
|
21855
|
+
get options() {
|
|
21856
|
+
return this._options;
|
|
21599
21857
|
}
|
|
21600
21858
|
get loaded() {
|
|
21601
21859
|
return this.loadingSubject.value === false; // Should be false when undefined (initial state)
|
|
@@ -21603,15 +21861,12 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21603
21861
|
get loading() {
|
|
21604
21862
|
return this.loadingSubject.value !== false; // Should be true when undefined (initial state)
|
|
21605
21863
|
}
|
|
21606
|
-
|
|
21607
|
-
// DEBUG console.debug("[entities-datasource] connect");
|
|
21608
|
-
return super.connect(collectionViewer);
|
|
21609
|
-
}
|
|
21610
|
-
disconnect(collectionViewer) {
|
|
21611
|
-
super.disconnect(collectionViewer);
|
|
21864
|
+
ngOnDestroy() {
|
|
21612
21865
|
this._stopWatching$.next();
|
|
21613
21866
|
this._stopWatching$.complete();
|
|
21867
|
+
this._stopWatching$.unsubscribe();
|
|
21614
21868
|
this.loadingSubject.complete();
|
|
21869
|
+
this.loadingSubject.unsubscribe();
|
|
21615
21870
|
}
|
|
21616
21871
|
watchAll(offset, size, sortBy, sortDirection, filter) {
|
|
21617
21872
|
this._stopWatching$.next();
|
|
@@ -21655,26 +21910,27 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21655
21910
|
// Get all rows
|
|
21656
21911
|
const rows = yield this.getRows();
|
|
21657
21912
|
// Finish editing all rows
|
|
21658
|
-
const
|
|
21913
|
+
const invalidRows = rows.filter(row => row.editing && !row.confirmEditCreate());
|
|
21659
21914
|
// Cannot finish some rows: error
|
|
21660
|
-
if (
|
|
21915
|
+
if (invalidRows.length) {
|
|
21661
21916
|
// log errors
|
|
21662
21917
|
if (this._debug)
|
|
21663
|
-
|
|
21918
|
+
invalidRows.forEach(row => AppTableUtils.logRowErrors(row, `[table-datasource] ${this._logTypeName} row #${row.id}`));
|
|
21664
21919
|
// Stop with an error
|
|
21665
21920
|
throw { code: ErrorCodes.TABLE_INVALID_ROW_ERROR, message: 'ERROR.TABLE_INVALID_ROW_ERROR' };
|
|
21666
21921
|
}
|
|
21667
21922
|
this._editingRowCount = 0;
|
|
21668
21923
|
let data;
|
|
21669
21924
|
let dataToSave;
|
|
21670
|
-
if (
|
|
21925
|
+
if (this._useValidator) {
|
|
21671
21926
|
dataToSave = [];
|
|
21672
21927
|
data = rows.map(row => {
|
|
21673
|
-
const
|
|
21928
|
+
const currentData = new this.dataConstructor();
|
|
21929
|
+
currentData.fromObject(row.currentData);
|
|
21674
21930
|
// Filter to keep only dirty row
|
|
21675
21931
|
if (onlyDirtyRows && row.validator.dirty)
|
|
21676
|
-
dataToSave.push(
|
|
21677
|
-
return
|
|
21932
|
+
dataToSave.push(currentData);
|
|
21933
|
+
return currentData;
|
|
21678
21934
|
});
|
|
21679
21935
|
if (!onlyDirtyRows)
|
|
21680
21936
|
dataToSave = data;
|
|
@@ -21711,33 +21967,25 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21711
21967
|
}
|
|
21712
21968
|
});
|
|
21713
21969
|
}
|
|
21714
|
-
|
|
21715
|
-
if (
|
|
21716
|
-
|
|
21717
|
-
|
|
21970
|
+
updateDatasource(data, opts) {
|
|
21971
|
+
if (this._debug)
|
|
21972
|
+
console.debug(`[table-datasource] Updating datasource with data:`, data);
|
|
21973
|
+
super.updateDatasource(data, opts);
|
|
21974
|
+
if (!opts || opts.emitEvent !== false) {
|
|
21975
|
+
this.markAsLoaded();
|
|
21718
21976
|
}
|
|
21719
|
-
return super.getDataFromRows(rows, options);
|
|
21720
21977
|
}
|
|
21721
|
-
|
|
21722
|
-
|
|
21723
|
-
|
|
21724
|
-
entity.fromObject(data);
|
|
21725
|
-
return entity;
|
|
21726
|
-
}
|
|
21727
|
-
return data;
|
|
21978
|
+
// Overwrite default signature
|
|
21979
|
+
createNew(insertAt) {
|
|
21980
|
+
this.asyncCreateNew(insertAt);
|
|
21728
21981
|
}
|
|
21729
|
-
|
|
21730
|
-
|
|
21731
|
-
|
|
21732
|
-
|
|
21733
|
-
|
|
21734
|
-
|
|
21735
|
-
|
|
21736
|
-
yield _super.updateDatasource.call(this, data, opts);
|
|
21737
|
-
if (opts.emitEvent) {
|
|
21738
|
-
this.markAsLoaded();
|
|
21739
|
-
}
|
|
21740
|
-
});
|
|
21982
|
+
connect(collectionViewer) {
|
|
21983
|
+
// DEBUG console.debug("[entities-datasource] connect");
|
|
21984
|
+
return super.connect(collectionViewer);
|
|
21985
|
+
}
|
|
21986
|
+
disconnect(collectionViewer) {
|
|
21987
|
+
super.disconnect(collectionViewer);
|
|
21988
|
+
this._stopWatching$.next();
|
|
21741
21989
|
}
|
|
21742
21990
|
waitIdle(debounceTimeMs) {
|
|
21743
21991
|
return firstFalsePromise(this.loadingSubject
|
|
@@ -21746,60 +21994,34 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21746
21994
|
));
|
|
21747
21995
|
}
|
|
21748
21996
|
confirmCreate(row) {
|
|
21749
|
-
|
|
21750
|
-
|
|
21751
|
-
|
|
21752
|
-
|
|
21753
|
-
|
|
21754
|
-
|
|
21755
|
-
|
|
21756
|
-
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
21757
|
-
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
21758
|
-
}
|
|
21759
|
-
return true;
|
|
21760
|
-
});
|
|
21997
|
+
if (!super.confirmCreate(row))
|
|
21998
|
+
return false;
|
|
21999
|
+
if (row.editing && row.validator) {
|
|
22000
|
+
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
22001
|
+
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
22002
|
+
}
|
|
22003
|
+
return true;
|
|
21761
22004
|
}
|
|
21762
22005
|
confirmEdit(row) {
|
|
21763
|
-
|
|
21764
|
-
|
|
21765
|
-
|
|
21766
|
-
|
|
21767
|
-
|
|
21768
|
-
|
|
21769
|
-
|
|
21770
|
-
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
21771
|
-
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
21772
|
-
}
|
|
21773
|
-
return true;
|
|
21774
|
-
});
|
|
22006
|
+
if (!super.confirmEdit(row))
|
|
22007
|
+
return false;
|
|
22008
|
+
if (row.editing && row.validator) {
|
|
22009
|
+
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
22010
|
+
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
22011
|
+
}
|
|
22012
|
+
return true;
|
|
21775
22013
|
}
|
|
21776
22014
|
startEdit(row) {
|
|
21777
|
-
|
|
21778
|
-
|
|
21779
|
-
|
|
21780
|
-
|
|
21781
|
-
if (row.editing)
|
|
21782
|
-
return; // Already editing
|
|
21783
|
-
if (this._debug)
|
|
21784
|
-
console.debug('[table-datasource] Start to edit row', row);
|
|
21785
|
-
const done = yield _super.startEdit.call(this, row);
|
|
21786
|
-
if (done)
|
|
21787
|
-
this._editingRowCount++;
|
|
21788
|
-
return done;
|
|
21789
|
-
});
|
|
22015
|
+
if (this._debug)
|
|
22016
|
+
console.debug('[table-datasource] Start to edit row', row);
|
|
22017
|
+
row.startEdit();
|
|
22018
|
+
this._editingRowCount++;
|
|
21790
22019
|
}
|
|
21791
|
-
|
|
21792
|
-
|
|
21793
|
-
|
|
21794
|
-
|
|
21795
|
-
|
|
21796
|
-
if (this._debug)
|
|
21797
|
-
console.debug('[table-datasource] Cancelling row', row);
|
|
21798
|
-
const done = yield _super.cancel.call(this, row);
|
|
21799
|
-
if (done)
|
|
21800
|
-
this._editingRowCount--;
|
|
21801
|
-
return done;
|
|
21802
|
-
});
|
|
22020
|
+
cancelOrDelete(row) {
|
|
22021
|
+
if (this._debug)
|
|
22022
|
+
console.debug('[table-datasource] Cancelling or deleting row', row);
|
|
22023
|
+
row.cancelOrDelete();
|
|
22024
|
+
this._editingRowCount--;
|
|
21803
22025
|
}
|
|
21804
22026
|
handleError(error, message) {
|
|
21805
22027
|
const errorMsg = error && error.message || error;
|
|
@@ -21814,77 +22036,59 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21814
22036
|
throw error;
|
|
21815
22037
|
}
|
|
21816
22038
|
delete(id) {
|
|
21817
|
-
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
|
|
21821
|
-
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21825
|
-
|
|
21826
|
-
|
|
21827
|
-
|
|
21828
|
-
|
|
21829
|
-
|
|
21830
|
-
|
|
21831
|
-
|
|
21832
|
-
yield this.dataService.deleteAll([row.currentData], this.serviceOptions);
|
|
21833
|
-
// Make sure row has been deleted (because GrapQHl cache remove can failed)
|
|
21834
|
-
yield sleep(300);
|
|
22039
|
+
// If new row: not need to propagate to the dataService
|
|
22040
|
+
if (id === -1) {
|
|
22041
|
+
return super.delete(id);
|
|
22042
|
+
}
|
|
22043
|
+
const row = this.getRow(id);
|
|
22044
|
+
if (!row) {
|
|
22045
|
+
console.error(`[table-datasource] Row to delete with id=${id} not found`);
|
|
22046
|
+
return;
|
|
22047
|
+
}
|
|
22048
|
+
this.loadingSubject.next(true);
|
|
22049
|
+
this.dataService.deleteAll([row.currentData], this.serviceOptions)
|
|
22050
|
+
.catch(err => this.handleErrorPromise(err))
|
|
22051
|
+
.then(() => {
|
|
22052
|
+
setTimeout(() => {
|
|
22053
|
+
// make sure row has been deleted (because GrapQHl cache remove can failed)
|
|
21835
22054
|
const present = this.getRow(id) === row;
|
|
21836
|
-
if (present)
|
|
21837
|
-
|
|
21838
|
-
|
|
21839
|
-
|
|
21840
|
-
}
|
|
21841
|
-
catch (err) {
|
|
21842
|
-
this.handleErrorPromise(err);
|
|
21843
|
-
}
|
|
21844
|
-
finally {
|
|
21845
|
-
this.markAsLoaded();
|
|
21846
|
-
}
|
|
22055
|
+
if (present)
|
|
22056
|
+
super.delete(id);
|
|
22057
|
+
this.loadingSubject.next(false);
|
|
22058
|
+
}, 300);
|
|
21847
22059
|
});
|
|
21848
22060
|
}
|
|
21849
22061
|
deleteAll(rows) {
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
|
|
21862
|
-
|
|
21863
|
-
|
|
21864
|
-
|
|
21865
|
-
const
|
|
21866
|
-
|
|
21867
|
-
|
|
21868
|
-
|
|
21869
|
-
|
|
21870
|
-
|
|
21871
|
-
|
|
21872
|
-
console.warn(`[table-datasource] Force deletion of ${rowNotDeleted.length} rows (Is service applying deletion to observable ?)`);
|
|
21873
|
-
yield Promise.all(rowNotDeleted.map(r => _super.delete.call(this, r.id)));
|
|
21874
|
-
}
|
|
21875
|
-
}
|
|
21876
|
-
catch (err) {
|
|
21877
|
-
this.handleErrorPromise(err);
|
|
21878
|
-
}
|
|
21879
|
-
finally {
|
|
21880
|
-
this.markAsLoaded();
|
|
22062
|
+
this.markAsLoading();
|
|
22063
|
+
const data = rows.map(r => r.currentData);
|
|
22064
|
+
const rowsById = rows.reduce((res, row) => {
|
|
22065
|
+
res[row.id] = row;
|
|
22066
|
+
return res;
|
|
22067
|
+
}, {});
|
|
22068
|
+
const self = this;
|
|
22069
|
+
const selfDelete = super.delete;
|
|
22070
|
+
return this.dataService.deleteAll(data, this.serviceOptions)
|
|
22071
|
+
.catch(err => this.handleErrorPromise(err))
|
|
22072
|
+
.then(() => {
|
|
22073
|
+
// Workaround, to be sure all rows has been deleted
|
|
22074
|
+
// Sometimes, the service miss deletion, or GrapQHl cache remove failed
|
|
22075
|
+
const rowNotDeleted = Object.getOwnPropertyNames(rowsById).reduce((res, id) => {
|
|
22076
|
+
const row = rowsById[id];
|
|
22077
|
+
const present = self.getRow(+id) === row;
|
|
22078
|
+
return present ? res.concat(row) : res;
|
|
22079
|
+
}, []).sort((a, b) => a.id > b.id ? -1 : 1);
|
|
22080
|
+
// Apply missing deletion
|
|
22081
|
+
if (isNotEmptyArray(rowNotDeleted)) {
|
|
22082
|
+
console.warn(`[table-datasource] Force deletion of ${rowNotDeleted.length} rows (Is service applying deletion to observable ?)`);
|
|
22083
|
+
rowNotDeleted.forEach(r => selfDelete.call(self, r.id));
|
|
21881
22084
|
}
|
|
22085
|
+
this.loadingSubject.next(false);
|
|
21882
22086
|
});
|
|
21883
22087
|
}
|
|
21884
22088
|
getRows() {
|
|
21885
|
-
return this.
|
|
22089
|
+
return firstNotNilPromise(this.connect(null));
|
|
21886
22090
|
}
|
|
21887
|
-
|
|
22091
|
+
asyncCreateNew(insertAt) {
|
|
21888
22092
|
const _super = Object.create(null, {
|
|
21889
22093
|
createNew: { get: () => super.createNew }
|
|
21890
22094
|
});
|
|
@@ -21892,39 +22096,22 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21892
22096
|
if (this._creating)
|
|
21893
22097
|
return; // Avoid multiple call (should never occur)
|
|
21894
22098
|
this._creating = true;
|
|
21895
|
-
|
|
21896
|
-
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
21900
|
-
|
|
21901
|
-
|
|
21902
|
-
|
|
21903
|
-
|
|
22099
|
+
_super.createNew.call(this, insertAt);
|
|
22100
|
+
const row = this.getRow(-1);
|
|
22101
|
+
if (row && this._options && this._options.onRowCreated) {
|
|
22102
|
+
const res = this._options.onRowCreated(row);
|
|
22103
|
+
// If async function, wait the end before ending
|
|
22104
|
+
if (res instanceof Promise) {
|
|
22105
|
+
try {
|
|
22106
|
+
yield res;
|
|
22107
|
+
}
|
|
22108
|
+
catch (err) {
|
|
22109
|
+
console.error(err && err.message || err, err);
|
|
22110
|
+
}
|
|
21904
22111
|
}
|
|
21905
22112
|
}
|
|
21906
|
-
|
|
21907
|
-
this._editingRowCount++;
|
|
22113
|
+
this._editingRowCount++;
|
|
21908
22114
|
this._creating = false;
|
|
21909
|
-
return done;
|
|
21910
|
-
});
|
|
21911
|
-
}
|
|
21912
|
-
createRowValidator() {
|
|
21913
|
-
const _super = Object.create(null, {
|
|
21914
|
-
createRowValidator: { get: () => super.createRowValidator }
|
|
21915
|
-
});
|
|
21916
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
21917
|
-
const validator = yield _super.createRowValidator.call(this);
|
|
21918
|
-
if (validator && this.config.onRowValidator) {
|
|
21919
|
-
try {
|
|
21920
|
-
yield this.config.onRowValidator(validator);
|
|
21921
|
-
}
|
|
21922
|
-
catch (err) {
|
|
21923
|
-
console.error(err && err.message || err, err);
|
|
21924
|
-
// Continue
|
|
21925
|
-
}
|
|
21926
|
-
}
|
|
21927
|
-
return validator;
|
|
21928
22115
|
});
|
|
21929
22116
|
}
|
|
21930
22117
|
getData() {
|
|
@@ -21939,7 +22126,7 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21939
22126
|
});
|
|
21940
22127
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21941
22128
|
if (!this._fetchMoreFn)
|
|
21942
|
-
return false;
|
|
22129
|
+
return false; // Avoid multiple call
|
|
21943
22130
|
if (this._editingRowCount > 0) {
|
|
21944
22131
|
console.warn('Cannot fetch more because still editing row');
|
|
21945
22132
|
return;
|
|
@@ -21953,10 +22140,9 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21953
22140
|
if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
|
|
21954
22141
|
return false;
|
|
21955
22142
|
// Update the data source
|
|
21956
|
-
// TODO review this, to keep existing rows, instead of creating new TableElement + validator !
|
|
21957
22143
|
const existingData = yield this.getData();
|
|
21958
|
-
|
|
21959
|
-
//
|
|
22144
|
+
_super.updateDatasource.call(this, existingData.concat(...res.data), opts);
|
|
22145
|
+
// Remember fetchMore
|
|
21960
22146
|
this._fetchMoreFn = res.fetchMore;
|
|
21961
22147
|
return true;
|
|
21962
22148
|
});
|
|
@@ -21979,8 +22165,8 @@ EntitiesTableDataSource.decorators = [
|
|
|
21979
22165
|
EntitiesTableDataSource.ctorParameters = () => [
|
|
21980
22166
|
{ type: Function },
|
|
21981
22167
|
{ type: undefined },
|
|
21982
|
-
{ type:
|
|
21983
|
-
{ type:
|
|
22168
|
+
{ type: ValidatorService },
|
|
22169
|
+
{ type: AppTableDataSourceOptions }
|
|
21984
22170
|
];
|
|
21985
22171
|
|
|
21986
22172
|
const SETTINGS_DISPLAY_COLUMNS = 'displayColumns';
|
|
@@ -22372,6 +22558,7 @@ class AppTable {
|
|
|
22372
22558
|
}
|
|
22373
22559
|
}
|
|
22374
22560
|
ngOnDestroy() {
|
|
22561
|
+
var _a;
|
|
22375
22562
|
this._subscription.unsubscribe();
|
|
22376
22563
|
// Unsubscribe column value changes
|
|
22377
22564
|
Object.keys(this._cellValueChangesDefs).forEach(col => this.stopCellValueChanges(col, true));
|
|
@@ -22396,6 +22583,7 @@ class AppTable {
|
|
|
22396
22583
|
this.onError.unsubscribe();
|
|
22397
22584
|
this._destroy$.next();
|
|
22398
22585
|
this._destroy$.unsubscribe();
|
|
22586
|
+
(_a = this._dataSource) === null || _a === void 0 ? void 0 : _a.ngOnDestroy();
|
|
22399
22587
|
}
|
|
22400
22588
|
updateView(res, opts) {
|
|
22401
22589
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -22437,7 +22625,7 @@ class AppTable {
|
|
|
22437
22625
|
this._dataSourceLoadingSubscription.unsubscribe();
|
|
22438
22626
|
this._subscription.remove(this._dataSourceLoadingSubscription);
|
|
22439
22627
|
}
|
|
22440
|
-
(_a = this._dataSource) === null || _a === void 0 ? void 0 : _a.
|
|
22628
|
+
(_a = this._dataSource) === null || _a === void 0 ? void 0 : _a.ngOnDestroy();
|
|
22441
22629
|
this._dataSource = null;
|
|
22442
22630
|
}
|
|
22443
22631
|
addColumnDef(column) {
|
|
@@ -22492,15 +22680,18 @@ class AppTable {
|
|
|
22492
22680
|
return true;
|
|
22493
22681
|
}
|
|
22494
22682
|
confirmAndForward(event, row) {
|
|
22495
|
-
|
|
22496
|
-
|
|
22497
|
-
|
|
22498
|
-
|
|
22499
|
-
|
|
22500
|
-
|
|
22683
|
+
var _a;
|
|
22684
|
+
row = row || this.editedRow;
|
|
22685
|
+
if (!this.confirmEditCreate(event, row)) {
|
|
22686
|
+
// If pending: Wait end of validation, then loop
|
|
22687
|
+
if ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.pending) {
|
|
22688
|
+
return AppFormUtils.waitWhilePending(row.validator).then(() => this.confirmAndForward(event, row));
|
|
22501
22689
|
}
|
|
22502
|
-
return
|
|
22503
|
-
}
|
|
22690
|
+
return false;
|
|
22691
|
+
}
|
|
22692
|
+
// Edit next row
|
|
22693
|
+
this.editRowById(event, row.id + 1, { focusColumn: this.firstUserColumn });
|
|
22694
|
+
return true;
|
|
22504
22695
|
}
|
|
22505
22696
|
editRowById(event, id, opts) {
|
|
22506
22697
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -22524,44 +22715,48 @@ class AppTable {
|
|
|
22524
22715
|
*/
|
|
22525
22716
|
confirmEditCreate(event, row) {
|
|
22526
22717
|
var _a;
|
|
22527
|
-
|
|
22528
|
-
|
|
22529
|
-
|
|
22530
|
-
|
|
22531
|
-
|
|
22532
|
-
|
|
22533
|
-
|
|
22534
|
-
|
|
22535
|
-
|
|
22536
|
-
|
|
22537
|
-
|
|
22538
|
-
this.editedRow = undefined;
|
|
22539
|
-
}
|
|
22540
|
-
// Mark table as dirty (if row is dirty)
|
|
22541
|
-
if ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty) {
|
|
22542
|
-
this.markAsDirty({ emitEvent: false /* because of resetError() */ });
|
|
22543
|
-
}
|
|
22544
|
-
// Clear error
|
|
22545
|
-
this.resetError();
|
|
22546
|
-
// Emit the confirm event
|
|
22547
|
-
this.onConfirmEditCreateRow.next(row);
|
|
22548
|
-
}
|
|
22549
|
-
else if (row.validator) {
|
|
22550
|
-
// NOT confirmed = row has error
|
|
22551
|
-
if (this.debug) {
|
|
22552
|
-
console.warn('[table] Cannot confirm row, because invalid');
|
|
22553
|
-
AppFormUtils.logFormErrors(row.validator, '[table] ');
|
|
22554
|
-
}
|
|
22555
|
-
// fix: mark all controls as touched to show errors
|
|
22556
|
-
row.validator.markAllAsTouched();
|
|
22557
|
-
// Compute row error, and propagate to table's error
|
|
22558
|
-
if (this.propagateRowError) {
|
|
22559
|
-
const error = this.getRowError(row);
|
|
22560
|
-
this.setError(error);
|
|
22561
|
-
}
|
|
22718
|
+
row = row || this.editedRow;
|
|
22719
|
+
if (!row || !row.editing)
|
|
22720
|
+
return true; // no row to confirm
|
|
22721
|
+
// Stop event
|
|
22722
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
22723
|
+
// Confirmation edition or creation
|
|
22724
|
+
const confirmed = row.confirmEditCreate();
|
|
22725
|
+
if (confirmed) {
|
|
22726
|
+
// If edit finished, forget edited row
|
|
22727
|
+
if (row === this.editedRow) {
|
|
22728
|
+
this.editedRow = undefined;
|
|
22562
22729
|
}
|
|
22563
|
-
|
|
22564
|
-
|
|
22730
|
+
// Mark table as dirty (if row is dirty)
|
|
22731
|
+
if ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty) {
|
|
22732
|
+
this.markAsDirty({ emitEvent: false /* because of resetError() */ });
|
|
22733
|
+
}
|
|
22734
|
+
// Clear error
|
|
22735
|
+
this.resetError();
|
|
22736
|
+
// Emit the confirm event
|
|
22737
|
+
this.onConfirmEditCreateRow.next(row);
|
|
22738
|
+
return true; // Continue
|
|
22739
|
+
}
|
|
22740
|
+
if (row.validator) {
|
|
22741
|
+
// If pending: Wait end of validation, then loop
|
|
22742
|
+
if (row.validator.pending) {
|
|
22743
|
+
AppFormUtils.waitWhilePending(row.validator).then(() => this.confirmEditCreate(event, row));
|
|
22744
|
+
return false;
|
|
22745
|
+
}
|
|
22746
|
+
// NOT confirmed = row has error
|
|
22747
|
+
if (this.debug) {
|
|
22748
|
+
console.warn('[table] Cannot confirm row, because invalid');
|
|
22749
|
+
AppFormUtils.logFormErrors(row.validator, '[table] ');
|
|
22750
|
+
}
|
|
22751
|
+
// fix: mark all controls as touched to show errors
|
|
22752
|
+
row.validator.markAllAsTouched();
|
|
22753
|
+
// Compute row error, and propagate to table's error
|
|
22754
|
+
if (this.propagateRowError) {
|
|
22755
|
+
const error = this.getRowError(row);
|
|
22756
|
+
this.setError(error);
|
|
22757
|
+
}
|
|
22758
|
+
}
|
|
22759
|
+
return false;
|
|
22565
22760
|
}
|
|
22566
22761
|
cancelOrDelete(event, row, opts) {
|
|
22567
22762
|
// Delete new row
|
|
@@ -22606,7 +22801,6 @@ class AppTable {
|
|
|
22606
22801
|
// Keep edited row id (should be done BEFORE confirmEditCreate() )
|
|
22607
22802
|
this.previouslyEditedRowId = opts.keepEditing ? ((((_a = this.editedRow) === null || _a === void 0 ? void 0 : _a.editing) ? this.editedRow.id : undefined) || ((_b = this.singleSelectedRow) === null || _b === void 0 ? void 0 : _b.id)) : undefined;
|
|
22608
22803
|
const previouslyEditedData = opts.keepEditing ? (isNotNil(this.previouslyEditedRowId) && ((_c = this.editedRow) === null || _c === void 0 ? void 0 : _c.currentData) || ((_d = this.singleSelectedRow) === null || _d === void 0 ? void 0 : _d.currentData)) : undefined;
|
|
22609
|
-
// TODO: remove this, has it redundant with dataSource.confirmAllRows() called in dataSource.save()
|
|
22610
22804
|
if (!this.confirmEditCreate()) {
|
|
22611
22805
|
throw { code: ErrorCodes.TABLE_INVALID_ROW_ERROR, message: 'ERROR.TABLE_INVALID_ROW_ERROR' };
|
|
22612
22806
|
}
|
|
@@ -23164,7 +23358,7 @@ class AppTable {
|
|
|
23164
23358
|
console.warn('[table] Opening row details, but data has no id!');
|
|
23165
23359
|
return false;
|
|
23166
23360
|
}
|
|
23167
|
-
return
|
|
23361
|
+
return this.router.navigate(['.', id.toString()], {
|
|
23168
23362
|
relativeTo: this.route,
|
|
23169
23363
|
queryParams: {}
|
|
23170
23364
|
});
|
|
@@ -23261,9 +23455,7 @@ class AppTable {
|
|
|
23261
23455
|
addRowToTable(insertAt) {
|
|
23262
23456
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23263
23457
|
this.focusFirstColumn = true;
|
|
23264
|
-
|
|
23265
|
-
if (!done)
|
|
23266
|
-
return undefined;
|
|
23458
|
+
yield this._dataSource.asyncCreateNew(insertAt);
|
|
23267
23459
|
this.editedRow = this._dataSource.getRow(-1);
|
|
23268
23460
|
// Emit start editing event
|
|
23269
23461
|
this.onStartEditingRow.emit(this.editedRow);
|
|
@@ -23394,64 +23586,59 @@ class AppTable {
|
|
|
23394
23586
|
}
|
|
23395
23587
|
}
|
|
23396
23588
|
deleteNewRow(event, row) {
|
|
23397
|
-
|
|
23398
|
-
|
|
23399
|
-
|
|
23400
|
-
|
|
23401
|
-
|
|
23402
|
-
|
|
23403
|
-
|
|
23404
|
-
|
|
23405
|
-
|
|
23406
|
-
|
|
23407
|
-
this.totalRowCount--;
|
|
23408
|
-
this.visibleRowCount--;
|
|
23409
|
-
}
|
|
23410
|
-
return done;
|
|
23411
|
-
});
|
|
23589
|
+
if (row.id !== -1)
|
|
23590
|
+
throw new Error('Row must have id = -1');
|
|
23591
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
23592
|
+
this.selection.clear();
|
|
23593
|
+
this.editedRow = undefined; // unselect row
|
|
23594
|
+
this._dataSource.cancelOrDelete(row);
|
|
23595
|
+
this.onCancelOrDeleteRow.next(row);
|
|
23596
|
+
this.resetError();
|
|
23597
|
+
this.totalRowCount--;
|
|
23598
|
+
this.visibleRowCount--;
|
|
23412
23599
|
}
|
|
23413
23600
|
deleteExistingRow(event, row, opts) {
|
|
23414
23601
|
// Make sure row will be cancelled, and NOT deleted
|
|
23415
23602
|
if (row.id === -1)
|
|
23416
23603
|
throw new Error('Row must have an id');
|
|
23417
23604
|
if (event === null || event === void 0 ? void 0 : event.defaultPrevented)
|
|
23418
|
-
return
|
|
23605
|
+
return 0; // SKip
|
|
23419
23606
|
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
23420
|
-
|
|
23607
|
+
this.deleteRow(null, row, opts);
|
|
23421
23608
|
}
|
|
23422
23609
|
cancelExistingRow(event, row, opts) {
|
|
23423
23610
|
var _a;
|
|
23424
|
-
|
|
23425
|
-
|
|
23426
|
-
|
|
23427
|
-
|
|
23428
|
-
|
|
23429
|
-
|
|
23430
|
-
|
|
23431
|
-
|
|
23432
|
-
|
|
23433
|
-
// If
|
|
23434
|
-
if (
|
|
23435
|
-
|
|
23436
|
-
}
|
|
23437
|
-
|
|
23438
|
-
|
|
23439
|
-
|
|
23440
|
-
|
|
23441
|
-
|
|
23442
|
-
|
|
23443
|
-
|
|
23444
|
-
|
|
23445
|
-
|
|
23446
|
-
|
|
23447
|
-
|
|
23448
|
-
}
|
|
23611
|
+
// Make sure row will be cancelled, and NOT deleted
|
|
23612
|
+
if (row.id === -1 || !row.editing)
|
|
23613
|
+
throw new Error('Row cannot be canceling, but only deleting');
|
|
23614
|
+
const confirmed = (!opts || opts.interactive !== false);
|
|
23615
|
+
// Ask user confirmation, if cancel
|
|
23616
|
+
if (!confirmed && ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty) && (this.confirmBeforeCancel || this.onBeforeCancelRows.observers.length > 0)) {
|
|
23617
|
+
event.stopPropagation();
|
|
23618
|
+
this.canCancelRows([row], opts)
|
|
23619
|
+
.then(confirm => {
|
|
23620
|
+
// If confirmed, loop
|
|
23621
|
+
if (confirm)
|
|
23622
|
+
this.cancelExistingRow(event, row, { interactive: false });
|
|
23623
|
+
});
|
|
23624
|
+
return;
|
|
23625
|
+
}
|
|
23626
|
+
const keepEditing = row.editing && (!opts || opts.keepEditing !== false);
|
|
23627
|
+
this.editedRow = undefined; // unselect row
|
|
23628
|
+
this._dataSource.cancelOrDelete(row);
|
|
23629
|
+
this.onCancelOrDeleteRow.next(row);
|
|
23630
|
+
// Mark row as pristine
|
|
23631
|
+
this.checkIfRowPristine(row);
|
|
23632
|
+
// Restore editing state
|
|
23633
|
+
if (keepEditing) {
|
|
23634
|
+
this.editRow(undefined, row);
|
|
23635
|
+
}
|
|
23449
23636
|
}
|
|
23450
23637
|
checkIfRowPristine(row, opts) {
|
|
23451
23638
|
var _a, _b;
|
|
23452
23639
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23453
23640
|
// Mark row as pristine
|
|
23454
|
-
const markRowAsPristine = ((_a = this.dataSource) === null || _a === void 0 ? void 0 : _a.
|
|
23641
|
+
const markRowAsPristine = ((_a = this.dataSource) === null || _a === void 0 ? void 0 : _a.options.keepOriginalDataAfterConfirm) === true;
|
|
23455
23642
|
if (markRowAsPristine) {
|
|
23456
23643
|
(_b = row.validator) === null || _b === void 0 ? void 0 : _b.markAsPristine();
|
|
23457
23644
|
// Check if table is now pristine
|
|
@@ -24259,6 +24446,12 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24259
24446
|
this.onUpdateView.complete();
|
|
24260
24447
|
this.onUpdateView.unsubscribe();
|
|
24261
24448
|
}
|
|
24449
|
+
waitIdle(opts) {
|
|
24450
|
+
// Wait end of saving
|
|
24451
|
+
if (this.saving)
|
|
24452
|
+
return waitFor(() => this.saving !== true);
|
|
24453
|
+
return super.waitIdle(opts);
|
|
24454
|
+
}
|
|
24262
24455
|
/**
|
|
24263
24456
|
* Load data from the snapshot route
|
|
24264
24457
|
*
|
|
@@ -24377,7 +24570,7 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24377
24570
|
const idChanged = isNotNil(data.id)
|
|
24378
24571
|
&& this.previousDataId !== undefined // Ignore if first loading (=undefined)
|
|
24379
24572
|
&& this.previousDataId !== data.id;
|
|
24380
|
-
opts = Object.assign({ updateRoute: this._autoUpdateRoute && idChanged && !this.loading
|
|
24573
|
+
opts = Object.assign({ updateRoute: this._autoUpdateRoute && idChanged && !this.loading }, opts);
|
|
24381
24574
|
this.data = data;
|
|
24382
24575
|
this.previousDataId = data.id || null;
|
|
24383
24576
|
yield this.ready();
|
|
@@ -24428,18 +24621,25 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24428
24621
|
// Save the opened tab into the queryParams
|
|
24429
24622
|
this.queryParams.tab = this.selectedTabIndex;
|
|
24430
24623
|
// Update route location
|
|
24431
|
-
|
|
24432
|
-
|
|
24433
|
-
|
|
24624
|
+
if (isNotNil(data === null || data === void 0 ? void 0 : data.id)) {
|
|
24625
|
+
const queryParams = Object.assign({}, this.queryParams);
|
|
24626
|
+
queryParams[this._pathIdAttribute] = data.id;
|
|
24627
|
+
if (this.debug)
|
|
24628
|
+
console.debug('[entity-editor] Updating route using params: ', queryParams);
|
|
24434
24629
|
yield this.router.navigate(['.'], {
|
|
24435
24630
|
relativeTo: this.route,
|
|
24436
|
-
queryParams
|
|
24631
|
+
queryParams
|
|
24437
24632
|
});
|
|
24438
24633
|
}
|
|
24634
|
+
// Move to ../new
|
|
24439
24635
|
else {
|
|
24636
|
+
const queryParams = Object.assign({}, this.queryParams);
|
|
24637
|
+
queryParams[this._pathIdAttribute] = 'new';
|
|
24638
|
+
if (this.debug)
|
|
24639
|
+
console.debug('[entity-editor] Updating route to \'../new\' using params: ', queryParams);
|
|
24440
24640
|
yield this.router.navigate(['..', 'new'], {
|
|
24441
24641
|
relativeTo: this.route,
|
|
24442
|
-
queryParams
|
|
24642
|
+
queryParams
|
|
24443
24643
|
});
|
|
24444
24644
|
}
|
|
24445
24645
|
yield this.updateRoute(data, this.queryParams);
|
|
@@ -24449,7 +24649,7 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24449
24649
|
* Update the route location, and open the next tab
|
|
24450
24650
|
*/
|
|
24451
24651
|
updateTabIndex(tabIndex) {
|
|
24452
|
-
if (isNotNil(tabIndex) && tabIndex
|
|
24652
|
+
if (isNotNil(tabIndex) && tabIndex !== this.selectedTabIndex) {
|
|
24453
24653
|
this.selectedTabIndex = tabIndex;
|
|
24454
24654
|
this.markForCheck();
|
|
24455
24655
|
}
|
|
@@ -24505,6 +24705,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24505
24705
|
if (this.debug)
|
|
24506
24706
|
console.debug('[data-editor] Saving data...');
|
|
24507
24707
|
try {
|
|
24708
|
+
// Compute next tab index (if enable)
|
|
24709
|
+
const nextTabIndex = this._autoOpenNextTab && isNil(this.previousDataId) && this.computeNextTabIndex();
|
|
24508
24710
|
// Get data
|
|
24509
24711
|
const data = yield this.getValue();
|
|
24510
24712
|
this.disable();
|
|
@@ -24512,7 +24714,9 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24512
24714
|
const updatedData = yield this.dataService.save(data, opts);
|
|
24513
24715
|
yield this.onEntitySaved(updatedData);
|
|
24514
24716
|
// Update the view (e.g metadata)
|
|
24515
|
-
yield this.updateView(updatedData,
|
|
24717
|
+
yield this.updateView(updatedData, Object.assign({
|
|
24718
|
+
// Open next tab only if user has not changed it
|
|
24719
|
+
openTabIndex: nextTabIndex > this._selectedTabIndex ? nextTabIndex : undefined }, opts));
|
|
24516
24720
|
// Subscribe to remote changes
|
|
24517
24721
|
if (!this._listenChangesSubscription)
|
|
24518
24722
|
this.startListenRemoteChanges();
|
|
@@ -24732,7 +24936,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24732
24936
|
// If NOT data, then add to page history
|
|
24733
24937
|
if (!this.isNewData) {
|
|
24734
24938
|
const page = yield this.computePageHistory(title);
|
|
24735
|
-
|
|
24939
|
+
if (page)
|
|
24940
|
+
return this.addToPageHistory(page);
|
|
24736
24941
|
}
|
|
24737
24942
|
});
|
|
24738
24943
|
}
|
|
@@ -24745,6 +24950,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24745
24950
|
}
|
|
24746
24951
|
computePageHistory(title) {
|
|
24747
24952
|
return __awaiter(this, void 0, void 0, function* () {
|
|
24953
|
+
if (this.debug)
|
|
24954
|
+
console.debug('[entity-editor] Computing page history, using url: ' + this.router.url);
|
|
24748
24955
|
return {
|
|
24749
24956
|
title,
|
|
24750
24957
|
path: this.router.url
|
|
@@ -24775,7 +24982,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24775
24982
|
fetchPolicy: 'no-cache' }, opts));
|
|
24776
24983
|
}
|
|
24777
24984
|
markForCheck() {
|
|
24778
|
-
|
|
24985
|
+
var _a;
|
|
24986
|
+
(_a = this.cd) === null || _a === void 0 ? void 0 : _a.markForCheck();
|
|
24779
24987
|
}
|
|
24780
24988
|
/* -- private functions -- */
|
|
24781
24989
|
/**
|
|
@@ -24860,7 +25068,7 @@ AppInMemoryTable.ctorParameters = () => [
|
|
|
24860
25068
|
{ type: Function },
|
|
24861
25069
|
{ type: InMemoryEntitiesService },
|
|
24862
25070
|
{ type: ValidatorService },
|
|
24863
|
-
{ type:
|
|
25071
|
+
{ type: AppTableDataSourceOptions },
|
|
24864
25072
|
{ type: undefined }
|
|
24865
25073
|
];
|
|
24866
25074
|
AppInMemoryTable.propDecorators = {
|
|
@@ -25884,7 +26092,7 @@ class PersonService extends BaseEntityService {
|
|
|
25884
26092
|
}
|
|
25885
26093
|
suggest(value, filter, sortBy, sortDirection) {
|
|
25886
26094
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25887
|
-
if (
|
|
26095
|
+
if (EntityUtils.isNotEmpty(value, 'id'))
|
|
25888
26096
|
return { data: [value] };
|
|
25889
26097
|
value = (typeof value === 'string' && value !== '*') && value || undefined;
|
|
25890
26098
|
sortBy = sortBy || filter.searchAttribute || (filter.searchAttributes && filter.searchAttributes[0]);
|
|
@@ -26036,11 +26244,7 @@ class UsersPage extends AppTable {
|
|
|
26036
26244
|
switch (authTokenType) {
|
|
26037
26245
|
case "basic":
|
|
26038
26246
|
this.setShowColumn('pubkey', false, { emitEvent: false });
|
|
26039
|
-
this.setShowColumn('username', true, { emitEvent: false });
|
|
26040
|
-
this.setShowColumn('usernameExtranet', true, { emitEvent: false });
|
|
26041
|
-
break;
|
|
26042
26247
|
case "basic-and-token":
|
|
26043
|
-
this.setShowColumn('pubkey', true, { emitEvent: false });
|
|
26044
26248
|
this.setShowColumn('username', true, { emitEvent: false });
|
|
26045
26249
|
this.setShowColumn('usernameExtranet', true, { emitEvent: false });
|
|
26046
26250
|
break;
|
|
@@ -26252,6 +26456,7 @@ class AutocompleteTestPage {
|
|
|
26252
26456
|
missingEntity: [null, SharedValidators.entity],
|
|
26253
26457
|
disableEntity: [null, SharedValidators.entity],
|
|
26254
26458
|
entities: [null, SharedFormArrayValidators.requiredArrayMinLength(1)],
|
|
26459
|
+
farEntity: [null, SharedValidators.entity]
|
|
26255
26460
|
});
|
|
26256
26461
|
this.form.get('disableEntity').disable();
|
|
26257
26462
|
}
|
|
@@ -26260,8 +26465,7 @@ class AutocompleteTestPage {
|
|
|
26260
26465
|
this.autocompleteFields.add('entity-suggestFn', {
|
|
26261
26466
|
suggestFn: (value, filter) => this.suggest(value, filter),
|
|
26262
26467
|
attributes: ['label', 'name'],
|
|
26263
|
-
displayWith: this.entityToString
|
|
26264
|
-
showAllOnFocus: false
|
|
26468
|
+
displayWith: this.entityToString
|
|
26265
26469
|
});
|
|
26266
26470
|
// From items array
|
|
26267
26471
|
this.autocompleteFields.add('entity-items', {
|
|
@@ -26289,22 +26493,34 @@ class AutocompleteTestPage {
|
|
|
26289
26493
|
attributes: ['label', 'name', 'description', 'comments'],
|
|
26290
26494
|
displayWith: this.entityToString
|
|
26291
26495
|
});
|
|
26292
|
-
//
|
|
26496
|
+
// Far entity, in the list
|
|
26497
|
+
this.autocompleteFields.add('entity-far', {
|
|
26498
|
+
suggestFn: (value, filter) => this.suggest(value, filter),
|
|
26499
|
+
attributes: ['label', 'name'],
|
|
26500
|
+
displayWith: this.entityToString
|
|
26501
|
+
});
|
|
26502
|
+
// For multiple value
|
|
26293
26503
|
this.autocompleteFields.add('entities-items-filter', {
|
|
26294
26504
|
service: {
|
|
26295
26505
|
suggest: (value, filter) => this.suggest(value, filter)
|
|
26296
26506
|
},
|
|
26297
26507
|
attributes: ['label', 'name'],
|
|
26298
26508
|
multiple: true
|
|
26299
|
-
//displayWith: this.entitiesToString
|
|
26300
26509
|
});
|
|
26301
|
-
|
|
26510
|
+
}
|
|
26511
|
+
ngAfterViewInit() {
|
|
26512
|
+
setTimeout(() => {
|
|
26513
|
+
this.farEntityField.suggestLengthThreshold = 2;
|
|
26514
|
+
this.farEntityField.reloadItems();
|
|
26515
|
+
}, 2000);
|
|
26516
|
+
setTimeout(() => this.loadData(), 1000);
|
|
26302
26517
|
}
|
|
26303
26518
|
// Load the form with data
|
|
26304
26519
|
loadData() {
|
|
26305
26520
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26306
26521
|
const data = {
|
|
26307
26522
|
entity: deepCopy(FAKE_ENTITIES)[0],
|
|
26523
|
+
farEntity: deepCopy(FAKE_ENTITIES)[2],
|
|
26308
26524
|
// This item is NOT in the items list => i should be displayed anyway
|
|
26309
26525
|
missingEntity: {
|
|
26310
26526
|
id: -1, label: '??', name: 'Missing item'
|
|
@@ -26341,7 +26557,7 @@ class AutocompleteTestPage {
|
|
|
26341
26557
|
total,
|
|
26342
26558
|
data: res.data,
|
|
26343
26559
|
fetchMore: (variables) => __awaiter(this, void 0, void 0, function* () {
|
|
26344
|
-
yield sleep(1000);
|
|
26560
|
+
yield sleep(1000); // Simulate access to server
|
|
26345
26561
|
return this.suggest(value, Object.assign(Object.assign({}, filter), variables));
|
|
26346
26562
|
})
|
|
26347
26563
|
};
|
|
@@ -26384,12 +26600,15 @@ class AutocompleteTestPage {
|
|
|
26384
26600
|
AutocompleteTestPage.decorators = [
|
|
26385
26601
|
{ type: Component, args: [{
|
|
26386
26602
|
selector: 'app-autocomplete-test',
|
|
26387
|
-
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"
|
|
26603
|
+
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 Entity far in the list (not in first page)\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small>\n <pre style=\"white-space: normal !important;\">value: {{stringify(form.controls.farEntity.value)}}</pre>\n </small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-autocomplete-field formControlName=\"farEntity\" #farEntityField\n [config]=\"autocompleteFields.get('entity-far')\"\n [mobile]=\"true\"\n [equals]=\"equals\"\n [logPrefix]=\"'[combo-mobile-far]'\"\n [debug]=\"true\"\n [required]=\"true\"\n [clearable]=\"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 [clearable]=\"true\"\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"
|
|
26388
26604
|
},] }
|
|
26389
26605
|
];
|
|
26390
26606
|
AutocompleteTestPage.ctorParameters = () => [
|
|
26391
26607
|
{ type: FormBuilder }
|
|
26392
26608
|
];
|
|
26609
|
+
AutocompleteTestPage.propDecorators = {
|
|
26610
|
+
farEntityField: [{ type: ViewChild, args: ['farEntityField',] }]
|
|
26611
|
+
};
|
|
26393
26612
|
|
|
26394
26613
|
class LatLongTestPage {
|
|
26395
26614
|
constructor(formBuilder) {
|
|
@@ -26450,20 +26669,20 @@ class LatLongTestPage {
|
|
|
26450
26669
|
LatLongTestPage.decorators = [
|
|
26451
26670
|
{ type: Component, args: [{
|
|
26452
26671
|
selector: 'app-latlong-test',
|
|
26453
|
-
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>Lat/Long field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!-- Empty value -->\n <form *ngIf=\"form.get('empty') as formGroup\" [formGroup]=\"formGroup\">\n <ion-grid>\n <ion-row><ion-col><ion-text><h4>Empty, with defaults</h4></ion-text></ion-col></ion-row>\n\n <ion-row >\n\n <!-- DD Default sign -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DD, defaultSign '-'\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DD\"\n defaultSign=\"-\"\n placeholder=\"Latitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button matSuffix mat-icon-button (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DD\"\n defaultSign=\"-\"\n placeholder=\"Longitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- DDMM Default sign -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DDMM, defaultSign '+'\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n defaultSign=\"+\"\n placeholder=\"Latitude\">\n\n <mat-icon matPrefix >room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n defaultSign=\"+\"\n placeholder=\"Longitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Mobile + DDMM -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Mobile=true\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n defaultSign=\"+\"\n placeholder=\"Latitude\"\n mobile=\"true\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n defaultSign=\"+\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <form *ngIf=\"form.get('enable') as formGroup\" [formGroup]=\"formGroup\">\n <ion-grid>\n <!-- With value -->\n <ion-row><ion-col><ion-text><h4>With value</h4></ion-text></ion-col></ion-row>\n\n <ion-row>\n\n <!-- DD -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DD\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DD\"\n placeholder=\"Latitude\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DD\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- DDMMSS -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DDMM\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Latitude\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n\n <!-- DDMMSS -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DDMMSS\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMMSS\"\n placeholder=\"Latitude\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMMSS\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <!-- Disable -->\n <form *ngIf=\"form.get('disable') as formGroup\" [formGroup]=\"formGroup\">\n <ion-grid>\n <ion-row><ion-col><ion-text><h4>Disabled control</h4></ion-text></ion-col></ion-row>\n <ion-row>\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-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Latitude\">\n <mat-icon matPrefix>room</mat-icon>\n <mat-icon matSuffix>gps_fixed</mat-icon>\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Longitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-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 Readonly (control is enable)\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n </mat-checkbox>\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field #readonlyField [formControl]=\"form.get('enable.latitude')\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Latitude\"\n [readonly]=\"true\">\n <mat-icon matPrefix>room</mat-icon>\n <mat-icon matSuffix>gps_fixed</mat-icon>\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n </form>\n\n</ion-content>\n"
|
|
26672
|
+
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>Lat/Long field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <!-- Empty value -->\n <form *ngIf=\"form.get('empty') as formGroup\" [formGroup]=\"formGroup\">\n <ion-grid>\n <ion-row><ion-col><ion-text><h4>Empty, with defaults</h4></ion-text></ion-col></ion-row>\n\n <ion-row >\n\n <!-- DD Default sign -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DD, defaultSign '-'\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DD\"\n defaultSign=\"-\"\n placeholder=\"Latitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button matSuffix mat-icon-button (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DD\"\n defaultSign=\"-\"\n placeholder=\"Longitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- DDMM Default sign -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DDMM, defaultSign '+'\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n defaultSign=\"+\"\n placeholder=\"Latitude\">\n\n <mat-icon matPrefix >room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n defaultSign=\"+\"\n placeholder=\"Longitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n </ion-row>\n </ion-grid>\n </form>\n\n <form *ngIf=\"form.get('enable') as formGroup\" [formGroup]=\"formGroup\">\n <ion-grid>\n <!-- With value -->\n <ion-row><ion-col><ion-text><h4>With value</h4></ion-text></ion-col></ion-row>\n\n <ion-row>\n\n <!-- DD -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DD\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DD\"\n placeholder=\"Latitude\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DD\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- DDMMSS -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DDMM\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Latitude\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n\n <!-- DDMMSS -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Format DDMMSS\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMMSS\"\n placeholder=\"Latitude\">\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMMSS\"\n placeholder=\"Longitude\">\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n <!-- Disable -->\n <form *ngIf=\"form.get('disable') as formGroup\" [formGroup]=\"formGroup\">\n <ion-grid>\n <ion-row><ion-col><ion-text><h4>Disabled control</h4></ion-text></ion-col></ion-row>\n <ion-row>\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-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(formGroup.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field formControlName=\"latitude\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Latitude\">\n <mat-icon matPrefix>room</mat-icon>\n <mat-icon matSuffix>gps_fixed</mat-icon>\n </mat-latlong-field>\n </ion-col>\n <ion-col>\n <mat-latlong-field formControlName=\"longitude\"\n type=\"longitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Longitude\">\n <mat-icon matPrefix>room</mat-icon>\n <button type=\"button\" mat-icon-button matSuffix\n (click)=\"geoPosition($event)\">\n <mat-icon>gps_fixed</mat-icon>\n </button>\n </mat-latlong-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 Readonly (control is enable)\n </ion-label>\n </ion-card-title>\n </ion-card-header>\n <ion-card-content>\n\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n </mat-checkbox>\n\n <ion-grid class=\"ion-no-padding\">\n <ion-row>\n <ion-col>\n <mat-latlong-field #readonlyField [formControl]=\"form.get('enable.latitude')\"\n type=\"latitude\"\n latLongPattern=\"DDMM\"\n placeholder=\"Latitude\"\n [readonly]=\"true\">\n <mat-icon matPrefix>room</mat-icon>\n <mat-icon matSuffix>gps_fixed</mat-icon>\n </mat-latlong-field>\n </ion-col>\n </ion-row>\n </ion-grid>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n </form>\n\n</ion-content>\n"
|
|
26454
26673
|
},] }
|
|
26455
26674
|
];
|
|
26456
26675
|
LatLongTestPage.ctorParameters = () => [
|
|
26457
26676
|
{ type: FormBuilder }
|
|
26458
26677
|
];
|
|
26459
26678
|
|
|
26460
|
-
const moment$
|
|
26679
|
+
const moment$6 = momentImported;
|
|
26461
26680
|
class SwipeTestPage {
|
|
26462
26681
|
constructor(formBuilder, dateFormatPipe) {
|
|
26463
26682
|
this.formBuilder = formBuilder;
|
|
26464
26683
|
this.dateFormatPipe = dateFormatPipe;
|
|
26465
26684
|
this.$dates = new BehaviorSubject(undefined);
|
|
26466
|
-
this._today = moment$
|
|
26685
|
+
this._today = moment$6().startOf('day');
|
|
26467
26686
|
this.form = formBuilder.group({
|
|
26468
26687
|
empty: [null, Validators.required],
|
|
26469
26688
|
date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
|
|
@@ -26476,7 +26695,7 @@ class SwipeTestPage {
|
|
|
26476
26695
|
ngOnInit() {
|
|
26477
26696
|
const dates = [];
|
|
26478
26697
|
for (let d = 0; d < 7; d++) {
|
|
26479
|
-
dates[d] = moment$
|
|
26698
|
+
dates[d] = moment$6(this._today).add(d - 3, 'day');
|
|
26480
26699
|
}
|
|
26481
26700
|
this.$dates.next(dates);
|
|
26482
26701
|
this.loadData();
|
|
@@ -26517,7 +26736,7 @@ SwipeTestPage.ctorParameters = () => [
|
|
|
26517
26736
|
{ type: DateFormatPipe }
|
|
26518
26737
|
];
|
|
26519
26738
|
|
|
26520
|
-
const moment$
|
|
26739
|
+
const moment$7 = momentImported;
|
|
26521
26740
|
class DateTimeTestPage {
|
|
26522
26741
|
constructor(platform, formBuilder, cd) {
|
|
26523
26742
|
this.platform = platform;
|
|
@@ -26529,7 +26748,8 @@ class DateTimeTestPage {
|
|
|
26529
26748
|
this.memoryMobile = true;
|
|
26530
26749
|
this.stringify = JSON.stringify;
|
|
26531
26750
|
this.form = formBuilder.group({
|
|
26532
|
-
empty: [null
|
|
26751
|
+
empty: [null],
|
|
26752
|
+
emptyRequired: [null, Validators.required],
|
|
26533
26753
|
enable: [null, Validators.required],
|
|
26534
26754
|
disable: [null, Validators.required],
|
|
26535
26755
|
readonly: [null]
|
|
@@ -26548,9 +26768,10 @@ class DateTimeTestPage {
|
|
|
26548
26768
|
// Load the form with data
|
|
26549
26769
|
loadData() {
|
|
26550
26770
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26551
|
-
const now = moment$
|
|
26771
|
+
const now = moment$7();
|
|
26552
26772
|
const data = {
|
|
26553
|
-
empty:
|
|
26773
|
+
empty: null,
|
|
26774
|
+
emptyRequired: null,
|
|
26554
26775
|
enable: toDateISOString(now),
|
|
26555
26776
|
disable: now,
|
|
26556
26777
|
readonly: now
|
|
@@ -26600,7 +26821,7 @@ class DateTimeTestPage {
|
|
|
26600
26821
|
DateTimeTestPage.decorators = [
|
|
26601
26822
|
{ type: Component, args: [{
|
|
26602
26823
|
selector: 'app-data-time-test',
|
|
26603
|
-
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>Date/Time field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <ion-grid>\n\n <!-- debugging memory leak -->\n <ion-row><ion-col><ion-text><h4>Debug memory leak</h4></ion-text></ion-col></ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\">Start timer</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\">Stop timer</ion-button>\n </ion-col>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"never\">\n <input matInput type=\"text\" hidden>\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [value]=\"memoryMobile\">\n Mobile ?\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n <ion-col>\n <mat-date-time-field formControlName=\"empty\"\n *ngIf=\"!memoryHide\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"memoryMobile\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-col>\n </ion-row>\n\n <!-- Mobile mode -->\n <ion-row><ion-col><ion-text><h4>Mobile mode</h4></ion-text></ion-col></ion-row>\n <ion-row>\n <ion-col>\n\n <!-- Empty value -->\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.empty.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"empty\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"true\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Enable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n With value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.enable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"enable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"true\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Disable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.disable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"disable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <!-- debug console -->\n <ion-row>\n <!-- buttons -->\n <ion-col size=\"2\">\n <!-- submit form -->\n <ion-button (click)=\"doSubmit($event)\"\n fill=\"outline\">\n <ion-icon name=\"checkmark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n\n <!-- clear log -->\n <ion-button (click)=\"clearLogPanel()\"\n fill=\"outline\">\n <ion-icon name=\"trash\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </ion-col>\n <ion-col size=\"10\" *ngIf=\"showLogPanel\">\n <ion-text color=\"primary\">Log:<br/></ion-text>\n <div class=\"ion-padding-start\">\n <ion-text color=\"medium\">\n <small [innerHTML]=\"logContent\"></small>\n </ion-text>\n </div>\n </ion-col>\n </ion-row>\n\n <!-- Desktop mode -->\n <ion-row><ion-col><ion-text><h4>Desktop mode</h4></ion-text></ion-col></ion-row>\n <ion-row>\n <ion-col>\n\n <!-- Empty value -->\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.empty.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"empty\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Enable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n With value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.enable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"enable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Disable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.disable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"disable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"false\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Readonly -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly toggle\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.readonly.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n </mat-checkbox>\n\n <mat-date-time-field #readonlyField formControlName=\"readonly\"\n placeholder=\"Date/Time\"\n [readonly]=\"true\"\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n</ion-content>\n"
|
|
26824
|
+
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>Date/Time field test page</ion-title>\n </ion-toolbar>\n</ion-header>\n\n<ion-content class=\"ion-padding\">\n\n <form class=\"form-container\" [formGroup]=\"form\" (ngSubmit)=\"doSubmit($event)\">\n\n <ion-grid>\n\n <!-- debugging memory leak -->\n <ion-row><ion-col><ion-text><h4>Debug memory leak</h4></ion-text></ion-col></ion-row>\n <ion-row>\n <ion-col size=\"2\">\n <ion-button *ngIf=\"!memoryTimer\" (click)=\"startMemoryTimer()\">Start timer</ion-button>\n <ion-button *ngIf=\"memoryTimer\" (click)=\"stopMemoryTimer()\">Stop timer</ion-button>\n </ion-col>\n <ion-col size=\"2\">\n <mat-form-field floatLabel=\"never\">\n <input matInput type=\"text\" hidden>\n <mat-checkbox (change)=\"memoryMobile=$event.checked\" [value]=\"memoryMobile\">\n Mobile ?\n </mat-checkbox>\n </mat-form-field>\n </ion-col>\n <ion-col>\n <mat-date-time-field formControlName=\"emptyRequired\"\n *ngIf=\"!memoryHide\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"memoryMobile\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-col>\n </ion-row>\n\n <!-- Mobile mode -->\n <ion-row><ion-col><ion-text><h4>Mobile mode</h4></ion-text></ion-col></ion-row>\n <ion-row>\n <ion-col>\n\n <!-- Empty value -->\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.empty.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"empty\"\n placeholder=\"Date/Time\"\n [mobile]=\"true\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Empty value + required -->\n <ion-col>\n\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty value + required\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.empty.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"emptyRequired\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"true\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Enable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n With value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.enable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"enable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"true\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Disable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.disable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"disable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n <!-- debug console -->\n <ion-row>\n <!-- buttons -->\n <ion-col size=\"2\">\n <!-- submit form -->\n <ion-button (click)=\"doSubmit($event)\"\n fill=\"outline\">\n <ion-icon name=\"checkmark\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n\n <!-- clear log -->\n <ion-button (click)=\"clearLogPanel()\"\n fill=\"outline\">\n <ion-icon name=\"trash\" slot=\"icon-only\"></ion-icon>\n </ion-button>\n </ion-col>\n <ion-col size=\"10\" *ngIf=\"showLogPanel\">\n <ion-text color=\"primary\">Log:<br/></ion-text>\n <div class=\"ion-padding-start\">\n <ion-text color=\"medium\">\n <small [innerHTML]=\"logContent\"></small>\n </ion-text>\n </div>\n </ion-col>\n </ion-row>\n\n <!-- Desktop mode -->\n <ion-row><ion-col><ion-text><h4>Desktop mode</h4></ion-text></ion-col></ion-row>\n <ion-row>\n <ion-col>\n\n <!-- Empty value -->\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.empty.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"empty\"\n placeholder=\"Date/Time\"\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Empty required value -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Empty value + required\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.empty.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"emptyRequired\"\n placeholder=\"Date/Time\"\n required\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Enable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n With value\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.enable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"enable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Disable -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Disable\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.disable.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-date-time-field formControlName=\"disable\"\n placeholder=\"Date/Time\"\n [required]=\"true\"\n [mobile]=\"false\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n\n </ion-card-content>\n </ion-card>\n </ion-col>\n\n <!-- Readonly -->\n <ion-col>\n <ion-card>\n <ion-card-header>\n <ion-card-title>\n <ion-label color=\"primary\">\n Readonly toggle\n </ion-label>\n </ion-card-title>\n <ion-card-subtitle>\n <ion-text color=\"medium\">\n <small><pre>{{stringify(form.controls.readonly.value)}}</pre></small>\n </ion-text>\n </ion-card-subtitle>\n </ion-card-header>\n <ion-card-content>\n <mat-checkbox (change)=\"readonlyField.readonly=$event.checked\" [checked]=\"readonlyField.readonly\">\n </mat-checkbox>\n\n <mat-date-time-field #readonlyField formControlName=\"readonly\"\n placeholder=\"Date/Time\"\n [readonly]=\"true\"\n [mobile]=\"false\"\n [clearable]=\"true\">\n <ion-icon matPrefix name=\"calendar-outline\"></ion-icon>\n </mat-date-time-field>\n </ion-card-content>\n </ion-card>\n </ion-col>\n </ion-row>\n </ion-grid>\n </form>\n\n</ion-content>\n"
|
|
26604
26825
|
},] }
|
|
26605
26826
|
];
|
|
26606
26827
|
DateTimeTestPage.ctorParameters = () => [
|
|
@@ -26792,7 +27013,7 @@ NumpadTestPage.ctorParameters = () => [
|
|
|
26792
27013
|
{ type: FormBuilder }
|
|
26793
27014
|
];
|
|
26794
27015
|
|
|
26795
|
-
const moment$
|
|
27016
|
+
const moment$8 = momentImported;
|
|
26796
27017
|
class DateTestPage {
|
|
26797
27018
|
constructor(formBuilder, cd) {
|
|
26798
27019
|
this.formBuilder = formBuilder;
|
|
@@ -26825,7 +27046,7 @@ class DateTestPage {
|
|
|
26825
27046
|
// Load the form with data
|
|
26826
27047
|
loadData() {
|
|
26827
27048
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26828
|
-
const now = moment$
|
|
27049
|
+
const now = moment$8();
|
|
26829
27050
|
const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
|
|
26830
27051
|
const data = {
|
|
26831
27052
|
empty: null,
|
|
@@ -27571,5 +27792,5 @@ CoreTestingModule.decorators = [
|
|
|
27571
27792
|
* Generated bundle index. Do not edit.
|
|
27572
27793
|
*/
|
|
27573
27794
|
|
|
27574
|
-
export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageService, MessageTypeList, MessageTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UserEvent, UserEventFilter, UserEventFragments, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh,
|
|
27795
|
+
export { APP_ABOUT_DEVELOPERS, APP_ABOUT_PARTNERS, APP_CONFIG_OPTIONS, APP_FORM_ERROR_I18N_KEYS, APP_GRAPHQL_TYPE_POLICIES, APP_HOME_BUTTONS, APP_LOCALES, APP_LOCAL_SETTINGS, APP_LOCAL_SETTINGS_OPTIONS, APP_LOCAL_STORAGE_TYPE_POLICIES, APP_MENU_ITEMS, APP_TESTING_PAGES, AboutModal, Account, AccountPage, AccountService, AccountToStringPipe, ActionsColumnComponent, AdminModule, AdminRoutingModule, Alerts, AndroidOsEnvironment, AnimationState, AppEditor, AppEditorOptions, AppEntityEditor, AppForm, AppFormField, AppFormProvider, AppFormUtils, AppGestureConfig, AppGraphQLModule, AppHelpModal, AppInMemoryTable, AppInstallUpgradeCard, AppListForm, AppLoadingSpinner, AppMenuModule, AppNullForm, AppPropertiesForm, AppTabEditor, AppTabEditorOptions, AppTable, AppTableDataSourceOptions, AppTableUtils, AppValidatorService, AppendToInputDirective, ArrayFilterPipe, ArrayFirstPipe, ArrayIncludesPipe, ArrayLengthPipe, ArrayPluckPipe, AudioProvider, AuthForm, AuthGuardService, AuthModal, AutocompleteTestPage, AutofocusDirective, Base58, BaseEntityService, BaseGraphqlService, BaseGraphqlServiceOptions, BaseReferential, Beans, CORE_CONFIG_OPTIONS, CORE_TESTING_PAGES, CellValueChangeListener, ChipsTestPage, Color, ColorScale, ComponentDirtyGuard, ConfigService, Configuration, CoreModule, CoreTestingModule, CryptoService, DATE_ISO_PATTERN, DATE_UNIX_MS_TIMESTAMP, DATE_UNIX_TIMESTAMP, DEFAULT_MENU_SHOW_WHEN, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLACEHOLDER_CHAR, DEFAULT_REQUIRED_COLUMNS, DateDiffDurationPipe, DateFormatPipe, DateFromNowPipe, DateTimeTestPage, DateUtils, Department, DepartmentToStringPipe, DragAndDropDirective, DurationPipe, ENTITIES_STORAGE_KEY_PREFIX, ENVIRONMENT, EmptyArrayPipe, EntitiesService, EntitiesStorage, EntitiesTableDataSource, Entity, EntityClass, EntityClasses, EntityFilter, EntityFilterUtils, EntityMetadataComponent, EntityStore, EntityUtils, Environment, EvenPipe, FileResponse, FileService, FileSizePipe, FilesUtils, FormArrayHelper, FormButtonsBarComponent, FormButtonsBarToken, FormErrorTranslatePipe, FormErrorTranslator, FormFieldValuesHolder, FormGetArrayPipe, FormGetControlPipe, FormGetGroupPipe, FormGetPipe, FormGetValuePipe, Fragments$1 as Fragments, GraphqlService, HAMMER_PRESS_TIME, HAMMER_TAP_TIME, HighlightPipe, HomePage, Hotkeys, HotkeysDialogComponent, InMemoryEntitiesService, IsLoginAccountPipe, IsNilOrBlankPipe, IsNotNilOrBlankPipe, IsNotOnFieldModePipe, IsOnFieldModePipe, JobUtils, KEYBOARD_HIDE_DELAY_MS, LAT_LONG_DEFAULT_MAX_DECIMALS, LAT_LONG_PATTERNS, LatLongFormatPipe, LatLongTestPage, LatitudeFormatPipe, LocalSettingsService, LongitudeFormatPipe, MINIFY_ENTITY_FOR_LOCAL_STORAGE, MINIFY_ENTITY_FOR_POD, MapGetPipe, MapKeysPipe, MapValuesPipe, MatAutocompleteConfigHolder, MatAutocompleteField, MatBadgeIconDirective, MatBooleanField, MatChipsField, MatDate, MatDateShort, MatDateTime, MatDuration, MatLatLongField, MatNumpadComponent, MatNumpadContainerComponent, MatNumpadContent, MatPaginatorI18n, MatStepperI18n, MatSwipeField, MaterialTestingModule, MathAbsPipe, MenuComponent, MenuItems, MenuService, Message, MessageFilter, MessageForm, MessageModal, MessageService, MessageTypeList, MessageTypes, MimeTypes, ModalToolbarComponent, NetworkService, NgInitDirective, NgVarDirective, NotEmptyArrayPipe, NumberFormatPipe, NumpadDirective, OddPipe, PRIORITIZED_AUTHORITIES, PUBKEY_REGEXP, Peer, Person, PersonFilter, PersonFragments, PersonService, PersonToStringPipe, PersonUtils, PersonValidatorService, PlatformService, ProgressBarService, ProgressInterceptor, PropertyGetPipe, RESERVED_END_COLUMNS, RESERVED_START_COLUMNS, Referential, ReferentialFilter, ReferentialRef, ReferentialUtils, ReferentialValidatorService, RegisterConfirmPage, SETTINGS_DISPLAY_COLUMNS, SETTINGS_FILTER, SETTINGS_PAGE_SIZE, SETTINGS_SORTED_COLUMN, SETTINGS_STORAGE_KEY, SETTINGS_TRANSIENT_PROPERTIES, SHARED_MATERIAL_TESTING_PAGES, SHARED_TESTING_PAGES, SPACE_PLACEHOLDER_CHAR, SelectPeerModal, SettingsPage, SharedAsyncValidators, SharedDirectivesModule, SharedFormArrayValidators, SharedFormGroupValidators, SharedHotkeysModule, SharedMatAutocompleteModule, SharedMatBadgeIconModule, SharedMatBooleanModule, SharedMatChipsModule, SharedMatDateTimeModule, SharedMatDurationModule, SharedMatLatLongModule, SharedMatNumpadModule, SharedMatSwipeModule, SharedMaterialModule, SharedModule, SharedPipesModule, SharedRoutingModule, SharedTestingModule, SharedTestsPage, SharedValidators, SocialErrorCodes, SocialModule, Software, StartableService, StatusById, StatusIds, StatusList, StrIncludesPipe, StrLengthPipe, SwipeTestPage, TableSelectColumnsComponent, TableTestPage, TableTestingModule, TextForm, TextPopover, TextPopoverTestingModule, TextPopoverTestingPage, ToStringPipe, Toasts, ToolbarComponent, ToolbarToken, TranslatablePipe, TranslateContextPipe, TranslateContextService, UploadFile, UploadFileComponent, UploadFilePopover, UploadFileTestingModule, UploadFileTestingPage, UriUtils, UserEvent, UserEventFilter, UserEventFragments, UserEventService, UserEventTypes, UserEventsTable, UserSettings, UsersPage, accountToString, adaptValueToControl, addValueInArray, arrayDistinct, arrayGroupBy, arraySize, asInputElement, canHaveFocus, capitalizeFirstLetter, chainPromises, changeCaseToUnderscore, clearValueInArray, copyEntity2Form, createPromiseEvent, createPromiseEventEmitter, departmentToString, departmentsToString, disableControls, emitPromiseEvent, entityToString, equals, equalsOrNil, escapeRegExp, fadeInAnimation, fadeInOutAnimation, filterFalse, filterNotNil, filterNumberInput, filterTrue, firstArrayValue, firstFalse, firstFalsePromise, firstNotNil, firstNotNilPromise, firstTrue, firstTruePromise, focusInput, focusNextInput, focusPreviousInput, formatLatitude, formatLongitude, fromDateISOString, fromScrollEndEvent, fromUnixMsTimestamp, fromUnixTimestamp, getCaretPosition, getColorContrast, getColorShade, getColorTint, getConnectionType, getControlFromPath, getFocusableInputElements, getFormErrors, getFormValueFromEntity, getProperty, getPropertyByPath, getPropertyByPathAsString, getRandomImage, hexToRgb, hexToRgbArray, isAndroid, isBlankString, isControlHasInput, isCordova, isEmptyArray, isIOS, isInputElement, isInstanceOf, isInt, isMobile, isNil, isNilOrBlank, isNilOrNaN, isNotEmptyArray, isNotNil, isNotNilBoolean, isNotNilOrBlank, isNotNilOrNaN, isNotNilString, isNumber, isNumberRange, isProgressEvent, isResponseEvent, isTouchUi, isWindows, joinProperties, joinPropertiesPath, logFormErrors, markAllAsTouched, markAsUntouched, markControlAsTouched, markFormGroupAsTouched, matchMedia, matchUpperCase, mergeLoadResult, mixHex, moment$5 as moment, moveInputCaretToSeparator, noTrailingSlash, notNilOrDefault, nullIfUndefined, parseLatitudeOrLongitude, propertiesPathComparator, propertyComparator, propertyPathComparator, referentialToString, referentialsToString, remove, removeAll, removeDiacritics, removeDuplicatesFromArray, removeEnd, removeValueInArray, replaceAll, resetCalculatedValue, resizeArray, rgbArrayToHex, rgbToHex, round, scrollFactory, selectInputContent, selectInputRange, setCalculatedValue, setTabIndex, sleep, slideInOutAnimation, slideUpDownAnimation, sort, splitById, splitByProperty, startsWithUpperCase, suggestFromArray, suggestFromStringArray, tabindexComparator, testUserAgent, toBoolean, toDateISOString, toDuration, toFloat, toInt, toNotNil, toNumber, trimEmptyToNull, tz, uncapitalizeFirstLetter, updateValueAndValidity, waitFor, waitForTrue, waitIdle, waitWhilePending, ɵ0, CustomReuseStrategy as ɵa, MatNumpadDomService as ɵb, isFocusableElement as ɵc, RegisterForm as ɵd, AccountValidatorService as ɵe, RegisterModal as ɵf, UserSettingsValidatorService as ɵg, LocalSettingsValidatorService as ɵh, AppUpdateOfflineModeCard as ɵi, AppIconComponent as ɵj, DateTestPage as ɵk, NumpadTestPage as ɵl, MatBadgeIconTestPage as ɵm, ToastTestingModule as ɵn, ToastTestingPage as ɵo };
|
|
27575
27796
|
//# sourceMappingURL=sumaris-net.ngx-components.js.map
|