@quandis/qbo4.ui 4.0.1-CI-20240403-131518 → 4.0.1-CI-20240405-163539
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 +2 -1
- package/readme.md +79 -417
- package/src/qbo/IApiService.d.ts +12 -0
- package/src/qbo/IApiService.js +8 -0
- package/src/qbo/IApiService.ts +18 -0
- package/src/qbo/IValidate.d.ts +16 -0
- package/src/qbo/IValidate.js +4 -0
- package/src/qbo/IValidate.ts +19 -0
- package/src/qbo/Program.d.ts +6 -2
- package/src/qbo/Program.js +6 -2
- package/src/qbo/Program.ts +6 -2
- package/src/qbo/RestApiService.d.ts +9 -0
- package/src/qbo/RestApiService.js +32 -0
- package/src/qbo/RestApiService.ts +45 -0
- package/src/qbo/Validators.d.ts +22 -0
- package/src/qbo/{qbo-validators.js → Validators.js} +8 -10
- package/src/qbo/{qbo-validators.ts → Validators.ts} +10 -22
- package/src/qbo/qbo-api.d.ts +0 -19
- package/src/qbo/qbo-api.js +3 -36
- package/src/qbo/qbo-api.ts +3 -57
- package/src/qbo/qbo-form-element.d.ts +20 -0
- package/src/qbo/qbo-form-element.js +128 -0
- package/src/qbo/qbo-form-element.ts +121 -0
- package/src/qbo/qbo-json.d.ts +3 -4
- package/src/qbo/qbo-json.js +24 -4
- package/src/qbo/qbo-json.ts +27 -4
- package/src/qbo/qbo-validate.d.ts +25 -7
- package/src/qbo/qbo-validate.js +84 -33
- package/src/qbo/qbo-validate.ts +81 -28
- package/wwwroot/js/qbo4.ui.js +47650 -11977
- package/wwwroot/js/qbo4.ui.min.js +84 -51
- package/wwwroot/js/qbo4.ui.min.js.map +1 -1
package/src/qbo/Program.js
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
|
+
export { services } from '@quandis/qbo4.logging';
|
|
3
|
+
export * from './IApiService.js';
|
|
4
|
+
export * from './IValidate.js';
|
|
5
|
+
export * from './Validators.js';
|
|
6
|
+
export * from './RestApiService.js';
|
|
2
7
|
export * from './qbo-badge.js';
|
|
3
8
|
export * from './qbo-datalist.js';
|
|
4
9
|
export * from './qbo-docviewer.js';
|
|
10
|
+
export * from './qbo-form-element.js';
|
|
5
11
|
export * from './qbo-json.js';
|
|
6
|
-
export * from './qbo-logging.js';
|
|
7
12
|
export * from './qbo-mainmenu.js';
|
|
8
13
|
export * from './qbo-markdown.js';
|
|
9
14
|
export * from './qbo-microphone.js';
|
|
@@ -14,5 +19,4 @@ export * from './qbo-select.js';
|
|
|
14
19
|
export * from './qbo-sidebar.js';
|
|
15
20
|
export * from './qbo-table.js';
|
|
16
21
|
export * from './qbo-validate.js';
|
|
17
|
-
export * from './qbo-validators.js';
|
|
18
22
|
export * from './qbo-api.js';
|
package/src/qbo/Program.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
|
|
3
|
+
export { services } from '@quandis/qbo4.logging';
|
|
4
|
+
export * from './IApiService.js';
|
|
5
|
+
export * from './IValidate.js';
|
|
6
|
+
export * from './Validators.js';
|
|
7
|
+
export * from './RestApiService.js';
|
|
3
8
|
export * from './qbo-badge.js';
|
|
4
9
|
export * from './qbo-datalist.js'
|
|
5
10
|
export * from './qbo-docviewer.js'
|
|
11
|
+
export * from './qbo-form-element.js';
|
|
6
12
|
export * from './qbo-json.js';
|
|
7
|
-
export * from './qbo-logging.js';
|
|
8
13
|
export * from './qbo-mainmenu.js';
|
|
9
14
|
export * from './qbo-markdown.js'
|
|
10
15
|
export * from './qbo-microphone.js'
|
|
@@ -15,5 +20,4 @@ export * from './qbo-select.js';
|
|
|
15
20
|
export * from './qbo-sidebar.js'
|
|
16
21
|
export * from './qbo-table.js';
|
|
17
22
|
export * from './qbo-validate.js';
|
|
18
|
-
export * from './qbo-validators.js';
|
|
19
23
|
export * from './qbo-api.js';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IApiService } from "./IApiService.js";
|
|
2
|
+
export declare class RestApiService implements IApiService {
|
|
3
|
+
private headers;
|
|
4
|
+
private apiEndpoint;
|
|
5
|
+
private method;
|
|
6
|
+
constructor(apiEndpoint: string, headers?: HeadersInit, method?: string | null);
|
|
7
|
+
fetch(relativePath: string | null, payload?: Record<string, string> | null): Promise<any>;
|
|
8
|
+
}
|
|
9
|
+
export declare function registerRestApi(name: string, apiEndpoint: string, headers?: HeadersInit, method?: string | null): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { services } from "@quandis/qbo4.logging";
|
|
2
|
+
import { substitute } from "./qbo-json.js";
|
|
3
|
+
export class RestApiService {
|
|
4
|
+
constructor(apiEndpoint, headers = { 'Content-Type': 'application/json' }, method = null) {
|
|
5
|
+
this.apiEndpoint = apiEndpoint;
|
|
6
|
+
this.headers = headers;
|
|
7
|
+
this.method = method;
|
|
8
|
+
}
|
|
9
|
+
async fetch(relativePath, payload = null) {
|
|
10
|
+
const endpoint = substitute(new URL(relativePath ?? '', this.apiEndpoint).href, payload);
|
|
11
|
+
const method = this.method ?? (payload !== null ? 'POST' : 'GET');
|
|
12
|
+
const headers = new Headers(this.headers || {});
|
|
13
|
+
if (payload !== null && !headers.has('Content-Type')) {
|
|
14
|
+
headers.append('Content-Type', 'application/json');
|
|
15
|
+
}
|
|
16
|
+
const response = await fetch(endpoint, {
|
|
17
|
+
method: method,
|
|
18
|
+
headers: headers,
|
|
19
|
+
body: (method === 'POST' && payload) ? JSON.stringify(payload) : null
|
|
20
|
+
});
|
|
21
|
+
if (!response.ok) {
|
|
22
|
+
throw new Error(`API request failed with status ${response.status}`);
|
|
23
|
+
}
|
|
24
|
+
return response.json();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
// Register a RestApiService with the default name 'default' and the base URL of the current page
|
|
28
|
+
services.container.registerInstance('default', new RestApiService(document.querySelector('base[href]')?.getAttribute('href') || window.location.origin));
|
|
29
|
+
// Sugar for registering a RestApiService with registerRestApi('myName', 'https://my.api.com')
|
|
30
|
+
export function registerRestApi(name, apiEndpoint, headers = { 'Content-Type': 'application/json' }, method) {
|
|
31
|
+
services.container.registerInstance(name, new RestApiService(apiEndpoint, headers, method));
|
|
32
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { services } from "@quandis/qbo4.logging";
|
|
2
|
+
import { IApiService } from "./IApiService.js";
|
|
3
|
+
import { substitute } from "./qbo-json.js";
|
|
4
|
+
|
|
5
|
+
export class RestApiService implements IApiService {
|
|
6
|
+
|
|
7
|
+
private headers: HeadersInit;
|
|
8
|
+
private apiEndpoint: string;
|
|
9
|
+
private method: string | null;
|
|
10
|
+
|
|
11
|
+
constructor(apiEndpoint: string, headers: HeadersInit = { 'Content-Type': 'application/json' }, method: string | null = null) {
|
|
12
|
+
this.apiEndpoint = apiEndpoint;
|
|
13
|
+
this.headers = headers;
|
|
14
|
+
this.method = method;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async fetch(relativePath: string | null, payload: Record<string, string> | null = null): Promise<any> {
|
|
18
|
+
const endpoint = substitute(new URL(relativePath ?? '', this.apiEndpoint).href, payload);
|
|
19
|
+
const method = this.method ?? (payload !== null ? 'POST' : 'GET');
|
|
20
|
+
const headers = new Headers(this.headers || {});
|
|
21
|
+
if (payload !== null && !headers.has('Content-Type')) {
|
|
22
|
+
headers.append('Content-Type', 'application/json');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const response = await fetch(endpoint, {
|
|
26
|
+
method: method,
|
|
27
|
+
headers: headers,
|
|
28
|
+
body: (method === 'POST' && payload) ? JSON.stringify(payload) : null
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw new Error(`API request failed with status ${response.status}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return response.json();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Register a RestApiService with the default name 'default' and the base URL of the current page
|
|
40
|
+
services.container.registerInstance<IApiService>('default', new RestApiService(document.querySelector('base[href]')?.getAttribute('href') || window.location.origin));
|
|
41
|
+
|
|
42
|
+
// Sugar for registering a RestApiService with registerRestApi('myName', 'https://my.api.com')
|
|
43
|
+
export function registerRestApi(name: string, apiEndpoint: string, headers: HeadersInit = { 'Content-Type': 'application/json' }, method?: string | null) {
|
|
44
|
+
services.container.registerInstance<IApiService>(name, new RestApiService(apiEndpoint, headers, method));
|
|
45
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { IValidate } from './IValidate.js';
|
|
2
|
+
/**
|
|
3
|
+
* A validator for a US zip code.
|
|
4
|
+
*/
|
|
5
|
+
export declare class ZipCodeValidator implements IValidate {
|
|
6
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
7
|
+
message: string;
|
|
8
|
+
selector: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* A validator for an email address.
|
|
12
|
+
*/
|
|
13
|
+
export declare class EmailValidator implements IValidate {
|
|
14
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
15
|
+
message: string;
|
|
16
|
+
selector: string;
|
|
17
|
+
}
|
|
18
|
+
export declare class ExistsValidator implements IValidate {
|
|
19
|
+
validate(input: HTMLElement): Promise<boolean>;
|
|
20
|
+
message: string;
|
|
21
|
+
selector: string;
|
|
22
|
+
}
|
|
@@ -4,13 +4,11 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
4
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
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { injectable } from 'tsyringe';
|
|
8
|
+
import { services } from '@quandis/qbo4.logging';
|
|
9
9
|
import { getArray } from './qbo-json.js';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
*/
|
|
13
|
-
export const ValidateToken = 'ValidateToken';
|
|
10
|
+
import { RestApiService } from './RestApiService.js';
|
|
11
|
+
import { ValidateToken } from './IValidate.js';
|
|
14
12
|
/**
|
|
15
13
|
* A validator for a US zip code.
|
|
16
14
|
*/
|
|
@@ -26,7 +24,7 @@ ZipCodeValidator = __decorate([
|
|
|
26
24
|
injectable()
|
|
27
25
|
], ZipCodeValidator);
|
|
28
26
|
export { ZipCodeValidator };
|
|
29
|
-
container.register(ValidateToken, { useClass: ZipCodeValidator });
|
|
27
|
+
services.container.register(ValidateToken, { useClass: ZipCodeValidator });
|
|
30
28
|
/**
|
|
31
29
|
* A validator for an email address.
|
|
32
30
|
*/
|
|
@@ -42,7 +40,7 @@ EmailValidator = __decorate([
|
|
|
42
40
|
injectable()
|
|
43
41
|
], EmailValidator);
|
|
44
42
|
export { EmailValidator };
|
|
45
|
-
container.register(ValidateToken, { useClass: EmailValidator });
|
|
43
|
+
services.container.register(ValidateToken, { useClass: EmailValidator });
|
|
46
44
|
let ExistsValidator = class ExistsValidator {
|
|
47
45
|
constructor() {
|
|
48
46
|
this.message = 'This value does not appear to exist.';
|
|
@@ -53,7 +51,7 @@ let ExistsValidator = class ExistsValidator {
|
|
|
53
51
|
if (!url)
|
|
54
52
|
return false;
|
|
55
53
|
var path = input.getAttribute('data-exists-path');
|
|
56
|
-
const service = container.isRegistered(url) ? container.resolve(url) : new RestApiService(url);
|
|
54
|
+
const service = services.container.isRegistered(url) ? services.container.resolve(url) : new RestApiService(url);
|
|
57
55
|
if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement) {
|
|
58
56
|
const response = await service.fetch(path, { value: input.value });
|
|
59
57
|
const json = getArray(response);
|
|
@@ -69,4 +67,4 @@ ExistsValidator = __decorate([
|
|
|
69
67
|
injectable()
|
|
70
68
|
], ExistsValidator);
|
|
71
69
|
export { ExistsValidator };
|
|
72
|
-
container.register(ValidateToken, { useClass: ExistsValidator });
|
|
70
|
+
services.container.register(ValidateToken, { useClass: ExistsValidator });
|
|
@@ -1,24 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { injectable } from 'tsyringe';
|
|
2
|
+
import { services } from '@quandis/qbo4.logging';
|
|
3
3
|
import { getArray } from './qbo-json.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
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
|
-
}
|
|
4
|
+
import { IApiService } from './IApiService.js';
|
|
5
|
+
import { RestApiService } from './RestApiService.js';
|
|
6
|
+
import { IValidate, ValidateToken } from './IValidate.js';
|
|
16
7
|
|
|
17
8
|
|
|
18
|
-
/**
|
|
19
|
-
* Define a token for the validators
|
|
20
|
-
*/
|
|
21
|
-
export const ValidateToken: InjectionToken<IValidate> = 'ValidateToken';
|
|
22
9
|
|
|
23
10
|
/**
|
|
24
11
|
* A validator for a US zip code.
|
|
@@ -29,7 +16,7 @@ export class ZipCodeValidator implements IValidate {
|
|
|
29
16
|
message = 'Zip code is invalid';
|
|
30
17
|
selector = '.zipcode';
|
|
31
18
|
}
|
|
32
|
-
container.register(ValidateToken, { useClass: ZipCodeValidator });
|
|
19
|
+
services.container.register(ValidateToken, { useClass: ZipCodeValidator });
|
|
33
20
|
|
|
34
21
|
/**
|
|
35
22
|
* A validator for an email address.
|
|
@@ -40,7 +27,7 @@ export class EmailValidator implements IValidate {
|
|
|
40
27
|
message = 'Email is invalid';
|
|
41
28
|
selector = '.email';
|
|
42
29
|
}
|
|
43
|
-
container.register(ValidateToken, { useClass: EmailValidator });
|
|
30
|
+
services.container.register(ValidateToken, { useClass: EmailValidator });
|
|
44
31
|
|
|
45
32
|
@injectable()
|
|
46
33
|
export class ExistsValidator implements IValidate {
|
|
@@ -48,7 +35,7 @@ export class ExistsValidator implements IValidate {
|
|
|
48
35
|
var url = input.getAttribute('data-exists');
|
|
49
36
|
if (!url) return false;
|
|
50
37
|
var path = input.getAttribute('data-exists-path');
|
|
51
|
-
const service: IApiService = container.isRegistered(url) ? container.resolve<IApiService>(url) : new RestApiService(url);
|
|
38
|
+
const service: IApiService = services.container.isRegistered(url) ? services.container.resolve<IApiService>(url) : new RestApiService(url);
|
|
52
39
|
|
|
53
40
|
if (input instanceof HTMLInputElement || input instanceof HTMLSelectElement || input instanceof HTMLTextAreaElement) {
|
|
54
41
|
const response = await service.fetch(path, { value: input.value });
|
|
@@ -62,5 +49,6 @@ export class ExistsValidator implements IValidate {
|
|
|
62
49
|
message = 'This value does not appear to exist.';
|
|
63
50
|
selector = '[data-exists]';
|
|
64
51
|
}
|
|
65
|
-
|
|
52
|
+
|
|
53
|
+
services.container.register(ValidateToken, { useClass: ExistsValidator });
|
|
66
54
|
|
package/src/qbo/qbo-api.d.ts
CHANGED
|
@@ -1,20 +1,4 @@
|
|
|
1
1
|
import { LitElement } from 'lit';
|
|
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 IApiService {
|
|
9
|
-
fetch(relativePath: string | null, payload: Record<string, string> | null): Promise<any>;
|
|
10
|
-
}
|
|
11
|
-
export declare class RestApiService implements IApiService {
|
|
12
|
-
private headers;
|
|
13
|
-
private apiEndpoint;
|
|
14
|
-
private method;
|
|
15
|
-
constructor(apiEndpoint: string, headers?: HeadersInit, method?: string | null);
|
|
16
|
-
fetch(relativePath: string | null, payload?: Record<string, string> | null): Promise<any>;
|
|
17
|
-
}
|
|
18
2
|
export declare class ApiServiceComponent extends LitElement {
|
|
19
3
|
name: string | null;
|
|
20
4
|
apiEndpoint: string | null;
|
|
@@ -22,6 +6,3 @@ export declare class ApiServiceComponent extends LitElement {
|
|
|
22
6
|
firstUpdated(): void;
|
|
23
7
|
render(): import("lit").TemplateResult<1>;
|
|
24
8
|
}
|
|
25
|
-
declare function registerRestApi(name: string, apiEndpoint: string, headers?: HeadersInit, method?: string | null): void;
|
|
26
|
-
declare function getApiService(name: string): IApiService;
|
|
27
|
-
export { registerRestApi, getApiService };
|
package/src/qbo/qbo-api.js
CHANGED
|
@@ -7,34 +7,9 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
7
7
|
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
8
8
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
9
9
|
};
|
|
10
|
-
import {
|
|
10
|
+
import { LitElement, html } from 'lit';
|
|
11
11
|
import { customElement, property } from 'lit/decorators.js';
|
|
12
|
-
import {
|
|
13
|
-
import { substitute } from './qbo-json.js';
|
|
14
|
-
export class RestApiService {
|
|
15
|
-
constructor(apiEndpoint, headers = { 'Content-Type': 'application/json' }, method = null) {
|
|
16
|
-
this.apiEndpoint = apiEndpoint;
|
|
17
|
-
this.headers = headers;
|
|
18
|
-
this.method = method;
|
|
19
|
-
}
|
|
20
|
-
async fetch(relativePath, payload = null) {
|
|
21
|
-
const endpoint = substitute(new URL(relativePath ?? '', this.apiEndpoint).href, payload);
|
|
22
|
-
const method = this.method ?? (payload !== null ? 'POST' : 'GET');
|
|
23
|
-
const headers = new Headers(this.headers || {});
|
|
24
|
-
if (payload !== null && !headers.has('Content-Type')) {
|
|
25
|
-
headers.append('Content-Type', 'application/json');
|
|
26
|
-
}
|
|
27
|
-
const response = await fetch(endpoint, {
|
|
28
|
-
method: method,
|
|
29
|
-
headers: headers,
|
|
30
|
-
body: (method === 'POST' && payload) ? JSON.stringify(payload) : null
|
|
31
|
-
});
|
|
32
|
-
if (!response.ok) {
|
|
33
|
-
throw new Error(`API request failed with status ${response.status}`);
|
|
34
|
-
}
|
|
35
|
-
return response.json();
|
|
36
|
-
}
|
|
37
|
-
}
|
|
12
|
+
import { registerRestApi } from './RestApiService.js';
|
|
38
13
|
let ApiServiceComponent = class ApiServiceComponent extends LitElement {
|
|
39
14
|
constructor() {
|
|
40
15
|
super(...arguments);
|
|
@@ -61,7 +36,7 @@ let ApiServiceComponent = class ApiServiceComponent extends LitElement {
|
|
|
61
36
|
headers['Content-Type'] = headers['ContentType'];
|
|
62
37
|
delete headers['ContentType'];
|
|
63
38
|
}
|
|
64
|
-
container.registerInstance(this.name
|
|
39
|
+
// container.registerInstance<IApiService>(this.name!, new RestApiService(this.apiEndpoint!, headers, this.method));
|
|
65
40
|
// Call the registerRestApi function with the extracted configuration
|
|
66
41
|
registerRestApi(this.name, this.apiEndpoint, headers, this.method);
|
|
67
42
|
}
|
|
@@ -86,11 +61,3 @@ ApiServiceComponent = __decorate([
|
|
|
86
61
|
customElement('qbo-api')
|
|
87
62
|
], ApiServiceComponent);
|
|
88
63
|
export { ApiServiceComponent };
|
|
89
|
-
container.registerInstance('default', new RestApiService(document.querySelector('base[href]')?.getAttribute('href') || window.location.origin));
|
|
90
|
-
function registerRestApi(name, apiEndpoint, headers = { 'Content-Type': 'application/json' }, method) {
|
|
91
|
-
container.registerInstance(name, new RestApiService(apiEndpoint, headers, method));
|
|
92
|
-
}
|
|
93
|
-
function getApiService(name) {
|
|
94
|
-
return container.resolve(name);
|
|
95
|
-
}
|
|
96
|
-
export { registerRestApi, getApiService };
|
package/src/qbo/qbo-api.ts
CHANGED
|
@@ -1,50 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LitElement, html } from 'lit';
|
|
2
2
|
import { customElement, property } from 'lit/decorators.js';
|
|
3
|
-
import {
|
|
4
|
-
import {substitute} from './qbo-json.js';
|
|
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 IApiService {
|
|
12
|
-
fetch(relativePath: string | null, payload: Record<string, string> | null): Promise<any>;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export class RestApiService implements IApiService {
|
|
16
|
-
|
|
17
|
-
private headers: HeadersInit;
|
|
18
|
-
private apiEndpoint: string;
|
|
19
|
-
private method: string | null;
|
|
20
|
-
|
|
21
|
-
constructor(apiEndpoint: string, headers: HeadersInit = { 'Content-Type': 'application/json' }, method: string | null = null) {
|
|
22
|
-
this.apiEndpoint = apiEndpoint;
|
|
23
|
-
this.headers = headers;
|
|
24
|
-
this.method = method;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
async fetch(relativePath: string | null, payload: Record<string, string> | null = null): Promise<any> {
|
|
28
|
-
const endpoint = substitute(new URL(relativePath ?? '', this.apiEndpoint).href, payload);
|
|
29
|
-
const method = this.method ?? (payload !== null ? 'POST' : 'GET');
|
|
30
|
-
const headers = new Headers(this.headers || {});
|
|
31
|
-
if (payload !== null && !headers.has('Content-Type')) {
|
|
32
|
-
headers.append('Content-Type', 'application/json');
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const response = await fetch(endpoint, {
|
|
36
|
-
method: method,
|
|
37
|
-
headers: headers,
|
|
38
|
-
body: (method === 'POST' && payload) ? JSON.stringify(payload) : null
|
|
39
|
-
});
|
|
3
|
+
import { registerRestApi } from './RestApiService.js';
|
|
40
4
|
|
|
41
|
-
if (!response.ok) {
|
|
42
|
-
throw new Error(`API request failed with status ${response.status}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return response.json();
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
5
|
|
|
49
6
|
|
|
50
7
|
@customElement('qbo-api')
|
|
@@ -81,7 +38,7 @@ export class ApiServiceComponent extends LitElement {
|
|
|
81
38
|
delete headers['ContentType'];
|
|
82
39
|
}
|
|
83
40
|
|
|
84
|
-
container.registerInstance<IApiService>(this.name!, new RestApiService(this.apiEndpoint!, headers, this.method));
|
|
41
|
+
// container.registerInstance<IApiService>(this.name!, new RestApiService(this.apiEndpoint!, headers, this.method));
|
|
85
42
|
|
|
86
43
|
// Call the registerRestApi function with the extracted configuration
|
|
87
44
|
registerRestApi(this.name!, this.apiEndpoint!, headers, this.method);
|
|
@@ -93,14 +50,3 @@ export class ApiServiceComponent extends LitElement {
|
|
|
93
50
|
}
|
|
94
51
|
}
|
|
95
52
|
|
|
96
|
-
container.registerInstance<IApiService>('default', new RestApiService(document.querySelector('base[href]')?.getAttribute('href') || window.location.origin));
|
|
97
|
-
|
|
98
|
-
function registerRestApi(name: string, apiEndpoint: string, headers: HeadersInit = { 'Content-Type': 'application/json' }, method?: string | null) {
|
|
99
|
-
container.registerInstance<IApiService>(name, new RestApiService(apiEndpoint, headers, method));
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
function getApiService(name: string) {
|
|
103
|
-
return container.resolve<IApiService>(name);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export { registerRestApi, getApiService }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ILoggerService } from '@quandis/qbo4.logging';
|
|
2
|
+
import { LitElement, PropertyValues } from 'lit';
|
|
3
|
+
export declare class QboFormElement extends LitElement {
|
|
4
|
+
static formAssociated: boolean;
|
|
5
|
+
value: FormData;
|
|
6
|
+
template: string;
|
|
7
|
+
name: string;
|
|
8
|
+
data: null;
|
|
9
|
+
private templateNode;
|
|
10
|
+
private internals;
|
|
11
|
+
logger: ILoggerService;
|
|
12
|
+
constructor();
|
|
13
|
+
connectedCallback(): void;
|
|
14
|
+
disconnectedCallback(): void;
|
|
15
|
+
updated(changedProperties: PropertyValues): void;
|
|
16
|
+
render(): import("lit").TemplateResult<1>;
|
|
17
|
+
establishFormData(): void;
|
|
18
|
+
handleFormChange: (event: any) => void;
|
|
19
|
+
augment: (event: any) => void;
|
|
20
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
var QboFormElement_1;
|
|
11
|
+
import { ILoggerServiceToken, services } from '@quandis/qbo4.logging';
|
|
12
|
+
import { html, LitElement } from 'lit';
|
|
13
|
+
import { customElement, property } from 'lit/decorators.js';
|
|
14
|
+
import { substitute } from './qbo-json.js';
|
|
15
|
+
let QboFormElement = class QboFormElement extends LitElement {
|
|
16
|
+
static { QboFormElement_1 = this; }
|
|
17
|
+
static { this.formAssociated = true; }
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
this.value = new FormData();
|
|
21
|
+
this.template = '';
|
|
22
|
+
this.name = '';
|
|
23
|
+
this.data = null;
|
|
24
|
+
this.templateNode = null;
|
|
25
|
+
this.handleFormChange = (event) => {
|
|
26
|
+
const target = event.target;
|
|
27
|
+
if (target.matches('input, select, textarea') && target.name && !target.assignedSlot) {
|
|
28
|
+
// if the element is assigned to a slot, it's already visible to the parent. Ignore it.
|
|
29
|
+
this.value.set(`${this.name}${target.name}`, target.value);
|
|
30
|
+
this.logger.logTrace(`${this.name}${target.name} was set to ${target.value}`);
|
|
31
|
+
}
|
|
32
|
+
this.internals.setFormValue(this.value);
|
|
33
|
+
this.dispatchEvent(new CustomEvent('qbo-form-update', { bubbles: true, composed: true, detail: { formData: this.value } }));
|
|
34
|
+
};
|
|
35
|
+
this.augment = (event) => {
|
|
36
|
+
event.stopPropagation();
|
|
37
|
+
console.log(event);
|
|
38
|
+
if (event instanceof CustomEvent && event.detail.formData instanceof FormData) {
|
|
39
|
+
// To replace existing entries instead of appending
|
|
40
|
+
for (let [key, value] of event.detail.formData.entries()) {
|
|
41
|
+
this.value.set(key, value);
|
|
42
|
+
console.log(`Added ${key}=${value} to ${this.name}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
this.internals.setFormValue(this.value);
|
|
46
|
+
this.dispatchEvent(new CustomEvent('qbo-form-update', { bubbles: true, composed: true, detail: { formData: this.value } }));
|
|
47
|
+
};
|
|
48
|
+
this.internals = this.attachInternals(); // Attach the form internals
|
|
49
|
+
this.logger = services.container.resolve(ILoggerServiceToken);
|
|
50
|
+
}
|
|
51
|
+
connectedCallback() {
|
|
52
|
+
super.connectedCallback();
|
|
53
|
+
this.templateNode = document.getElementById(this.template);
|
|
54
|
+
if (this.templateNode) {
|
|
55
|
+
this.appendChild(this.templateNode.content.cloneNode(true));
|
|
56
|
+
this.innerHTML = substitute(this.innerHTML, this.data);
|
|
57
|
+
}
|
|
58
|
+
this.shadowRoot?.addEventListener('change', this.handleFormChange);
|
|
59
|
+
this.shadowRoot?.addEventListener('qbo-form-update', this.augment);
|
|
60
|
+
}
|
|
61
|
+
disconnectedCallback() {
|
|
62
|
+
super.disconnectedCallback();
|
|
63
|
+
this.shadowRoot?.removeEventListener('change', this.handleFormChange);
|
|
64
|
+
this.shadowRoot?.removeEventListener('qbo-form-update', this.augment);
|
|
65
|
+
}
|
|
66
|
+
updated(changedProperties) {
|
|
67
|
+
super.updated(changedProperties);
|
|
68
|
+
this.establishFormData();
|
|
69
|
+
}
|
|
70
|
+
render() {
|
|
71
|
+
return html `<slot></slot>`;
|
|
72
|
+
}
|
|
73
|
+
establishFormData() {
|
|
74
|
+
const elements = this.shadowRoot?.querySelectorAll('input, select, textarea');
|
|
75
|
+
const inputs = Array.from(elements).filter(e => !e.assignedSlot
|
|
76
|
+
&& (e instanceof HTMLInputElement
|
|
77
|
+
|| e instanceof HTMLSelectElement
|
|
78
|
+
|| e instanceof HTMLTextAreaElement
|
|
79
|
+
|| e instanceof QboFormElement_1) && e.name);
|
|
80
|
+
inputs.forEach(element => {
|
|
81
|
+
const input = element;
|
|
82
|
+
if (input instanceof HTMLSelectElement) {
|
|
83
|
+
this.value.set(`${this.name}${input.name}`, input.value);
|
|
84
|
+
}
|
|
85
|
+
else if (input instanceof HTMLTextAreaElement) {
|
|
86
|
+
this.value.set(`${this.name}${input.name}`, input.value);
|
|
87
|
+
}
|
|
88
|
+
else if (input instanceof QboFormElement_1) {
|
|
89
|
+
for (let [key, value] of input.value.entries()) {
|
|
90
|
+
this.value.set(`${this.name}${key}`, value);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else if (input instanceof HTMLInputElement) {
|
|
94
|
+
if (input.type === 'checkbox' || input.type === 'radio') {
|
|
95
|
+
if (input.checked) {
|
|
96
|
+
this.value.set(`${this.name}${input.name}`, input.value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
this.value.set(`${this.name}${input.name}`, input.value);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
this.internals.setFormValue(this.value);
|
|
105
|
+
this.logger.logTrace(`Set ${this.name} values to `, this.value);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
__decorate([
|
|
109
|
+
property({ type: FormData }),
|
|
110
|
+
__metadata("design:type", FormData)
|
|
111
|
+
], QboFormElement.prototype, "value", void 0);
|
|
112
|
+
__decorate([
|
|
113
|
+
property({ type: String }),
|
|
114
|
+
__metadata("design:type", Object)
|
|
115
|
+
], QboFormElement.prototype, "template", void 0);
|
|
116
|
+
__decorate([
|
|
117
|
+
property({ type: String }),
|
|
118
|
+
__metadata("design:type", Object)
|
|
119
|
+
], QboFormElement.prototype, "name", void 0);
|
|
120
|
+
__decorate([
|
|
121
|
+
property({ type: Object }),
|
|
122
|
+
__metadata("design:type", Object)
|
|
123
|
+
], QboFormElement.prototype, "data", void 0);
|
|
124
|
+
QboFormElement = QboFormElement_1 = __decorate([
|
|
125
|
+
customElement('qbo-form-element'),
|
|
126
|
+
__metadata("design:paramtypes", [])
|
|
127
|
+
], QboFormElement);
|
|
128
|
+
export { QboFormElement };
|