lupine.web 1.0.28 → 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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lupine.web",
3
- "version": "1.0.28",
3
+ "version": "1.0.30",
4
4
  "license": "MIT",
5
5
  "author": "uuware.com",
6
6
  "homepage": "https://github.com/uuware/lupine.js",
@@ -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
- const el = topEl.querySelector(`[${newProps._id}]`);
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') {
@@ -1,10 +1,9 @@
1
- // import { mountSelfComponents, renderComponent } from "./mount-components";
2
-
3
- import { VNode } from "../jsx";
4
- import { bindAttributes } from "./bind-attributes";
5
- import { bindLinks } from "./bind-links";
6
- import { renderComponents } from "./render-components";
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'].loadContent = async (content: string | VNode<any>) => {
38
+ newProps['ref'].mountInnerComponent = async (content: string | VNode<any>) => {
42
39
  if (typeof content === 'object' && content.type && content.props) {
43
- // await mountComponents(el, content);
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-components';
10
+ export * from './mount-component';
12
11
  export * from './page-loaded-events';
13
12
  export * from './page-router';
14
13
  export * from './replace-innerhtml';
@@ -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 { mountComponents } from './mount-components';
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 mountComponents(null, jsxNodes);
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 mountComponents('.lupine-root', jsxNodes);
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
+ };
@@ -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 { mountComponents } from './mount-components';
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 mountComponents(selector, vNode);
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
- renderComponents(children.type, children.props);
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 renderComponents = (type: any, props: any) => {
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
- renderComponents(jsxNodes.type, jsxNodes.props);
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
- renderComponents(props._result.type, props._result.props);
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
- loadContent?: (content: string | VNode<any>) => Promise<void>;
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,7 +1,8 @@
1
1
  let flag = 0;
2
2
  export const debugWatch = (port: number) => {
3
3
  console.log('Creating debug-watch socket');
4
- const socket = new WebSocket('ws://localhost:' + port + '/debug/client');
4
+ const protocol = location.protocol === "https:" ? "wss:" : "ws:";
5
+ const socket = new WebSocket(`${protocol}//${location.host}/debug/client`);
5
6
  window.addEventListener('beforeunload', () => {
6
7
  socket.close();
7
8
  });
@@ -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
- // };