Path: blob/master/src/packages/frontend/editors/slate/keyboard/backspace.ts
1697 views
/*1* This file is part of CoCalc: Copyright © 2020 Sagemath, Inc.2* License: MS-RSL – see LICENSE.md for details3*/45/*6What happens when you hit the backspace/delete key.78- deleting (certain?) void elements. See9https://github.com/ianstormtaylor/slate/issues/387510for discussion of why we must implement this ourselves.11*/1213import { Editor, Path, Point, Range, Text, Transforms } from "slate";14import { register } from "./register";15import { getNodeAt } from "../slate-util";1617function backspaceKey({ editor }) {18if (editor.selection == null || !Range.isCollapsed(editor.selection)) {19selectionHack(editor);20return false;21}2223// In slatejs you can't delete various block elements at the beginning of the24// document. This is yet another **BUG IN SLATE**, which we workaround by25// inserting an empty node at the beginning of the document. This does not26// seem to be reported upstream, and I'm not even bothering since there's27// so many bugs like this we have to workaround. Morever, if this bug is28// fixed upstream, it breaks our workaround! Sigh.29if (isAtStart(editor.selection.focus)) {30editor.apply({31type: "insert_node",32path: [0],33node: { type: "paragraph", children: [{ text: "" }] },34});35Transforms.delete(editor, {36reverse: true,37});38}3940// This seems to work perfectly in all cases, including working around the41// void delete bug in Slate:42// https://github.com/ianstormtaylor/slate/issues/387543// IMPORTANT: this editor.deleteBackward() is implemented in44// format/delete-backward.ts and is quite complicated!45editor.deleteBackward();46return true;47}4849register({ key: "Backspace" }, backspaceKey);5051function deleteKey({ editor }) {52if (editor.selection == null) return true;53if (!Range.isCollapsed(editor.selection)) {54selectionHack(editor);55// deleteForward does nothing for non collapsed56Transforms.delete(editor);57return true;58}59editor.deleteForward();60return true;61}6263register({ key: "Delete" }, deleteKey);6465function isAtStart(loc: Point): boolean {66for (const n of loc.path) {67if (n != 0) return false;68}69return loc.offset == 0;70}7172// This is a hack to workaround this bug:73// https://github.com/ianstormtaylor/slate/issues/412174// which is in the core of slate. Call this before75// deleting the selection to ensure that the wrong thing76// isn't deleted...77function selectionHack(editor: Editor): void {78const { selection } = editor;79if (selection == null || Range.isCollapsed(selection)) return;80const edges = Range.edges(selection);81const node = getNodeAt(editor, edges[1].path);82if (!Text.isText(node)) return;83if (node.text.length != edges[1].offset) return;8485// OK, so at this point, we're in exactly the situation86// of issue 4121. In particular, the87// selection ends at the edge of a text node.88// Our hack is to move the cursor to the beginning of89// the *next* node, but make the offset 0,90// so that when we delete nothing is removed91// from there.92const path = Path.next(edges[1].path);93const nextNode = getNodeAt(editor, path);94if (Text.isText(nextNode)) {95// NOTE: it doesn't matter if we reverse the range here, since96// we're about to delete this selection.97const newSelection = {98anchor: edges[0],99focus: { path, offset: 0 },100};101Transforms.setSelection(editor, newSelection);102}103}104105106