/**
* @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
import { Client, syncClients, expectClients, clearBuffer } from './utils.js';
describe( 'transform', () => {
let john, kate;
beforeEach( () => {
return Promise.all( [
Client.get( 'john' ).then( client => ( john = client ) ),
Client.get( 'kate' ).then( client => ( kate = client ) )
] );
} );
afterEach( () => {
clearBuffer();
return Promise.all( [ john.destroy(), kate.destroy() ] );
} );
describe( 'attribute', () => {
describe( 'by attribute', () => {
it( 'in text at same path', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients( '<$text bold="true">Foo$text> <$text italic="true">Bar$text>' );
} );
it( 'in text at same path, then undo', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients( '<$text bold="true">Foo$text> <$text italic="true">Bar$text>' );
john.undo();
syncClients();
expectClients( 'Foo <$text italic="true">Bar$text>' );
} );
it( 'in text in different path', () => {
john.setData( 'F[o]oBar' );
kate.setData( 'FooB[a]r' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients(
'F<$text bold="true">o$text>o' +
'B<$text italic="true">a$text>r'
);
} );
it( 'in text with selection inside other client\'s selection #1', () => {
john.setData( '[Foo Bar]' );
kate.setData( 'Fo[o B]ar' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients(
'' +
'<$text bold="true">Fo$text><$text bold="true" italic="true">o B$text><$text bold="true">ar$text>' +
''
);
} );
it( 'in text with selection inside other client\'s selection #2', () => {
john.setData( 'F[oo Ba]r' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients(
'' +
'F' +
'<$text bold="true">oo $text>' +
'<$text bold="true" italic="true">Ba$text>' +
'<$text italic="true">r$text>' +
''
);
} );
it( 'in text with selection inside other client\'s selection #3', () => {
john.setData( '<$text bold="true">[Foo Bar]$text>' );
kate.setData( '<$text bold="true">Fo[o] Bar$text>' );
john.setAttribute( 'italic', true );
kate.setAttribute( 'underline', true );
syncClients();
expectClients(
'' +
'<$text bold="true" italic="true">Fo$text>' +
'<$text bold="true" italic="true" underline="true">o$text>' +
'<$text bold="true" italic="true"> Bar$text>' +
''
);
} );
it( 'in text at same position', () => {
john.setData( '[Foo Bar]' );
kate.setData( '[Foo Bar]' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients( '<$text bold="true" italic="true">Foo Bar$text>' );
} );
it( 'in element at same position', () => {
john.setData( '[Foo Bar]' );
kate.setData( '[Foo Bar]' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients( 'Foo Bar' );
} );
it( 'in collapsed selection', () => {
john.setData( 'F[]oo Bar' );
kate.setData( 'F[]oo Bar' );
john.setAttribute( 'bold', true );
kate.setAttribute( 'italic', true );
syncClients();
expectClients( 'Foo Bar' );
} );
it( 'in same range, then change attribute', () => {
john.setData( '[Foo Bar]' );
kate.setData( '[Foo Bar]' );
john.setAttribute( 'attr', 'foo' );
kate.setAttribute( 'attr', 'bar' );
syncClients();
expectClients( '<$text attr="foo">Foo Bar$text>' );
kate.setAttribute( 'attr', 'bar' );
syncClients();
expectClients( '<$text attr="bar">Foo Bar$text>' );
} );
// https://github.com/ckeditor/ckeditor5/issues/6265
it( 'on elements on different but intersecting "levels"', () => {
john.setData( '[
]' );
kate.setData( '' );
john.setAttribute( 'attr', 'foo' );
kate.setAttribute( 'attr', 'bar' );
syncClients();
expectClients(
''
);
} );
} );
describe( 'by insert', () => {
it( 'text in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[]Bar' );
john.setAttribute( 'bold', true );
kate.type( 'Abc' );
syncClients();
expectClients( '<$text bold="true">Foo$text>AbcBar' );
} );
it( 'text in different path #2', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[]Bar' );
john.setAttribute( 'bold', true );
kate.type( 'Abc' );
syncClients();
expectClients( 'FooAbcBar' );
} );
it( 'text at same path', () => {
john.setData( '[F]oo' );
kate.setData( 'Foo[]' );
john.setAttribute( 'bold', true );
kate.type( 'Abc' );
syncClients();
expectClients( '<$text bold="true">F$text>ooAbc' );
} );
it( 'text inside other client\'s selection', () => {
john.setData( '[Foo]' );
kate.setData( 'Fo[]o' );
john.setAttribute( 'bold', true );
kate.type( 'Abc' );
syncClients();
expectClients( '<$text bold="true">FoAbco$text>' );
} );
it( 'element between changed elements', () => {
john.setData( '[FooBar]' );
kate.setData( 'Foo[]Bar' );
john.setAttribute( 'bold', true );
kate.insert( 'Abc' );
syncClients();
expectClients(
'Foo' +
'Abc' +
'Bar'
);
} );
it( 'text between changed nodes', () => {
john.setData( '[FooBar]' );
kate.setData( 'FooB[]ar' );
john.setAttribute( 'bold', true );
kate.type( 'Abc' );
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'<$text bold="true">BAbcar$text>'
);
} );
it( 'element in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'FooBar[]' );
john.setAttribute( 'bold', true );
kate.insert( 'Abc' );
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Bar' +
'Abc'
);
} );
it( 'element in different path #2', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'FooBar[]' );
john.setAttribute( 'bold', true );
kate.insert( 'Abc' );
syncClients();
expectClients(
'Foo' +
'Bar' +
'Abc'
);
} );
it( 'remove attribute from element in different path', () => {
john.setData( '[]FooBar' );
kate.setData( 'Foo[Bar]' );
john.type( 'Abc' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'AbcFooBar' );
} );
it( 'remove attribute from text in different path', () => {
john.setData( '[]Foo<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.type( 'Abc' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'AbcFooBar' );
} );
it( 'remove attribute from text while typing in client\'s range', () => {
john.setData( 'F<$text bold="true">o[]o$text>' );
kate.setData( 'F<$text bold="true">[oo]$text>' );
john.type( 'Bar' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'FoBaro' );
} );
it( 'remove attribute from element in same path', () => {
john.setData( '[]Foo' );
kate.setData( '[Foo]' );
john.type( 'Bar' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'BarFoo' );
} );
it( 'remove attribute from text with 2 attributes while typing in client\'s range', () => {
john.setData( 'F<$text bold="true" italic="true">o[]o$text>' );
kate.setData( 'F<$text bold="true" italic="true">[oo]$text>' );
john.type( 'Bar', john.document.selection.getAttributes() );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'F<$text italic="true">oBaro$text>' );
} );
it( 'multiple typing', () => {
john.setData( '[Foo]' );
kate.setData( 'Fo[]o' );
john.setAttribute( 'bold', true );
kate.setSelection( [ 0, 2 ] );
kate.type( 'x' );
kate.setSelection( [ 0, 3 ] );
kate.type( 'x' );
kate.setSelection( [ 0, 4 ] );
kate.type( 'x' );
syncClients();
expectClients( '<$text bold="true">Foxxxo$text>' );
} );
it( 'type inside element which attribute changes', () => {
john.setData( '[]' );
kate.setData( '[]' );
john.setAttribute( 'bold', true );
kate.type( 'x' );
syncClients();
expectClients( 'x' );
} );
} );
describe( 'by move', () => {
it( 'text in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'FooB[ar]' );
john.setAttribute( 'bold', true );
kate.move( [ 1, 0 ] );
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'arB'
);
} );
it( 'text in different path #2', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'FooB[ar]' );
john.setAttribute( 'bold', true );
kate.move( [ 1, 0 ] );
syncClients();
expectClients(
'Foo' +
'arB'
);
} );
it( 'text in same path', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'Foo B[ar]' );
john.setAttribute( 'bold', true );
kate.move( [ 0, 4 ] );
syncClients();
expectClients( '<$text bold="true">Foo$text> arB' );
} );
it( 'text to other client\'s selection', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.move( [ 0, 1 ] );
syncClients();
expectClients( '<$text bold="true">F$text>Bar<$text bold="true">oo$text> ' );
} );
it( 'text from other client\'s selection', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'F[oo] Bar' );
john.setAttribute( 'bold', true );
kate.move( [ 0, 7 ] );
syncClients();
expectClients( '<$text bold="true">F$text> Bar<$text bold="true">oo$text>' );
} );
it( 'text from other client\'s selection #2', () => {
john.setData( '[Foo Bar]' );
kate.setData( 'F[oo] Bar' );
john.setAttribute( 'bold', true );
kate.move( [ 0, 7 ] );
syncClients();
expectClients( 'F Baroo' );
} );
it( 'remove attribute from element in different path', () => {
john.setData( 'F[oo]Bar' );
kate.setData( 'Foo[Bar]' );
john.move( [ 1, 0 ] );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'ooBar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData( 'F[oo]<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.move( [ 1, 0 ] );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'ooBar'
);
} );
it( 'remove attribute from text in same path', () => {
john.setData( '[Fo]<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.move( [ 0, 3 ] );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'oFo' );
} );
it( 'remove attribute from element in same path', () => {
john.setData( '[Fo]o' );
kate.setData( '[Foo]' );
john.move( [ 0, 3 ] );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'oFo' );
} );
it( 'remove attribute from text with 2 attributes in same path', () => {
john.setData( '[Fo]<$text bold="true" italic="true">o$text>' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>' );
john.move( [ 0, 3 ] );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '<$text italic="true">o$text>Fo' );
} );
it( 'remove attribute from text in other user\'s selection', () => {
john.setData( '<$text bold="true">[Foo]$text>' );
kate.setData( '<$text bold="true">[Foo]$text>' );
john.move( [ 1, 0 ] );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'' +
'Foo'
);
} );
} );
describe( 'by wrap', () => {
it( 'element into blockQuote in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[Bar]' );
john.setAttribute( 'bold', true );
kate.wrap( 'blockQuote' );
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Bar
'
);
} );
it( 'element into blockQuote in different path #2', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[Bar]' );
john.setAttribute( 'bold', true );
kate.wrap( 'blockQuote' );
syncClients();
expectClients(
'Foo' +
'Bar
'
);
} );
it( 'element into blockQuote in same path #1', () => {
john.setData( '[Foo]' );
kate.setData( '[Foo]' );
john.setAttribute( 'bold', true );
kate.wrap( 'blockQuote' );
syncClients();
expectClients(
'' +
'<$text bold="true">Foo$text>' +
'
'
);
} );
it( 'element into blockQuote in same path #2', () => {
john.setData( '[Foo]' );
kate.setData( '[Foo]' );
john.setAttribute( 'bold', true );
kate.wrap( 'blockQuote' );
syncClients();
expectClients(
'' +
'Foo' +
'
'
);
} );
it( 'remove attribute from element in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[Bar]' );
john.wrap( 'blockQuote' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'' +
'Foo' +
'
' +
'Bar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData( '[Foo]<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.wrap( 'blockQuote' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'' +
'Foo' +
'
' +
'Bar'
);
} );
it( 'remove attribute from text in same path', () => {
john.setData( '[Fo<$text bold="true">o$text>]' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.wrap( 'blockQuote' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo
' );
} );
it( 'remove attribute from element in same path', () => {
john.setData( '[Foo]' );
kate.setData( '[Foo]' );
john.wrap( 'blockQuote' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo
' );
} );
it( 'remove attribute from text with 2 attributes in same path', () => {
john.setData( '[Fo<$text bold="true" italic="true">o$text>]' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>' );
john.wrap( 'blockQuote' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'' +
'Fo<$text italic="true">o$text>' +
'
'
);
} );
} );
describe( 'by unwrap', () => {
it( 'element in different path', () => {
john.setData( '[Foo]Bar
' );
kate.setData( 'Foo[Bar]
' );
john.setAttribute( 'bold', true );
kate.unwrap();
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Bar'
);
} );
it( 'element in different path #2', () => {
john.setData( '[Foo]Bar
' );
kate.setData( 'Foo[Bar]
' );
john.setAttribute( 'bold', true );
kate.unwrap();
syncClients();
expectClients(
'Foo' +
'Bar'
);
} );
it( 'text in different path', () => {
john.setData( '[Foo]Bar
' );
kate.setData( 'Foo[]Bar
' );
john.setAttribute( 'bold', true );
kate.unwrap();
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Bar
'
);
} );
it( 'element in same path #1', () => {
john.setData( '[Foo]
' );
kate.setData( '[Foo]
' );
john.setAttribute( 'bold', true );
kate.unwrap();
syncClients();
expectClients( '<$text bold="true">Foo$text>' );
} );
it( 'element in same path #2', () => {
john.setData( '[Foo]
' );
kate.setData( '[Foo]
' );
john.setAttribute( 'bold', true );
kate.unwrap();
syncClients();
expectClients( 'Foo' );
} );
it( 'text in same path', () => {
john.setData( '[Foo]
' );
kate.setData( '[]Foo
' );
john.setAttribute( 'bold', true );
kate.unwrap();
syncClients();
expectClients( '<$text bold="true">Foo$text>
' );
} );
it( 'remove attribute from element in different path', () => {
john.setData(
'[Foo]
' +
'Bar' );
kate.setData(
'Foo
' +
'[Bar]' );
john.unwrap();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Foo' +
'Bar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData(
'[]Foo
' +
'<$text bold="true">Bar$text>' );
kate.setData(
'Foo
' +
'<$text bold="true">[Bar]$text>' );
john.unwrap();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Foo
' +
'Bar'
);
} );
it( 'remove attribute from text in same path', () => {
john.setData( '[]Fo<$text bold="true">o$text>
' );
kate.setData( 'Fo<$text bold="true">[o]$text>
' );
john.unwrap();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo
' );
} );
it( 'remove attribute from element in same path', () => {
john.setData( '[]Foo
' );
kate.setData( '[Foo]
' );
john.unwrap();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo
' );
} );
it( 'remove attribute from text with 2 attributes in same path', () => {
john.setData( '[]Fo<$text bold="true" italic="true">o$text>
' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>
' );
john.unwrap();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Fo<$text italic="true">o$text>
' );
} );
} );
describe( 'by split', () => {
it( 'text in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'FooBa[]r' );
john.setAttribute( 'bold', true );
kate.split();
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Ba' +
'r'
);
} );
it( 'text in different path #2', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'FooBa[]r' );
john.setAttribute( 'bold', true );
kate.split();
syncClients();
expectClients(
'Foo' +
'Ba' +
'r'
);
} );
it( 'text in same path #1', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'Foo B[]ar' );
john.setAttribute( 'bold', true );
kate.split();
syncClients();
expectClients(
'<$text bold="true">Foo$text> B' +
'ar'
);
} );
it( 'text in other user\'s selection', () => {
john.setData( '[Foo]' );
kate.setData( 'Fo[]o' );
john.setAttribute( 'bold', true );
kate.split();
syncClients();
expect(
'<$text bold="true">Fo$text>' +
'<$text bold="true">o$text>'
);
} );
it( 'text in other user\'s selection #2', () => {
john.setData( '[Foo Bar]' );
kate.setData( 'Foo B[]ar' );
john.setAttribute( 'bold', true );
kate.split();
syncClients();
expectClients(
'Foo B' +
'ar'
);
} );
it( 'text while changing attribute', () => {
john.setData( '<$text attr="foo">Foo B[ar]$text>' );
kate.setData( '<$text attr="foo">Foo B[]ar$text>' );
john.setAttribute( 'attr', 'bar' );
kate.split();
syncClients();
expectClients(
'<$text attr="foo">Foo B$text>' +
'<$text attr="bar">ar$text>'
);
} );
it( 'remove attribute from element in different path', () => {
john.setData( 'F[]ooBar' );
kate.setData( 'Foo[Bar]' );
john.split();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'oo' +
'Bar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData( 'F[]oo<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.split();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'oo' +
'Bar'
);
} );
it( 'remove attribute from text in same path #1', () => {
john.setData( 'F[]o<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.split();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'oo' );
} );
it( 'remove attribute from text in same path #2', () => {
john.setData( 'F<$text bold="true">o[]o$text>' );
kate.setData( 'F<$text bold="true">[oo]$text>' );
john.split();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Fo' +
'o' );
} );
it( 'remove attribute from element in same path', () => {
john.setData( 'F[]oo' );
kate.setData( '[Foo]' );
john.split();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'oo' );
} );
it( 'remove attribute from text with 2 attributes in same path', () => {
john.setData( 'F<$text bold="true" italic="true">o[]o$text>' );
kate.setData( 'F<$text bold="true" italic="true">[oo]$text>' );
john.split();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F<$text italic="true">o$text>' +
'<$text italic="true">o$text>'
);
} );
} );
describe( 'by remove', () => {
it( 'text in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[Bar]' );
john.setAttribute( 'bold', true );
kate.remove();
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
''
);
} );
it( 'text in same path', () => {
john.setData( '[Fo]o' );
kate.setData( 'Fo[o]' );
john.setAttribute( 'bold', true );
kate.remove();
syncClients();
expectClients( '<$text bold="true">Fo$text>' );
} );
it( 'text in other user\'s selection', () => {
john.setData( '[Foo]' );
kate.setData( 'F[oo]' );
john.setAttribute( 'bold', true );
kate.remove();
syncClients();
expectClients( '<$text bold="true">F$text>' );
} );
it( 'remove attribute from element in different path', () => {
john.setData( 'F[oo]Bar' );
kate.setData( 'Foo[Bar]' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'Bar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData( 'F[oo]<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F' +
'Bar'
);
} );
it( 'remove attribute from text in same path #1', () => {
john.setData( '[Fo]<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'o' );
} );
it( 'remove attribute from text in same path #2', () => {
john.setData( 'F[o<$text bold="true">o]z$text>Bar' );
kate.setData( 'Fo<$text bold="true">[oz]$text>Bar' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'FzBar'
);
} );
it( 'remove attribute from element in same path', () => {
john.setData( '[Fo]o' );
kate.setData( '[Foo]' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'o' );
} );
it( 'remove attribute from text with 2 attributes in same path #1', () => {
john.setData( '[Fo]<$text bold="true" italic="true">o$text>' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '<$text italic="true">o$text>' );
} );
it( 'remove attribute from text with 2 attributes in same path #2', () => {
john.setData( 'F[o<$text bold="true" italic="true">o]z$text>Bar' );
kate.setData( 'Fo<$text bold="true" italic="true">[oz]$text>Bar' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'F<$text italic="true">z$text>Bar'
);
} );
it( 'remove attribute from text in other user\'s selection', () => {
john.setData( '<$text bold="true">[Foo]$text>' );
kate.setData( '<$text bold="true">[Foo]$text>' );
john.remove();
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '' );
} );
} );
describe( 'by remove attribute', () => {
it( 'from element in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[Bar]' );
john.setAttribute( 'bold', true );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Bar'
);
} );
it( 'from text in different path', () => {
john.setData( '[Foo]<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.setAttribute( 'bold', true );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'<$text bold="true">Foo$text>' +
'Bar'
);
} );
it( 'from text in same path', () => {
john.setData( '[Fo]<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.setAttribute( 'bold', true );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '<$text bold="true">Fo$text>o' );
} );
it( 'from element in same path', () => {
john.setData( '[Fo]o' );
kate.setData( '[Foo]' );
john.setAttribute( 'italic', true );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '<$text italic="true">Fo$text>o' );
} );
it( 'from text with 2 attributes in same path', () => {
john.setData( '[Fo]<$text bold="true" italic="true">o$text>' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>' );
john.setAttribute( 'bold', true );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '<$text bold="true">Fo$text><$text italic="true">o$text>' );
} );
it( 'from text in other user\'s selection', () => {
john.setData( '<$text bold="true">[Foo]$text>' );
kate.setData( '<$text bold="true">[Foo]$text>' );
john.setAttribute( 'italic', true );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( '<$text italic="true">Foo$text>' );
} );
} );
describe( 'by marker', () => {
it( 'in text at same path', () => {
john.setData( '[Foo] Bar' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.setMarker( 'm1' );
syncClients();
expectClients( '<$text bold="true">Foo$text> Bar' );
} );
it( 'in text at same path #2', () => {
john.setData( '[Foo Bar]' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.setMarker( 'm1' );
syncClients();
expectClients(
'' +
'Foo Bar' +
''
);
} );
it( 'in text in different path', () => {
john.setData( 'F[o]oBar' );
kate.setData( 'FooB[a]r' );
john.setAttribute( 'bold', true );
kate.setMarker( 'm1' );
syncClients();
expectClients(
'F<$text bold="true">o$text>o' +
'Bar'
);
} );
it( 'in text with selection inside other client\'s selection #1', () => {
john.setData( '[Foo Bar]' );
kate.setData( 'Fo[o B]ar' );
john.setAttribute( 'bold', true );
kate.setMarker( 'm1' );
syncClients();
expectClients(
'' +
'<$text bold="true">Fo$text>' +
'<$text bold="true">o B$text><$text bold="true">ar$text>' +
''
);
} );
it( 'in text with selection inside other client\'s selection #2', () => {
john.setData( 'F[oo Ba]r' );
kate.setData( 'Foo [Bar]' );
john.setAttribute( 'bold', true );
kate.setMarker( 'm1' );
syncClients();
expectClients(
'' +
'F<$text bold="true">oo $text><$text bold="true">Ba$text>r' +
''
);
} );
it( 'in text at same position', () => {
john.setData( '[Foo Bar]' );
kate.setData( '[Foo Bar]' );
john.setAttribute( 'bold', true );
kate.setMarker( 'm1' );
syncClients();
expectClients( '<$text bold="true">Foo Bar$text>' );
} );
it( 'remove attribute from element in different path', () => {
john.setData( '[Foo]Bar' );
kate.setData( 'Foo[Bar]' );
john.setMarker( 'm1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Foo' +
'Bar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData( '[Foo]<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.setMarker( 'm1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Foo' +
'Bar'
);
} );
it( 'remove attribute from text in same path', () => {
john.setData( '[Fo]<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.setMarker( 'm1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo' );
} );
it( 'remove attribute from text in same path, then undo', () => {
john.setData( '[Fo]<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.setMarker( 'm1' );
kate.removeAttribute( 'bold' );
syncClients();
kate.undo();
syncClients();
expectClients( 'Fo<$text bold="true">o$text>' );
} );
it( 'remove attribute from text with 2 attributes in same path', () => {
john.setData( '[Fo]<$text bold="true" italic="true">o$text>' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>' );
john.setMarker( 'm1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Fo<$text italic="true">o$text>' );
} );
it( 'remove attribute from text in other user\'s selection', () => {
john.setData( '<$text bold="true">[Foo]$text>' );
kate.setData( '<$text bold="true">[Foo]$text>' );
john.setMarker( 'm1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo' );
} );
} );
describe( 'by merge', () => {
it( 'element into paragraph #1', () => {
john.setData( 'FooB[ar]' );
kate.setData( 'Foo[]Bar' );
john.setAttribute( 'bold', 'true' );
kate.merge();
syncClients();
expectClients( 'FooB<$text bold="true">ar$text>' );
} );
it( 'element into paragraph #2, then undo', () => {
john.setData( 'Foo[Bar]' );
kate.setData( 'Foo[]Bar' );
john.setAttribute( 'bold', 'true' );
kate.merge();
syncClients();
expectClients( 'FooBar' );
kate.undo();
syncClients();
expectClients( 'FooBar' );
} );
it( 'element in same path', () => {
john.setData( 'FooBar[Baz]' );
kate.setData( 'Foo[]BarBaz' );
john.setAttribute( 'bold', 'true' );
kate.merge();
syncClients();
expectClients( 'FooBarBaz' );
kate.undo();
john.undo();
syncClients();
expectClients( 'FooBarBaz' );
} );
} );
} );
describe( 'by rename', () => {
it( 'element in different path', () => {
john.setData( 'Foo[Ba]r' );
kate.setData( 'F[]ooBar' );
john.setAttribute( 'bold', true );
kate.rename( 'heading1' );
syncClients();
expectClients(
'Foo' +
'<$text bold="true">Ba$text>r'
);
} );
it( 'element in same path', () => {
john.setData( '[Foo Bar]' );
kate.setData( '[]Foo Bar' );
john.setAttribute( 'bold', true );
kate.rename( 'heading1' );
syncClients();
expectClients( '<$text bold="true">Foo Bar$text>' );
} );
it( 'element in user\'s selection', () => {
john.setData( '[Foo]' );
kate.setData( '[Foo]' );
john.setAttribute( 'bold', true );
kate.rename( 'heading1' );
syncClients();
expectClients( '<$text bold="true">Foo$text>' );
} );
it( 'element in user\'s selection, then undo', () => {
john.setData( '[Foo]' );
kate.setData( '[Foo]' );
john.setAttribute( 'bold', true );
kate.rename( 'heading1' );
syncClients();
john.undo();
kate.undo();
syncClients();
expectClients( 'Foo' );
} );
it( 'remove attribute from element in different path', () => {
john.setData( 'F[]ooBar' );
kate.setData( 'Foo[Bar]' );
john.rename( 'heading1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Foo' +
'Bar'
);
} );
it( 'remove attribute from text in different path', () => {
john.setData( 'F[]oo<$text bold="true">Bar$text>' );
kate.setData( 'Foo<$text bold="true">[Bar]$text>' );
john.rename( 'heading1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients(
'Foo' +
'Bar'
);
} );
it( 'remove attribute from text in same path', () => {
john.setData( 'F[]o<$text bold="true">o$text>' );
kate.setData( 'Fo<$text bold="true">[o]$text>' );
john.rename( 'heading1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo' );
} );
it( 'remove attribute from element in same path', () => {
john.setData( 'F[]oo' );
kate.setData( '[Foo]' );
john.rename( 'heading1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo' );
} );
it( 'remove attribute from text with 2 attributes in same path', () => {
john.setData( 'F[o]<$text bold="true" italic="true">o$text>' );
kate.setData( 'Fo<$text bold="true" italic="true">[o]$text>' );
john.rename( 'heading1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Fo<$text italic="true">o$text>' );
} );
it( 'remove attribute from text in other user\'s selection', () => {
john.setData( '<$text bold="true">[Foo]$text>' );
kate.setData( '<$text bold="true">[Foo]$text>' );
john.rename( 'heading1' );
kate.removeAttribute( 'bold' );
syncClients();
expectClients( 'Foo' );
} );
} );
} );