ngx-form-draft 1.0.2 → 2.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/README.md +6 -13
- package/dist/LICENSE +21 -0
- package/dist/README.md +144 -0
- package/dist/esm2020/form-draft-banner.component.mjs +105 -0
- package/dist/esm2020/form-draft.directive.mjs +221 -0
- package/dist/esm2020/form-draft.service.mjs +67 -0
- package/dist/esm2020/index.mjs +5 -0
- package/dist/esm2020/ngx-form-draft.mjs +5 -0
- package/dist/esm2020/ngx-form-draft.module.mjs +19 -0
- package/dist/fesm2015/ngx-form-draft.mjs +414 -0
- package/dist/fesm2015/ngx-form-draft.mjs.map +1 -0
- package/dist/fesm2020/ngx-form-draft.mjs +409 -0
- package/dist/fesm2020/ngx-form-draft.mjs.map +1 -0
- package/dist/form-draft-banner.component.d.ts +3 -0
- package/dist/form-draft.directive.d.ts +3 -0
- package/dist/form-draft.service.d.ts +3 -0
- package/dist/ngx-form-draft.module.d.ts +7 -0
- package/dist/package.json +64 -0
- package/package.json +25 -10
- package/dist/form-draft-banner.component.js +0 -111
- package/dist/form-draft.directive.js +0 -240
- package/dist/form-draft.service.js +0 -64
- package/dist/index.js +0 -4
- package/dist/ngx-form-draft.module.js +0 -15
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# ngx-form-draft
|
|
2
2
|
|
|
3
|
-
Zero-dependency Angular form draft auto-save and restore. Works with
|
|
3
|
+
Zero-dependency Angular form draft auto-save and restore. Works with Angular 14+.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -12,24 +12,17 @@ Zero-dependency Angular form draft auto-save and restore. Works with any Angular
|
|
|
12
12
|
- 7-day draft expiration
|
|
13
13
|
- Zero external dependencies
|
|
14
14
|
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Angular 14 or higher
|
|
18
|
+
- TypeScript 4.7+
|
|
19
|
+
|
|
15
20
|
## Installation
|
|
16
21
|
|
|
17
22
|
```bash
|
|
18
23
|
npm install ngx-form-draft
|
|
19
24
|
```
|
|
20
25
|
|
|
21
|
-
### Angular 12 Users
|
|
22
|
-
|
|
23
|
-
If you're using Angular 12, enable Ivy in your `tsconfig.json`:
|
|
24
|
-
|
|
25
|
-
```json
|
|
26
|
-
{
|
|
27
|
-
"angularCompilerOptions": {
|
|
28
|
-
"enableIvy": true
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
```
|
|
32
|
-
|
|
33
26
|
## Usage
|
|
34
27
|
|
|
35
28
|
### 1. Import the module
|
package/dist/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Neokyuubi
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# ngx-form-draft
|
|
2
|
+
|
|
3
|
+
Zero-dependency Angular form draft auto-save and restore. Works with Angular 14+.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Auto-saves form values to localStorage
|
|
8
|
+
- Restores drafts on page reload
|
|
9
|
+
- Works with Reactive and Template-driven forms
|
|
10
|
+
- Handles nested FormGroups and FormArrays
|
|
11
|
+
- Visual banner with discard option
|
|
12
|
+
- 7-day draft expiration
|
|
13
|
+
- Zero external dependencies
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- Angular 14 or higher
|
|
18
|
+
- TypeScript 4.7+
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install ngx-form-draft
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### 1. Import the module
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { NgxFormDraftModule } from 'ngx-form-draft';
|
|
32
|
+
|
|
33
|
+
@NgModule({
|
|
34
|
+
imports: [NgxFormDraftModule]
|
|
35
|
+
})
|
|
36
|
+
export class AppModule {}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 2. Add directive to your form
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<form [formGroup]="myForm" ngxFormDraft="uniqueFormId">
|
|
43
|
+
<!-- form fields -->
|
|
44
|
+
</form>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### 3. Scoped drafts (per entity)
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<form [formGroup]="editForm" [ngxFormDraft]="'edit_' + userId">
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Options
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<form
|
|
57
|
+
[formGroup]="myForm"
|
|
58
|
+
[ngxFormDraft]="'myForm_' + entityId"
|
|
59
|
+
[draftDebounce]="1000"
|
|
60
|
+
[draftExcludeFields]="['password', 'confirmPassword']"
|
|
61
|
+
[draftShowOnChange]="true"
|
|
62
|
+
[draftRestoredText]="'Draft restored'"
|
|
63
|
+
[draftSavedText]="'Draft saved'"
|
|
64
|
+
[draftSavedLabel]="'saved'"
|
|
65
|
+
[draftDiscardText]="'Discard'">
|
|
66
|
+
</form>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Input Properties
|
|
70
|
+
|
|
71
|
+
- `ngxFormDraft` (string): Unique form identifier
|
|
72
|
+
- `draftDebounce` (number): Debounce time in ms (default: 800)
|
|
73
|
+
- `draftExcludeFields` (string[]): Fields to exclude from draft
|
|
74
|
+
- `draftShowOnChange` (boolean): Show banner immediately on change (default: false)
|
|
75
|
+
- `draftRestoredText` (string): Banner text for restored draft
|
|
76
|
+
- `draftSavedText` (string): Banner text for saved draft
|
|
77
|
+
- `draftSavedLabel` (string): Label before timestamp
|
|
78
|
+
- `draftDiscardText` (string): Discard button text
|
|
79
|
+
|
|
80
|
+
## Internationalization (i18n)
|
|
81
|
+
|
|
82
|
+
The package has **zero dependencies** and supports any i18n solution. Just pass translated strings via inputs:
|
|
83
|
+
|
|
84
|
+
### With ngx-translate:
|
|
85
|
+
```html
|
|
86
|
+
<form
|
|
87
|
+
[formGroup]="myForm"
|
|
88
|
+
ngxFormDraft="myForm"
|
|
89
|
+
[draftRestoredText]="'form_draft.restored' | translate"
|
|
90
|
+
[draftSavedText]="'form_draft.saved' | translate"
|
|
91
|
+
[draftSavedLabel]="'form_draft.saved_label' | translate"
|
|
92
|
+
[draftDiscardText]="'form_draft.discard' | translate">
|
|
93
|
+
</form>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### With Angular i18n:
|
|
97
|
+
```html
|
|
98
|
+
<form
|
|
99
|
+
[formGroup]="myForm"
|
|
100
|
+
ngxFormDraft="myForm"
|
|
101
|
+
[draftRestoredText]="restoredText"
|
|
102
|
+
[draftSavedText]="savedText"
|
|
103
|
+
[draftDiscardText]="discardText"
|
|
104
|
+
i18n-draftRestoredText="@@formDraftRestored"
|
|
105
|
+
i18n-draftSavedText="@@formDraftSaved"
|
|
106
|
+
i18n-draftDiscardText="@@formDraftDiscard">
|
|
107
|
+
</form>
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### With component properties:
|
|
111
|
+
```typescript
|
|
112
|
+
// component.ts
|
|
113
|
+
export class MyComponent {
|
|
114
|
+
draftTexts = {
|
|
115
|
+
restored: 'Brouillon restauré',
|
|
116
|
+
saved: 'Brouillon sauvegardé',
|
|
117
|
+
savedLabel: 'sauvegardé',
|
|
118
|
+
discard: 'Supprimer'
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
```html
|
|
124
|
+
<!-- template.html -->
|
|
125
|
+
<form
|
|
126
|
+
[formGroup]="myForm"
|
|
127
|
+
ngxFormDraft="myForm"
|
|
128
|
+
[draftRestoredText]="draftTexts.restored"
|
|
129
|
+
[draftSavedText]="draftTexts.saved"
|
|
130
|
+
[draftSavedLabel]="draftTexts.savedLabel"
|
|
131
|
+
[draftDiscardText]="draftTexts.discard">
|
|
132
|
+
</form>
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Default English text:
|
|
136
|
+
If you don't provide any text inputs, defaults are:
|
|
137
|
+
- `draftRestoredText`: "Draft restored"
|
|
138
|
+
- `draftSavedText`: "Draft saved"
|
|
139
|
+
- `draftSavedLabel`: "saved"
|
|
140
|
+
- `draftDiscardText`: "Discard"
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
|
|
2
|
+
import { trigger, transition, style, animate } from '@angular/animations';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "@angular/common";
|
|
5
|
+
export class FormDraftBannerComponent {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.visible = false;
|
|
8
|
+
this.timeLabel = '';
|
|
9
|
+
this.isRestored = false;
|
|
10
|
+
this.restoredText = 'Draft restored';
|
|
11
|
+
this.savedText = 'Draft saved';
|
|
12
|
+
this.savedLabel = 'saved';
|
|
13
|
+
this.discardText = 'Discard';
|
|
14
|
+
this.discard = new EventEmitter();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
FormDraftBannerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftBannerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
18
|
+
FormDraftBannerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: FormDraftBannerComponent, selector: "ngx-form-draft-banner", inputs: { visible: "visible", timeLabel: "timeLabel", isRestored: "isRestored", restoredText: "restoredText", savedText: "savedText", savedLabel: "savedLabel", discardText: "discardText" }, outputs: { discard: "discard" }, ngImport: i0, template: `
|
|
19
|
+
<div class="form-draft-banner" *ngIf="visible" [@slideDown]>
|
|
20
|
+
<div class="form-draft-banner__icon">
|
|
21
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
22
|
+
<path d="M12 8V12L14.5 14.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
23
|
+
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/>
|
|
24
|
+
</svg>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="form-draft-banner__content">
|
|
27
|
+
<span class="form-draft-banner__text">
|
|
28
|
+
<span *ngIf="isRestored">{{ restoredText }}</span>
|
|
29
|
+
<span *ngIf="!isRestored">{{ savedText }}</span>
|
|
30
|
+
<span class="form-draft-banner__time" *ngIf="timeLabel && isRestored">
|
|
31
|
+
· {{ savedLabel }} {{ timeLabel }}
|
|
32
|
+
</span>
|
|
33
|
+
</span>
|
|
34
|
+
</div>
|
|
35
|
+
<div class="form-draft-banner__actions">
|
|
36
|
+
<button class="form-draft-banner__btn form-draft-banner__btn--discard" (click)="discard.emit()" type="button">
|
|
37
|
+
✕ {{ discardText }}
|
|
38
|
+
</button>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
`, isInline: true, styles: [":host{display:block;width:100%}.form-draft-banner{display:flex;align-items:center;gap:10px;padding:10px 14px;margin-bottom:12px;border-radius:8px;background:linear-gradient(135deg,#eef6ff 0%,#f0f4ff 100%);border:1px solid #c5ddf8;box-shadow:0 2px 8px #128ad614}.form-draft-banner__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;background:linear-gradient(135deg,#128ad6,#22b9ff);color:#fff;flex-shrink:0}.form-draft-banner__content{flex:1;min-width:0}.form-draft-banner__text{font-size:13px;font-weight:600;color:#1a3a5c}.form-draft-banner__time{font-weight:400;color:#6b8aaa;font-size:12px}.form-draft-banner__actions{flex-shrink:0}.form-draft-banner__btn{border:none;padding:5px 12px;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s ease}.form-draft-banner__btn--discard{background:transparent;color:#8899a6;border:1px solid #d0dce6}.form-draft-banner__btn--discard:hover{background:#fef2f2;color:#e62e43;border-color:#e62e43}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], animations: [
|
|
42
|
+
trigger('slideDown', [
|
|
43
|
+
transition(':enter', [
|
|
44
|
+
style({ opacity: 0, transform: 'translateY(-8px)' }),
|
|
45
|
+
animate('250ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0)' }))
|
|
46
|
+
]),
|
|
47
|
+
transition(':leave', [
|
|
48
|
+
animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-8px)' }))
|
|
49
|
+
])
|
|
50
|
+
])
|
|
51
|
+
], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
52
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftBannerComponent, decorators: [{
|
|
53
|
+
type: Component,
|
|
54
|
+
args: [{ selector: 'ngx-form-draft-banner', template: `
|
|
55
|
+
<div class="form-draft-banner" *ngIf="visible" [@slideDown]>
|
|
56
|
+
<div class="form-draft-banner__icon">
|
|
57
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
58
|
+
<path d="M12 8V12L14.5 14.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
59
|
+
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/>
|
|
60
|
+
</svg>
|
|
61
|
+
</div>
|
|
62
|
+
<div class="form-draft-banner__content">
|
|
63
|
+
<span class="form-draft-banner__text">
|
|
64
|
+
<span *ngIf="isRestored">{{ restoredText }}</span>
|
|
65
|
+
<span *ngIf="!isRestored">{{ savedText }}</span>
|
|
66
|
+
<span class="form-draft-banner__time" *ngIf="timeLabel && isRestored">
|
|
67
|
+
· {{ savedLabel }} {{ timeLabel }}
|
|
68
|
+
</span>
|
|
69
|
+
</span>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="form-draft-banner__actions">
|
|
72
|
+
<button class="form-draft-banner__btn form-draft-banner__btn--discard" (click)="discard.emit()" type="button">
|
|
73
|
+
✕ {{ discardText }}
|
|
74
|
+
</button>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
`, animations: [
|
|
78
|
+
trigger('slideDown', [
|
|
79
|
+
transition(':enter', [
|
|
80
|
+
style({ opacity: 0, transform: 'translateY(-8px)' }),
|
|
81
|
+
animate('250ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0)' }))
|
|
82
|
+
]),
|
|
83
|
+
transition(':leave', [
|
|
84
|
+
animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-8px)' }))
|
|
85
|
+
])
|
|
86
|
+
])
|
|
87
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%}.form-draft-banner{display:flex;align-items:center;gap:10px;padding:10px 14px;margin-bottom:12px;border-radius:8px;background:linear-gradient(135deg,#eef6ff 0%,#f0f4ff 100%);border:1px solid #c5ddf8;box-shadow:0 2px 8px #128ad614}.form-draft-banner__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:6px;background:linear-gradient(135deg,#128ad6,#22b9ff);color:#fff;flex-shrink:0}.form-draft-banner__content{flex:1;min-width:0}.form-draft-banner__text{font-size:13px;font-weight:600;color:#1a3a5c}.form-draft-banner__time{font-weight:400;color:#6b8aaa;font-size:12px}.form-draft-banner__actions{flex-shrink:0}.form-draft-banner__btn{border:none;padding:5px 12px;border-radius:6px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s ease}.form-draft-banner__btn--discard{background:transparent;color:#8899a6;border:1px solid #d0dce6}.form-draft-banner__btn--discard:hover{background:#fef2f2;color:#e62e43;border-color:#e62e43}\n"] }]
|
|
88
|
+
}], propDecorators: { visible: [{
|
|
89
|
+
type: Input
|
|
90
|
+
}], timeLabel: [{
|
|
91
|
+
type: Input
|
|
92
|
+
}], isRestored: [{
|
|
93
|
+
type: Input
|
|
94
|
+
}], restoredText: [{
|
|
95
|
+
type: Input
|
|
96
|
+
}], savedText: [{
|
|
97
|
+
type: Input
|
|
98
|
+
}], savedLabel: [{
|
|
99
|
+
type: Input
|
|
100
|
+
}], discardText: [{
|
|
101
|
+
type: Input
|
|
102
|
+
}], discard: [{
|
|
103
|
+
type: Output
|
|
104
|
+
}] } });
|
|
105
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS1kcmFmdC1iYW5uZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Zvcm0tZHJhZnQtYmFubmVyLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsWUFBWSxFQUFFLHVCQUF1QixFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2hHLE9BQU8sRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7O0FBK0QxRSxNQUFNLE9BQU8sd0JBQXdCO0lBN0RyQztRQThEVyxZQUFPLEdBQUcsS0FBSyxDQUFDO1FBQ2hCLGNBQVMsR0FBRyxFQUFFLENBQUM7UUFDZixlQUFVLEdBQUcsS0FBSyxDQUFDO1FBQ25CLGlCQUFZLEdBQUcsZ0JBQWdCLENBQUM7UUFDaEMsY0FBUyxHQUFHLGFBQWEsQ0FBQztRQUMxQixlQUFVLEdBQUcsT0FBTyxDQUFDO1FBQ3JCLGdCQUFXLEdBQUcsU0FBUyxDQUFDO1FBQ3ZCLFlBQU8sR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0tBQzlDOztxSEFUWSx3QkFBd0I7eUdBQXhCLHdCQUF3Qiw0UkEzRHpCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVCwwcENBdUJXO1FBQ1YsT0FBTyxDQUFDLFdBQVcsRUFBRTtZQUNuQixVQUFVLENBQUMsUUFBUSxFQUFFO2dCQUNuQixLQUFLLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxDQUFDO2dCQUNwRCxPQUFPLENBQUMsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FBQzthQUNqRyxDQUFDO1lBQ0YsVUFBVSxDQUFDLFFBQVEsRUFBRTtnQkFDbkIsT0FBTyxDQUFDLG9DQUFvQyxFQUFFLEtBQUssQ0FBQyxFQUFFLE9BQU8sRUFBRSxDQUFDLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLENBQUMsQ0FBQzthQUNwRyxDQUFDO1NBQ0gsQ0FBQztLQUNIOzJGQUdVLHdCQUF3QjtrQkE3RHBDLFNBQVM7K0JBQ0UsdUJBQXVCLFlBQ3ZCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVCxjQXVCVzt3QkFDVixPQUFPLENBQUMsV0FBVyxFQUFFOzRCQUNuQixVQUFVLENBQUMsUUFBUSxFQUFFO2dDQUNuQixLQUFLLENBQUMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxFQUFFLFNBQVMsRUFBRSxrQkFBa0IsRUFBRSxDQUFDO2dDQUNwRCxPQUFPLENBQUMsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FBQzs2QkFDakcsQ0FBQzs0QkFDRixVQUFVLENBQUMsUUFBUSxFQUFFO2dDQUNuQixPQUFPLENBQUMsb0NBQW9DLEVBQUUsS0FBSyxDQUFDLEVBQUUsT0FBTyxFQUFFLENBQUMsRUFBRSxTQUFTLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQyxDQUFDOzZCQUNwRyxDQUFDO3lCQUNILENBQUM7cUJBQ0gsbUJBQ2dCLHVCQUF1QixDQUFDLE1BQU07OEJBR3RDLE9BQU87c0JBQWYsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxTQUFTO3NCQUFqQixLQUFLO2dCQUNHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBQ0csV0FBVztzQkFBbkIsS0FBSztnQkFDSSxPQUFPO3NCQUFoQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIENoYW5nZURldGVjdGlvblN0cmF0ZWd5IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyB0cmlnZ2VyLCB0cmFuc2l0aW9uLCBzdHlsZSwgYW5pbWF0ZSB9IGZyb20gJ0Bhbmd1bGFyL2FuaW1hdGlvbnMnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICduZ3gtZm9ybS1kcmFmdC1iYW5uZXInLFxuICB0ZW1wbGF0ZTogYFxuICAgIDxkaXYgY2xhc3M9XCJmb3JtLWRyYWZ0LWJhbm5lclwiICpuZ0lmPVwidmlzaWJsZVwiIFtAc2xpZGVEb3duXT5cbiAgICAgIDxkaXYgY2xhc3M9XCJmb3JtLWRyYWZ0LWJhbm5lcl9faWNvblwiPlxuICAgICAgICA8c3ZnIHdpZHRoPVwiMThcIiBoZWlnaHQ9XCIxOFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj5cbiAgICAgICAgICA8cGF0aCBkPVwiTTEyIDhWMTJMMTQuNSAxNC41XCIgc3Ryb2tlPVwiY3VycmVudENvbG9yXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiLz5cbiAgICAgICAgICA8Y2lyY2xlIGN4PVwiMTJcIiBjeT1cIjEyXCIgcj1cIjlcIiBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBzdHJva2Utd2lkdGg9XCIyXCIvPlxuICAgICAgICA8L3N2Zz5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tZHJhZnQtYmFubmVyX19jb250ZW50XCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZm9ybS1kcmFmdC1iYW5uZXJfX3RleHRcIj5cbiAgICAgICAgICA8c3BhbiAqbmdJZj1cImlzUmVzdG9yZWRcIj57eyByZXN0b3JlZFRleHQgfX08L3NwYW4+XG4gICAgICAgICAgPHNwYW4gKm5nSWY9XCIhaXNSZXN0b3JlZFwiPnt7IHNhdmVkVGV4dCB9fTwvc3Bhbj5cbiAgICAgICAgICA8c3BhbiBjbGFzcz1cImZvcm0tZHJhZnQtYmFubmVyX190aW1lXCIgKm5nSWY9XCJ0aW1lTGFiZWwgJiYgaXNSZXN0b3JlZFwiPlxuICAgICAgICAgICAgJm1pZGRvdDsge3sgc2F2ZWRMYWJlbCB9fSB7eyB0aW1lTGFiZWwgfX1cbiAgICAgICAgICA8L3NwYW4+XG4gICAgICAgIDwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImZvcm0tZHJhZnQtYmFubmVyX19hY3Rpb25zXCI+XG4gICAgICAgIDxidXR0b24gY2xhc3M9XCJmb3JtLWRyYWZ0LWJhbm5lcl9fYnRuIGZvcm0tZHJhZnQtYmFubmVyX19idG4tLWRpc2NhcmRcIiAoY2xpY2spPVwiZGlzY2FyZC5lbWl0KClcIiB0eXBlPVwiYnV0dG9uXCI+XG4gICAgICAgICAg4pyVIHt7IGRpc2NhcmRUZXh0IH19XG4gICAgICAgIDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIGAsXG4gIHN0eWxlczogW2BcbiAgICA6aG9zdCB7IGRpc3BsYXk6IGJsb2NrOyB3aWR0aDogMTAwJTsgfVxuICAgIC5mb3JtLWRyYWZ0LWJhbm5lciB7XG4gICAgICBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBnYXA6IDEwcHg7IHBhZGRpbmc6IDEwcHggMTRweDsgbWFyZ2luLWJvdHRvbTogMTJweDtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDhweDsgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEzNWRlZywgI2VlZjZmZiAwJSwgI2YwZjRmZiAxMDAlKTtcbiAgICAgIGJvcmRlcjogMXB4IHNvbGlkICNjNWRkZjg7IGJveC1zaGFkb3c6IDAgMnB4IDhweCByZ2JhKDE4LCAxMzgsIDIxNCwgMC4wOCk7XG4gICAgfVxuICAgIC5mb3JtLWRyYWZ0LWJhbm5lcl9faWNvbiB7XG4gICAgICBkaXNwbGF5OiBmbGV4OyBhbGlnbi1pdGVtczogY2VudGVyOyBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsgd2lkdGg6IDMycHg7IGhlaWdodDogMzJweDtcbiAgICAgIGJvcmRlci1yYWRpdXM6IDZweDsgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEzNWRlZywgIzEyOGFkNiwgIzIyYjlmZik7IGNvbG9yOiAjZmZmOyBmbGV4LXNocmluazogMDtcbiAgICB9XG4gICAgLmZvcm0tZHJhZnQtYmFubmVyX19jb250ZW50IHsgZmxleDogMTsgbWluLXdpZHRoOiAwOyB9XG4gICAgLmZvcm0tZHJhZnQtYmFubmVyX190ZXh0IHsgZm9udC1zaXplOiAxM3B4OyBmb250LXdlaWdodDogNjAwOyBjb2xvcjogIzFhM2E1YzsgfVxuICAgIC5mb3JtLWRyYWZ0LWJhbm5lcl9fdGltZSB7IGZvbnQtd2VpZ2h0OiA0MDA7IGNvbG9yOiAjNmI4YWFhOyBmb250LXNpemU6IDEycHg7IH1cbiAgICAuZm9ybS1kcmFmdC1iYW5uZXJfX2FjdGlvbnMgeyBmbGV4LXNocmluazogMDsgfVxuICAgIC5mb3JtLWRyYWZ0LWJhbm5lcl9fYnRuIHtcbiAgICAgIGJvcmRlcjogbm9uZTsgcGFkZGluZzogNXB4IDEycHg7IGJvcmRlci1yYWRpdXM6IDZweDsgZm9udC1zaXplOiAxMnB4O1xuICAgICAgZm9udC13ZWlnaHQ6IDYwMDsgY3Vyc29yOiBwb2ludGVyOyB0cmFuc2l0aW9uOiBhbGwgMC4ycyBlYXNlO1xuICAgIH1cbiAgICAuZm9ybS1kcmFmdC1iYW5uZXJfX2J0bi0tZGlzY2FyZCB7IGJhY2tncm91bmQ6IHRyYW5zcGFyZW50OyBjb2xvcjogIzg4OTlhNjsgYm9yZGVyOiAxcHggc29saWQgI2QwZGNlNjsgfVxuICAgIC5mb3JtLWRyYWZ0LWJhbm5lcl9fYnRuLS1kaXNjYXJkOmhvdmVyIHsgYmFja2dyb3VuZDogI2ZlZjJmMjsgY29sb3I6ICNlNjJlNDM7IGJvcmRlci1jb2xvcjogI2U2MmU0MzsgfVxuICBgXSxcbiAgYW5pbWF0aW9uczogW1xuICAgIHRyaWdnZXIoJ3NsaWRlRG93bicsIFtcbiAgICAgIHRyYW5zaXRpb24oJzplbnRlcicsIFtcbiAgICAgICAgc3R5bGUoeyBvcGFjaXR5OiAwLCB0cmFuc2Zvcm06ICd0cmFuc2xhdGVZKC04cHgpJyB9KSxcbiAgICAgICAgYW5pbWF0ZSgnMjUwbXMgY3ViaWMtYmV6aWVyKDAuNCwgMCwgMC4yLCAxKScsIHN0eWxlKHsgb3BhY2l0eTogMSwgdHJhbnNmb3JtOiAndHJhbnNsYXRlWSgwKScgfSkpXG4gICAgICBdKSxcbiAgICAgIHRyYW5zaXRpb24oJzpsZWF2ZScsIFtcbiAgICAgICAgYW5pbWF0ZSgnMjAwbXMgY3ViaWMtYmV6aWVyKDAuNCwgMCwgMC4yLCAxKScsIHN0eWxlKHsgb3BhY2l0eTogMCwgdHJhbnNmb3JtOiAndHJhbnNsYXRlWSgtOHB4KScgfSkpXG4gICAgICBdKVxuICAgIF0pXG4gIF0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBGb3JtRHJhZnRCYW5uZXJDb21wb25lbnQge1xuICBASW5wdXQoKSB2aXNpYmxlID0gZmFsc2U7XG4gIEBJbnB1dCgpIHRpbWVMYWJlbCA9ICcnO1xuICBASW5wdXQoKSBpc1Jlc3RvcmVkID0gZmFsc2U7XG4gIEBJbnB1dCgpIHJlc3RvcmVkVGV4dCA9ICdEcmFmdCByZXN0b3JlZCc7XG4gIEBJbnB1dCgpIHNhdmVkVGV4dCA9ICdEcmFmdCBzYXZlZCc7XG4gIEBJbnB1dCgpIHNhdmVkTGFiZWwgPSAnc2F2ZWQnO1xuICBASW5wdXQoKSBkaXNjYXJkVGV4dCA9ICdEaXNjYXJkJztcbiAgQE91dHB1dCgpIGRpc2NhcmQgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XG59XG4iXX0=
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { Directive, Input, Optional, } from '@angular/core';
|
|
2
|
+
import { FormArray, FormGroup, FormControl } from '@angular/forms';
|
|
3
|
+
import { Subject } from 'rxjs';
|
|
4
|
+
import { debounceTime, takeUntil } from 'rxjs/operators';
|
|
5
|
+
import { FormDraftBannerComponent } from './form-draft-banner.component';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import * as i1 from "@angular/forms";
|
|
8
|
+
import * as i2 from "./form-draft.service";
|
|
9
|
+
/**
|
|
10
|
+
* Auto-saves and restores form drafts
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* <form [formGroup]="myForm" ngxFormDraft="myFormId">
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* <form [formGroup]="myForm" [ngxFormDraft]="'edit_' + entityId" [draftExcludeFields]="['password']">
|
|
17
|
+
*/
|
|
18
|
+
export class FormDraftDirective {
|
|
19
|
+
constructor(formGroupDir, ngForm, draftService, viewContainerRef, cdRef, elRef, renderer) {
|
|
20
|
+
this.formGroupDir = formGroupDir;
|
|
21
|
+
this.ngForm = ngForm;
|
|
22
|
+
this.draftService = draftService;
|
|
23
|
+
this.viewContainerRef = viewContainerRef;
|
|
24
|
+
this.cdRef = cdRef;
|
|
25
|
+
this.elRef = elRef;
|
|
26
|
+
this.renderer = renderer;
|
|
27
|
+
this.draftDebounce = 800;
|
|
28
|
+
this.draftExcludeFields = [];
|
|
29
|
+
this.draftShowOnChange = false;
|
|
30
|
+
this.draftRestoredText = 'Draft restored';
|
|
31
|
+
this.draftSavedText = 'Draft saved';
|
|
32
|
+
this.draftSavedLabel = 'saved';
|
|
33
|
+
this.draftDiscardText = 'Discard';
|
|
34
|
+
this.destroy$ = new Subject();
|
|
35
|
+
this.bannerRef = null;
|
|
36
|
+
this.formControl = null;
|
|
37
|
+
this.initialValues = {};
|
|
38
|
+
this.isRestoring = false;
|
|
39
|
+
}
|
|
40
|
+
ngOnInit() {
|
|
41
|
+
this.formControl = this.formGroupDir?.form || this.ngForm?.form || null;
|
|
42
|
+
if (!this.formControl || !this.formId)
|
|
43
|
+
return;
|
|
44
|
+
this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));
|
|
45
|
+
const draft = this.draftService.load(this.formId);
|
|
46
|
+
if (draft) {
|
|
47
|
+
this.restoreDraft(draft.values);
|
|
48
|
+
this.showBanner(draft.savedAt, true);
|
|
49
|
+
}
|
|
50
|
+
this.formControl.valueChanges
|
|
51
|
+
.pipe(debounceTime(this.draftDebounce), takeUntil(this.destroy$))
|
|
52
|
+
.subscribe((values) => {
|
|
53
|
+
if (this.isRestoring)
|
|
54
|
+
return;
|
|
55
|
+
this.saveDraft(values);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
ngOnDestroy() {
|
|
59
|
+
this.destroy$.next();
|
|
60
|
+
this.destroy$.complete();
|
|
61
|
+
this.destroyBanner();
|
|
62
|
+
}
|
|
63
|
+
saveDraft(values) {
|
|
64
|
+
const filtered = this.filterFields(values);
|
|
65
|
+
if (this.isAllEmpty(filtered) || this.matchesInitialValues(filtered)) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.draftService.save(this.formId, filtered);
|
|
69
|
+
if (this.draftShowOnChange && !this.bannerRef) {
|
|
70
|
+
this.showBanner(Date.now(), false);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
filterFields(values) {
|
|
74
|
+
if (!this.draftExcludeFields.length)
|
|
75
|
+
return values;
|
|
76
|
+
const result = { ...values };
|
|
77
|
+
this.draftExcludeFields.forEach(field => delete result[field]);
|
|
78
|
+
return result;
|
|
79
|
+
}
|
|
80
|
+
isAllEmpty(values) {
|
|
81
|
+
return Object.values(values).every(v => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0));
|
|
82
|
+
}
|
|
83
|
+
matchesInitialValues(values) {
|
|
84
|
+
return JSON.stringify(values) === JSON.stringify(this.initialValues);
|
|
85
|
+
}
|
|
86
|
+
restoreDraft(values) {
|
|
87
|
+
if (!this.formControl)
|
|
88
|
+
return;
|
|
89
|
+
this.isRestoring = true;
|
|
90
|
+
const form = this.formGroupDir?.form || this.ngForm?.form;
|
|
91
|
+
if (form) {
|
|
92
|
+
this.prepareFormArrays(form, values);
|
|
93
|
+
form.patchValue(values);
|
|
94
|
+
}
|
|
95
|
+
setTimeout(() => this.isRestoring = false, 100);
|
|
96
|
+
}
|
|
97
|
+
prepareFormArrays(control, value) {
|
|
98
|
+
if (!control || value == null)
|
|
99
|
+
return;
|
|
100
|
+
if (control instanceof FormGroup && value && typeof value === 'object' && !Array.isArray(value)) {
|
|
101
|
+
Object.keys(value).forEach(key => {
|
|
102
|
+
const childControl = control.get(key);
|
|
103
|
+
if (childControl)
|
|
104
|
+
this.prepareFormArrays(childControl, value[key]);
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
if (control instanceof FormArray && Array.isArray(value)) {
|
|
109
|
+
const formArray = control;
|
|
110
|
+
while (formArray.length < value.length) {
|
|
111
|
+
const template = formArray.at(0);
|
|
112
|
+
if (template instanceof FormGroup) {
|
|
113
|
+
const newGroup = new FormGroup({});
|
|
114
|
+
Object.keys(template.controls).forEach(ctrlName => {
|
|
115
|
+
const existing = template.get(ctrlName);
|
|
116
|
+
if (existing instanceof FormArray) {
|
|
117
|
+
newGroup.addControl(ctrlName, new FormArray([]));
|
|
118
|
+
}
|
|
119
|
+
else if (existing instanceof FormGroup) {
|
|
120
|
+
newGroup.addControl(ctrlName, new FormGroup({}));
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
newGroup.addControl(ctrlName, new FormControl(null));
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
formArray.push(newGroup);
|
|
127
|
+
}
|
|
128
|
+
else if (template) {
|
|
129
|
+
formArray.push(new FormControl(null));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
const firstValue = value[0];
|
|
133
|
+
if (firstValue && typeof firstValue === 'object' && !Array.isArray(firstValue)) {
|
|
134
|
+
const group = new FormGroup({});
|
|
135
|
+
Object.keys(firstValue).forEach(key => group.addControl(key, new FormControl(null)));
|
|
136
|
+
formArray.push(group);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
formArray.push(new FormControl(null));
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
while (formArray.length > value.length) {
|
|
144
|
+
formArray.removeAt(formArray.length - 1);
|
|
145
|
+
}
|
|
146
|
+
value.forEach((childValue, index) => {
|
|
147
|
+
this.prepareFormArrays(formArray.at(index), childValue);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
discardDraft() {
|
|
152
|
+
this.draftService.clear(this.formId);
|
|
153
|
+
if (this.formControl) {
|
|
154
|
+
this.isRestoring = true;
|
|
155
|
+
const form = this.formGroupDir?.form || this.ngForm?.form;
|
|
156
|
+
if (form) {
|
|
157
|
+
this.prepareFormArrays(form, this.initialValues);
|
|
158
|
+
form.reset(this.initialValues);
|
|
159
|
+
}
|
|
160
|
+
setTimeout(() => {
|
|
161
|
+
this.isRestoring = false;
|
|
162
|
+
}, this.draftDebounce + 200);
|
|
163
|
+
}
|
|
164
|
+
this.destroyBanner();
|
|
165
|
+
}
|
|
166
|
+
showBanner(savedAt, isRestored = false) {
|
|
167
|
+
this.bannerRef = this.viewContainerRef.createComponent(FormDraftBannerComponent);
|
|
168
|
+
this.bannerRef.setInput('visible', true);
|
|
169
|
+
this.bannerRef.setInput('isRestored', isRestored);
|
|
170
|
+
this.bannerRef.setInput('timeLabel', isRestored ? this.draftService.formatTimestamp(savedAt) : '');
|
|
171
|
+
this.bannerRef.setInput('restoredText', this.draftRestoredText);
|
|
172
|
+
this.bannerRef.setInput('savedText', this.draftSavedText);
|
|
173
|
+
this.bannerRef.setInput('savedLabel', this.draftSavedLabel);
|
|
174
|
+
this.bannerRef.setInput('discardText', this.draftDiscardText);
|
|
175
|
+
this.bannerRef.instance.discard.subscribe(() => this.discardDraft());
|
|
176
|
+
const bannerEl = this.bannerRef.location.nativeElement;
|
|
177
|
+
const formEl = this.elRef.nativeElement;
|
|
178
|
+
this.renderer.insertBefore(formEl, bannerEl, formEl.firstChild);
|
|
179
|
+
this.cdRef.detectChanges();
|
|
180
|
+
}
|
|
181
|
+
destroyBanner() {
|
|
182
|
+
if (this.bannerRef) {
|
|
183
|
+
this.bannerRef.destroy();
|
|
184
|
+
this.bannerRef = null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
clearDraft() {
|
|
188
|
+
this.draftService.clear(this.formId);
|
|
189
|
+
this.destroyBanner();
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
FormDraftDirective.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftDirective, deps: [{ token: i1.FormGroupDirective, optional: true }, { token: i1.NgForm, optional: true }, { token: i2.FormDraftService }, { token: i0.ViewContainerRef }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
193
|
+
FormDraftDirective.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: FormDraftDirective, selector: "[ngxFormDraft]", inputs: { formId: ["ngxFormDraft", "formId"], draftDebounce: "draftDebounce", draftExcludeFields: "draftExcludeFields", draftShowOnChange: "draftShowOnChange", draftRestoredText: "draftRestoredText", draftSavedText: "draftSavedText", draftSavedLabel: "draftSavedLabel", draftDiscardText: "draftDiscardText" }, ngImport: i0 });
|
|
194
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftDirective, decorators: [{
|
|
195
|
+
type: Directive,
|
|
196
|
+
args: [{
|
|
197
|
+
selector: '[ngxFormDraft]',
|
|
198
|
+
}]
|
|
199
|
+
}], ctorParameters: function () { return [{ type: i1.FormGroupDirective, decorators: [{
|
|
200
|
+
type: Optional
|
|
201
|
+
}] }, { type: i1.NgForm, decorators: [{
|
|
202
|
+
type: Optional
|
|
203
|
+
}] }, { type: i2.FormDraftService }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { formId: [{
|
|
204
|
+
type: Input,
|
|
205
|
+
args: ['ngxFormDraft']
|
|
206
|
+
}], draftDebounce: [{
|
|
207
|
+
type: Input
|
|
208
|
+
}], draftExcludeFields: [{
|
|
209
|
+
type: Input
|
|
210
|
+
}], draftShowOnChange: [{
|
|
211
|
+
type: Input
|
|
212
|
+
}], draftRestoredText: [{
|
|
213
|
+
type: Input
|
|
214
|
+
}], draftSavedText: [{
|
|
215
|
+
type: Input
|
|
216
|
+
}], draftSavedLabel: [{
|
|
217
|
+
type: Input
|
|
218
|
+
}], draftDiscardText: [{
|
|
219
|
+
type: Input
|
|
220
|
+
}] } });
|
|
221
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS1kcmFmdC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZm9ybS1kcmFmdC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFBRSxLQUFLLEVBQXFCLFFBQVEsR0FFOUMsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUErQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hILE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV6RCxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQzs7OztBQUV6RTs7Ozs7Ozs7R0FRRztBQUlILE1BQU0sT0FBTyxrQkFBa0I7SUFnQjdCLFlBQ3NCLFlBQWdDLEVBQ2hDLE1BQWMsRUFDMUIsWUFBOEIsRUFDOUIsZ0JBQWtDLEVBQ2xDLEtBQXdCLEVBQ3hCLEtBQWlCLEVBQ2pCLFFBQW1CO1FBTlAsaUJBQVksR0FBWixZQUFZLENBQW9CO1FBQ2hDLFdBQU0sR0FBTixNQUFNLENBQVE7UUFDMUIsaUJBQVksR0FBWixZQUFZLENBQWtCO1FBQzlCLHFCQUFnQixHQUFoQixnQkFBZ0IsQ0FBa0I7UUFDbEMsVUFBSyxHQUFMLEtBQUssQ0FBbUI7UUFDeEIsVUFBSyxHQUFMLEtBQUssQ0FBWTtRQUNqQixhQUFRLEdBQVIsUUFBUSxDQUFXO1FBckJwQixrQkFBYSxHQUFHLEdBQUcsQ0FBQztRQUNwQix1QkFBa0IsR0FBYSxFQUFFLENBQUM7UUFDbEMsc0JBQWlCLEdBQUcsS0FBSyxDQUFDO1FBQzFCLHNCQUFpQixHQUFHLGdCQUFnQixDQUFDO1FBQ3JDLG1CQUFjLEdBQUcsYUFBYSxDQUFDO1FBQy9CLG9CQUFlLEdBQUcsT0FBTyxDQUFDO1FBQzFCLHFC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O0lBQ3ZCLENBQUM7OytHQW5NVSxrQkFBa0I7bUdBQWxCLGtCQUFrQjsyRkFBbEIsa0JBQWtCO2tCQUg5QixTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxnQkFBZ0I7aUJBQzNCOzswQkFrQkksUUFBUTs7MEJBQ1IsUUFBUTsyTEFqQlksTUFBTTtzQkFBNUIsS0FBSzt1QkFBQyxjQUFjO2dCQUNaLGFBQWE7c0JBQXJCLEtBQUs7Z0JBQ0csa0JBQWtCO3NCQUExQixLQUFLO2dCQUNHLGlCQUFpQjtzQkFBekIsS0FBSztnQkFDRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBQ0csY0FBYztzQkFBdEIsS0FBSztnQkFDRyxlQUFlO3NCQUF2QixLQUFLO2dCQUNHLGdCQUFnQjtzQkFBeEIsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIERpcmVjdGl2ZSwgSW5wdXQsIE9uSW5pdCwgT25EZXN0cm95LCBPcHRpb25hbCwgQ29tcG9uZW50UmVmLFxuICBWaWV3Q29udGFpbmVyUmVmLCBDaGFuZ2VEZXRlY3RvclJlZiwgRWxlbWVudFJlZiwgUmVuZGVyZXIyLFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5nRm9ybSwgRm9ybUdyb3VwRGlyZWN0aXZlLCBBYnN0cmFjdENvbnRyb2wsIEZvcm1BcnJheSwgRm9ybUdyb3VwLCBGb3JtQ29udHJvbCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcbmltcG9ydCB7IGRlYm91bmNlVGltZSwgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRm9ybURyYWZ0U2VydmljZSB9IGZyb20gJy4vZm9ybS1kcmFmdC5zZXJ2aWNlJztcbmltcG9ydCB7IEZvcm1EcmFmdEJhbm5lckNvbXBvbmVudCB9IGZyb20gJy4vZm9ybS1kcmFmdC1iYW5uZXIuY29tcG9uZW50JztcblxuLyoqXG4gKiBBdXRvLXNhdmVzIGFuZCByZXN0b3JlcyBmb3JtIGRyYWZ0c1xuICogXG4gKiBAZXhhbXBsZVxuICogPGZvcm0gW2Zvcm1Hcm91cF09XCJteUZvcm1cIiBuZ3hGb3JtRHJhZnQ9XCJteUZvcm1JZFwiPlxuICogXG4gKiBAZXhhbXBsZVxuICogPGZvcm0gW2Zvcm1Hcm91cF09XCJteUZvcm1cIiBbbmd4Rm9ybURyYWZ0XT1cIidlZGl0XycgKyBlbnRpdHlJZFwiIFtkcmFmdEV4Y2x1ZGVGaWVsZHNdPVwiWydwYXNzd29yZCddXCI+XG4gKi9cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ1tuZ3hGb3JtRHJhZnRdJyxcbn0pXG5leHBvcnQgY2xhc3MgRm9ybURyYWZ0RGlyZWN0aXZlIGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xuICBASW5wdXQoJ25neEZvcm1EcmFmdCcpIGZvcm1JZCE6IHN0cmluZztcbiAgQElucHV0KCkgZHJhZnREZWJvdW5jZSA9IDgwMDtcbiAgQElucHV0KCkgZHJhZnRFeGNsdWRlRmllbGRzOiBzdHJpbmdbXSA9IFtdO1xuICBASW5wdXQoKSBkcmFmdFNob3dPbkNoYW5nZSA9IGZhbHNlO1xuICBASW5wdXQoKSBkcmFmdFJlc3RvcmVkVGV4dCA9ICdEcmFmdCByZXN0b3JlZCc7XG4gIEBJbnB1dCgpIGRyYWZ0U2F2ZWRUZXh0ID0gJ0RyYWZ0IHNhdmVkJztcbiAgQElucHV0KCkgZHJhZnRTYXZlZExhYmVsID0gJ3NhdmVkJztcbiAgQElucHV0KCkgZHJhZnREaXNjYXJkVGV4dCA9ICdEaXNjYXJkJztcblxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgcHJpdmF0ZSBiYW5uZXJSZWY6IENvbXBvbmVudFJlZjxGb3JtRHJhZnRCYW5uZXJDb21wb25lbnQ+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZm9ybUNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGluaXRpYWxWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgcHJpdmF0ZSBpc1Jlc3RvcmluZyA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgZm9ybUdyb3VwRGlyOiBGb3JtR3JvdXBEaXJlY3RpdmUsXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSBuZ0Zvcm06IE5nRm9ybSxcbiAgICBwcml2YXRlIGRyYWZ0U2VydmljZTogRm9ybURyYWZ0U2VydmljZSxcbiAgICBwcml2YXRlIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYsXG4gICAgcHJpdmF0ZSBjZFJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBlbFJlZjogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsXG4gICkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1Db250cm9sID0gdGhpcy5mb3JtR3JvdXBEaXI/LmZvcm0gfHwgdGhpcy5uZ0Zvcm0/LmZvcm0gfHwgbnVsbDtcbiAgICBpZiAoIXRoaXMuZm9ybUNvbnRyb2wgfHwgIXRoaXMuZm9ybUlkKSByZXR1cm47XG5cbiAgICB0aGlzLmluaXRpYWxWYWx1ZXMgPSBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KHRoaXMuZm9ybUNvbnRyb2wudmFsdWUpKTtcblxuICAgIGNvbnN0IGRyYWZ0ID0gdGhpcy5kcmFmdFNlcnZpY2UubG9hZCh0aGlzLmZvcm1JZCk7XG4gICAgaWYgKGRyYWZ0KSB7XG4gICAgICB0aGlzLnJlc3RvcmVEcmFmdChkcmFmdC52YWx1ZXMpO1xuICAgICAgdGhpcy5zaG93QmFubmVyKGRyYWZ0LnNhdmVkQXQsIHRydWUpO1xuICAgIH1cblxuICAgIHRoaXMuZm9ybUNvbnRyb2wudmFsdWVDaGFuZ2VzXG4gICAgICAucGlwZShkZWJvdW5jZVRpbWUodGhpcy5kcmFmdERlYm91bmNlKSwgdGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgLnN1YnNjcmliZSgodmFsdWVzKSA9PiB7XG4gICAgICAgIGlmICh0aGlzLmlzUmVzdG9yaW5nKSByZXR1cm47XG4gICAgICAgIHRoaXMuc2F2ZURyYWZ0KHZhbHVlcyk7XG4gICAgICB9KTtcbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcbiAgICB0aGlzLmRlc3Ryb3lCYW5uZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgc2F2ZURyYWZ0KHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xuICAgIGNvbnN0IGZpbHRlcmVkID0gdGhpcy5maWx0ZXJGaWVsZHModmFsdWVzKTtcbiAgICBcbiAgICBpZiAodGhpcy5pc0FsbEVtcHR5KGZpbHRlcmVkKSB8fCB0aGlzLm1hdGNoZXNJbml0aWFsVmFsdWVzKGZpbHRlcmVkKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuZHJhZnRTZXJ2aWNlLnNhdmUodGhpcy5mb3JtSWQsIGZpbHRlcmVkKTtcbiAgICBpZiAodGhpcy5kcmFmdFNob3dPbkNoYW5nZSAmJiAhdGhpcy5iYW5uZXJSZWYpIHtcbiAgICAgIHRoaXMuc2hvd0Jhbm5lcihEYXRlLm5vdygpLCBmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBmaWx0ZXJGaWVsZHModmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogUmVjb3JkPHN0cmluZywgYW55PiB7XG4gICAgaWYgKCF0aGlzLmRyYWZ0RXhjbHVkZUZpZWxkcy5sZW5ndGgpIHJldHVybiB2YWx1ZXM7XG4gICAgY29uc3QgcmVzdWx0ID0geyAuLi52YWx1ZXMgfTtcbiAgICB0aGlzLmRyYWZ0RXhjbHVkZUZpZWxkcy5mb3JFYWNoKGZpZWxkID0+IGRlbGV0ZSByZXN1bHRbZmllbGRdKTtcbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHJpdmF0ZSBpc0FsbEVtcHR5KHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBPYmplY3QudmFsdWVzKHZhbHVlcykuZXZlcnkoXG4gICAgICB2ID0+IHYgPT09IG51bGwgfHwgdiA9PT0gdW5kZWZpbmVkIHx8IHYgPT09ICcnIHx8IChBcnJheS5pc0FycmF5KHYpICYmIHYubGVuZ3RoID09PSAwKVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIG1hdGNoZXNJbml0aWFsVmFsdWVzKHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBKU09OLnN0cmluZ2lmeSh2YWx1ZXMpID09PSBKU09OLnN0cmluZ2lmeSh0aGlzLmluaXRpYWxWYWx1ZXMpO1xuICB9XG5cbiAgcHJpdmF0ZSByZXN0b3JlRHJhZnQodmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogdm9pZCB7XG4gICAgaWYgKCF0aGlzLmZvcm1Db250cm9sKSByZXR1cm47XG4gICAgdGhpcy5pc1Jlc3RvcmluZyA9IHRydWU7XG5cbiAgICBjb25zdCBmb3JtID0gdGhpcy5mb3JtR3JvdXBEaXI/LmZvcm0gfHwgdGhpcy5uZ0Zvcm0/LmZvcm07XG4gICAgaWYgKGZvcm0pIHtcbiAgICAgIHRoaXMucHJlcGFyZUZvcm1BcnJheXMoZm9ybSwgdmFsdWVzKTtcbiAgICAgIGZvcm0ucGF0Y2hWYWx1ZSh2YWx1ZXMpO1xuICAgIH1cblxuICAgIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5pc1Jlc3RvcmluZyA9IGZhbHNlLCAxMDApO1xuICB9XG5cbiAgcHJpdmF0ZSBwcmVwYXJlRm9ybUFycmF5cyhjb250cm9sOiBBYnN0cmFjdENvbnRyb2wsIHZhbHVlOiBhbnkpOiB2b2lkIHtcbiAgICBpZiAoIWNvbnRyb2wgfHwgdmFsdWUgPT0gbnVsbCkgcmV0dXJuO1xuXG4gICAgaWYgKGNvbnRyb2wgaW5zdGFuY2VvZiBGb3JtR3JvdXAgJiYgdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgIE9iamVjdC5rZXlzKHZhbHVlKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICAgIGNvbnN0IGNoaWxkQ29udHJvbCA9IGNvbnRyb2wuZ2V0KGtleSk7XG4gICAgICAgIGlmIChjaGlsZENvbnRyb2wpIHRoaXMucHJlcGFyZUZvcm1BcnJheXMoY2hpbGRDb250cm9sLCB2YWx1ZVtrZXldKTtcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChjb250cm9sIGluc3RhbmNlb2YgRm9ybUFycmF5ICYmIEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICBjb25zdCBmb3JtQXJyYXkgPSBjb250cm9sIGFzIEZvcm1BcnJheTtcblxuICAgICAgd2hpbGUgKGZvcm1BcnJheS5sZW5ndGggPCB2YWx1ZS5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgdGVtcGxhdGUgPSBmb3JtQXJyYXkuYXQoMCk7XG4gICAgICAgIGlmICh0ZW1wbGF0ZSBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgICAgIGNvbnN0IG5ld0dyb3VwID0gbmV3IEZvcm1Hcm91cCh7fSk7XG4gICAgICAgICAgT2JqZWN0LmtleXModGVtcGxhdGUuY29udHJvbHMpLmZvckVhY2goY3RybE5hbWUgPT4ge1xuICAgICAgICAgICAgY29uc3QgZXhpc3RpbmcgPSB0ZW1wbGF0ZS5nZXQoY3RybE5hbWUpIGFzIEFic3RyYWN0Q29udHJvbDtcbiAgICAgICAgICAgIGlmIChleGlzdGluZyBpbnN0YW5jZW9mIEZvcm1BcnJheSkge1xuICAgICAgICAgICAgICBuZXdHcm91cC5hZGRDb250cm9sKGN0cmxOYW1lLCBuZXcgRm9ybUFycmF5KFtdKSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGV4aXN0aW5nIGluc3RhbmNlb2YgRm9ybUdyb3VwKSB7XG4gICAgICAgICAgICAgIG5ld0dyb3VwLmFkZENvbnRyb2woY3RybE5hbWUsIG5ldyBGb3JtR3JvdXAoe30pKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIG5ld0dyb3VwLmFkZENvbnRyb2woY3RybE5hbWUsIG5ldyBGb3JtQ29udHJvbChudWxsKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgICAgZm9ybUFycmF5LnB1c2gobmV3R3JvdXApO1xuICAgICAgICB9IGVsc2UgaWYgKHRlbXBsYXRlKSB7XG4gICAgICAgICAgZm9ybUFycmF5LnB1c2gobmV3IEZvcm1Db250cm9sKG51bGwpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zdCBmaXJzdFZhbHVlID0gdmFsdWVbMF07XG4gICAgICAgICAgaWYgKGZpcnN0VmFsdWUgJiYgdHlwZW9mIGZpcnN0VmFsdWUgPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGZpcnN0VmFsdWUpKSB7XG4gICAgICAgICAgICBjb25zdCBncm91cCA9IG5ldyBGb3JtR3JvdXAoe30pO1xuICAgICAgICAgICAgT2JqZWN0LmtleXMoZmlyc3RWYWx1ZSkuZm9yRWFjaChrZXkgPT4gZ3JvdXAuYWRkQ29udHJvbChrZXksIG5ldyBGb3JtQ29udHJvbChudWxsKSkpO1xuICAgICAgICAgICAgZm9ybUFycmF5LnB1c2goZ3JvdXApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBmb3JtQXJyYXkucHVzaChuZXcgRm9ybUNvbnRyb2wobnVsbCkpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB3aGlsZSAoZm9ybUFycmF5Lmxlbmd0aCA+IHZhbHVlLmxlbmd0aCkge1xuICAgICAgICBmb3JtQXJyYXkucmVtb3ZlQXQoZm9ybUFycmF5Lmxlbmd0aCAtIDEpO1xuICAgICAgfVxuXG4gICAgICB2YWx1ZS5mb3JFYWNoKChjaGlsZFZhbHVlLCBpbmRleCkgPT4ge1xuICAgICAgICB0aGlzLnByZXBhcmVGb3JtQXJyYXlzKGZvcm1BcnJheS5hdChpbmRleCksIGNoaWxkVmFsdWUpO1xuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBkaXNjYXJkRHJhZnQoKTogdm9pZCB7XG4gICAgdGhpcy5kcmFmdFNlcnZpY2UuY2xlYXIodGhpcy5mb3JtSWQpO1xuXG4gICAgaWYgKHRoaXMuZm9ybUNvbnRyb2wpIHtcbiAgICAgIHRoaXMuaXNSZXN0b3JpbmcgPSB0cnVlO1xuICAgICAgY29uc3QgZm9ybSA9IHRoaXMuZm9ybUdyb3VwRGlyPy5mb3JtIHx8IHRoaXMubmdGb3JtPy5mb3JtO1xuICAgICAgaWYgKGZvcm0pIHtcbiAgICAgICAgdGhpcy5wcmVwYXJlRm9ybUFycmF5cyhmb3JtLCB0aGlzLmluaXRpYWxWYWx1ZXMpO1xuICAgICAgICBmb3JtLnJlc2V0KHRoaXMuaW5pdGlhbFZhbHVlcyk7XG4gICAgICB9XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgdGhpcy5pc1Jlc3RvcmluZyA9IGZhbHNlO1xuICAgICAgfSwgdGhpcy5kcmFmdERlYm91bmNlICsgMjAwKTtcbiAgICB9XG5cbiAgICB0aGlzLmRlc3Ryb3lCYW5uZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgc2hvd0Jhbm5lcihzYXZlZEF0OiBudW1iZXIsIGlzUmVzdG9yZWQgPSBmYWxzZSk6IHZvaWQge1xuICAgIHRoaXMuYmFubmVyUmVmID0gdGhpcy52aWV3Q29udGFpbmVyUmVmLmNyZWF0ZUNvbXBvbmVudChGb3JtRHJhZnRCYW5uZXJDb21wb25lbnQpO1xuICAgIHRoaXMuYmFubmVyUmVmLnNldElucHV0KCd2aXNpYmxlJywgdHJ1ZSk7XG4gICAgdGhpcy5iYW5uZXJSZWYuc2V0SW5wdXQoJ2lzUmVzdG9yZWQnLCBpc1Jlc3RvcmVkKTtcbiAgICB0aGlzLmJhbm5lclJlZi5zZXRJbnB1dCgndGltZUxhYmVsJywgaXNSZXN0b3JlZCA/IHRoaXMuZHJhZnRTZXJ2aWNlLmZvcm1hdFRpbWVzdGFtcChzYXZlZEF0KSA6ICcnKTtcbiAgICB0aGlzLmJhbm5lclJlZi5zZXRJbnB1dCgncmVzdG9yZWRUZXh0JywgdGhpcy5kcmFmdFJlc3RvcmVkVGV4dCk7XG4gICAgdGhpcy5iYW5uZXJSZWYuc2V0SW5wdXQoJ3NhdmVkVGV4dCcsIHRoaXMuZHJhZnRTYXZlZFRleHQpO1xuICAgIHRoaXMuYmFubmVyUmVmLnNldElucHV0KCdzYXZlZExhYmVsJywgdGhpcy5kcmFmdFNhdmVkTGFiZWwpO1xuICAgIHRoaXMuYmFubmVyUmVmLnNldElucHV0KCdkaXNjYXJkVGV4dCcsIHRoaXMuZHJhZnREaXNjYXJkVGV4dCk7XG5cbiAgICB0aGlzLmJhbm5lclJlZi5pbnN0YW5jZS5kaXNjYXJkLnN1YnNjcmliZSgoKSA9PiB0aGlzLmRpc2NhcmREcmFmdCgpKTtcblxuICAgIGNvbnN0IGJhbm5lckVsID0gdGhpcy5iYW5uZXJSZWYubG9jYXRpb24ubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBmb3JtRWwgPSB0aGlzLmVsUmVmLm5hdGl2ZUVsZW1lbnQ7XG4gICAgdGhpcy5yZW5kZXJlci5pbnNlcnRCZWZvcmUoZm9ybUVsLCBiYW5uZXJFbCwgZm9ybUVsLmZpcnN0Q2hpbGQpO1xuXG4gICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gIH1cblxuICBwcml2YXRlIGRlc3Ryb3lCYW5uZXIoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYmFubmVyUmVmKSB7XG4gICAgICB0aGlzLmJhbm5lclJlZi5kZXN0cm95KCk7XG4gICAgICB0aGlzLmJhbm5lclJlZiA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGNsZWFyRHJhZnQoKTogdm9pZCB7XG4gICAgdGhpcy5kcmFmdFNlcnZpY2UuY2xlYXIodGhpcy5mb3JtSWQpO1xuICAgIHRoaXMuZGVzdHJveUJhbm5lcigpO1xuICB9XG59XG4iXX0=
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class FormDraftService {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.STORAGE_PREFIX = 'form_draft_';
|
|
6
|
+
this.MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000;
|
|
7
|
+
}
|
|
8
|
+
buildKey(formId) {
|
|
9
|
+
return `${this.STORAGE_PREFIX}${formId}`;
|
|
10
|
+
}
|
|
11
|
+
save(formId, values) {
|
|
12
|
+
try {
|
|
13
|
+
const draft = { values, savedAt: Date.now(), formId };
|
|
14
|
+
localStorage.setItem(this.buildKey(formId), JSON.stringify(draft));
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
console.warn('[FormDraft] Could not save draft:', e);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
load(formId) {
|
|
21
|
+
try {
|
|
22
|
+
const raw = localStorage.getItem(this.buildKey(formId));
|
|
23
|
+
if (!raw)
|
|
24
|
+
return null;
|
|
25
|
+
const draft = JSON.parse(raw);
|
|
26
|
+
if (Date.now() - draft.savedAt > this.MAX_AGE_MS) {
|
|
27
|
+
this.clear(formId);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return draft;
|
|
31
|
+
}
|
|
32
|
+
catch (e) {
|
|
33
|
+
console.warn('[FormDraft] Could not load draft:', e);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
clear(formId) {
|
|
38
|
+
try {
|
|
39
|
+
localStorage.removeItem(this.buildKey(formId));
|
|
40
|
+
}
|
|
41
|
+
catch (e) {
|
|
42
|
+
console.warn('[FormDraft] Could not clear draft:', e);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
formatTimestamp(timestamp) {
|
|
46
|
+
const seconds = Math.floor((Date.now() - timestamp) / 1000);
|
|
47
|
+
if (seconds < 60)
|
|
48
|
+
return 'just now';
|
|
49
|
+
const minutes = Math.floor(seconds / 60);
|
|
50
|
+
if (minutes < 60)
|
|
51
|
+
return `${minutes}m ago`;
|
|
52
|
+
const hours = Math.floor(minutes / 60);
|
|
53
|
+
if (hours < 24)
|
|
54
|
+
return `${hours}h ago`;
|
|
55
|
+
const days = Math.floor(hours / 24);
|
|
56
|
+
return `${days}d ago`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
FormDraftService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
60
|
+
FormDraftService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftService, providedIn: 'root' });
|
|
61
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftService, decorators: [{
|
|
62
|
+
type: Injectable,
|
|
63
|
+
args: [{
|
|
64
|
+
providedIn: 'root'
|
|
65
|
+
}]
|
|
66
|
+
}] });
|
|
67
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS1kcmFmdC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2Zvcm0tZHJhZnQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDOztBQVczQyxNQUFNLE9BQU8sZ0JBQWdCO0lBSDdCO1FBSW1CLG1CQUFjLEdBQUcsYUFBYSxDQUFDO1FBQy9CLGVBQVUsR0FBRyxDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsSUFBSSxDQUFDO0tBa0R2RDtJQWhEUyxRQUFRLENBQUMsTUFBYztRQUM3QixPQUFPLEdBQUcsSUFBSSxDQUFDLGNBQWMsR0FBRyxNQUFNLEVBQUUsQ0FBQztJQUMzQyxDQUFDO0lBRUQsSUFBSSxDQUFDLE1BQWMsRUFBRSxNQUEyQjtRQUM5QyxJQUFJO1lBQ0YsTUFBTSxLQUFLLEdBQWtCLEVBQUUsTUFBTSxFQUFFLE9BQU8sRUFBRSxJQUFJLENBQUMsR0FBRyxFQUFFLEVBQUUsTUFBTSxFQUFFLENBQUM7WUFDckUsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztTQUNwRTtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsT0FBTyxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUN0RDtJQUNILENBQUM7SUFFRCxJQUFJLENBQUMsTUFBYztRQUNqQixJQUFJO1lBQ0YsTUFBTSxHQUFHLEdBQUcsWUFBWSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7WUFDeEQsSUFBSSxDQUFDLEdBQUc7Z0JBQUUsT0FBTyxJQUFJLENBQUM7WUFFdEIsTUFBTSxLQUFLLEdBQWtCLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7WUFDN0MsSUFBSSxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsS0FBSyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFO2dCQUNoRCxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO2dCQUNuQixPQUFPLElBQUksQ0FBQzthQUNiO1lBQ0QsT0FBTyxLQUFLLENBQUM7U0FDZDtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsT0FBTyxDQUFDLElBQUksQ0FBQyxtQ0FBbUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUNyRCxPQUFPLElBQUksQ0FBQztTQUNiO0lBQ0gsQ0FBQztJQUVELEtBQUssQ0FBQyxNQUFjO1FBQ2xCLElBQUk7WUFDRixZQUFZLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztTQUNoRDtRQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQ1YsT0FBTyxDQUFDLElBQUksQ0FBQyxvQ0FBb0MsRUFBRSxDQUFDLENBQUMsQ0FBQztTQUN2RDtJQUNILENBQUM7SUFFRCxlQUFlLENBQUMsU0FBaUI7UUFDL0IsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQztRQUM1RCxJQUFJLE9BQU8sR0FBRyxFQUFFO1lBQUUsT0FBTyxVQUFVLENBQUM7UUFDcEMsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDekMsSUFBSSxPQUFPLEdBQUcsRUFBRTtZQUFFLE9BQU8sR0FBRyxPQUFPLE9BQU8sQ0FBQztRQUMzQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUMsQ0FBQztRQUN2QyxJQUFJLEtBQUssR0FBRyxFQUFFO1lBQUUsT0FBTyxHQUFHLEtBQUssT0FBTyxDQUFDO1FBQ3ZDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxHQUFHLEVBQUUsQ0FBQyxDQUFDO1FBQ3BDLE9BQU8sR0FBRyxJQUFJLE9BQU8sQ0FBQztJQUN4QixDQUFDOzs2R0FuRFUsZ0JBQWdCO2lIQUFoQixnQkFBZ0IsY0FGZixNQUFNOzJGQUVQLGdCQUFnQjtrQkFINUIsVUFBVTttQkFBQztvQkFDVixVQUFVLEVBQUUsTUFBTTtpQkFDbkIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgRm9ybURyYWZ0RGF0YSB7XG4gIHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgc2F2ZWRBdDogbnVtYmVyO1xuICBmb3JtSWQ6IHN0cmluZztcbn1cblxuQEluamVjdGFibGUoe1xuICBwcm92aWRlZEluOiAncm9vdCdcbn0pXG5leHBvcnQgY2xhc3MgRm9ybURyYWZ0U2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgU1RPUkFHRV9QUkVGSVggPSAnZm9ybV9kcmFmdF8nO1xuICBwcml2YXRlIHJlYWRvbmx5IE1BWF9BR0VfTVMgPSA3ICogMjQgKiA2MCAqIDYwICogMTAwMDtcblxuICBwcml2YXRlIGJ1aWxkS2V5KGZvcm1JZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gYCR7dGhpcy5TVE9SQUdFX1BSRUZJWH0ke2Zvcm1JZH1gO1xuICB9XG5cbiAgc2F2ZShmb3JtSWQ6IHN0cmluZywgdmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCBhbnk+KTogdm9pZCB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGRyYWZ0OiBGb3JtRHJhZnREYXRhID0geyB2YWx1ZXMsIHNhdmVkQXQ6IERhdGUubm93KCksIGZvcm1JZCB9O1xuICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0odGhpcy5idWlsZEtleShmb3JtSWQpLCBKU09OLnN0cmluZ2lmeShkcmFmdCkpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGNvbnNvbGUud2FybignW0Zvcm1EcmFmdF0gQ291bGQgbm90IHNhdmUgZHJhZnQ6JywgZSk7XG4gICAgfVxuICB9XG5cbiAgbG9hZChmb3JtSWQ6IHN0cmluZyk6IEZvcm1EcmFmdERhdGEgfCBudWxsIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmF3ID0gbG9jYWxTdG9yYWdlLmdldEl0ZW0odGhpcy5idWlsZEtleShmb3JtSWQpKTtcbiAgICAgIGlmICghcmF3KSByZXR1cm4gbnVsbDtcblxuICAgICAgY29uc3QgZHJhZnQ6IEZvcm1EcmFmdERhdGEgPSBKU09OLnBhcnNlKHJhdyk7XG4gICAgICBpZiAoRGF0ZS5ub3coKSAtIGRyYWZ0LnNhdmVkQXQgPiB0aGlzLk1BWF9BR0VfTVMpIHtcbiAgICAgICAgdGhpcy5jbGVhcihmb3JtSWQpO1xuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkcmFmdDtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tGb3JtRHJhZnRdIENvdWxkIG5vdCBsb2FkIGRyYWZ0OicsIGUpO1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICB9XG5cbiAgY2xlYXIoZm9ybUlkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0cnkge1xuICAgICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0odGhpcy5idWlsZEtleShmb3JtSWQpKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tGb3JtRHJhZnRdIENvdWxkIG5vdCBjbGVhciBkcmFmdDonLCBlKTtcbiAgICB9XG4gIH1cblxuICBmb3JtYXRUaW1lc3RhbXAodGltZXN0YW1wOiBudW1iZXIpOiBzdHJpbmcge1xuICAgIGNvbnN0IHNlY29uZHMgPSBNYXRoLmZsb29yKChEYXRlLm5vdygpIC0gdGltZXN0YW1wKSAvIDEwMDApO1xuICAgIGlmIChzZWNvbmRzIDwgNjApIHJldHVybiAnanVzdCBub3cnO1xuICAgIGNvbnN0IG1pbnV0ZXMgPSBNYXRoLmZsb29yKHNlY29uZHMgLyA2MCk7XG4gICAgaWYgKG1pbnV0ZXMgPCA2MCkgcmV0dXJuIGAke21pbnV0ZXN9bSBhZ29gO1xuICAgIGNvbnN0IGhvdXJzID0gTWF0aC5mbG9vcihtaW51dGVzIC8gNjApO1xuICAgIGlmIChob3VycyA8IDI0KSByZXR1cm4gYCR7aG91cnN9aCBhZ29gO1xuICAgIGNvbnN0IGRheXMgPSBNYXRoLmZsb29yKGhvdXJzIC8gMjQpO1xuICAgIHJldHVybiBgJHtkYXlzfWQgYWdvYDtcbiAgfVxufVxuIl19
|