PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
tablepress / admin / js / edit / toolbar.js

toolbar.js in TablePress – Tables in WordPress made easy 3.4, at admin/js/edit/toolbar.js

1,168 lines 48.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /**
2 * JavaScript code for the "Edit" section integration of the "Toolbar".
3 *
4 * @package TablePress
5 * @subpackage Views JavaScript
6 * @author Tobias Bäthge
7 * @since 3.4.0
8 */
9
10 /**
11 * WordPress dependencies.
12 */
13 import { useEffect, useState } from 'react';
14 import {
15 Button,
16 __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis
17 Icon,
18 __experimentalNumberControl as NumberControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis
19 Modal,
20 Toolbar,
21 ToolbarButton,
22 ToolbarGroup,
23 __experimentalVStack as VStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis
24 } from '@wordpress/components';
25 import { RawHTML } from '@wordpress/element';
26 import { addAction, removeAction } from '@wordpress/hooks';
27 import { __, _n, sprintf } from '@wordpress/i18n';
28 import { displayShortcut, shortcutAriaLabel } from '@wordpress/keycodes';
29 import {
30 arrowDown,
31 arrowLeft,
32 arrowRight,
33 arrowUp,
34 column,
35 copy,
36 copySmall,
37 image,
38 link,
39 plus,
40 redo,
41 seen,
42 trash,
43 undo,
44 unseen,
45 } from '@wordpress/icons';
46 import { Menu } from '@wordpress/ui';
47
48 /**
49 * Internal dependencies.
50 */
51 import { initializeReactComponentInPortal } from '../common/react-loader';
52 import { Alert } from '../common/alert';
53 import { HelpBox } from '../common/help';
54 import {
55 cellsMerge,
56 cut,
57 formatting,
58 insertColumn,
59 insertColumnBefore,
60 insertColumnAfter,
61 insertRow,
62 insertRowBefore,
63 insertRowAfter,
64 moveFirst,
65 moveLast,
66 moveLeftRight,
67 moveTop,
68 moveBottom,
69 moveUpDown,
70 paste,
71 row,
72 sort,
73 sortAsc,
74 sortDesc,
75 } from '../../img/toolbar-icons';
76
77 /**
78 * Returns the Editor Toolbar component's JSX markup.
79 *
80 * @return {Object} Editor Toolbar component.
81 */
82 const Section = () => {
83 const [ columnsAppendNumber, setColumnsAppendNumber ] = useState( 1 );
84 const [ rowsAppendNumber, setRowsAppendNumber ] = useState( 1 );
85 const [ alertMoveInvalidIsShown, setAlertMoveInvalidIsShown ] = useState( false );
86 const [ alertDeleteRowsInvalidIsShown, setAlertDeleteRowsInvalidIsShown ] = useState( false );
87 const [ alertDeleteColumnsInvalidIsShown, setAlertDeleteColumnsInvalidIsShown ] = useState( false );
88 const [ alertMergeProhibitedIsShown, setAlertMergeProhibitedIsShown ] = useState( false );
89 const [ modalAddRowsIsShown, setModalAddRowsIsShown ] = useState( false );
90 const [ modalAddColumnsIsShown, setModalAddColumnsIsShown ] = useState( false );
91 const [ editorSelection, setEditorSelection ] = useState( () => ( { ...tp.helpers.selection } ) );
92 const [ tableSize, setTableSize ] = useState( () => ( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } ) );
93 const [ toolbarUndoRedoState, setToolbarUndoRedoState ] = useState( { undoDisabled: true, redoDisabled: true } );
94 const [ cellsMergeErrorMessage, setCellsMergeErrorMessage ] = useState( '' );
95
96 const numSelectedRows = editorSelection.rows.length;
97 const numSelectedColumns = editorSelection.columns.length;
98
99 /*
100 // @todo Conversion of dynamic state update via addAction/doAction?
101
102 // When the component is first rendered, register the action hook that is triggered when the editor selection is changed.
103 useEffect( () => {
104 addAction( 'tablepress.selectionChanged', 'tp/edit-screen/handle-selection-changed', ( meta ) => {
105 setEditorSelection( { ...meta } );
106 } );
107
108 return () => {
109 removeAction( 'tablepress.selectionChanged', 'tp/edit-screen/handle-selection-changed' );
110 };
111 }, [] );
112 // */
113
114 useEffect( () => {
115 addAction( 'tablepress.toolbarUndoRedoStateUpdate', 'tp/edit-screen/handle-toolbar-undo-redo-state-update', ( newToolbarUndoRedoState ) => {
116 setToolbarUndoRedoState( newToolbarUndoRedoState );
117 } );
118
119 return () => {
120 removeAction( 'tablepress.toolbarUndoRedoStateUpdate', 'tp/edit-screen/handle-toolbar-undo-redo-state-update' );
121 };
122 }, [] );
123
124 /**
125 * Merges/combines the selected cells, if allowed.
126 */
127 const mergeCells = () => {
128 // Call-by-reference object for the cell_merge_allowed() call.
129 const errorMessage = {
130 text: '',
131 };
132
133 if ( ! tp.helpers.cell_merge_allowed( errorMessage ) ) {
134 setCellsMergeErrorMessage( errorMessage.text );
135 setAlertMergeProhibitedIsShown( true );
136 return;
137 }
138
139 tp.callbacks.merge_cells();
140 };
141
142 /**
143 * Checks whether the selected rows or columns contain at least one element of the specific visibility.
144 *
145 * @param {string} type The type of the selected items to check ('rows' or 'columns').
146 * @param {number} visibility Visibility state to check for (0 for hidden, 1 for visible).
147 * @return {boolean} True if the entry shall be shown, false if not.
148 */
149 const selectionVisibilityContains = ( type, visibility ) => {
150 return editorSelection[ type ].some( ( rocIdx ) => ( tp.table.visibility[ type ][ rocIdx ] === visibility ) );
151 };
152
153 /**
154 * Determines whether moving the rows/columns of the current selection is allowed.
155 *
156 * @param {string} type The type of the selected items to move ('rows' or 'columns').
157 * @param {string} direction The direction to move ('up', 'down', 'left', 'right', 'top', 'bottom', 'first', 'last').
158 * @return {boolean} Whether the move is allowed or not.
159 */
160 const moveAllowed = ( type, direction ) => {
161 // When moving up or left, or to top or to first, test the first row/column of the selected range.
162 let rocToTest = editorSelection[ type ][0];
163 let minMaxRoC = 0; // First row/column.
164 // When moving down or right, or to bottom or to last, test the last row/column of the selected range.
165 if ( [ 'down', 'right', 'bottom', 'last' ].includes( direction ) ) {
166 rocToTest = editorSelection[ type ][ editorSelection[ type ].length - 1 ];
167 minMaxRoC = tableSize[ type ] - 1; // Last row/column.
168 }
169
170 // Moving is allowed if the first/last row/column is not already at the target edge.
171 return minMaxRoC !== rocToTest;
172 };
173
174 /**
175 * Moves the selected rows or columns.
176 *
177 * @param {string} direction The direction to move ('up', 'down', 'left', 'right', 'top', 'bottom', 'first', 'last').
178 * @param {string} type The type of the selected items to move ('rows' or 'columns').
179 */
180 const move = ( direction, type ) => {
181 if ( ! moveAllowed( type, direction ) ) {
182 setAlertMoveInvalidIsShown( true );
183 return;
184 }
185
186 tp.callbacks.move( direction, type );
187 };
188
189 /**
190 * Removes the selected rows or columns.
191 *
192 * @param {string} type The type of the selected items to remove ('rows' or 'columns').
193 */
194 const remove = ( type ) => {
195 // Prevent deleting all rows or columns.
196 if ( tableSize[ type ] === editorSelection[ type ].length ) {
197 if ( 'rows' === type ) {
198 setAlertDeleteRowsInvalidIsShown( true );
199 } else {
200 setAlertDeleteColumnsInvalidIsShown( true );
201 }
202 return;
203 }
204
205 tp.callbacks.remove( type );
206 };
207
208 return (
209 <HStack
210 spacing={ 1 }
211 alignment="left"
212 >
213 <HStack
214 alignment="left"
215 className="tablepress-toolbar-scroll-wrapper"
216 >
217 <Toolbar
218 label={ __( 'Table Manipulation', 'tablepress' ) }
219 style={ {
220 borderColor: '#c3c4c7',
221 } }
222 >
223 <ToolbarGroup
224 style={ {
225 borderRightColor: '#c3c4c7',
226 } }
227 >
228 <ToolbarButton
229 icon={ undo }
230 label={ __( 'Undo', 'tablepress' ) }
231 shortcut={ {
232 ariaLabel: shortcutAriaLabel.primary( 'z' ),
233 display: displayShortcut.primary( 'z' ),
234 } }
235 onClick={ () => tp.editor.undo() }
236 disabled={ toolbarUndoRedoState.undoDisabled }
237 />
238 <ToolbarButton
239 icon={ redo }
240 label={ __( 'Redo', 'tablepress' ) }
241 shortcut={ {
242 ariaLabel: shortcutAriaLabel.primary( 'y' ),
243 display: displayShortcut.primary( 'y' ),
244 } }
245 onClick={ () => tp.editor.redo() }
246 disabled={ toolbarUndoRedoState.redoDisabled }
247 />
248 </ToolbarGroup>
249 <ToolbarGroup
250 style={ {
251 borderRightColor: '#c3c4c7',
252 } }
253 >
254 <ToolbarButton
255 icon={ cut }
256 label={ __( 'Cut', 'tablepress' ) }
257 shortcut={ {
258 ariaLabel: shortcutAriaLabel.primary( 'x' ),
259 display: displayShortcut.primary( 'x' ),
260 } }
261 onClick={ () => {
262 /* eslint-disable @wordpress/no-global-active-element */
263 if ( 'TEXTAREA' === document.activeElement.tagName && document.activeElement.selectionStart !== document.activeElement.selectionEnd ) {
264 // @todo Does not work, likely due to blur event!
265 document.execCommand( 'copy' ); // If text is selected in the actively edited cell, only copy that.
266 const cursorPosition = document.activeElement.selectionStart;
267 document.activeElement.value = document.activeElement.value.slice( 0, document.activeElement.selectionStart ) + document.activeElement.value.slice( document.activeElement.selectionEnd ); // Cut the selected content.
268 document.activeElement.selectionEnd = cursorPosition;
269 } else {
270 tp.editor.copy( true ); // Otherwise, copy highlighted cells.
271 tp.editor.setValue( tp.editor.highlighted, '' ); // Make cell content empty.
272 }
273 /* eslint-enable @wordpress/no-global-active-element */
274 } }
275 />
276 <ToolbarButton
277 icon={ copy }
278 label={ __( 'Copy', 'tablepress' ) }
279 shortcut={ {
280 ariaLabel: shortcutAriaLabel.primary( 'c' ),
281 display: displayShortcut.primary( 'c' ),
282 } }
283 onClick={ () => {
284 if ( 'TEXTAREA' === document.activeElement.tagName && document.activeElement.selectionStart !== document.activeElement.selectionEnd ) { // eslint-disable-line @wordpress/no-global-active-element
285 // @todo Does not work, likely due to blur event!
286 document.execCommand( 'copy' ); // If text is selected in the actively edited cell, only copy that.
287 } else {
288 tp.editor.copy( true ); // Otherwise, copy highlighted cells.
289 }
290 } }
291 />
292 <ToolbarButton
293 icon={ paste }
294 label={ __( 'Paste', 'tablepress' ) }
295 shortcut={ {
296 ariaLabel: shortcutAriaLabel.primary( 'v' ),
297 display: displayShortcut.primary( 'v' ),
298 } }
299 onClick={ () => {
300 /* eslint-disable @wordpress/no-global-active-element */
301 if ( 'TEXTAREA' === document.activeElement.tagName ) {
302 // @todo Does not work, likely due to blur event!
303 window.navigator.clipboard.readText().then( ( text ) => {
304 if ( text ) {
305 const cursorPosition = document.activeElement.selectionStart + text.length;
306 document.activeElement.value = document.activeElement.value.slice( 0, document.activeElement.selectionStart ) + text + document.activeElement.value.slice( document.activeElement.selectionEnd ); // Paste at the selection.
307 document.activeElement.selectionEnd = cursorPosition;
308 }
309 } );
310 } else if ( tp.editor.selectedCell ) {
311 window.navigator.clipboard.readText().then( ( text ) => {
312 if ( text ) {
313 tp.editor.paste( tp.editor.selectedCell[0], tp.editor.selectedCell[1], text );
314 }
315 } );
316 }
317 /* eslint-enable @wordpress/no-global-active-element */
318 } }
319 // Older browser don't offer the readText() method, so "Paste" needs to be disabled.
320 disabled={ ! window?.navigator?.clipboard?.readText }
321 extraProps={ {
322 title: ! window?.navigator?.clipboard?.readText ? __( 'Your browser does not allow pasting via the context menu. Use the keyboard shortcut instead.', 'tablepress' ) : undefined,
323 } }
324 />
325 </ToolbarGroup>
326 <ToolbarGroup
327 style={ {
328 borderRightColor: '#c3c4c7',
329 } }
330 >
331 <ToolbarButton
332 icon={ link }
333 label={ __( 'Insert Link', 'tablepress' ) }
334 shortcut={ {
335 ariaLabel: shortcutAriaLabel.primary( 'l' ),
336 display: displayShortcut.primary( 'l' ),
337 } }
338 onClick={ () => tp.callbacks.insert_link.open_dialog() } // @todo Add parameter `( 'TEXTAREA' === document.activeElement.tagName ) ? document.activeElement : null`?
339 />
340 <ToolbarButton
341 icon={ image }
342 label={ __( 'Insert Image', 'tablepress' ) }
343 shortcut={ {
344 ariaLabel: shortcutAriaLabel.primary( 'i' ),
345 display: displayShortcut.primary( 'i' ),
346 } }
347 onClick={ () => tp.callbacks.insert_image.open_dialog() } // @todo Add parameter `( 'TEXTAREA' === document.activeElement.tagName ) ? document.activeElement : null`?
348 />
349 <ToolbarButton
350 icon={ formatting }
351 label={ __( 'Advanced Editor', 'tablepress' ) }
352 shortcut={ {
353 ariaLabel: shortcutAriaLabel.primary( 'e' ),
354 display: displayShortcut.primary( 'e' ),
355 } }
356 onClick={ () => tp.callbacks.advanced_editor.open_dialog() } // @todo Add parameter `( 'TEXTAREA' === document.activeElement.tagName ) ? document.activeElement : null`?
357 />
358 <ToolbarButton
359 icon={ cellsMerge }
360 label={ __( 'Combine/Merge cells', 'tablepress' ) }
361 onClick={ () => {
362 mergeCells();
363 } }
364 /*
365 // @todo After conversion to dynamic state update via addAction/doAction?
366 disabled={ ( 1 === numSelectedRows && 1 === numSelectedColumns ) || ! tp.helpers.cell_merge_allowed() }
367 extraProps={ {
368 title: ( 1 === numSelectedRows && 1 === numSelectedColumns ) || ! tp.helpers.cell_merge_allowed( errorMessage ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + errorMessage.text : undefined,
369 } }
370 */
371 />
372 </ToolbarGroup>
373 <ToolbarGroup
374 style={ {
375 borderRightColor: '#c3c4c7',
376 } }
377 >
378 <Menu.Root modal={ false }>
379 <Menu.Trigger
380 render={
381 <ToolbarButton
382 icon={ row }
383 label={ __( 'Actions for rows', 'tablepress' ) }
384 onClick={ () => {
385 // @todo Remove after conversion to dynamic state update via addAction/doAction.
386 setEditorSelection( { ...tp.helpers.selection } );
387 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
388 tp.helpers.visibility.update(); // Update information about hidden rows and columns.
389 } }
390 >
391 <span className="tablepress-toolbar-button-text">
392 { __( 'Rows…', 'tablepress' ) }
393 </span>
394 </ToolbarButton>
395 }
396 />
397 <Menu.Popup>
398 <Menu.Item
399 prefix={ <Menu.PrefixIcon icon={ copySmall } /> }
400 onClick={ ( event ) => {
401 tp.callbacks.insert_duplicate( 'duplicate', 'rows' );
402 if ( event.shiftKey ) {
403 event.preventBaseUIHandler();
404 // @todo Remove after conversion to dynamic state update via addAction/doAction.
405 setEditorSelection( { ...tp.helpers.selection } );
406 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
407 }
408 } }
409 >
410 <Menu.ItemLabel>
411 { _n( 'Duplicate row', 'Duplicate rows', numSelectedRows, 'tablepress' ) }
412 </Menu.ItemLabel>
413 </Menu.Item>
414 <Menu.SubmenuRoot>
415 <Menu.SubmenuTrigger
416 prefix={ <Menu.PrefixIcon icon={ insertRow } /> }
417 >
418 <Menu.ItemLabel>
419 { _n( 'Insert row…', 'Insert rows…', numSelectedRows, 'tablepress' ) }
420 </Menu.ItemLabel>
421 </Menu.SubmenuTrigger>
422 <Menu.Popup
423 positioner={ <Menu.Positioner align="center" /> }
424 >
425 <Menu.Item
426 prefix={ <Menu.PrefixIcon icon={ insertRowBefore } /> }
427 onClick={ ( event ) => {
428 tp.callbacks.insert_duplicate( 'insert', 'rows', 'before' );
429 if ( event.shiftKey ) {
430 event.preventBaseUIHandler();
431 // @todo Remove after conversion to dynamic state update via addAction/doAction.
432 setEditorSelection( { ...tp.helpers.selection } );
433 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
434 }
435 } }
436 >
437 <Menu.ItemLabel>
438 { _n( 'Insert row above', 'Insert rows above', numSelectedRows, 'tablepress' ) }
439 </Menu.ItemLabel>
440 </Menu.Item>
441 <Menu.Item
442 prefix={ <Menu.PrefixIcon icon={ insertRowAfter } /> }
443 onClick={ ( event ) => {
444 tp.callbacks.insert_duplicate( 'insert', 'rows', 'after' );
445 if ( event.shiftKey ) {
446 event.preventBaseUIHandler();
447 // @todo Remove after conversion to dynamic state update via addAction/doAction.
448 setEditorSelection( { ...tp.helpers.selection } );
449 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
450 }
451 } }
452 >
453 <Menu.ItemLabel>
454 { _n( 'Insert row below', 'Insert rows below', numSelectedRows, 'tablepress' ) }
455 </Menu.ItemLabel>
456 </Menu.Item>
457 </Menu.Popup>
458 </Menu.SubmenuRoot>
459 <Menu.Item
460 prefix={ <Menu.PrefixIcon icon={ plus } /> }
461 onClick={ () => setModalAddRowsIsShown( true ) }
462 >
463 <Menu.ItemLabel>
464 { __( 'Add rows…', 'tablepress' ) }
465 </Menu.ItemLabel>
466 </Menu.Item>
467 <Menu.Item
468 prefix={ <Menu.PrefixIcon icon={ trash } /> }
469 onClick={ ( event ) => {
470 remove( 'rows' );
471 if ( event.shiftKey ) {
472 event.preventBaseUIHandler();
473 // @todo Remove after conversion to dynamic state update via addAction/doAction.
474 setEditorSelection( { ...tp.helpers.selection } );
475 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
476 }
477 } }
478 disabled={ tableSize.rows === numSelectedRows }
479 title={ tableSize.rows === numSelectedRows ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'You can not delete all table rows!', 'tablepress' ) : undefined }
480 >
481 <Menu.ItemLabel>
482 { _n( 'Delete row', 'Delete rows', numSelectedRows, 'tablepress' ) }
483 </Menu.ItemLabel>
484 </Menu.Item>
485 <Menu.Separator />
486 <Menu.SubmenuRoot>
487 <Menu.SubmenuTrigger
488 prefix={ <Menu.PrefixIcon icon={ moveUpDown } /> }
489 disabled={ 1 === tableSize.rows }
490 title={ 1 === tableSize.rows ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'The table has only one row.', 'tablepress' ) : undefined }
491 >
492 <Menu.ItemLabel>
493 { _n( 'Move row…', 'Move rows…', numSelectedRows, 'tablepress' ) }
494 </Menu.ItemLabel>
495 </Menu.SubmenuTrigger>
496 <Menu.Popup
497 positioner={ <Menu.Positioner align="center" /> }
498 >
499 <Menu.Item
500 prefix={ <Menu.PrefixIcon icon={ moveTop } /> }
501 onClick={ ( event ) => {
502 move( 'top', 'rows' );
503 if ( event.shiftKey ) {
504 event.preventBaseUIHandler();
505 setEditorSelection( { ...tp.helpers.selection } );
506 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
507 }
508 } }
509
510 shortcut={ {
511 label: shortcutAriaLabel.secondary( '↑' ),
512 displayShortcut: displayShortcut.secondary( '↑' ),
513 } }
514 disabled={ ! moveAllowed( 'rows', 'top' ) }
515 title={ ! moveAllowed( 'rows', 'top' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected row is already at the top of the table.', 'The selected rows are already at the top of the table.', numSelectedRows, 'tablepress' ) : undefined }
516 >
517 <Menu.ItemLabel>
518 { _n( 'Move row to the top', 'Move rows to the top', numSelectedRows, 'tablepress' ) }
519 </Menu.ItemLabel>
520 </Menu.Item>
521 <Menu.Item
522 prefix={ <Menu.PrefixIcon icon={ arrowUp } /> }
523 onClick={ ( event ) => {
524 move( 'up', 'rows' );
525 if ( event.shiftKey ) {
526 event.preventBaseUIHandler();
527 setEditorSelection( { ...tp.helpers.selection } );
528 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
529 }
530 } }
531 shortcut={ {
532 label: shortcutAriaLabel.primaryShift( '↑' ),
533 displayShortcut: displayShortcut.primaryShift( '↑' ),
534 } }
535 disabled={ ! moveAllowed( 'rows', 'up' ) }
536 title={ ! moveAllowed( 'rows', 'up' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected row is already at the top of the table.', 'The selected rows are already at the top of the table.', numSelectedRows, 'tablepress' ) : undefined }
537 >
538 <Menu.ItemLabel>
539 { _n( 'Move row up', 'Move rows up', numSelectedRows, 'tablepress' ) }
540 </Menu.ItemLabel>
541 </Menu.Item>
542 <Menu.Separator />
543 <Menu.Item
544 prefix={ <Menu.PrefixIcon icon={ arrowDown } /> }
545 onClick={ ( event ) => {
546 move( 'down', 'rows' );
547 if ( event.shiftKey ) {
548 event.preventBaseUIHandler();
549 setEditorSelection( { ...tp.helpers.selection } );
550 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
551 }
552 } }
553 shortcut={ {
554 label: shortcutAriaLabel.primaryShift( '↓' ),
555 displayShortcut: displayShortcut.primaryShift( '↓' ),
556 } }
557 disabled={ ! moveAllowed( 'rows', 'down' ) }
558 title={ ! moveAllowed( 'rows', 'down' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected row is already at the bottom of the table.', 'The selected rows are already at the bottom of the table.', numSelectedRows, 'tablepress' ) : undefined }
559 >
560 <Menu.ItemLabel>
561 { _n( 'Move row down', 'Move rows down', numSelectedRows, 'tablepress' ) }
562 </Menu.ItemLabel>
563 </Menu.Item>
564 <Menu.Item
565 prefix={ <Menu.PrefixIcon icon={ moveBottom } /> }
566 onClick={ ( event ) => {
567 move( 'bottom', 'rows' );
568 if ( event.shiftKey ) {
569 event.preventBaseUIHandler();
570 setEditorSelection( { ...tp.helpers.selection } );
571 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
572 }
573 } }
574 shortcut={ {
575 label: shortcutAriaLabel.secondary( '↓' ),
576 displayShortcut: displayShortcut.secondary( '↓' ),
577 } }
578 disabled={ ! moveAllowed( 'rows', 'bottom' ) }
579 title={ ! moveAllowed( 'rows', 'bottom' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected row is already at the bottom of the table.', 'The selected rows are already at the bottom of the table.', numSelectedRows, 'tablepress' ) : undefined }
580 >
581 <Menu.ItemLabel>
582 { _n( 'Move row to the bottom', 'Move rows to the bottom', numSelectedRows, 'tablepress' ) }
583 </Menu.ItemLabel>
584 </Menu.Item>
585 </Menu.Popup>
586 </Menu.SubmenuRoot>
587 <Menu.SubmenuRoot>
588 <Menu.SubmenuTrigger
589 prefix={ <Menu.PrefixIcon icon={ sort } /> }
590 disabled={ 1 !== numSelectedColumns || 1 === tableSize.rows }
591 title={ 1 !== numSelectedColumns ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'More than one column was selected.', 'tablepress' ) : ( 1 === tableSize.rows ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'The table has only one row.', 'tablepress' ) : undefined ) } // eslint-disable-line no-nested-ternary
592 >
593 <Menu.ItemLabel>
594 { __( 'Sort rows…', 'tablepress' ) }
595 </Menu.ItemLabel>
596 </Menu.SubmenuTrigger>
597 <Menu.Popup
598 positioner={ <Menu.Positioner align="center" /> }
599 >
600 <Menu.Item
601 prefix={ <Menu.PrefixIcon icon={ sortAsc } /> }
602 onClick={ ( event ) => {
603 tp.callbacks.sort( 'asc' );
604 if ( event.shiftKey ) {
605 event.preventBaseUIHandler();
606 }
607 } }
608 disabled={ 1 !== numSelectedColumns || 1 === tableSize.rows }
609 title={ 1 !== numSelectedColumns ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'More than one column was selected.', 'tablepress' ) : ( 1 === tableSize.rows ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'The table has only one row.', 'tablepress' ) : undefined ) } // eslint-disable-line no-nested-ternary
610 >
611 <Menu.ItemLabel>
612 { __( 'Sort by column ascending', 'tablepress' ) }
613 </Menu.ItemLabel>
614 </Menu.Item>
615 <Menu.Item
616 prefix={ <Menu.PrefixIcon icon={ sortDesc } /> }
617 onClick={ ( event ) => {
618 tp.callbacks.sort( 'desc' );
619 if ( event.shiftKey ) {
620 event.preventBaseUIHandler();
621 }
622 } }
623 disabled={ 1 !== numSelectedColumns || 1 === tableSize.rows }
624 title={ 1 !== numSelectedColumns ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'More than one column was selected.', 'tablepress' ) : ( 1 === tableSize.rows ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'The table has only one row.', 'tablepress' ) : undefined ) } // eslint-disable-line no-nested-ternary
625 >
626 <Menu.ItemLabel>
627 { __( 'Sort by column descending', 'tablepress' ) }
628 </Menu.ItemLabel>
629 </Menu.Item>
630 </Menu.Popup>
631 </Menu.SubmenuRoot>
632 <Menu.SubmenuRoot>
633 <Menu.SubmenuTrigger
634 prefix={ <Menu.PrefixIcon icon={ unseen } /> }
635 >
636 <Menu.ItemLabel>
637 { _n( 'Hide/show row…', 'Hide/show rows…', numSelectedRows, 'tablepress' ) }
638 </Menu.ItemLabel>
639 </Menu.SubmenuTrigger>
640 <Menu.Popup
641 positioner={ <Menu.Positioner align="center" /> }
642 >
643 <Menu.Item
644 prefix={ <Menu.PrefixIcon icon={ unseen } /> }
645 onClick={ ( event ) => {
646 tp.callbacks.hide_unhide( 'hide', 'rows' );
647 if ( event.shiftKey ) {
648 event.preventBaseUIHandler();
649 // @todo Remove after conversion to dynamic state update via addAction/doAction.
650 setEditorSelection( { ...tp.helpers.selection } );
651 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
652 tp.helpers.visibility.update(); // Update information about hidden rows and columns.
653 }
654 } }
655 disabled={ ! selectionVisibilityContains( 'rows', 1 ) }
656 title={ ! selectionVisibilityContains( 'rows', 1 ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected row is already hidden.', 'The selected rows are already hidden.', numSelectedRows, 'tablepress' ) : undefined }
657 >
658 <Menu.ItemLabel>
659 { _n( 'Hide row', 'Hide rows', numSelectedRows, 'tablepress' ) }
660 </Menu.ItemLabel>
661 </Menu.Item>
662 <Menu.Item
663 prefix={ <Menu.PrefixIcon icon={ seen } /> }
664 onClick={ ( event ) => {
665 tp.callbacks.hide_unhide( 'unhide', 'rows' );
666 if ( event.shiftKey ) {
667 event.preventBaseUIHandler();
668 // @todo Remove after conversion to dynamic state update via addAction/doAction.
669 setEditorSelection( { ...tp.helpers.selection } );
670 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
671 tp.helpers.visibility.update(); // Update information about hidden rows and columns.
672 }
673 } }
674 disabled={ ! selectionVisibilityContains( 'rows', 0 ) }
675 title={ ! selectionVisibilityContains( 'rows', 0 ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected row is already visible.', 'The selected rows are already visible.', numSelectedRows, 'tablepress' ) : undefined }
676 >
677 <Menu.ItemLabel>
678 { _n( 'Show row', 'Show rows', numSelectedRows, 'tablepress' ) }
679 </Menu.ItemLabel>
680 </Menu.Item>
681 </Menu.Popup>
682 </Menu.SubmenuRoot>
683 </Menu.Popup>
684 </Menu.Root>
685 <Menu.Root modal={ false }>
686 <Menu.Trigger
687 render={
688 <ToolbarButton
689 icon={ column }
690 label={ __( 'Actions for columns', 'tablepress' ) }
691 onClick={ () => {
692 // @todo Remove after conversion to dynamic state update via addAction/doAction.
693 setEditorSelection( { ...tp.helpers.selection } );
694 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
695 tp.helpers.visibility.update(); // Update information about hidden rows and columns.
696 } }
697 >
698 <span className="tablepress-toolbar-button-text">
699 { __( 'Columns…', 'tablepress' ) }
700 </span>
701 </ToolbarButton>
702 }
703 />
704 <Menu.Popup>
705 <Menu.Item
706 prefix={ <Menu.PrefixIcon icon={ copySmall } /> }
707 onClick={ ( event ) => {
708 tp.callbacks.insert_duplicate( 'duplicate', 'columns' );
709 if ( event.shiftKey ) {
710 event.preventBaseUIHandler();
711 // @todo Remove after conversion to dynamic state update via addAction/doAction.
712 setEditorSelection( { ...tp.helpers.selection } );
713 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
714 }
715 } }
716 >
717 <Menu.ItemLabel>
718 { _n( 'Duplicate column', 'Duplicate columns', numSelectedColumns, 'tablepress' ) }
719 </Menu.ItemLabel>
720 </Menu.Item>
721 <Menu.SubmenuRoot>
722 <Menu.SubmenuTrigger
723 prefix={ <Menu.PrefixIcon icon={ insertColumn } /> }
724 >
725 <Menu.ItemLabel>
726 { _n( 'Insert column…', 'Insert columns…', numSelectedColumns, 'tablepress' ) }
727 </Menu.ItemLabel>
728 </Menu.SubmenuTrigger>
729 <Menu.Popup
730 positioner={ <Menu.Positioner align="center" /> }
731 >
732 <Menu.Item
733 prefix={ <Menu.PrefixIcon icon={ insertColumnBefore } /> }
734 onClick={ ( event ) => {
735 tp.callbacks.insert_duplicate( 'insert', 'columns', 'before' )
736 if ( event.shiftKey ) {
737 event.preventBaseUIHandler();
738 // @todo Remove after conversion to dynamic state update via addAction/doAction.
739 setEditorSelection( { ...tp.helpers.selection } );
740 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
741 }
742 } }
743 >
744 <Menu.ItemLabel>
745 { _n( 'Insert column on the left', 'Insert columns on the left', numSelectedColumns, 'tablepress' ) }
746 </Menu.ItemLabel>
747 </Menu.Item>
748 <Menu.Item
749 prefix={ <Menu.PrefixIcon icon={ insertColumnAfter } /> }
750 onClick={ ( event ) => {
751 tp.callbacks.insert_duplicate( 'insert', 'columns', 'after' )
752 if ( event.shiftKey ) {
753 event.preventBaseUIHandler();
754 // @todo Remove after conversion to dynamic state update via addAction/doAction.
755 setEditorSelection( { ...tp.helpers.selection } );
756 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
757 }
758 } }
759 >
760 <Menu.ItemLabel>
761 { _n( 'Insert column on the right', 'Insert columns on the right', numSelectedColumns, 'tablepress' ) }
762 </Menu.ItemLabel>
763 </Menu.Item>
764 </Menu.Popup>
765 </Menu.SubmenuRoot>
766 <Menu.Item
767 prefix={ <Menu.PrefixIcon icon={ plus } /> }
768 onClick={ () => setModalAddColumnsIsShown( true ) }
769 >
770 <Menu.ItemLabel>
771 { __( 'Add columns…', 'tablepress' ) }
772 </Menu.ItemLabel>
773 </Menu.Item>
774 <Menu.Item
775 prefix={ <Menu.PrefixIcon icon={ trash } /> }
776 onClick={ ( event ) => {
777 remove( 'columns' );
778 if ( event.shiftKey ) {
779 event.preventBaseUIHandler();
780 // @todo Remove after conversion to dynamic state update via addAction/doAction.
781 setEditorSelection( { ...tp.helpers.selection } );
782 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
783 }
784 } }
785 disabled={ tableSize.columns === numSelectedColumns }
786 title={ tableSize.columns === numSelectedColumns ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'You can not delete all table columns!', 'tablepress' ) : undefined }
787 >
788 <Menu.ItemLabel>
789 { _n( 'Delete column', 'Delete columns', numSelectedColumns, 'tablepress' ) }
790 </Menu.ItemLabel>
791 </Menu.Item>
792 <Menu.Separator />
793 <Menu.SubmenuRoot>
794 <Menu.SubmenuTrigger
795 prefix={ <Menu.PrefixIcon icon={ moveLeftRight } /> }
796 disabled={ 1 === tableSize.columns }
797 title={ 1 === tableSize.columns ? __( 'This option is disabled.', 'tablepress' ) + ' ' + __( 'The table has only one column.', 'tablepress' ) : undefined }
798 >
799 <Menu.ItemLabel>
800 { _n( 'Move column…', 'Move columns…', numSelectedColumns, 'tablepress' ) }
801 </Menu.ItemLabel>
802 </Menu.SubmenuTrigger>
803 <Menu.Popup
804 positioner={ <Menu.Positioner align="center" /> }
805 >
806 <Menu.Item
807 prefix={ <Menu.PrefixIcon icon={ moveFirst } /> }
808 onClick={ ( event ) => {
809 move( 'first', 'columns' );
810 if ( event.shiftKey ) {
811 event.preventBaseUIHandler();
812 setEditorSelection( { ...tp.helpers.selection } );
813 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
814 }
815 } }
816
817 shortcut={ {
818 label: shortcutAriaLabel.secondary( '←' ),
819 displayShortcut: displayShortcut.secondary( '←' ),
820 } }
821 disabled={ ! moveAllowed( 'columns', 'first' ) }
822 title={ ! moveAllowed( 'columns', 'first' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected column is already at the left edge of the table.', 'The selected columns are already at the left edge of the table.', numSelectedColumns, 'tablepress' ) : undefined }
823 >
824 <Menu.ItemLabel>
825 { _n( 'Move column to first', 'Move columns to first', numSelectedColumns, 'tablepress' ) }
826 </Menu.ItemLabel>
827 </Menu.Item>
828 <Menu.Item
829 prefix={ <Menu.PrefixIcon icon={ arrowLeft } /> }
830 onClick={ ( event ) => {
831 move( 'left', 'columns' );
832 if ( event.shiftKey ) {
833 event.preventBaseUIHandler();
834 setEditorSelection( { ...tp.helpers.selection } );
835 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
836 }
837 } }
838 shortcut={ {
839 label: shortcutAriaLabel.primaryShift( '←' ),
840 displayShortcut: displayShortcut.primaryShift( '←' ),
841 } }
842 disabled={ ! moveAllowed( 'columns', 'left' ) }
843 title={ ! moveAllowed( 'columns', 'left' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected column is already at the left edge of the table.', 'The selected columns are already at the left edge of the table.', numSelectedColumns, 'tablepress' ) : undefined }
844 >
845 <Menu.ItemLabel>
846 { _n( 'Move column left', 'Move columns left', numSelectedColumns, 'tablepress' ) }
847 </Menu.ItemLabel>
848 </Menu.Item>
849 <Menu.Separator />
850 <Menu.Item
851 prefix={ <Menu.PrefixIcon icon={ arrowRight } /> }
852 onClick={ ( event ) => {
853 move( 'right', 'columns' );
854 if ( event.shiftKey ) {
855 event.preventBaseUIHandler();
856 setEditorSelection( { ...tp.helpers.selection } );
857 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
858 }
859 } }
860 shortcut={ {
861 label: shortcutAriaLabel.primaryShift( '→' ),
862 displayShortcut: displayShortcut.primaryShift( '→' ),
863 } }
864 disabled={ ! moveAllowed( 'columns', 'right' ) }
865 title={ ! moveAllowed( 'columns', 'right' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected column is already at the right edge of the table.', 'The selected columns are already at the right edge of the table.', numSelectedColumns, 'tablepress' ) : undefined }
866 >
867 <Menu.ItemLabel>
868 { _n( 'Move column right', 'Move columns right', numSelectedColumns, 'tablepress' ) }
869 </Menu.ItemLabel>
870 </Menu.Item>
871 <Menu.Item
872 prefix={ <Menu.PrefixIcon icon={ moveLast } /> }
873 onClick={ ( event ) => {
874 move( 'last', 'columns' );
875 if ( event.shiftKey ) {
876 event.preventBaseUIHandler();
877 setEditorSelection( { ...tp.helpers.selection } );
878 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
879 }
880 } }
881 shortcut={ {
882 label: shortcutAriaLabel.secondary( '→' ),
883 displayShortcut: displayShortcut.secondary( '→' ),
884 } }
885 disabled={ ! moveAllowed( 'columns', 'last' ) }
886 title={ ! moveAllowed( 'columns', 'last' ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected column is already at the right edge of the table.', 'The selected columns are already at the right edge of the table.', numSelectedColumns, 'tablepress' ) : undefined }
887 >
888 <Menu.ItemLabel>
889 { _n( 'Move column to last', 'Move columns to last', numSelectedColumns, 'tablepress' ) }
890 </Menu.ItemLabel>
891 </Menu.Item>
892 </Menu.Popup>
893 </Menu.SubmenuRoot>
894 <Menu.SubmenuRoot>
895 <Menu.SubmenuTrigger
896 prefix={ <Menu.PrefixIcon icon={ unseen } /> }
897 >
898 <Menu.ItemLabel>
899 { _n( 'Hide/show column…', 'Hide/show columns…', numSelectedColumns, 'tablepress' ) }
900 </Menu.ItemLabel>
901 </Menu.SubmenuTrigger>
902 <Menu.Popup
903 positioner={ <Menu.Positioner align="center" /> }
904 >
905 <Menu.Item
906 prefix={ <Menu.PrefixIcon icon={ unseen } /> }
907 onClick={ ( event ) => {
908 tp.callbacks.hide_unhide( 'hide', 'columns' );
909 if ( event.shiftKey ) {
910 event.preventBaseUIHandler();
911 // @todo Remove after conversion to dynamic state update via addAction/doAction.
912 setEditorSelection( { ...tp.helpers.selection } );
913 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
914 tp.helpers.visibility.update(); // Update information about hidden rows and columns.
915 }
916 } }
917 disabled={ ! selectionVisibilityContains( 'columns', 1 ) }
918 title={ ! selectionVisibilityContains( 'columns', 1 ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected column is already hidden.', 'The selected columns are already hidden.', numSelectedColumns, 'tablepress' ) : undefined }
919 >
920 <Menu.ItemLabel>
921 { _n( 'Hide column', 'Hide columns', numSelectedColumns, 'tablepress' ) }
922 </Menu.ItemLabel>
923 </Menu.Item>
924 <Menu.Item
925 prefix={ <Menu.PrefixIcon icon={ seen } /> }
926 onClick={ ( event ) => {
927 tp.callbacks.hide_unhide( 'unhide', 'columns' );
928 if ( event.shiftKey ) {
929 event.preventBaseUIHandler();
930 // @todo Remove after conversion to dynamic state update via addAction/doAction.
931 setEditorSelection( { ...tp.helpers.selection } );
932 setTableSize( { rows: tp.editor.options.data.length, columns: tp.editor.options.columns.length } );
933 tp.helpers.visibility.update(); // Update information about hidden rows and columns.
934 }
935 } }
936 disabled={ ! selectionVisibilityContains( 'columns', 0 ) }
937 title={ ! selectionVisibilityContains( 'columns', 0 ) ? __( 'This option is disabled.', 'tablepress' ) + ' ' + _n( 'The selected column is already visible.', 'The selected columns are already visible.', numSelectedColumns, 'tablepress' ) : undefined }
938 >
939 <Menu.ItemLabel>
940 { _n( 'Show column', 'Show columns', numSelectedColumns, 'tablepress' ) }
941 </Menu.ItemLabel>
942 </Menu.Item>
943 </Menu.Popup>
944 </Menu.SubmenuRoot>
945 </Menu.Popup>
946 </Menu.Root>
947 </ToolbarGroup>
948 </Toolbar>
949 <HelpBox
950 title={ __( 'Table Editor Toolbar', 'tablepress' ) }
951 buttonProps={ {
952 size: 'compact',
953 label: __( 'Help on the Table Editor Toolbar', 'tablepress' ),
954 variant: 'icon',
955 } }
956 modalProps={ {
957 size: 'large',
958 } }
959 >
960 <p>
961 { __( 'The toolbar provides a set of tools for editing the data in your tables.', 'tablepress' ) }
962 { ' ' }
963 { __( 'You can use the Undo and Redo buttons to revert or reapply changes to your table.', 'tablepress' ) }
964 { ' ' }
965 { __( 'The Cut, Copy, and Paste buttons allow you to manipulate the data in your table.', 'tablepress' ) }
966 { ' ' }
967 { sprintf( __( 'Buttons for inserting links or images, for opening the “%1$s” with more styling options, and for combining or merging cells are available as well.', 'tablepress' ), __( 'Advanced Editor', 'tablepress' ) ) }
968 </p>
969 <RawHTML>
970 { '<p>' }
971 { sprintf( __( 'In addition, the toolbar provides quick access to common actions for editing the structure of your table, via the “%1$s” and “%2$s” buttons.', 'tablepress' ), __( 'Rows…', 'tablepress' ), __( 'Columns…', 'tablepress' ) ) }
972 { ' ' + __( 'Use these buttons to add, insert, duplicate, delete, sort, show/hide, or move rows and columns.', 'tablepress' ) }
973 { ' ' + __( 'If you’d like to repeat the same action multiple times, hold down the <kbd>Shift</kbd> key while clicking the action to keep the current menu open.', 'tablepress' ) }
974 { '</p>' }
975 </RawHTML>
976 <p>
977 { __( 'Most actions can also be performed by typing a keyboard shortcut, which is shown in the button’s tooltip or the menus.', 'tablepress' ) }
978 </p>
979 <h2>{ __( 'Help on combining cells', 'tablepress' ) }</h2>
980 <RawHTML>
981 { '<p>' }
982 { __( 'Table cells can span across more than one column or row.', 'tablepress' ) }
983 { ' ' + __( 'Combining consecutive cells within the same row is called “colspanning”.', 'tablepress' ) }
984 { ' ' + __( 'Combining consecutive cells within the same column is called “rowspanning”.', 'tablepress' ) }
985 { '</p>' }
986 </RawHTML>
987 <RawHTML>
988 { '<p>' }
989 { sprintf( __( 'To combine adjacent cells, select the desired cells and click the “%s” button or use the context menu.', 'tablepress' ), __( 'Combine/Merge cells', 'tablepress' ) ) }
990 { ' ' + __( 'The corresponding keywords, <code>#colspan#</code> and <code>#rowspan#</code>, will then be added for you.', 'tablepress' ) }
991 { '</p>' }
992 </RawHTML>
993 <p>
994 <strong>
995 { __( 'Be aware that the Table Features for Site Visitors, like sorting, filtering, and pagination, will not work in tables which have combined cells in their body rows.', 'tablepress' ) }
996 </strong>
997 { ' ' }
998 { __( 'It is however possible to use these features in tables that have combined cells in the table header or footer rows, to allow for creating complex header and footer layouts.', 'tablepress' ) }
999 </p>
1000 <h2>{ __( 'More information', 'tablepress' ) }</h2>
1001 <p>
1002 { /* eslint-disable-next-line react/jsx-no-target-blank */ }
1003 <a
1004 href="https://tablepress.org/documentation/?utm_source=plugin&utm_medium=textlink&utm_content=edit-screen-help-box"
1005 target="_blank"
1006 >
1007 { __( 'Documentation', 'tablepress' ) }
1008 </a>
1009 { " · " }
1010 { /* eslint-disable-next-line react/jsx-no-target-blank */ }
1011 <a
1012 href="https://tablepress.org/faq/?utm_source=plugin&utm_medium=textlink&utm_content=edit-screen-help-box"
1013 target="_blank"
1014 >
1015 { __( 'Frequently Asked Questions', 'tablepress' ) }
1016 </a>
1017 { " · " }
1018 { /* eslint-disable-next-line react/jsx-no-target-blank */ }
1019 <a
1020 href="https://tablepress.org/tutorials/?utm_source=plugin&utm_medium=textlink&utm_content=edit-screen-help-box"
1021 target="_blank"
1022 >
1023 { __( 'Tutorials', 'tablepress' ) }
1024 </a>
1025 </p>
1026 </HelpBox>
1027 </HStack>
1028 { alertMergeProhibitedIsShown && (
1029 <Alert
1030 icon={ cellsMerge }
1031 title={ __( 'Combine/Merge cells', 'tablepress' ) }
1032 text={ cellsMergeErrorMessage }
1033 onConfirm={ () => setAlertMergeProhibitedIsShown( false ) }
1034 modalProps={ {
1035 size: 'small',
1036 } }
1037 />
1038 ) }
1039 { alertMoveInvalidIsShown && (
1040 <Alert
1041 title={ __( 'Table Manipulation', 'tablepress' ) }
1042 text={ __( 'You can not do this move, because you reached the border of the table.', 'tablepress' ) }
1043 onConfirm={ () => setAlertMoveInvalidIsShown( false ) }
1044 modalProps={ {
1045 size: 'small',
1046 } }
1047 />
1048 ) }
1049 { alertDeleteRowsInvalidIsShown && (
1050 <Alert
1051 icon={ trash }
1052 title={ __( 'Table Manipulation', 'tablepress' ) }
1053 text={ __( 'You can not delete all table rows!', 'tablepress' ) }
1054 onConfirm={ () => setAlertDeleteRowsInvalidIsShown( false ) }
1055 />
1056 ) }
1057 { alertDeleteColumnsInvalidIsShown && (
1058 <Alert
1059 icon={ trash }
1060 title={ __( 'Table Manipulation', 'tablepress' ) }
1061 text={ __( 'You can not delete all table columns!', 'tablepress' ) }
1062 onConfirm={ () => setAlertDeleteColumnsInvalidIsShown( false ) }
1063 />
1064 ) }
1065 { modalAddRowsIsShown && (
1066 <Modal
1067 icon={ <Icon icon={ plus } size="36" style={ { display: 'flex', 'marginRight': '1rem' } } /> }
1068 title={ __( 'Add rows…', 'tablepress' ) }
1069 onRequestClose={ () => setModalAddRowsIsShown( false ) }
1070 focusOnMount="firstInputElement"
1071 style={ { width: '280px', minWidth: '280px' } }
1072 >
1073 <VStack>
1074 <HStack spacing={ 4 } alignment="bottom">
1075 <NumberControl
1076 label={ __( 'Number of rows', 'tablepress' ) }
1077 size="compact"
1078 title={ __( 'This field must contain a positive number.', 'tablepress' ) }
1079 isDragEnabled={ false }
1080 value={ rowsAppendNumber }
1081 onChange={ ( newRowsAppendNumber ) => {
1082 newRowsAppendNumber = '' !== newRowsAppendNumber ? parseInt( newRowsAppendNumber, 10 ) : 1;
1083 setRowsAppendNumber( newRowsAppendNumber );
1084 } }
1085 min={ 1 }
1086 required={ true }
1087 onKeyDown={ ( event ) => {
1088 if ( 'Enter' === event.key ) {
1089 event.preventDefault();
1090 tp.callbacks.append( 'rows', rowsAppendNumber );
1091 if ( ! event.shiftKey ) {
1092 setModalAddRowsIsShown( false );
1093 }
1094 }
1095 } }
1096 />
1097 <Button
1098 variant="primary"
1099 size="compact"
1100 text={ __( 'Add', 'tablepress' ) }
1101 onClick={ ( event ) => {
1102 tp.callbacks.append( 'rows', rowsAppendNumber );
1103 if ( ! event.shiftKey ) {
1104 setModalAddRowsIsShown( false );
1105 }
1106 } }
1107 />
1108 </HStack>
1109 </VStack>
1110 </Modal>
1111 ) }
1112 { modalAddColumnsIsShown && (
1113 <Modal
1114 icon={ <Icon icon={ plus } size="36" style={ { display: 'flex', 'marginRight': '1rem' } } /> }
1115 title={ __( 'Add columns…', 'tablepress' ) }
1116 onRequestClose={ () => setModalAddColumnsIsShown( false ) }
1117 focusOnMount="firstInputElement"
1118 style={ { width: '280px', minWidth: '280px' } }
1119 >
1120 <VStack>
1121 <HStack spacing={ 4 } alignment="bottom">
1122 <NumberControl
1123 label={ __( 'Number of columns', 'tablepress' ) }
1124 size="compact"
1125 title={ __( 'This field must contain a positive number.', 'tablepress' ) }
1126 isDragEnabled={ false }
1127 value={ columnsAppendNumber }
1128 onChange={ ( newColumnsAppendNumber ) => {
1129 newColumnsAppendNumber = '' !== newColumnsAppendNumber ? parseInt( newColumnsAppendNumber, 10 ) : 1;
1130 setColumnsAppendNumber( newColumnsAppendNumber );
1131 } }
1132 min={ 1 }
1133 required={ true }
1134 onKeyDown={ ( event ) => {
1135 if ( 'Enter' === event.key ) {
1136 event.preventDefault();
1137 tp.callbacks.append( 'columns', columnsAppendNumber );
1138 if ( ! event.shiftKey ) {
1139 setModalAddColumnsIsShown( false );
1140 }
1141 }
1142 } }
1143 />
1144 <Button
1145 variant="primary"
1146 size="compact"
1147 text={ __( 'Add', 'tablepress' ) }
1148 onClick={ ( event ) => {
1149 tp.callbacks.append( 'columns', columnsAppendNumber );
1150 if ( ! event.shiftKey ) {
1151 setModalAddColumnsIsShown( false );
1152 }
1153 } }
1154 />
1155 </HStack>
1156 </VStack>
1157 </Modal>
1158 ) }
1159 </HStack>
1160 );
1161 };
1162
1163 initializeReactComponentInPortal(
1164 'table-editor-toolbar',
1165 'edit',
1166 Section,
1167 );
1168