Fix Mathjax sometimes being deleted even though it's not selected (#1696)
* Fix frame element being deleted, when a frame handle is deleted from while selected * Fix mixing up preceding/following
This commit is contained in:
parent
5963791d85
commit
55c64e5b54
@ -13,7 +13,7 @@ import {
|
||||
import { on } from "../lib/events";
|
||||
import type { FrameHandle } from "./frame-handle";
|
||||
import {
|
||||
checkWhetherMovingIntoHandle,
|
||||
checkHandles,
|
||||
frameElementTagName,
|
||||
FrameEnd,
|
||||
FrameStart,
|
||||
@ -32,43 +32,39 @@ function restoreFrameHandles(mutations: MutationRecord[]): void {
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
* In some rare cases, nodes might be inserted into the frame itself.
|
||||
* For example after using execCommand.
|
||||
*/
|
||||
const placement = node.compareDocumentPosition(framed);
|
||||
// In some rare cases, nodes might be inserted into the frame itself.
|
||||
// For example after using execCommand.
|
||||
const placement = framed.compareDocumentPosition(node);
|
||||
|
||||
if (placement & Node.DOCUMENT_POSITION_FOLLOWING) {
|
||||
referenceNode = moveChildOutOfElement(frameElement, node, "afterend");
|
||||
continue;
|
||||
} else if (placement & Node.DOCUMENT_POSITION_PRECEDING) {
|
||||
if (placement & Node.DOCUMENT_POSITION_PRECEDING) {
|
||||
referenceNode = moveChildOutOfElement(
|
||||
frameElement,
|
||||
node,
|
||||
"beforebegin",
|
||||
);
|
||||
continue;
|
||||
} else if (placement & Node.DOCUMENT_POSITION_FOLLOWING) {
|
||||
referenceNode = moveChildOutOfElement(frameElement, node, "afterend");
|
||||
}
|
||||
}
|
||||
|
||||
for (const node of mutation.removedNodes) {
|
||||
if (
|
||||
/* avoid triggering when (un)mounting whole frame */
|
||||
mutations.length === 1 &&
|
||||
nodeIsElement(node) &&
|
||||
isFrameHandle(node)
|
||||
) {
|
||||
/* When deleting from _outer_ position in FrameHandle to _inner_ position */
|
||||
frameElement.remove();
|
||||
if (!isFrameHandle(node)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
nodeIsElement(node) &&
|
||||
isFrameHandle(node) &&
|
||||
frameElement.isConnected &&
|
||||
!frameElement.block
|
||||
/* avoid triggering when (un)mounting whole frame */
|
||||
mutations.length === 1 &&
|
||||
!node.partiallySelected
|
||||
) {
|
||||
// Similar to a "movein", this could be considered a
|
||||
// "deletein" event and could get some special treatment, e.g.
|
||||
// first highlight the entire frame-element.
|
||||
frameElement.remove();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frameElement.isConnected && !frameElement.block) {
|
||||
frameElement.refreshHandles();
|
||||
continue;
|
||||
}
|
||||
@ -248,7 +244,7 @@ function checkIfInsertingLineBreakAdjacentToBlockFrame() {
|
||||
}
|
||||
|
||||
function onSelectionChange() {
|
||||
checkWhetherMovingIntoHandle();
|
||||
checkHandles();
|
||||
checkIfInsertingLineBreakAdjacentToBlockFrame();
|
||||
}
|
||||
|
||||
@ -259,7 +255,7 @@ document.addEventListener("selectionchange", onSelectionChange);
|
||||
* <anki-frame>
|
||||
* <frame-handle-start> </frame-handle-start>
|
||||
* <your-element ... />
|
||||
* <frame-handle-end> </frame-handle-start>
|
||||
* <frame-handle-end> </frame-handle-end>
|
||||
* </anki-frame>
|
||||
*/
|
||||
export function frameElement(element: HTMLElement, block: boolean): FrameElement {
|
||||
|
@ -120,6 +120,14 @@ export abstract class FrameHandle extends HTMLElement {
|
||||
return ["data-frames"];
|
||||
}
|
||||
|
||||
/**
|
||||
* When a deletion is trigger with a FrameHandle selected, it will be treated
|
||||
* differently depending on whether it is selected:
|
||||
* - If partially selected, it should be restored (unless the frame element
|
||||
* is also selected).
|
||||
* - Otherwise, it should be deleted along with the frame element.
|
||||
*/
|
||||
partiallySelected = false;
|
||||
frames?: string;
|
||||
|
||||
constructor() {
|
||||
@ -273,15 +281,28 @@ export class FrameEnd extends FrameHandle {
|
||||
}
|
||||
}
|
||||
|
||||
export function checkWhetherMovingIntoHandle(): void {
|
||||
function checkWhetherMovingIntoHandle(selection: Selection, handle: FrameHandle): void {
|
||||
if (selection.anchorNode === handle.firstChild && isSelectionCollapsed(selection)) {
|
||||
handle.notifyMoveIn(selection.anchorOffset);
|
||||
}
|
||||
}
|
||||
|
||||
function checkWhetherSelectingHandle(selection: Selection, handle: FrameHandle): void {
|
||||
handle.partiallySelected =
|
||||
handle.firstChild && !isSelectionCollapsed(selection)
|
||||
? selection.containsNode(handle.firstChild)
|
||||
: false;
|
||||
}
|
||||
|
||||
export function checkHandles(): void {
|
||||
for (const handle of handles) {
|
||||
const selection = getSelection(handle)!;
|
||||
|
||||
if (
|
||||
selection.anchorNode === handle.firstChild &&
|
||||
isSelectionCollapsed(selection)
|
||||
) {
|
||||
handle.notifyMoveIn(selection.anchorOffset);
|
||||
if (selection.rangeCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkWhetherMovingIntoHandle(selection, handle);
|
||||
checkWhetherSelectingHandle(selection, handle);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user