PluginProbe
Code Profiler – WordPress Performance Profiling and Debugging Made Easy / 1.4
Code Profiler – WordPress Performance Profiling and Debugging Made Easy v1.4
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 1.6.8 All 40 releases
code-profiler / static / code-profiler.js

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

633 lines 15.6 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://code-profiler.com/ |
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 == 1 ) {
73 jQuery('#id-frontend').prop('disabled', false);
74 jQuery('#id-frontend').focus();
75 jQuery('#id-backend').prop('disabled', true);
76 jQuery('#id-custom').prop('disabled', true);
77 jQuery('#user-unauthenticated').prop('disabled', false);
78 } else if ( item == 2 ) {
79 jQuery('#id-backend').prop('disabled', false);
80 jQuery('#id-backend').focus();
81 jQuery('#id-frontend').prop('disabled', true);
82 jQuery('#id-custom').prop('disabled', true);
83 jQuery('#user-unauthenticated').prop('disabled', true);
84 jQuery('#user-authenticated').prop('checked', true)
85 } else {
86 jQuery('#id-custom').prop('disabled', false);
87 jQuery('#id-custom').focus();
88 jQuery('#id-backend').prop('disabled', true);
89 jQuery('#id-frontend').prop('disabled', true);
90 jQuery('#user-unauthenticated').prop('disabled', false);
91 }
92 }
93
94 // =====================================================================
95 // Log page: filter and delete the log.
96
97 function cpjs_filter_log() {
98 'use strict';
99 // Create bitmask
100 var bitmask = 0;
101 if ( document.cplogform.info.checked == true ) { bitmask += 1; }
102 if ( document.cplogform.warn.checked == true ) { bitmask += 2; }
103 if ( document.cplogform.error.checked == true ) { bitmask += 4; }
104
105 // Clear the textarea
106 document.cplogform.cptxtlog.value = '';
107
108 // Browser through our array and return only selected verbosity
109 var cp_count = 0;
110 var i = 0;
111 for ( i = 0; i < cplog_array.length; ++i ) {
112 var line = decodeURIComponent( cplog_array[i] );
113 var line_array = line.split( '~~', 2 );
114 if ( line_array[0] & bitmask ) {
115 document.cplogform.cptxtlog.value += line_array[1];
116 ++cp_count;
117 }
118 }
119 if ( cp_count == 0 ) {
120 document.cplogform.cptxtlog.value = '\n > ' + cpi18n.empty_log;
121 }
122 }
123
124 function cpjs_delete_log() {
125 'use strict';
126 if ( confirm( cpi18n.delete_log ) ) {
127 return true;
128 }
129 return false;
130 }
131 // =====================================================================
132 // AJAX call to start the profiler.
133
134 function cpjs_start_profiler() {
135 'use strict';
136 // Get the nonce
137 var cp_nonce = jQuery('#cp_nonce').val();
138 if ( cp_nonce == '' ) {
139 alert( cpi18n.missing_nonce );
140 return;
141 }
142
143 // Get the scan type (frontend/backend)
144 var post;
145 var where = jQuery('input[name="where"]:checked').val();
146 if ( where == 'frontend' ) {
147 post = jQuery('#id-frontend').val();
148
149 } else if ( where == 'backend' ) {
150 post = jQuery('#id-backend').val();
151
152 } else if ( where == 'custom' ) {
153 post = jQuery('#id-custom').val().trim(); // Trim user input
154
155 } else {
156 alert( cpi18n.missing_frontbackend );
157 return;
158 }
159 if ( post == '' ) {
160 alert( cpi18n.missing_post );
161 return;
162 }
163
164 // Get the profile's name
165 var profile = jQuery('input[name="profile"]').val();
166 if ( profile == '' ) {
167 alert( cpi18n.missing_profilename );
168 jQuery('input[name="profile"]').focus();
169 return;
170 }
171
172 var user = jQuery('input[name="user"]:checked').val();
173 if ( user == '' ) {
174 alert( cpi18n.missing_userauth );
175 return;
176 }
177
178 var ua = jQuery('#ua-id').val();
179 if ( ua == 'undefined' ) {
180 ua = 'FireFox';
181 }
182
183 // Change buttons status and add animated image with status message
184 jQuery('#start-profile').prop('disabled', true);
185 jQuery('#cp-progress-div').slideDown();
186 jQuery('#progress-gif').slideDown();
187 jQuery('#progress-text').slideDown();
188 jQuery('#code-profiler-error').slideUp();
189 jQuery('#cp-span-progress').css('width', '30%');
190
191 var data = {
192 'action': 'codeprofiler_start_profiler',
193 'cp_nonce': cp_nonce,
194 'where': where,
195 'post': post,
196 'profile': profile,
197 'user': user,
198 'ua': ua
199 };
200 // Send the request via AJAX
201 jQuery.ajax( {
202 type: "POST",
203 url: ajaxurl,
204 data: data,
205 dataType: 'json',
206 success: function( response ) {
207
208 if (typeof response === 'undefined') {
209 cpjs_start_error( '<p>'+ cpi18n.unknown_error +'</p>' );
210 return;
211 }
212
213 if ( response.status != 'success' ) {
214 cpjs_start_error( '<p>'+ response.message +'</p>' );
215 return;
216 }
217
218 // ------------------------------------------------------------
219 // Inform the user we're moving to step 2
220 jQuery('#cp-span-progress').css('width', '70%');
221 jQuery('#progress-text').html( cpi18n.preparing_report );
222
223 data['action'] = 'codeprofiler_prepare_report';
224 data['microtime'] = response.microtime;
225 jQuery.ajax( {
226 type: "POST",
227 url: ajaxurl,
228 data: data,
229 dataType: 'json',
230 success: function( response ) {
231
232 if (typeof response === 'undefined') {
233 cpjs_start_error( '<p>'+ cpi18n.unknown_error +'</p>' );
234 return;
235 }
236
237 if ( response.status != 'success' ) {
238 cpjs_start_error( '<p>'+ response.message +'</p>' );
239 return;
240 }
241 var cp_uri;
242 if (response.cp_profile !== 'undefined' && response.cp_profile != '' ) {
243 cp_uri = '&cptab=profiles_list&action=view_profile&id=' + response.cp_profile + '&section=1';
244 } else {
245 cp_uri = '&cptab=profiles_list';
246 }
247
248 // All good, redirect to the Profiles List tab
249 jQuery('#cp-span-progress').css('width', '100%');
250 window.location.href = window.location.href + cp_uri;
251 return;
252
253 },
254
255 // Display non-200 HTTP response
256 error: function( xhr, status, err ) {
257 if ( err != '' ) {
258
259 if ( xhr.status != 0 ) {
260 cpjs_start_error( '<p>'+ cpi18n.http_error +' '+ xhr.status +' '+ err +'.</p>' );
261 return;
262
263 } else {
264 cpjs_start_error( '<p>'+ cpi18n.unknown_error +' '+ err +'.</p>' );
265 return;
266 }
267 }
268 return;
269 }
270 });
271 // ------------------------------------------------------------
272 },
273
274 // Display non-200 HTTP response
275 error: function( xhr, status, err ) {
276 if ( err != '' ) {
277
278 if ( xhr.status != 0 ) {
279 cpjs_start_error( '<p>'+ cpi18n.http_error +' '+ xhr.status +' '+ err +'.</p>' );
280 return;
281
282 } else {
283 cpjs_start_error( '<p>'+ cpi18n.unknown_error +' '+ err +'.</p>' );
284 return;
285 }
286 }
287 return;
288 }
289 });
290 }
291
292 // Display error
293 function cpjs_start_error( error ) {
294 'use strict';
295 jQuery('#start-profile').prop('disabled', false);
296 jQuery('#progress-gif').slideUp();
297 jQuery('#progress-text').slideUp();
298 jQuery('#cp-span-progress').css('width', '0%');
299 jQuery('#code-profiler-error').html( error );
300 jQuery('#code-profiler-error').slideDown();
301 jQuery('#cp-progress-div').slideUp();
302
303 }
304
305 // =====================================================================
306 // Profiles List page.
307
308 function cpjs_delete_profile() {
309 'use strict';
310 if ( confirm( cpi18n.delete_profile ) ) {
311 return true;
312 }
313 return false;
314 }
315
316 // =====================================================================
317 // Plugins/Theme chart.
318
319 function cpjs_plugins_chart( caxis, clabel, cdata, ctotal_time ) {
320 'use strict';
321 // Switch between vertical and horizontal bars
322 var _indexAxis = caxis;
323 document.getElementById('htov').onclick = function() {
324 if ( _indexAxis == 'x' ) {
325 _indexAxis = 'y';
326 } else {
327 _indexAxis = 'x';
328 }
329 myChart.destroy();
330 myChart = new Chart(ctx, {
331 type: 'bar',
332 options: {
333 animation: {
334 duration: 1000,
335 onComplete: function() {
336 document.getElementById('download-png-img').href = myChart.toBase64Image();
337 }
338 },
339 indexAxis: _indexAxis,
340 plugins: chartPlugins
341 },
342 plugins:[ plugin],
343 data: chartData
344 });
345 };
346
347 var ctx = document.getElementById('myChart').getContext('2d');
348
349 var chartData = {
350 labels: clabel,
351 datasets: [{
352 label: cpi18n.exec_sec_plugins,
353 backgroundColor: 'rgba(204, 0, 0, .5)',
354 borderColor: '#c00',
355 borderWidth: 2,
356 hoverBackgroundColor: '#B45252',
357 data: cdata
358 }]
359 };
360
361 const total_time = ctotal_time;
362 const footer = (tooltipItems) => {
363 var sum;
364 tooltipItems.forEach(function(tooltipItem) {
365 if ( _indexAxis == 'x' ) {
366 sum = Math.round( ( tooltipItem.parsed.y / total_time ) * 100 );
367 } else {
368 sum = Math.round( ( tooltipItem.parsed.x / total_time ) * 100 );
369 }
370 });
371 return '('+ sum + cpi18n.pc_plugins +')';
372 };
373
374 var chartPlugins = {
375 title: {
376 display: true,
377 text: cpi18n.exec_tot_plugins_1 +' (' + cpi18n.chart_total +' '+ ctotal_time +')'
378 },
379 legend: {
380 display: false
381 },
382 tooltip: {
383 borderWidth: 1,
384 borderColor: '#666',
385 displayColors: false,
386 backgroundColor: '#F5F5B5',
387 titleColor:'#666',
388 padding: 8,
389 footerColor: '#666',
390 callbacks: {
391 footer: footer,
392 labelTextColor: function(context) {
393 return '#543453';
394 }
395 }
396 }
397 }
398
399 // We want a background colour for the downloaded PNG file
400 const plugin = {
401 id: 'custom_canvas_background_color',
402 beforeDraw: (chart) => {
403 const ctx = chart.canvas.getContext('2d');
404 ctx.save();
405 ctx.globalCompositeOperation = 'destination-over';
406 ctx.fillStyle = '#f0f0f1',
407 ctx.fillRect(0, 0, chart.width, chart.height);
408 ctx.restore();
409 }
410 }
411
412 var myChart = new Chart(ctx, {
413 type: 'bar',
414 data: chartData,
415 options: {
416 animation: {
417 duration: 700,
418 onComplete: function() {
419 jQuery('#cp-footer-buttons').slideDown(200);
420 document.getElementById('download-png-img').href = myChart.toBase64Image();
421 }
422 },
423 indexAxis: _indexAxis,
424 plugins: chartPlugins
425 },
426 plugins:[plugin]
427 });
428 }
429
430 // =====================================================================
431 // File I/O chart.
432
433 function cpjs_iostats_chart( caxis, clabel, cdata, ctotal_calls ) {
434 'use strict';
435 // Switch between vertical and horizontal bars
436 var _indexAxis = caxis;
437 document.getElementById('htov').onclick = function() {
438 if ( _indexAxis == 'x' ) {
439 _indexAxis = 'y';
440 } else {
441 _indexAxis = 'x';
442 }
443 myChart.destroy();
444 myChart = new Chart(ctx, {
445 type: 'line',
446 options: {
447 animation: {
448 duration: 1000,
449 onComplete: function() {
450 document.getElementById('download-png-img').href = myChart.toBase64Image();
451 }
452 },
453 indexAxis: _indexAxis,
454 plugins: chartPlugins
455 },
456 plugins:[ plugin],
457 data: chartData
458 });
459 };
460
461 var ctx = document.getElementById('myChart').getContext('2d');
462
463 var chartData = {
464 labels: clabel,
465 datasets: [{
466 label: cpi18n.iolist_total_calls,
467 backgroundColor: 'rgba(34, 113, 177, .5)',
468 borderColor: '#2271B1',
469 borderWidth: 2,
470 hoverBackgroundColor: '#FF0000',
471 data: cdata,
472 fill: 'origin',
473 radius: 6,
474 pointBackgroundColor: '#B45252'
475 }]
476 };
477 var chartPlugins = {
478 title: {
479 display: true,
480 text: cpi18n.io_calls +' (' + cpi18n.chart_total +' '+ ctotal_calls +')'
481 },
482 legend: {
483 display: false
484 },
485 tooltip: {
486 borderWidth: 1,
487 borderColor: '#666',
488 displayColors: false,
489 backgroundColor: '#F5F5B5',
490 titleColor:'#666',
491 padding: 8,
492 footerColor: '#666',
493 callbacks: {
494 labelTextColor: function(context) {
495 return '#543453';
496 }
497 }
498 }
499 }
500 // We want a background colour for the downloaded PNG file
501 const plugin = {
502 id: 'custom_canvas_background_color',
503 beforeDraw: (chart) => {
504 const ctx = chart.canvas.getContext('2d');
505 ctx.save();
506 ctx.globalCompositeOperation = 'destination-over';
507 ctx.fillStyle = '#f0f0f1',
508 ctx.fillRect(0, 0, chart.width, chart.height);
509 ctx.restore();
510 }
511 }
512
513 var myChart = new Chart(ctx, {
514 type: 'line',
515 data: chartData,
516 options: {
517 animation: {
518 duration: 700,
519 onComplete: function() {
520 jQuery('#cp-footer-buttons').slideDown(200);
521 document.getElementById('download-png-img').href = myChart.toBase64Image();
522 }
523 },
524 indexAxis: _indexAxis,
525 plugins: chartPlugins
526 },
527 plugins:[plugin]
528 });
529
530 }
531 // =====================================================================
532 // Disk I/O chart.
533
534 function cpjs_diskio_chart( caxis, clabel, cdata ) {
535 'use strict';
536 // Switch between vertical and horizontal bars
537 var _indexAxis = caxis;
538 document.getElementById('htov').onclick = function() {
539 if ( _indexAxis == 'x' ) {
540 _indexAxis = 'y';
541 } else {
542 _indexAxis = 'x';
543 }
544 myChart.destroy();
545 myChart = new Chart(ctx, {
546 type: 'line',
547 options: {
548 animation: {
549 duration: 1000,
550 onComplete: function() {
551 document.getElementById('download-png-img').href = myChart.toBase64Image();
552 }
553 },
554 indexAxis: _indexAxis,
555 plugins: chartPlugins
556 },
557 plugins:[ plugin],
558 data: chartData
559 });
560 };
561 var ctx = document.getElementById('myChart').getContext('2d');
562
563 var chartData = {
564 labels: clabel,
565 datasets: [{
566 label: cpi18n.disk_io_bytes,
567 backgroundColor: 'rgba(143, 240, 164, .5)',
568 borderColor: '#41B141',
569 borderWidth: 2,
570 hoverBackgroundColor: '#FF0000',
571 data: cdata,
572 fill: 'origin',
573 radius: 6,
574 pointBackgroundColor: '#B45252'
575 }]
576 };
577 var chartPlugins = {
578 title: {
579 display: true,
580 text: cpi18n.disk_io_title,
581 },
582 legend: {
583 display: false
584 },
585 tooltip: {
586 borderWidth: 1,
587 borderColor: '#666',
588 displayColors: false,
589 backgroundColor: '#F5F5B5',
590 titleColor:'#666',
591 padding: 8,
592 footerColor: '#666',
593 callbacks: {
594 labelTextColor: function(context) {
595 return '#543453';
596 }
597 }
598 }
599 }
600 // We want a background colour for the downloaded PNG file
601 const plugin = {
602 id: 'custom_canvas_background_color',
603 beforeDraw: (chart) => {
604 const ctx = chart.canvas.getContext('2d');
605 ctx.save();
606 ctx.globalCompositeOperation = 'destination-over';
607 ctx.fillStyle = '#f0f0f1',
608 ctx.fillRect(0, 0, chart.width, chart.height);
609 ctx.restore();
610 }
611 }
612
613 var myChart = new Chart(ctx, {
614 type: 'line',
615 data: chartData,
616 options: {
617 animation: {
618 duration: 700,
619 onComplete: function() {
620 jQuery('#cp-footer-buttons').slideDown(200);
621 document.getElementById('download-png-img').href = myChart.toBase64Image();
622 }
623 },
624 indexAxis: _indexAxis,
625 plugins: chartPlugins
626 },
627 plugins:[plugin]
628 });
629 }
630
631 // =====================================================================
632 // EOF
633