1// Dynamisch marked.js inladen 2(function() { 3 const script = document.createElement('script'); 4 script.src = "https://cdn.jsdelivr.net/npm/marked/marked.min.js"; 5 script.onload = function() { 6 console.log('â marked.js geladen'); 7 }; 8 document.head.appendChild(script); 9})(); 10 11jQuery(function($) { 12 // Helper: laad/sla messages (JSON) op in localStorage 13 function loadMessages() { 14 try { return JSON.parse(localStorage.getItem('chatMsgs') || '[]'); } 15 catch(e){ return []; } 16 } 17 function saveMessages(arr) { 18 localStorage.setItem('chatMsgs', JSON.stringify(arr)); 19 } 20 21 // Conversation ID aanmaken (1x) en bewaren 22 let conversationId = localStorage.getItem('conversationId'); 23 if (!conversationId) { 24 conversationId = (crypto && crypto.randomUUID) ? crypto.randomUUID() : 25 'conv_' + Math.random().toString(36).slice(2) + Date.now(); 26 localStorage.setItem('conversationId', conversationId); 27 } 28 29 // Herstel chat HTML (optioneel, puur voor weergave) 30 if (localStorage.getItem('chatHistory')) { 31 $('#chat-messages').html(localStorage.getItem('chatHistory')); 32 } 33 34 // ENTER verzendt bericht, SHIFT+ENTER nieuwe regel 35 $('#chat-input').on('keydown', function(e) { 36 if (e.key === 'Enter' && !e.shiftKey) { 37 e.preventDefault(); 38 $('#chat-form').submit(); 39 } 40 }); 41 42 $('#chat-form').on('submit', function(e) { 43 e.preventDefault(); 44 45 const msg = $('#chat-input').val().trim(); 46 if (!msg) return; 47 48 // 1) Toon het gebruikersbericht in de UI 49 $('#chat-messages').append(`<div class="chat-user">${msg}</div>`); 50 $('#chat-input').val(''); 51 52 // 2) Update de messages-array (voor Chatbase) 53 const messages = loadMessages(); 54 messages.push({ role: 'user', content: msg }); 55 saveMessages(messages); 56 57 // 3) Loader 58 $('#chat-messages').append(` 59 <div class="chat-bot-wrapper loading-bubble"> 60 <div class="chat-bot loader"> 61 <span class="dot"></span><span class="dot"></span><span class="dot"></span> 62 </div> 63 </div> 64 `); 65 $('#chat-messages').scrollTop($('#chat-messages')[0].scrollHeight); 66 67 // 4) Verstuur ALLES naar de server 68 $.post(flexhub_chatbot_ajax.ajax_url, { 69 action: 'flexhub_chatbot_message', 70 nonce: flexhub_chatbot_ajax.chatbot_nonce, 71 conversationId: conversationId, 72 messages: JSON.stringify(messages) // stuur de hele history mee 73 }, function(response) { 74 // Verwijder loader 75 $('.loading-bubble').remove(); 76 77 if (response && response.success) { 78 // Chatbase kan { text: "...", sources: [...] } teruggeven 79 const botText = (typeof response.data === 'object' && response.data !== null) 80 ? (response.data.text || '') 81 : (response.data || ''); 82 83 // 5) Toon antwoord 84 $('#chat-messages').append(` 85 <div class="chat-bot"> 86 <div class="editor"> 87 <img src="https://flexhub.nl/wp-content/uploads/2025/07/Beeldmerk_roze_RGB.svg" width="25" style="margin-right:5px;">Flexhub 88 </div> 89 ${marked.parse(botText)} 90 </div> 91 `); 92 93 // 6) Voeg assistent-bericht toe aan messages-array en sla op 94 const updated = loadMessages(); 95 updated.push({ role: 'assistant', content: botText }); 96 saveMessages(updated); 97 } else { 98 $('#chat-messages').append(`<div class="chat-bot error">Er ging iets mis...</div>`); 99 } 100 101 // Scroll + HTML-history bewaren (alleen voor UI) 102 $('#chat-messages').scrollTop($('#chat-messages')[0].scrollHeight); 103 localStorage.setItem('chatHistory', $('#chat-messages').html()); 104 }).fail(function() { 105 $('.loading-bubble').remove(); 106 $('#chat-messages').append(`<div class="chat-bot error">Er ging iets mis met de verbinding...</div>`); 107 }); 108 }); 109 110 // ========================= 111 // Toggle + icoon wisselen + promo-balk verbergen t/m einde van vandaag 112 // ========================= 113 const $btn = $('#chatbot-toggle'); 114 const $box = $('#chatbot-box');
115 const $promo = $('.chatbox-toggle-header'); // paarse tekstbalk 116 117 // === Cookie helpers === 118 function setCookieSeconds(name, value, seconds, domain) { 119 const attrs = [`path=/`, `max-age=${Math.max(0, seconds|0)}`]; 120 if (domain) attrs.push(`domain=${domain}`); 121 document.cookie = `${name}=${encodeURIComponent(value)}; ${attrs.join('; ')}`; 122 } 123 function getCookie(name) { 124 const nameEQ = name + "="; 125 const ca = document.cookie.split(';'); 126 for (let c of ca) { 127 while (c.charAt(0) === ' ') c = c.substring(1); 128 if (c.indexOf(nameEQ) === 0) return decodeURIComponent(c.substring(nameEQ.length)); 129 } 130 return null; 131 } 132 133 // Config 134 const PROMO_KEY = 'chatPromoHidden'; 135 const PROMO_DOMAIN = '.flexhub.nl'; // leeg laten als je het tot 1 host wilt beperken 136 137 function secondsUntilEndOfToday() { 138 const now = new Date(); 139 const end = new Date(now); 140 end.setHours(23, 59, 59, 999); 141 return Math.max(1, Math.floor((end - now) / 1000)); 142 } 143 144 // Bij laden: als cookie bestaat (waarde '1'), direct verbergen 145 if (getCookie(PROMO_KEY) === '1') { 146 $promo.addClass('hidden').hide(); 147 } 148 149 // Zorg dat er een <img> in de knop zit (zoals in je markup) 150 let $img = $btn.find('img').first(); 151 if ($img.length === 0) { 152 $img = $('<img>', { width: 30, alt: 'Open chat' }).appendTo($btn); 153 } 154 155 // Iconen 156 const BOT_ICON = 'https://flexhub.nl/wp-content/uploads/2025/08/bot.png'; 157 const CLOSE_ICON = "data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M18 6L6 18M6 6l12 12' stroke='white' stroke-width='2' stroke-linecap='round'/%3E%3C/svg%3E"; 158 159 // Promo-balk verbergen tot einde van vandaag 160 function hidePromoUntilEOD() { 161 if (!$promo.length) return; 162 const ttl = secondsUntilEndOfToday(); 163 setCookieSeconds(PROMO_KEY, '1', ttl, PROMO_DOMAIN); // verloopt om 23:59:59 164 try { localStorage.setItem(PROMO_KEY, '1'); } catch(e) {} // optioneel voor anti-flash 165 $promo.stop(true, true).fadeOut(50, function() { 166 $promo.addClass('hidden'); 167 }); 168 } 169 170 function setState(open) { 171 if (open) { 172 $box.removeClass('hidden'); 173 $btn.attr({ 'aria-expanded': 'true', 'aria-controls': 'chatbot-box', 'title': 'Sluit chat' }); 174 $img.attr({ src: CLOSE_ICON, alt: 'Sluit chat' }) 175 .css({ width: 20, height: 20, marginTop: 0 }); 176 // Bij openen: verberg promo tot einde van vandaag 177 hidePromoUntilEOD(); 178 } else { 179 $box.addClass('hidden'); 180 $btn.attr({ 'aria-expanded': 'false', 'aria-controls': 'chatbot-box', 'title': 'Open chat' }); 181 $img.attr({ src: BOT_ICON, alt: 'Open chat' }) 182 .css({ width: 30, height: 25, marginTop: -8 }); 183 // Cookie laten verlopen op middernacht; dan verschijnt promo vanzelf weer 184 } 185 } 186 187 // Initiale sync (markup zet .hidden standaard op de box) 188 setState(!$box.hasClass('hidden')); 189 190 // Toggle-handler 191 $(document).off('click', '#chatbot-toggle').on('click', '#chatbot-toggle', function (e) { 192 e.preventDefault(); 193 const open = $btn.attr('aria-expanded') === 'true'; 194 setState(!open); 195 }); 196 197 // Klik op de promo-balk -> verberg tot einde van vandaag (zonder chat te openen) 198 $(document).on('click', '.chatbox-toggle-header', function () { 199 hidePromoUntilEOD(); 200 // Eventueel ook direct chat openen: 201 // setState(true); 202 }); 203});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.