schlechtenburg/packages/core/lib/rich-text/selection.ts

94 lines
2.2 KiB
TypeScript

/*
* Copyright notice:
*
* Large parts of this file are heavily inspired if not downright copied from editor.js,
* copyright MIT.
* https://editorjs.io/
*/
import { isElement } from './dom';
export const getSelection = globalThis.getSelection ? globalThis.getSelection : () => null;
/**
* Returns range from passed Selection object
*
* @param selection - Selection object to get Range from
*/
export const getRangeFromSelection = (selection: Selection): Range|null => {
return selection && selection.rangeCount ? selection.getRangeAt(0) : null;
}
/**
* Returns selected anchor element
*
* @returns {Element|null}
*/
export const getAnchorElementForSelection = (selection: Selection): Element | null => {
const anchorNode = selection.anchorNode;
if (!anchorNode) {
return null;
}
if (!isElement(anchorNode)) {
return anchorNode.parentElement;
} else {
return anchorNode;
}
}
/**
* Calculates position and size of selected text
*
* @returns {DOMRect}
*/
export const getRect = (selection: Selection): DOMRect => {
const defaultRect = {
x: 0,
y: 0,
width: 0,
height: 0,
} as DOMRect;
if (selection.rangeCount === null || isNaN(selection.rangeCount)) {
console.warn('Method SelectionUtils.rangeCount is not supported');
return defaultRect;
}
if (selection.rangeCount === 0) {
return defaultRect;
}
const range = selection.getRangeAt(0).cloneRange() as Range;
let rect = { ...defaultRect };
if (range.getBoundingClientRect) {
rect = range.getBoundingClientRect() as DOMRect;
}
// Fall back to inserting a temporary element
if (rect.x === 0 && rect.y === 0) {
const span = document.createElement('span');
if (span.getBoundingClientRect) {
// Ensure span has dimensions and position by
// adding a zero-width space character
span.appendChild(document.createTextNode('\u200b'));
range.insertNode(span);
rect = span.getBoundingClientRect() as DOMRect;
const spanParent = span.parentNode;
if (spanParent) {
spanParent.removeChild(span);
// Glue any broken text nodes back together
spanParent.normalize();
}
}
}
return rect;
};