| @@ -11,228 +11,257 @@ | ||
| 11 | 11 | * |
| 12 | 12 | * @since Phase 5 |
| 13 | 13 | */ |
| 14 | 14 | (function () { |
| 15 | - // Wait for jQuery to be available | |
| 16 | - function initHostBlockingTest() { | |
| 17 | - if (typeof jQuery === 'undefined') { | |
| 18 | - setTimeout(initHostBlockingTest, 100); | |
| 19 | - return; | |
| 20 | - } | |
| 15 | + // Wait for jQuery to be available | |
| 16 | + function initHostBlockingTest() { | |
| 17 | + if (typeof jQuery === 'undefined') { | |
| 18 | + setTimeout(initHostBlockingTest, 100); | |
| 19 | + return; | |
| 20 | + } | |
| 21 | 21 | |
| 22 | - jQuery(document).ready(function ($) { | |
| 23 | - // Ensure ajax URL is available in this scope | |
| 24 | - var ajaxUrl = (typeof window.ajaxurl !== 'undefined' && window.ajaxurl) | |
| 25 | - ? window.ajaxurl | |
| 26 | - : metasyncHostBlockingData.ajaxUrl; | |
| 22 | + jQuery(document).ready(function ($) { | |
| 23 | + // Ensure ajax URL is available in this scope | |
| 24 | + var ajaxUrl = (typeof window.ajaxurl !== 'undefined' && window.ajaxurl) | |
| 25 | + ? window.ajaxurl | |
| 26 | + : metasyncHostBlockingData.ajaxUrl; | |
| 27 | 27 | |
| 28 | - // --- Settings page buttons (GET / POST / BOTH) --- | |
| 29 | - $(document).on('click', '#test-get-request', function (e) { | |
| 30 | - e.preventDefault(); | |
| 31 | - e.stopPropagation(); | |
| 32 | - runHostTest('GET'); | |
| 33 | - return false; | |
| 34 | - }); | |
| 28 | + // --- Settings page buttons (GET / POST / BOTH) --- | |
| 29 | + $(document).on('click', '#test-get-request', function (e) { | |
| 30 | + e.preventDefault(); | |
| 31 | + e.stopPropagation(); | |
| 32 | + runHostTest('GET'); | |
| 33 | + return false; | |
| 34 | + }); | |
| 35 | 35 | |
| 36 | - $(document).on('click', '#test-post-request', function (e) { | |
| 37 | - e.preventDefault(); | |
| 38 | - e.stopPropagation(); | |
| 39 | - runHostTest('POST'); | |
| 40 | - return false; | |
| 41 | - }); | |
| 36 | + $(document).on('click', '#test-post-request', function (e) { | |
| 37 | + e.preventDefault(); | |
| 38 | + e.stopPropagation(); | |
| 39 | + runHostTest('POST'); | |
| 40 | + return false; | |
| 41 | + }); | |
| 42 | 42 | |
| 43 | - // --- Shared "Test Both" button (settings + dashboard) --- | |
| 44 | - var $btn = $('#test-both-requests'); | |
| 43 | + // --- Shared "Test Both" button (settings + dashboard) --- | |
| 44 | + var $btn = $('#test-both-requests'); | |
| 45 | 45 | |
| 46 | - $btn.on('click', function (e) { | |
| 47 | - e.preventDefault(); | |
| 48 | - e.stopPropagation(); | |
| 49 | - runHostTest('BOTH'); | |
| 50 | - return false; | |
| 51 | - }); | |
| 46 | + $btn.on('click', function (e) { | |
| 47 | + e.preventDefault(); | |
| 48 | + e.stopPropagation(); | |
| 49 | + runHostTest('BOTH'); | |
| 50 | + return false; | |
| 51 | + }); | |
| 52 | 52 | |
| 53 | - $(document).on('click', '#test-both-requests', function (e) { | |
| 54 | - e.preventDefault(); | |
| 55 | - e.stopPropagation(); | |
| 56 | - runHostTest('BOTH'); | |
| 57 | - return false; | |
| 58 | - }); | |
| 53 | + $(document).on('click', '#test-both-requests', function (e) { | |
| 54 | + e.preventDefault(); | |
| 55 | + e.stopPropagation(); | |
| 56 | + runHostTest('BOTH'); | |
| 57 | + return false; | |
| 58 | + }); | |
| 59 | 59 | |
| 60 | - // Expose function globally for debugging | |
| 61 | - window.runHostBlockingTest = function () { | |
| 62 | - runHostTest('BOTH'); | |
| 63 | - }; | |
| 60 | + // Expose function globally for debugging | |
| 61 | + window.runHostBlockingTest = function () { | |
| 62 | + runHostTest('BOTH'); | |
| 63 | + }; | |
| 64 | 64 | |
| 65 | - function runHostTest(method) { | |
| 66 | - var buttonId = (method === 'BOTH' ? 'test-both-requests' : 'test-' + method.toLowerCase() + '-request'); | |
| 67 | - var $button = $('#' + buttonId); | |
| 65 | + function runHostTest(method) { | |
| 66 | + var buttonId = (method === 'BOTH' ? 'test-both-requests' : 'test-' + method.toLowerCase() + '-request'); | |
| 67 | + var $button = $('#' + buttonId); | |
| 68 | 68 | |
| 69 | - if ($button.length === 0) { | |
| 70 | - alert('Error: Test button not found. Please refresh the page.'); | |
| 71 | - return; | |
| 72 | - } | |
| 69 | + if ($button.length === 0) { | |
| 70 | + alert('Error: Test button not found. Please refresh the page.'); | |
| 71 | + return; | |
| 72 | + } | |
| 73 | 73 | |
| 74 | - var originalText = $button.text(); | |
| 74 | + var originalText = $button.text(); | |
| 75 | 75 | |
| 76 | - // Disable button and show loading | |
| 77 | - $button.prop('disabled', true); | |
| 78 | - $button.text('\uD83D\uDD04 Testing...'); | |
| 76 | + // Disable button and show loading | |
| 77 | + $button.prop('disabled', true); | |
| 78 | + $button.text('\uD83D\uDD04 Testing...'); | |
| 79 | 79 | |
| 80 | - // Prepare results area | |
| 81 | - var $resultsDiv = $('#host-test-results'); | |
| 82 | - var $resultsContent = $('#test-results-content'); | |
| 83 | - $resultsDiv.show(); | |
| 84 | - $resultsContent.html('<div class="notice notice-info"><p>Running ' + (method === 'BOTH' ? 'GET and POST' : method) + ' test(s)...</p></div>'); | |
| 80 | + // Prepare results area | |
| 81 | + var $resultsDiv = $('#host-test-results'); | |
| 82 | + var $resultsContent = $('#test-results-content'); | |
| 83 | + $resultsDiv.show(); | |
| 84 | + $resultsContent.html('<div class="notice notice-info"><p>Running ' + (method === 'BOTH' ? 'GET and POST' : method) + ' test(s)...</p></div>'); | |
| 85 | 85 | |
| 86 | - var testsToRun = (method === 'BOTH') ? ['GET', 'POST'] : [method]; | |
| 87 | - var completedTests = 0; | |
| 88 | - var allResults = []; | |
| 86 | + var testsToRun = (method === 'BOTH') ? ['GET', 'POST'] : [method]; | |
| 87 | + var completedTests = 0; | |
| 88 | + var allResults = []; | |
| 89 | 89 | |
| 90 | - testsToRun.forEach(function (testMethod) { | |
| 91 | - var action = 'metasync_test_host_blocking_' + testMethod.toLowerCase(); | |
| 90 | + testsToRun.forEach(function (testMethod) { | |
| 91 | + var action = 'metasync_test_host_blocking_' + testMethod.toLowerCase(); | |
| 92 | 92 | |
| 93 | - $.ajax({ | |
| 94 | - url: ajaxUrl, | |
| 95 | - type: 'POST', | |
| 96 | - dataType: 'json', | |
| 97 | - data: { action: action }, | |
| 98 | - timeout: 35000, | |
| 99 | - success: function (response, textStatus, xhr) { | |
| 100 | - try { | |
| 101 | - if (response && response.success && response.data) { | |
| 102 | - allResults.push(response.data); | |
| 103 | - } else { | |
| 104 | - allResults.push({ | |
| 105 | - method: testMethod, | |
| 106 | - status: 'error', | |
| 107 | - error: (response && response.data) ? response.data : 'Unexpected response', | |
| 108 | - blocked: true, | |
| 109 | - details: 'Received non-success response from server.' | |
| 110 | - }); | |
| 111 | - } | |
| 112 | - } catch (e) { | |
| 113 | - allResults.push({ | |
| 114 | - method: testMethod, | |
| 115 | - status: 'error', | |
| 116 | - error: 'Response parse error: ' + (e && e.message ? e.message : e), | |
| 117 | - blocked: true | |
| 118 | - }); | |
| 119 | - } | |
| 120 | - finalizeOne(); | |
| 121 | - }, | |
| 122 | - error: function (xhr, status, error) { | |
| 123 | - var payload = (xhr && xhr.responseText) ? xhr.responseText.substring(0, 500) : ''; | |
| 124 | - allResults.push({ | |
| 125 | - method: testMethod, | |
| 126 | - status: 'error', | |
| 127 | - error: 'AJAX failed: ' + error + (payload ? ' \u2014 ' + payload : ''), | |
| 128 | - blocked: true, | |
| 129 | - details: 'Request did not complete successfully. Status: ' + status | |
| 130 | - }); | |
| 131 | - finalizeOne(); | |
| 132 | - } | |
| 133 | - }); | |
| 134 | - }); | |
| 93 | + $.ajax({ | |
| 94 | + url: ajaxUrl, | |
| 95 | + type: 'POST', | |
| 96 | + dataType: 'json', | |
| 97 | + data: { action: action, nonce: metasyncHostBlockingData.nonce }, | |
| 98 | + timeout: 35000, | |
| 99 | + success: function (response, textStatus, xhr) { | |
| 100 | + try { | |
| 101 | + if (response && response.success && response.data) { | |
| 102 | + allResults.push(response.data); | |
| 103 | + } else { | |
| 104 | + allResults.push({ | |
| 105 | + method: testMethod, | |
| 106 | + status: 'error', | |
| 107 | + error: (response && response.data) ? response.data : 'Unexpected response', | |
| 108 | + blocked: true, | |
| 109 | + details: 'Received non-success response from server.' | |
| 110 | + }); | |
| 111 | + } | |
| 112 | + } catch (e) { | |
| 113 | + allResults.push({ | |
| 114 | + method: testMethod, | |
| 115 | + status: 'error', | |
| 116 | + error: 'Response parse error: ' + (e && e.message ? e.message : e), | |
| 117 | + blocked: true | |
| 118 | + }); | |
| 119 | + } | |
| 120 | + finalizeOne(); | |
| 121 | + }, | |
| 122 | + error: function (xhr, status, error) { | |
| 123 | + var payload = (xhr && xhr.responseText) ? xhr.responseText.substring(0, 500) : ''; | |
| 124 | + allResults.push({ | |
| 125 | + method: testMethod, | |
| 126 | + status: 'error', | |
| 127 | + error: 'AJAX failed: ' + error + (payload ? ' \u2014 ' + payload : ''), | |
| 128 | + blocked: true, | |
| 129 | + details: 'Request did not complete successfully. Status: ' + status | |
| 130 | + }); | |
| 131 | + finalizeOne(); | |
| 132 | + } | |
| 133 | + }); | |
| 134 | + }); | |
| 135 | 135 | |
| 136 | - function finalizeOne() { | |
| 137 | - completedTests++; | |
| 138 | - if (completedTests === testsToRun.length) { | |
| 139 | - displayResults(allResults); | |
| 140 | - resetButtons(); | |
| 141 | - // Scroll results into view for clarity | |
| 142 | - var $container = $('#host-test-results'); | |
| 143 | - if ($container && $container[0] && $container[0].scrollIntoView) { | |
| 144 | - $container[0].scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| 145 | - } | |
| 146 | - } | |
| 147 | - } | |
| 148 | - } | |
| 136 | + function finalizeOne() { | |
| 137 | + completedTests++; | |
| 138 | + if (completedTests === testsToRun.length) { | |
| 139 | + displayResults(allResults); | |
| 140 | + resetButtons(); | |
| 141 | + // Scroll results into view for clarity | |
| 142 | + var $container = $('#host-test-results'); | |
| 143 | + if ($container && $container[0] && $container[0].scrollIntoView) { | |
| 144 | + $container[0].scrollIntoView({ behavior: 'smooth', block: 'start' }); | |
| 145 | + } | |
| 146 | + } | |
| 147 | + } | |
| 148 | + } | |
| 149 | 149 | |
| 150 | - function resetButtons() { | |
| 151 | - $('#test-get-request, #test-post-request, #test-both-requests').prop('disabled', false); | |
| 152 | - $('#test-get-request').text('\uD83D\uDD0D Test GET Request'); | |
| 153 | - $('#test-post-request').text('\uD83D\uDCE4 Test POST Request'); | |
| 154 | - $('#test-both-requests').text('\uD83D\uDD04 Test Both Requests'); | |
| 155 | - } | |
| 150 | + function resetButtons() { | |
| 151 | + $('#test-get-request, #test-post-request, #test-both-requests').prop('disabled', false); | |
| 152 | + $('#test-get-request').text('\uD83D\uDD0D Test GET Request'); | |
| 153 | + $('#test-post-request').text('\uD83D\uDCE4 Test POST Request'); | |
| 154 | + $('#test-both-requests').text('\uD83D\uDD04 Test Both Requests'); | |
| 155 | + } | |
| 156 | 156 | |
| 157 | - function displayResults(results) { | |
| 158 | - var html = ''; | |
| 157 | + function makeText(str) { | |
| 158 | + return document.createTextNode(String(str)); | |
| 159 | + } | |
| 159 | 160 | |
| 160 | - results.forEach(function (result) { | |
| 161 | - var statusClass = result.status === 'success' ? 'success' : 'error'; | |
| 162 | - var statusIcon = result.status === 'success' ? '\u2705' : '\u274C'; | |
| 163 | - var blockedStatus = result.blocked ? 'BLOCKED' : 'ALLOWED'; | |
| 164 | - var blockedClass = result.blocked ? 'blocked' : 'allowed'; | |
| 161 | + function makePre(cssClass, content) { | |
| 162 | + var pre = document.createElement('pre'); | |
| 163 | + pre.className = cssClass; | |
| 164 | + pre.appendChild(makeText(content)); | |
| 165 | + return pre; | |
| 166 | + } | |
| 165 | 167 | |
| 166 | - html += '<div class="test-result-item ' + statusClass + '">'; | |
| 167 | - html += '<div class="test-result-header">'; | |
| 168 | - html += '<h4>' + statusIcon + ' ' + result.method + ' Request - ' + blockedStatus + '</h4>'; | |
| 169 | - html += '<span class="test-status ' + blockedClass + '">' + blockedStatus + '</span>'; | |
| 170 | - html += '</div>'; | |
| 168 | + function makeP(labelText, valueText) { | |
| 169 | + var p = document.createElement('p'); | |
| 170 | + var strong = document.createElement('strong'); | |
| 171 | + strong.appendChild(makeText(labelText)); | |
| 172 | + p.appendChild(strong); | |
| 173 | + p.appendChild(makeText(valueText)); | |
| 174 | + return p; | |
| 175 | + } | |
| 171 | 176 | |
| 172 | - html += '<div class="test-result-details">'; | |
| 173 | - html += '<p><strong>Response Time:</strong> ' + result.response_time + '</p>'; | |
| 174 | - html += '<p><strong>Status:</strong> ' + result.status + '</p>'; | |
| 177 | + function displayResults(results) { | |
| 178 | + var $container = $('#test-results-content').empty(); | |
| 175 | 179 | |
| 176 | - if (result.status_code) { | |
| 177 | - html += '<p><strong>HTTP Status Code:</strong> <span class="status-code">' + result.status_code + '</span></p>'; | |
| 178 | - } | |
| 180 | + results.forEach(function (result) { | |
| 181 | + var statusClass = result.status === 'success' ? 'success' : 'error'; | |
| 182 | + var statusIcon = result.status === 'success' ? '\u2705' : '\u274C'; | |
| 183 | + var blockedStatus = result.blocked ? 'BLOCKED' : 'ALLOWED'; | |
| 184 | + var blockedClass = result.blocked ? 'blocked' : 'allowed'; | |
| 179 | 185 | |
| 180 | - if (result.error) { | |
| 181 | - html += '<p><strong>Error:</strong> <span class="error-message">' + result.error + '</span></p>'; | |
| 182 | - } | |
| 186 | + var $item = $('<div>').addClass('test-result-item ' + statusClass); | |
| 183 | 187 | |
| 184 | - if (result.body) { | |
| 185 | - html += '<p><strong>Response Body:</strong></p>'; | |
| 186 | - html += '<pre class="response-body">' + escapeHtml(result.body) + '</pre>'; | |
| 187 | - } | |
| 188 | + // Header | |
| 189 | + var $header = $('<div>').addClass('test-result-header'); | |
| 190 | + $('<h4>').text(statusIcon + ' ' + result.method + ' Request - ' + blockedStatus).appendTo($header); | |
| 191 | + $('<span>').addClass('test-status ' + blockedClass).text(blockedStatus).appendTo($header); | |
| 192 | + $item.append($header); | |
| 188 | 193 | |
| 189 | - if (result.headers && Object.keys(result.headers).length > 0) { | |
| 190 | - html += '<p><strong>Response Headers:</strong></p>'; | |
| 191 | - html += '<pre class="response-headers">'; | |
| 192 | - Object.keys(result.headers).forEach(function (key) { | |
| 193 | - html += key + ': ' + result.headers[key] + '\n'; | |
| 194 | - }); | |
| 195 | - html += '</pre>'; | |
| 196 | - } | |
| 194 | + // Details | |
| 195 | + var $details = $('<div>').addClass('test-result-details'); | |
| 196 | + $details.append(makeP('Response Time: ', result.response_time)); | |
| 197 | + $details.append(makeP('Status: ', result.status)); | |
| 197 | 198 | |
| 198 | - if (result.sent_data) { | |
| 199 | - html += '<p><strong>Sent Data:</strong></p>'; | |
| 200 | - html += '<pre class="sent-data">' + escapeHtml(JSON.stringify(result.sent_data, null, 2)) + '</pre>'; | |
| 201 | - } | |
| 199 | + if (result.status_code) { | |
| 200 | + var $p = $('<p>'); | |
| 201 | + $('<strong>').text('HTTP Status Code: ').appendTo($p); | |
| 202 | + $('<span>').addClass('status-code').text(String(result.status_code)).appendTo($p); | |
| 203 | + $details.append($p); | |
| 204 | + } | |
| 202 | 205 | |
| 203 | - // Show parsed response data if available | |
| 204 | - if (result.parsed_response) { | |
| 205 | - html += '<p><strong>Parsed Response:</strong></p>'; | |
| 206 | - html += '<pre class="parsed-response">' + escapeHtml(JSON.stringify(result.parsed_response, null, 2)) + '</pre>'; | |
| 207 | - } | |
| 206 | + if (result.error) { | |
| 207 | + var $pe = $('<p>'); | |
| 208 | + $('<strong>').text('Error: ').appendTo($pe); | |
| 209 | + $('<span>').addClass('error-message').text(result.error).appendTo($pe); | |
| 210 | + $details.append($pe); | |
| 211 | + } | |
| 208 | 212 | |
| 209 | - html += '<p><strong>Details:</strong> ' + result.details + '</p>'; | |
| 210 | - html += '</div>'; | |
| 211 | - html += '</div>'; | |
| 212 | - }); | |
| 213 | + if (result.body) { | |
| 214 | + $details.append($('<p>').append($('<strong>').text('Response Body:'))); | |
| 215 | + $details.append(makePre('response-body', result.body)); | |
| 216 | + } | |
| 213 | 217 | |
| 214 | - $('#test-results-content').html(html); | |
| 215 | - $('#host-test-results').show(); | |
| 216 | - } | |
| 218 | + if (result.headers && Object.keys(result.headers).length > 0) { | |
| 219 | + $details.append($('<p>').append($('<strong>').text('Response Headers:'))); | |
| 220 | + var headersText = ''; | |
| 221 | + Object.keys(result.headers).forEach(function (key) { | |
| 222 | + headersText += key + ': ' + String(result.headers[key]) + '\n'; | |
| 223 | + }); | |
| 224 | + $details.append(makePre('response-headers', headersText)); | |
| 225 | + } | |
| 217 | 226 | |
| 218 | - function escapeHtml(text) { | |
| 219 | - var map = { | |
| 220 | - '&': '&', | |
| 221 | - '<': '<', | |
| 222 | - '>': '>', | |
| 223 | - '"': '"', | |
| 224 | - "'": ''' | |
| 225 | - }; | |
| 226 | - return text.replace(/[&<>"']/g, function (m) { return map[m]; }); | |
| 227 | - } | |
| 227 | + if (result.sent_data) { | |
| 228 | + $details.append($('<p>').append($('<strong>').text('Sent Data:'))); | |
| 229 | + $details.append(makePre('sent-data', JSON.stringify(result.sent_data, null, 2))); | |
| 230 | + } | |
| 228 | 231 | |
| 229 | - // Verify button exists on page load | |
| 230 | - setTimeout(function () { | |
| 231 | - var btnBoth = $('#test-both-requests'); | |
| 232 | - }, 500); | |
| 233 | - }); | |
| 234 | - } | |
| 232 | + if (result.parsed_response) { | |
| 233 | + $details.append($('<p>').append($('<strong>').text('Parsed Response:'))); | |
| 234 | + $details.append(makePre('parsed-response', JSON.stringify(result.parsed_response, null, 2))); | |
| 235 | + } | |
| 235 | 236 | |
| 236 | - // Start initialization | |
| 237 | - initHostBlockingTest(); | |
| 237 | + $details.append(makeP('Details: ', result.details)); | |
| 238 | + $item.append($details); | |
| 239 | + $container.append($item); | |
| 240 | + }); | |
| 241 | + | |
| 242 | + $('#host-test-results').show(); | |
| 243 | + } | |
| 244 | + | |
| 245 | + function escapeHtml(text) { | |
| 246 | + var map = { | |
| 247 | + '&': '&', | |
| 248 | + '<': '<', | |
| 249 | + '>': '>', | |
| 250 | + '"': '"', | |
| 251 | + "'": ''' | |
| 252 | + }; | |
| 253 | + return text.replace(/[&<>"']/g, function (m) { | |
| 254 | + return map[m]; | |
| 255 | + }); | |
| 256 | + } | |
| 257 | + | |
| 258 | + // Verify button exists on page load | |
| 259 | + setTimeout(function () { | |
| 260 | + var btnBoth = $('#test-both-requests'); | |
| 261 | + }, 500); | |
| 262 | + }); | |
| 263 | + } | |
| 264 | + | |
| 265 | + // Start initialization | |
| 266 | + initHostBlockingTest(); | |
| 238 | 267 | })(); |