PageSourceSearch

https://originalberlintours.com/wp-content/plugins/npformshield/as…inja-forms-realtime-validation.js?ver=1.0.6

js originalberlintours.com collected 2026-09-24 23:06:56 UTC 15,716 bytes, 342 lines download raw bytes

1jQuery(document).ready(function($) {
2    console.log('ASM Ninja Forms Real-time Validation Loaded');
3    
4    // Real-time validation for Ninja Forms
5    let blockedWords = {};
6    let formProtections = {};
7    
8    // No fallback protection - only use admin settings
9    const fallbackProtection = {};
10    
11    // Get form protection settings
12    function getFormProtection(formId) {
13        console.log('Getting protection for form ID:', formId);
14        
15        return new Promise((resolve, reject) => {
16            $.ajax({
17                url: nsf_ajax.ajax_url,
18                type: 'POST',
19                data: {
20                    action: 'nfs_get_form_protection', // changed from nsf_get_form_protection
21                    form_plugin: 'ninja-forms',
22                    form_id: formId,
23                    nonce: nsf_ajax.frontend_nonce
24                },
25                success: function(response) {
26                    console.log('AJAX response for Ninja Forms protection:', response);
27                    if (response.success && response.data && response.data.field_protections) {
28                        console.log('Using admin-configured protection settings:', response.data.field_protections);
29                        resolve(response.data);
30                    } else {
31                        console.log('No admin protection found - no validation will be applied');
32                        resolve(null);
33                    }
34                },
35                error: function(xhr, status, error) {
36                    console.error('AJAX error getting protection:', error);
37                    console.log('No validation will be applied due to AJAX error');
38                    resolve(null);
39                }
40            });
41        });
42    }
43    
44    // Check if text contains blocked words
45    function checkBlockedWords(text, protectionWords, protectionType) {
46        if (!text || !protectionWords) return { hasBlocked: false, blockedWord: null };
47        
48        const words = protectionWords.split(',').map(w => w.trim().toLowerCase());
49        const textLower = text.toLowerCase();
50        
51        if (protectionType === 'blacklist') {
52            // Blacklist: Block if any blacklisted word is found
53            for (let word of words) {
54                if (word && textLower.includes(word)) {
55                    return { hasBlocked: true, blockedWord: word };
56                }
57            }
58        } else if (protectionType === 'whitelist') {
59            // Whitelist: Block if text contains words NOT in whitelist
60            const textWords = textLower.split(/\s+/).filter(w => w.length > 0);
61            for (let textWord of textWords) {
62                let isWhitelisted = false;
63                for (let whiteWord of words) {
64                    if (whiteWord && textWord.includes(whiteWord)) {
65                        isWhitelisted = true;
66                        break;
67                    }
68                }
69                if (!isWhitelisted) {
70                    return { hasBlocked: true, blockedWord: textWord };
71                }
72            }
73        }
74        
75        return { hasBlocked: false, blockedWord: null };
76    }
77    
78    // Remove blocked words from text
79    function removeBlockedWords(text, protectionWords, protectionType) {
80        if (!text || !protectionWords) return text;
81        
82        const words = protectionWords.split(',').map(w => w.trim());
83        let cleanText = text;
84        
85        if (protectionType === 'blacklist') {
86            // Remove blacklisted words
87            words.forEach(word => {
88                if (word) {
89                    const regex = new RegExp(word.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
90                    cleanText = cleanText.replace(regex, '');
91                }
92            });
93        } else if (protectionType === 'whitelist') {
94            // For whitelist, remove words that are NOT in the whitelist
95            const textWords = cleanText.split(/\s+/);
96            const filteredWords = textWords.filter(textWord => {
97                if (!textWord.trim()) return true; // Keep empty strings/spaces
98                
99                const textWordLower = textWord.toLowerCase();
100                for (let whiteWord of words) {
101                    if (whiteWord && textWordLower.includes(whiteWord.toLowerCase())) {
102                        return true; // Keep whitelisted words
103                    }
104                }
105                return false; // Remove non-whitelisted words
106            });
107            cleanText = filteredWords.join(' ');
108        }
109        
110        return cleanText.trim();
111    }
112    
113    // Show warning message
114    function showWarning(field, message, protectionType) {
115        const $field = $(field);
116        const $container = $field.closest('.nf-field-container');
117        
118        // Remove existing warnings
119        $container.find('.asm-warning').remove();
120        
121        // Add warning styling
122        $field.addClass('asm-blocked-field');
123        
124        // Create appropriate warning message based on protection type
125        let warningText = message;
126        if (protectionType === 'blacklist') {
127            warningText = 'This content contains prohibited words and has been removed.';
128        } else if (protectionType === 'whitelist') {
129            warningText = 'Only specific words are allowed in this field. Unauthorized content has been removed.';
130        }
131        
132        // Add warning message
133        const $warning = $('<div class="asm-warning" style="color: #d63638; font-size: 12px; margin-top: 5px; display: flex; align-items: center;"><span class="dashicons dashicons-warning" style="margin-right: 5px; font-size: 14px;"></span>' + warningText + '</div>');
134        $container.append($warning);
135    }
136    
137    // Clear warning
138    function clearWarning(field) {
139        const $field = $(field);
140        const $container = $field.closest('.nf-field-container');
141        
142        $field.removeClass('asm-blocked-field');
143        $container.find('.asm-warning').remove();
144    }
145    
146    // Initialize real-time validation for Ninja Forms
147    function initNinjaFormsValidation() {
148        console.log('Initializing Ninja Forms validation...');
149        
150        // Find all Ninja Forms - use exact selectors from HTML structure
151        const $forms = $('.nf-form-wrap, .ninja-forms-form-wrap, div[class*="nf-form"]');
152        console.log('Found forms:', $forms.length);
153        
154        $forms.each(function() {
155            const $form = $(this);
156            console.log('Processing form:', $form);
157            
158            // Extract form ID from JavaScript variable (from screenshot)
159            let formId = null;
160            
161            // Method 1: Look for FormDisplay variable in page scripts
162            if (window.nfForms && window.nfForms.length > 0) {
163                formId = window.nfForms[0].id;
164                console.log('Form ID from nfForms global:', formId);
165            }
166            
167            // Method 2: Extract from form data attributes or classes
168            if (!formId) {
169                const formClass = $form.attr('class') || '';
170                const formIdMatch = formClass.match(/form-(\d+)/);
171                if (formIdMatch) {
172                    formId = formIdMatch[1];
173                    console.log('Form ID from class:', formId);
174                }
175            }
176            
177            // Method 3: Look for form ID in hidden inputs within the form
178            if (!formId) {
179                $form.find('input[type="hidden"]').each(function() {
180                    const name = $(this).attr('name');
181                    const value = $(this).val();
182                    console.log('Hidden input found:', name, '=', value);
183                    
184                    if (name === 'form_id' || name === 'id' || (name && name.includes('form') && /^\d+$/.test(value))) {
185                        formId = value;
186                        console.log('Form ID from hidden input:', formId);
187                        return false;
188                    }
189                });
190            }
191            
192            // Method 4: Extract from script tags containing form data
193            if (!formId) {
194                $('script').each(function() {
195                    const scriptContent = $(this).html();
196                    if (scriptContent && scriptContent.includes('form_id')) {
197                        const formIdMatch = scriptContent.match(/"form_id"\s*:\s*"?(\d+)"?/);
198                        if (formIdMatch) {
199                            formId = formIdMatch[1];
200                            console.log('Form ID from script:', formId);
201                            return false;
202                        }
203                    }
204                });
205            }
206            
207            // Method 5: Default fallback
208            if (!formId) {
209                console.log('No form ID found - using default form ID 1');
210                formId = '1';
211            }
212            
213            console.log('Form ID found:', formId);
214            
215            // Get protection settings for this form
216            getFormProtection(formId).then(function(protection) {
217                console.log('Protection settings received:', protection);
218                
219                if (!protection || !protection.field_protections) {
220                    console.log('No protection settings found - skipping validation for this form');
221                    return;
222                }
223                
224                const fieldProtections = typeof protection.field_protections === 'string' 
225                    ? JSON.parse(protection.field_protections) 
226                    : protection.field_protections;
227                
228                console.log('Parsed field protections:', fieldProtections);
229                
230                // Check if field protections is empty
231                if (!fieldProtections || Object.keys(fieldProtections).length === 0) {
232                    console.log('Field protections is empty - no validation will be applied');
233                    return;
234                }
235                
236                // Add real-time validation to ALL input fields
237                $form.find('input[type="text"], input[type="email"], textarea').each(function() {
238                    const $field = $(this);
239                    const $container = $field.closest('.nf-field-container, .field-wrap');
240                    const $label = $container.find('label, .nf-field-label');
241                    let fieldLabel = $label.text().trim();
242                    
243                    // Try multiple ways to get field label
244                    if (!fieldLabel) {
245                        fieldLabel = $field.attr('placeholder') || $field.attr('name') || $field.attr('id');
246                    }
247                    
248                    console.log('Found field with label:', fieldLabel);
249                    console.log('Available protections:', Object.keys(fieldProtections));
250                    
251                    // Check if this field has protection - try exact match and partial match
252                    let fieldProtection = fieldProtections[fieldLabel];
253                    
254                    // If no exact match, try partial matching
255                    if (!fieldProtection) {
256                        for (let protectionKey in fieldProtections) {
257                            if (fieldLabel.toLowerCase().includes(protectionKey.toLowerCase()) || 
258                                protectionKey.toLowerCase().includes(fieldLabel.toLowerCase())) {
259                                fieldProtection = fieldProtections[protectionKey];
260                                console.log('Found partial match:', protectionKey, 'for field:', fieldLabel);
261                                break;
262                            }
263                        }
264                    }
265                    
266                    // Also try matching by field position/index
267                    if (!fieldProtection) {
268                        const fieldIndex = $form.find('input[type="text"], input[type="email"], textarea').index(this);
269                        const protectionKeys = Object.keys(fieldProtections);
270                        if (protectionKeys[fieldIndex]) {
271                            fieldProtection = fieldProtections[protectionKeys[fieldIndex]];
272                            console.log('Found by index match:', protectionKeys[fieldIndex], 'for field at index:', fieldIndex);
273                        }
274                    }
275                    
276                    if (fieldProtection) {
277                        console.log('Adding validation to field:', fieldLabel, fieldProtection);
278                        
279                        // Add input event listener
280                        $field.on('input keyup paste', function() {
281                            const currentValue = $(this).val();
282                            console.log('Field value changed:', fieldLabel, currentValue);
283                            console.log('Protection type:', fieldProtection.type);
284                            console.log('Protection words:', fieldProtection.words);
285                            
286                            const result = checkBlockedWords(currentValue, fieldProtection.words, fieldProtection.type);
287                            console.log('Protection check result:', result);
288                            
289                            if (result.hasBlocked) {
290                                console.log('Blocked content found, removing...');
291                                
292                                // Auto-remove blocked content
293                                const cleanValue = removeBlockedWords(currentValue, fieldProtection.words, fieldProtection.type);
294                                $(this).val(cleanValue);
295                                
296                                // Show appropriate warning based on protection type
297                                if (fieldProtection.type === 'blacklist') {
298                                    showWarning(this, 'Blocked word "' + result.blockedWord + '" removed automatically', 'blacklist');
299                                } else if (fieldProtection.type === 'whitelist') {
300                                    showWarning(this, 'Non-whitelisted word "' + result.blockedWord + '" removed automatically', 'whitelist');
301                                }
302                                
303                                // Clear warning after 3 seconds
304                                setTimeout(() => {
305                                    clearWarning(this);
306                                }, 3000);
307                            } else {
308                                clearWarning(this);
309                            }
310                        });
311                    }
312                });
313            });
314        });
315    }
316    
317    // CSS for blocked fields
318    $('<style>')
319        .prop('type', 'text/css')
320        .html(`
321            .asm-blocked-field {
322                border: 2px solid #d63638 !important;
323                background-color: #fef7f7 !important;
324            }
325            .asm-warning {
326                animation: asm-fade-in 0.3s ease-in;
327            }
328            @keyframes asm-fade-in {
329                from { opacity: 0; transform: translateY(-10px); }
330                to { opacity: 1; transform: translateY(0); }
331            }
332        `)
333        .appendTo('head');
334    
335    // Initialize when DOM is ready
336    initNinjaFormsValidation();
337    
338    // Re-initialize when new forms are loaded (AJAX)
339    $(document).on('nfFormReady', function() {
340        setTimeout(initNinjaFormsValidation, 500);
341    });
342});

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.