@rws-framework/client 2.21.1 → 2.21.3
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/loaders/rws_fast_ts_loader.js +2 -2
- package/builder/webpack/scss/_import.js +1 -1
- package/cfg/build_steps/webpack/_loaders.js +11 -2
- package/package.json +1 -1
- package/src/components/_component.ts +99 -30
- package/src/components/_decorator.ts +7 -3
- package/src/components/_decorators/RWSInject.ts +1 -2
- package/src/services/IndexedDBService.ts +49 -0
|
@@ -37,8 +37,8 @@ module.exports = async function(content) {
|
|
|
37
37
|
let templateName = null;
|
|
38
38
|
let stylesPath = null;
|
|
39
39
|
|
|
40
|
-
if(decoratorData.decoratorArgs){
|
|
41
|
-
const decoratorArgs =
|
|
40
|
+
if(decoratorData.decoratorArgs){
|
|
41
|
+
const decoratorArgs = decoratorData.decoratorArgs
|
|
42
42
|
|
|
43
43
|
if(decoratorArgs.template){
|
|
44
44
|
templateName = decoratorData.decoratorArgs.template || null;
|
|
@@ -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) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const path = require('path');
|
|
2
|
+
const json5 = require('json5');
|
|
2
3
|
const fs = require('fs');
|
|
3
4
|
const os = require('os');
|
|
4
5
|
|
|
@@ -191,14 +192,22 @@ function extractRWSViewArgs(content, noReplace = false) {
|
|
|
191
192
|
|
|
192
193
|
let fastOptions = _defaultRWSLoaderOptions.fastOptions;
|
|
193
194
|
|
|
195
|
+
if(decoratorArgs && decoratorArgs !== ''){
|
|
196
|
+
try {
|
|
197
|
+
decoratorArgs = json5.parse(decoratorArgs);
|
|
198
|
+
}catch(e){
|
|
199
|
+
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
194
203
|
if (decoratorArgs && decoratorArgs.fastElementOptions) {
|
|
195
204
|
fastOptions = decoratorArgs.fastElementOptions;
|
|
196
205
|
}
|
|
197
206
|
|
|
198
207
|
let replacedDecorator = null;
|
|
199
208
|
|
|
200
|
-
if(!noReplace){
|
|
201
|
-
const [addedParamDefs, addedParams] = _extractRWSViewDefs(fastOptions, decoratorArgs);
|
|
209
|
+
if(!noReplace){
|
|
210
|
+
const [addedParamDefs, addedParams] = _extractRWSViewDefs(fastOptions, decoratorArgs);
|
|
202
211
|
const replacedViewDecoratorContent = processedContent.replace(
|
|
203
212
|
viewReg,
|
|
204
213
|
`@RWSView('$1', null, { template: rwsTemplate, styles${addedParams.length ? ', options: {' + (addedParams.join(', ')) + '}' : ''} })\n$3class $4 extends RWSViewComponent `
|
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;
|
|
@@ -11,7 +11,9 @@ import { handleExternalChange } from './_attrs/_external_handler';
|
|
|
11
11
|
interface RWSDecoratorOptions {
|
|
12
12
|
template?: string,
|
|
13
13
|
styles?: string,
|
|
14
|
-
fastElementOptions?:
|
|
14
|
+
fastElementOptions?: {
|
|
15
|
+
shadowOptions?: ShadowRootInit
|
|
16
|
+
},
|
|
15
17
|
ignorePackaging?: boolean,
|
|
16
18
|
debugPackaging?: boolean
|
|
17
19
|
oreoMode?: boolean
|
|
@@ -70,10 +72,12 @@ const applyConstructor = (component: RWSViewComponent, x: boolean = false): void
|
|
|
70
72
|
|
|
71
73
|
const regServices = loadRWSRichWindow().RWS._registered;
|
|
72
74
|
|
|
75
|
+
|
|
73
76
|
|
|
74
77
|
const depsToInject: string[] = (mainConstructor as IWithCompose<RWSViewComponent>)._depKeys[mainConstructor.name] || [];
|
|
75
78
|
const depsInInjector: string[] = Object.keys(existingInjectedDependencies);
|
|
76
79
|
|
|
80
|
+
|
|
77
81
|
const toInject: string[] = [...depsToInject]
|
|
78
82
|
|
|
79
83
|
type KeyType = {[key: string]: TheRWSService | string };
|
|
@@ -82,7 +86,7 @@ const applyConstructor = (component: RWSViewComponent, x: boolean = false): void
|
|
|
82
86
|
|
|
83
87
|
function inject(services: KeyType){
|
|
84
88
|
for (const prop in services) {
|
|
85
|
-
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;
|
|
86
90
|
_target[prop] = service;
|
|
87
91
|
}
|
|
88
92
|
}
|
|
@@ -94,7 +98,7 @@ const applyConstructor = (component: RWSViewComponent, x: boolean = false): void
|
|
|
94
98
|
|
|
95
99
|
const defaultDeps: [string, TheRWSService][] = Object.keys(existingInjectedDependencies)
|
|
96
100
|
.filter((depKey: string) => existingInjectedDependencies[depKey].isDefault()).map((depKey => [depKey, existingInjectedDependencies[depKey]]));
|
|
97
|
-
|
|
101
|
+
|
|
98
102
|
inject(defaultDeps.reduce((acc: KeyType, cur: [string, TheRWSService]) => {
|
|
99
103
|
acc[cur[0]] = cur[1];
|
|
100
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
|
}
|
|
@@ -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 };
|