/** * AI Assistant — Offcanvas panel with Help, Suggest, and Admin tabs * Supports: tool status indicators, link rendering, quick-reply buttons, conversation history */ (function() { 'use strict'; var panel = null; var offcanvasInstance = null; var currentTab = 'help'; var isStreaming = false; var abortController = null; // Conversation history per tab var conversationHistory = { help: [], admin: [] }; // Build the offcanvas panel HTML function buildPanel() { if (document.getElementById('aiAssistantPanel')) return; var isAdmin = document.body.getAttribute('data-is-admin') === 'true'; var html = '
' + escapeHtml(data.message) + '
' + '' + 'Submit an improvement suggestion for this page. It will be sent to the admin.
' + '' + '' + '' + code.trim() + '';
});
// Inline code
html = html.replace(/`([^`]+)`/g, '$1');
// Bold
html = html.replace(/\*\*(.+?)\*\*/g, '$1');
// Italic
html = html.replace(/\*(.+?)\*/g, '$1');
// Links [text](url)
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '$1');
// Auto-link URLs that aren't already in anchors
html = html.replace(/(^|[^"=])(https?:\/\/[^\s<]+)/g, '$1$2');
// Headers
html = html.replace(/^### (.+)$/gm, ''); html = '
' + html + '
'; // Clean up empty paragraphs html = html.replace(/\s*<\/p>/g, ''); // Don't wrap block elements in p tags html = html.replace(/
(<(?:pre|ul|ol|h[1-3]|div)[\s>])/g, '$1');
html = html.replace(/(<\/(?:pre|ul|ol|h[1-3]|div)>)<\/p>/g, '$1');
// Single newlines → br (within paragraphs)
html = html.replace(/([^>])\n([^<])/g, '$1
$2');
return html;
}
})();