diff --git a/web/public/embed.js b/web/public/embed.js index 0111ce8c31a2c9..8f13a7178c055a 100644 --- a/web/public/embed.js +++ b/web/public/embed.js @@ -14,17 +14,18 @@ const config = window[configKey]; // SVG icons for open and close states - const svgIcons = { - open: ` + const svgIcons = ` - `, - close: ` + + ` - }; + + `; // Main function to embed the chatbot async function embedChatbot() { + let isDragging = false + if (!config || !config.token) { console.error(`${configKey} is empty or token is not provided`); return; @@ -33,7 +34,9 @@ async function compressAndEncodeBase64(input) { const uint8Array = new TextEncoder().encode(input); const compressedStream = new Response( - new Blob([uint8Array]).stream().pipeThrough(new CompressionStream('gzip')) + new Blob([uint8Array]) + .stream() + .pipeThrough(new CompressionStream("gzip")) ).arrayBuffer(); const compressedUint8Array = new Uint8Array(await compressedStream); return btoa(String.fromCharCode(...compressedUint8Array)); @@ -112,33 +115,30 @@ // Function to reset the iframe position function resetIframePosition() { - if (window.innerWidth <= 640) - return + if (window.innerWidth <= 640) return; const targetIframe = document.getElementById(iframeId); const targetButton = document.getElementById(buttonId); if (targetIframe && targetButton) { const buttonRect = targetButton.getBoundingClientRect(); - const buttonInBottom = buttonRect.top - 5 > targetIframe.clientHeight + const buttonInBottom = buttonRect.top - 5 > targetIframe.clientHeight; if (buttonInBottom) { - targetIframe.style.bottom = '0px'; - targetIframe.style.top = 'unset'; - } - else { - targetIframe.style.bottom = 'unset'; - targetIframe.style.top = '0px'; + targetIframe.style.bottom = "0px"; + targetIframe.style.top = "unset"; + } else { + targetIframe.style.bottom = "unset"; + targetIframe.style.top = "0px"; } const buttonInRight = buttonRect.right > targetIframe.clientWidth; if (buttonInRight) { - targetIframe.style.right = '0'; - targetIframe.style.left = 'unset'; - } - else { - targetIframe.style.right = 'unset'; + targetIframe.style.right = "0"; + targetIframe.style.left = "unset"; + } else { + targetIframe.style.right = "unset"; targetIframe.style.left = 0; } } @@ -193,33 +193,41 @@ const displayDiv = document.createElement("div"); displayDiv.style.cssText = "position: relative; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;"; - displayDiv.innerHTML = svgIcons.open; + displayDiv.innerHTML = svgIcons; containerDiv.appendChild(displayDiv); document.body.appendChild(containerDiv); // Add click event listener to toggle chatbot - containerDiv.addEventListener("click", function () { + containerDiv.addEventListener("click", handleClick); + // Add touch event listener + containerDiv.addEventListener("touchend", handleClick); + + function handleClick() { + if (isDragging) return; + const targetIframe = document.getElementById(iframeId); if (!targetIframe) { - containerDiv.prepend(createIframe()); + containerDiv.appendChild(createIframe()); resetIframePosition(); this.title = "Exit (ESC)"; - displayDiv.innerHTML = svgIcons.close; - document.addEventListener('keydown', handleEscKey); + setSvgIcon("close"); + document.addEventListener("keydown", handleEscKey); return; } - targetIframe.style.display = targetIframe.style.display === "none" ? "block" : "none"; - displayDiv.innerHTML = targetIframe.style.display === "none" ? svgIcons.open : svgIcons.close; + targetIframe.style.display = + targetIframe.style.display === "none" ? "block" : "none"; + targetIframe.style.display === "none" + ? setSvgIcon("open") + : setSvgIcon("close"); if (targetIframe.style.display === "none") { - document.removeEventListener('keydown', handleEscKey); + document.removeEventListener("keydown", handleEscKey); } else { - document.addEventListener('keydown', handleEscKey); + document.addEventListener("keydown", handleEscKey); } - resetIframePosition(); - }); + } // Enable dragging if specified in config if (config.draggable) { @@ -229,20 +237,39 @@ // Function to enable dragging of the chat button function enableDragging(element, axis) { - let isDragging = false; - let startX, startY; + let startX, startY, startClientX, startClientY; element.addEventListener("mousedown", startDragging); - document.addEventListener("mousemove", drag); - document.addEventListener("mouseup", stopDragging); + element.addEventListener("touchstart", startDragging); function startDragging(e) { - isDragging = true; - startX = e.clientX - element.offsetLeft; - startY = e.clientY - element.offsetTop; + isDragging = false; + if (e.type === "touchstart") { + startX = e.touches[0].clientX - element.offsetLeft; + startY = e.touches[0].clientY - element.offsetTop; + startClientX = e.touches[0].clientX; + startClientY = e.touches[0].clientY; + } else { + startX = e.clientX - element.offsetLeft; + startY = e.clientY - element.offsetTop; + } + document.addEventListener("mousemove", drag); + document.addEventListener("touchmove", drag, { passive: false }); + document.addEventListener("mouseup", stopDragging); + document.addEventListener("touchend", stopDragging); + e.preventDefault(); } function drag(e) { + const touch = e.type === "touchmove" ? e.touches[0] : e; + const deltaX = touch.clientX - startClientX; + const deltaY = touch.clientY - startClientY; + + // Determine whether it is a drag operation + if (Math.abs(deltaX) > 8 || Math.abs(deltaY) > 8) { + isDragging = true; + } + if (!isDragging) return; element.style.transition = "none"; @@ -252,11 +279,17 @@ const targetIframe = document.getElementById(iframeId); if (targetIframe) { targetIframe.style.display = "none"; - element.querySelector("div").innerHTML = svgIcons.open; + setSvgIcon("open"); } - const newLeft = e.clientX - startX; - const newBottom = window.innerHeight - e.clientY - startY; + let newLeft, newBottom; + if (e.type === "touchmove") { + newLeft = e.touches[0].clientX - startX; + newBottom = window.innerHeight - e.touches[0].clientY - startY; + } else { + newLeft = e.clientX - startX; + newBottom = window.innerHeight - e.clientY - startY; + } const elementRect = element.getBoundingClientRect(); const maxX = window.innerWidth - elementRect.width; @@ -279,9 +312,16 @@ } function stopDragging() { - isDragging = false; + setTimeout(() => { + isDragging = false; + }, 0); element.style.transition = ""; element.style.cursor = "pointer"; + + document.removeEventListener("mousemove", drag); + document.removeEventListener("touchmove", drag); + document.removeEventListener("mouseup", stopDragging); + document.removeEventListener("touchend", stopDragging); } } @@ -291,18 +331,27 @@ } } + function setSvgIcon(type = "open") { + if (type === "open") { + document.getElementById("openIcon").style.display = "block"; + document.getElementById("closeIcon").style.display = "none"; + } else { + document.getElementById("openIcon").style.display = "none"; + document.getElementById("closeIcon").style.display = "block"; + } + } + // Add esc Exit keyboard event triggered function handleEscKey(event) { - if (event.key === 'Escape') { + if (event.key === "Escape") { const targetIframe = document.getElementById(iframeId); - const button = document.getElementById(buttonId); - if (targetIframe && targetIframe.style.display !== 'none') { - targetIframe.style.display = 'none'; - button.querySelector('div').innerHTML = svgIcons.open; + if (targetIframe && targetIframe.style.display !== "none") { + targetIframe.style.display = "none"; + setSvgIcon("open"); } } } - document.addEventListener('keydown', handleEscKey); + document.addEventListener("keydown", handleEscKey); // Set the embedChatbot function to run when the body is loaded,Avoid infinite nesting if (config?.dynamicScript) { @@ -310,4 +359,4 @@ } else { document.body.onload = embedChatbot; } -})(); \ No newline at end of file +})(); diff --git a/web/public/embed.min.js b/web/public/embed.min.js index 728f74bfd7dd69..13837183c0e1cc 100644 --- a/web/public/embed.min.js +++ b/web/public/embed.min.js @@ -1,8 +1,4 @@ -(()=>{let t="difyChatbotConfig",a="dify-chatbot-bubble-button",c="dify-chatbot-bubble-window",p=window[t],u={open:` - - `,close:` - - `};async function e(){if(p&&p.token){var e=new URLSearchParams({...await(async()=>{var e=p?.inputs||{};let n={};return await Promise.all(Object.entries(e).map(async([e,t])=>{n[e]=await o(t)})),n})(),...await(async()=>{var e=p?.systemVariables||{};let n={};return await Promise.all(Object.entries(e).map(async([e,t])=>{n["sys."+e]=await o(t)})),n})()});let t=`${p.baseUrl||`https://${p.isDev?"dev.":""}udify.app`}/chatbot/${p.token}?`+e;e=i();async function o(e){e=(new TextEncoder).encode(e),e=new Response(new Blob([e]).stream().pipeThrough(new CompressionStream("gzip"))).arrayBuffer(),e=new Uint8Array(await e);return btoa(String.fromCharCode(...e))}function i(){var e=document.createElement("iframe");return e.allow="fullscreen;microphone",e.title="dify chatbot bubble window",e.id=c,e.src=t,e.style.cssText=` +(()=>{let t="difyChatbotConfig",m="dify-chatbot-bubble-button",h="dify-chatbot-bubble-window",p=window[t];async function e(){let u=!1;if(p&&p.token){var e=new URLSearchParams({...await(async()=>{var e=p?.inputs||{};let n={};return await Promise.all(Object.entries(e).map(async([e,t])=>{n[e]=await o(t)})),n})(),...await(async()=>{var e=p?.systemVariables||{};let n={};return await Promise.all(Object.entries(e).map(async([e,t])=>{n["sys."+e]=await o(t)})),n})()});let t=`${p.baseUrl||`https://${p.isDev?"dev.":""}udify.app`}/chatbot/${p.token}?`+e;e=s();async function o(e){e=(new TextEncoder).encode(e),e=new Response(new Blob([e]).stream().pipeThrough(new CompressionStream("gzip"))).arrayBuffer(),e=new Uint8Array(await e);return btoa(String.fromCharCode(...e))}function s(){var e=document.createElement("iframe");return e.allow="fullscreen;microphone",e.title="dify chatbot bubble window",e.id=h,e.src=t,e.style.cssText=` position: absolute; display: flex; flex-direction: column; @@ -18,7 +14,7 @@ z-index: 2147483640; overflow: hidden; user-select: none; - `,e}function r(){var e,t;window.innerWidth<=640||(e=document.getElementById(c),t=document.getElementById(a),e&&t&&((t=t.getBoundingClientRect()).top-5>e.clientHeight?(e.style.bottom="0px",e.style.top="unset"):(e.style.bottom="unset",e.style.top="0px"),t.right>e.clientWidth?(e.style.right="0",e.style.left="unset"):(e.style.right="unset",e.style.left=0)))}function n(){let n=document.createElement("div");Object.entries(p.containerProps||{}).forEach(([e,t])=>{"className"===e?n.classList.add(...t.split(" ")):"style"===e?"object"==typeof t?Object.assign(n.style,t):n.style.cssText=t:"function"==typeof t?n.addEventListener(e.replace(/^on/,"").toLowerCase(),t):n[e]=t}),n.id=a;var e=document.createElement("style");document.head.appendChild(e),e.sheet.insertRule(` + `,e}function d(){var e,t;window.innerWidth<=640||(e=document.getElementById(h),t=document.getElementById(m),e&&t&&((t=t.getBoundingClientRect()).top-5>e.clientHeight?(e.style.bottom="0px",e.style.top="unset"):(e.style.bottom="unset",e.style.top="0px"),t.right>e.clientWidth?(e.style.right="0",e.style.left="unset"):(e.style.right="unset",e.style.left=0)))}function n(){let n=document.createElement("div");Object.entries(p.containerProps||{}).forEach(([e,t])=>{"className"===e?n.classList.add(...t.split(" ")):"style"===e?"object"==typeof t?Object.assign(n.style,t):n.style.cssText=t:"function"==typeof t?n.addEventListener(e.replace(/^on/,"").toLowerCase(),t):n[e]=t}),n.id=m;var e=document.createElement("style"),e=(document.head.appendChild(e),e.sheet.insertRule(` #${n.id} { position: fixed; bottom: var(--${n.id}-bottom, 1rem); @@ -33,4 +29,10 @@ cursor: pointer; z-index: 2147483647; } - `);let t=document.createElement("div");if(t.style.cssText="position: relative; display: flex; align-items: center; justify-content: center; width: 100%; height: 100%; z-index: 2147483647;",t.innerHTML=u.open,n.appendChild(t),document.body.appendChild(n),n.addEventListener("click",function(){var e=document.getElementById(c);e?(e.style.display="none"===e.style.display?"block":"none",t.innerHTML="none"===e.style.display?u.open:u.close,"none"===e.style.display?document.removeEventListener("keydown",d):document.addEventListener("keydown",d),r()):(n.prepend(i()),r(),this.title="Exit (ESC)",t.innerHTML=u.close,document.addEventListener("keydown",d))}),p.draggable){var s=n;var l=p.dragAxis||"both";let i=!1,r,d;s.addEventListener("mousedown",function(e){i=!0,r=e.clientX-s.offsetLeft,d=e.clientY-s.offsetTop}),document.addEventListener("mousemove",function(e){var t,n,o;i&&(s.style.transition="none",s.style.cursor="grabbing",(t=document.getElementById(c))&&(t.style.display="none",s.querySelector("div").innerHTML=u.open),t=e.clientX-r,e=window.innerHeight-e.clientY-d,o=s.getBoundingClientRect(),n=window.innerWidth-o.width,o=window.innerHeight-o.height,"x"!==l&&"both"!==l||s.style.setProperty(`--${a}-left`,Math.max(0,Math.min(t,n))+"px"),"y"!==l&&"both"!==l||s.style.setProperty(`--${a}-bottom`,Math.max(0,Math.min(e,o))+"px"))}),document.addEventListener("mouseup",function(){i=!1,s.style.transition="",s.style.cursor="pointer"})}}e.style.display="none",document.body.appendChild(e),2048 + + + + `,n.appendChild(e),document.body.appendChild(n),n.addEventListener("click",t),n.addEventListener("touchend",t),p.draggable){var r=n;var a=p.dragAxis||"both";let s,d,t,l;function o(e){u=!1,"touchstart"===e.type?(s=e.touches[0].clientX-r.offsetLeft,d=e.touches[0].clientY-r.offsetTop,t=e.touches[0].clientX,l=e.touches[0].clientY):(s=e.clientX-r.offsetLeft,d=e.clientY-r.offsetTop),document.addEventListener("mousemove",i),document.addEventListener("touchmove",i,{passive:!1}),document.addEventListener("mouseup",c),document.addEventListener("touchend",c),e.preventDefault()}function i(n){var o="touchmove"===n.type?n.touches[0]:n,i=o.clientX-t,o=o.clientY-l;if(u=8{u=!1},0),r.style.transition="",r.style.cursor="pointer",document.removeEventListener("mousemove",i),document.removeEventListener("touchmove",i),document.removeEventListener("mouseup",c),document.removeEventListener("touchend",c)}r.addEventListener("mousedown",o),r.addEventListener("touchstart",o)}}e.style.display="none",document.body.appendChild(e),2048