2020-02-03 10:24:25 +01:00
|
|
|
import { writable } from "svelte/store"
|
|
|
|
import { createCoreApi } from "./core"
|
|
|
|
import { getStateOrValue } from "./state/getState"
|
|
|
|
import { setState, setStateFromBinding } from "./state/setState"
|
|
|
|
import { trimSlash } from "./common/trimSlash"
|
|
|
|
import { isBound } from "./state/isState"
|
2020-02-14 12:51:45 +01:00
|
|
|
import { attachChildren } from "./render/attachChildren"
|
2020-02-03 10:24:25 +01:00
|
|
|
import { createTreeNode } from "./render/renderComponent"
|
2020-02-10 16:51:09 +01:00
|
|
|
import { screenRouter } from "./render/screenRouter"
|
2019-09-27 18:03:31 +02:00
|
|
|
|
2020-02-03 10:24:25 +01:00
|
|
|
export const createApp = (
|
|
|
|
document,
|
|
|
|
componentLibraries,
|
2020-02-10 22:35:51 +01:00
|
|
|
frontendDefinition,
|
|
|
|
backendDefinition,
|
2020-02-03 10:24:25 +01:00
|
|
|
user,
|
2020-02-12 13:45:24 +01:00
|
|
|
uiFunctions
|
2020-02-03 10:24:25 +01:00
|
|
|
) => {
|
2020-02-10 22:35:51 +01:00
|
|
|
const coreApi = createCoreApi(backendDefinition, user)
|
|
|
|
backendDefinition.hierarchy = coreApi.templateApi.constructHierarchy(
|
|
|
|
backendDefinition.hierarchy
|
2020-02-03 10:24:25 +01:00
|
|
|
)
|
2020-02-10 16:51:09 +01:00
|
|
|
const pageStore = writable({
|
2020-02-03 10:24:25 +01:00
|
|
|
_bbuser: user,
|
|
|
|
})
|
2019-09-19 05:35:40 +02:00
|
|
|
|
2020-02-03 10:24:25 +01:00
|
|
|
const relativeUrl = url =>
|
2020-02-10 22:35:51 +01:00
|
|
|
frontendDefinition.appRootPath
|
|
|
|
? frontendDefinition.appRootPath + "/" + trimSlash(url)
|
2020-02-03 10:24:25 +01:00
|
|
|
: url
|
2019-09-27 18:03:31 +02:00
|
|
|
|
2020-02-03 10:24:25 +01:00
|
|
|
const apiCall = method => (url, body) =>
|
|
|
|
fetch(relativeUrl(url), {
|
|
|
|
method: method,
|
|
|
|
headers: {
|
|
|
|
"Content-Type": "application/json",
|
|
|
|
},
|
|
|
|
body: body && JSON.stringify(body),
|
|
|
|
})
|
2019-09-29 07:40:06 +02:00
|
|
|
|
2020-02-03 10:24:25 +01:00
|
|
|
const api = {
|
|
|
|
post: apiCall("POST"),
|
|
|
|
get: apiCall("GET"),
|
|
|
|
patch: apiCall("PATCH"),
|
|
|
|
delete: apiCall("DELETE"),
|
|
|
|
}
|
2019-09-29 07:40:06 +02:00
|
|
|
|
2020-02-03 10:24:25 +01:00
|
|
|
const safeCallEvent = (event, context) => {
|
|
|
|
const isFunction = obj =>
|
|
|
|
!!(obj && obj.constructor && obj.call && obj.apply)
|
2019-09-29 07:40:06 +02:00
|
|
|
|
2020-02-03 10:24:25 +01:00
|
|
|
if (isFunction(event)) event(context)
|
|
|
|
}
|
2019-09-29 07:40:06 +02:00
|
|
|
|
2020-02-10 16:51:09 +01:00
|
|
|
let routeTo
|
|
|
|
let currentScreenStore
|
|
|
|
let currentScreenUbsubscribe
|
|
|
|
let currentUrl
|
2019-10-07 07:03:41 +02:00
|
|
|
|
2020-02-10 16:51:09 +01:00
|
|
|
const onScreenSlotRendered = screenSlotNode => {
|
|
|
|
const onScreenSelected = (screen, store, url) => {
|
2020-02-14 12:51:45 +01:00
|
|
|
const { getInitialiseParams, unsubscribe } = attachChildrenParams(store)
|
|
|
|
screenSlotNode.props._children = [screen.props]
|
|
|
|
const initialiseChildParams = getInitialiseParams(screenSlotNode)
|
|
|
|
attachChildren(initialiseChildParams)(screenSlotNode.rootElement, {
|
|
|
|
hydrate: true,
|
|
|
|
force: true,
|
|
|
|
})
|
2020-02-10 16:51:09 +01:00
|
|
|
if (currentScreenUbsubscribe) currentScreenUbsubscribe()
|
|
|
|
currentScreenUbsubscribe = unsubscribe
|
|
|
|
currentScreenStore = store
|
|
|
|
currentUrl = url
|
|
|
|
}
|
|
|
|
|
2020-02-12 13:45:24 +01:00
|
|
|
routeTo = screenRouter(frontendDefinition.screens, onScreenSelected)
|
2020-02-10 16:51:09 +01:00
|
|
|
routeTo(currentUrl || window.location.pathname)
|
|
|
|
}
|
|
|
|
|
2020-02-14 12:51:45 +01:00
|
|
|
const attachChildrenParams = store => {
|
2020-02-10 16:51:09 +01:00
|
|
|
let currentState = null
|
|
|
|
const unsubscribe = store.subscribe(s => {
|
|
|
|
currentState = s
|
|
|
|
})
|
|
|
|
|
2020-02-14 12:51:45 +01:00
|
|
|
const getInitialiseParams = treeNode => ({
|
2020-02-10 16:51:09 +01:00
|
|
|
bb: getBbClientApi,
|
|
|
|
coreApi,
|
|
|
|
store,
|
|
|
|
document,
|
|
|
|
componentLibraries,
|
2020-02-10 22:35:51 +01:00
|
|
|
frontendDefinition,
|
2020-02-10 16:51:09 +01:00
|
|
|
uiFunctions,
|
|
|
|
treeNode,
|
|
|
|
onScreenSlotRendered,
|
|
|
|
})
|
|
|
|
|
|
|
|
const getBbClientApi = (treeNode, componentProps) => {
|
|
|
|
return {
|
2020-02-14 12:51:45 +01:00
|
|
|
attachChildren: attachChildren(getInitialiseParams(treeNode)),
|
2020-02-10 16:51:09 +01:00
|
|
|
context: treeNode.context,
|
|
|
|
props: componentProps,
|
|
|
|
call: safeCallEvent,
|
|
|
|
setStateFromBinding: (binding, value) =>
|
|
|
|
setStateFromBinding(store, binding, value),
|
|
|
|
setState: (path, value) => setState(store, path, value),
|
|
|
|
getStateOrValue: (prop, currentContext) =>
|
|
|
|
getStateOrValue(currentState, prop, currentContext),
|
|
|
|
store,
|
|
|
|
relativeUrl,
|
|
|
|
api,
|
|
|
|
isBound,
|
|
|
|
parent,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return { getInitialiseParams, unsubscribe }
|
|
|
|
}
|
|
|
|
|
|
|
|
let rootTreeNode
|
|
|
|
|
|
|
|
const initialisePage = (page, target, urlPath) => {
|
|
|
|
currentUrl = urlPath
|
2019-09-19 05:35:40 +02:00
|
|
|
|
2020-02-10 16:51:09 +01:00
|
|
|
rootTreeNode = createTreeNode()
|
2020-02-14 12:51:45 +01:00
|
|
|
rootTreeNode.props = {
|
|
|
|
_children: [page.props],
|
|
|
|
}
|
|
|
|
rootTreeNode.rootElement = target
|
|
|
|
const { getInitialiseParams } = attachChildrenParams(pageStore)
|
|
|
|
const initChildParams = getInitialiseParams(rootTreeNode)
|
2020-02-10 16:51:09 +01:00
|
|
|
|
2020-02-14 12:51:45 +01:00
|
|
|
attachChildren(initChildParams)(target, {
|
|
|
|
hydrate: true,
|
|
|
|
force: true,
|
|
|
|
})
|
2020-02-10 16:51:09 +01:00
|
|
|
|
|
|
|
return rootTreeNode
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
initialisePage,
|
|
|
|
screenStore: () => currentScreenStore,
|
|
|
|
pageStore: () => pageStore,
|
|
|
|
routeTo: () => routeTo,
|
|
|
|
rootNode: () => rootTreeNode,
|
|
|
|
}
|
2019-09-19 05:35:40 +02:00
|
|
|
}
|