Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit 85719af

Browse files
authored
Merge pull request #153 from ckeditor/t/126
Fix: Make table a block element in the schema for quoting. Closes #126.
2 parents d4e042d + 8067c53 commit 85719af

File tree

5 files changed

+66
-19
lines changed

5 files changed

+66
-19
lines changed

src/converters/downcast.js

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,14 +51,17 @@ export function downcastInsertTable( options = {} ) {
5151
headingColumns: table.getAttribute( 'headingColumns' ) || 0
5252
};
5353

54+
// Cache for created table rows.
55+
const viewRows = new Map();
56+
5457
for ( const tableWalkerValue of tableWalker ) {
5558
const { row, cell } = tableWalkerValue;
5659

5760
const tableSection = getOrCreateTableSection( getSectionName( row, tableAttributes ), tableElement, conversionApi );
5861
const tableRow = table.getChild( row );
5962

60-
// Check if row was converted
61-
const trElement = getOrCreateTr( tableRow, row, tableSection, conversionApi );
63+
const trElement = viewRows.get( row ) || createTr( tableRow, row, tableSection, conversionApi );
64+
viewRows.set( row, trElement );
6265

6366
// Consume table cell - it will be always consumed as we convert whole table at once.
6467
conversionApi.consumable.consume( cell, 'insert' );
@@ -104,9 +107,14 @@ export function downcastInsertRow( options = {} ) {
104107
headingColumns: table.getAttribute( 'headingColumns' ) || 0
105108
};
106109

110+
// Cache for created table rows.
111+
const viewRows = new Map();
112+
107113
for ( const tableWalkerValue of tableWalker ) {
108114
const tableSection = getOrCreateTableSection( getSectionName( row, tableAttributes ), tableElement, conversionApi );
109-
const trElement = getOrCreateTr( tableRow, row, tableSection, conversionApi );
115+
116+
const trElement = viewRows.get( row ) || createTr( tableRow, row, tableSection, conversionApi );
117+
viewRows.set( row, trElement );
110118

111119
// Consume table cell - it will be always consumed as we convert whole row at once.
112120
conversionApi.consumable.consume( tableWalkerValue.cell, 'insert' );
@@ -404,29 +412,25 @@ function createViewTableCellElement( tableWalkerValue, tableAttributes, insertPo
404412
}
405413
}
406414

407-
// Creates or returns an existing `<tr>` element from the view.
415+
// Creates `<tr>` view element.
408416
//
409417
// @param {module:engine/view/element~Element} tableRow
410418
// @param {Number} rowIndex
411419
// @param {module:engine/view/element~Element} tableSection
412420
// @param {Object} conversionApi
413421
// @returns {module:engine/view/element~Element}
414-
function getOrCreateTr( tableRow, rowIndex, tableSection, conversionApi ) {
415-
let trElement = conversionApi.mapper.toViewElement( tableRow );
422+
function createTr( tableRow, rowIndex, tableSection, conversionApi ) {
423+
// Will always consume since we're converting <tableRow> element from a parent <table>.
424+
conversionApi.consumable.consume( tableRow, 'insert' );
416425

417-
if ( !trElement ) {
418-
// Will always consume since we're converting <tableRow> element from a parent <table>.
419-
conversionApi.consumable.consume( tableRow, 'insert' );
426+
const trElement = conversionApi.writer.createContainerElement( 'tr' );
427+
conversionApi.mapper.bindElements( tableRow, trElement );
420428

421-
trElement = conversionApi.writer.createContainerElement( 'tr' );
422-
conversionApi.mapper.bindElements( tableRow, trElement );
429+
const headingRows = tableRow.parent.getAttribute( 'headingRows' ) || 0;
430+
const offset = headingRows > 0 && rowIndex >= headingRows ? rowIndex - headingRows : rowIndex;
423431

424-
const headingRows = tableRow.parent.getAttribute( 'headingRows' ) || 0;
425-
const offset = headingRows > 0 && rowIndex >= headingRows ? rowIndex - headingRows : rowIndex;
426-
427-
const position = conversionApi.writer.createPositionAt( tableSection, offset );
428-
conversionApi.writer.insert( position, trElement );
429-
}
432+
const position = conversionApi.writer.createPositionAt( tableSection, offset );
433+
conversionApi.writer.insert( position, trElement );
430434

431435
return trElement;
432436
}

src/tableediting.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,8 @@ export default class TableEditing extends Plugin {
5656
allowWhere: '$block',
5757
allowAttributes: [ 'headingRows', 'headingColumns' ],
5858
isLimit: true,
59-
isObject: true
59+
isObject: true,
60+
isBlock: true
6061
} );
6162

6263
schema.register( 'tableRow', {

tests/_utils/utils.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ export function defaultSchema( schema, registerParagraph = true ) {
161161
allowWhere: '$block',
162162
allowAttributes: [ 'headingRows', 'headingColumns' ],
163163
isLimit: true,
164-
isObject: true
164+
isObject: true,
165+
isBlock: true
165166
} );
166167

167168
schema.register( 'tableRow', {

tests/converters/downcast.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,46 @@ describe( 'downcast converters', () => {
171171
) );
172172
} );
173173

174+
it( 'should re-create table on reinsert', () => {
175+
model.schema.register( 'wrapper', {
176+
allowWhere: '$block',
177+
allowContentOf: '$root'
178+
} );
179+
editor.conversion.elementToElement( { model: 'wrapper', view: 'div' } );
180+
181+
setModelData( model, modelTable( [ [ '[]' ] ] ) );
182+
183+
expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
184+
'<figure class="table">' +
185+
'<table>' +
186+
'<tbody>' +
187+
'<tr><td></td></tr>' +
188+
'</tbody>' +
189+
'</table>' +
190+
'</figure>'
191+
) );
192+
193+
model.change( writer => {
194+
const table = model.document.getRoot().getChild( 0 );
195+
const range = writer.createRange( writer.createPositionBefore( table ), writer.createPositionAfter( table ) );
196+
const wrapper = writer.createElement( 'wrapper' );
197+
198+
writer.wrap( range, wrapper );
199+
} );
200+
201+
expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formatTable(
202+
'<div>' +
203+
'<figure class="table">' +
204+
'<table>' +
205+
'<tbody>' +
206+
'<tr><td></td></tr>' +
207+
'</tbody>' +
208+
'</table>' +
209+
'</figure>' +
210+
'</div>'
211+
) );
212+
} );
213+
174214
describe( 'headingColumns attribute', () => {
175215
it( 'should mark heading columns table cells', () => {
176216
setModelData( model, modelTable( [

tests/tableediting.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ describe( 'TableEditing', () => {
4545
// Table:
4646
expect( model.schema.isRegistered( 'table' ) ).to.be.true;
4747
expect( model.schema.isObject( 'table' ) ).to.be.true;
48+
expect( model.schema.isBlock( 'table' ) ).to.be.true;
4849
expect( model.schema.isLimit( 'table' ) ).to.be.true;
4950

5051
expect( model.schema.checkChild( [ '$root' ], 'table' ) ).to.be.true;

0 commit comments

Comments
 (0)