export function registerObserver() { document.addEventListener("DOMContentLoaded", function () { // When the DOM loaded, only the Web client framework is available, Odoo loads its // stuff later and so we must wait, and react to new nodes as they are added const root = document.querySelector(".o_web_client"); if (!root) { return; } // This function is called (see below) whenever a DOM mutation happens const callback = function (mutationsList, observer) { for (let mutation of mutationsList) { try { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { // We are only interested in children that are adding nodes const elem = mutation.addedNodes.item(0); if (elem.classList === undefined) { // This skips nodes that are not HTML tags continue; } else if (elem.attributes.toni) { // As we clone tags further down, and add those clones, we'd enter an // infinite recursion unless we skip elements we created, which are // marked with an attribute console.debug("Skipping TONI element:", elem); continue; } if (elem.classList.contains("o_switch_company_item")) { // Now we have an individual company menu item in `elem`. To get rid of the // Odoo-provided click-event handler, we clone it, and replace the original, // as cloning does not copy the event handlers try { let clone = elem.cloneNode(true); clone.attributes.toni = true clone.addEventListener('click', () => { // … and we add our own event handler that opens a new window on the // subdomain URL for the other company const cid = clone.attributes["data-company-id"].value; const url = document.URL.replace(/:\/\/(\d+\.)?odoo/, `://${cid}.odoo`); if (url) { console.debug("Opening new window on", url); const newwin = window.open(url, "_blank", "noreferrer"); if (newwin) { newwin.focus(); } const menubtn = document.querySelector(".o_switch_company_menu > button:nth-child(1)"); if (menubtn) { // Finally, click the menu, so that it disappears menubtn.click(); } } else { console.error("URL is empty, clone is:", clone); } }); elem.parentNode.replaceChild(clone, elem); console.debug("Replaced with TONI clone:", clone); } catch (e) { console.error("While cloning element:", elem, e); } // TODO: The following is an attempt to modify the document title and include the // company name. but it get overwritten by Odoo right away, so we need another // approach /* } else if (elem.classList.contains("o_switch_company_menu")) { const btn = elem.childNodes[0]; const company = btn?.title; if (company !== undefined) { const titleelem = document.querySelector("title"); titleelem.innerText += ` | ${company}`; } */ } } } catch (e) { console.error("While handling mutation:", mutation, e); }; } }; // Configure and start the MutationObserver const observer = new MutationObserver(callback); const config = { childList: true, subtree: true }; observer.observe(root, config); console.info("Installed TONI observer"); }); }