/**
* MaplePress Search Speed Test - Simple Admin JavaScript
*/
(function($) {
'use strict';
var testResults = null;
var performanceChart = null;
$(document).ready(function() {
// Note: Notification permission will be requested when user runs first test
// (requestNotificationPermission() can only be called from user gesture)
// Run test button
$('#mpss-run-test').on('click', function() {
runSpeedTest();
});
// Cancel test button
$(document).on('click', '#mpss-cancel-test', function() {
if (confirm('Are you sure you want to cancel the test?')) {
cancelTest();
}
});
// Run again button
$(document).on('click', '#mpss-run-again', function() {
resetTest();
});
// Export results button
$(document).on('click', '#mpss-export-results', function() {
exportResults();
});
// Share results button
$(document).on('click', '#mpss-share-results', function() {
showShareModal();
});
// Close share modal
$(document).on('click', '#mpss-close-share-modal', function() {
closeShareModal();
});
// Share buttons
$(document).on('click', '.mpss-share-twitter', function() {
shareToTwitter();
});
$(document).on('click', '.mpss-share-facebook', function() {
shareToFacebook();
});
$(document).on('click', '.mpss-share-linkedin', function() {
shareToLinkedIn();
});
$(document).on('click', '.mpss-share-copy', function() {
copyShareLink();
});
// Handle mode card selection
$('.mpss-mode-card').on('click', function() {
var $radio = $(this).find('input[type="radio"]');
$radio.prop('checked', true);
// Update visual state of cards
$('.mpss-mode-card-inner').css({
'border-color': '#e0e0e0',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.05)',
'transform': 'scale(1)'
});
$(this).find('.mpss-mode-card-inner').css({
'border-color': '#667eea',
'box-shadow': '0 4px 15px rgba(102, 126, 234, 0.3)',
'transform': 'scale(1.02)'
});
});
// Add hover effects for mode cards
$('.mpss-mode-card').hover(
function() {
if (!$(this).find('input[type="radio"]').is(':checked')) {
$(this).find('.mpss-mode-card-inner').css({
'transform': 'translateY(-2px)',
'box-shadow': '0 4px 10px rgba(0, 0, 0, 0.1)'
});
}
},
function() {
if (!$(this).find('input[type="radio"]').is(':checked')) {
$(this).find('.mpss-mode-card-inner').css({
'transform': 'scale(1)',
'box-shadow': '0 1px 3px rgba(0, 0, 0, 0.05)'
});
}
}
);
// Add hover effect for run button
$('#mpss-run-test').hover(
function() {
$(this).css({
'transform': 'translateY(-2px)',
'box-shadow': '0 6px 20px rgba(102, 126, 234, 0.5)'
});
},
function() {
$(this).css({
'transform': 'translateY(0)',
'box-shadow': '0 4px 15px rgba(102, 126, 234, 0.4)'
});
}
);
// Add focus effect for select dropdown
$('#mpss-query-count').on('focus', function() {
$(this).css({
'border-color': '#667eea',
'box-shadow': '0 0 0 3px rgba(102, 126, 234, 0.1)'
});
}).on('blur', function() {
$(this).css({
'border-color': '#e0e0e0',
'box-shadow': 'none'
});
});
// Initialize the first card as selected
$('.mpss-mode-card').first().find('.mpss-mode-card-inner').css({
'border-color': '#667eea',
'box-shadow': '0 4px 15px rgba(102, 126, 234, 0.3)',
'transform': 'scale(1.02)'
});
});
var progressInterval = null;
var currentAjaxRequest = null;
function runSpeedTest() {
// Request notification permission on first test run
requestNotificationPermission();
var queryCount = parseInt($('#mpss-query-count').val()) || 10;
var executionMode = $('input[name="execution_mode"]:checked').val() || 'serial';
console.log('Starting speed test with ' + queryCount + ' queries in ' + executionMode + ' mode');
console.log('Execution mode value:', executionMode);
console.log('Radio button checked:', $('input[name="execution_mode"]:checked').length);
// Hide config, show progress
$('.mpss-test-config').fadeOut();
$('#mpss-results').hide();
$('#mpss-progress').fadeIn();
var modeText = executionMode === 'parallel' ? 'many at once' : 'one at a time';
$('#mpss-progress-text').text('Testing ' + queryCount + ' searches (' + modeText + ')...');
$('#mpss-progress-fill').css('width', '10%');
// Initialize counter
$('#mpss-total-count').text(queryCount);
$('#mpss-completed-count').text(0);
// Calculate and display estimated time
var estimatedSeconds = Math.ceil((queryCount * 200) / 1000); // 200ms per query
if (executionMode === 'parallel') {
estimatedSeconds = Math.ceil(estimatedSeconds * 0.1); // Parallel is much faster
}
updateTimeEstimate(estimatedSeconds);
// Start animated progress counter
startProgressAnimation(queryCount, estimatedSeconds);
// Make AJAX request
currentAjaxRequest = $.ajax({
url: mpssAjax.ajaxurl,
method: 'POST',
data: {
action: 'mpss_run_test',
nonce: mpssAjax.nonce,
query_count: queryCount,
execution_mode: executionMode
},
success: function(response) {
currentAjaxRequest = null;
console.log('Response received:', response);
// Stop the progress animation
stopProgressAnimation();
if (response.success) {
testResults = response.data;
console.log('Test results:', testResults);
// Complete the progress
$('#mpss-completed-count').text(queryCount);
$('#mpss-progress-fill').css('width', '100%');
$('#mpss-progress-text').text('Test complete!');
setTimeout(function() {
displayResults(testResults);
}, 500);
} else {
showError('Test failed: ' + (response.data ? response.data.message : 'Unknown error'));
}
},
error: function(xhr, status, error) {
currentAjaxRequest = null;
// Don't show error if request was aborted (cancelled by user)
if (status === 'abort') {
return;
}
console.error('AJAX error:', error);
stopProgressAnimation();
showError('Network error: ' + error);
}
});
}
function cancelTest() {
// Abort the AJAX request
if (currentAjaxRequest) {
currentAjaxRequest.abort();
currentAjaxRequest = null;
}
// Stop the animation
stopProgressAnimation();
// Hide progress and show config
$('#mpss-progress').fadeOut(function() {
$('.mpss-test-config').fadeIn();
});
// Show cancellation message
alert('Test cancelled');
}
function updateTimeEstimate(secondsRemaining) {
if (secondsRemaining <= 0) {
$('#mpss-time-estimate').text('Almost done...');
return;
}
var minutes = Math.floor(secondsRemaining / 60);
var seconds = secondsRemaining % 60;
var timeText = 'Estimated time: ';
if (minutes > 0) {
timeText += minutes + ' min ' + seconds + ' sec';
} else {
timeText += seconds + ' sec';
}
$('#mpss-time-estimate').text(timeText);
}
function startProgressAnimation(totalCount, estimatedSeconds) {
// Clear any existing interval
if (progressInterval) {
clearInterval(progressInterval);
}
var currentCount = 0;
var estimatedTime = totalCount * 200; // Rough estimate: 200ms per search
var updateInterval = 100; // Update every 100ms
var incrementPerUpdate = totalCount / (estimatedTime / updateInterval);
var reachedNinetyFive = false;
var timeRemaining = estimatedSeconds;
var lastTimeUpdate = Date.now();
progressInterval = setInterval(function() {
// Update time estimate every second
var now = Date.now();
if (now - lastTimeUpdate >= 1000) {
timeRemaining--;
updateTimeEstimate(timeRemaining);
lastTimeUpdate = now;
}
// After reaching 95%, slow down significantly
if (currentCount >= totalCount * 0.95 && !reachedNinetyFive) {
reachedNinetyFive = true;
incrementPerUpdate = incrementPerUpdate * 0.1; // Slow down to 10% speed
// Update the message and add pulsing animation
$('#mpss-progress-text').html('Almost done, finalizing results...');
$('#mpss-progress-fill').addClass('pulsing');
}
currentCount += incrementPerUpdate;
// Cap at 99% until we get the real result
var displayCount = Math.min(Math.floor(currentCount), Math.floor(totalCount * 0.99));
var percentage = Math.min((displayCount / totalCount) * 100, 99);
$('#mpss-completed-count').text(displayCount);
$('#mpss-progress-fill').css('width', percentage + '%');
// Stop at 99%
if (displayCount >= totalCount * 0.99) {
clearInterval(progressInterval);
progressInterval = null;
}
}, updateInterval);
}
function stopProgressAnimation() {
if (progressInterval) {
clearInterval(progressInterval);
progressInterval = null;
}
}
function displayResults(data) {
console.log('Displaying results...');
// Calculate average time for notification
var avgTime = data.total_time / data.total_queries;
// Play completion sound and show notification
playCompletionSound();
showTestCompleteNotification(avgTime, data.total_queries);
// Hide progress, show results
$('#mpss-progress').fadeOut();
$('#mpss-results').fadeIn();
// Display recommendations
displayRecommendations(data.total_queries, data.mode);
// Display summary stats (only total queries and total time)
$('#mpss-total-queries').text(data.total_queries.toLocaleString());
$('#mpss-total-time').text(data.total_time + ' sec');
// Add mode-specific explanation
var $chart = $('#mpss-chart');
var existingExplanation = $chart.parent().find('.mpss-mode-explanation');
if (existingExplanation.length) {
existingExplanation.remove();
}
var explanation = '';
if (data.mode === 'parallel') {
explanation = '
' +
'👥 Stress Test Mode:
' +
'' +
'We simulated ' + data.total_queries + ' people searching your site at the same time. It took ' + data.total_time + ' seconds to handle everyone.' +
'' +
'
';
} else {
explanation = '' +
'👤 Normal Mode:
' +
'' +
'We tested ' + data.total_queries + ' searches one at a time. The total test took ' + data.total_time + ' seconds to complete.' +
'' +
'
';
}
$chart.parent().prepend(explanation);
// Display chart
displayChart(data);
}
function displayChart(data) {
var chartContainer = $('#mpss-chart').parent();
// Destroy existing chart
if (performanceChart) {
performanceChart.destroy();
performanceChart = null;
}
// Restore the canvas if needed
if (!chartContainer.find('canvas').length) {
chartContainer.html('');
}
var ctx = document.getElementById('mpss-chart').getContext('2d');
// Prepare data
var labels = data.results.map(function(r, i) { return 'Query ' + (i + 1); });
var times = data.results.map(function(r) { return r.duration_ms; });
// Determine title based on mode
var chartTitle = 'How Long Each Search Took';
var chartSubtitle = '';
if (data.mode === 'parallel') {
chartSubtitle = 'Each dot shows how long one search took (all happening at the same time)';
} else {
chartSubtitle = 'Each dot shows how long one search took (one after another)';
}
// Create chart
performanceChart = new Chart(ctx, {
type: 'line',
data: {
labels: labels,
datasets: [{
label: 'Response Time (ms)',
data: times,
backgroundColor: 'rgba(102, 126, 234, 0.3)',
borderColor: 'rgba(102, 126, 234, 1)',
borderWidth: 2,
pointRadius: 3,
tension: 0.1
}]
},
options: {
responsive: true,
maintainAspectRatio: true,
plugins: {
legend: {
position: 'top',
},
title: {
display: true,
text: chartTitle
},
subtitle: {
display: true,
text: chartSubtitle,
font: {
size: 11,
style: 'italic'
},
color: '#666'
}
},
scales: {
x: {
display: false
},
y: {
beginAtZero: true,
title: {
display: true,
text: 'Response Time (ms)'
}
}
}
}
});
}
function exportResults() {
if (!testResults) {
alert('No results to export');
return;
}
// Calculate metrics
var avgTime = testResults.total_time / testResults.total_queries;
var avgMs = (avgTime * 1000).toFixed(0);
var modeLabel = testResults.mode === 'parallel' ? 'Stress Test - Many People at Once' : 'Normal - One Person at a Time';
var date = new Date();
var dateStr = date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
// Calculate statistics
var times = testResults.results.map(function(r) { return r.duration_ms; });
var minTime = Math.min.apply(null, times);
var maxTime = Math.max.apply(null, times);
var medianTime = calculateMedian(times);
// Build HTML report
var html = '\n';
html += '\n';
html += '\n';
html += ' \n';
html += ' \n';
html += ' Search Speed Test Report - ' + dateStr + '\n';
html += ' \n';
html += '\n';
html += '\n';
html += ' \n';
html += ' \n';
html += ' \n';
html += '
\n';
html += '
🚀
\n';
html += '
Search Speed Test Results
\n';
html += '
Average response time: ' + avgMs + ' ms
\n';
html += '
\n';
html += ' \n';
html += '
\n';
html += '
\n';
html += '
Average Time
\n';
html += '
' + avgMs + ' ms
\n';
html += '
\n';
html += '
\n';
html += '
Total Tests
\n';
html += '
' + testResults.total_queries + '
\n';
html += '
\n';
html += '
\n';
html += '
Total Time
\n';
html += '
' + testResults.total_time + ' s
\n';
html += '
\n';
html += '
\n';
html += '
Test Mode
\n';
html += '
' + escapeHtml(modeLabel.split(' - ')[0]) + '
\n';
html += '
\n';
html += '
\n';
html += ' \n';
html += '
\n';
html += '
Detailed Statistics
\n';
html += '
\n';
html += '
\n';
html += '
Fastest Response
\n';
html += '
' + minTime.toFixed(0) + ' ms
\n';
html += '
\n';
html += '
\n';
html += '
Slowest Response
\n';
html += '
' + maxTime.toFixed(0) + ' ms
\n';
html += '
\n';
html += '
\n';
html += '
Median Response
\n';
html += '
' + medianTime.toFixed(0) + ' ms
\n';
html += '
\n';
html += '
\n';
html += '
Test Mode
\n';
html += '
' + escapeHtml(modeLabel) + '
\n';
html += '
\n';
html += '
\n';
html += '
\n';
html += ' \n';
html += '
\n';
html += '
General Recommendations
\n';
html += '
\n';
html += '
💡 Optimization Tips
\n';
html += '
Consider these strategies to improve search performance:
\n';
html += '
\n';
html += ' - Install and configure a caching plugin (e.g., WP Super Cache, W3 Total Cache)
\n';
html += ' - Optimize your database with plugins like WP-Optimize
\n';
html += ' - Review and optimize database indexes
\n';
html += ' - Consider upgrading your hosting plan for better resources
\n';
html += ' - Monitor performance regularly as your site grows
\n';
html += '
\n';
html += '
\n';
html += '
\n';
html += ' \n';
html += ' \n';
html += '
\n';
html += '\n';
html += '';
// Create and download the HTML file
var htmlBlob = new Blob([html], {type: 'text/html'});
var url = URL.createObjectURL(htmlBlob);
var link = document.createElement('a');
link.href = url;
link.download = 'search-speed-test-report-' + Date.now() + '.html';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
// Show success message
alert('✅ Report exported! Open the HTML file in your browser and use "Print to PDF" to create a PDF version.');
}
function calculateMedian(arr) {
var sorted = arr.slice().sort(function(a, b) { return a - b; });
var mid = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 0) {
return (sorted[mid - 1] + sorted[mid]) / 2;
}
return sorted[mid];
}
function resetTest() {
$('#mpss-results').fadeOut();
$('.mpss-test-config').fadeIn();
testResults = null;
}
function showError(message) {
$('#mpss-progress').fadeOut();
$('.mpss-test-config').fadeIn();
alert('Error: ' + message);
}
function displayRecommendations(totalQueries, mode) {
var recommendations = [];
// Query count recommendations
if (totalQueries < 100) {
recommendations.push({
type: 'info',
icon: '📊',
title: 'Try more searches',
message: 'Testing with ' + totalQueries + ' searches gives you a basic idea. Try 500-1000 searches for more accurate results.'
});
}
// Mode-based recommendations
if (mode === 'serial') {
recommendations.push({
type: 'info',
icon: '🔄',
title: 'Try Stress Test mode',
message: 'You tested in Normal mode. Try "Stress Test - Many People at Once" to see how your site handles high traffic.'
});
} else {
recommendations.push({
type: 'info',
icon: '👥',
title: 'Consider traffic patterns',
message: 'Stress Test mode shows worst-case performance. If your site rarely gets simultaneous searches, Normal mode results matter more.'
});
}
// Build HTML
var html = '';
html += '
💡 Quick Tips
';
for (var i = 0; i < recommendations.length; i++) {
var rec = recommendations[i];
var bgColor, borderColor;
if (rec.type === 'success') {
bgColor = '#d1fae5';
borderColor = '#10b981';
} else if (rec.type === 'info') {
bgColor = '#dbeafe';
borderColor = '#3b82f6';
} else if (rec.type === 'warning') {
bgColor = '#fef3c7';
borderColor = '#f59e0b';
} else {
bgColor = '#fee2e2';
borderColor = '#ef4444';
}
html += '
';
html += '
' + rec.icon + ' ' + rec.title + '
';
html += '
' + rec.message + '
';
html += '
';
}
html += '
';
$('#mpss-recommendations').html(html);
}
function escapeHtml(text) {
var map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return String(text).replace(/[&<>"']/g, function(m) { return map[m]; });
}
function showShareModal() {
if (!testResults) {
alert('No results to share');
return;
}
// Calculate metrics
var avgTime = testResults.total_time / testResults.total_queries;
var avgMs = (avgTime * 1000).toFixed(0);
var modeLabel = testResults.mode === 'parallel' ? 'Stress Test' : 'Normal';
// Build share graphic
var graphicHtml = '';
graphicHtml += '
🚀
';
graphicHtml += '
My Search Speed Test Results
';
graphicHtml += '
' + avgMs + ' ms
';
graphicHtml += '
Average Response Time
';
graphicHtml += '
Tested ' + testResults.total_queries + ' searches in ' + modeLabel + ' mode
';
graphicHtml += '
';
$('#mpss-share-graphic').html(graphicHtml);
// Show modal with flex display
$('#mpss-share-modal').css('display', 'flex').hide().fadeIn(300);
}
function closeShareModal() {
$('#mpss-share-modal').fadeOut(300);
}
function shareToTwitter() {
if (!testResults) return;
var avgTime = testResults.total_time / testResults.total_queries;
var avgMs = (avgTime * 1000).toFixed(0);
var text = 'I just tested my website\'s search speed! 🚀 Average response time: ' + avgMs + 'ms #WebPerformance #SiteSpeed';
var url = window.location.href;
var twitterUrl = 'https://twitter.com/intent/tweet?text=' + encodeURIComponent(text) + '&url=' + encodeURIComponent(url);
window.open(twitterUrl, '_blank', 'width=550,height=420');
}
function shareToFacebook() {
if (!testResults) return;
var url = window.location.href;
var facebookUrl = 'https://www.facebook.com/sharer/sharer.php?u=' + encodeURIComponent(url);
window.open(facebookUrl, '_blank', 'width=550,height=420');
}
function shareToLinkedIn() {
if (!testResults) return;
var avgTime = testResults.total_time / testResults.total_queries;
var avgMs = (avgTime * 1000).toFixed(0);
var url = window.location.href;
var title = 'Website Search Speed Test Results';
var summary = 'I tested my website\'s search performance. Average response time: ' + avgMs + 'ms';
var linkedinUrl = 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(url);
window.open(linkedinUrl, '_blank', 'width=550,height=420');
}
function copyShareLink() {
if (!testResults) return;
var avgTime = testResults.total_time / testResults.total_queries;
var avgMs = (avgTime * 1000).toFixed(0);
var text = 'I just tested my website\'s search speed! 🚀 Average response time: ' + avgMs + 'ms\n' + window.location.href;
// Try to use modern clipboard API
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text).then(function() {
alert('✅ Link copied to clipboard!');
}).catch(function() {
fallbackCopyText(text);
});
} else {
fallbackCopyText(text);
}
}
function fallbackCopyText(text) {
// Fallback for older browsers
var textArea = document.createElement('textarea');
textArea.value = text;
textArea.style.position = 'fixed';
textArea.style.top = '0';
textArea.style.left = '0';
textArea.style.width = '2em';
textArea.style.height = '2em';
textArea.style.padding = '0';
textArea.style.border = 'none';
textArea.style.outline = 'none';
textArea.style.boxShadow = 'none';
textArea.style.background = 'transparent';
document.body.appendChild(textArea);
textArea.select();
try {
document.execCommand('copy');
alert('✅ Link copied to clipboard!');
} catch (err) {
alert('❌ Could not copy to clipboard. Please copy manually:\n\n' + text);
}
document.body.removeChild(textArea);
}
function requestNotificationPermission() {
// Check if browser supports notifications
if (!('Notification' in window)) {
console.log('This browser does not support desktop notifications');
return;
}
// Request permission if not already granted or denied
if (Notification.permission === 'default') {
Notification.requestPermission();
}
}
function showTestCompleteNotification(avgTime, totalQueries) {
// Check if notifications are supported and permitted
if (!('Notification' in window) || Notification.permission !== 'granted') {
return;
}
var avgMs = (avgTime * 1000).toFixed(0);
var title = 'Search Speed Test Complete!';
var body = 'Tested ' + totalQueries + ' searches. Average response time: ' + avgMs + 'ms';
var icon = ''; // WordPress doesn't have a default icon, but we could add one
try {
var notification = new Notification(title, {
body: body,
icon: icon,
badge: icon,
tag: 'mpss-test-complete',
requireInteraction: false
});
// Auto-close notification after 5 seconds
setTimeout(function() {
notification.close();
}, 5000);
// Focus window when notification is clicked
notification.onclick = function() {
window.focus();
notification.close();
};
} catch (e) {
console.log('Could not show notification:', e);
}
}
function playCompletionSound() {
// Create a simple success sound using Web Audio API
try {
var audioContext = new (window.AudioContext || window.webkitAudioContext)();
var oscillator = audioContext.createOscillator();
var gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
// Set sound parameters for a pleasant "ding" sound
oscillator.frequency.value = 800; // Start frequency
oscillator.type = 'sine';
gainNode.gain.setValueAtTime(0.3, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.5);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + 0.5);
// Add a second tone for a pleasant chord
setTimeout(function() {
var oscillator2 = audioContext.createOscillator();
var gainNode2 = audioContext.createGain();
oscillator2.connect(gainNode2);
gainNode2.connect(audioContext.destination);
oscillator2.frequency.value = 1000;
oscillator2.type = 'sine';
gainNode2.gain.setValueAtTime(0.2, audioContext.currentTime);
gainNode2.gain.exponentialRampToValueAtTime(0.01, audioContext.currentTime + 0.4);
oscillator2.start(audioContext.currentTime);
oscillator2.stop(audioContext.currentTime + 0.4);
}, 100);
} catch (e) {
console.log('Could not play sound:', e);
}
}
})(jQuery);