PluginProbe
404 Solution / 4.2.0
404 Solution v4.2.0
4.3.5 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 4.2.0 4.1.19 4.1.18 4.1.17 4.1.16 4.1.15 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.1.7 4.1.6 4.1.5 4.1.4 4.1.3 trunk 2.30.0 All 109 releases
404-solution / includes / js / general.js

general.js in 404 Solution 4.2.0, at includes/js/general.js

219 lines 7.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var abj404_whichButtonClicked = null;
2
3 jQuery(document).ready(function($) {
4 var adminOptionsPage = document.getElementById("admin-options-page");
5 if (adminOptionsPage) {
6 adminOptionsPage.addEventListener('submit', submitOptions);
7 }
8
9 var deleteDebugFileButton = document.querySelector('#deleteDebugFile');
10 if (deleteDebugFileButton) {
11 deleteDebugFileButton.addEventListener('click', function(e) {
12 abj404_whichButtonClicked = 'deleteDebugFile';
13 submitOptions(e);
14 });
15 }
16 })
17
18 function striphtml(html) {
19 var tmp = document.createElement("DIV");
20 tmp.innerHTML = html;
21 return tmp.textContent || tmp.innerText || "";
22 }
23
24 function submitOptions(e) {
25 e.preventDefault();
26
27 // Show loading overlay
28 showSaveOverlay();
29
30 // gather form data.
31 var form = document.getElementById("admin-options-page");
32 var formElements = form.elements;
33 var formData = {};
34 for (var i = 0; i < formElements.length; i++) {
35 var field = formElements[i];
36 var currentValue = field.value;
37 if (field.type == 'checkbox') {
38 currentValue = field.checked ? 1 : 0;
39 }
40
41 if (!(field.name in formData)) {
42 formData[field.name] = currentValue;
43 } else {
44 if (!Array.isArray(formData[field.name])) {
45 formData[field.name] = new Array(formData[field.name]);
46 }
47 formData[field.name].push(currentValue);
48 }
49 }
50
51 // if we should just delete the log file.
52 if (abj404_whichButtonClicked == 'deleteDebugFile') {
53 // set the action to 'updateOptions' and set deleteDebugFile to true
54 formData['action'] = 'updateOptions';
55 formData['deleteDebugFile'] = true;
56 } else {
57 formData['deleteDebugFile'] = false;
58 }
59
60 // fix checkboxes.
61 var formDataAsJson = JSON.stringify(formData);
62 var encodedData = encodeURI(formDataAsJson);
63
64 // save / send the data via an ajax request.
65 var saveOptionsURL = form.getAttribute('data-url')
66
67 // Set timeout to handle hung requests
68 var timeoutId = setTimeout(function() {
69 showSaveError('Request timed out. Please check your connection and try again.');
70 }, 30000); // 30 second timeout
71
72 jQuery.ajax({
73 url: saveOptionsURL,
74 type: 'POST',
75 data: {
76 'encodedData': encodedData
77 },
78 dataType :'json',
79 success: function (data) {
80 clearTimeout(timeoutId);
81 // Support both legacy payloads ({ newURL, message, error }) and WP-shaped responses
82 // ({ success: true|false, data: { ... } }).
83 var payload = data;
84 if (data && typeof data === 'object' && typeof data.success === 'boolean' && data.data !== undefined) {
85 if (data.success === false) {
86 var serverMsg = '';
87 if (typeof data.data === 'string') {
88 serverMsg = data.data;
89 } else if (data.data && data.data.message) {
90 serverMsg = data.data.message;
91 }
92 showSaveError(serverMsg || "Error saving settings. Please try again.");
93 return;
94 }
95 payload = data.data;
96 }
97
98 // Safety: if we don't have the redirect URL, treat as failure.
99 if (!payload || payload['newURL'] === undefined) {
100 showSaveError("Error saving settings. Please try again.");
101 return;
102 }
103
104 var message = striphtml(JSON.stringify(payload, null, 2));
105 console.log("saved options: " + message);
106
107 // redirect and post a message (overlay will disappear on page reload)
108 // Use DOM methods to avoid XSS from unescaped payload values in HTML attributes.
109 var formEl = document.createElement('form');
110 formEl.method = 'post';
111 formEl.action = payload['newURL'];
112 formEl.style.display = 'none';
113 var inputEl = document.createElement('input');
114 inputEl.type = 'text';
115 inputEl.name = 'display-this-message';
116 inputEl.value = payload['message'];
117 formEl.appendChild(inputEl);
118 document.body.appendChild(formEl);
119 formEl.submit();
120 },
121 error: function (request, error) {
122 clearTimeout(timeoutId);
123 var errMsg = "Error saving settings. Please try again.";
124
125 // Try to get a more specific error message
126 if (request.responseJSON && request.responseJSON.message) {
127 errMsg = request.responseJSON.message;
128 } else if (request.responseJSON && request.responseJSON.data) {
129 // wp_send_json_error() format: { success: false, data: ... }
130 if (typeof request.responseJSON.data === 'string') {
131 errMsg = request.responseJSON.data;
132 } else if (request.responseJSON.data.message) {
133 errMsg = request.responseJSON.data.message;
134 }
135 } else if (request.statusText && request.statusText !== 'error') {
136 errMsg = "Error: " + request.statusText;
137 }
138
139 showSaveError(errMsg);
140
141 // Log full error to console for debugging
142 console.error("Save error details:", {
143 request: request,
144 error: error
145 });
146 }
147 });
148
149 // don't submit the form.
150 return false;
151 }
152
153 function showSaveOverlay() {
154 var overlay = document.getElementById('abj404-save-overlay');
155 if (overlay) {
156 overlay.style.display = 'flex';
157 overlay.classList.remove('error');
158
159 // Update message to default
160 var message = overlay.querySelector('.abj404-save-message');
161 if (message) {
162 message.textContent = abj404General.savingSettings;
163 }
164
165 // Announce to screen readers
166 abj404AnnounceToScreenReader(abj404General.savingSettings);
167 }
168 }
169
170 /**
171 * Announce a message to screen readers using a live region
172 * @param {string} message The message to announce
173 * @param {string} priority 'polite' or 'assertive' (default: 'polite')
174 */
175 function abj404AnnounceToScreenReader(message, priority) {
176 priority = priority || 'polite';
177
178 // Create or get the live region
179 var liveRegion = document.getElementById('abj404-live-region');
180 if (!liveRegion) {
181 liveRegion = document.createElement('div');
182 liveRegion.id = 'abj404-live-region';
183 liveRegion.className = 'abj404-live-region';
184 liveRegion.setAttribute('aria-live', priority);
185 liveRegion.setAttribute('aria-atomic', 'true');
186 liveRegion.setAttribute('role', 'status');
187 document.body.appendChild(liveRegion);
188 }
189
190 // Update priority if needed
191 liveRegion.setAttribute('aria-live', priority);
192
193 // Clear and set the message (clearing first ensures re-announcement)
194 liveRegion.textContent = '';
195 setTimeout(function() {
196 liveRegion.textContent = message;
197 }, 100);
198 }
199
200 function showSaveError(errorMessage) {
201 var overlay = document.getElementById('abj404-save-overlay');
202 if (overlay) {
203 overlay.classList.add('error');
204
205 var message = overlay.querySelector('.abj404-save-message');
206 if (message) {
207 message.textContent = errorMessage;
208 }
209
210 // Announce error to screen readers with assertive priority
211 abj404AnnounceToScreenReader(errorMessage, 'assertive');
212
213 // Hide overlay after 5 seconds
214 setTimeout(function() {
215 overlay.style.display = 'none';
216 }, 5000);
217 }
218 }
219