PageSourceSearch

https://irisidea.com/wp-content/plugins/kalrav-ai-agent/js/kalrav-ui-helpers.js?ver=3.0.10

js irisidea.com collected 2026-10-01 14:04:50 UTC 38,543 bytes, 994 lines download raw bytes

1/**
2 * Kalrav AI - UI Helper Functions
3 * This module contains all helper functions for applying UI changes
4 * 
5 * LOAD THIS FILE FIRST before kalrav-ui-init.js
6 */
7(function(window) {
8    'use strict';
9    
10    window.KALRAV = window.KALRAV || {};
11    window.KALRAV.UIHelpers = {};
12
13    // ====================================================================
14    // HELPER FUNCTIONS
15    // ====================================================================
16  window.KALRAV.UIHelpers.getRelativeTime =function (timestamp) {
17    const now = new Date();
18    const past = new Date(timestamp);
19    const diffInSeconds = Math.floor((now - past) / 1000);
20
21    if (diffInSeconds < 10) {
22        return "Just now";
23    }
24
25    const diffInMinutes = Math.floor(diffInSeconds / 60);
26    if (diffInMinutes < 60) {
27        return `${diffInMinutes} minute${diffInMinutes > 1 ? 's' : ''} ago`;
28    }
29
30    const diffInHours = Math.floor(diffInMinutes / 60);
31    if (diffInHours < 24) {
32        return `${diffInHours} hour${diffInHours > 1 ? 's' : ''} ago`;
33    }
34
35    const diffInDays = Math.floor(diffInHours / 24);
36    return `${diffInDays} day${diffInDays > 1 ? 's' : ''} ago`;
37}
38    window.KALRAV.UIHelpers.initializeDefaultBotPosition = function() {
39        const defaultPosition =
40            window.KALRAV?.CONFIG?.BOT_LAUNCHER_POSITION ||
41            window.KALRAV?.DEFAULT_AGENT_SETTINGS?.bot_launcher_title_place ||
42            window.KALRAV?.DEFAULT_AGENT_SETTINGS?.botLauncherTitlePlace ||
43            'bottom_right';
44
45        window.KALRAV.UIHelpers.applyBotLauncherPosition(defaultPosition);
46    };
47
48    window.KALRAV.UIHelpers.applyWelcomeTexts = function(texts) {
49        const {
50            botLauncherTitle,
51            botLauncherTitlePlace,
52            headerSubheading,
53            welcomeHeadline,
54            welcomeIntroText,
55            sub_intro_text,
56            active_status_text,
57            welcome_message,
58        } = texts;
59
60        if (botLauncherTitle) {
61            const toggleBtnText = document.querySelector('.bubble-icon-text');
62            if (toggleBtnText) {
63                toggleBtnText.textContent = botLauncherTitle;
64            }
65        }
66        
67        // ✅ Always apply bot launcher position (with fallback to bottom_right)
68        window.KALRAV.UIHelpers.applyBotLauncherPosition(botLauncherTitlePlace || 'bottom_right');
69        
70        if (welcome_message) {
71            window.KALRAV.CONFIG.WELCOME_MESSAGE = welcome_message;
72        }
73      
74        if (active_status_text) {
75            const subheadingEl = document.querySelector('.chat-subheading');
76            if (subheadingEl) {
77                subheadingEl.textContent = active_status_text;
78            }
79        }
80        if (welcomeHeadline) {
81            const greetingEl = document.querySelector('.chat-greeting');
82            if (greetingEl) {
83                greetingEl.textContent = welcomeHeadline;
84            }
85        }
86        if (welcomeIntroText) {
87            const labelTextEl = document.querySelector('.chat-label-text');
88            if (labelTextEl) {
89                labelTextEl.textContent = welcomeIntroText;
90            }
91        }
92        if (sub_intro_text) {
93            const labelTextE2 = document.querySelector('.chat-subtext');
94            if (labelTextE2) {
95                labelTextE2.textContent = sub_intro_text;
96            }
97        }
98        
99        if (window.KALRAV?.CONFIG) {
100            window.KALRAV.CONFIG.WELCOME_TEXTS = {
101                botLauncherTitle,
102                botLauncherTitlePlace,
103                headerSubheading,
104                welcomeHeadline,
105                welcomeIntroText,
106            };
107        }
108    };
109
110  window.KALRAV.UIHelpers.applyInsideDisclaimer = function(disclaimerText, disclaimerUrl, disclaimerLinkText) {
111    const disclaimerEl = document.querySelector('.kalravai-inside-disclaimer');
112    if (!disclaimerEl || !disclaimerText) return;
113
114    disclaimerEl.innerHTML = '';
115    disclaimerEl.style.display = 'flex';
116
117    // Left: icon + text + link all inline
118    const container = document.createElement('div');
119    container.className = 'kalravai-inside-disclaimer-container';
120    container.style.cssText = `
121      display: flex;
122    gap: 12px;
123    flex: 1 1 0%;
124    flex-wrap: nowrap;
125    flex-direction: row;
126    `;
127
128    // Warning icon
129    const icon = document.createElement('span');
130    icon.textContent = '⚠️';
131    icon.style.cssText = `
132        flex-shrink: 0;
133        font-size: 12px;
134        align-self: flex-start;
135        margin-top: 2px;
136    `;
137
138    // Text + link together in one inline wrapper
139    const textWrapper = document.createElement('span');
140    textWrapper.style.cssText = `
141        font-family: Roboto, sans-serif;
142        font-weight: 400;
143        font-size: 12px;
144        color: #818181;
145        line-height: 1.4;
146    `;
147    textWrapper.textContent = disclaimerText;
148
149    if (disclaimerUrl) {
150        // Add a space before the link
151        textWrapper.appendChild(document.createTextNode(' '));
152
153        const link = document.createElement('a');
154        link.href = disclaimerUrl;
155        link.target = '_blank';
156        link.rel = 'noopener noreferrer';
157        link.textContent = disclaimerLinkText;
158        link.style.cssText = `
159            font-family: Roboto, sans-serif;
160            font-weight: 600;
161            font-size: 12px;
162           /* color: var(--primary-color, #007bff);*/
163            text-decoration: none;
164            white-space: nowrap;
165        `;
166        textWrapper.appendChild(link);
167    }
168
169    container.appendChild(icon);
170    container.appendChild(textWrapper);
171
172    // Right: close (×) button
173    const closeBtn = document.createElement('button');
174    closeBtn.className = 'kalravai-inside-disclaimer-close';
175    closeBtn.innerHTML = '&times;';
176    closeBtn.setAttribute('aria-label', 'Dismiss');
177    closeBtn.style.cssText = `
178        background: transparent;
179        border: none;
180        cursor: pointer;
181        font-size: 18px;
182        color: #888;
183        padding: 0 0 0 8px;
184        line-height: 1;
185        flex-shrink: 0;
186        align-self: flex-start;   /* ← stays at top when text wraps */
187        margin-top: 1px;
188    `;
189    closeBtn.addEventListener('click', function () {
190        disclaimerEl.style.display = 'none';
191    });
192
193    disclaimerEl.appendChild(container);
194    disclaimerEl.appendChild(closeBtn);
195};
196
197
198    window.KALRAV.UIHelpers.applyDisclaimer = function(footer_disclaimer_text, footer_disclaimer_url, footer_disclaimer_link_text) {
199        const disclaimerEl = document.querySelector('.kalravai-disclaimer');
200        if (!disclaimerEl || !footer_disclaimer_text) return;
201        disclaimerEl.innerHTML = '';
202      /*  disclaimerEl.innerHTML += `<span style="font-size:12px;">⚠️</span> `;*/
203        disclaimerEl.innerHTML += `<span style="font-size:11px;">${footer_disclaimer_text}</span>`;
204        if (footer_disclaimer_url) {
205            disclaimerEl.innerHTML += `
206                <a href="${footer_disclaimer_url}" 
207                   target="_blank" 
208                   rel="noopener noreferrer"
209                   style="margin-left:5px;text-decoration:none;font-size:11px;">
210                   ${footer_disclaimer_link_text}
211                </a>`;
212        }
213        disclaimerEl.style.display = 'block';
214    };
215
216    window.KALRAV.UIHelpers.applyFeatureToggles = function(features) {
217        const {
218            downloadChatEnabled,
219            speechSupportEnabled,
220            audioRecorderEnabled,
221            fileUploadsEnabled
222        } = features;
223
224        const downloadBtn = document.getElementById('download-history') || 
225                            document.getElementById('menu-toggle') ||
226                           document.querySelector('[data-action="download"]') ||
227                           document.querySelector('.download-chat');
228        
229        if (downloadBtn) {
230            downloadBtn.style.display = downloadChatEnabled ? '' : 'none';
231            downloadBtn.disabled = !downloadChatEnabled;
232        }
233
234        document.querySelectorAll('.voice-output-btn, #voice-output-btn').forEach(btn => {
235            btn.style.display = speechSupportEnabled ? '' : 'none';
236            btn.disabled = !speechSupportEnabled;
237        });
238
239        const audioRecorderBtn = document.getElementById('voice-input-btn') || 
240                                document.querySelector('[data-action="voice"]') ||
241                                document.querySelector('.audio-recorder');
242        
243        if (audioRecorderBtn) {
244            audioRecorderBtn.style.display = audioRecorderEnabled ? '' : 'none';
245            audioRecorderBtn.disabled = !audioRecorderEnabled;
246        }
247
248       /* const fileUploadBtn = document.getElementById('attach-btn') || 
249                             document.querySelector('[data-action="upload"]') ||
250                             document.querySelector('.file-upload') ||
251                             document.querySelector('input[type="file"]');
252        
253        if (fileUploadBtn) {
254            fileUploadBtn.style.display = fileUploadsEnabled ? '' : 'none';
255            fileUploadBtn.disabled = !fileUploadsEnabled;
256        }*/
257
258        window.KALRAV.FEATURES = features;
259    };
260
261    window.KALRAV.UIHelpers.applyBotLauncherPosition = function(position) {
262        const toggle = document.getElementById('chat-widget-toggle');
263        if (!toggle) return;
264
265        // Reset all position properties first
266        toggle.style.position = 'fixed';
267        toggle.style.inset = 'auto';
268        toggle.style.top = 'auto';
269        toggle.style.bottom = 'auto';
270        toggle.style.left = 'auto';
271        toggle.style.right = 'auto';
272
273        // Apply position based on setting
274        switch (position) {
275            case 'bottom_left':
276                toggle.style.left = '20px';
277                toggle.style.bottom = '20px';
278                break;
279            case 'top_left':
280                toggle.style.left = '20px';
281                toggle.style.top = '20px';
282                break;
283            case 'top_right':
284                toggle.style.right = '20px';
285                toggle.style.top = '20px';
286                break;
287            case 'bottom_right':
288            default:
289                toggle.style.right = '20px';
290                toggle.style.bottom = '20px';
291                break;
292        }
293
294        toggle.dataset.kalravLauncherReady = '1';
295        toggle.style.visibility = 'visible';
296        toggle.style.opacity = '1';
297
298        if (window.KALRAV?.CONFIG) {
299            window.KALRAV.CONFIG.BOT_LAUNCHER_POSITION = position;
300        }
301    };
302
303    window.KALRAV.UIHelpers.applyLogo = function(logoUrl) {
304        let apiLogo = logoUrl.trim();
305        const API_BASE = 'https://kalrav-central-system-api.kalrav.ai';
306
307        if (apiLogo.includes('/api/file/')) {
308            const urlObj = apiLogo.startsWith('http') ? new URL(apiLogo) : null;
309            const apiPath = urlObj ? urlObj.pathname : apiLogo;
310            apiLogo = API_BASE + apiPath;
311        }
312        else if (/^\/\//.test(apiLogo)) {
313            apiLogo = window.location.protocol + apiLogo;
314        }
315        else if (!/^https?:\/\//i.test(apiLogo)) {
316            apiLogo = window.location.origin + (apiLogo.startsWith('/') ? '' : '/') + apiLogo;
317        }
318
319        if (window.kalravData) {
320            window.kalravData.logoUrl = apiLogo;
321        }
322        if (window.KALRAV?.CONFIG) {
323            window.KALRAV.CONFIG.CHAT_LOGO_URL = apiLogo;
324        }
325
326        const logoSelectors = [
327            '#chat-widget-toggle img',
328            '#kalrav-header-logo img',
329            '.header-logo-img img',
330            '.chat-agent-avatar img',
331            '.chat-intro .chat-agent-avatar img',
332            '.user-header-response img'
333        ];
334
335        document.querySelectorAll(logoSelectors.join(',')).forEach(img => {
336            if (img && img.src !== apiLogo) {
337                img.src = apiLogo;
338            }
339        });
340    };
341
342    window.KALRAV.UIHelpers.applyLayoutColor = function(layoutColor) {
343        if (!layoutColor) return;
344        
345        window.KALRAV.layoutColor = layoutColor;
346        
347        const storedApiColor = localStorage.getItem('kalrav_last_api_color');
348        const userSelectedColor = localStorage.getItem('kalrav_user_selected_color');
349        
350        const apiColorChanged = storedApiColor !== layoutColor;
351        
352        if (apiColorChanged) {
353            //console.log('🎨 API color changed from', storedApiColor, 'to', layoutColor);
354            
355            localStorage.setItem('kalrav_last_api_color', layoutColor);
356            localStorage.removeItem('kalrav_user_selected_color');
357            
358            window.KALRAV.UIHelpers.applyApiLayoutColor(layoutColor);
359            window.KALRAV.UIHelpers.saveApiLayoutColorToWordPress(layoutColor);
360            
361        } else {
362            //console.log('🎨 API color unchanged:', layoutColor);
363            
364            if (userSelectedColor && userSelectedColor !== layoutColor) {
365               // console.log('🎨 Using user-selected color override:', userSelectedColor);
366                window.KALRAV.UIHelpers.applyApiLayoutColor(userSelectedColor);
367            } else {
368                window.KALRAV.UIHelpers.applyApiLayoutColor(layoutColor);
369            }
370        }
371    };
372
373    window.KALRAV.UIHelpers.applyApiLayoutColor = function(colorToApply) {
374        function updateNow() {
375            let appliedCount = 0;
376
377            document.documentElement.style.setProperty('--primary-color', colorToApply);
378            document.documentElement.style.setProperty('--primary-border-color', colorToApply);
379            document.documentElement.style.setProperty('--primary-color-hover', colorToApply);
380
381            const headerEl = document.querySelector('.kalravai_primary_color');
382            if (headerEl) {
383                headerEl.style.setProperty('background', colorToApply, 'important');
384                headerEl.style.color = '#fff';
385                appliedCount++;
386            }
387
388            const toggleEl = document.getElementById('chat-widget-toggle');
389            if (toggleEl) {
390                toggleEl.style.setProperty('background', colorToApply, 'important');
391                toggleEl.style.setProperty('borderColor', colorToApply, 'important');
392                appliedCount++;
393            }
394
395            return appliedCount > 0;
396        }
397
398        updateNow();
399    };
400
401    window.KALRAV.UIHelpers.saveApiLayoutColorToWordPress = function(apiColor) {
402        if (!apiColor || !window.kalravData?.ajaxUrl) return;
403        
404        fetch(window.kalravData.ajaxUrl, {
405            method: 'POST',
406            headers: {
407                'Content-Type': 'application/x-www-form-urlencoded',
408            },
409            body: new URLSearchParams({
410                action: 'kalrav_sync_api_layout_color',
411                color: apiColor,
412                nonce: window.kalravData?.chatNonce
413            })
414        }).then(response => response.json())
415          .then(data => {
416              if (data.success) {
417                  console.log('✅ API layout color synced:', data.data);
418              }
419          })
420          .catch(err => console.error('❌ Failed to sync API color:', err));
421    };
422
423    window.KALRAV.UIHelpers.handleManualColorSelection = function(selectedColor) {
424        const currentApiColor = window.KALRAV?.layoutColor || 
425                               localStorage.getItem('kalrav_last_api_color');
426        
427        if (selectedColor !== currentApiColor) {
428            console.log('🎨 User manually selected different c
428olor:', selectedColor);
429            
430            localStorage.setItem('kalrav_user_selected_color', selectedColor);
431            window.KALRAV.UIHelpers.applyApiLayoutColor(selectedColor);
432            window.KALRAV.UIHelpers.markColorAsManuallySet();
433        } else {
434            console.log('🎨 User selected API color, clearing override');
435            localStorage.removeItem('kalrav_user_selected_color');
436        }
437    };
438
439    window.KALRAV.UIHelpers.markColorAsManuallySet = function() {
440        if (!window.kalravData?.ajaxUrl) return;
441        
442        fetch(window.kalravData.ajaxUrl, {
443            method: 'POST',
444            headers: {
445                'Content-Type': 'application/x-www-form-urlencoded',
446            },
447            body: new URLSearchParams({
448                action: 'kalrav_mark_color_manually_set',
449                nonce: window.kalravData?.chatNonce
450            })
451        }).then(response => response.json())
452          .then(data => {
453              if (data.success) {
454                  console.log('✅ Color marked as manually set');
455              }
456          })
457          .catch(err => console.error('❌ Failed to mark color:', err));
458    };
459
460    window.KALRAV.UIHelpers.initializeColorSystem = function() {
461        const apiColor = window.KALRAV?.layoutColor;
462        
463        if (apiColor) {
464            if (!localStorage.getItem('kalrav_last_api_color')) {
465                localStorage.setItem('kalrav_last_api_color', apiColor);
466            }
467        }
468    };
469
470    window.KALRAV.UIHelpers.applyMessageColors = function(userInputColor, botResponseColor) {
471        function applyUserBackground(node) {
472            if (!userInputColor || !node) return;
473            
474            if (node.matches && node.matches('.user-message')) {
475                node.style.backgroundColor = userInputColor;
476            }
477            
478            const descendants = node.querySelectorAll && node.querySelectorAll('.user-message');
479            if (descendants && descendants.length) {
480                descendants.forEach(m => { 
481                    m.style.backgroundColor = userInputColor; 
482                });
483            }
484        }
485
486        function applyBotBackground(node) {
487            if (!botResponseColor || !node) return;
488            
489            if (node.matches && node.matches('.bot-message')) {
490                node.style.backgroundColor = botResponseColor;
491            }
492            
493            const descendants = node.querySelectorAll && node.querySelectorAll('.bot-message');
494            if (descendants && descendants.length) {
495                descendants.forEach(m => { 
496                    m.style.backgroundColor = botResponseColor; 
497                });
498            }
499        }
500
501        if (userInputColor) {
502            document.querySelectorAll('.user-message').forEach(msg => applyUserBackground(msg));
503        }
504        if (botResponseColor) {
505            document.querySelectorAll('.bot-message').forEach(msg => applyBotBackground(msg));
506        }
507
508        const messagesContainer = document.getElementById('chat-messages') || 
509                                  document.getElementById('chat-scroll-area');
510        
511        if (messagesContainer) {
512            const mo = new MutationObserver(mutations => {
513                for (const mut of mutations) {
514                    for (const node of Array.from(mut.addedNodes || [])) {
515                        if (node.nodeType !== 1) continue;
516                        
517                        if (userInputColor) applyUserBackground(node);
518                        if (botResponseColor) applyBotBackground(node);
519                    }
520                }
521            });
522            mo.observe(messagesContainer, { childList: true, subtree: true });
523        }
524    };
525  window.KALRAV.UIHelpers.applyFontColor = function(fontColor) {
526    const fontColorStyle = document.createElement('style');
527    fontColorStyle.id = 'kalrav-font-color-override';
528    fontColorStyle.textContent = `
529
530    .chat-content *:not(button):not(svg):not(path):not(.kalravai-disclaimer):not(.kalravai-disclaimer *):not(.user-message):not(.user-message *):not(.bot-message):not(.bot-message *):not(.chat-label-text),
531    #chat-messages *:not(button):not(svg):not(path):not(.user-message):not(.user-message *):not(.bot-message):not(.bot-message *):not(.chat-label-text),
532    
533    {
534      color: ${fontColor} !important;
535    }
536        
537        .kalravai-inside-disclaimer,
538        .kalravai-disclaimer  {
539            color: #818181 !important;
540        }
541        .kalravai-disclaimer a,.kalravai-inside-disclaimer a {
542            color: #0000FF !important;
543        }
544        .thumbsUp, .thumbsUp *, .thumbsDown, .thumbsDown *,
545        .thumbs-container button, .thumbs-container button *,
546        button.thumbsUp, button.thumbsDown {
547            color: inherit !important;
548        }
549        
550        .thumbsUp { color: #22b854ff !important; }
551        .thumbsUp svg { stroke: #22b854ff !important; }
552        .thumbsDown { color: #d41c1cff !important; }
553        .thumbsDown svg { stroke: #d41c1cff !important; }
554        
555        .thumbsUp svg[style*="fill: green"],
556        .thumbsUp svg[style*="fill:green"] {
557            fill: green !important;
558            stroke: green !important;
559        }
560        .thumbsDown svg[style*="fill: #d41c1cff"],
561        .thumbsDown svg[style*="fill:#d41c1cff"] {
562            fill: #d41c1cff !important;
563            stroke: #d41c1cff !important;
564        }
565        `;
566        document.head.appendChild(fontColorStyle);
567    };
568
569    window.KALRAV.UIHelpers.applyGreetingBgColor = function(greetingBgColor) {
570        const greetingBgStyle = document.createElement('style');
571        greetingBgStyle.textContent = `
572            #chat-help {
573                background-color: ${greetingBgColor} !important;
574            }
575        `;
576        document.head.appendChild(greetingBgStyle);
577    };
578
579   window.KALRAV.UIHelpers.applyFontStyle = function(fontStyle) {
580        const fontStyleRule = document.createElement('style');
581        fontStyleRule.textContent = `
582           #chat-scroll-area *:not(button):not(svg),
583           #chat-messages *:not(button):not(svg) ,
584           #chat-help *:not(button):not(svg) ,
585           #chat-header *:not(button):not(svg) ,
586           .top-chat-header *,
587           #chat-label *,
588           #chat-input *,
589           .kalravai-disclaimer *,
590           #chat-input-card *,
591           #placeholder-text *,
592           #chat-box *,
593           #clear-chat-dialog *,
594            #chat-scroll-area * {
595                font-family: ${fontStyle};
596        `;
597        document.head.appendChild(fontStyleRule);
598    };
599
600    window.KALRAV.UIHelpers.applyPlaceholderText = function(placeholderText) {
601        const chatInput = document.querySelector('#chat-input');
602        if (chatInput) {
603            chatInput.placeholder = placeholderText;
604        }
605    };
606
607  window.KALRAV.UIHelpers.applyDownloadText = function(downloadText) {
608    if (!downloadText) return;
609    const downloadBtn =document.getElementById('menu-toggle');
610    
611    if (downloadBtn) {
612        downloadBtn.title = downloadText;
613        downloadBtn.setAttribute('aria-label', downloadText);
614    }
615};
616
617    window.KALRAV.UIHelpers.applyClearChatTexts = function(texts) {
618        const {
619            clear_chat_title,
620            clear_chat_description,
621            clear_chat_confirm_button,
622            clear_chat_cancel_button,
623            clear_chat_cancel_bg_color,
624            clear_chat_cancel_text_color,
625            clear_chat_confirm_bg_color,
626            clear_chat_confirm_text_color
627        } = texts;
628
629        if (clear_chat_title) {
630            const titleEl = document.getElementById('clear-chat-title');
631            if (titleEl) titleEl.textContent = clear_chat_title;
632        }
633
634        if (clear_chat_description) {
635            const descEl = document.getElementById('clear-chat-description');
636            if (descEl) descEl.textContent = clear_chat_description;
637        }
638
639        if (clear_chat_confirm_button) {
640            const confirmTextEl = document.getElementById('confirm-clear-text');
641            if (confirmTextEl) confirmTextEl.textContent = clear_chat_confirm_button;
642        }
643
644        if (clear_chat_cancel_button) {
645            const cancelBtn = document.getElementById('cancel-clear');
646            //if (cancelBtn) cancelBtn.textContent = clear_chat_cancel_button;
647        }
648
649        // Apply button colors
650        if (clear_chat_cancel_bg_color || clear_chat_cancel_text_color) {
651            const cancelBtn = document.getElementById('cancel-clear');
652            if (cancelBtn) {
653                if (clear_chat_cancel_bg_color) {
654                    cancelBtn.style.backgroundColor = clear_chat_cancel_bg_color;
655                }
656                if (clear_chat_cancel_text_color) {
657                    cancelBtn.style.color = clear_chat_cancel_text_color;
658                }
659                // Update hover colors
660                cancelBtn.onmouseover = function() {
661                    this.style.backgroundColor = window.KALRAV.UIHelpers.adjustBrightness(clear_chat_cancel_bg_color || '#f3f4f6', -10);
662                };
663                cancelBtn.onmouseout = function() {
664                    this.style.backgroundColor = clear_chat_cancel_bg_color || '#f3f4f6';
665                };
666            }
667        }
668
669        if (clear_chat_confirm_bg_color || clear_chat_confirm_text_color) {
670            const confirmBtn = document.getElementById('confirm-clear');
671            if (confirmBtn) {
672                if (clear_chat_confirm_bg_color) {
673                    confirmBtn.style.backgroundColor = clear_chat_confirm_bg_color;
674                }
675                if (clear_chat_confirm_text_color) {
676                    confirmBtn.style.color = clear_chat_confirm_text_color;
677                }
678            }
679        }
680
681        if (window.KALRAV?.CONFIG) {
682            window.KALRAV.CONFIG.CLEAR_CHAT_TEXTS = texts;
683        }
684    };
685 window.KALRAV.UIHelpers.applyMessageTextColors = function(userTextColor, agentTextColor) {
686    const root = document.documentElement;
687    if (userTextColor) {
688        root.style.setProperty('--user-text-color', userTextColor);
689    }
690    if (agentTextColor) {
691        root.style.setProperty('--agent-text-color', agentTextColor);
692    }
693};
694    window.KALRAV.UIHelpers.applySendButtonColors = function(send_button_bg_color, send_button_text_color) {
695        const sendBtn = document.getElementById('send-chat');
696        
697        if (!sendBtn) return;
698        
699        if (send_button_bg_color) {
700            sendBtn.style.backgroundColor = send_button_bg_color;
701            sendBtn.style.setProperty('background', send_button_bg_color, 'important');
702        }
703        
704        if (send_button_text_color) {
705            sendBtn.style.color = send_button_text_color;
706            // Apply color to SVG inside button
707            const svg = sendBtn.querySelector('svg');
708            if (svg) {
709                svg.style.fill = send_button_text_color;
710            }
711        }
712        
713        // Update hover effect
714        if (send_button_bg_color) {
715            const hoverColor = window.KALRAV.UIHelpers.adjustBrightness(send_button_bg_color, -15);
716            sendBtn.onmouseover = function() {
717                this.style.backgroundColor = hoverColor;
718            };
719            sendBtn.onmouseout = function() {
720                this.style.backgroundColor = send_button_bg_color;
721            };
722        }
723        
724        // Store in config
725        if (window.KALRAV?.CONFIG) {
726            window.KALRAV.CONFIG.SEND_BUTTON_COLORS = {
727                background: send_button_bg_color,
728                text: send_button_text_color
729            };
730        }
731    };
732
733    window.KALRAV.UIHelpers.applyFeedbackButtonColors = function(colors) {
734        const {
735            yesBg,
736            yesText,
737            noBg,
738            noText
739        } = colors;
740
741        // Create a style element for feedback button colors
742        const feedbackColorStyle = document.createElement('style');
743        feedbackColorStyle.id = 'kalrav-feedback-colors';
744        
745        let cssRules = '';
746
747        // Yes button styles
748        if (yesBg || yesText) {
749            cssRules += `
750                .feedback-yes-btn,
751                button[data-feedback="yes"] {
752                    ${yesBg ? `background-color: ${yesBg} !important;` : ''}
753                    ${yesText ? `color: ${yesText} !important;` : ''}
754                }
755                .feedback-yes-btn:hover,
756                button[data-feedback="yes"]:hover {
757                    ${yesBg ? `background-color: ${window.KALRAV.UIHelpers.adjustBrightness(yesBg, -10)} !important;` : ''}
758                }
759            `;
760        }
761
762        // No button styles
763        if (noBg || noText) {
764            cssRules += `
765                .feedback-no-btn,
766                button[data-feedback="no"] {
767                    ${noBg ? `background-color: ${noBg} !important;` : ''}
768                    ${noText ? `color: ${noText} !important;` : ''}
769                }
770                .feedback-no-btn:hover,
771                button[data-feedback="no"]:hover {
772                    ${noBg ? `background-color: ${window.KALRAV.UIHelpers.adjustBrightness(noBg, -10)} !important;` : ''}
773                }
774            `;
775        }
776
777        feedbackColorStyle.textContent = cssRules;
778        document.head.appendChild(feedbackColorStyle);
779
780        // Store in config
781        if (window.KALRAV?.CONFIG) {
782            window.KALRAV.CONFIG.FEEDBACK_BUTTON_COLORS = colors;
783        }
784    };
785
786    // Helper function to adjust brightness for hover effect
787    window.KALRAV.UIHelpers.adjustBrightness = function(color, percent) {
788        const num = parseInt(color.replace("#", ""), 16);
789        const amt = Math.round(2.55 * percent);
790        const R = (num >> 16) + amt;
791        const G = (num >> 8 & 0x00FF) + amt;
792        const B = (num & 0x0000FF) + amt;
793        return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
794            (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
795            (B < 255 ? B < 1 ? 0 : B : 255))
796            .toString(16).slice(1);
797    };
798
799    window.KALRAV.UIHelpers.applyLanguageSelector = function(defaultLanguage, languagesAvailable) {
800        const languageMap = {
801            'english': { code: 'en', label: 'English' },
802            'hindi': { code: 'hi', label: 'Hindi' },
803            'french': { code: 'fr', label: 'French' },
804            'german': { code: 'de', label: 'German' },
805            'russian': { code: 'ru', label: 'Russian' },
806            'kannada': { code: 'kn', label: 'Kannada' },
807            'tamil': { code: 'ta', label: 'Tamil' },
808            'bengali': { code: 'bn', label: 'Bengali' },
809            'telugu': { code: 'te', label: 'Telugu' },
810            'malayalam': { code: 'ml', label: 'Malayalam' },
811            'spanish': { code: 'es', label: 'Spanish' },
812            'chinese': { code: 'zh', label: 'Chinese' },
813            'japanese': { code: 'ja', label: 'Japanese' }
814        };
815
816        const languageSelect = document.getElementById('language-select');
817        const configuredLanguages = Array.isArray(languagesAvailable) ? languagesAvailable : [];
818
819        if (languageSelect && configuredLanguages.length > 0) {
820            languageSelect.innerHTML = '';
821            
822            const defaultLangCode = languageMap[String(defaultLanguage || '').toLowerCase()]?.code || 'en';
823            
824            configuredLanguages.forEach(langName => {
825                const langKey = String(langName).toLowerCase();
826                const langInfo = languageMap[langKey];
827                
828                if (langInfo) {
829                    const option = document.createElement('option');
830                    option.value = langInfo.code;
831                    option.textContent = langInfo.label;
832                    
833                    if (langInfo.code === defaultLangCode) {
834                        option.selected = true;
835                    }
836                    
837                    languageSelect.appendChild(option);
838                }
839            });
840
841            const hasSingleLanguage = languageSelect.options.length === 1;
842
843            languageSelect.dataset.kalravSingleLanguage = hasSingleLanguage ? 'true' : 'false';
844            languageSelect.disabled = hasSingleLanguage;
845            languageSelect.setAttribute('aria-disabled', hasSingleLanguage ? 'true' : 'false');
846        }
847    };
848
849     window.KALRAV.UIHelpers.applyDefaultQuestions = function(defaultQuestions) {
850        window.kalravData = window.kalravData || {};
851        window.kalravData.kalravai_default_questions = defaultQuestions;
852
853        if (window.KALRAV && window.KALRAV.CONFIG) {
854            window.KALRAV.CONFIG.DEFAULT_QUESTIONS = defaultQuestions;
855        }
856
857        if (typeof window.KALRAV?.showDefaultSuggestions === 'function') {
858            try {
859                window.KALRAV.showDefaultSuggestions();
860            } catch (e) {
861                console.warn('Unable to refresh default suggestions:', e);
862            }
863        }
864    };
865
866
867    window.KALRAV.UIHelpers.applyLeadGenFormSettings = function(leadGenSettings) {  
868        const formWrapper = document.getElementById('contact-form-wrapper');
869        if (!formWrapper) {
870            console.warn('⚠️ Contact form wrapper not found');
871            return;
872        }
873       
874        const enable_crm = window.KALRAV.SHOW_LEAD_FORM;
875        
876        // Check if form should be shown at all
877        if (enable_crm !== true) {
878            formWrapper.style.display = 'none';
879            return;
880        }
881      
882        formWrapper.style.display = 'block';
883        const formFields = leadGenSettings.form_fields || {};
884        // Map API field names to HTML element IDs
885        const fieldMapping = {
886            'name': 'contact-name',
887            'email': 'contact-email',
888            'phone': 'contact-phone',
889            'company': 'contact-company',
890            'interest': 'contact-interest',
891            'message': 'contact-conversation'
892        };
893
894        // Process each field
895        Object.keys(fieldMapping).forEach(fieldKey => {
896            const fieldConfig = formFields[fieldKey];
897            const fieldId = fieldMapping[fieldKey];
898            const fieldElement = document.getElementById(fieldId);
899            
900            if (!fieldElement) {
901                console.warn(`⚠️ Field element not found: ${fieldId}`);
902                return;
903            }
904
905            const fieldContainer = fieldElement.parentElement;
906            
907            if (!fieldConfig || !fieldConfig.enabled) {
908                // Hide disabled fields
909                fieldContainer.style.display = 'none';
910                fieldElement.removeAttribute('required');
911            } else {
912                // Show enabled fields
913                fieldContainer.style.display = 'block';
914                
915                // Update label/placeholder
916                if (fieldConfig.label) {
917                    const requiredMark = fieldConfig.required ? ' *' : '';
918                    fieldElement.placeholder = fieldConfig.label + requiredMark;
919                }
920                
921                // Update required attribute
922                if (fieldConfig.required) {
923                    fieldElement.setAttribute('required', 'required');
924                } else {
925                    fieldElement.removeAttribute('required');
926                }
927            }
928        });
929
930        // Handle custom fields if present
931        if (leadGenSettings.custom_fields && leadGenSettings.custom_fields.length > 0) {
932           // console.log('📋 Custom fields detected:', leadGenSettings.custom_fields);
933            // Add custom fields dynamically
934            window.KALRAV.UIHelpers.addCustomFields(leadGenSettings.custom_fields);
935        }
936    };
937
938    window.KALRAV.UIHelpers.addCustomFields = function(customFields) {
939        const form = document.getElementById('contact-form');
940        if (!form) return;
941
942        const submitButton = form.querySelector('button[type="submit"]');
943        
944        customFields.forEach((field, index) => {
945            const fieldContainer = document.createElement('div');
946            fieldContainer.style.marginBottom = '12px';
947            fieldContainer.setAttribute('data-custom-field', 'true');
948
949            let inputElement;
950            
951            if (field.type === 'textarea') {
952                inputElement = document.createElement('textarea');
953                inputElement.style.height = '80px';
954            } else {
955                inputElement = document.createElement('input');
956                inputElement.type = field.type || 'text';
957            }
958
959            inputElement.id = `custom-field-${index}`;
960            inputElement.name = field.name || `custom_${index}`;
961            inputElement.placeholder = field.label + (field.required ? ' *' : '');
962            inputElement.style.cssText = `
963                width: 100%;
964                padding: 12px;
965                border: 1px solid #ddd;
966                border-radius: 8px;
967                font-size: 14px;
968                box-sizing: border-box;
969                font-family: 'Inter', Arial, sans-serif;
970            `;
971
972            if (field.required) {
973                inputElement.setAttribute('required', 'required');
974            }
975
976            fieldContainer.appendChild(inputElement);
977            
978            // Insert before submit button
979            if (submitButton) {
980                form.insertBefore(fieldContainer, submitButton);
981            } else {
982                form.appendChild(fieldContainer);
983            }
984        });
985    
986        console.log(`✅ Added ${customFields.length} custom fields to form`);
987    };
988
989    // Expose legacy functions for backward compatibility
990    window.KALRAV.handleManualColorSelection = window.KALRAV.UIHelpers.handleManualColorSelection;
991    window.KALRAV.initializeColorSystem = window.KALRAV.UIHelpers.initializeColorSystem;
992    window.KALRAV.initializeDefaultBotPosition = window.KALRAV.UIHelpers.initializeDefaultBotPosition;
993
994})(window);

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.