UNPKG

@wordpress/editor

Version:
244 lines (242 loc) 7.65 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // packages/editor/src/components/collaborators-overlay/cursor-dom-utils.ts var cursor_dom_utils_exports = {}; __export(cursor_dom_utils_exports, { findInnerBlockOffset: () => findInnerBlockOffset, getBlocksBetween: () => getBlocksBetween, getCursorPosition: () => getCursorPosition, getFullBlockSelectionRects: () => getFullBlockSelectionRects, getSelectionRects: () => getSelectionRects, isNodeBefore: () => isNodeBefore }); module.exports = __toCommonJS(cursor_dom_utils_exports); 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; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { findInnerBlockOffset, getBlocksBetween, getCursorPosition, getFullBlockSelectionRects, getSelectionRects, isNodeBefore }); //# sourceMappingURL=cursor-dom-utils.cjs.map