jodit
Version:
Jodit is an awesome and useful wysiwyg editor with filebrowser
161 lines (160 loc) • 5.68 kB
JavaScript
/*!
* Jodit Editor (https://xdsoft.net/jodit/)
* Released under MIT see LICENSE.txt in the project root for license information.
* Copyright (c) 2013-2026 Valerii 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);
}
}