refactor client library
This commit is contained in:
parent
7a3b368399
commit
e648dc80e8
28 changed files with 161 additions and 625 deletions
|
@ -155,7 +155,6 @@ const createScreen = store => (screenName, route, layoutComponentName) => {
|
||||||
description: "",
|
description: "",
|
||||||
url: "",
|
url: "",
|
||||||
_css: "",
|
_css: "",
|
||||||
uiFunctions: "",
|
|
||||||
props: createProps(rootComponent).props,
|
props: createProps(rootComponent).props,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +280,6 @@ const _savePage = async s => {
|
||||||
const page = s.pages[s.currentPageName]
|
const page = s.pages[s.currentPageName]
|
||||||
await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, {
|
await api.post(`/_builder/api/${s.appId}/pages/${s.currentPageName}`, {
|
||||||
page: { componentLibraries: s.pages.componentLibraries, ...page },
|
page: { componentLibraries: s.pages.componentLibraries, ...page },
|
||||||
uiFunctions: s.currentPageFunctions,
|
|
||||||
screens: page._screens,
|
screens: page._screens,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,8 +116,7 @@
|
||||||
stylesheetLinks,
|
stylesheetLinks,
|
||||||
selectedComponentType,
|
selectedComponentType,
|
||||||
selectedComponentId,
|
selectedComponentId,
|
||||||
frontendDefinition: JSON.stringify(frontendDefinition),
|
frontendDefinition: JSON.stringify(frontendDefinition)
|
||||||
currentPageFunctions: $store.currentPageFunctions,
|
|
||||||
})} />
|
})} />
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,7 +36,6 @@ export default ({
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
window["##BUDIBASE_FRONTEND_DEFINITION##"] = ${frontendDefinition};
|
window["##BUDIBASE_FRONTEND_DEFINITION##"] = ${frontendDefinition};
|
||||||
window["##BUDIBASE_FRONTEND_FUNCTIONS##"] = ${currentPageFunctions};
|
|
||||||
|
|
||||||
import('/_builder/budibase-client.esm.mjs')
|
import('/_builder/budibase-client.esm.mjs')
|
||||||
.then(module => {
|
.then(module => {
|
||||||
|
|
|
@ -32,6 +32,11 @@
|
||||||
type="number"
|
type="number"
|
||||||
class="budibase__input"
|
class="budibase__input"
|
||||||
bind:value={workflowBlock.args[parameter]} />
|
bind:value={workflowBlock.args[parameter]} />
|
||||||
|
{:else if type === 'longText'}
|
||||||
|
<textarea
|
||||||
|
type="text"
|
||||||
|
class="budibase__input"
|
||||||
|
bind:value={workflowBlock.args[parameter]} />
|
||||||
{:else if type === 'model'}
|
{:else if type === 'model'}
|
||||||
<select
|
<select
|
||||||
class="budibase__input"
|
class="budibase__input"
|
||||||
|
|
|
@ -66,8 +66,8 @@ const ACTION = {
|
||||||
params: {
|
params: {
|
||||||
to: "string",
|
to: "string",
|
||||||
from: "string",
|
from: "string",
|
||||||
subject: "string",
|
subject: "longText",
|
||||||
text: "string",
|
text: "longText",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
},
|
},
|
||||||
"_code": ""
|
"_code": ""
|
||||||
},
|
},
|
||||||
"_css": "",
|
"_css": ""
|
||||||
"uiFunctions": ""
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
},
|
},
|
||||||
"_code": ""
|
"_code": ""
|
||||||
},
|
},
|
||||||
"_css": "",
|
"_css": ""
|
||||||
"uiFunctions": ""
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,5 @@
|
||||||
},
|
},
|
||||||
"_code": ""
|
"_code": ""
|
||||||
},
|
},
|
||||||
"_css": "",
|
"_css": ""
|
||||||
"uiFunctions": ""
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
"deep-equal": "^2.0.1",
|
"deep-equal": "^2.0.1",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.15",
|
||||||
"lunr": "^2.3.5",
|
"lunr": "^2.3.5",
|
||||||
|
"mustache": "^4.0.1",
|
||||||
"regexparam": "^1.3.0",
|
"regexparam": "^1.3.0",
|
||||||
"shortid": "^2.2.8",
|
"shortid": "^2.2.8",
|
||||||
"svelte": "^3.9.2"
|
"svelte": "^3.9.2"
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import { loadRecord } from "./loadRecord"
|
|
||||||
import { listRecords } from "./listRecords"
|
|
||||||
import { authenticate } from "./authenticate"
|
import { authenticate } from "./authenticate"
|
||||||
import { saveRecord } from "./saveRecord"
|
|
||||||
import { triggerWorkflow } from "./workflow"
|
import { triggerWorkflow } from "./workflow"
|
||||||
|
|
||||||
export const createApi = ({ rootPath = "", setState, getState }) => {
|
export const createApi = ({ rootPath = "", setState, getState }) => {
|
||||||
|
@ -60,10 +57,7 @@ export const createApi = ({ rootPath = "", setState, getState }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
loadRecord: loadRecord(apiOpts),
|
|
||||||
listRecords: listRecords(apiOpts),
|
|
||||||
authenticate: authenticate(apiOpts),
|
authenticate: authenticate(apiOpts),
|
||||||
saveRecord: saveRecord(apiOpts),
|
|
||||||
triggerWorkflow: triggerWorkflow(apiOpts),
|
triggerWorkflow: triggerWorkflow(apiOpts),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { trimSlash } from "../common/trimSlash"
|
|
||||||
|
|
||||||
export const listRecords = api => async ({ indexKey, statePath }) => {
|
|
||||||
if (!indexKey) {
|
|
||||||
api.error("Load Record: record key not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statePath) {
|
|
||||||
api.error("Load Record: state path not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const records = await api.get({
|
|
||||||
url: `/api/listRecords/${trimSlash(indexKey)}`,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (api.isSuccess(records)) api.setState(statePath, records)
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
import { trimSlash } from "../common/trimSlash"
|
|
||||||
|
|
||||||
export const loadRecord = api => async ({ recordKey, statePath }) => {
|
|
||||||
if (!recordKey) {
|
|
||||||
api.error("Load Record: record key not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statePath) {
|
|
||||||
api.error("Load Record: state path not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const record = await api.get({
|
|
||||||
url: `/api/record/${trimSlash(recordKey)}`,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (api.isSuccess(record)) api.setState(statePath, record)
|
|
||||||
}
|
|
|
@ -1,29 +0,0 @@
|
||||||
import { trimSlash } from "../common/trimSlash"
|
|
||||||
|
|
||||||
export const saveRecord = api => async ({ statePath }) => {
|
|
||||||
if (!statePath) {
|
|
||||||
api.error("Load Record: state path not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const recordtoSave = api.getState(statePath)
|
|
||||||
|
|
||||||
if (!recordtoSave) {
|
|
||||||
api.error(`there is no record in state: ${statePath}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!recordtoSave.key) {
|
|
||||||
api.error(
|
|
||||||
`item in state does not appear to be a record - it has no key (${statePath})`
|
|
||||||
)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const savedRecord = await api.post({
|
|
||||||
url: `/api/record/${trimSlash(recordtoSave.key)}`,
|
|
||||||
body: recordtoSave,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (api.isSuccess(savedRecord)) api.setState(statePath, savedRecord)
|
|
||||||
}
|
|
|
@ -1,4 +1,5 @@
|
||||||
import get from "lodash/fp/get"
|
import get from "lodash/fp/get"
|
||||||
|
import mustache from "mustache";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The workflow orchestrator is a class responsible for executing workflows.
|
* The workflow orchestrator is a class responsible for executing workflows.
|
||||||
|
@ -41,23 +42,28 @@ export const clientStrategy = {
|
||||||
for (let arg in args) {
|
for (let arg in args) {
|
||||||
const argValue = args[arg]
|
const argValue = args[arg]
|
||||||
// Means that it's bound to state or workflow context
|
// Means that it's bound to state or workflow context
|
||||||
if (argValue.startsWith("$")) {
|
mappedArgs[arg] = mustache.render(argValue, {
|
||||||
// if value is bound to workflow context.
|
context: this.context,
|
||||||
if (argValue.startsWith("$context")) {
|
state: api.getState()
|
||||||
const path = argValue.replace("$context.", "")
|
});
|
||||||
// pass in the value from context
|
|
||||||
mappedArgs[arg] = get(path, this.context)
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the value is bound to state
|
|
||||||
if (argValue.startsWith("$state")) {
|
|
||||||
const path = argValue.replace("$state.", "")
|
|
||||||
// pass in the value from state
|
|
||||||
// TODO: not working
|
|
||||||
mappedArgs[arg] = api.getState(path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// if (argValue.startsWith("$")) {
|
||||||
|
// // if value is bound to workflow context.
|
||||||
|
// if (argValue.startsWith("$context")) {
|
||||||
|
// const path = argValue.replace("$context.", "")
|
||||||
|
// // pass in the value from context
|
||||||
|
// mappedArgs[arg] = get(path, this.context)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // if the value is bound to state
|
||||||
|
// if (argValue.startsWith("$state")) {
|
||||||
|
// const path = argValue.replace("$state.", "")
|
||||||
|
// // pass in the value from state
|
||||||
|
// // TODO: not working
|
||||||
|
// mappedArgs[arg] = api.getState(path)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
console.log(mappedArgs)
|
console.log(mappedArgs)
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,12 @@ import { createTreeNode } from "./render/prepareRenderComponent"
|
||||||
import { screenRouter } from "./render/screenRouter"
|
import { screenRouter } from "./render/screenRouter"
|
||||||
import { createStateManager } from "./state/stateManager"
|
import { createStateManager } from "./state/stateManager"
|
||||||
|
|
||||||
export const createApp = (
|
export const createApp = ({
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
user,
|
user,
|
||||||
uiFunctions,
|
|
||||||
window
|
window
|
||||||
) => {
|
}) => {
|
||||||
let routeTo
|
let routeTo
|
||||||
let currentUrl
|
let currentUrl
|
||||||
let screenStateManager
|
let screenStateManager
|
||||||
|
@ -21,7 +20,6 @@ export const createApp = (
|
||||||
store,
|
store,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered: () => {},
|
onScreenSlotRendered: () => {},
|
||||||
routeTo,
|
routeTo,
|
||||||
appRootPath: frontendDefinition.appRootPath,
|
appRootPath: frontendDefinition.appRootPath,
|
||||||
|
@ -53,7 +51,6 @@ export const createApp = (
|
||||||
const attachChildrenParams = stateManager => {
|
const attachChildrenParams = stateManager => {
|
||||||
const getInitialiseParams = treeNode => ({
|
const getInitialiseParams = treeNode => ({
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
treeNode,
|
treeNode,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
setupState: stateManager.setup,
|
setupState: stateManager.setup,
|
||||||
|
@ -68,7 +65,6 @@ export const createApp = (
|
||||||
store: writable({ _bbuser: user }),
|
store: writable({ _bbuser: user }),
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
appRootPath: frontendDefinition.appRootPath,
|
appRootPath: frontendDefinition.appRootPath,
|
||||||
// seems weird, but the routeTo variable may not be available at this point
|
// seems weird, but the routeTo variable may not be available at this point
|
||||||
|
|
|
@ -10,7 +10,6 @@ export const loadBudibase = async opts => {
|
||||||
// const _localStorage = (opts && opts.localStorage) || localStorage
|
// const _localStorage = (opts && opts.localStorage) || localStorage
|
||||||
|
|
||||||
const frontendDefinition = _window["##BUDIBASE_FRONTEND_DEFINITION##"]
|
const frontendDefinition = _window["##BUDIBASE_FRONTEND_DEFINITION##"]
|
||||||
const uiFunctions = _window["##BUDIBASE_FRONTEND_FUNCTIONS##"]
|
|
||||||
|
|
||||||
// TODO: update
|
// TODO: update
|
||||||
const user = {}
|
const user = {}
|
||||||
|
@ -36,14 +35,12 @@ export const loadBudibase = async opts => {
|
||||||
pageStore,
|
pageStore,
|
||||||
routeTo,
|
routeTo,
|
||||||
rootNode,
|
rootNode,
|
||||||
} = createApp(
|
} = createApp({
|
||||||
componentLibraryModules,
|
componentLibraries: componentLibraryModules,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
user,
|
user,
|
||||||
uiFunctions || {},
|
window
|
||||||
_window,
|
})
|
||||||
rootNode
|
|
||||||
)
|
|
||||||
|
|
||||||
const route = _window.location
|
const route = _window.location
|
||||||
? _window.location.pathname.replace(frontendDefinition.appRootPath, "")
|
? _window.location.pathname.replace(frontendDefinition.appRootPath, "")
|
||||||
|
|
|
@ -5,7 +5,6 @@ import deepEqual from "deep-equal"
|
||||||
|
|
||||||
export const attachChildren = initialiseOpts => (htmlElement, options) => {
|
export const attachChildren = initialiseOpts => (htmlElement, options) => {
|
||||||
const {
|
const {
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
treeNode,
|
treeNode,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
|
@ -31,8 +30,6 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// htmlElement.classList.add(`lay-${treeNode.props._id}`)
|
|
||||||
|
|
||||||
const childNodes = []
|
const childNodes = []
|
||||||
for (let childProps of treeNode.props._children) {
|
for (let childProps of treeNode.props._children) {
|
||||||
const { componentName, libName } = splitName(childProps._component)
|
const { componentName, libName } = splitName(childProps._component)
|
||||||
|
@ -45,7 +42,6 @@ export const attachChildren = initialiseOpts => (htmlElement, options) => {
|
||||||
props: childProps,
|
props: childProps,
|
||||||
parentNode: treeNode,
|
parentNode: treeNode,
|
||||||
ComponentConstructor,
|
ComponentConstructor,
|
||||||
uiFunctions,
|
|
||||||
htmlElement,
|
htmlElement,
|
||||||
anchor,
|
anchor,
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
|
|
|
@ -1,14 +1,11 @@
|
||||||
export const prepareRenderComponent = ({
|
export const prepareRenderComponent = ({
|
||||||
ComponentConstructor,
|
ComponentConstructor,
|
||||||
uiFunctions,
|
|
||||||
htmlElement,
|
htmlElement,
|
||||||
anchor,
|
anchor,
|
||||||
props,
|
props,
|
||||||
parentNode,
|
parentNode,
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
}) => {
|
}) => {
|
||||||
const func = props._id ? uiFunctions[props._id] : undefined
|
|
||||||
|
|
||||||
const parentContext = (parentNode && parentNode.context) || {}
|
const parentContext = (parentNode && parentNode.context) || {}
|
||||||
|
|
||||||
let nodesToRender = []
|
let nodesToRender = []
|
||||||
|
@ -42,13 +39,7 @@ export const prepareRenderComponent = ({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (func) {
|
createNodeAndRender()
|
||||||
const state = getCurrentState()
|
|
||||||
const routeParams = state["##routeParams"]
|
|
||||||
func(createNodeAndRender, parentContext, getCurrentState(), routeParams)
|
|
||||||
} else {
|
|
||||||
createNodeAndRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
return nodesToRender
|
return nodesToRender
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { getStateOrValue } from "./getState"
|
// import { getStateOrValue } from "./getState"
|
||||||
import { setState, setStateFromBinding } from "./setState"
|
import { setState, setStateFromBinding } from "./setState"
|
||||||
import { trimSlash } from "../common/trimSlash"
|
import { trimSlash } from "../common/trimSlash"
|
||||||
import { isBound } from "./parseBinding"
|
import { isBound } from "./parseBinding"
|
||||||
|
@ -10,7 +10,6 @@ export const bbFactory = ({
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
}) => {
|
}) => {
|
||||||
const relativeUrl = url => {
|
const relativeUrl = url => {
|
||||||
|
@ -41,17 +40,9 @@ export const bbFactory = ({
|
||||||
delete: apiCall("DELETE"),
|
delete: apiCall("DELETE"),
|
||||||
}
|
}
|
||||||
|
|
||||||
const safeCallEvent = (event, context) => {
|
|
||||||
const isFunction = obj =>
|
|
||||||
!!(obj && obj.constructor && obj.call && obj.apply)
|
|
||||||
|
|
||||||
if (isFunction(event)) event(context)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (treeNode, setupState) => {
|
return (treeNode, setupState) => {
|
||||||
const attachParams = {
|
const attachParams = {
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
treeNode,
|
treeNode,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
setupState,
|
setupState,
|
||||||
|
@ -62,12 +53,12 @@ export const bbFactory = ({
|
||||||
attachChildren: attachChildren(attachParams),
|
attachChildren: attachChildren(attachParams),
|
||||||
context: treeNode.context,
|
context: treeNode.context,
|
||||||
props: treeNode.props,
|
props: treeNode.props,
|
||||||
call: safeCallEvent,
|
call: (event, context) => event(context),
|
||||||
setStateFromBinding: (binding, value) =>
|
setStateFromBinding: (binding, value) =>
|
||||||
setStateFromBinding(store, binding, value),
|
setStateFromBinding(store, binding, value),
|
||||||
setState: (path, value) => setState(store, path, value),
|
setState: (path, value) => setState(store, path, value),
|
||||||
getStateOrValue: (prop, currentContext) =>
|
// getStateOrValue: (prop, currentContext) =>
|
||||||
getStateOrValue(getCurrentState(), prop, currentContext),
|
// getStateOrValue(getCurrentState(), prop, currentContext),
|
||||||
getContext: getContext(treeNode),
|
getContext: getContext(treeNode),
|
||||||
setContext: setContext(treeNode),
|
setContext: setContext(treeNode),
|
||||||
store: store,
|
store: store,
|
||||||
|
|
|
@ -1,71 +0,0 @@
|
||||||
import { ERROR } from "./standardState"
|
|
||||||
|
|
||||||
export const getNewChildRecordToState = (coreApi, setState) => ({
|
|
||||||
recordKey,
|
|
||||||
collectionName,
|
|
||||||
childRecordType,
|
|
||||||
statePath,
|
|
||||||
}) => {
|
|
||||||
const error = errorHandler(setState)
|
|
||||||
try {
|
|
||||||
if (!recordKey) {
|
|
||||||
error("getNewChild > recordKey not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!collectionName) {
|
|
||||||
error("getNewChild > collectionName not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!childRecordType) {
|
|
||||||
error("getNewChild > childRecordType not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statePath) {
|
|
||||||
error("getNewChild > statePath not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const rec = coreApi.recordApi.getNewChild(
|
|
||||||
recordKey,
|
|
||||||
collectionName,
|
|
||||||
childRecordType
|
|
||||||
)
|
|
||||||
setState(statePath, rec)
|
|
||||||
} catch (e) {
|
|
||||||
error(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getNewRecordToState = (coreApi, setState) => ({
|
|
||||||
collectionKey,
|
|
||||||
childRecordType,
|
|
||||||
statePath,
|
|
||||||
}) => {
|
|
||||||
const error = errorHandler(setState)
|
|
||||||
try {
|
|
||||||
if (!collectionKey) {
|
|
||||||
error("getNewChild > collectionKey not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!childRecordType) {
|
|
||||||
error("getNewChild > childRecordType not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!statePath) {
|
|
||||||
error("getNewChild > statePath not set")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const rec = coreApi.recordApi.getNew(collectionKey, childRecordType)
|
|
||||||
setState(statePath, rec)
|
|
||||||
} catch (e) {
|
|
||||||
error(e.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const errorHandler = setState => message => setState("##error_message", message)
|
|
|
@ -22,7 +22,7 @@ export const eventHandlers = (store, rootPath, routeTo) => {
|
||||||
const api = createApi({
|
const api = createApi({
|
||||||
rootPath,
|
rootPath,
|
||||||
setState: setStateWithStore,
|
setState: setStateWithStore,
|
||||||
getState: (path, fallback) => getState(currentState, path, fallback),
|
getState: (path, fallback) => getState(currentState, path, fallback)
|
||||||
})
|
})
|
||||||
|
|
||||||
const setStateHandler = ({ path, value }) => setState(store, path, value)
|
const setStateHandler = ({ path, value }) => setState(store, path, value)
|
||||||
|
|
|
@ -1,46 +1,49 @@
|
||||||
import { isUndefined, isObject } from "lodash/fp"
|
// import { isUndefined, isObject } from "lodash/fp"
|
||||||
import { parseBinding, isStoreBinding } from "./parseBinding"
|
import getOr from "lodash/fp/getOr";
|
||||||
|
// import { parseBinding, isStoreBinding } from "./parseBinding"
|
||||||
|
|
||||||
export const getState = (s, path, fallback) => {
|
export const getState = (state, path, fallback) => {
|
||||||
if (!s) return fallback
|
if (!state) return fallback
|
||||||
if (!path || path.length === 0) return fallback
|
if (!path || path.length === 0) return fallback
|
||||||
|
|
||||||
if (path === "$") return s
|
return getOr(fallback, path, state);
|
||||||
|
|
||||||
const pathParts = path.split(".")
|
// if (path === "$") return state
|
||||||
const safeGetPath = (obj, currentPartIndex = 0) => {
|
|
||||||
const currentKey = pathParts[currentPartIndex]
|
|
||||||
|
|
||||||
if (pathParts.length - 1 == currentPartIndex) {
|
// const pathParts = path.split(".")
|
||||||
const value = obj[currentKey]
|
// const safeGetPath = (obj, currentPartIndex = 0) => {
|
||||||
if (isUndefined(value)) return fallback
|
// const currentKey = pathParts[currentPartIndex]
|
||||||
else return value
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
// if (pathParts.length - 1 == currentPartIndex) {
|
||||||
obj[currentKey] === null ||
|
// const value = obj[currentKey]
|
||||||
obj[currentKey] === undefined ||
|
// if (isUndefined(value)) return fallback
|
||||||
!isObject(obj[currentKey])
|
// else return value
|
||||||
) {
|
// }
|
||||||
return fallback
|
|
||||||
}
|
|
||||||
|
|
||||||
return safeGetPath(obj[currentKey], currentPartIndex + 1)
|
// if (
|
||||||
}
|
// obj[currentKey] === null ||
|
||||||
|
// obj[currentKey] === undefined ||
|
||||||
|
// !isObject(obj[currentKey])
|
||||||
|
// ) {
|
||||||
|
// return fallback
|
||||||
|
// }
|
||||||
|
|
||||||
return safeGetPath(s)
|
// return safeGetPath(obj[currentKey], currentPartIndex + 1)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return safeGetPath(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getStateOrValue = (globalState, prop, currentContext) => {
|
// export const getStateOrValue = (globalState, prop, currentContext) => {
|
||||||
if (!prop) return prop
|
// if (!prop) return prop
|
||||||
|
|
||||||
const binding = parseBinding(prop)
|
// const binding = parseBinding(prop)
|
||||||
|
|
||||||
if (binding) {
|
// if (binding) {
|
||||||
const stateToUse = isStoreBinding(binding) ? globalState : currentContext
|
// const stateToUse = isStoreBinding(binding) ? globalState : currentContext
|
||||||
|
|
||||||
return getState(stateToUse, binding.path, binding.fallback)
|
// return getState(stateToUse, binding.path, binding.fallback)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return prop
|
// return prop
|
||||||
}
|
// }
|
||||||
|
|
|
@ -36,7 +36,7 @@ export const parseBinding = prop => {
|
||||||
export const isStoreBinding = binding => binding && binding.source === "store"
|
export const isStoreBinding = binding => binding && binding.source === "store"
|
||||||
export const isContextBinding = binding =>
|
export const isContextBinding = binding =>
|
||||||
binding && binding.source === "context"
|
binding && binding.source === "context"
|
||||||
export const isEventBinding = binding => binding && binding.source === "event"
|
// export const isEventBinding = binding => binding && binding.source === "event"
|
||||||
|
|
||||||
const hasBindingObject = prop =>
|
const hasBindingObject = prop =>
|
||||||
typeof prop === "object" && prop[BB_STATE_BINDINGPATH] !== undefined
|
typeof prop === "object" && prop[BB_STATE_BINDINGPATH] !== undefined
|
||||||
|
|
|
@ -1,32 +1,34 @@
|
||||||
import { isObject } from "lodash/fp"
|
// import isObject from "lodash/fp/isObject"
|
||||||
|
import set from "lodash/fp/set";
|
||||||
import { parseBinding } from "./parseBinding"
|
import { parseBinding } from "./parseBinding"
|
||||||
|
|
||||||
export const setState = (store, path, value) => {
|
export const setState = (store, path, value) => {
|
||||||
if (!path || path.length === 0) return
|
if (!path || path.length === 0) return
|
||||||
|
|
||||||
const pathParts = path.split(".")
|
// const pathParts = path.split(".")
|
||||||
|
|
||||||
const safeSetPath = (state, currentPartIndex = 0) => {
|
// const safeSetPath = (state, currentPartIndex = 0) => {
|
||||||
const currentKey = pathParts[currentPartIndex]
|
// const currentKey = pathParts[currentPartIndex]
|
||||||
|
|
||||||
if (pathParts.length - 1 == currentPartIndex) {
|
// if (pathParts.length - 1 == currentPartIndex) {
|
||||||
state[currentKey] = value
|
// state[currentKey] = value
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (
|
// if (
|
||||||
state[currentKey] === null ||
|
// state[currentKey] === null ||
|
||||||
state[currentKey] === undefined ||
|
// state[currentKey] === undefined ||
|
||||||
!isObject(state[currentKey])
|
// !isObject(state[currentKey])
|
||||||
) {
|
// ) {
|
||||||
state[currentKey] = {}
|
// state[currentKey] = {}
|
||||||
}
|
// }
|
||||||
|
|
||||||
safeSetPath(state[currentKey], currentPartIndex + 1)
|
// safeSetPath(state[currentKey], currentPartIndex + 1)
|
||||||
}
|
// }
|
||||||
|
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
safeSetPath(state)
|
// safeSetPath(state)
|
||||||
|
state = set(path, value, state);
|
||||||
return state
|
return state
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import {
|
||||||
import { bbFactory } from "./bbComponentApi"
|
import { bbFactory } from "./bbComponentApi"
|
||||||
import { getState } from "./getState"
|
import { getState } from "./getState"
|
||||||
import { attachChildren } from "../render/attachChildren"
|
import { attachChildren } from "../render/attachChildren"
|
||||||
|
import mustache from "mustache"
|
||||||
|
|
||||||
import { parseBinding } from "./parseBinding"
|
import { parseBinding } from "./parseBinding"
|
||||||
|
|
||||||
|
@ -18,14 +19,14 @@ const isMetaProp = propName =>
|
||||||
propName === "_id" ||
|
propName === "_id" ||
|
||||||
propName === "_style" ||
|
propName === "_style" ||
|
||||||
propName === "_code" ||
|
propName === "_code" ||
|
||||||
propName === "_codeMeta"
|
propName === "_codeMeta" ||
|
||||||
|
propName === "_styles"
|
||||||
|
|
||||||
export const createStateManager = ({
|
export const createStateManager = ({
|
||||||
store,
|
store,
|
||||||
appRootPath,
|
appRootPath,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
routeTo,
|
routeTo,
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -48,7 +49,6 @@ export const createStateManager = ({
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
frontendDefinition,
|
frontendDefinition,
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -60,7 +60,6 @@ export const createStateManager = ({
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
nodesWithCodeBoundChildren,
|
nodesWithCodeBoundChildren,
|
||||||
nodesBoundByProps,
|
nodesBoundByProps,
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
setupState: setup,
|
setupState: setup,
|
||||||
|
@ -79,13 +78,12 @@ const onStoreStateUpdated = ({
|
||||||
setCurrentState,
|
setCurrentState,
|
||||||
getCurrentState,
|
getCurrentState,
|
||||||
nodesWithCodeBoundChildren,
|
nodesWithCodeBoundChildren,
|
||||||
nodesBoundByProps,
|
// nodesBoundByProps,
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
setupState,
|
setupState,
|
||||||
}) => s => {
|
}) => state => {
|
||||||
setCurrentState(s)
|
setCurrentState(state)
|
||||||
|
|
||||||
// the original array gets changed by components' destroy()
|
// the original array gets changed by components' destroy()
|
||||||
// so we make a clone and check if they are still in the original
|
// so we make a clone and check if they are still in the original
|
||||||
|
@ -93,7 +91,6 @@ const onStoreStateUpdated = ({
|
||||||
for (let node of nodesWithBoundChildren_clone) {
|
for (let node of nodesWithBoundChildren_clone) {
|
||||||
if (!nodesWithCodeBoundChildren.includes(node)) continue
|
if (!nodesWithCodeBoundChildren.includes(node)) continue
|
||||||
attachChildren({
|
attachChildren({
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
componentLibraries,
|
||||||
treeNode: node,
|
treeNode: node,
|
||||||
onScreenSlotRendered,
|
onScreenSlotRendered,
|
||||||
|
@ -102,9 +99,9 @@ const onStoreStateUpdated = ({
|
||||||
})(node.rootElement, { hydrate: true, force: true })
|
})(node.rootElement, { hydrate: true, force: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let node of nodesBoundByProps) {
|
// for (let node of nodesBoundByProps) {
|
||||||
setNodeState(s, node)
|
// setNodeState(state, node)
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
const _registerBindings = (nodesBoundByProps, nodesWithCodeBoundChildren) => (
|
const _registerBindings = (nodesBoundByProps, nodesWithCodeBoundChildren) => (
|
||||||
|
@ -172,29 +169,36 @@ const _setup = (
|
||||||
|
|
||||||
const propValue = props[propName]
|
const propValue = props[propName]
|
||||||
|
|
||||||
const binding = parseBinding(propValue)
|
// const binding = parseBinding(propValue)
|
||||||
const isBound = !!binding
|
// const isBound = !!binding
|
||||||
|
|
||||||
if (isBound) binding.propName = propName
|
if (typeof propValue === "string") {
|
||||||
|
initialProps[propName] = mustache.render(propValue, {
|
||||||
if (isBound && binding.source === "state") {
|
state: currentStoreState,
|
||||||
storeBoundProps.push(binding)
|
context
|
||||||
|
})
|
||||||
initialProps[propName] = !currentStoreState
|
|
||||||
? binding.fallback
|
|
||||||
: getState(
|
|
||||||
currentStoreState,
|
|
||||||
binding.path,
|
|
||||||
binding.fallback,
|
|
||||||
binding.source
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isBound && binding.source === "context") {
|
// if (isBound) binding.propName = propName
|
||||||
initialProps[propName] = !context
|
|
||||||
? propValue
|
// if (isBound && binding.source === "state") {
|
||||||
: getState(context, binding.path, binding.fallback, binding.source)
|
// storeBoundProps.push(binding)
|
||||||
}
|
|
||||||
|
// initialProps[propName] = !currentStoreState
|
||||||
|
// ? binding.fallback
|
||||||
|
// : getState(
|
||||||
|
// currentStoreState,
|
||||||
|
// binding.path,
|
||||||
|
// binding.fallback,
|
||||||
|
// binding.source
|
||||||
|
// )
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (isBound && binding.source === "context") {
|
||||||
|
// initialProps[propName] = !context
|
||||||
|
// ? propValue
|
||||||
|
// : getState(context, binding.path, binding.fallback, binding.source)
|
||||||
|
// }
|
||||||
|
|
||||||
if (isEventType(propValue)) {
|
if (isEventType(propValue)) {
|
||||||
const handlersInfos = []
|
const handlersInfos = []
|
||||||
|
@ -203,33 +207,38 @@ const _setup = (
|
||||||
handlerType: event[EVENT_TYPE_MEMBER_NAME],
|
handlerType: event[EVENT_TYPE_MEMBER_NAME],
|
||||||
parameters: event.parameters,
|
parameters: event.parameters,
|
||||||
}
|
}
|
||||||
|
|
||||||
const resolvedParams = {}
|
const resolvedParams = {}
|
||||||
for (let paramName in handlerInfo.parameters) {
|
for (let paramName in handlerInfo.parameters) {
|
||||||
const paramValue = handlerInfo.parameters[paramName]
|
const paramValue = handlerInfo.parameters[paramName]
|
||||||
const paramBinding = parseBinding(paramValue)
|
resolvedParams[paramName] = () => mustache.render(paramValue, {
|
||||||
if (!paramBinding) {
|
state: getCurrentState(),
|
||||||
resolvedParams[paramName] = () => paramValue
|
context,
|
||||||
continue
|
})
|
||||||
}
|
// const paramBinding = parseBinding(paramValue)
|
||||||
|
// if (!paramBinding) {
|
||||||
|
// resolvedParams[paramName] = () => paramValue
|
||||||
|
// continue
|
||||||
|
// }
|
||||||
|
|
||||||
let paramValueSource
|
// let paramValueSource
|
||||||
|
|
||||||
if (paramBinding.source === "context") paramValueSource = context
|
// if (paramBinding.source === "context") paramValueSource = context
|
||||||
if (paramBinding.source === "state")
|
// if (paramBinding.source === "state")
|
||||||
paramValueSource = getCurrentState()
|
// paramValueSource = getCurrentState()
|
||||||
if (paramBinding.source === "context") paramValueSource = context
|
|
||||||
|
|
||||||
// The new dynamic event parameter bound to the relevant source
|
// // The new dynamic event parameter bound to the relevant source
|
||||||
resolvedParams[paramName] = () =>
|
// resolvedParams[paramName] = () =>
|
||||||
getState(paramValueSource, paramBinding.path, paramBinding.fallback)
|
// getState(paramValueSource, paramBinding.path, paramBinding.fallback)
|
||||||
}
|
}
|
||||||
|
|
||||||
handlerInfo.parameters = resolvedParams
|
handlerInfo.parameters = resolvedParams
|
||||||
handlersInfos.push(handlerInfo)
|
handlersInfos.push(handlerInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlersInfos.length === 0) initialProps[propName] = doNothing
|
if (handlersInfos.length === 0) {
|
||||||
else {
|
initialProps[propName] = doNothing
|
||||||
|
} else {
|
||||||
initialProps[propName] = async context => {
|
initialProps[propName] = async context => {
|
||||||
for (let handlerInfo of handlersInfos) {
|
for (let handlerInfo of handlersInfos) {
|
||||||
const handler = makeHandler(handlerTypes, handlerInfo)
|
const handler = makeHandler(handlerTypes, handlerInfo)
|
||||||
|
|
|
@ -1,283 +0,0 @@
|
||||||
import {
|
|
||||||
isEventType,
|
|
||||||
eventHandlers,
|
|
||||||
EVENT_TYPE_MEMBER_NAME,
|
|
||||||
} from "./eventHandlers"
|
|
||||||
import { bbFactory } from "./bbComponentApi"
|
|
||||||
import { getState } from "./getState"
|
|
||||||
import { attachChildren } from "../render/attachChildren"
|
|
||||||
|
|
||||||
import { parseBinding } from "./parseBinding"
|
|
||||||
|
|
||||||
const doNothing = () => {}
|
|
||||||
doNothing.isPlaceholder = true
|
|
||||||
|
|
||||||
const isMetaProp = propName =>
|
|
||||||
propName === "_component" ||
|
|
||||||
propName === "_children" ||
|
|
||||||
propName === "_id" ||
|
|
||||||
propName === "_style" ||
|
|
||||||
propName === "_code" ||
|
|
||||||
propName === "_codeMeta"
|
|
||||||
|
|
||||||
export const createStateManager = ({
|
|
||||||
store,
|
|
||||||
coreApi,
|
|
||||||
rootPath,
|
|
||||||
frontendDefinition,
|
|
||||||
componentLibraries,
|
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered,
|
|
||||||
routeTo,
|
|
||||||
}) => {
|
|
||||||
let handlerTypes = eventHandlers(store, coreApi, rootPath, routeTo)
|
|
||||||
let currentState
|
|
||||||
|
|
||||||
// any nodes that have props that are bound to the store
|
|
||||||
let nodesBoundByProps = []
|
|
||||||
|
|
||||||
// any node whose children depend on code, that uses the store
|
|
||||||
let nodesWithCodeBoundChildren = []
|
|
||||||
|
|
||||||
const getCurrentState = () => currentState
|
|
||||||
const registerBindings = _registerBindings(
|
|
||||||
nodesBoundByProps,
|
|
||||||
nodesWithCodeBoundChildren
|
|
||||||
)
|
|
||||||
const bb = bbFactory({
|
|
||||||
store,
|
|
||||||
getCurrentState,
|
|
||||||
frontendDefinition,
|
|
||||||
componentLibraries,
|
|
||||||
uiFunctions,
|
|
||||||
onScreenSlotRendered,
|
|
||||||
})
|
|
||||||
|
|
||||||
const setup = _setup(handlerTypes, getCurrentState, registerBindings, bb)
|
|
||||||
|
|
||||||
const unsubscribe = store.subscribe(
|
|
||||||
onStoreStateUpdated({
|
|
||||||
setCurrentState: s => (currentState = s),
|
|
||||||
getCurrentState,
|
|
||||||
nodesWithCodeBoundChildren,
|
|
||||||
nodesBoundByProps,
|
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
|
||||||
onScreenSlotRendered,
|
|
||||||
setupState: setup,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
return {
|
|
||||||
setup,
|
|
||||||
destroy: () => unsubscribe(),
|
|
||||||
getCurrentState,
|
|
||||||
store,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onStoreStateUpdated = ({
|
|
||||||
setCurrentState,
|
|
||||||
getCurrentState,
|
|
||||||
nodesWithCodeBoundChildren,
|
|
||||||
nodesBoundByProps,
|
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
|
||||||
onScreenSlotRendered,
|
|
||||||
setupState,
|
|
||||||
}) => s => {
|
|
||||||
setCurrentState(s)
|
|
||||||
|
|
||||||
// the original array gets changed by components' destroy()
|
|
||||||
// so we make a clone and check if they are still in the original
|
|
||||||
const nodesWithBoundChildren_clone = [...nodesWithCodeBoundChildren]
|
|
||||||
for (let node of nodesWithBoundChildren_clone) {
|
|
||||||
if (!nodesWithCodeBoundChildren.includes(node)) continue
|
|
||||||
attachChildren({
|
|
||||||
uiFunctions,
|
|
||||||
componentLibraries,
|
|
||||||
treeNode: node,
|
|
||||||
onScreenSlotRendered,
|
|
||||||
setupState,
|
|
||||||
getCurrentState,
|
|
||||||
})(node.rootElement, { hydrate: true, force: true })
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let node of nodesBoundByProps) {
|
|
||||||
setNodeState(s, node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _registerBindings = (nodesBoundByProps, nodesWithCodeBoundChildren) => (
|
|
||||||
node,
|
|
||||||
bindings
|
|
||||||
) => {
|
|
||||||
if (bindings.length > 0) {
|
|
||||||
node.bindings = bindings
|
|
||||||
nodesBoundByProps.push(node)
|
|
||||||
const onDestroy = () => {
|
|
||||||
nodesBoundByProps = nodesBoundByProps.filter(n => n === node)
|
|
||||||
node.onDestroy = node.onDestroy.filter(d => d === onDestroy)
|
|
||||||
}
|
|
||||||
node.onDestroy.push(onDestroy)
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
node.props._children &&
|
|
||||||
node.props._children.filter(c => c._codeMeta && c._codeMeta.dependsOnStore)
|
|
||||||
.length > 0
|
|
||||||
) {
|
|
||||||
nodesWithCodeBoundChildren.push(node)
|
|
||||||
const onDestroy = () => {
|
|
||||||
nodesWithCodeBoundChildren = nodesWithCodeBoundChildren.filter(
|
|
||||||
n => n === node
|
|
||||||
)
|
|
||||||
node.onDestroy = node.onDestroy.filter(d => d === onDestroy)
|
|
||||||
}
|
|
||||||
node.onDestroy.push(onDestroy)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const setNodeState = (storeState, node) => {
|
|
||||||
if (!node.component) return
|
|
||||||
const newProps = { ...node.bindings.initialProps }
|
|
||||||
|
|
||||||
for (let binding of node.bindings) {
|
|
||||||
const val = getState(storeState, binding.path, binding.fallback)
|
|
||||||
|
|
||||||
if (val === undefined && newProps[binding.propName] !== undefined) {
|
|
||||||
delete newProps[binding.propName]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (val !== undefined) {
|
|
||||||
newProps[binding.propName] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
node.component.$set(newProps)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bind a components event handler parameters to state, context or the event itself.
|
|
||||||
* @param {Array} eventHandlerProp - event handler array from component definition
|
|
||||||
*/
|
|
||||||
function bindComponentEventHandlers(
|
|
||||||
eventHandlerProp,
|
|
||||||
context,
|
|
||||||
getCurrentState
|
|
||||||
) {
|
|
||||||
const boundEventHandlers = []
|
|
||||||
for (let event of eventHandlerProp) {
|
|
||||||
const boundEventHandler = {
|
|
||||||
handlerType: event[EVENT_TYPE_MEMBER_NAME],
|
|
||||||
parameters: event.parameters,
|
|
||||||
}
|
|
||||||
|
|
||||||
const boundParameters = {}
|
|
||||||
for (let paramName in boundEventHandler.parameters) {
|
|
||||||
const paramValue = boundEventHandler.parameters[paramName]
|
|
||||||
const paramBinding = parseBinding(paramValue)
|
|
||||||
if (!paramBinding) {
|
|
||||||
boundParameters[paramName] = () => paramValue
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
let paramValueSource
|
|
||||||
|
|
||||||
if (paramBinding.source === "context") paramValueSource = context
|
|
||||||
if (paramBinding.source === "state") paramValueSource = getCurrentState()
|
|
||||||
|
|
||||||
// The new dynamic event parameter bound to the relevant source
|
|
||||||
boundParameters[paramName] = eventContext =>
|
|
||||||
getState(
|
|
||||||
paramBinding.source === "event" ? eventContext : paramValueSource,
|
|
||||||
paramBinding.path,
|
|
||||||
paramBinding.fallback
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
boundEventHandler.parameters = boundParameters
|
|
||||||
boundEventHandlers.push(boundEventHandlers)
|
|
||||||
|
|
||||||
return boundEventHandlers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const _setup = (
|
|
||||||
handlerTypes,
|
|
||||||
getCurrentState,
|
|
||||||
registerBindings,
|
|
||||||
bb
|
|
||||||
) => node => {
|
|
||||||
const props = node.props
|
|
||||||
const context = node.context || {}
|
|
||||||
const initialProps = { ...props }
|
|
||||||
const storeBoundProps = []
|
|
||||||
const currentStoreState = getCurrentState()
|
|
||||||
|
|
||||||
for (let propName in props) {
|
|
||||||
if (isMetaProp(propName)) continue
|
|
||||||
|
|
||||||
const propValue = props[propName]
|
|
||||||
|
|
||||||
const binding = parseBinding(propValue)
|
|
||||||
const isBound = !!binding
|
|
||||||
|
|
||||||
if (isBound) binding.propName = propName
|
|
||||||
|
|
||||||
if (isBound && binding.source === "state") {
|
|
||||||
storeBoundProps.push(binding)
|
|
||||||
|
|
||||||
initialProps[propName] = !currentStoreState
|
|
||||||
? binding.fallback
|
|
||||||
: getState(
|
|
||||||
currentStoreState,
|
|
||||||
binding.path,
|
|
||||||
binding.fallback,
|
|
||||||
binding.source
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isBound && binding.source === "context") {
|
|
||||||
initialProps[propName] = !context
|
|
||||||
? propValue
|
|
||||||
: getState(context, binding.path, binding.fallback, binding.source)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isEventType(propValue)) {
|
|
||||||
const boundEventHandlers = bindComponentEventHandlers(
|
|
||||||
propValue,
|
|
||||||
context,
|
|
||||||
getCurrentState
|
|
||||||
)
|
|
||||||
|
|
||||||
if (boundEventHandlers.length === 0) {
|
|
||||||
initialProps[propName] = doNothing
|
|
||||||
} else {
|
|
||||||
initialProps[propName] = async context => {
|
|
||||||
for (let handlerInfo of boundEventHandlers) {
|
|
||||||
const handler = makeHandler(handlerTypes, handlerInfo)
|
|
||||||
await handler(context)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerBindings(node, storeBoundProps)
|
|
||||||
|
|
||||||
const setup = _setup(handlerTypes, getCurrentState, registerBindings, bb)
|
|
||||||
initialProps._bb = bb(node, setup)
|
|
||||||
|
|
||||||
return initialProps
|
|
||||||
}
|
|
||||||
|
|
||||||
const makeHandler = (handlerTypes, handlerInfo) => {
|
|
||||||
const handlerType = handlerTypes[handlerInfo.handlerType]
|
|
||||||
return context => {
|
|
||||||
const parameters = {}
|
|
||||||
for (let paramName in handlerInfo.parameters) {
|
|
||||||
parameters[paramName] = handlerInfo.parameters[paramName](context)
|
|
||||||
}
|
|
||||||
handlerType.execute(parameters)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -13,7 +13,7 @@ export const load = async (page, screens, url, appRootPath) => {
|
||||||
autoAssignIds(s.props)
|
autoAssignIds(s.props)
|
||||||
}
|
}
|
||||||
setAppDef(dom.window, page, screens)
|
setAppDef(dom.window, page, screens)
|
||||||
addWindowGlobals(dom.window, page, screens, appRootPath, uiFunctions, {
|
addWindowGlobals(dom.window, page, screens, appRootPath, {
|
||||||
hierarchy: {},
|
hierarchy: {},
|
||||||
actions: [],
|
actions: [],
|
||||||
triggers: [],
|
triggers: [],
|
||||||
|
@ -27,13 +27,12 @@ export const load = async (page, screens, url, appRootPath) => {
|
||||||
return { dom, app }
|
return { dom, app }
|
||||||
}
|
}
|
||||||
|
|
||||||
const addWindowGlobals = (window, page, screens, appRootPath, uiFunctions) => {
|
const addWindowGlobals = (window, page, screens, appRootPath) => {
|
||||||
window["##BUDIBASE_FRONTEND_DEFINITION##"] = {
|
window["##BUDIBASE_FRONTEND_DEFINITION##"] = {
|
||||||
page,
|
page,
|
||||||
screens,
|
screens,
|
||||||
appRootPath,
|
appRootPath,
|
||||||
}
|
}
|
||||||
window["##BUDIBASE_FRONTEND_FUNCTIONS##"] = uiFunctions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const makePage = props => ({ props })
|
export const makePage = props => ({ props })
|
||||||
|
@ -183,29 +182,4 @@ const maketestlib = window => ({
|
||||||
set(opts.props)
|
set(opts.props)
|
||||||
opts.target.appendChild(node)
|
opts.target.appendChild(node)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const uiFunctions = {
|
|
||||||
never_render: () => {},
|
|
||||||
|
|
||||||
always_render: render => {
|
|
||||||
render()
|
|
||||||
},
|
|
||||||
|
|
||||||
three_clones: render => {
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
render()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
with_context: render => {
|
|
||||||
render({ testKey: "test value" })
|
|
||||||
},
|
|
||||||
|
|
||||||
n_clones_based_on_store: (render, _, state) => {
|
|
||||||
const n = state.componentCount || 0
|
|
||||||
for (let i = 0; i < n; i++) {
|
|
||||||
render({ index: `index_${i}` })
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
|
@ -103,7 +103,6 @@ const buildFrontendAppDefinition = async (config, appId, pageName, pkg) => {
|
||||||
filename,
|
filename,
|
||||||
`
|
`
|
||||||
window['##BUDIBASE_FRONTEND_DEFINITION##'] = ${clientUiDefinition};
|
window['##BUDIBASE_FRONTEND_DEFINITION##'] = ${clientUiDefinition};
|
||||||
window['##BUDIBASE_FRONTEND_FUNCTIONS##'] = ${pkg.uiFunctions};
|
|
||||||
`
|
`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue