PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.6.3
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.6.3
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.6.3, at views/js/metasync-report-issue.js

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