inital commit

This commit is contained in:
2026-01-01 15:25:19 +05:30
commit f0ae49465a
36361 changed files with 4894111 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* [[include:plugins/backspace/README.md]]
* @packageDocumentation
* @module plugins/backspace
*/
import type { IJodit } from "../../types/index";
import { Plugin } from "../../core/plugin/index";
import "./config";
export declare class backspace extends Plugin {
static requires: string[];
protected afterInit(jodit: IJodit): void;
protected beforeDestruct(jodit: IJodit): void;
/**
* Listener BackSpace or Delete button
*/
private onDelete;
/**
* Remove node and replace cursor position out of it
*/
private safeRemoveEmptyNode;
}

127
node_modules/jodit/esm/plugins/backspace/backspace.js generated vendored Normal file
View File

@@ -0,0 +1,127 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { INVISIBLE_SPACE, IS_PROD } from "../../core/constants.js";
import { Dom } from "../../core/dom/index.js";
import { pluginSystem } from "../../core/global.js";
import { isFunction } from "../../core/helpers/checker/is-function.js";
import { Plugin } from "../../core/plugin/index.js";
import { moveNodeInsideStart } from "../../core/selection/helpers/index.js";
import "./config.js";
import { checkNotCollapsed } from "./cases/check-not-collapsed.js";
import { cases } from "./cases/index.js";
export class backspace extends Plugin {
afterInit(jodit) {
jodit
.registerCommand('deleteButton', {
exec: () => this.onDelete(false),
hotkeys: jodit.o.delete.hotkeys.delete
}, {
stopPropagation: false
})
.registerCommand('backspaceButton', {
exec: () => this.onDelete(true),
hotkeys: jodit.o.delete.hotkeys.backspace
}, {
stopPropagation: false
})
.registerCommand('deleteWordButton', {
exec: () => this.onDelete(false, 'word'),
hotkeys: jodit.o.delete.hotkeys.deleteWord
})
.registerCommand('backspaceWordButton', {
exec: () => this.onDelete(true, 'word'),
hotkeys: jodit.o.delete.hotkeys.backspaceWord
})
.registerCommand('deleteSentenceButton', {
exec: () => this.onDelete(false, 'sentence'),
hotkeys: jodit.o.delete.hotkeys.deleteSentence
})
.registerCommand('backspaceSentenceButton', {
exec: () => this.onDelete(true, 'sentence'),
hotkeys: jodit.o.delete.hotkeys.backspaceSentence
});
}
beforeDestruct(jodit) {
jodit.e.off('afterCommand.delete');
}
/**
* Listener BackSpace or Delete button
*/
onDelete(backspace, mode = 'char') {
const jodit = this.j;
const sel = jodit.selection;
if (!sel.isFocused()) {
sel.focus();
}
if (checkNotCollapsed(jodit)) {
return false;
}
const range = sel.range;
const fakeNode = jodit.createInside.text(INVISIBLE_SPACE);
try {
Dom.safeInsertNode(range, fakeNode);
if (!Dom.isOrContains(jodit.editor, fakeNode)) {
return;
}
if (jodit.e.fire('backSpaceBeforeCases', backspace, fakeNode)) {
return false;
}
moveNodeInsideStart(jodit, fakeNode, backspace);
if (cases.some((func) => {
if (isFunction(func) &&
func(jodit, fakeNode, backspace, mode)) {
if (!IS_PROD) {
console.info('Remove case:', func.name);
}
return true;
}
})) {
return false;
}
}
catch (e) {
if (!IS_PROD) {
console.error(e);
}
throw e;
}
finally {
jodit.e.fire('backSpaceAfterDelete', backspace, fakeNode);
this.safeRemoveEmptyNode(fakeNode);
}
return false;
}
/**
* Remove node and replace cursor position out of it
*/
safeRemoveEmptyNode(fakeNode) {
var _a, _b;
const { range } = this.j.s;
if (range.startContainer === fakeNode) {
if (fakeNode.previousSibling) {
if (Dom.isText(fakeNode.previousSibling)) {
range.setStart(fakeNode.previousSibling, (_b = (_a = fakeNode.previousSibling.nodeValue) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0);
}
else {
range.setStartAfter(fakeNode.previousSibling);
}
}
else if (fakeNode.nextSibling) {
if (Dom.isText(fakeNode.nextSibling)) {
range.setStart(fakeNode.nextSibling, 0);
}
else {
range.setStartBefore(fakeNode.nextSibling);
}
}
range.collapse(true);
this.j.s.selectRange(range);
}
Dom.safeRemove(fakeNode);
}
}
backspace.requires = ['hotkeys'];
pluginSystem.add('backspace', backspace);

View File

@@ -0,0 +1,14 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Check if two separate elements can be connected
* @private
*/
export declare function checkJoinNeighbors(jodit: IJodit, fakeNode: Node, backspace: boolean): boolean;

View File

@@ -0,0 +1,62 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { LIST_TAGS } from "../../../core/constants.js";
import { Dom } from "../../../core/dom/dom.js";
import { getMoveFilter } from "../helpers.js";
/**
* Check if two separate elements can be connected
* @private
*/
export function checkJoinNeighbors(jodit, fakeNode, backspace) {
let nextBox = fakeNode, mainClosestBox = nextBox;
// Find the main big closest element
while (nextBox &&
!Dom.findNotEmptySibling(nextBox, backspace) &&
nextBox.parentElement !== jodit.editor) {
nextBox = nextBox.parentElement;
mainClosestBox = nextBox;
}
if (Dom.isElement(mainClosestBox) &&
Dom.isContentEditable(mainClosestBox, jodit.editor)) {
const sibling = Dom.findNotEmptySibling(mainClosestBox, backspace);
if (sibling &&
(checkMoveListContent(jodit, mainClosestBox, sibling, backspace) ||
moveContentAndRemoveEmpty(jodit, mainClosestBox, sibling, backspace))) {
jodit.s.setCursorBefore(fakeNode);
return true;
}
}
return false;
}
function checkMoveListContent(jodit, mainClosestBox, sibling, backspace) {
// Process UL/LI/OL cases
const siblingIsList = Dom.isTag(sibling, LIST_TAGS);
const boxIsList = Dom.isTag(mainClosestBox, LIST_TAGS);
const elementChild = (elm, side) => side ? elm.firstElementChild : elm.lastElementChild;
if (boxIsList) {
sibling = jodit.createInside.element(jodit.o.enterBlock);
Dom.before(mainClosestBox, sibling);
return moveContentAndRemoveEmpty(jodit, elementChild(mainClosestBox, backspace), sibling, backspace);
}
if (sibling && siblingIsList && !boxIsList) {
return moveContentAndRemoveEmpty(jodit, mainClosestBox, elementChild(sibling, !backspace), backspace);
}
return false;
}
function moveContentAndRemoveEmpty(jodit, mainClosestBox, sibling, backspace) {
// Move content and remove empty nodes
if (mainClosestBox && Dom.isElement(sibling)) {
Dom.moveContent(mainClosestBox, sibling, !backspace, getMoveFilter(jodit));
let remove = mainClosestBox;
while (remove && remove !== jodit.editor && Dom.isEmpty(remove)) {
const parent = remove.parentElement;
Dom.safeRemove(remove);
remove = parent;
}
return true;
}
return false;
}

View File

@@ -0,0 +1,23 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Try join two UL elements
*
* @example
* ```html
* <ul><li>one</li></ul>|<ol><li>two</li></ol>
* ```
* Result
* ```html
* <ul><li>one|</li><li>two</li></ul>
* ```
* @private
*/
export declare function checkJoinTwoLists(jodit: IJodit, fakeNode: Node, backspace: boolean): boolean;

View File

@@ -0,0 +1,39 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../../core/dom/dom.js";
import { call } from "../../../core/helpers/utils/utils.js";
import { getMoveFilter } from "../helpers.js";
/**
* Try join two UL elements
*
* @example
* ```html
* <ul><li>one</li></ul>|<ol><li>two</li></ol>
* ```
* Result
* ```html
* <ul><li>one|</li><li>two</li></ul>
* ```
* @private
*/
export function checkJoinTwoLists(jodit, fakeNode, backspace) {
const next = Dom.findSibling(fakeNode, backspace), prev = Dom.findSibling(fakeNode, !backspace);
if (!Dom.closest(fakeNode, Dom.isElement, jodit.editor) &&
Dom.isList(next) &&
Dom.isList(prev) &&
Dom.isTag(next.lastElementChild, 'li') &&
Dom.isTag(prev.firstElementChild, 'li')) {
const { setCursorBefore, setCursorAfter } = jodit.s;
const target = next.lastElementChild, second = prev.firstElementChild;
call(!backspace ? Dom.append : Dom.prepend, second, fakeNode);
Dom.moveContent(prev, next, !backspace, getMoveFilter(jodit));
Dom.safeRemove(prev);
call(backspace ? Dom.append : Dom.prepend, target, fakeNode);
call(backspace ? setCursorBefore : setCursorAfter, fakeNode);
return true;
}
return false;
}

View File

@@ -0,0 +1,23 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* On Not collapsed selection - should only remove whole selected content
*
* @example
* ```html
* <p>first | stop</p><p>second | stop</p>
* ```
* result
* ```html
* <p>first | stop</p>
* ```
* @private
*/
export declare function checkNotCollapsed(jodit: IJodit): boolean;

View File

@@ -0,0 +1,25 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* On Not collapsed selection - should only remove whole selected content
*
* @example
* ```html
* <p>first | stop</p><p>second | stop</p>
* ```
* result
* ```html
* <p>first | stop</p>
* ```
* @private
*/
export function checkNotCollapsed(jodit) {
if (!jodit.s.isCollapsed()) {
jodit.execCommand('Delete');
return true;
}
return false;
}

View File

@@ -0,0 +1,24 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
import type { DeleteMode } from "../interface";
/**
* Check possibility the char can be removed
*
* @example
* ```html
* te|st
* ```
* result
* ```html
* t|st
* ```
* @private
*/
export declare function checkRemoveChar(jodit: IJodit, fakeNode: Node, backspace: boolean, mode: DeleteMode): boolean;

View File

@@ -0,0 +1,160 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { INVISIBLE_SPACE, NBSP_SPACE } from "../../../core/constants.js";
import { Dom } from "../../../core/dom/index.js";
import { call, isVoid, toArray, trimInv } from "../../../core/helpers/index.js";
import { findMostNestedNeighbor } from "../helpers.js";
/**
* Check possibility the char can be removed
*
* @example
* ```html
* te|st
* ```
* result
* ```html
* t|st
* ```
* @private
*/
// eslint-disable-next-line complexity
export function checkRemoveChar(jodit, fakeNode, backspace, mode) {
var _a, _b;
const step = backspace ? -1 : 1;
const anotherSibling = Dom.sibling(fakeNode, !backspace);
let sibling = Dom.sibling(fakeNode, backspace);
let removeNeighbor = null;
let charRemoved = false;
let removed;
if (!sibling) {
sibling = getNextInlineSibling(fakeNode, backspace, jodit.editor);
}
while (sibling && (Dom.isText(sibling) || Dom.isInlineBlock(sibling))) {
while (Dom.isInlineBlock(sibling)) {
sibling = (backspace ? sibling === null || sibling === void 0 ? void 0 : sibling.lastChild : sibling === null || sibling === void 0 ? void 0 : sibling.firstChild);
}
if (!sibling) {
break;
}
if ((_a = sibling.nodeValue) === null || _a === void 0 ? void 0 : _a.length) {
removed = tryRemoveChar(sibling, backspace, step, anotherSibling);
if (!sibling.nodeValue.length &&
Dom.isInlineBlock(sibling.parentNode)) {
sibling.nodeValue = INVISIBLE_SPACE;
}
}
if (!((_b = sibling.nodeValue) === null || _b === void 0 ? void 0 : _b.length)) {
removeNeighbor = sibling;
}
if (!isVoid(removed) && removed !== INVISIBLE_SPACE) {
checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit);
charRemoved = true;
break;
}
const nextSibling = getNextInlineSibling(sibling, backspace, jodit.editor);
if (removeNeighbor) {
Dom.safeRemove(removeNeighbor);
removeNeighbor = null;
}
sibling = nextSibling;
}
if (removeNeighbor) {
Dom.safeRemove(removeNeighbor);
removeNeighbor = null;
}
if (charRemoved) {
removeEmptyForParent(fakeNode, 'a');
addBRInsideEmptyBlock(jodit, fakeNode);
jodit.s.setCursorBefore(fakeNode);
if (Dom.isTag(fakeNode.previousSibling, 'br') &&
!Dom.findNotEmptySibling(fakeNode, false)) {
Dom.after(fakeNode, jodit.createInside.element('br'));
}
}
return charRemoved;
}
function getNextInlineSibling(sibling, backspace, root) {
let nextSibling = Dom.sibling(sibling, backspace);
if (!nextSibling && sibling.parentNode && sibling.parentNode !== root) {
nextSibling = findMostNestedNeighbor(sibling, !backspace, root, true);
}
return nextSibling;
}
/**
* Helper removes all empty inline parents
*/
function removeEmptyForParent(node, tags) {
let parent = node.parentElement;
while (parent && Dom.isInlineBlock(parent) && Dom.isTag(parent, tags)) {
const p = parent.parentElement;
if (Dom.isEmpty(parent)) {
Dom.after(parent, node);
Dom.safeRemove(parent);
}
parent = p;
}
}
/**
* Helper add BR element inside empty block element
*/
function addBRInsideEmptyBlock(jodit, node) {
if (node.parentElement !== jodit.editor &&
Dom.isBlock(node.parentElement) &&
Dom.each(node.parentElement, Dom.isEmptyTextNode)) {
Dom.after(node, jodit.createInside.element('br'));
}
}
function tryRemoveChar(sibling, backspace, step, anotherSibling) {
// For Unicode escapes
let value = toArray(sibling.nodeValue);
const length = value.length;
let index = backspace ? length - 1 : 0;
if (value[index] === INVISIBLE_SPACE) {
while (value[index] === INVISIBLE_SPACE) {
index += step;
}
}
const removed = value[index];
if (value[index + step] === INVISIBLE_SPACE) {
index += step;
while (value[index] === INVISIBLE_SPACE) {
index += step;
}
index += backspace ? 1 : -1;
}
if (backspace && index < 0) {
value = [];
}
else {
value = value.slice(backspace ? 0 : index + 1, backspace ? index : length);
}
replaceSpaceOnNBSP(anotherSibling, backspace, value);
sibling.nodeValue = value.join('');
return removed;
}
function replaceSpaceOnNBSP(anotherSibling, backspace, value) {
var _a;
if (!anotherSibling ||
!Dom.isText(anotherSibling) ||
(!backspace ? / $/ : /^ /).test((_a = anotherSibling.nodeValue) !== null && _a !== void 0 ? _a : '') ||
!trimInv(anotherSibling.nodeValue || '').length) {
for (let i = backspace ? value.length - 1 : 0; backspace ? i >= 0 : i < value.length; i += backspace ? -1 : 1) {
if (value[i] === ' ') {
value[i] = NBSP_SPACE;
}
else {
break;
}
}
}
}
function checkRepeatRemoveCharAction(backspace, sibling, fakeNode, mode, removed, jodit) {
call(backspace ? Dom.after : Dom.before, sibling, fakeNode);
if (mode === 'sentence' ||
(mode === 'word' && removed !== ' ' && removed !== NBSP_SPACE)) {
checkRemoveChar(jodit, fakeNode, backspace, mode);
}
}

View File

@@ -0,0 +1,14 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Checks if a non-editable element can be deleted
* @private
*/
export declare function checkRemoveContentNotEditable(jodit: IJodit, fakeNode: Text, backspace: boolean): boolean;

View File

@@ -0,0 +1,29 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../../core/dom/index.js";
import { call } from "../../../core/helpers/index.js";
import { moveNodeInsideStart } from "../../../core/selection/helpers/index.js";
/**
* Checks if a non-editable element can be deleted
* @private
*/
export function checkRemoveContentNotEditable(jodit, fakeNode, backspace) {
let neighbor = Dom.findSibling(fakeNode, backspace);
if (!neighbor &&
fakeNode.parentElement &&
fakeNode.parentElement !== jodit.editor) {
neighbor = Dom.findSibling(fakeNode.parentElement, backspace);
}
if (Dom.isElement(neighbor) &&
!Dom.isContentEditable(neighbor, jodit.editor)) {
call(backspace ? Dom.before : Dom.after, neighbor, fakeNode);
Dom.safeRemove(neighbor);
moveNodeInsideStart(jodit, fakeNode, backspace);
call(backspace ? jodit.s.setCursorBefore : jodit.s.setCursorAfter, fakeNode);
return true;
}
return false;
}

View File

@@ -0,0 +1,23 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Check if it is possible to remove an empty adjacent element.
*
* @example
* ```html
* <p><br></p><p>|second stop</p>
* ```
* result
* ```html
* <p>|second stop</p>
* ```
* @private
*/
export declare function checkRemoveEmptyNeighbor(jodit: IJodit, fakeNode: Node, backspace: boolean): boolean;

View File

@@ -0,0 +1,32 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../../core/dom/dom.js";
/**
* Check if it is possible to remove an empty adjacent element.
*
* @example
* ```html
* <p><br></p><p>|second stop</p>
* ```
* result
* ```html
* <p>|second stop</p>
* ```
* @private
*/
export function checkRemoveEmptyNeighbor(jodit, fakeNode, backspace) {
const parent = Dom.closest(fakeNode, Dom.isElement, jodit.editor);
if (!parent) {
return false;
}
const neighbor = Dom.findNotEmptySibling(parent, backspace);
if (neighbor && Dom.isEmpty(neighbor)) {
Dom.safeRemove(neighbor);
jodit.s.setCursorBefore(fakeNode);
return true;
}
return false;
}

View File

@@ -0,0 +1,24 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Check if the current empty item can be removed
*
* @example
* ```html
* <p>first stop</p><p>|<br></p>
* ```
* result
* ```html
* <p>first stop|</p>
* ```
*
* @private
*/
export declare function checkRemoveEmptyParent(jodit: IJodit, fakeNode: Node, backspace: boolean): boolean;

View File

@@ -0,0 +1,55 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { INSEPARABLE_TAGS } from "../../../core/constants.js";
import { Dom } from "../../../core/dom/index.js";
import { checkJoinTwoLists } from "./check-join-two-lists.js";
/**
* Check if the current empty item can be removed
*
* @example
* ```html
* <p>first stop</p><p>|<br></p>
* ```
* result
* ```html
* <p>first stop|</p>
* ```
*
* @private
*/
export function checkRemoveEmptyParent(jodit, fakeNode, backspace) {
let found = false;
const { setCursorBefore, setCursorIn } = jodit.s;
let prn = Dom.closest(fakeNode, Dom.isElement, jodit.editor);
if (!prn || !Dom.isEmpty(prn)) {
return false;
}
const neighbor = Dom.findNotEmptyNeighbor(fakeNode, backspace, jodit.editor);
do {
if (prn && Dom.isEmpty(prn) && !Dom.isCell(prn)) {
Dom.after(prn, fakeNode);
const tmp = Dom.closest(prn, n => Dom.isElement(n) && n !== prn, jodit.editor);
Dom.safeRemove(prn);
found = true;
prn = tmp;
}
else {
break;
}
} while (prn);
if (found && checkJoinTwoLists(jodit, fakeNode, backspace)) {
return true;
}
if (neighbor &&
!Dom.isText(neighbor) &&
!Dom.isTag(neighbor, INSEPARABLE_TAGS)) {
setCursorIn(neighbor, !backspace);
}
else {
setCursorBefore(fakeNode);
}
return found;
}

View File

@@ -0,0 +1,24 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Check possibility inseparable Element can be removed (img, hr etc.)
*
* @example
* ```html
* <p>first second <img>| stop</p>
* ```
* result
* ```html
* <p>first second | stop</p>
* ```
*
* @private
*/
export declare function checkRemoveUnbreakableElement(jodit: IJodit, fakeNode: Node, backspace: boolean): boolean;

View File

@@ -0,0 +1,39 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { INSEPARABLE_TAGS } from "../../../core/constants.js";
import { Dom } from "../../../core/dom/dom.js";
import { checkRemoveEmptyParent } from "./check-remove-empty-parent.js";
/**
* Check possibility inseparable Element can be removed (img, hr etc.)
*
* @example
* ```html
* <p>first second <img>| stop</p>
* ```
* result
* ```html
* <p>first second | stop</p>
* ```
*
* @private
*/
export function checkRemoveUnbreakableElement(jodit, fakeNode, backspace) {
const neighbor = Dom.findSibling(fakeNode, backspace);
if (Dom.isElement(neighbor) &&
(Dom.isTag(neighbor, INSEPARABLE_TAGS) || Dom.isEmpty(neighbor))) {
Dom.safeRemove(neighbor);
if (Dom.isTag(neighbor, 'br') &&
!Dom.findNotEmptySibling(fakeNode, false)) {
Dom.after(fakeNode, jodit.createInside.element('br'));
}
jodit.s.setCursorBefore(fakeNode);
if (Dom.isTag(neighbor, 'br')) {
checkRemoveEmptyParent(jodit, fakeNode, backspace);
}
return true;
}
return false;
}

View File

@@ -0,0 +1,24 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* Inside the CELL table - nothing to do
*
* @example
* ```html
* <table><tr><td>|test</td></tr></table>
* ```
* result
* ```html
* <table><tr><td>|test</td></tr></table>
* ```
*
* @private
*/
export declare function checkTableCell(jodit: IJodit, fakeNode: Node): boolean;

View File

@@ -0,0 +1,27 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../../core/dom/dom.js";
/**
* Inside the CELL table - nothing to do
*
* @example
* ```html
* <table><tr><td>|test</td></tr></table>
* ```
* result
* ```html
* <table><tr><td>|test</td></tr></table>
* ```
*
* @private
*/
export function checkTableCell(jodit, fakeNode) {
const cell = fakeNode.parentElement;
if (Dom.isCell(cell)) {
return true;
}
return false;
}

View File

@@ -0,0 +1,24 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit } from "../../../types/index";
/**
* For the first item in a list on backspace, try to move his content in new P
*
* @example
* ```html
* <ul><li>|first</li><li>second</li></ul>
* ```
* Result
* ```html
* <p>|first</p><ul><li>second</li></ul>
* ```
*
* @private
*/
export declare function checkUnwrapFirstListItem(jodit: IJodit, fakeNode: Node, backspace: boolean): boolean;

View File

@@ -0,0 +1,41 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../../core/dom/dom.js";
import { call } from "../../../core/helpers/utils/index.js";
/**
* For the first item in a list on backspace, try to move his content in new P
*
* @example
* ```html
* <ul><li>|first</li><li>second</li></ul>
* ```
* Result
* ```html
* <p>|first</p><ul><li>second</li></ul>
* ```
*
* @private
*/
export function checkUnwrapFirstListItem(jodit, fakeNode, backspace) {
var _a;
const li = Dom.closest(fakeNode, Dom.isElement, jodit.editor);
const { s } = jodit;
if (Dom.isLeaf(li) &&
((_a = li === null || li === void 0 ? void 0 : li.parentElement) === null || _a === void 0 ? void 0 : _a[backspace ? 'firstElementChild' : 'lastElementChild']) === li &&
s.cursorInTheEdge(backspace, li)) {
const ul = li.parentElement;
const p = jodit.createInside.element(jodit.o.enterBlock);
call(backspace ? Dom.before : Dom.after, ul, p);
Dom.moveContent(li, p);
Dom.safeRemove(li);
if (Dom.isEmpty(ul)) {
Dom.safeRemove(ul);
}
call(backspace ? s.setCursorBefore : s.setCursorAfter, fakeNode);
return true;
}
return false;
}

View File

@@ -0,0 +1,11 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { checkRemoveChar } from "./check-remove-char";
import { checkRemoveContentNotEditable } from "./check-remove-content-not-editable";
/**
* @private
*/
export declare const cases: (typeof checkRemoveContentNotEditable | typeof checkRemoveChar)[];

View File

@@ -0,0 +1,31 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import { checkJoinNeighbors } from "./check-join-neighbors.js";
import { checkJoinTwoLists } from "./check-join-two-lists.js";
import { checkRemoveChar } from "./check-remove-char.js";
import { checkRemoveContentNotEditable } from "./check-remove-content-not-editable.js";
import { checkRemoveEmptyNeighbor } from "./check-remove-empty-neighbor.js";
import { checkRemoveEmptyParent } from "./check-remove-empty-parent.js";
import { checkRemoveUnbreakableElement } from "./check-remove-unbreakable-element.js";
import { checkTableCell } from "./check-table-cell.js";
import { checkUnwrapFirstListItem } from "./check-unwrap-first-list-item.js";
/**
* @private
*/
export const cases = [
checkRemoveUnbreakableElement,
checkRemoveContentNotEditable,
checkRemoveChar,
checkTableCell,
checkRemoveEmptyParent,
checkRemoveEmptyNeighbor,
checkJoinTwoLists,
checkJoinNeighbors,
checkUnwrapFirstListItem
];

20
node_modules/jodit/esm/plugins/backspace/config.d.ts generated vendored Normal file
View File

@@ -0,0 +1,20 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
declare module 'jodit/config' {
interface Config {
delete: {
hotkeys: {
delete: string[];
deleteWord: string[];
deleteSentence: string[];
backspace: string[];
backspaceWord: string[];
backspaceSentence: string[];
};
};
}
}
export {};

19
node_modules/jodit/esm/plugins/backspace/config.js generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import { Config } from "../../config.js";
Config.prototype.delete = {
hotkeys: {
delete: ['delete', 'cmd+backspace'],
deleteWord: ['ctrl+delete', 'cmd+alt+backspace', 'ctrl+alt+backspace'],
deleteSentence: ['ctrl+shift+delete', 'cmd+shift+delete'],
backspace: ['backspace'],
backspaceWord: ['ctrl+backspace'],
backspaceSentence: ['ctrl+shift+backspace', 'cmd+shift+backspace']
}
};

19
node_modules/jodit/esm/plugins/backspace/helpers.d.ts generated vendored Normal file
View File

@@ -0,0 +1,19 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
import type { IJodit, Nullable } from "../../types/index";
/**
* Finds the nearest neighbor that would be in the maximum nesting depth.
* Ie if neighbor `<DIV><SPAN>Text` then return Text node.
* @private
*/
export declare function findMostNestedNeighbor(node: Node, right: boolean, root: HTMLElement, onlyInlide?: boolean): Nullable<Node>;
/**
* @private
*/
export declare function getMoveFilter(jodit: IJodit): (node: Node) => boolean;

35
node_modules/jodit/esm/plugins/backspace/helpers.js generated vendored Normal file
View File

@@ -0,0 +1,35 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
import { Dom } from "../../core/dom/index.js";
/**
* Finds the nearest neighbor that would be in the maximum nesting depth.
* Ie if neighbor `<DIV><SPAN>Text` then return Text node.
* @private
*/
export function findMostNestedNeighbor(node, right, root, onlyInlide = false) {
const nextChild = (node) => right ? node.firstChild : node.lastChild;
let next = Dom.findNotEmptyNeighbor(node, !right, root);
if (onlyInlide && Dom.isElement(next) && !Dom.isInlineBlock(next)) {
return null;
}
if (next) {
do {
if (nextChild(next)) {
next = nextChild(next);
}
else {
return next;
}
} while (next);
}
return null;
}
/**
* @private
*/
export function getMoveFilter(jodit) {
return (node) => jodit.e.fire('backSpaceIsMovedIgnore', node) !== true;
}

View File

@@ -0,0 +1,50 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
/**
* @module plugins/backspace
*/
export type DeleteMode = 'char' | 'word' | 'sentence';
declare module 'jodit/types/events' {
interface IEventEmitter {
/**
* Enables content preparation prior to deletion, or allows for a complete
* override of the deletion logic if true is returned.
*/
on(event: 'backSpaceBeforeCases', callback: (backspace: boolean, fakeNode: Node) => void | true): this;
/**
* Triggers after the Backspace or Delete key has been pressed and processed.
*/
on(event: 'backSpaceAfterDelete', callback: (backspace: boolean, fakeNode: Node) => void): this;
}
}
declare module 'jodit/types/jodit' {
interface IJodit {
/**
* Backspace plugin: Deletes the next character or selected text.
*/
execCommand(command: 'deleteButton'): void;
/**
* Backspace plugin: Deletes the previous character or selected text.
*/
execCommand(command: 'backspaceButton'): void;
/**
* Backspace plugin: Deletes the next word or selected text.
*/
execCommand(command: 'deleteWordButton'): void;
/**
* Backspace plugin: Deletes the previous word or selected text.
*/
execCommand(command: 'backspaceWordButton'): void;
/**
* Backspace plugin: Deletes the next sentence or selected text.
*/
execCommand(command: 'deleteSentenceButton'): void;
/**
* Backspace plugin: Deletes the previous sentence or selected text.
*/
execCommand(command: 'backspaceSentenceButton'): void;
}
}

View File

@@ -0,0 +1,6 @@
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2025 Valeriy Chupurnov. All rights reserved. https://xdsoft.net
*/
export {};