I'm experimenting with a text editor (just playing around with different ways to make one) and am using a svelte text area. One problem with this text area is that tab is not enabled by default. I was able to implement Ctrl+s quite easily but tab is more tricky.
The current method I'm using is to:
- Prevent default when there is a keydown on tab
- Set variables for the current cursor position, and a flag to indicate tab was pressed
- Manipulate the text area text using the substring method for strings to substring up to the selected area and after the selected area
- On subsequent keydown or keyup to reset my tab flag
This feels quite hacky to me so wanted to see if there was a more efficient way to do this.
Posting code here:
<script>
import { onMount } from 'svelte';
const endpoint = "http://localhost:5000/";
// State
let planner_text;
let textarea_elem;
let tab_selected = 0;
let tab = false;
// Load test.txt on mount
onMount(async () => {
const response = await fetch(endpoint);
const data = await response.json();
planner_text = data["text"];
});
// Save functionality
const update_planner = () => {
fetch(endpoint, {
method: "POST",
body: JSON.stringify({
data: planner_text
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
});
}
// Key down funcitonality
const keydown = e => {
tabset();
// save
if (e.ctrlKey && e.keyCode == 83) {
e.preventDefault();
update_planner();
} /* tab */ else if (e.keyCode == 9) {
e.preventDefault();
const {selectionStart, selectionEnd} = textarea_elem;
tab_selected = selectionStart + 1;
tab = true;
planner_text = planner_text.substring(0, selectionStart)
+ '\t' + planner_text.substring(selectionEnd)
textarea_elem.setSelectionRange(tab_selected, tab_selected)
}
}
const tabset = () => {
if (tab) {
textarea_elem.setSelectionRange(tab_selected, tab_selected)
tab = false;
}
};
</script>
<main>
<div class="container">
<textarea
class="scratch-pad"
bind:this={textarea_elem}
bind:value={planner_text}
on:keydown={keydown}
on:keyup={() => {tabset()}}/>
<button class="lock-in-btn" on:click={update_planner}>Lock in</button>
</div>
</main>