@rws-framework/client 2.21.2 → 2.21.4
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/builder/webpack/scss/_import.js +1 -1
- package/package.json +1 -1
- package/src/components/_component.ts +99 -30
- package/src/components/_decorator.ts +4 -2
- package/src/components/_decorators/RWSInject.ts +1 -2
- package/src/index.ts +3 -2
- package/src/services/IndexedDBService.ts +49 -0
- package/src/types/IRWSViewComponent.ts +2 -2
|
@@ -23,7 +23,7 @@ function processImportPath(importPath, rwsWorkspaceDir, appRootDir, fileRootDir
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
if (importPath.indexOf('@workspace') === 0) {
|
|
26
|
-
return path.join(workspaceDir, importPath.replace('@workspace', ''));
|
|
26
|
+
return path.join(workspaceDir, 'src', importPath.replace('@workspace', ''));
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
if (importPath.indexOf('@public') === 0) {
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import UtilsService, { UtilsServiceInstance } from '../services/UtilsService';
|
|
|
5
5
|
import DOMService, { DOMServiceInstance, DOMOutputType } from '../services/DOMService';
|
|
6
6
|
import ApiService, { ApiServiceInstance } from '../services/ApiService';
|
|
7
7
|
import NotifyService, { NotifyServiceInstance } from '../services/NotifyService';
|
|
8
|
+
import IndexedDBService, { IndexedDBServiceInstance } from '../services/IndexedDBService';
|
|
8
9
|
import { IRWSViewComponent, IAssetShowOptions } from '../types/IRWSViewComponent';
|
|
9
10
|
import RWSWindow, { RWSWindowComponentInterface, loadRWSRichWindow } from '../types/RWSWindow';
|
|
10
11
|
import { applyConstructor, RWSInject } from './_decorator';
|
|
@@ -14,22 +15,26 @@ import { IFastDefinition, isDefined, defineComponent, getDefinition } from './_d
|
|
|
14
15
|
import { on, $emitDown, observe, sendEventToOutside } from './_event_handling';
|
|
15
16
|
|
|
16
17
|
type ComposeMethodType<
|
|
17
|
-
T extends FoundationElementDefinition,
|
|
18
|
+
T extends FoundationElementDefinition,
|
|
18
19
|
K extends Constructable<RWSViewComponent>
|
|
19
20
|
> = (this: K, elementDefinition: T) => (overrideDefinition?: OverrideFoundationElementDefinition<T>) => FoundationElementRegistry<FoundationElementDefinition, T>;
|
|
20
21
|
|
|
22
|
+
type CSSInjectMode = 'adopted' | 'legacy' | 'both';
|
|
23
|
+
|
|
24
|
+
const _DEFAULT_INJECT_CSS_CACHE_LIMIT_DAYS = 1;
|
|
25
|
+
|
|
21
26
|
export interface IWithCompose<T extends RWSViewComponent> {
|
|
22
27
|
[key: string]: any
|
|
23
|
-
new
|
|
28
|
+
new(...args: any[]): T;
|
|
24
29
|
definition?: IFastDefinition
|
|
25
30
|
defineComponent: <T extends RWSViewComponent>(this: IWithCompose<T>) => void
|
|
26
31
|
isDefined<T extends RWSViewComponent>(this: IWithCompose<T>): boolean
|
|
27
32
|
compose: ComposeMethodType<FoundationElementDefinition, Constructable<T>>;
|
|
28
33
|
define<TType extends (...params: any[]) => any>(type: TType, nameOrDef?: string | PartialFASTElementDefinition | undefined): TType;
|
|
29
34
|
_verbose: boolean;
|
|
30
|
-
_toInject: {[key: string]: TheRWSService};
|
|
31
|
-
_depKeys: {[key: string]: string[]};
|
|
32
|
-
_externalAttrs: { [key:string]: string[] };
|
|
35
|
+
_toInject: { [key: string]: TheRWSService };
|
|
36
|
+
_depKeys: { [key: string]: string[] };
|
|
37
|
+
_externalAttrs: { [key: string]: string[] };
|
|
33
38
|
setExternalAttr: (componentName: string, key: string) => void
|
|
34
39
|
sendEventToOutside: <T>(eventName: string, data: T) => void
|
|
35
40
|
_EVENTS: {
|
|
@@ -48,35 +53,39 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
48
53
|
|
|
49
54
|
static autoLoadFastElement = true;
|
|
50
55
|
static _defined: { [key: string]: boolean } = {};
|
|
51
|
-
static _toInject: {[key: string]: TheRWSService} = {};
|
|
52
|
-
static _depKeys: {[key: string]: string[]} = {_all: []};
|
|
56
|
+
static _toInject: { [key: string]: TheRWSService } = {};
|
|
57
|
+
static _depKeys: { [key: string]: string[] } = { _all: [] };
|
|
53
58
|
static _externalAttrs: { [key: string]: string[] } = {};
|
|
54
59
|
static _verbose: boolean = false;
|
|
55
60
|
|
|
61
|
+
private static FORCE_INJECT_STYLES?: string[] = [];
|
|
62
|
+
private static FORCE_INJECT_MODE?: CSSInjectMode = 'adopted';
|
|
63
|
+
|
|
56
64
|
static _EVENTS = {
|
|
57
65
|
component_define: 'rws:lifecycle:defineComponent',
|
|
58
66
|
component_parted_load: 'rws:lifecycle:loadPartedComponents',
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
@RWSInject(
|
|
69
|
+
@RWSInject(IndexedDBService, true) protected indexedDBService: IndexedDBServiceInstance;
|
|
70
|
+
@RWSInject(ConfigService, true) protected config: ConfigServiceInstance;
|
|
62
71
|
@RWSInject(DOMService, true) protected domService: DOMServiceInstance;
|
|
63
72
|
@RWSInject(UtilsService, true) protected utilsService: UtilsServiceInstance;
|
|
64
|
-
@RWSInject(ApiService, true) protected apiService: ApiServiceInstance;
|
|
73
|
+
@RWSInject(ApiService, true) protected apiService: ApiServiceInstance;
|
|
65
74
|
@RWSInject(NotifyService, true) protected notifyService: NotifyServiceInstance;
|
|
66
75
|
|
|
67
76
|
@observable trashIterator: number = 0;
|
|
68
77
|
@observable fileAssets: {
|
|
69
78
|
[key: string]: ViewTemplate
|
|
70
|
-
} = {};
|
|
79
|
+
} = {};
|
|
71
80
|
|
|
72
81
|
constructor() {
|
|
73
|
-
super();
|
|
74
|
-
applyConstructor(this);
|
|
82
|
+
super();
|
|
83
|
+
applyConstructor(this);
|
|
75
84
|
}
|
|
76
85
|
|
|
77
|
-
connectedCallback() {
|
|
78
|
-
super.connectedCallback();
|
|
79
|
-
applyConstructor(this);
|
|
86
|
+
connectedCallback() {
|
|
87
|
+
super.connectedCallback();
|
|
88
|
+
applyConstructor(this);
|
|
80
89
|
|
|
81
90
|
if (!(this.constructor as IWithCompose<this>).definition && (this.constructor as IWithCompose<this>).autoLoadFastElement) {
|
|
82
91
|
throw new Error('RWS component is not named. Add `static definition = {name, template};`');
|
|
@@ -84,8 +93,12 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
84
93
|
|
|
85
94
|
this.applyFileList();
|
|
86
95
|
|
|
96
|
+
if (RWSViewComponent.FORCE_INJECT_STYLES) {
|
|
97
|
+
this.injectStyles(RWSViewComponent.FORCE_INJECT_STYLES, RWSViewComponent.FORCE_INJECT_MODE);
|
|
98
|
+
}
|
|
99
|
+
|
|
87
100
|
RWSViewComponent.instances.push(this);
|
|
88
|
-
}
|
|
101
|
+
}
|
|
89
102
|
|
|
90
103
|
passRouteParams(routeParams: Record<string, string> = null) {
|
|
91
104
|
if (routeParams) {
|
|
@@ -111,8 +124,7 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
111
124
|
return $emitDown.bind(this)(eventName, payload);
|
|
112
125
|
}
|
|
113
126
|
|
|
114
|
-
observe(callback: (component: RWSViewComponent, node: Node, observer: MutationObserver) => Promise<void>, condition: (component: RWSViewComponent, node: Node) => boolean = null, observeRemoved: boolean = false)
|
|
115
|
-
{
|
|
127
|
+
observe(callback: (component: RWSViewComponent, node: Node, observer: MutationObserver) => Promise<void>, condition: (component: RWSViewComponent, node: Node) => boolean = null, observeRemoved: boolean = false) {
|
|
116
128
|
return observe.bind(this)(callback, condition, observeRemoved);
|
|
117
129
|
}
|
|
118
130
|
|
|
@@ -187,8 +199,15 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
187
199
|
sendEventToOutside(eventName, data);
|
|
188
200
|
}
|
|
189
201
|
|
|
190
|
-
|
|
191
|
-
|
|
202
|
+
static injectStyles(linkedStyles: string[], mode?: CSSInjectMode) {
|
|
203
|
+
if (mode) {
|
|
204
|
+
RWSViewComponent.FORCE_INJECT_MODE = mode;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
RWSViewComponent.FORCE_INJECT_STYLES = linkedStyles;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
private applyFileList(): void {
|
|
192
211
|
try {
|
|
193
212
|
(this.constructor as IWithCompose<this>).fileList.forEach((file: string) => {
|
|
194
213
|
if (this.fileAssets[file]) {
|
|
@@ -203,11 +222,10 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
203
222
|
console.error('Error loading file content:', e.message);
|
|
204
223
|
console.error(e.stack);
|
|
205
224
|
}
|
|
206
|
-
}
|
|
225
|
+
}
|
|
207
226
|
|
|
208
|
-
static setExternalAttr(componentName: string, key: string)
|
|
209
|
-
|
|
210
|
-
if(!Object.keys(RWSViewComponent._externalAttrs).includes(componentName)){
|
|
227
|
+
static setExternalAttr(componentName: string, key: string) {
|
|
228
|
+
if (!Object.keys(RWSViewComponent._externalAttrs).includes(componentName)) {
|
|
211
229
|
RWSViewComponent._externalAttrs[componentName] = [];
|
|
212
230
|
}
|
|
213
231
|
|
|
@@ -218,24 +236,75 @@ abstract class RWSViewComponent extends FoundationElement implements IRWSViewCom
|
|
|
218
236
|
this.getInstances().forEach(instance => instance.forceReload());
|
|
219
237
|
}
|
|
220
238
|
|
|
221
|
-
static isDefined<T extends RWSViewComponent>(this: IWithCompose<T>): boolean
|
|
222
|
-
{
|
|
239
|
+
static isDefined<T extends RWSViewComponent>(this: IWithCompose<T>): boolean {
|
|
223
240
|
return isDefined<T>(this);
|
|
224
241
|
}
|
|
225
242
|
|
|
226
|
-
static defineComponent<T extends RWSViewComponent>(this: IWithCompose<T>): void
|
|
227
|
-
{
|
|
243
|
+
static defineComponent<T extends RWSViewComponent>(this: IWithCompose<T>): void {
|
|
228
244
|
return defineComponent<T>(this);
|
|
229
245
|
}
|
|
230
246
|
|
|
231
|
-
static getDefinition(tagName: string, htmlTemplate: ViewTemplate, styles: ElementStyles = null)
|
|
232
|
-
{
|
|
247
|
+
static getDefinition(tagName: string, htmlTemplate: ViewTemplate, styles: ElementStyles = null) {
|
|
233
248
|
return getDefinition(tagName, htmlTemplate, styles);
|
|
234
249
|
}
|
|
235
250
|
|
|
236
251
|
private static getInstances(): RWSViewComponent[] {
|
|
237
252
|
return RWSViewComponent.instances;
|
|
238
253
|
}
|
|
254
|
+
|
|
255
|
+
protected async injectStyles(styleLinks: string[], mode: CSSInjectMode = 'adopted', maxDaysExp?: number) {
|
|
256
|
+
const dbName = 'css-cache';
|
|
257
|
+
const storeName = 'styles';
|
|
258
|
+
const db = await this.indexedDBService.openDB(dbName, storeName);
|
|
259
|
+
const maxAgeMs = 1000 * 60 * 60 * 24; // 24h
|
|
260
|
+
const maxDaysAge = maxDaysExp ? maxDaysExp : _DEFAULT_INJECT_CSS_CACHE_LIMIT_DAYS;
|
|
261
|
+
const maxAgeDays = maxAgeMs * maxDaysAge;
|
|
262
|
+
|
|
263
|
+
let adoptedSheets: CSSStyleSheet[] = [];
|
|
264
|
+
|
|
265
|
+
for (const styleLink of styleLinks) {
|
|
266
|
+
if (mode === 'legacy' || mode === 'both') {
|
|
267
|
+
const link = document.createElement('link');
|
|
268
|
+
link.rel = 'stylesheet';
|
|
269
|
+
link.href = styleLink;
|
|
270
|
+
this.getShadowRoot().appendChild(link);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (mode === 'adopted' || mode === 'both') {
|
|
274
|
+
const entry = await this.indexedDBService.getFromDB(db, storeName, styleLink);
|
|
275
|
+
|
|
276
|
+
let cssText: string | null = null;
|
|
277
|
+
|
|
278
|
+
if (entry && typeof entry === 'object' && 'css' in entry && 'timestamp' in entry) {
|
|
279
|
+
const expired = Date.now() - entry.timestamp > maxAgeDays;
|
|
280
|
+
if (!expired) {
|
|
281
|
+
cssText = entry.css;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
if (!cssText) {
|
|
286
|
+
cssText = await fetch(styleLink).then(res => res.text());
|
|
287
|
+
await this.indexedDBService.saveToDB(db, storeName, styleLink, {
|
|
288
|
+
css: cssText,
|
|
289
|
+
timestamp: Date.now()
|
|
290
|
+
});
|
|
291
|
+
console.log(`System saved stylesheet: ${styleLink} to IndexedDB`)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const sheet = new CSSStyleSheet();
|
|
295
|
+
await sheet.replace(cssText);
|
|
296
|
+
|
|
297
|
+
adoptedSheets.push(sheet);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
if(adoptedSheets.length){
|
|
302
|
+
this.getShadowRoot().adoptedStyleSheets = [
|
|
303
|
+
...adoptedSheets,
|
|
304
|
+
...this.getShadowRoot().adoptedStyleSheets,
|
|
305
|
+
];
|
|
306
|
+
}
|
|
307
|
+
}
|
|
239
308
|
}
|
|
240
309
|
|
|
241
310
|
export default RWSViewComponent;
|
|
@@ -72,10 +72,12 @@ const applyConstructor = (component: RWSViewComponent, x: boolean = false): void
|
|
|
72
72
|
|
|
73
73
|
const regServices = loadRWSRichWindow().RWS._registered;
|
|
74
74
|
|
|
75
|
+
|
|
75
76
|
|
|
76
77
|
const depsToInject: string[] = (mainConstructor as IWithCompose<RWSViewComponent>)._depKeys[mainConstructor.name] || [];
|
|
77
78
|
const depsInInjector: string[] = Object.keys(existingInjectedDependencies);
|
|
78
79
|
|
|
80
|
+
|
|
79
81
|
const toInject: string[] = [...depsToInject]
|
|
80
82
|
|
|
81
83
|
type KeyType = {[key: string]: TheRWSService | string };
|
|
@@ -84,7 +86,7 @@ const applyConstructor = (component: RWSViewComponent, x: boolean = false): void
|
|
|
84
86
|
|
|
85
87
|
function inject(services: KeyType){
|
|
86
88
|
for (const prop in services) {
|
|
87
|
-
const service = (typeof services[prop] === 'string' ? existingInjectedDependencies[prop] : services[prop]) as TheRWSService;
|
|
89
|
+
const service = (typeof services[prop] === 'string' ? existingInjectedDependencies[prop] : services[prop]) as TheRWSService;
|
|
88
90
|
_target[prop] = service;
|
|
89
91
|
}
|
|
90
92
|
}
|
|
@@ -96,7 +98,7 @@ const applyConstructor = (component: RWSViewComponent, x: boolean = false): void
|
|
|
96
98
|
|
|
97
99
|
const defaultDeps: [string, TheRWSService][] = Object.keys(existingInjectedDependencies)
|
|
98
100
|
.filter((depKey: string) => existingInjectedDependencies[depKey].isDefault()).map((depKey => [depKey, existingInjectedDependencies[depKey]]));
|
|
99
|
-
|
|
101
|
+
|
|
100
102
|
inject(defaultDeps.reduce((acc: KeyType, cur: [string, TheRWSService]) => {
|
|
101
103
|
acc[cur[0]] = cur[1];
|
|
102
104
|
return acc;
|
|
@@ -8,8 +8,7 @@ import { handleExternalChange } from '../_attrs/_external_handler';
|
|
|
8
8
|
type InjectDecoratorReturnType = (target: any, key?: string | number | undefined, parameterIndex?: number) => void;
|
|
9
9
|
type TargetType = any;
|
|
10
10
|
|
|
11
|
-
function addToComponentInjection(targetComponentName: string, constructor: any, depKey: string, dependencyClass: Key, isDefaultService: boolean = false){
|
|
12
|
-
|
|
11
|
+
function addToComponentInjection(targetComponentName: string, constructor: any, depKey: string, dependencyClass: Key, isDefaultService: boolean = false){
|
|
13
12
|
if(isDefaultService){
|
|
14
13
|
targetComponentName = '_all';
|
|
15
14
|
}
|
package/src/index.ts
CHANGED
|
@@ -22,7 +22,7 @@ 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
27
|
import type { IKDBTypeInfo, IKDBTypesResponse } from './types/IBackendCore';
|
|
28
28
|
import type { DOMOutputType, TagsProcessorType } from './services/DOMService';
|
|
@@ -84,5 +84,6 @@ export type {
|
|
|
84
84
|
IAssetShowOptions as IRWSAssetShowOptions,
|
|
85
85
|
IRWSConfig,
|
|
86
86
|
IRWSUser,
|
|
87
|
-
TagsProcessorType
|
|
87
|
+
TagsProcessorType,
|
|
88
|
+
IRWSViewComponent
|
|
88
89
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import RWSService from './_service';
|
|
2
|
+
|
|
3
|
+
class IndexedDBService extends RWSService {
|
|
4
|
+
static _DEFAULT: boolean = true;
|
|
5
|
+
openDB(dbName: string, storeName: string): Promise<IDBDatabase> {
|
|
6
|
+
return new Promise((resolve, reject) => {
|
|
7
|
+
const request = indexedDB.open(dbName, 1);
|
|
8
|
+
|
|
9
|
+
request.onupgradeneeded = () => {
|
|
10
|
+
const db = request.result;
|
|
11
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
12
|
+
db.createObjectStore(storeName);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
request.onsuccess = () => resolve(request.result);
|
|
17
|
+
request.onerror = () => reject(request.error);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
getFromDB(db: IDBDatabase, store: string, key: string): Promise<{
|
|
22
|
+
css: string,
|
|
23
|
+
timestamp: number
|
|
24
|
+
} | null> {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
const tx = db.transaction(store, 'readonly');
|
|
27
|
+
const request = tx.objectStore(store).get(key);
|
|
28
|
+
|
|
29
|
+
request.onsuccess = () => resolve(request.result ?? null);
|
|
30
|
+
request.onerror = () => reject(request.error);
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
saveToDB(db: IDBDatabase, store: string, key: string, value: {
|
|
35
|
+
css: string,
|
|
36
|
+
timestamp: number
|
|
37
|
+
}): Promise<void> {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const tx = db.transaction(store, 'readwrite');
|
|
40
|
+
const request = tx.objectStore(store).put(value, key);
|
|
41
|
+
|
|
42
|
+
request.onsuccess = () => resolve();
|
|
43
|
+
request.onerror = () => reject(request.error);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export default IndexedDBService.getSingleton();
|
|
49
|
+
export { IndexedDBService as IndexedDBServiceInstance };
|
|
@@ -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;
|