UNPKG

@wordpress/core-data

Version:
128 lines (127 loc) 3.65 kB
// 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