[IMP] web, website: remove website menu loading effect
The goal of this commit is to remove the menu fade-in effect on page load since we can now call the initAutoMoreMenu in non-lazy JS code. When 'initAutoMoreMenu' called, images won't be loaded yet, that's why we add a class: '.o_menu_image_placeholder' to set a default size on images and once all images are loaded, we reupdate the menu. task-2618929 X-original-commit: 6be166df24dedbe4729e1e7bfe6a302713932b74 Part-of: odoo/odoo#77843
This commit is contained in:
@@ -11,6 +11,9 @@
|
||||
* can take => the overflowing (foldable) items are added in the dropdown-menu.
|
||||
* @param {string} [options.minSize] the menu auto-hide option will be disabled
|
||||
* if viewport is smaller than minSize.
|
||||
* @param {Array} [options.images=[]] images to wait for before menu update.
|
||||
* @param {Array} [options.loadingStyleClasses=[]] list of CSS classes to add while
|
||||
* updating the menu.
|
||||
*/
|
||||
export async function initAutoMoreMenu(el, options) {
|
||||
if (!el) {
|
||||
@@ -20,6 +23,8 @@ export async function initAutoMoreMenu(el, options) {
|
||||
unfoldable: 'none',
|
||||
maxWidth: false,
|
||||
minSize: '767',
|
||||
images: [],
|
||||
loadingStyleClasses: [],
|
||||
}, options || {});
|
||||
|
||||
const isUserNavbar = el.parentElement.classList.contains('o_main_navbar');
|
||||
@@ -29,6 +34,11 @@ export async function initAutoMoreMenu(el, options) {
|
||||
var extraItemsToggle = null;
|
||||
let debounce;
|
||||
|
||||
if (options.images.length) {
|
||||
await _afterImagesLoading(options.images);
|
||||
_adapt();
|
||||
}
|
||||
|
||||
const debouncedAdapt = () => {
|
||||
clearTimeout(debounce);
|
||||
debounce = setTimeout(_adapt, 250);
|
||||
@@ -173,6 +183,26 @@ export async function initAutoMoreMenu(el, options) {
|
||||
el.removeEventListener('dom:autoMoreMenu:adapt', _adapt);
|
||||
}
|
||||
|
||||
function _afterImagesLoading(images) {
|
||||
const defs = images.map((image) => {
|
||||
if (image.complete || !image.getClientRects().length) {
|
||||
return null;
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
if (!image.width) {
|
||||
// The purpose of the 'o_menu_image_placeholder' class is to add a default
|
||||
// size to non loaded images (on the first update) to prevent flickering.
|
||||
image.classList.add('o_menu_image_placeholder');
|
||||
}
|
||||
image.addEventListener('load', () => {
|
||||
image.classList.remove('o_menu_image_placeholder');
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
return Promise.all(defs);
|
||||
}
|
||||
|
||||
function _endAutoMoreMenu() {
|
||||
el.classList.remove(...options.loadingStyleClasses);
|
||||
}
|
||||
|
||||
@@ -7,33 +7,27 @@ import { initAutoMoreMenu } from '@web/legacy/js/core/menu';
|
||||
*/
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
const header = document.querySelector('header#top');
|
||||
if (!header || header.classList.contains('o_no_autohide_menu')) {
|
||||
return;
|
||||
}
|
||||
const topMenu = header.querySelector('#top_menu');
|
||||
const unfoldable = '.divider, .divider ~ li, .o_no_autohide_item, .js_language_selector';
|
||||
const excludedImagesSelector = '.o_mega_menu, .o_offcanvas_logo_container, .o_lang_flag';
|
||||
const excludedImages = [...header.querySelectorAll(excludedImagesSelector)];
|
||||
const images = [...header.querySelectorAll('img')].filter((img) => {
|
||||
excludedImages.forEach(node => {
|
||||
if (node.contains(img)) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return img.matches && !img.matches(excludedImagesSelector);
|
||||
});
|
||||
const defs = images.map((image) => {
|
||||
if (image.complete) {
|
||||
return null;
|
||||
if (header) {
|
||||
const topMenu = header.querySelector('#top_menu');
|
||||
if (header.classList.contains('o_no_autohide_menu')) {
|
||||
topMenu.classList.remove('o_menu_loading');
|
||||
return;
|
||||
}
|
||||
return new Promise(function (resolve, reject) {
|
||||
image.addEventListener('load', () => {
|
||||
resolve();
|
||||
const unfoldable = '.divider, .divider ~ li, .o_no_autohide_item, .js_language_selector';
|
||||
const excludedImagesSelector = '.o_mega_menu, .o_offcanvas_logo_container, .o_lang_flag';
|
||||
const excludedImages = [...header.querySelectorAll(excludedImagesSelector)];
|
||||
const images = [...header.querySelectorAll('img')].filter((img) => {
|
||||
excludedImages.forEach(node => {
|
||||
if (node.contains(img)) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
return img.matches && !img.matches(excludedImagesSelector);
|
||||
});
|
||||
});
|
||||
|
||||
await Promise.all(defs);
|
||||
initAutoMoreMenu(topMenu, {unfoldable: unfoldable});
|
||||
topMenu.classList.remove('o_menu_loading');
|
||||
initAutoMoreMenu(topMenu, {
|
||||
unfoldable: unfoldable,
|
||||
images: images,
|
||||
loadingStyleClasses: ['o_menu_loading']
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -207,20 +207,19 @@ body:not(.o_fullscreen) {
|
||||
.navbar-collapse {
|
||||
min-width: 0; // Allows it to shrink during loading
|
||||
}
|
||||
.nav-item {
|
||||
transition: opacity 1000ms ease 0s;
|
||||
}
|
||||
.btn {
|
||||
// This was a default bootstrap style before but it was removed from
|
||||
// the library at some point. It seems important in the header so that
|
||||
// the header does not flicker during loading.
|
||||
white-space: nowrap;
|
||||
}
|
||||
.o_menu_loading {
|
||||
.o_menu_image_placeholder {
|
||||
width: 80px !important;
|
||||
}
|
||||
#top_menu {
|
||||
flex-wrap: nowrap !important;
|
||||
overflow: hidden !important;
|
||||
|
||||
.nav-item {
|
||||
&.o_menu_loading {
|
||||
overflow: hidden !important;
|
||||
opacity: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user