sorry
This commit is contained in:
parent
b19c87b5d6
commit
c397cda8af
157
src/js/editor.ts
157
src/js/editor.ts
|
|
@ -5,16 +5,19 @@ import { focusInput } from "./focus.js"
|
||||||
const INDENT_SIZE = 2
|
const INDENT_SIZE = 2
|
||||||
|
|
||||||
export function initEditor() {
|
export function initEditor() {
|
||||||
document.addEventListener("input", adjustHeight)
|
document.addEventListener("input", handleAdjustHeight)
|
||||||
focusTextareaOnCreation()
|
focusTextareaOnCreation()
|
||||||
}
|
}
|
||||||
|
|
||||||
function adjustHeight(e: Event) {
|
function handleAdjustHeight(e: Event) {
|
||||||
const target = e.target as HTMLElement
|
const target = e.target as HTMLElement
|
||||||
if (target?.matches(".editor")) {
|
if (target?.matches(".editor"))
|
||||||
target.style.height = "auto"
|
adjustHeight(target as HTMLTextAreaElement)
|
||||||
target.style.height = target.scrollHeight + "px"
|
}
|
||||||
}
|
|
||||||
|
function adjustHeight(editor: HTMLTextAreaElement) {
|
||||||
|
editor.style.height = "auto"
|
||||||
|
editor.style.height = editor.scrollHeight + "px"
|
||||||
}
|
}
|
||||||
|
|
||||||
function focusTextareaOnCreation() {
|
function focusTextareaOnCreation() {
|
||||||
|
|
@ -33,25 +36,75 @@ function focusTextareaOnCreation() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function keydownHandler(e: KeyboardEvent) {
|
function keydownHandler(e: KeyboardEvent) {
|
||||||
const target = e.target as HTMLTextAreaElement
|
const editor = e.target as HTMLTextAreaElement
|
||||||
|
|
||||||
if (e.key === "Tab") {
|
if (e.key === "Tab") {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
if (e.shiftKey)
|
if (e.shiftKey)
|
||||||
removeTab(target)
|
removeTab(editor)
|
||||||
else
|
else
|
||||||
insertTab(target)
|
insertTab(editor)
|
||||||
} else if (e.ctrlKey && e.key === "c") {
|
} else if (e.ctrlKey && e.key === "c") {
|
||||||
focusInput()
|
focusInput()
|
||||||
} else if ((e.ctrlKey && e.key === "s") || (e.ctrlKey && e.key === "Enter")) {
|
} else if ((e.ctrlKey && e.key === "s") || (e.ctrlKey && e.key === "Enter")) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
send({
|
send({
|
||||||
id: target.dataset.path,
|
id: editor.dataset.path,
|
||||||
type: "save-file",
|
type: "save-file",
|
||||||
data: target.value
|
data: editor.value
|
||||||
})
|
})
|
||||||
|
} else if (e.key === "{") {
|
||||||
|
if (editor.selectionStart !== editor.selectionEnd) {
|
||||||
|
insertAroundSelection(editor, '{', '}')
|
||||||
|
e.preventDefault()
|
||||||
|
} else {
|
||||||
|
setTimeout(() => insertAfterCaret(editor, "}"), 0)
|
||||||
|
}
|
||||||
|
} else if (e.key === "}" && isNextChar(editor, '}')) {
|
||||||
|
moveOneRight(editor)
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
} else if (e.key === "[") {
|
||||||
|
if (editor.selectionStart !== editor.selectionEnd) {
|
||||||
|
insertAroundSelection(editor, '[', ']')
|
||||||
|
e.preventDefault()
|
||||||
|
} else {
|
||||||
|
setTimeout(() => insertAfterCaret(editor, "]"), 0)
|
||||||
|
}
|
||||||
|
} else if (e.key === "]" && isNextChar(editor, ']')) {
|
||||||
|
moveOneRight(editor)
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
} else if (e.key === "(") {
|
||||||
|
if (editor.selectionStart !== editor.selectionEnd) {
|
||||||
|
insertAroundSelection(editor, '(', ')')
|
||||||
|
e.preventDefault()
|
||||||
|
} else {
|
||||||
|
setTimeout(() => insertAfterCaret(editor, ")"), 0)
|
||||||
|
}
|
||||||
|
} else if (e.key === ")" && isNextChar(editor, ')')) {
|
||||||
|
moveOneRight(editor)
|
||||||
|
e.preventDefault()
|
||||||
|
} else if (e.key === '"') {
|
||||||
|
if (isNextChar(editor, '"')) {
|
||||||
|
moveOneRight(editor)
|
||||||
|
e.preventDefault()
|
||||||
|
} else if (editor.selectionStart !== editor.selectionEnd) {
|
||||||
|
insertAroundSelection(editor, '"', '"')
|
||||||
|
e.preventDefault()
|
||||||
|
} else {
|
||||||
|
setTimeout(() => insertAfterCaret(editor, '"'), 0)
|
||||||
|
}
|
||||||
|
} else if (e.key === "Enter") {
|
||||||
|
indentNewlineForBraces(e, editor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function moveOneRight(editor: HTMLTextAreaElement) {
|
||||||
|
const pos = editor.selectionStart
|
||||||
|
editor.selectionStart = editor.selectionEnd = pos + 1
|
||||||
|
}
|
||||||
|
|
||||||
function insertTab(editor: HTMLTextAreaElement) {
|
function insertTab(editor: HTMLTextAreaElement) {
|
||||||
const start = editor.selectionStart
|
const start = editor.selectionStart
|
||||||
const end = editor.selectionEnd
|
const end = editor.selectionEnd
|
||||||
|
|
@ -72,4 +125,84 @@ function removeTab(editor: HTMLTextAreaElement) {
|
||||||
editor.selectionStart = start - INDENT_SIZE
|
editor.selectionStart = start - INDENT_SIZE
|
||||||
editor.selectionEnd = end - INDENT_SIZE
|
editor.selectionEnd = end - INDENT_SIZE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function insertAfterCaret(editor: HTMLTextAreaElement, char: string) {
|
||||||
|
const pos = editor.selectionStart
|
||||||
|
editor.value = editor.value.slice(0, pos) + char + editor.value.slice(pos)
|
||||||
|
editor.selectionStart = editor.selectionEnd = pos
|
||||||
|
}
|
||||||
|
|
||||||
|
function isNextChar(editor: HTMLTextAreaElement, char: string): boolean {
|
||||||
|
return editor.value[editor.selectionStart] === char
|
||||||
|
}
|
||||||
|
|
||||||
|
function indentNewlineForBraces(e: KeyboardEvent, editor: HTMLTextAreaElement) {
|
||||||
|
e.preventDefault()
|
||||||
|
|
||||||
|
if (isBetween(editor, "{", "}") || isBetween(editor, "[", "]")) {
|
||||||
|
setTimeout(() => insertMoreIndentedNewline(editor), 0)
|
||||||
|
} else {
|
||||||
|
setTimeout(() => insertIndentedNewline(editor), 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function isBetween(editor: HTMLTextAreaElement, start: string, end: string): boolean {
|
||||||
|
const pos = editor.selectionStart
|
||||||
|
const val = editor.value
|
||||||
|
|
||||||
|
if (pos <= 0 || pos >= val.length) return false
|
||||||
|
return val[pos - 1] === start && val[pos] === end
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertIndentedNewline(editor: HTMLTextAreaElement) {
|
||||||
|
const pos = editor.selectionStart
|
||||||
|
|
||||||
|
const before = editor.value.slice(0, pos)
|
||||||
|
|
||||||
|
const prevLineStart = before.lastIndexOf("\n", pos - 1) + 1
|
||||||
|
const prevLine = before.slice(prevLineStart)
|
||||||
|
|
||||||
|
let leading = 0
|
||||||
|
while (prevLine[leading] === " ") leading++
|
||||||
|
|
||||||
|
const indent = " ".repeat(leading)
|
||||||
|
|
||||||
|
const insert = "\n" + indent
|
||||||
|
editor.value = editor.value.slice(0, pos) + insert + editor.value.slice(pos)
|
||||||
|
|
||||||
|
const newPos = pos + insert.length
|
||||||
|
editor.selectionStart = editor.selectionEnd = newPos
|
||||||
|
|
||||||
|
adjustHeight(editor)
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertAroundSelection(editor: HTMLTextAreaElement, before: string, after: string) {
|
||||||
|
const start = editor.selectionStart
|
||||||
|
const end = editor.selectionEnd
|
||||||
|
|
||||||
|
editor.value = editor.value.slice(0, start) + before + editor.value.slice(start, end) + after + editor.value.slice(end)
|
||||||
|
}
|
||||||
|
|
||||||
|
function insertMoreIndentedNewline(editor: HTMLTextAreaElement) {
|
||||||
|
const pos = editor.selectionStart
|
||||||
|
|
||||||
|
const before = editor.value.slice(0, pos)
|
||||||
|
|
||||||
|
const prevLineStart = before.lastIndexOf("\n", pos - 1) + 1
|
||||||
|
const prevLine = before.slice(prevLineStart)
|
||||||
|
|
||||||
|
let leading = 0
|
||||||
|
while (prevLine[leading] === " ") leading++
|
||||||
|
|
||||||
|
const oldIndent = " ".repeat(leading)
|
||||||
|
const newIndent = " ".repeat(leading + INDENT_SIZE)
|
||||||
|
|
||||||
|
const insert = "\n" + newIndent + "\n" + oldIndent
|
||||||
|
editor.value = editor.value.slice(0, pos) + insert + editor.value.slice(pos)
|
||||||
|
|
||||||
|
const newPos = pos + insert.length
|
||||||
|
editor.selectionStart = editor.selectionEnd = newPos - 1 - oldIndent.length
|
||||||
|
|
||||||
|
adjustHeight(editor)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user