PluginProbe
TablePress – Tables in WordPress made easy / 3.3.3
TablePress – Tables in WordPress made easy v3.3.3
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 / table-manipulation.js

table-manipulation.js in TablePress – Tables in WordPress made easy 3.3.3, at admin/js/edit/table-manipulation.js

421 lines 14.1 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 "Table Manipulation" buttons.
3 *
4 * @package TablePress
5 * @subpackage Views JavaScript
6 * @author Tobias Bäthge
7 * @since 3.0.0
8 */
9
10 /**
11 * WordPress dependencies.
12 */
13 import { useState } from 'react';
14 import {
15 Button,
16 __experimentalHStack as HStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis
17 __experimentalNumberControl as NumberControl, // eslint-disable-line @wordpress/no-unsafe-wp-apis
18 __experimentalVStack as VStack, // eslint-disable-line @wordpress/no-unsafe-wp-apis
19 } from '@wordpress/components';
20 import { createInterpolateElement, RawHTML } from '@wordpress/element';
21 import { __, sprintf } from '@wordpress/i18n';
22 import { displayShortcut, shortcutAriaLabel } from '@wordpress/keycodes';
23
24 /**
25 * Internal dependencies.
26 */
27 import { initializeReactComponentInPortal } from '../common/react-loader';
28 import { Alert } from '../common/alert';
29 import { HelpBox } from '../common/help';
30
31 const Section = () => {
32 const [ columnsAppendNumber, setColumnsAppendNumber ] = useState( 1 );
33 const [ rowsAppendNumber, setRowsAppendNumber ] = useState( 1 );
34 const [ alertMoveInvalidIsShown, setAlertMoveInvalidIsShown ] = useState( false );
35 const [ alertDeleteRowsInvalidIsShown, setAlertDeleteRowsInvalidIsShown ] = useState( false );
36 const [ alertDeleteColumnsInvalidIsShown, setAlertDeleteColumnsInvalidIsShown ] = useState( false );
37
38 const move = ( direction, type ) => {
39 if ( ! tp.helpers.move_allowed( type, direction ) ) {
40 setAlertMoveInvalidIsShown( true );
41 return;
42 }
43 tp.callbacks.move( direction, type );
44 };
45
46 const remove = ( type ) => {
47 const handlingRows = ( 'rows' === type );
48 const numRoCs = handlingRows ? tp.editor.options.data.length : tp.editor.options.columns.length;
49 if ( numRoCs === tp.helpers.selection[ type ].length ) {
50 if ( handlingRows ) {
51 setAlertDeleteRowsInvalidIsShown( true );
52 } else {
53 setAlertDeleteColumnsInvalidIsShown( true );
54 }
55 return;
56 }
57 tp.callbacks.remove( type );
58 };
59
60 return (
61 <VStack
62 spacing="16px"
63 style={ {
64 paddingTop: '6px',
65 } }
66 >
67 <table className="tablepress-postbox-table fixed">
68 <tbody>
69 <tr className="bottom-border">
70 <td className="column-1">
71 <HStack alignment="left">
72 <span>{ __( 'Selected cells', 'tablepress' ) }:</span>
73 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
74 <Button
75 variant="secondary"
76 size="compact"
77 text={ __( 'Insert Link', 'tablepress' ) }
78 shortcut={ {
79 ariaLabel: shortcutAriaLabel.primary( 'l' ),
80 display: displayShortcut.primary( 'l' ),
81 } }
82 onClick={ () => tp.callbacks.insert_link.open_dialog() }
83 />
84 <Button
85 variant="secondary"
86 size="compact"
87 text={ __( 'Insert Image', 'tablepress' ) }
88 shortcut={ {
89 ariaLabel: shortcutAriaLabel.primary( 'i' ),
90 display: displayShortcut.primary( 'i' ),
91 } }
92 onClick={ () => tp.callbacks.insert_image.open_dialog() }
93 />
94 <Button
95 variant="secondary"
96 size="compact"
97 text={ __( 'Advanced Editor', 'tablepress' ) }
98 shortcut={ {
99 ariaLabel: shortcutAriaLabel.primary( 'e' ),
100 display: displayShortcut.primary( 'e' ),
101 } }
102 onClick={ () => tp.callbacks.advanced_editor.open_dialog() }
103 />
104 </HStack>
105 </HStack>
106 </td>
107 <td className="column-2">
108 <HStack alignment="left">
109 <span>{ __( 'Selected cells', 'tablepress' ) }:</span>
110 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
111 <Button
112 variant="secondary"
113 size="compact"
114 text={ __( 'Combine/Merge', 'tablepress' ) }
115 onClick={ () => {
116 if ( tp.helpers.cell_merge_allowed( 'alert' ) ) {
117 tp.callbacks.merge_cells();
118 }
119 } }
120 />
121 <HelpBox
122 buttonProps={ {
123 size: 'compact',
124 label: __( 'Help on combining cells', 'tablepress' ),
125 } }
126 modalProps={ {
127 size: 'medium',
128 } }
129 title={ __( 'Help on combining cells', 'tablepress' ) }
130 >
131 <p>
132 { __( 'Table cells can span across more than one column or row.', 'tablepress' ) }
133 </p>
134 <RawHTML>
135 { '<p>' }
136 { __( 'Combining consecutive cells within the same row is called &#8220;colspanning&#8221;.', 'tablepress' ) }
137 { ' ' + __( 'Combining consecutive cells within the same column is called &#8220;rowspanning&#8221;.', 'tablepress' ) }
138 { '</p>' }
139 </RawHTML>
140 <RawHTML>
141 { '<p>' }
142 { sprintf( __( 'To combine adjacent cells, select the desired cells and click the “%s” button or use the context menu.', 'tablepress' ), __( 'Combine/Merge', 'tablepress' ) ) }
143 { ' ' + __( 'The corresponding keywords, <code>#colspan#</code> and <code>#rowspan#</code>, will then be added for you.', 'tablepress' ) }
144 { '</p>' }
145 </RawHTML>
146 <p>
147 <strong>
148 { __( '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' ) }
149 </strong>
150 { ' ' }
151 { __( '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' ) }
152 </p>
153 </HelpBox>
154 </HStack>
155 </HStack>
156 </td>
157 </tr>
158 <tr className="top-border">
159 <td className="column-1">
160 <HStack alignment="left">
161 <span>{ __( 'Selected rows', 'tablepress' ) }:</span>
162 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
163 <Button
164 variant="secondary"
165 size="compact"
166 text={ __( 'Duplicate', 'tablepress' ) }
167 onClick={ () => tp.callbacks.insert_duplicate( 'duplicate', 'rows' ) }
168 />
169 <Button
170 variant="secondary"
171 size="compact"
172 text={ __( 'Insert', 'tablepress' ) }
173 onClick={ () => tp.callbacks.insert_duplicate( 'insert', 'rows' ) }
174 />
175 <Button
176 variant="secondary"
177 size="compact"
178 text={ __( 'Delete', 'tablepress' ) }
179 onClick={ () => remove( 'rows' ) }
180 />
181 </HStack>
182 </HStack>
183 </td>
184 <td className="column-2">
185 <HStack alignment="left">
186 <span>{ __( 'Selected columns', 'tablepress' ) }:</span>
187 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
188 <Button
189 variant="secondary"
190 size="compact"
191 text={ __( 'Duplicate', 'tablepress' ) }
192 onClick={ () => tp.callbacks.insert_duplicate( 'duplicate', 'columns' ) }
193 />
194 <Button
195 variant="secondary"
196 size="compact"
197 text={ __( 'Insert', 'tablepress' ) }
198 onClick={ () => tp.callbacks.insert_duplicate( 'insert', 'columns' ) }
199 />
200 <Button
201 variant="secondary"
202 size="compact"
203 text={ __( 'Delete', 'tablepress' ) }
204 onClick={ () => remove( 'columns' ) }
205 />
206 </HStack>
207 </HStack>
208 </td>
209 </tr>
210 <tr>
211 <td className="column-1">
212 <HStack alignment="left">
213 <span>{ __( 'Selected rows', 'tablepress' ) }:</span>
214 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
215 <Button
216 variant="secondary"
217 size="compact"
218 text={ __( 'Move up', 'tablepress' ) }
219 shortcut={ {
220 ariaLabel: shortcutAriaLabel.primaryShift( '↑' ),
221 display: displayShortcut.primaryShift( '↑' ),
222 } }
223 onClick={ () => move( 'up', 'rows' ) }
224 />
225 <Button
226 variant="secondary"
227 size="compact"
228 text={ __( 'Move down', 'tablepress' ) }
229 shortcut={ {
230 ariaLabel: shortcutAriaLabel.primaryShift( '↓' ),
231 display: displayShortcut.primaryShift( '↓' ),
232 } }
233 onClick={ () => move( 'down', 'rows' ) }
234 />
235 </HStack>
236 </HStack>
237 </td>
238 <td className="column-2">
239 <HStack alignment="left">
240 <span>{ __( 'Selected columns', 'tablepress' ) }:</span>
241 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
242 <Button
243 variant="secondary"
244 size="compact"
245 text={ __( 'Move left', 'tablepress' ) }
246 shortcut={ {
247 ariaLabel: shortcutAriaLabel.primaryShift( '←' ),
248 display: displayShortcut.primaryShift( '←' ),
249 } }
250 onClick={ () => move( 'left', 'columns' ) }
251 />
252 <Button
253 variant="secondary"
254 size="compact"
255 text={ __( 'Move right', 'tablepress' ) }
256 shortcut={ {
257 ariaLabel: shortcutAriaLabel.primaryShift( '→' ),
258 display: displayShortcut.primaryShift( '→' ),
259 } }
260 onClick={ () => move( 'right', 'columns' ) }
261 />
262 </HStack>
263 </HStack>
264 </td>
265 </tr>
266 <tr className="bottom-border">
267 <td className="column-1">
268 <HStack alignment="left">
269 <span>{ __( 'Selected rows', 'tablepress' ) }:</span>
270 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
271 <Button
272 variant="secondary"
273 size="compact"
274 text={ __( 'Hide', 'tablepress' ) }
275 onClick={ () => tp.callbacks.hide_unhide( 'hide', 'rows' ) }
276 />
277 <Button
278 variant="secondary"
279 size="compact"
280 text={ __( 'Show', 'tablepress' ) }
281 onClick={ () => tp.callbacks.hide_unhide( 'unhide', 'rows' ) }
282 />
283 </HStack>
284 </HStack>
285 </td>
286 <td className="column-2">
287 <HStack alignment="left">
288 <span>{ __( 'Selected columns', 'tablepress' ) }:</span>
289 <HStack spacing="4px" alignment="left" expanded={ false } wrap={ true }>
290 <Button
291 variant="secondary"
292 size="compact"
293 text={ __( 'Hide', 'tablepress' ) }
294 onClick={ () => tp.callbacks.hide_unhide( 'hide', 'columns' ) }
295 />
296 <Button
297 variant="secondary"
298 size="compact"
299 text={ __( 'Show', 'tablepress' ) }
300 onClick={ () => tp.callbacks.hide_unhide( 'unhide', 'columns' ) }
301 />
302 </HStack>
303 </HStack>
304 </td>
305 </tr>
306 <tr className="top-border">
307 <td className="column-1">
308 <HStack alignment="left">
309 <label htmlFor="rows-append-number">
310 <HStack>
311 {
312 createInterpolateElement(
313 __( 'Add <input /> row(s)', 'tablepress' ),
314 {
315 input: (
316 <NumberControl
317 size="compact"
318 id="rows-append-number"
319 title={ __( 'This field must contain a positive number.', 'tablepress' ) }
320 isDragEnabled={ false }
321 value={ rowsAppendNumber }
322 onChange={ ( newRowsAppendNumber ) => {
323 newRowsAppendNumber = '' !== newRowsAppendNumber ? parseInt( newRowsAppendNumber, 10 ) : 1;
324 setRowsAppendNumber( newRowsAppendNumber )
325 } }
326 min={ 1 }
327 required={ true }
328 style={ {
329 width: '55px',
330 } }
331 />
332 ),
333 },
334 )
335 }
336 </HStack>
337 </label>
338 <Button
339 variant="secondary"
340 size="compact"
341 text={ __( 'Add', 'tablepress' ) }
342 onClick={ () => tp.callbacks.append( 'rows', rowsAppendNumber ) }
343 />
344 </HStack>
345 </td>
346 <td className="column-2">
347 <HStack alignment="left">
348 <label htmlFor="columns-append-number">
349 <HStack>
350 {
351 createInterpolateElement(
352 __( 'Add <input /> column(s)', 'tablepress' ),
353 {
354 input: (
355 <NumberControl
356 size="compact"
357 id="columns-append-number"
358 title={ __( 'This field must contain a positive number.', 'tablepress' ) }
359 isDragEnabled={ false }
360 value={ columnsAppendNumber }
361 onChange={ ( newColumnsAppendNumber ) => {
362 newColumnsAppendNumber = '' !== newColumnsAppendNumber ? parseInt( newColumnsAppendNumber, 10 ) : 1;
363 setColumnsAppendNumber( newColumnsAppendNumber )
364 } }
365 min={ 1 }
366 required={ true }
367 style={ {
368 width: '55px',
369 } }
370 />
371 ),
372 },
373 )
374 }
375 </HStack>
376 </label>
377 <Button
378 variant="secondary"
379 size="compact"
380 text={ __( 'Add', 'tablepress' ) }
381 onClick={ () => tp.callbacks.append( 'columns', columnsAppendNumber ) }
382 />
383 </HStack>
384 </td>
385 </tr>
386 </tbody>
387 </table>
388 { alertMoveInvalidIsShown && (
389 <Alert
390 title={ __( 'Table Manipulation', 'tablepress' ) }
391 text={ __( 'You can not do this move, because you reached the border of the table.', 'tablepress' ) }
392 onConfirm={ () => setAlertMoveInvalidIsShown( false ) }
393 modalProps={ {
394 size: 'small',
395 } }
396 />
397 ) }
398 { alertDeleteRowsInvalidIsShown && (
399 <Alert
400 title={ __( 'Table Manipulation', 'tablepress' ) }
401 text={ __( 'You can not delete all table rows!', 'tablepress' ) }
402 onConfirm={ () => setAlertDeleteRowsInvalidIsShown( false ) }
403 />
404 ) }
405 { alertDeleteColumnsInvalidIsShown && (
406 <Alert
407 title={ __( 'Table Manipulation', 'tablepress' ) }
408 text={ __( 'You can not delete all table columns!', 'tablepress' ) }
409 onConfirm={ () => setAlertDeleteColumnsInvalidIsShown( false ) }
410 />
411 ) }
412 </VStack>
413 );
414 };
415
416 initializeReactComponentInPortal(
417 'table-manipulation',
418 'edit',
419 Section,
420 );
421