client: providing access to component root elements

This commit is contained in:
Michael Shanks 2020-01-29 22:47:58 +00:00
parent 54202e6344
commit 7823be0592
5 changed files with 65 additions and 47 deletions

View File

@ -5,8 +5,9 @@ import { setState, setStateFromBinding } from "./state/setState";
import { trimSlash } from "./common/trimSlash"; import { trimSlash } from "./common/trimSlash";
import { isBound } from "./state/isState"; import { isBound } from "./state/isState";
import { _initialiseChildren } from "./render/initialiseChildren"; import { _initialiseChildren } from "./render/initialiseChildren";
import { createTreeNode } from "./render/renderComponent";
export const createApp = (componentLibraries, appDefinition, user, uiFunctions) => { export const createApp = (document, componentLibraries, appDefinition, user, uiFunctions) => {
const coreApi = createCoreApi(appDefinition, user); const coreApi = createCoreApi(appDefinition, user);
appDefinition.hierarchy = coreApi.templateApi.constructHierarchy(appDefinition.hierarchy); appDefinition.hierarchy = coreApi.templateApi.constructHierarchy(appDefinition.hierarchy);
@ -50,19 +51,19 @@ export const createApp = (componentLibraries, appDefinition, user, uiFunctions)
if(isFunction(event)) event(context); if(isFunction(event)) event(context);
} }
const initialiseChildrenParams = (hydrate, parentContext, childIndex) => ({ const initialiseChildrenParams = (hydrate, treeNode) => ({
bb, coreApi, store, parentContext, bb, coreApi, store, document,
componentLibraries, appDefinition, componentLibraries, appDefinition,
hydrate, uiFunctions, childIndex hydrate, uiFunctions, treeNode
}); });
const bb = (componentProps, componentContext, childIndex) => ({ const bb = (treeNode, componentProps) => ({
hydrateChildren: _initialiseChildren(initialiseChildrenParams(true, componentContext, childIndex)), hydrateChildren: _initialiseChildren(initialiseChildrenParams(true, treeNode)),
appendChildren: _initialiseChildren(initialiseChildrenParams(false, componentContext, childIndex)), appendChildren: _initialiseChildren(initialiseChildrenParams(false, treeNode)),
insertChildren: (props, htmlElement, anchor) => insertChildren: (props, htmlElement, anchor) =>
_initialiseChildren(initialiseChildrenParams(false, componentContext, childIndex)) _initialiseChildren(initialiseChildrenParams(false, treeNode))
(props, htmlElement, anchor), (props, htmlElement, anchor),
context: componentContext, context: treeNode.context,
props: componentProps, props: componentProps,
call:safeCallEvent, call:safeCallEvent,
setStateFromBinding: (binding, value) => setStateFromBinding(store, binding, value), setStateFromBinding: (binding, value) => setStateFromBinding(store, binding, value),
@ -76,6 +77,6 @@ export const createApp = (componentLibraries, appDefinition, user, uiFunctions)
parent parent
}); });
return bb(); return bb(createTreeNode());
} }

View File

@ -36,6 +36,7 @@ export const loadBudibase = async ({
} }
const app = createApp( const app = createApp(
window.document,
componentLibraries, componentLibraries,
appDefinition, appDefinition,
user, user,

View File

@ -12,10 +12,15 @@ export const _initialiseChildren = (initialiseOpts) =>
(childrenProps, htmlElement, anchor=null) => { (childrenProps, htmlElement, anchor=null) => {
const { uiFunctions, bb, coreApi, const { uiFunctions, bb, coreApi,
store, componentLibraries, childIndex, store, componentLibraries, treeNode,
appDefinition, parentContext, hydrate } = initialiseOpts; appDefinition, document, hydrate } = initialiseOpts;
const childComponents = []; for(let childNode of treeNode.children) {
if(childNode.unsubscribe)
childNode.unsubscribe();
if(childNode.component)
childNode.component.$destroy();
}
if(hydrate) { if(hydrate) {
while (htmlElement.firstChild) { while (htmlElement.firstChild) {
@ -23,7 +28,7 @@ export const _initialiseChildren = (initialiseOpts) =>
} }
} }
let childIndex = 0; const renderedComponents = [];
for(let childProps of childrenProps) { for(let childProps of childrenProps) {
const {componentName, libName} = splitName(childProps._component); const {componentName, libName} = splitName(childProps._component);
@ -34,25 +39,22 @@ export const _initialiseChildren = (initialiseOpts) =>
store, childProps, coreApi, store, childProps, coreApi,
appDefinition.appRootPath); appDefinition.appRootPath);
const componentConstructor = componentLibraries[libName][componentName]; const componentConstructor = componentLibraries[libName][componentName];
const {component, context, lastChildIndex} = renderComponent({ const renderedComponentsThisIteration = renderComponent({
props: childProps,
parentNode: treeNode,
componentConstructor,uiFunctions, componentConstructor,uiFunctions,
htmlElement, anchor, childIndex, htmlElement, anchor, initialProps,
parentContext, initialProps, bb}); bb, document});
childIndex = lastChildIndex; for(let comp of renderedComponentsThisIteration) {
comp.unsubscribe = bind(comp.component);
const unsubscribe = bind(component); renderedComponents.push(comp);
childComponents.push({ }
component,
context,
unsubscribe
});
} }
return childComponents; return renderedComponents;
} }
const splitName = fullname => { const splitName = fullname => {

View File

@ -1,34 +1,43 @@
export const renderComponent = ({ export const renderComponent = ({
componentConstructor, uiFunctions, componentConstructor, uiFunctions,
htmlElement, anchor, parentContext, htmlElement, anchor, props,
initialProps, bb, childIndex}) => { initialProps, bb, document,
parentNode}) => {
const func = initialProps._id const func = initialProps._id
? uiFunctions[componentProps._id] ? uiFunctions[initialProps._id]
: undefined; : undefined;
let component; const parentContext = (parentNode && parentNode.context) || {};
let componentContext;
let renderedNodes = [];
const render = (context) => { const render = (context) => {
let componentContext = parentContext;
if(context) { if(context) {
componentContext = {...componentContext}; componentContext = {...componentContext};
componentContext.$parent = parentContext; componentContext.$parent = parentContext;
} else {
componentContext = parentContext;
} }
initialProps._bb = bb(initialProps, componentContext); const thisNode = createTreeNode();
thisNode.context = componentContext;
thisNode.parentNode = parentNode;
component = new componentConstructor({ parentNode.children.push(thisNode);
renderedNodes.push(thisNode);
initialProps._bb = bb(thisNode, props);
thisNode.component = new componentConstructor({
target: htmlElement, target: htmlElement,
props: initialProps, props: initialProps,
hydrate:false, hydrate:false,
anchor anchor
}); });
childIndex += 1; thisNode.rootElement = htmlElement.children[
htmlElement.children.length - 1];
} }
if(func) { if(func) {
@ -37,10 +46,15 @@ export const renderComponent = ({
render(); render();
} }
return ({ return renderedNodes;
context: componentContext,
lastChildIndex: childIndex,
component
});
} }
export const createTreeNode = () => ({
context: {},
rootElement: null,
parentNode: null,
children: [],
component: null,
unsubscribe: () => {}
});

View File

@ -70,7 +70,7 @@ const maketestlib = (window) => ({
node.removeChild(c); node.removeChild(c);
} }
const components = currentProps._bb.appendChildren(currentProps._children, node); const components = currentProps._bb.appendChildren(currentProps._children, node);
childNodes = components.map(c => c._element); childNodes = components.map(c => c.component._element);
} else { } else {
currentProps._bb.hydrateChildren(currentProps._children, node); currentProps._bb.hydrateChildren(currentProps._children, node);
} }