@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
209 lines (208 loc) • 5.97 kB
JavaScript
// packages/editor/src/components/collaborators-overlay/compute-selection.ts
import { privateApis as coreDataPrivateApis } from "@wordpress/core-data";
import { unlock } from "../../lock-unlock.mjs";
import {
getCursorPosition,
getOrderedBlockRange,
getSelectionRects
} from "./cursor-dom-utils.mjs";
var { SelectionDirection, SelectionType } = unlock(
coreDataPrivateApis
);
function resolveTargetElement(editorDocument, resolvedSelection) {
if (!resolvedSelection.localClientId) {
return null;
}
const blockElement = editorDocument.querySelector(
`[data-block="${resolvedSelection.localClientId}"]`
);
if (!blockElement || !resolvedSelection.attributeKey) {
return blockElement;
}
const attrKey = CSS.escape(resolvedSelection.attributeKey);
const byKey = blockElement.querySelector(
`[data-wp-block-attribute-key="${attrKey}"]`
);
if (byKey) {
return byKey;
}
const editable = blockElement.querySelector(
'[contenteditable="true"]'
);
if (editable) {
return editable;
}
const textEl = blockElement.querySelector(
"p, h1, h2, h3, h4, h5, h6, pre, blockquote, td, th, li, figcaption"
);
return textEl ?? blockElement;
}
function computeSelectionVisual(selection, start, end, overlayContext) {
if (selection.type === SelectionType.None || selection.type === SelectionType.WholeBlock) {
return {};
}
if (selection.type === SelectionType.Cursor) {
return computeCursorOnly(start, overlayContext);
}
if (!end) {
return {};
}
return computeTextSelection(selection, start, end, overlayContext);
}
function computeCursorOnly(start, overlayContext) {
if (!start.localClientId) {
return {};
}
const targetElement = resolveTargetElement(
overlayContext.editorDocument,
start
);
return {
coords: getCursorPosition(
start.richTextOffset,
targetElement,
overlayContext.editorDocument,
overlayContext.overlayRect
)
};
}
function computeTextSelection(selection, start, end, overlayContext) {
if (!start.localClientId || !end.localClientId) {
return {};
}
const isReverse = selection.selectionDirection === SelectionDirection.Backward;
const activeEnd = isReverse ? start : end;
if (selection.type === SelectionType.SelectionInOneBlock) {
if (start.richTextOffset === null || end.richTextOffset === null) {
return {};
}
const result = computeSingleBlockRects(start, end, overlayContext);
if (result.rects.length > 0) {
return {
coords: getCursorPosition(
activeEnd.richTextOffset,
result.blockElement,
overlayContext.editorDocument,
overlayContext.overlayRect
),
selectionRects: result.rects
};
}
return {
coords: getCursorPosition(
start.richTextOffset,
resolveTargetElement(overlayContext.editorDocument, start),
overlayContext.editorDocument,
overlayContext.overlayRect
)
};
}
return computeMultiBlockOverlayRects(start, end, overlayContext);
}
function blockBoundingRect(blockEl, overlayRect) {
const r = blockEl.getBoundingClientRect();
return {
x: r.left - overlayRect.left,
y: r.top - overlayRect.top,
width: r.width,
height: r.height
};
}
function computeMultiBlockOverlayRects(start, end, overlayContext) {
const { editorDocument, overlayRect } = overlayContext;
const range = getOrderedBlockRange(
start.localClientId,
end.localClientId,
editorDocument
);
if (!range) {
return {};
}
const docFirst = range.firstId === start.localClientId ? start : end;
const docLast = range.firstId === start.localClientId ? end : start;
const {
firstEl: docFirstEl,
lastEl: docLastEl,
middleEls,
sameContainer
} = range;
if (sameContainer) {
return docFirstEl.innerText?.trim() ? {
selectionRects: [
blockBoundingRect(docFirstEl, overlayRect)
]
} : {};
}
const MAX = Number.MAX_SAFE_INTEGER;
const rects = [];
if (docFirstEl.innerText?.trim()) {
const firstOffset = docFirst.richTextOffset;
if (firstOffset === null || firstOffset === 0) {
rects.push(blockBoundingRect(docFirstEl, overlayRect));
} else {
const el = resolveTargetElement(editorDocument, docFirst);
const textRects = el ? getSelectionRects(
el,
firstOffset,
MAX,
editorDocument,
overlayRect
) : null;
rects.push(
...textRects ?? [
blockBoundingRect(docFirstEl, overlayRect)
]
);
}
}
for (const blockEl of middleEls) {
if (blockEl.innerText?.trim()) {
rects.push(blockBoundingRect(blockEl, overlayRect));
}
}
if (docLastEl.innerText?.trim()) {
const lastOffset = docLast.richTextOffset;
if (lastOffset === null) {
rects.push(blockBoundingRect(docLastEl, overlayRect));
} else if (lastOffset > 0) {
const el = resolveTargetElement(editorDocument, docLast);
const textRects = el ? getSelectionRects(
el,
0,
lastOffset,
editorDocument,
overlayRect
) : null;
rects.push(
...textRects ?? [
blockBoundingRect(docLastEl, overlayRect)
]
);
}
}
return rects.length > 0 ? { selectionRects: rects } : {};
}
function computeSingleBlockRects(start, end, overlayContext) {
const blockElement = resolveTargetElement(
overlayContext.editorDocument,
start
);
if (!blockElement || start.richTextOffset === null || end.richTextOffset === null) {
return { rects: [], blockElement: null };
}
return {
rects: getSelectionRects(
blockElement,
start.richTextOffset,
end.richTextOffset,
overlayContext.editorDocument,
overlayContext.overlayRect
) ?? [],
blockElement
};
}
export {
computeSelectionVisual,
resolveTargetElement
};
//# sourceMappingURL=compute-selection.mjs.map