PluginProbe
TablePress – Tables in WordPress made easy / 1.12
TablePress – Tables in WordPress made easy v1.12
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.js

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

1,270 lines 46.7 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" screen
3 *
4 * @package TablePress
5 * @subpackage Views JavaScript
6 * @author Tobias Bäthge
7 * @since 1.0.0
8 */
9
10 /* global alert, confirm, tp, tablepress_strings, tablepress_options, ajaxurl, wpLink, tb_show, wp, JSON */
11
12 // Ensure the global `tp` object exists.
13 window.tp = window.tp || {};
14
15 jQuery( document ).ready( function( $ ) {
16
17 'use strict';
18
19 /* Wrapper to find elements in the page faster with JS-native functions */
20 var $id = function( element_id ) {
21 return $( document.getElementById( element_id ) );
22 };
23
24 /**
25 * TablePress object, mostly with functionality for the "Edit" screen
26 *
27 * @since 1.0.0
28 */
29 tp.made_changes = false;
30
31 tp.table = {
32 id: $id( 'table-id' ).val(),
33 new_id: $id( 'table-new-id' ).val(),
34 rows: parseInt( $id( 'number-rows' ).val(), 10 ),
35 columns: parseInt( $id( 'number-columns' ).val(), 10 ),
36 head: $id( 'option-table-head' ).prop( 'checked' ),
37 foot: $id( 'option-table-foot' ).prop( 'checked' ),
38 no_data_columns_pre: 2,
39 no_data_columns_post: 1,
40 body_cells_pre: '<tr><td><span class="move-handle"></span></td><td><input type="checkbox" /><input type="hidden" class="visibility" name="table[visibility][rows][]" value="1" /></td>',
41 body_cells_post: '<td><span class="move-handle"></span></td></tr>',
42 body_cell: '<td><textarea rows="1"></textarea></td>',
43 head_cell: '<th class="head"><span class="sort-control sort-desc" title="' + tablepress_strings.sort_desc + '"><span class="sorting-indicator"></span></span><span class="sort-control sort-asc" title="' + tablepress_strings.sort_asc + '"><span class="sorting-indicator"></span></span><span class="move-handle"></span></th>',
44 foot_cell: '<th><input type="checkbox" /><input type="hidden" class="visibility" name="table[visibility][columns][]" value="1" /></th>',
45 set_table_changed: function() {
46 tp.made_changes = true;
47 },
48 unset_table_changed: function() {
49 tp.made_changes = false;
50 $id( 'edit-form-body' ).one( 'change', 'textarea', tp.table.set_table_changed );
51 // @TODO: maybe use .tablepress-postbox-table here and further below
52 $( '#tablepress_edit-table-information, #tablepress_edit-table-options, #tablepress_edit-datatables-features' ).one( 'change', 'input, textarea, select', tp.table.set_table_changed );
53 },
54 change_id: function( /* event */ ) {
55 // empty table IDs are not allowed
56 if ( '' === $.trim( $id( 'table-new-id' ).val() ) ) {
57 alert( tablepress_strings.table_id_not_empty );
58 $id( 'table-new-id' ).val( tp.table.new_id ).focus().select();
59 return;
60 }
61 // the '0' table ID is not allowed
62 if ( '0' === $.trim( $id( 'table-new-id' ).val() ) ) {
63 alert( tablepress_strings.table_id_not_zero );
64 $id( 'table-new-id' ).val( tp.table.new_id ).focus().select();
65 return;
66 }
67
68 if ( this.value === tp.table.new_id ) {
69 return;
70 }
71
72 if ( confirm( tablepress_strings.ays_change_table_id ) ) {
73 tp.table.new_id = this.value;
74 $( '.table-shortcode' ).val( '[' + tablepress_options.shortcode + ' id=' + tp.table.new_id + ' /]' ).click(); // click() to focus and select
75 tp.table.set_table_changed();
76 } else {
77 $(this).val( tp.table.new_id );
78 }
79 },
80 change_table_head: function( /* event */ ) {
81 tp.table.head = $(this).prop( 'checked' );
82 $id( 'option-use-datatables' ).prop( 'disabled', ! tp.table.head ).change();
83 $id( 'notice-datatables-head-row' ).toggle( ! tp.table.head );
84 tp.rows.stripe();
85 },
86 change_table_foot: function( /* event */ ) {
87 tp.table.foot = $(this).prop( 'checked' );
88 tp.rows.stripe();
89 },
90 change_print_name_description: function( /* event */ ) {
91 $id( this.id + '-position' ).prop( 'disabled', ! $(this).prop( 'checked' ) );
92 },
93 change_datatables: function() {
94 var $datatables_checkbox = $id( 'option-use-datatables' ),
95 checkboxes_disabled = ! ( $datatables_checkbox.prop( 'checked' ) && ! $datatables_checkbox.prop( 'disabled' ) );
96 $datatables_checkbox.closest( 'tbody' ).find( 'input' ).not( $datatables_checkbox ).prop( 'disabled', checkboxes_disabled );
97 tp.table.change_datatables_pagination();
98 },
99 change_datatables_pagination: function() {
100 var $pagination_checkbox = $id( 'option-datatables-paginate' ),
101 pagination_enabled = ( $pagination_checkbox.prop( 'checked' ) && ! $pagination_checkbox.prop( 'disabled' ) );
102 $id( 'option-datatables-lengthchange' ).prop( 'disabled', ! pagination_enabled );
103 $id( 'option-datatables-paginate_entries' ).prop( 'disabled', ! pagination_enabled );
104 },
105 prepare_ajax_request: function( wp_action, wp_nonce ) {
106 var $table_body = $id( 'edit-form-body' ),
107 table_data = [],
108 table_options,
109 table_number = { rows: tp.table.rows, columns: tp.table.columns, hidden_rows: 0, hidden_columns: 0 },
110 table_visibility = { rows: [], columns: [] };
111
112 $table_body.children().each( function( idx, row ) {
113 table_data[ idx ] = $( row ).find( 'textarea' )
114 .map( function() {
115 return $(this).val();
116 } )
117 .get();
118 } );
119 table_data = JSON.stringify( table_data );
120
121 // @TODO: maybe for options saving: https://stackoverflow.com/questions/1184624/convert-form-data-to-javascript-object-with-jquery
122 // or each()-loop through all checkboxes/textfields/selects
123 table_options = {
124 // Table Options
125 table_head: tp.table.head,
126 table_foot: tp.table.foot,
127 alternating_row_colors: $id( 'option-alternating-row-colors' ).prop( 'checked' ),
128 row_hover: $id( 'option-row-hover' ).prop( 'checked' ),
129 print_name: $id( 'option-print-name' ).prop( 'checked' ),
130 print_description: $id( 'option-print-description' ).prop( 'checked' ),
131 print_name_position: $id( 'option-print-name-position' ).val(),
132 print_description_position: $id( 'option-print-description-position' ).val(),
133 extra_css_classes: $id( 'option-extra-css-classes' ).val(),
134 // DataTables JS features
135 use_datatables: $id( 'option-use-datatables' ).prop( 'checked' ),
136 datatables_sort: $id( 'option-datatables-sort' ).prop( 'checked' ),
137 datatables_filter: $id( 'option-datatables-filter' ).prop( 'checked' ),
138 datatables_paginate: $id( 'option-datatables-paginate' ).prop( 'checked' ),
139 datatables_lengthchange: $id( 'option-datatables-lengthchange' ).prop( 'checked' ),
140 datatables_paginate_entries: $id( 'option-datatables-paginate_entries' ).val(),
141 datatables_info: $id( 'option-datatables-info' ).prop( 'checked' ),
142 datatables_scrollx: $id( 'option-datatables-scrollx' ).prop( 'checked' ),
143 datatables_custom_commands: $id( 'option-datatables-custom-commands' ).val()
144 };
145 table_options = JSON.stringify( table_options );
146
147 table_visibility.rows = $table_body.find( 'input[type="hidden"]' )
148 .map( function() {
149 if ( '1' === $(this).val() ) {
150 return 1;
151 }
152 table_number.hidden_rows += 1;
153 return 0;
154 } )
155 .get();
156 table_visibility.columns = $id( 'edit-form-foot' ).find( 'input[type="hidden"]' )
157 .map( function() {
158 if ( '1' === $(this).val() ) {
159 return 1;
160 }
161 table_number.hidden_columns += 1;
162 return 0;
163 } )
164 .get();
165 table_visibility = JSON.stringify( table_visibility );
166
167 // request_data =
168 return {
169 action: wp_action,
170 _ajax_nonce : $( wp_nonce ).val(),
171 tablepress: {
172 id: tp.table.id,
173 new_id: tp.table.new_id,
174 name: $id( 'table-name' ).val(),
175 description: $id( 'table-description' ).val(),
176 number: table_number,
177 data: table_data,
178 options: table_options,
179 visibility: table_visibility
180 }
181 };
182 },
183 preview: {
184 trigger: function( /* event */ ) {
185 if ( ! tp.made_changes ) {
186 tp.table.preview.show( $(this).attr( 'href' ) + '&TB_iframe=true' );
187 return false;
188 }
189
190 // validation checks
191 if ( $id( 'option-datatables-paginate' ).prop( 'checked' ) && ! ( /^[1-9][0-9]{0,4}$/ ).test( $id( 'option-datatables-paginate_entries' ).val() ) ) {
192 alert( tablepress_strings.num_pagination_entries_invalid );
193 $id( 'option-datatables-paginate_entries' ).focus().select();
194 return;
195 }
196 if ( ( /[^A-Za-z0-9- _:]/ ).test( $id( 'option-extra-css-classes' ).val() ) ) {
197 alert( tablepress_strings.extra_css_classes_invalid );
198 $id( 'option-extra-css-classes' ).focus().select();
199 return;
200 }
201
202 $(this).closest( 'p' ).append( '<span class="animation-preview spinner is-active" title="' + tablepress_strings.preparing_preview + '"/>' );
203 $( 'body' ).addClass( 'wait' );
204 $id( 'table-preview' ).empty(); // clear preview
205
206 $.ajax({
207 'type': 'POST',
208 'url': ajaxurl,
209 'data': tp.table.prepare_ajax_request( 'tablepress_preview_table', '#nonce-preview-table' ),
210 'success': tp.table.preview.ajax_success,
211 'error': tp.table.preview.ajax_error,
212 'dataType': 'json'
213 } );
214
215 return false;
216 },
217 ajax_success: function( data, status /*, jqXHR */ ) {
218 if ( ( 'undefined' === typeof status ) || ( 'success' !== status ) ) {
219 tp.table.preview.error( 'AJAX call successful, but unclear status.' );
220 } else if ( ( 'undefined' === typeof data ) || ( null === data ) || ( '-1' === data ) || ( 'undefined' === typeof data.success ) || ( true !== data.success ) ) {
221 tp.table.preview.error( 'AJAX call successful, but unclear data.' );
222 } else {
223 tp.table.preview.success( data );
224 }
225 },
226 ajax_error: function( jqXHR, status, error_thrown ) {
227 tp.table.preview.error( 'AJAX call failed: ' + status + ' - ' + error_thrown );
228 },
229 success: function( data ) {
230 $id( 'table-preview' ).empty();
231 $( '<iframe id="table-preview-iframe" />' ).load( function() {
232 var $iframe = $(this).contents();
233 $iframe.find( 'head' ).append( data.head_html );
234 $iframe.find( 'body' ).append( data.body_html );
235 } ).appendTo( '#table-preview' );
236 $( '.animation-preview' ).remove();
237 $( 'body' ).removeClass( 'wait' );
238 tp.table.preview.show( '#TB_inline?inlineId=preview-container' );
239 },
240 error: function( message ) {
241 $( '.animation-preview' ).closest( 'p' )
242 .after( '<div class="ajax-alert preview-error error"><p>' + tablepress_strings.preview_error + ': ' + message + '</p></div>' );
243 $( '.animation-preview' ).remove();
244 $( '.preview-error' ).delay( 6000 ).fadeOut( 2000, function() { $(this).remove(); } );
245 $( 'body' ).removeClass( 'wait' );
246 },
247 show: function( url ) {
248 var width = $( window ).width() - 120,
249 height = $( window ).height() - 120;
250 if ( $( '#wpadminbar' ).length ) {
251 height -= parseInt( $( '#wpadminbar' ).css( 'height' ), 10 );
252 }
253 tb_show( $( '.show-preview-button' ).first().text(), url + '&height=' + height + '&width=' + width, false );
254 }
255 }
256 };
257
258 tp.rows = {
259 create: function( num_rows ) {
260 var i, j,
261 column_idxs,
262 new_rows = '';
263
264 for ( i = 0; i < num_rows; i++ ) {
265 new_rows += tp.table.body_cells_pre;
266 for ( j = 0; j < tp.table.columns; j++ ) {
267 new_rows += tp.table.body_cell;
268 }
269 new_rows += tp.table.body_cells_post;
270 }
271
272 column_idxs = $id( 'edit-form-foot' ).find( '.column-hidden' )
273 .map( function() { return $(this).index(); } ).get();
274 return $( new_rows ).each( function( row_idx, row ) {
275 $( row ).children()
276 .filter( function( idx ) { return ( -1 !== $.inArray( idx, column_idxs ) ); } )
277 .addClass( 'column-hidden' );
278 } );
279 },
280 append: function( /* event */ ) {
281 var num_rows = $id( 'rows-append-number' ).val();
282
283 if ( ! ( /^[1-9][0-9]{0,4}$/ ).test( num_rows ) ) {
284 alert( tablepress_strings.append_num_rows_invalid );
285 $id( 'rows-append-number' ).focus().select();
286 return;
287 }
288
289 $id( 'edit-form-body' ).append( tp.rows.create( num_rows ) );
290
291 tp.rows.stripe();
292 tp.reindex();
293 },
294 insert: function( event ) {
295 var $selected_rows = $id( 'edit-form-body' ).find( 'input:checked' )
296 .prop( 'checked', event.shiftKey ).closest( 'tr' );
297
298 if ( 0 === $selected_rows.length ) {
299 alert( tablepress_strings.no_rows_selected );
300 return;
301 }
302
303 $selected_rows.before( tp.rows.create( 1 ) );
304
305 tp.rows.stripe();
306 tp.reindex();
307 },
308 duplicate: function( event ) {
309 var $selected_rows = $id( 'edit-form-body' ).find( 'input:checked' )
310 .prop( 'checked', event.shiftKey ).closest( 'tr' );
311
312 if ( 0 === $selected_rows.length ) {
313 alert( tablepress_strings.no_rows_selected );
314 return;
315 }
316
317 $selected_rows.each( function( idx, row ) {
318 var $row = $( row ),
319 $textareas = $row.find( 'textarea' ),
320 $duplicated_row = $row.clone();
321 $duplicated_row.find( 'textarea' ).removeAttr( 'id' ).each( function( idx, cell ) {
322 $( cell ).val( $textareas.eq( idx ).val() ); // setting val() is necessary, as clone() doesn't copy the current value, see jQuery bugs 5524, 2285, 3016
323 } );
324 $row.after( $duplicated_row );
325 } );
326
327 tp.rows.stripe();
328 tp.reindex();
329 },
330 hide: function( event ) {
331 var $selected_rows = $id( 'edit-form-body' ).find( 'input:checked' )
332 .prop( 'checked', event.shiftKey ).closest( 'tr' );
333
334 if ( 0 === $selected_rows.length ) {
335 alert( tablepress_strings.no_rows_selected );
336 return;
337 }
338
339 $selected_rows.addClass( 'row-hidden' ).find( '.visibility' ).val( '0' );
340
341 tp.rows.stripe();
342 tp.table.set_table_changed();
343 },
344 unhide: function( event ) {
345 var $selected_rows = $id( 'edit-form-body' ).find( 'input:checked' )
346 .prop( 'checked', event.shiftKey ).closest( 'tr' );
347
348 if ( 0 === $selected_rows.length ) {
349 alert( tablepress_strings.no_rows_selected );
350 return;
351 }
352
353 $selected_rows.removeClass( 'row-hidden' ).find( '.visibility' ).val( '1' );
354
355 tp.rows.stripe();
356 tp.table.set_table_changed();
357 },
358 remove: function( /* event */ ) {
359 var confirm_message,
360 $selected_rows = $id( 'edit-form-body' ).find( 'input:checked' ).closest( 'tr' );
361
362 if ( 0 === $selected_rows.length ) {
363 alert( tablepress_strings.no_rows_selected );
364 return;
365 }
366
367 if ( tp.table.rows === $selected_rows.length ) {
368 alert( tablepress_strings.no_remove_all_rows );
369 return;
370 }
371
372 if ( 1 === $selected_rows.length ) {
373 confirm_message = tablepress_strings.ays_remove_rows_singular;
374 } else {
375 confirm_message = tablepress_strings.ays_remove_rows_plural;
376 }
377 if ( ! confirm( confirm_message ) ) {
378 return;
379 }
380
381 $selected_rows.remove();
382
383 tp.rows.stripe();
384 tp.reindex();
385 },
386 move: {
387 start: function( event, ui ) {
388 $( ui.placeholder ).removeClass( 'row-hidden' ).css( 'visibility', 'visible' )
389 .html( '<td colspan="' + ( tp.table.columns + tp.table.no_data_columns_pre + tp.table.no_data_columns_post ) + '"><div/></td>' );
390 $( ui.helper ).removeClass( 'odd head-row foot-row' );
391 },
392 change: function( event, ui ) {
393 tp.rows.stripe( ui.helper );
394 },
395 stop: function( /* event, ui */ ) {
396 tp.rows.stripe();
397 }
398 },
399 sort: function() {
400 var column_idx = $(this).parent().index(),
401 direction = ( $(this).hasClass( 'sort-asc' ) ) ? 1 : -1,
402 $table_body = $('#edit-form-body'),
403 $head_rows = $table_body.find( '.head-row' ).prevAll().addBack(),
404 $foot_rows = $table_body.find( '.foot-row' ).nextAll().addBack(),
405 rows = $table_body.children().not( $head_rows ).not( $foot_rows ).get(),
406 /*
407 * Natural Sort algorithm for Javascript - Version 0.8.1 - Released under MIT license
408 * Author: Jim Palmer (based on chunking idea from Dave Koelle)
409 * See: https://github.com/overset/javascript-natural-sort and http://www.overset.com/2008/09/01/javascript-natural-sort-algorithm-with-unicode-support/
410 */
411 natural_sort = function( a, b ) {
412 var re = /(^([+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|^0x[\da-fA-F]+$|\d+)/g,
413 sre = /^\s+|\s+$/g, // trim pre-post whitespace
414 snre = /\s+/g, // normalize all whitespace to single ' ' character
415 dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
416 hre = /^0x[0-9a-f]+$/i,
417 ore = /^0/,
418 // strip whitespace
419 x = a.replace(sre, '') || '',
420 y = b.replace(sre, '') || '',
421 // chunk/tokenize
422 xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
423 yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
424 // numeric, hex or date detection
425 xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && Date.parse(x)),
426 yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null,
427 normChunk = function(s, l) {
428 // normalize spaces; find floats not starting with '0', string or 0 if not defined (Clint Priest)
429 return (!s.match(ore) || l === 1) && parseFloat(s) || s.replace(snre, ' ').replace(sre, '') || 0;
430 },
431 oFxNcL, oFyNcL;
432 // first try and sort Hex codes or Dates
433 if (yD) {
434 if (xD < yD) { return -1; }
435 else if (xD > yD) { return 1; }
436 }
437 // natural sorting through split numeric strings and default strings
438 for(var cLoc = 0, xNl = xN.length, yNl = yN.length, numS = Math.max(xNl, yNl); cLoc < numS; cLoc++) {
439 oFxNcL = normChunk(xN[cLoc] || '', xNl);
440 oFyNcL = normChunk(yN[cLoc] || '', yNl);
441 // handle numeric vs string comparison - number < string - (Kyle Adams)
442 if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
443 return isNaN(oFxNcL) ? 1 : -1;
444 }
445 // if unicode use locale comparison
446 if (/[^\x00-\x80]/.test(oFxNcL + oFyNcL) && oFxNcL.localeCompare) {
447 var comp = oFxNcL.localeCompare(oFyNcL);
448 return comp / Math.abs(comp);
449 }
450 if (oFxNcL < oFyNcL) { return -1; }
451 else if (oFxNcL > oFyNcL) { return 1; }
452 }
453 };
454
455 $.each( rows, function( row_idx, row ) {
456 row.sort_key = ( '' + $( row ).children().eq( column_idx ).find( 'textarea' ).val() ).toLowerCase(); // convert to string, and lower case for case insensitive sorting
457 } );
458
459 rows.sort( function( a, b ) {
460 return direction * natural_sort( a.sort_key, b.sort_key );
461 } );
462
463 // might not be necessary:
464 $.each( rows, function( row_idx, row ) {
465 row.sort_key = null;
466 } );
467
468 $table_body.append( $head_rows );
469 $table_body.append( rows );
470 $table_body.append( $foot_rows );
471
472 tp.rows.stripe();
473 tp.reindex();
474 },
475 stripe: function( helper ) {
476 if ( 'undefined' === typeof helper ) {
477 helper = null;
478 }
479 helper = $( helper );
480 var $rows = $id( 'edit-form-body' ).children().removeClass( 'odd head-row foot-row' ).not( helper );
481 $rows.filter( ':even' ).addClass( 'odd' );
482 $rows = $rows.not( '.row-hidden' );
483 if ( helper.hasClass( 'row-hidden' ) ) {
484 $rows = $rows.not( '.ui-sortable-placeholder' );
485 }
486 if ( tp.table.head ) {
487 $rows.first().addClass( 'head-row' );
488 }
489 if ( tp.table.foot ) {
490 $rows.last().addClass( 'foot-row' );
491 }
492 }
493 };
494
495 tp.columns = {
496 append: function( /* event */ ) {
497 var i,
498 num_columns = $id( 'columns-append-number' ).val(),
499 new_head_cells = '', new_body_cells = '', new_foot_cells = '';
500
501 if ( ! ( /^[1-9][0-9]{0,4}$/ ).test( num_columns ) ) {
502 alert( tablepress_strings.append_num_columns_invalid );
503 $id( 'columns-append-number' ).focus().select();
504 return;
505 }
506
507 for ( i = 0; i < num_columns; i++ ) {
508 new_body_cells += tp.table.body_cell;
509 new_head_cells += tp.table.head_cell;
510 new_foot_cells += tp.table.foot_cell;
511 }
512
513 $id( 'edit-form-body' ).children().each( function( row_idx, row ) {
514 $( row ).children().slice( - tp.table.no_data_columns_post )
515 .before( new_body_cells );
516 } );
517 $id( 'edit-form-head' ).children().slice( - tp.table.no_data_columns_post )
518 .before( new_head_cells );
519 $id( 'edit-form-foot' ).children().slice( - tp.table.no_data_columns_post )
520 .before( new_foot_cells );
521
522 tp.reindex();
523 },
524 insert: function( event ) {
525 var column_idxs,
526 $selected_columns = $id( 'edit-form-foot' ).find( 'input:checked' )
527 .prop( 'checked', event.shiftKey ).closest( 'th' );
528
529 if ( 0 === $selected_columns.length ) {
530 alert( tablepress_strings.no_columns_selected );
531 return;
532 }
533
534 column_idxs = $selected_columns.map( function() { return $(this).index(); } ).get();
535 $id( 'edit-form-body' ).children().each( function( row_idx, row ) {
536 $( row ).children()
537 .filter( function( idx ) { return ( -1 !== $.inArray( idx, column_idxs ) ); } )
538 .before( tp.table.body_cell );
539 } );
540 $id( 'edit-form-head' ).children()
541 .filter( function( idx ) { return ( -1 !== $.inArray( idx, column_idxs ) ); } )
542 .before( tp.table.head_cell );
543 $selected_columns.before( tp.table.foot_cell );
544
545 tp.reindex();
546 },
547 duplicate: function( event ) {
548 var column_idxs,
549 $selected_columns = $id( 'edit-form-foot' ).find( 'input:checked' )
550 .prop( 'checked', event.shiftKey ).closest( 'th' );
551
552 if ( 0 === $selected_columns.length ) {
553 alert( tablepress_strings.no_columns_selected );
554 return;
555 }
556
557 column_idxs = $selected_columns.map( function() { return $(this).index(); } ).get();
558 $id( 'edit-form' ).find( 'tr' ).each( function( row_idx, row ) {
559 $( row ).children().each( function( idx, cell ) {
560 if ( -1 !== $.inArray( idx, column_idxs ) ) {
561 var $cell = $( cell ),
562 $duplicated_cell = $cell.clone();
563 $duplicated_cell.find( 'textarea' ).removeAttr( 'id' ).val( $cell.find( 'textarea' ).val() ); // setting val() is necessary, as clone() doesn't copy the current value, see jQuery bugs 5524, 2285, 3016
564 $cell.after( $duplicated_cell );
565 }
566 } );
567 } );
568
569 tp.reindex();
570 },
571 hide: function( event ) {
572 var column_idxs,
573 $selected_columns = $id( 'edit-form-foot' ).find( 'input:checked' )
574 .prop( 'checked', event.shiftKey ).closest( 'th' );
575
576 if ( 0 === $selected_columns.length ) {
577 alert( tablepress_strings.no_columns_selected );
578 return;
579 }
580
581 column_idxs = $selected_columns.map( function() { return $(this).index(); } ).get();
582 $id( 'edit-form-body' ).children().add( '#edit-form-head' ).each( function( row_idx, row ) {
583 $( row ).children()
584 .filter( function( idx ) { return ( -1 !== $.inArray( idx, column_idxs ) ); } )
585 .addClass( 'column-hidden' );
586 } );
587 $selected_columns.addClass( 'column-hidden' ).find( '.visibility' ).val( '0' );
588
589 tp.table.set_table_changed();
590 },
591 unhide: function( event ) {
592 var column_idxs,
593 $selected_columns = $id( 'edit-form-foot' ).find( 'input:checked' )
594 .prop( 'checked', event.shiftKey ).closest( 'th' );
595
596 if ( 0 === $selected_columns.length ) {
597 alert( tablepress_strings.no_columns_selected );
598 return;
599 }
600
601 column_idxs = $selected_columns.map( function() { return $(this).index(); } ).get();
602 $id( 'edit-form-body' ).children().add( '#edit-form-head' ).each( function( row_idx, row ) {
603 $( row ).children()
604 .filter( function( idx ) { return ( -1 !== $.inArray( idx, column_idxs ) ); } )
605 .removeClass( 'column-hidden' );
606 } );
607 $selected_columns.removeClass( 'column-hidden' ).find( '.visibility' ).val( '1' );
608
609 tp.table.set_table_changed();
610 },
611 remove: function( /* event */ ) {
612 var column_idxs,
613 confirm_message,
614 $selected_columns = $id( 'edit-form-foot' ).find( 'input:checked' ).closest( 'th' );
615
616 if ( 0 === $selected_columns.length ) {
617 alert( tablepress_strings.no_columns_selected );
618 return;
619 }
620
621 if ( tp.table.columns === $selected_columns.length ) {
622 alert( tablepress_strings.no_remove_all_columns );
623 return;
624 }
625
626 if ( 1 === $selected_columns.length ) {
627 confirm_message = tablepress_strings.ays_remove_columns_singular;
628 } else {
629 confirm_message = tablepress_strings.ays_remove_columns_plural;
630 }
631 if ( ! confirm( confirm_message ) ) {
632 return;
633 }
634
635 column_idxs = $selected_columns.map( function() { return $(this).index(); } ).get();
636 $id( 'edit-form-body' ).children().add( '#edit-form-head' ).each( function( row_idx, row ) {
637 $( row ).children()
638 .filter( function( idx ) { return ( -1 !== $.inArray( idx, column_idxs ) ); } )
639 .remove();
640 } );
641 $selected_columns.remove();
642
643 tp.reindex();
644 },
645 move: {
646 source_idx: -1,
647 target_idx: -1,
648 $rows: null,
649 $row_children: null,
650 $cell: null,
651 $cells: null,
652 $placeholder: null,
653 $helper: null,
654 start: function( event, ui ) {
655 var $item = $( ui.item ),
656 column_width;
657
658 tp.columns.move.source_idx = $item.index();
659
660 tp.columns.move.$rows = $id( 'edit-form-body' ).children().add( '#edit-form-foot' );
661
662 tp.columns.move.$cells = tp.columns.move.$rows
663 .children( ':nth-child(' + ( tp.columns.move.source_idx + 1 ) + ')' )
664 .each( function() {
665 tp.columns.move.$cell = $(this);
666 $( '<td class="move-placeholder"><div/></td>' ).insertBefore( tp.columns.move.$cell );
667 tp.columns.move.$cell.insertAfter( tp.columns.move.$cell.nextAll().last() )
668 .clone().addClass( 'move-hover' ).insertAfter( tp.columns.move.$cell )
669 .find( 'textarea' ).val( tp.columns.move.$cell.find( 'textarea' ).val() );
670 // last line works around problem with clone() of textareas, see jQuery bugs 5524, 2285, 3016
671 } )
672 .hide();
673
674 tp.columns.move.$helper = tp.columns.move.$rows.find( '.move-hover' );
675 /* // seems not to be working for rows, so disable it for columns
676 .each( function() {
677 tp.columns.move.$cell = $(this);
678 tp.columns.move.$cell.css( 'top', ( tp.columns.move.$cell.position().top - 3 ) + 'px' );
679 } );
680 */
681
682 column_width = tp.columns.move.$helper.eq(1).width(); // eq(0) is table foot
683 tp.columns.move.$helper.eq(0).width( column_width );
684 tp.columns.move.$placeholder = tp.columns.move.$rows.find( '.move-placeholder' );
685 tp.columns.move.$placeholder.find( 'div' ).width( column_width );
686 },
687 change: function( event, ui ) {
688 tp.columns.move.target_idx = $( ui.placeholder ).index();
689
690 if ( ( tp.columns.move.target_idx - tp.columns.move.source_idx ) === 1 ) {
691 tp.columns.move.target_idx += 1;
692 } else {
693 if ( tp.columns.move.target_idx === tp.columns.move.source_idx ) {
694 tp.columns.move.target_idx -= 1;
695 }
696 }
697
698 tp.columns.move.$placeholder.each( function() {
699 tp.columns.move.$cell = $(this);
700 tp.columns.move.$cell.insertBefore( tp.columns.move.$cell.parent().children().eq( tp.columns.move.target_idx ) );
701 } );
702
703 if ( tp.columns.move.target_idx > tp.columns.move.source_idx ) {
704 tp.columns.move.target_idx -= 1;
705 }
706
707 tp.columns.move.source_idx = tp.columns.move.target_idx;
708 },
709 sort: function( event, ui ) {
710 tp.columns.move.$helper.css( 'left', ui.position.left );
711 },
712 stop: function( /* event, ui */ ) {
713 tp.columns.move.$helper.remove();
714 tp.columns.move.$cells
715 .each( function() {
716 tp.columns.move.$cell = $(this);
717 tp.columns.move.$cell.insertBefore( tp.columns.move.$cell.parent().find( '.move-placeholder' ) );
718 } )
719 .show();
720 tp.columns.move.$placeholder.remove();
721
722 tp.columns.move.source_idx = tp.columns.move.target_idx = -1;
723 tp.columns.move.$rows = tp.columns.move.$row_children = tp.columns.move.$cell = tp.columns.move.$cells = tp.columns.move.$placeholder = tp.columns.move.$helper = null;
724
725 tp.reindex();
726 }
727 },
728 number_to_letter: function( number ) {
729 var column = '';
730 while ( number > 0 ) {
731 column = String.fromCharCode( 65 + ( ( number-1) % 26 ) ) + column;
732 number = Math.floor( (number-1) / 26 );
733 }
734 return column;
735 }/*,
736 letter_to_number: function( column ) {
737 column = column.toUpperCase();
738 var count = column.length,
739 number = 0,
740 i;
741 for ( i = 0; i < count; i++ ) {
742 number += ( column.charCodeAt( count-1-i ) - 64 ) * Math.pow( 26, i );
743 }
744 return number;
745 }*/
746 };
747
748 tp.cells = {
749 $focus: $( null ),
750 $textarea: null,
751 autogrow: function( /* event */ ) {
752 tp.cells.$focus.removeClass( 'focus' );
753 tp.cells.$focus = $(this).closest( 'tr' ).addClass( 'focus' );
754 },
755 advanced_editor: {
756 prompt_shown: false,
757 keyopen: function( event ) {
758 if ( ! event.shiftKey ) {
759 return;
760 }
761
762 var $advanced_editor = $id( 'advanced-editor-content' );
763 tp.cells.$textarea = $(this).blur();
764 $advanced_editor.val( tp.cells.$textarea.val() );
765 $id( 'advanced-editor' ).wpdialog( 'open' );
766 $advanced_editor.get(0).selectionStart = $advanced_editor.get(0).selectionEnd = $advanced_editor.val().length;
767 $advanced_editor.focus();
768 },
769 buttonopen: function() {
770 if ( ! tp.cells.advanced_editor.prompt_shown ) {
771 if ( ! confirm( tablepress_strings.advanced_editor_open ) ) {
772 return;
773 }
774 }
775
776 tp.cells.advanced_editor.prompt_shown = true;
777 $id( 'edit-form-body' ).one( 'click', 'textarea', function() {
778 var $advanced_editor = $id( 'advanced-editor-content' );
779 tp.cells.$textarea = $(this).blur();
780 $advanced_editor.val( tp.cells.$textarea.val() );
781 $id( 'advanced-editor' ).wpdialog( 'open' );
782 $advanced_editor.get(0).selectionStart = $advanced_editor.get(0).selectionEnd = $advanced_editor.val().length;
783 $advanced_editor.focus();
784 } );
785 },
786 save: function() {
787 var $ve_content = $id( 'advanced-editor-content' ).blur().val();
788 if ( tp.cells.$textarea.val() !== $ve_content ) {
789 tp.cells.$textarea.val( $ve_content );
790 // position cursor at the end
791 tp.cells.$textarea.get(0).selectionStart = tp.cells.$textarea.get(0).selectionEnd = tp.cells.$textarea.val().length;
792 tp.table.set_table_changed();
793 }
794 tp.cells.$textarea.focus();
795 tp.cells.advanced_editor.close();
796 },
797 close: function() {
798 $id( 'advanced-editor' ).wpdialog( 'close' );
799 return false;
800 }
801 },
802 checkboxes: {
803 last_clicked: { '#edit-form-body' : false, '#edit-form-foot' : false },
804 multi_select: function ( event ) {
805 if ( 'undefined' === event.shiftKey ) {
806 return true;
807 }
808
809 if ( event.shiftKey ) {
810 if ( ! tp.cells.checkboxes.last_clicked[ event.data.parent ] ) {
811 return true;
812 }
813
814 var $checkboxes = $( event.data.parent ).find( ':checkbox' ),
815 first_cb = $checkboxes.index( tp.cells.checkboxes.last_clicked[ event.data.parent ] ),
816 last_cb = $checkboxes.index( this );
817 if ( first_cb !== last_cb ) {
818 $checkboxes.slice( Math.min( first_cb, last_cb ), Math.max( first_cb, last_cb ) ).prop( 'checked', $(this).prop( 'checked' ) );
819 }
820 }
821 tp.cells.checkboxes.last_clicked[ event.data.parent ] = this;
822 return true;
823 }
824 }
825 };
826
827 tp.content = {
828 link: {
829 prompt_shown: false,
830 add: function( /* event */ ) {
831 if ( ! tp.content.link.prompt_shown ) {
832 if ( ! confirm( tablepress_strings.link_add ) ) {
833 return;
834 }
835 }
836
837 tp.content.link.prompt_shown = true;
838 // mousedown instead of click to allow selection of text
839 // mousedown will set the desired target textarea, and mouseup anywhere will show the link box
840 // other approaches can lead to the wrong textarea being selected
841 $id( 'edit-form-body' ).one( 'mousedown', 'textarea', function() {
842 var editor_id = this.id;
843 $( document ).one( 'mouseup', function() {
844 if ( typeof wpLink !== 'undefined' ) {
845 wpLink.open( editor_id );
846 tp.table.set_table_changed();
847 }
848 } );
849 } );
850 }
851 },
852 image: {
853 prompt_shown: false,
854 add: function( /* event */ ) {
855 if ( ! tp.content.image.prompt_shown ) {
856 if ( ! confirm( tablepress_strings.image_add ) ) {
857 return;
858 }
859 }
860
861 tp.content.image.prompt_shown = true;
862 $id( 'edit-form-body' ).one( 'click', 'textarea', function() {
863 var editor = this.id,
864 options = {
865 frame: 'post',
866 state: 'insert',
867 title: wp.media.view.l10n.addMedia,
868 multiple: true
869 };
870
871 // Move caret to the end, to prevent inserting right between existing text, as that's ugly in small cells (though possible in the Advanced Editor and Insert Link dialog).
872 this.selectionStart = this.selectionEnd = this.value.length;
873
874 // Remove focus from the textarea to prevent Opera from showing the outline of the textarea above the modal.
875 // See: WP Core #22445
876 $(this).blur();
877
878 wp.media.editor.open( editor, options );
879 tp.table.set_table_changed();
880 } );
881 }
882 },
883 span: {
884 prompt_shown: false,
885 add: function( span ) {
886 var span_add_msg = ( '#rowspan#' === span ) ? tablepress_strings.rowspan_add : tablepress_strings.colspan_add;
887
888 // init object, due to string keys
889 if ( false === tp.content.span.prompt_shown ) {
890 tp.content.span.prompt_shown = {};
891 tp.content.span.prompt_shown['#rowspan#'] = tp.content.span.prompt_shown['#colspan#'] = false;
892 }
893
894 // Automatically deactivate DataTables, if cells are combined
895 if ( $id( 'option-use-datatables' ).prop( 'checked' ) ) {
896 if ( confirm( tablepress_strings.span_add_datatables_warning ) ) {
897 $id( 'option-use-datatables' ).prop( 'checked', false ).change();
898 } else {
899 return;
900 }
901 }
902
903 if ( ! tp.content.span.prompt_shown[ span ] ) {
904 if ( ! confirm( span_add_msg ) ) {
905 return;
906 }
907 }
908
909 tp.content.span.prompt_shown[ span ] = true;
910 $id( 'edit-form-body' ).one( 'click', 'textarea', function() {
911 var $textarea = $(this),
912 col_idx = $textarea.parent().index(),
913 row_idx = $textarea.closest( 'tr' ).index();
914 if ( '#rowspan#' === span ) {
915 if ( 0 === row_idx ) {
916 alert( tablepress_strings.no_rowspan_first_row );
917 return;
918 }
919 if ( tp.table.head && 1 === row_idx ) {
920 alert( tablepress_strings.no_rowspan_table_head );
921 return;
922 }
923 if ( tp.table.foot && ( tp.table.rows - 1 ) === row_idx ) {
924 alert( tablepress_strings.no_rowspan_table_foot );
925 return;
926 }
927 } else if ( ( '#colspan#' === span ) && ( tp.table.no_data_columns_pre === col_idx ) ) {
928 alert( tablepress_strings.no_colspan_first_col );
929 return;
930 }
931 $textarea.val( span );
932 tp.table.set_table_changed();
933 } );
934 }
935 }
936 };
937
938 tp.check = {
939 table_id: function( event ) {
940 if ( ( 37 === event.which ) || ( 39 === event.which ) ) {
941 return;
942 }
943 var $input = $(this);
944 $input.val( $input.val().replace( /[^0-9a-zA-Z-_]/g, '' ) );
945 },
946 changes_saved: function() {
947 if ( tp.made_changes ) {
948 return tablepress_strings.unsaved_changes_unload;
949 }
950 }
951 };
952
953 tp.reindex = function() {
954 var $row,
955 $rows = $id( 'edit-form-body' ).children(),
956 $cell, known_references = {};
957
958 tp.table.rows = $rows.length;
959 if ( tp.table.rows > 0 ) {
960 tp.table.columns = $rows.first().children().length - tp.table.no_data_columns_pre - tp.table.no_data_columns_post;
961 } else {
962 tp.table.columns = 0;
963 }
964
965 $rows
966 .each( function( row_idx, row ) {
967 $row = $( row );
968 $row.find( 'textarea' )
969 .val( function( column_idx, value ) {
970 // If the cell is not a formula, there's nothing to do here
971 if ( ( '' === value ) || ( '=' !== value.charAt(0) ) ) {
972 return value;
973 }
974
975 return value.replace( /([A-Z]+[0-9]+)(?::([A-Z]+[0-9]+))?/g, function( full_match, first_cell, second_cell ) {
976 // first_cell must always exist, while second_cell only exists in ranges like A4:B7
977 // we will use full_match as our result variable, so that we don't need an extra one
978
979 if ( ! known_references.hasOwnProperty( first_cell ) ) {
980 $cell = $id( 'cell-' + first_cell );
981 if ( $cell.length ) {
982 known_references[ first_cell ] = tp.columns.number_to_letter( $cell.parent().index() - tp.table.no_data_columns_pre + 1 ) + ( $cell.closest( 'tr' ).index() + 1 );
983 } else {
984 known_references[ first_cell ] = first_cell;
985 }
986 }
987 full_match = known_references[ first_cell ];
988
989 if ( ( 'undefined' !== typeof second_cell ) && ( '' !== second_cell ) ) { // Chrome and IE pass an undefined variable, while Firefox passes an empty string
990 if ( ! known_references.hasOwnProperty( second_cell ) ) {
991 $cell = $id( 'cell-' + second_cell );
992 if ( $cell.length ) {
993 known_references[ second_cell ] = tp.columns.number_to_letter( $cell.parent().index() - tp.table.no_data_columns_pre + 1 ) + ( $cell.closest( 'tr' ).index() + 1 );
994 } else {
995 known_references[ second_cell ] = second_cell;
996 }
997 }
998 full_match += ':' + known_references[ second_cell ];
999 }
1000
1001 return full_match;
1002 } );
1003 } )
1004 .attr( 'name', function( column_idx /*, old_name */ ) {
1005 return 'table[data][' + row_idx + '][' + column_idx + ']';
1006 } );
1007
1008 $row.find( '.move-handle' ).html( row_idx + 1 );
1009 } )
1010 .each( function( row_idx, row ) { // need a second loop here to not break logic in previous loop, that queries textareas by their old ID
1011 $( row ).find( 'textarea' ).attr( 'id', function( column_idx /*, old_id */ ) {
1012 return 'cell-' + tp.columns.number_to_letter( column_idx + 1 ) + ( row_idx + 1 );
1013 } );
1014 });
1015 $id( 'edit-form-head' ).find( '.move-handle' )
1016 .html( function( idx ) { return tp.columns.number_to_letter( idx + 1 ); } );
1017
1018 $id( 'number-rows' ).val( tp.table.rows );
1019 $id( 'number-columns' ).val( tp.table.columns );
1020
1021 tp.table.set_table_changed();
1022 };
1023
1024 tp.save_changes = {
1025 trigger: function( event ) {
1026 // validation checks
1027 if ( $id( 'option-datatables-paginate' ).prop( 'checked' ) && ! ( /^[1-9][0-9]{0,4}$/ ).test( $id( 'option-datatables-paginate_entries' ).val() ) ) {
1028 alert( tablepress_strings.num_pagination_entries_invalid );
1029 $id( 'option-datatables-paginate_entries' ).focus().select();
1030 return;
1031 }
1032 if ( ( /[^A-Za-z0-9- _:]/ ).test( $id( 'option-extra-css-classes' ).val() ) ) {
1033 alert( tablepress_strings.extra_css_classes_invalid );
1034 $id( 'option-extra-css-classes' ).focus().select();
1035 return;
1036 }
1037
1038 if ( event.shiftKey ) {
1039 tp.made_changes = false; // to prevent onunload warning
1040 $id( 'tablepress-page' ).find( 'form' ).submit();
1041 return;
1042 }
1043
1044 $(this).closest( 'p' ).append( '<span class="animation-saving spinner is-active" title="' + tablepress_strings.saving_changes + '"/>' );
1045 $( '.save-changes-button' ).prop( 'disabled', true );
1046 $( 'body' ).addClass( 'wait' );
1047
1048 $.ajax({
1049 'type': 'POST',
1050 'url': ajaxurl,
1051 'data': tp.table.prepare_ajax_request( 'tablepress_save_table', '#nonce-edit-table' ),
1052 'success': tp.save_changes.ajax_success,
1053 'error': tp.save_changes.ajax_error,
1054 'dataType': 'json'
1055 } );
1056 },
1057 ajax_success: function( data, status /*, jqXHR */ ) {
1058 if ( ( 'undefined' === typeof status ) || ( 'success' !== status ) ) {
1059 tp.save_changes.error( 'AJAX call successful, but unclear status. Try again while holding down the &#8220;Shift&#8221; key.' );
1060 } else if ( ( 'undefined' === typeof data ) || ( null === data ) || ( '-1' === data ) || ( 'undefined' === typeof data.success ) ) {
1061 tp.save_changes.error( 'AJAX call successful, but unclear data. Try again while holding down the &#8220;Shift&#8221; key.' );
1062 } else if ( true !== data.success ) {
1063 var debug_html = '';
1064 // Print debug information, if we are in debug mode
1065 if ( ( 'undefined' !== typeof data.error_details ) && ( tablepress_options.print_debug_output ) ) {
1066 debug_html = '</p><p>These errors were encountered:</p><pre>' + data.error_details + '</pre><p>'; // Some HTML magic because this is wrapped in <p> when printed
1067 }
1068 tp.save_changes.error( 'AJAX call successful, internal saving process failed. Try again while holding down the &#8220;Shift&#8221; key.' + debug_html );
1069 } else {
1070 tp.save_changes.success( data );
1071 }
1072 },
1073 ajax_error: function( jqXHR, status, error_thrown ) {
1074 tp.save_changes.error( 'AJAX call failed: ' + status + ' - ' + error_thrown + '. Try again while holding down the &#8220;Shift&#8221; key.' );
1075 },
1076 success: function( data ) {
1077 // saving was successful, so the original ID has changed to the (maybe) new ID -> we need to adjust all occurrences
1078 if ( tp.table.id !== data.table_id ) {
1079 // update URL (for HTML5 browsers only), but only if ID really changed, to not get dummy entries in the browser history
1080 if ( ( 'pushState' in window.history ) && null !== window.history.pushState ) {
1081 window.history.pushState( '', '', window.location.href.replace( /table_id=[0-9a-zA-Z-_]+/gi, 'table_id=' + data.table_id ) );
1082 }
1083 }
1084 // update CSS class for data field form
1085 $id( 'edit-form' ).removeClass( 'tablepress-edit-screen-id-' + tp.table.id ).addClass( 'tablepress-edit-screen-id-' + data.table_id );
1086 // update table ID in input fields (type text and hidden)
1087 tp.table.id = tp.table.new_id = data.table_id;
1088 $id( 'table-id' ).val( tp.table.id );
1089 $id( 'table-new-id' ).val( tp.table.new_id );
1090 // update the Shortcode text field
1091 $( '.table-shortcode' ).val( '[' + tablepress_options.shortcode + ' id=' + tp.table.new_id + ' /]' );
1092 // update the nonces
1093 $id( 'nonce-edit-table' ).val( data.new_edit_nonce );
1094 $id( 'nonce-preview-table' ).val( data.new_preview_nonce );
1095 // update URLs in Preview links
1096 var $show_preview_buttons = $( '.show-preview-button' );
1097 if ( $show_preview_buttons.length ) { // check necessary, because Preview button might not be visible
1098 $show_preview_buttons.attr( 'href',
1099 $show_preview_buttons.first().attr( 'href' )
1100 .replace( /item=[a-zA-Z0-9_-]+/g, 'item=' + data.table_id )
1101 .replace( /&_wpnonce=[a-z0-9]+/ig, '&_wpnonce=' + data.new_preview_nonce )
1102 );
1103 }
1104 // update last modified date and user nickname
1105 $id( 'last-modified' ).text( data.last_modified );
1106 $id( 'last-editor' ).text( data.last_editor );
1107 tp.table.unset_table_changed();
1108 tp.save_changes.after_saving_dialog( 'success', tablepress_strings[ data.message ] );
1109 },
1110 error: function( message ) {
1111 tp.save_changes.after_saving_dialog( 'error', message );
1112 },
1113 after_saving_dialog: function( type, message ) {
1114 if ( 'undefined' === typeof message ) {
1115 message = '';
1116 } else {
1117 message = ': ' + message;
1118 }
1119 var delay,
1120 div_class = 'save-changes-' + type;
1121 if ( 'success' === type ) {
1122 div_class += ' notice notice-success';
1123 delay = 3000;
1124 } else {
1125 div_class += ' notice notice-error';
1126 delay = 6000;
1127 }
1128 $( '.animation-saving' ).closest( 'p' )
1129 .after( '<div class="ajax-alert ' + div_class + '"><p>' + tablepress_strings['save_changes_' + type] + message + '</p></div>' );
1130 $( '.animation-saving' ).remove();
1131 $( '.save-changes-' + type ).delay( delay ).fadeOut( 2000, function() { $(this).remove(); } );
1132 $( '.save-changes-button' ).prop( 'disabled', false );
1133 $( 'body' ).removeClass( 'wait' );
1134 }
1135 };
1136
1137 tp.init = function() {
1138 var callbacks = {
1139 'click': {
1140 '#rows-insert': tp.rows.insert,
1141 '#columns-insert': tp.columns.insert,
1142 '#rows-duplicate': tp.rows.duplicate,
1143 '#columns-duplicate': tp.columns.duplicate,
1144 '#rows-remove': tp.rows.remove,
1145 '#columns-remove': tp.columns.remove,
1146 '#rows-hide': tp.rows.hide,
1147 '#columns-hide': tp.columns.hide,
1148 '#rows-unhide': tp.rows.unhide,
1149 '#columns-unhide': tp.columns.unhide,
1150 '#rows-append': tp.rows.append,
1151 '#columns-append': tp.columns.append,
1152 '#link-add': tp.content.link.add,
1153 '#image-add': tp.content.image.add,
1154 '#span-add-rowspan': function() { tp.content.span.add( '#rowspan#' ); },
1155 '#span-add-colspan': function() { tp.content.span.add( '#colspan#' ); },
1156 '.show-preview-button': tp.table.preview.trigger,
1157 '.save-changes-button': tp.save_changes.trigger,
1158 '.show-help-box': function() {
1159 $(this).next().wpdialog( {
1160 title: $(this).attr( 'title' ),
1161 height: 470,
1162 width: 320,
1163 modal: true,
1164 dialogClass: 'wp-dialog',
1165 resizable: false
1166 } );
1167 }
1168 },
1169 'keyup': {
1170 '#table-new-id': tp.check.table_id
1171 },
1172 'change': {
1173 '#option-table-head': tp.table.change_table_head,
1174 '#option-table-foot': tp.table.change_table_foot,
1175 '#option-use-datatables': tp.table.change_datatables,
1176 '#option-datatables-paginate': tp.table.change_datatables_pagination
1177 },
1178 'blur': {
1179 '#table-new-id': tp.table.change_id // onchange would not recognize changed values from tp.check.table_id
1180 }
1181 },
1182 $table = $id( 'edit-form-body' );
1183
1184 $.each( callbacks, function( event, event_callbacks ) {
1185 $.each( event_callbacks, function( selector, callback ) {
1186 $( selector ).on( event, callback );
1187 } );
1188 } );
1189
1190 $( window ).on( 'beforeunload', tp.check.changes_saved );
1191
1192 // do this before the next lines, to not trigger set_table_changed()
1193 $id( 'option-table-head' ).change(); // init changed/disabled states of DataTables JS features checkboxes
1194 $id( 'option-print-name' ).change( tp.table.change_print_name_description ).change(); // init dropdowns for name and description position
1195 $id( 'option-print-description' ).change( tp.table.change_print_name_description ).change();
1196
1197 // just once is enough, will be reset after saving
1198 $table.one( 'change', 'textarea', tp.table.set_table_changed );
1199 $( '#tablepress_edit-table-information, #tablepress_edit-table-options, #tablepress_edit-datatables-features' ).one( 'change', 'input, textarea, select', tp.table.set_table_changed );
1200
1201 if ( tablepress_options.cells_advanced_editor ) {
1202 $table.on( 'click', 'textarea', tp.cells.advanced_editor.keyopen );
1203 $id( 'advanced-editor-open' ).on( 'click', tp.cells.advanced_editor.buttonopen );
1204 $id( 'advanced-editor-confirm' ).on( 'click', tp.cells.advanced_editor.save );
1205 $id( 'advanced-editor-cancel' ).on( 'click', tp.cells.advanced_editor.close );
1206 $id( 'advanced-editor' ).wpdialog( {
1207 autoOpen: false,
1208 title: $id( 'advanced-editor-open' ).val(),
1209 width: 600,
1210 modal: true,
1211 dialogClass: 'wp-dialog',
1212 resizable: false
1213 } );
1214 // Fix issue with input fields not being usable (they are immediately losing focus without this) in the wpLink dialog when called through the "Advanced Editor"
1215 $id( 'wp-link' ).on( 'focus', 'input', function( event ) {
1216 event.stopPropagation();
1217 } );
1218 } else {
1219 $id( 'advanced-editor-open' ).hide();
1220 }
1221
1222 // Fix issue with input fields not being usable (they are immediately losing focus without this) in the sidebar of the new Media Manager
1223 $( 'body' ).on( 'focus', '.media-modal .media-frame-content input, .media-modal .media-frame-content textarea', function( event ) {
1224 event.stopPropagation();
1225 } );
1226
1227 if ( tablepress_options.cells_auto_grow ) {
1228 $table.on( 'focus', 'textarea', tp.cells.autogrow );
1229 }
1230
1231 $id( 'edit-form-body' ).on( 'click', 'input:checkbox', { parent: '#edit-form-body' }, tp.cells.checkboxes.multi_select );
1232 $id( 'edit-form-foot' ).on( 'click', 'input:checkbox', { parent: '#edit-form-foot' }, tp.cells.checkboxes.multi_select );
1233
1234 $id( 'edit-form-head' ).on( 'click', '.sort-control', tp.rows.sort );
1235
1236 // on form submit: Enable disabled fields, so that they are transmitted in the POST request
1237 $id( 'tablepress-page' ).find( 'form' ).on( 'submit', function() {
1238 $(this).find( '.tablepress-postbox-table' ).find( 'input, select' ).prop( 'disabled', false );
1239 } );
1240
1241 $table.sortable( {
1242 axis: 'y',
1243 containment: $id( 'edit-form' ), // to get better behavior when dragging before/after the first/last row
1244 forceHelperSize: true, // necessary?
1245 handle: '.move-handle',
1246 start: tp.rows.move.start,
1247 change: tp.rows.move.change,
1248 stop: tp.rows.move.stop,
1249 update: tp.reindex
1250 } ); // disableSelection() prohibits selection of text in textareas via keyboard
1251
1252 $id( 'edit-form-head' ).sortable( {
1253 axis: 'x',
1254 items: '.head',
1255 containment: 'parent',
1256 forceHelperSize: true, // necessary?
1257 helper: 'clone',
1258 handle: '.move-handle',
1259 start: tp.columns.move.start,
1260 stop: tp.columns.move.stop,
1261 change: tp.columns.move.change,
1262 sort: tp.columns.move.sort
1263 } ).disableSelection();
1264 };
1265
1266 // Run TablePress initialization.
1267 tp.init();
1268
1269 } );
1270