lupine.web 1.0.29 → 1.0.31
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/core/bind-attributes.ts +4 -1
- package/src/core/bind-ref.ts +11 -15
- package/src/core/index.ts +1 -2
- package/src/core/initialize.ts +3 -3
- package/src/core/mount-component.ts +68 -0
- package/src/core/page-router.ts +11 -2
- package/src/core/{render-components.ts → render-component.ts} +4 -4
- package/src/core/replace-innerhtml.ts +8 -5
- package/src/jsx.ts +2 -1
- package/src/core/component-factory.ts +0 -19
- package/src/core/mount-components.ts +0 -42
package/package.json
CHANGED
|
@@ -22,7 +22,10 @@ export const bindAttributesChildren = (topEl: Element, children: any) => {
|
|
|
22
22
|
export const bindAttributes = (topEl: Element, type: any, props: any) => {
|
|
23
23
|
const newProps = (props._result && props._result.props) || props;
|
|
24
24
|
if (newProps._id) {
|
|
25
|
-
|
|
25
|
+
let el = topEl.querySelector(`[${newProps._id}]`);
|
|
26
|
+
if (!el && topEl.getAttribute(newProps._id) === '') {
|
|
27
|
+
el = topEl;
|
|
28
|
+
}
|
|
26
29
|
if (el) {
|
|
27
30
|
for (let i in newProps) {
|
|
28
31
|
if (i === 'ref') {
|
package/src/core/bind-ref.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { replaceInnerhtml } from "./replace-innerhtml";
|
|
1
|
+
import { VNode } from '../jsx';
|
|
2
|
+
import { bindAttributes } from './bind-attributes';
|
|
3
|
+
import { bindLinks } from './bind-links';
|
|
4
|
+
import { mountInnerComponent, mountOuterComponent } from './mount-component';
|
|
5
|
+
import { renderComponent } from './render-component';
|
|
6
|
+
import { replaceInnerhtml } from './replace-innerhtml';
|
|
8
7
|
|
|
9
8
|
export const bindRef = (type: any, newProps: any, el: Element) => {
|
|
10
9
|
// console.log('========', newProps, el);
|
|
@@ -31,22 +30,19 @@ export const bindRef = (type: any, newProps: any, el: Element) => {
|
|
|
31
30
|
*/
|
|
32
31
|
newProps['ref'].$ = (selector: string) => {
|
|
33
32
|
return el.querySelector(`[${id}] ` + selector);
|
|
34
|
-
// const dom = LiteDom.queryOne(el);
|
|
35
|
-
// return dom && dom.$(selector, value);
|
|
36
33
|
};
|
|
37
34
|
newProps['ref'].$all = (selector: string) => {
|
|
38
35
|
return el.querySelectorAll(`[${id}] ` + selector);
|
|
39
36
|
};
|
|
40
37
|
|
|
41
|
-
newProps['ref'].
|
|
38
|
+
newProps['ref'].mountInnerComponent = async (content: string | VNode<any>) => {
|
|
42
39
|
if (typeof content === 'object' && content.type && content.props) {
|
|
43
|
-
|
|
44
|
-
renderComponents(content.type, content.props);
|
|
45
|
-
await replaceInnerhtml(el, content.props._html.join(''));
|
|
46
|
-
bindAttributes(el, content.type, content.props);
|
|
47
|
-
bindLinks(el);
|
|
40
|
+
await mountInnerComponent(el, content);
|
|
48
41
|
} else {
|
|
49
42
|
await replaceInnerhtml(el, content as string);
|
|
50
43
|
}
|
|
51
44
|
};
|
|
45
|
+
newProps['ref'].mountOuterComponent = async (content: VNode<any>) => {
|
|
46
|
+
await mountOuterComponent(el, content);
|
|
47
|
+
};
|
|
52
48
|
};
|
package/src/core/index.ts
CHANGED
|
@@ -5,10 +5,9 @@ export * from './bind-meta';
|
|
|
5
5
|
export * from './bind-ref';
|
|
6
6
|
export * from './bind-styles';
|
|
7
7
|
export * from './bind-theme';
|
|
8
|
-
export * from './component-factory';
|
|
9
8
|
export * from './export-lupine';
|
|
10
9
|
export * from './camel-to-hyphens';
|
|
11
|
-
export * from './mount-
|
|
10
|
+
export * from './mount-component';
|
|
12
11
|
export * from './page-loaded-events';
|
|
13
12
|
export * from './page-router';
|
|
14
13
|
export * from './replace-innerhtml';
|
package/src/core/initialize.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Logger } from '../lib/logger';
|
|
2
2
|
import { generateAllGlobalStyles } from './bind-styles';
|
|
3
3
|
import { defaultThemeName, getCurrentTheme, updateTheme } from './bind-theme';
|
|
4
|
-
import {
|
|
4
|
+
import { mountInnerComponent } from './mount-component';
|
|
5
5
|
// import { callPageResetEvent } from './page-reset-events';
|
|
6
6
|
import { PageRouter } from './page-router';
|
|
7
7
|
import { callPageLoadedEvent } from './page-loaded-events';
|
|
@@ -42,7 +42,7 @@ const generatePage = async (props: PageProps, toClientDelivery: IToClientDeliver
|
|
|
42
42
|
};
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
await
|
|
45
|
+
await mountInnerComponent(null, jsxNodes);
|
|
46
46
|
const currentTheme = getCurrentTheme();
|
|
47
47
|
const cssText = generateAllGlobalStyles();
|
|
48
48
|
const content = jsxNodes.props._html.join('');
|
|
@@ -93,7 +93,7 @@ export const initializePage = async (newUrl?: string) => {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
// generateAllGlobalStyles will be updated directly in Browser
|
|
96
|
-
await
|
|
96
|
+
await mountInnerComponent('.lupine-root', jsxNodes);
|
|
97
97
|
updateTheme(getCurrentTheme().themeName);
|
|
98
98
|
|
|
99
99
|
// title
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { bindAttributes } from './bind-attributes';
|
|
2
|
+
import { bindLinks } from './bind-links';
|
|
3
|
+
import { VNode } from '../jsx';
|
|
4
|
+
// import { Logger } from '../lib/logger';
|
|
5
|
+
// import { bindPageResetEvent } from './page-reset-events';
|
|
6
|
+
import { callUnload, replaceInnerhtml } from './replace-innerhtml';
|
|
7
|
+
import { renderComponent } from './render-component';
|
|
8
|
+
|
|
9
|
+
// const logger = new Logger('mount-components');
|
|
10
|
+
export const mountInnerComponent = async (selector: string | null | Element, jsxNodes: VNode<any>) => {
|
|
11
|
+
renderComponent(jsxNodes.type, jsxNodes.props);
|
|
12
|
+
const el = selector && (typeof selector === 'string' ? document.querySelector(selector) : selector);
|
|
13
|
+
if (el) {
|
|
14
|
+
// call unload before releace innerHTML
|
|
15
|
+
await replaceInnerhtml(el, jsxNodes.props._html.join(''));
|
|
16
|
+
|
|
17
|
+
bindAttributes(el, jsxNodes.type, jsxNodes.props);
|
|
18
|
+
bindLinks(el);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// suggest to use HtmlVar.
|
|
23
|
+
export const mountOuterComponent = async (selector: string | Element, jsxNodes: VNode<any>) => {
|
|
24
|
+
renderComponent(jsxNodes.type, jsxNodes.props);
|
|
25
|
+
let el = selector && (typeof selector === 'string' ? document.querySelector(selector) : selector);
|
|
26
|
+
if (el) {
|
|
27
|
+
// Can't do outerHTML directly because it will lose attributes
|
|
28
|
+
const template = document.createElement('template');
|
|
29
|
+
// template.innerHTML = jsxNodes.props._html.join("");
|
|
30
|
+
// call unload before releace innerHTML
|
|
31
|
+
await replaceInnerhtml(template, jsxNodes.props._html.join(''));
|
|
32
|
+
// renderComponent should only have one element
|
|
33
|
+
template.content.children.length > 1 &&
|
|
34
|
+
console.error('renderComponent should only have one element: ', template.content.children.length);
|
|
35
|
+
const newEl = template.content.firstChild as Element;
|
|
36
|
+
// el.replaceWith(newEl);
|
|
37
|
+
await callUnload(el);
|
|
38
|
+
el.parentNode?.replaceChild(newEl, el);
|
|
39
|
+
bindAttributes(newEl, jsxNodes.type, jsxNodes.props);
|
|
40
|
+
bindLinks(newEl);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// suggest to use HtmlVar.
|
|
45
|
+
export const mountSiblingComponent = async (selector: string | Element, jsxNodes: VNode<any>, position: 'before' | 'after' = 'after') => {
|
|
46
|
+
renderComponent(jsxNodes.type, jsxNodes.props);
|
|
47
|
+
let el = selector && (typeof selector === 'string' ? document.querySelector(selector) : selector);
|
|
48
|
+
if (el) {
|
|
49
|
+
// Can't do outerHTML directly because it will lose attributes
|
|
50
|
+
const template = document.createElement('template');
|
|
51
|
+
// template.innerHTML = jsxNodes.props._html.join("");
|
|
52
|
+
// call unload before releace innerHTML
|
|
53
|
+
await replaceInnerhtml(template, jsxNodes.props._html.join(''));
|
|
54
|
+
// renderComponent should only have one element
|
|
55
|
+
template.content.children.length > 1 &&
|
|
56
|
+
console.error('renderComponent should only have one element: ', template.content.children.length);
|
|
57
|
+
const newEl = template.content.firstChild as Element;
|
|
58
|
+
// el.replaceWith(newEl);
|
|
59
|
+
await callUnload(el);
|
|
60
|
+
if (el.nextSibling || position === 'before') {
|
|
61
|
+
el.parentNode?.insertBefore(newEl, position === 'after' ? el.nextSibling : el);
|
|
62
|
+
} else {
|
|
63
|
+
el.parentNode?.appendChild(newEl);
|
|
64
|
+
}
|
|
65
|
+
bindAttributes(newEl, jsxNodes.type, jsxNodes.props);
|
|
66
|
+
bindLinks(newEl);
|
|
67
|
+
}
|
|
68
|
+
};
|
package/src/core/page-router.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { VNode } from '../jsx';
|
|
2
2
|
import { isFrontEnd } from '../lib/is-frontend';
|
|
3
3
|
import { PageProps } from './export-lupine';
|
|
4
|
-
import {
|
|
4
|
+
import { mountInnerComponent } from './mount-component';
|
|
5
5
|
import { Logger } from '../lib/logger';
|
|
6
6
|
|
|
7
7
|
export type PageRouterCallback = (props: PageProps) => Promise<VNode<any> | null>;
|
|
@@ -23,6 +23,7 @@ export class PageRouter {
|
|
|
23
23
|
private routerData: PageRouterData[] = [];
|
|
24
24
|
private filter: PageRouterCallback | undefined;
|
|
25
25
|
private framePage: FramePageProps | undefined;
|
|
26
|
+
private subDir: string = '';
|
|
26
27
|
|
|
27
28
|
// if the filter returns null (passed filter), the router will continue.
|
|
28
29
|
// it works in the same way as in use method
|
|
@@ -30,6 +31,11 @@ export class PageRouter {
|
|
|
30
31
|
this.filter = filter;
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
// if the script is under a sub-dir (without last /), then findRoute needs to remove it from the url
|
|
35
|
+
setSubDir(subDir: string) {
|
|
36
|
+
this.subDir = subDir;
|
|
37
|
+
}
|
|
38
|
+
|
|
33
39
|
setFramePage(framePage: FramePageProps) {
|
|
34
40
|
this.framePage = framePage;
|
|
35
41
|
}
|
|
@@ -149,6 +155,9 @@ export class PageRouter {
|
|
|
149
155
|
}
|
|
150
156
|
|
|
151
157
|
async handleRoute(url: string, props: PageProps, renderPartPage: boolean): Promise<VNode<any> | null> {
|
|
158
|
+
if (url.startsWith(this.subDir)) {
|
|
159
|
+
url = url.substring(this.subDir.length);
|
|
160
|
+
}
|
|
152
161
|
let vNode = null;
|
|
153
162
|
if (this.filter) {
|
|
154
163
|
vNode = await this.callHandle(this.filter, url, props);
|
|
@@ -160,7 +169,7 @@ export class PageRouter {
|
|
|
160
169
|
if (vNode && this.framePage) {
|
|
161
170
|
const selector = '.' + this.framePage.placeholderClassname;
|
|
162
171
|
if (renderPartPage && isFrontEnd() && document.querySelector(selector)) {
|
|
163
|
-
await
|
|
172
|
+
await mountInnerComponent(selector, vNode);
|
|
164
173
|
return null;
|
|
165
174
|
} else {
|
|
166
175
|
return this.framePage.component(this.framePage.placeholderClassname, vNode);
|
|
@@ -25,7 +25,7 @@ function renderChildren(html: string[], children: any) {
|
|
|
25
25
|
renderChildren(html, item);
|
|
26
26
|
}
|
|
27
27
|
} else if (children.type && children.props) {
|
|
28
|
-
|
|
28
|
+
renderComponent(children.type, children.props);
|
|
29
29
|
html.push(...children.props._html);
|
|
30
30
|
children.props._html.length = 0;
|
|
31
31
|
} else {
|
|
@@ -137,11 +137,11 @@ function renderAttribute(type: any, props: any, jsxNodes: any) {
|
|
|
137
137
|
// }
|
|
138
138
|
|
|
139
139
|
// The result has only one element
|
|
140
|
-
export const
|
|
140
|
+
export const renderComponent = (type: any, props: any) => {
|
|
141
141
|
// logger.log("==================renderComponent", type);
|
|
142
142
|
if (Array.isArray(props)) {
|
|
143
143
|
const jsxNodes = { type: 'Fragment', props: { children: props } } as any;
|
|
144
|
-
|
|
144
|
+
renderComponent(jsxNodes.type, jsxNodes.props);
|
|
145
145
|
return;
|
|
146
146
|
}
|
|
147
147
|
|
|
@@ -159,7 +159,7 @@ export const renderComponents = (type: any, props: any) => {
|
|
|
159
159
|
// }
|
|
160
160
|
// logger.log('==========props._result', props._result);
|
|
161
161
|
if (typeof props._result.type === 'function') {
|
|
162
|
-
|
|
162
|
+
renderComponent(props._result.type, props._result.props);
|
|
163
163
|
if (props._result.props._html) {
|
|
164
164
|
props._html.push(...props._result.props._html);
|
|
165
165
|
props._result.props._html.length = 0;
|
|
@@ -5,6 +5,14 @@ export const replaceInnerhtml = async (el: Element, newHtml: string) => {
|
|
|
5
5
|
firstDom.parentNode?.removeChild(firstDom);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
|
+
await callUnload(el);
|
|
9
|
+
el.innerHTML = newHtml;
|
|
10
|
+
|
|
11
|
+
if (firstDom && firstDom.tagName === 'STYLE') {
|
|
12
|
+
el.insertBefore(firstDom, el.firstChild);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
export const callUnload = async (el: Element) => {
|
|
8
16
|
const promises: Promise<void>[] = [];
|
|
9
17
|
el.querySelectorAll('[data-ref]').forEach((child: any) => {
|
|
10
18
|
if (child._lj && child._lj.onUnload) {
|
|
@@ -12,9 +20,4 @@ export const replaceInnerhtml = async (el: Element, newHtml: string) => {
|
|
|
12
20
|
}
|
|
13
21
|
});
|
|
14
22
|
await Promise.all(promises);
|
|
15
|
-
el.innerHTML = newHtml;
|
|
16
|
-
|
|
17
|
-
if (firstDom && firstDom.tagName === 'STYLE') {
|
|
18
|
-
el.insertBefore(firstDom, el.firstChild);
|
|
19
|
-
}
|
|
20
23
|
};
|
package/src/jsx.ts
CHANGED
|
@@ -25,7 +25,8 @@ export type RefProps = {
|
|
|
25
25
|
onUnload?: (el: Element) => Promise<void>;
|
|
26
26
|
$?: any; // (selector: string) => undefined | Element,
|
|
27
27
|
$all?: any; // (selector: string) => undefined | Element,
|
|
28
|
-
|
|
28
|
+
mountInnerComponent?: (content: string | VNode<any>) => Promise<void>;
|
|
29
|
+
mountOuterComponent?: (content: VNode<any>) => Promise<void>;
|
|
29
30
|
};
|
|
30
31
|
|
|
31
32
|
export interface ClassAttributes<T> extends Attributes {
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { RefProps } from '../jsx';
|
|
2
|
-
import { mountComponents } from './mount-components';
|
|
3
|
-
|
|
4
|
-
export class ComponentFactory {
|
|
5
|
-
private static _session: Map<Function, { [key: string]: any }> = new Map<Function, { [key: string]: any }>();
|
|
6
|
-
|
|
7
|
-
static getSession(fn: Function) {
|
|
8
|
-
let ret = this._session.get(fn);
|
|
9
|
-
if (!ret) {
|
|
10
|
-
ret = {};
|
|
11
|
-
this._session.set(fn, ret);
|
|
12
|
-
}
|
|
13
|
-
return ret;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
static async refresh(fn: Function, props: any, ref: RefProps) {
|
|
17
|
-
mountComponents(ref.current!, await fn(props));
|
|
18
|
-
}
|
|
19
|
-
}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { bindAttributes } from './bind-attributes';
|
|
2
|
-
import { bindLinks } from './bind-links';
|
|
3
|
-
import { VNode } from '../jsx';
|
|
4
|
-
// import { Logger } from '../lib/logger';
|
|
5
|
-
// import { bindPageResetEvent } from './page-reset-events';
|
|
6
|
-
import { replaceInnerhtml } from './replace-innerhtml';
|
|
7
|
-
import { renderComponents } from './render-components';
|
|
8
|
-
|
|
9
|
-
// const logger = new Logger('mount-components');
|
|
10
|
-
export const mountComponents = async (selector: string | null | Element, jsxNodes: VNode<any>) => {
|
|
11
|
-
renderComponents(jsxNodes.type, jsxNodes.props);
|
|
12
|
-
const el = selector && (typeof selector === 'string' ? document.querySelector(selector) : selector);
|
|
13
|
-
if (el) {
|
|
14
|
-
// call unload before releace innerHTML
|
|
15
|
-
await replaceInnerhtml(el, jsxNodes.props._html.join(''));
|
|
16
|
-
|
|
17
|
-
bindAttributes(el, jsxNodes.type, jsxNodes.props);
|
|
18
|
-
bindLinks(el);
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
// // suggest to use HtmlVar.
|
|
23
|
-
// export const mountSelfComponents = async (selector: string | null | Element, jsxNodes: VNode<any>) => {
|
|
24
|
-
// renderComponents(jsxNodes.type, jsxNodes.props);
|
|
25
|
-
// let el = selector && (typeof selector === 'string' ? document.querySelector(selector) : selector);
|
|
26
|
-
// if (el) {
|
|
27
|
-
// const parentNode = el.parentElement;
|
|
28
|
-
// // Can't do outerHTML directly because it will lose attributes
|
|
29
|
-
// const template = document.createElement('template');
|
|
30
|
-
// // template.innerHTML = jsxNodes.props._html.join("");
|
|
31
|
-
// // call unload before releace innerHTML
|
|
32
|
-
// await replaceInnerhtml(template, jsxNodes.props._html.join(''));
|
|
33
|
-
|
|
34
|
-
// // renderComponent should only have one element
|
|
35
|
-
// template.content.children.length > 1 &&
|
|
36
|
-
// console.error('renderComponent should only have one element: ', template.content.children.length);
|
|
37
|
-
// el.replaceWith(template.content.firstChild as Element);
|
|
38
|
-
// el = parentNode as Element;
|
|
39
|
-
// bindAttributes(el, jsxNodes.type, jsxNodes.props);
|
|
40
|
-
// bindLinks(el);
|
|
41
|
-
// }
|
|
42
|
-
// };
|