@sumaris-net/ngx-components 1.20.0-rc3 → 1.20.0
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 +1504 -1317
- 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 +46 -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/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 -189
- 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 +81 -58
- package/esm2015/src/app/shared/material/autocomplete/testing/autocomplete.test.js +24 -9
- 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 +5 -5
- 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 +1049 -827
- 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/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 -25
- 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/testing/autocomplete.test.d.ts +4 -2
- 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 +2 -2
- 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 [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,
|
|
@@ -2222,52 +2249,49 @@ function roundFloat(input, maxDecimals) {
|
|
|
2222
2249
|
return input;
|
|
2223
2250
|
}
|
|
2224
2251
|
|
|
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
2252
|
class LatitudeFormatPipe {
|
|
2241
2253
|
constructor() {
|
|
2242
2254
|
this.transform = formatLatitude;
|
|
2243
2255
|
}
|
|
2244
2256
|
}
|
|
2245
|
-
LatitudeFormatPipe.ɵprov = ɵɵdefineInjectable({ factory: function LatitudeFormatPipe_Factory() { return new LatitudeFormatPipe(); }, token: LatitudeFormatPipe, providedIn: "root" });
|
|
2246
2257
|
LatitudeFormatPipe.decorators = [
|
|
2247
2258
|
{ type: Pipe, args: [{
|
|
2248
2259
|
name: 'latitudeFormat'
|
|
2249
|
-
},] }
|
|
2250
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
2260
|
+
},] }
|
|
2251
2261
|
];
|
|
2252
2262
|
class LongitudeFormatPipe {
|
|
2253
2263
|
constructor() {
|
|
2254
2264
|
this.transform = formatLongitude;
|
|
2255
2265
|
}
|
|
2256
2266
|
}
|
|
2257
|
-
LongitudeFormatPipe.ɵprov = ɵɵdefineInjectable({ factory: function LongitudeFormatPipe_Factory() { return new LongitudeFormatPipe(); }, token: LongitudeFormatPipe, providedIn: "root" });
|
|
2258
2267
|
LongitudeFormatPipe.decorators = [
|
|
2259
2268
|
{ type: Pipe, args: [{
|
|
2260
2269
|
name: 'longitudeFormat'
|
|
2261
|
-
},] }
|
|
2262
|
-
|
|
2270
|
+
},] }
|
|
2271
|
+
];
|
|
2272
|
+
/**
|
|
2273
|
+
* @deprecated use 'latitudeFormat' or 'longitudeFormat' instead
|
|
2274
|
+
*/
|
|
2275
|
+
class LatLongFormatPipe {
|
|
2276
|
+
transform(value, opts) {
|
|
2277
|
+
return ((!opts || (opts === null || opts === void 0 ? void 0 : opts.type) !== 'latitude') ? formatLongitude : formatLatitude)(value, opts);
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
2280
|
+
LatLongFormatPipe.decorators = [
|
|
2281
|
+
{ type: Pipe, args: [{
|
|
2282
|
+
name: 'latLongFormat'
|
|
2283
|
+
},] }
|
|
2263
2284
|
];
|
|
2264
2285
|
|
|
2265
2286
|
class NumberFormatPipe {
|
|
2266
|
-
transform(val,
|
|
2287
|
+
transform(val, opts) {
|
|
2267
2288
|
// Format the output to display any way you want here.
|
|
2268
2289
|
// For instance:
|
|
2269
2290
|
if (val !== undefined && val !== null) {
|
|
2270
|
-
|
|
2291
|
+
if (opts === null || opts === void 0 ? void 0 : opts.fixedDecimals) {
|
|
2292
|
+
return val.toFixed(opts.fixedDecimals);
|
|
2293
|
+
}
|
|
2294
|
+
return val.toLocaleString(undefined, opts);
|
|
2271
2295
|
}
|
|
2272
2296
|
else {
|
|
2273
2297
|
return '';
|
|
@@ -2380,15 +2404,9 @@ FileSizePipe.decorators = [
|
|
|
2380
2404
|
];
|
|
2381
2405
|
|
|
2382
2406
|
const moment$1 = momentImported;
|
|
2383
|
-
const tz = momentTZImported;
|
|
2384
2407
|
const DATE_UNIX_TIMESTAMP = 'X';
|
|
2385
2408
|
const DATE_UNIX_MS_TIMESTAMP = 'x';
|
|
2386
2409
|
class DateUtils {
|
|
2387
|
-
constructor() {
|
|
2388
|
-
this.toDateISOString = toDateISOString;
|
|
2389
|
-
this.fromDateISOString = fromDateISOString;
|
|
2390
|
-
this.toDuration = toDuration;
|
|
2391
|
-
}
|
|
2392
2410
|
static min(date1, date2) {
|
|
2393
2411
|
return date1 && (!date2 || date1.isSameOrBefore(date2)) ? date1 : date2;
|
|
2394
2412
|
}
|
|
@@ -2438,6 +2456,9 @@ class DateUtils {
|
|
|
2438
2456
|
return date.day() === weekday;
|
|
2439
2457
|
}
|
|
2440
2458
|
}
|
|
2459
|
+
DateUtils.toDateISOString = toDateISOString;
|
|
2460
|
+
DateUtils.fromDateISOString = fromDateISOString;
|
|
2461
|
+
DateUtils.toDuration = toDuration;
|
|
2441
2462
|
function toDateISOString(value) {
|
|
2442
2463
|
if (!value)
|
|
2443
2464
|
return undefined;
|
|
@@ -2908,7 +2929,7 @@ const moment$2 = momentImported;
|
|
|
2908
2929
|
// @dynamic
|
|
2909
2930
|
class SharedValidators {
|
|
2910
2931
|
static getDoubleRegexp(maxDecimals) {
|
|
2911
|
-
if (isNil(maxDecimals)
|
|
2932
|
+
if (isNil(maxDecimals))
|
|
2912
2933
|
return this._REGEXP_CACHE.DOUBLE_BY_MAX_DECIMALS.NO_LIMIT;
|
|
2913
2934
|
if (maxDecimals < 0)
|
|
2914
2935
|
throw new Error(`Invalid maxDecimals value: ${maxDecimals}`);
|
|
@@ -2969,7 +2990,7 @@ class SharedValidators {
|
|
|
2969
2990
|
}
|
|
2970
2991
|
return null;
|
|
2971
2992
|
}
|
|
2972
|
-
static
|
|
2993
|
+
static decimal(opts) {
|
|
2973
2994
|
const regexp = this.getDoubleRegexp(opts === null || opts === void 0 ? void 0 : opts.maxDecimals);
|
|
2974
2995
|
return (control) => {
|
|
2975
2996
|
let value = control.value;
|
|
@@ -2978,7 +2999,7 @@ class SharedValidators {
|
|
|
2978
2999
|
return null;
|
|
2979
3000
|
}
|
|
2980
3001
|
if (isNotNil(value) && value !== '' && !regexp.test(value)) {
|
|
2981
|
-
return
|
|
3002
|
+
return isNotNil(opts === null || opts === void 0 ? void 0 : opts.maxDecimals) ? { maxDecimals: { maxDecimals: opts.maxDecimals } } : { decimal: true };
|
|
2982
3003
|
}
|
|
2983
3004
|
return null;
|
|
2984
3005
|
};
|
|
@@ -3110,6 +3131,7 @@ SharedValidators.I18N_ERROR_KEYS = {
|
|
|
3110
3131
|
dateMinDuration: 'ERROR.FIELD_NOT_VALID_DATE_MIN_DURATION',
|
|
3111
3132
|
dateMaxDuration: 'ERROR.FIELD_NOT_VALID_DATE_MAX_DURATION',
|
|
3112
3133
|
maxDecimals: 'ERROR.FIELD_MAXIMUM_DECIMALS',
|
|
3134
|
+
double: 'ERROR.FIELD_NOT_VALID_DOUBLE',
|
|
3113
3135
|
integer: 'ERROR.FIELD_NOT_VALID_INTEGER',
|
|
3114
3136
|
email: 'ERROR.FIELD_NOT_VALID_EMAIL',
|
|
3115
3137
|
latitude: 'ERROR.FIELD_NOT_VALID_LATITUDE',
|
|
@@ -3118,6 +3140,10 @@ SharedValidators.I18N_ERROR_KEYS = {
|
|
|
3118
3140
|
unique: 'ERROR.FIELD_NOT_UNIQUE',
|
|
3119
3141
|
entity: 'ERROR.FIELD_INVALID'
|
|
3120
3142
|
};
|
|
3143
|
+
/**
|
|
3144
|
+
* @deprecated use decimal
|
|
3145
|
+
*/
|
|
3146
|
+
SharedValidators.double = SharedValidators.decimal;
|
|
3121
3147
|
// @dynamic
|
|
3122
3148
|
class SharedFormGroupValidators {
|
|
3123
3149
|
static dateRange(startDateField, endDateField, msg) {
|
|
@@ -4132,8 +4158,8 @@ class FormErrorTranslatePipe {
|
|
|
4132
4158
|
// if there is a subscription to onLangChange, clean it
|
|
4133
4159
|
this._dispose();
|
|
4134
4160
|
// subscribe to onTranslationChange event, in case the translations change
|
|
4135
|
-
if (!this.
|
|
4136
|
-
this.
|
|
4161
|
+
if (!this._onFormStatusChanges) {
|
|
4162
|
+
this._onFormStatusChanges = form.statusChanges.subscribe((status) => {
|
|
4137
4163
|
this._updateValue(form, opts, status);
|
|
4138
4164
|
});
|
|
4139
4165
|
}
|
|
@@ -4156,9 +4182,9 @@ class FormErrorTranslatePipe {
|
|
|
4156
4182
|
* Clean any existing subscription to change events
|
|
4157
4183
|
*/
|
|
4158
4184
|
_dispose() {
|
|
4159
|
-
if (typeof this.
|
|
4160
|
-
this.
|
|
4161
|
-
this.
|
|
4185
|
+
if (typeof this._onFormStatusChanges !== 'undefined') {
|
|
4186
|
+
this._onFormStatusChanges.unsubscribe();
|
|
4187
|
+
this._onFormStatusChanges = undefined;
|
|
4162
4188
|
}
|
|
4163
4189
|
}
|
|
4164
4190
|
}
|
|
@@ -4177,48 +4203,112 @@ class FormGetPipe {
|
|
|
4177
4203
|
return form.get(path);
|
|
4178
4204
|
}
|
|
4179
4205
|
}
|
|
4180
|
-
FormGetPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetPipe_Factory() { return new FormGetPipe(); }, token: FormGetPipe, providedIn: "root" });
|
|
4181
4206
|
FormGetPipe.decorators = [
|
|
4182
4207
|
{ type: Pipe, args: [{
|
|
4183
4208
|
name: 'formGet'
|
|
4184
|
-
},] }
|
|
4185
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
4209
|
+
},] }
|
|
4186
4210
|
];
|
|
4187
4211
|
class FormGetControlPipe {
|
|
4188
4212
|
transform(form, path) {
|
|
4189
|
-
return form.get(path);
|
|
4213
|
+
return (form && path && form.get(path) || form);
|
|
4190
4214
|
}
|
|
4191
4215
|
}
|
|
4192
|
-
FormGetControlPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetControlPipe_Factory() { return new FormGetControlPipe(); }, token: FormGetControlPipe, providedIn: "root" });
|
|
4193
4216
|
FormGetControlPipe.decorators = [
|
|
4194
4217
|
{ type: Pipe, args: [{
|
|
4195
4218
|
name: 'formGetControl'
|
|
4196
|
-
},] }
|
|
4197
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
4219
|
+
},] }
|
|
4198
4220
|
];
|
|
4199
4221
|
class FormGetArrayPipe {
|
|
4200
4222
|
transform(form, path) {
|
|
4201
|
-
return form.get(path);
|
|
4223
|
+
return (form && path && form.get(path) || form);
|
|
4202
4224
|
}
|
|
4203
4225
|
}
|
|
4204
|
-
FormGetArrayPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetArrayPipe_Factory() { return new FormGetArrayPipe(); }, token: FormGetArrayPipe, providedIn: "root" });
|
|
4205
4226
|
FormGetArrayPipe.decorators = [
|
|
4206
4227
|
{ type: Pipe, args: [{
|
|
4207
4228
|
name: 'formGetArray'
|
|
4208
|
-
},] }
|
|
4209
|
-
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
4229
|
+
},] }
|
|
4210
4230
|
];
|
|
4211
4231
|
class FormGetGroupPipe {
|
|
4212
4232
|
transform(form, path) {
|
|
4213
|
-
return form.get(path);
|
|
4233
|
+
return (form && path && form.get(path) || form);
|
|
4214
4234
|
}
|
|
4215
4235
|
}
|
|
4216
|
-
FormGetGroupPipe.ɵprov = ɵɵdefineInjectable({ factory: function FormGetGroupPipe_Factory() { return new FormGetGroupPipe(); }, token: FormGetGroupPipe, providedIn: "root" });
|
|
4217
4236
|
FormGetGroupPipe.decorators = [
|
|
4218
4237
|
{ type: Pipe, args: [{
|
|
4219
4238
|
name: 'formGetGroup'
|
|
4220
|
-
},] }
|
|
4221
|
-
|
|
4239
|
+
},] }
|
|
4240
|
+
];
|
|
4241
|
+
class FormGetValuePipe {
|
|
4242
|
+
constructor(adapter, _ref) {
|
|
4243
|
+
this.adapter = adapter;
|
|
4244
|
+
this._ref = _ref;
|
|
4245
|
+
this.value = undefined;
|
|
4246
|
+
this._lastControl = null;
|
|
4247
|
+
}
|
|
4248
|
+
transform(form, path, listenStatusChanges = false) {
|
|
4249
|
+
if (!form) {
|
|
4250
|
+
this._dispose();
|
|
4251
|
+
return undefined;
|
|
4252
|
+
}
|
|
4253
|
+
// if we ask another time for the same form and opts, return the last value
|
|
4254
|
+
if (form === this._lastControl && equals(path, this._lastPath)) {
|
|
4255
|
+
return this.value;
|
|
4256
|
+
}
|
|
4257
|
+
// store the query, in case it changes
|
|
4258
|
+
this._lastControl = form;
|
|
4259
|
+
// store the params, in case they change
|
|
4260
|
+
this._lastPath = path;
|
|
4261
|
+
// set the value
|
|
4262
|
+
const control = path ? form.get(path) : form;
|
|
4263
|
+
this.value = control === null || control === void 0 ? void 0 : control.value;
|
|
4264
|
+
// if there is a subscription to onLangChange, clean it
|
|
4265
|
+
this._dispose();
|
|
4266
|
+
// subscribe to valueChanges event, in case control value change
|
|
4267
|
+
if (!this._onControlValueChanges && control) {
|
|
4268
|
+
this._onControlValueChanges = control.valueChanges.subscribe((value) => {
|
|
4269
|
+
if (value !== this.value) {
|
|
4270
|
+
this.value = value;
|
|
4271
|
+
this._ref.markForCheck();
|
|
4272
|
+
}
|
|
4273
|
+
});
|
|
4274
|
+
}
|
|
4275
|
+
if (listenStatusChanges && !this._onControlStatusChanges && control) {
|
|
4276
|
+
this._onControlStatusChanges = control.statusChanges.subscribe((status) => {
|
|
4277
|
+
const value = control.value;
|
|
4278
|
+
if (value !== this.value) {
|
|
4279
|
+
this.value = value;
|
|
4280
|
+
this._ref.markForCheck();
|
|
4281
|
+
}
|
|
4282
|
+
});
|
|
4283
|
+
}
|
|
4284
|
+
return this.value;
|
|
4285
|
+
}
|
|
4286
|
+
ngOnDestroy() {
|
|
4287
|
+
this._dispose();
|
|
4288
|
+
}
|
|
4289
|
+
/**
|
|
4290
|
+
* Clean any existing subscription to change events
|
|
4291
|
+
*/
|
|
4292
|
+
_dispose() {
|
|
4293
|
+
if (typeof this._onControlValueChanges !== 'undefined') {
|
|
4294
|
+
this._onControlValueChanges.unsubscribe();
|
|
4295
|
+
this._onControlValueChanges = undefined;
|
|
4296
|
+
}
|
|
4297
|
+
if (typeof this._onControlStatusChanges !== 'undefined') {
|
|
4298
|
+
this._onControlStatusChanges.unsubscribe();
|
|
4299
|
+
this._onControlStatusChanges = undefined;
|
|
4300
|
+
}
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
FormGetValuePipe.decorators = [
|
|
4304
|
+
{ type: Pipe, args: [{
|
|
4305
|
+
name: 'formGetValue',
|
|
4306
|
+
pure: false
|
|
4307
|
+
},] }
|
|
4308
|
+
];
|
|
4309
|
+
FormGetValuePipe.ctorParameters = () => [
|
|
4310
|
+
{ type: FormErrorTranslator },
|
|
4311
|
+
{ type: ChangeDetectorRef }
|
|
4222
4312
|
];
|
|
4223
4313
|
|
|
4224
4314
|
class SharedPipesModule {
|
|
@@ -4267,7 +4357,8 @@ SharedPipesModule.decorators = [
|
|
|
4267
4357
|
FormGetPipe,
|
|
4268
4358
|
FormGetControlPipe,
|
|
4269
4359
|
FormGetArrayPipe,
|
|
4270
|
-
FormGetGroupPipe
|
|
4360
|
+
FormGetGroupPipe,
|
|
4361
|
+
FormGetValuePipe
|
|
4271
4362
|
],
|
|
4272
4363
|
exports: [
|
|
4273
4364
|
PropertyGetPipe,
|
|
@@ -4306,7 +4397,8 @@ SharedPipesModule.decorators = [
|
|
|
4306
4397
|
FormGetPipe,
|
|
4307
4398
|
FormGetControlPipe,
|
|
4308
4399
|
FormGetArrayPipe,
|
|
4309
|
-
FormGetGroupPipe
|
|
4400
|
+
FormGetGroupPipe,
|
|
4401
|
+
FormGetValuePipe
|
|
4310
4402
|
]
|
|
4311
4403
|
},] }
|
|
4312
4404
|
];
|
|
@@ -4583,10 +4675,10 @@ class MatLatLongField {
|
|
|
4583
4675
|
this.disabling = false;
|
|
4584
4676
|
this.writing = false;
|
|
4585
4677
|
this._readonly = false;
|
|
4678
|
+
this.required = false;
|
|
4679
|
+
this.floatLabel = 'auto';
|
|
4586
4680
|
this.maxDecimals = LAT_LONG_DEFAULT_MAX_DECIMALS;
|
|
4587
4681
|
this.placeholderChar = DEFAULT_PLACEHOLDER_CHAR;
|
|
4588
|
-
this.floatLabel = 'auto';
|
|
4589
|
-
this.required = false;
|
|
4590
4682
|
this.onBlur = new EventEmitter();
|
|
4591
4683
|
this.onFocus = new EventEmitter();
|
|
4592
4684
|
}
|
|
@@ -4601,7 +4693,6 @@ class MatLatLongField {
|
|
|
4601
4693
|
return this._readonly;
|
|
4602
4694
|
}
|
|
4603
4695
|
ngOnInit() {
|
|
4604
|
-
this.mobile = isNotNil(this.mobile) ? this.mobile : isMobile(window);
|
|
4605
4696
|
this.type = this.type || 'latitude';
|
|
4606
4697
|
this.pattern = this.pattern || 'DDMM';
|
|
4607
4698
|
this.mask = MASKS[this.type] && MASKS[this.type][this.pattern];
|
|
@@ -4632,8 +4723,8 @@ class MatLatLongField {
|
|
|
4632
4723
|
this.maxDecimals = DEFAULT_MAX_DECIMALS;
|
|
4633
4724
|
}
|
|
4634
4725
|
this.showSignControl = this.pattern !== 'DD';
|
|
4635
|
-
this.
|
|
4636
|
-
this.
|
|
4726
|
+
this._formatFn = this.type === 'latitude' ? formatLatitude : formatLongitude;
|
|
4727
|
+
this._formatOptions = { pattern: this.pattern, maxDecimals: this.maxDecimals, hideSign: this.showSignControl };
|
|
4637
4728
|
this.inputPlaceholder = 'COMMON.LAT_LONG.' + (this.type === 'longitude' && 'D' || '') + this.pattern + '_PLACEHOLDER';
|
|
4638
4729
|
this.textFormControl = this.formBuilder.control(this.required ? [null, Validators.required] : [null]);
|
|
4639
4730
|
this.textMaskConfig = { mask: this.mask, keepCharPositions: true, placeholderChar: this.placeholderChar };
|
|
@@ -4667,7 +4758,7 @@ class MatLatLongField {
|
|
|
4667
4758
|
return;
|
|
4668
4759
|
this.value = (typeof obj === 'string') ? parseFloat(obj.replace(/,/g, '.')) : obj;
|
|
4669
4760
|
this.writing = true;
|
|
4670
|
-
const strValue = this.
|
|
4761
|
+
const strValue = this._formatFn(this.value, Object.assign(Object.assign({}, this._formatOptions), { placeholderChar: this.placeholderChar }));
|
|
4671
4762
|
const sign = isNotNil(this.value) ? (this.value < 0 ? -1 : 1) :
|
|
4672
4763
|
// Use default sign, if any
|
|
4673
4764
|
(this.defaultSign ? (this.defaultSign === '-' ? -1 : 1) : null);
|
|
@@ -4700,41 +4791,13 @@ class MatLatLongField {
|
|
|
4700
4791
|
this.disabling = false;
|
|
4701
4792
|
this.markForCheck();
|
|
4702
4793
|
}
|
|
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;
|
|
4794
|
+
/**
|
|
4795
|
+
* Format value to display as string (no placeholder char, and show sign)
|
|
4796
|
+
* @param value
|
|
4797
|
+
* @param opts
|
|
4798
|
+
*/
|
|
4799
|
+
_format(value, opts) {
|
|
4800
|
+
return this._formatFn(value, Object.assign(Object.assign({}, this._formatOptions), { hideSign: false, placeholderChar: '' }));
|
|
4738
4801
|
}
|
|
4739
4802
|
_onFocus(event) {
|
|
4740
4803
|
// Apply the default sign, when pattern is DD and field is empty
|
|
@@ -4743,7 +4806,8 @@ class MatLatLongField {
|
|
|
4743
4806
|
// Compute the text value, using the default sign
|
|
4744
4807
|
const defaultSign = this.defaultSign === '-' ? -1 : 1;
|
|
4745
4808
|
if (this.pattern === 'DD') {
|
|
4746
|
-
let valueStr = this.
|
|
4809
|
+
let valueStr = this._formatFn(defaultSign, Object.assign(Object.assign({}, this._formatOptions), { placeholderChar: this.placeholderChar }));
|
|
4810
|
+
// Keep only the sign ('+' or '-') and placeholder chars, but NOT the '1'
|
|
4747
4811
|
valueStr = valueStr && valueStr.replace('1', this.placeholderChar);
|
|
4748
4812
|
// Wait end of focus animation (label should move to top)
|
|
4749
4813
|
setTimeout(() => {
|
|
@@ -4843,6 +4907,42 @@ class MatLatLongField {
|
|
|
4843
4907
|
}
|
|
4844
4908
|
}
|
|
4845
4909
|
}
|
|
4910
|
+
onFormChange(strValue) {
|
|
4911
|
+
if (this.writing)
|
|
4912
|
+
return; // Skip if call by self
|
|
4913
|
+
this.writing = true;
|
|
4914
|
+
if (this.textFormControl.invalid || this.signFormControl.invalid) {
|
|
4915
|
+
this.formControl.markAsPending();
|
|
4916
|
+
this.formControl.setErrors(Object.assign(Object.assign(Object.assign({}, this.formControl.errors), this.textFormControl.errors), this.signFormControl.errors));
|
|
4917
|
+
this.writing = false;
|
|
4918
|
+
return;
|
|
4919
|
+
}
|
|
4920
|
+
const parsedValue = isNotNilOrBlank(strValue) ? parseLatitudeOrLongitude(strValue, this.pattern, 7 /*=precision of the converted double value */, this.placeholderChar) : null;
|
|
4921
|
+
// DEBUG
|
|
4922
|
+
//console.debug('parsedValue=', parsedValue);
|
|
4923
|
+
if (isNaN(parsedValue)) {
|
|
4924
|
+
this.formControl.markAsPending();
|
|
4925
|
+
this.formControl.setErrors(this.type === 'latitude' ? { latitude: true } : { longitude: true });
|
|
4926
|
+
this.writing = false;
|
|
4927
|
+
return;
|
|
4928
|
+
}
|
|
4929
|
+
const sign = (this.pattern === 'DD') ? 1 /*ignore sign*/ : (this.signFormControl.value || 1);
|
|
4930
|
+
this.value = isNotNil(parsedValue) ? sign * parsedValue : null;
|
|
4931
|
+
// Get the model value
|
|
4932
|
+
//console.debug("[mat-latlon] Setting value {" + this.value + "} parsed from {" + strValue + "}");
|
|
4933
|
+
this.formControl.patchValue(this.value, { emitEvent: false });
|
|
4934
|
+
this.writing = false;
|
|
4935
|
+
this.markForCheck();
|
|
4936
|
+
this._onChangeCallback(this.value);
|
|
4937
|
+
}
|
|
4938
|
+
checkIfTouched() {
|
|
4939
|
+
if (this.formControl.touched || this.textFormControl.touched) {
|
|
4940
|
+
this.markForCheck();
|
|
4941
|
+
this._onTouchedCallback();
|
|
4942
|
+
return true;
|
|
4943
|
+
}
|
|
4944
|
+
return false;
|
|
4945
|
+
}
|
|
4846
4946
|
markForCheck() {
|
|
4847
4947
|
this.cd.markForCheck();
|
|
4848
4948
|
}
|
|
@@ -4850,7 +4950,7 @@ class MatLatLongField {
|
|
|
4850
4950
|
MatLatLongField.decorators = [
|
|
4851
4951
|
{ type: Component, args: [{
|
|
4852
4952
|
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>{{
|
|
4953
|
+
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
4954
|
providers: [
|
|
4855
4955
|
{
|
|
4856
4956
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -4859,7 +4959,7 @@ MatLatLongField.decorators = [
|
|
|
4859
4959
|
}
|
|
4860
4960
|
],
|
|
4861
4961
|
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:
|
|
4962
|
+
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
4963
|
},] }
|
|
4864
4964
|
];
|
|
4865
4965
|
MatLatLongField.ctorParameters = () => [
|
|
@@ -4869,19 +4969,18 @@ MatLatLongField.ctorParameters = () => [
|
|
|
4869
4969
|
{ type: FormGroupDirective, decorators: [{ type: Optional }] }
|
|
4870
4970
|
];
|
|
4871
4971
|
MatLatLongField.propDecorators = {
|
|
4872
|
-
mobile: [{ type: Input }],
|
|
4873
4972
|
formControl: [{ type: Input }],
|
|
4874
4973
|
formControlName: [{ type: Input }],
|
|
4875
|
-
placeholder: [{ type: Input }],
|
|
4876
4974
|
type: [{ type: Input }],
|
|
4877
4975
|
pattern: [{ type: Input, args: ['latLongPattern',] }],
|
|
4976
|
+
required: [{ type: Input }],
|
|
4977
|
+
floatLabel: [{ type: Input }],
|
|
4978
|
+
placeholder: [{ type: Input }],
|
|
4979
|
+
tabindex: [{ type: Input }],
|
|
4878
4980
|
defaultSign: [{ type: Input }],
|
|
4879
4981
|
maxDecimals: [{ type: Input }],
|
|
4880
4982
|
placeholderChar: [{ type: Input }],
|
|
4881
|
-
floatLabel: [{ type: Input }],
|
|
4882
4983
|
readonly: [{ type: Input }],
|
|
4883
|
-
required: [{ type: Input }],
|
|
4884
|
-
tabindex: [{ type: Input }],
|
|
4885
4984
|
onBlur: [{ type: Output }],
|
|
4886
4985
|
onFocus: [{ type: Output }],
|
|
4887
4986
|
inputElement: [{ type: ViewChild, args: ['inputElement',] }]
|
|
@@ -5234,7 +5333,7 @@ class MatDate {
|
|
|
5234
5333
|
MatDate.decorators = [
|
|
5235
5334
|
{ type: Component, args: [{
|
|
5236
5335
|
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 <
|
|
5336
|
+
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
5337
|
providers: [
|
|
5239
5338
|
DEFAULT_VALUE_ACCESSOR,
|
|
5240
5339
|
],
|
|
@@ -5331,7 +5430,7 @@ class MatDateTime {
|
|
|
5331
5430
|
// Workaround because ion-datetime has issue (do not returned a ISO date)
|
|
5332
5431
|
this._keyboardHideDelay = this.mobile && KEYBOARD_HIDE_DELAY_MS || 0;
|
|
5333
5432
|
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
|
|
5433
|
+
// Add 'validDate' validator (when existing validator are null or required, to be sure to keep)
|
|
5335
5434
|
if (!this.formControl.validator || this.formControl.validator === Validators.required) {
|
|
5336
5435
|
this.formControl.setValidators(this.required ? [Validators.required, SharedValidators.validDate] : SharedValidators.validDate);
|
|
5337
5436
|
}
|
|
@@ -5340,12 +5439,9 @@ class MatDateTime {
|
|
|
5340
5439
|
[this.formControl.validator, SharedValidators.validDate]);
|
|
5341
5440
|
}
|
|
5342
5441
|
// Create the day control
|
|
5343
|
-
this.dayControl = this.formBuilder.control(null
|
|
5442
|
+
this.dayControl = this.formBuilder.control(null);
|
|
5344
5443
|
// 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);
|
|
5444
|
+
this.hourControl = this.formBuilder.control(null, this.mobile ? null : Validators.pattern(HOUR_REGEXP));
|
|
5349
5445
|
// Get patterns to display date and date+time
|
|
5350
5446
|
this._subscription.add(this.translate.get(['COMMON.DATE_PATTERN', 'COMMON.DATE_TIME_PATTERN'])
|
|
5351
5447
|
.subscribe((patterns) => this.updatePattern(patterns)));
|
|
@@ -5528,7 +5624,9 @@ class MatDateTime {
|
|
|
5528
5624
|
if (incompleteValue || this.dayControl.invalid || this.hourControl.invalid) {
|
|
5529
5625
|
this.formControl.markAsPending({ onlySelf: true });
|
|
5530
5626
|
this.formControl.setErrors(Object.assign(Object.assign(Object.assign({ validDate: incompleteValue }, this.formControl.errors), this.dayControl.errors), this.hourControl.errors));
|
|
5531
|
-
this.
|
|
5627
|
+
if (this.dayControl.dirty || this.hourControl.dirty) {
|
|
5628
|
+
this.formControl.markAsDirty();
|
|
5629
|
+
}
|
|
5532
5630
|
this._writing = false;
|
|
5533
5631
|
return;
|
|
5534
5632
|
}
|
|
@@ -5907,7 +6005,7 @@ class MatDateShort {
|
|
|
5907
6005
|
MatDateShort.decorators = [
|
|
5908
6006
|
{ type: Component, args: [{
|
|
5909
6007
|
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 <
|
|
6008
|
+
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
6009
|
providers: [
|
|
5912
6010
|
DEFAULT_VALUE_ACCESSOR$2,
|
|
5913
6011
|
],
|
|
@@ -7045,8 +7143,8 @@ class MatSwipeField {
|
|
|
7045
7143
|
this.required = false;
|
|
7046
7144
|
this.clearable = false;
|
|
7047
7145
|
this.onClick = new EventEmitter();
|
|
7048
|
-
this.
|
|
7049
|
-
this.
|
|
7146
|
+
this.blurred = new EventEmitter();
|
|
7147
|
+
this.focused = new EventEmitter();
|
|
7050
7148
|
this.selectInputContent = selectInputContent;
|
|
7051
7149
|
}
|
|
7052
7150
|
set tabindex(value) {
|
|
@@ -7314,8 +7412,8 @@ MatSwipeField.propDecorators = {
|
|
|
7314
7412
|
tabindex: [{ type: Input }],
|
|
7315
7413
|
items: [{ type: Input }],
|
|
7316
7414
|
onClick: [{ type: Output, args: ['click',] }],
|
|
7317
|
-
|
|
7318
|
-
|
|
7415
|
+
blurred: [{ type: Output, args: ['blur',] }],
|
|
7416
|
+
focused: [{ type: Output, args: ['focus',] }],
|
|
7319
7417
|
fakeInput: [{ type: ViewChild, args: ['fakeInput',] }],
|
|
7320
7418
|
slides: [{ type: ViewChild, args: ['slides', { static: true },] }],
|
|
7321
7419
|
prevButton: [{ type: ViewChild, args: ['prevButton',] }],
|
|
@@ -8276,7 +8374,8 @@ AppGestureConfig.decorators = [
|
|
|
8276
8374
|
class ToolbarToken {
|
|
8277
8375
|
}
|
|
8278
8376
|
class ToolbarComponent {
|
|
8279
|
-
constructor(router, routerOutlet, cd, progressBarService) {
|
|
8377
|
+
constructor(route, router, routerOutlet, cd, progressBarService) {
|
|
8378
|
+
this.route = route;
|
|
8280
8379
|
this.router = router;
|
|
8281
8380
|
this.routerOutlet = routerOutlet;
|
|
8282
8381
|
this.cd = cd;
|
|
@@ -8362,15 +8461,28 @@ class ToolbarComponent {
|
|
|
8362
8461
|
return __awaiter(this, void 0, void 0, function* () {
|
|
8363
8462
|
console.debug('[toolbar] calling goBack()');
|
|
8364
8463
|
if (this._backHref) {
|
|
8365
|
-
|
|
8464
|
+
const replaceUrl = !this.routerOutlet.canGoBack();
|
|
8465
|
+
// Relative href
|
|
8466
|
+
if (this._backHref.startsWith('.')) {
|
|
8467
|
+
yield this.router.navigate([this._backHref], { relativeTo: this.route, replaceUrl });
|
|
8468
|
+
}
|
|
8469
|
+
else {
|
|
8470
|
+
yield this.router.navigateByUrl(this._backHref, { replaceUrl });
|
|
8471
|
+
}
|
|
8366
8472
|
}
|
|
8367
8473
|
else if (this.routerOutlet.canGoBack()) {
|
|
8368
8474
|
yield this.routerOutlet.pop();
|
|
8369
8475
|
}
|
|
8370
8476
|
else if (this._defaultBackHref) {
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8477
|
+
// Relative href
|
|
8478
|
+
if (this._defaultBackHref.startsWith('.')) {
|
|
8479
|
+
yield this.router.navigate([this._defaultBackHref], { relativeTo: this.route, replaceUrl: true });
|
|
8480
|
+
}
|
|
8481
|
+
else {
|
|
8482
|
+
yield this.router.navigateByUrl(this._defaultBackHref, {
|
|
8483
|
+
replaceUrl: true
|
|
8484
|
+
});
|
|
8485
|
+
}
|
|
8374
8486
|
}
|
|
8375
8487
|
else {
|
|
8376
8488
|
console.error('[toolbar] Cannot go back. Missing attribute \'defaultBackHref\' or \'backHref\'');
|
|
@@ -8429,7 +8541,7 @@ class ToolbarComponent {
|
|
|
8429
8541
|
ToolbarComponent.decorators = [
|
|
8430
8542
|
{ type: Component, args: [{
|
|
8431
8543
|
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",
|
|
8544
|
+
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
8545
|
providers: [
|
|
8434
8546
|
{ provide: ToolbarToken, useExisting: ToolbarComponent }
|
|
8435
8547
|
],
|
|
@@ -8438,6 +8550,7 @@ ToolbarComponent.decorators = [
|
|
|
8438
8550
|
},] }
|
|
8439
8551
|
];
|
|
8440
8552
|
ToolbarComponent.ctorParameters = () => [
|
|
8553
|
+
{ type: ActivatedRoute },
|
|
8441
8554
|
{ type: Router },
|
|
8442
8555
|
{ type: IonRouterOutlet },
|
|
8443
8556
|
{ type: ChangeDetectorRef },
|
|
@@ -8459,7 +8572,8 @@ ToolbarComponent.propDecorators = {
|
|
|
8459
8572
|
onValidateAndClose: [{ type: Output }],
|
|
8460
8573
|
onBackClick: [{ type: Output }],
|
|
8461
8574
|
onSearch: [{ type: Output }],
|
|
8462
|
-
searchbar: [{ type: ViewChild, args: ['searchbar', { static: true },] }]
|
|
8575
|
+
searchbar: [{ type: ViewChild, args: ['searchbar', { static: true },] }],
|
|
8576
|
+
menuToggle: [{ type: ViewChild, args: ['menuToggle', { static: true },] }]
|
|
8463
8577
|
};
|
|
8464
8578
|
|
|
8465
8579
|
class MatPaginatorI18n extends MatPaginatorIntl {
|
|
@@ -8746,7 +8860,7 @@ class AppFormField {
|
|
|
8746
8860
|
AppFormField.decorators = [
|
|
8747
8861
|
{ type: Component, args: [{
|
|
8748
8862
|
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:{
|
|
8863
|
+
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
8864
|
providers: [
|
|
8751
8865
|
{
|
|
8752
8866
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -9730,10 +9844,6 @@ class EntityUtils {
|
|
|
9730
9844
|
return isNotNil(obj.__typename) && (typeof obj.fromObject === 'function') && (typeof obj.asObject === 'function');
|
|
9731
9845
|
}
|
|
9732
9846
|
// 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
9847
|
static isNotEmpty(obj, checkedAttribute) {
|
|
9738
9848
|
return !!obj && obj[checkedAttribute] !== null && obj[checkedAttribute] !== undefined;
|
|
9739
9849
|
}
|
|
@@ -9813,6 +9923,8 @@ class EntityUtils {
|
|
|
9813
9923
|
(items || []).forEach(EntityUtils.cleanIdAndUpdateDate);
|
|
9814
9924
|
}
|
|
9815
9925
|
static sort(data, sortBy, sortDirection) {
|
|
9926
|
+
if (!data || data.length <= 1 || !sortBy)
|
|
9927
|
+
return data;
|
|
9816
9928
|
return data.sort(this.sortComparator(sortBy, sortDirection));
|
|
9817
9929
|
}
|
|
9818
9930
|
static sortComparator(sortBy, sortDirection) {
|
|
@@ -11837,11 +11949,10 @@ class EntityStore {
|
|
|
11837
11949
|
/**
|
|
11838
11950
|
*
|
|
11839
11951
|
* @param opts
|
|
11840
|
-
* opts.
|
|
11952
|
+
* opts.skipIfPristine = false persist all entities, even if not dirty
|
|
11841
11953
|
*/
|
|
11842
|
-
persist(opts) {
|
|
11954
|
+
persist(opts = { skipIfPristine: true }) {
|
|
11843
11955
|
return __awaiter(this, void 0, void 0, function* () {
|
|
11844
|
-
opts = Object.assign({ skipIfPristine: this.policy.skipNonLocalEntities }, opts);
|
|
11845
11956
|
// Skip is not dirty
|
|
11846
11957
|
if (opts.skipIfPristine && !this._dirty) {
|
|
11847
11958
|
console.debug(`[entity-storage] Persisting ${this.name} not need. Skip`);
|
|
@@ -12051,7 +12162,7 @@ class EntityStore {
|
|
|
12051
12162
|
if (variables.size === 0)
|
|
12052
12163
|
return { data: [], total };
|
|
12053
12164
|
// Sort by
|
|
12054
|
-
if (
|
|
12165
|
+
if (variables.sortBy) {
|
|
12055
12166
|
EntityUtils.sort(data, variables.sortBy, variables.sortDirection);
|
|
12056
12167
|
}
|
|
12057
12168
|
// Slice in a page (using offset and size)
|
|
@@ -12124,6 +12235,33 @@ class EntitiesStorage extends StartableService {
|
|
|
12124
12235
|
get dirty() {
|
|
12125
12236
|
return this._dirty || Object.values(this._data).some(store => store.dirty);
|
|
12126
12237
|
}
|
|
12238
|
+
ngOnStart() {
|
|
12239
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12240
|
+
const now = Date.now();
|
|
12241
|
+
console.info(`[entities-storage] Starting entity storage...`);
|
|
12242
|
+
// Restore stores
|
|
12243
|
+
yield this.restoreLocally();
|
|
12244
|
+
// Start a save timer
|
|
12245
|
+
this.registerSubscription(merge(this._$save, timer(this._saveTimerPeriod, this._saveTimerPeriod))
|
|
12246
|
+
.pipe(
|
|
12247
|
+
// Avoid to many call (e.g. when $save AND timer are triggered
|
|
12248
|
+
throttleTime(this._saveTimerPeriod))
|
|
12249
|
+
.subscribe(() => this.storeLocally({ skipIfPristine: true })));
|
|
12250
|
+
// Save, when platform is in pause
|
|
12251
|
+
this.registerSubscription(this.platform.pause.subscribe(() => __awaiter(this, void 0, void 0, function* () {
|
|
12252
|
+
console.warn(`[entities-storage] Platform will pause: saving...`);
|
|
12253
|
+
yield this.storeLocally({ skipIfPristine: true });
|
|
12254
|
+
console.warn(`[entities-storage] Platform will pause: saving [OK]`);
|
|
12255
|
+
})));
|
|
12256
|
+
console.info(`[entities-storage] Starting [OK] in ${Date.now() - now}ms`);
|
|
12257
|
+
return this._data;
|
|
12258
|
+
});
|
|
12259
|
+
}
|
|
12260
|
+
ngOnStop() {
|
|
12261
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
12262
|
+
yield this.storeLocally({ skipIfPristine: true });
|
|
12263
|
+
});
|
|
12264
|
+
}
|
|
12127
12265
|
watchAll(entityName, variables, opts) {
|
|
12128
12266
|
// Make sure store is ready
|
|
12129
12267
|
if (!this.started) {
|
|
@@ -12389,34 +12527,8 @@ class EntitiesStorage extends StartableService {
|
|
|
12389
12527
|
this._$save.emit();
|
|
12390
12528
|
});
|
|
12391
12529
|
}
|
|
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
|
-
});
|
|
12530
|
+
persist(opts = { skipIfPristine: true }) {
|
|
12531
|
+
return this.storeLocally(opts);
|
|
12420
12532
|
}
|
|
12421
12533
|
/* -- protected methods -- */
|
|
12422
12534
|
getEntityStore(name, opts) {
|
|
@@ -12455,9 +12567,9 @@ class EntitiesStorage extends StartableService {
|
|
|
12455
12567
|
console.debug(`[entities-storage] Restoring entities [OK] ${entitiesCount} entities found in ${Date.now() - now}ms`);
|
|
12456
12568
|
});
|
|
12457
12569
|
}
|
|
12458
|
-
storeLocally() {
|
|
12570
|
+
storeLocally(opts = { skipIfPristine: true }) {
|
|
12459
12571
|
return __awaiter(this, void 0, void 0, function* () {
|
|
12460
|
-
if (!this.dirty)
|
|
12572
|
+
if (opts.skipIfPristine && !this.dirty)
|
|
12461
12573
|
return; // skip
|
|
12462
12574
|
// Saving progress: report this save later
|
|
12463
12575
|
if (this._saving) {
|
|
@@ -12481,11 +12593,11 @@ class EntitiesStorage extends StartableService {
|
|
|
12481
12593
|
console.warn(`[entities-storage] Persisting ${entityName}: store not found!`);
|
|
12482
12594
|
return;
|
|
12483
12595
|
}
|
|
12484
|
-
// SKip store if
|
|
12485
|
-
if (!entityStore.dirty)
|
|
12486
|
-
return Promise.resolve();
|
|
12596
|
+
// SKip store if pristine
|
|
12597
|
+
if (opts.skipIfPristine && !entityStore.dirty)
|
|
12598
|
+
return Promise.resolve();
|
|
12487
12599
|
// Persist store
|
|
12488
|
-
return
|
|
12600
|
+
return entityStore.persist(opts)
|
|
12489
12601
|
.then(count => {
|
|
12490
12602
|
// If no entity found, remove from the entity names array
|
|
12491
12603
|
if (!count) {
|
|
@@ -12734,9 +12846,6 @@ class ReferentialUtils {
|
|
|
12734
12846
|
// A referential entity should always have a 'id' filled (can be negative is local and temporary)
|
|
12735
12847
|
return EntityUtils.isNotEmpty(obj, 'id');
|
|
12736
12848
|
}
|
|
12737
|
-
static isNotEmptyReferential(obj) {
|
|
12738
|
-
return EntityUtils.isNotEmpty(obj, 'id');
|
|
12739
|
-
}
|
|
12740
12849
|
static isEmpty(obj) {
|
|
12741
12850
|
return EntityUtils.isEmpty(obj, 'id');
|
|
12742
12851
|
}
|
|
@@ -14637,7 +14746,7 @@ class AccountService extends BaseGraphqlService {
|
|
|
14637
14746
|
return this._$additionalFields.getValue();
|
|
14638
14747
|
}
|
|
14639
14748
|
get $additionalFields() {
|
|
14640
|
-
return this._$additionalFields;
|
|
14749
|
+
return this._$additionalFields.asObservable();
|
|
14641
14750
|
}
|
|
14642
14751
|
getAdditionalField(key) {
|
|
14643
14752
|
return this._$additionalFields.getValue().find(f => f.key === key);
|
|
@@ -15684,6 +15793,196 @@ ConfigService.ctorParameters = () => [
|
|
|
15684
15793
|
{ type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [APP_CONFIG_OPTIONS,] }] }
|
|
15685
15794
|
];
|
|
15686
15795
|
|
|
15796
|
+
class UploadFile extends File {
|
|
15797
|
+
}
|
|
15798
|
+
class FileResponse {
|
|
15799
|
+
constructor(init) {
|
|
15800
|
+
this.type = HttpEventType.Response;
|
|
15801
|
+
this.body = isNotNil(init === null || init === void 0 ? void 0 : init.body) ? init.body : null;
|
|
15802
|
+
this.status = (init === null || init === void 0 ? void 0 : init.status) || 0;
|
|
15803
|
+
this.statusText = (init === null || init === void 0 ? void 0 : init.statusText) || 'OK';
|
|
15804
|
+
}
|
|
15805
|
+
}
|
|
15806
|
+
function isProgressEvent(event) {
|
|
15807
|
+
return event && (event.type === HttpEventType.UploadProgress
|
|
15808
|
+
|| event.type === HttpEventType.DownloadProgress);
|
|
15809
|
+
}
|
|
15810
|
+
function isResponseEvent(event) {
|
|
15811
|
+
return event && event.type === HttpEventType.Response;
|
|
15812
|
+
}
|
|
15813
|
+
|
|
15814
|
+
class UploadFilePopover {
|
|
15815
|
+
constructor(popoverController, translate, cd) {
|
|
15816
|
+
this.popoverController = popoverController;
|
|
15817
|
+
this.translate = translate;
|
|
15818
|
+
this.cd = cd;
|
|
15819
|
+
this.uniqueFile = false;
|
|
15820
|
+
this.instantUpload = false;
|
|
15821
|
+
this.importing = false;
|
|
15822
|
+
}
|
|
15823
|
+
get files() {
|
|
15824
|
+
return this.uploader.files;
|
|
15825
|
+
}
|
|
15826
|
+
get disabled() {
|
|
15827
|
+
return this.importing || isEmptyArray(this.files);
|
|
15828
|
+
}
|
|
15829
|
+
get valid() {
|
|
15830
|
+
return isNotEmptyArray(this.files);
|
|
15831
|
+
}
|
|
15832
|
+
onValidate(event) {
|
|
15833
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15834
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
15835
|
+
// Avoid multiple call
|
|
15836
|
+
if (this.importing)
|
|
15837
|
+
return;
|
|
15838
|
+
console.debug('[upload-file-popover] Validate form: will upload all files...');
|
|
15839
|
+
try {
|
|
15840
|
+
this.importing = true;
|
|
15841
|
+
this.resetError();
|
|
15842
|
+
try {
|
|
15843
|
+
// Wait processing files finished
|
|
15844
|
+
yield this.uploader.waitIdle();
|
|
15845
|
+
// upload all files
|
|
15846
|
+
yield this.uploader.uploadFiles();
|
|
15847
|
+
const files = (this.uploader.processedFiles || [])
|
|
15848
|
+
.filter(file => !file.deleting); // Remove deleting file (deletion in progress)
|
|
15849
|
+
// Nothing to upload: close popover
|
|
15850
|
+
if (isEmptyArray(files))
|
|
15851
|
+
return this.cancel();
|
|
15852
|
+
// check errors
|
|
15853
|
+
const errors = files.map(file => file.error).filter(isNotNilOrBlank);
|
|
15854
|
+
// If error: stop
|
|
15855
|
+
if (errors.length) {
|
|
15856
|
+
errors.forEach((error) => console.error(error));
|
|
15857
|
+
throw { message: 'FILE.UPLOAD.ERROR' };
|
|
15858
|
+
}
|
|
15859
|
+
// return files
|
|
15860
|
+
yield this.popoverController.dismiss(files);
|
|
15861
|
+
}
|
|
15862
|
+
catch (err) {
|
|
15863
|
+
this.error = (err && err.message) || err;
|
|
15864
|
+
}
|
|
15865
|
+
}
|
|
15866
|
+
finally {
|
|
15867
|
+
this.importing = false;
|
|
15868
|
+
this.cd.markForCheck();
|
|
15869
|
+
}
|
|
15870
|
+
});
|
|
15871
|
+
}
|
|
15872
|
+
cancel() {
|
|
15873
|
+
return this.popoverController.dismiss();
|
|
15874
|
+
}
|
|
15875
|
+
resetError() {
|
|
15876
|
+
if (this.error) {
|
|
15877
|
+
this.error = null;
|
|
15878
|
+
this.cd.markForCheck();
|
|
15879
|
+
}
|
|
15880
|
+
}
|
|
15881
|
+
}
|
|
15882
|
+
UploadFilePopover.decorators = [
|
|
15883
|
+
{ type: Component, args: [{
|
|
15884
|
+
selector: 'app-upload-file-popover',
|
|
15885
|
+
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",
|
|
15886
|
+
encapsulation: ViewEncapsulation.None,
|
|
15887
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
15888
|
+
styles: [".importing-info{-webkit-padding-start:var(--ion-padding);padding-inline-start:var(--ion-padding);display:inline-flex;flex-wrap:nowrap;padding-top:8px}"]
|
|
15889
|
+
},] }
|
|
15890
|
+
];
|
|
15891
|
+
UploadFilePopover.ctorParameters = () => [
|
|
15892
|
+
{ type: PopoverController },
|
|
15893
|
+
{ type: TranslateService },
|
|
15894
|
+
{ type: ChangeDetectorRef }
|
|
15895
|
+
];
|
|
15896
|
+
UploadFilePopover.propDecorators = {
|
|
15897
|
+
uploader: [{ type: ViewChild, args: ['uploader', { static: true },] }],
|
|
15898
|
+
fileExtension: [{ type: Input }],
|
|
15899
|
+
title: [{ type: Input }],
|
|
15900
|
+
uniqueFile: [{ type: Input }],
|
|
15901
|
+
instantUpload: [{ type: Input }],
|
|
15902
|
+
uploadFn: [{ type: Input }],
|
|
15903
|
+
deleteFn: [{ type: Input }],
|
|
15904
|
+
maxParallelUpload: [{ type: Input }]
|
|
15905
|
+
};
|
|
15906
|
+
|
|
15907
|
+
const MimeTypes = Object.freeze({
|
|
15908
|
+
ANDROID_APK: 'application/vnd.android.package-archive'
|
|
15909
|
+
});
|
|
15910
|
+
class FilesUtils {
|
|
15911
|
+
static showUploadPopover(popoverController, event, opts) {
|
|
15912
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
15913
|
+
const modal = yield popoverController.create({
|
|
15914
|
+
component: UploadFilePopover,
|
|
15915
|
+
componentProps: opts,
|
|
15916
|
+
backdropDismiss: false,
|
|
15917
|
+
keyboardClose: false,
|
|
15918
|
+
event,
|
|
15919
|
+
translucent: true,
|
|
15920
|
+
cssClass: 'popover-large',
|
|
15921
|
+
});
|
|
15922
|
+
yield modal.present();
|
|
15923
|
+
const { data, role } = yield modal.onDidDismiss();
|
|
15924
|
+
return {
|
|
15925
|
+
role,
|
|
15926
|
+
data: data ? data : undefined
|
|
15927
|
+
};
|
|
15928
|
+
});
|
|
15929
|
+
}
|
|
15930
|
+
static readAsText(file, encoding) {
|
|
15931
|
+
const $progress = new Subject();
|
|
15932
|
+
const reader = new FileReader();
|
|
15933
|
+
encoding = (encoding || 'UTF-8').toLowerCase();
|
|
15934
|
+
// Listen progress
|
|
15935
|
+
reader.onprogress = (e) => {
|
|
15936
|
+
const total = e.total || 1;
|
|
15937
|
+
const loaded = e.total || 0;
|
|
15938
|
+
if (loaded < total)
|
|
15939
|
+
$progress.next({ type: HttpEventType.UploadProgress, loaded, total });
|
|
15940
|
+
};
|
|
15941
|
+
// Listen end
|
|
15942
|
+
reader.onloadend = (e) => {
|
|
15943
|
+
const body = reader.result;
|
|
15944
|
+
if (typeof body === 'string') {
|
|
15945
|
+
$progress.next(new FileResponse({ body }));
|
|
15946
|
+
$progress.complete();
|
|
15947
|
+
}
|
|
15948
|
+
else {
|
|
15949
|
+
console.error(`Cannot read file '${file.name}' as text`);
|
|
15950
|
+
$progress.error(`Cannot read file as text`);
|
|
15951
|
+
}
|
|
15952
|
+
};
|
|
15953
|
+
// Listen error
|
|
15954
|
+
reader.onerror = (event) => {
|
|
15955
|
+
console.error('[files] Error while reading file:', event);
|
|
15956
|
+
$progress.error(event);
|
|
15957
|
+
};
|
|
15958
|
+
// Start reading the file
|
|
15959
|
+
reader.readAsText(file, encoding);
|
|
15960
|
+
return $progress.asObservable();
|
|
15961
|
+
}
|
|
15962
|
+
}
|
|
15963
|
+
class UriUtils {
|
|
15964
|
+
/**
|
|
15965
|
+
* Extract the filename, from an uri (using the last slash)
|
|
15966
|
+
* @param uri
|
|
15967
|
+
*/
|
|
15968
|
+
static getFilename(uri) {
|
|
15969
|
+
if (!uri)
|
|
15970
|
+
return uri;
|
|
15971
|
+
let filename = uri.trim();
|
|
15972
|
+
// Get last part (or all string, if no '/')
|
|
15973
|
+
const lastSlashIndex = filename.lastIndexOf('/');
|
|
15974
|
+
if (lastSlashIndex !== -1 && lastSlashIndex !== uri.length - 1) {
|
|
15975
|
+
filename = filename.substring(lastSlashIndex + 1);
|
|
15976
|
+
}
|
|
15977
|
+
// Remove query params
|
|
15978
|
+
const queryParamIndex = filename.indexOf('?');
|
|
15979
|
+
if (queryParamIndex !== -1) {
|
|
15980
|
+
filename = filename.substring(0, queryParamIndex);
|
|
15981
|
+
}
|
|
15982
|
+
return filename;
|
|
15983
|
+
}
|
|
15984
|
+
}
|
|
15985
|
+
|
|
15687
15986
|
const moment$4 = momentImported;
|
|
15688
15987
|
const AndroidOsEnvironment = Object.freeze({
|
|
15689
15988
|
DIRECTORY_DOWNLOADS: 'Download',
|
|
@@ -15720,7 +16019,7 @@ class PlatformService extends StartableService {
|
|
|
15720
16019
|
switch (platformName) {
|
|
15721
16020
|
case 'mobile':
|
|
15722
16021
|
case 'mobileweb':
|
|
15723
|
-
// Exclude Windows touch screens - see
|
|
16022
|
+
// Exclude Windows touch screens - see sumaris-app issues #323 and #346
|
|
15724
16023
|
return this.platform.is(platformName) && !isWindows(window);
|
|
15725
16024
|
default:
|
|
15726
16025
|
return this.platform.is(platformName);
|
|
@@ -15774,6 +16073,7 @@ class PlatformService extends StartableService {
|
|
|
15774
16073
|
this._cordova = this.is('cordova');
|
|
15775
16074
|
this._android = this.is('android');
|
|
15776
16075
|
this._ios = this.is('ios');
|
|
16076
|
+
this.configureClassList(this._mobile);
|
|
15777
16077
|
this.configureCordovaPlugins();
|
|
15778
16078
|
// Force some settings
|
|
15779
16079
|
this.settings.mobile = this._mobile;
|
|
@@ -15808,7 +16108,7 @@ class PlatformService extends StartableService {
|
|
|
15808
16108
|
this.accountService.tokenType = tokenType;
|
|
15809
16109
|
});
|
|
15810
16110
|
// Hide the splashscreen (if mobile) - after 1s - and play start sound
|
|
15811
|
-
if (this.
|
|
16111
|
+
if (this._mobile) {
|
|
15812
16112
|
setTimeout(() => {
|
|
15813
16113
|
var _a;
|
|
15814
16114
|
(_a = this.splashScreen) === null || _a === void 0 ? void 0 : _a.hide();
|
|
@@ -15844,34 +16144,48 @@ class PlatformService extends StartableService {
|
|
|
15844
16144
|
return this._downloadingJobs.get(uri);
|
|
15845
16145
|
}
|
|
15846
16146
|
download(request) {
|
|
16147
|
+
var _a, _b;
|
|
15847
16148
|
if (!request || !request.uri)
|
|
15848
16149
|
throw new Error('Missing argument \'request\' or \'request.uri\'');
|
|
15849
16150
|
if (this._android && this.downloader) {
|
|
15850
16151
|
// Check if not already downloading file
|
|
15851
|
-
let
|
|
15852
|
-
if (
|
|
15853
|
-
return
|
|
15854
|
-
|
|
15855
|
-
|
|
16152
|
+
let job$ = this._downloadingJobs.get(request.uri);
|
|
16153
|
+
if (job$)
|
|
16154
|
+
return job$;
|
|
16155
|
+
// Compute subPath (final filename)
|
|
16156
|
+
let subPath = ((_a = request.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.subPath) || ((_b = request.destinationInExternalFilesDir) === null || _b === void 0 ? void 0 : _b.subPath)
|
|
16157
|
+
|| request.filename || UriUtils.getFilename(request.uri)
|
|
16158
|
+
|| request.title || 'download';
|
|
16159
|
+
subPath = subPath.toLowerCase()
|
|
16160
|
+
// Remove spaces
|
|
16161
|
+
.replace(/\s+/g, '-');
|
|
16162
|
+
// Force APK to finish with '.apk'
|
|
16163
|
+
if (request.mimeType === MimeTypes.ANDROID_APK && !subPath.toLowerCase().endsWith('.apk')) {
|
|
16164
|
+
subPath += '.apk';
|
|
16165
|
+
}
|
|
16166
|
+
const downloadRequest = Object.assign(Object.assign({ visibleInDownloadsUi: true, notificationVisibility: NotificationVisibility.VisibleNotifyCompleted }, request), { filename: undefined, destinationInExternalPublicDir: !request.destinationInExternalFilesDir
|
|
16167
|
+
? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalPublicDir), { subPath }) : undefined, destinationInExternalFilesDir: request.destinationInExternalFilesDir
|
|
16168
|
+
? Object.assign(Object.assign({ dirType: AndroidOsEnvironment.DIRECTORY_DOWNLOADS }, request.destinationInExternalFilesDir), { subPath }) : undefined });
|
|
15856
16169
|
// Start download
|
|
15857
|
-
|
|
16170
|
+
console.debug('[platform] Downloading, using request: ' + JSON.stringify(downloadRequest));
|
|
16171
|
+
job$ = from(this.downloader.download(downloadRequest));
|
|
15858
16172
|
// Remember this request uri
|
|
15859
|
-
this._downloadingJobs.set(
|
|
15860
|
-
return
|
|
16173
|
+
this._downloadingJobs.set(downloadRequest.uri, job$);
|
|
16174
|
+
return job$
|
|
15861
16175
|
.pipe(tap(location => {
|
|
15862
16176
|
console.info('[platform] File successfully downloaded at:' + location);
|
|
15863
|
-
// Forget
|
|
15864
|
-
this._downloadingJobs.delete(
|
|
16177
|
+
// Forget job
|
|
16178
|
+
this._downloadingJobs.delete(downloadRequest.uri);
|
|
15865
16179
|
return location;
|
|
15866
16180
|
}), catchError(err => {
|
|
15867
16181
|
var _a;
|
|
15868
16182
|
console.error('[platform] Unable to download: ' + (err && err.message || err));
|
|
15869
16183
|
// Forget the request
|
|
15870
|
-
this._downloadingJobs.delete(
|
|
16184
|
+
this._downloadingJobs.delete(downloadRequest.uri);
|
|
15871
16185
|
// Retry with another location - issue in older Android version
|
|
15872
|
-
if (((_a =
|
|
15873
|
-
|
|
15874
|
-
return this.download(
|
|
16186
|
+
if (((_a = downloadRequest.destinationInExternalPublicDir) === null || _a === void 0 ? void 0 : _a.dirType) === AndroidOsEnvironment.DIRECTORY_DOWNLOADS) {
|
|
16187
|
+
downloadRequest.destinationInExternalPublicDir.dirType = AndroidOsEnvironment.DIRECTORY_DOWNLOADS_OLD;
|
|
16188
|
+
return this.download(downloadRequest);
|
|
15875
16189
|
}
|
|
15876
16190
|
throw err;
|
|
15877
16191
|
}));
|
|
@@ -15896,6 +16210,17 @@ class PlatformService extends StartableService {
|
|
|
15896
16210
|
//}
|
|
15897
16211
|
}
|
|
15898
16212
|
/* -- protected methods -- */
|
|
16213
|
+
configureClassList(mobile, win = window) {
|
|
16214
|
+
var _a, _b;
|
|
16215
|
+
if (mobile)
|
|
16216
|
+
return; // Nothing to do
|
|
16217
|
+
// Workaround, for MS Windows touch screen (detected as mobile, but forced as desktop)
|
|
16218
|
+
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')))) {
|
|
16219
|
+
console.warn('[platform] Force class list to: <html class="plt-desktop">. Workaround for Windows touch screen.');
|
|
16220
|
+
win.document.documentElement.classList.remove('plt-mobile', 'plt-mobileweb');
|
|
16221
|
+
win.document.documentElement.classList.add('plt-desktop');
|
|
16222
|
+
}
|
|
16223
|
+
}
|
|
15899
16224
|
configureCordovaPlugins() {
|
|
15900
16225
|
console.info('[platform] Configuring Cordova plugins...');
|
|
15901
16226
|
if (this.statusBar) {
|
|
@@ -16223,24 +16548,6 @@ MatStepperI18n.ctorParameters = () => [
|
|
|
16223
16548
|
{ type: TranslateService }
|
|
16224
16549
|
];
|
|
16225
16550
|
|
|
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
16551
|
class UploadFileComponent {
|
|
16245
16552
|
constructor(cd, translate) {
|
|
16246
16553
|
this.cd = cd;
|
|
@@ -16435,99 +16742,6 @@ UploadFileComponent.propDecorators = {
|
|
|
16435
16742
|
maxParallelUpload: [{ type: Input }]
|
|
16436
16743
|
};
|
|
16437
16744
|
|
|
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
16745
|
const APP_TESTING_PAGES = new InjectionToken('testingPages');
|
|
16532
16746
|
class SharedTestsPage {
|
|
16533
16747
|
constructor(route, router, translate, pages) {
|
|
@@ -16910,8 +17124,8 @@ class ComponentDirtyGuard {
|
|
|
16910
17124
|
}
|
|
16911
17125
|
canDeactivate(component, currentRoute, currentState, nextState) {
|
|
16912
17126
|
return __awaiter(this, void 0, void 0, function* () {
|
|
16913
|
-
const dirty = component.dirty;
|
|
16914
|
-
const valid = component.valid;
|
|
17127
|
+
const dirty = component === null || component === void 0 ? void 0 : component.dirty;
|
|
17128
|
+
const valid = component === null || component === void 0 ? void 0 : component.valid;
|
|
16915
17129
|
let can = {
|
|
16916
17130
|
confirmed: !dirty,
|
|
16917
17131
|
save: false,
|
|
@@ -17791,6 +18005,7 @@ class JobUtils {
|
|
|
17791
18005
|
return progression;
|
|
17792
18006
|
}
|
|
17793
18007
|
static fetchAllPages(loadPageFn, opts) {
|
|
18008
|
+
var _a, _b;
|
|
17794
18009
|
return __awaiter(this, void 0, void 0, function* () {
|
|
17795
18010
|
const maxProgression = toNumber(opts === null || opts === void 0 ? void 0 : opts.maxProgression, 100);
|
|
17796
18011
|
const progression = opts === null || opts === void 0 ? void 0 : opts.progression;
|
|
@@ -17823,7 +18038,7 @@ class JobUtils {
|
|
|
17823
18038
|
progressionStep = maxProgression / pageCount;
|
|
17824
18039
|
// DEBUG
|
|
17825
18040
|
if (opts && opts.logPrefix)
|
|
17826
|
-
console.debug(`${opts.logPrefix} {pageCount: ${pageCount},
|
|
18041
|
+
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
18042
|
}
|
|
17828
18043
|
}
|
|
17829
18044
|
// Increment progression on each iteration (if possible)
|
|
@@ -17850,7 +18065,7 @@ class JobUtils {
|
|
|
17850
18065
|
}
|
|
17851
18066
|
// DEBUG
|
|
17852
18067
|
if (opts && opts.logPrefix)
|
|
17853
|
-
console.debug(`${opts.logPrefix} All pages fetched - {
|
|
18068
|
+
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
18069
|
// Final increment
|
|
17855
18070
|
if (progression && progressionStep > 0) {
|
|
17856
18071
|
progression.next(progression.value + progressionStep);
|
|
@@ -17863,60 +18078,6 @@ class JobUtils {
|
|
|
17863
18078
|
}
|
|
17864
18079
|
}
|
|
17865
18080
|
|
|
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
18081
|
/**
|
|
17921
18082
|
* Define here theme colors
|
|
17922
18083
|
*/
|
|
@@ -18723,7 +18884,7 @@ HomePage.decorators = [
|
|
|
18723
18884
|
{ type: Component, args: [{
|
|
18724
18885
|
moduleId: module.id.toString(),
|
|
18725
18886
|
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
|
|
18887
|
+
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
18888
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
18728
18889
|
animations: [fadeInAnimation, slideUpDownAnimation],
|
|
18729
18890
|
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 +19131,9 @@ class AccountPage extends AppForm {
|
|
|
18970
19131
|
this.setValue(this.accountService.account);
|
|
18971
19132
|
this.markAsPristine();
|
|
18972
19133
|
}));
|
|
18973
|
-
this.registerSubscription(this.accountService.$additionalFields
|
|
18974
|
-
|
|
19134
|
+
this.registerSubscription(this.accountService.$additionalFields
|
|
19135
|
+
.subscribe((additionalFields) => {
|
|
19136
|
+
this.additionalFields = additionalFields.slice(); // Copy
|
|
18975
19137
|
if (accountService.isLogin()) {
|
|
18976
19138
|
this.onLogin(this.accountService.account);
|
|
18977
19139
|
}
|
|
@@ -19105,9 +19267,21 @@ class AccountPage extends AppForm {
|
|
|
19105
19267
|
this.form.controls.pubkey.disable();
|
|
19106
19268
|
// Always disable some additional fields
|
|
19107
19269
|
this.additionalFields
|
|
19108
|
-
.filter(field => field.extra && field.extra.account && field.extra.account.disabled || false)
|
|
19109
19270
|
.forEach(field => {
|
|
19110
|
-
|
|
19271
|
+
var _a, _b;
|
|
19272
|
+
const control = this.form.controls[field.key];
|
|
19273
|
+
if (!control)
|
|
19274
|
+
return; // Skip
|
|
19275
|
+
const disabled = ((_a = field.extra) === null || _a === void 0 ? void 0 : _a.account) && field.extra.account.disabled || false;
|
|
19276
|
+
if (disabled && control.enabled) {
|
|
19277
|
+
control.disable();
|
|
19278
|
+
}
|
|
19279
|
+
const required = ((_b = field.extra) === null || _b === void 0 ? void 0 : _b.account) && field.extra.account.required || false;
|
|
19280
|
+
if (!field.required && required) {
|
|
19281
|
+
control.setValidators(control.validator
|
|
19282
|
+
? Validators.compose([control.validator, Validators.required])
|
|
19283
|
+
: Validators.required);
|
|
19284
|
+
}
|
|
19111
19285
|
});
|
|
19112
19286
|
this.markForCheck();
|
|
19113
19287
|
}
|
|
@@ -19164,11 +19338,62 @@ EntityMetadataComponent.propDecorators = {
|
|
|
19164
19338
|
showRecorder: [{ type: Input }]
|
|
19165
19339
|
};
|
|
19166
19340
|
|
|
19341
|
+
const DEFAULT_MENU_SHOW_WHEN = 'lg';
|
|
19342
|
+
class MenuService {
|
|
19343
|
+
constructor() {
|
|
19344
|
+
this._$toggled = new Subject();
|
|
19345
|
+
this._$opened = new Subject();
|
|
19346
|
+
this._$splitPaneWhen = new BehaviorSubject(DEFAULT_MENU_SHOW_WHEN);
|
|
19347
|
+
this._$enabled = new BehaviorSubject(true);
|
|
19348
|
+
}
|
|
19349
|
+
get opened() {
|
|
19350
|
+
return this._$opened.asObservable();
|
|
19351
|
+
}
|
|
19352
|
+
get splitPaneWhen() {
|
|
19353
|
+
return this._$splitPaneWhen.asObservable();
|
|
19354
|
+
}
|
|
19355
|
+
get enabled() {
|
|
19356
|
+
return this._$enabled.asObservable();
|
|
19357
|
+
}
|
|
19358
|
+
toggle() {
|
|
19359
|
+
this._$toggled.next();
|
|
19360
|
+
}
|
|
19361
|
+
enable(value) {
|
|
19362
|
+
this._$enabled.next(value);
|
|
19363
|
+
}
|
|
19364
|
+
setSplitPaneShowWhen(value) {
|
|
19365
|
+
if (this._$splitPaneWhen.value !== value) {
|
|
19366
|
+
this._$splitPaneWhen.next(value);
|
|
19367
|
+
}
|
|
19368
|
+
}
|
|
19369
|
+
toggleSplitPaneWhen() {
|
|
19370
|
+
if (this._$splitPaneWhen.value !== false) {
|
|
19371
|
+
this._$splitPaneWhen.next(false);
|
|
19372
|
+
}
|
|
19373
|
+
else {
|
|
19374
|
+
this._$splitPaneWhen.next(DEFAULT_MENU_SHOW_WHEN);
|
|
19375
|
+
}
|
|
19376
|
+
}
|
|
19377
|
+
_markAsOpened() {
|
|
19378
|
+
this._$opened.next(true);
|
|
19379
|
+
}
|
|
19380
|
+
_markAsClosed() {
|
|
19381
|
+
this._$opened.next(false);
|
|
19382
|
+
}
|
|
19383
|
+
}
|
|
19384
|
+
MenuService.ɵprov = ɵɵdefineInjectable({ factory: function MenuService_Factory() { return new MenuService(); }, token: MenuService, providedIn: "root" });
|
|
19385
|
+
MenuService.decorators = [
|
|
19386
|
+
{ type: Injectable, args: [{
|
|
19387
|
+
providedIn: 'root'
|
|
19388
|
+
},] }
|
|
19389
|
+
];
|
|
19390
|
+
|
|
19167
19391
|
class FormButtonsBarToken {
|
|
19168
19392
|
}
|
|
19169
19393
|
class FormButtonsBarComponent {
|
|
19170
|
-
constructor(hotkeys) {
|
|
19394
|
+
constructor(hotkeys, menu) {
|
|
19171
19395
|
this.hotkeys = hotkeys;
|
|
19396
|
+
this.menu = menu;
|
|
19172
19397
|
this._subscription = new Subscription();
|
|
19173
19398
|
this.disabled = false;
|
|
19174
19399
|
this.disabledCancel = false;
|
|
@@ -19200,15 +19425,16 @@ class FormButtonsBarComponent {
|
|
|
19200
19425
|
FormButtonsBarComponent.decorators = [
|
|
19201
19426
|
{ type: Component, args: [{
|
|
19202
19427
|
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",
|
|
19428
|
+
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
19429
|
providers: [
|
|
19205
19430
|
{ provide: FormButtonsBarToken, useExisting: FormButtonsBarComponent }
|
|
19206
19431
|
],
|
|
19207
|
-
styles: [":host{width:100%}:host ion-toolbar{height:var(--app-form-buttons-bar-height);padding:0 6px}:host ion-col{padding:0}"]
|
|
19432
|
+
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
19433
|
},] }
|
|
19209
19434
|
];
|
|
19210
19435
|
FormButtonsBarComponent.ctorParameters = () => [
|
|
19211
|
-
{ type: Hotkeys }
|
|
19436
|
+
{ type: Hotkeys },
|
|
19437
|
+
{ type: MenuService }
|
|
19212
19438
|
];
|
|
19213
19439
|
FormButtonsBarComponent.propDecorators = {
|
|
19214
19440
|
disabled: [{ type: Input }],
|
|
@@ -20084,7 +20310,7 @@ AppListForm.decorators = [
|
|
|
20084
20310
|
selector: 'app-list-form',
|
|
20085
20311
|
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
20312
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20087
|
-
styles: [":host{--ion-item-background-selected:var(--ion-color-secondary100);--ion-item-
|
|
20313
|
+
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
20314
|
},] }
|
|
20089
20315
|
];
|
|
20090
20316
|
AppListForm.ctorParameters = () => [
|
|
@@ -20145,9 +20371,6 @@ PersonToStringPipe.decorators = [
|
|
|
20145
20371
|
{ type: Injectable, args: [{ providedIn: 'root' },] }
|
|
20146
20372
|
];
|
|
20147
20373
|
|
|
20148
|
-
const MimeTypes = Object.freeze({
|
|
20149
|
-
ANDROID_APK: 'application/vnd.android.package-archive'
|
|
20150
|
-
});
|
|
20151
20374
|
class AppInstallUpgradeCard {
|
|
20152
20375
|
constructor(modalCtrl, configService, toastController, alertController, translate, cd, platform, network, environment) {
|
|
20153
20376
|
this.modalCtrl = modalCtrl;
|
|
@@ -20160,7 +20383,6 @@ class AppInstallUpgradeCard {
|
|
|
20160
20383
|
this.network = network;
|
|
20161
20384
|
this.environment = environment;
|
|
20162
20385
|
this._subscription = new Subscription();
|
|
20163
|
-
this._showUpdateOfflineFeature = false;
|
|
20164
20386
|
this.loading = true;
|
|
20165
20387
|
this.hasDownloader = false;
|
|
20166
20388
|
this.downloading = false;
|
|
@@ -20168,16 +20390,6 @@ class AppInstallUpgradeCard {
|
|
|
20168
20390
|
this.showUpgradeWarning = true;
|
|
20169
20391
|
this.showOfflineWarning = true;
|
|
20170
20392
|
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
20393
|
}
|
|
20182
20394
|
ngOnInit() {
|
|
20183
20395
|
this.offline = this.network.offline;
|
|
@@ -20201,7 +20413,6 @@ class AppInstallUpgradeCard {
|
|
|
20201
20413
|
ngOnDestroy() {
|
|
20202
20414
|
this._subscription.unsubscribe();
|
|
20203
20415
|
this._subscription = null;
|
|
20204
|
-
this.onUpdateOfflineModeClick.complete();
|
|
20205
20416
|
this.installLinks = null;
|
|
20206
20417
|
this.upgradeLinks = null;
|
|
20207
20418
|
}
|
|
@@ -20352,10 +20563,10 @@ class AppInstallUpgradeCard {
|
|
|
20352
20563
|
let title;
|
|
20353
20564
|
let mimeType;
|
|
20354
20565
|
// Get file name
|
|
20355
|
-
let filename =
|
|
20566
|
+
let filename = UriUtils.getFilename(url);
|
|
20356
20567
|
let version = minVersion || 'latest';
|
|
20357
20568
|
// 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')) {
|
|
20569
|
+
if (filename === null || filename === void 0 ? void 0 : filename.toLowerCase().endsWith('.apk')) {
|
|
20359
20570
|
// Define mime type
|
|
20360
20571
|
mimeType = MimeTypes.ANDROID_APK;
|
|
20361
20572
|
// Get the file version (if any)
|
|
@@ -20366,11 +20577,9 @@ class AppInstallUpgradeCard {
|
|
|
20366
20577
|
filename = `${name}-v${version}.apk`.toLowerCase();
|
|
20367
20578
|
title = `${name} v${version}`;
|
|
20368
20579
|
}
|
|
20369
|
-
|
|
20370
|
-
|
|
20371
|
-
|
|
20372
|
-
filename = filename.replace('latest', version);
|
|
20373
|
-
}
|
|
20580
|
+
// Replace 'latest' with the app version, if present in the filename
|
|
20581
|
+
else if (filename.indexOf('latest') && version !== 'latest') {
|
|
20582
|
+
filename = filename.replace('latest', version);
|
|
20374
20583
|
}
|
|
20375
20584
|
}
|
|
20376
20585
|
result.push({ name, url, platform: 'android', version, filename, title, mimeType });
|
|
@@ -20382,18 +20591,6 @@ class AppInstallUpgradeCard {
|
|
|
20382
20591
|
//}
|
|
20383
20592
|
return result;
|
|
20384
20593
|
}
|
|
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
20594
|
listenDownloadJobs() {
|
|
20398
20595
|
// Listening downloading promise, if exists
|
|
20399
20596
|
(this.upgradeLinks || []).forEach(link => {
|
|
@@ -20491,7 +20688,7 @@ class AppInstallUpgradeCard {
|
|
|
20491
20688
|
AppInstallUpgradeCard.decorators = [
|
|
20492
20689
|
{ type: Component, args: [{
|
|
20493
20690
|
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<!--
|
|
20691
|
+
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
20692
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20496
20693
|
animations: [slideUpDownAnimation],
|
|
20497
20694
|
styles: ["ion-text small{font-size:85%}"]
|
|
@@ -20512,9 +20709,7 @@ AppInstallUpgradeCard.propDecorators = {
|
|
|
20512
20709
|
isLogin: [{ type: Input }],
|
|
20513
20710
|
showUpgradeWarning: [{ type: Input }],
|
|
20514
20711
|
showOfflineWarning: [{ type: Input }],
|
|
20515
|
-
showInstallButton: [{ type: Input }]
|
|
20516
|
-
showUpdateOfflineFeature: [{ type: Input }],
|
|
20517
|
-
onUpdateOfflineModeClick: [{ type: Output }]
|
|
20712
|
+
showInstallButton: [{ type: Input }]
|
|
20518
20713
|
};
|
|
20519
20714
|
|
|
20520
20715
|
class IsLoginAccountPipe {
|
|
@@ -20627,33 +20822,7 @@ ActionsColumnComponent.propDecorators = {
|
|
|
20627
20822
|
forward: [{ type: Output }]
|
|
20628
20823
|
};
|
|
20629
20824
|
|
|
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
20825
|
const APP_MENU_ITEMS = new InjectionToken('menuItems');
|
|
20656
|
-
const SPLIT_PANE_SHOW_WHEN = 'lg';
|
|
20657
20826
|
class MenuComponent {
|
|
20658
20827
|
constructor(platformService, accountService, router, menu, modalCtrl, alertController, translate, configService, cd, menuService, environment, items) {
|
|
20659
20828
|
this.platformService = platformService;
|
|
@@ -20672,28 +20841,35 @@ class MenuComponent {
|
|
|
20672
20841
|
this.loading = true;
|
|
20673
20842
|
this.isLogin = false;
|
|
20674
20843
|
this.$items = new BehaviorSubject(undefined);
|
|
20675
|
-
this.
|
|
20844
|
+
this.id = 'menu';
|
|
20845
|
+
this.menuId = 'left';
|
|
20676
20846
|
this.side = 'left';
|
|
20847
|
+
this.contentId = 'menu-content';
|
|
20848
|
+
this.appVersion = this.environment.version;
|
|
20677
20849
|
this._debug = !environment.production;
|
|
20678
20850
|
}
|
|
20679
20851
|
ngOnInit() {
|
|
20680
20852
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20681
|
-
this.
|
|
20682
|
-
this.splitPane.when = SPLIT_PANE_SHOW_WHEN;
|
|
20853
|
+
this.splitPane.when = yield firstNotNilPromise(this.menuService.splitPaneWhen);
|
|
20683
20854
|
// Wait platform started
|
|
20684
20855
|
yield this.platformService.ready();
|
|
20685
|
-
this.splitPaneOpened = true;
|
|
20686
20856
|
// Listen to menu service event
|
|
20687
|
-
this.menuService.
|
|
20688
|
-
.subscribe(() => this.
|
|
20857
|
+
this.menuService.splitPaneWhen
|
|
20858
|
+
.subscribe((value) => this.setSplitPaneWhen(value));
|
|
20859
|
+
this.menuService.enabled
|
|
20860
|
+
.subscribe((value) => this.enable(value));
|
|
20861
|
+
this.menuService.opened
|
|
20862
|
+
// Avoid duplicated events
|
|
20863
|
+
.pipe(distinctUntilChanged())
|
|
20864
|
+
.subscribe((value) => value ? this.open() : this.close());
|
|
20689
20865
|
// Update component when refresh is need (=login events or config changed)
|
|
20690
20866
|
this._subscription.add(merge(this.accountService.onLogin, this.accountService.onLogout, this.configService.config
|
|
20691
20867
|
.pipe(tap(config => this._config = config)))
|
|
20692
20868
|
.pipe(
|
|
20693
20869
|
// Wait account service ready (can be restarted)
|
|
20694
|
-
mergeMap(() => this.accountService.ready()))
|
|
20695
|
-
.subscribe(
|
|
20696
|
-
if (
|
|
20870
|
+
mergeMap(() => this.accountService.ready()), map(() => this.accountService.isLogin()), distinctUntilChanged())
|
|
20871
|
+
.subscribe(login => {
|
|
20872
|
+
if (login) {
|
|
20697
20873
|
this.onLogin(this.accountService.account);
|
|
20698
20874
|
}
|
|
20699
20875
|
else {
|
|
@@ -20721,8 +20897,6 @@ class MenuComponent {
|
|
|
20721
20897
|
if (!skipRedirect)
|
|
20722
20898
|
console.debug('[menu] logout');
|
|
20723
20899
|
this.isLogin = false;
|
|
20724
|
-
//this.splitPaneOpened = false;
|
|
20725
|
-
//this.splitPane.when = false;
|
|
20726
20900
|
this.accountAvatar = null;
|
|
20727
20901
|
this.accountEmail = null;
|
|
20728
20902
|
this.accountName = null;
|
|
@@ -20751,7 +20925,8 @@ class MenuComponent {
|
|
|
20751
20925
|
text: translations['COMMON.BTN_CANCEL'],
|
|
20752
20926
|
role: 'cancel',
|
|
20753
20927
|
cssClass: 'secondary'
|
|
20754
|
-
},
|
|
20928
|
+
},
|
|
20929
|
+
{
|
|
20755
20930
|
text: translations['AUTH.LOGOUT.BTN_CONFIRM'],
|
|
20756
20931
|
cssClass: 'ion-color-primary',
|
|
20757
20932
|
handler: () => {
|
|
@@ -20766,9 +20941,40 @@ class MenuComponent {
|
|
|
20766
20941
|
yield alert.present();
|
|
20767
20942
|
});
|
|
20768
20943
|
}
|
|
20769
|
-
|
|
20944
|
+
enable(value) {
|
|
20945
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20946
|
+
const enabled = yield this.menu.isEnabled(this.menuId);
|
|
20947
|
+
if (enabled !== value) {
|
|
20948
|
+
yield this.menu.enable(value, this.menuId);
|
|
20949
|
+
if (!value)
|
|
20950
|
+
yield this.close();
|
|
20951
|
+
}
|
|
20952
|
+
});
|
|
20953
|
+
}
|
|
20954
|
+
open() {
|
|
20955
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20956
|
+
console.debug('[menu] Checking open event...');
|
|
20957
|
+
const opened = yield this.menu.isOpen(this.menuId);
|
|
20958
|
+
if (!opened) {
|
|
20959
|
+
console.debug('[menu] Opening menu');
|
|
20960
|
+
yield this.menu.open(this.menuId);
|
|
20961
|
+
// Propage to service
|
|
20962
|
+
this.menuService._markAsOpened();
|
|
20963
|
+
}
|
|
20964
|
+
return true;
|
|
20965
|
+
});
|
|
20966
|
+
}
|
|
20967
|
+
close() {
|
|
20770
20968
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20771
|
-
|
|
20969
|
+
console.debug('[menu] Checking close event...');
|
|
20970
|
+
const opened = yield this.menu.isOpen(this.menuId);
|
|
20971
|
+
if (opened) {
|
|
20972
|
+
console.debug('[menu] Closing menu');
|
|
20973
|
+
yield this.menu.close(this.menuId);
|
|
20974
|
+
// Propage to service
|
|
20975
|
+
this.menuService._markAsClosed();
|
|
20976
|
+
}
|
|
20977
|
+
return true;
|
|
20772
20978
|
});
|
|
20773
20979
|
}
|
|
20774
20980
|
openAboutModal(event) {
|
|
@@ -20777,24 +20983,33 @@ class MenuComponent {
|
|
|
20777
20983
|
return modal.present();
|
|
20778
20984
|
});
|
|
20779
20985
|
}
|
|
20780
|
-
|
|
20986
|
+
setSplitPaneWhen(value) {
|
|
20987
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
20988
|
+
console.debug('[menu] Checking splitPane when...');
|
|
20989
|
+
if (this.splitPane.when !== value) {
|
|
20990
|
+
console.debug('[menu] Set splitPane when to ' + value);
|
|
20991
|
+
this.splitPane.when = value;
|
|
20992
|
+
this.detectChanges();
|
|
20993
|
+
// Propagate to the menu service
|
|
20994
|
+
setTimeout(() => this.menuService.setSplitPaneShowWhen(value), 200);
|
|
20995
|
+
}
|
|
20996
|
+
});
|
|
20997
|
+
}
|
|
20998
|
+
toggleSplitPaneShow(event) {
|
|
20781
20999
|
if (event && event.defaultPrevented)
|
|
20782
21000
|
return;
|
|
20783
21001
|
if (event)
|
|
20784
21002
|
event.preventDefault();
|
|
20785
|
-
this.
|
|
20786
|
-
|
|
20787
|
-
this.splitPane.when = false;
|
|
21003
|
+
if (this.splitPane.when === false) {
|
|
21004
|
+
return this.setSplitPaneWhen(DEFAULT_MENU_SHOW_WHEN);
|
|
20788
21005
|
}
|
|
20789
21006
|
else {
|
|
20790
|
-
this.
|
|
21007
|
+
return this.setSplitPaneWhen(false);
|
|
20791
21008
|
}
|
|
20792
|
-
this.menuService.menuVisible(this.splitPaneOpened);
|
|
20793
|
-
this.detectChanges();
|
|
20794
21009
|
}
|
|
20795
21010
|
doAction(action, event) {
|
|
20796
21011
|
return __awaiter(this, void 0, void 0, function* () {
|
|
20797
|
-
this.
|
|
21012
|
+
this.close();
|
|
20798
21013
|
switch (action) {
|
|
20799
21014
|
case 'logout':
|
|
20800
21015
|
yield this.logout();
|
|
@@ -20880,7 +21095,7 @@ class MenuComponent {
|
|
|
20880
21095
|
MenuComponent.decorators = [
|
|
20881
21096
|
{ type: Component, args: [{
|
|
20882
21097
|
selector: 'app-menu',
|
|
20883
|
-
template: "<ion-split-pane #splitPane contentId=\"
|
|
21098
|
+
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
21099
|
animations: [fadeInAnimation],
|
|
20885
21100
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
20886
21101
|
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 +21116,13 @@ MenuComponent.ctorParameters = () => [
|
|
|
20901
21116
|
{ type: Array, decorators: [{ type: Optional }, { type: Inject, args: [APP_MENU_ITEMS,] }] }
|
|
20902
21117
|
];
|
|
20903
21118
|
MenuComponent.propDecorators = {
|
|
21119
|
+
id: [{ type: Input }],
|
|
21120
|
+
menuId: [{ type: Input }],
|
|
21121
|
+
side: [{ type: Input }],
|
|
21122
|
+
contentId: [{ type: Input }],
|
|
20904
21123
|
logo: [{ type: Input }],
|
|
20905
21124
|
appName: [{ type: Input }],
|
|
20906
21125
|
appVersion: [{ type: Input }],
|
|
20907
|
-
side: [{ type: Input }],
|
|
20908
21126
|
splitPane: [{ type: ViewChild, args: ['splitPane', { static: true },] }]
|
|
20909
21127
|
};
|
|
20910
21128
|
|
|
@@ -20958,6 +21176,30 @@ AppIconComponent.propDecorators = {
|
|
|
20958
21176
|
ref: [{ type: Input }]
|
|
20959
21177
|
};
|
|
20960
21178
|
|
|
21179
|
+
class AppUpdateOfflineModeCard {
|
|
21180
|
+
constructor() {
|
|
21181
|
+
this.onUpdateClick = new EventEmitter();
|
|
21182
|
+
}
|
|
21183
|
+
ngOnDestroy() {
|
|
21184
|
+
this.onUpdateClick.complete();
|
|
21185
|
+
}
|
|
21186
|
+
}
|
|
21187
|
+
AppUpdateOfflineModeCard.decorators = [
|
|
21188
|
+
{ type: Component, args: [{
|
|
21189
|
+
selector: 'app-update-offline-mode-card',
|
|
21190
|
+
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",
|
|
21191
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
21192
|
+
animations: [slideUpDownAnimation],
|
|
21193
|
+
styles: ["ion-text small{font-size:85%}"]
|
|
21194
|
+
},] }
|
|
21195
|
+
];
|
|
21196
|
+
AppUpdateOfflineModeCard.ctorParameters = () => [];
|
|
21197
|
+
AppUpdateOfflineModeCard.propDecorators = {
|
|
21198
|
+
progressionMessage: [{ type: Input }],
|
|
21199
|
+
progressionValue: [{ type: Input }],
|
|
21200
|
+
onUpdateClick: [{ type: Output }]
|
|
21201
|
+
};
|
|
21202
|
+
|
|
20961
21203
|
class CoreModule {
|
|
20962
21204
|
static forRoot() {
|
|
20963
21205
|
console.info('[core] Creating module (root)');
|
|
@@ -20978,7 +21220,6 @@ CoreModule.decorators = [
|
|
|
20978
21220
|
CacheModule,
|
|
20979
21221
|
IonicStorageModule,
|
|
20980
21222
|
NgxJdenticonModule,
|
|
20981
|
-
TranslateModule.forChild(),
|
|
20982
21223
|
// Sub modules
|
|
20983
21224
|
AppGraphQLModule,
|
|
20984
21225
|
AppMenuModule
|
|
@@ -21005,6 +21246,7 @@ CoreModule.decorators = [
|
|
|
21005
21246
|
// Network
|
|
21006
21247
|
SelectPeerModal,
|
|
21007
21248
|
AppInstallUpgradeCard,
|
|
21249
|
+
AppUpdateOfflineModeCard,
|
|
21008
21250
|
// Other components
|
|
21009
21251
|
TableSelectColumnsComponent,
|
|
21010
21252
|
ActionsColumnComponent,
|
|
@@ -21040,6 +21282,7 @@ CoreModule.decorators = [
|
|
|
21040
21282
|
AppPropertiesForm,
|
|
21041
21283
|
AppListForm,
|
|
21042
21284
|
AppInstallUpgradeCard,
|
|
21285
|
+
AppUpdateOfflineModeCard,
|
|
21043
21286
|
DepartmentToStringPipe,
|
|
21044
21287
|
AppIconComponent,
|
|
21045
21288
|
TextPopover,
|
|
@@ -21048,6 +21291,9 @@ CoreModule.decorators = [
|
|
|
21048
21291
|
},] }
|
|
21049
21292
|
];
|
|
21050
21293
|
|
|
21294
|
+
const moment$5 = momentImported;
|
|
21295
|
+
const tz = momentTZImported;
|
|
21296
|
+
|
|
21051
21297
|
class AuthGuardService {
|
|
21052
21298
|
constructor(accountService, modalCtrl, router, environment) {
|
|
21053
21299
|
this.accountService = accountService;
|
|
@@ -21567,6 +21813,8 @@ class AppTableUtils {
|
|
|
21567
21813
|
}
|
|
21568
21814
|
}
|
|
21569
21815
|
|
|
21816
|
+
class AppTableDataSourceOptions {
|
|
21817
|
+
}
|
|
21570
21818
|
// @dynamic
|
|
21571
21819
|
// eslint-disable-next-line @angular-eslint/directive-class-suffix
|
|
21572
21820
|
class EntitiesTableDataSource extends TableDataSource {
|
|
@@ -21575,27 +21823,34 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21575
21823
|
*
|
|
21576
21824
|
* @param dataService A service to load and save data
|
|
21577
21825
|
* @param dataType Type of data contained by the Table. If not specified, then `data` with at least one element must be specified.
|
|
21826
|
+
* @param environment
|
|
21578
21827
|
* @param validatorService Service that create instances of the FormGroup used to validate row fields.
|
|
21579
21828
|
* @param config Additional configuration for table.
|
|
21580
21829
|
*/
|
|
21581
21830
|
constructor(dataType, dataService, validatorService, config) {
|
|
21582
|
-
super([], dataType, validatorService,
|
|
21831
|
+
super([], dataType, validatorService, config);
|
|
21583
21832
|
this.dataService = dataService;
|
|
21584
21833
|
this._creating = false;
|
|
21585
21834
|
this._saving = false;
|
|
21835
|
+
this._useValidator = false;
|
|
21586
21836
|
this._stopWatching$ = new Subject();
|
|
21587
21837
|
this._editingRowCount = 0;
|
|
21588
21838
|
this._fetchMoreFn = null;
|
|
21589
21839
|
this.loadingSubject = new BehaviorSubject(undefined);
|
|
21840
|
+
this._options = Object.assign({ dataServiceOptions: {}, debug: config && config.suppressErrors === false, keepOriginalDataAfterConfirm: false }, config);
|
|
21841
|
+
this._useValidator = isNotNil(validatorService);
|
|
21590
21842
|
this._logTypeName = removeEnd((new dataType()).__typename || 'UnknownVO', 'VO');
|
|
21591
21843
|
// For DEV ONLY
|
|
21592
|
-
this._debug = this.
|
|
21844
|
+
this._debug = this._options.debug === true;
|
|
21593
21845
|
}
|
|
21594
21846
|
get serviceOptions() {
|
|
21595
|
-
return this.
|
|
21847
|
+
return this._options.dataServiceOptions;
|
|
21596
21848
|
}
|
|
21597
21849
|
set serviceOptions(value) {
|
|
21598
|
-
this.
|
|
21850
|
+
this._options.dataServiceOptions = value;
|
|
21851
|
+
}
|
|
21852
|
+
get options() {
|
|
21853
|
+
return this._options;
|
|
21599
21854
|
}
|
|
21600
21855
|
get loaded() {
|
|
21601
21856
|
return this.loadingSubject.value === false; // Should be false when undefined (initial state)
|
|
@@ -21603,11 +21858,12 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21603
21858
|
get loading() {
|
|
21604
21859
|
return this.loadingSubject.value !== false; // Should be true when undefined (initial state)
|
|
21605
21860
|
}
|
|
21606
|
-
|
|
21607
|
-
super.disconnect(collectionViewer);
|
|
21861
|
+
ngOnDestroy() {
|
|
21608
21862
|
this._stopWatching$.next();
|
|
21609
21863
|
this._stopWatching$.complete();
|
|
21864
|
+
this._stopWatching$.unsubscribe();
|
|
21610
21865
|
this.loadingSubject.complete();
|
|
21866
|
+
this.loadingSubject.unsubscribe();
|
|
21611
21867
|
}
|
|
21612
21868
|
watchAll(offset, size, sortBy, sortDirection, filter) {
|
|
21613
21869
|
this._stopWatching$.next();
|
|
@@ -21651,26 +21907,27 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21651
21907
|
// Get all rows
|
|
21652
21908
|
const rows = yield this.getRows();
|
|
21653
21909
|
// Finish editing all rows
|
|
21654
|
-
const
|
|
21910
|
+
const invalidRows = rows.filter(row => row.editing && !row.confirmEditCreate());
|
|
21655
21911
|
// Cannot finish some rows: error
|
|
21656
|
-
if (
|
|
21912
|
+
if (invalidRows.length) {
|
|
21657
21913
|
// log errors
|
|
21658
21914
|
if (this._debug)
|
|
21659
|
-
|
|
21915
|
+
invalidRows.forEach(row => AppTableUtils.logRowErrors(row, `[table-datasource] ${this._logTypeName} row #${row.id}`));
|
|
21660
21916
|
// Stop with an error
|
|
21661
21917
|
throw { code: ErrorCodes.TABLE_INVALID_ROW_ERROR, message: 'ERROR.TABLE_INVALID_ROW_ERROR' };
|
|
21662
21918
|
}
|
|
21663
21919
|
this._editingRowCount = 0;
|
|
21664
21920
|
let data;
|
|
21665
21921
|
let dataToSave;
|
|
21666
|
-
if (
|
|
21922
|
+
if (this._useValidator) {
|
|
21667
21923
|
dataToSave = [];
|
|
21668
21924
|
data = rows.map(row => {
|
|
21669
|
-
const
|
|
21925
|
+
const currentData = new this.dataConstructor();
|
|
21926
|
+
currentData.fromObject(row.currentData);
|
|
21670
21927
|
// Filter to keep only dirty row
|
|
21671
21928
|
if (onlyDirtyRows && row.validator.dirty)
|
|
21672
|
-
dataToSave.push(
|
|
21673
|
-
return
|
|
21929
|
+
dataToSave.push(currentData);
|
|
21930
|
+
return currentData;
|
|
21674
21931
|
});
|
|
21675
21932
|
if (!onlyDirtyRows)
|
|
21676
21933
|
dataToSave = data;
|
|
@@ -21707,33 +21964,25 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21707
21964
|
}
|
|
21708
21965
|
});
|
|
21709
21966
|
}
|
|
21710
|
-
|
|
21711
|
-
if (
|
|
21712
|
-
|
|
21713
|
-
|
|
21967
|
+
updateDatasource(data, opts) {
|
|
21968
|
+
if (this._debug)
|
|
21969
|
+
console.debug(`[table-datasource] Updating datasource with data:`, data);
|
|
21970
|
+
super.updateDatasource(data, opts);
|
|
21971
|
+
if (!opts || opts.emitEvent !== false) {
|
|
21972
|
+
this.markAsLoaded();
|
|
21714
21973
|
}
|
|
21715
|
-
return super.getDataFromRows(rows, options);
|
|
21716
21974
|
}
|
|
21717
|
-
|
|
21718
|
-
|
|
21719
|
-
|
|
21720
|
-
entity.fromObject(data);
|
|
21721
|
-
return entity;
|
|
21722
|
-
}
|
|
21723
|
-
return data;
|
|
21975
|
+
// Overwrite default signature
|
|
21976
|
+
createNew(insertAt) {
|
|
21977
|
+
this.asyncCreateNew(insertAt);
|
|
21724
21978
|
}
|
|
21725
|
-
|
|
21726
|
-
|
|
21727
|
-
|
|
21728
|
-
|
|
21729
|
-
|
|
21730
|
-
|
|
21731
|
-
|
|
21732
|
-
yield _super.updateDatasource.call(this, data, opts);
|
|
21733
|
-
if (opts.emitEvent) {
|
|
21734
|
-
this.markAsLoaded();
|
|
21735
|
-
}
|
|
21736
|
-
});
|
|
21979
|
+
connect(collectionViewer) {
|
|
21980
|
+
// DEBUG console.debug("[entities-datasource] connect");
|
|
21981
|
+
return super.connect(collectionViewer);
|
|
21982
|
+
}
|
|
21983
|
+
disconnect(collectionViewer) {
|
|
21984
|
+
super.disconnect(collectionViewer);
|
|
21985
|
+
this._stopWatching$.next();
|
|
21737
21986
|
}
|
|
21738
21987
|
waitIdle(debounceTimeMs) {
|
|
21739
21988
|
return firstFalsePromise(this.loadingSubject
|
|
@@ -21742,60 +21991,34 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21742
21991
|
));
|
|
21743
21992
|
}
|
|
21744
21993
|
confirmCreate(row) {
|
|
21745
|
-
|
|
21746
|
-
|
|
21747
|
-
|
|
21748
|
-
|
|
21749
|
-
|
|
21750
|
-
|
|
21751
|
-
|
|
21752
|
-
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
21753
|
-
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
21754
|
-
}
|
|
21755
|
-
return true;
|
|
21756
|
-
});
|
|
21994
|
+
if (!super.confirmCreate(row))
|
|
21995
|
+
return false;
|
|
21996
|
+
if (row.editing && row.validator) {
|
|
21997
|
+
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
21998
|
+
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
21999
|
+
}
|
|
22000
|
+
return true;
|
|
21757
22001
|
}
|
|
21758
22002
|
confirmEdit(row) {
|
|
21759
|
-
|
|
21760
|
-
|
|
21761
|
-
|
|
21762
|
-
|
|
21763
|
-
|
|
21764
|
-
|
|
21765
|
-
|
|
21766
|
-
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
21767
|
-
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
21768
|
-
}
|
|
21769
|
-
return true;
|
|
21770
|
-
});
|
|
22003
|
+
if (!super.confirmEdit(row))
|
|
22004
|
+
return false;
|
|
22005
|
+
if (row.editing && row.validator) {
|
|
22006
|
+
console.warn('[table-datasource] Row still has {editing: true} after confirmCreate()! Force editing to false');
|
|
22007
|
+
row.validator.disable({ onlySelf: true, emitEvent: false });
|
|
22008
|
+
}
|
|
22009
|
+
return true;
|
|
21771
22010
|
}
|
|
21772
22011
|
startEdit(row) {
|
|
21773
|
-
|
|
21774
|
-
|
|
21775
|
-
|
|
21776
|
-
|
|
21777
|
-
if (row.editing)
|
|
21778
|
-
return; // Already editing
|
|
21779
|
-
if (this._debug)
|
|
21780
|
-
console.debug('[table-datasource] Start to edit row', row);
|
|
21781
|
-
const done = yield _super.startEdit.call(this, row);
|
|
21782
|
-
if (done)
|
|
21783
|
-
this._editingRowCount++;
|
|
21784
|
-
return done;
|
|
21785
|
-
});
|
|
22012
|
+
if (this._debug)
|
|
22013
|
+
console.debug('[table-datasource] Start to edit row', row);
|
|
22014
|
+
row.startEdit();
|
|
22015
|
+
this._editingRowCount++;
|
|
21786
22016
|
}
|
|
21787
|
-
|
|
21788
|
-
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
if (this._debug)
|
|
21793
|
-
console.debug('[table-datasource] Cancelling row', row);
|
|
21794
|
-
const done = yield _super.cancel.call(this, row);
|
|
21795
|
-
if (done)
|
|
21796
|
-
this._editingRowCount--;
|
|
21797
|
-
return done;
|
|
21798
|
-
});
|
|
22017
|
+
cancelOrDelete(row) {
|
|
22018
|
+
if (this._debug)
|
|
22019
|
+
console.debug('[table-datasource] Cancelling or deleting row', row);
|
|
22020
|
+
row.cancelOrDelete();
|
|
22021
|
+
this._editingRowCount--;
|
|
21799
22022
|
}
|
|
21800
22023
|
handleError(error, message) {
|
|
21801
22024
|
const errorMsg = error && error.message || error;
|
|
@@ -21810,77 +22033,59 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21810
22033
|
throw error;
|
|
21811
22034
|
}
|
|
21812
22035
|
delete(id) {
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
|
|
21821
|
-
|
|
21822
|
-
|
|
21823
|
-
|
|
21824
|
-
|
|
21825
|
-
|
|
21826
|
-
|
|
21827
|
-
|
|
21828
|
-
yield this.dataService.deleteAll([row.currentData], this.serviceOptions);
|
|
21829
|
-
// Make sure row has been deleted (because GrapQHl cache remove can failed)
|
|
21830
|
-
yield sleep(300);
|
|
22036
|
+
// If new row: not need to propagate to the dataService
|
|
22037
|
+
if (id === -1) {
|
|
22038
|
+
return super.delete(id);
|
|
22039
|
+
}
|
|
22040
|
+
const row = this.getRow(id);
|
|
22041
|
+
if (!row) {
|
|
22042
|
+
console.error(`[table-datasource] Row to delete with id=${id} not found`);
|
|
22043
|
+
return;
|
|
22044
|
+
}
|
|
22045
|
+
this.loadingSubject.next(true);
|
|
22046
|
+
this.dataService.deleteAll([row.currentData], this.serviceOptions)
|
|
22047
|
+
.catch(err => this.handleErrorPromise(err))
|
|
22048
|
+
.then(() => {
|
|
22049
|
+
setTimeout(() => {
|
|
22050
|
+
// make sure row has been deleted (because GrapQHl cache remove can failed)
|
|
21831
22051
|
const present = this.getRow(id) === row;
|
|
21832
|
-
if (present)
|
|
21833
|
-
|
|
21834
|
-
|
|
21835
|
-
|
|
21836
|
-
}
|
|
21837
|
-
catch (err) {
|
|
21838
|
-
this.handleErrorPromise(err);
|
|
21839
|
-
}
|
|
21840
|
-
finally {
|
|
21841
|
-
this.markAsLoaded();
|
|
21842
|
-
}
|
|
22052
|
+
if (present)
|
|
22053
|
+
super.delete(id);
|
|
22054
|
+
this.loadingSubject.next(false);
|
|
22055
|
+
}, 300);
|
|
21843
22056
|
});
|
|
21844
22057
|
}
|
|
21845
22058
|
deleteAll(rows) {
|
|
21846
|
-
|
|
21847
|
-
|
|
21848
|
-
|
|
21849
|
-
|
|
21850
|
-
|
|
21851
|
-
|
|
21852
|
-
|
|
21853
|
-
|
|
21854
|
-
|
|
21855
|
-
|
|
21856
|
-
|
|
21857
|
-
|
|
21858
|
-
|
|
21859
|
-
|
|
21860
|
-
|
|
21861
|
-
const
|
|
21862
|
-
|
|
21863
|
-
|
|
21864
|
-
|
|
21865
|
-
|
|
21866
|
-
|
|
21867
|
-
|
|
21868
|
-
console.warn(`[table-datasource] Force deletion of ${rowNotDeleted.length} rows (Is service applying deletion to observable ?)`);
|
|
21869
|
-
yield Promise.all(rowNotDeleted.map(r => _super.delete.call(this, r.id)));
|
|
21870
|
-
}
|
|
21871
|
-
}
|
|
21872
|
-
catch (err) {
|
|
21873
|
-
this.handleErrorPromise(err);
|
|
21874
|
-
}
|
|
21875
|
-
finally {
|
|
21876
|
-
this.markAsLoaded();
|
|
22059
|
+
this.markAsLoading();
|
|
22060
|
+
const data = rows.map(r => r.currentData);
|
|
22061
|
+
const rowsById = rows.reduce((res, row) => {
|
|
22062
|
+
res[row.id] = row;
|
|
22063
|
+
return res;
|
|
22064
|
+
}, {});
|
|
22065
|
+
const self = this;
|
|
22066
|
+
const selfDelete = super.delete;
|
|
22067
|
+
return this.dataService.deleteAll(data, this.serviceOptions)
|
|
22068
|
+
.catch(err => this.handleErrorPromise(err))
|
|
22069
|
+
.then(() => {
|
|
22070
|
+
// Workaround, to be sure all rows has been deleted
|
|
22071
|
+
// Sometimes, the service miss deletion, or GrapQHl cache remove failed
|
|
22072
|
+
const rowNotDeleted = Object.getOwnPropertyNames(rowsById).reduce((res, id) => {
|
|
22073
|
+
const row = rowsById[id];
|
|
22074
|
+
const present = self.getRow(+id) === row;
|
|
22075
|
+
return present ? res.concat(row) : res;
|
|
22076
|
+
}, []).sort((a, b) => a.id > b.id ? -1 : 1);
|
|
22077
|
+
// Apply missing deletion
|
|
22078
|
+
if (isNotEmptyArray(rowNotDeleted)) {
|
|
22079
|
+
console.warn(`[table-datasource] Force deletion of ${rowNotDeleted.length} rows (Is service applying deletion to observable ?)`);
|
|
22080
|
+
rowNotDeleted.forEach(r => selfDelete.call(self, r.id));
|
|
21877
22081
|
}
|
|
22082
|
+
this.loadingSubject.next(false);
|
|
21878
22083
|
});
|
|
21879
22084
|
}
|
|
21880
22085
|
getRows() {
|
|
21881
|
-
return this.
|
|
22086
|
+
return firstNotNilPromise(this.connect(null));
|
|
21882
22087
|
}
|
|
21883
|
-
|
|
22088
|
+
asyncCreateNew(insertAt) {
|
|
21884
22089
|
const _super = Object.create(null, {
|
|
21885
22090
|
createNew: { get: () => super.createNew }
|
|
21886
22091
|
});
|
|
@@ -21888,39 +22093,22 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21888
22093
|
if (this._creating)
|
|
21889
22094
|
return; // Avoid multiple call (should never occur)
|
|
21890
22095
|
this._creating = true;
|
|
21891
|
-
|
|
21892
|
-
|
|
21893
|
-
|
|
21894
|
-
|
|
21895
|
-
|
|
21896
|
-
|
|
21897
|
-
|
|
21898
|
-
|
|
21899
|
-
|
|
22096
|
+
_super.createNew.call(this, insertAt);
|
|
22097
|
+
const row = this.getRow(-1);
|
|
22098
|
+
if (row && this._options && this._options.onRowCreated) {
|
|
22099
|
+
const res = this._options.onRowCreated(row);
|
|
22100
|
+
// If async function, wait the end before ending
|
|
22101
|
+
if (res instanceof Promise) {
|
|
22102
|
+
try {
|
|
22103
|
+
yield res;
|
|
22104
|
+
}
|
|
22105
|
+
catch (err) {
|
|
22106
|
+
console.error(err && err.message || err, err);
|
|
22107
|
+
}
|
|
21900
22108
|
}
|
|
21901
22109
|
}
|
|
21902
|
-
|
|
21903
|
-
this._editingRowCount++;
|
|
22110
|
+
this._editingRowCount++;
|
|
21904
22111
|
this._creating = false;
|
|
21905
|
-
return done;
|
|
21906
|
-
});
|
|
21907
|
-
}
|
|
21908
|
-
createRowValidator() {
|
|
21909
|
-
const _super = Object.create(null, {
|
|
21910
|
-
createRowValidator: { get: () => super.createRowValidator }
|
|
21911
|
-
});
|
|
21912
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
21913
|
-
const validator = yield _super.createRowValidator.call(this);
|
|
21914
|
-
if (validator && this.config.onRowValidator) {
|
|
21915
|
-
try {
|
|
21916
|
-
yield this.config.onRowValidator(validator);
|
|
21917
|
-
}
|
|
21918
|
-
catch (err) {
|
|
21919
|
-
console.error(err && err.message || err, err);
|
|
21920
|
-
// Continue
|
|
21921
|
-
}
|
|
21922
|
-
}
|
|
21923
|
-
return validator;
|
|
21924
22112
|
});
|
|
21925
22113
|
}
|
|
21926
22114
|
getData() {
|
|
@@ -21935,7 +22123,7 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21935
22123
|
});
|
|
21936
22124
|
return __awaiter(this, void 0, void 0, function* () {
|
|
21937
22125
|
if (!this._fetchMoreFn)
|
|
21938
|
-
return false;
|
|
22126
|
+
return false; // Avoid multiple call
|
|
21939
22127
|
if (this._editingRowCount > 0) {
|
|
21940
22128
|
console.warn('Cannot fetch more because still editing row');
|
|
21941
22129
|
return;
|
|
@@ -21949,10 +22137,9 @@ class EntitiesTableDataSource extends TableDataSource {
|
|
|
21949
22137
|
if (isNotEmptyArray(res === null || res === void 0 ? void 0 : res.data))
|
|
21950
22138
|
return false;
|
|
21951
22139
|
// Update the data source
|
|
21952
|
-
// TODO review this, to keep existing rows, instead of creating new TableElement + validator !
|
|
21953
22140
|
const existingData = yield this.getData();
|
|
21954
|
-
|
|
21955
|
-
//
|
|
22141
|
+
_super.updateDatasource.call(this, existingData.concat(...res.data), opts);
|
|
22142
|
+
// Remember fetchMore
|
|
21956
22143
|
this._fetchMoreFn = res.fetchMore;
|
|
21957
22144
|
return true;
|
|
21958
22145
|
});
|
|
@@ -21975,8 +22162,8 @@ EntitiesTableDataSource.decorators = [
|
|
|
21975
22162
|
EntitiesTableDataSource.ctorParameters = () => [
|
|
21976
22163
|
{ type: Function },
|
|
21977
22164
|
{ type: undefined },
|
|
21978
|
-
{ type:
|
|
21979
|
-
{ type:
|
|
22165
|
+
{ type: ValidatorService },
|
|
22166
|
+
{ type: AppTableDataSourceOptions }
|
|
21980
22167
|
];
|
|
21981
22168
|
|
|
21982
22169
|
const SETTINGS_DISPLAY_COLUMNS = 'displayColumns';
|
|
@@ -22368,6 +22555,7 @@ class AppTable {
|
|
|
22368
22555
|
}
|
|
22369
22556
|
}
|
|
22370
22557
|
ngOnDestroy() {
|
|
22558
|
+
var _a;
|
|
22371
22559
|
this._subscription.unsubscribe();
|
|
22372
22560
|
// Unsubscribe column value changes
|
|
22373
22561
|
Object.keys(this._cellValueChangesDefs).forEach(col => this.stopCellValueChanges(col, true));
|
|
@@ -22392,6 +22580,7 @@ class AppTable {
|
|
|
22392
22580
|
this.onError.unsubscribe();
|
|
22393
22581
|
this._destroy$.next();
|
|
22394
22582
|
this._destroy$.unsubscribe();
|
|
22583
|
+
(_a = this._dataSource) === null || _a === void 0 ? void 0 : _a.ngOnDestroy();
|
|
22395
22584
|
}
|
|
22396
22585
|
updateView(res, opts) {
|
|
22397
22586
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -22433,7 +22622,7 @@ class AppTable {
|
|
|
22433
22622
|
this._dataSourceLoadingSubscription.unsubscribe();
|
|
22434
22623
|
this._subscription.remove(this._dataSourceLoadingSubscription);
|
|
22435
22624
|
}
|
|
22436
|
-
(_a = this._dataSource) === null || _a === void 0 ? void 0 : _a.
|
|
22625
|
+
(_a = this._dataSource) === null || _a === void 0 ? void 0 : _a.ngOnDestroy();
|
|
22437
22626
|
this._dataSource = null;
|
|
22438
22627
|
}
|
|
22439
22628
|
addColumnDef(column) {
|
|
@@ -22488,15 +22677,18 @@ class AppTable {
|
|
|
22488
22677
|
return true;
|
|
22489
22678
|
}
|
|
22490
22679
|
confirmAndForward(event, row) {
|
|
22491
|
-
|
|
22492
|
-
|
|
22493
|
-
|
|
22494
|
-
|
|
22495
|
-
|
|
22496
|
-
|
|
22680
|
+
var _a;
|
|
22681
|
+
row = row || this.editedRow;
|
|
22682
|
+
if (!this.confirmEditCreate(event, row)) {
|
|
22683
|
+
// If pending: Wait end of validation, then loop
|
|
22684
|
+
if ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.pending) {
|
|
22685
|
+
return AppFormUtils.waitWhilePending(row.validator).then(() => this.confirmAndForward(event, row));
|
|
22497
22686
|
}
|
|
22498
|
-
return
|
|
22499
|
-
}
|
|
22687
|
+
return false;
|
|
22688
|
+
}
|
|
22689
|
+
// Edit next row
|
|
22690
|
+
this.editRowById(event, row.id + 1, { focusColumn: this.firstUserColumn });
|
|
22691
|
+
return true;
|
|
22500
22692
|
}
|
|
22501
22693
|
editRowById(event, id, opts) {
|
|
22502
22694
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -22520,44 +22712,48 @@ class AppTable {
|
|
|
22520
22712
|
*/
|
|
22521
22713
|
confirmEditCreate(event, row) {
|
|
22522
22714
|
var _a;
|
|
22523
|
-
|
|
22524
|
-
|
|
22525
|
-
|
|
22526
|
-
|
|
22527
|
-
|
|
22528
|
-
|
|
22529
|
-
|
|
22530
|
-
|
|
22531
|
-
|
|
22532
|
-
|
|
22533
|
-
|
|
22534
|
-
this.editedRow = undefined;
|
|
22535
|
-
}
|
|
22536
|
-
// Mark table as dirty (if row is dirty)
|
|
22537
|
-
if ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty) {
|
|
22538
|
-
this.markAsDirty({ emitEvent: false /* because of resetError() */ });
|
|
22539
|
-
}
|
|
22540
|
-
// Clear error
|
|
22541
|
-
this.resetError();
|
|
22542
|
-
// Emit the confirm event
|
|
22543
|
-
this.onConfirmEditCreateRow.next(row);
|
|
22544
|
-
}
|
|
22545
|
-
else if (row.validator) {
|
|
22546
|
-
// NOT confirmed = row has error
|
|
22547
|
-
if (this.debug) {
|
|
22548
|
-
console.warn('[table] Cannot confirm row, because invalid');
|
|
22549
|
-
AppFormUtils.logFormErrors(row.validator, '[table] ');
|
|
22550
|
-
}
|
|
22551
|
-
// fix: mark all controls as touched to show errors
|
|
22552
|
-
row.validator.markAllAsTouched();
|
|
22553
|
-
// Compute row error, and propagate to table's error
|
|
22554
|
-
if (this.propagateRowError) {
|
|
22555
|
-
const error = this.getRowError(row);
|
|
22556
|
-
this.setError(error);
|
|
22557
|
-
}
|
|
22715
|
+
row = row || this.editedRow;
|
|
22716
|
+
if (!row || !row.editing)
|
|
22717
|
+
return true; // no row to confirm
|
|
22718
|
+
// Stop event
|
|
22719
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
22720
|
+
// Confirmation edition or creation
|
|
22721
|
+
const confirmed = row.confirmEditCreate();
|
|
22722
|
+
if (confirmed) {
|
|
22723
|
+
// If edit finished, forget edited row
|
|
22724
|
+
if (row === this.editedRow) {
|
|
22725
|
+
this.editedRow = undefined;
|
|
22558
22726
|
}
|
|
22559
|
-
|
|
22560
|
-
|
|
22727
|
+
// Mark table as dirty (if row is dirty)
|
|
22728
|
+
if ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty) {
|
|
22729
|
+
this.markAsDirty({ emitEvent: false /* because of resetError() */ });
|
|
22730
|
+
}
|
|
22731
|
+
// Clear error
|
|
22732
|
+
this.resetError();
|
|
22733
|
+
// Emit the confirm event
|
|
22734
|
+
this.onConfirmEditCreateRow.next(row);
|
|
22735
|
+
return true; // Continue
|
|
22736
|
+
}
|
|
22737
|
+
if (row.validator) {
|
|
22738
|
+
// If pending: Wait end of validation, then loop
|
|
22739
|
+
if (row.validator.pending) {
|
|
22740
|
+
AppFormUtils.waitWhilePending(row.validator).then(() => this.confirmEditCreate(event, row));
|
|
22741
|
+
return false;
|
|
22742
|
+
}
|
|
22743
|
+
// NOT confirmed = row has error
|
|
22744
|
+
if (this.debug) {
|
|
22745
|
+
console.warn('[table] Cannot confirm row, because invalid');
|
|
22746
|
+
AppFormUtils.logFormErrors(row.validator, '[table] ');
|
|
22747
|
+
}
|
|
22748
|
+
// fix: mark all controls as touched to show errors
|
|
22749
|
+
row.validator.markAllAsTouched();
|
|
22750
|
+
// Compute row error, and propagate to table's error
|
|
22751
|
+
if (this.propagateRowError) {
|
|
22752
|
+
const error = this.getRowError(row);
|
|
22753
|
+
this.setError(error);
|
|
22754
|
+
}
|
|
22755
|
+
}
|
|
22756
|
+
return false;
|
|
22561
22757
|
}
|
|
22562
22758
|
cancelOrDelete(event, row, opts) {
|
|
22563
22759
|
// Delete new row
|
|
@@ -22602,7 +22798,6 @@ class AppTable {
|
|
|
22602
22798
|
// Keep edited row id (should be done BEFORE confirmEditCreate() )
|
|
22603
22799
|
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;
|
|
22604
22800
|
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;
|
|
22605
|
-
// TODO: remove this, has it redundant with dataSource.confirmAllRows() called in dataSource.save()
|
|
22606
22801
|
if (!this.confirmEditCreate()) {
|
|
22607
22802
|
throw { code: ErrorCodes.TABLE_INVALID_ROW_ERROR, message: 'ERROR.TABLE_INVALID_ROW_ERROR' };
|
|
22608
22803
|
}
|
|
@@ -23160,7 +23355,7 @@ class AppTable {
|
|
|
23160
23355
|
console.warn('[table] Opening row details, but data has no id!');
|
|
23161
23356
|
return false;
|
|
23162
23357
|
}
|
|
23163
|
-
return
|
|
23358
|
+
return this.router.navigate(['.', id.toString()], {
|
|
23164
23359
|
relativeTo: this.route,
|
|
23165
23360
|
queryParams: {}
|
|
23166
23361
|
});
|
|
@@ -23257,9 +23452,7 @@ class AppTable {
|
|
|
23257
23452
|
addRowToTable(insertAt) {
|
|
23258
23453
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23259
23454
|
this.focusFirstColumn = true;
|
|
23260
|
-
|
|
23261
|
-
if (!done)
|
|
23262
|
-
return undefined;
|
|
23455
|
+
yield this._dataSource.asyncCreateNew(insertAt);
|
|
23263
23456
|
this.editedRow = this._dataSource.getRow(-1);
|
|
23264
23457
|
// Emit start editing event
|
|
23265
23458
|
this.onStartEditingRow.emit(this.editedRow);
|
|
@@ -23390,64 +23583,59 @@ class AppTable {
|
|
|
23390
23583
|
}
|
|
23391
23584
|
}
|
|
23392
23585
|
deleteNewRow(event, row) {
|
|
23393
|
-
|
|
23394
|
-
|
|
23395
|
-
|
|
23396
|
-
|
|
23397
|
-
|
|
23398
|
-
|
|
23399
|
-
|
|
23400
|
-
|
|
23401
|
-
|
|
23402
|
-
|
|
23403
|
-
this.totalRowCount--;
|
|
23404
|
-
this.visibleRowCount--;
|
|
23405
|
-
}
|
|
23406
|
-
return done;
|
|
23407
|
-
});
|
|
23586
|
+
if (row.id !== -1)
|
|
23587
|
+
throw new Error('Row must have id = -1');
|
|
23588
|
+
event === null || event === void 0 ? void 0 : event.stopPropagation();
|
|
23589
|
+
this.selection.clear();
|
|
23590
|
+
this.editedRow = undefined; // unselect row
|
|
23591
|
+
this._dataSource.cancelOrDelete(row);
|
|
23592
|
+
this.onCancelOrDeleteRow.next(row);
|
|
23593
|
+
this.resetError();
|
|
23594
|
+
this.totalRowCount--;
|
|
23595
|
+
this.visibleRowCount--;
|
|
23408
23596
|
}
|
|
23409
23597
|
deleteExistingRow(event, row, opts) {
|
|
23410
23598
|
// Make sure row will be cancelled, and NOT deleted
|
|
23411
23599
|
if (row.id === -1)
|
|
23412
23600
|
throw new Error('Row must have an id');
|
|
23413
23601
|
if (event === null || event === void 0 ? void 0 : event.defaultPrevented)
|
|
23414
|
-
return
|
|
23602
|
+
return 0; // SKip
|
|
23415
23603
|
event === null || event === void 0 ? void 0 : event.preventDefault();
|
|
23416
|
-
|
|
23604
|
+
this.deleteRow(null, row, opts);
|
|
23417
23605
|
}
|
|
23418
23606
|
cancelExistingRow(event, row, opts) {
|
|
23419
23607
|
var _a;
|
|
23420
|
-
|
|
23421
|
-
|
|
23422
|
-
|
|
23423
|
-
|
|
23424
|
-
|
|
23425
|
-
|
|
23426
|
-
|
|
23427
|
-
|
|
23428
|
-
|
|
23429
|
-
// If
|
|
23430
|
-
if (
|
|
23431
|
-
|
|
23432
|
-
}
|
|
23433
|
-
|
|
23434
|
-
|
|
23435
|
-
|
|
23436
|
-
|
|
23437
|
-
|
|
23438
|
-
|
|
23439
|
-
|
|
23440
|
-
|
|
23441
|
-
|
|
23442
|
-
|
|
23443
|
-
|
|
23444
|
-
}
|
|
23608
|
+
// Make sure row will be cancelled, and NOT deleted
|
|
23609
|
+
if (row.id === -1 || !row.editing)
|
|
23610
|
+
throw new Error('Row cannot be canceling, but only deleting');
|
|
23611
|
+
const confirmed = (!opts || opts.interactive !== false);
|
|
23612
|
+
// Ask user confirmation, if cancel
|
|
23613
|
+
if (!confirmed && ((_a = row.validator) === null || _a === void 0 ? void 0 : _a.dirty) && (this.confirmBeforeCancel || this.onBeforeCancelRows.observers.length > 0)) {
|
|
23614
|
+
event.stopPropagation();
|
|
23615
|
+
this.canCancelRows([row], opts)
|
|
23616
|
+
.then(confirm => {
|
|
23617
|
+
// If confirmed, loop
|
|
23618
|
+
if (confirm)
|
|
23619
|
+
this.cancelExistingRow(event, row, { interactive: false });
|
|
23620
|
+
});
|
|
23621
|
+
return;
|
|
23622
|
+
}
|
|
23623
|
+
const keepEditing = row.editing && (!opts || opts.keepEditing !== false);
|
|
23624
|
+
this.editedRow = undefined; // unselect row
|
|
23625
|
+
this._dataSource.cancelOrDelete(row);
|
|
23626
|
+
this.onCancelOrDeleteRow.next(row);
|
|
23627
|
+
// Mark row as pristine
|
|
23628
|
+
this.checkIfRowPristine(row);
|
|
23629
|
+
// Restore editing state
|
|
23630
|
+
if (keepEditing) {
|
|
23631
|
+
this.editRow(undefined, row);
|
|
23632
|
+
}
|
|
23445
23633
|
}
|
|
23446
23634
|
checkIfRowPristine(row, opts) {
|
|
23447
23635
|
var _a, _b;
|
|
23448
23636
|
return __awaiter(this, void 0, void 0, function* () {
|
|
23449
23637
|
// Mark row as pristine
|
|
23450
|
-
const markRowAsPristine = ((_a = this.dataSource) === null || _a === void 0 ? void 0 : _a.
|
|
23638
|
+
const markRowAsPristine = ((_a = this.dataSource) === null || _a === void 0 ? void 0 : _a.options.keepOriginalDataAfterConfirm) === true;
|
|
23451
23639
|
if (markRowAsPristine) {
|
|
23452
23640
|
(_b = row.validator) === null || _b === void 0 ? void 0 : _b.markAsPristine();
|
|
23453
23641
|
// Check if table is now pristine
|
|
@@ -24255,6 +24443,12 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24255
24443
|
this.onUpdateView.complete();
|
|
24256
24444
|
this.onUpdateView.unsubscribe();
|
|
24257
24445
|
}
|
|
24446
|
+
waitIdle(opts) {
|
|
24447
|
+
// Wait end of saving
|
|
24448
|
+
if (this.saving)
|
|
24449
|
+
return waitFor(() => this.saving !== true);
|
|
24450
|
+
return super.waitIdle(opts);
|
|
24451
|
+
}
|
|
24258
24452
|
/**
|
|
24259
24453
|
* Load data from the snapshot route
|
|
24260
24454
|
*
|
|
@@ -24373,7 +24567,7 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24373
24567
|
const idChanged = isNotNil(data.id)
|
|
24374
24568
|
&& this.previousDataId !== undefined // Ignore if first loading (=undefined)
|
|
24375
24569
|
&& this.previousDataId !== data.id;
|
|
24376
|
-
opts = Object.assign({ updateRoute: this._autoUpdateRoute && idChanged && !this.loading
|
|
24570
|
+
opts = Object.assign({ updateRoute: this._autoUpdateRoute && idChanged && !this.loading }, opts);
|
|
24377
24571
|
this.data = data;
|
|
24378
24572
|
this.previousDataId = data.id || null;
|
|
24379
24573
|
yield this.ready();
|
|
@@ -24424,18 +24618,25 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24424
24618
|
// Save the opened tab into the queryParams
|
|
24425
24619
|
this.queryParams.tab = this.selectedTabIndex;
|
|
24426
24620
|
// Update route location
|
|
24427
|
-
|
|
24428
|
-
|
|
24429
|
-
|
|
24621
|
+
if (isNotNil(data === null || data === void 0 ? void 0 : data.id)) {
|
|
24622
|
+
const queryParams = Object.assign({}, this.queryParams);
|
|
24623
|
+
queryParams[this._pathIdAttribute] = data.id;
|
|
24624
|
+
if (this.debug)
|
|
24625
|
+
console.debug('[entity-editor] Updating route using params: ', queryParams);
|
|
24430
24626
|
yield this.router.navigate(['.'], {
|
|
24431
24627
|
relativeTo: this.route,
|
|
24432
|
-
queryParams
|
|
24628
|
+
queryParams
|
|
24433
24629
|
});
|
|
24434
24630
|
}
|
|
24631
|
+
// Move to ../new
|
|
24435
24632
|
else {
|
|
24633
|
+
const queryParams = Object.assign({}, this.queryParams);
|
|
24634
|
+
queryParams[this._pathIdAttribute] = 'new';
|
|
24635
|
+
if (this.debug)
|
|
24636
|
+
console.debug('[entity-editor] Updating route to \'../new\' using params: ', queryParams);
|
|
24436
24637
|
yield this.router.navigate(['..', 'new'], {
|
|
24437
24638
|
relativeTo: this.route,
|
|
24438
|
-
queryParams
|
|
24639
|
+
queryParams
|
|
24439
24640
|
});
|
|
24440
24641
|
}
|
|
24441
24642
|
yield this.updateRoute(data, this.queryParams);
|
|
@@ -24445,7 +24646,7 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24445
24646
|
* Update the route location, and open the next tab
|
|
24446
24647
|
*/
|
|
24447
24648
|
updateTabIndex(tabIndex) {
|
|
24448
|
-
if (isNotNil(tabIndex) && tabIndex
|
|
24649
|
+
if (isNotNil(tabIndex) && tabIndex !== this.selectedTabIndex) {
|
|
24449
24650
|
this.selectedTabIndex = tabIndex;
|
|
24450
24651
|
this.markForCheck();
|
|
24451
24652
|
}
|
|
@@ -24501,6 +24702,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24501
24702
|
if (this.debug)
|
|
24502
24703
|
console.debug('[data-editor] Saving data...');
|
|
24503
24704
|
try {
|
|
24705
|
+
// Compute next tab index (if enable)
|
|
24706
|
+
const nextTabIndex = this._autoOpenNextTab && isNil(this.previousDataId) && this.computeNextTabIndex();
|
|
24504
24707
|
// Get data
|
|
24505
24708
|
const data = yield this.getValue();
|
|
24506
24709
|
this.disable();
|
|
@@ -24508,7 +24711,9 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24508
24711
|
const updatedData = yield this.dataService.save(data, opts);
|
|
24509
24712
|
yield this.onEntitySaved(updatedData);
|
|
24510
24713
|
// Update the view (e.g metadata)
|
|
24511
|
-
yield this.updateView(updatedData,
|
|
24714
|
+
yield this.updateView(updatedData, Object.assign({
|
|
24715
|
+
// Open next tab only if user has not changed it
|
|
24716
|
+
openTabIndex: nextTabIndex > this._selectedTabIndex ? nextTabIndex : undefined }, opts));
|
|
24512
24717
|
// Subscribe to remote changes
|
|
24513
24718
|
if (!this._listenChangesSubscription)
|
|
24514
24719
|
this.startListenRemoteChanges();
|
|
@@ -24728,7 +24933,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24728
24933
|
// If NOT data, then add to page history
|
|
24729
24934
|
if (!this.isNewData) {
|
|
24730
24935
|
const page = yield this.computePageHistory(title);
|
|
24731
|
-
|
|
24936
|
+
if (page)
|
|
24937
|
+
return this.addToPageHistory(page);
|
|
24732
24938
|
}
|
|
24733
24939
|
});
|
|
24734
24940
|
}
|
|
@@ -24741,6 +24947,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24741
24947
|
}
|
|
24742
24948
|
computePageHistory(title) {
|
|
24743
24949
|
return __awaiter(this, void 0, void 0, function* () {
|
|
24950
|
+
if (this.debug)
|
|
24951
|
+
console.debug('[entity-editor] Computing page history, using url: ' + this.router.url);
|
|
24744
24952
|
return {
|
|
24745
24953
|
title,
|
|
24746
24954
|
path: this.router.url
|
|
@@ -24771,7 +24979,8 @@ class AppEntityEditor extends AppTabEditor {
|
|
|
24771
24979
|
fetchPolicy: 'no-cache' }, opts));
|
|
24772
24980
|
}
|
|
24773
24981
|
markForCheck() {
|
|
24774
|
-
|
|
24982
|
+
var _a;
|
|
24983
|
+
(_a = this.cd) === null || _a === void 0 ? void 0 : _a.markForCheck();
|
|
24775
24984
|
}
|
|
24776
24985
|
/* -- private functions -- */
|
|
24777
24986
|
/**
|
|
@@ -24856,7 +25065,7 @@ AppInMemoryTable.ctorParameters = () => [
|
|
|
24856
25065
|
{ type: Function },
|
|
24857
25066
|
{ type: InMemoryEntitiesService },
|
|
24858
25067
|
{ type: ValidatorService },
|
|
24859
|
-
{ type:
|
|
25068
|
+
{ type: AppTableDataSourceOptions },
|
|
24860
25069
|
{ type: undefined }
|
|
24861
25070
|
];
|
|
24862
25071
|
AppInMemoryTable.propDecorators = {
|
|
@@ -25880,7 +26089,7 @@ class PersonService extends BaseEntityService {
|
|
|
25880
26089
|
}
|
|
25881
26090
|
suggest(value, filter, sortBy, sortDirection) {
|
|
25882
26091
|
return __awaiter(this, void 0, void 0, function* () {
|
|
25883
|
-
if (
|
|
26092
|
+
if (EntityUtils.isNotEmpty(value, 'id'))
|
|
25884
26093
|
return { data: [value] };
|
|
25885
26094
|
value = (typeof value === 'string' && value !== '*') && value || undefined;
|
|
25886
26095
|
sortBy = sortBy || filter.searchAttribute || (filter.searchAttributes && filter.searchAttributes[0]);
|
|
@@ -26032,11 +26241,7 @@ class UsersPage extends AppTable {
|
|
|
26032
26241
|
switch (authTokenType) {
|
|
26033
26242
|
case "basic":
|
|
26034
26243
|
this.setShowColumn('pubkey', false, { emitEvent: false });
|
|
26035
|
-
this.setShowColumn('username', true, { emitEvent: false });
|
|
26036
|
-
this.setShowColumn('usernameExtranet', true, { emitEvent: false });
|
|
26037
|
-
break;
|
|
26038
26244
|
case "basic-and-token":
|
|
26039
|
-
this.setShowColumn('pubkey', true, { emitEvent: false });
|
|
26040
26245
|
this.setShowColumn('username', true, { emitEvent: false });
|
|
26041
26246
|
this.setShowColumn('usernameExtranet', true, { emitEvent: false });
|
|
26042
26247
|
break;
|
|
@@ -26248,6 +26453,7 @@ class AutocompleteTestPage {
|
|
|
26248
26453
|
missingEntity: [null, SharedValidators.entity],
|
|
26249
26454
|
disableEntity: [null, SharedValidators.entity],
|
|
26250
26455
|
entities: [null, SharedFormArrayValidators.requiredArrayMinLength(1)],
|
|
26456
|
+
farEntity: [null, SharedValidators.entity]
|
|
26251
26457
|
});
|
|
26252
26458
|
this.form.get('disableEntity').disable();
|
|
26253
26459
|
}
|
|
@@ -26256,8 +26462,7 @@ class AutocompleteTestPage {
|
|
|
26256
26462
|
this.autocompleteFields.add('entity-suggestFn', {
|
|
26257
26463
|
suggestFn: (value, filter) => this.suggest(value, filter),
|
|
26258
26464
|
attributes: ['label', 'name'],
|
|
26259
|
-
displayWith: this.entityToString
|
|
26260
|
-
showAllOnFocus: false
|
|
26465
|
+
displayWith: this.entityToString
|
|
26261
26466
|
});
|
|
26262
26467
|
// From items array
|
|
26263
26468
|
this.autocompleteFields.add('entity-items', {
|
|
@@ -26285,22 +26490,34 @@ class AutocompleteTestPage {
|
|
|
26285
26490
|
attributes: ['label', 'name', 'description', 'comments'],
|
|
26286
26491
|
displayWith: this.entityToString
|
|
26287
26492
|
});
|
|
26288
|
-
//
|
|
26493
|
+
// Far entity, in the list
|
|
26494
|
+
this.autocompleteFields.add('entity-far', {
|
|
26495
|
+
suggestFn: (value, filter) => this.suggest(value, filter),
|
|
26496
|
+
attributes: ['label', 'name'],
|
|
26497
|
+
displayWith: this.entityToString
|
|
26498
|
+
});
|
|
26499
|
+
// For multiple value
|
|
26289
26500
|
this.autocompleteFields.add('entities-items-filter', {
|
|
26290
26501
|
service: {
|
|
26291
26502
|
suggest: (value, filter) => this.suggest(value, filter)
|
|
26292
26503
|
},
|
|
26293
26504
|
attributes: ['label', 'name'],
|
|
26294
26505
|
multiple: true
|
|
26295
|
-
//displayWith: this.entitiesToString
|
|
26296
26506
|
});
|
|
26297
|
-
|
|
26507
|
+
}
|
|
26508
|
+
ngAfterViewInit() {
|
|
26509
|
+
setTimeout(() => {
|
|
26510
|
+
this.farEntityField.suggestLengthThreshold = 2;
|
|
26511
|
+
this.farEntityField.reloadItems();
|
|
26512
|
+
}, 2000);
|
|
26513
|
+
setTimeout(() => this.loadData(), 1000);
|
|
26298
26514
|
}
|
|
26299
26515
|
// Load the form with data
|
|
26300
26516
|
loadData() {
|
|
26301
26517
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26302
26518
|
const data = {
|
|
26303
26519
|
entity: deepCopy(FAKE_ENTITIES)[0],
|
|
26520
|
+
farEntity: deepCopy(FAKE_ENTITIES)[2],
|
|
26304
26521
|
// This item is NOT in the items list => i should be displayed anyway
|
|
26305
26522
|
missingEntity: {
|
|
26306
26523
|
id: -1, label: '??', name: 'Missing item'
|
|
@@ -26337,7 +26554,7 @@ class AutocompleteTestPage {
|
|
|
26337
26554
|
total,
|
|
26338
26555
|
data: res.data,
|
|
26339
26556
|
fetchMore: (variables) => __awaiter(this, void 0, void 0, function* () {
|
|
26340
|
-
yield sleep(1000);
|
|
26557
|
+
yield sleep(1000); // Simulate access to server
|
|
26341
26558
|
return this.suggest(value, Object.assign(Object.assign({}, filter), variables));
|
|
26342
26559
|
})
|
|
26343
26560
|
};
|
|
@@ -26380,12 +26597,15 @@ class AutocompleteTestPage {
|
|
|
26380
26597
|
AutocompleteTestPage.decorators = [
|
|
26381
26598
|
{ type: Component, args: [{
|
|
26382
26599
|
selector: 'app-autocomplete-test',
|
|
26383
|
-
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"
|
|
26600
|
+
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"
|
|
26384
26601
|
},] }
|
|
26385
26602
|
];
|
|
26386
26603
|
AutocompleteTestPage.ctorParameters = () => [
|
|
26387
26604
|
{ type: FormBuilder }
|
|
26388
26605
|
];
|
|
26606
|
+
AutocompleteTestPage.propDecorators = {
|
|
26607
|
+
farEntityField: [{ type: ViewChild, args: ['farEntityField',] }]
|
|
26608
|
+
};
|
|
26389
26609
|
|
|
26390
26610
|
class LatLongTestPage {
|
|
26391
26611
|
constructor(formBuilder) {
|
|
@@ -26446,20 +26666,20 @@ class LatLongTestPage {
|
|
|
26446
26666
|
LatLongTestPage.decorators = [
|
|
26447
26667
|
{ type: Component, args: [{
|
|
26448
26668
|
selector: 'app-latlong-test',
|
|
26449
|
-
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"
|
|
26669
|
+
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"
|
|
26450
26670
|
},] }
|
|
26451
26671
|
];
|
|
26452
26672
|
LatLongTestPage.ctorParameters = () => [
|
|
26453
26673
|
{ type: FormBuilder }
|
|
26454
26674
|
];
|
|
26455
26675
|
|
|
26456
|
-
const moment$
|
|
26676
|
+
const moment$6 = momentImported;
|
|
26457
26677
|
class SwipeTestPage {
|
|
26458
26678
|
constructor(formBuilder, dateFormatPipe) {
|
|
26459
26679
|
this.formBuilder = formBuilder;
|
|
26460
26680
|
this.dateFormatPipe = dateFormatPipe;
|
|
26461
26681
|
this.$dates = new BehaviorSubject(undefined);
|
|
26462
|
-
this._today = moment$
|
|
26682
|
+
this._today = moment$6().startOf('day');
|
|
26463
26683
|
this.form = formBuilder.group({
|
|
26464
26684
|
empty: [null, Validators.required],
|
|
26465
26685
|
date: [null, Validators.compose([Validators.required, SharedValidators.validDate])],
|
|
@@ -26472,7 +26692,7 @@ class SwipeTestPage {
|
|
|
26472
26692
|
ngOnInit() {
|
|
26473
26693
|
const dates = [];
|
|
26474
26694
|
for (let d = 0; d < 7; d++) {
|
|
26475
|
-
dates[d] = moment$
|
|
26695
|
+
dates[d] = moment$6(this._today).add(d - 3, 'day');
|
|
26476
26696
|
}
|
|
26477
26697
|
this.$dates.next(dates);
|
|
26478
26698
|
this.loadData();
|
|
@@ -26513,7 +26733,7 @@ SwipeTestPage.ctorParameters = () => [
|
|
|
26513
26733
|
{ type: DateFormatPipe }
|
|
26514
26734
|
];
|
|
26515
26735
|
|
|
26516
|
-
const moment$
|
|
26736
|
+
const moment$7 = momentImported;
|
|
26517
26737
|
class DateTimeTestPage {
|
|
26518
26738
|
constructor(platform, formBuilder, cd) {
|
|
26519
26739
|
this.platform = platform;
|
|
@@ -26525,7 +26745,8 @@ class DateTimeTestPage {
|
|
|
26525
26745
|
this.memoryMobile = true;
|
|
26526
26746
|
this.stringify = JSON.stringify;
|
|
26527
26747
|
this.form = formBuilder.group({
|
|
26528
|
-
empty: [null
|
|
26748
|
+
empty: [null],
|
|
26749
|
+
emptyRequired: [null, Validators.required],
|
|
26529
26750
|
enable: [null, Validators.required],
|
|
26530
26751
|
disable: [null, Validators.required],
|
|
26531
26752
|
readonly: [null]
|
|
@@ -26544,9 +26765,10 @@ class DateTimeTestPage {
|
|
|
26544
26765
|
// Load the form with data
|
|
26545
26766
|
loadData() {
|
|
26546
26767
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26547
|
-
const now = moment$
|
|
26768
|
+
const now = moment$7();
|
|
26548
26769
|
const data = {
|
|
26549
|
-
empty:
|
|
26770
|
+
empty: null,
|
|
26771
|
+
emptyRequired: null,
|
|
26550
26772
|
enable: toDateISOString(now),
|
|
26551
26773
|
disable: now,
|
|
26552
26774
|
readonly: now
|
|
@@ -26596,7 +26818,7 @@ class DateTimeTestPage {
|
|
|
26596
26818
|
DateTimeTestPage.decorators = [
|
|
26597
26819
|
{ type: Component, args: [{
|
|
26598
26820
|
selector: 'app-data-time-test',
|
|
26599
|
-
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"
|
|
26821
|
+
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"
|
|
26600
26822
|
},] }
|
|
26601
26823
|
];
|
|
26602
26824
|
DateTimeTestPage.ctorParameters = () => [
|
|
@@ -26788,7 +27010,7 @@ NumpadTestPage.ctorParameters = () => [
|
|
|
26788
27010
|
{ type: FormBuilder }
|
|
26789
27011
|
];
|
|
26790
27012
|
|
|
26791
|
-
const moment$
|
|
27013
|
+
const moment$8 = momentImported;
|
|
26792
27014
|
class DateTestPage {
|
|
26793
27015
|
constructor(formBuilder, cd) {
|
|
26794
27016
|
this.formBuilder = formBuilder;
|
|
@@ -26821,7 +27043,7 @@ class DateTestPage {
|
|
|
26821
27043
|
// Load the form with data
|
|
26822
27044
|
loadData() {
|
|
26823
27045
|
return __awaiter(this, void 0, void 0, function* () {
|
|
26824
|
-
const now = moment$
|
|
27046
|
+
const now = moment$8();
|
|
26825
27047
|
const nowAtMahe = now.clone().tz(this.timezone).startOf('day');
|
|
26826
27048
|
const data = {
|
|
26827
27049
|
empty: null,
|
|
@@ -27567,5 +27789,5 @@ CoreTestingModule.decorators = [
|
|
|
27567
27789
|
* Generated bundle index. Do not edit.
|
|
27568
27790
|
*/
|
|
27569
27791
|
|
|
27570
|
-
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,
|
|
27792
|
+
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 };
|
|
27571
27793
|
//# sourceMappingURL=sumaris-net.ngx-components.js.map
|