fix Y.Text formatting issue - closes #606

This commit is contained in:
Kevin Jahns 2024-01-21 11:27:12 +01:00
parent 7a8ca6eaa5
commit 1cb52dc863
36 changed files with 62 additions and 46 deletions

View File

@ -34,8 +34,17 @@ on Yjs. [![Become a Sponsor](https://img.shields.io/static/v1?label=Become%20a%2
## Professional Support
* [Support Contract with the Maintainer](https://github.com/sponsors/dmonad) - By contributing financially to the open-source Yjs project, you can receive professional support directly from the author. This includes the opportunity for weekly video calls to discuss your specific challenges.
* [Synergy Codes](https://synergycodes.com/yjs-services/) - Specializing in consulting and developing real-time collaborative editing solutions for visual apps, Synergy Codes focuses on interactive diagrams, complex graphs, charts, and various data visualization types. Their expertise empowers developers to build engaging and interactive visual experiences leveraging the power of Yjs. See their work in action at [Visual Collaboration Showcase](https://yjs-diagram.synergy.codes/).
* [Support Contract with the Maintainer](https://github.com/sponsors/dmonad) -
By contributing financially to the open-source Yjs project, you can receive
professional support directly from the author. This includes the opportunity for
weekly video calls to discuss your specific challenges.
* [Synergy Codes](https://synergycodes.com/yjs-services/) - Specializing in
consulting and developing real-time collaborative editing solutions for visual
apps, Synergy Codes focuses on interactive diagrams, complex graphs, charts, and
various data visualization types. Their expertise empowers developers to build
engaging and interactive visual experiences leveraging the power of Yjs. See
their work in action at [Visual Collaboration
Showcase](https://yjs-diagram.synergy.codes/).
## Who is using Yjs

View File

@ -1,4 +1,3 @@
export * from './utils/AbstractConnector.js'
export * from './utils/DeleteSet.js'
export * from './utils/Doc.js'

View File

@ -1,4 +1,3 @@
import {
UpdateEncoderV1, UpdateEncoderV2, ID, Transaction // eslint-disable-line
} from '../internals.js'

View File

@ -1,4 +1,3 @@
import {
addToDeleteSet,
UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, StructStore, Item, Transaction // eslint-disable-line

View File

@ -1,4 +1,3 @@
import {
Doc, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction, Item // eslint-disable-line
} from '../internals.js'

View File

@ -1,4 +1,3 @@
import {
UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, StructStore, Item, Transaction // eslint-disable-line
} from '../internals.js'

View File

@ -1,4 +1,3 @@
import {
YText, UpdateDecoderV1, UpdateDecoderV2, UpdateEncoderV1, UpdateEncoderV2, Item, StructStore, Transaction // eslint-disable-line
} from '../internals.js'

View File

@ -1,4 +1,3 @@
import {
readYArray,
readYMap,

View File

@ -1,4 +1,3 @@
import {
AbstractStruct,
addStruct,

View File

@ -1,4 +1,3 @@
import {
GC,
getState,

View File

@ -1,4 +1,3 @@
import {
AbstractStruct,
UpdateEncoderV1, UpdateEncoderV2, StructStore, Transaction, ID // eslint-disable-line

View File

@ -1,4 +1,3 @@
import {
removeEventHandlerListener,
callEventHandlerListeners,

View File

@ -1,4 +1,3 @@
/**
* @module YMap
*/

View File

@ -1,4 +1,3 @@
/**
* @module YText
*/
@ -118,14 +117,15 @@ const findNextPosition = (transaction, pos, count) => {
* @param {Transaction} transaction
* @param {AbstractType<any>} parent
* @param {number} index
* @param {boolean} useSearchMarker
* @return {ItemTextListPosition}
*
* @private
* @function
*/
const findPosition = (transaction, parent, index) => {
const findPosition = (transaction, parent, index, useSearchMarker) => {
const currentAttributes = new Map()
const marker = findMarker(parent, index)
const marker = useSearchMarker ? findMarker(parent, index) : null
if (marker) {
const pos = new ItemTextListPosition(marker.p.left, marker.p, marker.index, currentAttributes)
return findNextPosition(transaction, pos, index - marker.index)
@ -1120,7 +1120,7 @@ export class YText extends AbstractType {
const y = this.doc
if (y !== null) {
transact(y, transaction => {
const pos = findPosition(transaction, this, index)
const pos = findPosition(transaction, this, index, !attributes)
if (!attributes) {
attributes = {}
// @ts-ignore
@ -1138,20 +1138,20 @@ export class YText extends AbstractType {
*
* @param {number} index The index to insert the embed at.
* @param {Object | AbstractType<any>} embed The Object that represents the embed.
* @param {TextAttributes} attributes Attribute information to apply on the
* @param {TextAttributes} [attributes] Attribute information to apply on the
* embed
*
* @public
*/
insertEmbed (index, embed, attributes = {}) {
insertEmbed (index, embed, attributes) {
const y = this.doc
if (y !== null) {
transact(y, transaction => {
const pos = findPosition(transaction, this, index)
insertText(transaction, this, pos, embed, attributes)
const pos = findPosition(transaction, this, index, !attributes)
insertText(transaction, this, pos, embed, attributes || {})
})
} else {
/** @type {Array<function>} */ (this._pending).push(() => this.insertEmbed(index, embed, attributes))
/** @type {Array<function>} */ (this._pending).push(() => this.insertEmbed(index, embed, attributes || {}))
}
}
@ -1170,7 +1170,7 @@ export class YText extends AbstractType {
const y = this.doc
if (y !== null) {
transact(y, transaction => {
deleteText(transaction, findPosition(transaction, this, index), length)
deleteText(transaction, findPosition(transaction, this, index, true), length)
})
} else {
/** @type {Array<function>} */ (this._pending).push(() => this.delete(index, length))
@ -1194,7 +1194,7 @@ export class YText extends AbstractType {
const y = this.doc
if (y !== null) {
transact(y, transaction => {
const pos = findPosition(transaction, this, index)
const pos = findPosition(transaction, this, index, false)
if (pos.right === null) {
return
}

View File

@ -1,4 +1,3 @@
import {
YEvent,
YXmlText, YXmlElement, YXmlFragment, Transaction // eslint-disable-line

View File

@ -1,4 +1,3 @@
import {
YMap,
YXmlHookRefID,

View File

@ -1,4 +1,3 @@
import {
YText,
YXmlTextRefID,

View File

@ -1,4 +1,3 @@
import { Observable } from 'lib0/observable'
import {

View File

@ -1,4 +1,3 @@
import {
findIndexSS,
getState,

View File

@ -1,4 +1,3 @@
import { AbstractType } from '../internals.js' // eslint-disable-line
import * as decoding from 'lib0/decoding'

View File

@ -1,4 +1,3 @@
import {
YArray,
YMap,

View File

@ -1,4 +1,3 @@
import {
writeID,
readID,

View File

@ -1,4 +1,3 @@
import {
isDeleted,
createDeleteSetFromStructStore,

View File

@ -1,4 +1,3 @@
import {
GC,
splitItem,

View File

@ -1,4 +1,3 @@
import {
getState,
writeStructsFromTransaction,

View File

@ -1,4 +1,3 @@
import * as error from 'lib0/error'
import * as encoding from 'lib0/encoding'

View File

@ -1,4 +1,3 @@
import {
isDeleted,
Item, AbstractType, Transaction, AbstractStruct // eslint-disable-line

View File

@ -1,4 +1,3 @@
/**
* @module encoding
*/

View File

@ -1,4 +1,3 @@
import { AbstractType, Item } from '../internals.js' // eslint-disable-line
/**

View File

@ -1,4 +1,3 @@
import {
AbstractType // eslint-disable-line
} from '../internals.js'

View File

@ -1,4 +1,3 @@
import * as binary from 'lib0/binary'
import * as decoding from 'lib0/decoding'
import * as encoding from 'lib0/encoding'

View File

@ -1,4 +1,3 @@
/**
* Testing if encoding/decoding compatibility and integration compatiblity is given.
* We expect that the document always looks the same, even if we upgrade the integration algorithm, or add additional encoding approaches.

View File

@ -1,4 +1,3 @@
import * as Y from '../src/index.js'
import * as t from 'lib0/testing'

View File

@ -1,4 +1,3 @@
import * as Y from '../src/index.js'
import * as t from 'lib0/testing'

View File

@ -1,4 +1,3 @@
import * as t from 'lib0/testing'
import * as prng from 'lib0/prng'
import * as encoding from 'lib0/encoding'

View File

@ -3,6 +3,46 @@ import { init } from './testHelper.js' // eslint-disable-line
import * as Y from '../src/index.js'
import * as t from 'lib0/testing'
export const testInconsistentFormat = () => {
/**
* @param {Y.Doc} ydoc
*/
const testYjsMerge = ydoc => {
const content = /** @type {Y.XmlText} */ (ydoc.get('text', Y.XmlText))
content.format(0, 6, { bold: null })
content.format(6, 4, { type: 'text' })
t.compare(content.toDelta(), [
{
attributes: { type: 'text' },
insert: 'Merge Test'
},
{
attributes: { type: 'text', italic: true },
insert: ' After'
}
])
}
const initializeYDoc = () => {
const yDoc = new Y.Doc({ gc: false })
const content = /** @type {Y.XmlText} */ (yDoc.get('text', Y.XmlText))
content.insert(0, ' After', { type: 'text', italic: true })
content.insert(0, 'Test', { type: 'text' })
content.insert(0, 'Merge ', { type: 'text', bold: true })
return yDoc
}
{
const yDoc = initializeYDoc()
testYjsMerge(yDoc)
}
{
const initialYDoc = initializeYDoc()
const yDoc = new Y.Doc({ gc: false })
Y.applyUpdate(yDoc, Y.encodeStateAsUpdate(initialYDoc))
testYjsMerge(yDoc)
}
}
/**
* @param {t.TestCase} tc
*/