@quandis/qbo4.ui 4.0.1-CI-20240421-210609 → 4.0.1-CI-20240422-135811

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/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "author": "Quandis, Inc.",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
- "version": "4.0.1-CI-20240421-210609",
6
+ "version": "4.0.1-CI-20240422-135811",
7
7
  "workspaces": [
8
8
  "code"
9
9
  ],
package/readme.md CHANGED
@@ -104,8 +104,15 @@ The `IValidate` interface is:
104
104
 
105
105
  ```typescript
106
106
  export interface IValidate {
107
- validate(input: HTMLElement): Promise<boolean>;
107
+ // Called by `QboValidate` when fields change or a form is submitted.
108
+ validate(input: HTMLElement): Promise<boolean>;
109
+ // Called by `QboValidate` when the component is connected to the DOM.
110
+ connect(form: HTMLFormElement): void { };
111
+ // Called by `QboValidate` when the component is disconnected from the DOM.
112
+ disconnect(): void { };
113
+ // Message to display when validation fails.
108
114
  message: string;
115
+ // Selector to use to find elements to apply the IValidate implementation to.
109
116
  selector: string;
110
117
  }
111
118
  ```
@@ -130,7 +137,7 @@ For example:
130
137
 
131
138
  In this example, the `Other` field will only be enabled if either the `This` or `That` field have a value.
132
139
 
133
- Options available include:
140
+ ### DependValidator Options
134
141
 
135
142
  |Option|Default|Description|
136
143
  |-|-|-|
@@ -153,16 +160,26 @@ Options available include:
153
160
  |`{"depends": "!This"}`|`This` must have an empty value.|
154
161
  |`{"depends": "This=Foo*"}`|`This` must have a value that **starts with** `Foo`.|
155
162
  |`{"depends": "This=*Bar"}`|`This` must have a value that **ends with** `Bar`.|
156
- |`{"depends": "This=*oo*"}`|`This` must have a value that **contains** `Bar`.|
163
+ |`{"depends": "This=*oo*"}`|`This` must have a value that **contains** `oo`.|
157
164
 
158
- > HTML markup and browser standards require that attributes containing JSON be double-quoted:
165
+ The `depends` attribute may reference elements by `id` or by `name`.
166
+ In the case of a conflict, the `id` will be used.
167
+ The following expression is used find the target element:
168
+
169
+ ```typescript
170
+ const target = this.form.querySelector(`#${CSS.escape(selector)}`)
171
+ ?? this.form.querySelector(`[name="${CSS.escape(selector)}"]`);
172
+ ```
173
+
174
+ HTML markup and browser standards require that attributes containing JSON be double-quoted:
159
175
 
160
176
  ```html
161
177
  <input type="text" data-depend-options='{"depends": "This"}'/>
162
178
  ```
163
179
 
164
- > is valid, but the following is not:
180
+ is valid, but the following is not:
165
181
 
166
182
  ```html
167
183
  <input type="text" data-depend-options="{'depends': 'This'}"/>
168
184
  ```
185
+
@@ -6,21 +6,16 @@ export declare class Dependency {
6
6
  value: string | null;
7
7
  }
8
8
  export declare class DependencyValidatorOptions {
9
- dependencies: Element[];
10
9
  evaluators: any[];
11
- values: Map<Element, string>;
12
10
  depends: string;
13
11
  condition: string;
14
12
  emptyOnDisable: boolean;
15
13
  resetOnDisable: boolean;
16
- conditionalRequired: boolean;
17
- required: boolean;
18
14
  disabledClass: string;
19
- target: string | null;
20
15
  disableChildren: boolean;
21
16
  }
22
17
  export declare const DependencyValidatorOptionsToken: InjectionToken<DependencyValidatorOptions>;
23
- export declare class DependValidator implements IValidate {
18
+ export declare class DependencyValidator implements IValidate {
24
19
  message: string;
25
20
  selector: string;
26
21
  form: HTMLFormElement;
@@ -22,17 +22,17 @@ export class Dependency {
22
22
  }
23
23
  export class DependencyValidatorOptions {
24
24
  constructor() {
25
- this.dependencies = [];
25
+ // public dependencies: Element[] = [];
26
26
  this.evaluators = [];
27
- this.values = new Map();
27
+ // public values: Map<Element, string> = new Map();
28
28
  this.depends = '';
29
29
  this.condition = 'or';
30
30
  this.emptyOnDisable = false;
31
31
  this.resetOnDisable = true;
32
- this.conditionalRequired = true;
33
- this.required = false;
32
+ // public conditionalRequired: boolean = true;
33
+ // public required: boolean = false;
34
34
  this.disabledClass = 'disabled';
35
- this.target = null;
35
+ // public target: string | null = null;
36
36
  this.disableChildren = true;
37
37
  }
38
38
  }
@@ -49,7 +49,7 @@ const operations = new Map([
49
49
  ]);
50
50
  // operations.set('', () => null);
51
51
  const operationsKeys = Array.from(operations.keys());
52
- let DependValidator = class DependValidator {
52
+ let DependencyValidator = class DependencyValidator {
53
53
  constructor(containingForm, options) {
54
54
  this.message = 'Dependency condition not met';
55
55
  this.selector = '[data-depend-options]';
@@ -87,47 +87,29 @@ let DependValidator = class DependValidator {
87
87
  // let isValid: boolean;
88
88
  let opValid;
89
89
  if (options.condition === 'or') {
90
- // isValid = options.dependencies.some(el => this.isElementValid(el, options));
91
90
  opValid = options.evaluators.some((evaluator) => evaluator() === true);
92
91
  }
93
92
  else {
94
- // isValid = options.dependencies.every(el => this.isElementValid(el, options));
95
93
  opValid = options.evaluators.every((evaluator) => evaluator() === true);
96
94
  }
97
95
  if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement)
98
96
  input.disabled = !opValid;
99
97
  input.classList.toggle(options.disabledClass, !opValid);
98
+ const targets = elementSelectorAll(input, 'input,select,textarea');
100
99
  if (!opValid) {
101
100
  if (options.disableChildren)
102
- elementSelectorAll(input, 'input,select,textarea').forEach((el) => el.setAttribute('disabled', 'disabled'));
101
+ targets.forEach((el) => el.setAttribute('disabled', 'disabled'));
103
102
  if (options.resetOnDisable)
104
- elementSelectorAll(input, 'input,select,textarea').forEach((el) => elementResetValue(el));
103
+ targets.forEach((el) => elementResetValue(el));
105
104
  else if (options.emptyOnDisable)
106
- elementSelectorAll(input, 'input,select,textarea').forEach((el) => elementClearValue(el));
105
+ targets.forEach((el) => elementClearValue(el));
107
106
  }
108
107
  else {
109
108
  if (options.disableChildren)
110
- elementSelectorAll(input, 'input,select,textarea').forEach((el) => el.removeAttribute('disabled'));
109
+ targets.forEach((el) => el.removeAttribute('disabled'));
111
110
  }
112
111
  return Promise.resolve(opValid);
113
112
  }
114
- //private isElementValid(element: Element | null, options: DependencyValidatorOptions): boolean {
115
- // if (!element) {
116
- // return false;
117
- // }
118
- // // const evaluator: OperationFunc | null = options.evaluators.get(element) ?? null;
119
- // if (element instanceof HTMLInputElement) {
120
- // if (element.type === 'checkbox' || element.type === 'radio') {
121
- // return element.checked;
122
- // } else {
123
- // return element.value.trim() !== '';
124
- // }
125
- // }
126
- // if (element instanceof HTMLSelectElement) {
127
- // return element.selectedIndex > 0;
128
- // }
129
- // return element.textContent?.trim() !== '';
130
- //}
131
113
  getOptions(input) {
132
114
  let options = this.optionsCache.get(input);
133
115
  if (!options) {
@@ -178,32 +160,6 @@ let DependValidator = class DependValidator {
178
160
  return (operator === "!=") ? () => target.selected : () => !target.selected;
179
161
  }
180
162
  }).filter(op => op !== undefined);
181
- options.dependencies = options.depends.split(',').map((depend) => {
182
- depend = depend.trim();
183
- let operator = operationsKeys.find(op => depend.includes(op)) ?? '!=';
184
- let selector = null;
185
- let value = '';
186
- if (operator) {
187
- const parts = depend.split(operator);
188
- selector = parts[0];
189
- value = parts[1];
190
- }
191
- else if (depend.startsWith('!')) {
192
- operator = '=';
193
- selector = depend.substring(1);
194
- }
195
- else {
196
- operator = '!=';
197
- selector = depend;
198
- }
199
- const target = this.form.querySelector(`#${CSS.escape(selector)}`)
200
- ?? this.form.querySelector(`[name="${CSS.escape(selector)}"]`);
201
- //if (target instanceof HTMLElement) {
202
- // options?.evaluators.set(target, operations.get(operator) ?? (() => null));
203
- // options?.values.set(target, value);
204
- //}
205
- return target;
206
- }).filter((elem) => elem !== null);
207
163
  this.optionsCache.set(input, options);
208
164
  }
209
165
  return options;
@@ -214,12 +170,12 @@ let DependValidator = class DependValidator {
214
170
  }
215
171
  ;
216
172
  };
217
- DependValidator = __decorate([
173
+ DependencyValidator = __decorate([
218
174
  injectable(),
219
175
  __param(1, inject(DependencyValidatorOptionsToken)),
220
176
  __metadata("design:paramtypes", [HTMLFormElement,
221
177
  DependencyValidatorOptions])
222
- ], DependValidator);
223
- export { DependValidator };
178
+ ], DependencyValidator);
179
+ export { DependencyValidator };
224
180
  services.container.register(DependencyValidatorOptionsToken, { useValue: new DependencyValidatorOptions() });
225
- services.container.register(ValidateToken, { useClass: DependValidator });
181
+ services.container.register(ValidateToken, { useClass: DependencyValidator });
@@ -11,17 +11,17 @@ export class Dependency {
11
11
 
12
12
  type OperationFunc = (left: any, right: any) => boolean | null;
13
13
  export class DependencyValidatorOptions {
14
- public dependencies: Element[] = [];
14
+ // public dependencies: Element[] = [];
15
15
  public evaluators: any[] = [];
16
- public values: Map<Element, string> = new Map();
16
+ // public values: Map<Element, string> = new Map();
17
17
  public depends: string = '';
18
18
  public condition: string = 'or';
19
19
  public emptyOnDisable: boolean = false;
20
20
  public resetOnDisable: boolean = true;
21
- public conditionalRequired: boolean = true;
22
- public required: boolean = false;
21
+ // public conditionalRequired: boolean = true;
22
+ // public required: boolean = false;
23
23
  public disabledClass: string = 'disabled';
24
- public target: string | null = null;
24
+ // public target: string | null = null;
25
25
  public disableChildren: boolean = true
26
26
  }
27
27
  export const DependencyValidatorOptionsToken: InjectionToken<DependencyValidatorOptions> = 'DependencyValidatorOptions';
@@ -41,7 +41,7 @@ const operations: Map<string, OperationFunc> = new Map([
41
41
  const operationsKeys = Array.from(operations.keys());
42
42
 
43
43
  @injectable()
44
- export class DependValidator implements IValidate {
44
+ export class DependencyValidator implements IValidate {
45
45
  message: string = 'Dependency condition not met';
46
46
  selector: string = '[data-depend-options]';
47
47
  form: HTMLFormElement;
@@ -86,47 +86,24 @@ export class DependValidator implements IValidate {
86
86
  // let isValid: boolean;
87
87
  let opValid: boolean;
88
88
  if (options.condition === 'or') {
89
- // isValid = options.dependencies.some(el => this.isElementValid(el, options));
90
89
  opValid = options.evaluators.some((evaluator: any) => evaluator() === true);
91
90
  } else {
92
- // isValid = options.dependencies.every(el => this.isElementValid(el, options));
93
91
  opValid = options.evaluators.every((evaluator: any) => evaluator() === true);
94
92
  }
95
93
  if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement)
96
94
  input.disabled = !opValid;
97
95
  input.classList.toggle(options.disabledClass, !opValid);
98
-
96
+ const targets = elementSelectorAll(input, 'input,select,textarea');
99
97
  if (!opValid) {
100
- if (options.disableChildren) elementSelectorAll(input, 'input,select,textarea').forEach((el) => el.setAttribute('disabled', 'disabled'));
101
- if (options.resetOnDisable) elementSelectorAll(input, 'input,select,textarea').forEach((el) => elementResetValue(el));
102
- else if (options.emptyOnDisable) elementSelectorAll(input, 'input,select,textarea').forEach((el) => elementClearValue(el));
98
+ if (options.disableChildren) targets.forEach((el) => el.setAttribute('disabled', 'disabled'));
99
+ if (options.resetOnDisable) targets.forEach((el) => elementResetValue(el));
100
+ else if (options.emptyOnDisable) targets.forEach((el) => elementClearValue(el));
103
101
  } else {
104
- if (options.disableChildren) elementSelectorAll(input, 'input,select,textarea').forEach((el) => el.removeAttribute('disabled'));
102
+ if (options.disableChildren) targets.forEach((el) => el.removeAttribute('disabled'));
105
103
  }
106
104
  return Promise.resolve(opValid);
107
105
  }
108
106
 
109
- //private isElementValid(element: Element | null, options: DependencyValidatorOptions): boolean {
110
- // if (!element) {
111
- // return false;
112
- // }
113
-
114
- // // const evaluator: OperationFunc | null = options.evaluators.get(element) ?? null;
115
- // if (element instanceof HTMLInputElement) {
116
- // if (element.type === 'checkbox' || element.type === 'radio') {
117
- // return element.checked;
118
- // } else {
119
- // return element.value.trim() !== '';
120
- // }
121
- // }
122
-
123
- // if (element instanceof HTMLSelectElement) {
124
- // return element.selectedIndex > 0;
125
- // }
126
-
127
- // return element.textContent?.trim() !== '';
128
- //}
129
-
130
107
  private getOptions(input: HTMLElement): DependencyValidatorOptions | null {
131
108
  let options = this.optionsCache.get(input);
132
109
  if (!options) {
@@ -175,30 +152,6 @@ export class DependValidator implements IValidate {
175
152
  return (operator === "!=") ? () => target.selected : () => !target.selected;
176
153
  }
177
154
  }).filter(op => op !== undefined);
178
- options.dependencies = options.depends.split(',').map((depend: string) => {
179
- depend = depend.trim();
180
- let operator = operationsKeys.find(op => depend.includes(op)) ?? '!=';
181
- let selector: string | null = null;
182
- let value: string = '';
183
- if (operator) {
184
- const parts = depend.split(operator);
185
- selector = parts[0];
186
- value = parts[1];
187
- } else if (depend.startsWith('!')) {
188
- operator = '=';
189
- selector = depend.substring(1);
190
- } else {
191
- operator = '!=';
192
- selector = depend;
193
- }
194
- const target = this.form.querySelector(`#${CSS.escape(selector)}`)
195
- ?? this.form.querySelector(`[name="${CSS.escape(selector)}"]`);
196
- //if (target instanceof HTMLElement) {
197
- // options?.evaluators.set(target, operations.get(operator) ?? (() => null));
198
- // options?.values.set(target, value);
199
- //}
200
- return target;
201
- }).filter((elem: Element | null): elem is Element => elem !== null);
202
155
  this.optionsCache.set(input, options);
203
156
  }
204
157
  return options;
@@ -211,4 +164,4 @@ export class DependValidator implements IValidate {
211
164
  }
212
165
 
213
166
  services.container.register(DependencyValidatorOptionsToken, { useValue: new DependencyValidatorOptions() });
214
- services.container.register(ValidateToken, { useClass: DependValidator });
167
+ services.container.register(ValidateToken, { useClass: DependencyValidator });
@@ -3,7 +3,7 @@ export { services } from '@quandis/qbo4.configuration';
3
3
  export * from './IApiService.js';
4
4
  export * from './IValidate.js';
5
5
  export * from './Validators.js';
6
- export * from './ValidateDepends.js';
6
+ export * from './DependencyValidator.js';
7
7
  export * from './RestApiService.js';
8
8
  export * from './qbo-badge.js';
9
9
  export * from './qbo-datalist.js';
@@ -3,7 +3,7 @@ export { services } from '@quandis/qbo4.configuration';
3
3
  export * from './IApiService.js';
4
4
  export * from './IValidate.js';
5
5
  export * from './Validators.js';
6
- export * from './ValidateDepends.js';
6
+ export * from './DependencyValidator.js';
7
7
  export * from './RestApiService.js';
8
8
  export * from './qbo-badge.js';
9
9
  export * from './qbo-datalist.js';
@@ -4,7 +4,7 @@ export { services } from '@quandis/qbo4.configuration';
4
4
  export * from './IApiService.js';
5
5
  export * from './IValidate.js';
6
6
  export * from './Validators.js';
7
- export * from './ValidateDepends.js';
7
+ export * from './DependencyValidator.js';
8
8
  export * from './RestApiService.js';
9
9
  export * from './qbo-badge.js';
10
10
  export * from './qbo-datalist.js'