PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 4.0.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v4.0.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 4.0.0, at js/frame.js

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