ngx-form-draft 2.2.11 → 2.2.13
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/LICENSE +21 -21
- package/README.md +206 -206
- package/esm2020/form-draft-banner.component.mjs +84 -84
- package/esm2020/form-draft.directive.mjs +267 -267
- package/esm2020/form-draft.service.mjs +92 -92
- package/esm2020/index.mjs +4 -4
- package/esm2020/ngx-form-draft.mjs +4 -4
- package/esm2020/ngx-form-draft.module.mjs +19 -19
- package/fesm2015/ngx-form-draft.mjs +446 -446
- package/fesm2015/ngx-form-draft.mjs.map +1 -1
- package/fesm2020/ngx-form-draft.mjs +439 -439
- package/fesm2020/ngx-form-draft.mjs.map +1 -1
- package/form-draft-banner.component.d.ts +14 -14
- package/form-draft.directive.d.ts +56 -56
- package/form-draft.service.d.ts +35 -35
- package/index.d.ts +4 -4
- package/ngx-form-draft.module.d.ts +9 -9
- package/package.json +1 -1
|
@@ -1,268 +1,268 @@
|
|
|
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, filter } 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.draftService.registerReset(this.formId, () => this.performResetAndDestroyBanner());
|
|
45
|
-
// For reactive forms, capture initial values and restore draft immediately
|
|
46
|
-
if (this.formGroupDir) {
|
|
47
|
-
this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));
|
|
48
|
-
const draft = this.draftService.load(this.formId);
|
|
49
|
-
if (draft) {
|
|
50
|
-
this.restoreDraft(draft.values);
|
|
51
|
-
this.showBanner(draft.savedAt, true);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
let hasUserInteraction = false;
|
|
55
|
-
this.formControl.valueChanges
|
|
56
|
-
.pipe(filter(() => {
|
|
57
|
-
if (this.isRestoring)
|
|
58
|
-
return false;
|
|
59
|
-
if (this.ngForm && !hasUserInteraction) {
|
|
60
|
-
const currentValues = this.formControl?.value || {};
|
|
61
|
-
const isDifferent = JSON.stringify(currentValues) !== JSON.stringify(this.initialValues);
|
|
62
|
-
if (isDifferent) {
|
|
63
|
-
hasUserInteraction = true;
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
return false;
|
|
67
|
-
}
|
|
68
|
-
return true;
|
|
69
|
-
}), debounceTime(this.draftDebounce), takeUntil(this.destroy$))
|
|
70
|
-
.subscribe((values) => {
|
|
71
|
-
this.saveDraft(values);
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
ngAfterViewInit() {
|
|
75
|
-
if (this.ngForm && this.formControl) {
|
|
76
|
-
const draft = this.draftService.load(this.formId);
|
|
77
|
-
if (draft) {
|
|
78
|
-
this.isRestoring = true;
|
|
79
|
-
}
|
|
80
|
-
setTimeout(() => {
|
|
81
|
-
if (draft) {
|
|
82
|
-
this.restoreDraft(draft.values);
|
|
83
|
-
this.showBanner(draft.savedAt, true);
|
|
84
|
-
this.initialValues = {};
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));
|
|
88
|
-
}
|
|
89
|
-
}, 0);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
ngOnDestroy() {
|
|
93
|
-
this.draftService.unregisterReset(this.formId);
|
|
94
|
-
this.destroy$.next();
|
|
95
|
-
this.destroy$.complete();
|
|
96
|
-
this.destroyBanner();
|
|
97
|
-
}
|
|
98
|
-
saveDraft(values) {
|
|
99
|
-
const filtered = this.filterFields(values);
|
|
100
|
-
// Don't save if empty
|
|
101
|
-
if (this.isAllEmpty(filtered)) {
|
|
102
|
-
return;
|
|
103
|
-
}
|
|
104
|
-
// Don't save if matches initial values (even if initial is empty)
|
|
105
|
-
if (this.matchesInitialValues(filtered)) {
|
|
106
|
-
return;
|
|
107
|
-
}
|
|
108
|
-
this.draftService.save(this.formId, filtered);
|
|
109
|
-
if (this.draftShowOnChange && !this.bannerRef) {
|
|
110
|
-
this.showBanner(Date.now(), false);
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
filterFields(values) {
|
|
114
|
-
if (!this.draftExcludeFields.length)
|
|
115
|
-
return values;
|
|
116
|
-
const result = { ...values };
|
|
117
|
-
this.draftExcludeFields.forEach(field => delete result[field]);
|
|
118
|
-
return result;
|
|
119
|
-
}
|
|
120
|
-
isAllEmpty(values) {
|
|
121
|
-
return Object.values(values).every(v => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0));
|
|
122
|
-
}
|
|
123
|
-
matchesInitialValues(values) {
|
|
124
|
-
return JSON.stringify(values) === JSON.stringify(this.initialValues);
|
|
125
|
-
}
|
|
126
|
-
restoreDraft(values) {
|
|
127
|
-
if (!this.formControl)
|
|
128
|
-
return;
|
|
129
|
-
this.isRestoring = true;
|
|
130
|
-
const form = this.formGroupDir?.form || this.ngForm?.form;
|
|
131
|
-
if (form) {
|
|
132
|
-
this.prepareFormArrays(form, values);
|
|
133
|
-
form.patchValue(values);
|
|
134
|
-
}
|
|
135
|
-
setTimeout(() => this.isRestoring = false, 100);
|
|
136
|
-
}
|
|
137
|
-
prepareFormArrays(control, value) {
|
|
138
|
-
if (!control || value == null)
|
|
139
|
-
return;
|
|
140
|
-
if (control instanceof FormGroup && value && typeof value === 'object' && !Array.isArray(value)) {
|
|
141
|
-
Object.keys(value).forEach(key => {
|
|
142
|
-
const childControl = control.get(key);
|
|
143
|
-
if (childControl)
|
|
144
|
-
this.prepareFormArrays(childControl, value[key]);
|
|
145
|
-
});
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
if (control instanceof FormArray && Array.isArray(value)) {
|
|
149
|
-
const formArray = control;
|
|
150
|
-
while (formArray.length < value.length) {
|
|
151
|
-
const template = formArray.at(0);
|
|
152
|
-
if (template instanceof FormGroup) {
|
|
153
|
-
const newGroup = new FormGroup({});
|
|
154
|
-
Object.keys(template.controls).forEach(ctrlName => {
|
|
155
|
-
const existing = template.get(ctrlName);
|
|
156
|
-
if (existing instanceof FormArray) {
|
|
157
|
-
newGroup.addControl(ctrlName, new FormArray([]));
|
|
158
|
-
}
|
|
159
|
-
else if (existing instanceof FormGroup) {
|
|
160
|
-
newGroup.addControl(ctrlName, new FormGroup({}));
|
|
161
|
-
}
|
|
162
|
-
else {
|
|
163
|
-
newGroup.addControl(ctrlName, new FormControl(null));
|
|
164
|
-
}
|
|
165
|
-
});
|
|
166
|
-
formArray.push(newGroup);
|
|
167
|
-
}
|
|
168
|
-
else if (template) {
|
|
169
|
-
formArray.push(new FormControl(null));
|
|
170
|
-
}
|
|
171
|
-
else {
|
|
172
|
-
const firstValue = value[0];
|
|
173
|
-
if (firstValue && typeof firstValue === 'object' && !Array.isArray(firstValue)) {
|
|
174
|
-
const group = new FormGroup({});
|
|
175
|
-
Object.keys(firstValue).forEach(key => group.addControl(key, new FormControl(null)));
|
|
176
|
-
formArray.push(group);
|
|
177
|
-
}
|
|
178
|
-
else {
|
|
179
|
-
formArray.push(new FormControl(null));
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
while (formArray.length > value.length) {
|
|
184
|
-
formArray.removeAt(formArray.length - 1);
|
|
185
|
-
}
|
|
186
|
-
value.forEach((childValue, index) => {
|
|
187
|
-
this.prepareFormArrays(formArray.at(index), childValue);
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
discardDraft() {
|
|
192
|
-
this.draftService.clear(this.formId);
|
|
193
|
-
this.performResetAndDestroyBanner();
|
|
194
|
-
}
|
|
195
|
-
/**
|
|
196
|
-
* Resets the form to initial values and destroys the draft banner.
|
|
197
|
-
* Used by the service when clearAndReset(formId) is called (e.g. on submit).
|
|
198
|
-
*/
|
|
199
|
-
performResetAndDestroyBanner() {
|
|
200
|
-
if (this.formControl) {
|
|
201
|
-
this.isRestoring = true;
|
|
202
|
-
const form = this.formGroupDir?.form || this.ngForm?.form;
|
|
203
|
-
if (form) {
|
|
204
|
-
this.prepareFormArrays(form, this.initialValues);
|
|
205
|
-
form.reset(this.initialValues);
|
|
206
|
-
}
|
|
207
|
-
setTimeout(() => {
|
|
208
|
-
this.isRestoring = false;
|
|
209
|
-
}, this.draftDebounce + 200);
|
|
210
|
-
}
|
|
211
|
-
this.destroyBanner();
|
|
212
|
-
}
|
|
213
|
-
showBanner(savedAt, isRestored = false) {
|
|
214
|
-
this.bannerRef = this.viewContainerRef.createComponent(FormDraftBannerComponent);
|
|
215
|
-
this.bannerRef.setInput('visible', true);
|
|
216
|
-
this.bannerRef.setInput('isRestored', isRestored);
|
|
217
|
-
this.bannerRef.setInput('timeLabel', isRestored ? this.draftService.formatTimestamp(savedAt) : '');
|
|
218
|
-
this.bannerRef.setInput('restoredText', this.draftRestoredText);
|
|
219
|
-
this.bannerRef.setInput('savedText', this.draftSavedText);
|
|
220
|
-
this.bannerRef.setInput('savedLabel', this.draftSavedLabel);
|
|
221
|
-
this.bannerRef.setInput('discardText', this.draftDiscardText);
|
|
222
|
-
this.bannerRef.instance.discard.subscribe(() => this.discardDraft());
|
|
223
|
-
const bannerEl = this.bannerRef.location.nativeElement;
|
|
224
|
-
const formEl = this.elRef.nativeElement;
|
|
225
|
-
this.renderer.insertBefore(formEl, bannerEl, formEl.firstChild);
|
|
226
|
-
this.cdRef.detectChanges();
|
|
227
|
-
}
|
|
228
|
-
destroyBanner() {
|
|
229
|
-
if (this.bannerRef) {
|
|
230
|
-
this.bannerRef.destroy();
|
|
231
|
-
this.bannerRef = null;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
clearDraft() {
|
|
235
|
-
this.draftService.clear(this.formId);
|
|
236
|
-
this.destroyBanner();
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
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 });
|
|
240
|
-
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 });
|
|
241
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftDirective, decorators: [{
|
|
242
|
-
type: Directive,
|
|
243
|
-
args: [{
|
|
244
|
-
selector: '[ngxFormDraft]',
|
|
245
|
-
}]
|
|
246
|
-
}], ctorParameters: function () { return [{ type: i1.FormGroupDirective, decorators: [{
|
|
247
|
-
type: Optional
|
|
248
|
-
}] }, { type: i1.NgForm, decorators: [{
|
|
249
|
-
type: Optional
|
|
250
|
-
}] }, { type: i2.FormDraftService }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { formId: [{
|
|
251
|
-
type: Input,
|
|
252
|
-
args: ['ngxFormDraft']
|
|
253
|
-
}], draftDebounce: [{
|
|
254
|
-
type: Input
|
|
255
|
-
}], draftExcludeFields: [{
|
|
256
|
-
type: Input
|
|
257
|
-
}], draftShowOnChange: [{
|
|
258
|
-
type: Input
|
|
259
|
-
}], draftRestoredText: [{
|
|
260
|
-
type: Input
|
|
261
|
-
}], draftSavedText: [{
|
|
262
|
-
type: Input
|
|
263
|
-
}], draftSavedLabel: [{
|
|
264
|
-
type: Input
|
|
265
|
-
}], draftDiscardText: [{
|
|
266
|
-
type: Input
|
|
267
|
-
}] } });
|
|
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, filter } 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.draftService.registerReset(this.formId, () => this.performResetAndDestroyBanner());
|
|
45
|
+
// For reactive forms, capture initial values and restore draft immediately
|
|
46
|
+
if (this.formGroupDir) {
|
|
47
|
+
this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));
|
|
48
|
+
const draft = this.draftService.load(this.formId);
|
|
49
|
+
if (draft) {
|
|
50
|
+
this.restoreDraft(draft.values);
|
|
51
|
+
this.showBanner(draft.savedAt, true);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
let hasUserInteraction = false;
|
|
55
|
+
this.formControl.valueChanges
|
|
56
|
+
.pipe(filter(() => {
|
|
57
|
+
if (this.isRestoring)
|
|
58
|
+
return false;
|
|
59
|
+
if (this.ngForm && !hasUserInteraction) {
|
|
60
|
+
const currentValues = this.formControl?.value || {};
|
|
61
|
+
const isDifferent = JSON.stringify(currentValues) !== JSON.stringify(this.initialValues);
|
|
62
|
+
if (isDifferent) {
|
|
63
|
+
hasUserInteraction = true;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
return true;
|
|
69
|
+
}), debounceTime(this.draftDebounce), takeUntil(this.destroy$))
|
|
70
|
+
.subscribe((values) => {
|
|
71
|
+
this.saveDraft(values);
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
ngAfterViewInit() {
|
|
75
|
+
if (this.ngForm && this.formControl) {
|
|
76
|
+
const draft = this.draftService.load(this.formId);
|
|
77
|
+
if (draft) {
|
|
78
|
+
this.isRestoring = true;
|
|
79
|
+
}
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
if (draft) {
|
|
82
|
+
this.restoreDraft(draft.values);
|
|
83
|
+
this.showBanner(draft.savedAt, true);
|
|
84
|
+
this.initialValues = {};
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.initialValues = JSON.parse(JSON.stringify(this.formControl.value));
|
|
88
|
+
}
|
|
89
|
+
}, 0);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
ngOnDestroy() {
|
|
93
|
+
this.draftService.unregisterReset(this.formId);
|
|
94
|
+
this.destroy$.next();
|
|
95
|
+
this.destroy$.complete();
|
|
96
|
+
this.destroyBanner();
|
|
97
|
+
}
|
|
98
|
+
saveDraft(values) {
|
|
99
|
+
const filtered = this.filterFields(values);
|
|
100
|
+
// Don't save if empty
|
|
101
|
+
if (this.isAllEmpty(filtered)) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Don't save if matches initial values (even if initial is empty)
|
|
105
|
+
if (this.matchesInitialValues(filtered)) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
this.draftService.save(this.formId, filtered);
|
|
109
|
+
if (this.draftShowOnChange && !this.bannerRef) {
|
|
110
|
+
this.showBanner(Date.now(), false);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
filterFields(values) {
|
|
114
|
+
if (!this.draftExcludeFields.length)
|
|
115
|
+
return values;
|
|
116
|
+
const result = { ...values };
|
|
117
|
+
this.draftExcludeFields.forEach(field => delete result[field]);
|
|
118
|
+
return result;
|
|
119
|
+
}
|
|
120
|
+
isAllEmpty(values) {
|
|
121
|
+
return Object.values(values).every(v => v === null || v === undefined || v === '' || (Array.isArray(v) && v.length === 0));
|
|
122
|
+
}
|
|
123
|
+
matchesInitialValues(values) {
|
|
124
|
+
return JSON.stringify(values) === JSON.stringify(this.initialValues);
|
|
125
|
+
}
|
|
126
|
+
restoreDraft(values) {
|
|
127
|
+
if (!this.formControl)
|
|
128
|
+
return;
|
|
129
|
+
this.isRestoring = true;
|
|
130
|
+
const form = this.formGroupDir?.form || this.ngForm?.form;
|
|
131
|
+
if (form) {
|
|
132
|
+
this.prepareFormArrays(form, values);
|
|
133
|
+
form.patchValue(values);
|
|
134
|
+
}
|
|
135
|
+
setTimeout(() => this.isRestoring = false, 100);
|
|
136
|
+
}
|
|
137
|
+
prepareFormArrays(control, value) {
|
|
138
|
+
if (!control || value == null)
|
|
139
|
+
return;
|
|
140
|
+
if (control instanceof FormGroup && value && typeof value === 'object' && !Array.isArray(value)) {
|
|
141
|
+
Object.keys(value).forEach(key => {
|
|
142
|
+
const childControl = control.get(key);
|
|
143
|
+
if (childControl)
|
|
144
|
+
this.prepareFormArrays(childControl, value[key]);
|
|
145
|
+
});
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (control instanceof FormArray && Array.isArray(value)) {
|
|
149
|
+
const formArray = control;
|
|
150
|
+
while (formArray.length < value.length) {
|
|
151
|
+
const template = formArray.at(0);
|
|
152
|
+
if (template instanceof FormGroup) {
|
|
153
|
+
const newGroup = new FormGroup({});
|
|
154
|
+
Object.keys(template.controls).forEach(ctrlName => {
|
|
155
|
+
const existing = template.get(ctrlName);
|
|
156
|
+
if (existing instanceof FormArray) {
|
|
157
|
+
newGroup.addControl(ctrlName, new FormArray([]));
|
|
158
|
+
}
|
|
159
|
+
else if (existing instanceof FormGroup) {
|
|
160
|
+
newGroup.addControl(ctrlName, new FormGroup({}));
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
newGroup.addControl(ctrlName, new FormControl(null));
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
formArray.push(newGroup);
|
|
167
|
+
}
|
|
168
|
+
else if (template) {
|
|
169
|
+
formArray.push(new FormControl(null));
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const firstValue = value[0];
|
|
173
|
+
if (firstValue && typeof firstValue === 'object' && !Array.isArray(firstValue)) {
|
|
174
|
+
const group = new FormGroup({});
|
|
175
|
+
Object.keys(firstValue).forEach(key => group.addControl(key, new FormControl(null)));
|
|
176
|
+
formArray.push(group);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
formArray.push(new FormControl(null));
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
while (formArray.length > value.length) {
|
|
184
|
+
formArray.removeAt(formArray.length - 1);
|
|
185
|
+
}
|
|
186
|
+
value.forEach((childValue, index) => {
|
|
187
|
+
this.prepareFormArrays(formArray.at(index), childValue);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
discardDraft() {
|
|
192
|
+
this.draftService.clear(this.formId);
|
|
193
|
+
this.performResetAndDestroyBanner();
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Resets the form to initial values and destroys the draft banner.
|
|
197
|
+
* Used by the service when clearAndReset(formId) is called (e.g. on submit).
|
|
198
|
+
*/
|
|
199
|
+
performResetAndDestroyBanner() {
|
|
200
|
+
if (this.formControl) {
|
|
201
|
+
this.isRestoring = true;
|
|
202
|
+
const form = this.formGroupDir?.form || this.ngForm?.form;
|
|
203
|
+
if (form) {
|
|
204
|
+
this.prepareFormArrays(form, this.initialValues);
|
|
205
|
+
form.reset(this.initialValues);
|
|
206
|
+
}
|
|
207
|
+
setTimeout(() => {
|
|
208
|
+
this.isRestoring = false;
|
|
209
|
+
}, this.draftDebounce + 200);
|
|
210
|
+
}
|
|
211
|
+
this.destroyBanner();
|
|
212
|
+
}
|
|
213
|
+
showBanner(savedAt, isRestored = false) {
|
|
214
|
+
this.bannerRef = this.viewContainerRef.createComponent(FormDraftBannerComponent);
|
|
215
|
+
this.bannerRef.setInput('visible', true);
|
|
216
|
+
this.bannerRef.setInput('isRestored', isRestored);
|
|
217
|
+
this.bannerRef.setInput('timeLabel', isRestored ? this.draftService.formatTimestamp(savedAt) : '');
|
|
218
|
+
this.bannerRef.setInput('restoredText', this.draftRestoredText);
|
|
219
|
+
this.bannerRef.setInput('savedText', this.draftSavedText);
|
|
220
|
+
this.bannerRef.setInput('savedLabel', this.draftSavedLabel);
|
|
221
|
+
this.bannerRef.setInput('discardText', this.draftDiscardText);
|
|
222
|
+
this.bannerRef.instance.discard.subscribe(() => this.discardDraft());
|
|
223
|
+
const bannerEl = this.bannerRef.location.nativeElement;
|
|
224
|
+
const formEl = this.elRef.nativeElement;
|
|
225
|
+
this.renderer.insertBefore(formEl, bannerEl, formEl.firstChild);
|
|
226
|
+
this.cdRef.detectChanges();
|
|
227
|
+
}
|
|
228
|
+
destroyBanner() {
|
|
229
|
+
if (this.bannerRef) {
|
|
230
|
+
this.bannerRef.destroy();
|
|
231
|
+
this.bannerRef = null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
clearDraft() {
|
|
235
|
+
this.draftService.clear(this.formId);
|
|
236
|
+
this.destroyBanner();
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
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 });
|
|
240
|
+
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 });
|
|
241
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: FormDraftDirective, decorators: [{
|
|
242
|
+
type: Directive,
|
|
243
|
+
args: [{
|
|
244
|
+
selector: '[ngxFormDraft]',
|
|
245
|
+
}]
|
|
246
|
+
}], ctorParameters: function () { return [{ type: i1.FormGroupDirective, decorators: [{
|
|
247
|
+
type: Optional
|
|
248
|
+
}] }, { type: i1.NgForm, decorators: [{
|
|
249
|
+
type: Optional
|
|
250
|
+
}] }, { type: i2.FormDraftService }, { type: i0.ViewContainerRef }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }]; }, propDecorators: { formId: [{
|
|
251
|
+
type: Input,
|
|
252
|
+
args: ['ngxFormDraft']
|
|
253
|
+
}], draftDebounce: [{
|
|
254
|
+
type: Input
|
|
255
|
+
}], draftExcludeFields: [{
|
|
256
|
+
type: Input
|
|
257
|
+
}], draftShowOnChange: [{
|
|
258
|
+
type: Input
|
|
259
|
+
}], draftRestoredText: [{
|
|
260
|
+
type: Input
|
|
261
|
+
}], draftSavedText: [{
|
|
262
|
+
type: Input
|
|
263
|
+
}], draftSavedLabel: [{
|
|
264
|
+
type: Input
|
|
265
|
+
}], draftDiscardText: [{
|
|
266
|
+
type: Input
|
|
267
|
+
}] } });
|
|
268
268
|
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybS1kcmFmdC5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZm9ybS1kcmFmdC5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFBRSxLQUFLLEVBQW9DLFFBQVEsR0FFN0QsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUErQyxTQUFTLEVBQUUsU0FBUyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hILE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxTQUFTLEVBQVEsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFdkUsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sK0JBQStCLENBQUM7Ozs7QUFFekU7Ozs7Ozs7O0dBUUc7QUFJSCxNQUFNLE9BQU8sa0JBQWtCO0lBZ0I3QixZQUNzQixZQUFnQyxFQUNoQyxNQUFjLEVBQzFCLFlBQThCLEVBQzlCLGdCQUFrQyxFQUNsQyxLQUF3QixFQUN4QixLQUFpQixFQUNqQixRQUFtQjtRQU5QLGlCQUFZLEdBQVosWUFBWSxDQUFvQjtRQUNoQyxXQUFNLEdBQU4sTUFBTSxDQUFRO1FBQzFCLGlCQUFZLEdBQVosWUFBWSxDQUFrQjtRQUM5QixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQ2xDLFVBQUssR0FBTCxLQUFLLENBQW1CO1FBQ3hCLFVBQUssR0FBTCxLQUFLLENBQVk7UUFDakIsYUFBUSxHQUFSLFFBQVEsQ0FBVztRQXJCcEIsa0JBQWEsR0FBRyxHQUFHLENBQUM7UUFDcEIsdUJBQWtCLEdBQWEsRUFBRSxDQUFDO1FBQ2xDLHNCQUFpQixHQUFHLEtBQUssQ0FBQztRQUMxQixzQkFBaUIsR0FBRyxnQkFBZ0IsQ0FBQztRQUNyQyxtQkFBYyxHQUFHLGFBQWEsQ0FBQztRQUMvQixvQkFBZSxHQUFHLE9BQU8sQ0FB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QyxhQUFhLENBQUM7UUFDdkQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLENBQUM7UUFDeEMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFaEUsSUFBSSxDQUFDLEtBQUssQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUM3QixDQUFDO0lBRU8sYUFBYTtRQUNuQixJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDbEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUN6QixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztTQUN2QjtJQUNILENBQUM7SUFFTSxVQUFVO1FBQ2YsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQ3JDLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN2QixDQUFDOzsrR0ExUFUsa0JBQWtCO21HQUFsQixrQkFBa0I7MkZBQWxCLGtCQUFrQjtrQkFIOUIsU0FBUzttQkFBQztvQkFDVCxRQUFRLEVBQUUsZ0JBQWdCO2lCQUMzQjs7MEJBa0JJLFFBQVE7OzBCQUNSLFFBQVE7MkxBakJZLE1BQU07c0JBQTVCLEtBQUs7dUJBQUMsY0FBYztnQkFDWixhQUFhO3NCQUFyQixLQUFLO2dCQUNHLGtCQUFrQjtzQkFBMUIsS0FBSztnQkFDRyxpQkFBaUI7c0JBQXpCLEtBQUs7Z0JBQ0csaUJBQWlCO3NCQUF6QixLQUFLO2dCQUNHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBQ0csZUFBZTtzQkFBdkIsS0FBSztnQkFDRyxnQkFBZ0I7c0JBQXhCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBEaXJlY3RpdmUsIElucHV0LCBPbkluaXQsIEFmdGVyVmlld0luaXQsIE9uRGVzdHJveSwgT3B0aW9uYWwsIENvbXBvbmVudFJlZixcbiAgVmlld0NvbnRhaW5lclJlZiwgQ2hhbmdlRGV0ZWN0b3JSZWYsIEVsZW1lbnRSZWYsIFJlbmRlcmVyMixcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ0Zvcm0sIEZvcm1Hcm91cERpcmVjdGl2ZSwgQWJzdHJhY3RDb250cm9sLCBGb3JtQXJyYXksIEZvcm1Hcm91cCwgRm9ybUNvbnRyb2wgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIHRha2VVbnRpbCwgc2tpcCwgZmlsdGVyIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHsgRm9ybURyYWZ0U2VydmljZSB9IGZyb20gJy4vZm9ybS1kcmFmdC5zZXJ2aWNlJztcbmltcG9ydCB7IEZvcm1EcmFmdEJhbm5lckNvbXBvbmVudCB9IGZyb20gJy4vZm9ybS1kcmFmdC1iYW5uZXIuY29tcG9uZW50JztcblxuLyoqXG4gKiBBdXRvLXNhdmVzIGFuZCByZXN0b3JlcyBmb3JtIGRyYWZ0c1xuICogXG4gKiBAZXhhbXBsZVxuICogPGZvcm0gW2Zvcm1Hcm91cF09XCJteUZvcm1cIiBuZ3hGb3JtRHJhZnQ9XCJteUZvcm1JZFwiPlxuICogXG4gKiBAZXhhbXBsZVxuICogPGZvcm0gW2Zvcm1Hcm91cF09XCJteUZvcm1cIiBbbmd4Rm9ybURyYWZ0XT1cIidlZGl0XycgKyBlbnRpdHlJZFwiIFtkcmFmdEV4Y2x1ZGVGaWVsZHNdPVwiWydwYXNzd29yZCddXCI+XG4gKi9cbkBEaXJlY3RpdmUoe1xuICBzZWxlY3RvcjogJ1tuZ3hGb3JtRHJhZnRdJyxcbn0pXG5leHBvcnQgY2xhc3MgRm9ybURyYWZ0RGlyZWN0aXZlIGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xuICBASW5wdXQoJ25neEZvcm1EcmFmdCcpIGZvcm1JZCE6IHN0cmluZztcbiAgQElucHV0KCkgZHJhZnREZWJvdW5jZSA9IDgwMDtcbiAgQElucHV0KCkgZHJhZnRFeGNsdWRlRmllbGRzOiBzdHJpbmdbXSA9IFtdO1xuICBASW5wdXQoKSBkcmFmdFNob3dPbkNoYW5nZSA9IGZhbHNlO1xuICBASW5wdXQoKSBkcmFmdFJlc3RvcmVkVGV4dCA9ICdEcmFmdCByZXN0b3JlZCc7XG4gIEBJbnB1dCgpIGRyYWZ0U2F2ZWRUZXh0ID0gJ0RyYWZ0IHNhdmVkJztcbiAgQElucHV0KCkgZHJhZnRTYXZlZExhYmVsID0gJ3NhdmVkJztcbiAgQElucHV0KCkgZHJhZnREaXNjYXJkVGV4dCA9ICdEaXNjYXJkJztcblxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgcHJpdmF0ZSBiYW5uZXJSZWY6IENvbXBvbmVudFJlZjxGb3JtRHJhZnRCYW5uZXJDb21wb25lbnQ+IHwgbnVsbCA9IG51bGw7XG4gIHByaXZhdGUgZm9ybUNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGluaXRpYWxWYWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4gPSB7fTtcbiAgcHJpdmF0ZSBpc1Jlc3RvcmluZyA9IGZhbHNlO1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgZm9ybUdyb3VwRGlyOiBGb3JtR3JvdXBEaXJlY3RpdmUsXG4gICAgQE9wdGlvbmFsKCkgcHJpdmF0ZSBuZ0Zvcm06IE5nRm9ybSxcbiAgICBwcml2YXRlIGRyYWZ0U2VydmljZTogRm9ybURyYWZ0U2VydmljZSxcbiAgICBwcml2YXRlIHZpZXdDb250YWluZXJSZWY6IFZpZXdDb250YWluZXJSZWYsXG4gICAgcHJpdmF0ZSBjZFJlZjogQ2hhbmdlRGV0ZWN0b3JSZWYsXG4gICAgcHJpdmF0ZSBlbFJlZjogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIHJlbmRlcmVyOiBSZW5kZXJlcjIsXG4gICkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1Db250cm9sID0gdGhpcy5mb3JtR3JvdXBEaXI/LmZvcm0gfHwgdGhpcy5uZ0Zvcm0/LmZvcm0gfHwgbnVsbDtcbiAgICBpZiAoIXRoaXMuZm9ybUNvbnRyb2wgfHwgIXRoaXMuZm9ybUlkKSByZXR1cm47XG5cbiAgICB0aGlzLmRyYWZ0U2VydmljZS5yZWdpc3RlclJlc2V0KHRoaXMuZm9ybUlkLCAoKSA9PiB0aGlzLnBlcmZvcm1SZXNldEFuZERlc3Ryb3lCYW5uZXIoKSk7XG5cbiAgICAvLyBGb3IgcmVhY3RpdmUgZm9ybXMsIGNhcHR1cmUgaW5pdGlhbCB2YWx1ZXMgYW5kIHJlc3RvcmUgZHJhZnQgaW1tZWRpYXRlbHlcbiAgICBpZiAodGhpcy5mb3JtR3JvdXBEaXIpIHtcbiAgICAgIHRoaXMuaW5pdGlhbFZhbHVlcyA9IEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodGhpcy5mb3JtQ29udHJvbC52YWx1ZSkpO1xuICAgICAgXG4gICAgICBjb25zdCBkcmFmdCA9IHRoaXMuZHJhZnRTZXJ2aWNlLmxvYWQodGhpcy5mb3JtSWQpO1xuICAgICAgaWYgKGRyYWZ0KSB7XG4gICAgICAgIHRoaXMucmVzdG9yZURyYWZ0KGRyYWZ0LnZhbHVlcyk7XG4gICAgICAgIHRoaXMuc2hvd0Jhbm5lcihkcmFmdC5zYXZlZEF0LCB0cnVlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsZXQgaGFzVXNlckludGVyYWN0aW9uID0gZmFsc2U7XG4gICAgXG4gICAgdGhpcy5mb3JtQ29udHJvbC52YWx1ZUNoYW5nZXNcbiAgICAgIC5waXBlKFxuICAgICAgICBmaWx0ZXIoKCkgPT4ge1xuICAgICAgICAgIGlmICh0aGlzLmlzUmVzdG9yaW5nKSByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgaWYgKHRoaXMubmdGb3JtICYmICFoYXNVc2VySW50ZXJhY3Rpb24pIHtcbiAgICAgICAgICAgIGNvbnN0IGN1cnJlbnRWYWx1ZXMgPSB0aGlzLmZvcm1Db250cm9sPy52YWx1ZSB8fCB7fTtcbiAgICAgICAgICAgIGNvbnN0IGlzRGlmZmVyZW50ID0gSlNPTi5zdHJpbmdpZnkoY3VycmVudFZhbHVlcykgIT09IEpTT04uc3RyaW5naWZ5KHRoaXMuaW5pdGlhbFZhbHVlcyk7XG4gICAgICAgICAgICBpZiAoaXNEaWZmZXJlbnQpIHtcbiAgICAgICAgICAgICAgaGFzVXNlckludGVyYWN0aW9uID0gdHJ1ZTtcbiAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9KSxcbiAgICAgICAgZGVib3VuY2VUaW1lKHRoaXMuZHJhZnREZWJvdW5jZSksXG4gICAgICAgIHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKVxuICAgICAgKVxuICAgICAgLnN1YnNjcmliZSgodmFsdWVzKSA9PiB7XG4gICAgICAgIHRoaXMuc2F2ZURyYWZ0KHZhbHVlcyk7XG4gICAgICB9KTtcbiAgfVxuXG4gIG5nQWZ0ZXJWaWV3SW5pdCgpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5uZ0Zvcm0gJiYgdGhpcy5mb3JtQ29udHJvbCkge1xuICAgICAgY29uc3QgZHJhZnQgPSB0aGlzLmRyYWZ0U2VydmljZS5sb2FkKHRoaXMuZm9ybUlkKTtcbiAgICAgIFxuICAgICAgaWYgKGRyYWZ0KSB7XG4gICAgICAgIHRoaXMuaXNSZXN0b3JpbmcgPSB0cnVlO1xuICAgICAgfVxuICAgICAgXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgaWYgKGRyYWZ0KSB7XG4gICAgICAgICAgdGhpcy5yZXN0b3JlRHJhZnQoZHJhZnQudmFsdWVzKTtcbiAgICAgICAgICB0aGlzLnNob3dCYW5uZXIoZHJhZnQuc2F2ZWRBdCwgdHJ1ZSk7XG4gICAgICAgICAgdGhpcy5pbml0aWFsVmFsdWVzID0ge307XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5pbml0aWFsVmFsdWVzID0gSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeSh0aGlzLmZvcm1Db250cm9sIS52YWx1ZSkpO1xuICAgICAgICB9XG4gICAgICB9LCAwKTtcbiAgICB9XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRyYWZ0U2VydmljZS51bnJlZ2lzdGVyUmVzZXQodGhpcy5mb3JtSWQpO1xuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcbiAgICB0aGlzLmRlc3Ryb3lCYW5uZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgc2F2ZURyYWZ0KHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xuICAgIGNvbnN0IGZpbHRlcmVkID0gdGhpcy5maWx0ZXJGaWVsZHModmFsdWVzKTtcbiAgICBcbiAgICAvLyBEb24ndCBzYXZlIGlmIGVtcHR5XG4gICAgaWYgKHRoaXMuaXNBbGxFbXB0eShmaWx0ZXJlZCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBEb24ndCBzYXZlIGlmIG1hdGNoZXMgaW5pdGlhbCB2YWx1ZXMgKGV2ZW4gaWYgaW5pdGlhbCBpcyBlbXB0eSlcbiAgICBpZiAodGhpcy5tYXRjaGVzSW5pdGlhbFZhbHVlcyhmaWx0ZXJlZCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmRyYWZ0U2VydmljZS5zYXZlKHRoaXMuZm9ybUlkLCBmaWx0ZXJlZCk7XG4gICAgaWYgKHRoaXMuZHJhZnRTaG93T25DaGFuZ2UgJiYgIXRoaXMuYmFubmVyUmVmKSB7XG4gICAgICB0aGlzLnNob3dCYW5uZXIoRGF0ZS5ub3coKSwgZmFsc2UpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZmlsdGVyRmllbGRzKHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IFJlY29yZDxzdHJpbmcsIGFueT4ge1xuICAgIGlmICghdGhpcy5kcmFmdEV4Y2x1ZGVGaWVsZHMubGVuZ3RoKSByZXR1cm4gdmFsdWVzO1xuICAgIGNvbnN0IHJlc3VsdCA9IHsgLi4udmFsdWVzIH07XG4gICAgdGhpcy5kcmFmdEV4Y2x1ZGVGaWVsZHMuZm9yRWFjaChmaWVsZCA9PiBkZWxldGUgcmVzdWx0W2ZpZWxkXSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHByaXZhdGUgaXNBbGxFbXB0eSh2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBib29sZWFuIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh2YWx1ZXMpLmV2ZXJ5KFxuICAgICAgdiA9PiB2ID09PSBudWxsIHx8IHYgPT09IHVuZGVmaW5lZCB8fCB2ID09PSAnJyB8fCAoQXJyYXkuaXNBcnJheSh2KSAmJiB2Lmxlbmd0aCA9PT0gMClcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBtYXRjaGVzSW5pdGlhbFZhbHVlcyh2YWx1ZXM6IFJlY29yZDxzdHJpbmcsIGFueT4pOiBib29sZWFuIHtcbiAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWVzKSA9PT0gSlNPTi5zdHJpbmdpZnkodGhpcy5pbml0aWFsVmFsdWVzKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVzdG9yZURyYWZ0KHZhbHVlczogUmVjb3JkPHN0cmluZywgYW55Pik6IHZvaWQge1xuICAgIGlmICghdGhpcy5mb3JtQ29udHJvbCkgcmV0dXJuO1xuICAgIHRoaXMuaXNSZXN0b3JpbmcgPSB0cnVlO1xuXG4gICAgY29uc3QgZm9ybSA9IHRoaXMuZm9ybUdyb3VwRGlyPy5mb3JtIHx8IHRoaXMubmdGb3JtPy5mb3JtO1xuICAgIGlmIChmb3JtKSB7XG4gICAgICB0aGlzLnByZXBhcmVGb3JtQXJyYXlzKGZvcm0sIHZhbHVlcyk7XG4gICAgICBmb3JtLnBhdGNoVmFsdWUodmFsdWVzKTtcbiAgICB9XG5cbiAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMuaXNSZXN0b3JpbmcgPSBmYWxzZSwgMTAwKTtcbiAgfVxuXG4gIHByaXZhdGUgcHJlcGFyZUZvcm1BcnJheXMoY29udHJvbDogQWJzdHJhY3RDb250cm9sLCB2YWx1ZTogYW55KTogdm9pZCB7XG4gICAgaWYgKCFjb250cm9sIHx8IHZhbHVlID09IG51bGwpIHJldHVybjtcblxuICAgIGlmIChjb250cm9sIGluc3RhbmNlb2YgRm9ybUdyb3VwICYmIHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICBPYmplY3Qua2V5cyh2YWx1ZSkuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgICBjb25zdCBjaGlsZENvbnRyb2wgPSBjb250cm9sLmdldChrZXkpO1xuICAgICAgICBpZiAoY2hpbGRDb250cm9sKSB0aGlzLnByZXBhcmVGb3JtQXJyYXlzKGNoaWxkQ29udHJvbCwgdmFsdWVba2V5XSk7XG4gICAgICB9KTtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoY29udHJvbCBpbnN0YW5jZW9mIEZvcm1BcnJheSAmJiBBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgY29uc3QgZm9ybUFycmF5ID0gY29udHJvbCBhcyBGb3JtQXJyYXk7XG5cbiAgICAgIHdoaWxlIChmb3JtQXJyYXkubGVuZ3RoIDwgdmFsdWUubGVuZ3RoKSB7XG4gICAgICAgIGNvbnN0IHRlbXBsYXRlID0gZm9ybUFycmF5LmF0KDApO1xuICAgICAgICBpZiAodGVtcGxhdGUgaW5zdGFuY2VvZiBGb3JtR3JvdXApIHtcbiAgICAgICAgICBjb25zdCBuZXdHcm91cCA9IG5ldyBGb3JtR3JvdXAoe30pO1xuICAgICAgICAgIE9iamVjdC5rZXlzKHRlbXBsYXRlLmNvbnRyb2xzKS5mb3JFYWNoKGN0cmxOYW1lID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGV4aXN0aW5nID0gdGVtcGxhdGUuZ2V0KGN0cmxOYW1lKSBhcyBBYnN0cmFjdENvbnRyb2w7XG4gICAgICAgICAgICBpZiAoZXhpc3RpbmcgaW5zdGFuY2VvZiBGb3JtQXJyYXkpIHtcbiAgICAgICAgICAgICAgbmV3R3JvdXAuYWRkQ29udHJvbChjdHJsTmFtZSwgbmV3IEZvcm1BcnJheShbXSkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChleGlzdGluZyBpbnN0YW5jZW9mIEZvcm1Hcm91cCkge1xuICAgICAgICAgICAgICBuZXdHcm91cC5hZGRDb250cm9sKGN0cmxOYW1lLCBuZXcgRm9ybUdyb3VwKHt9KSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBuZXdHcm91cC5hZGRDb250cm9sKGN0cmxOYW1lLCBuZXcgRm9ybUNvbnRyb2wobnVsbCkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGZvcm1BcnJheS5wdXNoKG5ld0dyb3VwKTtcbiAgICAgICAgfSBlbHNlIGlmICh0ZW1wbGF0ZSkge1xuICAgICAgICAgIGZvcm1BcnJheS5wdXNoKG5ldyBGb3JtQ29udHJvbChudWxsKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uc3QgZmlyc3RWYWx1ZSA9IHZhbHVlWzBdO1xuICAgICAgICAgIGlmIChmaXJzdFZhbHVlICYmIHR5cGVvZiBmaXJzdFZhbHVlID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShmaXJzdFZhbHVlKSkge1xuICAgICAgICAgICAgY29uc3QgZ3JvdXAgPSBuZXcgRm9ybUdyb3VwKHt9KTtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKGZpcnN0VmFsdWUpLmZvckVhY2goa2V5ID0+IGdyb3VwLmFkZENvbnRyb2woa2V5LCBuZXcgRm9ybUNvbnRyb2wobnVsbCkpKTtcbiAgICAgICAgICAgIGZvcm1BcnJheS5wdXNoKGdyb3VwKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9ybUFycmF5LnB1c2gobmV3IEZvcm1Db250cm9sKG51bGwpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgd2hpbGUgKGZvcm1BcnJheS5sZW5ndGggPiB2YWx1ZS5sZW5ndGgpIHtcbiAgICAgICAgZm9ybUFycmF5LnJlbW92ZUF0KGZvcm1BcnJheS5sZW5ndGggLSAxKTtcbiAgICAgIH1cblxuICAgICAgdmFsdWUuZm9yRWFjaCgoY2hpbGRWYWx1ZSwgaW5kZXgpID0+IHtcbiAgICAgICAgdGhpcy5wcmVwYXJlRm9ybUFycmF5cyhmb3JtQXJyYXkuYXQoaW5kZXgpLCBjaGlsZFZhbHVlKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgZGlzY2FyZERyYWZ0KCk6IHZvaWQge1xuICAgIHRoaXMuZHJhZnRTZXJ2aWNlLmNsZWFyKHRoaXMuZm9ybUlkKTtcbiAgICB0aGlzLnBlcmZvcm1SZXNldEFuZERlc3Ryb3lCYW5uZXIoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXNldHMgdGhlIGZvcm0gdG8gaW5pdGlhbCB2YWx1ZXMgYW5kIGRlc3Ryb3lzIHRoZSBkcmFmdCBiYW5uZXIuXG4gICAqIFVzZWQgYnkgdGhlIHNlcnZpY2Ugd2hlbiBjbGVhckFuZFJlc2V0KGZvcm1JZCkgaXMgY2FsbGVkIChlLmcuIG9uIHN1Ym1pdCkuXG4gICAqL1xuICBwdWJsaWMgcGVyZm9ybVJlc2V0QW5kRGVzdHJveUJhbm5lcigpOiB2b2lkIHtcbiAgICBpZiAodGhpcy5mb3JtQ29udHJvbCkge1xuICAgICAgdGhpcy5pc1Jlc3RvcmluZyA9IHRydWU7XG4gICAgICBjb25zdCBmb3JtID0gdGhpcy5mb3JtR3JvdXBEaXI/LmZvcm0gfHwgdGhpcy5uZ0Zvcm0/LmZvcm07XG4gICAgICBpZiAoZm9ybSkge1xuICAgICAgICB0aGlzLnByZXBhcmVGb3JtQXJyYXlzKGZvcm0sIHRoaXMuaW5pdGlhbFZhbHVlcyk7XG4gICAgICAgIGZvcm0ucmVzZXQodGhpcy5pbml0aWFsVmFsdWVzKTtcbiAgICAgIH1cbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLmlzUmVzdG9yaW5nID0gZmFsc2U7XG4gICAgICB9LCB0aGlzLmRyYWZ0RGVib3VuY2UgKyAyMDApO1xuICAgIH1cbiAgICB0aGlzLmRlc3Ryb3lCYW5uZXIoKTtcbiAgfVxuXG4gIHByaXZhdGUgc2hvd0Jhbm5lcihzYXZlZEF0OiBudW1iZXIsIGlzUmVzdG9yZWQgPSBmYWxzZSk6IHZvaWQge1xuICAgIHRoaXMuYmFubmVyUmVmID0gdGhpcy52aWV3Q29udGFpbmVyUmVmLmNyZWF0ZUNvbXBvbmVudChGb3JtRHJhZnRCYW5uZXJDb21wb25lbnQpO1xuICAgIHRoaXMuYmFubmVyUmVmLnNldElucHV0KCd2aXNpYmxlJywgdHJ1ZSk7XG4gICAgdGhpcy5iYW5uZXJSZWYuc2V0SW5wdXQoJ2lzUmVzdG9yZWQnLCBpc1Jlc3RvcmVkKTtcbiAgICB0aGlzLmJhbm5lclJlZi5zZXRJbnB1dCgndGltZUxhYmVsJywgaXNSZXN0b3JlZCA/IHRoaXMuZHJhZnRTZXJ2aWNlLmZvcm1hdFRpbWVzdGFtcChzYXZlZEF0KSA6ICcnKTtcbiAgICB0aGlzLmJhbm5lclJlZi5zZXRJbnB1dCgncmVzdG9yZWRUZXh0JywgdGhpcy5kcmFmdFJlc3RvcmVkVGV4dCk7XG4gICAgdGhpcy5iYW5uZXJSZWYuc2V0SW5wdXQoJ3NhdmVkVGV4dCcsIHRoaXMuZHJhZnRTYXZlZFRleHQpO1xuICAgIHRoaXMuYmFubmVyUmVmLnNldElucHV0KCdzYXZlZExhYmVsJywgdGhpcy5kcmFmdFNhdmVkTGFiZWwpO1xuICAgIHRoaXMuYmFubmVyUmVmLnNldElucHV0KCdkaXNjYXJkVGV4dCcsIHRoaXMuZHJhZnREaXNjYXJkVGV4dCk7XG5cbiAgICB0aGlzLmJhbm5lclJlZi5pbnN0YW5jZS5kaXNjYXJkLnN1YnNjcmliZSgoKSA9PiB0aGlzLmRpc2NhcmREcmFmdCgpKTtcblxuICAgIGNvbnN0IGJhbm5lckVsID0gdGhpcy5iYW5uZXJSZWYubG9jYXRpb24ubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBmb3JtRWwgPSB0aGlzLmVsUmVmLm5hdGl2ZUVsZW1lbnQ7XG4gICAgdGhpcy5yZW5kZXJlci5pbnNlcnRCZWZvcmUoZm9ybUVsLCBiYW5uZXJFbCwgZm9ybUVsLmZpcnN0Q2hpbGQpO1xuXG4gICAgdGhpcy5jZFJlZi5kZXRlY3RDaGFuZ2VzKCk7XG4gIH1cblxuICBwcml2YXRlIGRlc3Ryb3lCYW5uZXIoKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYmFubmVyUmVmKSB7XG4gICAgICB0aGlzLmJhbm5lclJlZi5kZXN0cm95KCk7XG4gICAgICB0aGlzLmJhbm5lclJlZiA9IG51bGw7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIGNsZWFyRHJhZnQoKTogdm9pZCB7XG4gICAgdGhpcy5kcmFmdFNlcnZpY2UuY2xlYXIodGhpcy5mb3JtSWQpO1xuICAgIHRoaXMuZGVzdHJveUJhbm5lcigpO1xuICB9XG59XG4iXX0=
|