2020-05-07 15:30:04 +02:00
|
|
|
<script>
|
2020-08-25 11:20:39 +02:00
|
|
|
import { Icon } from "@budibase/bbui"
|
2020-08-26 09:11:16 +02:00
|
|
|
import Input from "./PropertyPanelControls/Input.svelte"
|
2020-08-14 15:56:34 +02:00
|
|
|
import { store, backendUiStore } from "builderStore"
|
|
|
|
import fetchBindableProperties from "builderStore/fetchBindableProperties"
|
2020-08-12 17:30:20 +02:00
|
|
|
import { DropdownMenu } from "@budibase/bbui"
|
|
|
|
import BindingDropdown from "components/userInterface/BindingDropdown.svelte"
|
2020-05-18 17:32:00 +02:00
|
|
|
import { onMount, getContext } from "svelte"
|
|
|
|
|
2020-05-07 15:30:04 +02:00
|
|
|
export let label = ""
|
|
|
|
export let control = null
|
2020-05-19 18:00:53 +02:00
|
|
|
export let key = ""
|
2020-05-21 15:28:32 +02:00
|
|
|
export let value
|
2020-05-07 15:30:04 +02:00
|
|
|
export let props = {}
|
|
|
|
export let onChange = () => {}
|
2020-08-14 15:56:34 +02:00
|
|
|
|
2020-08-25 11:20:39 +02:00
|
|
|
let temporaryBindableValue = value
|
|
|
|
|
|
|
|
function handleClose() {
|
|
|
|
handleChange(key, temporaryBindableValue)
|
|
|
|
}
|
|
|
|
|
2020-08-14 15:56:34 +02:00
|
|
|
let bindableProperties
|
|
|
|
|
2020-08-12 17:30:20 +02:00
|
|
|
let anchor
|
|
|
|
let dropdown
|
2020-05-19 18:00:53 +02:00
|
|
|
|
2020-08-14 15:56:34 +02:00
|
|
|
async function getBindableProperties() {
|
|
|
|
// Get all bindableProperties
|
|
|
|
bindableProperties = fetchBindableProperties({
|
|
|
|
componentInstanceId: $store.currentComponentInfo._id,
|
|
|
|
components: $store.components,
|
|
|
|
screen: $store.currentPreviewItem,
|
|
|
|
models: $backendUiStore.models,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-08-28 14:43:28 +02:00
|
|
|
const CAPTURE_VAR_INSIDE_MUSTACHE = /{{([^}]+)}}/g
|
2020-08-27 11:00:36 +02:00
|
|
|
async function replaceBindings(textWithBindings) {
|
2020-08-14 15:56:34 +02:00
|
|
|
getBindableProperties()
|
|
|
|
// Find all instances of mustasche
|
2020-08-27 11:00:36 +02:00
|
|
|
const boundValues = textWithBindings.match(CAPTURE_VAR_INSIDE_MUSTACHE)
|
2020-08-14 15:56:34 +02:00
|
|
|
|
|
|
|
// Replace with names:
|
2020-08-25 10:15:51 +02:00
|
|
|
boundValues &&
|
2020-08-27 11:00:36 +02:00
|
|
|
boundValues.forEach(boundValue => {
|
2020-08-25 10:15:51 +02:00
|
|
|
const binding = bindableProperties.find(({ readableBinding }) => {
|
2020-08-27 11:00:36 +02:00
|
|
|
return boundValue === `{{ ${readableBinding} }}`
|
2020-08-25 10:15:51 +02:00
|
|
|
})
|
|
|
|
if (binding) {
|
2020-08-27 11:00:36 +02:00
|
|
|
textWithBindings = textWithBindings.replace(
|
|
|
|
boundValue,
|
|
|
|
`{{ ${binding.runtimeBinding} }}`
|
|
|
|
)
|
2020-08-25 10:15:51 +02:00
|
|
|
}
|
2020-08-14 15:56:34 +02:00
|
|
|
})
|
2020-08-27 11:00:36 +02:00
|
|
|
onChange(key, textWithBindings)
|
2020-08-14 15:56:34 +02:00
|
|
|
}
|
|
|
|
|
2020-05-19 18:00:53 +02:00
|
|
|
function handleChange(key, v) {
|
2020-07-26 12:54:55 +02:00
|
|
|
let innerVal = v
|
|
|
|
if (typeof v === "object") {
|
|
|
|
if ("detail" in v) {
|
|
|
|
innerVal = v.detail
|
|
|
|
} else if ("target" in v) {
|
|
|
|
innerVal = props.valueKey ? v.target[props.valueKey] : v.target.value
|
|
|
|
}
|
2020-05-20 12:55:25 +02:00
|
|
|
}
|
2020-08-14 15:56:34 +02:00
|
|
|
replaceBindings(innerVal)
|
2020-05-19 18:00:53 +02:00
|
|
|
}
|
|
|
|
|
2020-05-25 16:23:56 +02:00
|
|
|
const safeValue = () => {
|
2020-08-14 15:56:34 +02:00
|
|
|
getBindableProperties()
|
|
|
|
let temp = value
|
2020-08-28 14:43:28 +02:00
|
|
|
const boundValues =
|
|
|
|
(typeof value === "string" && value.match(CAPTURE_VAR_INSIDE_MUSTACHE)) ||
|
|
|
|
[]
|
2020-08-14 15:56:34 +02:00
|
|
|
|
|
|
|
// Replace with names:
|
|
|
|
boundValues.forEach(v => {
|
2020-08-26 09:11:16 +02:00
|
|
|
const binding = bindableProperties.find(({ runtimeBinding }) => {
|
|
|
|
return v === `{{ ${runtimeBinding} }}`
|
|
|
|
})
|
|
|
|
if (binding) {
|
|
|
|
temp = temp.replace(v, `{{ ${binding.readableBinding} }}`)
|
2020-08-14 15:56:34 +02:00
|
|
|
}
|
|
|
|
})
|
|
|
|
// console.log(temp)
|
2020-05-25 16:23:56 +02:00
|
|
|
return value === undefined && props.defaultValue !== undefined
|
|
|
|
? props.defaultValue
|
2020-08-14 15:56:34 +02:00
|
|
|
: temp
|
2020-05-25 16:23:56 +02:00
|
|
|
}
|
|
|
|
|
2020-05-21 15:28:32 +02:00
|
|
|
//Incase the component has a different value key name
|
|
|
|
const handlevalueKey = value =>
|
2020-05-25 16:23:56 +02:00
|
|
|
props.valueKey ? { [props.valueKey]: safeValue() } : { value: safeValue() }
|
2020-05-07 15:30:04 +02:00
|
|
|
</script>
|
|
|
|
|
2020-08-14 15:56:34 +02:00
|
|
|
<div class="property-control" bind:this={anchor}>
|
2020-05-07 15:30:04 +02:00
|
|
|
<div class="label">{label}</div>
|
2020-08-05 16:18:28 +02:00
|
|
|
<div data-cy={`${key}-prop-control`} class="control">
|
2020-05-07 15:30:04 +02:00
|
|
|
<svelte:component
|
|
|
|
this={control}
|
2020-05-21 15:28:32 +02:00
|
|
|
{...handlevalueKey(value)}
|
2020-05-19 18:00:53 +02:00
|
|
|
on:change={val => handleChange(key, val)}
|
|
|
|
onChange={val => handleChange(key, val)}
|
2020-06-11 12:56:16 +02:00
|
|
|
{...props}
|
|
|
|
name={key} />
|
2020-05-07 15:30:04 +02:00
|
|
|
</div>
|
2020-08-25 11:20:39 +02:00
|
|
|
{#if control == Input}
|
2020-08-28 13:57:46 +02:00
|
|
|
<button data-cy={`${key}-binding-button`} on:click={dropdown.show}>
|
2020-08-25 11:20:39 +02:00
|
|
|
<Icon name="edit" />
|
|
|
|
</button>
|
|
|
|
{/if}
|
2020-05-07 15:30:04 +02:00
|
|
|
</div>
|
2020-08-25 11:20:39 +02:00
|
|
|
{#if control == Input}
|
|
|
|
<DropdownMenu
|
|
|
|
on:close={handleClose}
|
|
|
|
bind:this={dropdown}
|
|
|
|
{anchor}
|
|
|
|
align="right">
|
|
|
|
<BindingDropdown
|
|
|
|
{...handlevalueKey(value)}
|
2020-08-28 15:40:43 +02:00
|
|
|
close={dropdown.hide}
|
2020-08-25 11:20:39 +02:00
|
|
|
on:update={e => (temporaryBindableValue = e.detail)}
|
|
|
|
{bindableProperties} />
|
|
|
|
</DropdownMenu>
|
|
|
|
{/if}
|
2020-05-07 15:30:04 +02:00
|
|
|
|
|
|
|
<style>
|
|
|
|
.property-control {
|
2020-08-14 15:56:34 +02:00
|
|
|
position: relative;
|
2020-05-07 15:30:04 +02:00
|
|
|
display: flex;
|
2020-05-26 21:44:24 +02:00
|
|
|
flex-flow: row;
|
2020-08-05 15:19:56 +02:00
|
|
|
width: 260px;
|
2020-05-07 15:30:04 +02:00
|
|
|
margin: 8px 0px;
|
2020-05-26 21:44:24 +02:00
|
|
|
align-items: center;
|
2020-05-07 15:30:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.label {
|
2020-05-28 17:24:53 +02:00
|
|
|
display: flex;
|
|
|
|
align-items: center;
|
2020-05-07 15:30:04 +02:00
|
|
|
font-size: 12px;
|
2020-05-26 21:44:24 +02:00
|
|
|
font-weight: 400;
|
2020-08-05 15:19:56 +02:00
|
|
|
width: 100px;
|
2020-05-07 15:30:04 +02:00
|
|
|
text-align: left;
|
2020-05-26 21:44:24 +02:00
|
|
|
color: var(--ink);
|
|
|
|
margin-right: auto;
|
|
|
|
text-transform: capitalize;
|
2020-05-07 15:30:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
.control {
|
|
|
|
flex: 1;
|
2020-05-30 19:48:20 +02:00
|
|
|
display: flex;
|
2020-05-26 21:44:24 +02:00
|
|
|
padding-left: 2px;
|
|
|
|
max-width: 164px;
|
2020-05-07 15:30:04 +02:00
|
|
|
}
|
2020-08-14 15:56:34 +02:00
|
|
|
button {
|
|
|
|
position: absolute;
|
|
|
|
background: none;
|
|
|
|
border: none;
|
2020-08-25 11:20:39 +02:00
|
|
|
border-radius: 50%;
|
|
|
|
height: 24px;
|
|
|
|
width: 24px;
|
|
|
|
background: rgb(224, 224, 224);
|
|
|
|
right: 5px;
|
|
|
|
--spacing-s: 0;
|
2020-08-14 15:56:34 +02:00
|
|
|
}
|
2020-05-07 15:30:04 +02:00
|
|
|
</style>
|