@quandis/qbo4.ui 4.0.1-CI-20240403-131518
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 +52 -0
- package/readme.md +456 -0
- package/src/qbo/Program.d.ts +18 -0
- package/src/qbo/Program.js +18 -0
- package/src/qbo/Program.ts +19 -0
- package/src/qbo/qbo-api.d.ts +27 -0
- package/src/qbo/qbo-api.js +96 -0
- package/src/qbo/qbo-api.ts +106 -0
- package/src/qbo/qbo-badge.d.ts +32 -0
- package/src/qbo/qbo-badge.js +93 -0
- package/src/qbo/qbo-badge.js.map +1 -0
- package/src/qbo/qbo-badge.ts +80 -0
- package/src/qbo/qbo-breadcrumb.d.ts +23 -0
- package/src/qbo/qbo-breadcrumb.js +132 -0
- package/src/qbo/qbo-breadcrumb.ts +96 -0
- package/src/qbo/qbo-datalist.d.ts +22 -0
- package/src/qbo/qbo-datalist.js +126 -0
- package/src/qbo/qbo-datalist.ts +104 -0
- package/src/qbo/qbo-docviewer.d.ts +15 -0
- package/src/qbo/qbo-docviewer.js +55 -0
- package/src/qbo/qbo-docviewer.ts +39 -0
- package/src/qbo/qbo-fetch.d.ts +29 -0
- package/src/qbo/qbo-fetch.js +134 -0
- package/src/qbo/qbo-fetch.ts +127 -0
- package/src/qbo/qbo-json.d.ts +8 -0
- package/src/qbo/qbo-json.js +85 -0
- package/src/qbo/qbo-json.ts +92 -0
- package/src/qbo/qbo-link.d.ts +15 -0
- package/src/qbo/qbo-link.js +48 -0
- package/src/qbo/qbo-link.js.map +1 -0
- package/src/qbo/qbo-link.ts +34 -0
- package/src/qbo/qbo-logging.d.ts +13 -0
- package/src/qbo/qbo-logging.js +92 -0
- package/src/qbo/qbo-logging.ts +72 -0
- package/src/qbo/qbo-mainmenu.d.ts +41 -0
- package/src/qbo/qbo-mainmenu.js +307 -0
- package/src/qbo/qbo-mainmenu.ts +263 -0
- package/src/qbo/qbo-markdown.d.ts +9 -0
- package/src/qbo/qbo-markdown.js +33 -0
- package/src/qbo/qbo-markdown.js.map +1 -0
- package/src/qbo/qbo-markdown.ts +22 -0
- package/src/qbo/qbo-microphone.d.ts +31 -0
- package/src/qbo/qbo-microphone.js +149 -0
- package/src/qbo/qbo-microphone.js.map +1 -0
- package/src/qbo/qbo-microphone.ts +137 -0
- package/src/qbo/qbo-popover.d.ts +8 -0
- package/src/qbo/qbo-popover.js +41 -0
- package/src/qbo/qbo-popover.ts +26 -0
- package/src/qbo/qbo-popup-listener.d.ts +25 -0
- package/src/qbo/qbo-popup-listener.js +145 -0
- package/src/qbo/qbo-popup-listener.ts +129 -0
- package/src/qbo/qbo-popup.d.ts +19 -0
- package/src/qbo/qbo-popup.js +95 -0
- package/src/qbo/qbo-popup.ts +84 -0
- package/src/qbo/qbo-select.d.ts +22 -0
- package/src/qbo/qbo-select.js +87 -0
- package/src/qbo/qbo-select.ts +65 -0
- package/src/qbo/qbo-sidebar.d.ts +10 -0
- package/src/qbo/qbo-sidebar.js +65 -0
- package/src/qbo/qbo-sidebar.ts +41 -0
- package/src/qbo/qbo-table.d.ts +23 -0
- package/src/qbo/qbo-table.js +94 -0
- package/src/qbo/qbo-table.js.map +1 -0
- package/src/qbo/qbo-table.ts +80 -0
- package/src/qbo/qbo-validate.d.ts +20 -0
- package/src/qbo/qbo-validate.js +92 -0
- package/src/qbo/qbo-validate.js.map +1 -0
- package/src/qbo/qbo-validate.ts +77 -0
- package/src/qbo/qbo-validators.d.ts +37 -0
- package/src/qbo/qbo-validators.js +72 -0
- package/src/qbo/qbo-validators.ts +66 -0
- package/src/qbo/styles.d.ts +3 -0
- package/src/qbo/styles.js +27 -0
- package/src/qbo/styles.ts +30 -0
- package/src/qbo-code/qbo-code.d.ts +12 -0
- package/src/qbo-code/qbo-code.js +54 -0
- package/src/qbo-code/qbo-code.ts +40 -0
- package/src/qbo-flowchart/qbo-flowchart.d.ts +45 -0
- package/src/qbo-flowchart/qbo-flowchart.js +309 -0
- package/src/qbo-flowchart/qbo-flowchart.js.map +1 -0
- package/src/qbo-flowchart/qbo-flowchart.ts +320 -0
- package/src/qbo-flowchart/readme.md +2 -0
- package/wwwroot/js/qbo4.ui-code.js +37965 -0
- package/wwwroot/js/qbo4.ui-code.min.js +3 -0
- package/wwwroot/js/qbo4.ui-code.min.js.LICENSE.txt +32 -0
- package/wwwroot/js/qbo4.ui-code.min.js.map +1 -0
- package/wwwroot/js/qbo4.ui-flowchart.js +44909 -0
- package/wwwroot/js/qbo4.ui-flowchart.min.js +9 -0
- package/wwwroot/js/qbo4.ui-flowchart.min.js.LICENSE.txt +43 -0
- package/wwwroot/js/qbo4.ui-flowchart.min.js.map +1 -0
- package/wwwroot/js/qbo4.ui.js +18840 -0
- package/wwwroot/js/qbo4.ui.min.js +108 -0
- package/wwwroot/js/qbo4.ui.min.js.LICENSE.txt +53 -0
- package/wwwroot/js/qbo4.ui.min.js.map +1 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { html, css } from 'lit';
|
|
2
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import { getArray, replicate } from './qbo-json.js';
|
|
4
|
+
import { QboFetch } from './qbo-fetch.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Renders a <select> element with options populated from a JSON array.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* This element is a thin wrapper around {@link QboFetch} that renders a <table> element with options populated from a JSON array.
|
|
11
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/template#examples
|
|
12
|
+
*/
|
|
13
|
+
@customElement('qbo-table')
|
|
14
|
+
export class QboTable extends QboFetch {
|
|
15
|
+
@property({ type: Boolean })
|
|
16
|
+
loading = false;
|
|
17
|
+
|
|
18
|
+
@property({ type: Boolean })
|
|
19
|
+
renderInHost = false;
|
|
20
|
+
|
|
21
|
+
@property({ attribute: 'qbo-class' })
|
|
22
|
+
qboClass = 'table table-striped table-hover';
|
|
23
|
+
|
|
24
|
+
@property()
|
|
25
|
+
dataSelector = null;
|
|
26
|
+
|
|
27
|
+
@property()
|
|
28
|
+
options: Array<{ [key: string]: string }> | null = null;
|
|
29
|
+
|
|
30
|
+
async connectedCallback() {
|
|
31
|
+
super.connectedCallback();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* @description Let related elements know that the content has changed by raising a content-changed event. */
|
|
35
|
+
//updated(changedProperties) {
|
|
36
|
+
// super.update(changedProperties);
|
|
37
|
+
// this.dispatchEvent(new CustomEvent('qbo-updated', { bubbles: true, composed: true }));
|
|
38
|
+
//}
|
|
39
|
+
|
|
40
|
+
createRenderRoot() {
|
|
41
|
+
return this.renderInHost ? this : super.createRenderRoot();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
render() {
|
|
45
|
+
this.options = getArray(this.jsonData)
|
|
46
|
+
?? this.loadData()
|
|
47
|
+
?? [{ Loading: "..." }];
|
|
48
|
+
|
|
49
|
+
const body = this.querySelector('tbody');
|
|
50
|
+
const template = this.querySelector('template');
|
|
51
|
+
|
|
52
|
+
// If the user has specified a <template> for the body, replicate it for each item in the array.
|
|
53
|
+
replicate(this.querySelector('tbody'), this.querySelector('template'), this.options);
|
|
54
|
+
|
|
55
|
+
const keys = Object.keys(this.options[0]);
|
|
56
|
+
return html`<slot>
|
|
57
|
+
<table class=${this.qboClass}>
|
|
58
|
+
<thead>
|
|
59
|
+
${this.querySelector('*[slot=header]') != null ? html`<tr><th colspan="${keys.length}"><slot name="header"></slot></th></tr>` : null}
|
|
60
|
+
<tr>${keys.map(key => html`<th>${key}</th>`)}</tr>
|
|
61
|
+
</thead>
|
|
62
|
+
<tbody>${this.options.map((option, index) => html`<tr data-index="${index}">${keys.map(key => html`<td>${option[key]}</td>`)}</tr>`)}</tbody>
|
|
63
|
+
<tfoot><tr><td colspan="${keys.length}"><slot name="footer">${keys.length} rows rendered.</slot></td></tr></tfoot>
|
|
64
|
+
</table>
|
|
65
|
+
</slot>`
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
loadData(): Array<{ [key: string]: string }> | null {
|
|
69
|
+
if (this.dataSelector != null) {
|
|
70
|
+
const script = document.querySelector(this.dataSelector);
|
|
71
|
+
if (script != null) {
|
|
72
|
+
return getArray((<HTMLScriptElement>script).text);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { LitElement } from 'lit';
|
|
2
|
+
import { IValidate } from './qbo-validators.js';
|
|
3
|
+
/**
|
|
4
|
+
* Renders a <form> element and applies extensible validators.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* Use HTML5 validation attributes to specify the type of validation to apply.
|
|
8
|
+
*/
|
|
9
|
+
export declare class QboValidate extends LitElement {
|
|
10
|
+
renderInHost: boolean;
|
|
11
|
+
autoComplete: string;
|
|
12
|
+
validatedClass: string;
|
|
13
|
+
workingClass: string[];
|
|
14
|
+
form: HTMLFormElement | null;
|
|
15
|
+
validators: IValidate[];
|
|
16
|
+
connectedCallback(): Promise<void>;
|
|
17
|
+
disconnectedCallback(): Promise<void>;
|
|
18
|
+
validate(event: any): void;
|
|
19
|
+
render(): import("lit").TemplateResult<1>;
|
|
20
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
|
+
};
|
|
10
|
+
import { html, LitElement } from 'lit';
|
|
11
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
12
|
+
import { container } from 'tsyringe';
|
|
13
|
+
import { ValidateToken } from './qbo-validators.js';
|
|
14
|
+
/**
|
|
15
|
+
* Renders a <form> element and applies extensible validators.
|
|
16
|
+
*
|
|
17
|
+
* @remarks
|
|
18
|
+
* Use HTML5 validation attributes to specify the type of validation to apply.
|
|
19
|
+
*/
|
|
20
|
+
let QboValidate = class QboValidate extends LitElement {
|
|
21
|
+
constructor() {
|
|
22
|
+
super(...arguments);
|
|
23
|
+
this.renderInHost = false;
|
|
24
|
+
this.autoComplete = 'off';
|
|
25
|
+
this.validatedClass = 'was-validated';
|
|
26
|
+
this.workingClass = ['bg-light', 'text-secondary'];
|
|
27
|
+
this.form = null;
|
|
28
|
+
this.validators = [];
|
|
29
|
+
}
|
|
30
|
+
async connectedCallback() {
|
|
31
|
+
super.connectedCallback();
|
|
32
|
+
this.form = this.closest('form');
|
|
33
|
+
if (this.form == null)
|
|
34
|
+
return;
|
|
35
|
+
this.form?.addEventListener('submit', this.validate.bind(this));
|
|
36
|
+
this.validators = container.resolveAll(ValidateToken);
|
|
37
|
+
this.validators.forEach(validator => {
|
|
38
|
+
this.form?.querySelectorAll(validator.selector).forEach(element => {
|
|
39
|
+
element.addEventListener('change', async () => {
|
|
40
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement) {
|
|
41
|
+
element.setCustomValidity('');
|
|
42
|
+
if (!element.checkValidity())
|
|
43
|
+
return;
|
|
44
|
+
this.workingClass.forEach(c => element.classList.add(c));
|
|
45
|
+
var valid = await validator.validate(element);
|
|
46
|
+
this.workingClass.forEach(c => element.classList.add(c));
|
|
47
|
+
element.setCustomValidity(valid ? '' : validator.message);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
async disconnectedCallback() {
|
|
54
|
+
super.disconnectedCallback();
|
|
55
|
+
this.form?.removeEventListener('submit', this.validate.bind(this));
|
|
56
|
+
}
|
|
57
|
+
validate(event) {
|
|
58
|
+
if (!this.form?.checkValidity()) {
|
|
59
|
+
event.preventDefault();
|
|
60
|
+
event.stopPropagation();
|
|
61
|
+
}
|
|
62
|
+
this.form?.classList.add(this.validatedClass);
|
|
63
|
+
}
|
|
64
|
+
render() {
|
|
65
|
+
return html ``;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
__decorate([
|
|
69
|
+
property({ type: Boolean }),
|
|
70
|
+
__metadata("design:type", Object)
|
|
71
|
+
], QboValidate.prototype, "renderInHost", void 0);
|
|
72
|
+
__decorate([
|
|
73
|
+
property({ type: String }),
|
|
74
|
+
__metadata("design:type", Object)
|
|
75
|
+
], QboValidate.prototype, "autoComplete", void 0);
|
|
76
|
+
__decorate([
|
|
77
|
+
property({ type: String }),
|
|
78
|
+
__metadata("design:type", Object)
|
|
79
|
+
], QboValidate.prototype, "validatedClass", void 0);
|
|
80
|
+
__decorate([
|
|
81
|
+
property({
|
|
82
|
+
converter: {
|
|
83
|
+
fromAttribute: (value, type) => value?.split(' '),
|
|
84
|
+
toAttribute: (value, type) => value.join(' ')
|
|
85
|
+
}
|
|
86
|
+
}),
|
|
87
|
+
__metadata("design:type", Object)
|
|
88
|
+
], QboValidate.prototype, "workingClass", void 0);
|
|
89
|
+
QboValidate = __decorate([
|
|
90
|
+
customElement('qbo-validate')
|
|
91
|
+
], QboValidate);
|
|
92
|
+
export { QboValidate };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qbo-validate.js","sourceRoot":"","sources":["qbo-validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { html, css, LitElement } from 'lit';
|
|
2
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
+
import { container, injectable, injectAll, InjectionToken } from 'tsyringe';
|
|
4
|
+
import { IValidate, ValidateToken } from './qbo-validators.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Renders a <form> element and applies extensible validators.
|
|
8
|
+
*
|
|
9
|
+
* @remarks
|
|
10
|
+
* Use HTML5 validation attributes to specify the type of validation to apply.
|
|
11
|
+
*/
|
|
12
|
+
@customElement('qbo-validate')
|
|
13
|
+
export class QboValidate extends LitElement {
|
|
14
|
+
|
|
15
|
+
@property({ type: Boolean })
|
|
16
|
+
renderInHost = false;
|
|
17
|
+
|
|
18
|
+
@property({ type: String })
|
|
19
|
+
autoComplete = 'off';
|
|
20
|
+
|
|
21
|
+
@property({ type: String })
|
|
22
|
+
validatedClass = 'was-validated';
|
|
23
|
+
|
|
24
|
+
@property({
|
|
25
|
+
converter: {
|
|
26
|
+
fromAttribute: (value, type) => value?.split(' '),
|
|
27
|
+
toAttribute: (value: Array<string>, type) => value.join(' ')
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
workingClass = ['bg-light', 'text-secondary'];
|
|
31
|
+
|
|
32
|
+
form: HTMLFormElement | null = null;
|
|
33
|
+
validators: IValidate[] = [];
|
|
34
|
+
|
|
35
|
+
async connectedCallback() {
|
|
36
|
+
super.connectedCallback();
|
|
37
|
+
this.form = this.closest('form');
|
|
38
|
+
if (this.form == null)
|
|
39
|
+
return;
|
|
40
|
+
|
|
41
|
+
this.form?.addEventListener('submit', this.validate.bind(this));
|
|
42
|
+
this.validators = container.resolveAll<IValidate>(ValidateToken);
|
|
43
|
+
this.validators.forEach(validator => {
|
|
44
|
+
this.form?.querySelectorAll(validator.selector).forEach(element => {
|
|
45
|
+
element.addEventListener('change', async () => {
|
|
46
|
+
if (element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement) {
|
|
47
|
+
element.setCustomValidity('');
|
|
48
|
+
if (!element.checkValidity())
|
|
49
|
+
return;
|
|
50
|
+
this.workingClass.forEach(c => element.classList.add(c));
|
|
51
|
+
var valid = await validator.validate(element);
|
|
52
|
+
this.workingClass.forEach(c => element.classList.add(c))
|
|
53
|
+
element.setCustomValidity(valid ? '' : validator.message);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
async disconnectedCallback() {
|
|
61
|
+
super.disconnectedCallback();
|
|
62
|
+
this.form?.removeEventListener('submit', this.validate.bind(this));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
validate(event: any) {
|
|
66
|
+
if (!this.form?.checkValidity()) {
|
|
67
|
+
event.preventDefault()
|
|
68
|
+
event.stopPropagation()
|
|
69
|
+
}
|
|
70
|
+
this.form?.classList.add(this.validatedClass);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
render() {
|
|
74
|
+
return html``;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { InjectionToken } from 'tsyringe';
|
|
2
|
+
/**
|
|
3
|
+
* Defines a contract for form field validation.
|
|
4
|
+
* @remarks
|
|
5
|
+
* External classes may define custom validators by implementing this interface.
|
|
6
|
+
* Register the custom validator with the tsyringe DI container using {@link ValidateToken}.
|
|
7
|
+
*/
|
|
8
|
+
export interface IValidate {
|
|
9
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
10
|
+
message: string;
|
|
11
|
+
selector: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Define a token for the validators
|
|
15
|
+
*/
|
|
16
|
+
export declare const ValidateToken: InjectionToken<IValidate>;
|
|
17
|
+
/**
|
|
18
|
+
* A validator for a US zip code.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ZipCodeValidator implements IValidate {
|
|
21
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
22
|
+
message: string;
|
|
23
|
+
selector: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* A validator for an email address.
|
|
27
|
+
*/
|
|
28
|
+
export declare class EmailValidator implements IValidate {
|
|
29
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
30
|
+
message: string;
|
|
31
|
+
selector: string;
|
|
32
|
+
}
|
|
33
|
+
export declare class ExistsValidator implements IValidate {
|
|
34
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
35
|
+
message: string;
|
|
36
|
+
selector: string;
|
|
37
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { container, injectable } from 'tsyringe';
|
|
8
|
+
import { RestApiService } from './qbo-api.js';
|
|
9
|
+
import { getArray } from './qbo-json.js';
|
|
10
|
+
/**
|
|
11
|
+
* Define a token for the validators
|
|
12
|
+
*/
|
|
13
|
+
export const ValidateToken = 'ValidateToken';
|
|
14
|
+
/**
|
|
15
|
+
* A validator for a US zip code.
|
|
16
|
+
*/
|
|
17
|
+
let ZipCodeValidator = class ZipCodeValidator {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.message = 'Zip code is invalid';
|
|
20
|
+
this.selector = '.zipcode';
|
|
21
|
+
}
|
|
22
|
+
validate(input) { return Promise.resolve(true); }
|
|
23
|
+
;
|
|
24
|
+
};
|
|
25
|
+
ZipCodeValidator = __decorate([
|
|
26
|
+
injectable()
|
|
27
|
+
], ZipCodeValidator);
|
|
28
|
+
export { ZipCodeValidator };
|
|
29
|
+
container.register(ValidateToken, { useClass: ZipCodeValidator });
|
|
30
|
+
/**
|
|
31
|
+
* A validator for an email address.
|
|
32
|
+
*/
|
|
33
|
+
let EmailValidator = class EmailValidator {
|
|
34
|
+
constructor() {
|
|
35
|
+
this.message = 'Email is invalid';
|
|
36
|
+
this.selector = '.email';
|
|
37
|
+
}
|
|
38
|
+
validate(input) { return Promise.resolve(true); }
|
|
39
|
+
;
|
|
40
|
+
};
|
|
41
|
+
EmailValidator = __decorate([
|
|
42
|
+
injectable()
|
|
43
|
+
], EmailValidator);
|
|
44
|
+
export { EmailValidator };
|
|
45
|
+
container.register(ValidateToken, { useClass: EmailValidator });
|
|
46
|
+
let ExistsValidator = class ExistsValidator {
|
|
47
|
+
constructor() {
|
|
48
|
+
this.message = 'This value does not appear to exist.';
|
|
49
|
+
this.selector = '[data-exists]';
|
|
50
|
+
}
|
|
51
|
+
async validate(input) {
|
|
52
|
+
var url = input.getAttribute('data-exists');
|
|
53
|
+
if (!url)
|
|
54
|
+
return false;
|
|
55
|
+
var path = input.getAttribute('data-exists-path');
|
|
56
|
+
const service = container.isRegistered(url) ? container.resolve(url) : new RestApiService(url);
|
|
57
|
+
if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement) {
|
|
58
|
+
const response = await service.fetch(path, { value: input.value });
|
|
59
|
+
const json = getArray(response);
|
|
60
|
+
if (json == null)
|
|
61
|
+
return false;
|
|
62
|
+
return json.length > 0;
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
;
|
|
67
|
+
};
|
|
68
|
+
ExistsValidator = __decorate([
|
|
69
|
+
injectable()
|
|
70
|
+
], ExistsValidator);
|
|
71
|
+
export { ExistsValidator };
|
|
72
|
+
container.register(ValidateToken, { useClass: ExistsValidator });
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { container, injectable, InjectionToken } from 'tsyringe';
|
|
2
|
+
import { IApiService, RestApiService } from './qbo-api.js';
|
|
3
|
+
import { getArray } from './qbo-json.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Defines a contract for form field validation.
|
|
7
|
+
* @remarks
|
|
8
|
+
* External classes may define custom validators by implementing this interface.
|
|
9
|
+
* Register the custom validator with the tsyringe DI container using {@link ValidateToken}.
|
|
10
|
+
*/
|
|
11
|
+
export interface IValidate {
|
|
12
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
13
|
+
message: string;
|
|
14
|
+
selector: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Define a token for the validators
|
|
20
|
+
*/
|
|
21
|
+
export const ValidateToken: InjectionToken<IValidate> = 'ValidateToken';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* A validator for a US zip code.
|
|
25
|
+
*/
|
|
26
|
+
@injectable()
|
|
27
|
+
export class ZipCodeValidator implements IValidate {
|
|
28
|
+
validate(input: HTMLElement): Promise<boolean> { return Promise.resolve(true); };
|
|
29
|
+
message = 'Zip code is invalid';
|
|
30
|
+
selector = '.zipcode';
|
|
31
|
+
}
|
|
32
|
+
container.register(ValidateToken, { useClass: ZipCodeValidator });
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A validator for an email address.
|
|
36
|
+
*/
|
|
37
|
+
@injectable()
|
|
38
|
+
export class EmailValidator implements IValidate {
|
|
39
|
+
validate(input: HTMLElement): Promise<boolean> { return Promise.resolve(true); };
|
|
40
|
+
message = 'Email is invalid';
|
|
41
|
+
selector = '.email';
|
|
42
|
+
}
|
|
43
|
+
container.register(ValidateToken, { useClass: EmailValidator });
|
|
44
|
+
|
|
45
|
+
@injectable()
|
|
46
|
+
export class ExistsValidator implements IValidate {
|
|
47
|
+
async validate(input: HTMLElement): Promise<boolean> {
|
|
48
|
+
var url = input.getAttribute('data-exists');
|
|
49
|
+
if (!url) return false;
|
|
50
|
+
var path = input.getAttribute('data-exists-path');
|
|
51
|
+
const service: IApiService = container.isRegistered(url) ? container.resolve<IApiService>(url) : new RestApiService(url);
|
|
52
|
+
|
|
53
|
+
if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement) {
|
|
54
|
+
const response = await service.fetch(path, { value: input.value });
|
|
55
|
+
const json = getArray(response);
|
|
56
|
+
if (json == null)
|
|
57
|
+
return false;
|
|
58
|
+
return json.length > 0;
|
|
59
|
+
}
|
|
60
|
+
return false;
|
|
61
|
+
};
|
|
62
|
+
message = 'This value does not appear to exist.';
|
|
63
|
+
selector = '[data-exists]';
|
|
64
|
+
}
|
|
65
|
+
container.register(ValidateToken, { useClass: ExistsValidator });
|
|
66
|
+
|