1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import { Plugin } from 'ckeditor5/src/core';
|
9 | import upcastTable, { ensureParagraphInTableCell, skipEmptyTableRow, upcastTableFigure } from './converters/upcasttable';
|
10 | import { convertParagraphInTableCell, downcastCell, downcastRow, downcastTable } from './converters/downcast';
|
11 | import InsertTableCommand from './commands/inserttablecommand';
|
12 | import InsertRowCommand from './commands/insertrowcommand';
|
13 | import InsertColumnCommand from './commands/insertcolumncommand';
|
14 | import SplitCellCommand from './commands/splitcellcommand';
|
15 | import MergeCellCommand from './commands/mergecellcommand';
|
16 | import RemoveRowCommand from './commands/removerowcommand';
|
17 | import RemoveColumnCommand from './commands/removecolumncommand';
|
18 | import SetHeaderRowCommand from './commands/setheaderrowcommand';
|
19 | import SetHeaderColumnCommand from './commands/setheadercolumncommand';
|
20 | import MergeCellsCommand from './commands/mergecellscommand';
|
21 | import SelectRowCommand from './commands/selectrowcommand';
|
22 | import SelectColumnCommand from './commands/selectcolumncommand';
|
23 | import TableUtils from '../src/tableutils';
|
24 | import injectTableLayoutPostFixer from './converters/table-layout-post-fixer';
|
25 | import injectTableCellParagraphPostFixer from './converters/table-cell-paragraph-post-fixer';
|
26 | import tableHeadingsRefreshHandler from './converters/table-headings-refresh-handler';
|
27 | import tableCellRefreshHandler from './converters/table-cell-refresh-handler';
|
28 | import '../theme/tableediting.css';
|
29 |
|
30 |
|
31 |
|
32 | export default class TableEditing extends Plugin {
|
33 | |
34 |
|
35 |
|
36 | static get pluginName() {
|
37 | return 'TableEditing';
|
38 | }
|
39 | |
40 |
|
41 |
|
42 | static get requires() {
|
43 | return [TableUtils];
|
44 | }
|
45 | |
46 |
|
47 |
|
48 | constructor(editor) {
|
49 | super(editor);
|
50 | this._additionalSlots = [];
|
51 | }
|
52 | |
53 |
|
54 |
|
55 | init() {
|
56 | const editor = this.editor;
|
57 | const model = editor.model;
|
58 | const schema = model.schema;
|
59 | const conversion = editor.conversion;
|
60 | const tableUtils = editor.plugins.get(TableUtils);
|
61 | schema.register('table', {
|
62 | inheritAllFrom: '$blockObject',
|
63 | allowAttributes: ['headingRows', 'headingColumns']
|
64 | });
|
65 | schema.register('tableRow', {
|
66 | allowIn: 'table',
|
67 | isLimit: true
|
68 | });
|
69 | schema.register('tableCell', {
|
70 | allowContentOf: '$container',
|
71 | allowIn: 'tableRow',
|
72 | allowAttributes: ['colspan', 'rowspan'],
|
73 | isLimit: true,
|
74 | isSelectable: true
|
75 | });
|
76 |
|
77 | conversion.for('upcast').add(upcastTableFigure());
|
78 |
|
79 | conversion.for('upcast').add(upcastTable());
|
80 | conversion.for('editingDowncast').elementToStructure({
|
81 | model: {
|
82 | name: 'table',
|
83 | attributes: ['headingRows']
|
84 | },
|
85 | view: downcastTable(tableUtils, {
|
86 | asWidget: true,
|
87 | additionalSlots: this._additionalSlots
|
88 | })
|
89 | });
|
90 | conversion.for('dataDowncast').elementToStructure({
|
91 | model: {
|
92 | name: 'table',
|
93 | attributes: ['headingRows']
|
94 | },
|
95 | view: downcastTable(tableUtils, {
|
96 | additionalSlots: this._additionalSlots
|
97 | })
|
98 | });
|
99 |
|
100 | conversion.for('upcast').elementToElement({ model: 'tableRow', view: 'tr' });
|
101 | conversion.for('upcast').add(skipEmptyTableRow());
|
102 | conversion.for('downcast').elementToElement({
|
103 | model: 'tableRow',
|
104 | view: downcastRow()
|
105 | });
|
106 |
|
107 | conversion.for('upcast').elementToElement({ model: 'tableCell', view: 'td' });
|
108 | conversion.for('upcast').elementToElement({ model: 'tableCell', view: 'th' });
|
109 | conversion.for('upcast').add(ensureParagraphInTableCell('td'));
|
110 | conversion.for('upcast').add(ensureParagraphInTableCell('th'));
|
111 | conversion.for('editingDowncast').elementToElement({
|
112 | model: 'tableCell',
|
113 | view: downcastCell({ asWidget: true })
|
114 | });
|
115 | conversion.for('dataDowncast').elementToElement({
|
116 | model: 'tableCell',
|
117 | view: downcastCell()
|
118 | });
|
119 |
|
120 | conversion.for('editingDowncast').elementToElement({
|
121 | model: 'paragraph',
|
122 | view: convertParagraphInTableCell({ asWidget: true }),
|
123 | converterPriority: 'high'
|
124 | });
|
125 | conversion.for('dataDowncast').elementToElement({
|
126 | model: 'paragraph',
|
127 | view: convertParagraphInTableCell(),
|
128 | converterPriority: 'high'
|
129 | });
|
130 |
|
131 | conversion.for('downcast').attributeToAttribute({ model: 'colspan', view: 'colspan' });
|
132 | conversion.for('upcast').attributeToAttribute({
|
133 | model: { key: 'colspan', value: upcastCellSpan('colspan') },
|
134 | view: 'colspan'
|
135 | });
|
136 | conversion.for('downcast').attributeToAttribute({ model: 'rowspan', view: 'rowspan' });
|
137 | conversion.for('upcast').attributeToAttribute({
|
138 | model: { key: 'rowspan', value: upcastCellSpan('rowspan') },
|
139 | view: 'rowspan'
|
140 | });
|
141 |
|
142 | editor.config.define('table.defaultHeadings.rows', 0);
|
143 | editor.config.define('table.defaultHeadings.columns', 0);
|
144 |
|
145 | editor.commands.add('insertTable', new InsertTableCommand(editor));
|
146 | editor.commands.add('insertTableRowAbove', new InsertRowCommand(editor, { order: 'above' }));
|
147 | editor.commands.add('insertTableRowBelow', new InsertRowCommand(editor, { order: 'below' }));
|
148 | editor.commands.add('insertTableColumnLeft', new InsertColumnCommand(editor, { order: 'left' }));
|
149 | editor.commands.add('insertTableColumnRight', new InsertColumnCommand(editor, { order: 'right' }));
|
150 | editor.commands.add('removeTableRow', new RemoveRowCommand(editor));
|
151 | editor.commands.add('removeTableColumn', new RemoveColumnCommand(editor));
|
152 | editor.commands.add('splitTableCellVertically', new SplitCellCommand(editor, { direction: 'vertically' }));
|
153 | editor.commands.add('splitTableCellHorizontally', new SplitCellCommand(editor, { direction: 'horizontally' }));
|
154 | editor.commands.add('mergeTableCells', new MergeCellsCommand(editor));
|
155 | editor.commands.add('mergeTableCellRight', new MergeCellCommand(editor, { direction: 'right' }));
|
156 | editor.commands.add('mergeTableCellLeft', new MergeCellCommand(editor, { direction: 'left' }));
|
157 | editor.commands.add('mergeTableCellDown', new MergeCellCommand(editor, { direction: 'down' }));
|
158 | editor.commands.add('mergeTableCellUp', new MergeCellCommand(editor, { direction: 'up' }));
|
159 | editor.commands.add('setTableColumnHeader', new SetHeaderColumnCommand(editor));
|
160 | editor.commands.add('setTableRowHeader', new SetHeaderRowCommand(editor));
|
161 | editor.commands.add('selectTableRow', new SelectRowCommand(editor));
|
162 | editor.commands.add('selectTableColumn', new SelectColumnCommand(editor));
|
163 | injectTableLayoutPostFixer(model);
|
164 | injectTableCellParagraphPostFixer(model);
|
165 | this.listenTo(model.document, 'change:data', () => {
|
166 | tableHeadingsRefreshHandler(model, editor.editing);
|
167 | tableCellRefreshHandler(model, editor.editing);
|
168 | });
|
169 | }
|
170 | |
171 |
|
172 |
|
173 | registerAdditionalSlot(slotHandler) {
|
174 | this._additionalSlots.push(slotHandler);
|
175 | }
|
176 | }
|
177 |
|
178 |
|
179 |
|
180 |
|
181 |
|
182 |
|
183 | function upcastCellSpan(type) {
|
184 | return (cell) => {
|
185 | const span = parseInt(cell.getAttribute(type));
|
186 | if (Number.isNaN(span) || span <= 0) {
|
187 | return null;
|
188 | }
|
189 | return span;
|
190 | };
|
191 | }
|