Number.prototype.between = function (a, b) { return a > b ? this >= b && this <= a : this >= a && this <= b; }; const DEFAULT_WINDOW_HEIGHT = 761; // based on iPhone 12 let notch; let menu; let EXPANDED_TOP; let BASE_TOP; let MENU_HEIGHT; let BEFORE_FOOTER_HEIGHT; let canChange = true; const toggleNavigation = () => { canChange = false; const wasExpanded = menu.hasClass("expanded"); menu.toggleClass("expanded"); const newTop = wasExpanded ? BASE_TOP : EXPANDED_TOP; menu.animate({ top: `${newTop}px` }, 300, () => { canChange = true; }); }; window.addEventListener("resize", () => { if (!menu) return; BASE_TOP = (document.body.clientHeight || DEFAULT_WINDOW_HEIGHT) - BEFORE_FOOTER_HEIGHT; EXPANDED_TOP = (document.body.clientHeight || DEFAULT_WINDOW_HEIGHT) - MENU_HEIGHT; if (menu.hasClass("expanded")) { menu.css("top", `${EXPANDED_TOP}px`); } else { menu.css("top", `${BASE_TOP}px`); } }); window.addEventListener("click", (event) => { if (!menu || !notch) return; if ( menu.has($(event.target)).length <= 0 && notch.has($(event.target)).length <= 0 && menu.hasClass("expanded") ) { toggleNavigation(); } }); const initMenu = () => { notch.on("click", () => {}); menu.on("click", () => {}); menu.on("touchmove", (event) => { event.preventDefault(); }); notch.on("touchstart", () => { const dateStart = new Date(); let moved = false; const handleTouchMove = (event) => { event.preventDefault(); if (!moved) moved = true; if (!canChange) return; const currentY = event.originalEvent.touches[0].clientY; if (currentY.between(EXPANDED_TOP, BASE_TOP)) menu.css("top", `${currentY}px`); }; const handleTouchEnd = () => { const dateEnd = new Date(); notch.off("touchmove", handleTouchMove); notch.off("touchend", handleTouchEnd); if (!canChange) return; if (!moved || dateEnd - dateStart < 300) return toggleNavigation(); canChange = false; const currentTop = parseInt(menu.css("top").split("px")[0]); const expand = Math.abs(currentTop - EXPANDED_TOP) < Math.abs(currentTop - BASE_TOP); const newTop = expand ? EXPANDED_TOP : BASE_TOP; if (expand) { menu.addClass("expanded"); } else { menu.removeClass("expanded"); } menu.animate({ top: `${newTop}px` }, 300, () => { canChange = true; }); }; notch.on("touchmove", handleTouchMove); notch.on("touchend", handleTouchEnd); }); BASE_TOP = (document.body.clientHeight || DEFAULT_WINDOW_HEIGHT) - BEFORE_FOOTER_HEIGHT; EXPANDED_TOP = (document.body.clientHeight || DEFAULT_WINDOW_HEIGHT) - MENU_HEIGHT; menu.css("top", `${BASE_TOP}px`); menu.css("visibility", "visible"); }; $(document).on("pageshow", (event, ui) => { const iframe = document.querySelectorAll("iframe"); iframe.forEach((item) => { // reload iframe to avoid bug on iOS item.src = item.src; }); const target = ui.toPage; notch = target.find("#notch"); menu = target.find("#menu"); MENU_HEIGHT = menu.outerHeight(); BEFORE_FOOTER_HEIGHT = target.find("#visible-before-footer").outerHeight(); initMenu(); });