PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.9.6
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.9.6
1.9.6 1.9.5 1.9.4 1.9.3 trunk 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.6 1.6.1 1.6.10 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 All 41 releases
code-profiler / static / code-profiler.js

code-profiler.js in Code Profiler – WordPress Performance Profiling and Debugging Made Easy 1.9.6, at static/code-profiler.js

918 lines 23.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 +=====================================================================+
3 | ____ _ ____ __ _ _ |
4 | / ___|___ __| | ___ | _ \ _ __ ___ / _(_) | ___ _ __ |
5 | | | / _ \ / _` |/ _ \ | |_) | '__/ _ \| |_| | |/ _ \ '__| |
6 | | |__| (_) | (_| | __/ | __/| | | (_) | _| | | __/ | |
7 | \____\___/ \__,_|\___| |_| |_| \___/|_| |_|_|\___|_| |
8 | |
9 | (c) Jerome Bruandet ~ https://nintechnet.com/codeprofiler/ |
10 +=====================================================================+
11 */
12
13 // =====================================================================
14 // Generic stuff
15
16 // TipTip tooltip
17 jQuery( document ).ready(function( $ ) {
18 'use strict';
19 $('.code-profiler-tip').tipTip( {
20 'attribute': 'data-tip',
21 'fadeIn': 50,
22 'fadeOut': 50,
23 'delay': 100,
24 'maxWidth' : '350px'
25 });
26
27 // We remove the '&action=delete_profiles...' query string because
28 // if the user reloaded the page that would throw an error:
29 var url = window.location.href;
30 window.history.replaceState({},
31 document.title,
32 url.replace( /&action=delete_profiles&.+/, '')
33 );
34
35 });
36
37 // Append/clear the search query to/from the query string
38 function cpjs_search_query() {
39
40 'use strict';
41 var query;
42 if ( jQuery('#search_id-search-input').val().length > 0 ) {
43 query = '&s=' + jQuery('#search_id-search-input').val();
44 // Case sensitivity
45 if ( jQuery('#case-search-input').is(':checked') === true ) {
46 query += '&c=1';
47 }
48 jQuery('#profile-form').attr('action', jQuery('#profile-form').attr('action')+ query );
49
50 } else {
51 jQuery('#profile-form').attr('action','');
52 var url = window.location.href;
53 window.history.replaceState({},
54 document.title,
55 url.replace( /&s=[^&$]+/, '')
56 );
57 var url = window.location.href;
58 window.history.replaceState({},
59 document.title,
60 url.replace( /&c=1/, '')
61 );
62 }
63 }
64
65 // =====================================================================
66 // Summary page
67
68 function cpjs_front_or_backend( item ) {
69 'use strict';
70 // Enable/disable frontend/backend select box
71 // depending on user's choice
72 if ( item == 'frontend') {
73 jQuery('#p-frontend').show();
74 jQuery('#p-backend').hide();
75 jQuery('#p-custom').hide();
76 jQuery('#p-wpcron').hide();
77 jQuery('#id-frontend').focus();
78 jQuery('#user-unauthenticated').prop('disabled', false);
79 jQuery('#user-authenticated').prop('disabled', false);
80 } else if ( item == 'backend') {
81 jQuery('#p-backend').show();
82 jQuery('#p-frontend').hide();
83 jQuery('#p-custom').hide();
84 jQuery('#p-wpcron').hide();
85 jQuery('#id-backend').focus();
86 jQuery('#user-unauthenticated').prop('disabled', true);
87 jQuery('#user-authenticated').prop('disabled', false);
88 jQuery('#user-authenticated').prop('checked', true);
89 jQuery('#user-name').prop('disabled', false);
90 } else if ( item == 'custom') {
91 jQuery('#p-custom').show();
92 jQuery('#p-frontend').hide();
93 jQuery('#p-backend').hide();
94 jQuery('#p-wpcron').hide();
95 jQuery('#id-custom').focus();
96 jQuery('#user-unauthenticated').prop('disabled', false);
97 jQuery('#user-authenticated').prop('disabled', false);
98 } else {
99 jQuery('#p-wpcron').show();
100 jQuery('#p-custom').hide();
101 jQuery('#p-frontend').hide();
102 jQuery('#p-backend').hide();
103 jQuery('#id-wpcron').focus();
104 jQuery('#user-unauthenticated').prop('disabled', false);
105 }
106 }
107
108 function cpjs_authenticated( id ) {
109 if ( id == 1 ) {
110 jQuery('#user-name').prop('disabled', false);
111 jQuery('#user-name').focus();
112 } else {
113 jQuery('#user-name').prop('disabled', true);
114 }
115 }
116
117 function cpjs_show_adv_settings() {
118 jQuery('#cp-advanced-settings').slideDown();
119 jQuery('#button-adv-settings').prop('disabled', true);
120 }
121
122 function cpjs_get_post( id ) {
123 if ( id == 1 ) {
124 jQuery('#post-value').prop('disabled', false);
125 jQuery('#id-content-type').prop('disabled', false);
126 jQuery('#post-value').focus();
127 } else {
128 jQuery('#post-value').prop('disabled', true);
129 jQuery('#id-content-type').prop('disabled', true);
130 }
131 }
132
133 function cpjs_content_type( value ) {
134 if ( value == 1 ) {
135 jQuery('#ct-1').slideDown();
136 jQuery('#ct-3').slideUp();
137 jQuery('#ct-2').slideUp();
138 } else if ( value == 2 ) {
139 jQuery('#ct-2').slideDown();
140 jQuery('#ct-3').slideUp();
141 jQuery('#ct-1').slideUp();
142 } else {
143 jQuery('#ct-3').slideDown();
144 jQuery('#ct-1').slideUp();
145 jQuery('#ct-2').slideUp();
146 }
147 }
148
149 function cpjs_isJSON( data ) {
150
151 if ( jQuery('#id-content-type').val() == 1 || jQuery('#get-method').prop('checked') == true ) {
152 // Ignore
153 return 1;
154 }
155 try {
156 return JSON.parse( data );
157 } catch (e) {
158 // Not a JSON-encoded string
159 return null;
160 }
161 }
162
163 function cpjs_ismultiline( data ) {
164 if ( data.match( /[\n\r]/) ) {
165 return true;
166 }
167 return false;
168 }
169
170 // =====================================================================
171 // Log page: filter and delete the log.
172
173 function cpjs_filter_log() {
174 'use strict';
175 // Create bitmask
176 var bitmask = 0;
177 if ( document.cplogform.info.checked == true ) { bitmask += 1; }
178 if ( document.cplogform.warn.checked == true ) { bitmask += 2; }
179 if ( document.cplogform.error.checked == true ) { bitmask += 4; }
180 if ( document.cplogform.debug.checked == true ) { bitmask += 8; }
181
182 // Clear the textarea
183 document.cplogform.cptxtlog.value = '';
184
185 // Browser through our array and return only selected verbosity
186 var cp_count = 0;
187 var i = 0;
188 for ( i = 0; i < cplog_array.length; ++i ) {
189 var line = decodeURIComponent( cplog_array[i] );
190 var line_array = line.split('~~', 2 );
191 if ( line_array[0] & bitmask ) {
192 document.cplogform.cptxtlog.value += line_array[1];
193 ++cp_count;
194 }
195 }
196 if ( cp_count == 0 ) {
197 document.cplogform.cptxtlog.value = '\n > ' + cpi18n.empty_log;
198 }
199 }
200
201 function cpjs_delete_log() {
202 'use strict';
203 if ( confirm( cpi18n.delete_log ) ) {
204 return true;
205 }
206 return false;
207 }
208 // =====================================================================
209 // AJAX call to start the profiler.
210
211 function cpjs_start_profiler() {
212
213 'use strict';
214
215 jQuery('html, body').animate( {
216 scrollTop: jQuery('#button-adv-settings').offset().top
217 }, 1000 );
218
219 // Get the nonce
220 var cp_nonce = jQuery('#cp_nonce').val();
221 if ( cp_nonce == '') {
222 alert( cpi18n.missing_nonce );
223 return;
224 }
225
226 // Get the scan type (frontend/backend)
227 var post;
228 var x_end = jQuery('input[name="x_end"]:checked').val();
229 if ( x_end == 'frontend') {
230 post = jQuery('#id-frontend').val();
231
232 } else if ( x_end == 'backend') {
233 post = jQuery('#id-backend').val();
234
235 } else if ( x_end == 'custom') {
236 post = jQuery('#id-custom').val().trim(); // Trim user input
237
238 } else if ( x_end == 'wpcron') {
239 post = jQuery('#id-wpcron').val();
240 if ( post == 0 ) {
241 alert( cpi18n.missing_wpcron );
242 return;
243 }
244
245 } else {
246 alert( cpi18n.missing_frontbackend );
247 return;
248 }
249 if ( post == '') {
250 alert( cpi18n.missing_post );
251 return;
252 }
253
254 // Get the profile's name
255 var profile = jQuery('input[name="profile"]').val();
256 if ( profile == '') {
257 alert( cpi18n.missing_profilename );
258 jQuery('input[name="profile"]').focus();
259 return;
260 }
261
262 var x_auth = jQuery('input[name="x_auth"]:checked').val();
263 if ( x_auth == '') {
264 alert( cpi18n.missing_userauth );
265 return;
266 }
267
268 var username = jQuery('#user-name').val().trim(); // Trim user input
269 if ( x_auth == 'authenticated') {
270 if ( username == '') {
271 alert( cpi18n.missing_username );
272 jQuery('#user-name').focus();
273 return;
274 }
275 }
276
277 var user_agent = jQuery('#ua-id').val();
278 if ( user_agent == 'undefined') {
279 user_agent = 'FireFox';
280 }
281
282 var theme = jQuery('#id-theme').val();
283
284 // GET or POST
285 var method = jQuery('input[name="method"]:checked').val();
286 var payload = '';
287 if ( method == 'post') {
288 // Payload
289 payload = jQuery('#post-value').val();
290 } else {
291 method = 'get';
292 }
293
294 //Content type
295 var ct = jQuery('#id-content-type').val();
296 if ( ct == 2 ) {
297 // application/json
298 if ( cpjs_isJSON( payload ) == null ) {
299 alert( cpi18n.missing_ajax );
300 jQuery('#user-name').focus();
301 return;
302 }
303 } else if ( ct == 3 ) {
304 // Raw format must be on one single line
305 if ( cpjs_ismultiline( payload.trim() ) == true ) {
306 alert( cpi18n.multiline_raw );
307 jQuery('#post-value').focus();
308 return;
309 }
310 }
311
312 var cookies = jQuery('#cp-cookies').val();
313 var headers = jQuery('#custom-headers').val();
314 var exclusions = jQuery('#exclusions').val();
315
316 // Change buttons status and add animated image with status message
317 jQuery('#start-profile').prop('disabled', true);
318 jQuery('#cp-progress-div').slideDown();
319 jQuery('#progress-gif').slideDown();
320 jQuery('#progress-text').slideDown();
321 jQuery('#code-profiler-error').slideUp();
322 jQuery('#cp-span-progress').css('width', '30%');
323
324 var data = {
325 'action': 'codeprofiler_start_profiler',
326 'cp_nonce': cp_nonce,
327 'x_end': x_end,
328 'post': post,
329 'content_type': ct,
330 'profile': profile,
331 'x_auth': x_auth,
332 'username': username,
333 'cookies': cookies,
334 'custom_headers': headers,
335 'exclusions': exclusions,
336 'method': method,
337 'payload': payload,
338 'user_agent': user_agent,
339 'theme': theme
340 };
341 // Send the request via AJAX
342 jQuery.ajax( {
343 type: 'POST',
344 url: ajaxurl,
345 data: data,
346 dataType: 'json',
347 success: function( response ) {
348
349 if (typeof response === 'undefined') {
350 cpjs_start_error('<p>'+ cpi18n.unknown_error +'</p>');
351 return;
352 }
353
354 if ( response.status != 'success') {
355 cpjs_start_error('<p>'+ response.message +'</p>');
356 return;
357 }
358
359 // ------------------------------------------------------------
360 // Inform the user we're moving to step 2
361 jQuery('#cp-span-progress').css('width', '70%');
362 jQuery('#progress-text').html( cpi18n.preparing_report );
363
364 data['action'] = 'codeprofiler_prepare_report';
365 data['microtime'] = response.microtime;
366 jQuery.ajax( {
367 type: 'POST',
368 url: ajaxurl,
369 data: data,
370 dataType: 'json',
371 success: function( response ) {
372
373 if (typeof response === 'undefined') {
374 cpjs_start_error('<p>'+ cpi18n.unknown_error +'</p>');
375 return;
376 }
377
378 if ( response.status != 'success') {
379 cpjs_start_error('<p>'+ response.message +'</p>');
380 return;
381 }
382 var cp_uri;
383 if (response.cp_profile !== 'undefined' && response.cp_profile != '') {
384 cp_uri = '&cptab=profiles_list&action=view_profile&id=' + response.cp_profile + '&section=1';
385 } else {
386 cp_uri = '&cptab=profiles_list';
387 }
388
389 // All good, redirect to the Profiles List tab
390 jQuery('#cp-span-progress').css('width', '100%');
391 window.location.href = window.location.href + cp_uri;
392 return;
393
394 },
395
396 // Display non-200 HTTP response
397 error: function( xhr, status, err ) {
398 if ( err != '') {
399 if ( xhr.status != 0 ) {
400 var message = cpi18n.http_error +' '+ xhr.status +' '+ err;
401 // Timeout
402 if ( xhr.status == 503 || xhr.status == 504 ) {
403 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.timeout_error +'.</p>');
404 // Redirections, not found
405 } else if ( xhr.status == 301 || xhr.status == 302 || xhr.status == 404 ) {
406 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.notfound_error +'.</p>');
407 // Forbidden
408 } else if ( xhr.status == 403 ) {
409 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.forbidden_error +'.</p>');
410 // Internal error
411 } else if ( xhr.status == 500 ) {
412 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.internal_error +'.<br />'+ cpi18n.timeout_error +'.</p>');
413 } else {
414 cpjs_start_error('<p>'+ cpi18n.http_error +' '+ xhr.status +' '+ err +'.</p>');
415 }
416 return;
417
418 } else {
419 cpjs_start_error('<p>'+ cpi18n.unknown_error +' '+ err +'.</p>');
420 return;
421 }
422 }
423 return;
424 }
425 });
426 // ------------------------------------------------------------
427 },
428
429 // Display non-200 HTTP response
430 error: function( xhr, status, err ) {
431 if ( err != '') {
432 if ( xhr.status != 0 ) {
433 var message = cpi18n.http_error +' '+ xhr.status +' '+ err;
434 // Timeout
435 if ( xhr.status == 503 || xhr.status == 504 ) {
436 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.timeout_error +'.</p>');
437 // Redirections, not found
438 } else if ( xhr.status == 301 || xhr.status == 302 || xhr.status == 404 ) {
439 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.notfound_error +'.</p>');
440 // Forbidden
441 } else if ( xhr.status == 403 ) {
442 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.forbidden_error +'.</p>');
443 // Internal error
444 } else if ( xhr.status == 500 ) {
445 cpjs_start_error('<p>'+ message +'<br />'+ cpi18n.internal_error +'.<br />'+ cpi18n.timeout_error +'.</p>');
446 } else {
447 cpjs_start_error('<p>'+ cpi18n.http_error +' '+ xhr.status +' '+ err +'.</p>');
448 }
449 return;
450
451 } else {
452 cpjs_start_error('<p>'+ cpi18n.unknown_error +' '+ err +'.</p>');
453 return;
454 }
455 }
456 return;
457 }
458 });
459 }
460
461 // Display error
462 function cpjs_start_error( error ) {
463 'use strict';
464 jQuery('#start-profile').prop('disabled', false);
465 jQuery('#progress-gif').slideUp();
466 jQuery('#progress-text').slideUp();
467 jQuery('#cp-span-progress').css('width', '0%');
468 jQuery('#code-profiler-error').html( error );
469 jQuery('#code-profiler-error').slideDown();
470 jQuery('#cp-progress-div').slideUp();
471
472 }
473
474 // =====================================================================
475 // Profiles List page.
476
477 function cpjs_delete_profile() {
478 'use strict';
479 if ( confirm( cpi18n.delete_profile ) ) {
480 return true;
481 }
482 return false;
483 }
484
485 // Hide/show the edit box and buttons when renaming a profile.
486 function cpjs_toggle_name( row ) {
487 if ( jQuery('#profile_div_'+ row).css('display') == 'none') {
488 jQuery('#profile_name_'+ row).hide();
489 jQuery('#profile_div_'+ row).show();
490 jQuery('#edit-'+ row).val( jQuery('#profile_name_'+ row).html() );
491 jQuery('#edit-'+ row).focus();
492 } else {
493 jQuery('#profile_div_'+ row).hide();
494 jQuery('#profile_name_'+ row).show();
495 }
496 }
497
498 // Edit the profile name via AJAX endpoint.
499 function cpjs_edit_name( profile, id, cp_nonce, row ) {
500
501 'use strict';
502
503 if ( cp_nonce == '') {
504 alert( cpi18n.missing_nonce );
505 return;
506 }
507 if ( profile == '') {
508 alert( cpi18n.missing_profileid );
509 return;
510 }
511
512 var new_name = jQuery('#edit-'+ id).val().trim();
513 if ( new_name == '') {
514 alert( cpi18n.missing_profilename );
515 return;
516 }
517
518 jQuery('#profile_spinner_'+ row).addClass('is-active');
519
520 var data = {
521 'action': 'codeprofiler_rename',
522 'cp_nonce': cp_nonce,
523 'new_name': new_name,
524 'profile': profile,
525 };
526
527 // Send the request via AJAX
528 jQuery.ajax( {
529 type: 'POST',
530 url: ajaxurl,
531 data: data,
532 dataType: 'json',
533 success: function( response ) {
534 jQuery('#profile_spinner_'+ row ).removeClass('is-active');
535
536 if (typeof response === 'undefined') {
537 alert( cpi18n.unknown_error );
538 return;
539 }
540
541 if ( response.status != 'success') {
542 alert( response.message );
543 return;
544 }
545
546 // Success: update the name in the table
547 jQuery('#profile_name_'+ id).html( response.newname );
548 cpjs_toggle_name(row);
549 },
550 // Display non-200 HTTP response
551 error: function( xhr, status, err ) {
552 jQuery('#profile_spinner_'+ row ).removeClass('is-active');
553 if ( err != '') {
554 if ( xhr.status != 0 ) {
555 var message = cpi18n.http_error +' '+ xhr.status +' '+ err;
556 // Timeout
557 if ( xhr.status == 503 || xhr.status == 504 ) {
558 alert( message +'<br />'+ cpi18n.timeout_error );
559 // Redirections, not found
560 } else if ( xhr.status == 301 || xhr.status == 302 || xhr.status == 404 ) {
561 alert( message +'<br />'+ cpi18n.notfound_error );
562 // Forbidden
563 } else if ( xhr.status == 403 ) {
564 alert( message +'<br />'+ cpi18n.forbidden_error );
565 // Internal error
566 } else if ( xhr.status == 500 ) {
567 alert( message +'<br />'+ cpi18n.internal_error +'.<br />'+ cpi18n.timeout_error );
568 } else {
569 alert( cpi18n.http_error +' '+ xhr.status +' '+ err );
570 }
571 return;
572
573 } else {
574 alert( cpi18n.unknown_error +' '+ err );
575 return;
576 }
577 }
578 return;
579 }
580 });
581 }
582
583 // =====================================================================
584 // Plugins/Theme chart.
585
586 function cpjs_plugins_chart( caxis, clabel, cdata, ctotal_time ) {
587 'use strict';
588 // Switch between vertical and horizontal bars
589 var _indexAxis = caxis;
590 document.getElementById('htov').onclick = function() {
591 if ( _indexAxis == 'x') {
592 _indexAxis = 'y';
593 } else {
594 _indexAxis = 'x';
595 }
596 myChart.destroy();
597 myChart = new Chart(ctx, {
598 type: 'bar',
599 options: {
600 animation: {
601 duration: 1000,
602 },
603 indexAxis: _indexAxis,
604 plugins: chartPlugins
605 },
606 plugins:[ plugin],
607 data: chartData
608 });
609 };
610
611 var ctx = document.getElementById('myChart').getContext('2d');
612
613 var chartData = {
614 labels: clabel,
615 datasets: [{
616 label: cpi18n.exec_sec_plugins,
617 backgroundColor: 'rgba(204, 0, 0, .5)',
618 borderColor: '#c00',
619 borderWidth: 2,
620 hoverBackgroundColor: '#B45252',
621 data: cdata
622 }]
623 };
624
625 const total_time = ctotal_time;
626 const footer = (tooltipItems) => {
627 var sum;
628 tooltipItems.forEach(function(tooltipItem) {
629 if ( _indexAxis == 'x') {
630 sum = Math.round( ( tooltipItem.parsed.y / total_time ) * 100 );
631 } else {
632 sum = Math.round( ( tooltipItem.parsed.x / total_time ) * 100 );
633 }
634 });
635 return sum + cpi18n.pc_plugins;
636 };
637
638 var chartPlugins = {
639 title: {
640 display: true,
641 text: cpi18n.exec_tot_plugins_1 +' (' + cpi18n.chart_total +' '+ ctotal_time +')'
642 },
643 legend: {
644 display: false
645 },
646 tooltip: {
647 borderWidth: 1,
648 borderColor: '#666',
649 displayColors: false,
650 backgroundColor: '#F5F5B5',
651 titleColor:'#666',
652 padding: 8,
653 footerColor: '#666',
654 callbacks: {
655 footer: footer,
656 labelTextColor: function(context) {
657 return '#543453';
658 }
659 }
660 }
661 }
662
663 // We want a background colour for the downloaded PNG file
664 const plugin = {
665 id: 'custom_canvas_background_color',
666 beforeDraw: (chart) => {
667 const ctx = chart.canvas.getContext('2d');
668 ctx.save();
669 ctx.globalCompositeOperation = 'destination-over';
670 ctx.fillStyle = '#f0f0f1',
671 ctx.fillRect(0, 0, chart.width, chart.height);
672 ctx.restore();
673 }
674 }
675
676 var myChart = new Chart(ctx, {
677 type: 'bar',
678 data: chartData,
679 options: {
680 animation: {
681 duration: 700,
682 onComplete: function() {
683 jQuery('#cp-footer-buttons').slideDown(200);
684 }
685 },
686 indexAxis: _indexAxis,
687 plugins: chartPlugins
688 },
689 plugins:[plugin]
690 });
691
692 document.getElementById('download-png-img').onclick = function() {
693 var a = document.createElement('a');
694 a.href = myChart.toBase64Image();
695 a.download = jQuery('#download-png-img').attr('download');
696 a.click();
697 }
698 }
699
700 // =====================================================================
701 // File I/O chart.
702
703 function cpjs_iostats_chart( caxis, clabel, cdata, ctotal_calls ) {
704 'use strict';
705 // Switch between vertical and horizontal bars
706 var _indexAxis = caxis;
707 document.getElementById('htov').onclick = function() {
708 if ( _indexAxis == 'x') {
709 _indexAxis = 'y';
710 } else {
711 _indexAxis = 'x';
712 }
713 myChart.destroy();
714 myChart = new Chart(ctx, {
715 type: 'line',
716 options: {
717 animation: {
718 duration: 1000,
719 },
720 indexAxis: _indexAxis,
721 plugins: chartPlugins
722 },
723 plugins:[ plugin],
724 data: chartData
725 });
726 };
727
728 var ctx = document.getElementById('myChart').getContext('2d');
729
730 var chartData = {
731 labels: clabel,
732 datasets: [{
733 label: cpi18n.iolist_total_calls,
734 backgroundColor: 'rgba(34, 113, 177, .5)',
735 borderColor: '#2271B1',
736 borderWidth: 2,
737 hoverBackgroundColor: '#FF0000',
738 data: cdata,
739 fill: 'origin',
740 radius: 6,
741 pointBackgroundColor: '#B45252'
742 }]
743 };
744 var chartPlugins = {
745 title: {
746 display: true,
747 text: cpi18n.io_calls +' (' + cpi18n.chart_total +' '+ ctotal_calls +')'
748 },
749 legend: {
750 display: false
751 },
752 tooltip: {
753 borderWidth: 1,
754 borderColor: '#666',
755 displayColors: false,
756 backgroundColor: '#F5F5B5',
757 titleColor:'#666',
758 padding: 8,
759 footerColor: '#666',
760 callbacks: {
761 labelTextColor: function(context) {
762 return '#543453';
763 }
764 }
765 }
766 }
767 // We want a background colour for the downloaded PNG file
768 const plugin = {
769 id: 'custom_canvas_background_color',
770 beforeDraw: (chart) => {
771 const ctx = chart.canvas.getContext('2d');
772 ctx.save();
773 ctx.globalCompositeOperation = 'destination-over';
774 ctx.fillStyle = '#f0f0f1',
775 ctx.fillRect(0, 0, chart.width, chart.height);
776 ctx.restore();
777 }
778 }
779
780 var myChart = new Chart(ctx, {
781 type: 'line',
782 data: chartData,
783 options: {
784 animation: {
785 duration: 700,
786 onComplete: function() {
787 jQuery('#cp-footer-buttons').slideDown(200);
788 }
789 },
790 indexAxis: _indexAxis,
791 plugins: chartPlugins
792 },
793 plugins:[plugin]
794 });
795
796 document.getElementById('download-png-img').onclick = function() {
797 var a = document.createElement('a');
798 a.href = myChart.toBase64Image();
799 a.download = jQuery('#download-png-img').attr('download');
800 a.click();
801 }
802
803 }
804 // =====================================================================
805 // Disk I/O chart.
806
807 function cpjs_diskio_chart( caxis, clabel, cdata ) {
808 'use strict';
809 // Switch between vertical and horizontal bars
810 var _indexAxis = caxis;
811 document.getElementById('htov').onclick = function() {
812 if ( _indexAxis == 'x') {
813 _indexAxis = 'y';
814 } else {
815 _indexAxis = 'x';
816 }
817 myChart.destroy();
818 myChart = new Chart(ctx, {
819 type: 'line',
820 options: {
821 animation: {
822 duration: 1000,
823 },
824 indexAxis: _indexAxis,
825 plugins: chartPlugins
826 },
827 plugins:[ plugin],
828 data: chartData
829 });
830 };
831 var ctx = document.getElementById('myChart').getContext('2d');
832
833 var chartData = {
834 labels: clabel,
835 datasets: [{
836 label: cpi18n.disk_io_bytes,
837 backgroundColor: 'rgba(143, 240, 164, .5)',
838 borderColor: '#41B141',
839 borderWidth: 2,
840 hoverBackgroundColor: '#FF0000',
841 data: cdata,
842 fill: 'origin',
843 radius: 6,
844 pointBackgroundColor: '#B45252'
845 }]
846 };
847 var chartPlugins = {
848 title: {
849 display: true,
850 text: cpi18n.disk_io_title,
851 },
852 legend: {
853 display: false
854 },
855 tooltip: {
856 borderWidth: 1,
857 borderColor: '#666',
858 displayColors: false,
859 backgroundColor: '#F5F5B5',
860 titleColor:'#666',
861 padding: 8,
862 footerColor: '#666',
863 callbacks: {
864 labelTextColor: function(context) {
865 return '#543453';
866 }
867 }
868 }
869 }
870 // We want a background colour for the downloaded PNG file
871 const plugin = {
872 id: 'custom_canvas_background_color',
873 beforeDraw: (chart) => {
874 const ctx = chart.canvas.getContext('2d');
875 ctx.save();
876 ctx.globalCompositeOperation = 'destination-over';
877 ctx.fillStyle = '#f0f0f1',
878 ctx.fillRect(0, 0, chart.width, chart.height);
879 ctx.restore();
880 }
881 }
882
883 var myChart = new Chart(ctx, {
884 type: 'line',
885 data: chartData,
886 options: {
887 animation: {
888 duration: 700,
889 onComplete: function() {
890 jQuery('#cp-footer-buttons').slideDown(200);
891 }
892 },
893 indexAxis: _indexAxis,
894 plugins: chartPlugins
895 },
896 plugins:[plugin]
897 });
898
899 document.getElementById('download-png-img').onclick = function() {
900 var a = document.createElement('a');
901 a.href = myChart.toBase64Image();
902 a.download = jQuery('#download-png-img').attr('download');
903 a.click();
904 }
905 }
906
907 // =====================================================================
908 // Settings page
909
910 function cpjs_copy_textarea( id ) {
911 document.getElementById(id).select();
912 document.execCommand('copy');
913 alert( cpi18n.text_copied );
914 }
915
916 // =====================================================================
917 // EOF
918