PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.1
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.1
2.7.1 2.7.2 2.7.0 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 All 141 releases
metasync / views / js / metasync-report-issue.js

metasync-report-issue.js in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.7.1, at views/js/metasync-report-issue.js

160 lines 6.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /* global jQuery, ajaxurl */
2 /**
3 * MetaSync report issue form.
4 *
5 * Extracted from views/metasync-report-issue.php (Phase 5, #887).
6 */
7 jQuery(document).ready(function($) {
8 const CHAR_LIMIT = 1000;
9 const $messageField = $('#metasync_issue_message');
10 const $charCounter = $('#metasync_char_counter');
11
12 // Update character counter and show feedback
13 function updateCharCounter() {
14 const len = $messageField.val() ? $messageField.val().length : 0;
15 $charCounter.text(len + '/' + CHAR_LIMIT);
16 $charCounter.removeClass('metasync-char-counter-warning metasync-char-counter-limit');
17 if (len >= CHAR_LIMIT) {
18 $charCounter.addClass('metasync-char-counter-limit');
19 } else if (len >= CHAR_LIMIT - 50) {
20 $charCounter.addClass('metasync-char-counter-warning');
21 }
22 }
23
24 $messageField.on('input keyup paste', updateCharCounter);
25 updateCharCounter(); // Initial state
26
27 $('#metasync-report-issue-form').on('submit', function(e) {
28 e.preventDefault();
29
30 const $form = $(this);
31 const $submitBtn = $('#metasync-submit-report-btn');
32 const $btnText = $submitBtn.find('.metasync-btn-text');
33 const $btnLoading = $submitBtn.find('.metasync-btn-loading');
34 const $responseMsg = $('#metasync-report-response-message');
35 const $messageField = $('#metasync_issue_message');
36
37 // Validate message length
38 const message = $messageField.val() ? $messageField.val().trim() : '';
39 if (message.length < 10) {
40 $responseMsg
41 .removeClass('success')
42 .addClass('error')
43 .html('❌ Please provide a more detailed description (at least 10 characters).')
44 .css('display', 'block');
45 return;
46 }
47
48 // Validate message length (max 1000 characters)
49 if (message.length > 1000) {
50 $responseMsg
51 .removeClass('success')
52 .addClass('error')
53 .html('❌ Message is too long. Please limit to 1000 characters.')
54 .css('display', 'block');
55 return;
56 }
57
58 // Validate file size (max 5MB)
59 const $fileInput = $('#metasync_issue_attachment')[0];
60 if ($fileInput && $fileInput.files && $fileInput.files[0]) {
61 const fileSize = $fileInput.files[0].size;
62 const maxSize = 5 * 1024 * 1024; // 5MB
63 if (fileSize > maxSize) {
64 $responseMsg
65 .removeClass('success')
66 .addClass('error')
67 .html('❌ File size exceeds 5MB. Please choose a smaller file.')
68 .css('display', 'block');
69 return;
70 }
71 }
72
73 // Disable submit button and show loading
74 $submitBtn.prop('disabled', true);
75 $btnText.css('display', 'none');
76 $btnLoading.css('display', 'flex');
77 $responseMsg.css('display', 'none');
78
79 // Prepare form data using FormData to support file uploads
80 const formData = new FormData();
81 formData.append('action', 'metasync_submit_issue_report');
82 formData.append('nonce', $form.find('#metasync_report_issue_nonce').val());
83 formData.append('issue_message', message);
84 formData.append('issue_severity', $('#metasync_issue_severity').val());
85 formData.append('include_user_info', $('#metasync_include_user_info').is(':checked'));
86
87 // Add file if selected
88 if ($fileInput && $fileInput.files && $fileInput.files[0]) {
89 formData.append('issue_attachment', $fileInput.files[0]);
90 }
91
92 // Submit via AJAX
93 $.ajax({
94 url: ajaxurl,
95 type: 'POST',
96 data: formData,
97 dataType: 'json',
98 processData: false,
99 contentType: false,
100 success: function(response) {
101 // Ensure response is valid
102 if (!response || typeof response !== 'object') {
103 $responseMsg
104 .removeClass('success')
105 .addClass('error')
106 .html('❌ Invalid response from server. Please try again.')
107 .css('display', 'block');
108 return;
109 }
110
111 if (response.success) {
112 const message = (response.data && response.data.message) ? response.data.message : 'Report submitted successfully!';
113 $responseMsg
114 .removeClass('error')
115 .addClass('success')
116 .text('�
117 ' + message) // SECURITY: Use .text() to prevent XSS
118 .css('display', 'block');
119
120 // Reset form
121 $form[0].reset();
122 updateCharCounter();
123
124 // Scroll to success message
125 if ($responseMsg.offset()) {
126 $('html, body').animate({
127 scrollTop: $responseMsg.offset().top - 100
128 }, 500);
129 }
130 } else {
131 const errorMessage = (response.data && response.data.message) ? response.data.message : 'Failed to submit report. Please try again.';
132 $responseMsg
133 .removeClass('success')
134 .addClass('error')
135 .text('❌ ' + errorMessage) // SECURITY: Use .text() to prevent XSS
136 .css('display', 'block');
137 }
138 },
139 error: function(xhr, status, error) {
140 $responseMsg
141 .removeClass('success')
142 .addClass('error')
143 .html('❌ An error occurred while submitting your report. Please try again later.')
144 .css('display', 'block');
145
146 // Log error only in debug mode
147 if (typeof console !== 'undefined' && console.error && window.metasyncDebug) {
148 console.error('MetaSync report submission error:', error);
149 }
150 },
151 complete: function() {
152 // Re-enable submit button
153 $submitBtn.prop('disabled', false);
154 $btnText.css('display', 'inline');
155 $btnLoading.css('display', 'none');
156 }
157 });
158 });
159 });
160