mirror of
https://github.com/codex-team/editor.js
synced 2026-03-17 16:10:07 +01:00
chore: restore execCommand in selection.ts
This commit is contained in:
parent
7940e123e5
commit
6a6c8731f5
1 changed files with 11 additions and 102 deletions
|
|
@ -56,6 +56,12 @@ export default class SelectionUtils {
|
|||
*/
|
||||
public isFakeBackgroundEnabled = false;
|
||||
|
||||
/**
|
||||
* Native Document's commands for fake background
|
||||
*/
|
||||
private readonly commandBackground: string = 'backColor';
|
||||
private readonly commandRemoveFormat: string = 'removeFormat';
|
||||
|
||||
/**
|
||||
* Editor styles
|
||||
*
|
||||
|
|
@ -173,9 +179,9 @@ export default class SelectionUtils {
|
|||
*
|
||||
* @param range - range to check
|
||||
*/
|
||||
public static isRangeAtEditor(range: Range | null): boolean {
|
||||
public static isRangeAtEditor(range: Range): boolean | void {
|
||||
if (!range) {
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
let selectedNode: Node | null = range.startContainer;
|
||||
|
|
@ -239,7 +245,7 @@ export default class SelectionUtils {
|
|||
height: 0,
|
||||
} as DOMRect;
|
||||
|
||||
if (sel && 'type' in sel && sel.type !== 'Control') {
|
||||
if (sel && sel.type !== 'Control') {
|
||||
sel = sel as MSSelection;
|
||||
range = sel.createRange() as TextRange;
|
||||
rect.x = range.boundingLeft;
|
||||
|
|
@ -412,111 +418,14 @@ export default class SelectionUtils {
|
|||
}
|
||||
|
||||
this.isFakeBackgroundEnabled = false;
|
||||
|
||||
const selection = window.getSelection();
|
||||
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
const container = range.commonAncestorContainer;
|
||||
const walkerContainer = container.nodeType === Node.TEXT_NODE && container.parentNode
|
||||
? container.parentNode
|
||||
: container;
|
||||
const walker = document.createTreeWalker(
|
||||
walkerContainer,
|
||||
NodeFilter.SHOW_ELEMENT,
|
||||
null
|
||||
);
|
||||
|
||||
const elementsToProcess: HTMLElement[] = [];
|
||||
let node: Node | null = walker.currentNode as Node;
|
||||
|
||||
// Collect all elements in the range
|
||||
while (node) {
|
||||
if (node instanceof HTMLElement && range.intersectsNode(node)) {
|
||||
elementsToProcess.push(node);
|
||||
}
|
||||
node = walker.nextNode();
|
||||
}
|
||||
|
||||
// Also check text nodes' parent elements
|
||||
if (range.startContainer.nodeType === Node.TEXT_NODE && range.startContainer.parentElement) {
|
||||
if (!elementsToProcess.includes(range.startContainer.parentElement)) {
|
||||
elementsToProcess.push(range.startContainer.parentElement);
|
||||
}
|
||||
}
|
||||
if (range.endContainer.nodeType === Node.TEXT_NODE && range.endContainer.parentElement) {
|
||||
if (!elementsToProcess.includes(range.endContainer.parentElement)) {
|
||||
elementsToProcess.push(range.endContainer.parentElement);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove background-color style from collected elements
|
||||
elementsToProcess.forEach((element) => {
|
||||
const bgColor = element.style.backgroundColor;
|
||||
const isFakeBackground = bgColor === '#a8d6ff' || bgColor === 'rgb(168, 214, 255)';
|
||||
|
||||
if (isFakeBackground) {
|
||||
// If it's a span with the fake background color, unwrap it
|
||||
if (element.tagName.toLowerCase() === 'span') {
|
||||
const parent = element.parentNode;
|
||||
|
||||
if (parent) {
|
||||
while (element.firstChild) {
|
||||
parent.insertBefore(element.firstChild, element);
|
||||
}
|
||||
parent.removeChild(element);
|
||||
parent.normalize();
|
||||
}
|
||||
} else {
|
||||
// Otherwise, just remove the background-color style
|
||||
element.style.backgroundColor = '';
|
||||
if (!element.style.cssText.trim()) {
|
||||
element.removeAttribute('style');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
document.execCommand(this.commandRemoveFormat);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets fake background
|
||||
*/
|
||||
public setFakeBackground(): void {
|
||||
const selection = window.getSelection();
|
||||
|
||||
if (!selection || selection.rangeCount === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range = selection.getRangeAt(0);
|
||||
|
||||
// If range is collapsed (no selection), do nothing
|
||||
if (range.collapsed) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if selection is already wrapped in a single element
|
||||
const contents = range.extractContents();
|
||||
const span = document.createElement('span');
|
||||
|
||||
span.style.backgroundColor = '#a8d6ff';
|
||||
span.appendChild(contents);
|
||||
range.insertNode(span);
|
||||
|
||||
// Normalize to merge adjacent text nodes
|
||||
if (span.parentNode) {
|
||||
span.parentNode.normalize();
|
||||
}
|
||||
|
||||
// Update selection to include the new span
|
||||
const newRange = document.createRange();
|
||||
|
||||
newRange.selectNodeContents(span);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(newRange);
|
||||
document.execCommand(this.commandBackground, false, '#a8d6ff');
|
||||
|
||||
this.isFakeBackgroundEnabled = true;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue