UNPKG

json-joy

Version:

Collection of libraries for building collaborative editing apps.

125 lines (124 loc) 4.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.QuillDeltaApi = void 0; const constants_1 = require("./constants"); const nodes_1 = require("../../json-crdt/model/api/nodes"); const Konst_1 = require("../../json-crdt-patch/builder/Konst"); const constants_2 = require("../peritext/slice/constants"); const PersistedSlice_1 = require("../peritext/slice/PersistedSlice"); const util_1 = require("./util"); const updateAttributes = (txt, attributes, pos, len) => { if (!attributes) return; const range = txt.rangeAt(pos, len); const keys = Object.keys(attributes); const length = keys.length; const savedSlices = txt.savedSlices; for (let i = 0; i < length; i++) { const key = keys[i]; const value = attributes[key]; if (value === null) { savedSlices.ins(range, constants_2.SliceStacking.Erase, key); } else { savedSlices.ins(range, constants_2.SliceStacking.One, key, (0, Konst_1.konst)(value)); } } }; const rewriteAttributes = (txt, attributes, pos, len) => { if (typeof attributes !== 'object') return; const range = txt.rangeAt(pos, len); range.expand(); const slices = txt.overlay.findOverlapping(range); const length = slices.size; const relevantOverlappingButNotContained = new Set(); if (length) { const savedSlices = txt.savedSlices; // biome-ignore lint: slices is not iterable slices.forEach((slice) => { if (slice instanceof PersistedSlice_1.PersistedSlice) { const isContained = range.contains(slice); if (!isContained) { relevantOverlappingButNotContained.add(slice.type); return; } const type = slice.type; if (type in attributes) { savedSlices.del(slice.id); } } }); } const keys = Object.keys(attributes); const attributeLength = keys.length; const attributesCopy = { ...attributes }; for (let i = 0; i < attributeLength; i++) { const key = keys[i]; const value = attributes[key]; if (value === null && !relevantOverlappingButNotContained.has(key)) { delete attributesCopy[key]; } } updateAttributes(txt, attributesCopy, pos, len); }; const maybeUpdateAttributes = (txt, attributes, pos, len) => { const range = txt.rangeAt(pos, 1); const overlayPoint = txt.overlay.getOrNextLower(range.start); if (!overlayPoint && !attributes) return; if (!overlayPoint) { updateAttributes(txt, (0, util_1.removeErasures)(attributes), pos, len); return; } const pointAttributes = (0, util_1.getAttributes)(overlayPoint); const attributeDiff = (0, util_1.diffAttributes)(pointAttributes, attributes); if (attributeDiff) updateAttributes(txt, attributeDiff, pos, len); }; class QuillDeltaApi extends nodes_1.NodeApi { text() { return this.api.wrap(this.node.text()); } slices() { return this.api.wrap(this.node.slices()); } apply(ops) { const txt = this.node.txt; const overlay = txt.overlay; const length = ops.length; let pos = 0; for (let i = 0; i < length; i++) { overlay.refresh(true); const op = ops[i]; if (typeof op.retain === 'number') { const { retain, attributes } = op; if (attributes) rewriteAttributes(txt, attributes, pos, retain); pos += retain; } else if (typeof op.delete === 'number') { txt.delAt(pos, op.delete); } else if (op.insert) { const { insert } = op; let { attributes } = op; if (typeof insert === 'string') { txt.insAt(pos, insert); const insertLength = insert.length; maybeUpdateAttributes(txt, attributes, pos, insertLength); pos += insertLength; } else { txt.insAt(pos, constants_1.QuillConst.EmbedChar); if (!attributes) attributes = {}; attributes[constants_1.QuillConst.EmbedSliceType] = insert; maybeUpdateAttributes(txt, attributes, pos, 1); pos += 1; } } } } } exports.QuillDeltaApi = QuillDeltaApi;