class MoveableChatFrame { constructor() { try { this.initializeElements(); if (!this.frame) { console.warn( "MoveableChatFrame: Required elements not found, skipping initialization", ); return; } this.isDragging = false; this.isResizing = false; this.isMinimized = false; this.dragOffset = { x: 0, y: 0 }; this.resizeHandle = null; this.chatLoaded = false; this.initializeEventListeners(); this.loadSavedState(); } catch (error) { console.error("MoveableChatFrame initialization failed:", error); } } initializeElements() { this.frame = document.getElementById("moveableChatFrame"); this.header = document.getElementById("chatFrameHeader"); this.toggleBtn = document.getElementById("toggleChatBtn"); this.minimizeBtn = document.getElementById("minimizeChatBtn"); this.closeBtn = document.getElementById("closeChatBtn"); if (!this.frame || !this.header || !this.toggleBtn) { console.warn("MoveableChatFrame: Missing required DOM elements"); return false; } return true; } initializeEventListeners() { if ( !this.toggleBtn || !this.minimizeBtn || !this.closeBtn || !this.header ) { console.warn("MoveableChatFrame: Cannot bind events - missing elements"); return; } try { this.toggleBtn.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); this.toggleChat(); }); this.minimizeBtn.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); this.toggleMinimize(); }); this.closeBtn.addEventListener("click", (e) => { e.preventDefault(); e.stopPropagation(); this.closeChat(); }); this.header.addEventListener("mousedown", (e) => { if (e.target.closest(".chat-control-btn")) return; e.preventDefault(); this.startDragging(e); }); const resizeHandles = this.frame.querySelectorAll(".resize-handle"); for (const handle of resizeHandles) { handle.addEventListener("mousedown", (e) => { e.preventDefault(); this.startResizing(e, handle); }); } document.addEventListener( "mousemove", (e) => { if (this.isDragging) { this.drag(e); } else if (this.isResizing) { this.resize(e); } }, { passive: true }, ); document.addEventListener( "mouseup", () => { this.stopDragging(); this.stopResizing(); }, { passive: true }, ); this.header.addEventListener( "touchstart", (e) => { if (e.target.closest(".chat-control-btn")) return; e.preventDefault(); this.startDragging(e.touches[0]); }, { passive: false }, ); document.addEventListener( "touchmove", (e) => { if (this.isDragging) { e.preventDefault(); this.drag(e.touches[0]); } }, { passive: false }, ); document.addEventListener( "touchend", () => { this.stopDragging(); }, { passive: true }, ); window.addEventListener( "resize", () => { this.constrainToViewport(); }, { passive: true }, ); } catch (error) { console.error("Error binding MoveableChatFrame events:", error); } } toggleChat() { if (!this.frame) return; if (this.frame.style.display === "none") { this.openChat(); } else { this.closeChat(); } } openChat() { if (!this.frame) return; this.frame.style.display = "flex"; document.body.classList.add("chat-open"); if (!this.chatLoaded) { this.loadChatContent(); } this.saveState(); } loadChatContent() { const streamId = document.querySelector('meta[name="stream-id"]')?.content; if (!streamId) { this.showChatError("Stream ID not found"); return; } console.log("Loading chat for stream ID:", streamId); this.showLoading(); const iframe = document.createElement("iframe"); iframe.className = "chat-frame-iframe"; iframe.src = `/chat/${encodeURIComponent(streamId)}`; iframe.style.cssText = ` width: 100%; height: 100%; border: none; border-radius: 0 0 12px 12px; background: var(--bg-card); `; iframe.onload = () => { this.chatLoaded = true; this.hideLoading(); console.log("Chat iframe loaded successfully"); }; iframe.onerror = () => { console.error("Failed to load chat iframe"); this.showChatError("Failed to load chat"); }; const loadTimeout = setTimeout(() => { if (!this.chatLoaded) { console.warn("Chat loading timeout"); this.showChatError("Chat loading timeout"); } }, 10000); iframe.addEventListener("load", () => { clearTimeout(loadTimeout); }); const content = this.frame.querySelector(".chat-frame-content"); if (content) { content.innerHTML = ""; content.appendChild(iframe); } } closeChat() { if (!this.frame) return; this.frame.style.display = "none"; document.body.classList.remove("chat-open"); const content = this.frame.querySelector(".chat-frame-content"); if (content) { content.innerHTML = ""; } this.chatLoaded = false; this.saveState(); } toggleMinimize() { if (!this.frame || !this.minimizeBtn) return; this.isMinimized = !this.isMinimized; this.frame.classList.toggle("minimized", this.isMinimized); const icon = this.minimizeBtn.querySelector("svg path"); if (icon) { if (this.isMinimized) { icon.setAttribute("d", "M18 15l-6-6-6 6"); this.minimizeBtn.title = "Maximize"; } else { icon.setAttribute("d", "M6 9l6 6 6-6"); this.minimizeBtn.title = "Minimize"; } } this.saveState(); } showLoading() { if (!this.frame) return; const loadingDiv = document.createElement("div"); loadingDiv.className = "chat-frame-loading"; loadingDiv.innerHTML = `
Loading chat... `; const content = this.frame.querySelector(".chat-frame-content"); if (content) { content.innerHTML = ""; content.appendChild(loadingDiv); } } hideLoading() {} showChatError(message) { if (!this.frame) return; const errorDiv = document.createElement("div"); errorDiv.className = "chat-frame-error"; errorDiv.innerHTML = `