Skip to content

Commit

Permalink
Improve getDOMInsertPointRect (#2705)
Browse files Browse the repository at this point in the history
* Improve getDOMInsertPointRect

* fix build
  • Loading branch information
JiuqingSong committed Jun 17, 2024
1 parent 8f7e125 commit 5c39847
Showing 1 changed file with 25 additions and 32 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,18 @@ import type { DOMInsertPoint, Rect } from 'roosterjs-content-model-types';
* @param pos The input DOM insert point
*/
export function getDOMInsertPointRect(doc: Document, pos: DOMInsertPoint): Rect | null {
let { node, offset } = pos;
const range = doc.createRange();

range.setStart(node, offset);

// 1) try to get rect using range.getBoundingClientRect()
let rect = normalizeRect(range.getBoundingClientRect());
return (
tryGetRectFromPos(pos, range) ?? // 1. try get from the pos directly using getBoundingClientRect or getClientRects
tryGetRectFromPos((pos = normalizeInsertPoint(pos)), range) ?? // 2. try get normalized pos, this can work when insert point is inside text node
tryGetRectFromNode(pos.node) // 3. fallback to node rect using getBoundingClientRect
);
}

if (rect) {
return rect;
}
function normalizeInsertPoint(pos: DOMInsertPoint) {
let { node, offset } = pos;

// 2) try to get rect using range.getClientRects
while (node.lastChild) {
if (offset == node.childNodes.length) {
node = node.lastChild;
Expand All @@ -31,34 +30,28 @@ export function getDOMInsertPointRect(doc: Document, pos: DOMInsertPoint): Rect
}
}

const rects = range.getClientRects && range.getClientRects();
rect = rects && rects.length == 1 ? normalizeRect(rects[0]) : null;
if (rect) {
return rect;
}
return { node, offset };
}

// 3) if node is text node, try inserting a SPAN and get the rect of SPAN for others
if (isNodeOfType(node, 'TEXT_NODE')) {
const span = node.ownerDocument.createElement('span');
function tryGetRectFromPos(pos: DOMInsertPoint, range: Range): Rect | null {
const { node, offset } = pos;

span.textContent = '\u200b';
range.insertNode(span);
rect = normalizeRect(span.getBoundingClientRect());
span.parentNode?.removeChild(span);
range.setStart(node, offset);
range.setEnd(node, offset);

if (rect) {
return rect;
}
}
const rect = normalizeRect(range.getBoundingClientRect());

// 4) try getBoundingClientRect on element
if (isNodeOfType(node, 'ELEMENT_NODE') && node.getBoundingClientRect) {
rect = normalizeRect(node.getBoundingClientRect());
if (rect) {
return rect;
} else {
const rects = range.getClientRects && range.getClientRects();

if (rect) {
return rect;
}
return rects && rects.length == 1 ? normalizeRect(rects[0]) : null;
}
}

return null;
function tryGetRectFromNode(node: Node) {
return isNodeOfType(node, 'ELEMENT_NODE') && node.getBoundingClientRect
? normalizeRect(node.getBoundingClientRect())
: null;
}

0 comments on commit 5c39847

Please sign in to comment.