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

Commit 1eb5d6d

Browse files
authored
Merge pull request #127 from ckeditor/t/125
Fix: A table cell should always have a `<paragraph>` in the model. Closes #125. BREAKING CHANGE: The `injectTablePostFixer()` function from `table/converters/table-post-fixer` is now `injectTableLayoutPostFixer()`and is moved to `table/converters/table-layout-post-fixer` module.
2 parents 2f2fe4a + 996136f commit 1eb5d6d

5 files changed

+270
-31
lines changed
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/**
2+
* @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
3+
* For licensing, see LICENSE.md.
4+
*/
5+
6+
/**
7+
* @module table/converters/table-cell-content-post-fixer
8+
*/
9+
10+
/**
11+
* Injects a table cell post-fixer into the model.
12+
*
13+
* The role of the table post-fixer is to ensure that the table cells have the correct content
14+
* after a {@link module:engine/model/model~Model#change `change()`} block was executed.
15+
*
16+
* A table cells must contains at least one block as a child. The empty table cell will have empty `<paragraph>` as a child.
17+
*
18+
* <table>
19+
* <tableRow>
20+
* <tableCell></tableCell>
21+
* </tableRow>
22+
* </table>
23+
*
24+
* Will be fixed to:
25+
*
26+
* <table>
27+
* <tableRow>
28+
* <tableCell><paragraph></paragraph></tableCell>
29+
* </tableRow>
30+
* </table>
31+
*
32+
* @param {module:engine/model/model~Model} model
33+
*/
34+
export default function injectTableCellContentPostFixer( model ) {
35+
model.document.registerPostFixer( writer => tableCellContentsPostFixer( writer, model ) );
36+
}
37+
38+
// The table cell contents post-fixer.
39+
//
40+
// @param {module:engine/model/writer~Writer} writer
41+
// @param {module:engine/model/model~Model} model
42+
function tableCellContentsPostFixer( writer, model ) {
43+
const changes = model.document.differ.getChanges();
44+
45+
let wasFixed = false;
46+
47+
for ( const entry of changes ) {
48+
// Enforce paragraph in tableCell even after other feature remove its contents.
49+
if ( entry.type == 'remove' && entry.position.parent.is( 'tableCell' ) ) {
50+
wasFixed = fixTableCellContent( entry.position.parent, writer ) || wasFixed;
51+
}
52+
53+
// Analyze table cells on insertion.
54+
if ( entry.type == 'insert' ) {
55+
if ( entry.name == 'table' ) {
56+
wasFixed = fixTable( entry.position.nodeAfter, writer ) || wasFixed;
57+
}
58+
59+
if ( entry.name == 'tableRow' ) {
60+
wasFixed = fixTableRow( entry.position.nodeAfter, writer ) || wasFixed;
61+
}
62+
63+
if ( entry.name == 'tableCell' ) {
64+
wasFixed = fixTableCellContent( entry.position.nodeAfter, writer ) || wasFixed;
65+
}
66+
}
67+
}
68+
69+
return wasFixed;
70+
}
71+
72+
// Fixes all table cells in a table.
73+
//
74+
// @param {module:engine/model/element~Element} table
75+
// @param {module:engine/model/writer~Writer} writer
76+
function fixTable( table, writer ) {
77+
let wasFixed = false;
78+
79+
for ( const row of table.getChildren() ) {
80+
wasFixed = fixTableRow( row, writer ) || wasFixed;
81+
}
82+
83+
return wasFixed;
84+
}
85+
86+
// Fixes all table cells in a table row.
87+
//
88+
// @param {module:engine/model/element~Element} tableRow
89+
// @param {module:engine/model/writer~Writer} writer
90+
function fixTableRow( tableRow, writer ) {
91+
let wasFixed = false;
92+
93+
for ( const tableCell of tableRow.getChildren() ) {
94+
wasFixed = fixTableCellContent( tableCell, writer ) || wasFixed;
95+
}
96+
97+
return wasFixed;
98+
}
99+
100+
// Fixes all table cell content by adding paragraph to a table cell without any child.
101+
//
102+
// @param {module:engine/model/element~Element} table
103+
// @param {module:engine/model/writer~Writer} writer
104+
function fixTableCellContent( tableCell, writer ) {
105+
if ( tableCell.childCount == 0 ) {
106+
writer.insertElement( 'paragraph', tableCell );
107+
108+
return true;
109+
}
110+
111+
return false;
112+
}

src/converters/table-post-fixer.js renamed to src/converters/table-layout-post-fixer.js

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,24 @@
44
*/
55

66
/**
7-
* @module table/converters/table-post-fixer
7+
* @module table/converters/table-layout-post-fixer
88
*/
99

1010
import Position from '@ckeditor/ckeditor5-engine/src/model/position';
1111
import { createEmptyTableCell, findAncestor, updateNumericAttribute } from './../commands/utils';
1212
import TableWalker from './../tablewalker';
1313

1414
/**
15-
* Injects a table post-fixer into the model.
15+
* Injects a table layout post-fixer into the model.
1616
*
17-
* The role of the table post-fixer is to ensure that the table rows have the correct structure
17+
* The role of the table layout post-fixer is to ensure that the table rows have the correct structure
1818
* after a {@link module:engine/model/model~Model#change `change()`} block was executed.
1919
*
2020
* The correct structure means that:
2121
*
2222
* * All table rows have the same size.
2323
* * None of a table cells that extend vertically beyond their section (either header or body).
24+
* * A table cell has always at least one element as child.
2425
*
2526
* If the table structure is not correct, the post-fixer will automatically correct it in two steps:
2627
*
@@ -35,12 +36,12 @@ import TableWalker from './../tablewalker';
3536
*
3637
* <table headingRows="1">
3738
* <tableRow>
38-
* <tableCell rowspan="2">FOO</tableCell>
39-
* <tableCell colspan="2">BAR</tableCell>
39+
* <tableCell rowspan="2"><paragraph>FOO</paragraph></tableCell>
40+
* <tableCell colspan="2"><paragraph>BAR</paragraph></tableCell>
4041
* </tableRow>
4142
* <tableRow>
42-
* <tableCell>BAZ</tableCell>
43-
* <tableCell>XYZ</tableCell>
43+
* <tableCell><paragraph>BAZ</paragraph></tableCell>
44+
* <tableCell><paragraph>XYZ</paragraph></tableCell>
4445
* </tableRow>
4546
* </table>
4647
*
@@ -55,8 +56,8 @@ import TableWalker from './../tablewalker';
5556
* </thead>
5657
* <tbody>
5758
* <tr>
58-
* <td>BAZ<td>
59-
* <td>XYZ<td>
59+
* <td>BAZ</td>
60+
* <td>XYZ</td>
6061
* </tr>
6162
* </tbody>
6263
* </table>
@@ -90,8 +91,8 @@ import TableWalker from './../tablewalker';
9091
* </thead>
9192
* <tbody>
9293
* <tr>
93-
* <td>BAZ<td>
94-
* <td>XYZ<td>
94+
* <td>BAZ</td>
95+
* <td>XYZ</td>
9596
* </tr>
9697
* </tbody>
9798
* </table>
@@ -113,8 +114,8 @@ import TableWalker from './../tablewalker';
113114
* <td>12</td>
114115
* </tr>
115116
* <tr>
116-
* <td>21<td>
117-
* <td>22<td>
117+
* <td>21</td>
118+
* <td>22</td>
118119
* </tr>
119120
* </tbody>
120121
* </table>
@@ -156,8 +157,8 @@ import TableWalker from './../tablewalker';
156157
* <td>(empty, inserted by A)</td>
157158
* </tr>
158159
* <tr>
159-
* <td>21<td>
160-
* <td>22<td>
160+
* <td>21</td>
161+
* <td>22</td>
161162
* <td>(empty, inserted by A)</td>
162163
* </tr>
163164
* <tr>
@@ -197,32 +198,31 @@ import TableWalker from './../tablewalker';
197198
* <tr>
198199
* <td>11</td>
199200
* <td>12</td>
200-
* <td>(empty, inserted by a post-fixer after undo)<td>
201+
* <td>(empty, inserted by a post-fixer after undo)</td>
201202
* </tr>
202203
* <tr>
203-
* <td>21<td>
204-
* <td>22<td>
205-
* <td>(empty, inserted by a post-fixer after undo)<td>
204+
* <td>21</td>
205+
* <td>22</td>
206+
* <td>(empty, inserted by a post-fixer after undo)</td>
206207
* </tr>
207208
* <tr>
208-
* <td>(empty, inserted by B)<td>
209-
* <td>(empty, inserted by B)<td>
210-
* <td>(empty, inserted by a post-fixer)<td>
209+
* <td>(empty, inserted by B)</td>
210+
* <td>(empty, inserted by B)</td>
211+
* <td>(empty, inserted by a post-fixer)</td>
211212
* </tr>
212213
* </tbody>
213214
* </table>
214-
*
215215
* @param {module:engine/model/model~Model} model
216216
*/
217-
export default function injectTablePostFixer( model ) {
218-
model.document.registerPostFixer( writer => tablePostFixer( writer, model ) );
217+
export default function injectTableLayoutPostFixer( model ) {
218+
model.document.registerPostFixer( writer => tableLayoutPostFixer( writer, model ) );
219219
}
220220

221-
// The table post-fixer.
221+
// The table layout post-fixer.
222222
//
223223
// @param {module:engine/model/writer~Writer} writer
224224
// @param {module:engine/model/model~Model} model
225-
function tablePostFixer( writer, model ) {
225+
function tableLayoutPostFixer( writer, model ) {
226226
const changes = model.document.differ.getChanges();
227227

228228
let wasFixed = false;
@@ -233,7 +233,6 @@ function tablePostFixer( writer, model ) {
233233
for ( const entry of changes ) {
234234
let table;
235235

236-
// Fix table on table insert.
237236
if ( entry.name == 'table' && entry.type == 'insert' ) {
238237
table = entry.position.nodeAfter;
239238
}

src/tableediting.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ import SetHeaderColumnCommand from './commands/setheadercolumncommand';
3333
import { findAncestor } from './commands/utils';
3434
import TableUtils from '../src/tableutils';
3535

36-
import injectTablePostFixer from './converters/table-post-fixer';
36+
import injectTableLayoutPostFixer from './converters/table-layout-post-fixer';
37+
import injectTableCellContentsPostFixer from './converters/table-cell-content-post-fixer';
3738
import injectTableCellPostFixer from './converters/tablecell-post-fixer';
3839

3940
import '../theme/tableediting.css';
@@ -145,7 +146,8 @@ export default class TableEditing extends Plugin {
145146
editor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );
146147
editor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );
147148

148-
injectTablePostFixer( model );
149+
injectTableLayoutPostFixer( model );
150+
injectTableCellContentsPostFixer( model );
149151

150152
// Handle tab key navigation.
151153
this.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );

0 commit comments

Comments
 (0)