Add data binding enrichment

This commit is contained in:
Andrew Kingston 2020-11-19 09:24:58 +00:00
parent 3a5daa8ab1
commit 0ff8a9a67b
3 changed files with 53 additions and 5 deletions

View File

@ -1,10 +1,15 @@
<script> <script>
import { getContext } from "svelte"
import * as ComponentLibrary from "@budibase/standard-components" import * as ComponentLibrary from "@budibase/standard-components"
import Router from "./Router.svelte" import Router from "./Router.svelte"
import renderMustacheString from "../utils/renderMustacheString"
const dataProviderStore = getContext("data")
export let definition = {} export let definition = {}
$: componentProps = extractValidProps(definition) $: contextRow = dataProviderStore ? $dataProviderStore.row : undefined
$: componentProps = extractValidProps(definition, contextRow)
$: children = definition._children $: children = definition._children
$: componentName = extractComponentName(definition._component) $: componentName = extractComponentName(definition._component)
$: constructor = getComponentConstructor(componentName) $: constructor = getComponentConstructor(componentName)
@ -18,13 +23,20 @@
} }
// Extracts valid props to pass to the real svelte component // Extracts valid props to pass to the real svelte component
const extractValidProps = component => { const extractValidProps = (component, row) => {
let props = {} let props = {}
Object.entries(component) Object.entries(component)
.filter(([name]) => !name.startsWith("_")) .filter(([name]) => !name.startsWith("_"))
.forEach(([key, value]) => { .forEach(([key, value]) => {
props[key] = value props[key] = value
}) })
// Enrich props if we're in a data provider context
if (row !== undefined) {
Object.entries(props).forEach(([key, value]) => {
props[key] = renderMustacheString(value, { data: row })
})
}
return props return props
} }

View File

@ -0,0 +1,32 @@
import mustache from "mustache"
// this is a much more liberal version of mustache's escape function
// ...just ignoring < and > to prevent tags from user input
// original version here https://github.com/janl/mustache.js/blob/4b7908f5c9fec469a11cfaed2f2bed23c84e1c5c/mustache.js#L78
const entityMap = {
"<": "&lt;",
">": "&gt;",
}
mustache.escape = text => {
return text.replace(/[<>]/g, function fromEntityMap(s) {
return entityMap[s] || s
})
}
// Regex to test inputs with to see if they are likely candidates for mustache
const looksLikeMustache = /{{.*}}/
/**
* Enriches a given input with a row from the database.
*/
export default (input, context) => {
// Only accept string inputs
if (!input || typeof input !== "string") {
return input
}
// Do a fast regex check if this looks like a mustache string
if (!looksLikeMustache.test(input)) {
return input
}
return mustache.render(input, context)
}

View File

@ -2,14 +2,18 @@
import { setContext, onMount } from "svelte" import { setContext, onMount } from "svelte"
import { createDataProviderStore } from "./stores/dataProvider" import { createDataProviderStore } from "./stores/dataProvider"
export let row
const dataProviderStore = createDataProviderStore() const dataProviderStore = createDataProviderStore()
setContext("data", dataProviderStore) setContext("data", dataProviderStore)
export let row
let loaded = false
onMount(async () => { onMount(async () => {
await dataProviderStore.actions.setRow(row) await dataProviderStore.actions.setRow(row)
loaded = true
}) })
</script> </script>
<slot /> {#if loaded}
<slot />
{/if}