UNPKG

jodit

Version:

Jodit is an awesome and useful wysiwyg editor with filebrowser

161 lines (160 loc) 5.68 kB
/*! * 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); } }