@oneteme/jquery-table 0.0.13 → 0.0.15
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 +138 -23
- package/esm2022/lib/component/export.manager.mjs +6 -5
- package/esm2022/lib/component/table-preferences.manager.mjs +13 -3
- package/esm2022/lib/component/table.component.mjs +398 -143
- package/esm2022/lib/component/table.constants.mjs +3 -1
- package/esm2022/lib/directive/jqt-cell-def.directive.mjs +4 -2
- package/esm2022/lib/jquery-table.model.mjs +1 -1
- package/fesm2022/oneteme-jquery-table.mjs +418 -148
- package/fesm2022/oneteme-jquery-table.mjs.map +1 -1
- package/lib/component/table.component.d.ts +98 -24
- package/lib/component/table.constants.d.ts +2 -0
- package/lib/directive/jqt-cell-def.directive.d.ts +5 -1
- package/lib/jquery-table.model.d.ts +50 -9
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
Bibliothèque Angular qui encapsule Angular Material Table avec une API orientée configuration runtime.
|
|
4
4
|
|
|
5
|
+
> **Documentation et démonstrations** : [ouvrir l'application de documentation](https://oneteme.github.io/jquery-charts/)
|
|
6
|
+
>
|
|
7
|
+
> La documentation interactive présente les colonnes configurables, la recherche, le Group by, les slices, les préférences et l'intégration avec l'Organizer.
|
|
8
|
+
|
|
9
|
+
## Nouveautés intégrées
|
|
10
|
+
|
|
11
|
+
- préférences persistantes par tableau via `TablePreferencesConfig` et `localStorage` ;
|
|
12
|
+
- export CSV limité aux lignes filtrées et aux colonnes visibles, avec transformation personnalisable ;
|
|
13
|
+
- Group by avec pagination indépendante et slices dynamiques depuis le menu View ;
|
|
14
|
+
- colonnes lazy avec états `idle`, `loading`, `loaded` et `error` ;
|
|
15
|
+
- snapshots de configuration pour conserver les colonnes visibles, l'ordre, les largeurs, le tri, le regroupement et les filtres.
|
|
16
|
+
|
|
5
17
|
## Features
|
|
6
18
|
|
|
7
19
|
- Configuration déclarative du tableau via `TableProvider`
|
|
@@ -12,7 +24,7 @@ Bibliothèque Angular qui encapsule Angular Material Table avec une API orienté
|
|
|
12
24
|
- Pagination standard et pagination par groupe
|
|
13
25
|
- **Group by** : regroupement des lignes par colonne, groupes pliables/dépliables, pagination indépendante par groupe
|
|
14
26
|
- **Slice panel** : filtres catégoriels latéraux, statiques (prédéfinis) ou dynamiques (colonne valeurs uniques), multi-sélection configurable
|
|
15
|
-
- **Chargement paresseux** (lazy) de
|
|
27
|
+
- **Chargement paresseux** (lazy) de colonnes : `lazy: true` + `lazyLoader` dans la config (la colonne n'est demandée qu'à son activation)
|
|
16
28
|
- Rendus de cellule personnalisés via directive `jqtCellDef`
|
|
17
29
|
- État de chargement (`isLoading`) et état vide configurable
|
|
18
30
|
- Événement de clic sur ligne (`rowSelected`)
|
|
@@ -107,6 +119,7 @@ Le `config` complet reste disponible pour activer les fonctionnalités avancées
|
|
|
107
119
|
| `columnsConfig` | `TableColumnProvider<T>[]` | Configuration des colonnes (remplace `config.columns`) |
|
|
108
120
|
| `columnLabels` | `Record<string, string>` | Labels des colonnes pour le mode allégé |
|
|
109
121
|
| `isLoading` | `boolean` | Affiche l'état de chargement (défaut : `false`) |
|
|
122
|
+
| `lazyError` | `boolean` | `true` quand la requête relancée après `lazyColumnsRequested` échoue : les colonnes lazy en attente affichent « Réessayer » (voir colonnes lazy) |
|
|
110
123
|
| `view` | `TableViewConfig` | Surcharge `config.view` si défini (mode HTML) |
|
|
111
124
|
|
|
112
125
|
### Outputs
|
|
@@ -119,6 +132,7 @@ Le `config` complet reste disponible pour activer les fonctionnalités avancées
|
|
|
119
132
|
| `searchChange` | `string` | Frappe dans la barre de recherche |
|
|
120
133
|
| `groupByChange` | `string \| null` | Group by activé (clé) ou désactivé (`null`) |
|
|
121
134
|
| `columnsChange` | `string[]` | Colonnes visibles modifiées (clés dans l'ordre d'affichage) |
|
|
135
|
+
| `lazyColumnsRequested` | `string[]` | Clés cumulées des colonnes `lazy` demandées, émises à l'activation d'une nouvelle colonne (voir colonnes lazy) |
|
|
122
136
|
| `columnAdded` | `TableColumnProvider<T>` | Colonne ajoutée aux colonnes actives |
|
|
123
137
|
| `columnRemoved` | `TableColumnProvider<T>` | Colonne retirée des colonnes actives |
|
|
124
138
|
| `categorySelected` | `string` | Catégorie de slice sélectionnée |
|
|
@@ -141,6 +155,7 @@ interface TableProvider<T = any> {
|
|
|
141
155
|
view?: TableViewConfig;
|
|
142
156
|
labels?: TableLabelsConfig;
|
|
143
157
|
export?: TableExportConfig<T>;
|
|
158
|
+
lazyLoader?: (lazyColumns: string[]) => Observable<T[]>; // Charge les colonnes lazy (lignes complètes)
|
|
144
159
|
preferences?: TablePreferencesConfig; // Sauvegarde dans localStorage
|
|
145
160
|
|
|
146
161
|
defaultSort?: { active: string; direction: 'asc' | 'desc' };
|
|
@@ -168,16 +183,14 @@ interface TableColumnProvider<T = any> {
|
|
|
168
183
|
width?: string; // Largeur CSS en px uniquement pour le calcul min-width (ex: '120px')
|
|
169
184
|
// Les unités %, em, rem sont ignorées dans le calcul de tableMinWidth
|
|
170
185
|
|
|
171
|
-
optional?: boolean; // Colonne masquée par défaut, ajoutables via View menu
|
|
186
|
+
optional?: boolean; // Colonne masquée par défaut, ajoutables via View menu (implicite pour une colonne lazy)
|
|
172
187
|
removable?: boolean; // Peut être retirée manuellement
|
|
173
188
|
|
|
174
189
|
groupable?: boolean; // Disponible comme critère de regroupement dans View menu
|
|
175
190
|
sliceable?: boolean; // Disponible comme slice dynamique dans View menu
|
|
176
191
|
searchValue?: DataProvider<string>; // Valeur utilisée par la recherche texte (si différente de value)
|
|
177
192
|
|
|
178
|
-
lazy?:
|
|
179
|
-
fetchFn: () => Observable<any[]>; // Retourne un tableau dans le même ordre que les lignes
|
|
180
|
-
};
|
|
193
|
+
lazy?: true; // Absente de la requête de base, forcément optionnelle : demandée à sa première activation
|
|
181
194
|
}
|
|
182
195
|
```
|
|
183
196
|
|
|
@@ -288,13 +301,13 @@ Seuls les champs fournis écrasent les défauts français. Voir `JqtI18n` pour l
|
|
|
288
301
|
|
|
289
302
|
## Fonctionnalité — Group by
|
|
290
303
|
|
|
291
|
-
Le regroupement
|
|
304
|
+
Le regroupement est disponible par défaut pour les colonnes qui possèdent un `header`. Utilisez `groupable: false` pour retirer une colonne du menu Group by ; `groupable: true` reste utile pour une colonne sans `header`.
|
|
292
305
|
|
|
293
306
|
```ts
|
|
294
307
|
columns: [
|
|
295
|
-
{ key: 'team', header: 'Équipe'
|
|
296
|
-
{ key: 'status', header: 'Statut'
|
|
297
|
-
{ key: 'name', header: 'Nom' },
|
|
308
|
+
{ key: 'team', header: 'Équipe' },
|
|
309
|
+
{ key: 'status', header: 'Statut' },
|
|
310
|
+
{ key: 'name', header: 'Nom', groupable: false },
|
|
298
311
|
],
|
|
299
312
|
view: { enabled: true },
|
|
300
313
|
pagination: {
|
|
@@ -339,11 +352,12 @@ slices: [
|
|
|
339
352
|
|
|
340
353
|
### Slices dynamiques (depuis le menu View)
|
|
341
354
|
|
|
342
|
-
|
|
355
|
+
Les colonnes qui possèdent un `header` sont disponibles par défaut comme slices dynamiques depuis le menu View. Utilisez `sliceable: false` pour retirer une colonne ; `sliceable: true` reste utile pour une colonne sans `header`.
|
|
343
356
|
|
|
344
357
|
```ts
|
|
345
358
|
columns: [
|
|
346
|
-
{ key: 'team', header: 'Équipe'
|
|
359
|
+
{ key: 'team', header: 'Équipe' },
|
|
360
|
+
{ key: 'reference', header: 'Référence', sliceable: false },
|
|
347
361
|
],
|
|
348
362
|
view: { enabled: true },
|
|
349
363
|
```
|
|
@@ -385,19 +399,70 @@ interface SliceCategory<T = any> {
|
|
|
385
399
|
|
|
386
400
|
## Fonctionnalité — lazy columns
|
|
387
401
|
|
|
402
|
+
Une colonne `lazy: true` est absente de la requête de base : elle réduit la réponse du premier rendu et n'est demandée que si l'utilisateur l'affiche. Elle est donc **forcément optionnelle** : `optional: true` est implicite (inutile de l'écrire) et `optional: false` lève une erreur explicite, car la colonne serait demandée dès le premier rendu, soit une requête de plus pour rien. Le type refuse aussi cette combinaison à la compilation.
|
|
403
|
+
|
|
404
|
+
### Avec `lazyLoader` (le plus simple)
|
|
405
|
+
|
|
406
|
+
`[data]` reste la requête de base de l'application. Le chargeur de la config est appelé à l'activation d'une colonne lazy et retourne les **lignes complètes** (colonnes de base + colonnes lazy demandées) :
|
|
407
|
+
|
|
388
408
|
```ts
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
lazy:
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
]
|
|
409
|
+
config: TableProvider<Country> = {
|
|
410
|
+
columns: [
|
|
411
|
+
col('code', 'Code'),
|
|
412
|
+
col('name', 'Pays'),
|
|
413
|
+
col('capital', 'Capitale', { lazy: true }),
|
|
414
|
+
col('currency', 'Devise', { lazy: true }),
|
|
415
|
+
],
|
|
416
|
+
// colonnes lazy demandées (cumul) : ['capital'], puis ['capital', 'currency']
|
|
417
|
+
lazyLoader: columns => this.api.fetchCountries(columns), // Observable<Country[]>
|
|
418
|
+
};
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
```html
|
|
422
|
+
<jquery-table [config]="config" [data]="countries"></jquery-table>
|
|
398
423
|
```
|
|
399
424
|
|
|
400
|
-
|
|
425
|
+
La table appelle `lazyLoader`, affiche le skeleton, remplace ses lignes par la réponse, gère l'erreur et le bouton « Réessayer » (sans `[lazyError]`), et annule l'appel en cours si une nouvelle demande arrive.
|
|
426
|
+
|
|
427
|
+
- Un nouveau `[data]` (rafraîchissement de l'application) l'emporte sur les lignes du chargeur : si des colonnes lazy ont déjà été demandées, la table rappelle `lazyLoader` avec ce cumul (le skeleton réapparaît le temps de la requête). Pour une page rafraîchie en continu, préférer le mode événement ci-dessous afin d'éviter cette seconde requête.
|
|
428
|
+
- Rien n'est appelé tant que le tableau n'a aucune ligne.
|
|
429
|
+
|
|
430
|
+
### Avec l'événement `lazyColumnsRequested` (l'application garde la main)
|
|
431
|
+
|
|
432
|
+
Sans `lazyLoader`, la table émet `(lazyColumnsRequested)` ; l'application **relance sa requête complète en incluant ces colonnes** et repasse les nouvelles `data`. Tant qu'elles ne sont pas arrivées, la colonne affiche un skeleton ; à leur arrivée, elles remplacent les anciennes lignes.
|
|
433
|
+
|
|
434
|
+
```ts
|
|
435
|
+
config: TableProvider<Session> = {
|
|
436
|
+
columns: [
|
|
437
|
+
col('name', 'Nom'),
|
|
438
|
+
col('address', 'Adresse', { lazy: true }),
|
|
439
|
+
col('status', 'Statut', { lazy: true }),
|
|
440
|
+
],
|
|
441
|
+
};
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
```html
|
|
445
|
+
<jquery-table [config]="config" [data]="rows" [lazyError]="lazyFailed" (lazyColumnsRequested)="onLazyColumns($event)"></jquery-table>
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
```ts
|
|
449
|
+
onLazyColumns(columns: string[]) { // ex. ['address'], puis ['address', 'status']
|
|
450
|
+
this.lazyFailed = false;
|
|
451
|
+
this.api.fetchRows(columns).subscribe({ // même requête que la base + ces colonnes
|
|
452
|
+
next: rows => this.rows = rows,
|
|
453
|
+
error: () => this.lazyFailed = true,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
- `lazyColumnsRequested` émet **toutes** les colonnes lazy demandées depuis le début (cumul) : la requête complète peut être reconstruite à partir de cette seule liste, y compris lors d'un rafraîchissement périodique.
|
|
459
|
+
- Les colonnes `lazy: true` apparaissent dans Organizer > Champs sans être demandées ; l'événement part à l'activation (ou si la colonne sert de Group by / Slice by, y compris `defaultGroupBy`, une préférence restaurée ou un snapshot). Plusieurs colonnes activées dans le même tick partent dans un seul événement.
|
|
460
|
+
- Rien n'est émis tant que le tableau n'a aucune ligne : la première réponse de l'application ne doit pas être prise pour celle qui contient les colonnes.
|
|
461
|
+
- Les nouvelles `data` (changement de `[data]` ou `[dataSource]`) marquent toutes les colonnes demandées comme prêtes. Les données fournies ensuite (rafraîchissement, changement de `config`) doivent donc déjà contenir les colonnes demandées : la table ne les redemande pas.
|
|
462
|
+
- Pour garder le tableau visible pendant la requête, ne pas passer `isLoading` à `true` : seul le skeleton de la colonne apparaît. Annuler la requête précédente (`switchMap`) évite qu'une réponse périmée soit prise pour la bonne.
|
|
463
|
+
- En cas d'échec, passer `[lazyError]` à `true` : les colonnes en attente affichent « Réessayer » (cellule, ou en-tête de groupe si la colonne sert de Group by). Le clic réémet `lazyColumnsRequested` ; repasser `lazyError` à `false` au nouvel essai.
|
|
464
|
+
- Sans `lazyLoader` ni écouteur, une colonne lazy activée resterait en skeleton : en développement, la table l'indique par un avertissement dans la console.
|
|
465
|
+
- Une fois reçue, la colonne se comporte comme une colonne ordinaire : tri, recherche, Group by, Slice by, `value`, `sortValue`, `searchValue`, `jqtCellDef` et export CSV. L'export n'écrit jamais d'état de chargement ou d'erreur (cellule vide).
|
|
401
466
|
|
|
402
467
|
---
|
|
403
468
|
|
|
@@ -420,6 +485,7 @@ Le composant gère l'état `idle | loading | loaded | error` par colonne, avec p
|
|
|
420
485
|
Contexte du template :
|
|
421
486
|
- `$implicit` la ligne brute (`T`)
|
|
422
487
|
- `index` index global de la ligne
|
|
488
|
+
- `value` valeur affichée de la cellule ; seul moyen de lire la valeur d'une colonne `lazy`, absente de la ligne brute (`let-value="value"`). Pour une colonne lazy, le template n'est rendu qu'une fois la valeur chargée : le skeleton et le bouton d'erreur sont gérés par le tableau.
|
|
423
489
|
|
|
424
490
|
---
|
|
425
491
|
|
|
@@ -460,8 +526,7 @@ config: TableProvider<Row> = {
|
|
|
460
526
|
| `sliceConfigs` | `SliceConfig<T>[]` | Configurations des slices |
|
|
461
527
|
| `columns` | `SliceColumnDef<T>[]` | Définitions des colonnes pour la résolution des valeurs |
|
|
462
528
|
| `data` | `T[]` | Données source |
|
|
463
|
-
| `
|
|
464
|
-
| `lazyStatus` | `Map<string, 'idle'\|'loading'\|'loaded'\|'error'>` | État par colonne lazy |
|
|
529
|
+
| `lazyStatus` | `Map<string, 'idle'\|'loading'\|'loaded'\|'error'>` | État par colonne lazy (leurs valeurs sont lues dans les lignes de `data`) |
|
|
465
530
|
| `showToggle` | `boolean` | Affiche le bouton collapse du panel (défaut : `true`) |
|
|
466
531
|
| `showCounts` | `boolean` | Affiche le nombre de lignes par catégorie (défaut : `true`) |
|
|
467
532
|
| `collapsedByDefault` | `boolean` | Les slices démarrent repliés (défaut : `false`) |
|
|
@@ -505,9 +570,59 @@ jquery-table {
|
|
|
505
570
|
/* Accent & danger */
|
|
506
571
|
--jqt-primary-color: #1d4ed8;
|
|
507
572
|
--jqt-danger-color: #dc2626;
|
|
573
|
+
|
|
574
|
+
/* Header / footer */
|
|
575
|
+
--jqt-header-bg: #f5f5f5;
|
|
576
|
+
--jqt-header-text-color: #374151;
|
|
577
|
+
--jqt-header-height: 56px;
|
|
578
|
+
--jqt-header-cell-padding-y: 0px;
|
|
579
|
+
--jqt-footer-bg: #f5f5f5;
|
|
580
|
+
--jqt-footer-text-color: #374151;
|
|
581
|
+
--jqt-footer-icon-color: #374151;
|
|
582
|
+
--jqt-footer-height: 56px;
|
|
583
|
+
|
|
584
|
+
/* Contrôles de la toolbar */
|
|
585
|
+
--jqt-toolbar-control-height: 34px;
|
|
586
|
+
|
|
587
|
+
/* Panneau de slices */
|
|
588
|
+
--jqt-slice-panel-min-width: 155px;
|
|
589
|
+
--jqt-slice-panel-max-width: 190px;
|
|
590
|
+
--jqt-slice-header-height: 34px;
|
|
591
|
+
--jqt-slice-header-margin-bottom: 8px;
|
|
592
|
+
--jqt-slice-body-padding: 4px 10px 10px;
|
|
593
|
+
--jqt-slice-section-title-font-size: 14px;
|
|
594
|
+
--jqt-slice-item-font-size: 13px;
|
|
595
|
+
--jqt-slice-item-min-height: 30px;
|
|
596
|
+
--jqt-slice-item-padding: 5px 10px 5px 16px;
|
|
597
|
+
|
|
598
|
+
/* Bouton Organizer */
|
|
599
|
+
--jqt-organizer-button-height: 34px;
|
|
600
|
+
--jqt-organizer-button-width: 34px;
|
|
601
|
+
--jqt-organizer-button-min-width: 34px;
|
|
602
|
+
--jqt-organizer-button-radius: 8px;
|
|
603
|
+
--jqt-organizer-button-border-color: #e0e0e0;
|
|
604
|
+
--jqt-organizer-button-background: #ffffff;
|
|
605
|
+
--jqt-organizer-button-hover-border-color: #9e9e9e;
|
|
606
|
+
--jqt-organizer-button-hover-background: #ffffff;
|
|
607
|
+
--jqt-organizer-button-icon-color: #000000;
|
|
508
608
|
}
|
|
509
609
|
```
|
|
510
610
|
|
|
611
|
+
Le bouton Organizer intégré peut aussi être configuré via `TableProvider` :
|
|
612
|
+
|
|
613
|
+
```ts
|
|
614
|
+
const table: TableProvider<Row> = {
|
|
615
|
+
organizer: {
|
|
616
|
+
buttonLabel: 'Vue',
|
|
617
|
+
buttonIcon: 'tune',
|
|
618
|
+
showButtonIcon: true,
|
|
619
|
+
hideMenuValues: false,
|
|
620
|
+
},
|
|
621
|
+
};
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
Les variables CSS sont héritées par le tableau, son panneau de slices et son Organizer. Elles permettent notamment de réduire le header/footer, d'ajuster la largeur et la densité des filtres, et de modifier le bouton sans cibler les classes internes Angular Material.
|
|
625
|
+
|
|
511
626
|
---
|
|
512
627
|
|
|
513
628
|
## Utilitaires exportés
|
|
@@ -17,7 +17,8 @@ export class ExportManager {
|
|
|
17
17
|
return;
|
|
18
18
|
const rows = this.getRows();
|
|
19
19
|
const columns = this.getColumns();
|
|
20
|
-
const
|
|
20
|
+
const baseName = cfg.filename || 'export';
|
|
21
|
+
const filename = baseName.toLowerCase().endsWith('.csv') ? baseName : baseName + '.csv';
|
|
21
22
|
const header = columns.map(c => this._csvEscape(c.header || c.key)).join(',');
|
|
22
23
|
const lines = rows.map((row, idx) => {
|
|
23
24
|
if (cfg.transform) {
|
|
@@ -31,15 +32,15 @@ export class ExportManager {
|
|
|
31
32
|
const url = URL.createObjectURL(blob);
|
|
32
33
|
const a = document.createElement('a');
|
|
33
34
|
a.href = url;
|
|
34
|
-
a.download = filename
|
|
35
|
+
a.download = filename;
|
|
35
36
|
a.click();
|
|
36
37
|
URL.revokeObjectURL(url);
|
|
37
38
|
}
|
|
38
39
|
_csvEscape(value) {
|
|
39
|
-
if (value.includes(',') || value.includes('"') || value.includes('\n')) {
|
|
40
|
-
return '"' + value.
|
|
40
|
+
if (value.includes(',') || value.includes('"') || value.includes('\n') || value.includes('\r')) {
|
|
41
|
+
return '"' + value.replaceAll('"', '""') + '"';
|
|
41
42
|
}
|
|
42
43
|
return value;
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
46
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwb3J0Lm1hbmFnZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9vbmV0ZW1lL2pxdWVyeS10YWJsZS9zcmMvbGliL2NvbXBvbmVudC9leHBvcnQubWFuYWdlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFFQTs7Ozs7R0FLRztBQUNILE1BQU0sT0FBTyxhQUFhO0lBQ3hCLFlBQ21CLE9BQWtCLEVBQ2xCLFVBQTBDLEVBQzFDLFNBQWlELEVBQ2pELGdCQUE2RTtRQUg3RSxZQUFPLEdBQVAsT0FBTyxDQUFXO1FBQ2xCLGVBQVUsR0FBVixVQUFVLENBQWdDO1FBQzFDLGNBQVMsR0FBVCxTQUFTLENBQXdDO1FBQ2pELHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBNkQ7SUFDN0YsQ0FBQztJQUVKLE1BQU07UUFDSixNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7UUFDN0IsSUFBSSxDQUFDLEdBQUcsRUFBRSxPQUFPO1lBQUUsT0FBTztRQUMxQixNQUFNLElBQUksR0FBTSxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDL0IsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQ2xDLE1BQU0sUUFBUSxHQUFHLEdBQUcsQ0FBQyxRQUFRLElBQUksUUFBUSxDQUFDO1FBQzFDLE1BQU0sUUFBUSxHQUFHLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsUUFBUSxHQUFHLE1BQU0sQ0FBQztRQUV4RixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM5RSxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO1lBQ2xDLElBQUksR0FBRyxDQUFDLFNBQVMsRUFBRTtnQkFDakIsTUFBTSxDQUFDLEdBQUcsR0FBRyxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQztnQkFDN0IsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO2FBQzVFO1lBQ0QsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN2RyxDQUFDLENBQUMsQ0FBQztRQUVILG1EQUFtRDtRQUNuRCxNQUFNLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLFFBQVEsR0FBRyxDQUFDLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLHdCQUF3QixFQUFFLENBQUMsQ0FBQztRQUN0RyxNQUFNLEdBQUcsR0FBSSxHQUFHLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZDLE1BQU0sQ0FBQyxHQUFNLFFBQVEsQ0FBQyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDekMsQ0FBQyxDQUFDLElBQUksR0FBRyxHQUFHLENBQUM7UUFDYixDQUFDLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQztRQUN0QixDQUFDLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDVixHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFFTyxVQUFVLENBQUMsS0FBYTtRQUM5QixJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDOUYsT0FBTyxHQUFHLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsR0FBRyxDQUFDO1NBQ2hEO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0NBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBUYWJsZUNvbHVtblByb3ZpZGVyLCBUYWJsZUV4cG9ydENvbmZpZyB9IGZyb20gJy4uL2pxdWVyeS10YWJsZS5tb2RlbCc7XG5cbi8qKlxuICogRXhwb3J0TWFuYWdlclxuICpcbiAqIEVuY2Fwc3VsZSBsJ2V4cG9ydCBDU1YgOiBjb25zdHJ1Y3Rpb24gZHUgZmljaGllciBCT00vVVRGLTgsIMOpY2hhcHBlbWVudCBldCBkw6ljbGVuY2hlbWVudCBkdSB0w6lsw6ljaGFyZ2VtZW50LlxuICogQXVjdW5lIGTDqXBlbmRhbmNlIEFuZ3VsYXIg4oCUIGluZMOpcGVuZGFudCBkdSBjeWNsZSBkZSB2aWUgZHUgY29tcG9zYW50LlxuICovXG5leHBvcnQgY2xhc3MgRXhwb3J0TWFuYWdlcjxUPiB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0Um93czogKCkgPT4gVFtdLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0Q29sdW1uczogKCkgPT4gVGFibGVDb2x1bW5Qcm92aWRlcjxUPltdLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0Q29uZmlnOiAoKSA9PiBUYWJsZUV4cG9ydENvbmZpZzxUPiB8IHVuZGVmaW5lZCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlc29sdmVDZWxsVmFsdWU6IChjb2w6IFRhYmxlQ29sdW1uUHJvdmlkZXI8VD4sIHJvdzogVCwgaW5kZXg6IG51bWJlcikgPT4gYW55LFxuICApIHt9XG5cbiAgZXhwb3J0KCk6IHZvaWQge1xuICAgIGNvbnN0IGNmZyA9IHRoaXMuZ2V0Q29uZmlnKCk7XG4gICAgaWYgKCFjZmc/LmVuYWJsZWQpIHJldHVybjtcbiAgICBjb25zdCByb3dzICAgID0gdGhpcy5nZXRSb3dzKCk7XG4gICAgY29uc3QgY29sdW1ucyA9IHRoaXMuZ2V0Q29sdW1ucygpO1xuICAgIGNvbnN0IGJhc2VOYW1lID0gY2ZnLmZpbGVuYW1lIHx8ICdleHBvcnQnO1xuICAgIGNvbnN0IGZpbGVuYW1lID0gYmFzZU5hbWUudG9Mb3dlckNhc2UoKS5lbmRzV2l0aCgnLmNzdicpID8gYmFzZU5hbWUgOiBiYXNlTmFtZSArICcuY3N2JztcblxuICAgIGNvbnN0IGhlYWRlciA9IGNvbHVtbnMubWFwKGMgPT4gdGhpcy5fY3N2RXNjYXBlKGMuaGVhZGVyIHx8IGMua2V5KSkuam9pbignLCcpO1xuICAgIGNvbnN0IGxpbmVzID0gcm93cy5tYXAoKHJvdywgaWR4KSA9PiB7XG4gICAgICBpZiAoY2ZnLnRyYW5zZm9ybSkge1xuICAgICAgICBjb25zdCB0ID0gY2ZnLnRyYW5zZm9ybShyb3cpO1xuICAgICAgICByZXR1cm4gY29sdW1ucy5tYXAoYyA9PiB0aGlzLl9jc3ZFc2NhcGUoU3RyaW5nKHRbYy5rZXldID8/ICcnKSkpLmpvaW4oJywnKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjb2x1bW5zLm1hcChjID0+IHRoaXMuX2NzdkVzY2FwZShTdHJpbmcodGhpcy5yZXNvbHZlQ2VsbFZhbHVlKGMsIHJvdywgaWR4KSA/PyAnJykpKS5qb2luKCcsJyk7XG4gICAgfSk7XG5cbiAgICAvLyBCT00gVVRGLTggcG91ciB1bmUgb3V2ZXJ0dXJlIGNvcnJlY3RlIHNvdXMgRXhjZWxcbiAgICBjb25zdCBibG9iID0gbmV3IEJsb2IoWydcXHVGRUZGJyArIFtoZWFkZXIsIC4uLmxpbmVzXS5qb2luKCdcXG4nKV0sIHsgdHlwZTogJ3RleHQvY3N2O2NoYXJzZXQ9dXRmLTgnIH0pO1xuICAgIGNvbnN0IHVybCAgPSBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpO1xuICAgIGNvbnN0IGEgICAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgYS5ocmVmID0gdXJsO1xuICAgIGEuZG93bmxvYWQgPSBmaWxlbmFtZTtcbiAgICBhLmNsaWNrKCk7XG4gICAgVVJMLnJldm9rZU9iamVjdFVSTCh1cmwpO1xuICB9XG5cbiAgcHJpdmF0ZSBfY3N2RXNjYXBlKHZhbHVlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGlmICh2YWx1ZS5pbmNsdWRlcygnLCcpIHx8IHZhbHVlLmluY2x1ZGVzKCdcIicpIHx8IHZhbHVlLmluY2x1ZGVzKCdcXG4nKSB8fCB2YWx1ZS5pbmNsdWRlcygnXFxyJykpIHtcbiAgICAgIHJldHVybiAnXCInICsgdmFsdWUucmVwbGFjZUFsbCgnXCInLCAnXCJcIicpICsgJ1wiJztcbiAgICB9XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9XG59XG4iXX0=
|
|
@@ -28,11 +28,21 @@ export class TablePreferencesManager {
|
|
|
28
28
|
}
|
|
29
29
|
/** Supprime la configuration sauvegardée. */
|
|
30
30
|
clear() {
|
|
31
|
-
|
|
31
|
+
try {
|
|
32
|
+
localStorage.removeItem(this.key);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// stockage indisponible : rien à effacer
|
|
36
|
+
}
|
|
32
37
|
}
|
|
33
38
|
/** Indique si une configuration est actuellement sauvegardée. */
|
|
34
39
|
hasSaved() {
|
|
35
|
-
|
|
40
|
+
try {
|
|
41
|
+
return localStorage.getItem(this.key) !== null;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
36
46
|
}
|
|
37
47
|
}
|
|
38
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
48
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFibGUtcHJlZmVyZW5jZXMubWFuYWdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL29uZXRlbWUvanF1ZXJ5LXRhYmxlL3NyYy9saWIvY29tcG9uZW50L3RhYmxlLXByZWZlcmVuY2VzLm1hbmFnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFDO0FBRXBDOzs7R0FHRztBQUNILE1BQU0sT0FBTyx1QkFBdUI7SUFHbEMsWUFBWSxPQUFlO1FBQ3pCLElBQUksQ0FBQyxHQUFHLEdBQUcsY0FBYyxHQUFHLE9BQU8sQ0FBQztJQUN0QyxDQUFDO0lBRUQsK0VBQStFO0lBQy9FLElBQUk7UUFDRixJQUFJO1lBQ0YsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDM0MsT0FBTyxHQUFHLENBQUMsQ0FBQyxDQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFzQixDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7U0FDM0Q7UUFBQyxNQUFNO1lBQ04sT0FBTyxJQUFJLENBQUM7U0FDYjtJQUNILENBQUM7SUFFRCxzREFBc0Q7SUFDdEQsSUFBSSxDQUFDLE1BQXdCO1FBQzNCLElBQUk7WUFDRixZQUFZLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1NBQ3hEO1FBQUMsTUFBTTtZQUNOLDBFQUEwRTtTQUMzRTtJQUNILENBQUM7SUFFRCw2Q0FBNkM7SUFDN0MsS0FBSztRQUNILElBQUk7WUFDRixZQUFZLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztTQUNuQztRQUFDLE1BQU07WUFDTix5Q0FBeUM7U0FDMUM7SUFDSCxDQUFDO0lBRUQsaUVBQWlFO0lBQ2pFLFFBQVE7UUFDTixJQUFJO1lBQ0YsT0FBTyxZQUFZLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxJQUFJLENBQUM7U0FDaEQ7UUFBQyxNQUFNO1lBQ04sT0FBTyxLQUFLLENBQUM7U0FDZDtJQUNILENBQUM7Q0FDRiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFNhdmVkVGFibGVDb25maWcgfSBmcm9tICcuLi9qcXVlcnktdGFibGUubW9kZWwnO1xuXG5jb25zdCBTVE9SQUdFX1BSRUZJWCA9ICdqcXRfcHJlZnNfJztcblxuLyoqXG4gKiBHw6hyZSBsYSBwZXJzaXN0YW5jZSBkZSBsYSBjb25maWd1cmF0aW9uIGQndW4gdGFibGVhdSBkYW5zIGxlIGxvY2FsU3RvcmFnZS5cbiAqIElkZW50aWZpZSBjaGFxdWUgdGFibGVhdSBwYXIgdW4gYHRhYmxlSWRgIHVuaXF1ZSBmb3VybmkgcGFyIGwndXRpbGlzYXRldXIuXG4gKi9cbmV4cG9ydCBjbGFzcyBUYWJsZVByZWZlcmVuY2VzTWFuYWdlciB7XG4gIHJlYWRvbmx5IGtleTogc3RyaW5nO1xuXG4gIGNvbnN0cnVjdG9yKHRhYmxlSWQ6IHN0cmluZykge1xuICAgIHRoaXMua2V5ID0gU1RPUkFHRV9QUkVGSVggKyB0YWJsZUlkO1xuICB9XG5cbiAgLyoqIFJldG91cm5lIGxhIGNvbmZpZ3VyYXRpb24gc2F1dmVnYXJkw6llLCBvdSBgbnVsbGAgc2kgYWJzZW50ZSAvIGNvcnJvbXB1ZS4gKi9cbiAgbG9hZCgpOiBTYXZlZFRhYmxlQ29uZmlnIHwgbnVsbCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJhdyA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMua2V5KTtcbiAgICAgIHJldHVybiByYXcgPyAoSlNPTi5wYXJzZShyYXcpIGFzIFNhdmVkVGFibGVDb25maWcpIDogbnVsbDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBQZXJzaXN0ZSBsYSBjb25maWd1cmF0aW9uIGRhbnMgbGUgbG9jYWxTdG9yYWdlLiAqL1xuICBzYXZlKGNvbmZpZzogU2F2ZWRUYWJsZUNvbmZpZyk6IHZvaWQge1xuICAgIHRyeSB7XG4gICAgICBsb2NhbFN0b3JhZ2Uuc2V0SXRlbSh0aGlzLmtleSwgSlNPTi5zdHJpbmdpZnkoY29uZmlnKSk7XG4gICAgfSBjYXRjaCB7XG4gICAgICAvLyBsb2NhbFN0b3JhZ2UgcGV1dCDDqnRyZSBpbmRpc3BvbmlibGUgKG1vZGUgcHJpdsOpIHN0cmljdCwgcXVvdGEgZMOpcGFzc8Op4oCmKVxuICAgIH1cbiAgfVxuXG4gIC8qKiBTdXBwcmltZSBsYSBjb25maWd1cmF0aW9uIHNhdXZlZ2FyZMOpZS4gKi9cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKHRoaXMua2V5KTtcbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIHN0b2NrYWdlIGluZGlzcG9uaWJsZSA6IHJpZW4gw6AgZWZmYWNlclxuICAgIH1cbiAgfVxuXG4gIC8qKiBJbmRpcXVlIHNpIHVuZSBjb25maWd1cmF0aW9uIGVzdCBhY3R1ZWxsZW1lbnQgc2F1dmVnYXJkw6llLiAqL1xuICBoYXNTYXZlZCgpOiBib29sZWFuIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGxvY2FsU3RvcmFnZS5nZXRJdGVtKHRoaXMua2V5KSAhPT0gbnVsbDtcbiAgICB9IGNhdGNoIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cbn1cbiJdfQ==
|