@fagon/ngx-intellitoolx 16.0.1
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 +5 -0
- package/README.md +959 -0
- package/esm2022/fagon-ngx-intellitoolx.mjs +5 -0
- package/esm2022/lib/directives/required-marker/required-marker.config.mjs +2 -0
- package/esm2022/lib/directives/required-marker/required-marker.defaults.mjs +9 -0
- package/esm2022/lib/directives/required-marker/required-marker.directive.mjs +79 -0
- package/esm2022/lib/directives/required-marker/required-marker.token.mjs +3 -0
- package/esm2022/lib/form-errors/form-errors.component.mjs +110 -0
- package/esm2022/lib/form-update/confirm-handler.type.mjs +2 -0
- package/esm2022/lib/form-update/form-update-message-config.interface.mjs +2 -0
- package/esm2022/lib/form-update/form-update-message.component.mjs +53 -0
- package/esm2022/lib/form-update/unsaved-changes.guard.mjs +19 -0
- package/esm2022/lib/form-validators/index.mjs +6 -0
- package/esm2022/lib/form-validators/max-amount.validator.mjs +18 -0
- package/esm2022/lib/form-validators/max-words.validator.mjs +11 -0
- package/esm2022/lib/form-validators/min-amount.validator.mjs +18 -0
- package/esm2022/lib/form-validators/password-mismatch.validator.mjs +16 -0
- package/esm2022/lib/form-validators/unique-email.validators.mjs +40 -0
- package/esm2022/lib/helpers/intellitoolx.helper.mjs +156 -0
- package/esm2022/lib/ngx-intellitoolx.component.mjs +11 -0
- package/esm2022/lib/ngx-intellitoolx.module.mjs +17 -0
- package/esm2022/lib/pipes/json-parse.pipe.mjs +18 -0
- package/esm2022/lib/regex/regex.utils.mjs +7 -0
- package/esm2022/public-api.mjs +27 -0
- package/fesm2022/fagon-ngx-intellitoolx.mjs +576 -0
- package/fesm2022/fagon-ngx-intellitoolx.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/directives/required-marker/required-marker.config.d.ts +9 -0
- package/lib/directives/required-marker/required-marker.defaults.d.ts +2 -0
- package/lib/directives/required-marker/required-marker.directive.d.ts +17 -0
- package/lib/directives/required-marker/required-marker.token.d.ts +3 -0
- package/lib/form-errors/form-errors.component.d.ts +29 -0
- package/lib/form-update/confirm-handler.type.d.ts +1 -0
- package/lib/form-update/form-update-message-config.interface.d.ts +11 -0
- package/lib/form-update/form-update-message.component.d.ts +14 -0
- package/lib/form-update/unsaved-changes.guard.d.ts +11 -0
- package/lib/form-validators/index.d.ts +5 -0
- package/lib/form-validators/max-amount.validator.d.ts +2 -0
- package/lib/form-validators/max-words.validator.d.ts +2 -0
- package/lib/form-validators/min-amount.validator.d.ts +2 -0
- package/lib/form-validators/password-mismatch.validator.d.ts +2 -0
- package/lib/form-validators/unique-email.validators.d.ts +2 -0
- package/lib/helpers/intellitoolx.helper.d.ts +16 -0
- package/lib/ngx-intellitoolx.component.d.ts +5 -0
- package/lib/ngx-intellitoolx.module.d.ts +7 -0
- package/lib/pipes/json-parse.pipe.d.ts +7 -0
- package/lib/regex/regex.utils.d.ts +6 -0
- package/package.json +29 -0
- package/public-api.d.ts +14 -0
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
import * as i1 from '@angular/common';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import * as i0 from '@angular/core';
|
|
4
|
+
import { NgModule, Pipe, Component, Input, InjectionToken, inject, Directive, Injectable } from '@angular/core';
|
|
5
|
+
import * as i1$1 from '@angular/forms';
|
|
6
|
+
import { FormGroup, FormArray, FormControl, Validators } from '@angular/forms';
|
|
7
|
+
import { merge } from 'rxjs';
|
|
8
|
+
|
|
9
|
+
class NgxIntellitoolxModule {
|
|
10
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxIntellitoolxModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
|
|
11
|
+
static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: NgxIntellitoolxModule, imports: [CommonModule] }); }
|
|
12
|
+
static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxIntellitoolxModule, imports: [CommonModule] }); }
|
|
13
|
+
}
|
|
14
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxIntellitoolxModule, decorators: [{
|
|
15
|
+
type: NgModule,
|
|
16
|
+
args: [{
|
|
17
|
+
declarations: [],
|
|
18
|
+
imports: [CommonModule],
|
|
19
|
+
exports: [],
|
|
20
|
+
}]
|
|
21
|
+
}] });
|
|
22
|
+
|
|
23
|
+
class IntelliToolxHelper {
|
|
24
|
+
static captureInitialValue(form) {
|
|
25
|
+
const initialValue = form.getRawValue?.() ?? form.value;
|
|
26
|
+
form.markAsPristine();
|
|
27
|
+
return this.clone(initialValue);
|
|
28
|
+
}
|
|
29
|
+
static trimFormGroup(control) {
|
|
30
|
+
if (control instanceof FormGroup) {
|
|
31
|
+
Object.keys(control.controls).forEach((key) => this.trimFormGroup(control.controls[key]));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (control instanceof FormArray) {
|
|
35
|
+
control.controls.forEach((ctrl) => this.trimFormGroup(ctrl));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
if (control instanceof FormControl) {
|
|
39
|
+
const value = control.value;
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
|
+
control.setValue(value.trim(), { emitEvent: false });
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
static deepEqual(obj1, obj2) {
|
|
46
|
+
// treat null, undefined, and empty string as equal
|
|
47
|
+
if (this.isEmpty(obj1) && this.isEmpty(obj2)) {
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// normalize numeric values
|
|
51
|
+
if (typeof obj1 === 'number' && typeof obj2 === 'number') {
|
|
52
|
+
return Number(obj1) === Number(obj2);
|
|
53
|
+
}
|
|
54
|
+
// strict equality shortcut
|
|
55
|
+
if (obj1 === obj2)
|
|
56
|
+
return true;
|
|
57
|
+
// File comparison
|
|
58
|
+
if (obj1 instanceof File && obj2 instanceof File) {
|
|
59
|
+
return (obj1.name === obj2.name &&
|
|
60
|
+
obj1.size === obj2.size &&
|
|
61
|
+
obj1.type === obj2.type &&
|
|
62
|
+
obj1.lastModified === obj2.lastModified);
|
|
63
|
+
}
|
|
64
|
+
// if not objects → not equal
|
|
65
|
+
if (typeof obj1 !== 'object' ||
|
|
66
|
+
typeof obj2 !== 'object' ||
|
|
67
|
+
obj1 === null ||
|
|
68
|
+
obj2 === null) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
// arrays
|
|
72
|
+
if (Array.isArray(obj1) && Array.isArray(obj2)) {
|
|
73
|
+
if (obj1.length !== obj2.length)
|
|
74
|
+
return false;
|
|
75
|
+
return obj1.every((v, i) => this.deepEqual(v, obj2[i]));
|
|
76
|
+
}
|
|
77
|
+
const keys1 = Object.keys(obj1);
|
|
78
|
+
const keys2 = Object.keys(obj2);
|
|
79
|
+
if (keys1.length !== keys2.length)
|
|
80
|
+
return false;
|
|
81
|
+
for (const key of keys1) {
|
|
82
|
+
if (!keys2.includes(key))
|
|
83
|
+
return false;
|
|
84
|
+
if (!this.deepEqual(obj1[key], obj2[key]))
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
static isEmpty(value) {
|
|
90
|
+
return (value === null ||
|
|
91
|
+
value === undefined ||
|
|
92
|
+
(typeof value === 'string' && value.trim() === ''));
|
|
93
|
+
}
|
|
94
|
+
static clone(value) {
|
|
95
|
+
return structuredClone(value); // Angular 14+ safe
|
|
96
|
+
}
|
|
97
|
+
static formHasChanges(initialValue, form) {
|
|
98
|
+
if (!form)
|
|
99
|
+
return false;
|
|
100
|
+
const current = form.getRawValue();
|
|
101
|
+
return !this.deepEqual(initialValue, current);
|
|
102
|
+
}
|
|
103
|
+
static async confirmIfChanged(hasChanges, confirmHandler) {
|
|
104
|
+
if (!hasChanges)
|
|
105
|
+
return true;
|
|
106
|
+
if (confirmHandler) {
|
|
107
|
+
const result = confirmHandler();
|
|
108
|
+
return typeof result === 'boolean' ? result : await result;
|
|
109
|
+
}
|
|
110
|
+
// fallback (only if handler not provided)
|
|
111
|
+
return confirm('You have unsaved changes. Continue?');
|
|
112
|
+
}
|
|
113
|
+
static registerBeforeUnload(shouldBlock, message) {
|
|
114
|
+
const handler = (event) => {
|
|
115
|
+
if (!shouldBlock())
|
|
116
|
+
return;
|
|
117
|
+
event.preventDefault();
|
|
118
|
+
event.returnValue = message || '';
|
|
119
|
+
};
|
|
120
|
+
window.addEventListener('beforeunload', handler);
|
|
121
|
+
return () => window.removeEventListener('beforeunload', handler);
|
|
122
|
+
}
|
|
123
|
+
static getFormControl(form, path) {
|
|
124
|
+
if (!form || !path)
|
|
125
|
+
return null;
|
|
126
|
+
const segments = path.split('.');
|
|
127
|
+
let current = form;
|
|
128
|
+
for (const segment of segments) {
|
|
129
|
+
if (!current)
|
|
130
|
+
return null;
|
|
131
|
+
// Treat numeric segment as FormArray index
|
|
132
|
+
const index = Number(segment);
|
|
133
|
+
if (!isNaN(index) && current instanceof FormArray) {
|
|
134
|
+
current = current.at(index);
|
|
135
|
+
}
|
|
136
|
+
else if (current instanceof FormGroup) {
|
|
137
|
+
current = current.get(segment);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return current instanceof FormControl ? current : null;
|
|
144
|
+
}
|
|
145
|
+
static convertImageToBase64(file) {
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
const reader = new FileReader();
|
|
148
|
+
reader.readAsDataURL(file);
|
|
149
|
+
reader.onload = () => {
|
|
150
|
+
const base64String = reader.result;
|
|
151
|
+
const base64StringArray = base64String.split(',');
|
|
152
|
+
resolve(base64StringArray[1]);
|
|
153
|
+
};
|
|
154
|
+
reader.onerror = (error) => {
|
|
155
|
+
reject(error);
|
|
156
|
+
};
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
static replaceCharacter(text, replaceChar, replaceWithChar) {
|
|
160
|
+
return text?.replaceAll(replaceChar, replaceWithChar) || '';
|
|
161
|
+
}
|
|
162
|
+
static convertJsonStringToJson(value) {
|
|
163
|
+
if (!value) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
if (typeof value === 'string') {
|
|
167
|
+
try {
|
|
168
|
+
return JSON.parse(value);
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return value;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
class JsonParsePipe {
|
|
179
|
+
transform(value) {
|
|
180
|
+
return IntelliToolxHelper.convertJsonStringToJson(value);
|
|
181
|
+
}
|
|
182
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: JsonParsePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
183
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "16.2.12", ngImport: i0, type: JsonParsePipe, isStandalone: true, name: "jsonParse" }); }
|
|
184
|
+
}
|
|
185
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: JsonParsePipe, decorators: [{
|
|
186
|
+
type: Pipe,
|
|
187
|
+
args: [{
|
|
188
|
+
name: 'jsonParse',
|
|
189
|
+
standalone: true,
|
|
190
|
+
}]
|
|
191
|
+
}] });
|
|
192
|
+
|
|
193
|
+
class NgxIntellitoolxComponent {
|
|
194
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxIntellitoolxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
195
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: NgxIntellitoolxComponent, isStandalone: true, selector: "lib-ngx-intellitoolx", ngImport: i0, template: ` <p>ngx-intellitoolx works!</p> `, isInline: true }); }
|
|
196
|
+
}
|
|
197
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: NgxIntellitoolxComponent, decorators: [{
|
|
198
|
+
type: Component,
|
|
199
|
+
args: [{ selector: 'lib-ngx-intellitoolx', standalone: true, template: ` <p>ngx-intellitoolx works!</p> ` }]
|
|
200
|
+
}] });
|
|
201
|
+
|
|
202
|
+
class IntellitoolxFormUpdateMessage {
|
|
203
|
+
constructor() {
|
|
204
|
+
this.defaultMessage = 'There are no changes to save. Please modify a field to continue.';
|
|
205
|
+
}
|
|
206
|
+
get containerStyles() {
|
|
207
|
+
return {
|
|
208
|
+
padding: this.itxFormUpdateMessageConfig?.padding || '1rem',
|
|
209
|
+
gap: this.itxFormUpdateMessageConfig?.iconAndMessageGap || '0.5rem',
|
|
210
|
+
color: this.itxFormUpdateMessageConfig?.textColor || '#963C00',
|
|
211
|
+
border: '1px solid ' +
|
|
212
|
+
(this.itxFormUpdateMessageConfig?.borderColor || '#f3cd5a'),
|
|
213
|
+
'background-color': this.itxFormUpdateMessageConfig?.backgroundColor || '#fff3cd',
|
|
214
|
+
'font-weight': String(this.itxFormUpdateMessageConfig?.fontWeight || 400),
|
|
215
|
+
'border-radius': this.itxFormUpdateMessageConfig?.borderRadius || '0.5rem',
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
get iconStyles() {
|
|
219
|
+
return {
|
|
220
|
+
'font-size': this.itxFormUpdateMessageConfig?.iconSize || '1rem',
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IntellitoolxFormUpdateMessage, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
224
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: IntellitoolxFormUpdateMessage, isStandalone: true, selector: "itx-form-update-message", inputs: { itxFormUpdateMessageConfig: "itxFormUpdateMessageConfig" }, ngImport: i0, template: `
|
|
225
|
+
<div class="form-update-message" role="alert" [ngStyle]="containerStyles">
|
|
226
|
+
<span class="form-update-icon" aria-hidden="true" [ngStyle]="iconStyles"
|
|
227
|
+
>⚠</span
|
|
228
|
+
>
|
|
229
|
+
<span>
|
|
230
|
+
{{ itxFormUpdateMessageConfig?.message || defaultMessage }}
|
|
231
|
+
</span>
|
|
232
|
+
</div>
|
|
233
|
+
`, isInline: true, styles: [".form-update-message{display:flex;margin-top:.5rem}.form-update-icon{flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] }); }
|
|
234
|
+
}
|
|
235
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IntellitoolxFormUpdateMessage, decorators: [{
|
|
236
|
+
type: Component,
|
|
237
|
+
args: [{ selector: 'itx-form-update-message', standalone: true, imports: [CommonModule], template: `
|
|
238
|
+
<div class="form-update-message" role="alert" [ngStyle]="containerStyles">
|
|
239
|
+
<span class="form-update-icon" aria-hidden="true" [ngStyle]="iconStyles"
|
|
240
|
+
>⚠</span
|
|
241
|
+
>
|
|
242
|
+
<span>
|
|
243
|
+
{{ itxFormUpdateMessageConfig?.message || defaultMessage }}
|
|
244
|
+
</span>
|
|
245
|
+
</div>
|
|
246
|
+
`, styles: [".form-update-message{display:flex;margin-top:.5rem}.form-update-icon{flex-shrink:0}\n"] }]
|
|
247
|
+
}], propDecorators: { itxFormUpdateMessageConfig: [{
|
|
248
|
+
type: Input
|
|
249
|
+
}] } });
|
|
250
|
+
|
|
251
|
+
class IntellitoolxFormErrors {
|
|
252
|
+
constructor() {
|
|
253
|
+
this.control = null;
|
|
254
|
+
this.componentValidation = {};
|
|
255
|
+
this.controlLabel = null;
|
|
256
|
+
this.errorMessages = {
|
|
257
|
+
required: 'This field is required',
|
|
258
|
+
email: 'The email entered is invalid',
|
|
259
|
+
minlength: 'You must enter at least {length} characters',
|
|
260
|
+
maxlength: 'You must not enter more than {length} characters',
|
|
261
|
+
pattern: 'Your entry must match the required pattern',
|
|
262
|
+
passwordMismatch: 'Password and confirm password do not match.',
|
|
263
|
+
futureDate: 'Future date is not allowed.',
|
|
264
|
+
exceededAllowedDateDifference: 'Date difference can only be one month.',
|
|
265
|
+
exceededLeastDateAllowed: 'Start date cannot be greater than end date',
|
|
266
|
+
duplicateEmail: 'Each email must be unique.',
|
|
267
|
+
maxWords: 'Exceeded maximum number of words.',
|
|
268
|
+
maxMonthYear: 'Date is later than allowed.',
|
|
269
|
+
minMonthYear: 'Date is earlier than allowed.',
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
getErrorMessage(key, value) {
|
|
273
|
+
if (!this.control)
|
|
274
|
+
return '';
|
|
275
|
+
const customMessage = this.componentValidation?.[key]?.message;
|
|
276
|
+
if (typeof value === 'boolean') {
|
|
277
|
+
return customMessage || this.errorMessages[key] || '';
|
|
278
|
+
}
|
|
279
|
+
if (typeof value === 'string') {
|
|
280
|
+
return customMessage || value;
|
|
281
|
+
}
|
|
282
|
+
if (typeof value === 'object') {
|
|
283
|
+
switch (key) {
|
|
284
|
+
case 'pattern':
|
|
285
|
+
return (customMessage ||
|
|
286
|
+
`Please provide a valid ${this.controlLabel || 'data'}.`);
|
|
287
|
+
case 'min':
|
|
288
|
+
return customMessage
|
|
289
|
+
? customMessage
|
|
290
|
+
: this.controlLabel
|
|
291
|
+
? `${this.controlLabel} cannot be less than ${value.min}.`
|
|
292
|
+
: `Number cannot be less than ${value.min}`;
|
|
293
|
+
case 'max':
|
|
294
|
+
return customMessage
|
|
295
|
+
? customMessage
|
|
296
|
+
: this.controlLabel
|
|
297
|
+
? `${this.controlLabel} cannot be greater than ${value.max}.`
|
|
298
|
+
: `Number cannot be greater than ${value.max}`;
|
|
299
|
+
case 'minlength':
|
|
300
|
+
return (customMessage ||
|
|
301
|
+
this.errorMessages.minlength.replace('{length}', value?.requiredLength || ''));
|
|
302
|
+
case 'maxlength':
|
|
303
|
+
return (customMessage ||
|
|
304
|
+
this.errorMessages.maxlength.replace('{length}', value?.requiredLength || ''));
|
|
305
|
+
case 'customMinValue':
|
|
306
|
+
case 'customMaxValue':
|
|
307
|
+
return customMessage || value?.message || '';
|
|
308
|
+
case 'ngbDate':
|
|
309
|
+
return (customMessage ||
|
|
310
|
+
(this.control.value ? 'Invalid date format provided' : ''));
|
|
311
|
+
case 'passwordMismatch':
|
|
312
|
+
case 'futureDate':
|
|
313
|
+
case 'duplicateEmail':
|
|
314
|
+
case 'maxWords':
|
|
315
|
+
case 'maxMonthYear':
|
|
316
|
+
case 'minMonthYear':
|
|
317
|
+
case 'exceededAllowedDateDifference':
|
|
318
|
+
case 'exceededLeastDateAllowed':
|
|
319
|
+
return customMessage || this.errorMessages[key];
|
|
320
|
+
default:
|
|
321
|
+
return customMessage || '';
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return '';
|
|
325
|
+
}
|
|
326
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IntellitoolxFormErrors, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
327
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: IntellitoolxFormErrors, isStandalone: true, selector: "itx-form-errors", inputs: { control: "control", componentValidation: "componentValidation", controlLabel: "controlLabel" }, ngImport: i0, template: `
|
|
328
|
+
<ng-container *ngIf="control?.touched && control?.invalid">
|
|
329
|
+
<ng-container *ngFor="let error of control?.errors | keyvalue">
|
|
330
|
+
{{ getErrorMessage(error?.key ?? '', error?.value) }}
|
|
331
|
+
</ng-container>
|
|
332
|
+
</ng-container>
|
|
333
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }] }); }
|
|
334
|
+
}
|
|
335
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: IntellitoolxFormErrors, decorators: [{
|
|
336
|
+
type: Component,
|
|
337
|
+
args: [{
|
|
338
|
+
selector: 'itx-form-errors',
|
|
339
|
+
standalone: true,
|
|
340
|
+
imports: [CommonModule],
|
|
341
|
+
template: `
|
|
342
|
+
<ng-container *ngIf="control?.touched && control?.invalid">
|
|
343
|
+
<ng-container *ngFor="let error of control?.errors | keyvalue">
|
|
344
|
+
{{ getErrorMessage(error?.key ?? '', error?.value) }}
|
|
345
|
+
</ng-container>
|
|
346
|
+
</ng-container>
|
|
347
|
+
`,
|
|
348
|
+
}]
|
|
349
|
+
}], propDecorators: { control: [{
|
|
350
|
+
type: Input
|
|
351
|
+
}], componentValidation: [{
|
|
352
|
+
type: Input
|
|
353
|
+
}], controlLabel: [{
|
|
354
|
+
type: Input
|
|
355
|
+
}] } });
|
|
356
|
+
|
|
357
|
+
function customMaxAmountValidator(maxValue) {
|
|
358
|
+
return (control) => {
|
|
359
|
+
if (control.value !== null && control.value > maxValue) {
|
|
360
|
+
control.setErrors({ exceededMaximumValue: true });
|
|
361
|
+
const maxValueToFloat = maxValue.toFixed(2);
|
|
362
|
+
return {
|
|
363
|
+
customMaxValue: {
|
|
364
|
+
requiredMin: maxValue,
|
|
365
|
+
actual: control.value,
|
|
366
|
+
message: `The value must not exceed ${maxValueToFloat}`,
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
control.setErrors(null);
|
|
371
|
+
return null;
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function MaxWordsValidator(maxWords) {
|
|
376
|
+
return (control) => {
|
|
377
|
+
if (!control.value)
|
|
378
|
+
return null;
|
|
379
|
+
const wordCount = control.value.trim().split(/\s+/).length;
|
|
380
|
+
return wordCount > maxWords
|
|
381
|
+
? { maxWords: { actual: wordCount, max: maxWords } }
|
|
382
|
+
: null;
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function customMinAmountValidator(minValue) {
|
|
387
|
+
return (control) => {
|
|
388
|
+
if (control.value !== null && control.value < minValue) {
|
|
389
|
+
control.setErrors({ exceededMinimumValue: true });
|
|
390
|
+
const minValueToFloat = minValue.toFixed(2);
|
|
391
|
+
return {
|
|
392
|
+
customMinValue: {
|
|
393
|
+
requiredMin: minValue,
|
|
394
|
+
actual: control.value,
|
|
395
|
+
message: `The value must be at least ${minValueToFloat}`,
|
|
396
|
+
},
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
control.setErrors(null);
|
|
400
|
+
return null;
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
function PasswordMismatchValidator(controlName, matchingControlName) {
|
|
405
|
+
return (formGroup) => {
|
|
406
|
+
const control = formGroup.controls[controlName];
|
|
407
|
+
const matchingControl = formGroup.controls[matchingControlName];
|
|
408
|
+
if (matchingControl.errors && !matchingControl.errors['passwordMismatch']) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
if (control.value !== matchingControl.value) {
|
|
412
|
+
matchingControl.setErrors({ passwordMismatch: true });
|
|
413
|
+
}
|
|
414
|
+
else {
|
|
415
|
+
matchingControl.setErrors(null);
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function uniqueEmailsValidator() {
|
|
421
|
+
return (formArray) => {
|
|
422
|
+
if (!(formArray instanceof FormArray)) {
|
|
423
|
+
return null;
|
|
424
|
+
}
|
|
425
|
+
const controls = formArray.controls;
|
|
426
|
+
// Collect all email values safely
|
|
427
|
+
const emails = controls.map((control) => {
|
|
428
|
+
const value = control.get('email')?.value;
|
|
429
|
+
return typeof value === 'string' ? value.toLowerCase().trim() : '';
|
|
430
|
+
});
|
|
431
|
+
// Count occurrences
|
|
432
|
+
const emailCounts = {};
|
|
433
|
+
emails.forEach((email) => {
|
|
434
|
+
if (email) {
|
|
435
|
+
emailCounts[email] = (emailCounts[email] || 0) + 1;
|
|
436
|
+
}
|
|
437
|
+
});
|
|
438
|
+
// Update each control's errors
|
|
439
|
+
controls.forEach((control) => {
|
|
440
|
+
const emailControl = control.get('email');
|
|
441
|
+
const email = emailControl?.value?.toLowerCase()?.trim();
|
|
442
|
+
if (emailControl) {
|
|
443
|
+
const currentErrors = emailControl.errors || {};
|
|
444
|
+
if (email && emailCounts[email] > 1) {
|
|
445
|
+
emailControl.setErrors({ ...currentErrors, duplicateEmail: true });
|
|
446
|
+
}
|
|
447
|
+
else if (currentErrors?.['duplicateEmail']) {
|
|
448
|
+
delete currentErrors['duplicateEmail'];
|
|
449
|
+
const hasOtherErrors = Object.keys(currentErrors)?.length > 0;
|
|
450
|
+
emailControl.setErrors(hasOtherErrors ? currentErrors : null);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
const hasDuplicates = Object.values(emailCounts)?.some((count) => count > 1);
|
|
455
|
+
return hasDuplicates ? { duplicateEmails: true } : null;
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
const IntellitoolxRegExps = {
|
|
460
|
+
EMAIL_REGEX: /^(?=.{1,50}$)[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[A-Za-z]{2,}$/,
|
|
461
|
+
NUMBER_REGEX: /^\d+$/,
|
|
462
|
+
AMOUNT_REGEX: /^\d+(\.\d{1,2})?$/,
|
|
463
|
+
DOMAIN_REGEX: /^(?=.{1,255}$)(https?|ftp):\/\/([\w.-]+)\.([a-z\.]{2,6})(:[0-9]{1,5})?(\/\S*)?$/,
|
|
464
|
+
};
|
|
465
|
+
|
|
466
|
+
const REQUIRED_MARKER_GLOBAL_CONFIG = new InjectionToken('Required Marker Global Config');
|
|
467
|
+
|
|
468
|
+
const DEFAULT_REQUIRED_MARKER_CONFIG = {
|
|
469
|
+
sign: '*',
|
|
470
|
+
color: 'red',
|
|
471
|
+
position: 'after',
|
|
472
|
+
spacing: '2px',
|
|
473
|
+
className: '',
|
|
474
|
+
showIfOptional: false,
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
class RequiredMarkerDirective {
|
|
478
|
+
constructor(el, renderer, parentForm) {
|
|
479
|
+
this.el = el;
|
|
480
|
+
this.renderer = renderer;
|
|
481
|
+
this.parentForm = parentForm;
|
|
482
|
+
this.globalConfig = inject(REQUIRED_MARKER_GLOBAL_CONFIG, {
|
|
483
|
+
optional: true,
|
|
484
|
+
});
|
|
485
|
+
}
|
|
486
|
+
resolveConfig() {
|
|
487
|
+
return {
|
|
488
|
+
...DEFAULT_REQUIRED_MARKER_CONFIG,
|
|
489
|
+
...this.globalConfig,
|
|
490
|
+
};
|
|
491
|
+
}
|
|
492
|
+
ngAfterViewInit() {
|
|
493
|
+
const label = this.el.nativeElement;
|
|
494
|
+
const controlId = label.getAttribute('for');
|
|
495
|
+
if (!controlId)
|
|
496
|
+
return;
|
|
497
|
+
const control = this.parentForm.form.get(controlId);
|
|
498
|
+
if (!control)
|
|
499
|
+
return;
|
|
500
|
+
this.updateLabel(label, control);
|
|
501
|
+
this.subscription = merge(control.valueChanges, control.statusChanges).subscribe(() => this.updateLabel(label, control));
|
|
502
|
+
}
|
|
503
|
+
updateLabel(label, control) {
|
|
504
|
+
const config = this.resolveConfig();
|
|
505
|
+
const isRequired = control.hasValidator?.(Validators.required);
|
|
506
|
+
const original = label.getAttribute('data-original') || label.textContent || '';
|
|
507
|
+
if (!label.getAttribute('data-original')) {
|
|
508
|
+
label.setAttribute('data-original', original.trim());
|
|
509
|
+
}
|
|
510
|
+
const match = original.match(/^([^\(]+)(.*)$/);
|
|
511
|
+
const mainText = match ? match[1].trim() : original;
|
|
512
|
+
const extraText = match ? match[2] : '';
|
|
513
|
+
this.renderer.setProperty(label, 'textContent', '');
|
|
514
|
+
const main = this.renderer.createText(mainText);
|
|
515
|
+
const marker = this.renderer.createElement('span');
|
|
516
|
+
this.renderer.setStyle(marker, 'color', config.color);
|
|
517
|
+
this.renderer.setStyle(marker, 'margin-left', config.spacing);
|
|
518
|
+
this.renderer.appendChild(marker, this.renderer.createText(config.sign));
|
|
519
|
+
if (isRequired) {
|
|
520
|
+
if (config.position === 'before') {
|
|
521
|
+
this.renderer.appendChild(label, marker);
|
|
522
|
+
this.renderer.appendChild(label, main);
|
|
523
|
+
}
|
|
524
|
+
else {
|
|
525
|
+
this.renderer.appendChild(label, main);
|
|
526
|
+
this.renderer.appendChild(label, marker);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
else {
|
|
530
|
+
this.renderer.appendChild(label, main);
|
|
531
|
+
}
|
|
532
|
+
const extra = this.renderer.createText(extraText);
|
|
533
|
+
this.renderer.appendChild(label, extra);
|
|
534
|
+
}
|
|
535
|
+
ngOnDestroy() {
|
|
536
|
+
this.subscription?.unsubscribe();
|
|
537
|
+
}
|
|
538
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequiredMarkerDirective, deps: [{ token: i0.ElementRef }, { token: i0.Renderer2 }, { token: i1$1.FormGroupDirective }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
539
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: RequiredMarkerDirective, isStandalone: true, selector: "label[itxRequired]", ngImport: i0 }); }
|
|
540
|
+
}
|
|
541
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequiredMarkerDirective, decorators: [{
|
|
542
|
+
type: Directive,
|
|
543
|
+
args: [{
|
|
544
|
+
selector: 'label[itxRequired]',
|
|
545
|
+
standalone: true,
|
|
546
|
+
}]
|
|
547
|
+
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i0.Renderer2 }, { type: i1$1.FormGroupDirective }]; } });
|
|
548
|
+
|
|
549
|
+
class UnsavedChangesGuard {
|
|
550
|
+
canDeactivate(component) {
|
|
551
|
+
if (!component.hasUnsavedChanges()) {
|
|
552
|
+
return true;
|
|
553
|
+
}
|
|
554
|
+
const message = component.getUnsavedMessage?.() ||
|
|
555
|
+
'You have unsaved changes. Leave without saving?';
|
|
556
|
+
return confirm(message);
|
|
557
|
+
}
|
|
558
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UnsavedChangesGuard, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
559
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UnsavedChangesGuard, providedIn: 'root' }); }
|
|
560
|
+
}
|
|
561
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: UnsavedChangesGuard, decorators: [{
|
|
562
|
+
type: Injectable,
|
|
563
|
+
args: [{ providedIn: 'root' }]
|
|
564
|
+
}] });
|
|
565
|
+
|
|
566
|
+
/*
|
|
567
|
+
* Public API Surface of ngx-intellitoolx
|
|
568
|
+
*/
|
|
569
|
+
// Moddules
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* Generated bundle index. Do not edit.
|
|
573
|
+
*/
|
|
574
|
+
|
|
575
|
+
export { DEFAULT_REQUIRED_MARKER_CONFIG, IntelliToolxHelper, IntellitoolxFormErrors, IntellitoolxFormUpdateMessage, IntellitoolxRegExps, JsonParsePipe, MaxWordsValidator, NgxIntellitoolxComponent, NgxIntellitoolxModule, PasswordMismatchValidator, REQUIRED_MARKER_GLOBAL_CONFIG, RequiredMarkerDirective, UnsavedChangesGuard, customMaxAmountValidator, customMinAmountValidator, uniqueEmailsValidator };
|
|
576
|
+
//# sourceMappingURL=fagon-ngx-intellitoolx.mjs.map
|