2025-04-20 19:28:36 +02:00
|
|
|
import {
|
|
|
|
|
Item, AbstractContent, IdMap // eslint-disable-line
|
|
|
|
|
} from '../internals.js'
|
|
|
|
|
|
|
|
|
|
import * as error from 'lib0/error'
|
|
|
|
|
|
2025-04-28 02:42:06 +02:00
|
|
|
/**
|
|
|
|
|
* @typedef {Object} Attribution
|
|
|
|
|
* @property {Array<any>} [Attribution.insert]
|
|
|
|
|
* @property {number} [Attribution.insertedAt]
|
|
|
|
|
* @property {Array<any>} [Attribution.suggest]
|
|
|
|
|
* @property {number} [Attribution.suggestedAt]
|
|
|
|
|
* @property {Array<any>} [Attribution.delete]
|
|
|
|
|
* @property {number} [Attribution.deletedAt]
|
|
|
|
|
* @property {{ [key: string]: Array<any> }} [Attribution.attributes]
|
|
|
|
|
* @property {number} [Attribution.attributedAt]
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @param {Array<import('./IdMap.js').AttributionItem<any>>?} attrs
|
|
|
|
|
* @param {boolean} deleted - whether the attributed item is deleted
|
|
|
|
|
* @return {Attribution?}
|
|
|
|
|
*/
|
|
|
|
|
export const createAttributionFromAttrs = (attrs, deleted) => {
|
|
|
|
|
/**
|
|
|
|
|
* @type {Attribution?}
|
|
|
|
|
*/
|
|
|
|
|
let attribution = null
|
|
|
|
|
if (attrs != null) {
|
|
|
|
|
attribution = {}
|
|
|
|
|
if (deleted) {
|
|
|
|
|
attribution.delete = []
|
|
|
|
|
} else {
|
|
|
|
|
attribution.insert = []
|
|
|
|
|
}
|
|
|
|
|
attrs.forEach(attr => {
|
|
|
|
|
switch (attr.name) {
|
|
|
|
|
case 'insert':
|
|
|
|
|
case 'delete':
|
|
|
|
|
case 'suggest': {
|
|
|
|
|
const as = /** @type {import('../utils/Delta.js').Attribution} */ (attribution)
|
|
|
|
|
const ls = as[attr.name] = as[attr.name] ?? []
|
|
|
|
|
ls.push(attr.val)
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
default: {
|
|
|
|
|
if (attr.name[0] !== '_') {
|
|
|
|
|
/** @type {any} */ (attribution)[attr.name] = attr.val
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return attribution
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-20 19:28:36 +02:00
|
|
|
/**
|
|
|
|
|
* @template T
|
|
|
|
|
*/
|
|
|
|
|
export class AttributedContent {
|
|
|
|
|
/**
|
|
|
|
|
* @param {AbstractContent} content
|
|
|
|
|
* @param {boolean} deleted
|
2025-04-28 02:42:06 +02:00
|
|
|
* @param {Array<import('./IdMap.js').AttributionItem<T>> | null} attrs
|
2025-04-20 19:28:36 +02:00
|
|
|
*/
|
|
|
|
|
constructor (content, deleted, attrs) {
|
|
|
|
|
this.content = content
|
|
|
|
|
this.deleted = deleted
|
|
|
|
|
this.attrs = attrs
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Abstract class for associating Attributions to content / changes
|
|
|
|
|
*/
|
|
|
|
|
export class AbstractAttributionManager {
|
|
|
|
|
/**
|
2025-04-28 00:02:06 +02:00
|
|
|
* @param {Array<AttributedContent<any>>} _contents
|
2025-04-20 19:28:36 +02:00
|
|
|
* @param {Item} _item
|
|
|
|
|
*/
|
2025-04-28 00:02:06 +02:00
|
|
|
readContent (_contents, _item) {
|
2025-04-20 19:28:36 +02:00
|
|
|
error.methodUnimplemented()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Abstract class for associating Attributions to content / changes
|
|
|
|
|
*
|
|
|
|
|
* @implements AbstractAttributionManager
|
|
|
|
|
*/
|
|
|
|
|
export class TwosetAttributionManager {
|
|
|
|
|
/**
|
|
|
|
|
* @param {IdMap<any>} inserts
|
|
|
|
|
* @param {IdMap<any>} deletes
|
|
|
|
|
*/
|
|
|
|
|
constructor (inserts, deletes) {
|
|
|
|
|
this.inserts = inserts
|
|
|
|
|
this.deletes = deletes
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
2025-04-28 00:02:06 +02:00
|
|
|
* @param {Array<AttributedContent<any>>} contents
|
2025-04-20 19:28:36 +02:00
|
|
|
* @param {Item} item
|
|
|
|
|
*/
|
2025-04-28 00:02:06 +02:00
|
|
|
readContent (contents, item) {
|
2025-04-20 19:28:36 +02:00
|
|
|
const deleted = item.deleted
|
|
|
|
|
const slice = (deleted ? this.deletes : this.inserts).slice(item.id, item.length)
|
|
|
|
|
let content = slice.length === 1 ? item.content : item.content.copy()
|
2025-04-28 00:02:06 +02:00
|
|
|
slice.forEach(s => {
|
2025-04-20 19:28:36 +02:00
|
|
|
const c = content
|
|
|
|
|
if (s.len < c.getLength()) {
|
|
|
|
|
content = c.splice(s.len)
|
|
|
|
|
}
|
2025-04-28 00:02:06 +02:00
|
|
|
if (!deleted || s.attrs != null) {
|
|
|
|
|
contents.push(new AttributedContent(c, deleted, s.attrs))
|
|
|
|
|
}
|
2025-04-20 19:28:36 +02:00
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Abstract class for associating Attributions to content / changes
|
|
|
|
|
*
|
|
|
|
|
* @implements AbstractAttributionManager
|
|
|
|
|
*/
|
|
|
|
|
export class NoAttributionsManager {
|
|
|
|
|
/**
|
2025-04-28 00:02:06 +02:00
|
|
|
* @param {Array<AttributedContent<any>>} contents
|
2025-04-20 19:28:36 +02:00
|
|
|
* @param {Item} item
|
|
|
|
|
*/
|
2025-04-28 00:02:06 +02:00
|
|
|
readContent (contents, item) {
|
|
|
|
|
if (!item.deleted) {
|
|
|
|
|
contents.push(new AttributedContent(item.content, false, null))
|
|
|
|
|
}
|
2025-04-20 19:28:36 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const noAttributionsManager = new NoAttributionsManager()
|