Make it so you don't have to close the HTML mode for html to be written back

This commit is contained in:
Henrik Giesel 2021-06-17 21:36:56 +02:00
parent a87f81f00b
commit 9cbc1c33e7
6 changed files with 56 additions and 28 deletions

View file

@ -21,6 +21,11 @@ const codeMirrorOptions = {
const parser = new DOMParser(); const parser = new DOMParser();
function parseHTML(html: string): string {
const doc = parser.parseFromString(html, "text/html");
return doc.documentElement.innerHTML;
}
export class Codable extends HTMLTextAreaElement { export class Codable extends HTMLTextAreaElement {
codeMirror: CodeMirror | undefined; codeMirror: CodeMirror | undefined;
active: boolean; active: boolean;
@ -30,18 +35,29 @@ export class Codable extends HTMLTextAreaElement {
this.active = false; this.active = false;
} }
set fieldHTML(content: string) {
this.value = content;
}
get fieldHTML(): string {
return parseHTML(this.codeMirror.getValue());
}
connectedCallback(): void { connectedCallback(): void {
this.setAttribute("hidden", ""); this.setAttribute("hidden", "");
} }
setup(html: string): void { setup(html: string): void {
this.active = true; this.active = true;
this.value = html; this.fieldHTML = html;
this.codeMirror = CodeMirror.fromTextArea(this, codeMirrorOptions); this.codeMirror = CodeMirror.fromTextArea(this, codeMirrorOptions);
} }
focus(): void { focus(): void {
this.codeMirror.focus(); this.codeMirror.focus();
}
caretToEnd(): void {
this.codeMirror.setCursor(this.codeMirror.lineCount(), 0); this.codeMirror.setCursor(this.codeMirror.lineCount(), 0);
} }
@ -49,8 +65,6 @@ export class Codable extends HTMLTextAreaElement {
this.active = false; this.active = false;
this.codeMirror.toTextArea(); this.codeMirror.toTextArea();
this.codeMirror = undefined; this.codeMirror = undefined;
return parseHTML(this.value);
const doc = parser.parseFromString(this.value, "text/html");
return doc.documentElement.innerHTML;
} }
} }

View file

@ -1,7 +1,7 @@
// Copyright: Ankitects Pty Ltd and contributors // Copyright: Ankitects Pty Ltd and contributors
// License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html // License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import { nodeIsInline } from "./helpers"; import { nodeIsInline, caretToEnd } from "./helpers";
function containsInlineContent(field: Element): boolean { function containsInlineContent(field: Element): boolean {
if (field.childNodes.length === 0) { if (field.childNodes.length === 0) {
@ -36,4 +36,8 @@ export class Editable extends HTMLElement {
connectedCallback(): void { connectedCallback(): void {
this.setAttribute("contenteditable", ""); this.setAttribute("contenteditable", "");
} }
caretToEnd() {
caretToEnd(this);
}
} }

View file

@ -10,7 +10,6 @@ import type { Codable } from "./codable";
import { updateActiveButtons } from "./toolbar"; import { updateActiveButtons } from "./toolbar";
import { bridgeCommand } from "./lib"; import { bridgeCommand } from "./lib";
import { caretToEnd } from "./helpers";
import { onInput, onKey, onKeyUp } from "./inputHandlers"; import { onInput, onKey, onKeyUp } from "./inputHandlers";
import { onFocus, onBlur } from "./focusHandlers"; import { onFocus, onBlur } from "./focusHandlers";
@ -51,16 +50,20 @@ export class EditingArea extends HTMLDivElement {
this.shadowRoot!.appendChild(this.codable); this.shadowRoot!.appendChild(this.codable);
} }
get activeInput(): Editable | Codable {
return this.codable.active ? this.codable : this.editable;
}
get ord(): number { get ord(): number {
return Number(this.getAttribute("ord")); return Number(this.getAttribute("ord"));
} }
set fieldHTML(content: string) { set fieldHTML(content: string) {
this.editable.fieldHTML = content; this.activeInput.fieldHTML = content;
} }
get fieldHTML(): string { get fieldHTML(): string {
return this.editable.fieldHTML; return this.activeInput.fieldHTML;
} }
connectedCallback(): void { connectedCallback(): void {
@ -119,12 +122,24 @@ export class EditingArea extends HTMLDivElement {
return this.shadowRoot!.getSelection()!; return this.shadowRoot!.getSelection()!;
} }
focusEditable(): void { focus(): void {
this.editable.focus(); this.activeInput.focus();
} }
blur(): void {
this.activeInput.blur();
}
/* legacy */
focusEditable(): void {
focus();
}
blurEditable(): void { blurEditable(): void {
this.editable.blur(); blur();
}
caretToEnd(): void {
this.activeInput.caretToEnd();
} }
hasFocus(): boolean { hasFocus(): boolean {
@ -135,21 +150,17 @@ export class EditingArea extends HTMLDivElement {
const hadFocus = this.hasFocus(); const hadFocus = this.hasFocus();
if (this.codable.active) { if (this.codable.active) {
const html = this.codable.teardown(); this.fieldHTML = this.codable.teardown();
this.fieldHTML = html;
this.editable.hidden = false; this.editable.hidden = false;
if (hadFocus) {
this.focusEditable();
caretToEnd(this);
}
} else { } else {
this.editable.hidden = true; this.editable.hidden = true;
console.log("eyo", this.fieldHTML);
this.codable.setup(this.fieldHTML); this.codable.setup(this.fieldHTML);
}
if (hadFocus) { if (hadFocus) {
this.codable.focus(); this.focus();
} this.caretToEnd();
} }
} }
} }

View file

@ -69,11 +69,11 @@ export function nodeIsInline(node: Node): boolean {
return !nodeIsElement(node) || INLINE_TAGS.includes(node.tagName); return !nodeIsElement(node) || INLINE_TAGS.includes(node.tagName);
} }
export function caretToEnd(currentField: EditingArea): void { export function caretToEnd(node: Node): void {
const range = document.createRange(); const range = document.createRange();
range.selectNodeContents(currentField.editable); range.selectNodeContents(node);
range.collapse(false); range.collapse(false);
const selection = currentField.getSelection(); const selection = (node.getRootNode() as Document | ShadowRoot).getSelection()!;
selection.removeAllRanges(); selection.removeAllRanges();
selection.addRange(range); selection.addRange(range);
} }

View file

@ -11,7 +11,6 @@ import { setupI18n, ModuleName } from "lib/i18n";
import "./fields.css"; import "./fields.css";
import { caretToEnd } from "./helpers";
import { saveField } from "./changeTimer"; import { saveField } from "./changeTimer";
import { EditorField } from "./editorField"; import { EditorField } from "./editorField";
@ -52,7 +51,7 @@ export function focusField(n: number): void {
if (field) { if (field) {
field.editingArea.focusEditable(); field.editingArea.focusEditable();
caretToEnd(field.editingArea); field.editingArea.caretToEnd();
updateActiveButtons(new Event("manualfocus")); updateActiveButtons(new Event("manualfocus"));
} }
} }

View file

@ -7,7 +7,7 @@
import { updateActiveButtons } from "./toolbar"; import { updateActiveButtons } from "./toolbar";
import { EditingArea } from "./editingArea"; import { EditingArea } from "./editingArea";
import { caretToEnd, nodeIsElement, getBlockElement } from "./helpers"; import { nodeIsElement, getBlockElement } from "./helpers";
import { triggerChangeTimer } from "./changeTimer"; import { triggerChangeTimer } from "./changeTimer";
import { registerShortcut } from "lib/shortcuts"; import { registerShortcut } from "lib/shortcuts";
@ -59,7 +59,7 @@ export function onKey(evt: KeyboardEvent): void {
function updateFocus(evt: FocusEvent) { function updateFocus(evt: FocusEvent) {
const newFocusTarget = evt.target; const newFocusTarget = evt.target;
if (newFocusTarget instanceof EditingArea) { if (newFocusTarget instanceof EditingArea) {
caretToEnd(newFocusTarget); newFocusTarget.caretToEnd();
updateActiveButtons(evt); updateActiveButtons(evt);
} }
} }