139 lines
4.5 KiB
JavaScript
139 lines
4.5 KiB
JavaScript
/*!
|
|
* 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 { globalWindow } from "../../../core/constants.js";
|
|
import { Dom } from "../../../core/dom/dom.js";
|
|
import { $$ } from "../../../core/helpers/utils/selector.js";
|
|
/**
|
|
* @private
|
|
*/
|
|
const TMP_ATTR = 'jd-tmp-selection';
|
|
/**
|
|
* @private
|
|
*/
|
|
export function highlightTextRanges(jodit, rng, restRanges, ci, root) {
|
|
if (rng.startContainer.nodeValue == null ||
|
|
rng.endContainer.nodeValue == null) {
|
|
return;
|
|
}
|
|
if (checkNativeSelectionMethod(jodit, rng, restRanges)) {
|
|
return;
|
|
}
|
|
const span = ci.element('span', {
|
|
[TMP_ATTR]: true
|
|
});
|
|
Dom.markTemporary(span);
|
|
normalizeRanges(rng, restRanges, ci);
|
|
let next = rng.startContainer;
|
|
do {
|
|
if (!next) {
|
|
break;
|
|
}
|
|
if (Dom.isText(next) && !isSelectionWrapper(next.parentNode)) {
|
|
Dom.wrap(next, span.cloneNode(), ci);
|
|
}
|
|
if (next === rng.endContainer) {
|
|
break;
|
|
}
|
|
let step = next.firstChild || next.nextSibling;
|
|
if (!step) {
|
|
while (next && !next.nextSibling && next !== root) {
|
|
next = next.parentNode;
|
|
}
|
|
step = next === null || next === void 0 ? void 0 : next.nextSibling;
|
|
}
|
|
next = step;
|
|
} while (next && next !== root);
|
|
}
|
|
/**
|
|
* @private
|
|
*/
|
|
export function getSelectionWrappers(root) {
|
|
return $$(`[${TMP_ATTR}]`, root);
|
|
}
|
|
/**
|
|
* @private
|
|
*/
|
|
export function clearSelectionWrappers(jodit) {
|
|
getSelectionWrappers(jodit.editor).forEach(span => Dom.unwrap(span));
|
|
clearNativeSelection(jodit);
|
|
}
|
|
/**
|
|
* @private
|
|
*/
|
|
export function clearSelectionWrappersFromHTML(root) {
|
|
return root.replace(RegExp(`<span[^>]+${TMP_ATTR}[^>]+>(.*?)</span>`, 'g'), '$1');
|
|
}
|
|
/**
|
|
* @private
|
|
*/
|
|
function isSelectionWrapper(node) {
|
|
return Dom.isElement(node) && node.hasAttribute(TMP_ATTR);
|
|
}
|
|
function checkNativeSelectionMethod(jodit, rng, restRanges) {
|
|
if (jodit.o.search.useCustomHighlightAPI &&
|
|
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
|
|
globalWindow &&
|
|
typeof globalWindow.Highlight !== 'undefined') {
|
|
const ranges = [rng, ...restRanges].map(rng => {
|
|
const range = jodit.selection.createRange();
|
|
range.setStart(rng.startContainer, rng.startOffset);
|
|
range.setEnd(rng.endContainer, rng.endOffset);
|
|
return range;
|
|
});
|
|
const searchHighlight = new Highlight(...ranges);
|
|
// @ts-ignore
|
|
CSS.highlights.clear();
|
|
// @ts-ignore
|
|
CSS.highlights.set('jodit-search-result', searchHighlight);
|
|
restRanges.length = 0;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
export function clearNativeSelection(jodit) {
|
|
if (jodit.o.search.useCustomHighlightAPI &&
|
|
// @ts-ignore Because Highlight is not defined in the types TS 5.3.3
|
|
globalWindow &&
|
|
typeof globalWindow.Highlight !== 'undefined') {
|
|
// @ts-ignore
|
|
CSS.highlights.clear();
|
|
}
|
|
}
|
|
function normalizeRanges(rng, restRanges, ci) {
|
|
const startText = rng.startContainer.nodeValue;
|
|
let diff = 0;
|
|
if (rng.startOffset !== 0) {
|
|
const text = ci.text(startText.substring(0, rng.startOffset));
|
|
rng.startContainer.nodeValue = startText.substring(rng.startOffset);
|
|
Dom.before(rng.startContainer, text);
|
|
if (rng.startContainer === rng.endContainer) {
|
|
diff = rng.startOffset;
|
|
rng.endOffset -= diff;
|
|
}
|
|
rng.startOffset = 0;
|
|
}
|
|
const endText = rng.endContainer.nodeValue;
|
|
if (rng.endOffset !== endText.length) {
|
|
const text = ci.text(endText.substring(rng.endOffset));
|
|
rng.endContainer.nodeValue = endText.substring(0, rng.endOffset);
|
|
Dom.after(rng.endContainer, text);
|
|
for (const range of restRanges) {
|
|
if (range.startContainer === rng.endContainer) {
|
|
range.startContainer = text;
|
|
range.startOffset = range.startOffset - rng.endOffset - diff;
|
|
if (range.endContainer === rng.endContainer) {
|
|
range.endContainer = text;
|
|
range.endOffset = range.endOffset - rng.endOffset - diff;
|
|
}
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
rng.endOffset = rng.endContainer.nodeValue.length;
|
|
}
|
|
}
|