mirror of
https://github.com/ankitects/anki.git
synced 2025-09-25 01:06:35 -04:00
Make it so you don't have to close the HTML mode for html to be written back
This commit is contained in:
parent
a87f81f00b
commit
9cbc1c33e7
6 changed files with 56 additions and 28 deletions
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue