/** * @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 ) ) ] ).then( () => { john.editor.model.schema.register( 'div', { inheritAllFrom: 'blockQuote' } ); kate.editor.model.schema.register( 'div', { inheritAllFrom: 'blockQuote' } ); } ); } ); afterEach( () => { clearBuffer(); return Promise.all( [ john.destroy(), kate.destroy() ] ); } ); describe( 'wrap', () => { describe( 'by wrap', () => { it( 'element in different path', () => { john.setData( '[Foo]Bar' ); kate.setData( 'Foo[Bar]' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); expectClients( '
Foo
' + '
Bar
' ); } ); it( 'the same element', () => { john.setData( '[Foo]' ); kate.setData( '[Foo]' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( '
Foo
' ); expectClients( '
Foo
' ); } ); it( 'intersecting wrap #1', () => { john.setData( '[FooBar]Xyz' ); kate.setData( 'Foo[BarXyz]' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // '
' + // 'Foo' + // 'Bar' + // '
' + // '
' + // 'Xyz' + // '
' // ); expectClients( '
Foo
Xyz
Bar
' ); } ); it( 'intersecting wrap #2', () => { john.setData( '[FooBarAbc]' ); kate.setData( 'Foo[Bar]Abc' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // '
' + // 'Foo' + // 'Bar' + // 'Abc' + // '
' // ); expectClients( '
Foo
Bar
Abc
' ); } ); it( 'intersecting wrap #3', () => { john.setData( '[FooBar]Abc' ); kate.setData( '[Foo]BarAbc' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // '
' + // 'Foo' + // 'Bar' + // '
' + // 'Abc' // ); expectClients( '
FooBar
Abc' ); } ); it( 'intersecting wrap, then undo #1', () => { john.setData( '[FooBar]Abc' ); kate.setData( 'Foo[BarAbc]' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // '
' + // 'Foo' + // 'Bar' + // '
' + // '
' + // 'Abc' + // '
' // ); expectClients( '
Foo
Abc
Bar
' ); john.undo(); kate.undo(); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // 'Foo' + // 'Bar' + // 'Abc' // ); expectClients( 'AbcFooBar' ); } ); it( 'intersecting wrap, then undo #2', () => { john.setData( '[FooBar]Abc' ); kate.setData( 'Foo[BarAbc]' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( // '
' + // 'Foo' + // 'Bar' + // '
' + // '
' + // 'Abc' + // '
' // ); expectClients( '
Foo
Abc
Bar
' ); john.undo(); kate.undo(); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( 'FooBarAbc' ); expectClients( 'AbcFooBar' ); } ); it( 'intersecting wrap, then undo #3', () => { john.setData( '[FooBar]Abc' ); kate.setData( '[Foo]BarAbc' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); john.undo(); kate.undo(); syncClients(); expectClients( 'Foo' + 'Bar' + 'Abc' ); } ); it( 'element and text', () => { john.setData( '[Foo]' ); kate.setData( '[Foo]' ); john.wrap( 'blockQuote' ); kate.wrap( 'div' ); syncClients(); expectClients( '
Foo
' ); } ); } ); describe( 'by unwrap', () => { it( 'element in different path', () => { john.setData( '[Foo]
Bar
' ); kate.setData( 'Foo
[Bar]
' ); john.wrap( 'blockQuote' ); kate.unwrap(); syncClients(); expectClients( '
Foo
' + 'Bar' ); } ); it( 'text in different path', () => { john.setData( '[Foo]
Bar
' ); kate.setData( 'Foo
[]Bar
' ); john.wrap( 'div' ); kate.unwrap(); syncClients(); expectClients( '
Foo
' + '
Bar
' ); } ); it( 'the same element through undo', () => { john.setData( '[Foo]' ); kate.setData( '[]Foo' ); john.wrap( 'blockQuote' ); syncClients(); expectClients( '
Foo
' ); kate.setSelection( [ 0, 0 ] ); kate.unwrap(); syncClients(); expectClients( 'Foo' ); john.undo(); kate.undo(); syncClients(); expectClients( 'Foo' ); } ); it( 'wrap in unwrapped element', () => { john.setData( '
[Foo]
' ); kate.setData( '
[]Foo
' ); john.wrap( 'div' ); kate.unwrap(); syncClients(); // Below would be the expected effect with correct wrap transformation. // expectClients( '
Foo
' ); expectClients( '' ); } ); it.skip( 'wrap in unwrapped element, then undo', () => { // This is interesting scenario actually. Normally in wrap x wrap situation the stronger wrap just wins // so we won't get incorrect model. But John was actually to make a wrap like this then he had //

structure for a while. So it should be possible to revert to it. john.setData( '

[Foo]
' ); kate.setData( '
[]Foo
' ); john.wrap( 'div' ); kate.unwrap(); syncClients(); expectClients( '
Foo
' ); kate.undo(); syncClients(); expectClients( '
Foo
' ); } ); it.skip( 'the same text, then undo', () => { // This is interesting scenario actually. Normally in wrap x wrap situation the stronger wrap just wins // so we won't get incorrect model. But John was actually to make a wrap like this then he had //

structure for a while. So it should be possible to revert to it. john.setData( '
[Foo]
' ); kate.setData( '
[]Foo
' ); john.wrap( 'div' ); kate.unwrap(); syncClients(); expectClients( '
Foo
' ); kate.undo(); syncClients(); expectClients( '
Foo
' ); } ); } ); describe( 'by delete', () => { it( 'text in two elements #1', () => { john.setData( '[Foo]Bar' ); kate.setData( 'Fo[oBa]r' ); john.wrap( 'blockQuote' ); kate.delete(); syncClients(); expectClients( '
' + 'For' + '
' ); } ); it( 'text in two elements #2', () => { john.setData( '[Foo]Bar' ); kate.setData( 'Fo[oBa]r' ); john.wrap( 'div' ); kate.delete(); syncClients(); expectClients( '
Fo
r
' ); } ); it( 'delete all wrapped content', () => { john.setData( '[FooBarAbc]' ); kate.setData( '[FooBarAb]c' ); john.wrap( 'blockQuote' ); kate.delete(); syncClients(); expectClients( '
c
' ); } ); it( 'delete all wrapped content and undo', () => { john.setData( '[FooBarAbc]' ); kate.setData( '[FooBarAb]c' ); john.wrap( 'blockQuote' ); kate.delete(); syncClients(); expectClients( '
c
' ); john.undo(); // There is a bug in undo for Kate. // Kate's content is: '
c
'. // Then goes undo and it returns "Foo" paragraph into block quote, but "Bar" goes after it. // There is a move (reinsert) x wrap transformation and the move is not included inside the wrap. kate.undo(); syncClients(); expectClients( 'FooBarAbc' ); } ); } ); describe( 'by remove', () => { it( 'remove the only wrapped element', () => { john.setData( '[Foo]Bar' ); kate.setData( '[Foo]Bar' ); john.wrap( 'blockQuote' ); kate.remove(); syncClients(); expectClients( 'Bar' ); } ); it( 'remove one of two wrapped elements', () => { john.setData( '[FooBar]' ); kate.setData( '[Foo]Bar' ); john.wrap( 'blockQuote' ); kate.remove(); syncClients(); expectClients( '
Bar
' ); } ); it( 'remove all wrapped elements', () => { john.setData( '[FooBar]Xyz' ); kate.setData( '[Foo]BarXyz' ); john.wrap( 'blockQuote' ); kate.remove(); kate.setSelection( [ 0 ], [ 1 ] ); kate.remove(); syncClients(); expectClients( 'Xyz' ); } ); it( 'remove the only wrapped element with undo', () => { john.setData( '[Foo]Bar' ); kate.setData( '[Foo]Bar' ); john.wrap( 'blockQuote' ); kate.remove(); syncClients(); expectClients( 'Bar' ); john.undo(); kate.undo(); syncClients(); expectClients( 'FooBar' ); } ); it( 'remove one of two wrapped elements with undo', () => { john.setData( '[FooBar]' ); kate.setData( '[Foo]Bar' ); john.wrap( 'blockQuote' ); kate.remove(); syncClients(); expectClients( '
Bar
' ); john.undo(); kate.undo(); syncClients(); expectClients( 'FooBar' ); } ); it( 'remove all wrapped elements with undo', () => { john.setData( '[FooBar]Xyz' ); kate.setData( '[Foo]BarXyz' ); john.wrap( 'blockQuote' ); kate.remove(); kate.setSelection( [ 0 ], [ 1 ] ); kate.remove(); syncClients(); expectClients( 'Xyz' ); john.undo(); kate.undo(); kate.undo(); syncClients(); expectClients( 'FooBarXyz' ); } ); } ); describe( 'by merge', () => { it( 'element into paragraph #1', () => { john.setData( '[Foo]Bar' ); kate.setData( 'Foo[]Bar' ); john.wrap( 'blockQuote' ); kate.merge(); syncClients(); expectClients( '
FooBar
' ); } ); it( 'element into paragraph #2', () => { john.setData( '[Foo]Bar' ); kate.setData( 'Foo[]Bar' ); john.wrap( 'div' ); kate.merge(); syncClients(); john.undo(); kate.undo(); syncClients(); expectClients( 'FooBar' ); } ); it( 'element into paragraph, then undo', () => { john.setData( 'Foo[Bar]' ); kate.setData( 'Foo[]Bar' ); john.wrap( 'blockQuote' ); kate.merge(); syncClients(); expectClients( 'FooBar' ); john.undo(); kate.undo(); syncClients(); expectClients( 'FooBar' ); } ); } ); } ); } );