diff --git a/addons/im_livechat/__manifest__.py b/addons/im_livechat/__manifest__.py index 8e4bc5d390a..8966d6788bb 100644 --- a/addons/im_livechat/__manifest__.py +++ b/addons/im_livechat/__manifest__.py @@ -102,7 +102,6 @@ Help your customers with this chat, and analyse their feedback. 'im_livechat/static/src/embed/common/**/*', ], 'im_livechat.assets_embed_external': [ - 'web/static/lib/jquery/jquery.js', 'web/static/src/libs/fontawesome/css/font-awesome.css', 'im_livechat/static/src/embed/common/scss/bootstrap_overridden.scss', ('include', 'web._assets_helpers'), @@ -121,7 +120,8 @@ Help your customers with this chat, and analyse their feedback. 'bus/static/src/services/**/*.js', 'bus/static/src/workers/websocket_worker.js', 'bus/static/src/workers/websocket_worker_utils.js', - + ('remove', 'bus/static/src/services/assets_watchdog_service.js'), + ('remove', 'bus/static/src/simple_notification_service.js'), ('include', 'im_livechat.assets_embed_core'), 'im_livechat/static/src/embed/external/**/*', ], diff --git a/addons/im_livechat/static/src/embed/external/boot.js b/addons/im_livechat/static/src/embed/external/boot.js index c287f7bae39..f28a0727a8e 100644 --- a/addons/im_livechat/static/src/embed/external/boot.js +++ b/addons/im_livechat/static/src/embed/external/boot.js @@ -1,11 +1,9 @@ /* @odoo-module */ -import { makeRoot, makeShadow } from "@im_livechat/embed/common/boot_helpers"; import { LivechatButton } from "@im_livechat/embed/common/livechat_button"; +import { makeShadow, makeRoot } from "@im_livechat/embed/common/boot_helpers"; import { serverUrl } from "@im_livechat/embed/common/livechat_data"; -import { ChatWindowContainer } from "@mail/core/common/chat_window_container"; - import { mount, whenReady } from "@odoo/owl"; import { templates } from "@web/core/assets"; @@ -19,7 +17,6 @@ import { session } from "@web/session"; await whenReady(); const mainComponentsRegistry = registry.category("main_components"); mainComponentsRegistry.add("LivechatRoot", { Component: LivechatButton }); - mainComponentsRegistry.add("ChatWindowContainer", { Component: ChatWindowContainer }); const env = makeEnv(); await startServices(env); odoo.isReady = true; diff --git a/addons/im_livechat/static/src/embed/external/overrides.scss b/addons/im_livechat/static/src/embed/external/overrides.scss new file mode 100644 index 00000000000..414d81c412e --- /dev/null +++ b/addons/im_livechat/static/src/embed/external/overrides.scss @@ -0,0 +1,3 @@ +.o-main-components-container, .o_notification_manager { + position: fixed !important; +} diff --git a/addons/mail/__manifest__.py b/addons/mail/__manifest__.py index 374b37d8d6d..288c21018cc 100644 --- a/addons/mail/__manifest__.py +++ b/addons/mail/__manifest__.py @@ -134,6 +134,7 @@ For more specific needs, you may also assign custom-defined actions ('remove', 'mail/static/lib/lame/lame.js'), 'mail/static/src/js/**/*', 'mail/static/src/core/common/**/*', + 'mail/static/src/core/web_portal/**/*', 'mail/static/src/core/web/**/*', 'mail/static/src/**/common/**/*', 'mail/static/src/**/web/**/*', diff --git a/addons/mail/static/src/core/common/chat_window.xml b/addons/mail/static/src/core/common/chat_window.xml index 8bc58375020..6ac41b4a922 100644 --- a/addons/mail/static/src/core/common/chat_window.xml +++ b/addons/mail/static/src/core/common/chat_window.xml @@ -7,7 +7,7 @@ t-att-class="{ 'w-100 h-100 o-mobile': ui.isSmall, 'o-folded': props.chatWindow.folded, - 'position-absolute bottom-0 overflow-hidden d-flex flex-column': !props.chatWindow.hidden, + 'position-fixed bottom-0 overflow-hidden d-flex flex-column': !props.chatWindow.hidden, 'rounded-top-3': !props.chatWindow.hidden and !ui.isSmall, }" t-on-keydown="onKeydown" diff --git a/addons/mail/static/src/core/common/message.js b/addons/mail/static/src/core/common/message.js index efa8b278451..7ff72a9fcdb 100644 --- a/addons/mail/static/src/core/common/message.js +++ b/addons/mail/static/src/core/common/message.js @@ -18,7 +18,6 @@ import { Component, onMounted, onPatched, - onWillUnmount, useChildSubEnv, useEffect, useRef, @@ -99,8 +98,6 @@ export class Message extends Component { isHovered: false, isClicked: false, expandOptions: false, - lastReadMoreIndex: 0, - isReadMoreByIndex: new Map(), originalEmail: false, emailHeaderOpen: false, }); @@ -150,15 +147,14 @@ export class Message extends Component { }); onMounted(() => { if (this.messageBody.el) { - $(this.messageBody.el).find(".o-mail-read-more-less").remove(); - this.insertReadMoreLess($(this.messageBody.el)); + this.prepareMessageBody(this.messageBody.el); } if (this.shadowBody.el) { this.shadowRoot = this.shadowBody.el.attachShadow({ mode: "open" }); const body = document.createElement("span"); body.innerHTML = this.props.messageSearch?.highlight(this.message.body) ?? this.message.body; - this.insertReadMoreLess($(body)); + this.prepareMessageBody(body); const color = cookie.get("color_scheme") === "dark" ? "white" : "black"; this.shadowStyle = document.createElement("style"); this.shadowStyle.innerHTML = ` @@ -180,11 +176,6 @@ export class Message extends Component { this.shadowRoot.appendChild(body); } }); - onWillUnmount(() => { - if (this.messageBody.el) { - $(this.messageBody.el).find(".o-mail-read-more-less").remove(); - } - }); } get attClass() { @@ -436,6 +427,11 @@ export class Message extends Component { this.enterEditMode(); } + /** + * @param {HTMLElement} element + */ + prepareMessageBody(element) {} + enterEditMode() { const messageContent = convertBrToLineBreak(this.props.message.body); this.props.message.composer = { @@ -473,91 +469,6 @@ export class Message extends Component { }); } - /** - * Modifies the message to add the 'read more/read less' functionality - * All element nodes with 'data-o-mail-quote' attribute are concerned. - * All text nodes after a ``#stopSpelling`` element are concerned. - * Those text nodes need to be wrapped in a span (toggle functionality). - * All consecutive elements are joined in one 'read more/read less'. - * - * FIXME This method should be rewritten (task-2308951) - * - * @param {jQuery} $element - */ - insertReadMoreLess($element) { - const groups = []; - let readMoreNodes; - - // nodeType 1: element_node - // nodeType 3: text_node - const $children = $element - .contents() - .filter( - (index, content) => - content.nodeType === 1 || (content.nodeType === 3 && content.nodeValue.trim()) - ); - - for (const child of $children) { - let $child = $(child); - - // Hide Text nodes if "stopSpelling" - if (child.nodeType === 3 && $child.prevAll('[id*="stopSpelling"]').length > 0) { - // Convert Text nodes to Element nodes - $child = $("", { - text: child.textContent, - "data-o-mail-quote": "1", - }); - child.parentNode.replaceChild($child[0], child); - } - - // Create array for each 'read more' with nodes to toggle - if ( - $child.attr("data-o-mail-quote") || - ($child.get(0).nodeName === "BR" && - $child.prev('[data-o-mail-quote="1"]').length > 0) - ) { - if (!readMoreNodes) { - readMoreNodes = []; - groups.push(readMoreNodes); - } - $child.hide(); - readMoreNodes.push($child); - } else { - readMoreNodes = undefined; - this.insertReadMoreLess($child); - } - } - - for (const group of groups) { - const index = this.state.lastReadMoreIndex++; - // Insert link just before the first node - const $readMoreLess = $("", { - class: "o-mail-read-more-less d-block", - href: "#", - text: "Read More", - }).insertBefore(group[0]); - - // Toggle All next nodes - if (!this.state.isReadMoreByIndex.has(index)) { - this.state.isReadMoreByIndex.set(index, true); - } - const updateFromState = () => { - const isReadMore = this.state.isReadMoreByIndex.get(index); - for (const $child of group) { - $child.hide(); - $child.toggle(!isReadMore); - } - $readMoreLess.text(isReadMore ? "Read More" : "Read Less"); - }; - $readMoreLess.click((e) => { - e.preventDefault(); - this.state.isReadMoreByIndex.set(index, !this.state.isReadMoreByIndex.get(index)); - updateFromState(); - }); - updateFromState(); - } - } - openReactionMenu() { this.dialog.add(MessageReactionMenu, { message: this.props.message, diff --git a/addons/mail/static/src/core/web_portal/message_patch.js b/addons/mail/static/src/core/web_portal/message_patch.js new file mode 100644 index 00000000000..659fd2285a7 --- /dev/null +++ b/addons/mail/static/src/core/web_portal/message_patch.js @@ -0,0 +1,111 @@ +/* @odoo-module */ + +import { patch } from "@web/core/utils/patch"; +import { Message } from "@mail/core/common/message"; +import { onWillUnmount } from "@odoo/owl"; + +patch(Message.prototype, { + setup() { + super.setup(...arguments); + this.state.lastReadMoreIndex = 0; + this.state.isReadMoreByIndex = new Map(); + onWillUnmount(() => { + this.messageBody.el?.querySelector(".o-mail-read-more-less")?.remove(); + }); + }, + + /** + * @override + * @param {HTMLElement} element + */ + prepareMessageBody(element) { + const $el = $(element); + $el.find(".o-mail-read-more-less").remove(); + this.insertReadMoreLess($el); + }, + + /** + * Modifies the message to add the 'read more/read less' functionality + * All element nodes with 'data-o-mail-quote' attribute are concerned. + * All text nodes after a ``#stopSpelling`` element are concerned. + * Those text nodes need to be wrapped in a span (toggle functionality). + * All consecutive elements are joined in one 'read more/read less'. + * + * FIXME This method should be rewritten (task-2308951) + * + * @param {jQuery} $element + */ + insertReadMoreLess($element) { + const groups = []; + let readMoreNodes; + + // nodeType 1: element_node + // nodeType 3: text_node + const $children = $element + .contents() + .filter( + (index, content) => + content.nodeType === 1 || (content.nodeType === 3 && content.nodeValue.trim()) + ); + + for (const child of $children) { + let $child = $(child); + + // Hide Text nodes if "stopSpelling" + if (child.nodeType === 3 && $child.prevAll('[id*="stopSpelling"]').length > 0) { + // Convert Text nodes to Element nodes + $child = $("", { + text: child.textContent, + "data-o-mail-quote": "1", + }); + child.parentNode.replaceChild($child[0], child); + } + + // Create array for each 'read more' with nodes to toggle + if ( + $child.attr("data-o-mail-quote") || + ($child.get(0).nodeName === "BR" && + $child.prev('[data-o-mail-quote="1"]').length > 0) + ) { + if (!readMoreNodes) { + readMoreNodes = []; + groups.push(readMoreNodes); + } + $child.hide(); + readMoreNodes.push($child); + } else { + readMoreNodes = undefined; + this.insertReadMoreLess($child); + } + } + + for (const group of groups) { + const index = this.state.lastReadMoreIndex++; + // Insert link just before the first node + const $readMoreLess = $("", { + class: "o-mail-read-more-less d-block", + href: "#", + text: "Read More", + }).insertBefore(group[0]); + + // Toggle All next nodes + if (!this.state.isReadMoreByIndex.has(index)) { + this.state.isReadMoreByIndex.set(index, true); + } + const updateFromState = () => { + const isReadMore = this.state.isReadMoreByIndex.get(index); + for (const $child of group) { + $child.hide(); + $child.toggle(!isReadMore); + } + $readMoreLess.text(isReadMore ? "Read More" : "Read Less"); + }; + $readMoreLess.click((e) => { + e.preventDefault(); + this.state.isReadMoreByIndex.set(index, !this.state.isReadMoreByIndex.get(index)); + updateFromState(); + }); + updateFromState(); + } + }, +}); diff --git a/addons/mail/static/src/utils/common/format.js b/addons/mail/static/src/utils/common/format.js index 6a3134211b7..5928c0f5a88 100644 --- a/addons/mail/static/src/utils/common/format.js +++ b/addons/mail/static/src/utils/common/format.js @@ -64,11 +64,13 @@ export function parseAndTransform(htmlString, transformFunction) { const string = htmlString.replace(/</g, openToken); let children; try { - children = $("
").html(string).contents(); + const div = document.createElement("div"); + div.innerHTML = string; + children = Array.from(div.childNodes); } catch { - children = $("
") - .html("
" + string + "
") - .contents(); + const div = document.createElement("div"); + div.innerHTML = `
${string}
`; + children = Array.from(div.childNodes); } return _parseAndTransform(children, transformFunction).replace( new RegExp(openToken, "g"),