/** * @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 Model from '../../../src/model/model'; import DocumentFragment from '../../../src/model/documentfragment'; import getSelectedContent from '../../../src/model/utils/getselectedcontent'; import { setData, stringify } from '../../../src/dev-utils/model'; describe( 'DataController utils', () => { let model, doc; describe( 'getSelectedContent', () => { it( 'should use parent batch', () => { model = new Model(); doc = model.document; doc.createRoot(); model.schema.extend( '$text', { allowIn: '$root' } ); setData( model, 'x[abc]x' ); model.change( writer => { getSelectedContent( model, doc.selection ); expect( writer.batch.operations ).to.length( 1 ); } ); } ); describe( 'in simple scenarios', () => { beforeEach( () => { model = new Model(); doc = model.document; doc.createRoot(); const schema = model.schema; schema.register( 'image', { allowWhere: '$text', allowIn: '$root' } ); schema.extend( '$text', { allowIn: '$root', allowAttributes: [ 'bold', 'italic' ] } ); } ); it( 'returns empty fragment for no selection', () => { setData( model, 'abc' ); const frag = getSelectedContent( model, doc.selection ); expect( frag ).instanceOf( DocumentFragment ); expect( frag.isEmpty ).to.be.true; } ); it( 'returns empty fragment for empty selection', () => { setData( model, 'a[]bc' ); const frag = getSelectedContent( model, doc.selection ); expect( frag ).instanceOf( DocumentFragment ); expect( frag.isEmpty ).to.be.true; } ); it( 'gets one character', () => { setData( model, 'a[b]c' ); const frag = getSelectedContent( model, doc.selection ); const content = stringify( frag ); expect( frag ).instanceOf( DocumentFragment ); expect( content ).to.equal( 'b' ); } ); it( 'gets full text', () => { setData( model, '[abc]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abc' ); } ); it( 'gets text with an attribute', () => { setData( model, 'xxx<$text bold="true">a[b]c' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( '<$text bold="true">b' ); } ); it( 'gets text with attributes', () => { setData( model, 'x<$text bold="true">a[b<$text italic="true">c]dx' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( '<$text bold="true">b<$text italic="true">c' ); } ); it( 'gets text with and without attribute', () => { setData( model, '<$text bold="true">a[bc]d' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( '<$text bold="true">bc' ); } ); it( 'gets text and element', () => { setData( model, '[abc]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abc' ); } ); it( 'gets one element', () => { setData( model, 'a[]b' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( '' ); } ); it( 'gets multiple elements', () => { setData( model, '[]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( '' ); } ); } ); describe( 'in blocks', () => { beforeEach( () => { model = new Model(); doc = model.document; doc.createRoot(); const schema = model.schema; schema.register( 'paragraph', { inheritAllFrom: '$block' } ); schema.register( 'heading1', { inheritAllFrom: '$block' } ); schema.register( 'blockImage', { isObject: true } ); schema.register( 'caption' ); schema.register( 'image', { allowWhere: '$text' } ); schema.extend( 'blockImage', { allowIn: '$root' } ); schema.extend( 'caption', { allowIn: 'blockImage' } ); schema.extend( '$text', { allowIn: 'caption', allowAttributes: 'bold' } ); } ); it( 'gets one character', () => { setData( model, 'a[b]c' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'b' ); } ); it( 'gets entire paragraph content', () => { setData( model, '[ab]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'ab' ); } ); it( 'gets two blocks - partial, partial', () => { setData( model, 'a[bcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcde' ); } ); it( 'gets two blocks - full, partial', () => { setData( model, '[abcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abcde' ); } ); it( 'gets two blocks - full, partial 2', () => { setData( model, '[abcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abcde' ); } ); it( 'gets two blocks - full, partial 3', () => { setData( model, 'x[abcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abcde' ); } ); it( 'gets two blocks - full, partial 4', () => { setData( model, '[abcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abcde' ); } ); it( 'gets two blocks - partial, full', () => { setData( model, 'a[bcdef]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcdef' ); } ); it( 'gets two blocks - partial, full 2', () => { setData( model, 'a[bcdef]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcdef' ); } ); // See https://github.com/ckeditor/ckeditor5-engine/issues/652#issuecomment-261358484 it( 'gets two blocks - empty, full', () => { setData( model, 'abc[def]' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'def' ); } ); // See https://github.com/ckeditor/ckeditor5-engine/issues/652#issuecomment-261358484 it( 'gets two blocks - partial, empty', () => { setData( model, 'a[bc]def' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bc' ); } ); it( 'gets three blocks', () => { setData( model, 'a[bcxde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcxde' ); } ); it( 'gets block image', () => { setData( model, 'a[Foo]b' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'Foo' ); } ); it( 'gets two blocks', () => { setData( model, 'a[]b' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( '' ); } ); // Purely related to the current implementation. it( 'gets content when multiple text items needs to be removed from the right excess', () => { setData( model, 'a[bc]d<$text bold="true">ef' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ) .to.equal( 'bc' ); } ); // Purely related to the current implementation. it( 'gets content when multiple text items needs to be removed from the left excess', () => { setData( model, 'a<$text bold="true">bc[de]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ) .to.equal( 'de' ); } ); } ); describe( 'in blocks (deeply nested)', () => { beforeEach( () => { model = new Model(); doc = model.document; doc.createRoot(); const schema = model.schema; schema.register( 'paragraph', { inheritAllFrom: '$block' } ); schema.register( 'heading1', { inheritAllFrom: '$block' } ); schema.register( 'quote' ); schema.extend( '$block', { allowIn: 'quote' } ); schema.extend( 'quote', { allowIn: '$root' } ); } ); it( 'gets content when ends are equally deeply nested', () => { setData( model, 'xa[bcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcde' ); } ); it( 'gets content when left end nested deeper', () => { setData( model, 'a[bcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcde' ); } ); it( 'gets content when left end nested deeper 2', () => { setData( model, 'a[bcxde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcxde' ); } ); it( 'gets content when left end nested deeper 3', () => { setData( model, 'xa[bcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcde' ); } ); // See https://github.com/ckeditor/ckeditor5-engine/issues/652#issuecomment-261358484 it( 'gets content when left end nested deeper 4', () => { setData( model, 'x[abcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'abcde' ); } ); it( 'gets content when right end nested deeper', () => { setData( model, 'a[bcde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ).to.equal( 'bcde' ); } ); it( 'gets content when both ends nested deeper than the middle element', () => { setData( model, 'a[bcxde]f' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ) .to.equal( 'bcxde' ); } ); // See: https://github.com/ckeditor/ckeditor5-engine/pull/1043#issuecomment-318012286 it( 'ensures that elements are retrieved by indexes instead of offsets', () => { model.schema.extend( '$text', { allowIn: '$root' } ); model.schema.extend( '$text', { allowIn: 'quote' } ); setData( model, 'foo' + '' + '' + 'b[ar' + '' + 'bo]m' + '' ); const content = stringify( getSelectedContent( model, doc.selection ) ); expect( content ) .to.equal( 'arbo' ); } ); } ); } ); } );