The hubspot code inserts 2 js files into the <head>
and injects some inline stylesheets into the <body>
- one of the js files (conversations-embed.js) creates a div with the id #hubspot-messages-iframe-container
. As its name suggests, it contains an iframe with the chat window. It also adds a bunch of css to the body.
The main problem here is that Turbolinks replaces everything in the <body>
per page change, leaving the hubspot script unaware of the fact that a page has been changed. Since everything is replaced, the div injected by the script and the css disappears.
My first try was to clone the chat container div into a window variable, and use appendChild(clonedNode)
to the event.data.newBody
element within the turbolinks:before-render
event. While this kinda works, it isn't very elegant. It disappears and reappears each time you change a page. Also, the state was not carried over so if I closed the window it would be open at the next page and so on.
What does work is to move the #hubspot-messages-iframe-container
out of the body into the html tag itself, leaving it out of harms way from turbolinks. It's state is kept (open, closed, etc...) and does not blink or have any side effects. Remember that you have to manually remove it from the pages you may not want it on.
I know it's a bit hacky, but it works and until they have some sort of api to reinitialse the chat window this is a workaround:
document.addEventListener("turbolinks:load", function() {
let targetNode = document.body
let config = { childList: true }
let callback = function() {
if (document.body.querySelector('#hubspot-messages-iframe-container')) {
document.documentElement.appendChild(
document.getElementById('hubspot-messages-iframe-container')
)
observer.disconnect()
}
}
let observer = new MutationObserver(callback)
if (!document.querySelector("html > #hubspot-messages-iframe-container")) {
observer.observe(targetNode, config)
}
})
You will also need to copy the style injected into the body, since Turbolinks will also replace this. This is what I ended up with (converted to Sass):
html.hs-messages-widget-open.hs-messages-mobile
height: 100% !important
overflow: hidden !important
position: relative !important
body
height: 100% !important
overflow: hidden !important
position: relative !important
margin: 0 !important
#hubspot-messages-iframe-container
display: initial !important
z-index: 2147483647
position: fixed !important
bottom: 0 !important
right: 0 !important
&.internal
z-index: 1016
iframe
min-width: 108px
.shadow
display: initial !important
z-index: -1
position: absolute
width: 0
height: 0
bottom: 0
right: 0
content: ""
&.internal
display: none !important
&.active
width: 400px
height: 400px
background: radial-gradient(ellipse at bottom right, rgba(29, 39, 54, 0.16) 0, rgba(29, 39, 54, 0) 72%)
iframe
display: initial !important
width: 100% !important
height: 100% !important
border: none !important
position: absolute !important
bottom: 0 !important
right: 0 !important
background: transparent !important