mirror of
https://github.com/yjs/yjs.git
synced 2026-01-08 15:33:53 -05:00
more generic gedDelta implementation (could be used for events)
This commit is contained in:
@@ -514,15 +514,17 @@ export const typeListGetContent = (type, am) => {
|
||||
for (let item = type._start; item !== null; cs.length = 0) {
|
||||
// populate cs
|
||||
for (; item !== null && cs.length < 50; item = item.right) {
|
||||
am.readContent(cs, item, false)
|
||||
am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, true)
|
||||
}
|
||||
for (let i = 0; i < cs.length; i++) {
|
||||
const { content, deleted, attrs } = cs[i]
|
||||
const { attribution, retainOnly } = createAttributionFromAttributionItems(attrs, deleted)
|
||||
if (retainOnly) {
|
||||
d.retain(content.getLength())
|
||||
} else if (content.isCountable()) {
|
||||
d.insert(content.getContent(), null, attribution)
|
||||
const c = cs[i]
|
||||
const attribution = createAttributionFromAttributionItems(c.attrs, c.deleted).attribution
|
||||
if (c.content.isCountable()) {
|
||||
if (c.render) {
|
||||
d.insert(c.content.getContent(), null, attribution)
|
||||
} else {
|
||||
d.retain(c.content.getLength())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1009,7 +1011,7 @@ export const typeMapGetContent = (parent, am) => {
|
||||
* @type {Array<import('../internals.js').AttributedContent<any>>}
|
||||
*/
|
||||
const cs = []
|
||||
am.readContent(cs, item, false)
|
||||
am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, true)
|
||||
const { deleted, attrs, content } = cs[cs.length - 1]
|
||||
const c = array.last(content.getContent())
|
||||
const { attribution } = createAttributionFromAttributionItems(attrs, deleted)
|
||||
@@ -1025,7 +1027,7 @@ export const typeMapGetContent = (parent, am) => {
|
||||
* @type {Array<import('../internals.js').AttributedContent<any>>}
|
||||
*/
|
||||
const tmpcs = []
|
||||
am.readContent(tmpcs, prevItem, false)
|
||||
am.readContent(tmpcs, prevItem.id.client, prevItem.id.clock, prevItem.deleted, prevItem.content, true)
|
||||
cs = tmpcs.concat(cs)
|
||||
if (cs.length === 0 || cs[0].attrs == null) {
|
||||
cs.splice(0, cs.findIndex(c => c.attrs != null))
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
updateMarkerChanges,
|
||||
ContentType,
|
||||
warnPrematureAccess,
|
||||
IdSet, noAttributionsManager, AbstractAttributionManager, ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item, Transaction, // eslint-disable-line
|
||||
noAttributionsManager, AbstractAttributionManager, ArraySearchMarker, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Doc, Item, Transaction, // eslint-disable-line
|
||||
createAttributionFromAttributionItems
|
||||
} from '../internals.js'
|
||||
|
||||
@@ -675,7 +675,7 @@ export class YTextEvent extends YEvent {
|
||||
for (let item = this.target._start; item !== null; cs.length = 0, item = item.right) {
|
||||
const freshDelete = item.deleted && tr.deleteSet.hasId(item.id) && !tr.insertSet.hasId(item.id)
|
||||
const freshInsert = !item.deleted && tr.insertSet.hasId(item.id)
|
||||
am.readContent(cs, item, freshDelete) // do item.right after calling this
|
||||
am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, !item.deleted || freshDelete) // do item.right after calling this
|
||||
for (let i = 0; i < cs.length; i++) {
|
||||
const c = cs[i]
|
||||
const { attribution } = createAttributionFromAttributionItems(c.attrs, c.deleted)
|
||||
@@ -709,6 +709,7 @@ export class YTextEvent extends YEvent {
|
||||
break
|
||||
case ContentFormat: {
|
||||
const { key, value } = /** @type {ContentFormat} */ (c.content)
|
||||
// # update attributes
|
||||
const currAttrVal = currentAttributes[key] ?? null
|
||||
if (freshDelete || freshInsert) {
|
||||
// create fresh references
|
||||
@@ -744,6 +745,29 @@ export class YTextEvent extends YEvent {
|
||||
currentAttributes[key] = value
|
||||
previousAttributes[key] = value
|
||||
}
|
||||
// # Update Attributions
|
||||
if (attribution != null) {
|
||||
/**
|
||||
* @type {import('../utils/Delta.js').Attribution}
|
||||
*/
|
||||
const formattingAttribution = object.assign({}, d.usedAttribution)
|
||||
const attributesChanged = /** @type {{ [key: string]: Array<any> }} */ (formattingAttribution.attributes = object.assign({}, formattingAttribution.attributes ?? {}))
|
||||
if (value === null) {
|
||||
delete attributesChanged[key]
|
||||
} else {
|
||||
const by = attributesChanged[key] = (attributesChanged[key]?.slice() ?? [])
|
||||
by.push(...((c.deleted ? attribution.delete : attribution.insert) ?? []))
|
||||
const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt)
|
||||
if (attributedAt) formattingAttribution.attributedAt = attributedAt
|
||||
}
|
||||
if (object.isEmpty(attributesChanged)) {
|
||||
d.useAttribution(null)
|
||||
} else {
|
||||
const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt)
|
||||
if (attributedAt != null) formattingAttribution.attributedAt = attributedAt
|
||||
d.useAttribution(formattingAttribution)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -967,6 +991,7 @@ export class YText extends AbstractType {
|
||||
* @public
|
||||
*/
|
||||
getContent (am = noAttributionsManager) {
|
||||
return this.getDelta(am)
|
||||
this.doc ?? warnPrematureAccess()
|
||||
/**
|
||||
* @type {delta.TextDelta<Embeds>}
|
||||
@@ -1044,6 +1069,168 @@ export class YText extends AbstractType {
|
||||
return d
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {AbstractAttributionManager} am
|
||||
* @param {import('../utils/IdSet.js').IdSet?} itemsToRender
|
||||
* @param {boolean} retainOnly - if true, retain the rendered items with attributes and attributions.
|
||||
* @return {import('../utils/Delta.js').TextDelta<Embeds>} The Delta representation of this type.
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
getDelta (am = noAttributionsManager, itemsToRender = null, retainOnly = false) {
|
||||
/**
|
||||
* @type {import('../utils/Delta.js').TextDelta<Embeds>}
|
||||
*/
|
||||
const d = delta.createTextDelta()
|
||||
/**
|
||||
* @type {import('../utils/Delta.js').FormattingAttributes}
|
||||
*/
|
||||
let currentAttributes = {} // saves all current attributes for insert
|
||||
let usingCurrentAttributes = false
|
||||
/**
|
||||
* @type {import('../utils/Delta.js').FormattingAttributes}
|
||||
*/
|
||||
let changedAttributes = {} // saves changed attributes for retain
|
||||
let usingChangedAttributes = false
|
||||
/**
|
||||
* @type {import('../utils/Delta.js').FormattingAttributes}
|
||||
*/
|
||||
const previousAttributes = {} // The value before changes
|
||||
|
||||
/**
|
||||
* @type {Array<import('../internals.js').AttributedContent<any>>}
|
||||
*/
|
||||
const cs = []
|
||||
for (let item = this._start; item !== null; cs.length = 0) {
|
||||
if (itemsToRender != null) {
|
||||
for (; item !== null && cs.length < 50; item = item.right) {
|
||||
const rslice = itemsToRender.slice(item.id.client, item.id.clock, item.length)
|
||||
let itemContent = rslice.length > 1 ? item.content.copy() : item.content
|
||||
for (let ir = 0; ir < rslice.length; ir++) {
|
||||
const idrange = rslice[ir]
|
||||
const content = itemContent
|
||||
if (ir !== rslice.length - 1) {
|
||||
itemContent.splice(idrange.len)
|
||||
}
|
||||
am.readContent(cs, item.id.client, idrange.clock, item.deleted, content, idrange.exists)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (; item !== null && cs.length < 50; item = item.right) {
|
||||
am.readContent(cs, item.id.client, item.id.clock, item.deleted, item.content, true)
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < cs.length; i++) {
|
||||
const c = cs[i]
|
||||
const renderDelete = c.deleted && c.attrs != null && c.render
|
||||
const renderInsert = !c.deleted && (c.render || c.attrs != null)
|
||||
const attribution = (renderDelete || renderInsert) ? createAttributionFromAttributionItems(c.attrs, c.deleted).attribution : null
|
||||
switch (c.content.constructor) {
|
||||
case ContentType:
|
||||
case ContentEmbed:
|
||||
if (renderInsert) {
|
||||
d.usedAttributes = currentAttributes
|
||||
usingCurrentAttributes = true
|
||||
d.insert(c.content.getContent()[0], null, attribution)
|
||||
} else if (renderDelete) {
|
||||
d.delete(1)
|
||||
} else if (!c.deleted) {
|
||||
d.usedAttributes = changedAttributes
|
||||
usingChangedAttributes = true
|
||||
d.retain(1)
|
||||
}
|
||||
break
|
||||
case ContentString:
|
||||
if (renderInsert || (renderDelete && attribution?.delete != null)) {
|
||||
d.usedAttributes = currentAttributes
|
||||
usingCurrentAttributes = true
|
||||
d.insert(/** @type {ContentString} */ (c.content).str, null, attribution)
|
||||
} else if (renderDelete) {
|
||||
d.delete(c.content.getLength())
|
||||
} else if (!c.deleted) {
|
||||
d.usedAttributes = changedAttributes
|
||||
usingChangedAttributes = true
|
||||
d.retain(c.content.getLength())
|
||||
}
|
||||
break
|
||||
case ContentFormat: {
|
||||
const { key, value } = /** @type {ContentFormat} */ (c.content)
|
||||
const currAttrVal = currentAttributes[key] ?? null
|
||||
// # Update Attributes
|
||||
if (renderDelete || renderInsert) {
|
||||
// create fresh references
|
||||
if (usingCurrentAttributes) {
|
||||
currentAttributes = object.assign({}, currentAttributes)
|
||||
usingCurrentAttributes = false
|
||||
}
|
||||
if (usingChangedAttributes) {
|
||||
usingChangedAttributes = false
|
||||
changedAttributes = object.assign({}, changedAttributes)
|
||||
}
|
||||
}
|
||||
if (renderInsert) {
|
||||
if (equalAttrs(value, currAttrVal)) {
|
||||
// item.delete(transaction)
|
||||
} else if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
||||
delete currentAttributes[key]
|
||||
delete changedAttributes[key]
|
||||
} else {
|
||||
currentAttributes[key] = value
|
||||
changedAttributes[key] = value
|
||||
}
|
||||
} else if (renderDelete) {
|
||||
if (equalAttrs(value,currAttrVal)) {
|
||||
delete changedAttributes[key]
|
||||
delete currentAttributes[key]
|
||||
} else {
|
||||
changedAttributes[key] = currAttrVal
|
||||
currentAttributes[key] = currAttrVal
|
||||
}
|
||||
previousAttributes[key] = value
|
||||
} else if (!c.deleted) {
|
||||
// fresh reference to currentAttributes only
|
||||
if (usingCurrentAttributes) {
|
||||
currentAttributes = object.assign({}, currentAttributes)
|
||||
usingCurrentAttributes = false
|
||||
}
|
||||
if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
||||
delete currentAttributes[key]
|
||||
} else {
|
||||
currentAttributes[key] = value
|
||||
}
|
||||
previousAttributes[key] = value
|
||||
}
|
||||
// # Update Attributions
|
||||
if (attribution != null) {
|
||||
/**
|
||||
* @type {import('../utils/Delta.js').Attribution}
|
||||
*/
|
||||
const formattingAttribution = object.assign({}, d.usedAttribution)
|
||||
const attributesChanged = /** @type {{ [key: string]: Array<any> }} */ (formattingAttribution.attributes = object.assign({}, formattingAttribution.attributes ?? {}))
|
||||
if (value === null) {
|
||||
delete attributesChanged[key]
|
||||
} else {
|
||||
const by = attributesChanged[key] = (attributesChanged[key]?.slice() ?? [])
|
||||
by.push(...((c.deleted ? attribution.delete : attribution.insert) ?? []))
|
||||
const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt)
|
||||
if (attributedAt) formattingAttribution.attributedAt = attributedAt
|
||||
}
|
||||
if (object.isEmpty(attributesChanged)) {
|
||||
d.useAttribution(null)
|
||||
} else {
|
||||
const attributedAt = (c.deleted ? attribution.deletedAt : attribution.insertedAt)
|
||||
if (attributedAt != null) formattingAttribution.attributedAt = attributedAt
|
||||
d.useAttribution(formattingAttribution)
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return d.done()
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert text at a given index.
|
||||
*
|
||||
|
||||
@@ -5,13 +5,14 @@ import {
|
||||
createDeleteSetFromStructStore,
|
||||
createIdMapFromIdSet,
|
||||
ContentDeleted,
|
||||
Snapshot, Doc, Item, AbstractContent, IdMap, // eslint-disable-line
|
||||
Snapshot, Doc, AbstractContent, IdMap, // eslint-disable-line
|
||||
insertIntoIdMap,
|
||||
insertIntoIdSet,
|
||||
diffIdMap,
|
||||
createIdMap,
|
||||
createAttributionItem,
|
||||
mergeIdMaps
|
||||
mergeIdMaps,
|
||||
createID
|
||||
} from '../internals.js'
|
||||
|
||||
import * as error from 'lib0/error'
|
||||
@@ -29,6 +30,7 @@ import * as error from 'lib0/error'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @todo SHOULD NOT RETURN AN OBJECT!
|
||||
* @param {Array<import('./IdMap.js').AttributionItem<any>>?} attrs
|
||||
* @param {boolean} deleted - whether the attributed item is deleted
|
||||
* @return {{ attribution: Attribution?, retainOnly: boolean }}
|
||||
@@ -78,11 +80,13 @@ export class AttributedContent {
|
||||
* @param {AbstractContent} content
|
||||
* @param {boolean} deleted
|
||||
* @param {Array<import('./IdMap.js').AttributionItem<T>> | null} attrs
|
||||
* @param {boolean} render
|
||||
*/
|
||||
constructor (content, deleted, attrs) {
|
||||
constructor (content, deleted, attrs, render) {
|
||||
this.content = content
|
||||
this.deleted = deleted
|
||||
this.attrs = attrs
|
||||
this.render = render
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,11 +95,14 @@ export class AttributedContent {
|
||||
*/
|
||||
export class AbstractAttributionManager {
|
||||
/**
|
||||
* @param {Array<AttributedContent<any>>} _contents
|
||||
* @param {Item} _item
|
||||
* @param {boolean} _forceRead read content even if it is unattributed and deleted
|
||||
* @param {Array<AttributedContent<any>>} _contents - where to write the result
|
||||
* @param {number} _client
|
||||
* @param {number} _clock
|
||||
* @param {boolean} _deleted
|
||||
* @param {AbstractContent} _content
|
||||
* @param {boolean} _shouldRender - whether this should render or just result in a `retain` operation
|
||||
*/
|
||||
readContent (_contents, _item, _forceRead) {
|
||||
readContent (_contents, _client, _clock, _deleted, _content, _shouldRender) {
|
||||
error.methodUnimplemented()
|
||||
}
|
||||
|
||||
@@ -118,21 +125,23 @@ export class TwosetAttributionManager {
|
||||
destroy () {}
|
||||
|
||||
/**
|
||||
* @param {Array<AttributedContent<any>>} contents
|
||||
* @param {Item} item
|
||||
* @param {boolean} forceRead read content even if it is unattributed and deleted
|
||||
* @param {Array<AttributedContent<any>>} contents - where to write the result
|
||||
* @param {number} client
|
||||
* @param {number} clock
|
||||
* @param {boolean} deleted
|
||||
* @param {AbstractContent} content
|
||||
* @param {boolean} shouldRender - whether this should render or just result in a `retain` operation
|
||||
*/
|
||||
readContent (contents, item, forceRead) {
|
||||
const deleted = item.deleted
|
||||
const slice = (deleted ? this.deletes : this.inserts).sliceId(item.id, item.length)
|
||||
let content = slice.length === 1 ? item.content : item.content.copy()
|
||||
readContent (contents, client, clock, deleted, content, shouldRender) {
|
||||
const slice = (deleted ? this.deletes : this.inserts).slice(client, clock, content.getLength())
|
||||
content = slice.length === 1 ? content : content.copy()
|
||||
slice.forEach(s => {
|
||||
const c = content
|
||||
if (s.len < c.getLength()) {
|
||||
content = c.splice(s.len)
|
||||
}
|
||||
if (!deleted || s.attrs != null || forceRead) {
|
||||
contents.push(new AttributedContent(c, deleted, s.attrs))
|
||||
if (!deleted || s.attrs != null) {
|
||||
contents.push(new AttributedContent(c, deleted, s.attrs, shouldRender))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -147,13 +156,16 @@ export class NoAttributionsManager {
|
||||
destroy () {}
|
||||
|
||||
/**
|
||||
* @param {Array<AttributedContent<any>>} contents
|
||||
* @param {Item} item
|
||||
* @param {boolean} forceRead read content even if it is unattributed and deleted
|
||||
* @param {Array<AttributedContent<any>>} contents - where to write the result
|
||||
* @param {number} _client
|
||||
* @param {number} _clock
|
||||
* @param {boolean} deleted
|
||||
* @param {AbstractContent} content
|
||||
* @param {boolean} shouldRender - whether this should render or just result in a `retain` operation
|
||||
*/
|
||||
readContent (contents, item, forceRead) {
|
||||
if (!item.deleted || forceRead) {
|
||||
contents.push(new AttributedContent(item.content, false, null))
|
||||
readContent (contents, _client, _clock, deleted, content, shouldRender) {
|
||||
if (!deleted || shouldRender) {
|
||||
contents.push(new AttributedContent(content, deleted, null, shouldRender))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -219,21 +231,23 @@ export class DiffAttributionManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<AttributedContent<any>>} contents
|
||||
* @param {Item} item
|
||||
* @param {boolean} forceRead read content even if it is unattributed and deleted
|
||||
* @param {Array<AttributedContent<any>>} contents - where to write the result
|
||||
* @param {number} client
|
||||
* @param {number} clock
|
||||
* @param {boolean} deleted
|
||||
* @param {AbstractContent} content
|
||||
* @param {boolean} shouldRender - whether this should render or just result in a `retain` operation
|
||||
*/
|
||||
readContent (contents, item, forceRead) {
|
||||
const deleted = item.deleted || /** @type {any} */ (item.parent).doc !== this._nextDoc
|
||||
const slice = (deleted ? this.deletes : this.inserts).sliceId(item.id, item.length)
|
||||
let content = slice.length === 1 ? item.content : item.content.copy()
|
||||
if (content instanceof ContentDeleted && slice[0].attrs != null && !this.inserts.hasId(item.id)) {
|
||||
readContent (contents, client, clock, deleted, content, shouldRender) {
|
||||
const slice = (deleted ? this.deletes : this.inserts).slice(client, clock, content.getLength())
|
||||
content = slice.length === 1 ? content : content.copy()
|
||||
if (content instanceof ContentDeleted && slice[0].attrs != null && !this.inserts.has(client, clock)) {
|
||||
// Retrieved item is never more fragmented than the newer item.
|
||||
const prevItem = getItem(this._prevDocStore, item.id)
|
||||
const prevItem = getItem(this._prevDocStore, createID(client, clock))
|
||||
content = prevItem.length > 1 ? prevItem.content.copy() : prevItem.content
|
||||
// trim itemContent to the correct size.
|
||||
const diffStart = prevItem.id.clock - item.id.clock
|
||||
const diffEnd = prevItem.id.clock + prevItem.length - item.id.clock - item.length
|
||||
const diffStart = prevItem.id.clock - clock
|
||||
const diffEnd = prevItem.id.clock + prevItem.length - clock - content.getLength()
|
||||
if (diffStart > 0) {
|
||||
content = content.splice(diffStart)
|
||||
}
|
||||
@@ -246,8 +260,8 @@ export class DiffAttributionManager {
|
||||
if (s.len < c.getLength()) {
|
||||
content = c.splice(s.len)
|
||||
}
|
||||
if (!deleted || s.attrs != null || forceRead) {
|
||||
contents.push(new AttributedContent(c, deleted, s.attrs))
|
||||
if (!deleted || s.attrs != null || shouldRender) {
|
||||
contents.push(new AttributedContent(c, deleted, s.attrs, shouldRender))
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -288,28 +302,31 @@ export class SnapshotAttributionManager {
|
||||
destroy () { }
|
||||
|
||||
/**
|
||||
* @param {Array<AttributedContent<any>>} contents
|
||||
* @param {Item} item
|
||||
* @param {boolean} forceRead read content even if it is unattributed and deleted
|
||||
* @param {Array<AttributedContent<any>>} contents - where to write the result
|
||||
* @param {number} client
|
||||
* @param {number} clock
|
||||
* @param {boolean} _deleted
|
||||
* @param {AbstractContent} content
|
||||
* @param {boolean} shouldRender - whether this should render or just result in a `retain` operation
|
||||
*/
|
||||
readContent (contents, item, forceRead) {
|
||||
if ((this.nextSnapshot.sv.get(item.id.client) ?? 0) <= item.id.clock) return // future item that should not be displayed
|
||||
const slice = this.attrs.sliceId(item.id, item.length)
|
||||
let content = slice.length === 1 ? item.content : item.content.copy()
|
||||
readContent (contents, client, clock, _deleted, content, shouldRender) {
|
||||
if ((this.nextSnapshot.sv.get(client) ?? 0) <= clock) return // future item that should not be displayed
|
||||
const slice = this.attrs.slice(client, clock, content.getLength())
|
||||
content = slice.length === 1 ? content : content.copy()
|
||||
slice.forEach(s => {
|
||||
const deleted = this.nextSnapshot.ds.has(item.id.client, s.clock)
|
||||
const nonExistend = (this.nextSnapshot.sv.get(item.id.client) ?? 0) <= s.clock
|
||||
const deleted = this.nextSnapshot.ds.has(client, s.clock)
|
||||
const nonExistend = (this.nextSnapshot.sv.get(client) ?? 0) <= s.clock
|
||||
const c = content
|
||||
if (s.len < c.getLength()) {
|
||||
content = c.splice(s.len)
|
||||
}
|
||||
if (nonExistend) return
|
||||
if (!deleted || forceRead || (s.attrs != null && s.attrs.length > 0)) {
|
||||
if (!deleted || shouldRender || (s.attrs != null && s.attrs.length > 0)) {
|
||||
let attrsWithoutChange = s.attrs?.filter(attr => attr.name !== 'change') ?? null
|
||||
if (s.attrs?.length === 0) {
|
||||
attrsWithoutChange = null
|
||||
}
|
||||
contents.push(new AttributedContent(c, deleted, attrsWithoutChange))
|
||||
contents.push(new AttributedContent(c, deleted, attrsWithoutChange, shouldRender))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2267,7 +2267,7 @@ export const testAttributedContent = _tc => {
|
||||
})
|
||||
t.group('unformat', () => {
|
||||
ytext.applyDelta([{ retain: 5, attributes: { italic: null } }])
|
||||
const expectedContent = delta.createTextDelta().insert('Hell', null, { attributes: { italic: [] } }).insert('o attributions!')
|
||||
const expectedContent = delta.createTextDelta().insert('Hell', { italic: null }, { attributes: { italic: [] } }).insert('o attributions!')
|
||||
const attributedContent = ytext.getContent(attributionManager)
|
||||
console.log(attributedContent.toJSON())
|
||||
t.assert(attributedContent.equals(expectedContent))
|
||||
|
||||
@@ -315,15 +315,16 @@ export const testElementAttributedContentViaDiffer = _tc => {
|
||||
yelement.setAttribute('key', '42')
|
||||
})
|
||||
const attributionManager = Y.createAttributionManagerFromDiff(ydocV1, ydoc)
|
||||
const expectedContent = delta.createArrayDelta().insert([delta.createTextDelta().insert('hello', null, { delete: [] })], null, { delete: [] }).insert([elem2.getContentDeep()]).insert([delta.createTextDelta().insert('world', null, { insert: [] })], null, { insert: [] })
|
||||
const expectedContent = delta.createArrayDelta().insert([delta.createTextDelta().insert('hello')], null, { delete: [] }).insert([elem2.getContentDeep()]).insert([delta.createTextDelta().insert('world', null, { insert: [] })], null, { insert: [] })
|
||||
const attributedContent = yelement.getContentDeep(attributionManager)
|
||||
console.log('children', attributedContent.children.toJSON())
|
||||
console.log('attributes', attributedContent.attributes)
|
||||
t.compare(attributedContent.children.toJSON(), expectedContent.toJSON())
|
||||
t.assert(attributedContent.children.equals(expectedContent))
|
||||
t.compare(attributedContent.attributes, { key: { prevValue: undefined, value: '42', attribution: { insert: [] } } })
|
||||
t.group('test getContentDeep', () => {
|
||||
const expectedContent = delta.createArrayDelta().insert(
|
||||
[delta.createTextDelta().insert('hello', null, { delete: [] })],
|
||||
[delta.createTextDelta().insert('hello')],
|
||||
null,
|
||||
{ delete: [] }
|
||||
).insert([{ nodeName: 'span', children: delta.createArrayDelta(), attributes: {} }])
|
||||
@@ -344,7 +345,7 @@ export const testElementAttributedContentViaDiffer = _tc => {
|
||||
t.group('test getContentDeep after some more updates', () => {
|
||||
t.info('expecting diffingAttributionManager to auto update itself')
|
||||
const expectedContent = delta.createArrayDelta().insert(
|
||||
[delta.createTextDelta().insert('hello', null, { delete: [] })],
|
||||
[delta.createTextDelta().insert('hello')],
|
||||
null,
|
||||
{ delete: [] }
|
||||
).insert([{ nodeName: 'span', children: delta.createArrayDelta(), attributes: {} }])
|
||||
|
||||
Reference in New Issue
Block a user