94 lines
2.2 KiB
TypeScript
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;
|
||
|
};
|