@wordpress/core-data
Version:
Access to and manipulation of core WordPress entities.
128 lines (127 loc) • 3.65 kB
JavaScript
// packages/core-data/src/utils/crdt-utils.ts
import { Y } from "@wordpress/sync";
import { create, insert, toHTMLString } from "@wordpress/rich-text";
import { CRDT_RECORD_MAP_KEY } from "../sync.mjs";
function getRootMap(doc, key) {
return doc.getMap(key);
}
function createYMap(partial = {}) {
return new Y.Map(Object.entries(partial));
}
function isYMap(value) {
return value instanceof Y.Map;
}
function asRichTextOffset(offset) {
return offset;
}
function asHtmlStringIndex(index) {
return index;
}
function getYTextByAttributeKey(attributes, attributeKey) {
const directValue = attributes.get(attributeKey);
if (directValue instanceof Y.Text) {
return directValue;
}
let value = attributes;
for (const pathPart of attributeKey.split(".")) {
if (value instanceof Y.Map) {
value = value.get(pathPart);
} else if (value instanceof Y.Array) {
const index = Number.parseInt(pathPart, 10);
if (!Number.isSafeInteger(index) || index < 0 || index.toString() !== pathPart) {
return null;
}
value = value.get(index);
} else {
return null;
}
}
return value instanceof Y.Text ? value : null;
}
function findBlockByClientIdInDoc(blockId, ydoc) {
const ymap = getRootMap(ydoc, CRDT_RECORD_MAP_KEY);
const blocks = ymap.get("blocks");
if (!(blocks instanceof Y.Array)) {
return null;
}
return findBlockByClientIdInBlocks(blockId, blocks);
}
var MARKER_START = 57344;
function pickMarker(text) {
const tryCount = 16;
for (let code = MARKER_START; code < MARKER_START + tryCount; code++) {
const candidate = String.fromCharCode(code);
if (!text.includes(candidate)) {
return candidate;
}
}
return null;
}
function htmlIndexToRichTextOffset(html, htmlIndex) {
if (!html.includes("<") && !html.includes("&")) {
return asRichTextOffset(htmlIndex);
}
const marker = pickMarker(html);
if (!marker) {
return asRichTextOffset(htmlIndex);
}
const withMarker = html.slice(0, htmlIndex) + marker + html.slice(htmlIndex);
const value = create({ html: withMarker });
const markerPos = value.text.indexOf(marker);
return asRichTextOffset(markerPos === -1 ? htmlIndex : markerPos);
}
function richTextOffsetToHtmlIndex(html, richTextOffset) {
if (!html.includes("<") && !html.includes("&")) {
return asHtmlStringIndex(richTextOffset);
}
const marker = pickMarker(html);
if (!marker) {
return asHtmlStringIndex(richTextOffset);
}
const value = create({ html });
const markerValue = create({ text: marker });
if (value.formats[richTextOffset]) {
markerValue.formats[0] = value.formats[richTextOffset];
}
const withMarker = insert(
value,
markerValue,
richTextOffset,
richTextOffset
);
const htmlWithMarker = toHTMLString({ value: withMarker });
const markerIndex = htmlWithMarker.indexOf(marker);
return asHtmlStringIndex(
markerIndex === -1 ? richTextOffset : markerIndex
);
}
function findBlockByClientIdInBlocks(blockId, blocks) {
for (const block of blocks) {
if (block.get("clientId") === blockId) {
return block;
}
const innerBlocks = block.get("innerBlocks");
if (innerBlocks && innerBlocks.length > 0) {
const innerBlock = findBlockByClientIdInBlocks(
blockId,
innerBlocks
);
if (innerBlock) {
return innerBlock;
}
}
}
return null;
}
export {
asHtmlStringIndex,
asRichTextOffset,
createYMap,
findBlockByClientIdInDoc,
getRootMap,
getYTextByAttributeKey,
htmlIndexToRichTextOffset,
isYMap,
richTextOffsetToHtmlIndex
};
//# sourceMappingURL=crdt-utils.mjs.map