Open ishields opened 5 days ago
Hello, and thank you for the suggestion.
So the Crisp docs are not really affected with this because it's not a SPA, but regular HTML pages.
Do you have any link to your site so we can check this with turbolinks?
Thanks for the quick response. Yes that's totally fair - I was sort of just using it as an example of the behavior. Totally makes sense the doc page is just reloading so of course it's going to behave this way. I haven't deployed the chat widget to my site because of this problem. And since I have a fix I was going to deploy it with it working. Would you like me to temporarily deploy the chat widget with the flashing or would a video suffice? Alternatively I can make a feature toggle that lets you enable the problem on my domain but by default it will work as designed with my hack.
Alternately just create a dummy rails project with turbo so we can fully reproduce
Happy to do that. Would you want me to just send you the zip of the dummy project and you can test locally or you need it deployed somewhere?
Sure. Feel free to send to it baptiste@crisp.chat
Just emailed you the sample project with instructions. Also below is my fix for this issue. As mentioned it's a bit hacky and not something I really want to leave in long term. It messes with the MutationObserver instructor core js constructor in order to gain access to the crisps mutation observer so it can be disabled.
const { Crisp } = require('crisp-sdk-web')
let originalMutationObserver = window.MutationObserver
let listOfObservers = []
// Override Mutation Observer such that whenever a new one is created it checks to see if it's a Crisp one.
window.MutationObserver = (aFunction) => {
let observer = new originalMutationObserver(aFunction)
const stack = new Error().stack
// Only add Crisp observers to the list we care about.
if (stack?.includes('crisp')) {
//console.log('Tracking this crisp observer')
listOfObservers.push(observer)
} else {
//console.log('Not tracking this observer')
}
return observer
}
window.overrideCrispObserver = () => {
const originalMO = window.MutationObserver
// Backup the MutationObserver constructor
window.MutationObserver = function (callback) {
// Create an observer but do not attach it
const observer = new originalMO(callback)
// Save the observer to disable later
originalMutationObserver = observer
return observer
}
}
const disconnectAllObservers = () => {
listOfObservers.forEach((observer) => {
observer.disconnect()
})
}
const reconnectAllObservers = () => {
listOfObservers.forEach((observer) => {
observer.disconnect()
})
}
const onCrispReady = () => {
console.log('Crisp chat widget is rendered and ready!')
// You can add other actions here
moveCrispToPermanentContainer()
preserveScrollOnChatBot()
}
// // This method is fired by crisp when it is initialized and ready
window.CRISP_READY_TRIGGER = onCrispReady
const moveCrispToPermanentContainer = () => {
const crispWidget = document.querySelector('.crisp-client')
const crispWrapper = document.getElementById('crisp-wrapper')
if (crispWidget && crispWrapper && !crispWrapper.contains(crispWidget)) {
// Temporarily disable the MutationObserver
disconnectAllObservers()
// Move the widget to a persistent container
crispWrapper.appendChild(crispWidget)
// Re-enable the MutationObserver
reconnectAllObservers()
// console.log('Crisp widget moved to permanent container and observers reconnected)
}
}
const preserveScrollOnChatBot = () => {
// not including this here. It fixes a scrolling issue also caused by Turbo. Turbo scrolls pages to the top when new pages
//load. Without a fix here it also scrolls the chat window to the beginning of the conversation
}
Crisp.configure('...TODO: Add your token... ')
I'm migrating to Crisp and have been implementing the Chat bot on our website. I thought this would be a quick but I ran into a pretty big incompatibility issue with the popular web frame Ruby on Rails and it's Turbo functionality. The issue I observed was that when clicking around on my website, the Chatbot would disappear for a second and then re-appear.. This occurred when the chatbot was open or closed and didn't look great. The behavior I expected was that the chatbot would stay consistently in view like it does on crisp's main website. I did notice that on Crisps documentation page the same behavior exists (though in this case it's expected because the documentation does full page loads). Below video shows the expected vs the unexpected behavior. Notice on the documentation each click results in the widget disappearing and re-rendering. On the main crisp site this doesn't happen. (video below)
Problem Summary:
Desired long term solution
This should be a simple fix. All we need to be able to do is be able to configure the element that the Crisp chatbot will be placed into. I imagine this will look something like this
We would then add the special ovrride option on that wrapper so that Turbo does not update the element.
My Hacky Solution
Persistent Container (data-turbo-permanent): Wrapping Crisp in a data-turbo-permanent container prevents Turbo from replacing it. However, this doesn’t work directly because Crisp appends itself to
, outside of any data-turbo-permanent wrapper. Disabling Crisp’s MutationObserver:We intercept Crisp's MutationObserver to prevent it from triggering a reload. By temporarily disconnecting the observer, we can move the Crisp widget to our container without triggering a re-render.
When Crisp reloads, move it to a data-turbo-permanent positon Listening for Crisp's session:loaded event allows us to detect when Crisp reloads itself. Each time Crisp reloads, we move it to a data-turbo-permanent container to persist through Turbo navigations.
I will attach the actual source of this solution soon. It works however I'd like to clean it up before sharing.