)]}' {"version": 3, "sources": ["/web/static/src/module_loader.js", "/web/static/src/session.js", "/web/static/src/core/browser/cookie.js", "/web/static/src/legacy/js/public/lazyloader.js", "/web_editor/static/src/js/frontend/loader_loading.js", "/website/static/src/js/content/inject_dom.js", "/website/static/src/js/content/auto_hide_menu.js", "/website/static/src/js/content/redirect.js", "/website/static/src/js/content/adapt_content.js"], "mappings": "AAAA;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AClOA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;;;;ACJA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACvCA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AClHA;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACjCA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACpDA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACpTA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;ACtDA;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA", "sourcesContent": ["/**\n *------------------------------------------------------------------------------\n * Odoo Web Boostrap Code\n *------------------------------------------------------------------------------\n */\n(function () {\n \"use strict\";\n\n class ModuleLoader {\n /** @type {Map} mapping name => deps/fn */\n factories = new Map();\n /** @type {Set} names of modules waiting to be started */\n jobs = new Set();\n /** @type {Set} names of failed modules */\n failed = new Set();\n\n /** @type {Map} mapping name => value */\n modules = new Map();\n\n bus = new EventTarget();\n\n checkErrorProm = null;\n\n /**\n * @param {string} name\n * @param {string[]} deps\n * @param {Function} factory\n */\n define(name, deps, factory) {\n if (typeof name !== \"string\") {\n throw new Error(`Invalid name definition: ${name} (should be a string)\"`);\n }\n if (!(deps instanceof Array)) {\n throw new Error(`Dependencies should be defined by an array: ${deps}`);\n }\n if (typeof factory !== \"function\") {\n throw new Error(`Factory should be defined by a function ${factory}`);\n }\n if (!this.factories.has(name)) {\n this.factories.set(name, {\n deps,\n fn: factory,\n ignoreMissingDeps: globalThis.__odooIgnoreMissingDependencies,\n });\n this.addJob(name);\n this.checkErrorProm ||= Promise.resolve().then(() => {\n this.checkAndReportErrors();\n this.checkErrorProm = null;\n });\n }\n }\n\n addJob(name) {\n this.jobs.add(name);\n this.startModules();\n }\n\n findJob() {\n for (const job of this.jobs) {\n if (this.factories.get(job).deps.every((dep) => this.modules.has(dep))) {\n return job;\n }\n }\n return null;\n }\n\n startModules() {\n let job;\n while ((job = this.findJob())) {\n this.startModule(job);\n }\n }\n\n startModule(name) {\n const require = (name) => this.modules.get(name);\n this.jobs.delete(name);\n const factory = this.factories.get(name);\n let value = null;\n try {\n value = factory.fn(require);\n } catch (error) {\n this.failed.add(name);\n throw new Error(`Error while loading \"${name}\":\\n${error}`);\n }\n this.modules.set(name, value);\n this.bus.dispatchEvent(\n new CustomEvent(\"module-started\", { detail: { moduleName: name, module: value } })\n );\n }\n\n findErrors() {\n // cycle detection\n const dependencyGraph = new Map();\n for (const job of this.jobs) {\n dependencyGraph.set(job, this.factories.get(job).deps);\n }\n function visitJobs(jobs, visited = new Set()) {\n for (const job of jobs) {\n const result = visitJob(job, visited);\n if (result) {\n return result;\n }\n }\n return null;\n }\n\n function visitJob(job, visited) {\n if (visited.has(job)) {\n const jobs = Array.from(visited).concat([job]);\n const index = jobs.indexOf(job);\n return jobs\n .slice(index)\n .map((j) => `\"${j}\"`)\n .join(\" => \");\n }\n const deps = dependencyGraph.get(job);\n return deps ? visitJobs(deps, new Set(visited).add(job)) : null;\n }\n\n // missing dependencies\n const missing = new Set();\n for (const job of this.jobs) {\n const factory = this.factories.get(job);\n if (factory.ignoreMissingDeps) {\n continue;\n }\n for (const dep of factory.deps) {\n if (!this.factories.has(dep)) {\n missing.add(dep);\n }\n }\n }\n\n return {\n failed: [...this.failed],\n cycle: visitJobs(this.jobs),\n missing: [...missing],\n unloaded: [...this.jobs].filter((j) => !this.factories.get(j).ignoreMissingDeps),\n };\n }\n\n async checkAndReportErrors() {\n const { failed, cycle, missing, unloaded } = this.findErrors();\n if (!failed.length && !unloaded.length) {\n return;\n }\n\n function domReady(cb) {\n if (document.readyState === \"complete\") {\n cb();\n } else {\n document.addEventListener(\"DOMContentLoaded\", cb);\n }\n }\n\n function list(heading, names) {\n const frag = document.createDocumentFragment();\n if (!names || !names.length) {\n return frag;\n }\n frag.textContent = heading;\n const ul = document.createElement(\"ul\");\n for (const el of names) {\n const li = document.createElement(\"li\");\n li.textContent = el;\n ul.append(li);\n }\n frag.appendChild(ul);\n return frag;\n }\n\n domReady(() => {\n // Empty body\n while (document.body.childNodes.length) {\n document.body.childNodes[0].remove();\n }\n const container = document.createElement(\"div\");\n container.className =\n \"o_module_error position-fixed w-100 h-100 d-flex align-items-center flex-column bg-white overflow-auto modal\";\n container.style.zIndex = \"10000\";\n const alert = document.createElement(\"div\");\n alert.className = \"alert alert-danger o_error_detail fw-bold m-auto\";\n container.appendChild(alert);\n alert.appendChild(\n list(\n \"The following modules failed to load because of an error, you may find more information in the devtools console:\",\n failed\n )\n );\n alert.appendChild(\n list(\n \"The following modules could not be loaded because they form a dependency cycle:\",\n cycle && [cycle]\n )\n );\n alert.appendChild(\n list(\n \"The following modules are needed by other modules but have not been defined, they may not be present in the correct asset bundle:\",\n missing\n )\n );\n alert.appendChild(\n list(\n \"The following modules could not be loaded because they have unmet dependencies, this is a secondary error which is likely caused by one of the above problems:\",\n unloaded\n )\n );\n document.body.appendChild(container);\n });\n }\n }\n\n if (!globalThis.odoo) {\n globalThis.odoo = {};\n }\n const odoo = globalThis.odoo;\n if (odoo.debug && !new URLSearchParams(location.search).has(\"debug\")) {\n // remove debug mode if not explicitely set in url\n odoo.debug = \"\";\n }\n\n const loader = new ModuleLoader();\n odoo.define = loader.define.bind(loader);\n\n odoo.loader = loader;\n})();\n", "/** @odoo-module **/\n\nexport const session = odoo.__session_info__ || {};\ndelete odoo.__session_info__;\n", "/** @odoo-module **/\n\n/**\n * Utils to make use of document.cookie\n * https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies\n * As recommended, storage should not be done by the cookie\n * but with localStorage/sessionStorage\n */\n\nconst COOKIE_TTL = 24 * 60 * 60 * 365;\n\nexport const cookie = {\n get _cookieMonster() {\n return document.cookie;\n },\n set _cookieMonster(value) {\n document.cookie = value;\n },\n get(str) {\n const parts = this._cookieMonster.split(\"; \");\n for (const part of parts) {\n const [key, value] = part.split(/=(.*)/);\n if (key === str) {\n return value || \"\";\n }\n }\n },\n set(key, value, ttl = COOKIE_TTL) {\n let fullCookie = [];\n if (value !== undefined) {\n fullCookie.push(`${key}=${value}`);\n }\n fullCookie = fullCookie.concat([\"path=/\", `max-age=${ttl}`]);\n this._cookieMonster = fullCookie.join(\"; \");\n },\n delete(key) {\n this.set(key, \"kill\", 0);\n },\n};\n", "/** @odoo-module **/\n\nvar blockEvents = ['submit', 'click'];\nvar blockFunction = function (ev) {\n ev.preventDefault();\n ev.stopImmediatePropagation();\n};\n\nvar waitingLazy = false;\n\n/**\n * Blocks the DOM sections which explicitly require the lazy loaded JS to be\n * working (those sections should be marked with the 'o_wait_lazy_js' class).\n *\n * @see stopWaitingLazy\n */\nfunction waitLazy() {\n if (waitingLazy) {\n return;\n }\n waitingLazy = true;\n\n var lazyEls = document.querySelectorAll('.o_wait_lazy_js');\n for (var i = 0; i < lazyEls.length; i++) {\n var element = lazyEls[i];\n blockEvents.forEach(function (evType) {\n element.addEventListener(evType, blockFunction);\n });\n }\n\n document.body.classList.add('o_lazy_js_waiting');\n}\n/**\n * Unblocks the DOM sections blocked by @see waitLazy and removes the related\n * 'o_wait_lazy_js' class from the whole DOM.\n */\nfunction stopWaitingLazy() {\n if (!waitingLazy) {\n return;\n }\n waitingLazy = false;\n\n var lazyEls = document.querySelectorAll('.o_wait_lazy_js');\n for (var i = 0; i < lazyEls.length; i++) {\n var element = lazyEls[i];\n blockEvents.forEach(function (evType) {\n element.removeEventListener(evType, blockFunction);\n });\n element.classList.remove('o_wait_lazy_js');\n }\n\n document.body.classList.remove('o_lazy_js_waiting');\n}\n\n// Start waiting for lazy loading as soon as the DOM is available\nif (document.readyState !== 'loading') {\n waitLazy();\n} else {\n document.addEventListener('DOMContentLoaded', function () {\n waitLazy();\n });\n}\n\n// As soon as everything is fully loaded, start loading all the remaining JS\n// and unblock the related DOM section when all of it have been loaded and\n// executed\nvar doResolve = null;\nvar _allScriptsLoaded = new Promise(function (resolve) {\n if (doResolve) {\n resolve();\n } else {\n doResolve = resolve;\n }\n}).then(function () {\n stopWaitingLazy();\n});\nif (document.readyState === 'complete') {\n setTimeout(_loadScripts, 0);\n} else {\n window.addEventListener('load', function () {\n setTimeout(_loadScripts, 0);\n });\n}\n\n/**\n * @param {DOMElement[]} scripts\n * @param {integer} index\n */\nfunction _loadScripts(scripts, index) {\n if (scripts === undefined) {\n scripts = document.querySelectorAll('script[data-src]');\n }\n if (index === undefined) {\n index = 0;\n }\n if (index >= scripts.length) {\n if (typeof doResolve === 'function') {\n doResolve();\n } else {\n doResolve = true;\n }\n return;\n }\n var script = scripts[index];\n script.addEventListener('load', _loadScripts.bind(this, scripts, index + 1));\n script.setAttribute('defer', 'defer');\n script.src = script.dataset.src;\n script.removeAttribute('data-src');\n}\n\nexport default {\n loadScripts: _loadScripts,\n allScriptsLoaded: _allScriptsLoaded,\n};\n", "(function () {\n'use strict';\n\n/**\n * This file makes sure textarea elements with a specific editor class are\n * tweaked as soon as the DOM is ready so that they appear to be loading.\n *\n * They must then be loaded using standard Odoo modules system. In particular,\n * @see @web_editor/js/frontend/loadWysiwygFromTextarea\n */\n\ndocument.addEventListener('DOMContentLoaded', () => {\n // Standard loop for better browser support\n var textareaEls = document.querySelectorAll('textarea.o_wysiwyg_loader');\n for (var i = 0; i < textareaEls.length; i++) {\n var textarea = textareaEls[i];\n var wrapper = document.createElement('div');\n wrapper.classList.add('position-relative', 'o_wysiwyg_textarea_wrapper');\n\n var loadingElement = document.createElement('div');\n loadingElement.classList.add('o_wysiwyg_loading');\n var loadingIcon = document.createElement('i');\n loadingIcon.classList.add('text-600', 'text-center',\n 'fa', 'fa-circle-o-notch', 'fa-spin', 'fa-2x');\n loadingElement.appendChild(loadingIcon);\n wrapper.appendChild(loadingElement);\n\n textarea.parentNode.insertBefore(wrapper, textarea);\n wrapper.insertBefore(textarea, loadingElement);\n }\n});\n\n})();\n", "/** @odoo-module */\n\nimport { cookie as cookieManager } from \"@web/core/browser/cookie\";\nimport { session } from \"@web/session\";\n\n/**\n * Unhide elements that are hidden by default and that should be visible\n * according to the snippet visibility option.\n */\nexport function unhideConditionalElements() {\n // Create CSS rules in a dedicated style tag according to the snippet\n // visibility option's computed ones (saved as data attributes).\n const styleEl = document.createElement('style');\n styleEl.id = \"conditional_visibility\";\n document.head.appendChild(styleEl);\n const conditionalEls = document.querySelectorAll('[data-visibility=\"conditional\"]');\n for (const conditionalEl of conditionalEls) {\n const selectors = conditionalEl.dataset.visibilitySelectors;\n styleEl.sheet.insertRule(`${selectors} { display: none !important; }`);\n }\n\n // Now remove the classes that makes them always invisible\n for (const conditionalEl of conditionalEls) {\n conditionalEl.classList.remove('o_conditional_hidden');\n }\n}\n\ndocument.addEventListener('DOMContentLoaded', () => {\n // Transfer cookie/session data as HTML element's attributes so that CSS\n // selectors can be based on them.\n const htmlEl = document.documentElement;\n const cookieNamesToDataNames = {\n 'utm_source': 'utmSource',\n 'utm_medium': 'utmMedium',\n 'utm_campaign': 'utmCampaign',\n };\n for (const [name, dsName] of Object.entries(cookieNamesToDataNames)) {\n const cookie = cookieManager.get(`odoo_${name}`);\n if (cookie) {\n // Remove leading and trailing \" and '\n htmlEl.dataset[dsName] = cookie.replace(/(^[\"']|[\"']$)/g, '');\n }\n }\n const country = session.geoip_country_code;\n if (country) {\n htmlEl.dataset.country = country;\n }\n\n htmlEl.dataset.logged = !session.is_website_user;\n\n unhideConditionalElements();\n});\n", "/** @odoo-module **/\n\nconst BREAKPOINT_SIZES = {sm: '575', md: '767', lg: '991', xl: '1199', xxl: '1399'};\n\n/**\n * Creates an automatic 'more' dropdown-menu for a set of navbar items.\n *\n * @param {HTMLElement} el\n * @param {Object} [options]\n * @param {string} [options.unfoldable='none'] selector for items that do not\n * need to be added to dropdown-menu.\n * @param {Array} [options.images=[]] images to wait for before menu update.\n * @param {Array} [options.loadingStyleClasses=[]] list of CSS classes to add while\n * updating the menu.\n * @param {function} [options.autoClose] returns a value that represents the\n * \"auto-close\" behaviour of the dropdown (e.g. used to prevent auto-closing in\n * \"edit\" mode).\n*/\nasync function autoHideMenu(el, options) {\n if (!el) {\n return;\n }\n const navbar = el.closest('.navbar');\n // Get breakpoint related information from the navbar to correctly handle\n // the \"auto-hide\" on mobile menu.\n const [breakpoint = 'md'] = navbar ? Object.keys(BREAKPOINT_SIZES)\n .filter(suffix => navbar.classList.contains(`navbar-expand-${suffix}`)) : [];\n const isNoHamburgerMenu = !!navbar && navbar.classList.contains('navbar-expand');\n const minSize = BREAKPOINT_SIZES[breakpoint];\n let isExtraMenuOpen = false;\n\n options = Object.assign({\n unfoldable: 'none',\n images: [],\n loadingStyleClasses: [],\n autoClose: () => true,\n }, options || {});\n\n const isUserNavbar = el.parentElement.classList.contains('o_main_navbar');\n const dropdownSubMenuClasses = ['show', 'border-0', 'position-static'];\n const dropdownToggleClasses = ['h-auto', 'py-2', 'text-secondary'];\n const autoMarginLeftRegex = /\\bm[sx]?(?:-(?:sm|md|lg|xl|xxl))?-auto\\b/; // grep: ms-auto mx-auto\n const autoMarginRightRegex = /\\bm[ex]?(?:-(?:sm|md|lg|xl|xxl))?-auto\\b/; // grep: me-auto mx-auto\n var extraItemsToggle = null;\n const afterFontsloading = new Promise((resolve) => {\n if (document.fonts) {\n document.fonts.ready.then(resolve);\n } else {\n // IE: don't wait more than max .15s.\n setTimeout(resolve, 150);\n }\n });\n afterFontsloading.then(_adapt);\n\n if (options.images.length) {\n await _afterImagesLoading(options.images);\n _adapt();\n }\n\n let pending = false;\n let refreshId = null;\n const onRefresh = () => {\n if (pending) {\n refreshId = window.requestAnimationFrame(onRefresh);\n _adapt();\n pending = false;\n } else {\n refreshId = null;\n }\n };\n // This should throttle the `_adapt()` method to the browser's refresh\n // rate. The first menu adaptation is always executed immediately.\n const throttleAdapt = () => {\n if (refreshId === null) {\n refreshId = window.requestAnimationFrame(onRefresh);\n _adapt();\n } else {\n pending = true;\n }\n };\n\n window.addEventListener('resize', throttleAdapt);\n\n function _restore() {\n if (!extraItemsToggle) {\n return;\n }\n // Move extra menu items from dropdown-menu to menu element in the same order.\n [...extraItemsToggle.querySelector('.dropdown-menu').children].forEach((item) => {\n if (!isUserNavbar) {\n item.classList.add('nav-item');\n const itemLink = item.querySelector('.dropdown-item');\n if (itemLink) {\n itemLink.classList.remove('dropdown-item');\n itemLink.classList.add('nav-link');\n }\n } else {\n item.classList.remove('dropdown-item');\n const dropdownSubMenu = item.querySelector('.dropdown-menu');\n const dropdownSubMenuButton = item.querySelector('.dropdown-toggle');\n if (dropdownSubMenu) {\n dropdownSubMenu.classList.remove(...dropdownSubMenuClasses);\n }\n if (dropdownSubMenuButton) {\n dropdownSubMenuButton.classList.remove(...dropdownToggleClasses);\n }\n }\n el.insertBefore(item, extraItemsToggle);\n });\n extraItemsToggle.remove();\n extraItemsToggle = null;\n }\n\n function _adapt() {\n const wysiwyg = window.$ && $('#wrapwrap').data('wysiwyg');\n const odooEditor = wysiwyg && wysiwyg.odooEditor;\n if (odooEditor) {\n odooEditor.observerUnactive(\"adapt\");\n odooEditor.withoutRollback(__adapt);\n odooEditor.observerActive(\"adapt\");\n return;\n }\n __adapt();\n }\n\n function __adapt() {\n if (options.loadingStyleClasses.length) {\n el.classList.add(...options.loadingStyleClasses);\n }\n // The goal here is to get the state of the extra menu dropdown if it is\n // there, which will be restored after the menu adaptation.\n const extraMenuEl = _getExtraMenuEl();\n isExtraMenuOpen = extraMenuEl && extraMenuEl.classList.contains(\"show\");\n _restore();\n\n // Ignore invisible/toggleable top menu element & small viewports.\n if (!el.getClientRects().length || el.closest('.show')\n || (window.matchMedia(`(max-width: ${minSize}px)`).matches && !isNoHamburgerMenu)) {\n return _endAutoMoreMenu();\n }\n\n let unfoldableItems = [];\n const items = [...el.children].filter((node) => {\n if (node.matches && !node.matches(options.unfoldable)) {\n return true;\n }\n unfoldableItems.push(node);\n return false;\n });\n var nbItems = items.length;\n var menuItemsWidth = items.reduce((sum, el) => sum + computeFloatOuterWidthWithMargins(el, true, true, false), 0);\n let maxWidth = 0;\n\n if (!maxWidth) {\n maxWidth = computeFloatOuterWidthWithMargins(el, true, true, true);\n var style = window.getComputedStyle(el);\n maxWidth -= (parseFloat(style.paddingLeft) + parseFloat(style.paddingRight) + parseFloat(style.borderLeftWidth) + parseFloat(style.borderRightWidth));\n maxWidth -= unfoldableItems.reduce((sum, el) => sum + computeFloatOuterWidthWithMargins(el, true, true, false), 0);\n }\n // Ignore if there is no overflow.\n if (maxWidth - menuItemsWidth >= -0.001) {\n return _endAutoMoreMenu();\n }\n\n const dropdownMenu = _addExtraItemsButton(items[nbItems - 1].nextElementSibling);\n menuItemsWidth += computeFloatOuterWidthWithMargins(extraItemsToggle, true, true, false);\n do {\n menuItemsWidth -= computeFloatOuterWidthWithMargins(items[--nbItems], true, true, false);\n } while (!(maxWidth - menuItemsWidth >= -0.001) && (nbItems > 0));\n\n const extraItems = items.slice(nbItems);\n extraItems.forEach((el) => {\n if (!isUserNavbar) {\n const navLink = el.querySelector('.nav-link, a');\n el.classList.remove('nav-item');\n if (navLink) {\n navLink.classList.remove('nav-link');\n navLink.classList.add('dropdown-item');\n navLink.classList.toggle('active', el.classList.contains('active'));\n }\n } else {\n const dropdownSubMenu = el.querySelector('.dropdown-menu');\n const dropdownSubMenuButton = el.querySelector('.dropdown-toggle');\n el.classList.add('dropdown-item', 'p-0');\n if (dropdownSubMenu) {\n dropdownSubMenu.classList.add(...dropdownSubMenuClasses);\n }\n if (dropdownSubMenuButton) {\n dropdownSubMenuButton.classList.add(...dropdownToggleClasses);\n }\n }\n dropdownMenu.appendChild(el);\n });\n _endAutoMoreMenu();\n }\n\n function computeFloatOuterWidthWithMargins(el, mLeft, mRight, considerAutoMargins) {\n var rect = el.getBoundingClientRect();\n var style = window.getComputedStyle(el);\n var outerWidth = rect.right - rect.left;\n const isRTL = style.direction === 'rtl';\n if (mLeft !== false && (considerAutoMargins || !(isRTL ? autoMarginRightRegex : autoMarginLeftRegex).test(el.getAttribute('class')))) {\n outerWidth += parseFloat(style.marginLeft);\n }\n if (mRight !== false && (considerAutoMargins || !(isRTL ? autoMarginLeftRegex : autoMarginRightRegex).test(el.getAttribute('class')))) {\n outerWidth += parseFloat(style.marginRight);\n }\n // Would be NaN for invisible elements for example\n return isNaN(outerWidth) ? 0 : outerWidth;\n }\n\n function _addExtraItemsButton(target) {\n let dropdownMenu = document.createElement('div');\n extraItemsToggle = dropdownMenu.cloneNode();\n const extraItemsToggleIcon = document.createElement('i');\n const extraItemsToggleLink = document.createElement('a');\n\n dropdownMenu.className = 'dropdown-menu';\n extraItemsToggle.className = 'nav-item dropdown o_extra_menu_items';\n extraItemsToggleIcon.className = 'fa fa-plus';\n Object.entries({\n role: 'button',\n href: '#',\n class: 'nav-link dropdown-toggle o-no-caret',\n 'data-bs-toggle': 'dropdown',\n 'aria-expanded': false,\n }).forEach(([key, value]) => {\n extraItemsToggleLink.setAttribute(key, value);\n });\n\n extraItemsToggleLink.appendChild(extraItemsToggleIcon);\n extraItemsToggle.appendChild(extraItemsToggleLink);\n extraItemsToggle.appendChild(dropdownMenu);\n el.insertBefore(extraItemsToggle, target);\n if (!options.autoClose()) {\n extraItemsToggleLink.setAttribute(\"data-bs-auto-close\", \"outside\");\n }\n return dropdownMenu;\n }\n\n function _afterImagesLoading(images) {\n const defs = images.map((image) => {\n if (image.complete || !image.getClientRects().length) {\n return null;\n }\n return new Promise(function (resolve, reject) {\n if (!image.width) {\n // The purpose of the 'o_menu_image_placeholder' class is to add a default\n // size to non loaded images (on the first update) to prevent flickering.\n image.classList.add('o_menu_image_placeholder');\n }\n image.addEventListener('load', () => {\n image.classList.remove('o_menu_image_placeholder');\n resolve();\n });\n });\n });\n return Promise.all(defs);\n }\n\n function _getExtraMenuEl() {\n return el.querySelector(\".o_extra_menu_items .dropdown-toggle\");\n }\n\n function _endAutoMoreMenu() {\n const extraMenuEl = _getExtraMenuEl();\n if (extraMenuEl && isExtraMenuOpen) {\n extraMenuEl.click();\n }\n el.classList.remove(...options.loadingStyleClasses);\n }\n}\n\n/**\n * Auto adapt the header layout so that elements are not wrapped on a new line.\n */\ndocument.addEventListener('DOMContentLoaded', async () => {\n const header = document.querySelector('header#top');\n if (header) {\n // TODO in master: remove `#top_menu` from the selector.\n const topMenu = header.querySelector(\"#top_menu, .top_menu\");\n if (header.classList.contains('o_no_autohide_menu')) {\n topMenu.classList.remove('o_menu_loading');\n return;\n }\n const unfoldable = '.divider, .divider ~ li, .o_no_autohide_item, .js_language_selector';\n const excludedImagesSelector = '.o_mega_menu, .o_offcanvas_logo_container, .o_lang_flag';\n const excludedImages = [...header.querySelectorAll(excludedImagesSelector)];\n const images = [...header.querySelectorAll('img')].filter((img) => {\n excludedImages.forEach(node => {\n if (node.contains(img)) {\n return false;\n }\n });\n return img.matches && !img.matches(excludedImagesSelector);\n });\n autoHideMenu(topMenu, {\n unfoldable: unfoldable,\n images: images,\n loadingStyleClasses: ['o_menu_loading'],\n // The \"auto-hide\" menu is closed when clicking inside the extra\n // menu items. The goal here is to prevent this default behaviour\n // on \"edit\" mode to allow correct editing of extra menu items, mega\n // menu content...\n autoClose: () => !document.body.classList.contains(\"editor_enable\"),\n });\n }\n});\n", "/** @odoo-module */\n\nimport { session } from '@web/session';\n\n/**\n * This script, served with frontend pages, displays buttons in the top left\n * corner to provide the authenticated user an access to his odoo backend.\n * In the case of the page being viewed in the website_preview client action,\n * it will forward some events to its parent.\n */\ndocument.addEventListener('DOMContentLoaded', () => {\n if (session.is_website_user) {\n return;\n }\n\n if (!window.frameElement) {\n const frontendToBackendNavEl = document.querySelector('.o_frontend_to_backend_nav');\n if (frontendToBackendNavEl) {\n frontendToBackendNavEl.classList.add('d-flex');\n frontendToBackendNavEl.classList.remove('d-none');\n }\n // Auto redirect to frontend if edit/translation mode is requested\n const currentUrl = new URL(window.location.href);\n currentUrl.pathname = `/@${currentUrl.pathname}`;\n if (currentUrl.searchParams.get('enable_editor') || currentUrl.searchParams.get('edit_translations')) {\n document.body.innerHTML = '';\n window.location.replace(currentUrl.href);\n return;\n }\n const backendEditBtnEl = document.querySelector('.o_frontend_to_backend_edit_btn');\n if (backendEditBtnEl) {\n backendEditBtnEl.href = currentUrl.href;\n document.addEventListener(\"keydown\", ev => {\n if (ev.key === \"a\" && ev.altKey) {\n currentUrl.searchParams.set('enable_editor', 1);\n window.location.replace(currentUrl.href);\n }\n }, true);\n }\n } else {\n const backendUserDropdownLinkEl = document.getElementById('o_backend_user_dropdown_link');\n if (backendUserDropdownLinkEl) {\n backendUserDropdownLinkEl.classList.add('d-none');\n backendUserDropdownLinkEl.classList.remove('d-flex');\n }\n // Multiple reasons to do this:\n // - It seems like DOMContentLoaded doesn't always trigger when\n // listened from the parent window\n // - Having an event that's fire only when the page is from Odoo avoids\n // weird behaviours. (e.g. if we want to clear out the iframe, it might\n // fire an DOMContentLoaded on a non odoo page)\n window.frameElement.dispatchEvent(new CustomEvent('OdooFrameContentLoaded'));\n }\n});\n", "/** @odoo-module */\n\ndocument.addEventListener('DOMContentLoaded', () => {\n const htmlEl = document.documentElement;\n const editTranslations = !!htmlEl.dataset.edit_translations;\n // Hack: on translation editor, textareas with translatable text content\n // will get a `` as translation value which stays visible until\n // the values are updated on the editor. The same issue was fixed on CSS\n // for `placeholder` and `value` attributes (since we can get the elements\n // with attribute translation on CSS). But here, we need to hide the text\n // on JS until the editor's code sets the right values on textareas.\n if (editTranslations) {\n [...document.querySelectorAll('textarea')].map(textarea => {\n if (textarea.value.indexOf('data-oe-translation-initial-sha') !== -1) {\n textarea.classList.add('o_text_content_invisible');\n }\n });\n }\n});\n"], "file": "/web/assets/1/3f0116c/web.assets_frontend_minimal.js", "sourceRoot": "../../../../"}