diff --git a/web/static/src/ts/core/utils.ts b/web/static/src/ts/core/utils.ts index 06ff89d8..c85d87ac 100644 --- a/web/static/src/ts/core/utils.ts +++ b/web/static/src/ts/core/utils.ts @@ -51,3 +51,35 @@ export function memoize R>( } return memoizedFunction as T; } + +/** + * Returns a function, that, as long as it continues to be invoked, will not + * be triggered. The function will be called after it stops being called for + * N milliseconds. If `immediate` is passed, trigger the function on the + * leading edge, instead of the trailing. + * + * Inspired by https://davidwalsh.name/javascript-debounce-function + */ +export function debounce( + func: Function, + wait: number, + immediate?: boolean +): Function { + let timeout; + return function(this: any) { + const context = this; + const args = arguments; + function later() { + timeout = null; + if (!immediate) { + func.apply(context, args); + } + } + const callNow = immediate && !timeout; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + if (callNow) { + func.apply(context, args); + } + }; +} diff --git a/web/static/src/ts/env.ts b/web/static/src/ts/env.ts index f62c0797..5deaced1 100644 --- a/web/static/src/ts/env.ts +++ b/web/static/src/ts/env.ts @@ -74,6 +74,6 @@ export const makeEnvironment = memoize(function(): Env { rpc: ajax.rpc, debug: false, - isMobile: false + isMobile: window.innerWidth <= 768 }; }); diff --git a/web/static/src/ts/main.ts b/web/static/src/ts/main.ts index 57c28ac9..11fd908c 100644 --- a/web/static/src/ts/main.ts +++ b/web/static/src/ts/main.ts @@ -4,6 +4,7 @@ import { makeEnvironment } from "./env"; import { registry } from "./registry"; import { Discuss } from "./widgets/discuss"; import { Root } from "./root"; +import { debounce } from "./core/utils"; //------------------------------------------------------------------------------ // Prepare application registry @@ -17,4 +18,12 @@ document.addEventListener("DOMContentLoaded", async function() { const env = makeEnvironment(); const rootWidget = new Root(env); await rootWidget.mount(document.body); + + window.addEventListener("resize", debounce(() => { + const isMobile = window.innerWidth <= 768; + if (isMobile !== env.isMobile) { + env.isMobile = isMobile; + rootWidget.render(); + } + }, 100)); }); diff --git a/web/static/src/ts/widgets/Navbar.ts b/web/static/src/ts/widgets/Navbar.ts index ba408d00..1b1ce40b 100644 --- a/web/static/src/ts/widgets/Navbar.ts +++ b/web/static/src/ts/widgets/Navbar.ts @@ -3,7 +3,7 @@ import { Env, Menu } from "../env"; const template = ` " `; + +exports[`mobile mode: navbar is different 1`] = ` +"
+ Odoo MOBILE +
    + +
+
" +`; diff --git a/web/static/tests/widgets/navbar.test.ts b/web/static/tests/widgets/navbar.test.ts index 5a8a5e3d..0531244a 100644 --- a/web/static/tests/widgets/navbar.test.ts +++ b/web/static/tests/widgets/navbar.test.ts @@ -34,3 +34,10 @@ test("can render one menu item", async () => { await navbar.mount(fixture); expect(fixture.innerHTML).toMatchSnapshot(); }); + +test("mobile mode: navbar is different", async () => { + env.isMobile = true; + const navbar = new Navbar(env); + await navbar.mount(fixture); + expect(fixture.innerHTML).toMatchSnapshot(); +});