2020-12-31 00:46:37 +13:00
|
|
|
<script>
|
2021-01-15 09:51:03 +13:00
|
|
|
import CodeMirror from "./codemirror"
|
2021-04-29 01:54:35 +12:00
|
|
|
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
|
2021-02-19 06:44:56 +13:00
|
|
|
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 marker
|
|
|
|
let error_line
|
|
|
|
let destroyed = false
|
|
|
|
|
|
|
|
$: if (editor && width && height) {
|
|
|
|
editor.refresh()
|
2021-01-12 06:18:22 +13:00
|
|
|
}
|
2021-01-09 01:06:37 +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-09 01:06:37 +13:00
|
|
|
|
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-10 23:06:31 +12:00
|
|
|
theme: 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-10 23:06:31 +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>
|
|
|
|
|
2021-02-23 01:23:46 +13:00
|
|
|
{#if label}
|
|
|
|
<Label small>{label}</Label>
|
|
|
|
{/if}
|
2021-02-19 06:44:56 +13:00
|
|
|
<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
|
|
|
|
2021-04-29 01:54:35 +12:00
|
|
|
div {
|
|
|
|
margin-top: var(--spacing-s);
|
|
|
|
}
|
|
|
|
|
2021-02-19 06:44:56 +13:00
|
|
|
div :global(.CodeMirror) {
|
|
|
|
height: var(--code-mirror-height) !important;
|
2021-01-23 05:49:22 +13:00
|
|
|
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>
|