1
0
Fork 0
mirror of synced 2024-07-16 11:45:47 +12:00
budibase/packages/builder/src/components/integration/QueryEditor.svelte

192 lines
3.9 KiB
Svelte
Raw Normal View History

2020-12-31 00:46:37 +13:00
<script>
2021-01-15 09:51:03 +13:00
import CodeMirror from "./codemirror"
import { Label } from "@budibase/bbui"
2020-12-31 00:46:37 +13:00
import { onMount, createEventDispatcher } from "svelte"
2021-01-15 09:51:03 +13:00
import { themeStore } from "builderStore"
2020-12-31 00:46:37 +13:00
const dispatch = createEventDispatcher()
2021-01-15 09:51:03 +13:00
const THEMES = {
DARK: "tomorrow-night-eighties",
LIGHT: "default",
}
2020-12-31 00:46:37 +13:00
2021-02-20 01:07:37 +13:00
export let label
2021-01-15 09:51:03 +13:00
export let value = ""
export let readOnly = false
export let lineNumbers = true
export let tab = true
export let mode
export let editorHeight = 500
2021-02-02 00:51:53 +13:00
// export let parameters = []
2021-01-15 09:51:03 +13:00
let width
let height
2020-12-31 00:46:37 +13:00
2021-01-15 09:51:03 +13:00
// We have to expose set and update methods, rather
// than making this state-driven through props,
// because it's difficult to update an editor
// without resetting scroll otherwise
export async function set(new_value, new_mode) {
if (new_mode !== mode) {
await createEditor((mode = new_mode))
2021-01-12 06:18:22 +13:00
}
2021-01-15 09:51:03 +13:00
value = new_value
updating_externally = true
if (editor) editor.setValue(value)
updating_externally = false
}
export function update(new_value) {
value = new_value
if (editor) {
const { left, top } = editor.getScrollInfo()
editor.setValue((value = new_value))
editor.scrollTo(left, top)
}
}
export function resize() {
editor.refresh()
}
export function focus() {
editor.focus()
}
const modes = {
js: {
name: "javascript",
json: false,
},
json: {
name: "javascript",
json: true,
},
sql: {
name: "sql",
},
svelte: {
name: "handlebars",
base: "text/html",
},
}
const refs = {}
let editor
let updating_externally = false
let destroyed = false
$: if (editor && width && height) {
editor.refresh()
2021-01-12 06:18:22 +13:00
}
2021-01-12 06:18:22 +13:00
onMount(() => {
2021-01-15 09:51:03 +13:00
createEditor(mode).then(() => {
if (editor) editor.setValue(value || "")
})
2021-01-15 09:51:03 +13:00
return () => {
destroyed = true
if (editor) editor.toTextArea()
}
})
let first = true
async function createEditor(mode) {
if (destroyed || !CodeMirror) return
if (editor) editor.toTextArea()
const opts = {
lineNumbers,
2020-12-31 00:46:37 +13:00
lineWrapping: true,
2021-01-15 09:51:03 +13:00
indentWithTabs: true,
2020-12-31 00:46:37 +13:00
indentUnit: 2,
tabSize: 2,
2021-01-15 09:51:03 +13:00
value: "",
mode: modes[mode] || {
name: mode,
},
2021-02-02 00:51:53 +13:00
2021-01-15 09:51:03 +13:00
readOnly,
2020-12-31 00:46:37 +13:00
autoCloseBrackets: true,
autoCloseTags: true,
2021-05-12 23:38:49 +12:00
theme: $themeStore.theme.includes("light") ? THEMES.LIGHT : THEMES.DARK,
2021-01-15 09:51:03 +13:00
}
if (!tab)
opts.extraKeys = {
Tab: tab,
"Shift-Tab": tab,
}
// Creating a text editor is a lot of work, so we yield
// the main thread for a moment. This helps reduce jank
if (first) await sleep(50)
if (destroyed) return
2021-05-11 01:50:37 +12:00
CodeMirror.commands.autocomplete = function (cm) {
2021-03-27 03:56:34 +13:00
CodeMirror.showHint(cm, CodeMirror.hint.javascript)
}
2021-01-15 09:51:03 +13:00
editor = CodeMirror.fromTextArea(refs.editor, opts)
2021-05-04 22:32:22 +12:00
editor.on("change", instance => {
2021-01-15 09:51:03 +13:00
if (!updating_externally) {
const value = instance.getValue()
dispatch("change", { value })
}
2020-12-31 00:46:37 +13:00
})
2021-01-12 06:18:22 +13:00
2021-02-02 00:51:53 +13:00
// editor.on("cursorActivity", function() {
// editor.showHint({
// hint: function() {
// return {
// from: editor.getDoc().getCursor(),
// to: editor.getDoc().getCursor(),
// list: completions,
// }
// },
// })
// })
2021-01-15 09:51:03 +13:00
if (first) await sleep(50)
editor.refresh()
2021-01-12 06:18:22 +13:00
2021-01-15 09:51:03 +13:00
first = false
}
function sleep(ms) {
2021-05-04 22:32:22 +12:00
return new Promise(fulfil => setTimeout(fulfil, ms))
2021-01-15 09:51:03 +13:00
}
2020-12-31 00:46:37 +13:00
</script>
{#if label}
<Label small>{label}</Label>
{/if}
<div style={`--code-mirror-height: ${editorHeight}px`}>
<textarea tabindex="0" bind:this={refs.editor} readonly {value} />
</div>
2021-01-08 02:13:46 +13:00
<style>
textarea {
2021-01-15 09:51:03 +13:00
visibility: hidden;
2021-01-08 02:13:46 +13:00
}
2021-01-15 09:51:03 +13:00
div {
margin-top: var(--spacing-s);
}
div :global(.CodeMirror) {
height: var(--code-mirror-height) !important;
border-radius: var(--border-radius-s);
font-family: monospace !important;
line-height: 1.3;
2021-01-09 07:22:03 +13:00
}
2021-01-08 02:13:46 +13:00
</style>