aboutsummaryrefslogtreecommitdiff
path: root/editor/editor.ts
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2021-07-26 04:18:32 +0700
committerShulhan <ms@kilabit.info>2021-07-26 04:18:32 +0700
commitd22ecec866f9da676ed6a5b06a6089770ae1139d (patch)
tree14039a70115c3df8f723d84a99eea2e9b582dea4 /editor/editor.ts
parent1a49542d36fcc715b3839facee0ccac9952d5ecd (diff)
downloadpakakeh.ts-d22ecec866f9da676ed6a5b06a6089770ae1139d.tar.xz
all: implement editor
Diffstat (limited to 'editor/editor.ts')
-rw-r--r--editor/editor.ts180
1 files changed, 180 insertions, 0 deletions
diff --git a/editor/editor.ts b/editor/editor.ts
new file mode 100644
index 0000000..f021db0
--- /dev/null
+++ b/editor/editor.ts
@@ -0,0 +1,180 @@
+import { IVfsNode, Response } from "../vfs/vfs"
+
+export interface IEditor {
+ id: string
+ is_editable: boolean
+
+ OpenFile(path: string): Response
+ SaveFile(node: IVfsNode): Response
+}
+
+export class Editor implements IEditor {
+ id: string
+ is_editable: boolean
+ private el: HTMLElement | null
+ private activeFile: IVfsNode | null = null
+ private activeText: HTMLElement | null = null
+ private rangeBegin: number = 0
+ private rangeEnd: number = 0
+ private lines: EditorLine[] = []
+
+ constructor(public opts: IEditor) {
+ this.id = opts.id
+ this.is_editable = opts.is_editable
+
+ this.el = document.getElementById(opts.id)
+ if (!this.el) {
+ console.error("Editor: element ID not found:", opts.id)
+ return
+ }
+ this.el.classList.add("wui-editor")
+ }
+
+ OpenFile(path: string): Response {
+ let res: Response = {
+ code: 500,
+ }
+ if (!this.el) {
+ return res
+ }
+
+ res = this.opts.OpenFile(path)
+ if (res.code != 200) {
+ return res
+ }
+ if (!res.data) {
+ return res
+ }
+
+ this.activeFile = res.data as IVfsNode
+
+ let content = this.activeFile.content as string
+ content = content.replace("\r\n", "\n")
+ let lines = content.split("\n")
+
+ for (let x = 0; x < lines.length; x++) {
+ let line = new EditorLine(x, lines[x], this)
+ this.lines.push(line)
+ }
+
+ this.render()
+
+ return res
+ }
+
+ SaveFile(node: IVfsNode): Response {
+ let res = this.opts.SaveFile(node)
+ return res
+ }
+
+ insertNewline(x: number) {
+ console.log("enter new line:", x)
+ let newline = new EditorLine(x, "", this)
+ for (let y = x; y < this.lines.length; y++) {
+ this.lines[y].setNumber(y + 2)
+ }
+ this.lines.splice(x, 0, newline)
+ this.render()
+ }
+
+ onClickText(text: HTMLElement) {
+ if (this.activeText) {
+ this.activeText.contentEditable = "false"
+ this.activeText.style.borderWidth = "0"
+ }
+ text.contentEditable = "true"
+ text.style.borderWidth = "2px"
+ this.activeText = text
+ text.focus()
+ }
+
+ onKeydownText(x: number, text: HTMLElement, ev: KeyboardEvent) {
+ if (ev.key === "Escape") {
+ text.contentEditable = "false"
+ text.style.borderWidth = "0"
+ this.activeText = null
+ return false
+ }
+ if (ev.key === "Enter") {
+ this.insertNewline(x + 1)
+ ev.preventDefault()
+ return false
+ }
+ return true
+ }
+
+ onMouseDownAtLine(x: number) {
+ this.rangeBegin = x
+ }
+
+ onMouseUpAtLine(x: number) {
+ this.rangeEnd = x
+ console.log("range: ", this.rangeBegin, " - ", this.rangeEnd)
+ if (this.rangeEnd < this.rangeBegin) {
+ return
+ }
+ if (!this.el) {
+ return
+ }
+ let y = 0
+ for (; y < this.rangeBegin; y++) {
+ this.el.children[y].setAttribute("style", "")
+ }
+ for (; y <= this.rangeEnd; y++) {
+ this.el.children[y].setAttribute("style", "background-color:lightsalmon")
+ }
+ for (; y < this.el.children.length; y++) {
+ this.el.children[y].setAttribute("style", "")
+ }
+ }
+
+ render() {
+ if (!this.el) {
+ return
+ }
+ this.el.innerHTML = ""
+ for (const line of this.lines) {
+ this.el.appendChild(line.el)
+ }
+ }
+}
+
+class EditorLine {
+ el!: HTMLElement
+ elNumber!: HTMLElement
+ elText!: HTMLElement
+
+ constructor(public x: number, public text: string, ed: Editor) {
+ this.el = document.createElement("div")
+ this.el.classList.add("wui-editor-line")
+
+ this.elNumber = document.createElement("span")
+ this.elNumber.classList.add("wui-line-number")
+ this.elNumber.innerText = x + 1 + ""
+
+ this.elNumber.onmousedown = (ev: MouseEvent) => {
+ ed.onMouseDownAtLine(x)
+ }
+ this.elNumber.onmouseup = (ev: MouseEvent) => {
+ ed.onMouseUpAtLine(x)
+ }
+
+ this.elText = document.createElement("span")
+ this.elText.classList.add("wui-line-text")
+ this.elText.innerText = text
+
+ this.elText.onclick = (ev: MouseEvent) => {
+ ed.onClickText(this.elText)
+ }
+ this.elText.onkeydown = (ev: KeyboardEvent) => {
+ return ed.onKeydownText(x, this.elText, ev)
+ }
+
+ this.el.appendChild(this.elNumber)
+ this.el.appendChild(this.elText)
+ }
+
+ setNumber(x: number) {
+ this.elNumber.innerText = x + ""
+ }
+}