@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';
|
|
@@ -2349,53 +2349,52 @@ class NaturalAbstractDetail extends NaturalAbstractPanel {
|
|
|
2349
2349
|
this.form.disable();
|
|
2350
2350
|
this.service
|
|
2351
2351
|
.create(this.data.model)
|
|
2352
|
-
.pipe(
|
|
2353
|
-
.subscribe(model => {
|
|
2352
|
+
.pipe(switchMap$1(model => {
|
|
2354
2353
|
this.alertService.info($localize `Créé`);
|
|
2355
2354
|
this.form.patchValue(model);
|
|
2356
|
-
this.postCreate(model).
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2355
|
+
return this.postCreate(model).pipe(endWith(model), last());
|
|
2356
|
+
}), switchMap$1(model => {
|
|
2357
|
+
var _a;
|
|
2358
|
+
if (redirect) {
|
|
2359
|
+
if (this.isPanel) {
|
|
2360
|
+
const oldUrl = this.router.url;
|
|
2361
|
+
const nextUrl = (_a = this.panelData) === null || _a === void 0 ? void 0 : _a.config.params.nextRoute;
|
|
2362
|
+
const newUrl = oldUrl.replace('/new', '/' + model.id) + (nextUrl ? '/' + nextUrl : '');
|
|
2363
|
+
return this.router.navigateByUrl(newUrl); // replace /new by /123
|
|
2364
|
+
}
|
|
2365
|
+
else {
|
|
2366
|
+
return this.router.navigate(['..', model.id], { relativeTo: this.route });
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
return EMPTY;
|
|
2370
|
+
}), finalize(() => this.form.enable()))
|
|
2371
|
+
.subscribe();
|
|
2373
2372
|
}
|
|
2374
2373
|
delete(redirectionRoute) {
|
|
2374
|
+
this.form.disable();
|
|
2375
2375
|
this.alertService
|
|
2376
2376
|
.confirm($localize `Suppression`, $localize `Voulez-vous supprimer définitivement cet élément ?`, $localize `Supprimer définitivement`)
|
|
2377
|
-
.
|
|
2378
|
-
if (confirmed) {
|
|
2379
|
-
|
|
2380
|
-
this.form.disable();
|
|
2381
|
-
this.service
|
|
2382
|
-
.delete([this.data.model])
|
|
2383
|
-
.pipe(finalize(() => this.form.enable()))
|
|
2384
|
-
.subscribe(() => {
|
|
2385
|
-
var _a;
|
|
2386
|
-
this.alertService.info($localize `Supprimé`);
|
|
2387
|
-
if (!this.isPanel) {
|
|
2388
|
-
const defaultRoute = ['../../' + kebabCase(this.key)];
|
|
2389
|
-
this.router.navigate(redirectionRoute ? redirectionRoute : defaultRoute, {
|
|
2390
|
-
relativeTo: this.route,
|
|
2391
|
-
});
|
|
2392
|
-
}
|
|
2393
|
-
else {
|
|
2394
|
-
(_a = this.panelService) === null || _a === void 0 ? void 0 : _a.goToPenultimatePanel();
|
|
2395
|
-
}
|
|
2396
|
-
});
|
|
2377
|
+
.pipe(switchMap$1(confirmed => {
|
|
2378
|
+
if (!confirmed) {
|
|
2379
|
+
return EMPTY;
|
|
2397
2380
|
}
|
|
2398
|
-
|
|
2381
|
+
this.preDelete(this.data.model);
|
|
2382
|
+
return this.service.delete([this.data.model]).pipe(switchMap$1(() => {
|
|
2383
|
+
var _a;
|
|
2384
|
+
this.alertService.info($localize `Supprimé`);
|
|
2385
|
+
if (this.isPanel) {
|
|
2386
|
+
(_a = this.panelService) === null || _a === void 0 ? void 0 : _a.goToPenultimatePanel();
|
|
2387
|
+
return EMPTY;
|
|
2388
|
+
}
|
|
2389
|
+
else {
|
|
2390
|
+
const defaultRoute = ['../../' + kebabCase(this.key)];
|
|
2391
|
+
return this.router.navigate(redirectionRoute ? redirectionRoute : defaultRoute, {
|
|
2392
|
+
relativeTo: this.route,
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
}));
|
|
2396
|
+
}), finalize(() => this.form.enable()))
|
|
2397
|
+
.subscribe();
|
|
2399
2398
|
}
|
|
2400
2399
|
postUpdate(model) { }
|
|
2401
2400
|
/**
|
|
@@ -3559,6 +3558,7 @@ function cancellableTimeout(canceller, milliSeconds = 0) {
|
|
|
3559
3558
|
function debug(debugName) {
|
|
3560
3559
|
return tap({
|
|
3561
3560
|
subscribe: () => console.log('SUBSCRIBE', debugName),
|
|
3561
|
+
unsubscribe: () => console.log('UNSUBSCRIBE', debugName),
|
|
3562
3562
|
next: value => console.log('NEXT', debugName, value),
|
|
3563
3563
|
error: error => console.log('ERROR', debugName, error),
|
|
3564
3564
|
complete: () => console.log('COMPLETE', debugName),
|
|
@@ -3566,18 +3566,15 @@ function debug(debugName) {
|
|
|
3566
3566
|
}
|
|
3567
3567
|
|
|
3568
3568
|
class NaturalAbstractModelService {
|
|
3569
|
-
constructor(apollo, name, oneQuery, allQuery, createMutation, updateMutation, deleteMutation) {
|
|
3569
|
+
constructor(apollo, naturalDebounceService, name, oneQuery, allQuery, createMutation, updateMutation, deleteMutation) {
|
|
3570
3570
|
this.apollo = apollo;
|
|
3571
|
+
this.naturalDebounceService = naturalDebounceService;
|
|
3571
3572
|
this.name = name;
|
|
3572
3573
|
this.oneQuery = oneQuery;
|
|
3573
3574
|
this.allQuery = allQuery;
|
|
3574
3575
|
this.createMutation = createMutation;
|
|
3575
3576
|
this.updateMutation = updateMutation;
|
|
3576
3577
|
this.deleteMutation = deleteMutation;
|
|
3577
|
-
/**
|
|
3578
|
-
* Stores the debounced update function
|
|
3579
|
-
*/
|
|
3580
|
-
this.debouncedUpdateCache = new Map();
|
|
3581
3578
|
/**
|
|
3582
3579
|
* Store the creation mutations that are pending
|
|
3583
3580
|
*/
|
|
@@ -3809,36 +3806,7 @@ class NaturalAbstractModelService {
|
|
|
3809
3806
|
this.throwIfNotQuery(this.updateMutation);
|
|
3810
3807
|
// Keep a single instance of the debounced update function
|
|
3811
3808
|
const id = object.id;
|
|
3812
|
-
|
|
3813
|
-
if (!debounced) {
|
|
3814
|
-
const source = new ReplaySubject(1);
|
|
3815
|
-
let wasCancelled = false;
|
|
3816
|
-
const canceller = new Subject();
|
|
3817
|
-
canceller.subscribe(() => {
|
|
3818
|
-
wasCancelled = true;
|
|
3819
|
-
source.complete();
|
|
3820
|
-
canceller.complete();
|
|
3821
|
-
});
|
|
3822
|
-
// Create debounced update function
|
|
3823
|
-
const result = source.pipe(debounceTime(2000), // Wait 2sec.
|
|
3824
|
-
take(1), mergeMap(() => {
|
|
3825
|
-
this.debouncedUpdateCache.delete(id);
|
|
3826
|
-
if (wasCancelled) {
|
|
3827
|
-
return EMPTY;
|
|
3828
|
-
}
|
|
3829
|
-
return this.updateNow(object);
|
|
3830
|
-
}), shareReplay());
|
|
3831
|
-
debounced = {
|
|
3832
|
-
source,
|
|
3833
|
-
canceller,
|
|
3834
|
-
result,
|
|
3835
|
-
};
|
|
3836
|
-
this.debouncedUpdateCache.set(id, debounced);
|
|
3837
|
-
}
|
|
3838
|
-
// Notify our debounced update each time we ask to update
|
|
3839
|
-
debounced.source.next();
|
|
3840
|
-
// Return and observable that is updated when mutation is done
|
|
3841
|
-
return debounced.result;
|
|
3809
|
+
return this.naturalDebounceService.debounce(this, id, this.updateNow(object));
|
|
3842
3810
|
}
|
|
3843
3811
|
/**
|
|
3844
3812
|
* Update an object immediately when subscribing
|
|
@@ -3890,8 +3858,7 @@ class NaturalAbstractModelService {
|
|
|
3890
3858
|
this.throwIfNotQuery(this.deleteMutation);
|
|
3891
3859
|
const ids = objects.map(o => {
|
|
3892
3860
|
// Cancel pending update
|
|
3893
|
-
|
|
3894
|
-
debounced === null || debounced === void 0 ? void 0 : debounced.canceller.next();
|
|
3861
|
+
this.naturalDebounceService.cancel(this, o.id);
|
|
3895
3862
|
return o.id;
|
|
3896
3863
|
});
|
|
3897
3864
|
const variables = merge({
|
|
@@ -4072,6 +4039,132 @@ class NaturalAbstractModelService {
|
|
|
4072
4039
|
}
|
|
4073
4040
|
}
|
|
4074
4041
|
|
|
4042
|
+
/**
|
|
4043
|
+
* Debounce subscriptions to observable, with possibility to cancel one, or flush all of them. Typically,
|
|
4044
|
+
* observables are object updates, so `NaturalAbstractModelService.updateNow()`.
|
|
4045
|
+
*
|
|
4046
|
+
* `key` must be an instance of `NaturalAbstractModelService` to separate objects by their types. So User with ID 1 is
|
|
4047
|
+
* not confused with Product with ID 1. It has no other purpose.
|
|
4048
|
+
*
|
|
4049
|
+
* `id` should be the ID of the object that will be updated.
|
|
4050
|
+
*/
|
|
4051
|
+
class NaturalDebounceService {
|
|
4052
|
+
constructor() {
|
|
4053
|
+
this.flusher = new Subject();
|
|
4054
|
+
/**
|
|
4055
|
+
* Stores the debounced update function
|
|
4056
|
+
*/
|
|
4057
|
+
this.allDebouncedUpdateCache = new Map();
|
|
4058
|
+
}
|
|
4059
|
+
/**
|
|
4060
|
+
* Debounce the given source observable for a short time. If called multiple times with the same key and id,
|
|
4061
|
+
* it will postpone the subscription to the source observable.
|
|
4062
|
+
*
|
|
4063
|
+
* Giving the same key and id but a different source observable will replace the original observable, but
|
|
4064
|
+
* keep the same debouncing timeline.
|
|
4065
|
+
*/
|
|
4066
|
+
debounce(key, id, source) {
|
|
4067
|
+
const debouncedUpdateCache = this.getMap(key);
|
|
4068
|
+
let debounced = debouncedUpdateCache.get(id);
|
|
4069
|
+
if (debounced) {
|
|
4070
|
+
debounced.source = source;
|
|
4071
|
+
}
|
|
4072
|
+
else {
|
|
4073
|
+
const debouncer = new ReplaySubject(1);
|
|
4074
|
+
let wasCancelled = false;
|
|
4075
|
+
const canceller = new Subject();
|
|
4076
|
+
canceller.subscribe(() => {
|
|
4077
|
+
wasCancelled = true;
|
|
4078
|
+
debouncer.complete();
|
|
4079
|
+
canceller.complete();
|
|
4080
|
+
this.delete(key, id);
|
|
4081
|
+
});
|
|
4082
|
+
debounced = {
|
|
4083
|
+
debouncer,
|
|
4084
|
+
canceller,
|
|
4085
|
+
source,
|
|
4086
|
+
result: debouncer.pipe(debounceTime$1(2000), // Wait 2 seconds...
|
|
4087
|
+
raceWith(this.flusher), // ...unless flusher is triggered
|
|
4088
|
+
take$1(1), mergeMap(() => {
|
|
4089
|
+
this.delete(key, id);
|
|
4090
|
+
if (wasCancelled || !debounced) {
|
|
4091
|
+
return EMPTY;
|
|
4092
|
+
}
|
|
4093
|
+
return debounced.source;
|
|
4094
|
+
}), shareReplay$1()),
|
|
4095
|
+
};
|
|
4096
|
+
debouncedUpdateCache.set(id, debounced);
|
|
4097
|
+
}
|
|
4098
|
+
// Notify our debounced update each time we ask to update
|
|
4099
|
+
debounced.debouncer.next();
|
|
4100
|
+
// Return and observable that is updated when mutation is done
|
|
4101
|
+
return debounced.result;
|
|
4102
|
+
}
|
|
4103
|
+
cancel(key, id) {
|
|
4104
|
+
var _a;
|
|
4105
|
+
const debounced = (_a = this.allDebouncedUpdateCache.get(key)) === null || _a === void 0 ? void 0 : _a.get(id);
|
|
4106
|
+
debounced === null || debounced === void 0 ? void 0 : debounced.canceller.next();
|
|
4107
|
+
}
|
|
4108
|
+
/**
|
|
4109
|
+
* Immediately execute all pending updates.
|
|
4110
|
+
*
|
|
4111
|
+
* It should typically be called before login out.
|
|
4112
|
+
*
|
|
4113
|
+
* The returned observable will complete when all updates complete, even if some of them error.
|
|
4114
|
+
*/
|
|
4115
|
+
flush() {
|
|
4116
|
+
const all = [];
|
|
4117
|
+
this.allDebouncedUpdateCache.forEach(map => map.forEach(debounced => {
|
|
4118
|
+
all.push(debounced.result.pipe(catchError(() => of(undefined))));
|
|
4119
|
+
}));
|
|
4120
|
+
if (!all.length) {
|
|
4121
|
+
all.push(of(undefined));
|
|
4122
|
+
}
|
|
4123
|
+
return new Observable(subscriber => {
|
|
4124
|
+
const subscription = forkJoin(all)
|
|
4125
|
+
.pipe(map$1(() => undefined))
|
|
4126
|
+
.subscribe(subscriber);
|
|
4127
|
+
// Flush only after subscription process is finished
|
|
4128
|
+
this.flusher.next();
|
|
4129
|
+
return subscription;
|
|
4130
|
+
});
|
|
4131
|
+
}
|
|
4132
|
+
/**
|
|
4133
|
+
* Count of pending updates
|
|
4134
|
+
*/
|
|
4135
|
+
get count() {
|
|
4136
|
+
let count = 0;
|
|
4137
|
+
this.allDebouncedUpdateCache.forEach(map => (count += map.size));
|
|
4138
|
+
return count;
|
|
4139
|
+
}
|
|
4140
|
+
getMap(key) {
|
|
4141
|
+
let debouncedUpdateCache = this.allDebouncedUpdateCache.get(key);
|
|
4142
|
+
if (!debouncedUpdateCache) {
|
|
4143
|
+
debouncedUpdateCache = new Map();
|
|
4144
|
+
this.allDebouncedUpdateCache.set(key, debouncedUpdateCache);
|
|
4145
|
+
}
|
|
4146
|
+
return debouncedUpdateCache;
|
|
4147
|
+
}
|
|
4148
|
+
delete(key, id) {
|
|
4149
|
+
const map = this.allDebouncedUpdateCache.get(key);
|
|
4150
|
+
if (!map) {
|
|
4151
|
+
return;
|
|
4152
|
+
}
|
|
4153
|
+
map.delete(id);
|
|
4154
|
+
if (!map.size) {
|
|
4155
|
+
this.allDebouncedUpdateCache.delete(key);
|
|
4156
|
+
}
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
NaturalDebounceService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
4160
|
+
NaturalDebounceService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, providedIn: 'root' });
|
|
4161
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalDebounceService, decorators: [{
|
|
4162
|
+
type: Injectable,
|
|
4163
|
+
args: [{
|
|
4164
|
+
providedIn: 'root',
|
|
4165
|
+
}]
|
|
4166
|
+
}] });
|
|
4167
|
+
|
|
4075
4168
|
const enumTypeQuery = gql `
|
|
4076
4169
|
query EnumType($name: String!) {
|
|
4077
4170
|
__type(name: $name) {
|
|
@@ -4280,6 +4373,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
|
|
|
4280
4373
|
}]
|
|
4281
4374
|
}], ctorParameters: function () { return [{ type: i1$1.Apollo }]; } });
|
|
4282
4375
|
|
|
4376
|
+
const patterns = [
|
|
4377
|
+
/^(?<day>\d{1,2})\.(?<month>\d{1,2})\.(?<year>\d{4}|\d{2})$/,
|
|
4378
|
+
/^(?<day>\d{1,2})-(?<month>\d{1,2})-(?<year>\d{4}|\d{2})$/,
|
|
4379
|
+
/^(?<day>\d{1,2})\/(?<month>\d{1,2})\/(?<year>\d{4}|\d{2})$/,
|
|
4380
|
+
/^(?<day>\d{1,2})\\(?<month>\d{1,2})\\(?<year>\d{4}|\d{2})$/,
|
|
4381
|
+
// strict ISO format
|
|
4382
|
+
/^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})$/,
|
|
4383
|
+
];
|
|
4283
4384
|
class NaturalSwissParsingDateAdapter extends NativeDateAdapter {
|
|
4284
4385
|
/**
|
|
4285
4386
|
* Parse commonly accepted swiss format, such as:
|
|
@@ -4293,24 +4394,24 @@ class NaturalSwissParsingDateAdapter extends NativeDateAdapter {
|
|
|
4293
4394
|
return new Date(value);
|
|
4294
4395
|
}
|
|
4295
4396
|
if (typeof value === 'string') {
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4397
|
+
const trimmed = value.trim();
|
|
4398
|
+
for (const pattern of patterns) {
|
|
4399
|
+
const m = trimmed.match(pattern);
|
|
4400
|
+
if (m === null || m === void 0 ? void 0 : m.groups) {
|
|
4401
|
+
const year = +m.groups.year;
|
|
4402
|
+
const month = +m.groups.month;
|
|
4403
|
+
const day = +m.groups.day;
|
|
4404
|
+
return this.createDateIfValid(year, month, day);
|
|
4302
4405
|
}
|
|
4303
|
-
return this.createDateIfValid(year, +m[2], +m[1]);
|
|
4304
|
-
}
|
|
4305
|
-
// Attempt strict ISO format
|
|
4306
|
-
m = value.match(/(\d{4})-(\d{2})-(\d{2})/);
|
|
4307
|
-
if (m) {
|
|
4308
|
-
return this.createDateIfValid(+m[1], +m[2], +m[3]);
|
|
4309
4406
|
}
|
|
4310
4407
|
}
|
|
4311
4408
|
return null;
|
|
4312
4409
|
}
|
|
4313
4410
|
createDateIfValid(year, month, date) {
|
|
4411
|
+
// Assume year 2000 if only two digits
|
|
4412
|
+
if (year < 100) {
|
|
4413
|
+
year += 2000;
|
|
4414
|
+
}
|
|
4314
4415
|
month = month - 1;
|
|
4315
4416
|
if (month >= 0 && month <= 11 && date >= 1 && date <= 31) {
|
|
4316
4417
|
return this.createDate(year, month, date);
|
|
@@ -8125,6 +8226,17 @@ function createFileInput(document) {
|
|
|
8125
8226
|
fileElem.type = 'file';
|
|
8126
8227
|
return fileElem;
|
|
8127
8228
|
}
|
|
8229
|
+
function isDirectory(file) {
|
|
8230
|
+
return file
|
|
8231
|
+
.slice(0, 1)
|
|
8232
|
+
.text()
|
|
8233
|
+
.then(text => {
|
|
8234
|
+
// Firefox will return empty string for a folder, so we must check that special case.
|
|
8235
|
+
// That means that any empty file will incorrectly be interpreted as a folder on all
|
|
8236
|
+
// browsers, but that's tolerable because there is no real use-case to upload an empty file.
|
|
8237
|
+
return text !== '';
|
|
8238
|
+
}, () => false);
|
|
8239
|
+
}
|
|
8128
8240
|
function stopEvent(event) {
|
|
8129
8241
|
event.preventDefault();
|
|
8130
8242
|
event.stopPropagation();
|
|
@@ -8223,10 +8335,6 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8223
8335
|
this.element = element;
|
|
8224
8336
|
this.naturalFileService = naturalFileService;
|
|
8225
8337
|
this.document = document;
|
|
8226
|
-
this.validators = [
|
|
8227
|
-
{ name: 'accept', fn: this.acceptValidator },
|
|
8228
|
-
{ name: 'fileSize', fn: this.fileSizeValidator },
|
|
8229
|
-
];
|
|
8230
8338
|
/**
|
|
8231
8339
|
* Whether we should accept a single file or multiple files
|
|
8232
8340
|
*/
|
|
@@ -8323,8 +8431,7 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8323
8431
|
valid: [],
|
|
8324
8432
|
invalid: [],
|
|
8325
8433
|
};
|
|
8326
|
-
|
|
8327
|
-
const error = this.validate(file);
|
|
8434
|
+
forkJoin(files.map(file => this.validate(file).pipe(tap$1(error => {
|
|
8328
8435
|
if (error) {
|
|
8329
8436
|
selection.invalid.push({
|
|
8330
8437
|
file: file,
|
|
@@ -8334,17 +8441,18 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8334
8441
|
else {
|
|
8335
8442
|
selection.valid.push(file);
|
|
8336
8443
|
}
|
|
8337
|
-
}
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
}
|
|
8341
|
-
if (selection.valid.length || selection.invalid.length) {
|
|
8342
|
-
this.filesChange.emit(selection);
|
|
8343
|
-
if (this.broadcast) {
|
|
8344
|
-
this.naturalFileService.filesChanged.next(selection);
|
|
8444
|
+
})))).subscribe(() => {
|
|
8445
|
+
if (selection.valid.length) {
|
|
8446
|
+
this.fileChange.emit(selection.valid[0]);
|
|
8345
8447
|
}
|
|
8346
|
-
|
|
8347
|
-
|
|
8448
|
+
if (selection.valid.length || selection.invalid.length) {
|
|
8449
|
+
this.filesChange.emit(selection);
|
|
8450
|
+
if (this.broadcast) {
|
|
8451
|
+
this.naturalFileService.filesChanged.next(selection);
|
|
8452
|
+
}
|
|
8453
|
+
}
|
|
8454
|
+
this.getFileElement().value = '';
|
|
8455
|
+
});
|
|
8348
8456
|
}
|
|
8349
8457
|
/**
|
|
8350
8458
|
* Called when input has files
|
|
@@ -8391,18 +8499,18 @@ class NaturalAbstractFile extends NaturalAbstractController {
|
|
|
8391
8499
|
this.handleFiles(files);
|
|
8392
8500
|
}
|
|
8393
8501
|
validate(file) {
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8502
|
+
return forkJoin({
|
|
8503
|
+
accept: of(acceptType(this.accept, file.type, file.name)),
|
|
8504
|
+
fileSize: of(!(this.maxSize && file.size > this.maxSize)),
|
|
8505
|
+
directory: isDirectory(file),
|
|
8506
|
+
}).pipe(map$1(result => {
|
|
8507
|
+
for (const [key, value] of Object.entries(result)) {
|
|
8508
|
+
if (!value) {
|
|
8509
|
+
return key;
|
|
8510
|
+
}
|
|
8397
8511
|
}
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
}
|
|
8401
|
-
acceptValidator(item) {
|
|
8402
|
-
return acceptType(this.accept, item.type, item.name);
|
|
8403
|
-
}
|
|
8404
|
-
fileSizeValidator(item) {
|
|
8405
|
-
return !(this.maxSize && item.size > this.maxSize);
|
|
8512
|
+
return null;
|
|
8513
|
+
}));
|
|
8406
8514
|
}
|
|
8407
8515
|
}
|
|
8408
8516
|
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 });
|
|
@@ -8760,9 +8868,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
|
|
|
8760
8868
|
*/
|
|
8761
8869
|
|
|
8762
8870
|
class NaturalFixedButtonDetailComponent {
|
|
8763
|
-
constructor() {
|
|
8871
|
+
constructor(route) {
|
|
8872
|
+
this.canChange = true;
|
|
8873
|
+
this.isCreation = false;
|
|
8764
8874
|
this.create = new EventEmitter();
|
|
8765
8875
|
this.delete = new EventEmitter();
|
|
8876
|
+
route.params.subscribe(() => (this.canChange = true));
|
|
8877
|
+
}
|
|
8878
|
+
get model() {
|
|
8879
|
+
return this._model;
|
|
8880
|
+
}
|
|
8881
|
+
set model(value) {
|
|
8882
|
+
this._model = value;
|
|
8883
|
+
if (this.canChange) {
|
|
8884
|
+
this.isCreation = !this._model.id;
|
|
8885
|
+
}
|
|
8766
8886
|
}
|
|
8767
8887
|
clickCreate() {
|
|
8768
8888
|
if (this.form.enabled) {
|
|
@@ -8775,12 +8895,12 @@ class NaturalFixedButtonDetailComponent {
|
|
|
8775
8895
|
}
|
|
8776
8896
|
}
|
|
8777
8897
|
}
|
|
8778
|
-
NaturalFixedButtonDetailComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
8779
|
-
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=\"
|
|
8898
|
+
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 });
|
|
8899
|
+
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"] }] });
|
|
8780
8900
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImport: i0, type: NaturalFixedButtonDetailComponent, decorators: [{
|
|
8781
8901
|
type: Component,
|
|
8782
|
-
args: [{ selector: 'natural-fixed-button-detail', template: "<natural-fixed-button\n (click)=\"clickCreate()\"\n *ngIf=\"
|
|
8783
|
-
}], propDecorators: { model: [{
|
|
8902
|
+
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" }]
|
|
8903
|
+
}], ctorParameters: function () { return [{ type: i2$1.ActivatedRoute }]; }, propDecorators: { model: [{
|
|
8784
8904
|
type: Input
|
|
8785
8905
|
}], form: [{
|
|
8786
8906
|
type: Input
|
|
@@ -10916,5 +11036,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.1.1", ngImpor
|
|
|
10916
11036
|
* Generated bundle index. Do not edit.
|
|
10917
11037
|
*/
|
|
10918
11038
|
|
|
10919
|
-
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 };
|
|
11039
|
+
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 };
|
|
10920
11040
|
//# sourceMappingURL=ecodev-natural.mjs.map
|