@ecodev/natural 44.0.6 → 45.0.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/esm2020/lib/classes/abstract-detail.mjs +39 -40
- package/esm2020/lib/classes/rxjs.mjs +2 -1
- package/esm2020/lib/modules/file/abstract-file.mjs +26 -29
- package/esm2020/lib/modules/file/utils.mjs +12 -1
- package/esm2020/lib/modules/fixed-button-detail/fixed-button-detail.component.mjs +22 -9
- package/esm2020/lib/services/abstract-model.service.mjs +7 -40
- package/esm2020/lib/services/debounce.service.mjs +128 -0
- package/esm2020/lib/services/swiss-parsing-date-adapter.service.mjs +21 -13
- package/esm2020/public-api.mjs +2 -1
- package/fesm2015/ecodev-natural.mjs +244 -124
- package/fesm2015/ecodev-natural.mjs.map +1 -1
- package/fesm2020/ecodev-natural.mjs +241 -122
- package/fesm2020/ecodev-natural.mjs.map +1 -1
- package/lib/modules/file/abstract-file.d.ts +0 -3
- package/lib/modules/file/utils.d.ts +1 -0
- package/lib/modules/fixed-button-detail/fixed-button-detail.component.d.ts +14 -6
- package/lib/services/abstract-model.service.d.ts +3 -5
- package/lib/services/debounce.service.d.ts +46 -0
- package/package.json +1 -1
- package/public-api.d.ts +1 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import '@angular/localize/init';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
3
|
import { Directive, Component, Inject, Injectable, HostBinding, HostListener, InjectionToken, Input, NgModule, EventEmitter, ChangeDetectionStrategy, Output, ContentChildren, Pipe, TemplateRef, ViewEncapsulation, ViewChild, Injector, Optional, Self, ContentChild, createEnvironmentInjector, createComponent, PLATFORM_ID, ErrorHandler } from '@angular/core';
|
|
4
|
-
import { Subject, BehaviorSubject, of, timer, EMPTY, Observable, first as first$1, combineLatest, ReplaySubject, forkJoin, merge as merge$1,
|
|
4
|
+
import { Subject, BehaviorSubject, of, timer, switchMap as switchMap$1, endWith, last, EMPTY, Observable, first as first$1, combineLatest, ReplaySubject, debounceTime as debounceTime$1, raceWith, take as take$1, mergeMap, shareReplay as shareReplay$1, catchError, forkJoin, map as map$1, merge as merge$1, tap as tap$1, asyncScheduler } from 'rxjs';
|
|
5
5
|
import * as i3 from '@angular/forms';
|
|
6
6
|
import { FormGroup, FormArray, Validators, UntypedFormGroup, UntypedFormArray, UntypedFormControl, FormsModule, FormControl, FormControlDirective, FormControlName, ReactiveFormsModule } from '@angular/forms';
|
|
7
7
|
import * as i2$1 from '@angular/router';
|
|
@@ -13,7 +13,7 @@ import * as i4 from '@angular/material/button';
|
|
|
13
13
|
import { MatButtonModule } from '@angular/material/button';
|
|
14
14
|
import * as i2 from '@angular/material/snack-bar';
|
|
15
15
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
16
|
-
import { switchMap, map, first, filter, finalize, takeUntil, take, tap, takeWhile, debounceTime, shareReplay,
|
|
16
|
+
import { switchMap, map, first, filter, finalize, takeUntil, take, tap, takeWhile, debounceTime, shareReplay, startWith, distinctUntilChanged, throttleTime } from 'rxjs/operators';
|
|
17
17
|
import * as i7$2 from '@angular/material/table';
|
|
18
18
|
import { MatTableDataSource, MatTableModule } from '@angular/material/table';
|
|
19
19
|
import { DataSource, SelectionModel } from '@angular/cdk/collections';
|
|
@@ -2346,51 +2346,50 @@ class NaturalAbstractDetail extends NaturalAbstractPanel {
|
|
|
2346
2346
|
this.form.disable();
|
|
2347
2347
|
this.service
|
|
2348
2348
|
.create(this.data.model)
|
|
2349
|
-
.pipe(
|
|
2350
|
-
.subscribe(model => {
|
|
2349
|
+
.pipe(switchMap$1(model => {
|
|
2351
2350
|
this.alertService.info($localize `Créé`);
|
|
2352
2351
|
this.form.patchValue(model);
|
|
2353
|
-
this.postCreate(model).
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2352
|
+
return this.postCreate(model).pipe(endWith(model), last());
|
|
2353
|
+
}), switchMap$1(model => {
|
|
2354
|
+
if (redirect) {
|
|
2355
|
+
if (this.isPanel) {
|
|
2356
|
+
const oldUrl = this.router.url;
|
|
2357
|
+
const nextUrl = this.panelData?.config.params.nextRoute;
|
|
2358
|
+
const newUrl = oldUrl.replace('/new', '/' + model.id) + (nextUrl ? '/' + nextUrl : '');
|
|
2359
|
+
return this.router.navigateByUrl(newUrl); // replace /new by /123
|
|
2360
|
+
}
|
|
2361
|
+
else {
|
|
2362
|
+
return this.router.navigate(['..', model.id], { relativeTo: this.route });
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
return EMPTY;
|
|
2366
|
+
}), finalize(() => this.form.enable()))
|
|
2367
|
+
.subscribe();
|
|
2369
2368
|
}
|
|
2370
2369
|
delete(redirectionRoute) {
|
|
2370
|
+
this.form.disable();
|
|
2371
2371
|
this.alertService
|
|
2372
2372
|
.confirm($localize `Suppression`, $localize `Voulez-vous supprimer définitivement cet élément ?`, $localize `Supprimer définitivement`)
|
|
2373
|
-
.
|
|
2374
|
-
if (confirmed) {
|
|
2375
|
-
|
|
2376
|
-
this.form.disable();
|
|
2377
|
-
this.service
|
|
2378
|
-
.delete([this.data.model])
|
|
2379
|
-
.pipe(finalize(() => this.form.enable()))
|
|
2380
|
-
.subscribe(() => {
|
|
2381
|
-
this.alertService.info($localize `Supprimé`);
|
|
2382
|
-
if (!this.isPanel) {
|
|
2383
|
-
const defaultRoute = ['../../' + kebabCase(this.key)];
|
|
2384
|
-
this.router.navigate(redirectionRoute ? redirectionRoute : defaultRoute, {
|
|
2385
|
-
relativeTo: this.route,
|
|
2386
|
-
});
|
|
2387
|
-
}
|
|
2388
|
-
else {
|
|
2389
|
-
this.panelService?.goToPenultimatePanel();
|
|
2390
|
-
}
|
|
2391
|
-
});
|
|
2373
|
+
.pipe(switchMap$1(confirmed => {
|
|
2374
|
+
if (!confirmed) {
|
|
2375
|
+
return EMPTY;
|
|
2392
2376
|
}
|
|
2393
|
-
|
|
2377
|
+
this.preDelete(this.data.model);
|
|
2378
|
+
return this.service.delete([this.data.model]).pipe(switchMap$1(() => {
|
|
2379
|
+
this.alertService.info($localize `Supprimé`);
|
|
2380
|
+
if (this.isPanel) {
|
|
2381
|
+
this.panelService?.goToPenultimatePanel();
|
|
2382
|
+
return EMPTY;
|
|
2383
|
+
}
|
|
2384
|
+
else {
|
|
2385
|
+
const defaultRoute = ['../../' + kebabCase(this.key)];
|
|
2386
|
+
return this.router.navigate(redirectionRoute ? redirectionRoute : defaultRoute, {
|
|
2387
|
+
relativeTo: this.route,
|
|
2388
|
+
});
|
|
2389
|
+
}
|
|
2390
|
+
}));
|
|
2391
|
+
}), finalize(() => this.form.enable()))
|
|
2392
|
+
.subscribe();
|
|
2394
2393
|
}
|
|
2395
2394
|
postUpdate(model) { }
|
|
2396
2395
|
/**
|
|
@@ -3553,6 +3552,7 @@ function cancellableTimeout(canceller, milliSeconds = 0) {
|
|
|
3553
3552
|
function debug(debugName) {
|
|
3554
3553
|
return tap({
|
|
3555
3554
|
subscribe: () => console.log('SUBSCRIBE', debugName),
|
|
3555
|
+
unsubscribe: () => console.log('UNSUBSCRIBE', debugName),
|
|
3556
3556
|
next: value => console.log('NEXT', debugName, value),
|
|
3557
3557
|
error: error => console.log('ERROR', debugName, error),
|
|
3558
3558
|
complete: () => console.log('COMPLETE', debugName),
|
|
@@ -3560,18 +3560,15 @@ function debug(debugName) {
|
|
|
3560
3560
|
}
|
|
3561
3561
|
|
|
3562
3562
|
class NaturalAbstractModelService {
|
|
3563
|
-
constructor(apollo, name, oneQuery, allQuery, createMutation, updateMutation, deleteMutation) {
|
|
3563
|
+
constructor(apollo, naturalDebounceService, name, oneQuery, allQuery, createMutation, updateMutation, deleteMutation) {
|
|
3564
3564
|
this.apollo = apollo;
|
|
3565
|
+
this.naturalDebounceService = naturalDebounceService;
|
|
3565
3566
|
this.name = name;
|
|
3566
3567
|
this.oneQuery = oneQuery;
|
|
3567
3568
|
this.allQuery = allQuery;
|
|
3568
3569
|
this.createMutation = createMutation;
|
|
3569
3570
|
this.updateMutation = updateMutation;
|
|
3570
3571
|
this.deleteMutation = deleteMutation;
|
|
3571
|
-
/**
|
|
3572
|
-
* Stores the debounced update function
|
|
3573
|
-
*/
|
|
3574
|
-
this.debouncedUpdateCache = new Map();
|
|
3575
3572
|
/**
|
|
3576
3573
|
* Store the creation mutations that are pending
|
|
3577
3574
|
*/
|
|
@@ -3803,36 +3800,7 @@ class NaturalAbstractModelService {
|
|
|
3803
3800
|
this.throwIfNotQuery(this.updateMutation);
|
|
3804
3801
|
// Keep a single instance of the debounced update function
|
|
3805
3802
|
const id = object.id;
|
|
3806
|
-
|
|
3807
|
-
if (!debounced) {
|
|
3808
|
-
const source = new ReplaySubject(1);
|
|
3809
|
-
let wasCancelled = false;
|
|
3810
|
-
const canceller = new Subject();
|
|
3811
|
-
canceller.subscribe(() => {
|
|
3812
|
-
wasCancelled = true;
|
|
3813
|
-
source.complete();
|
|
3814
|
-
canceller.complete();
|
|
3815
|
-
});
|
|
3816
|
-
// Create debounced update function
|
|
3817
|
-
const result = source.pipe(debounceTime(2000), // Wait 2sec.
|
|
3818
|
-
take(1), mergeMap(() => {
|
|
3819
|
-
this.debouncedUpdateCache.delete(id);
|
|
3820
|
-
if (wasCancelled) {
|
|
3821
|
-
return EMPTY;
|
|
3822
|
-
}
|
|
3823
|
-
return this.updateNow(object);
|
|
3824
|
-
}), shareReplay());
|
|
3825
|
-
debounced = {
|
|
3826
|
-
source,
|
|
3827
|
-
canceller,
|
|
3828
|
-
result,
|
|
3829
|
-
};
|
|
3830
|
-
this.debouncedUpdateCache.set(id, debounced);
|
|
3831
|
-
}
|
|
3832
|
-
// Notify our debounced update each time we ask to update
|
|
3833
|
-
debounced.source.next();
|
|
3834
|
-
// Return and observable that is updated when mutation is done
|
|
3835
|
-
return debounced.result;
|
|
3803
|
+
return this.naturalDebounceService.debounce(this, id, this.updateNow(object));
|
|
3836
3804
|
}
|
|
3837
3805
|
/**
|
|
3838
3806
|
* Update an object immediately when subscribing
|
|
@@ -3884,8 +3852,7 @@ class NaturalAbstractModelService {
|
|
|
3884
3852
|
this.throwIfNotQuery(this.deleteMutation);
|
|
3885
3853
|
const ids = objects.map(o => {
|
|
3886
3854
|
// Cancel pending update
|
|
3887
|
-
|
|
3888
|
-
debounced?.canceller.next();
|
|
3855
|
+
this.naturalDebounceService.cancel(this, o.id);
|
|
3889
3856
|
return o.id;
|
|
3890
3857
|
});
|
|
3891
3858
|
const variables = merge({
|
|
@@ -4066,6 +4033,131 @@ class NaturalAbstractModelService {
|
|
|
4066
4033
|
}
|
|
4067
4034
|
}
|
|
4068
4035
|
|
|
4036
|
+
/**
|
|
4037
|
+
* Debounce subscriptions to observable, with possibility to cancel one, or flush all of them. Typically,
|
|
4038
|
+
* observables are object updates, so `NaturalAbstractModelService.updateNow()`.
|
|
4039
|
+
*
|
|
4040
|
+
* `key` must be an instance of `NaturalAbstractModelService` to separate objects by their types. So User with ID 1 is
|
|
4041
|
+
* not confused with Product with ID 1. It has no other purpose.
|
|
4042
|
+
*
|
|
4043
|
+
* `id` should be the ID of the object that will be updated.
|
|
4044
|
+
*/
|
|
4045
|
+
class NaturalDebounceService {
|
|
4046
|
+
constructor() {
|
|
4047
|
+
this.flusher = new Subject();
|
|
4048
|
+
/**
|
|
4049
|
+
* Stores the debounced update function
|
|
4050
|
+
*/
|
|
4051
|
+
this.allDebouncedUpdateCache = new Map();
|
|
4052
|
+
}
|
|
4053
|
+
/**
|
|
4054
|
+
* Debounce the given source observable for a short time. If called multiple times with the same key and id,
|
|
4055
|
+
* it will postpone the subscription to the source observable.
|
|
4056
|
+
*
|
|
4057
|
+
* Giving the same key and id but a different source observable will replace the original observable, but
|
|
4058
|
+
* keep the same debouncing timeline.
|
|
4059
|
+
*/
|
|
4060
|
+
debounce(key, id, source) {
|
|
4061
|
+
const debouncedUpdateCache = this.getMap(key);
|
|
4062
|
+
let debounced = debouncedUpdateCache.get(id);
|
|
4063
|
+
if (debounced) {
|
|
4064
|
+
debounced.source = source;
|
|
4065
|
+
}
|
|
4066
|
+
else {
|
|
4067
|
+
const debouncer = new ReplaySubject(1);
|
|
4068
|
+
let wasCancelled = false;
|
|
4069
|
+
const canceller = new Subject();
|
|
4070
|
+
canceller.subscribe(() => {
|
|
4071
|
+
wasCancelled = true;
|
|
4072
|
+
debouncer.complete();
|
|
4073
|
+
canceller.complete();
|
|
4074
|
+
this.delete(key, id);
|
|
4075
|
+
});
|
|
4076
|
+
debounced = {
|
|
4077
|
+
debouncer,
|
|
4078
|
+
canceller,
|
|
4079
|
+
source,
|
|
4080
|
+
result: debouncer.pipe(debounceTime$1(2000), // Wait 2 seconds...
|
|
4081
|
+
raceWith(this.flusher), // ...unless flusher is triggered
|
|
4082
|
+
take$1(1), mergeMap(() => {
|
|
4083
|
+
this.delete(key, id);
|
|
4084
|
+
if (wasCancelled || !debounced) {
|
|
4085
|
+
return EMPTY;
|
|
4086
|
+
}
|
|
4087
|
+
return debounced.source;
|
|
4088
|
+
}), shareReplay$1()),
|
|
4089
|
+
};
|
|
4090
|
+
debouncedUpdateCache.set(id, debounced);
|
|
4091
|
+
}
|
|
4092
|
+
// Notify our debounced update each time we ask to update
|
|
4093
|
+
debounced.debouncer.next();
|
|
4094
|
+
// Return and observable that is updated when mutation is done
|
|
4095
|
+
return debounced.result;
|
|
4096
|
+
}
|
|
4097
|
+
cancel(key, id) {
|
|
4098
|
+
const debounced = this.allDebouncedUpdateCache.get(key)?.get(id);
|
|
4099
|
+
debounced?.canceller.next();
|
|
4100
|
+
}
|
|
4101
|
+
/**
|
|
4102
|
+
* Immediately execute all pending updates.
|
|
4103
|
+
*
|
|
4104
|
+
* It should typically be called before login out.
|
|
4105
|
+
*
|
|
4106
|
+
* The returned observable will complete when all updates complete, even if some of them error.
|
|
4107
|
+
*/
|
|
4108
|
+
flush() {
|
|
4109
|
+
const all = [];
|
|
4110
|
+
this.allDebouncedUpdateCache.forEach(map => map.forEach(debounced => {
|
|
4111
|
+
all.push(debounced.result.pipe(catchError(() => of(undefined))));
|
|
4112
|
+
}));
|
|
4113
|
+
if (!all.length) {
|
|
4114
|
+
all.push(of(undefined));
|
|
4115
|
+
}
|
|
4116
|
+
return new Observable(subscriber => {
|
|
4117
|
+
const subscription = forkJoin(all)
|
|
4118
|
+
.pipe(map$1(() => undefined))
|
|
4119
|
+
.subscribe(subscriber);
|
|
4120
|
+
// Flush only after subscription process is finished
|
|
4121
|
+
this.flusher.next();
|
|
4122
|
+
return subscription;
|
|
4123
|
+
});
|
|
4124
|
+
}
|
|
4125
|
+
/**
|
|
4126
|
+
* Count of pending updates
|
|
4127
|
+
*/
|
|
4128
|
+
get count() {
|
|
4129
|
+
let count = 0;
|
|
4130
|
+
this.allDebouncedUpdateCache.forEach(map => (count += map.size));
|
|
4131
|
+
return count;
|
|
4132
|
+
}
|
|
4133
|
+
getMap(key) {
|
|
4134
|
+
let debouncedUpdateCache = this.allDebouncedUpdateCache.get(key);
|
|
4135
|
+
if (!debouncedUpdateCache) {
|
|
4136
|
+
debouncedUpdateCache = new Map();
|
|
4137
|
+
this.allDebouncedUpdateCache.set(key, debouncedUpdateCache);
|
|
4138
|
+
}
|
|
4139
|
+
return debouncedUpdateCache;
|
|
4140
|
+
}
|
|
4141
|
+
delete(key, id) {
|
|
4142
|
+
const map = this.allDebouncedUpdateCache.get(key);
|
|
4143
|
+
if (!map) {
|
|
4144
|
+
return;
|
|
4145
|
+
}
|
|
4146
|
+
map.delete(id);
|
|
4147
|
+
if (!map.size) {
|
|
4148
|
+
this.allDebouncedUpdateCache.delete(key);
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
}
|
|
4152
|
+
NaturalDebounceService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4153
|
+
NaturalDebounceService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, providedIn: 'root' });
|
|
4154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, decorators: [{
|
|
4155
|
+
type: Injectable,
|
|
4156
|
+
args: [{
|
|
4157
|
+
providedIn: 'root',
|
|
4158
|
+
}]
|
|
4159
|
+
}] });
|
|
4160
|
+
|
|
4069
4161
|
const enumTypeQuery = gql `
|
|
4070
4162
|
query EnumType($name: String!) {
|
|
4071
4163
|
__type(name: $name) {
|
|
@@ -4273,6 +4365,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
|
|
|
4273
4365
|
}]
|
|
4274
4366
|
}], ctorParameters: function () { return [{ type: i1$1.Apollo }]; } });
|
|
4275
4367
|
|
|
4368
|
+
const patterns = [
|
|
4369
|
+
/^(?<day>\d{1,2})\.(?<month>\d{1,2})\.(?<year>\d{4}|\d{2})$/,
|
|
4370
|
+
/^(?<day>\d{1,2})-(?<month>\d{1,2})-(?<year>\d{4}|\d{2})$/,
|
|
4371
|
+
/^(?<day>\d{1,2})\/(?<month>\d{1,2})\/(?<year>\d{4}|\d{2})$/,
|
|
4372
|
+
/^(?<day>\d{1,2})\\(?<month>\d{1,2})\\(?<year>\d{4}|\d{2})$/,
|
|
4373
|
+
// strict ISO format
|
|
4374
|
+
/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/,
|
|
4375
|
+
];
|
|
4276
4376
|
class NaturalSwissParsingDateAdapter extends NativeDateAdapter {
|
|
4277
4377
|
/**
|
|
4278
4378
|
* Parse commonly accepted swiss format, such as:
|
|
@@ -4286,24 +4386,24 @@ class NaturalSwissParsingDateAdapter extends NativeDateAdapter {
|
|
|
4286
4386
|
return new Date(value);
|
|
4287
4387
|
}
|
|
4288
4388
|
if (typeof value === 'string') {
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4389
|
+
const trimmed = value.trim();
|
|
4390
|
+
for (const pattern of patterns) {
|
|
4391
|
+
const m = trimmed.match(pattern);
|
|
4392
|
+
if (m?.groups) {
|
|
4393
|
+
const year = +m.groups.year;
|
|
4394
|
+
const month = +m.groups.month;
|
|
4395
|
+
const day = +m.groups.day;
|
|
4396
|
+
return this.createDateIfValid(year, month, day);
|
|
4295
4397
|
}
|
|
4296
|
-
return this.createDateIfValid(year, +m[2], +m[1]);
|
|
4297
|
-
}
|
|
4298
|
-
// Attempt strict ISO format
|
|
4299
|
-
m = value.match(/(\d{4})-(\d{2})-(\d{2})/);
|
|
4300
|
-
if (m) {
|
|
4301
|
-
return this.createDateIfValid(+m[1], +m[2], +m[3]);
|
|
4302
4398
|
}
|
|
4303
4399
|
}
|
|
4304
4400
|
return null;
|
|
4305
4401
|
}
|
|
4306
4402
|
createDateIfValid(year, month, date) {
|
|
4403
|
+
// Assume year 2000 if only two digits
|
|
4404
|
+
if (year < 100) {
|
|
4405
|
+
year += 2000;
|
|
4406
|
+
}
|
|
4307
4407
|
month = month - 1;
|
|
4308
4408
|
if (month >= 0 && month <= 11 && date >= 1 && date <= 31) {
|
|
4309
4409
|
return this.createDate(year, month, date);
|
|
@@ -8069,6 +8169,17 @@ function createFileInput(document) {
|
|
|
8069
8169
|
fileElem.type = 'file';
|
|
8070
8170
|
return fileElem;
|
|
8071
8171
|
}
|
|
8172
|
+
function isDirectory(file) {
|
|
8173
|
+
return file
|
|
8174
|
+
.slice(0, 1)
|
|
8175
|
+
.text()
|
|
8176
|
+
.then(text => {
|
|
8177
|
+
// Firefox will return empty string for a folder, so we must check that special case.
|
|
8178
|
+
// That means that any empty file will incorrectly be interpreted as a folder on all
|
|
8179
|
+
// browsers, but that's tolerable because there is no real use-case to upload an empty file.
|
|
8180
|
+
return text !== '';
|
|
8181
|
+
}, () => false);
|
|
8182
|
+
}
|
|
8072
8183
|
function stopEvent(event) {
|
|
8073
8184
|
event.preventDefault();
|
|
8074
8185
|
event.stopPropagation();
|
|
@@ -8164,10 +8275,6 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8164
8275
|
this.element = element;
|
|
8165
8276
|
this.naturalFileService = naturalFileService;
|
|
8166
8277
|
this.document = document;
|
|
8167
|
-
this.validators = [
|
|
8168
|
-
{ name: 'accept', fn: this.acceptValidator },
|
|
8169
|
-
{ name: 'fileSize', fn: this.fileSizeValidator },
|
|
8170
|
-
];
|
|
8171
8278
|
/**
|
|
8172
8279
|
* Whether we should accept a single file or multiple files
|
|
8173
8280
|
*/
|
|
@@ -8264,8 +8371,7 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8264
8371
|
valid: [],
|
|
8265
8372
|
invalid: [],
|
|
8266
8373
|
};
|
|
8267
|
-
|
|
8268
|
-
const error = this.validate(file);
|
|
8374
|
+
forkJoin(files.map(file => this.validate(file).pipe(tap$1(error => {
|
|
8269
8375
|
if (error) {
|
|
8270
8376
|
selection.invalid.push({
|
|
8271
8377
|
file: file,
|
|
@@ -8275,17 +8381,18 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8275
8381
|
else {
|
|
8276
8382
|
selection.valid.push(file);
|
|
8277
8383
|
}
|
|
8278
|
-
}
|
|
8279
|
-
|
|
8280
|
-
|
|
8281
|
-
}
|
|
8282
|
-
if (selection.valid.length || selection.invalid.length) {
|
|
8283
|
-
this.filesChange.emit(selection);
|
|
8284
|
-
if (this.broadcast) {
|
|
8285
|
-
this.naturalFileService.filesChanged.next(selection);
|
|
8384
|
+
})))).subscribe(() => {
|
|
8385
|
+
if (selection.valid.length) {
|
|
8386
|
+
this.fileChange.emit(selection.valid[0]);
|
|
8286
8387
|
}
|
|
8287
|
-
|
|
8288
|
-
|
|
8388
|
+
if (selection.valid.length || selection.invalid.length) {
|
|
8389
|
+
this.filesChange.emit(selection);
|
|
8390
|
+
if (this.broadcast) {
|
|
8391
|
+
this.naturalFileService.filesChanged.next(selection);
|
|
8392
|
+
}
|
|
8393
|
+
}
|
|
8394
|
+
this.getFileElement().value = '';
|
|
8395
|
+
});
|
|
8289
8396
|
}
|
|
8290
8397
|
/**
|
|
8291
8398
|
* Called when input has files
|
|
@@ -8332,18 +8439,18 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8332
8439
|
this.handleFiles(files);
|
|
8333
8440
|
}
|
|
8334
8441
|
validate(file) {
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8442
|
+
return forkJoin({
|
|
8443
|
+
accept: of(acceptType(this.accept, file.type, file.name)),
|
|
8444
|
+
fileSize: of(!(this.maxSize && file.size > this.maxSize)),
|
|
8445
|
+
directory: isDirectory(file),
|
|
8446
|
+
}).pipe(map$1(result => {
|
|
8447
|
+
for (const [key, value] of Object.entries(result)) {
|
|
8448
|
+
if (!value) {
|
|
8449
|
+
return key;
|
|
8450
|
+
}
|
|
8338
8451
|
}
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
}
|
|
8342
|
-
acceptValidator(item) {
|
|
8343
|
-
return acceptType(this.accept, item.type, item.name);
|
|
8344
|
-
}
|
|
8345
|
-
fileSizeValidator(item) {
|
|
8346
|
-
return !(this.maxSize && item.size > this.maxSize);
|
|
8452
|
+
return null;
|
|
8453
|
+
}));
|
|
8347
8454
|
}
|
|
8348
8455
|
}
|
|
8349
8456
|
NaturalAbstractFile.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalAbstractFile, deps: [{ token: i0.ElementRef }, { token: NaturalFileService }, { token: DOCUMENT }], target: i0.ɵɵFactoryTarget.Directive });
|
|
@@ -8695,9 +8802,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
|
|
|
8695
8802
|
*/
|
|
8696
8803
|
|
|
8697
8804
|
class NaturalFixedButtonDetailComponent {
|
|
8698
|
-
constructor() {
|
|
8805
|
+
constructor(route) {
|
|
8806
|
+
this.canChange = true;
|
|
8807
|
+
this.isCreation = false;
|
|
8699
8808
|
this.create = new EventEmitter();
|
|
8700
8809
|
this.delete = new EventEmitter();
|
|
8810
|
+
route.params.subscribe(() => (this.canChange = true));
|
|
8811
|
+
}
|
|
8812
|
+
get model() {
|
|
8813
|
+
return this._model;
|
|
8814
|
+
}
|
|
8815
|
+
set model(value) {
|
|
8816
|
+
this._model = value;
|
|
8817
|
+
if (this.canChange) {
|
|
8818
|
+
this.isCreation = !this._model.id;
|
|
8819
|
+
}
|
|
8701
8820
|
}
|
|
8702
8821
|
clickCreate() {
|
|
8703
8822
|
if (this.form.enabled) {
|
|
@@ -8710,12 +8829,12 @@ class NaturalFixedButtonDetailComponent {
|
|
|
8710
8829
|
}
|
|
8711
8830
|
}
|
|
8712
8831
|
}
|
|
8713
|
-
NaturalFixedButtonDetailComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8714
|
-
NaturalFixedButtonDetailComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: NaturalFixedButtonDetailComponent, selector: "natural-fixed-button-detail", inputs: { model: "model", form: "form" }, outputs: { create: "create", delete: "delete" }, ngImport: i0, template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"
|
|
8832
|
+
NaturalFixedButtonDetailComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, deps: [{ token: i2$1.ActivatedRoute }], target: i0.ɵɵFactoryTarget.Component });
|
|
8833
|
+
NaturalFixedButtonDetailComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.1.1", type: NaturalFixedButtonDetailComponent, selector: "natural-fixed-button-detail", inputs: { model: "model", form: "form" }, outputs: { create: "create", delete: "delete" }, ngImport: i0, template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"isCreation\"\n [disabled]=\"form.disabled\"\n [color]=\"form.valid ? 'accent' : 'warn'\"\n class=\"detail-speed-dial\"\n icon=\"save\"\n></natural-fixed-button>\n\n<natural-fixed-button\n (click)=\"clickDelete()\"\n *ngIf=\"!isCreation && (!model.permissions || model.permissions.delete)\"\n [disabled]=\"form.disabled\"\n class=\"detail-speed-dial\"\n color=\"warn\"\n icon=\"delete_forever\"\n i18n-matTooltip\n matTooltip=\"Supprimer d\u00E9finitivement\"\n matTooltipPosition=\"left\"\n></natural-fixed-button>\n", styles: [""], dependencies: [{ kind: "directive", type: i1$3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: NaturalFixedButtonComponent, selector: "natural-fixed-button", inputs: ["icon", "link", "color", "disabled"] }, { kind: "directive", type: i7.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
|
|
8715
8834
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, decorators: [{
|
|
8716
8835
|
type: Component,
|
|
8717
|
-
args: [{ selector: 'natural-fixed-button-detail', template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"
|
|
8718
|
-
}], propDecorators: { model: [{
|
|
8836
|
+
args: [{ selector: 'natural-fixed-button-detail', template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"isCreation\"\n [disabled]=\"form.disabled\"\n [color]=\"form.valid ? 'accent' : 'warn'\"\n class=\"detail-speed-dial\"\n icon=\"save\"\n></natural-fixed-button>\n\n<natural-fixed-button\n (click)=\"clickDelete()\"\n *ngIf=\"!isCreation && (!model.permissions || model.permissions.delete)\"\n [disabled]=\"form.disabled\"\n class=\"detail-speed-dial\"\n color=\"warn\"\n icon=\"delete_forever\"\n i18n-matTooltip\n matTooltip=\"Supprimer d\u00E9finitivement\"\n matTooltipPosition=\"left\"\n></natural-fixed-button>\n" }]
|
|
8837
|
+
}], ctorParameters: function () { return [{ type: i2$1.ActivatedRoute }]; }, propDecorators: { model: [{
|
|
8719
8838
|
type: Input
|
|
8720
8839
|
}], form: [{
|
|
8721
8840
|
type: Input
|
|
@@ -10842,5 +10961,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
|
|
|
10842
10961
|
* Generated bundle index. Do not edit.
|
|
10843
10962
|
*/
|
|
10844
10963
|
|
|
10845
|
-
export { AvatarComponent, AvatarService, FileComponent, IconsConfigService, LOCAL_STORAGE, NATURAL_DROPDOWN_DATA, NATURAL_SEO_CONFIG, NaturalAbstractController, NaturalAbstractDetail, NaturalAbstractEditableList, NaturalAbstractList, NaturalAbstractModelService, NaturalAbstractNavigableList, NaturalAbstractPanel, NaturalAlertModule, NaturalAlertService, NaturalAvatarModule, NaturalCapitalizePipe, NaturalColumnsPickerColumnDirective, NaturalColumnsPickerComponent, NaturalColumnsPickerModule, NaturalCommonModule, NaturalConfirmComponent, NaturalDataSource, NaturalDetailHeaderComponent, NaturalDetailHeaderModule, NaturalDialogTriggerComponent, NaturalDialogTriggerModule, NaturalDropdownComponentsModule, NaturalDropdownRef, NaturalEllipsisPipe, NaturalEnumPipe, NaturalEnumService, NaturalErrorHandler, NaturalErrorModule, NaturalFileDropDirective, NaturalFileModule, NaturalFileSelectDirective, NaturalFileService, NaturalFixedButtonComponent, NaturalFixedButtonDetailComponent, NaturalFixedButtonDetailModule, NaturalFixedButtonModule, NaturalHierarchicSelectorComponent, NaturalHierarchicSelectorDialogComponent, NaturalHierarchicSelectorDialogService, NaturalHierarchicSelectorModule, NaturalHierarchicSelectorService, NaturalHttpPrefixDirective, NaturalIconComponent, NaturalIconModule, NaturalLinkMutationService, NaturalLinkableTabDirective, NaturalLoggerConfigExtra, NaturalLoggerConfigUrl, NaturalMatomoModule, NaturalMatomoService, NaturalMemoryStorage, NaturalPanelsComponent, NaturalPanelsModule, NaturalPanelsService, NaturalPersistenceService, NaturalQueryVariablesManager, NaturalRelationsComponent, NaturalRelationsModule, NaturalSearchComponent, NaturalSearchModule, NaturalSelectComponent, NaturalSelectEnumComponent, NaturalSelectHierarchicComponent, NaturalSelectModule, NaturalSeoService, NaturalSidenavComponent, NaturalSidenavContainerComponent, NaturalSidenavContentComponent, NaturalSidenavModule, NaturalSidenavService, NaturalSidenavStackService, NaturalSrcDensityDirective, NaturalStampComponent, NaturalStampModule, NaturalSwissDatePipe, NaturalSwissParsingDateAdapter, NaturalTableButtonComponent, NaturalTableButtonModule, PanelsHooksConfig, SESSION_STORAGE, SortingOrder, TypeDateComponent, TypeDateRangeComponent, TypeHierarchicSelectorComponent, TypeNaturalSelectComponent, TypeNumberComponent, TypeSelectComponent, TypeTextComponent, available, cancellableTimeout, cleanSameValues, collectErrors, copyToClipboard, debug, decimal, deepFreeze, deliverableEmail, ensureHttpPrefix, fallbackIfNoOpenedPanels, formatIsoDate, formatIsoDateTime, fromUrl, getForegroundColor, hasFilesAndProcessDate, ifValid, integer, localStorageFactory, localStorageProvider, lowerCaseFirstLetter, makePlural, memoryLocalStorageProvider, memorySessionStorageProvider, mergeOverrideArray, money, naturalPanelsUrlMatcher, relationsToIds, replaceObjectKeepingReference, replaceOperatorByField, replaceOperatorByName, sessionStorageFactory, sessionStorageProvider, toGraphQLDoctrineFilter, toNavigationParameters, toUrl, unique, upperCaseFirstLetter, urlValidator, validTlds, validateAllFormControls, wrapLike };
|
|
10964
|
+
export { AvatarComponent, AvatarService, FileComponent, IconsConfigService, LOCAL_STORAGE, NATURAL_DROPDOWN_DATA, NATURAL_SEO_CONFIG, NaturalAbstractController, NaturalAbstractDetail, NaturalAbstractEditableList, NaturalAbstractList, NaturalAbstractModelService, NaturalAbstractNavigableList, NaturalAbstractPanel, NaturalAlertModule, NaturalAlertService, NaturalAvatarModule, NaturalCapitalizePipe, NaturalColumnsPickerColumnDirective, NaturalColumnsPickerComponent, NaturalColumnsPickerModule, NaturalCommonModule, NaturalConfirmComponent, NaturalDataSource, NaturalDebounceService, NaturalDetailHeaderComponent, NaturalDetailHeaderModule, NaturalDialogTriggerComponent, NaturalDialogTriggerModule, NaturalDropdownComponentsModule, NaturalDropdownRef, NaturalEllipsisPipe, NaturalEnumPipe, NaturalEnumService, NaturalErrorHandler, NaturalErrorModule, NaturalFileDropDirective, NaturalFileModule, NaturalFileSelectDirective, NaturalFileService, NaturalFixedButtonComponent, NaturalFixedButtonDetailComponent, NaturalFixedButtonDetailModule, NaturalFixedButtonModule, NaturalHierarchicSelectorComponent, NaturalHierarchicSelectorDialogComponent, NaturalHierarchicSelectorDialogService, NaturalHierarchicSelectorModule, NaturalHierarchicSelectorService, NaturalHttpPrefixDirective, NaturalIconComponent, NaturalIconModule, NaturalLinkMutationService, NaturalLinkableTabDirective, NaturalLoggerConfigExtra, NaturalLoggerConfigUrl, NaturalMatomoModule, NaturalMatomoService, NaturalMemoryStorage, NaturalPanelsComponent, NaturalPanelsModule, NaturalPanelsService, NaturalPersistenceService, NaturalQueryVariablesManager, NaturalRelationsComponent, NaturalRelationsModule, NaturalSearchComponent, NaturalSearchModule, NaturalSelectComponent, NaturalSelectEnumComponent, NaturalSelectHierarchicComponent, NaturalSelectModule, NaturalSeoService, NaturalSidenavComponent, NaturalSidenavContainerComponent, NaturalSidenavContentComponent, NaturalSidenavModule, NaturalSidenavService, NaturalSidenavStackService, NaturalSrcDensityDirective, NaturalStampComponent, NaturalStampModule, NaturalSwissDatePipe, NaturalSwissParsingDateAdapter, NaturalTableButtonComponent, NaturalTableButtonModule, PanelsHooksConfig, SESSION_STORAGE, SortingOrder, TypeDateComponent, TypeDateRangeComponent, TypeHierarchicSelectorComponent, TypeNaturalSelectComponent, TypeNumberComponent, TypeSelectComponent, TypeTextComponent, available, cancellableTimeout, cleanSameValues, collectErrors, copyToClipboard, debug, decimal, deepFreeze, deliverableEmail, ensureHttpPrefix, fallbackIfNoOpenedPanels, formatIsoDate, formatIsoDateTime, fromUrl, getForegroundColor, hasFilesAndProcessDate, ifValid, integer, localStorageFactory, localStorageProvider, lowerCaseFirstLetter, makePlural, memoryLocalStorageProvider, memorySessionStorageProvider, mergeOverrideArray, money, naturalPanelsUrlMatcher, relationsToIds, replaceObjectKeepingReference, replaceOperatorByField, replaceOperatorByName, sessionStorageFactory, sessionStorageProvider, toGraphQLDoctrineFilter, toNavigationParameters, toUrl, unique, upperCaseFirstLetter, urlValidator, validTlds, validateAllFormControls, wrapLike };
|
|
10846
10965
|
//# sourceMappingURL=ecodev-natural.mjs.map
|