PluginProbe
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder / 51.1.78
King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder v51.1.78
51.1.83 51.1.82 51.1.81 51.1.79 51.1.78 51.1.77 51.1.76 51.1.74 51.1.75 51.1.65 51.1.64 51.1.63 trunk 51.1.14 51.1.2 51.1.35 51.1.36 51.1.37 51.1.38 51.1.39 51.1.44 51.1.45 51.1.46 51.1.47 51.1.49 All 37 releases
king-addons / includes / extensions / Data_Table_Builder / assets / admin.js

admin.js in King Addons for Elementor – 80+ Elementor Widgets, 4 000+ Elementor Templates, WooCommerce, Mega Menu, Popup Builder 51.1.78, at includes/extensions/Data_Table_Builder/assets/admin.js

601 lines 19.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function($) {
2 'use strict';
3
4 function parseJSON(value, fallback) {
5 try {
6 var parsed = JSON.parse(value);
7 return parsed && typeof parsed === 'object' ? parsed : fallback;
8 } catch (e) {
9 return fallback;
10 }
11 }
12
13 function csvToArray(text) {
14 var rows = [];
15 var row = [];
16 var current = '';
17 var inQuotes = false;
18 var i = 0;
19
20 text = text.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
21
22 for (i = 0; i < text.length; i++) {
23 var char = text[i];
24 var next = text[i + 1];
25
26 if (char === '"') {
27 if (inQuotes && next === '"') {
28 current += '"';
29 i++;
30 } else {
31 inQuotes = !inQuotes;
32 }
33 continue;
34 }
35
36 if (char === ',' && !inQuotes) {
37 row.push(current);
38 current = '';
39 continue;
40 }
41
42 if (char === '\n' && !inQuotes) {
43 row.push(current);
44 rows.push(row);
45 row = [];
46 current = '';
47 continue;
48 }
49
50 current += char;
51 }
52
53 if (current !== '' || row.length) {
54 row.push(current);
55 rows.push(row);
56 }
57
58 return rows;
59 }
60
61 function TableBuilder($editor) {
62 this.$editor = $editor;
63 this.state = parseJSON($editor.attr('data-state') || '{}', {});
64 this.state.columns = this.state.columns || [];
65 this.state.rows = this.state.rows || [];
66 this.state.config = this.state.config || {};
67 this.state.style = this.state.style || {};
68 this.state.filters = this.state.filters || {};
69 this.state.responsive = this.state.responsive || {};
70 this.selected = { row: 0, col: 0 };
71
72 this.$grid = $editor.find('#kng-table-grid');
73 this.$columnList = $editor.find('.kng-column-list');
74
75 this.normalizeState();
76 this.bindEvents();
77 this.render();
78 }
79
80 TableBuilder.prototype.normalizeState = function() {
81 if (!this.state.columns.length) {
82 this.state.columns = [{ label: 'Column 1', type: 'text', sortable: true, hide_mobile: false, align: 'left' }];
83 }
84
85 var colCount = this.state.columns.length;
86 this.state.rows = this.state.rows.map(function(row) {
87 row = Array.isArray(row) ? row : [];
88 while (row.length < colCount) {
89 row.push({ value: '', tooltip: '', rowspan: 1, colspan: 1 });
90 }
91 return row;
92 });
93
94 if (!this.state.rows.length) {
95 this.state.rows = [[{ value: '', tooltip: '', rowspan: 1, colspan: 1 }]];
96 }
97 };
98
99 TableBuilder.prototype.bindEvents = function() {
100 var self = this;
101
102 var $segment = $('#ka-v3-theme-segment');
103 var $buttons = $segment.find('.ka-v3-segmented-btn');
104 var mql = window.matchMedia ? window.matchMedia('(prefers-color-scheme: dark)') : null;
105 var mode = ($segment.attr('data-active') || 'dark').toString();
106 var mqlHandler = null;
107
108 function saveUISetting(value) {
109 if (!window.KNGTableBuilder) {
110 return;
111 }
112 $.post(KNGTableBuilder.ajaxUrl, {
113 action: 'king_addons_save_dashboard_ui',
114 nonce: KNGTableBuilder.themeNonce,
115 key: 'theme_mode',
116 value: value
117 });
118 }
119
120 function updateSegment(activeMode) {
121 $segment.attr('data-active', activeMode);
122 $buttons.each(function() {
123 var theme = ($(this).data('theme') || 'dark').toString();
124 $(this).attr('aria-pressed', theme === activeMode ? 'true' : 'false');
125 });
126 }
127
128 function applyTheme(isDark) {
129 $('body').toggleClass('ka-v3-dark', isDark);
130 document.documentElement.classList.toggle('ka-v3-dark', isDark);
131 }
132
133 function setThemeMode(nextMode, save) {
134 mode = (nextMode || 'dark').toString();
135 updateSegment(mode);
136
137 if (mqlHandler && mql) {
138 if (mql.removeEventListener) {
139 mql.removeEventListener('change', mqlHandler);
140 } else if (mql.removeListener) {
141 mql.removeListener(mqlHandler);
142 }
143 mqlHandler = null;
144 }
145
146 if (mode === 'auto') {
147 applyTheme(!!(mql && mql.matches));
148 mqlHandler = function(e) {
149 if (mode !== 'auto') {
150 return;
151 }
152 applyTheme(!!e.matches);
153 };
154 if (mql) {
155 if (mql.addEventListener) {
156 mql.addEventListener('change', mqlHandler);
157 } else if (mql.addListener) {
158 mql.addListener(mqlHandler);
159 }
160 }
161 } else {
162 applyTheme(mode === 'dark');
163 }
164
165 if (save) {
166 saveUISetting(mode);
167 }
168 }
169
170 $segment.on('click', '.ka-v3-segmented-btn', function(e) {
171 e.preventDefault();
172 setThemeMode(($(this).data('theme') || 'dark').toString(), true);
173 });
174
175 window.kaV3ToggleDark = function() {
176 var isDark = $('body').hasClass('ka-v3-dark');
177 setThemeMode(isDark ? 'light' : 'dark', true);
178 };
179
180 setThemeMode(mode, false);
181
182 $('.kng-add-row').on('click', function() {
183 self.addRow();
184 });
185
186 $('.kng-remove-row').on('click', function() {
187 self.removeRow();
188 });
189
190 $('.kng-add-column').on('click', function() {
191 self.addColumn();
192 });
193
194 $('.kng-remove-column').on('click', function() {
195 self.removeColumn();
196 });
197
198 $('.kng-apply-span').on('click', function() {
199 self.applySpan();
200 });
201
202 $('.kng-apply-import').on('click', function() {
203 var text = $('.kng-table-import-text').val() || '';
204 self.applyImport(text);
205 });
206
207 $('.kng-paste-clipboard').on('click', function() {
208 if (navigator.clipboard && navigator.clipboard.readText) {
209 navigator.clipboard.readText().then(function(text) {
210 $('.kng-table-import-text').val(text);
211 });
212 }
213 });
214
215 $('.kng-table-form').on('submit', function() {
216 self.syncHiddenFields();
217 });
218 };
219
220 TableBuilder.prototype.render = function() {
221 this.renderTable();
222 this.renderColumns();
223 this.bindDynamicInputs();
224 this.updateInspector();
225 };
226
227 TableBuilder.prototype.renderTable = function() {
228 var self = this;
229 var columns = this.state.columns;
230 var rows = this.state.rows;
231 var $thead = $('<tr></tr>');
232
233 columns.forEach(function(column, index) {
234 var $th = $('<th contenteditable="true"></th>');
235 $th.text(column.label || ('Column ' + (index + 1)));
236 $th.attr('data-col', index);
237 $thead.append($th);
238 });
239
240 this.$grid.find('thead').html($thead);
241
242 var $tbody = $('<tbody></tbody>');
243 var skipMap = [];
244
245 rows.forEach(function(row, rowIndex) {
246 var $tr = $('<tr></tr>');
247 var colIndex = 0;
248
249 while (colIndex < columns.length) {
250 if (skipMap[colIndex] && skipMap[colIndex] > 0) {
251 skipMap[colIndex]--;
252 colIndex++;
253 continue;
254 }
255
256 var cell = row[colIndex] || { value: '', tooltip: '', rowspan: 1, colspan: 1 };
257 var colspan = parseInt(cell.colspan || 1, 10);
258 var rowspan = parseInt(cell.rowspan || 1, 10);
259
260 var $td = $('<td contenteditable="true"></td>');
261 $td.text(cell.value || '');
262 $td.attr('data-row', rowIndex);
263 $td.attr('data-col', colIndex);
264 $td.attr('data-tooltip', cell.tooltip || '');
265 $td.attr('data-rowspan', rowspan);
266 $td.attr('data-colspan', colspan);
267
268 if (rowspan > 1) {
269 $td.attr('rowspan', rowspan);
270 for (var spanCol = 0; spanCol < colspan; spanCol++) {
271 skipMap[colIndex + spanCol] = rowspan - 1;
272 }
273 }
274
275 if (colspan > 1) {
276 $td.attr('colspan', colspan);
277 }
278
279 $tr.append($td);
280 colIndex += colspan;
281 }
282
283 $tbody.append($tr);
284 });
285
286 this.$grid.find('tbody').replaceWith($tbody);
287
288 this.$grid.find('td, th').on('click', function() {
289 var $cell = $(this);
290 self.selectCell($cell);
291 });
292
293 this.$grid.find('td').on('input', function() {
294 var $cell = $(this);
295 self.updateCellValue($cell);
296 });
297
298 this.$grid.find('th').on('input', function() {
299 var $cell = $(this);
300 self.updateColumnLabel($cell);
301 });
302 };
303
304 TableBuilder.prototype.renderColumns = function() {
305 var self = this;
306 this.$columnList.empty();
307
308 this.state.columns.forEach(function(column, index) {
309 var $row = $('<div class="kng-column-item"></div>');
310 var $label = $('<input type="text" class="kng-column-label" />');
311 $label.val(column.label || '');
312 $label.attr('data-col', index);
313
314 var $type = $('<select class="kng-column-type"></select>');
315 $type.append('<option value="text">Text</option>');
316 $type.append('<option value="number">Number</option>');
317 $type.append('<option value="link">Link</option>');
318 $type.val(column.type || 'text');
319 $type.attr('data-col', index);
320
321 var $hide = $('<label><input type="checkbox" class="kng-column-hide" /> Hide on mobile</label>');
322 $hide.find('input').prop('checked', !!column.hide_mobile).attr('data-col', index);
323
324 var $wrap = $('<div></div>');
325 $wrap.append($label).append($type).append($hide);
326
327 $row.append($wrap);
328 self.$columnList.append($row);
329 });
330 };
331
332 TableBuilder.prototype.bindDynamicInputs = function() {
333 var self = this;
334
335 this.$columnList.find('.kng-column-label').off('input').on('input', function() {
336 var col = parseInt($(this).attr('data-col'), 10);
337 self.state.columns[col].label = $(this).val();
338 self.$grid.find('th[data-col="' + col + '"]').text($(this).val());
339 });
340
341 this.$columnList.find('.kng-column-type').off('change').on('change', function() {
342 var col = parseInt($(this).attr('data-col'), 10);
343 self.state.columns[col].type = $(this).val();
344 });
345
346 this.$columnList.find('.kng-column-hide').off('change').on('change', function() {
347 var col = parseInt($(this).attr('data-col'), 10);
348 self.state.columns[col].hide_mobile = $(this).is(':checked');
349 });
350
351 this.$editor.find('[data-config]').off('change input').on('change input', function() {
352 var key = $(this).attr('data-config');
353 if ($(this).is(':checkbox')) {
354 self.state.config[key] = $(this).is(':checked');
355 } else {
356 self.state.config[key] = $(this).val();
357 }
358 });
359
360 this.$editor.find('[data-style]').off('change').on('change', function() {
361 var key = $(this).attr('data-style');
362 if ($(this).is(':checkbox')) {
363 self.state.style[key] = $(this).is(':checked');
364 } else {
365 self.state.style[key] = $(this).val();
366 }
367 });
368
369 this.$editor.find('[data-responsive]').off('change').on('change', function() {
370 var key = $(this).attr('data-responsive');
371 if ($(this).is(':checkbox')) {
372 self.state.responsive[key] = $(this).is(':checked');
373 } else {
374 self.state.responsive[key] = $(this).val();
375 }
376 });
377
378 this.$editor.find('.kng-cell-tooltip').off('input').on('input', function() {
379 var $cell = self.getSelectedCell();
380 if (!$cell) {
381 return;
382 }
383 var tooltip = $(this).val();
384 $cell.attr('data-tooltip', tooltip);
385 self.updateCellMeta($cell);
386 });
387 };
388
389 TableBuilder.prototype.selectCell = function($cell) {
390 this.$grid.find('.kng-selected').removeClass('kng-selected');
391 $cell.addClass('kng-selected');
392
393 if ($cell.is('th')) {
394 this.selected = { row: 0, col: parseInt($cell.attr('data-col'), 10) };
395 } else {
396 this.selected = {
397 row: parseInt($cell.attr('data-row'), 10),
398 col: parseInt($cell.attr('data-col'), 10)
399 };
400 }
401
402 this.updateInspector();
403 };
404
405 TableBuilder.prototype.getSelectedCell = function() {
406 var row = this.selected.row;
407 var col = this.selected.col;
408 return this.$grid.find('td[data-row="' + row + '"][data-col="' + col + '"]');
409 };
410
411 TableBuilder.prototype.updateInspector = function() {
412 var $cell = this.getSelectedCell();
413 if (!$cell || !$cell.length) {
414 return;
415 }
416
417 var tooltip = $cell.attr('data-tooltip') || '';
418 var rowspan = $cell.attr('data-rowspan') || 1;
419 var colspan = $cell.attr('data-colspan') || 1;
420
421 this.$editor.find('.kng-cell-tooltip').val(tooltip);
422 this.$editor.find('.kng-cell-rowspan').val(rowspan);
423 this.$editor.find('.kng-cell-colspan').val(colspan);
424 };
425
426 TableBuilder.prototype.applySpan = function() {
427 var $cell = this.getSelectedCell();
428 if (!$cell || !$cell.length) {
429 return;
430 }
431
432 var rowspan = parseInt(this.$editor.find('.kng-cell-rowspan').val(), 10) || 1;
433 var colspan = parseInt(this.$editor.find('.kng-cell-colspan').val(), 10) || 1;
434
435 $cell.attr('data-rowspan', rowspan).attr('data-colspan', colspan);
436 $cell.attr('rowspan', rowspan).attr('colspan', colspan);
437
438 this.updateCellMeta($cell);
439 this.render();
440 };
441
442 TableBuilder.prototype.updateCellValue = function($cell) {
443 var row = parseInt($cell.attr('data-row'), 10);
444 var col = parseInt($cell.attr('data-col'), 10);
445
446 this.state.rows[row][col].value = $cell.text();
447 };
448
449 TableBuilder.prototype.updateCellMeta = function($cell) {
450 var row = parseInt($cell.attr('data-row'), 10);
451 var col = parseInt($cell.attr('data-col'), 10);
452
453 var cell = this.state.rows[row][col];
454 cell.tooltip = $cell.attr('data-tooltip') || '';
455 cell.rowspan = parseInt($cell.attr('data-rowspan'), 10) || 1;
456 cell.colspan = parseInt($cell.attr('data-colspan'), 10) || 1;
457 };
458
459 TableBuilder.prototype.updateColumnLabel = function($cell) {
460 var col = parseInt($cell.attr('data-col'), 10);
461 this.state.columns[col].label = $cell.text();
462 this.$columnList.find('.kng-column-label[data-col="' + col + '"]').val($cell.text());
463 };
464
465 TableBuilder.prototype.addRow = function() {
466 if (window.KNGTableBuilder && !KNGTableBuilder.isPro && this.state.rows.length >= KNGTableBuilder.maxRows) {
467 alert('Free limit reached. Upgrade to Pro for more rows.');
468 return;
469 }
470
471 var row = [];
472 for (var i = 0; i < this.state.columns.length; i++) {
473 row.push({ value: '', tooltip: '', rowspan: 1, colspan: 1 });
474 }
475 this.state.rows.push(row);
476 this.render();
477 };
478
479 TableBuilder.prototype.removeRow = function() {
480 if (this.state.rows.length <= 1) {
481 return;
482 }
483 this.state.rows.pop();
484 this.render();
485 };
486
487 TableBuilder.prototype.addColumn = function() {
488 if (window.KNGTableBuilder && !KNGTableBuilder.isPro && this.state.columns.length >= KNGTableBuilder.maxCols) {
489 alert('Free limit reached. Upgrade to Pro for more columns.');
490 return;
491 }
492
493 var index = this.state.columns.length + 1;
494 this.state.columns.push({
495 label: 'Column ' + index,
496 type: 'text',
497 sortable: true,
498 hide_mobile: false,
499 align: 'left'
500 });
501
502 this.state.rows.forEach(function(row) {
503 row.push({ value: '', tooltip: '', rowspan: 1, colspan: 1 });
504 });
505
506 this.render();
507 };
508
509 TableBuilder.prototype.removeColumn = function() {
510 if (this.state.columns.length <= 1) {
511 return;
512 }
513
514 this.state.columns.pop();
515 this.state.rows.forEach(function(row) {
516 row.pop();
517 });
518
519 this.render();
520 };
521
522 TableBuilder.prototype.applyImport = function(text) {
523 if (!text.trim()) {
524 return;
525 }
526
527 var raw = text.trim();
528 if (raw.indexOf('\t') !== -1 && raw.indexOf(',') === -1) {
529 raw = raw.replace(/\t/g, ',');
530 }
531
532 var rows = csvToArray(raw);
533 if (!rows.length) {
534 return;
535 }
536
537 var header = rows.shift();
538 var columns = header.map(function(label, index) {
539 return {
540 label: label || ('Column ' + (index + 1)),
541 type: 'text',
542 sortable: true,
543 hide_mobile: false,
544 align: 'left'
545 };
546 });
547
548 if (window.KNGTableBuilder && !KNGTableBuilder.isPro && columns.length > KNGTableBuilder.maxCols) {
549 alert('CSV exceeds free column limit.');
550 return;
551 }
552
553 var dataRows = rows.map(function(row) {
554 return columns.map(function(_, colIndex) {
555 return {
556 value: row[colIndex] || '',
557 tooltip: '',
558 rowspan: 1,
559 colspan: 1
560 };
561 });
562 });
563
564 if (window.KNGTableBuilder && !KNGTableBuilder.isPro && dataRows.length > KNGTableBuilder.maxRows) {
565 alert('CSV exceeds free row limit.');
566 return;
567 }
568
569 this.state.columns = columns;
570 this.state.rows = dataRows;
571 this.render();
572 };
573
574 TableBuilder.prototype.syncHiddenFields = function() {
575 var responsive = $.extend({}, this.state.responsive);
576 responsive.hide_columns = [];
577
578 this.state.columns.forEach(function(column, index) {
579 if (column.hide_mobile) {
580 responsive.hide_columns.push(index);
581 }
582 });
583
584 $('#kng-table-data').val(JSON.stringify({
585 columns: this.state.columns,
586 rows: this.state.rows,
587 schema_version: 1
588 }));
589 $('#kng-table-config').val(JSON.stringify(this.state.config));
590 $('#kng-table-style').val(JSON.stringify(this.state.style));
591 $('#kng-table-responsive').val(JSON.stringify(responsive));
592 };
593
594 $(document).ready(function() {
595 var $editor = $('.kng-table-editor');
596 if ($editor.length) {
597 new TableBuilder($editor);
598 }
599 });
600 })(jQuery);
601