json-joy
Version:
Collection of libraries for building collaborative editing apps.
125 lines (124 loc) • 4.63 kB
JavaScript
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;
;