@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
214 lines (213 loc) • 6.35 kB
JavaScript
// packages/editor/src/components/collaborators-overlay/cursor-dom-utils.ts
var MAX_NODE_OFFSET_COUNT = 500;
var getCursorPosition = (absolutePositionIndex, blockElement, editorDocument, overlayRect) => {
if (absolutePositionIndex === null || !blockElement) {
return null;
}
return getOffsetPositionInBlock(
blockElement,
absolutePositionIndex,
editorDocument,
overlayRect
) ?? null;
};
var getOffsetPositionInBlock = (blockElement, charOffset, editorDocument, overlayRect) => {
const { node, offset } = findInnerBlockOffset(
blockElement,
charOffset,
editorDocument
);
const cursorRange = editorDocument.createRange();
try {
cursorRange.setStart(node, offset);
} catch (error) {
return null;
}
cursorRange.collapse(true);
const cursorRect = cursorRange.getBoundingClientRect();
const blockRect = blockElement.getBoundingClientRect();
let cursorX = 0;
let cursorY = 0;
if (cursorRect.x === 0 && cursorRect.y === 0 && cursorRect.width === 0 && cursorRect.height === 0) {
cursorX = blockRect.left - overlayRect.left;
cursorY = blockRect.top - overlayRect.top;
} else {
cursorX = cursorRect.left - overlayRect.left;
cursorY = cursorRect.top - overlayRect.top;
}
let cursorHeight = cursorRect.height;
if (cursorHeight === 0) {
const view = editorDocument.defaultView ?? window;
cursorHeight = parseInt(view.getComputedStyle(blockElement).lineHeight, 10) || blockRect.height;
}
return {
x: cursorX,
y: cursorY,
height: cursorHeight
};
};
var getSelectionRects = (blockElement, startOffset, endOffset, editorDocument, overlayRect) => {
let normalizedStart = startOffset;
let normalizedEnd = endOffset;
if (normalizedStart > normalizedEnd) {
[normalizedStart, normalizedEnd] = [normalizedEnd, normalizedStart];
}
const startPos = findInnerBlockOffset(
blockElement,
normalizedStart,
editorDocument
);
const endPos = findInnerBlockOffset(
blockElement,
normalizedEnd,
editorDocument
);
const range = editorDocument.createRange();
try {
range.setStart(startPos.node, startPos.offset);
range.setEnd(endPos.node, endPos.offset);
} catch {
return null;
}
const clientRects = range.getClientRects();
const rects = [];
for (const rect of clientRects) {
if (rect.width === 0 && rect.height === 0) {
continue;
}
const x = rect.left - overlayRect.left;
const y = rect.top - overlayRect.top;
const isDuplicate = rects.some(
(r) => r.x === x && r.y === y && r.width === rect.width && r.height === rect.height
);
if (isDuplicate) {
continue;
}
rects.push({
x,
y,
width: rect.width,
height: rect.height
});
}
return rects.length > 0 ? rects : null;
};
var getFullBlockSelectionRects = (blockElement, editorDocument, overlayRect) => {
const range = editorDocument.createRange();
range.selectNodeContents(blockElement);
const clientRects = range.getClientRects();
const rects = [];
for (const rect of clientRects) {
if (rect.width === 0 && rect.height === 0) {
continue;
}
rects.push({
x: rect.left - overlayRect.left,
y: rect.top - overlayRect.top,
width: rect.width,
height: rect.height
});
}
if (rects.length === 0) {
const blockRect = blockElement.getBoundingClientRect();
if (blockRect.width > 0 && blockRect.height > 0) {
rects.push({
x: blockRect.left - overlayRect.left,
y: blockRect.top - overlayRect.top,
width: blockRect.width,
height: blockRect.height
});
}
}
return rects;
};
var getBlocksBetween = (startBlockId, endBlockId, editorDocument) => {
const allBlocks = editorDocument.querySelectorAll("[data-block]");
let startIndex = -1;
let endIndex = -1;
for (let i = 0; i < allBlocks.length; i++) {
const blockId = allBlocks[i].getAttribute("data-block");
if (blockId === startBlockId) {
startIndex = i;
}
if (blockId === endBlockId) {
endIndex = i;
}
}
if (startIndex === -1 || endIndex === -1) {
return [];
}
if (startIndex > endIndex) {
[startIndex, endIndex] = [endIndex, startIndex];
}
const result = [];
for (let i = startIndex + 1; i < endIndex; i++) {
result.push(allBlocks[i]);
}
return result;
};
var findInnerBlockOffset = (blockElement, offset, editorDocument) => {
const treeWalker = editorDocument.createTreeWalker(
blockElement,
NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT
// eslint-disable-line no-bitwise
);
let currentOffset = 0;
let lastTextNode = null;
let node = null;
let nodeCount = 1;
while (node = treeWalker.nextNode()) {
nodeCount++;
if (nodeCount > MAX_NODE_OFFSET_COUNT) {
if (lastTextNode) {
return { node: lastTextNode, offset: 0 };
}
return { node: blockElement, offset: 0 };
}
const nodeLength = node.nodeValue?.length ?? 0;
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.nodeName === "BR") {
if (currentOffset + 1 >= offset) {
const nodeAfterBr = treeWalker.nextNode();
if (nodeAfterBr?.nodeType === Node.TEXT_NODE) {
return { node: nodeAfterBr, offset: 0 };
} else if (lastTextNode) {
return {
node: lastTextNode,
offset: lastTextNode.nodeValue?.length ?? 0
};
}
return { node: blockElement, offset: 0 };
}
currentOffset += 1;
continue;
} else {
continue;
}
}
if (nodeLength === 0) {
continue;
}
if (currentOffset + nodeLength >= offset) {
return { node, offset: offset - currentOffset };
}
currentOffset += nodeLength;
if (node.nodeType === Node.TEXT_NODE) {
lastTextNode = node;
}
}
if (lastTextNode && lastTextNode.nodeValue?.length) {
return { node: lastTextNode, offset: lastTextNode.nodeValue.length };
}
return { node: blockElement, offset: 0 };
};
var isNodeBefore = (a, b) => a.compareDocumentPosition(b) === Node.DOCUMENT_POSITION_FOLLOWING;
export {
findInnerBlockOffset,
getBlocksBetween,
getCursorPosition,
getFullBlockSelectionRects,
getSelectionRects,
isNodeBefore
};
//# sourceMappingURL=cursor-dom-utils.mjs.map