/** * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. */ import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; import { upcastElementToElement } from '@ckeditor/ckeditor5-engine/src/conversion/upcast-converters'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { downcastTable, upcastTable } from '../src/converters'; describe( 'Table converters', () => { let editor, model, viewDocument; beforeEach( () => { return VirtualTestEditor.create() .then( newEditor => { editor = newEditor; model = editor.model; viewDocument = editor.editing.view; const conversion = editor.conversion; const schema = model.schema; schema.register( 'table', { allowWhere: '$block', allowAttributes: [ 'headingRows', 'headingColumns' ], isBlock: true, isObject: true } ); schema.register( 'tableRow', { allowIn: 'table', allowAttributes: [], isBlock: true, isLimit: true } ); schema.register( 'tableCell', { allowIn: 'tableRow', allowContentOf: '$block', allowAttributes: [ 'colspan', 'rowspan' ], isBlock: true, isLimit: true } ); conversion.for( 'upcast' ).add( upcastTable() ); conversion.for( 'downcast' ).add( downcastTable() ); // Table row upcast only since downcast conversion is done in `downcastTable()`. conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableRow', view: 'tr' } ) ); // Table cell conversion. conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'td' } ) ); conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'tableCell', view: 'th' } ) ); conversion.attributeToAttribute( { model: 'colspan', view: 'colspan' } ); conversion.attributeToAttribute( { model: 'rowspan', view: 'rowspan' } ); } ); } ); describe( 'upcastTable()', () => { function expectModel( data ) { expect( getModelData( model, { withoutSelection: true } ) ).to.equal( data ); } beforeEach( () => { // Since this part of test tests only view->model conversion editing pipeline is not necessary // so defining model->view converters won't be necessary. editor.editing.destroy(); } ); it( 'should create table model from table without thead', () => { editor.setData( '' + '' + '
1
' ); expectModel( '' + '1' + '
' ); } ); it( 'should create table model from table with one thead with one row', () => { editor.setData( '' + '' + '
1
' ); expectModel( '' + '1' + '
' ); } ); it( 'should create table model from table with one thead with more then on row', () => { editor.setData( '' + '' + '' + '' + '' + '' + '
1
2
3
' ); expectModel( '' + '1' + '2' + '3' + '
' ); } ); it( 'should create table model from table with two theads with one row', () => { editor.setData( '' + '' + '' + '' + '
1
2
3
' ); expectModel( '' + '1' + '2' + '3' + '
' ); } ); it( 'should create table model from table with thead after the tbody', () => { editor.setData( '' + '' + '' + '
2
1
' ); expectModel( '' + '1' + '2' + '
' ); } ); it( 'should create table model from table with one tfoot with one row', () => { editor.setData( '' + '' + '
1
' ); expectModel( '' + '1' + '
' ); } ); it( 'should create valid table model from empty table', () => { editor.setData( '' + '
' ); expectModel( '
' ); } ); it( 'should skip unknown table children', () => { editor.setData( '' + '' + '' + '
foo
bar
' ); expectModel( 'bar
' ); } ); it( 'should create table model from some broken table', () => { editor.setData( '

foo

' ); expectModel( 'foo
' ); } ); it( 'should fix if inside other blocks', () => { // Using
instead of

as it breaks on Edge. editor.model.schema.register( 'div', { inheritAllFrom: '$block' } ); editor.conversion.for( 'upcast' ).add( upcastElementToElement( { model: 'div', view: 'div' } ) ); editor.setData( '

foo' + '' + '' + '' + '
2
1
' + 'bar
' ); expectModel( '
foo
' + '' + '1' + '2' + '
' + '
bar
' ); } ); it( 'should be possible to overwrite table conversion', () => { editor.model.schema.register( 'fooTable', { allowWhere: '$block', allowAttributes: [ 'headingRows' ], isBlock: true, isObject: true } ); editor.conversion.elementToElement( { model: 'fooTable', view: 'table', priority: 'high' } ); editor.setData( '' + '' + '
foo
' ); expectModel( '' ); } ); describe( 'headingColumns', () => { it( 'should properly calculate heading columns', () => { editor.setData( '' + '' + // This row starts with 1 th (3 total). '' + // This row starts with 2 th (2 total). This one has max number of heading columns: 2. '' + // This row starts with 1 th (1 total). '' + // This row starts with 0 th (3 total). '' + '' + '' + // This row has 4 ths but it is a thead. '' + '' + '
21222324
31323334
41424344
51525354
11121314
' ); expectModel( '' + '' + '11121314' + '' + '' + '21222324' + '' + '' + '31323334' + '' + '' + '41424344' + '' + '' + '51525354' + '' + '
' ); } ); it( 'should calculate heading columns of cells with colspan', () => { editor.setData( '' + '' + // This row has colspan of 3 so it should be the whole table should have 3 heading columns. '' + '' + '' + '' + // This row has 4 ths but it is a thead. '' + '' + '
21222324
313334
11121314
' ); expectModel( '' + '' + '11121314' + '' + '' + '21222324' + '' + '' + '313334' + '' + '
' ); } ); } ); } ); describe( 'downcastTable()', () => { it( 'should create table with tbody', () => { setModelData( model, '' + '' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '
' ); } ); it( 'should create table with tbody and thead', () => { setModelData( model, '' + '1' + '2' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '' + '' + '' + '
1
2
' ); } ); it( 'should create table with thead', () => { setModelData( model, '' + '1' + '2' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '' + '
1
2
' ); } ); it( 'should create table with heading columns and rows', () => { setModelData( model, '' + '' + '11121314' + '' + '' + '21222324' + '' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '' + '' + '' + '
11121314
21222324
' ); } ); it( 'should be possible to overwrite', () => { editor.conversion.elementToElement( { model: 'tableRow', view: 'tr' } ); editor.conversion.elementToElement( { model: 'tableCell', view: 'td' } ); editor.conversion.for( 'downcast' ).add( dispatcher => { dispatcher.on( 'insert:table', ( evt, data, conversionApi ) => { conversionApi.consumable.consume( data.item, 'insert' ); const tableElement = conversionApi.writer.createContainerElement( 'table', { foo: 'bar' } ); const viewPosition = conversionApi.mapper.toViewPosition( data.range.start ); conversionApi.mapper.bindElements( data.item, tableElement ); conversionApi.writer.insert( viewPosition, tableElement ); }, { priority: 'high' } ); } ); setModelData( model, '' + '' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '
' ); } ); describe( 'headingColumns attribute', () => { it( 'should mark heading columns table cells', () => { setModelData( model, '' + '111213' + '212223' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '' + '
111213
212223
' ); } ); it( 'should mark heading columns table cells when one has colspan attribute', () => { setModelData( model, '' + '' + '11121314' + '' + '212324' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '' + '
11121314
212324
' ); } ); it( 'should work with colspan and rowspan attributes on table cells', () => { // The table in this test looks like a table below: // // Row headings | Normal cells // | // +----+----+----+----+ // | 11 | 12 | 13 | 14 | // | +----+ +----+ // | | 22 | | 24 | // |----+----+ +----+ // | 31 | | 34 | // | +----+----+ // | | 43 | 44 | // +----+----+----+----+ setModelData( model, '' + '' + '11' + '12' + '13' + '14' + '' + '2224' + '3134' + '4344' + '
' ); expect( getViewData( viewDocument, { withoutSelection: true } ) ).to.equal( '' + '' + '' + '' + '' + '' + '' + '
11121314
2224
3134
4344
' ); } ); } ); } ); } );