ngx-form-draft 1.0.1 → 1.0.3
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 +12 -0
- package/dist/LICENSE +21 -0
- package/dist/README.md +151 -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 +21 -6
- 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
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata } from "tslib";
|
|
2
|
-
import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy } from '@angular/core';
|
|
3
|
-
import { trigger, transition, style, animate } from '@angular/animations';
|
|
4
|
-
let FormDraftBannerComponent = class FormDraftBannerComponent {
|
|
5
|
-
constructor() {
|
|
6
|
-
this.visible = false;
|
|
7
|
-
this.timeLabel = '';
|
|
8
|
-
this.isRestored = false;
|
|
9
|
-
this.restoredText = 'Draft restored';
|
|
10
|
-
this.savedText = 'Draft saved';
|
|
11
|
-
this.savedLabel = 'saved';
|
|
12
|
-
this.discardText = 'Discard';
|
|
13
|
-
this.discard = new EventEmitter();
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
__decorate([
|
|
17
|
-
Input(),
|
|
18
|
-
__metadata("design:type", Object)
|
|
19
|
-
], FormDraftBannerComponent.prototype, "visible", void 0);
|
|
20
|
-
__decorate([
|
|
21
|
-
Input(),
|
|
22
|
-
__metadata("design:type", Object)
|
|
23
|
-
], FormDraftBannerComponent.prototype, "timeLabel", void 0);
|
|
24
|
-
__decorate([
|
|
25
|
-
Input(),
|
|
26
|
-
__metadata("design:type", Object)
|
|
27
|
-
], FormDraftBannerComponent.prototype, "isRestored", void 0);
|
|
28
|
-
__decorate([
|
|
29
|
-
Input(),
|
|
30
|
-
__metadata("design:type", Object)
|
|
31
|
-
], FormDraftBannerComponent.prototype, "restoredText", void 0);
|
|
32
|
-
__decorate([
|
|
33
|
-
Input(),
|
|
34
|
-
__metadata("design:type", Object)
|
|
35
|
-
], FormDraftBannerComponent.prototype, "savedText", void 0);
|
|
36
|
-
__decorate([
|
|
37
|
-
Input(),
|
|
38
|
-
__metadata("design:type", Object)
|
|
39
|
-
], FormDraftBannerComponent.prototype, "savedLabel", void 0);
|
|
40
|
-
__decorate([
|
|
41
|
-
Input(),
|
|
42
|
-
__metadata("design:type", Object)
|
|
43
|
-
], FormDraftBannerComponent.prototype, "discardText", void 0);
|
|
44
|
-
__decorate([
|
|
45
|
-
Output(),
|
|
46
|
-
__metadata("design:type", Object)
|
|
47
|
-
], FormDraftBannerComponent.prototype, "discard", void 0);
|
|
48
|
-
FormDraftBannerComponent = __decorate([
|
|
49
|
-
Component({
|
|
50
|
-
selector: 'ngx-form-draft-banner',
|
|
51
|
-
template: `
|
|
52
|
-
<div class="form-draft-banner" *ngIf="visible" [@slideDown]>
|
|
53
|
-
<div class="form-draft-banner__icon">
|
|
54
|
-
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
55
|
-
<path d="M12 8V12L14.5 14.5" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
|
56
|
-
<circle cx="12" cy="12" r="9" stroke="currentColor" stroke-width="2"/>
|
|
57
|
-
</svg>
|
|
58
|
-
</div>
|
|
59
|
-
<div class="form-draft-banner__content">
|
|
60
|
-
<span class="form-draft-banner__text">
|
|
61
|
-
<span *ngIf="isRestored">{{ restoredText }}</span>
|
|
62
|
-
<span *ngIf="!isRestored">{{ savedText }}</span>
|
|
63
|
-
<span class="form-draft-banner__time" *ngIf="timeLabel && isRestored">
|
|
64
|
-
· {{ savedLabel }} {{ timeLabel }}
|
|
65
|
-
</span>
|
|
66
|
-
</span>
|
|
67
|
-
</div>
|
|
68
|
-
<div class="form-draft-banner__actions">
|
|
69
|
-
<button class="form-draft-banner__btn form-draft-banner__btn--discard" (click)="discard.emit()" type="button">
|
|
70
|
-
✕ {{ discardText }}
|
|
71
|
-
</button>
|
|
72
|
-
</div>
|
|
73
|
-
</div>
|
|
74
|
-
`,
|
|
75
|
-
styles: [`
|
|
76
|
-
:host { display: block; width: 100%; }
|
|
77
|
-
.form-draft-banner {
|
|
78
|
-
display: flex; align-items: center; gap: 10px; padding: 10px 14px; margin-bottom: 12px;
|
|
79
|
-
border-radius: 8px; background: linear-gradient(135deg, #eef6ff 0%, #f0f4ff 100%);
|
|
80
|
-
border: 1px solid #c5ddf8; box-shadow: 0 2px 8px rgba(18, 138, 214, 0.08);
|
|
81
|
-
}
|
|
82
|
-
.form-draft-banner__icon {
|
|
83
|
-
display: flex; align-items: center; justify-content: center; width: 32px; height: 32px;
|
|
84
|
-
border-radius: 6px; background: linear-gradient(135deg, #128ad6, #22b9ff); color: #fff; flex-shrink: 0;
|
|
85
|
-
}
|
|
86
|
-
.form-draft-banner__content { flex: 1; min-width: 0; }
|
|
87
|
-
.form-draft-banner__text { font-size: 13px; font-weight: 600; color: #1a3a5c; }
|
|
88
|
-
.form-draft-banner__time { font-weight: 400; color: #6b8aaa; font-size: 12px; }
|
|
89
|
-
.form-draft-banner__actions { flex-shrink: 0; }
|
|
90
|
-
.form-draft-banner__btn {
|
|
91
|
-
border: none; padding: 5px 12px; border-radius: 6px; font-size: 12px;
|
|
92
|
-
font-weight: 600; cursor: pointer; transition: all 0.2s ease;
|
|
93
|
-
}
|
|
94
|
-
.form-draft-banner__btn--discard { background: transparent; color: #8899a6; border: 1px solid #d0dce6; }
|
|
95
|
-
.form-draft-banner__btn--discard:hover { background: #fef2f2; color: #e62e43; border-color: #e62e43; }
|
|
96
|
-
`],
|
|
97
|
-
animations: [
|
|
98
|
-
trigger('slideDown', [
|
|
99
|
-
transition(':enter', [
|
|
100
|
-
style({ opacity: 0, transform: 'translateY(-8px)' }),
|
|
101
|
-
animate('250ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 1, transform: 'translateY(0)' }))
|
|
102
|
-
]),
|
|
103
|
-
transition(':leave', [
|
|
104
|
-
animate('200ms cubic-bezier(0.4, 0, 0.2, 1)', style({ opacity: 0, transform: 'translateY(-8px)' }))
|
|
105
|
-
])
|
|
106
|
-
])
|
|
107
|
-
],
|
|
108
|
-
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
109
|
-
})
|
|
110
|
-
], FormDraftBannerComponent);
|
|
111
|
-
export { FormDraftBannerComponent };
|
|
@@ -1,240 +0,0 @@
|
|
|
1
|
-
import { __decorate, __metadata, __param } from "tslib";
|
|
2
|
-
import { Directive, Input, Optional, ViewContainerRef, ChangeDetectorRef, ElementRef, Renderer2, } from '@angular/core';
|
|
3
|
-
import { NgForm, FormGroupDirective, FormArray, FormGroup, FormControl } from '@angular/forms';
|
|
4
|
-
import { Subject } from 'rxjs';
|
|
5
|
-
import { debounceTime, takeUntil } from 'rxjs/operators';
|
|
6
|
-
import { FormDraftService } from './form-draft.service';
|
|
7
|
-
import { FormDraftBannerComponent } from './form-draft-banner.component';
|
|
8
|
-
/**
|
|
9
|
-
* Auto-saves and restores form drafts
|
|
10
|
-
*
|
|
11
|
-
* @example
|
|
12
|
-
* <form [formGroup]="myForm" ngxFormDraft="myFormId">
|
|
13
|
-
*
|
|
14
|
-
* @example
|
|
15
|
-
* <form [formGroup]="myForm" [ngxFormDraft]="'edit_' + entityId" [draftExcludeFields]="['password']">
|
|
16
|
-
*/
|
|
17
|
-
let FormDraftDirective = class FormDraftDirective {
|
|
18
|
-
constructor(formGroupDir, ngForm, draftService, viewContainerRef, cdRef, elRef, renderer) {
|
|
19
|
-
this.formGroupDir = formGroupDir;
|
|
20
|
-
this.ngForm = ngForm;
|
|
21
|
-
this.draftService = draftService;
|
|
22
|
-
this.viewContainerRef = viewContainerRef;
|
|
23
|
-
this.cdRef = cdRef;
|
|
24
|
-
this.elRef = elRef;
|
|
25
|
-
this.renderer = renderer;
|
|
26
|
-
this.draftDebounce = 800;
|
|
27
|
-
this.draftExcludeFields = [];
|
|
28
|
-
this.draftShowOnChange = false;
|
|
29
|
-
this.draftRestoredText = 'Draft restored';
|
|
30
|
-
this.draftSavedText = 'Draft saved';
|
|
31
|
-
this.draftSavedLabel = 'saved';
|
|
32
|
-
this.draftDiscardText = 'Discard';
|
|
33
|
-
this.destroy$ = new Subject();
|
|
34
|
-
this.bannerRef = null;
|
|
35
|
-
this.formControl = null;
|
|
36
|
-
this.initialValues = {};
|
|
37
|
-
this.isRestoring = false;
|
|
38
|
-
}
|
|
39
|
-
ngOnInit() {
|
|
40
|
-
var _a, _b;
|
|
41
|
-
this.formControl = ((_a = this.formGroupDir) === null || _a === void 0 ? void 0 : _a.form) || ((_b = this.ngForm) === null || _b === void 0 ? void 0 : _b.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 = Object.assign({}, 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
|
-
var _a, _b;
|
|
88
|
-
if (!this.formControl)
|
|
89
|
-
return;
|
|
90
|
-
this.isRestoring = true;
|
|
91
|
-
const form = ((_a = this.formGroupDir) === null || _a === void 0 ? void 0 : _a.form) || ((_b = this.ngForm) === null || _b === void 0 ? void 0 : _b.form);
|
|
92
|
-
if (form) {
|
|
93
|
-
this.prepareFormArrays(form, values);
|
|
94
|
-
form.patchValue(values);
|
|
95
|
-
}
|
|
96
|
-
setTimeout(() => this.isRestoring = false, 100);
|
|
97
|
-
}
|
|
98
|
-
prepareFormArrays(control, value) {
|
|
99
|
-
if (!control || value == null)
|
|
100
|
-
return;
|
|
101
|
-
if (control instanceof FormGroup && value && typeof value === 'object' && !Array.isArray(value)) {
|
|
102
|
-
Object.keys(value).forEach(key => {
|
|
103
|
-
const childControl = control.get(key);
|
|
104
|
-
if (childControl)
|
|
105
|
-
this.prepareFormArrays(childControl, value[key]);
|
|
106
|
-
});
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
if (control instanceof FormArray && Array.isArray(value)) {
|
|
110
|
-
const formArray = control;
|
|
111
|
-
while (formArray.length < value.length) {
|
|
112
|
-
const template = formArray.at(0);
|
|
113
|
-
if (template instanceof FormGroup) {
|
|
114
|
-
const newGroup = new FormGroup({});
|
|
115
|
-
Object.keys(template.controls).forEach(ctrlName => {
|
|
116
|
-
const existing = template.get(ctrlName);
|
|
117
|
-
if (existing instanceof FormArray) {
|
|
118
|
-
newGroup.addControl(ctrlName, new FormArray([]));
|
|
119
|
-
}
|
|
120
|
-
else if (existing instanceof FormGroup) {
|
|
121
|
-
newGroup.addControl(ctrlName, new FormGroup({}));
|
|
122
|
-
}
|
|
123
|
-
else {
|
|
124
|
-
newGroup.addControl(ctrlName, new FormControl(null));
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
formArray.push(newGroup);
|
|
128
|
-
}
|
|
129
|
-
else if (template) {
|
|
130
|
-
formArray.push(new FormControl(null));
|
|
131
|
-
}
|
|
132
|
-
else {
|
|
133
|
-
const firstValue = value[0];
|
|
134
|
-
if (firstValue && typeof firstValue === 'object' && !Array.isArray(firstValue)) {
|
|
135
|
-
const group = new FormGroup({});
|
|
136
|
-
Object.keys(firstValue).forEach(key => group.addControl(key, new FormControl(null)));
|
|
137
|
-
formArray.push(group);
|
|
138
|
-
}
|
|
139
|
-
else {
|
|
140
|
-
formArray.push(new FormControl(null));
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
while (formArray.length > value.length) {
|
|
145
|
-
formArray.removeAt(formArray.length - 1);
|
|
146
|
-
}
|
|
147
|
-
value.forEach((childValue, index) => {
|
|
148
|
-
this.prepareFormArrays(formArray.at(index), childValue);
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
discardDraft() {
|
|
153
|
-
var _a, _b;
|
|
154
|
-
this.draftService.clear(this.formId);
|
|
155
|
-
if (this.formControl) {
|
|
156
|
-
this.isRestoring = true;
|
|
157
|
-
const form = ((_a = this.formGroupDir) === null || _a === void 0 ? void 0 : _a.form) || ((_b = this.ngForm) === null || _b === void 0 ? void 0 : _b.form);
|
|
158
|
-
if (form) {
|
|
159
|
-
this.prepareFormArrays(form, this.initialValues);
|
|
160
|
-
form.reset(this.initialValues);
|
|
161
|
-
}
|
|
162
|
-
setTimeout(() => {
|
|
163
|
-
this.isRestoring = false;
|
|
164
|
-
}, this.draftDebounce + 200);
|
|
165
|
-
}
|
|
166
|
-
this.destroyBanner();
|
|
167
|
-
}
|
|
168
|
-
showBanner(savedAt, isRestored = false) {
|
|
169
|
-
this.bannerRef = this.viewContainerRef.createComponent(FormDraftBannerComponent);
|
|
170
|
-
this.bannerRef.setInput('visible', true);
|
|
171
|
-
this.bannerRef.setInput('isRestored', isRestored);
|
|
172
|
-
this.bannerRef.setInput('timeLabel', isRestored ? this.draftService.formatTimestamp(savedAt) : '');
|
|
173
|
-
this.bannerRef.setInput('restoredText', this.draftRestoredText);
|
|
174
|
-
this.bannerRef.setInput('savedText', this.draftSavedText);
|
|
175
|
-
this.bannerRef.setInput('savedLabel', this.draftSavedLabel);
|
|
176
|
-
this.bannerRef.setInput('discardText', this.draftDiscardText);
|
|
177
|
-
this.bannerRef.instance.discard.subscribe(() => this.discardDraft());
|
|
178
|
-
const bannerEl = this.bannerRef.location.nativeElement;
|
|
179
|
-
const formEl = this.elRef.nativeElement;
|
|
180
|
-
this.renderer.insertBefore(formEl, bannerEl, formEl.firstChild);
|
|
181
|
-
this.cdRef.detectChanges();
|
|
182
|
-
}
|
|
183
|
-
destroyBanner() {
|
|
184
|
-
if (this.bannerRef) {
|
|
185
|
-
this.bannerRef.destroy();
|
|
186
|
-
this.bannerRef = null;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
clearDraft() {
|
|
190
|
-
this.draftService.clear(this.formId);
|
|
191
|
-
this.destroyBanner();
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
__decorate([
|
|
195
|
-
Input('ngxFormDraft'),
|
|
196
|
-
__metadata("design:type", String)
|
|
197
|
-
], FormDraftDirective.prototype, "formId", void 0);
|
|
198
|
-
__decorate([
|
|
199
|
-
Input(),
|
|
200
|
-
__metadata("design:type", Object)
|
|
201
|
-
], FormDraftDirective.prototype, "draftDebounce", void 0);
|
|
202
|
-
__decorate([
|
|
203
|
-
Input(),
|
|
204
|
-
__metadata("design:type", Array)
|
|
205
|
-
], FormDraftDirective.prototype, "draftExcludeFields", void 0);
|
|
206
|
-
__decorate([
|
|
207
|
-
Input(),
|
|
208
|
-
__metadata("design:type", Object)
|
|
209
|
-
], FormDraftDirective.prototype, "draftShowOnChange", void 0);
|
|
210
|
-
__decorate([
|
|
211
|
-
Input(),
|
|
212
|
-
__metadata("design:type", Object)
|
|
213
|
-
], FormDraftDirective.prototype, "draftRestoredText", void 0);
|
|
214
|
-
__decorate([
|
|
215
|
-
Input(),
|
|
216
|
-
__metadata("design:type", Object)
|
|
217
|
-
], FormDraftDirective.prototype, "draftSavedText", void 0);
|
|
218
|
-
__decorate([
|
|
219
|
-
Input(),
|
|
220
|
-
__metadata("design:type", Object)
|
|
221
|
-
], FormDraftDirective.prototype, "draftSavedLabel", void 0);
|
|
222
|
-
__decorate([
|
|
223
|
-
Input(),
|
|
224
|
-
__metadata("design:type", Object)
|
|
225
|
-
], FormDraftDirective.prototype, "draftDiscardText", void 0);
|
|
226
|
-
FormDraftDirective = __decorate([
|
|
227
|
-
Directive({
|
|
228
|
-
selector: '[ngxFormDraft]',
|
|
229
|
-
}),
|
|
230
|
-
__param(0, Optional()),
|
|
231
|
-
__param(1, Optional()),
|
|
232
|
-
__metadata("design:paramtypes", [FormGroupDirective,
|
|
233
|
-
NgForm,
|
|
234
|
-
FormDraftService,
|
|
235
|
-
ViewContainerRef,
|
|
236
|
-
ChangeDetectorRef,
|
|
237
|
-
ElementRef,
|
|
238
|
-
Renderer2])
|
|
239
|
-
], FormDraftDirective);
|
|
240
|
-
export { FormDraftDirective };
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
2
|
-
import { Injectable } from '@angular/core';
|
|
3
|
-
let FormDraftService = 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 = __decorate([
|
|
60
|
-
Injectable({
|
|
61
|
-
providedIn: 'root'
|
|
62
|
-
})
|
|
63
|
-
], FormDraftService);
|
|
64
|
-
export { FormDraftService };
|
package/dist/index.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { __decorate } from "tslib";
|
|
2
|
-
import { NgModule } from '@angular/core';
|
|
3
|
-
import { CommonModule } from '@angular/common';
|
|
4
|
-
import { FormDraftDirective } from './form-draft.directive';
|
|
5
|
-
import { FormDraftBannerComponent } from './form-draft-banner.component';
|
|
6
|
-
let NgxFormDraftModule = class NgxFormDraftModule {
|
|
7
|
-
};
|
|
8
|
-
NgxFormDraftModule = __decorate([
|
|
9
|
-
NgModule({
|
|
10
|
-
declarations: [FormDraftDirective, FormDraftBannerComponent],
|
|
11
|
-
imports: [CommonModule],
|
|
12
|
-
exports: [FormDraftDirective, FormDraftBannerComponent],
|
|
13
|
-
})
|
|
14
|
-
], NgxFormDraftModule);
|
|
15
|
-
export { NgxFormDraftModule };
|