PageSourceSearch

https://www.3chi.com/wp-content/plugins/3c-odoo-helpdesk/public/js/form-script.js?ver=1.0.0

js 3chi.com collected 2026-09-25 23:52:00 UTC 14,484 bytes, 391 lines download raw bytes

1/**
2 * Public JavaScript for Odoo Helpdesk Integration
3 */
4(function($) {
5    'use strict';
6
7    // Form handling
8    $(document).ready(function() {
9        const $form = $('#odoo-helpdesk-form');
10        
11        // If form not found, exit
12        if (!$form.length) {
13            return; 
14        }
15        
16        const filesCollection = [];
17        const $fileInput = $('#odoo-file-upload');
18        const $fileList = $('#odoo-file-list');
19        const $submitBtn = $('#odoo-form-submit');
20        const $successMsg = $('#odoo-form-success');
21        const $errorMsg = $('#odoo-form-error');
22        const $loadingIndicator = $('#odoo-form-loading');
23        
24        // File selection handling
25        $fileInput.on('change', function() {
26            // Get the newly selected files
27            const newFiles = Array.from(this.files);
28            
29            // Add new files to collection
30            newFiles.forEach(file => {
31                // Check if file with same name already exists in collection
32                const exists = filesCollection.some(f => f.name === file.name);
33                if (!exists) {
34                    filesCollection.push(file);
35                }
36            });
37            
38            // Clear the file input so the next selection doesn't replace these files
39            $(this).val('');
40            
41            // Update the file list display
42            updateFileList();
43        });
44        
45        // Validate file size and type
46        function validateFile(file) {
47            // Check file size (convert MB to bytes)
48            const maxSizeBytes = parseInt(odooHelpdeskForm.messages.maxFileSize || 5) * 1024 * 1024;
49            if (file.size > maxSizeBytes) {
50                return {
51                    valid: false,
52                    message: odooHelpdeskForm.messages.fileTooBig
53                };
54            }
55            
56            // Check file type
57            const allowedTypes = [
58                'image/jpeg',
59                'image/jpg',
60                'image/png',
61                'image/gif',
62                'image/bmp',
63                'image/webp',
64                'image/tiff',
65                'image/svg+xml',
66                'image/heic',
67                'image/heif'
68            ];
69            
70            if (allowedTypes.indexOf(file.type) === -1) {
71                return {
72                    valid: false,
73                    message: odooHelpdeskForm.messages.invalidFileType
74                };
75            }
76            
77            return { valid: true };
78        }
79        
80        // Update file list display
81        function updateFileList() {
82            $fileList.empty();
83            
84            if (filesCollection.length === 0) {
85                return;
86            }
87            
88            let allValid = true;
89            
90            for (let i = 0; i < filesCollection.length; i++) {
91                const file = filesCollection[i];
92                const validation = validateFile(file);
93                const $item = $('<div>', {
94                    class: 'odoo-file-item' + (validation.valid ? '' : ' invalid')
95                });
96                
97                $item.append(
98                    $('<span>', { class: 'file-name', text: file.name }),
99                    $('<span>', { 
100                        class: 'file-size', 
101                        text: formatFileSize(file.size) 
102                    })
103                );
104                
105                // Add a remove button for each file
106                const $removeBtn = $('<button>', {
107                    type: 'button',
108                    class: 'odoo-file-remove',
109                    text: 'x',
110                    'data-index': i,
111                    click: function() {
112                        const index = $(this).data('index');
113                        filesCollection.splice(index, 1);
114                        updateFileList();
115                    }
116                });
117                
118                $item.append($removeBtn);
119                
120                if (!validation.valid) {
121                    $item.append(
122                        $('<span>', { 
123                            class: 'file-error', 
124                            text: validation.message 
125                        })
126                    );
127                    allValid = false;
128                }
129                
130                $fileList.append($item);
131            }
132            
133            // Disable submit if any files are invalid
134            $submitBtn.prop('disabled', !allValid);
135        }
136        
137        // Format file size for display
138        function formatFileSize(bytes) {
139            if (bytes === 0) return '0 Bytes';
140            
141            const k = 1024;
142            const sizes = ['Bytes', 'KB', 'MB'];
143            const i = Math.floor(Math.log(bytes) / Math.log(k));
144            
145            return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
146        }
147        
148        // Custom form validation
149        function validateForm() {
150            let isValid = true;
151            let firstInvalid = null;
152            
153            // Check required fields
154            $form.find('[required]').each(function() {
155                const $field = $(this);
156                const $formGroup = $field.closest('.odoo-form-group');
157                const $errorMessage = $formGroup.find('.validation-error');
158                
159                // Remove any existing error message
160                if ($errorMessage.length) {
161                    $errorMessage.remove();
162                }
163                
164                // Check if field is empty
165                if (!$field.val().trim()) {
166                    isValid = false;
167                    
168                    // Create and add error message
169                    const fieldName = $field.attr('aria-labelledby') 
170                        ? $('#' + $field.attr('aria-labelledby')).text().replace('*', '').trim()
171                        : 'This field';
172                    
173                    const $error = $('<div>', {
174                        'class': 'validation-error',
175                        'id': $field.attr('id') + '-error',
176                        'text': fieldName + ' is required.',
177                        'role': 'alert'
178                    });
179                    
180                    $formGroup.append($error);
181                    $field.attr('aria-invalid', 'true')
182                        .attr('aria-describedby', $field.attr('id') + '-error');
183                    
184                    if (!firstInvalid) {
185                        firstInvalid = $field;
186                    }
187                } else {
188                    $field.removeAttr('aria-invalid')
189                        .removeAttr('aria-describedby');
190                }
191            });
192            
193            // Check if any category is selected
194            if ($('input[name="category"]:checked').length === 0) {
195                isValid = false;
196                const $radioGroup = $('.odoo-radio-group');
197                
198                // Remove any existing error message
199                $radioGroup.find('.validation-error').remove();
200                
201                // Create and add error message
202                const $error = $('<div>', {
203                    'class': 'validation-error',
204                    'id': 'category-error',
205                    'text': 'Please select a support category.',
206                    'role': 'alert'
207                });
208                
209                $radioGroup.append($error);
210                $radioGroup.attr('aria-describedby', 'category-error');
211                
212                if (!firstInvalid) {
213                    firstInvalid = $('input[name="category"]').first();
214                }
215            } else {
216                $('.odoo-radio-group').removeAttr('aria-describedby');
217            }
218            
219            // Focus the first invalid field
220            if (firstInvalid) {
221                firstInvalid.focus();
222            }
223            
224            return isValid;
225        }
226        
227        // Form submission
228        $form.on('submit', function(e) {
229            e.preventDefault();
230            
231            // Hide previous messages
232            $successMsg.hide();
233            $errorMsg.hide();
234            
235            // Validate form
236            if (!$form[0].checkValidity()) {
237                $form[0].reportValidity();
238                return;
239            }
240            
241            // Check reCAPTCHA if enabled
242            if (odooHelpdeskForm.recaptchaEnabled) {
243                const recaptchaResponse = grecaptcha.getResponse();
244                if (recaptchaResponse.length === 0) {
245                    $errorMsg.text(odooHelpdeskForm.messages.recaptchaError).show();
246                    return;
247                }
248            }
249            
250            // Show loading indicator
251            $loadingIndicator.show();
252            $submitBtn.prop('disabled', true);
253            
254            // Prepare form data
255            const formData = new FormData($form[0]);
256            formData.append('action', 'submit_odoo_ticket');
257            formData.append('odoo_helpdesk_nonce', odooHelpdeskForm.nonce);
258            
259            // Submit form data via AJAX
260            $.ajax({
261                url: odooHelpdeskForm.ajaxUrl,
262                type: 'POST',
263                data: formData,
264                processData: false,
265                contentType: false,
266                success: function(response) {
267                    if (response.success) {
268                        // Handle successful ticket creation
269                        handleSuccessfulSubmission(response.data);
270                    } else {
271                        // Handle error
272                        $errorMsg.text(response.data.message || odooHelpdeskForm.messages.error).show();
273                        $submitBtn.prop('disabled', false);
274                        // Reset recaptcha if enabled
275                        if (odooHelpdeskForm.recaptchaEnabled) {
276                            grecaptcha.reset();
277                        }
278                    }
279                },
280                error: function() {
281                    $errorMsg.text(odooHelpdeskForm.messages.error).show();
282                    $submitBtn.prop('disabled', false);
283                    // Reset recaptcha if enabled
284                    if (odooHelpdeskForm.recaptchaEnabled) {
285                        grecaptcha.reset();
286                    }
287                },
288                complete: function() {
289                    $loadingIndicator.hide();
290                }
291            });
292        });
293        
294        // Display error message
295        function showError(message) {
296            $errorMsg.text(message).show();
297            $errorMsg.focus(); // Focus for screen readers
298        }
299        
300        // Handle successful form submission and file uploads
301        function handleSuccessfulSubmission(data) {
302            const ticketId = data.ticket_id;
303            
304            // If no files to upload, show success message immediately
305            if (filesCollection.length === 0) {
306                showSuccessMessage();
307                return;
308            }
309            
310            // Upload files one by one
311            let uploadedCount = 0;
312            let failedUploads = 0;
313            
314            const uploadNextFile = function(index) {
315                if (index >= filesCollection.length) {
316                    // All files processed
317                    if (failedUploads > 0) {
318                        $successMsg.text(
319                            odooHelpdeskForm.messages.success + ' ' + 
320                            failedUploads + ' file(s) could not be uploaded.'
321                        ).show();
322                    } else {
323                        showSuccessMessage();
324                    }
325                    return;
326                }
327                
328                const file = filesCollection[index];
329                const fileData = new FormData();
330                fileData.append('action', 'upload_odoo_attachment');
331                fileData.append('odoo_helpdesk_nonce', odooHelpdeskForm.nonce);
332                fileData.append('ticket_id', ticketId);
333                fileData.append('file', file);
334                
335                $.ajax({
336                    url: odooHelpdeskForm.ajaxUrl,
337                    type: 'POST',
338                    data: fileData,
339                    processData: false,
340                    contentType: false,
341                    success: function(response) {
342                        if (response.success) {
343                            uploadedCount++;
344                        } else {
345                            failedUploads++;
346                        }
347                    },
348                    error: function() {
349                        failedUploads++;
350                    },
351                    complete: function() {
352                        // Process next file
353                        uploadNextFile(index + 1);
354                    }
355                });
356            };
357            
358            // Start uploading files
359            uploadNextFile(0);
360        }
361        
362        // Show success message and reset form
363        function showSuccessMessage() {
364            $form.hide();
365            $successMsg.text(odooHelpdeskForm.messages.success).show();
366            $form[0].reset();
367            $fileList.empty();
368            filesCollection.length = 0;
369
370            // Reset recaptcha if enabled
371            if (odooHelpdeskForm.recaptchaEnabled && typeof grecaptcha !== 'undefined') {
372                grecaptcha.reset();
373            }
374        }
375        
376        // Add CSS for validation errors
377        $('<style>')
378            .text(`
379                .validation-error {
380                    color: #d63638;
381                    font-size: 0.9em;
382                    margin-top: 5px;
383                }
384                [aria-invalid="true"] {
385                    border-color: #d63638;
386                }
387            `)
388            .appendTo('head');
389    });
390
391})(jQuery);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.