@rws-framework/client 2.22.0 → 2.22.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/package.json +1 -1
- package/src/components/_component.ts +59 -30
- package/src/events.ts +3 -0
- package/src/index.ts +8 -6
- package/src/services/ApiService.ts +11 -8
- package/src/services/DOMService.ts +1 -1
- package/src/services/_api/backend.ts +41 -9
- package/src/types/IRWSViewComponent.ts +2 -2
- package/src/types/IBackendCore.ts +0 -12
- package/src/types/IRWSResource.ts +0 -5
- package/src/types/IReFormerField.ts +0 -5
package/package.json
CHANGED
|
@@ -13,6 +13,7 @@ import TheRWSService from '../services/_service';
|
|
|
13
13
|
import { handleExternalChange } from './_attrs/_external_handler';
|
|
14
14
|
import { IFastDefinition, isDefined, defineComponent, getDefinition } from './_definitions';
|
|
15
15
|
import { on, $emitDown, observe, sendEventToOutside } from './_event_handling';
|
|
16
|
+
import { domEvents } from '../events';
|
|
16
17
|
|
|
17
18
|
type ComposeMethodType<
|
|
18
19
|
T extends FoundationElementDefinition,
|
|
@@ -21,6 +22,8 @@ type ComposeMethodType<
|
|
|
21
22
|
|
|
22
23
|
type CSSInjectMode = 'adopted' | 'legacy' | 'both';
|
|
23
24
|
|
|
25
|
+
const _DEFAULT_INJECT_CSS_CACHE_LIMIT_DAYS = 1;
|
|
26
|
+
|
|
24
27
|
export interface IWithCompose<T extends RWSViewComponent> {
|
|
25
28
|
[key: string]: any
|
|
26
29
|
new(...args: any[]): T;
|
|
@@ -250,55 +253,81 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
250
253
|
return RWSViewComponent.instances;
|
|
251
254
|
}
|
|
252
255
|
|
|
253
|
-
protected async injectStyles(styleLinks: string[], mode: CSSInjectMode = 'adopted') {
|
|
256
|
+
protected async injectStyles(styleLinks: string[], mode: CSSInjectMode = 'adopted', maxDaysExp?: number) {
|
|
254
257
|
const dbName = 'css-cache';
|
|
255
258
|
const storeName = 'styles';
|
|
256
259
|
const db = await this.indexedDBService.openDB(dbName, storeName);
|
|
260
|
+
const maxAgeMs = 1000 * 60 * 60 * 24; // 24h
|
|
261
|
+
const maxDaysAge = maxDaysExp ? maxDaysExp : _DEFAULT_INJECT_CSS_CACHE_LIMIT_DAYS;
|
|
262
|
+
const maxAgeDays = maxAgeMs * maxDaysAge;
|
|
257
263
|
|
|
258
264
|
let adoptedSheets: CSSStyleSheet[] = [];
|
|
259
265
|
|
|
266
|
+
let doneAdded = false;
|
|
267
|
+
|
|
260
268
|
for (const styleLink of styleLinks) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
269
|
+
const loadPromise = new Promise<void>(async (resolve, reject) => {
|
|
270
|
+
if (mode === 'legacy' || mode === 'both') {
|
|
271
|
+
const link = document.createElement('link');
|
|
272
|
+
link.rel = 'stylesheet';
|
|
273
|
+
link.href = styleLink;
|
|
274
|
+
this.getShadowRoot().appendChild(link);
|
|
275
|
+
|
|
276
|
+
link.onload = () => {
|
|
277
|
+
doneAdded = true;
|
|
278
|
+
|
|
279
|
+
if(mode === 'legacy'){
|
|
280
|
+
resolve();
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
}
|
|
267
284
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
const maxAgeMs = 1000 * 60 * 60 * 24; // 24h
|
|
285
|
+
if (mode === 'adopted' || mode === 'both') {
|
|
286
|
+
const entry = await this.indexedDBService.getFromDB(db, storeName, styleLink);
|
|
271
287
|
|
|
272
|
-
|
|
288
|
+
let cssText: string | null = null;
|
|
273
289
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
290
|
+
if (entry && typeof entry === 'object' && 'css' in entry && 'timestamp' in entry) {
|
|
291
|
+
const expired = Date.now() - entry.timestamp > maxAgeDays;
|
|
292
|
+
if (!expired) {
|
|
293
|
+
cssText = entry.css;
|
|
294
|
+
}
|
|
278
295
|
}
|
|
279
|
-
}
|
|
280
296
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
297
|
+
if (!cssText) {
|
|
298
|
+
cssText = await fetch(styleLink).then(res => res.text());
|
|
299
|
+
await this.indexedDBService.saveToDB(db, storeName, styleLink, {
|
|
300
|
+
css: cssText,
|
|
301
|
+
timestamp: Date.now()
|
|
302
|
+
});
|
|
303
|
+
console.log(`System saved stylesheet: ${styleLink} to IndexedDB`)
|
|
304
|
+
}
|
|
289
305
|
|
|
290
|
-
|
|
291
|
-
|
|
306
|
+
const sheet = new CSSStyleSheet();
|
|
307
|
+
await sheet.replace(cssText);
|
|
292
308
|
|
|
293
|
-
|
|
294
|
-
|
|
309
|
+
adoptedSheets.push(sheet);
|
|
310
|
+
|
|
311
|
+
if(mode === 'adopted' || mode === 'both'){
|
|
312
|
+
resolve();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
await loadPromise;
|
|
295
318
|
}
|
|
296
319
|
|
|
297
|
-
if(adoptedSheets.length){
|
|
298
|
-
this.getShadowRoot().adoptedStyleSheets = [
|
|
320
|
+
if (adoptedSheets.length) {
|
|
321
|
+
this.getShadowRoot().adoptedStyleSheets = [
|
|
299
322
|
...adoptedSheets,
|
|
300
323
|
...this.getShadowRoot().adoptedStyleSheets,
|
|
301
324
|
];
|
|
325
|
+
|
|
326
|
+
doneAdded = true;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (doneAdded) {
|
|
330
|
+
this.$emit(domEvents.loadedLinkedStyles);
|
|
302
331
|
}
|
|
303
332
|
}
|
|
304
333
|
}
|
package/src/events.ts
ADDED
package/src/index.ts
CHANGED
|
@@ -22,14 +22,14 @@ import { RWSIgnore, RWSInject, RWSView } from './components/_decorator';
|
|
|
22
22
|
import type { DefaultRWSPluginOptionsType } from './plugins/_plugin';
|
|
23
23
|
import type { IRWSPlugin, IStaticRWSPlugin, IPluginSpawnOption } from './types/IRWSPlugin';
|
|
24
24
|
import type IRWSUser from './types/IRWSUser';
|
|
25
|
-
import type { IAssetShowOptions } from './components/_component';
|
|
25
|
+
import type { IAssetShowOptions, IRWSViewComponent } from './components/_component';
|
|
26
26
|
import type { RWSDecoratorOptions } from './components/_decorator';
|
|
27
|
-
import type { IKDBTypeInfo, IKDBTypesResponse } from './types/IBackendCore';
|
|
28
27
|
import type { DOMOutputType, TagsProcessorType } from './services/DOMService';
|
|
29
28
|
import type { IBackendRoute, IHTTProute, IPrefixedHTTProutes } from './services/ApiService';
|
|
30
29
|
import type IRWSConfig from './types/IRWSConfig';
|
|
31
30
|
import type RWSNotify from './types/RWSNotify';
|
|
32
31
|
import type { NotifyUiType, NotifyLogType } from './types/RWSNotify';
|
|
32
|
+
import * as RWSEvents from './events';
|
|
33
33
|
|
|
34
34
|
export default RWSClient;
|
|
35
35
|
|
|
@@ -70,11 +70,12 @@ export {
|
|
|
70
70
|
RWSService,
|
|
71
71
|
RWSViewComponent,
|
|
72
72
|
|
|
73
|
-
RWSContainer
|
|
73
|
+
RWSContainer,
|
|
74
|
+
|
|
75
|
+
RWSEvents
|
|
74
76
|
};
|
|
75
77
|
|
|
76
|
-
export type {
|
|
77
|
-
IKDBTypeInfo, IKDBTypesResponse,
|
|
78
|
+
export type {
|
|
78
79
|
NotifyUiType,
|
|
79
80
|
NotifyLogType,
|
|
80
81
|
IBackendRoute as IRWSBackendRoute,
|
|
@@ -84,5 +85,6 @@ export type {
|
|
|
84
85
|
IAssetShowOptions as IRWSAssetShowOptions,
|
|
85
86
|
IRWSConfig,
|
|
86
87
|
IRWSUser,
|
|
87
|
-
TagsProcessorType
|
|
88
|
+
TagsProcessorType,
|
|
89
|
+
IRWSViewComponent
|
|
88
90
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ITypesResponse } from '../../../components/src/types/IBackendCore';
|
|
2
2
|
import TheService from './_service';
|
|
3
3
|
|
|
4
4
|
//@4DI
|
|
@@ -20,11 +20,14 @@ interface IAPIOptions {
|
|
|
20
20
|
routeParams?: {
|
|
21
21
|
[key: string]: string
|
|
22
22
|
},
|
|
23
|
+
queryParams?: {
|
|
24
|
+
[key: string]: string
|
|
25
|
+
}
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
interface IHTTProute<P = {[key: string]: any}> {
|
|
26
29
|
name: string;
|
|
27
|
-
path: string;
|
|
30
|
+
path: string | string[];
|
|
28
31
|
method: string;
|
|
29
32
|
noParams?: boolean;
|
|
30
33
|
options?: any;
|
|
@@ -89,16 +92,16 @@ class ApiService extends TheService {
|
|
|
89
92
|
public delete = calls.delete;
|
|
90
93
|
|
|
91
94
|
public back = {
|
|
92
|
-
get: async <T>(routeName: string, options?: IAPIOptions, token?: string): Promise<T> => calls.get.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams), options) as Promise<T>,
|
|
93
|
-
post: async <T, P extends object = object>(routeName: string, payload?: P, options?: IAPIOptions): Promise<T> => calls.post.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams), payload, options) as Promise<T>,
|
|
94
|
-
put: async <T, P extends object = object>(routeName: string, payload: P, options?: IAPIOptions): Promise<T> => calls.put.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams), payload, options) as Promise<T>,
|
|
95
|
-
delete: async <T>(routeName: string, options?: IAPIOptions): Promise<T> => calls.delete.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams), options) as Promise<T>,
|
|
95
|
+
get: async <T>(routeName: string, options?: IAPIOptions, token?: string): Promise<T> => calls.get.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams, options?.queryParams), options) as Promise<T>,
|
|
96
|
+
post: async <T, P extends object = object>(routeName: string, payload?: P, options?: IAPIOptions): Promise<T> => calls.post.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams, options?.queryParams), payload, options) as Promise<T>,
|
|
97
|
+
put: async <T, P extends object = object>(routeName: string, payload: P, options?: IAPIOptions): Promise<T> => calls.put.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams, options?.queryParams), payload, options) as Promise<T>,
|
|
98
|
+
delete: async <T>(routeName: string, options?: IAPIOptions): Promise<T> => calls.delete.bind(this)(backend.getBackendUrl.bind(this)(routeName, options?.routeParams, options?.queryParams), options) as Promise<T>,
|
|
96
99
|
uploadFile: async (routeName: string, file: File, onProgress: (progress: number) => void, options: IAPIOptions = {}, payload: any = {}): Promise<UploadResponse> => this.uploadFile(backend.getBackendUrl.bind(this)(routeName, options?.routeParams), file, onProgress, payload),
|
|
97
100
|
};
|
|
98
101
|
|
|
99
|
-
async getResource(resourceName: string): Promise<
|
|
102
|
+
async getResource(resourceName: string): Promise<ITypesResponse>
|
|
100
103
|
{
|
|
101
|
-
return calls.get.bind(this)(`${this.config.get('backendUrl')}${this.config.get('apiPrefix') || ''}/api/rws/resource/${resourceName}`) as Promise<
|
|
104
|
+
return calls.get.bind(this)(`${this.config.get('backendUrl')}${this.config.get('apiPrefix') || ''}/api/rws/resource/${resourceName}`) as Promise<ITypesResponse>
|
|
102
105
|
}
|
|
103
106
|
}
|
|
104
107
|
|
|
@@ -83,7 +83,7 @@ class DOMService extends RWSService {
|
|
|
83
83
|
sanitizeOptions: DOMPurify.Config = { })
|
|
84
84
|
{
|
|
85
85
|
const output: string = line.trim();
|
|
86
|
-
const sanitized = DOMPurify.sanitize(output, { USE_PROFILES: { html: true }, ...sanitizeOptions});
|
|
86
|
+
const sanitized = DOMPurify.sanitize(output, { USE_PROFILES: { html: true }, ...sanitizeOptions}) as string;
|
|
87
87
|
return sanitized;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
@@ -2,7 +2,7 @@ import { ApiServiceInstance, IBackendRoute, IHTTProute } from "../ApiService";
|
|
|
2
2
|
import { ConfigServiceInstance } from "../ConfigService";
|
|
3
3
|
|
|
4
4
|
export const backend = {
|
|
5
|
-
getBackendUrl(this: ApiServiceInstance, routeName: string, params: {[key: string]: string} = {}): string
|
|
5
|
+
getBackendUrl(this: ApiServiceInstance, routeName: string, params: {[key: string]: string} = {}, queryParams: {[key: string]: string} = {}): string
|
|
6
6
|
{
|
|
7
7
|
const config = this.config;
|
|
8
8
|
const routesPackage = config.get('backendRoutes');
|
|
@@ -43,13 +43,12 @@ export const backend = {
|
|
|
43
43
|
];
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
routes = [...routes, ...item.routes.map((subRouteItem: IHTTProute): IHTTProute => {
|
|
47
47
|
const subRoute: IHTTProute = {
|
|
48
|
-
path: item.prefix + subRouteItem.path,
|
|
48
|
+
path: Array.isArray(subRouteItem.path) ? subRouteItem.path.map(subPath => item.prefix + subPath) : item.prefix + subRouteItem.path,
|
|
49
49
|
name: backend.checkPrefixedRouteName(subRouteItem.name, item.controllerName),
|
|
50
50
|
method: subRouteItem.method || 'GET'
|
|
51
|
-
};
|
|
52
|
-
|
|
51
|
+
};
|
|
53
52
|
return subRoute;
|
|
54
53
|
})];
|
|
55
54
|
|
|
@@ -65,15 +64,48 @@ export const backend = {
|
|
|
65
64
|
throw new Error(`Backend route '${routeName}' does not exist.`);
|
|
66
65
|
}
|
|
67
66
|
|
|
68
|
-
let apiPath = route.path;
|
|
67
|
+
let apiPath: string | string[] = route.path;
|
|
68
|
+
|
|
69
|
+
if(Array.isArray(apiPath)){
|
|
70
|
+
const paramsLength = Object.keys(params).length;
|
|
71
|
+
if(paramsLength > 0){
|
|
72
|
+
for(const searchedPath of apiPath){
|
|
73
|
+
let foundParams = 0;
|
|
74
|
+
for(const p of Object.keys(params)){
|
|
75
|
+
if(searchedPath.indexOf(`:${p}`) !== -1){
|
|
76
|
+
foundParams++;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if(foundParams === paramsLength){
|
|
81
|
+
apiPath = searchedPath;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}else{
|
|
86
|
+
for(const searchedPath of apiPath){
|
|
87
|
+
if(!searchedPath.includes(':')){
|
|
88
|
+
apiPath = searchedPath;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
69
94
|
|
|
70
95
|
Object.keys(params).forEach((paramKey: string) => {
|
|
71
96
|
const paramValue = params[paramKey];
|
|
72
97
|
|
|
73
|
-
apiPath = apiPath.replace(`:${paramKey}`, paramValue);
|
|
74
|
-
});
|
|
98
|
+
apiPath = (apiPath as string).replace(`:${paramKey}`, paramValue);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
let finalUrl = `${config.get('backendUrl')}${config.get('apiPrefix') || ''}${apiPath}`;
|
|
102
|
+
|
|
103
|
+
if(Object.keys(queryParams).length > 0){
|
|
104
|
+
const queryString = new URLSearchParams(queryParams).toString();
|
|
105
|
+
finalUrl += `?${queryString}`;
|
|
106
|
+
}
|
|
75
107
|
|
|
76
|
-
return
|
|
108
|
+
return finalUrl;
|
|
77
109
|
},
|
|
78
110
|
checkPrefixedRouteName(routeName: string, prefixName: string){
|
|
79
111
|
let finalRoute = routeName;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ViewTemplate } from '@microsoft/fast-element';
|
|
1
|
+
import { FASTElement, ViewTemplate } from '@microsoft/fast-element';
|
|
2
2
|
import { DOMOutputType } from '../services/DOMService';
|
|
3
3
|
|
|
4
4
|
type IAssetShowOptions = Record<string, any>;
|
|
5
5
|
|
|
6
|
-
interface IRWSViewComponent extends
|
|
6
|
+
interface IRWSViewComponent extends FASTElement {
|
|
7
7
|
__isLoading: boolean;
|
|
8
8
|
routeParams: Record<string, string>;
|
|
9
9
|
trashIterator: number;
|