1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | import { Plugin } from 'ckeditor5/src/core';
|
9 | import { addListToDropdown, createDropdown, Model, SplitButtonView, SwitchButtonView } from 'ckeditor5/src/ui';
|
10 | import { Collection } from 'ckeditor5/src/utils';
|
11 | import InsertTableView from './ui/inserttableview';
|
12 | import tableIcon from './../theme/icons/table.svg';
|
13 | import tableColumnIcon from './../theme/icons/table-column.svg';
|
14 | import tableRowIcon from './../theme/icons/table-row.svg';
|
15 | import tableMergeCellIcon from './../theme/icons/table-merge-cell.svg';
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 |
|
25 |
|
26 | export default class TableUI extends Plugin {
|
27 | |
28 |
|
29 |
|
30 | static get pluginName() {
|
31 | return 'TableUI';
|
32 | }
|
33 | |
34 |
|
35 |
|
36 | init() {
|
37 | const editor = this.editor;
|
38 | const t = this.editor.t;
|
39 | const contentLanguageDirection = editor.locale.contentLanguageDirection;
|
40 | const isContentLtr = contentLanguageDirection === 'ltr';
|
41 | editor.ui.componentFactory.add('insertTable', locale => {
|
42 | const command = editor.commands.get('insertTable');
|
43 | const dropdownView = createDropdown(locale);
|
44 | dropdownView.bind('isEnabled').to(command);
|
45 |
|
46 | dropdownView.buttonView.set({
|
47 | icon: tableIcon,
|
48 | label: t('Insert table'),
|
49 | tooltip: true
|
50 | });
|
51 | let insertTableView;
|
52 | dropdownView.on('change:isOpen', () => {
|
53 | if (insertTableView) {
|
54 | return;
|
55 | }
|
56 |
|
57 | insertTableView = new InsertTableView(locale);
|
58 | dropdownView.panelView.children.add(insertTableView);
|
59 | insertTableView.delegate('execute').to(dropdownView);
|
60 | dropdownView.on('execute', () => {
|
61 | editor.execute('insertTable', { rows: insertTableView.rows, columns: insertTableView.columns });
|
62 | editor.editing.view.focus();
|
63 | });
|
64 | });
|
65 | return dropdownView;
|
66 | });
|
67 | editor.ui.componentFactory.add('tableColumn', locale => {
|
68 | const options = [
|
69 | {
|
70 | type: 'switchbutton',
|
71 | model: {
|
72 | commandName: 'setTableColumnHeader',
|
73 | label: t('Header column'),
|
74 | bindIsOn: true
|
75 | }
|
76 | },
|
77 | { type: 'separator' },
|
78 | {
|
79 | type: 'button',
|
80 | model: {
|
81 | commandName: isContentLtr ? 'insertTableColumnLeft' : 'insertTableColumnRight',
|
82 | label: t('Insert column left')
|
83 | }
|
84 | },
|
85 | {
|
86 | type: 'button',
|
87 | model: {
|
88 | commandName: isContentLtr ? 'insertTableColumnRight' : 'insertTableColumnLeft',
|
89 | label: t('Insert column right')
|
90 | }
|
91 | },
|
92 | {
|
93 | type: 'button',
|
94 | model: {
|
95 | commandName: 'removeTableColumn',
|
96 | label: t('Delete column')
|
97 | }
|
98 | },
|
99 | {
|
100 | type: 'button',
|
101 | model: {
|
102 | commandName: 'selectTableColumn',
|
103 | label: t('Select column')
|
104 | }
|
105 | }
|
106 | ];
|
107 | return this._prepareDropdown(t('Column'), tableColumnIcon, options, locale);
|
108 | });
|
109 | editor.ui.componentFactory.add('tableRow', locale => {
|
110 | const options = [
|
111 | {
|
112 | type: 'switchbutton',
|
113 | model: {
|
114 | commandName: 'setTableRowHeader',
|
115 | label: t('Header row'),
|
116 | bindIsOn: true
|
117 | }
|
118 | },
|
119 | { type: 'separator' },
|
120 | {
|
121 | type: 'button',
|
122 | model: {
|
123 | commandName: 'insertTableRowAbove',
|
124 | label: t('Insert row above')
|
125 | }
|
126 | },
|
127 | {
|
128 | type: 'button',
|
129 | model: {
|
130 | commandName: 'insertTableRowBelow',
|
131 | label: t('Insert row below')
|
132 | }
|
133 | },
|
134 | {
|
135 | type: 'button',
|
136 | model: {
|
137 | commandName: 'removeTableRow',
|
138 | label: t('Delete row')
|
139 | }
|
140 | },
|
141 | {
|
142 | type: 'button',
|
143 | model: {
|
144 | commandName: 'selectTableRow',
|
145 | label: t('Select row')
|
146 | }
|
147 | }
|
148 | ];
|
149 | return this._prepareDropdown(t('Row'), tableRowIcon, options, locale);
|
150 | });
|
151 | editor.ui.componentFactory.add('mergeTableCells', locale => {
|
152 | const options = [
|
153 | {
|
154 | type: 'button',
|
155 | model: {
|
156 | commandName: 'mergeTableCellUp',
|
157 | label: t('Merge cell up')
|
158 | }
|
159 | },
|
160 | {
|
161 | type: 'button',
|
162 | model: {
|
163 | commandName: isContentLtr ? 'mergeTableCellRight' : 'mergeTableCellLeft',
|
164 | label: t('Merge cell right')
|
165 | }
|
166 | },
|
167 | {
|
168 | type: 'button',
|
169 | model: {
|
170 | commandName: 'mergeTableCellDown',
|
171 | label: t('Merge cell down')
|
172 | }
|
173 | },
|
174 | {
|
175 | type: 'button',
|
176 | model: {
|
177 | commandName: isContentLtr ? 'mergeTableCellLeft' : 'mergeTableCellRight',
|
178 | label: t('Merge cell left')
|
179 | }
|
180 | },
|
181 | { type: 'separator' },
|
182 | {
|
183 | type: 'button',
|
184 | model: {
|
185 | commandName: 'splitTableCellVertically',
|
186 | label: t('Split cell vertically')
|
187 | }
|
188 | },
|
189 | {
|
190 | type: 'button',
|
191 | model: {
|
192 | commandName: 'splitTableCellHorizontally',
|
193 | label: t('Split cell horizontally')
|
194 | }
|
195 | }
|
196 | ];
|
197 | return this._prepareMergeSplitButtonDropdown(t('Merge cells'), tableMergeCellIcon, options, locale);
|
198 | });
|
199 | }
|
200 | |
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 | _prepareDropdown(label, icon, options, locale) {
|
208 | const editor = this.editor;
|
209 | const dropdownView = createDropdown(locale);
|
210 | const commands = this._fillDropdownWithListOptions(dropdownView, options);
|
211 |
|
212 | dropdownView.buttonView.set({
|
213 | label,
|
214 | icon,
|
215 | tooltip: true
|
216 | });
|
217 |
|
218 | dropdownView.bind('isEnabled').toMany(commands, 'isEnabled', (...areEnabled) => {
|
219 | return areEnabled.some(isEnabled => isEnabled);
|
220 | });
|
221 | this.listenTo(dropdownView, 'execute', evt => {
|
222 | editor.execute(evt.source.commandName);
|
223 |
|
224 | if (!(evt.source instanceof SwitchButtonView)) {
|
225 | editor.editing.view.focus();
|
226 | }
|
227 | });
|
228 | return dropdownView;
|
229 | }
|
230 | |
231 |
|
232 |
|
233 |
|
234 |
|
235 |
|
236 |
|
237 |
|
238 | _prepareMergeSplitButtonDropdown(label, icon, options, locale) {
|
239 | const editor = this.editor;
|
240 | const dropdownView = createDropdown(locale, SplitButtonView);
|
241 | const mergeCommandName = 'mergeTableCells';
|
242 |
|
243 | const mergeCommand = editor.commands.get(mergeCommandName);
|
244 |
|
245 | const commands = this._fillDropdownWithListOptions(dropdownView, options);
|
246 | dropdownView.buttonView.set({
|
247 | label,
|
248 | icon,
|
249 | tooltip: true,
|
250 | isEnabled: true
|
251 | });
|
252 |
|
253 | dropdownView.bind('isEnabled').toMany([mergeCommand, ...commands], 'isEnabled', (...areEnabled) => {
|
254 | return areEnabled.some(isEnabled => isEnabled);
|
255 | });
|
256 |
|
257 | this.listenTo(dropdownView.buttonView, 'execute', () => {
|
258 | editor.execute(mergeCommandName);
|
259 | editor.editing.view.focus();
|
260 | });
|
261 |
|
262 | this.listenTo(dropdownView, 'execute', evt => {
|
263 | editor.execute(evt.source.commandName);
|
264 | editor.editing.view.focus();
|
265 | });
|
266 | return dropdownView;
|
267 | }
|
268 | |
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 | _fillDropdownWithListOptions(dropdownView, options) {
|
276 | const editor = this.editor;
|
277 | const commands = [];
|
278 | const itemDefinitions = new Collection();
|
279 | for (const option of options) {
|
280 | addListOption(option, editor, commands, itemDefinitions);
|
281 | }
|
282 | addListToDropdown(dropdownView, itemDefinitions);
|
283 | return commands;
|
284 | }
|
285 | }
|
286 |
|
287 |
|
288 |
|
289 |
|
290 |
|
291 |
|
292 |
|
293 | function addListOption(option, editor, commands, itemDefinitions) {
|
294 | if (option.type === 'button' || option.type === 'switchbutton') {
|
295 | const model = option.model = new Model(option.model);
|
296 | const { commandName, bindIsOn } = option.model;
|
297 | const command = editor.commands.get(commandName);
|
298 | commands.push(command);
|
299 | model.set({ commandName });
|
300 | model.bind('isEnabled').to(command);
|
301 | if (bindIsOn) {
|
302 | model.bind('isOn').to(command, 'value');
|
303 | }
|
304 | model.set({
|
305 | withText: true
|
306 | });
|
307 | }
|
308 | itemDefinitions.add(option);
|
309 | }
|