PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.13
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.13
2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 2.6.4 2.6.3 2.5.23 All 138 releases
metasync / admin / js / metasync-execution-settings.js

metasync-execution-settings.js in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.6.13, at admin/js/metasync-execution-settings.js

268 lines 9.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global metasyncExecSettingsData, jQuery, ajaxurl */
2 /**
3 * MetaSync Execution Settings
4 *
5 * Extracted for Phase 5, #887.
6 * Real-time validation and AJAX save for execution / performance settings.
7 *
8 * Localized object: metasyncExecSettingsData
9 * - serverMaxExecTime (int|string 'Infinity')
10 * - serverMaxMemory (int|string 'Infinity')
11 * - canChangeMemory (bool)
12 *
13 * @since Phase 5
14 */
15 jQuery(document).ready(function ($) {
16 var $form = $('#metasync-execution-settings-form');
17 var $saveBtn = $('#metasync-execution-settings-save-btn');
18 var $message = $('#metasync-execution-settings-message');
19
20 // Server limit values from localized data
21 var serverMaxExecTime = metasyncExecSettingsData.serverMaxExecTime;
22 var serverMaxMemory = metasyncExecSettingsData.serverMaxMemory;
23 var canChangeMemory = metasyncExecSettingsData.canChangeMemory;
24
25 // Normalize to numbers ('Infinity' marker -> JS Infinity). wp_localize_script
26 // casts every scalar to a string, so these arrive as e.g. "2048"; comparing a
27 // string field value against a string limit ("256" > "2048") would be
28 // lexicographic and wrong, so coerce to numbers here.
29 serverMaxExecTime = (serverMaxExecTime === 'Infinity') ? Infinity : parseInt(serverMaxExecTime, 10);
30 serverMaxMemory = (serverMaxMemory === 'Infinity') ? Infinity : parseInt(serverMaxMemory, 10);
31
32 // Real-time validation for server limits
33 function checkServerLimits() {
34 var maxExecTime = parseInt($('#max_execution_time').val()) || 0;
35 var maxMemory = parseInt($('#max_memory_limit').val()) || 0;
36
37 // Check execution time limit
38 if (serverMaxExecTime !== Infinity && maxExecTime > serverMaxExecTime) {
39 $('#max_execution_time_warning').show();
40 } else {
41 $('#max_execution_time_warning').hide();
42 }
43
44 // Check memory limit (only if server allows changing it)
45 if (canChangeMemory && serverMaxMemory !== Infinity && maxMemory > serverMaxMemory) {
46 $('#max_memory_limit_warning').show();
47 } else {
48 $('#max_memory_limit_warning').hide();
49 }
50 }
51
52 // Real-time validation on input change
53 $('#max_execution_time, #max_memory_limit').on('input change', function () {
54 checkServerLimits();
55 // Remove error styling when user starts typing
56 $(this).css('border-color', 'var(--dashboard-border)');
57 });
58
59 // Add visual feedback for invalid inputs
60 function highlightInvalidField($field, isValid) {
61 if (isValid) {
62 $field.css({
63 'border-color': 'var(--dashboard-border)',
64 'box-shadow': 'none'
65 });
66 } else {
67 $field.css({
68 'border-color': '#ef4444',
69 'box-shadow': '0 0 0 3px rgba(239, 68, 68, 0.1)'
70 });
71 }
72 }
73
74 // Validate individual fields on blur
75 $('#max_execution_time').on('blur', function () {
76 var value = parseInt($(this).val()) || 0;
77 var isValid = value >= 1 && value <= 300 && (serverMaxExecTime === Infinity || value <= serverMaxExecTime);
78 highlightInvalidField($(this), isValid);
79 });
80
81 $('#max_memory_limit').on('blur', function () {
82 if (!canChangeMemory) {
83 return;
84 }
85 var value = parseInt($(this).val()) || 0;
86 var isValid = value >= 64 && (serverMaxMemory === Infinity || value <= serverMaxMemory);
87 highlightInvalidField($(this), isValid);
88 });
89
90 // Initial check on page load
91 checkServerLimits();
92
93 // Save button click (not form submit — form is nested inside #metaSyncGeneralSetting which would double-fire)
94 $saveBtn.on('click', function (e) {
95 e.preventDefault();
96
97 var formData = {
98 action: 'metasync_save_execution_settings',
99 execution_settings_nonce: $('#execution_settings_nonce').val(),
100 max_execution_time: $('#max_execution_time').val(),
101 max_memory_limit: $('#max_memory_limit').val(),
102 log_batch_size: $('#log_batch_size').val(),
103 action_scheduler_batches: $('#action_scheduler_batches').val(),
104 otto_rate_limit: $('#otto_rate_limit').val(),
105 queue_cleanup_days: $('#queue_cleanup_days').val()
106 };
107
108 // Clear previous error highlights
109 $('input[type="number"]').css({
110 'border-color': 'var(--dashboard-border)',
111 'box-shadow': 'none'
112 });
113
114 // Validate ranges
115 var hasError = false;
116 var errorField = null;
117
118 if (formData.max_execution_time < 1 || formData.max_execution_time > 300) {
119 showMessage('Max Execution Time must be between 1 and 300 seconds.', 'error');
120 highlightInvalidField($('#max_execution_time'), false);
121 errorField = $('#max_execution_time');
122 hasError = true;
123 } else if (serverMaxExecTime !== Infinity && formData.max_execution_time > serverMaxExecTime) {
124 showMessage('Max Execution Time exceeds server limit of ' + serverMaxExecTime + ' seconds. Please reduce the value.', 'error');
125 highlightInvalidField($('#max_execution_time'), false);
126 errorField = $('#max_execution_time');
127 hasError = true;
128 }
129
130 // Only validate memory limit if server allows changing it
131 if (canChangeMemory) {
132 if (formData.max_memory_limit < 64) {
133 showMessage('Max Memory Limit must be at least 64 MB.', 'error');
134 highlightInvalidField($('#max_memory_limit'), false);
135 if (!hasError) {
136 errorField = $('#max_memory_limit');
137 hasError = true;
138 }
139 } else if (serverMaxMemory !== Infinity && formData.max_memory_limit > serverMaxMemory) {
140 showMessage('Max Memory Limit must be between 64 and ' + serverMaxMemory + ' MB.', 'error');
141 highlightInvalidField($('#max_memory_limit'), false);
142 if (!hasError) {
143 errorField = $('#max_memory_limit');
144 hasError = true;
145 }
146 }
147 }
148
149 if (formData.log_batch_size < 100 || formData.log_batch_size > 5000) {
150 showMessage('Log Batch Size must be between 100 and 5000 lines.', 'error');
151 highlightInvalidField($('#log_batch_size'), false);
152 if (!hasError) {
153 errorField = $('#log_batch_size');
154 hasError = true;
155 }
156 }
157 if (formData.action_scheduler_batches < 1 || formData.action_scheduler_batches > 10) {
158 showMessage('Action Scheduler Batches must be between 1 and 10.', 'error');
159 highlightInvalidField($('#action_scheduler_batches'), false);
160 if (!hasError) {
161 errorField = $('#action_scheduler_batches');
162 hasError = true;
163 }
164 }
165 if (formData.otto_rate_limit < 1 || formData.otto_rate_limit > 60) {
166 showMessage('OTTO Rate Limit must be between 1 and 60 calls per minute.', 'error');
167 highlightInvalidField($('#otto_rate_limit'), false);
168 if (!hasError) {
169 errorField = $('#otto_rate_limit');
170 hasError = true;
171 }
172 }
173 if (formData.queue_cleanup_days < 7 || formData.queue_cleanup_days > 90) {
174 showMessage('Queue Cleanup Days must be between 7 and 90 days.', 'error');
175 highlightInvalidField($('#queue_cleanup_days'), false);
176 if (!hasError) {
177 errorField = $('#queue_cleanup_days');
178 hasError = true;
179 }
180 }
181
182 if (hasError) {
183 if (errorField) {
184 errorField.focus();
185 // Scroll to error field
186 $('html, body').animate({
187 scrollTop: errorField.offset().top - 100
188 }, 300);
189 }
190 return;
191 }
192
193 // Show loading state
194 $saveBtn.prop('disabled', true);
195 $saveBtn.find('.save-text').text('Saving...');
196 $saveBtn.find('.save-spinner').show();
197 $message.hide();
198
199 $.ajax({
200 url: ajaxurl,
201 type: 'POST',
202 data: formData,
203 success: function (response) {
204 if (response.success) {
205 showMessage(response.data.message || 'Settings saved successfully!', 'success');
206 // Re-enable button
207 $saveBtn.prop('disabled', false);
208 $saveBtn.find('.save-text').text('Save Settings');
209 $saveBtn.find('.save-spinner').hide();
210 // Re-check server limits after save
211 setTimeout(function () {
212 checkServerLimits();
213 }, 100);
214 // Scroll to top to show success message
215 $('html, body').animate({
216 scrollTop: $form.offset().top - 100
217 }, 300);
218 } else {
219 showMessage(response.data.message || 'Error saving settings.', 'error');
220 $saveBtn.prop('disabled', false);
221 $saveBtn.find('.save-text').text('Save Settings');
222 $saveBtn.find('.save-spinner').hide();
223 // Scroll to show error message
224 $('html, body').animate({
225 scrollTop: $message.offset().top - 100
226 }, 300);
227 }
228 },
229 error: function () {
230 showMessage('An error occurred while saving settings. Please try again.', 'error');
231 $saveBtn.prop('disabled', false);
232 $saveBtn.find('.save-text').text('Save Settings');
233 $saveBtn.find('.save-spinner').hide();
234 // Scroll to show error message
235 $('html, body').animate({
236 scrollTop: $message.offset().top - 100
237 }, 300);
238 }
239 });
240 });
241
242 function showMessage(text, type) {
243 $message.removeClass('notice-success notice-error')
244 .addClass('notice-' + type)
245 .css({
246 'background': type === 'success' ? 'rgba(34, 197, 94, 0.1)' : 'rgba(239, 68, 68, 0.1)',
247 'border': '1px solid ' + (type === 'success' ? 'rgba(34, 197, 94, 0.3)' : 'rgba(239, 68, 68, 0.3)'),
248 'color': type === 'success' ? '#22c55e' : '#ef4444',
249 'padding': '12px 16px',
250 'border-radius': '6px',
251 'font-size': '14px',
252 'line-height': '1.5',
253 'display': 'block'
254 })
255 .empty()
256 .append($('<strong>').css('margin-right', '8px').text(type === 'success' ? '\u2713' : '\u2717'))
257 .show();
258 $message[0].appendChild(document.createTextNode(text));
259
260 // Auto-hide success messages after 5 seconds
261 if (type === 'success') {
262 setTimeout(function () {
263 $message.fadeOut(300);
264 }, 5000);
265 }
266 }
267 });
268