/** * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. */ import Editor from '@ckeditor/ckeditor5-core/src/editor/editor'; import Model from '@ckeditor/ckeditor5-engine/src/model/model'; import IndentCommand from '../src/indentcommand'; import Range from '@ckeditor/ckeditor5-engine/src/model/range'; import Position from '@ckeditor/ckeditor5-engine/src/model/position'; import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; describe( 'IndentCommand', () => { let editor, model, doc, root; beforeEach( () => { editor = new Editor(); editor.model = new Model(); model = editor.model; doc = model.document; root = doc.createRoot(); model.schema.register( 'listItem', { inheritAllFrom: '$block', allowAttributes: [ 'type', 'indent' ] } ); model.schema.register( 'paragraph', { inheritAllFrom: '$block' } ); setData( model, 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); describe( 'IndentCommand', () => { let command; beforeEach( () => { command = new IndentCommand( editor, 'forward' ); } ); afterEach( () => { command.destroy(); } ); describe( 'isEnabled', () => { it( 'should be true if selection starts in list item', () => { model.change( writer => { writer.setSelection( root.getChild( 5 ) ); } ); expect( command.isEnabled ).to.be.true; } ); it( 'should be false if selection starts in first list item', () => { model.change( writer => { writer.setSelection( root.getChild( 0 ) ); } ); expect( command.isEnabled ).to.be.false; } ); // Reported in PR #53. it( 'should be false if selection starts in first list item #2', () => { setData( model, 'a' + 'b' + 'c' + '[]d' + 'e' ); expect( command.isEnabled ).to.be.false; } ); // Reported in PR #53. it( 'should be false if selection starts in first list item #3', () => { setData( model, 'a' + 'b' + 'c' + 'd' + '[]e' ); expect( command.isEnabled ).to.be.false; } ); it( 'should be false if selection starts in first list item of top level list with different type than previous list', () => { setData( model, 'a' + '[]b' ); expect( command.isEnabled ).to.be.false; } ); it( 'should be false if selection starts in a list item that has bigger indent than it\'s previous sibling', () => { model.change( writer => { writer.setSelection( root.getChild( 2 ) ); } ); expect( command.isEnabled ).to.be.false; } ); // Edge case but may happen that some other blocks will also use the indent attribute // and before we fixed it the command was enabled in such a case. it( 'should be false if selection starts in a paragraph with indent attribute', () => { model.schema.extend( 'paragraph', { allowAttributes: 'indent' } ); setData( model, 'ab[]' ); expect( command.isEnabled ).to.be.false; } ); } ); describe( 'execute()', () => { it( 'should use parent batch', () => { model.change( writer => { writer.setSelection( root.getChild( 5 ) ); } ); model.change( writer => { expect( writer.batch.deltas.length ).to.equal( 0 ); command.execute(); expect( writer.batch.deltas.length ).to.be.above( 0 ); } ); } ); it( 'should increment indent attribute by 1', () => { model.change( writer => { writer.setSelection( root.getChild( 5 ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); it( 'should increment indent of all sub-items of indented item', () => { model.change( writer => { writer.setSelection( root.getChild( 1 ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); it( 'should increment indent of all selected item when multiple items are selected', () => { model.change( writer => { writer.setSelection( new Range( new Position( root.getChild( 1 ), [ 0 ] ), new Position( root.getChild( 3 ), [ 1 ] ) ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); } ); } ); describe( 'IndentCommand - backward (outdent)', () => { let command; beforeEach( () => { command = new IndentCommand( editor, 'backward' ); } ); afterEach( () => { command.destroy(); } ); describe( 'isEnabled', () => { it( 'should be true if selection starts in list item', () => { model.change( writer => { writer.setSelection( root.getChild( 5 ) ); } ); expect( command.isEnabled ).to.be.true; } ); it( 'should be true if selection starts in first list item', () => { // This is in contrary to forward indent command. model.change( writer => { writer.setSelection( root.getChild( 0 ) ); } ); expect( command.isEnabled ).to.be.true; } ); it( 'should be true if selection starts in a list item that has bigger indent than it\'s previous sibling', () => { // This is in contrary to forward indent command. model.change( writer => { writer.setSelection( root.getChild( 2 ) ); } ); expect( command.isEnabled ).to.be.true; } ); } ); describe( 'execute()', () => { it( 'should decrement indent attribute by 1 (if it is bigger than 0)', () => { model.change( writer => { writer.setSelection( root.getChild( 5 ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); it( 'should rename listItem to paragraph (if indent is equal to 0)', () => { model.change( writer => { writer.setSelection( root.getChild( 0 ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); it( 'should decrement indent of all sub-items of outdented item', () => { model.change( writer => { writer.setSelection( root.getChild( 1 ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); it( 'should outdent all selected item when multiple items are selected', () => { model.change( writer => { writer.setSelection( new Range( new Position( root.getChild( 1 ), [ 0 ] ), new Position( root.getChild( 3 ), [ 1 ] ) ) ); } ); command.execute(); expect( getData( model, { withoutSelection: true } ) ).to.equal( 'a' + 'b' + 'c' + 'd' + 'e' + 'f' + 'g' ); } ); } ); } ); } );