lupine.web 1.0.29 → 1.0.30
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 +2 -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>;
|
|
@@ -160,7 +160,7 @@ export class PageRouter {
|
|
|
160
160
|
if (vNode && this.framePage) {
|
|
161
161
|
const selector = '.' + this.framePage.placeholderClassname;
|
|
162
162
|
if (renderPartPage && isFrontEnd() && document.querySelector(selector)) {
|
|
163
|
-
await
|
|
163
|
+
await mountInnerComponent(selector, vNode);
|
|
164
164
|
return null;
|
|
165
165
|
} else {
|
|
166
166
|
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
|
-
// };
|