const backStyle = {'border': 'none', 'borderRadius': '2rem', 'display': 'flex', 'height': '200px', 'inset': 'auto 1.05rem 5rem auto', 'maxHeight': '100%', 'maxWidth': '100vm', 'mobile': {'inset': 'auto 1rem 3rem auto'}, 'position': 'fixed', 'smInset': 'auto 1rem 3rem auto', 'transition': 'all 0.3s ease-out', 'width': '480px', 'zIndex': '99999'}; const config = { token: "eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAicGlyZWxseTM2MEBhcHBzcG90LmdzZXJ2aWNlYWNjb3VudC5jb20iLCAic3ViIjogInBpcmVsbHkzNjBAYXBwc3BvdC5nc2VydmljZWFjY291bnQuY29tIiwgImF1ZCI6ICJodHRwczovL2lkZW50aXR5dG9vbGtpdC5nb29nbGVhcGlzLmNvbS9nb29nbGUuaWRlbnRpdHkuaWRlbnRpdHl0b29sa2l0LnYxLklkZW50aXR5VG9vbGtpdCIsICJ1aWQiOiAiZTRhMTgwY2UtYjFmZC00ZmRhLTk1NWEtY2UwOTNiNzY1ZDQ2IiwgImlhdCI6IDE3NTI3NjUyNzQsICJleHAiOiAxNzUyNzY4ODc0LCAiY2xhaW1zIjogeyJjb252SUQiOiAiOTkxMWViNGEzYmI0YTU3YTJiMjAiLCAiY3VzSUQiOiAiMDNlOTFmMjBhYmU5NDFlNDJiMWU2IiwgImRlYWxlclVSTCI6ICJodHRwczovL2J1ZGdldG5vcndhbGsuY29tLyIsICJkZWFsZXJOYW1lIjogIkJ1ZGdldCBDYXIgU2FsZXMgb2YgTm9yd2FsayIsICJBSU5hbWUiOiAiRWQgTWlsbGVyIiwgImlzT3BlbiI6IHRydWUsICJ1aWQiOiAiSGpMVHo3aWVLQ2ZvZXNublloQ1lObEJSTjVoMiIsICJwaWNOdW0iOiA3fX0.CtDe5kW_j62r0uXBVjqOrcLwmdDgxk8xzIIO5IulSTBU4DrBLfSEPEmUze-r1o4DrjSKWbfoYmNrVlqWexgd0PUtMvjUVwuYtr1EPIDFjkDCZO0uXcB5dgv_OR_jBvINWV0Bivef_ACLffct0w_OImxSZmnI7t05VaspfV_ZmbTBI7H1d6cNUC72gr9r8-U5-xrFC9FNG8o6oIwrtZ3Vnh0PBXY4ECbgIlKWDy2M-xEoSRVFdYnH-a_wvPFQnZlyd7jZgR4trxK_hteYW1kWJBgJt7mkTZGGEeaNvJRuzl5w4IGQ90vjLRw9zbO4Z0GugU0GMzn2ms4sGLfbPXGvlw", url: "https://salesagent-widget.web.app/", iframeId: 'salesAgent-widget-iframe', cookieFreeMode: true, allowedOrigins: [ "https://salesagent-widget.web.app/", "https://budgetnorwalk.com/", ], styles: backStyle, attributes: { 'data-termly-embed': 'essential' }, }; const createIframe = () => { const iframe = document.createElement('iframe'); // Apply attributes with security enhancements Object.entries({ ...config.attributes, 'data-termly-origin': window.location.origin, 'data-termly-domain': window.location.hostname }).forEach(([key, value]) => { iframe.setAttribute(key, value); }); // Secure URL construction with encoded parameters const params = new URLSearchParams({ token: encodeURIComponent(config.token), width: window.innerWidth, height: window.innerHeight, origin: encodeURIComponent(window.location.origin), parentDomain: encodeURIComponent(window.location.hostname), termlyEmbed: 'essential', _: Date.now() // Cache buster }); iframe.src = `${config.url}?${params}`; iframe.id = config.iframeId; iframe.name = 'salesAgentWidget'; iframe.loading = 'eager'; // Apply styles with responsive defaults Object.assign(iframe.style, { position: 'fixed', border: 'none', zIndex: '999999', ...config.styles, // Responsive fallbacks maxWidth: '100vw', maxHeight: '100vh' }); return iframe; }; // Enhanced message handler with origin validation function createMessageHandler(iframeId) { const script = document.createElement('script'); script.innerHTML = ` (function() { const salesAgentWidgetIframe = document.getElementById("${iframeId}"); const allowedOrigins = ${JSON.stringify(config.allowedOrigins.map(o => o.replace(/\/$/, '')))}; // Termly override if needed if (window.TERMLY_CUSTOM_BLOCKING_MAP) { window.TERMLY_CUSTOM_BLOCKING_MAP["${config.url.split('?')[0]}"] = "essential"; } window.addEventListener("message", function(event) { try { // Validate origin // const originMatches = allowedOrigins.some(allowed => // event.origin === allowed || // event.origin === window.location.origin // ); // if (!originMatches) return; const { width, height, isChatOpen, type } = event.data; // Handle resize messages if (type === 'WIDGET_RESIZE') { salesAgentWidgetIframe.style.inset = isChatOpen ? "auto 0 0 auto" : window.innerWidth < 640 ? "${config.styles.mobile?.inset || 'auto 0 0 auto'}" : "${config.styles.inset}"; salesAgentWidgetIframe.style.borderRadius = isChatOpen ? '2rem 2rem 0 2rem' : '0'; salesAgentWidgetIframe.style.width = width; salesAgentWidgetIframe.style.height = height; } // Handle Termly-specific messages if (type === 'TERMLY_STATUS') { console.log('Termly status:', event.data.status); } } catch(e) { console.warn('Widget message error:', e); } }); })(); `; return script; } // Enhanced route change detection function listenForRouteChanges(iframe) { let currentUrl = window.location.href; const observer = new MutationObserver(() => { if (window.location.href !== currentUrl) { currentUrl = window.location.href; safePostMessage(iframe, { type: 'ROUTE_CHANGE', url: currentUrl }); } }); observer.observe(document, { subtree: true, childList: true, attributes: true }); } // Safe message posting with fallback function safePostMessage(iframe, message) { try { if (iframe.contentWindow) { config.allowedOrigins.forEach(origin => { iframe.contentWindow.postMessage(message, origin); }); } } catch(e) { console.warn('PostMessage failed:', e); } } // Initialization with error handling const init = () => { try { const iframe = createIframe(); document.body.appendChild(iframe); const messageHandler = createMessageHandler(config.iframeId); document.head.appendChild(messageHandler); // Better than body listenForRouteChanges(iframe); // Fallback for Termly blocking setTimeout(() => { if (!iframe.contentWindow) { console.warn('Iframe may be blocked by Termly'); safePostMessage(iframe, { type: 'TERMLY_CHECK' }); } }, 2000); } catch(e) { console.error('Widget initialization failed:', e); } }; // Modern initialization if (document.readyState !== 'loading') { init(); } else { document.addEventListener('DOMContentLoaded', init, { once: true }); } // Handle potential Termly blocking window.addEventListener('message', (event) => { if (event.data?.type === 'TERMLY_BLOCKED') { console.warn('Termly blocked iframe loading'); // Implement fallback UI here if needed } });