/** * InsertrControlPanel - Unified UI Controller * Handles all presentation layer concerns for the insertr system * * Architecture: * - Pure presentation layer - no business logic * - Event-driven communication with core modules * - Unified control panel design * - Responsive and accessible */ export class InsertrControlPanel { constructor(auth, editor, apiClient, options = {}) { this.auth = auth; this.editor = editor; this.apiClient = apiClient; this.options = options; // UI state this.elements = {}; this.isInitialized = false; // Bind methods for event listeners this.handleAuthToggle = this.handleAuthToggle.bind(this); this.handleEditToggle = this.handleEditToggle.bind(this); this.handleEnhanceClick = this.handleEnhanceClick.bind(this); } /** * Initialize the control panel (called after DOM is ready) */ init() { if (this.isInitialized) return; console.log('🎨 Initializing Insertr Control Panel'); this.createControlPanel(); this.setupEventListeners(); this.updateVisualState(); this.isInitialized = true; } /** * Create the unified control panel structure */ createControlPanel() { // Check if control panel already exists if (document.getElementById('insertr-control-panel')) { this.cacheElements(); return; } const controlPanelHtml = `
Visitor Mode
`; // Add control panel to page document.body.insertAdjacentHTML('beforeend', controlPanelHtml); this.cacheElements(); console.log('📱 Control panel created'); } /** * Cache DOM elements for performance */ cacheElements() { this.elements = { controlPanel: document.getElementById('insertr-control-panel'), statusSection: document.getElementById('insertr-status-section'), statusIndicator: document.getElementById('insertr-status-indicator'), statusText: document.querySelector('.insertr-status-text'), statusDot: document.querySelector('.insertr-status-dot'), actionSection: document.getElementById('insertr-action-section'), authToggle: document.getElementById('insertr-auth-toggle'), editToggle: document.getElementById('insertr-edit-toggle'), enhanceBtn: document.getElementById('insertr-enhance-btn') }; } /** * Setup event listeners for all UI interactions */ setupEventListeners() { if (this.elements.authToggle) { this.elements.authToggle.addEventListener('click', this.handleAuthToggle); } if (this.elements.editToggle) { this.elements.editToggle.addEventListener('click', this.handleEditToggle); } if (this.elements.enhanceBtn) { this.elements.enhanceBtn.addEventListener('click', this.handleEnhanceClick); } // Listen for auth state changes if (this.auth && typeof this.auth.on === 'function') { this.auth.on('stateChange', () => this.updateVisualState()); } // Listen for editor state changes if (this.editor && typeof this.editor.on === 'function') { this.editor.on('modeChange', () => this.updateVisualState()); } } /** * Handle authentication toggle click */ handleAuthToggle() { if (this.auth && typeof this.auth.toggleAuthentication === 'function') { this.auth.toggleAuthentication(); this.updateVisualState(); } } /** * Handle edit mode toggle click */ handleEditToggle() { if (this.auth && typeof this.auth.toggleEditMode === 'function') { this.auth.toggleEditMode(); this.updateVisualState(); } } /** * Handle enhance button click */ async handleEnhanceClick() { if (!this.elements.enhanceBtn) return; const enhanceBtn = this.elements.enhanceBtn; const siteId = window.insertrConfig?.siteId || this.options.siteId || 'demo'; try { // Show loading state enhanceBtn.textContent = '⏳ Enhancing...'; enhanceBtn.disabled = true; // Smart server detection for enhance API const isDevelopment = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1'; const enhanceUrl = isDevelopment ? `http://localhost:8080/api/enhance?site_id=${siteId}` : `/api/enhance?site_id=${siteId}`; // Call enhance API const response = await fetch(enhanceUrl, { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.auth?.getCurrentUser()?.token || 'mock-token'}` } }); if (!response.ok) { throw new Error(`Enhancement failed: ${response.status} ${response.statusText}`); } const result = await response.json(); console.log('✅ Files enhanced successfully:', result); // Show success state briefly enhanceBtn.textContent = '✅ Enhanced!'; // Reset button after success setTimeout(() => { enhanceBtn.textContent = '🔄 Enhance'; enhanceBtn.disabled = false; }, 2000); } catch (error) { console.error('❌ Enhancement failed:', error); enhanceBtn.textContent = '❌ Failed'; // Reset button after error setTimeout(() => { enhanceBtn.textContent = '🔄 Enhance'; enhanceBtn.disabled = false; }, 2000); } } /** * Update all visual elements based on current state */ updateVisualState() { if (!this.isInitialized || !this.elements.statusText) return; const isAuthenticated = this.auth ? this.auth.isAuthenticated() : false; const isEditMode = this.auth ? this.auth.isEditMode() : false; // Update status indicator this.updateStatusIndicator(isAuthenticated, isEditMode); // Update button states this.updateButtonStates(isAuthenticated, isEditMode); // Update body classes for global styling this.updateBodyClasses(isAuthenticated, isEditMode); } /** * Update status indicator text and visual state */ updateStatusIndicator(isAuthenticated, isEditMode) { const { statusText, statusDot } = this.elements; if (!statusText || !statusDot) return; if (!isAuthenticated) { statusText.textContent = 'Visitor Mode'; statusDot.className = 'insertr-status-dot insertr-status-visitor'; } else if (isEditMode) { statusText.textContent = 'Editing'; statusDot.className = 'insertr-status-dot insertr-status-editing'; } else { statusText.textContent = 'Authenticated'; statusDot.className = 'insertr-status-dot insertr-status-authenticated'; } } /** * Update button text, visibility, and states */ updateButtonStates(isAuthenticated, isEditMode) { const { authToggle, editToggle, enhanceBtn } = this.elements; // Update auth toggle button if (authToggle) { authToggle.textContent = isAuthenticated ? 'Logout' : 'Login as Client'; authToggle.className = `insertr-action-btn insertr-auth-btn ${ isAuthenticated ? 'insertr-authenticated' : '' }`; } // Update edit mode toggle button if (editToggle) { editToggle.style.display = isAuthenticated ? 'inline-block' : 'none'; editToggle.textContent = `Edit Mode: ${isEditMode ? 'On' : 'Off'}`; editToggle.className = `insertr-action-btn insertr-edit-btn ${ isEditMode ? 'insertr-edit-active' : '' }`; } // Update enhance button (dev-mode only) if (enhanceBtn) { enhanceBtn.style.display = isAuthenticated ? 'inline-block' : 'none'; } } /** * Update body CSS classes for global styling hooks */ updateBodyClasses(isAuthenticated, isEditMode) { document.body.classList.toggle('insertr-authenticated', isAuthenticated); document.body.classList.toggle('insertr-edit-mode', isEditMode); } /** * Add editing indicators to content elements */ addEditingIndicators() { if (!this.editor || !this.editor.core) return; const elements = this.editor.core.getAllElements(); console.log(`🎨 Adding editing indicators to ${elements.length} elements`); elements.forEach(meta => { this.initializeElementVisuals(meta.element); }); } /** * Initialize visual editing indicators for a single element */ initializeElementVisuals(element) { // Add visual indicators element.style.cursor = 'pointer'; element.style.position = 'relative'; // Add hover effects element.addEventListener('mouseenter', () => { if (this.auth && this.auth.isAuthenticated() && this.auth.isEditMode()) { element.classList.add('insertr-editing-hover'); } }); element.addEventListener('mouseleave', () => { element.classList.remove('insertr-editing-hover'); }); } /** * Remove editing indicators (when edit mode is disabled) */ removeEditingIndicators() { const elements = document.querySelectorAll('.insertr-editing-hover'); elements.forEach(element => { element.classList.remove('insertr-editing-hover'); }); } /** * Show status message to user */ showStatusMessage(message, type = 'info', duration = 3000) { // Remove existing status message const existing = document.getElementById('insertr-status-message'); if (existing) { existing.remove(); } const messageHtml = `

${message}

`; document.body.insertAdjacentHTML('beforeend', messageHtml); // Auto-remove after duration setTimeout(() => { const messageEl = document.getElementById('insertr-status-message'); if (messageEl) { messageEl.remove(); } }, duration); } /** * Destroy the control panel (cleanup) */ destroy() { if (this.elements.controlPanel) { this.elements.controlPanel.remove(); } this.elements = {}; this.isInitialized = false; // Remove body classes document.body.classList.remove('insertr-authenticated', 'insertr-edit-mode'); console.log('🗑️ Control panel destroyed'); } }