diff --git a/Gemfile b/Gemfile index 38dee9bc4..9241cc253 100644 --- a/Gemfile +++ b/Gemfile @@ -166,7 +166,7 @@ gem 'audited', '~> 5.4', '>= 5.4.1' # need for google auth gem 'omniauth', '>= 2.1.2' gem 'omniauth-google-oauth2', '>= 1.1.2' -gem 'omniauth-rails_csrf_protection', '~> 1.0' +gem 'omniauth-rails_csrf_protection', '~> 1.0', '>= 1.0.2' ## Gems for reponse bot # adds cosine similarity to postgres using vector extension diff --git a/Gemfile.lock b/Gemfile.lock index 5dc67bef1..2aa13fea9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -148,7 +148,7 @@ GEM barnes (0.0.9) multi_json (~> 1) statsd-ruby (~> 1.1) - base64 (0.1.1) + base64 (0.2.0) bcrypt (3.1.20) bigdecimal (3.1.7) bindex (0.8.1) @@ -369,7 +369,7 @@ GEM mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (1.14.4) + i18n (1.14.5) concurrent-ruby (~> 1.0) image_processing (1.12.2) mini_magick (>= 4.9.5, < 5) @@ -490,14 +490,14 @@ GEM newrelic_rpm (9.6.0) base64 nio4r (2.7.1) - nokogiri (1.16.4) + nokogiri (1.16.5) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.16.4-arm64-darwin) + nokogiri (1.16.5-arm64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-darwin) + nokogiri (1.16.5-x86_64-darwin) racc (~> 1.4) - nokogiri (1.16.4-x86_64-linux) + nokogiri (1.16.5-x86_64-linux) racc (~> 1.4) oauth (1.1.0) oauth-tty (~> 1.0, >= 1.0.1) @@ -524,7 +524,7 @@ GEM omniauth-oauth2 (1.8.0) oauth2 (>= 1.4, < 3) omniauth (~> 2.0) - omniauth-rails_csrf_protection (1.0.1) + omniauth-rails_csrf_protection (1.0.2) actionpack (>= 4.2) omniauth (~> 2.0) openssl (3.1.0) @@ -904,7 +904,7 @@ DEPENDENCIES omniauth (>= 2.1.2) omniauth-google-oauth2 (>= 1.1.2) omniauth-oauth2 - omniauth-rails_csrf_protection (~> 1.0) + omniauth-rails_csrf_protection (~> 1.0, >= 1.0.2) pg pg_search pgvector diff --git a/app/javascript/packs/sdk.js b/app/javascript/packs/sdk.js index 9bb8314ca..84cf5fe2d 100755 --- a/app/javascript/packs/sdk.js +++ b/app/javascript/packs/sdk.js @@ -10,14 +10,37 @@ import { getUserCookieName, hasUserKeys, } from '../sdk/cookieHelpers'; -import { addClasses, removeClasses } from '../sdk/DOMHelpers'; +import { + addClasses, + removeClasses, + restoreWidgetInDOM, +} from '../sdk/DOMHelpers'; import { setCookieWithDomain } from '../sdk/cookieHelpers'; import { SDK_SET_BUBBLE_VISIBILITY } from 'shared/constants/sharedFrameEvents'; + const runSDK = ({ baseUrl, websiteToken }) => { if (window.$chatwoot) { return; } + if (window.Turbo) { + // if this is a Rails Turbo app + document.addEventListener('turbo:before-render', event => + restoreWidgetInDOM(event.detail.newBody) + ); + } + + if (window.Turbolinks) { + document.addEventListener('turbolinks:before-render', event => { + restoreWidgetInDOM(event.data.newBody); + }); + } + + // if this is an astro app + document.addEventListener('astro:before-swap', event => + restoreWidgetInDOM(event.newDocument.body) + ); + const chatwootSettings = window.chatwootSettings || {}; let locale = chatwootSettings.locale; let baseDomain = chatwootSettings.baseDomain; diff --git a/app/javascript/sdk/DOMHelpers.js b/app/javascript/sdk/DOMHelpers.js index 47a45cc78..f8ba55337 100644 --- a/app/javascript/sdk/DOMHelpers.js +++ b/app/javascript/sdk/DOMHelpers.js @@ -4,9 +4,28 @@ import { IFrameHelper } from './IFrameHelper'; export const loadCSS = () => { const css = document.createElement('style'); css.innerHTML = `${SDK_CSS}`; + css.id = 'cw-widget-styles'; document.body.appendChild(css); }; +// This is a method specific to Turbo +// The body replacing strategy removes Chatwoot styles +// as well as the widget, this help us get it back +export const restoreElement = (id, newBody) => { + const element = document.getElementById(id); + const newElement = newBody.querySelector(`#${id}`); + + if (element && !newElement) { + newBody.appendChild(element); + } +}; + +export const restoreWidgetInDOM = newBody => { + restoreElement('cw-bubble-holder', newBody); + restoreElement('cw-widget-holder', newBody); + restoreElement('cw-widget-styles', newBody); +}; + export const addClasses = (elm, classes) => { elm.classList.add(...classes.split(' ')); }; diff --git a/app/javascript/sdk/IFrameHelper.js b/app/javascript/sdk/IFrameHelper.js index 2166b4304..3687fa311 100644 --- a/app/javascript/sdk/IFrameHelper.js +++ b/app/javascript/sdk/IFrameHelper.js @@ -78,6 +78,7 @@ export const IFrameHelper = { } addClasses(widgetHolder, holderClassName); + widgetHolder.id = 'cw-widget-holder'; widgetHolder.appendChild(iframe); body.appendChild(widgetHolder); IFrameHelper.initPostMessageCommunication(); diff --git a/app/javascript/sdk/bubbleHelpers.js b/app/javascript/sdk/bubbleHelpers.js index 54401a82c..600c1444a 100644 --- a/app/javascript/sdk/bubbleHelpers.js +++ b/app/javascript/sdk/bubbleHelpers.js @@ -61,6 +61,7 @@ export const createBubbleHolder = hideMessageBubble => { addClasses(bubbleHolder, 'woot-hidden'); } addClasses(bubbleHolder, 'woot--bubble-holder'); + bubbleHolder.id = 'cw-bubble-holder'; body.appendChild(bubbleHolder); }; diff --git a/app/javascript/widget/components/Form/PhoneInput.vue b/app/javascript/widget/components/Form/PhoneInput.vue index 8a37d02c9..c7fafa916 100644 --- a/app/javascript/widget/components/Form/PhoneInput.vue +++ b/app/javascript/widget/components/Form/PhoneInput.vue @@ -39,6 +39,9 @@ v-on-clickaway="closeDropdown" :class="dropdownBackgroundClass" class="country-dropdown h-48 overflow-y-auto z-10 absolute top-12 px-0 pt-0 pl-1 pr-1 pb-1 rounded shadow-lg" + @keydown.up="moveSelectionUp" + @keydown.down="moveSelectionDown" + @keydown.enter="onSelect" >