Adds A-Z dropdown navigation, Tab key support for form fields, and copy customer details functionality
Size
11.7 KB
Version
1.1.1
Created
Nov 29, 2025
Updated
18 days ago
1// ==UserScript==
2// @name Customer Form Auto-Fill & Navigation Helper
3// @description Adds A-Z dropdown navigation, Tab key support for form fields, and copy customer details functionality
4// @version 1.1.1
5// @match http://192.168.3.251/*
6// ==/UserScript==
7(function() {
8 'use strict';
9
10 console.log('Customer Form Auto-Fill & Navigation Helper loaded');
11
12 // Debounce function to prevent excessive calls
13 function debounce(func, wait) {
14 let timeout;
15 return function executedFunction(...args) {
16 const later = () => {
17 clearTimeout(timeout);
18 func(...args);
19 };
20 clearTimeout(timeout);
21 timeout = setTimeout(later, wait);
22 };
23 }
24
25 // Initialize the extension
26 async function init() {
27 console.log('Initializing Customer Form Helper...');
28
29 // Wait for the page to be fully loaded
30 if (document.readyState === 'loading') {
31 document.addEventListener('DOMContentLoaded', setupFeatures);
32 } else {
33 setupFeatures();
34 }
35 }
36
37 function setupFeatures() {
38 console.log('Setting up features...');
39
40 // Add A-Z dropdown navigation
41 addAlphabetNavigation();
42
43 // Enable Tab key support for all form fields
44 enableTabKeySupport();
45
46 // Add copy customer details functionality
47 addCopyCustomerDetailsButton();
48
49 // Observe DOM changes to re-apply features when needed
50 observeDOMChanges();
51 }
52
53 // Add A-Z dropdown navigation
54 function addAlphabetNavigation() {
55 console.log('Adding A-Z navigation...');
56
57 // Check if we're on the customer list page
58 const customerTable = document.querySelector('#example1');
59 if (!customerTable) {
60 console.log('Customer table not found, skipping A-Z navigation');
61 return;
62 }
63
64 // Check if navigation already exists
65 if (document.getElementById('az-navigation')) {
66 console.log('A-Z navigation already exists');
67 return;
68 }
69
70 // Create A-Z navigation container
71 const navContainer = document.createElement('div');
72 navContainer.id = 'az-navigation';
73 navContainer.style.cssText = `
74 margin: 15px 0;
75 padding: 15px;
76 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
77 border-radius: 8px;
78 box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
79 `;
80
81 // Create label
82 const label = document.createElement('label');
83 label.textContent = 'Quick Search by Letter: ';
84 label.style.cssText = `
85 color: white;
86 font-weight: bold;
87 font-size: 14px;
88 margin-right: 10px;
89 `;
90
91 // Create dropdown
92 const dropdown = document.createElement('select');
93 dropdown.id = 'az-dropdown';
94 dropdown.style.cssText = `
95 padding: 8px 15px;
96 border: 2px solid white;
97 border-radius: 5px;
98 font-size: 14px;
99 font-weight: bold;
100 background: white;
101 color: #667eea;
102 cursor: pointer;
103 min-width: 100px;
104 transition: all 0.3s ease;
105 `;
106
107 // Add hover effect
108 dropdown.addEventListener('mouseenter', () => {
109 dropdown.style.transform = 'scale(1.05)';
110 dropdown.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
111 });
112 dropdown.addEventListener('mouseleave', () => {
113 dropdown.style.transform = 'scale(1)';
114 dropdown.style.boxShadow = 'none';
115 });
116
117 // Add default option
118 const defaultOption = document.createElement('option');
119 defaultOption.value = '';
120 defaultOption.textContent = 'Select Letter';
121 dropdown.appendChild(defaultOption);
122
123 // Add A-Z options
124 for (let i = 65; i <= 90; i++) {
125 const letter = String.fromCharCode(i);
126 const option = document.createElement('option');
127 option.value = letter;
128 option.textContent = letter;
129 dropdown.appendChild(option);
130 }
131
132 // Add "All" option
133 const allOption = document.createElement('option');
134 allOption.value = 'ALL';
135 allOption.textContent = 'Show All';
136 dropdown.appendChild(allOption);
137
138 // Handle dropdown change
139 dropdown.addEventListener('change', async function() {
140 const selectedLetter = this.value;
141 console.log('Selected letter:', selectedLetter);
142
143 if (selectedLetter === '') {
144 return;
145 }
146
147 const searchBox = document.querySelector('#txtSearch');
148 if (searchBox) {
149 if (selectedLetter === 'ALL') {
150 searchBox.value = '';
151 } else {
152 searchBox.value = selectedLetter;
153 }
154
155 // Trigger search
156 const searchButton = document.querySelector('#btnSearch');
157 if (searchButton) {
158 searchButton.click();
159 }
160 }
161 });
162
163 navContainer.appendChild(label);
164 navContainer.appendChild(dropdown);
165
166 // Insert navigation before the table
167 const tableContainer = customerTable.closest('.card-body');
168 if (tableContainer) {
169 tableContainer.insertBefore(navContainer, tableContainer.firstChild);
170 console.log('A-Z navigation added successfully');
171 }
172 }
173
174 // Enable Tab key support for all form fields
175 function enableTabKeySupport() {
176 console.log('Enabling Tab key support...');
177
178 const form = document.querySelector('#frmParty');
179 if (!form) {
180 console.log('Form not found, skipping Tab key support');
181 return;
182 }
183
184 // Get all form inputs, selects, and textareas
185 const formFields = form.querySelectorAll('input:not([type="hidden"]), select, textarea');
186 console.log('Found', formFields.length, 'form fields');
187
188 formFields.forEach((field, index) => {
189 // Set tabindex for proper tab order
190 field.setAttribute('tabindex', index + 1);
191
192 // Add visual feedback on focus
193 field.addEventListener('focus', function() {
194 this.style.outline = '2px solid #667eea';
195 this.style.boxShadow = '0 0 8px rgba(102, 126, 234, 0.5)';
196 });
197
198 field.addEventListener('blur', function() {
199 this.style.outline = '';
200 this.style.boxShadow = '';
201 });
202
203 // Handle Tab key for select2 dropdowns
204 if (field.classList.contains('select2-hidden-accessible')) {
205 const select2Container = field.nextElementSibling;
206 if (select2Container && select2Container.classList.contains('select2')) {
207 select2Container.addEventListener('keydown', function(e) {
208 if (e.key === 'Tab') {
209 // Let the default Tab behavior work
210 console.log('Tab pressed on select2 field');
211 }
212 });
213 }
214 }
215 });
216
217 console.log('Tab key support enabled for all form fields');
218 }
219
220 // Add copy customer details functionality
221 function addCopyCustomerDetailsButton() {
222 console.log('Adding copy customer details button...');
223
224 // Check if we're on the customer list page
225 const customerTable = document.querySelector('#example1 tbody');
226 if (!customerTable) {
227 console.log('Customer table body not found');
228 return;
229 }
230
231 // Add copy button to each customer row
232 const rows = customerTable.querySelectorAll('tr');
233 console.log('Found', rows.length, 'customer rows');
234
235 rows.forEach((row) => {
236 // Check if copy button already exists
237 if (row.querySelector('.copy-customer-btn')) {
238 return;
239 }
240
241 const actionCell = row.querySelector('td:last-child div');
242 if (!actionCell) {
243 return;
244 }
245
246 // Create copy button
247 const copyButton = document.createElement('button');
248 copyButton.className = 'btn btn-icon btn-info copy-customer-btn';
249 copyButton.title = 'Copy Customer Details';
250 copyButton.style.cssText = `
251 margin-left: 5px;
252 background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
253 border: none;
254 transition: all 0.3s ease;
255 `;
256
257 copyButton.innerHTML = '<i class="fas fa-copy"></i>';
258
259 // Add hover effect
260 copyButton.addEventListener('mouseenter', () => {
261 copyButton.style.transform = 'scale(1.1)';
262 copyButton.style.boxShadow = '0 4px 8px rgba(102, 126, 234, 0.4)';
263 });
264 copyButton.addEventListener('mouseleave', () => {
265 copyButton.style.transform = 'scale(1)';
266 copyButton.style.boxShadow = 'none';
267 });
268
269 // Handle copy button click
270 copyButton.addEventListener('click', async function(e) {
271 e.preventDefault();
272 e.stopPropagation();
273
274 const cells = row.querySelectorAll('td');
275 if (cells.length >= 3) {
276 const customerName = cells[0].textContent.trim();
277 const address = cells[1].textContent.trim();
278 const state = cells[2].textContent.trim();
279
280 const customerDetails = `Customer Name: ${customerName}\nAddress: ${address}\nState: ${state}`;
281
282 try {
283 // Use GM.setClipboard to copy to clipboard
284 await GM.setClipboard(customerDetails);
285
286 // Show success feedback
287 const originalHTML = copyButton.innerHTML;
288 copyButton.innerHTML = '<i class="fas fa-check"></i>';
289 copyButton.style.background = 'linear-gradient(135deg, #11998e 0%, #38ef7d 100%)';
290
291 setTimeout(() => {
292 copyButton.innerHTML = originalHTML;
293 copyButton.style.background = 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
294 }, 2000);
295
296 console.log('Customer details copied to clipboard');
297 } catch (error) {
298 console.error('Failed to copy to clipboard:', error);
299 alert('Failed to copy customer details');
300 }
301 }
302 });
303
304 actionCell.appendChild(copyButton);
305 });
306
307 console.log('Copy buttons added to all customer rows');
308 }
309
310 // Observe DOM changes to re-apply features when needed
311 function observeDOMChanges() {
312 const observer = new MutationObserver(debounce((mutations) => {
313 console.log('DOM changed, re-applying features...');
314
315 // Re-apply features if new content is loaded
316 addAlphabetNavigation();
317 enableTabKeySupport();
318 addCopyCustomerDetailsButton();
319 }, 1000));
320
321 observer.observe(document.body, {
322 childList: true,
323 subtree: true
324 });
325
326 console.log('DOM observer started');
327 }
328
329 // Start the extension
330 init();
331
332})();