const scsUi=(function (){
'use strict';
let chatVisible=false;
let typingIndicatorElement=null;
let audioUnlocked=false;
let elements={};
function initElements(){
elements={
app: document.getElementById('scs-app'),
bubble: document.getElementById('scs-chatBubble'),
popup: document.getElementById('scs-chatPopup'),
closeBtn: document.getElementById('scs-closeChatBtn'),
chatContainer: document.getElementById('scs-chat-container'),
startFormContainer: document.getElementById('scs-startChatForm'),
startForm: document.getElementById('scs-newChatFormSubmit'),
chatInterface: document.getElementById('scs-chatInterface'),
userInput: document.getElementById('scs-userInput'),
sendBtn: document.getElementById('scs-sendBtn'),
newChatBtn: document.getElementById('scs-newChatBtn'),
accessibilityBtn: document.getElementById('scs-accessibilityBtn'),
accessibilityPanel: document.getElementById('scs-accessibility-panel'),
sound: document.getElementById('scs-notificationSound'),
attachToggleBtn: document.getElementById('scs-attach-toggle-btn'),
fileInputHidden: document.getElementById('scs-file-input-hidden'),
filePreviewsContainer: document.getElementById('scs-file-previews-container')
};}
function init(){
initElements();
if(typeof scsConfig==='undefined'){
return;
}
if(!elements.bubble||!elements.popup){
return;
}
const primaryColor=scsConfig.primaryColor||'#4f46e5';
document.documentElement.style.setProperty('--scs-primary-color', primaryColor);
const primaryTextColor=scsConfig.primaryTextColor||'#000000';
document.documentElement.style.setProperty('--scs-primary-text-color', primaryTextColor);
const bubbleIconSvg=document.getElementById('scs-bubble-icon-svg');
if(bubbleIconSvg){
bubbleIconSvg.innerHTML=scsUtils.ICON_PATHS[scsConfig.bubbleIcon]||scsUtils.ICON_PATHS['chat-dots'];
}
const pos=scsConfig.bubblePosition||'bottom-right';
const bBottom=parseInt(scsConfig.bubbleBottom)||20;
const bTop=parseInt(scsConfig.bubbleTop)||20;
const bLeft=parseInt(scsConfig.bubbleLeft)||20;
const bRight=parseInt(scsConfig.bubbleRight)||20;
const offset=80;
elements.bubble.style.bottom='auto';
elements.bubble.style.top='auto';
elements.bubble.style.left='auto';
elements.bubble.style.right='auto';
elements.popup.style.bottom='auto';
elements.popup.style.top='auto';
elements.popup.style.left='auto';
elements.popup.style.right='auto';
if(pos==='bottom-right'){
elements.bubble.style.bottom=bBottom + 'px';
elements.bubble.style.right=bRight + 'px';
}else if(pos==='bottom-left'){
elements.bubble.style.bottom=bBottom + 'px';
elements.bubble.style.left=bLeft + 'px';
}else if(pos==='top-right'){
elements.bubble.style.top=bTop + 'px';
elements.bubble.style.right=bRight + 'px';
}else if(pos==='top-left'){
elements.bubble.style.top=bTop + 'px';
elements.bubble.style.left=bLeft + 'px';
}
if(scsUtils.isMobile()){
elements.popup.style.top='';
elements.popup.style.bottom='';
elements.popup.style.left='';
elements.popup.style.right='';
elements.popup.style.width='';
elements.popup.style.height='';
elements.popup.style.transform='none';
}else if(scsConfig.chatTemplate!=='robustiana'){
if(pos==='bottom-right'){
elements.popup.style.bottom=(bBottom + offset) + 'px';
elements.popup.style.right=bRight + 'px';
elements.popup.style.transformOrigin='bottom right';
}else if(pos==='bottom-left'){
elements.popup.style.bottom=(bBottom + offset) + 'px';
elements.popup.style.left=bLeft + 'px';
elements.popup.style.transformOrigin='bottom left';
}else if(pos==='top-right'){
elements.popup.style.top=(bTop + offset) + 'px';
elements.popup.style.right=bRight + 'px';
elements.popup.style.transformOrigin='top right';
}else if(pos==='top-left'){
elements.popup.style.top=(bTop + offset) + 'px';
elements.popup.style.left=bLeft + 'px';
elements.popup.style.transformOrigin='top left';
}
elements.popup.style.width=(scsConfig.popupWidth||400) + 'px';
elements.popup.style.height=(scsConfig.popupHeight||600) + 'px';
}else{
elements.popup.style.top='';
elements.popup.style.bottom='';
elements.popup.style.left='';
elements.popup.style.right='';
elements.popup.style.width='';
elements.popup.style.height='';
elements.popup.style.transform='none';
}
if(elements.sound){
elements.sound.src=scsConfig.notificationSound;
}
if(scsConfig.isTestMode==='1'){
const headerTitle=elements.popup.querySelector('#scs-mainHeader h2, #scs-mainHeader h3');
if(headerTitle){
const testAlert=document.createElement('span');
testAlert.className='scs-test-alert';
testAlert.textContent=scsUtils.__('testMode');
headerTitle.appendChild(testAlert);
}}
elements.bubble.addEventListener('click', (e)=> {
e.stopPropagation();
toggleChat(!chatVisible);
unlockAudio();
});
if(elements.closeBtn){
elements.closeBtn.addEventListener('click', (e)=> {
e.stopPropagation();
toggleChat(false);
});
}
if(elements.userInput){
elements.userInput.addEventListener('input', checkInputAndToggleSendButton);
}
if(elements.attachToggleBtn&&elements.fileInputHidden){
elements.attachToggleBtn.addEventListener('click', (e)=> {
e.preventDefault();
e.stopPropagation();
elements.fileInputHidden.click();
});
}
if(elements.removeFileBtn){
elements.removeFileBtn.addEventListener('click', (e)=> {
e.preventDefault();
e.stopPropagation();
document.dispatchEvent(new CustomEvent('scs-remove-selected-file'));
});
}
hideFilePreview();
checkInputAndToggleSendButton();
toggleLoading(false);
if(typeof (Storage)!=="undefined"){
const wasOpen=localStorage.getItem('scs_chat_open')==='true';
if(wasOpen){
setTimeout(()=> {
toggleChat(true);
}, 300);
}}
}
function toggleChat(visible){
chatVisible=visible;
if(!elements.popup||!elements.bubble) return;
if(scsConfig.chatTemplate==='robustiana'){
elements.popup.style.transform='none';
}else{
elements.popup.style.transform='';
}
if(visible){
elements.popup.style.display='flex';
setTimeout(()=> {
document.body.classList.add('scs-chat-open');
}, 10);
}else{
document.body.classList.remove('scs-chat-open');
setTimeout(()=> {
if(!chatVisible){
elements.popup.style.display='none';
}}, 300);
}
elements.bubble.style.transform=chatVisible ? 'rotate(90deg)':'rotate(0deg)';
if(typeof (Storage)!=="undefined"){
localStorage.setItem('scs_chat_open', chatVisible);
}
const fsToggle=document.getElementById('scs-fullscreen-toggle');
const isMobile=scsUtils.isMobile();
if(chatVisible&&(isMobile||(fsToggle&&fsToggle.checked))){
document.body.classList.add('scs-fullscreen-mode');
elements.bubble.style.display='none';
if(isMobile){
elements.popup.style.top='';
elements.popup.style.bottom='';
elements.popup.style.left='';
elements.popup.style.right='';
elements.popup.style.width='';
elements.popup.style.height='';
}}
if(!chatVisible){
document.body.classList.remove('scs-fullscreen-mode');
elements.bubble.style.display='';
}}
function addMessage(sender, text, options={}){
const { isUser=false, isSecurityAlert=false, timestamp=null }=options;
if(!elements.chatContainer) return;
const msgWrapper=document.createElement('div');
let className=isUser ? 'scs-justify-end scs-user-message':'scs-justify-start scs-assistant-message';
if(isSecurityAlert) className='scs-justify-start scs-assistant-message scs-security-message';
msgWrapper.className=`scs-flex scs-mb-2 scs-align-end ${className}`;
const avatar=document.createElement('img');
avatar.className='scs-avatar';
avatar.src=(isUser&&!isSecurityAlert) ? scsConfig.avatarUser:scsConfig.avatarBot;
const msgContent=document.createElement('div');
msgContent.className='scs-msg-content';
const senderName=isSecurityAlert ? scsUtils.__('securityAlert'):(isUser ? scsUtils.__('you'):scsUtils.__('assistant'));
let formattedText;
if(isUser||isSecurityAlert){
formattedText=scsUtils.sanitizeInput(text).replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>');
}else{
const withMarkdown=scsUtils.parseMarkdown(text);
const withLinks=scsUtils.linkify(withMarkdown);
formattedText=scsUtils.sanitizeHtml(withLinks);
}
const timeString=timestamp ? scsUtils.formatTimestamp(timestamp):scsUtils.formatTimestamp(new Date().toISOString());
const safeAttachmentUrl=options.attachmentUrl ? scsUtils.sanitizeInput(options.attachmentUrl):'';
let attachmentHtml='';
if(safeAttachmentUrl){
const fileName=safeAttachmentUrl.split('/').pop();
const isImage=/\.(jpg|jpeg|png|gif|webp)$/i.test(fileName);
if(isImage){
attachmentHtml=`<div class="scs-message-attachment"><img src="${safeAttachmentUrl}" style="max-width: 100%; border-radius: 8px; margin-top: 8px; cursor: pointer;" onclick="window.open(this.src)"></div>`;
}else{
attachmentHtml=`
<a href="${safeAttachmentUrl}" target="_blank" class="scs-message-attachment">
📁 ${fileName}
</a>
`;
}}
msgContent.innerHTML=`
<span class="scs-small scs-fw-bold scs-opacity-75 scs-d-block scs-mb-1 scs-text-start">${senderName}</span>
<div class="scs-text-start scs-msg-text">${formattedText}${attachmentHtml}</div>
<span class="scs-msg-time">${timeString}</span>
`;
if(isUser&&!isSecurityAlert){
msgWrapper.appendChild(msgContent);
msgWrapper.appendChild(avatar);
}else{
msgWrapper.appendChild(avatar);
msgWrapper.appendChild(msgContent);
}
elements.chatContainer.appendChild(msgWrapper);
elements.chatContainer.scrollTop=elements.chatContainer.scrollHeight;
return timeString;
}
function showTypingIndicator(){
if(typingIndicatorElement||!elements.chatContainer) return;
typingIndicatorElement=document.createElement('div');
typingIndicatorElement.className='scs-flex scs-mb-2 scs-align-end scs-typing-indicator';
typingIndicatorElement.innerHTML=`
<img class="scs-avatar" src="${scsConfig.avatarBot}" alt="${scsUtils.__('assistantWriting', { agente: scsConfig.botName })}">
<div class="scs-msg-content">
<span>${scsUtils.__('assistantTyping', { agente: scsConfig.botName })}</span>
<span class="scs-dot scs-dot-1"></span>
<span class="scs-dot scs-dot-2"></span>
<span class="scs-dot scs-dot-3"></span>
</div>
`;
elements.chatContainer.appendChild(typingIndicatorElement);
elements.chatContainer.scrollTop=elements.chatContainer.scrollHeight;
}
function removeTypingIndicator(){
if(typingIndicatorElement&&elements.chatContainer){
elements.chatContainer.removeChild(typingIndicatorElement);
typingIndicatorElement=null;
}}
function checkInputAndToggleSendButton(){
if(!elements.userInput||!elements.sendBtn) return;
const hasText=elements.userInput.value.trim().length > 0;
const isSending=elements.sendBtn.innerHTML.includes('spinner-border');
elements.sendBtn.disabled = !hasText||isSending;
}
function toggleLoading(isLoading){
if(!elements.userInput||!elements.sendBtn) return;
const spinnerHtml='<span class="scs-spinner" role="status" aria-hidden="true" style="width: 20px; height: 20px;"></span>';
const sendIconHtml=`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 16 16"><path d="M15.964.686a.5.5 0 0 0-.65-.65L.767 5.855H.766l-.452.18a.5.5 0 0 0-.082.887l.41.26.001.002 4.995 3.178 3.178 4.995.002.002.26.41a.5.5 0 0 0 .886-.083l6-15Zm-1.833 1.89L6.637 10.07l-.215-.338a.5.5 0 0 0-.154-.154l-.338-.215 7.494-7.494 1.178-.471-.47 1.178Z"/></svg>`;
elements.userInput.disabled=isLoading;
elements.sendBtn.innerHTML=isLoading ? spinnerHtml:sendIconHtml;
checkInputAndToggleSendButton();
if(isLoading) showTypingIndicator();
else {
removeTypingIndicator();
elements.userInput.focus();
}}
function unlockAudio(){
if(audioUnlocked||!elements.sound) return;
elements.sound.volume=0;
elements.sound.play().then(()=> {
elements.sound.pause();
elements.sound.currentTime=0;
elements.sound.volume=1;
audioUnlocked=true;
}).catch(()=> { });
}
function playNotificationSound(){
if(elements.sound){
unlockAudio();
elements.sound.pause();
elements.sound.currentTime=0;
elements.sound.play().catch(()=> { });
}}
function updateFilePreviews(files, onRemove){
if(!elements.filePreviewsContainer) return;
elements.filePreviewsContainer.innerHTML='';
if(!files||files.length===0){
elements.filePreviewsContainer.style.display='none';
return;
}
elements.filePreviewsContainer.style.display='flex';
files.forEach((file, index)=> {
const chip=createFilePreviewChip(file, index, onRemove);
elements.filePreviewsContainer.appendChild(chip);
});
}
function createFilePreviewChip(file, index, onRemove){
const chip=document.createElement('div');
chip.className='scs-file-preview';
chip.style.display='flex';
const mediaDiv=document.createElement('div');
mediaDiv.className='scs-file-preview-media';
const nameSpan=document.createElement('span');
nameSpan.className='scs-file-preview-name';
nameSpan.textContent=file.name;
const removeBtn=document.createElement('button');
removeBtn.type='button';
removeBtn.className='scs-remove-file-btn';
removeBtn.innerHTML='&times;';
removeBtn.title=scsUtils.__('removeFile');
removeBtn.onclick=(e)=> {
e.preventDefault();
onRemove(index);
};
chip.appendChild(mediaDiv);
chip.appendChild(nameSpan);
chip.appendChild(removeBtn);
const ext=file.name.split('.').pop().toLowerCase();
if(['jpg', 'jpeg', 'png', 'gif', 'webp'].includes(ext)){
const reader=new FileReader();
reader.onload=(e)=> {
const img=document.createElement('img');
img.src=e.target.result;
mediaDiv.appendChild(img);
};
reader.readAsDataURL(file);
}else{
const iconSpan=document.createElement('span');
iconSpan.textContent=getFileIcon(file.name);
mediaDiv.appendChild(iconSpan);
}
return chip;
}
function getFileIcon(fileName){
const ext=fileName.split('.').pop().toLowerCase();
const icons={
'pdf': '📄',
'doc': '📝',
'docx': '📝',
'txt': '📝',
'xls': '📊',
'xlsx': '📊',
'csv': '📊',
'zip': '📦',
'rar': '📦',
'7z': '📦',
'mp3': '🎵',
'wav': '🎵',
'mp4': '🎬',
'mov': '🎬'
};
return icons[ext]||'📁';
}
function hideFilePreview(){
if(elements.filePreviewsContainer){
elements.filePreviewsContainer.style.display='none';
elements.filePreviewsContainer.innerHTML='';
}}
return {
init: init,
getElements: ()=> elements,
toggleChat: toggleChat,
addMessage: addMessage,
toggleLoading: toggleLoading,
playNotificationSound: playNotificationSound,
checkInputAndToggleSendButton: checkInputAndToggleSendButton,
updateFilePreviews: updateFilePreviews,
hideFilePreview: hideFilePreview
};})();