PluginProbe
Tag Groups is the Advanced Way to Display Your Taxonomy Terms / trunk
Tag Groups is the Advanced Way to Display Your Taxonomy Terms vtrunk
2.2.2 2.2.1 2.2.0 trunk 1.40.0 1.40.2 1.41.0 1.42.1 1.43.0 1.43.1 1.43.10 1.43.10.1 1.43.2 1.43.3 1.43.4 1.43.5 1.43.6 1.43.7 1.43.9 1.44.0 1.44.1 1.44.3 1.44.3.1 2.0.0 2.0.1 All 36 releases
tag-groups / assets / js / backend.js

backend.js in Tag Groups is the Advanced Way to Display Your Taxonomy Terms trunk, at assets/js/backend.js

481 lines 16.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*!
2 * Last modified: 2021/09/03 13:50:24
3 * Part of the WordPress plugin Tag Groups
4 * Plugin URI: https://chattymango.com/tag-groups/
5 * Author: Christoph Amthor
6 * License: GNU GENERAL PUBLIC LICENSE, Version 3
7 */
8
9 /*
10 * Makes the actual Ajax request and populates the table, the pager and the message box
11 */
12 function tg_do_ajax(tg_params, send_data, labels) {
13 var nonce = jQuery('#tg_nonce').val();
14 var data = {
15 action: 'tg_ajax_manage_groups',
16 nonce: nonce,
17 };
18 jQuery.extend(send_data, data);
19
20 send_data.tag_groups_start_position = jQuery('#tg_start_position').val();
21
22 send_data.tag_groups_filter_label = jQuery('#filter_label').val();
23
24 var message_output = '';
25
26 jQuery('#tg_groups_container').fadeTo(200, 0.7);
27
28 /*
29 * Send request and parse response
30 */
31 jQuery.ajax({
32 url: tg_params.ajaxurl,
33 data: send_data,
34 dataType: 'text',
35 method: 'post',
36 success: function (data) {
37 try {
38 // strip anything before the first opening {
39 const dataOld = data;
40 data = data.replace(/[^{]*{/, '{');
41 // workaround for strange layout issue
42 if (data !== dataOld) {
43 jQuery('#wpfooter').hide();
44 }
45 var dataParsed = JSON.parse(data);
46 } catch (e) {
47 tg_display_error(
48 e.message + '\n\n' + data.toString(),
49 tg_params.isPremium
50 );
51 return false;
52 }
53 var status = dataParsed.data;
54 var message = dataParsed.supplemental.message;
55 var nonce = dataParsed.supplemental.nonce;
56 var showParents = tg_params.show_parents || false;
57
58 // write new nonce
59 if (nonce !== '') {
60 jQuery('#tg_nonce').val(nonce);
61 }
62 if (status === 'success') {
63 var groups = dataParsed.supplemental.groups;
64 var start_position = dataParsed.supplemental.start_position;
65 if (start_position !== '') {
66 jQuery('#tg_start_position').val(start_position);
67 } else {
68 start_position = send_data.start_position;
69 }
70
71 var max_number = dataParsed.supplemental.max_number;
72 var output = '';
73
74 var newGroupRow =
75 '<tr class="tg_new_group_row" style="display:none;" id="tg_new_group">\n' +
76 '<td style="display:none;">' + labels.newgroup + '</td>\n' +
77 '<td colspan="5"><input placeholder="' + labels.placeholder_new + '">' +
78 '<span class="tg_new_yes dashicons dashicons-yes tg_pointer" style="font-size: 30px; line-height: 1;"></span>' +
79 '</td>\n' +
80 '</tr>\n';
81
82 output += newGroupRow;
83
84 // disable sorting by drag and drop if the list is not complete
85 if (dataParsed.supplemental.is_filtered) {
86 jQuery('#tg_groups_container')
87 .removeClass('ui-sortable')
88 .sortable('disable');
89 } else {
90 jQuery('#tg_groups_container')
91 .addClass('ui-sortable')
92 .sortable('enable');
93 }
94
95 if (max_number > 0 || dataParsed.supplemental.is_filtered) {
96 if (dataParsed.supplemental.parents_available) {
97 jQuery('.tg_group_admin_parent').css('display', 'block');
98 } else {
99 jQuery('.tg_group_admin_parent').css('display', 'none');
100 }
101 if ((dataParsed.supplemental.only_parents && !dataParsed.supplemental.is_filtered) || max_number === 0) {
102 output += tg_html_first_group(labels);
103 }
104
105 for (var key in groups) {
106 var data_set = groups[key];
107 if (data_set.id != null) {
108 if (showParents && data_set.is_parent) {
109 output +=
110 '<tr class="tg_sort_tr tg_is_parent" data-position="' +
111 data_set.position +
112 '">\n';
113 output +=
114 '<td class="tg_label_column">';
115 output += '<span class="dashicons dashicons-networking" title="' + labels.tooltip_parent + '"></span> ';
116 output += '<div style="display:inline-block" class="tg_edit_label tg_text tg_truncate" data-position="' +
117 data_set.position +
118 '" data-label="' +
119 escape_html(data_set.label) +
120 '">';
121 output +=
122 escape_html(data_set.label) +
123 '<span class="dashicons dashicons-edit tg_pointer" style="display:none;"></span></div></td>\n';
124 output += '<td colspan="2"></td>';
125 } else {
126 output +=
127 '<tr class="tg_sort_tr" data-position="' + data_set.position + '">\n';
128
129 output +=
130 '<td class="tg_label_column"><div class="tg_edit_label tg_text tg_truncate tg_child_label" data-position="' +
131 data_set.position +
132 '" data-label="' +
133 escape_html(data_set.label) +
134 '" data-is_child="1">';
135 output +=
136 escape_html(data_set.label) +
137 '<span class="dashicons dashicons-edit tg_pointer" style="display:none;"></span></div></td>\n';
138 if (dataParsed.supplemental.parents_available) {
139 output +=
140 '<td class="tg_hide_when_drag"><div class="tg_truncate">' +
141 data_set.parent_label +
142 '</div></td>\n';
143 }
144 output +=
145 '<td class="tg_hide_when_drag"><div class="tg_term_amounts">';
146 if (tg_params.tagsurl !== '') {
147 output +=
148 '<a href="' +
149 tg_params.tagsurl +
150 '&term-filter=' +
151 data_set.id +
152 '">' +
153 data_set.amount +
154 '</a>';
155 } else {
156 output += data_set.amount + '</span>';
157 }
158 output += '</div>';
159 output += '</td>\n';
160 }
161 let outputFilters = '';
162 if (tg_params.tagsurl !== '') {
163 outputFilters +=
164 '<a href="' +
165 tg_params.tagsurl +
166 '&term-filter=' +
167 data_set.id +
168 '"><span class="tg_pointer dashicons dashicons-tag"></span></a> ';
169 }
170 if (tg_params.postsurl !== '') {
171 outputFilters +=
172 '<a href="' +
173 tg_params.postsurl +
174 '&post_status=all&tg_filter_posts_value=' +
175 data_set.id +
176 '" title="' +
177 labels.tooltip_showposts +
178 '"><span class="tg_pointer dashicons dashicons-admin-page"></span></a>';
179 }
180 output += outputFilters
181 ? '<td class="tg_hide_when_drag">' + outputFilters + '</td>\n'
182 : '';
183 output += '<td class="tg_hide_when_drag">';
184 output +=
185 '<span class="tg_delete tg_pointer dashicons dashicons-trash" data-position="' +
186 data_set.position +
187 '"></span>';
188 output += '</td>\n';
189 output += '<td class="tg_hide_when_drag">';
190
191 output +=
192 '<div style="overflow:hidden; position:relative; height:20px; clear:both;">';
193 if (!dataParsed.supplemental.is_filtered && data_set.position > 1) {
194 output +=
195 '<span class="tg_up tg_pointer dashicons dashicons-arrow-up" data-position="' +
196 data_set.position +
197 '"></span>';
198 }
199 output += '</div>';
200
201 output +=
202 '<div style="overflow:hidden; position:relative; height:20px; clear:both;">';
203 if (!dataParsed.supplemental.is_filtered && data_set.position < max_number) {
204 output +=
205 '<span class="tg_down tg_pointer dashicons dashicons-arrow-down" data-position="' +
206 data_set.position +
207 '"></span>';
208 }
209 output += '</div>';
210 output += '<td>' + data_set.id + '</td>\n';
211
212 output += '</td>\n';
213 output += '</tr>\n';
214
215 // hidden row for adding a new group
216 var newGroupRow =
217 '<tr class="tg_new_group_row" style="display:none;" id="tg_new_group">\n' +
218 '<td style="display:none;">' + labels.newgroup + '</td>\n' +
219 '<td colspan="5"><input placeholder="' + labels.placeholder_new + '">' +
220 '<span class="tg_new_yes dashicons dashicons-yes tg_pointer" style="font-size: 30px; line-height: 1;"></span>' +
221 '</td>\n' +
222 '</tr>\n';
223
224 // Prepend new group row before existing groups
225 output = newGroupRow + output;
226 }
227 }
228 } else {
229 // no tag groups yet
230 output += tg_html_first_group(labels);
231 }
232
233 // move add new group button outside the table
234 const $tagGroupContainer = jQuery('#new_group');
235
236 if ($tagGroupContainer.length){
237 const $tagExistingButton = $tagGroupContainer.find('.new_group_pointer.button');
238
239 if (!$tagExistingButton.length){
240 const $addTagGroupButton = jQuery('<span>', {
241 class: 'new_group_pointer button',
242 text: labels.tooltip_addnew,
243 });
244
245 $addTagGroupButton.on('click', function () {
246 var $row = jQuery('#tg_new_group');
247
248 // Ensure the row is fully removed and re-added
249 if (!$row.length) {
250 jQuery('#tg_groups_container table').prepend(newGroupRow);
251 $row = jQuery('#tg_new_group'); // Re-select the newly added row
252 }
253
254 // Append a fresh new row
255 jQuery('#tg_new_group').fadeIn();
256
257 jQuery('#tg_groups_container table').prepend(newGroupRow);
258 jQuery('#tg_new_group input').val('').show().trigger('focus');
259 });
260
261 $tagGroupContainer.append($addTagGroupButton);
262 }
263 }
264
265 // write table of groups
266 jQuery('#tg_groups_container').html(output);
267
268 // pager
269 var pager_output = '';
270 var page, current_page;
271 var items_per_page = Number(tg_params.items_per_page);
272 if (items_per_page < 1) {
273 items_per_page = 1;
274 }
275 current_page = Math.floor(start_position / items_per_page) + 1;
276 max_page = Math.floor((max_number - 1) / items_per_page) + 1;
277
278 if (current_page > 1) {
279 pager_output +=
280 '<button class="button-secondary tg_pager_button" data-page="' +
281 (current_page - 1) +
282 '" title="' +
283 labels.tooltip_previous +
284 '"><span class="dashicons dashicons-arrow-left-alt2"></span></button>';
285 } else {
286 pager_output +=
287 '<button class="button-secondary tg_pager_button" disabled><span class="dashicons dashicons-arrow-left-alt2"></span></button>';
288 }
289
290 for (i = 1; i <= max_number; i += items_per_page) {
291 page = Math.floor(i / items_per_page) + 1;
292 if (page == current_page) {
293 pager_output +=
294 '<button class="tg_reload_button tg_pointer button-secondary" id="tg_groups_reload"><span class="dashicons dashicons-update"></span></button>';
295 } else {
296 pager_output +=
297 '<button class="button-secondary tg_pager_button" data-page="' +
298 page +
299 '" title="' +
300 labels.tooltip_go_to_page + ' ' + page +
301 '"><span>' +
302 page +
303 '</span></button>';
304 }
305 }
306
307 if (current_page < max_page) {
308 pager_output +=
309 '<button class="button-secondary tg_pager_button" data-page="' +
310 (current_page + 1) +
311 '" title="' +
312 labels.tooltip_next +
313 '"><span class="dashicons dashicons-arrow-right-alt2"></span></button>';
314 } else {
315 pager_output +=
316 '<button class="button-secondary tg_pager_button" disabled><span class="dashicons dashicons-arrow-right-alt2"></span></button>';
317 }
318
319 jQuery('#tg_pager_container').fadeOut(200, function () {
320 jQuery(this)
321 .html(pager_output)
322 .fadeIn(400, function () {
323 jQuery('#tg_pager_container_adjuster').css({
324 height: Number(jQuery('#tg_pager_container').height()) + 10,
325 });
326 });
327 });
328
329 if (message != '') {
330 message_output +=
331 '<div class="notice notice-success"><p>' +
332 message +
333 '</p></div>';
334 } else {
335 message_output += '';
336 }
337 jQuery('#tg_message_container').fadeTo(200, 0, function () {
338 jQuery(this).html(message_output).fadeTo(400, 1);
339 });
340 jQuery('#new_parent').val('');
341 } else {
342 if (message == '') {
343 message = 'Error loading data.';
344 console.log(data);
345 }
346 message_output +=
347 '<div class="notice notice-error"><p>' +
348 message +
349 '</p></div>';
350
351 jQuery('#tg_message_container').fadeTo(200, 0, function () {
352 jQuery(this).html(message_output).fadeTo(400, 1);
353 });
354 }
355 jQuery('#tg_groups_container').fadeTo(200, 1);
356 },
357 error: function (xhr, textStatus, errorThrown) {
358 tg_display_error(xhr.responseText, tg_params.isPremium);
359 },
360 });
361 }
362
363 function tg_html_first_group(labels) {
364 let output = '<tr id="tg_new_1">\n';
365 output +=
366 '<td colspan="2" style="text-align: left;">' +
367 '<span style="display: flex; align-items: center; gap: 10px;">' +
368 '<input data-position="0" placeholder="' + labels.newgroup + '">' +
369 '<span class="tg_new_yes dashicons dashicons-yes tg_pointer" data-id="1" style="font-size: 30px; line-height: 1;"></span>' +
370 '</span>' +
371 '</td>\n';
372 output += '</tr>\n';
373 return output;
374 }
375
376 function tg_display_error(message, isPremium) {
377 console.log('[Tag Groups] ' + message);
378 let url;
379 if (isPremium) {
380 url =
381 'https://taxopress.com/docs/list-not-loading-tag-groups/';
382 } else {
383 url =
384 'https://taxopress.com/docs/list-not-loading-tag-groups/';
385 }
386
387 message = message.replace(/\n/g, '<br>');
388 message_output =
389 '<tr><td colspan="6"><div class="notice notice-error"><p>Error loading groups. Please check the error description below and read the <a href="' +
390 url +
391 '" target="_blank">troublshooting page</a>.<br><br>' +
392 message +
393 '</p><div clear="both"></div></div></td></tr>';
394
395 jQuery('#tg_groups_container')
396 .fadeTo(200, 0, function () {
397 jQuery(this).html(message_output).fadeTo(400, 1);
398 })
399 .removeClass('ui-sortable')
400 .sortable('disable');
401 }
402
403 /*
404 * Turn an editable label field back into normal text
405 */
406 function tg_close_textfield(element, saved) {
407 const position = element.children(':first').attr('data-position');
408 var label;
409 const isChild = element.attr('data-is_child');
410 if (saved) {
411 label = escape_html(element.children(':first').attr('value'));
412 } else {
413 label = escape_html(element.children(':first').attr('data-label'));
414 }
415 if (isChild) {
416 element.replaceWith(
417 '<span class="tg_edit_label tg_text tg_child_label" data-position="' +
418 position +
419 '" data-label="' +
420 label +
421 '" data-is_child=1>' +
422 label +
423 ' <span class="dashicons dashicons-edit tg_pointer" style="display:none;"></span></span>'
424 );
425 } else {
426 element.replaceWith(
427 '<span class="tg_edit_label tg_text" data-position="' +
428 position +
429 '" data-label="' +
430 label +
431 '">' +
432 label +
433 ' <span class="dashicons dashicons-edit tg_pointer" style="display:none;"></span></span>'
434 );
435 }
436 }
437
438 /*
439 * Toggling the "new group" boxes
440 */
441 function tg_toggle_clear() {
442 var row = jQuery('#tg_new_');
443 if (row.is(':visible')) {
444 row.find('input').val('');
445 row.children().fadeOut(300, function () {
446 row.slideUp(600);
447 });
448 } else {
449 jQuery('[id^="tg_new_"]:visible')
450 .children()
451 .fadeOut(300, function () {
452 jQuery('[id^="tg_new_"]:visible').slideUp(400);
453 });
454 row.delay(200).slideDown(400, function () {
455 row.children().fadeIn(300);
456 row.find('input').val('').show().trigger('focus');
457 });
458 }
459 }
460
461 /*
462 * Parse all editable label fields in order to turn them into normal text
463 */
464 function tg_close_all_textfields() {
465 jQuery('.tg_edit_label_active').each(function () {
466 tg_close_textfield(jQuery(this), false);
467 });
468 }
469
470 /*
471 * Prevent HTML from breaking
472 */
473 function escape_html(text) {
474 return text
475 .replace(/&/g, '&amp;')
476 .replace(/</g, '&lt;')
477 .replace(/>/g, '&gt;')
478 .replace(/"/g, '&quot;')
479 .replace(/'/g, '&#039;');
480 }
481