/**
* @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, expectClients, clearBuffer } from './utils.js';
import DocumentFragment from '../../../../src/model/documentfragment';
import Element from '../../../../src/model/element';
import Text from '../../../../src/model/text';
describe( 'transform', () => {
let john;
beforeEach( () => {
return Client.get( 'john' ).then( client => ( john = client ) );
} );
afterEach( () => {
clearBuffer();
return john.destroy();
} );
it( 'split, remove', () => {
john.setData( 'Foo[]Bar' );
john.split();
john.setSelection( [ 1 ], [ 2 ] );
john.remove();
john.undo();
john.undo();
expectClients( 'FooBar' );
} );
it( 'move, merge', () => {
john.setData( '[Foo]Bar' );
john.move( [ 2 ] );
john.setSelection( [ 1 ] );
john.merge();
john.undo();
john.undo();
expectClients( 'FooBar' );
} );
it.skip( 'move multiple, merge', () => {
john.setData( '[FooBar]Xyz' );
john.move( [ 3 ] );
expectClients( 'XyzFooBar' );
john.setSelection( [ 1 ] );
john.merge();
expectClients( 'XyzFooBar' );
john.undo();
expectClients( 'XyzFooBar' );
john.undo();
// Wrong move is done.
expectClients( 'FooBarXyz' );
} );
it( 'move inside unwrapped content', () => {
john.setData( '
[Foo]Bar
' );
john.move( [ 0, 2 ] );
john.setSelection( [ 0, 0 ] );
john.unwrap();
john.undo();
john.undo();
expectClients(
'' +
'Foo' +
'Bar' +
'
'
);
} );
it( 'remove node, merge', () => {
john.setData( 'Foo[Bar]' );
john.remove();
john.setSelection( [ 1 ] );
john.merge();
john.undo();
john.undo();
expectClients( 'FooBar' );
} );
it( 'merge, merge #1', () => {
john.setData(
'' +
'Foo' +
'Bar' +
'
' +
'[]' +
'' +
'Xyz' +
'
'
);
john.merge();
john.setSelection( [ 0, 2 ] );
john.merge();
expectClients(
'' +
'Foo' +
'BarXyz' +
'
'
);
john.undo();
john.undo();
expectClients(
'' +
'Foo' +
'Bar' +
'
' +
'' +
'Xyz' +
'
'
);
} );
it( 'merge, merge #2', () => {
john.setData(
'' +
'Foo' +
'
' +
'[]' +
'' +
'Bar' +
'Xyz' +
'
'
);
john.merge();
john.setSelection( [ 0, 1 ] );
john.merge();
expectClients(
'' +
'FooBar' +
'Xyz' +
'
'
);
john.undo();
john.undo();
expectClients(
'' +
'Foo' +
'
' +
'' +
'Bar' +
'Xyz' +
'
'
);
} );
it( 'merge, unwrap', () => {
john.setData( '[]Foo' );
john.merge();
john.setSelection( [ 0, 0 ] );
john.unwrap();
john.undo();
john.undo();
expectClients( 'Foo' );
} );
it( 'remove node at the split position #1', () => {
john.setData( 'Ab[]Xy' );
john.merge();
john.setSelection( [ 0, 1 ], [ 0, 2 ] );
john.remove();
john.undo();
john.undo();
expectClients( 'AbXy' );
} );
it( 'remove node at the split position #2', () => {
john.setData( 'Ab[]Xy' );
john.merge();
john.setSelection( [ 0, 2 ], [ 0, 3 ] );
john.remove();
john.undo();
john.undo();
expectClients( 'AbXy' );
} );
it( 'undoing split after the element created by split has been removed', () => {
// This example is ported here from ckeditor5-undo to keep 100% CC in ckeditor5-engine alone.
john.setData( 'Foo[]bar' );
john.split();
john.setSelection( [ 0, 3 ], [ 1, 3 ] );
john.delete();
expectClients( 'Foo' );
john.undo();
expectClients( 'Foobar' );
john.undo();
expectClients( 'Foobar' );
} );
it( 'remove text from paragraph and merge it', () => {
john.setData( 'Foo[Bar]' );
john.remove();
john.setSelection( [ 1 ] );
john.merge();
expectClients( 'Foo' );
john.undo();
expectClients( 'Foo' );
john.undo();
expectClients( 'FooBar' );
} );
it( 'delete split paragraphs', () => {
john.setData( 'FooB[]ar' );
john.split();
john.setSelection( [ 2, 1 ] );
john.split();
john.setSelection( [ 1, 0 ], [ 3, 1 ] );
john.delete();
john.setSelection( [ 1 ] );
john.merge();
expectClients( 'Foo' );
john.undo();
expectClients( 'Foo' );
john.undo();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'Foo' );
john.redo();
expectClients( 'Foo' );
} );
it( 'pasting on collapsed selection undo and redo', () => {
john.setData( 'Foo[]Bar' );
// Below simulates pasting.
john.editor.model.change( () => {
john.split();
john.setSelection( [ 1 ] );
john.insert( '1' );
john.setSelection( [ 1 ] );
john.merge();
john.setSelection( [ 1 ] );
john.insert( '2' );
john.setSelection( [ 2 ] );
john.merge();
} );
expectClients( 'Foo12Bar' );
john.undo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'Foo12Bar' );
john.undo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'Foo12Bar' );
} );
it( 'selection attribute setting: split, bold, merge, undo, undo, undo', () => {
// This test is ported from undo to keep 100% CC in engine.
john.setData( 'Foo[]Bar' );
john.split();
john.setSelection( [ 1, 0 ] );
john._processExecute( 'bold' );
john._processExecute( 'forwardDelete' );
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
} );
// https://github.com/ckeditor/ckeditor5/issues/1288
it( 'remove two groups of blocks then undo, undo', () => {
john.setData(
'XAB[CD]'
);
john.delete();
john.setSelection( [ 0, 1 ], [ 2, 1 ] );
john.delete();
expectClients( 'X' );
john.undo();
expectClients( 'XAB' );
john.undo();
expectClients(
'XABCD'
);
} );
// https://github.com/ckeditor/ckeditor5/issues/1287 TC1
it( 'pasting on non-collapsed selection undo and redo', () => {
john.setData( 'Fo[oB]ar' );
// Below simulates pasting.
john.editor.model.change( () => {
john.editor.model.deleteContent( john.document.selection );
john.setSelection( [ 0, 2 ] );
john.split();
john.setSelection( [ 1 ] );
john.insert( '1' );
john.setSelection( [ 1 ] );
john.merge();
john.setSelection( [ 1 ] );
john.insert( '2' );
john.setSelection( [ 2 ] );
john.merge();
} );
expectClients( 'Fo12ar' );
john.undo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'Fo12ar' );
john.undo();
expectClients( 'FooBar' );
} );
it( 'collapsed marker at the beginning of merged element then undo', () => {
john.setData( 'Foo[]Bar' );
john.setMarker( 'm1' );
john.setSelection( [ 1 ] );
john.merge();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
} );
it( 'collapsed marker at the end of merge-target element then undo', () => {
john.setData( 'Foo[]Bar' );
john.setMarker( 'm1' );
john.setSelection( [ 1 ] );
john.merge();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
} );
it( 'empty marker between merged elements then undo', () => {
john.setData( 'Foo[]Bar' );
john.setMarker( 'm1' );
john.setSelection( [ 1 ] );
john.merge();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
} );
it( 'left side of marker moved then undo', () => {
john.setData( 'Foo[bar]' );
john.setMarker( 'm1' );
john.setSelection( [ 0, 2 ], [ 0, 4 ] );
john.move( [ 1, 0 ] );
expectClients( 'Foarob' );
john.undo();
expectClients( 'Foobar' );
} );
it( 'right side of marker moved then undo', () => {
john.setData( '[Foo]bar' );
john.setMarker( 'm1' );
john.setSelection( [ 0, 2 ], [ 0, 4 ] );
john.move( [ 1, 0 ] );
expectClients( 'Foarob' );
john.undo();
expectClients( 'Foobar' );
} );
it( 'marker on closing and opening tag - remove multiple elements #1', () => {
john.setData(
'Abc' +
'Foo[' +
']Bar'
);
john.setMarker( 'm1' );
john.setSelection( [ 0, 1 ], [ 2, 2 ] );
john._processExecute( 'delete' );
expectClients( 'Ar' );
john.undo();
expectClients(
'Abc' +
'Foo' +
'Bar'
);
} );
it( 'marker on closing and opening tag - remove multiple elements #2', () => {
john.setData(
'Foo[' +
']Bar' +
'Xyz'
);
john.setMarker( 'm1' );
john.setSelection( [ 0, 1 ], [ 2, 2 ] );
john._processExecute( 'delete' );
expectClients( 'Fz' );
john.undo();
expectClients(
'Foo' +
'Bar' +
'Xyz'
);
} );
it( 'marker on closing and opening tag + some text - merge elements + remove text', () => {
john.setData(
'Foo[' +
'B]ar'
);
john.setMarker( 'm1' );
john.setSelection( [ 0, 1 ], [ 1, 2 ] );
john._processExecute( 'delete' );
expectClients( 'Fr' );
john.undo();
expectClients(
'Foo' +
'Bar'
);
} );
// https://github.com/ckeditor/ckeditor5-engine/issues/1668
it( 'marker and moves with undo-redo-undo', () => {
john.setData( 'X[]Y' );
const inputBufferBatch = john.editor.commands.get( 'input' ).buffer.batch;
john.editor.model.enqueueChange( inputBufferBatch, () => {
john.type( 'a' );
john.type( 'b' );
john.type( 'c' );
john.setSelection( [ 0, 1 ], [ 0, 4 ] );
john.setMarker( 'm1' );
} );
expectClients( 'XabcY' );
john.setSelection( [ 0, 0 ], [ 0, 5 ] );
john._processExecute( 'delete' );
expectClients( '' );
john.undo();
expectClients( 'XabcY' );
john.undo();
expectClients( 'XY' );
john.redo();
expectClients( 'XabcY' );
john.redo();
expectClients( '' );
john.undo();
expectClients( 'XabcY' );
john.undo();
expectClients( 'XY' );
} );
// https://github.com/ckeditor/ckeditor5/issues/1385
it( 'paste inside paste + undo, undo + redo, redo', () => {
const model = john.editor.model;
john.setData( '[]' );
model.insertContent( getPastedContent() );
john.setSelection( [ 0, 3 ] );
model.insertContent( getPastedContent() );
expectClients( 'FooFoobarbar' );
john.undo();
expectClients( 'Foobar' );
john.undo();
expectClients( '' );
john.redo();
expectClients( 'Foobar' );
john.redo();
expectClients( 'FooFoobarbar' );
function getPastedContent() {
return new Element( 'heading1', null, new Text( 'Foobar' ) );
}
} );
// https://github.com/ckeditor/ckeditor5/issues/1540
it( 'paste, select all, paste, undo, undo, redo, redo, redo', () => {
john.setData( '[]' );
pasteContent();
john.setSelection( [ 0, 0 ], [ 1, 3 ] );
pasteContent();
expectClients( 'FooBar' );
john.undo();
expectClients( 'FooBar' );
john.undo();
expectClients( '' );
john.redo();
expectClients( 'FooBar' );
john.redo();
expectClients( 'FooBar' );
function pasteContent() {
john.editor.model.insertContent(
new DocumentFragment( [
new Element( 'heading1', null, new Text( 'Foo' ) ),
new Element( 'paragraph', null, new Text( 'Bar' ) )
] )
);
}
} );
// Happens in track changes. Emulated here.
// https://github.com/ckeditor/ckeditor5-engine/issues/1701
it( 'paste, remove, undo, undo, redo, redo', () => {
john.setData( 'Ab[]cdWxyz' );
john.editor.model.insertContent(
new DocumentFragment( [
new Element( 'paragraph', null, new Text( 'Foo' ) ),
new Element( 'paragraph', null, new Text( 'Bar' ) )
] )
);
john.setSelection( [ 1, 3 ], [ 2, 2 ] );
john._processExecute( 'delete' );
expectClients( 'AbFooBaryz' );
john.undo();
expectClients( 'AbFooBarcdWxyz' );
john.undo();
expectClients( 'AbcdWxyz' );
john.redo();
expectClients( 'AbFooBarcdWxyz' );
john.redo();
expectClients( 'AbFooBaryz' );
} );
} );