mirror of
https://github.com/yjs/yjs.git
synced 2025-12-16 19:57:45 +01:00
only have a single getDelta implementation for events and retrieving content
This commit is contained in:
@@ -29,19 +29,19 @@
|
|||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
"types": "./dist/src/index.d.ts",
|
"types": "./dist/src/index.d.ts",
|
||||||
"module": "./dist/yjs.mjs",
|
"module": "./src/index.js",
|
||||||
"require": "./dist/yjs.cjs",
|
"require": "./dist/yjs.cjs",
|
||||||
"import": "./src/index.js"
|
"import": "./src/index.js"
|
||||||
},
|
},
|
||||||
"./internals": {
|
"./internals": {
|
||||||
"types": "./dist/src/internals.d.ts",
|
"types": "./dist/src/internals.d.ts",
|
||||||
"module": "./dist/internals.mjs",
|
"module": "./src/internals.js",
|
||||||
"require": "./dist/internals.cjs",
|
"require": "./dist/internals.cjs",
|
||||||
"import": "./src/internals.js"
|
"import": "./src/internals.js"
|
||||||
},
|
},
|
||||||
"./testHelper": {
|
"./testHelper": {
|
||||||
"types": "./dist/testHelper.d.ts",
|
"types": "./dist/testHelper.d.ts",
|
||||||
"module": "./dist/testHelper.mjs",
|
"module": "./tests/testHelper.js",
|
||||||
"require": "./dist/testHelper.cjs",
|
"require": "./dist/testHelper.cjs",
|
||||||
"import": "./tests/testHelper.js"
|
"import": "./tests/testHelper.js"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ import {
|
|||||||
|
|
||||||
import * as delta from '../utils/Delta.js'
|
import * as delta from '../utils/Delta.js'
|
||||||
|
|
||||||
|
import * as traits from 'lib0/traits'
|
||||||
import * as object from 'lib0/object'
|
import * as object from 'lib0/object'
|
||||||
import * as map from 'lib0/map'
|
import * as map from 'lib0/map'
|
||||||
import * as error from 'lib0/error'
|
import * as error from 'lib0/error'
|
||||||
@@ -649,6 +650,18 @@ export class YTextEvent extends YEvent {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
getDelta (am = noAttributionsManager) {
|
getDelta (am = noAttributionsManager) {
|
||||||
|
const whatToWatch = mergeIdSets([diffIdSet(this.transaction.insertSet, this.transaction.deleteSet), diffIdSet(this.transaction.deleteSet, this.transaction.insertSet)])
|
||||||
|
const genericDelta = this.target.getDelta(am, whatToWatch)
|
||||||
|
return genericDelta;
|
||||||
|
/*
|
||||||
|
if (!d.equals(genericDelta)) {
|
||||||
|
console.log(d.toJSON())
|
||||||
|
console.log(genericDelta.toJSON())
|
||||||
|
debugger
|
||||||
|
const d2 = this.target.getDelta(am, whatToWatch)
|
||||||
|
throw new Error('should match', d2)
|
||||||
|
}
|
||||||
|
return d
|
||||||
const ydoc = /** @type {Doc} */ (this.target.doc)
|
const ydoc = /** @type {Doc} */ (this.target.doc)
|
||||||
/**
|
/**
|
||||||
* @type {import('../utils/Delta.js').TextDelta<TextEmbeds>}
|
* @type {import('../utils/Delta.js').TextDelta<TextEmbeds>}
|
||||||
@@ -729,23 +742,42 @@ export class YTextEvent extends YEvent {
|
|||||||
if (equalAttrs(value, currAttrVal)) {
|
if (equalAttrs(value, currAttrVal)) {
|
||||||
item.delete(transaction)
|
item.delete(transaction)
|
||||||
} else if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
} else if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
||||||
delete currentAttributes[key]
|
|
||||||
delete changedAttributes[key]
|
delete changedAttributes[key]
|
||||||
} else {
|
} else {
|
||||||
currentAttributes[key] = value
|
|
||||||
changedAttributes[key] = value
|
changedAttributes[key] = value
|
||||||
}
|
}
|
||||||
|
if (value == null) {
|
||||||
|
delete currentAttributes[key]
|
||||||
|
} else {
|
||||||
|
currentAttributes[key] = value
|
||||||
|
}
|
||||||
} else if (freshDelete) {
|
} else if (freshDelete) {
|
||||||
|
if (equalAttrs(value, currAttrVal)) {
|
||||||
|
// nop
|
||||||
|
} else if (equalAttrs(currAttrVal, previousAttributes[key] ?? null)) {
|
||||||
|
delete changedAttributes[key]
|
||||||
|
} else {
|
||||||
changedAttributes[key] = currAttrVal
|
changedAttributes[key] = currAttrVal
|
||||||
currentAttributes[key] = currAttrVal
|
}
|
||||||
|
// current attributes doesn't change
|
||||||
previousAttributes[key] = value
|
previousAttributes[key] = value
|
||||||
|
|
||||||
} else if (!c.deleted) {
|
} else if (!c.deleted) {
|
||||||
// fresh reference to currentAttributes only
|
// fresh reference to currentAttributes only
|
||||||
if (usingCurrentAttributes) {
|
if (usingCurrentAttributes) {
|
||||||
currentAttributes = object.assign({}, currentAttributes)
|
currentAttributes = object.assign({}, currentAttributes)
|
||||||
usingCurrentAttributes = false
|
usingCurrentAttributes = false
|
||||||
}
|
}
|
||||||
|
if (usingChangedAttributes && changedAttributes[key] !== undefined) {
|
||||||
|
usingChangedAttributes = false
|
||||||
|
changedAttributes = object.assign({}, changedAttributes)
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
|
delete currentAttributes[key]
|
||||||
|
} else {
|
||||||
currentAttributes[key] = value
|
currentAttributes[key] = value
|
||||||
|
}
|
||||||
|
delete changedAttributes[key]
|
||||||
previousAttributes[key] = value
|
previousAttributes[key] = value
|
||||||
}
|
}
|
||||||
// # Update Attributions
|
// # Update Attributions
|
||||||
@@ -788,6 +820,7 @@ export class YTextEvent extends YEvent {
|
|||||||
// throw new Error('should match', d2)
|
// throw new Error('should match', d2)
|
||||||
// }
|
// }
|
||||||
// return d
|
// return d
|
||||||
|
// */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1005,81 +1038,81 @@ export class YText extends AbstractType {
|
|||||||
*/
|
*/
|
||||||
getContent (am = noAttributionsManager) {
|
getContent (am = noAttributionsManager) {
|
||||||
return this.getDelta(am)
|
return this.getDelta(am)
|
||||||
this.doc ?? warnPrematureAccess()
|
// this.doc ?? warnPrematureAccess()
|
||||||
/**
|
// /**
|
||||||
* @type {delta.TextDelta<Embeds>}
|
// * @type {delta.TextDelta<Embeds>}
|
||||||
*/
|
// */
|
||||||
const d = delta.createTextDelta()
|
// const d = delta.createTextDelta()
|
||||||
/**
|
// /**
|
||||||
* @type {Array<import('../internals.js').AttributedContent<any>>}
|
// * @type {Array<import('../internals.js').AttributedContent<any>>}
|
||||||
*/
|
// */
|
||||||
const cs = []
|
// const cs = []
|
||||||
for (let item = this._start; item !== null; cs.length = 0) {
|
// for (let item = this._start; item !== null; cs.length = 0) {
|
||||||
// populate cs
|
// // populate cs
|
||||||
for (; item !== null && cs.length < 50; item = item.right) {
|
// for (; item !== null && cs.length < 50; item = item.right) {
|
||||||
am.readContent(cs, item, false)
|
// am.readContent(cs, item, false)
|
||||||
}
|
// }
|
||||||
for (let i = 0; i < cs.length; i++) {
|
// for (let i = 0; i < cs.length; i++) {
|
||||||
const { content, deleted, attrs } = cs[i]
|
// const { content, deleted, attrs } = cs[i]
|
||||||
const { attribution, retainOnly } = createAttributionFromAttributionItems(attrs, deleted)
|
// const { attribution, retainOnly } = createAttributionFromAttributionItems(attrs, deleted)
|
||||||
switch (content.constructor) {
|
// switch (content.constructor) {
|
||||||
case ContentString: {
|
// case ContentString: {
|
||||||
if (retainOnly) {
|
// if (retainOnly) {
|
||||||
d.retain(content.getLength(), null, attribution)
|
// d.retain(content.getLength(), null, attribution)
|
||||||
} else {
|
// } else {
|
||||||
d.insert(/** @type {ContentString} */ (content).str, null, attribution)
|
// d.insert(/** @type {ContentString} */ (content).str, null, attribution)
|
||||||
}
|
// }
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
case ContentType:
|
// case ContentType:
|
||||||
case ContentEmbed: {
|
// case ContentEmbed: {
|
||||||
if (retainOnly) {
|
// if (retainOnly) {
|
||||||
d.retain(content.getLength(), null, attribution)
|
// d.retain(content.getLength(), null, attribution)
|
||||||
} else {
|
// } else {
|
||||||
d.insert(/** @type {ContentEmbed | ContentType} */ (content).getContent()[0], null, attribution)
|
// d.insert(/** @type {ContentEmbed | ContentType} */ (content).getContent()[0], null, attribution)
|
||||||
}
|
// }
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
case ContentFormat: {
|
// case ContentFormat: {
|
||||||
const contentFormat = /** @type {ContentFormat} */ (content)
|
// const contentFormat = /** @type {ContentFormat} */ (content)
|
||||||
if (attribution != null) {
|
// if (attribution != null) {
|
||||||
/**
|
// /**
|
||||||
* @type {import('../utils/Delta.js').Attribution}
|
// * @type {import('../utils/Delta.js').Attribution}
|
||||||
*/
|
// */
|
||||||
const formattingAttribution = object.assign({}, d.usedAttribution)
|
// const formattingAttribution = object.assign({}, d.usedAttribution)
|
||||||
const attributesChanged = /** @type {{ [key: string]: Array<any> }} */ (formattingAttribution.attributes = object.assign({}, formattingAttribution.attributes ?? {}))
|
// const attributesChanged = /** @type {{ [key: string]: Array<any> }} */ (formattingAttribution.attributes = object.assign({}, formattingAttribution.attributes ?? {}))
|
||||||
if (contentFormat.value === null) {
|
// if (contentFormat.value === null) {
|
||||||
delete attributesChanged[contentFormat.key]
|
// delete attributesChanged[contentFormat.key]
|
||||||
} else {
|
// } else {
|
||||||
const by = attributesChanged[contentFormat.key] = attributesChanged[contentFormat.key]?.slice() ?? []
|
// const by = attributesChanged[contentFormat.key] = attributesChanged[contentFormat.key]?.slice() ?? []
|
||||||
by.push(...((deleted ? attribution.delete : attribution.insert) ?? []))
|
// by.push(...((deleted ? attribution.delete : attribution.insert) ?? []))
|
||||||
const attributedAt = (deleted ? attribution.deletedAt : attribution.insertedAt)
|
// const attributedAt = (deleted ? attribution.deletedAt : attribution.insertedAt)
|
||||||
if (attributedAt) formattingAttribution.attributedAt = attributedAt
|
// if (attributedAt) formattingAttribution.attributedAt = attributedAt
|
||||||
}
|
// }
|
||||||
if (object.isEmpty(attributesChanged)) {
|
// if (object.isEmpty(attributesChanged)) {
|
||||||
d.useAttribution(null)
|
// d.useAttribution(null)
|
||||||
} else {
|
// } else {
|
||||||
const attributedAt = (deleted ? attribution.deletedAt : attribution.insertedAt)
|
// const attributedAt = (deleted ? attribution.deletedAt : attribution.insertedAt)
|
||||||
if (attributedAt != null) formattingAttribution.attributedAt = attributedAt
|
// if (attributedAt != null) formattingAttribution.attributedAt = attributedAt
|
||||||
d.useAttribution(formattingAttribution)
|
// d.useAttribution(formattingAttribution)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if (!deleted) {
|
// if (!deleted) {
|
||||||
const currAttrs = d.usedAttributes
|
// const currAttrs = d.usedAttributes
|
||||||
if (contentFormat.value == null) {
|
// if (contentFormat.value == null) {
|
||||||
const nextAttrs = object.assign({}, currAttrs)
|
// const nextAttrs = object.assign({}, currAttrs)
|
||||||
delete nextAttrs[contentFormat.key]
|
// delete nextAttrs[contentFormat.key]
|
||||||
d.useAttributes(nextAttrs)
|
// d.useAttributes(nextAttrs)
|
||||||
} else {
|
// } else {
|
||||||
d.useAttributes(object.assign({}, currAttrs, { [contentFormat.key]: contentFormat.value }))
|
// d.useAttributes(object.assign({}, currAttrs, { [contentFormat.key]: contentFormat.value }))
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
break
|
// break
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return d
|
// return d
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1169,6 +1202,7 @@ export class YText extends AbstractType {
|
|||||||
case ContentFormat: {
|
case ContentFormat: {
|
||||||
const { key, value } = /** @type {ContentFormat} */ (c.content)
|
const { key, value } = /** @type {ContentFormat} */ (c.content)
|
||||||
const currAttrVal = currentAttributes[key] ?? null
|
const currAttrVal = currentAttributes[key] ?? null
|
||||||
|
// @todo write a function "updateCurrentAttributes" and "updateChangedAttributes"
|
||||||
// # Update Attributes
|
// # Update Attributes
|
||||||
if (renderDelete || renderInsert) {
|
if (renderDelete || renderInsert) {
|
||||||
// create fresh references
|
// create fresh references
|
||||||
@@ -1185,20 +1219,24 @@ export class YText extends AbstractType {
|
|||||||
if (equalAttrs(value, currAttrVal)) {
|
if (equalAttrs(value, currAttrVal)) {
|
||||||
// item.delete(transaction)
|
// item.delete(transaction)
|
||||||
} else if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
} else if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
||||||
delete currentAttributes[key]
|
|
||||||
delete changedAttributes[key]
|
delete changedAttributes[key]
|
||||||
} else {
|
} else {
|
||||||
currentAttributes[key] = value
|
|
||||||
changedAttributes[key] = value
|
changedAttributes[key] = value
|
||||||
}
|
}
|
||||||
|
if (value == null) {
|
||||||
|
delete currentAttributes[key]
|
||||||
|
} else {
|
||||||
|
currentAttributes[key] = value
|
||||||
|
}
|
||||||
} else if (renderDelete) {
|
} else if (renderDelete) {
|
||||||
if (equalAttrs(value, currAttrVal)) {
|
if (equalAttrs(value, currAttrVal)) {
|
||||||
|
// nop
|
||||||
|
} else if (equalAttrs(currAttrVal, previousAttributes[key] ?? null) && changedAttributes[key] !== undefined) {
|
||||||
delete changedAttributes[key]
|
delete changedAttributes[key]
|
||||||
delete currentAttributes[key]
|
|
||||||
} else {
|
} else {
|
||||||
changedAttributes[key] = currAttrVal
|
changedAttributes[key] = currAttrVal
|
||||||
currentAttributes[key] = currAttrVal
|
|
||||||
}
|
}
|
||||||
|
// current attributes doesn't change
|
||||||
previousAttributes[key] = value
|
previousAttributes[key] = value
|
||||||
} else if (!c.deleted) {
|
} else if (!c.deleted) {
|
||||||
// fresh reference to currentAttributes only
|
// fresh reference to currentAttributes only
|
||||||
@@ -1206,11 +1244,16 @@ export class YText extends AbstractType {
|
|||||||
currentAttributes = object.assign({}, currentAttributes)
|
currentAttributes = object.assign({}, currentAttributes)
|
||||||
usingCurrentAttributes = false
|
usingCurrentAttributes = false
|
||||||
}
|
}
|
||||||
if (equalAttrs(value, previousAttributes[key] ?? null)) {
|
if (usingChangedAttributes && changedAttributes[key] !== undefined) {
|
||||||
|
usingChangedAttributes = false
|
||||||
|
changedAttributes = object.assign({}, changedAttributes)
|
||||||
|
}
|
||||||
|
if (value == null) {
|
||||||
delete currentAttributes[key]
|
delete currentAttributes[key]
|
||||||
} else {
|
} else {
|
||||||
currentAttributes[key] = value
|
currentAttributes[key] = value
|
||||||
}
|
}
|
||||||
|
delete changedAttributes[key]
|
||||||
previousAttributes[key] = value
|
previousAttributes[key] = value
|
||||||
}
|
}
|
||||||
// # Update Attributions
|
// # Update Attributions
|
||||||
@@ -1419,6 +1462,13 @@ export class YText extends AbstractType {
|
|||||||
_write (encoder) {
|
_write (encoder) {
|
||||||
encoder.writeTypeRef(YTextRefID)
|
encoder.writeTypeRef(YTextRefID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {this} other
|
||||||
|
*/
|
||||||
|
[traits.EqualityTraitSymbol] (other) {
|
||||||
|
return this.getContent().equals(other.getContent())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1621,7 +1621,7 @@ export const testDeltaAfterConcurrentFormatting = tc => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
testConnector.flushAllMessages()
|
testConnector.flushAllMessages()
|
||||||
t.compare(deltas, [[{ retain: 3, attributes: { bold: true } }, { retain: 2, attributes: { bold: null } }]])
|
t.compare(deltas, [[{ retain: 2, attributes: { bold: true } }, { retain: 1 }, { retain: 1, attributes: { bold: null } }]])
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -2267,7 +2267,7 @@ export const testAttributedContent = _tc => {
|
|||||||
})
|
})
|
||||||
t.group('unformat', () => {
|
t.group('unformat', () => {
|
||||||
ytext.applyDelta([{ retain: 5, attributes: { italic: null } }])
|
ytext.applyDelta([{ retain: 5, attributes: { italic: null } }])
|
||||||
const expectedContent = delta.createTextDelta().insert('Hell', { italic: null }, { attributes: { italic: [] } }).insert('o attributions!')
|
const expectedContent = delta.createTextDelta().insert('Hell', null, { attributes: { italic: [] } }).insert('o attributions!')
|
||||||
const attributedContent = ytext.getContent(attributionManager)
|
const attributedContent = ytext.getContent(attributionManager)
|
||||||
console.log(attributedContent.toJSON())
|
console.log(attributedContent.toJSON())
|
||||||
t.assert(attributedContent.equals(expectedContent))
|
t.assert(attributedContent.equals(expectedContent))
|
||||||
|
|||||||
Reference in New Issue
Block a user