diff options
| author | Shulhan <ms@kilabit.info> | 2021-07-26 04:18:32 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2021-07-26 04:18:32 +0700 |
| commit | d22ecec866f9da676ed6a5b06a6089770ae1139d (patch) | |
| tree | 14039a70115c3df8f723d84a99eea2e9b582dea4 /editor/editor.ts | |
| parent | 1a49542d36fcc715b3839facee0ccac9952d5ecd (diff) | |
| download | pakakeh.ts-d22ecec866f9da676ed6a5b06a6089770ae1139d.tar.xz | |
all: implement editor
Diffstat (limited to 'editor/editor.ts')
| -rw-r--r-- | editor/editor.ts | 180 |
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 + "" + } +} |
