render function, with code blocks - tested simple cases

This commit is contained in:
Michael Shanks 2020-01-26 22:56:36 +00:00
parent 80514d07bc
commit 9a857dcd77
6 changed files with 147 additions and 20 deletions

View File

@ -6,8 +6,7 @@ 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";
export const createApp = (componentLibraries, appDefinition, user) => { export const createApp = (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);
@ -40,7 +39,7 @@ export const createApp = (componentLibraries, appDefinition, user) => {
post: apiCall("POST"), post: apiCall("POST"),
get: apiCall("GET"), get: apiCall("GET"),
patch: apiCall("PATCH"), patch: apiCall("PATCH"),
delete:apiCall("DELETE") delete: apiCall("DELETE")
}; };
const safeCallEvent = (event, context) => { const safeCallEvent = (event, context) => {
@ -54,7 +53,7 @@ export const createApp = (componentLibraries, appDefinition, user) => {
const initialiseChildrenParams = (parentContext, hydrate) => ({ const initialiseChildrenParams = (parentContext, hydrate) => ({
bb, coreApi, store, bb, coreApi, store,
componentLibraries, appDefinition, componentLibraries, appDefinition,
parentContext, hydrate parentContext, hydrate, uiFunctions
}); });
const bb = (context, props) => ({ const bb = (context, props) => ({

View File

@ -1,7 +1,9 @@
import { createApp } from "./createApp"; import { createApp } from "./createApp";
import { trimSlash } from "./common/trimSlash"; import { trimSlash } from "./common/trimSlash";
export const loadBudibase = async ({componentLibraries, props, window, localStorage}) => { export const loadBudibase = async ({
componentLibraries, props,
window, localStorage, uiFunctions }) => {
const appDefinition = window["##BUDIBASE_APPDEFINITION##"]; const appDefinition = window["##BUDIBASE_APPDEFINITION##"];
@ -33,7 +35,7 @@ export const loadBudibase = async ({componentLibraries, props, window, localStor
props = appDefinition.props; props = appDefinition.props;
} }
const _app = createApp(componentLibraries, appDefinition, user); const _app = createApp(componentLibraries, appDefinition, user, uiFunctions);
_app.hydrateChildren( _app.hydrateChildren(
[props], [props],
window.document.body); window.document.body);

View File

@ -6,10 +6,15 @@ import {
last last
} from "lodash/fp"; } from "lodash/fp";
import { $ } from "../core/common"; import { $ } from "../core/common";
import { renderComponent } from "./renderComponent";
export const _initialiseChildren = ({ bb, coreApi, store, componentLibraries, appDefinition, parentContext, hydrate }) => export const _initialiseChildren = (initialiseOpts) =>
(childrenProps, htmlElement, context, anchor=null) => { (childrenProps, htmlElement, context, anchor=null) => {
const { uiFunctions, bb, coreApi,
store, componentLibraries,
appDefinition, parentContext, hydrate } = initialiseOpts;
const childComponents = []; const childComponents = [];
if(hydrate) { if(hydrate) {
@ -19,6 +24,7 @@ export const _initialiseChildren = ({ bb, coreApi, store, componentLibraries, ap
} }
for(let childProps of childrenProps) { for(let childProps of childrenProps) {
const {componentName, libName} = splitName(childProps._component); const {componentName, libName} = splitName(childProps._component);
if(!componentName || !libName) return; if(!componentName || !libName) return;
@ -27,18 +33,19 @@ export const _initialiseChildren = ({ bb, coreApi, store, componentLibraries, ap
store, childProps, coreApi, store, childProps, coreApi,
context || parentContext, appDefinition.appRootPath); context || parentContext, appDefinition.appRootPath);
/// here needs to go inside renderComponent ???
const componentProps = { const componentProps = {
...initialProps, ...initialProps,
_bb:bb(context || parentContext, childProps) _bb:bb(context || parentContext, childProps)
}; };
const component = new (componentLibraries[libName][componentName])({ const componentConstructor = componentLibraries[libName][componentName];
target: htmlElement,
props: componentProps, const {component} = renderComponent({
hydrate:false, componentConstructor,uiFunctions,
anchor htmlElement, anchor,
}); parentContext, componentProps});
bind(component); bind(component);
childComponents.push(component); childComponents.push(component);

View File

@ -0,0 +1,38 @@
export const renderComponent = ({
componentConstructor, uiFunctions,
htmlElement, anchor, parentContext,
componentProps}) => {
const func = uiFunctions[componentProps._id];
let component;
let componentContext;
const render = (context) => {
if(context) {
componentContext = {...componentContext};
componentContext.$parent = parentContext;
} else {
componentContext = parentContext;
}
component = new componentConstructor({
target: htmlElement,
props: componentProps,
hydrate:false,
anchor
});
}
if(func) {
func(render, parentContext);
} else {
render();
}
return ({
context: componentContext,
component
});
}

View File

@ -0,0 +1,52 @@
import { load } from "./testAppDef";
describe("controlFlow", () => {
it("should display simple div, with always true render function", async () => {
const {dom} = await load({
_component: "testlib/div",
className: "my-test-class",
_id: "always_render"
});
expect(dom.window.document.body.children.length).toBe(1);
const child = dom.window.document.body.children[0];
expect(child.className).toBe("my-test-class");
})
it("should not display div, with always false render function", async () => {
const {dom} = await load({
_component: "testlib/div",
className: "my-test-class",
_id: "never_render"
});
expect(dom.window.document.body.children.length).toBe(0);
})
it("should display 3 divs in a looped render function", async () => {
const {dom} = await load({
_component: "testlib/div",
className: "my-test-class",
_id: "three_clones"
});
expect(dom.window.document.body.children.length).toBe(3);
const child0 = dom.window.document.body.children[0];
expect(child0.className).toBe("my-test-class");
const child1 = dom.window.document.body.children[1];
expect(child1.className).toBe("my-test-class");
const child2 = dom.window.document.body.children[2];
expect(child2.className).toBe("my-test-class");
})
});

View File

@ -3,16 +3,32 @@ import { loadBudibase } from "../src/index";
export const load = async (props) => { export const load = async (props) => {
const dom = new JSDOM(`<!DOCTYPE html><html><body></body><html>`); const dom = new JSDOM(`<!DOCTYPE html><html><body></body><html>`);
autoAssignIds(props);
setAppDef(dom.window, props); setAppDef(dom.window, props);
const app = await loadBudibase({ const app = await loadBudibase({
componentLibraries: allLibs(dom.window), componentLibraries: allLibs(dom.window),
window: dom.window, window: dom.window,
localStorage: createLocalStorage(), localStorage: createLocalStorage(),
props props,
uiFunctions
}); });
return {dom, app}; return {dom, app};
} }
// this happens for real by the builder...
// ..this only assigns _ids when missing
const autoAssignIds = (props, count=0) => {
if(!props._id) {
props._id = `auto_id_${count}`;
}
if(props._children) {
for(let child of props._children) {
count += 1;
autoAssignIds(child, count);
}
}
}
const setAppDef = (window, props) => { const setAppDef = (window, props) => {
window["##BUDIBASE_APPDEFINITION##"] = ({ window["##BUDIBASE_APPDEFINITION##"] = ({
componentLibraries: [], componentLibraries: [],
@ -87,5 +103,18 @@ const maketestlib = (window) => ({
} }
}); });
const uiFunctions = ({
never_render : (render, parentContext) => {},
always_render : (render, parentContext) => {
render();
},
three_clones : (render, parentContext) => {
for(let i = 0; i<3; i++) {
render();
}
}
});