Merge pull request #393 from dkuhnert/issue-392

cleanup redundant text attributes when delete attributes
This commit is contained in:
Kevin Jahns 2022-02-24 22:07:49 +01:00 committed by GitHub
commit fef9e39d91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 69 additions and 1 deletions

View File

@ -291,7 +291,8 @@ const formatText = (transaction, parent, currPos, length, attributes) => {
const negatedAttributes = insertAttributes(transaction, parent, currPos, attributes)
// iterate until first non-format or null is found
// delete all formats with attributes[format.key] != null
while (length > 0 && currPos.right !== null) {
// also check the attributes after the first non-format as we do not want to insert redundant negated attributes there
while (currPos.right !== null && (length > 0 || currPos.right.content.constructor === ContentFormat)) {
if (!currPos.right.deleted) {
switch (currPos.right.content.constructor) {
case ContentFormat: {

View File

@ -527,3 +527,41 @@ export const testUndoBlockBug = tc => {
undoManager.redo() // {"text":{}}
t.compare(design.toJSON(), { text: { blocks: { text: '4' } } })
}
/**
* Undo text formatting delete should not corrupt peer state.
*
* @see https://github.com/yjs/yjs/issues/392
* @param {t.TestCase} tc
*/
export const testUndoDeleteTextFormat = tc => {
const doc = new Y.Doc()
const text = doc.getText()
text.insert(0, 'Attack ships on fire off the shoulder of Orion.')
const doc2 = new Y.Doc()
const text2 = doc2.getText();
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
const undoManager = new Y.UndoManager(text)
text.format(13, 7, { bold: true })
undoManager.stopCapturing()
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
text.format(16, 4, { bold: null })
undoManager.stopCapturing()
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
undoManager.undo()
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
const expect = [
{ insert: 'Attack ships ' },
{
insert: 'on fire',
attributes: { bold: true }
},
{ insert: ' off the shoulder of Orion.' }
]
t.compare(text.toDelta(), expect)
t.compare(text2.toDelta(), expect)
}

View File

@ -607,6 +607,35 @@ export const testFormattingBug = async tc => {
console.log(text1.toDelta())
}
/**
* Delete formatting should not leave redundant formatting items.
*
* @param {t.TestCase} tc
*/
export const testDeleteFormatting = tc => {
const doc = new Y.Doc()
const text = doc.getText()
text.insert(0, 'Attack ships on fire off the shoulder of Orion.')
const doc2 = new Y.Doc()
const text2 = doc2.getText()
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
text.format(13, 7, { bold: true })
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
text.format(16, 4, { bold: null })
Y.applyUpdate(doc2, Y.encodeStateAsUpdate(doc))
const expected = [
{ insert: 'Attack ships ' },
{ insert: 'on ', attributes: { bold: true } },
{ insert: 'fire off the shoulder of Orion.' }
]
t.compare(text.toDelta(), expected)
t.compare(text2.toDelta(), expected)
}
// RANDOM TESTS
let charCounter = 0