PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.11.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.11.0
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
visualizer / js / frame.js

frame.js in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.11.0, at js/frame.js

879 lines 35.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global prompt */
2 /* global visualizer */
3 /* global alert */
4 /* global confirm */
5 /* global ajaxurl */
6 /* global CodeMirror */
7 /* global vizHaveSettingsChanged */
8
9 (function ($) {
10 $(window).on('load', function(){
11 // scroll to the selected chart type.
12 $('#chart-select').scrollIntoView();
13 });
14
15 $(document).ready(function () {
16 onReady();
17 });
18
19 function initTabs(){
20 $( "#sidebar" ).lock();
21 $( "#viz-tabs" ).tabs({
22 create: function( event, ui ) {
23 $(this).addClass('done');
24 $( "#sidebar" ).unlock();
25 },
26 beforeActivate: function( event, ui ) {
27 // if settings have changed in tab #2 and tab #1 is being activated, warn the user.
28 if(vizHaveSettingsChanged() && ui.newTab.find( 'a' ).attr( 'id' ).includes('viz-tab-basic')){
29 return confirm(visualizer.l10n.save_settings);
30 }
31 }
32 });
33 }
34
35 function onReady() {
36 initTabs();
37
38 // open the correct source tab/sub-tab.
39 var source = $('#visualizer-chart-id').attr('data-chart-source');
40 $('li.viz-group.' + source).addClass('open');
41 $('li.viz-group.' + source + ' span.viz-section-title.' + source).addClass('open');
42 $('li.viz-group.' + source + ' span.viz-section-title.' + source + '.open').parent().find('div.viz-section-items').show();
43
44 init_permissions();
45
46 if(typeof visualizer !== 'undefined' && visualizer.is_pro) {
47 init_db_import();
48 init_filter_import();
49 }
50
51 init_json_import();
52
53 init_editor_table();
54
55 // update the manual configuation link to point to the correct chart type.
56 var type = $('#visualizer-chart-id').attr('data-chart-type');
57 var chart_type_in_api_link = type + 'chart';
58 switch (type) {
59 case "gauge":
60 case "table":
61 case "timeline":
62 chart_type_in_api_link = type;
63 break;
64 }
65
66 if($('span.viz-gvlink').length > 0) {
67 $('span.viz-gvlink').html($('span.viz-gvlink').html().replace('?', chart_type_in_api_link));
68 }
69
70 $('.type-radio').change(function () {
71 $('.type-label-selected').removeClass('type-label-selected');
72 $(this).parent().addClass('type-label-selected');
73 });
74
75 // collapse other open sections of this group
76 $(document).on('click', '.viz-group-title', function () {
77 var parent = $(this).parent();
78
79 if (parent.hasClass('open')) {
80 parent.removeClass('open');
81 } else {
82 parent.parent().find('.viz-group.open').removeClass('open');
83 parent.addClass('open');
84 }
85
86 /*
87 * if the user wants to perform an action and click that tab to change the source
88 * and the chart is no longer showing because that particular LHS screen is showing
89 * e.g. create parameters, import json, db query box etc.
90 * we need to make sure we cancel the current process WITHOUT saving
91 * and then show the chart as it was
92 * let's close the LHS window and show the chart that is hidden
93 */
94 $('body').trigger('visualizer:change:action');
95 });
96
97 // collapse other open subsections of this section
98 $(document).on('click', '.viz-section-title', function () {
99 var grandparent = $(this).parent().parent();
100 grandparent.find('.viz-section-title.open ~ .viz-section-items').hide();
101 grandparent.find('.viz-section-title.open').removeClass('open');
102 });
103
104 $('#view-remote-file').click(function () {
105 var url = $(this).parent().find('#vz-schedule-url').val();
106
107 if (url !== '') {
108 if (url.indexOf('localhost') !== -1 || /^([a-z]([a-z]|\d|\+|-|\.)*):(\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?((\[(|(v[\da-f]{1,}\.(([a-z]|\d|-|\.|_|~)|[!\$&'\(\)\*\+,;=]|:)+))\])|((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=])*)(:\d*)?)(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*|(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)|((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)){0})(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(url)) {
109 if (url.substr(url.length - 8) === '/pubhtml') {
110 url = url.substring(0, url.length - 8) + '/export?format=csv';
111 }
112
113 $('#canvas').lock();
114 $(this).parent().submit();
115 } else {
116 alert(visualizer.l10n.invalid_source);
117 }
118 }
119 });
120
121 $('#vz-import-file').click(function (e) {
122 e.preventDefault();
123 if ($.trim($(this).parent().find("#csv-file").val()) !== '') {
124 $('#canvas').lock();
125 $(this).parent().submit();
126 }
127 });
128
129 $( window ).on( 'load', function() {
130 $('#canvas').unlock();
131 } );
132
133 $(document).on('click', '.viz-section-title', function () {
134 $(this).toggleClass('open').parent().find('.viz-section-items').toggle();
135 });
136
137 $(document).on('click', '.more-info', function () {
138 $(this).parent().find('.viz-section-description:first').toggle();
139 return false;
140 });
141
142 $('#cancel-button').click(function () {
143 $('#cancel-form').submit();
144 });
145
146 init_available_chart_list();
147
148 $('.viz-abort').on('click', function(e){
149 e.preventDefault();
150 window.parent.postMessage('visualizer:mediaframe:close', '*');
151 });
152
153 }
154
155 /**
156 * Initialize/Update the available chart list based on their supported renderer libraries.
157 *
158 * @returns {void}
159 */
160 function init_available_chart_list() {
161 const rendererSelect = document.querySelector('select.viz-select-library');
162 if ( ! rendererSelect ) {
163 return;
164 }
165
166 const rendererTypesMappingData = rendererSelect?.getAttribute('data-type-vs-library');
167 if( ! rendererTypesMappingData ) {
168 return;
169 }
170
171 /** @type {Record<string, ('GoogleCharts' | 'ChartJS' | 'DataTable')[]>} */
172 const rendererTypesMapping = JSON.parse( rendererTypesMappingData );
173
174 document.querySelectorAll('input.type-radio').forEach( chartTypeRadio => {
175
176 // Init the lib based on the default selected chart type.
177 if ( chartTypeRadio.checked ) {
178 const chartType = chartTypeRadio.value;
179 if ( ! chartType ) {
180 return;
181 }
182
183 const selectedRenderer = rendererSelect.value;
184 if ( ! rendererTypesMapping[chartType]?.includes( selectedRenderer ) ) {
185 disable_renderer_select_placeholder();
186 rendererSelect.value = rendererTypesMapping[chartType][0]
187 }
188 }
189
190 chartTypeRadio.addEventListener('click', (event) => {
191 // Check if the chart type is supported by the selected renderer. If not, select the first supported renderer.
192 const chartType = event.target.value;
193 if ( ! chartType ) {
194 return;
195 }
196
197 const selectedRenderer = rendererSelect.value;
198 if ( ! rendererTypesMapping[chartType]?.includes( selectedRenderer ) ) {
199 disable_renderer_select_placeholder();
200 rendererSelect.value = rendererTypesMapping[chartType][0]
201 }
202 });
203 });
204
205 // Update the chart list on user interaction.
206 rendererSelect.addEventListener('change', (event) => {
207 disable_renderer_select_placeholder();
208 toggle_renderer_type( event.target.value );
209 toggle_chart_types_by_render( event.target.value );
210 });
211
212 }
213
214 /**
215 * Disable the placeholder option in the renderer select.
216 */
217 function disable_renderer_select_placeholder() {
218 const placeholderOption = document.querySelector('#library-select-placeholder');
219 if ( placeholderOption && placeholderOption.disabled === false ) {
220 placeholderOption.disabled = true;
221 }
222 }
223
224 /**
225 * Toggle the renderer type class based on the given renderer type.
226 *
227 * The class is used to style the chart type picker based on the given renderer library.
228 *
229 * @param {('GoogleCharts' | 'ChartJS' | 'DataTable')} rendererType The renderer type to toggle the class.
230 */
231 function toggle_renderer_type( rendererType ) {
232 const typePicker = document.querySelector('#type-picker');
233 if ( ! typePicker ) {
234 return;
235 }
236
237 typePicker.classList.remove('lib-GoogleCharts', 'lib-ChartJS', 'lib-DataTable');
238 typePicker.classList.add(`lib-${rendererType}`);
239 }
240
241 /**
242 * Toggle chart types based on the given renderer type.
243 *
244 * @param {('GoogleCharts' | 'ChartJS' | 'DataTable')} rendererType The renderer type to filter the chart types.
245 */
246 function toggle_chart_types_by_render( rendererType ) {
247 document.querySelectorAll('.type-box').forEach( typeBox => {
248 const hasLib = typeBox.classList.contains(`type-lib-${rendererType}`);
249 typeBox.classList.toggle('viz-hidden', ! hasLib );
250
251 // Reset unavailable chart type selection.
252 const chartOption = typeBox.querySelector('input[type="radio"]');
253 if ( ! hasLib && chartOption?.checked ) {
254 chartOption.checked = false;
255 }
256 });
257
258 enable_libraries_for($('input.type-radio:checked').val(), $typeVsLibrary);
259 }
260
261 function enable_libraries_for($type, $typeVsLibrary) {
262 $('select.viz-select-library option').addClass('disabled').attr('disabled', 'disabled');
263 $('select.viz-select-library option .premium-label').remove();
264 $('select.viz-select-library option').append('<span class="premium-label"> (PREMIUM)</span>');
265 var $libs = $typeVsLibrary[$type];
266 $.each($libs, function( i, $lib ) {
267 $('select.viz-select-library option[value="' + $lib + '"]').removeClass('disabled').removeAttr('disabled');
268 $('select.viz-select-library option[value="' + $lib + '"] .premium-label').remove();
269 });
270 $('select.viz-select-library').val( $('select.viz-select-library option:not(.disabled)').val() );
271 }
272
273 function init_permissions(){
274 $('.visualizer-permission').chosen({
275 width : '50%',
276 search_contains : true
277 });
278
279 $('.visualizer-permission-type').each(function(x, y){
280 var type = $(y).attr('data-visualizer-permission-type');
281 var child = $('.visualizer-permission-' + type + '-specific');
282 if($(y).val() === 'all'){
283 child.next('div.chosen-container').hide();
284 return;
285 }
286 });
287
288 $('.visualizer-permission-type').on('change', function(evt, params) {
289 var type = $(this).attr('data-visualizer-permission-type');
290 var child = $('.visualizer-permission-' + type + '-specific');
291 child.empty();
292 if(params.selected === 'all'){
293 child.next('div.chosen-container').hide();
294 return;
295 } else {
296 child.next('div.chosen-container').show();
297 }
298 child.append('<option value="">' + visualizer.l10n['loading'] + '</option>').trigger('chosen:updated');
299 $.ajax({
300 url : visualizer.ajax['url'],
301 method : 'post',
302 data : {
303 'action' : visualizer.ajax['actions']['permissions'],
304 'nonce' : visualizer.ajax['nonces']['permissions'],
305 'type' : params.selected
306 },
307 success : function(d, textStatus, XMLHttpRequest){
308 if(d.success) {
309 child.empty();
310 $.each(d.data, function(k, v){
311 child.append('<option value="' + k + '">' + v + '</option>');
312 });
313 child.trigger('chosen:updated');
314 }
315 }
316 });
317 });
318 }
319
320 // https://codemirror.net/
321 function init_db_import_component(){
322 var table_columns = visualizer.db_query.tables;
323 var code_mirror = wp.CodeMirror || CodeMirror;
324 var cm = code_mirror.fromTextArea($('.visualizer-db-query').get(0), {
325 value: $('.visualizer-db-query').val(),
326 autofocus: true,
327 mode: 'text/x-mysql',
328 lineWrapping: true,
329 dragDrop: false,
330 matchBrackets: true,
331 autoCloseBrackets: true,
332 extraKeys: {"Shift-Space": "autocomplete"},
333 hintOptions: { tables: table_columns }
334 });
335
336 // force refresh so that the query shows on first time load. Otherwise you have to click on the editor for it to show.
337 $('body').on('visualizer:db:query:focus', function(event, data){
338 cm.refresh();
339 });
340
341 cm.focus();
342
343 // update text area.
344 cm.on('inputRead', function(x, y){
345 cm.save();
346 });
347
348 // backspace and delete do not register so the text box does not get empty if the entire query is deleted
349 // from the editor. Let's force this.
350 $('body').on('visualizer:db:query:update', function(event, data){
351 cm.save();
352 });
353
354 // clear the editor.
355 $('body').on('visualizer:db:query:setvalue', function(event, data){
356 cm.setValue(data.value);
357 cm.clearHistory();
358 cm.refresh();
359 });
360
361 // set an option at runtime?
362 $('body').on('visualizer:db:query:changeoption', function(event, data){
363 cm.setOption(data.name, data.value);
364 });
365 }
366
367 function init_filter_import() {
368 $( '#db-filter-save-button' ).on( 'click', function(){
369 $('#vz-filter-wizard').submit();
370 });
371 }
372
373 function init_db_import(){
374 $( '#visualizer-db-query' ).css("z-index", "-1").hide();
375
376 init_db_import_component();
377
378 $('#visualizer-query-fetch').on('click', function(e){
379
380 $('body').trigger('visualizer:db:query:update', {});
381 if($('.visualizer-db-query').val() === ''){
382 return;
383 }
384
385 start_ajax($('#visualizer-db-query'));
386 $('.db-wizard-results').empty();
387 $('.db-wizard-error').empty();
388 $.ajax({
389 url : ajaxurl,
390 method : 'post',
391 data : {
392 'action' : visualizer.ajax['actions']['db_get_data'],
393 'security' : visualizer.ajax['nonces']['db_get_data'],
394 'params' : $('#db-query-form').serialize()
395 },
396 success : function(data){
397 if(data.success){
398 $('.db-wizard-results').html(data.data.table);
399 $('#results').DataTable({
400 "paging": false
401 });
402 }else{
403 $('.db-wizard-error').html(data.data.msg);
404 }
405 },
406 complete: function(){
407 end_ajax($('#visualizer-db-query'));
408 }
409 });
410 });
411
412 $( '#db-chart-button' ).on( 'click', function(){
413
414 $('body').off('visualizer:change:action').on('visualizer:change:action', function(e){
415 var filter_button = $( '#db-chart-button' );
416 $( '#visualizer-db-query' ).css("z-index", "-1").hide();
417 filter_button.val( filter_button.attr( 'data-t-chart' ) );
418 filter_button.html( filter_button.attr( 'data-t-chart' ) );
419 filter_button.attr( 'data-current', 'chart' );
420 $( '#canvas' ).css("z-index", "1").show();
421 });
422
423 $('#content').css('width', 'calc(100% - 350px)');
424 if( $(this).attr( 'data-current' ) === 'chart'){
425 $(this).val( $(this).attr( 'data-t-filter' ) );
426 $(this).html( $(this).attr( 'data-t-filter' ) );
427 $(this).attr( 'data-current', 'filter' );
428 $( '.visualizer-editor-lhs' ).hide();
429 $( '#visualizer-db-query' ).css("z-index", "9999").show();
430 $('body').trigger('visualizer:db:query:focus', {});
431 $( '#canvas' ).hide();
432 }else{
433 var filter_button = $(this);
434 $( '#visualizer-db-query' ).css("z-index", "-1").hide();
435 $('#canvas').lock();
436 filter_button.val( filter_button.attr( 'data-t-chart' ) );
437 filter_button.html( filter_button.attr( 'data-t-chart' ) );
438 filter_button.attr( 'data-current', 'chart' );
439 $( '#canvas' ).css("z-index", "1").show();
440 $( '#db-chart-save-button' ).trigger('click');
441 }
442 } );
443
444 $( '#db-chart-save-button' ).on( 'click', function(){
445 // submit only if a query has been provided.
446 if($('#db-query-form .visualizer-db-query').val().length > 0){
447 $('#viz-db-wizard-params').val($('#db-query-form').serialize());
448 $('#vz-db-wizard').submit();
449 }else{
450 $('#canvas').unlock();
451 }
452 });
453 }
454
455 function init_json_import(){
456 if(typeof visualizer === 'undefined'){
457 return;
458 }
459
460 var regex = new RegExp(visualizer.json_tag_separator, 'g');
461
462 $( '#visualizer-json-screen' ).css("z-index", "-1").hide();
463 $('.visualizer-json-form').accordion({
464 heightStyle: 'content',
465 active: 0
466 });
467 $('.visualizer-json-subform').accordion({
468 heightStyle: 'content',
469 active: false,
470 collapsible: true
471 });
472
473 // open the accordions by default if they are indicated with the 'open' class.
474 $('.visualizer-json-subform .viz-substep.open').each(function(i, e){
475 $('.visualizer-json-subform').accordion( "option", "active", i );
476 });
477
478 // toggle between chart and create/modify parameters
479 $( '#json-chart-button, #woo-chart-button' ).on( 'click', function(){
480
481 $('body').off('visualizer:change:action').on('visualizer:change:action', function(e){
482 var filter_button = $( '#json-chart-button, #woo-chart-button' );
483 $( '#visualizer-json-screen' ).css("z-index", "-1").hide();
484 filter_button.val( filter_button.attr( 'data-t-chart' ) );
485 filter_button.html( filter_button.attr( 'data-t-chart' ) );
486 filter_button.attr( 'data-current', 'chart' );
487 $( '#canvas' ).css("z-index", "1").show();
488 $( '#vz-import-woo-report' ).find( 'select, input' ).removeAttr( 'disabled' );
489 });
490
491 if ( 'json-chart-button' === $( this ).attr( 'id' ) ) {
492 $( '#vz-import-woo-report' ).find( 'select, input' ).attr( 'disabled', true );
493 } else {
494 $( '#vz-import-woo-report' ).find( 'select, input' ).removeAttr( 'disabled' );
495 }
496 $('#content').css('width', 'calc(100% - 100px)');
497 if( $(this).attr( 'data-current' ) === 'chart'){
498 // toggle from chart to LHS form
499 $(this).val( $(this).attr( 'data-t-filter' ) );
500 $(this).html( $(this).attr( 'data-t-filter' ) );
501 $(this).attr( 'data-current', 'filter' );
502 $( '.visualizer-editor-lhs' ).hide();
503 $( '#visualizer-json-screen' ).css("z-index", "9999").show();
504 if ( 'woo-chart-button' === $( this ).attr( 'id' ) && '' !== $( '#vz-woo-source:visible' ).val() ) {
505 $( '#vz-import-json-url' ).val( visualizer.rest_base + $( '#vz-woo-source' ).val() ).attr( 'readonly', true );
506 } else {
507 if ( 'undefined' !== $( '#vz-import-json-url' ).attr( 'readonly' ) ) {
508 $( '#vz-import-json-url' ).val( '' ).removeAttr( 'readonly' ).removeAttr( 'value' );
509 $('#json-endpoint-form')[0].reset();
510 $('.visualizer-json-form h3.viz-step:not(.step1)').addClass('ui-state-disabled');
511 }
512 }
513 $( '#canvas' ).hide();
514 }else{
515 // toggle from LHS form to chart
516 $( '#json-conclude-form' ).trigger('submit');
517 }
518 } );
519
520 $('body').on('visualizer:json:form:submit', function() {
521 var filter_button = $( '#json-chart-button, #woo-chart-button' );
522 $( '#visualizer-json-screen' ).css("z-index", "-1").hide();
523 $('#canvas').lock();
524 filter_button.val( filter_button.attr( 'data-t-chart' ) );
525 filter_button.html( filter_button.attr( 'data-t-chart' ) );
526 filter_button.attr( 'data-current', 'chart' );
527 end_ajax( $( '#visualizer-json-screen' ) );
528 $( '#canvas' ).removeClass('visualizer-chart-loaded').css("z-index", "1").show();
529 });
530
531
532 // fetch the roots for the provided endpoint
533 $( '#visualizer-json-fetch' ).on( 'click', function(e){
534 e.preventDefault();
535 $('.visualizer-json-form').accordion( 'option', 'active', 0 );
536 $('.visualizer-json-form h3.viz-step:not(.step1)').addClass('ui-state-disabled');
537 $('.json-table').html('');
538 start_ajax( $( '#visualizer-json-screen' ) );
539 $.ajax({
540 url : ajaxurl,
541 method : 'post',
542 data : {
543 'action' : visualizer.ajax['actions']['json_get_roots'],
544 'security' : visualizer.ajax['nonces']['json_get_roots'],
545 'params' : $('#json-endpoint-form').serialize()
546 },
547 success : function(data){
548 if(data.success){
549 $('#vz-import-json-root').empty();
550 $.each(data.data.roots, function(i, name){
551 $('#vz-import-json-root').append('<option value="' + name + '">' + name.replace(regex, visualizer.json_tag_separator_view) + '</option>');
552 });
553 $('#json-root-form').fadeIn('medium');
554 json_accordion_activate(1, true);
555 }else{
556 alert(data.data.msg);
557 }
558 },
559 complete: function(){
560 end_ajax($('#visualizer-json-screen'));
561 }
562 });
563 });
564
565 // fetch the data for the chosen root
566 $( '#visualizer-json-parse' ).on( 'click', function(e){
567 e.preventDefault();
568 $('.visualizer-json-form h3.viz-step:not(.step1):not(.step2)').addClass('ui-state-disabled');
569 $('.json-table').html('');
570 start_ajax( $( '#visualizer-json-screen' ) );
571 $.ajax({
572 url : ajaxurl,
573 method : 'post',
574 data : {
575 'action' : visualizer.ajax['actions']['json_get_data'],
576 'security' : visualizer.ajax['nonces']['json_get_data'],
577 'params' : $('#json-root-form, #json-endpoint-form').serialize()
578 },
579 success : function(data){
580 if(data.success){
581 $('#vz-import-json-paging option:not(.static)').remove();
582 if(data.data.paging.length > 0){
583 var $template = $('#vz-import-json-paging').attr('data-template');
584 $.each(data.data.paging, function(i, name){
585 var display = name.replace(regex, visualizer.json_tag_separator_view);
586 display = $template.replace('?', display);
587 $('#vz-import-json-paging').append('<option value="' + name + '">' + display + '</option>');
588 });
589 $('.json-pagination').show();
590 }
591 $('#json-conclude-form .json-table').html(data.data.table);
592
593 var $table = create_editor_table( '#json-conclude-form' );
594
595 json_accordion_activate(3, true);
596 json_accordion_activate(2, false);
597 $table.columns.adjust().draw();
598 }else{
599 alert(data.data.msg);
600 }
601 },
602 complete: function(){
603 end_ajax($('#visualizer-json-screen'));
604 }
605 });
606 });
607
608 // when the data is set and the chart is updated, toggle the screen so that the chart is shown
609 $('#json-conclude-form').on( 'submit', function(e){
610 // at least one column has to be selected as non-excluded.
611 var count_selected = 0;
612 $('select.viz-select-data-type').each(function(i, element){
613 if($(element).prop('selectedIndex') > 0){
614 count_selected++;
615 }
616 });
617 if(count_selected === 0){
618 alert(visualizer.l10n.select_columns);
619 return false;
620 }
621
622 // populate the form elements that are in the other tabs.
623 $('#json-conclude-form-helper .json-form-element, #json-endpoint-form .json-form-element, #json-root-form .json-form-element, #vz-import-json .json-form-element, #vz-import-woo-report .json-form-element:not(:disabled)').each(function(x, y){
624 $('#json-conclude-form').append('<input type="hidden" name="' + y.name + '" value="' + y.value + '">');
625 });
626
627 $('body').trigger('visualizer:json:form:submit');
628 });
629
630 // update the schedule
631 $('#json-chart-save-button, #woo-chart-save-button').on('click', function(e){
632 e.preventDefault();
633 $('#canvas').lock();
634 var btnID = jQuery( this ).attr( 'id' );
635 $.ajax({
636 url : ajaxurl,
637 method : 'post',
638 data : {
639 'action' : visualizer.ajax['actions']['json_set_schedule'],
640 'security' : visualizer.ajax['nonces']['json_set_schedule'],
641 'chart' : $('#vz-json-time, #vz-woo-time').attr('data-chart'),
642 'time' : $('#vz-json-time, #vz-woo-time').val(),
643 'is_woocommerce_report': 'woo-chart-save-button' === btnID,
644 },
645 success : function(data){
646 // do nothing.
647 },
648 complete: function(){
649 $('#canvas').unlock();
650 }
651 });
652 });
653
654 // Select WooCommerce report endpoint.
655 $( '#vz-woo-source' ).on( 'click', function( e ) {
656 // Trigger change action.
657 $( 'body' ).trigger( 'visualizer:change:action' );
658
659 if ( '' !== $( this ).val() ) {
660 $( '#woo-chart-button, #woo-chart-save-button' ).removeAttr( 'disabled' );
661 } else {
662 $( '#woo-chart-button, #woo-chart-save-button' ).attr( 'disabled', true );
663 }
664 } );
665
666 }
667
668 function init_editor_table() {
669 $('body').on('visualizer:db:editor:table:init', function(event, data){
670 var $table = create_editor_table('.viz-table-editor', data.config);
671 $('body').on('visualizer:db:editor:table:redraw', function(event, data){
672 $table.draw();
673 });
674 });
675 }
676
677 function create_editor_table(element, config) {
678 var settings = {
679 paging: false,
680 searching: false,
681 ordering: false,
682 select: false,
683 scrollX: "100%",
684 scrollY: "400px",
685 info: false,
686 colReorder: {
687 fixedColumnsLeft: 1
688 }
689 };
690
691 // show column visibility button only when more than 6 columns are found (including the Label column)
692 if($(element + ' table.viz-editor-table thead tr th').length > 6){
693 $.extend( settings, {
694 dom: 'Bt',
695 buttons: [
696 {
697 extend: 'colvis',
698 columns: ':gt(0)',
699 collectionLayout: 'four-column'
700 }
701 ]
702 } );
703 }
704 if(config){
705 $.extend( settings, config );
706 }
707
708 var $table = $(element + ' .viz-editor-table').DataTable(settings);
709 return $table;
710 }
711
712 function json_accordion_activate($step, $activate){
713 $('.visualizer-json-form h3.viz-step.step' + ( $step + 1 )).removeClass('ui-state-disabled');
714 if($activate){
715 $('.visualizer-json-form').accordion( 'option', 'active', $step );
716 }
717 }
718
719 function start_ajax(element){
720 element.lock();
721 }
722
723 function end_ajax(element){
724 element.unlock();
725 }
726
727 })(jQuery);
728
729 (function ($) {
730 $.fn.lock = function () {
731 $(this).each(function () {
732 var $this = $(this);
733 var position = $this.css('position');
734
735 if (!position) {
736 position = 'static';
737 }
738
739 switch (position) {
740 case 'absolute':
741 case 'relative':
742 break;
743 default:
744 $this.css('position', 'relative');
745 break;
746 }
747 $this.data('position', position);
748
749 var width = $this.width(),
750 height = $this.height();
751
752 var locker = $('<div class="locker"></div>');
753 locker.width(width).height(height);
754
755 var loader = $('<div class="locker-loader"></div>');
756 loader.width(width).height(height);
757
758 locker.append(loader);
759 $this.append(locker);
760 $(window).resize(function () {
761 $this.find('.locker,.locker-loader').width($this.width()).height($this.height());
762 });
763 });
764
765 return $(this);
766 };
767
768 $.fn.unlock = function () {
769 $(this).each(function () {
770 $(this).find('.locker').remove();
771 $(this).css('position', $(this).data('position'));
772 });
773
774 return $(this);
775 };
776
777 // Telemetry
778 function getChartID() {
779 const urlParams = new URLSearchParams(window.location.search);
780 return urlParams.get('chart') ?? '';
781 }
782
783 const groupId = getChartID();
784
785 const chartTypes = document.querySelector('#viz-types-form')
786 if( chartTypes ) {
787 document.querySelector('.push-right[type=submit]')?.addEventListener('click', async function (event) {
788 if ( typeof window.tiTrk !== 'undefined' ) {
789 event.preventDefault();
790 try {
791 const formData = new FormData(document.querySelector('#viz-types-form'));
792 const savedData = Object.fromEntries(formData);
793
794 tiTrk?.with('visualizer')?.add({
795 feature: 'chart-create',
796 featureComponent: 'saved-data',
797 featureData: {
798 type: savedData?.['type'],
799 library: savedData?.['chart-library']
800 },
801 groupId
802 });
803
804 // Do not make the user to wait too long for the event to be uploaded.
805 const timer = new Promise((resolve) => setTimeout(resolve, 500));
806 await Promise.race([timer, tiTrk?.uploadEvents()]);
807 } catch (e) {
808 console.warn(e);
809 }
810 $('#viz-types-form').submit();
811 }
812 });
813 }
814
815 [
816 {
817 selector: '#editor-button',
818 featureComponent: 'source-manual-data'
819 },
820 {
821 selector: '#vz-import-file',
822 featureComponent: 'source-import-csv-file'
823 },
824 {
825 selector: '#vz-save-schedule',
826 featureComponent: 'source-import-csv-remote'
827 },
828 {
829 selector: '#visualizer-json-fetch',
830 featureComponent: 'source-import-json-remote'
831 },
832 {
833 selector: '#existing-chart',
834 featureComponent: 'source-import-chart'
835 },
836 {
837 selector: '#filter-chart-button',
838 featureComponent: 'source-import-wordpress',
839 },
840 {
841 selector: '#woo-chart-button',
842 featureComponent: 'source-import-woocommerce'
843 },
844 {
845 selector: '#db-chart-button',
846 featureComponent: 'source-import-database'
847 }
848 ].forEach(({ selector, featureComponent }) => {
849 document.querySelector(selector)?.addEventListener('click', function () {
850 window?.tiTrk?.with('visualizer')?.set('used-source',{
851 feature: 'chart-edit-used-source',
852 featureComponent,
853 groupId
854 });
855 });
856 });
857 })(jQuery);
858
859
860 document.querySelector('#viz-copy-shortcode')?.addEventListener('click', function() {
861 var copyText = document.querySelector('#viz-shortcode')?.value;
862 if ( !copyText ) {
863 return;
864 }
865
866 navigator.clipboard.writeText(copyText);
867 alert(visualizer.l10n.copied);
868 });
869
870 // Connect Chart Backend Title Info Panel with the field from the settings form.
871 const interactiveBackendTitleField = document.querySelector( '#viz-backend-name' );
872 const backendTitleSave = document.querySelector( '#settings-form input[name="backend-title"]' );
873
874 if ( interactiveBackendTitleField && backendTitleSave ) {
875 interactiveBackendTitleField.addEventListener('input', function() {
876 backendTitleSave.value = this.value;
877 });
878 }
879