UNPKG

besper-frontend-site-dev-main

Version:

Professional B-esper Frontend Site - Site-wide integration toolkit for full website bot deployment

208 lines (186 loc) 5.75 kB
/** * Message Component * Handles individual message rendering and behavior in the chat widget */ export class Message { constructor(content, sender, options = {}) { this.content = content; this.sender = sender; // 'user' or 'bot' this.timestamp = options.timestamp || new Date().toISOString(); this.id = options.id || this.generateMessageId(); this.config = options.config || {}; } /** * Generate a unique message ID * @returns {string} Unique message ID */ generateMessageId() { return 'msg-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9); } /** * Get the formatted message time * @returns {string} Formatted time string */ getFormattedTime() { const messageDate = this.timestamp ? new Date(this.timestamp) : new Date(); return messageDate.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', }); } /** * Get the avatar HTML for the message * @returns {string} Avatar HTML */ getAvatarHTML() { const config = this.config || {}; if (this.sender === 'bot') { const shouldHideAvatar = !config.logoUrl; const style = shouldHideAvatar ? 'style="display: none;"' : ''; return ` <div class="besper-message-avatar besper-${this.sender}" ${style}> ${ config.logoUrl ? `<img src="${config.logoUrl}" alt="Bot Logo" class="besper-avatar-image">` : '' } </div> `; } else { return ` <div class="besper-message-avatar besper-${this.sender}"> U </div> `; } } /** * Get the overflow warning HTML if needed * @returns {string} Overflow warning HTML or empty string */ getOverflowWarningHTML() { // Only show overflow warning for bot messages with tables if (this.sender !== 'bot' || !this.hasTable()) { return ''; } return ` <div class="besper-table-overflow-warning" style="display: none;"> <div class="besper-overflow-content"> <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/> </svg> <span class="besper-overflow-text">Optimize view for better readability (Click to expand)</span> </div> </div> `; } /** * Check if the message content contains tables * @returns {boolean} Whether the message has tables */ hasTable() { return typeof this.content === 'string' && this.content.includes('<table'); } /** * Generate the complete HTML for the message * @returns {string} Message HTML string */ getHTML() { const messageTime = this.getFormattedTime(); const avatarHTML = this.getAvatarHTML(); const overflowWarningHTML = this.getOverflowWarningHTML(); return ` <div class="besper-message besper-${this.sender}" id="${this.id}"> ${avatarHTML} <div class="besper-message-content"> <div class="besper-message-text">${this.content}</div> ${overflowWarningHTML} <div class="besper-message-time">${messageTime}</div> </div> </div> `; } /** * Check for table overflow after the message is rendered * @param {HTMLElement} messageElement - The rendered message element * @param {Function} onOverflow - Callback function when overflow is detected */ checkTableOverflow(messageElement, onOverflow) { if (!messageElement || this.sender !== 'bot') return; // Skip overflow check on mobile devices if (this.isMobileDevice()) return; const tables = messageElement.querySelectorAll('table'); if (tables.length === 0) return; let hasOverflow = false; tables.forEach(table => { if (table.scrollWidth > table.clientWidth) { hasOverflow = true; } }); if (hasOverflow) { const warningElement = messageElement.querySelector( '.besper-table-overflow-warning' ); if (warningElement) { warningElement.style.display = 'flex'; if (onOverflow) { onOverflow(warningElement); } } } } /** * Setup event listeners for the message * @param {HTMLElement} messageElement - The rendered message element * @param {Object} callbacks - Callback functions for events */ setupEventListeners(messageElement, callbacks = {}) { // Table overflow warning click handler const overflowWarning = messageElement.querySelector( '.besper-table-overflow-warning' ); if (overflowWarning && callbacks.onOverflowClick) { overflowWarning.addEventListener('click', () => { callbacks.onOverflowClick(); }); } // Any other message-specific interactions can be added here } /** * Mobile device detection * @returns {boolean} Whether the device is mobile */ isMobileDevice() { return ( window.innerWidth <= 480 || /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test( navigator.userAgent ) ); } /** * Convert the message to a plain object for storage * @returns {Object} Message data object */ toObject() { return { id: this.id, content: this.content, sender: this.sender, timestamp: this.timestamp, }; } /** * Create a Message instance from a plain object * @param {Object} data - Message data object * @param {Object} config - Bot configuration * @returns {Message} Message instance */ static fromObject(data, config = {}) { return new Message(data.content, data.sender, { id: data.id, timestamp: data.timestamp, config, }); } }