VFS Global Form Auto-Filler

Automatically fills VFS Global visa application forms with saved data

Size

14.8 KB

Version

1.1.2

Created

Dec 8, 2025

Updated

4 days ago

1// ==UserScript==
2// @name		VFS Global Form Auto-Filler
3// @description		Automatically fills VFS Global visa application forms with saved data
4// @version		1.1.2
5// @match		https://*.visa.vfsglobal.com/*
6// @icon		https://liftassets.vfsglobal.com/_angular/assets/images/global/vfs.ico
7// ==/UserScript==
8(function() {
9    'use strict';
10
11    console.log('VFS Global Form Auto-Filler initialized');
12
13    // Debounce function to prevent excessive calls
14    function debounce(func, wait) {
15        let timeout;
16        return function executedFunction(...args) {
17            const later = () => {
18                clearTimeout(timeout);
19                func(...args);
20            };
21            clearTimeout(timeout);
22            timeout = setTimeout(later, wait);
23        };
24    }
25
26    // Add custom styles for the UI
27    TM_addStyle(`
28        .vfs-autofill-container {
29            position: fixed;
30            top: 20px;
31            right: 20px;
32            z-index: 10000;
33            background: white;
34            border: 2px solid #ff6b35;
35            border-radius: 8px;
36            padding: 15px;
37            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
38            font-family: Arial, sans-serif;
39            max-width: 300px;
40        }
41
42        .vfs-autofill-header {
43            font-size: 16px;
44            font-weight: bold;
45            color: #333;
46            margin-bottom: 10px;
47            display: flex;
48            justify-content: space-between;
49            align-items: center;
50        }
51
52        .vfs-close-btn {
53            background: none;
54            border: none;
55            font-size: 20px;
56            cursor: pointer;
57            color: #666;
58            padding: 0;
59            width: 24px;
60            height: 24px;
61            line-height: 20px;
62        }
63
64        .vfs-close-btn:hover {
65            color: #ff6b35;
66        }
67
68        .vfs-autofill-btn {
69            background: #ff6b35;
70            color: white;
71            border: none;
72            padding: 10px 20px;
73            border-radius: 5px;
74            cursor: pointer;
75            font-size: 14px;
76            font-weight: bold;
77            width: 100%;
78            margin-bottom: 10px;
79            transition: background 0.3s;
80        }
81
82        .vfs-autofill-btn:hover {
83            background: #e55a2b;
84        }
85
86        .vfs-autofill-btn:disabled {
87            background: #ccc;
88            cursor: not-allowed;
89        }
90
91        .vfs-settings-btn {
92            background: white;
93            color: #ff6b35;
94            border: 2px solid #ff6b35;
95            padding: 8px 16px;
96            border-radius: 5px;
97            cursor: pointer;
98            font-size: 13px;
99            width: 100%;
100            transition: all 0.3s;
101        }
102
103        .vfs-settings-btn:hover {
104            background: #ff6b35;
105            color: white;
106        }
107
108        .vfs-form-group {
109            margin-bottom: 12px;
110        }
111
112        .vfs-form-group label {
113            display: block;
114            font-size: 13px;
115            color: #333;
116            margin-bottom: 5px;
117            font-weight: 500;
118        }
119
120        .vfs-form-group input,
121        .vfs-form-group select {
122            width: 100%;
123            padding: 8px;
124            border: 1px solid #ddd;
125            border-radius: 4px;
126            font-size: 13px;
127            box-sizing: border-box;
128        }
129
130        .vfs-form-group input:focus,
131        .vfs-form-group select:focus {
132            outline: none;
133            border-color: #ff6b35;
134        }
135
136        .vfs-save-btn {
137            background: #4CAF50;
138            color: white;
139            border: none;
140            padding: 10px 20px;
141            border-radius: 5px;
142            cursor: pointer;
143            font-size: 14px;
144            font-weight: bold;
145            width: 100%;
146            margin-top: 10px;
147            transition: background 0.3s;
148        }
149
150        .vfs-save-btn:hover {
151            background: #45a049;
152        }
153
154        .vfs-status-message {
155            padding: 8px;
156            border-radius: 4px;
157            font-size: 12px;
158            margin-top: 10px;
159            text-align: center;
160        }
161
162        .vfs-status-success {
163            background: #d4edda;
164            color: #155724;
165            border: 1px solid #c3e6cb;
166        }
167
168        .vfs-status-error {
169            background: #f8d7da;
170            color: #721c24;
171            border: 1px solid #f5c6cb;
172        }
173
174        .vfs-floating-btn {
175            position: fixed;
176            bottom: 30px;
177            right: 30px;
178            z-index: 9999;
179            background: #ff6b35;
180            color: white;
181            border: none;
182            padding: 15px 25px;
183            border-radius: 50px;
184            cursor: pointer;
185            font-size: 14px;
186            font-weight: bold;
187            box-shadow: 0 4px 12px rgba(255, 107, 53, 0.4);
188            transition: all 0.3s;
189        }
190
191        .vfs-floating-btn:hover {
192            background: #e55a2b;
193            transform: translateY(-2px);
194            box-shadow: 0 6px 16px rgba(255, 107, 53, 0.5);
195        }
196    `);
197
198    // Main initialization
199    async function init() {
200        console.log('Initializing VFS Form Auto-Filler...');
201        
202        // Wait for page to be fully loaded
203        if (document.readyState === 'loading') {
204            document.addEventListener('DOMContentLoaded', createUI);
205        } else {
206            createUI();
207        }
208    }
209
210    // Create the floating button
211    function createUI() {
212        console.log('Creating UI...');
213        
214        // Remove existing button if any
215        const existingBtn = document.querySelector('.vfs-floating-btn');
216        if (existingBtn) {
217            existingBtn.remove();
218        }
219
220        // Create floating button
221        const floatingBtn = document.createElement('button');
222        floatingBtn.className = 'vfs-floating-btn';
223        floatingBtn.textContent = '🚀 Auto-Fill Form';
224        floatingBtn.addEventListener('click', showPanel);
225        document.body.appendChild(floatingBtn);
226        
227        console.log('Floating button created');
228    }
229
230    // Show the control panel
231    async function showPanel() {
232        console.log('Showing panel...');
233        
234        // Remove existing panel if any
235        const existingPanel = document.querySelector('.vfs-autofill-container');
236        if (existingPanel) {
237            existingPanel.remove();
238            return;
239        }
240
241        // Load saved data
242        const savedData = await GM.getValue('vfs_form_data', {});
243        console.log('Loaded saved data:', savedData);
244
245        // Create panel
246        const panel = document.createElement('div');
247        panel.className = 'vfs-autofill-container';
248        panel.innerHTML = `
249            <div class="vfs-autofill-header">
250                <span>VFS Auto-Filler</span>
251                <button class="vfs-close-btn" id="vfs-close">×</button>
252            </div>
253            <button class="vfs-autofill-btn" id="vfs-fill-btn">Fill Form Now</button>
254            <button class="vfs-settings-btn" id="vfs-settings-btn">⚙️ Edit Saved Data</button>
255            <div id="vfs-settings-panel" style="display: none; margin-top: 15px; border-top: 1px solid #ddd; padding-top: 15px;">
256                <div class="vfs-form-group">
257                    <label>First Name:</label>
258                    <input type="text" id="vfs-firstname" value="${savedData.firstName || ''}" placeholder="Enter first name">
259                </div>
260                <div class="vfs-form-group">
261                    <label>Last Name:</label>
262                    <input type="text" id="vfs-lastname" value="${savedData.lastName || ''}" placeholder="Enter last name">
263                </div>
264                <div class="vfs-form-group">
265                    <label>Passport Number:</label>
266                    <input type="text" id="vfs-passport" value="${savedData.passportNumber || ''}" placeholder="Enter passport number">
267                </div>
268                <div class="vfs-form-group">
269                    <label>Nationality:</label>
270                    <input type="text" id="vfs-nationality" value="${savedData.nationality || ''}" placeholder="e.g., Algeria">
271                </div>
272                <button class="vfs-save-btn" id="vfs-save-btn">💾 Save Data</button>
273            </div>
274            <div id="vfs-status"></div>
275        `;
276
277        document.body.appendChild(panel);
278
279        // Add event listeners
280        document.getElementById('vfs-close').addEventListener('click', () => panel.remove());
281        document.getElementById('vfs-fill-btn').addEventListener('click', fillForm);
282        document.getElementById('vfs-settings-btn').addEventListener('click', toggleSettings);
283        document.getElementById('vfs-save-btn').addEventListener('click', saveData);
284
285        console.log('Panel created and displayed');
286    }
287
288    // Toggle settings panel
289    function toggleSettings() {
290        const settingsPanel = document.getElementById('vfs-settings-panel');
291        if (settingsPanel.style.display === 'none') {
292            settingsPanel.style.display = 'block';
293        } else {
294            settingsPanel.style.display = 'none';
295        }
296    }
297
298    // Save user data
299    async function saveData() {
300        console.log('Saving data...');
301        
302        const firstName = document.getElementById('vfs-firstname').value.trim();
303        const lastName = document.getElementById('vfs-lastname').value.trim();
304        const passportNumber = document.getElementById('vfs-passport').value.trim();
305        const nationality = document.getElementById('vfs-nationality').value.trim();
306
307        if (!firstName || !lastName || !passportNumber || !nationality) {
308            showStatus('Please fill all fields', 'error');
309            return;
310        }
311
312        const data = {
313            firstName: firstName,
314            lastName: lastName,
315            passportNumber: passportNumber,
316            nationality: nationality
317        };
318
319        await GM.setValue('vfs_form_data', data);
320        console.log('Data saved:', data);
321        showStatus('Data saved successfully!', 'success');
322    }
323
324    // Fill the form
325    async function fillForm() {
326        console.log('Filling form...');
327        
328        const savedData = await GM.getValue('vfs_form_data', {});
329        
330        if (!savedData.firstName || !savedData.lastName || !savedData.passportNumber || !savedData.nationality) {
331            showStatus('Please save your data first', 'error');
332            return;
333        }
334
335        try {
336            // Fill First Name
337            const firstNameInput = document.querySelector('input[placeholder*="first name" i]');
338            if (firstNameInput) {
339                firstNameInput.value = savedData.firstName.toUpperCase();
340                firstNameInput.dispatchEvent(new Event('input', { bubbles: true }));
341                firstNameInput.dispatchEvent(new Event('change', { bubbles: true }));
342                console.log('First name filled:', savedData.firstName);
343            } else {
344                console.error('First name input not found');
345            }
346
347            // Fill Last Name
348            const lastNameInput = document.querySelector('input[placeholder*="last name" i]');
349            if (lastNameInput) {
350                lastNameInput.value = savedData.lastName.toUpperCase();
351                lastNameInput.dispatchEvent(new Event('input', { bubbles: true }));
352                lastNameInput.dispatchEvent(new Event('change', { bubbles: true }));
353                console.log('Last name filled:', savedData.lastName);
354            } else {
355                console.error('Last name input not found');
356            }
357
358            // Fill Passport Number
359            const passportInput = document.querySelector('input[placeholder*="passport number" i]:not([type="password"])');
360            if (passportInput) {
361                passportInput.value = savedData.passportNumber.toUpperCase();
362                passportInput.dispatchEvent(new Event('input', { bubbles: true }));
363                passportInput.dispatchEvent(new Event('change', { bubbles: true }));
364                console.log('Passport number filled');
365            } else {
366                console.error('Passport number input not found');
367            }
368
369            // Fill Confirm Passport Number
370            const confirmPassportInput = document.querySelector('input[type="password"][placeholder*="*"]');
371            if (confirmPassportInput) {
372                confirmPassportInput.value = savedData.passportNumber.toUpperCase();
373                confirmPassportInput.dispatchEvent(new Event('input', { bubbles: true }));
374                confirmPassportInput.dispatchEvent(new Event('change', { bubbles: true }));
375                console.log('Confirm passport number filled');
376            } else {
377                console.error('Confirm passport number input not found');
378            }
379
380            // Fill Nationality dropdown
381            setTimeout(async () => {
382                const nationalitySelect = document.querySelector('mat-select[aria-labelledby*="mat-select-value"]');
383                if (nationalitySelect) {
384                    nationalitySelect.click();
385                    console.log('Nationality dropdown clicked');
386                    
387                    // Wait for dropdown to open
388                    setTimeout(() => {
389                        const options = document.querySelectorAll('mat-option');
390                        console.log('Found options:', options.length);
391                        
392                        for (const option of options) {
393                            const optionText = option.textContent.trim().toLowerCase();
394                            if (optionText.includes(savedData.nationality.toLowerCase())) {
395                                option.click();
396                                console.log('Nationality selected:', optionText);
397                                showStatus('Form filled successfully!', 'success');
398                                return;
399                            }
400                        }
401                        
402                        console.error('Nationality not found in dropdown');
403                        showStatus('Nationality not found in dropdown', 'error');
404                    }, 500);
405                } else {
406                    console.error('Nationality dropdown not found');
407                    showStatus('Form filled (nationality dropdown not found)', 'success');
408                }
409            }, 300);
410
411        } catch (error) {
412            console.error('Error filling form:', error);
413            showStatus('Error filling form', 'error');
414        }
415    }
416
417    // Show status message
418    function showStatus(message, type) {
419        const statusDiv = document.getElementById('vfs-status');
420        if (!statusDiv) return;
421        
422        statusDiv.textContent = message;
423        statusDiv.className = `vfs-status-message vfs-status-${type}`;
424        
425        setTimeout(() => {
426            statusDiv.textContent = '';
427            statusDiv.className = '';
428        }, 3000);
429    }
430
431    // Start the extension
432    init();
433
434})();
VFS Global Form Auto-Filler | Robomonkey