mirror of
https://github.com/BookStackApp/BookStack.git
synced 2025-09-09 06:29:32 +03:00
Lexical: Added backspace handling for details
Allows more reliable removal of details block on backspace at first child position with the details block.
This commit is contained in:
@@ -91,9 +91,6 @@ export function createPageEditorInstance(container: HTMLElement, htmlContent: st
|
||||
window.debugEditorState = () => {
|
||||
return editor.getEditorState().toJSON();
|
||||
};
|
||||
context.manager.onSelectionChange((selection) => {
|
||||
console.log(selection, context.editor.getEditorState());
|
||||
});
|
||||
|
||||
registerCommonNodeMutationListeners(context);
|
||||
|
||||
|
@@ -307,7 +307,7 @@ export class ElementNode extends LexicalNode {
|
||||
let anchorOffset = _anchorOffset;
|
||||
let focusOffset = _focusOffset;
|
||||
const childrenCount = this.getChildrenSize();
|
||||
if (!this.canBeEmpty()) {
|
||||
if (!this.canBeEmpty() && !this.shouldSelectDirectly()) {
|
||||
if (_anchorOffset === 0 && _focusOffset === 0) {
|
||||
const firstChild = this.getFirstChild();
|
||||
if ($isTextNode(firstChild) || $isElementNode(firstChild)) {
|
||||
|
@@ -178,6 +178,10 @@ export class DetailsNode extends ElementNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
canBeEmpty(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function $createDetailsNode() {
|
||||
|
@@ -18,6 +18,7 @@ import {$setInsetForSelection} from "../utils/lists";
|
||||
import {$isListItemNode} from "@lexical/list";
|
||||
import {$isDetailsNode, DetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
|
||||
import {$isDiagramNode} from "../utils/diagrams";
|
||||
import {$unwrapDetailsNode} from "../utils/details";
|
||||
|
||||
function isSingleSelectedNode(nodes: LexicalNode[]): boolean {
|
||||
if (nodes.length === 1) {
|
||||
@@ -172,6 +173,35 @@ function getDetailsScenario(editor: LexicalEditor): {
|
||||
}
|
||||
}
|
||||
|
||||
function unwrapDetailsNode(context: EditorUiContext, event: KeyboardEvent): boolean {
|
||||
const selection = $getSelection();
|
||||
const nodes = selection?.getNodes() || [];
|
||||
|
||||
if (nodes.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const selectedNearestBlock = $getNearestNodeBlockParent(nodes[0]);
|
||||
if (!selectedNearestBlock) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const selectedParentBlock = selectedNearestBlock.getParent();
|
||||
const selectRange = selection?.getStartEndPoints();
|
||||
|
||||
if (selectRange && $isDetailsNode(selectedParentBlock) && selectRange[0].offset === 0 && selectedNearestBlock.getIndexWithinParent() === 0) {
|
||||
event.preventDefault();
|
||||
context.editor.update(() => {
|
||||
$unwrapDetailsNode(selectedParentBlock);
|
||||
selectedNearestBlock.selectStart();
|
||||
context.manager.triggerLayoutUpdate();
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function $isSingleListItem(nodes: LexicalNode[]): boolean {
|
||||
if (nodes.length !== 1) {
|
||||
return false;
|
||||
@@ -201,9 +231,9 @@ function handleInsetOnTab(editor: LexicalEditor, event: KeyboardEvent|null): boo
|
||||
}
|
||||
|
||||
export function registerKeyboardHandling(context: EditorUiContext): () => void {
|
||||
const unregisterBackspace = context.editor.registerCommand(KEY_BACKSPACE_COMMAND, (): boolean => {
|
||||
const unregisterBackspace = context.editor.registerCommand(KEY_BACKSPACE_COMMAND, (event): boolean => {
|
||||
deleteSingleSelectedNode(context.editor);
|
||||
return false;
|
||||
return unwrapDetailsNode(context, event);
|
||||
}, COMMAND_PRIORITY_LOW);
|
||||
|
||||
const unregisterDelete = context.editor.registerCommand(KEY_DELETE_COMMAND, (): boolean => {
|
||||
|
@@ -34,6 +34,7 @@ import {$isDiagramNode, $openDrawingEditorForNode, showDiagramManagerForInsert}
|
||||
import {$createLinkedImageNodeFromImageData, showImageManager} from "../../../utils/images";
|
||||
import {$showDetailsForm, $showImageForm, $showLinkForm, $showMediaForm} from "../forms/objects";
|
||||
import {formatCodeBlock} from "../../../utils/formats";
|
||||
import {$unwrapDetailsNode} from "../../../utils/details";
|
||||
|
||||
export const link: EditorButtonDefinition = {
|
||||
label: 'Insert/edit link',
|
||||
@@ -251,11 +252,7 @@ export const detailsUnwrap: EditorButtonDefinition = {
|
||||
context.editor.update(() => {
|
||||
const details = $getNodeFromSelection($getSelection(), $isDetailsNode);
|
||||
if ($isDetailsNode(details)) {
|
||||
const children = details.getChildren();
|
||||
for (const child of children) {
|
||||
details.insertBefore(child);
|
||||
}
|
||||
details.remove();
|
||||
$unwrapDetailsNode(details);
|
||||
context.manager.triggerLayoutUpdate();
|
||||
}
|
||||
})
|
||||
|
9
resources/js/wysiwyg/utils/details.ts
Normal file
9
resources/js/wysiwyg/utils/details.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import {DetailsNode} from "@lexical/rich-text/LexicalDetailsNode";
|
||||
|
||||
export function $unwrapDetailsNode(node: DetailsNode) {
|
||||
const children = node.getChildren();
|
||||
for (const child of children) {
|
||||
node.insertBefore(child);
|
||||
}
|
||||
node.remove();
|
||||
}
|
Reference in New Issue
Block a user