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 = '×'; 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.