[FIX] website: fix footer slideout animations

This commit ensures that the slideout footer is visible by the visitor
before start its animations. Now to start an option in the footer
slideout, you have to scroll enough for the element to be visible.

Steps to reproduce the fixed bug:
 - Enter edit mode
 - click on the footer
 - choose a slideout effect other than "Regular"
 - set an animation to an item inside the footer and select "Everytime"
 in Animation Launch

=> the element is animated only once on page load (because the footer is
actually directly in the viewport but behind the content of the page)

task-2878421

closes odoo/odoo#93133

Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
Guillaume (gdi)
2022-07-04 15:23:59 +02:00
parent 1d23ebf95e
commit 2050328a37
3 changed files with 44 additions and 18 deletions
@@ -1235,7 +1235,7 @@ registry.WebsiteAnimate = publicWidget.Widget.extend({
});
$(window).off('.o_animate');
this.$scrollingElement[0].removeEventListener('scroll', this.__onScrollWebsiteAnimate, {capture: true});
this.$scrollingElement[0].classList.remove('o_wanim_overflow_x_hidden');
this.$scrollingElement[0].classList.remove('o_wanim_overflow_xy_hidden');
},
//--------------------------------------------------------------------------
@@ -1251,13 +1251,13 @@ registry.WebsiteAnimate = publicWidget.Widget.extend({
_startAnimation($el) {
// Forces the browser to redraw using setTimeout.
setTimeout(() => {
this._toggleOverflowXHidden(true);
this._toggleOverflowXYHidden(true);
$el
.css({"animation-play-state": "running"})
.addClass("o_animating")
.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', () => {
$el.addClass("o_animated").removeClass("o_animating");
this._toggleOverflowXHidden(false);
this._toggleOverflowXYHidden(false);
$(window).trigger("resize");
});
});
@@ -1271,22 +1271,23 @@ registry.WebsiteAnimate = publicWidget.Widget.extend({
$el.css({"animation-name": "dummy-none", "animation-play-state": ""})
.removeClass("o_animated o_animating");
this._toggleOverflowXHidden(false);
this._toggleOverflowXYHidden(false);
// trigger a DOM reflow
void $el[0].offsetWidth;
$el.css({'animation-name': animationName , 'animation-play-state': 'paused'});
},
/**
* Shows/hides the horizontal scrollbar (on the #wrapwrap).
* Shows/hides the horizontal scrollbar (on the #wrapwrap) and prevents
* flicker of the page height (on the slideout footer).
*
* @private
* @param {Boolean} add
*/
_toggleOverflowXHidden(add) {
_toggleOverflowXYHidden(add) {
if (add) {
this.$scrollingElement[0].classList.add('o_wanim_overflow_x_hidden');
this.$scrollingElement[0].classList.add('o_wanim_overflow_xy_hidden');
} else if (!this.$scrollingElement.find('.o_animating').length) {
this.$scrollingElement[0].classList.remove('o_wanim_overflow_x_hidden');
this.$scrollingElement[0].classList.remove('o_wanim_overflow_xy_hidden');
}
},
/**
@@ -1294,13 +1295,18 @@ registry.WebsiteAnimate = publicWidget.Widget.extend({
*
* @private
* @param {Element} el
* @param {HTMLElement} [topEl] if specified, calculates the top distance to
* this element.
*/
_getElementOffsetTop(el) {
_getElementOffsetTop(el, topEl) {
// Loop through the DOM tree and add its parent's offset to get page offset.
var top = 0;
do {
top += el.offsetTop || 0;
el = el.offsetParent;
if (topEl && el === topEl) {
return top;
}
} while (el);
return top;
},
@@ -1325,12 +1331,29 @@ registry.WebsiteAnimate = publicWidget.Widget.extend({
// Cookies bar might be opened and considered as a modal but it is
// not really one (eg 'discrete' layout), and should not be used as
// scrollTop value.
const scrollTop = document.body.classList.contains("modal-open") ?
this.$target.find('.modal:visible').scrollTop() :
this.$scrollingElement.scrollTop();
const elTop = this._getElementOffsetTop($el[0]) - scrollTop;
const visible = this.windowsHeight > (elTop + elOffset) && 0 < (elTop + elHeight - elOffset);
let visible;
const footerEl = el.closest('.o_footer_slideout');
const wrapEl = this.$target[0];
if (footerEl && wrapEl.classList.contains('o_footer_effect_enable')) {
// Since the footer slideout is always in the viewport but not
// always displayed, the way to calculate if an element is
// visible in the footer is different. We decided to handle this
// case specifically instead of a generic solution using
// elementFromPoint as it is a rare case and the implementation
// would have been too complicated for such a small use case.
const actualScroll = wrapEl.scrollTop + this.windowsHeight;
const totalScrollHeight = wrapEl.scrollHeight;
const heightFromFooter = this._getElementOffsetTop(el, footerEl);
visible = actualScroll >=
totalScrollHeight - heightFromFooter - elHeight + elOffset;
} else {
const scrollTop = document.body.classList.contains("modal-open") ?
this.$target.find('.modal:visible').scrollTop() :
this.$scrollingElement.scrollTop();
const elTop = this._getElementOffsetTop($el[0]) - scrollTop;
visible = this.windowsHeight > (elTop + elOffset) &&
0 < (elTop + elHeight - elOffset);
}
if (visible && state === "paused") {
$el.addClass("o_visible");
this._startAnimation($el);
@@ -3093,10 +3093,10 @@ options.registry.WebsiteAnimate = options.Class.extend({
// Trigger a DOM reflow.
void this.$target[0].offsetWidth;
this.$target.addClass('o_animating');
$scrollingElement[0].classList.add('o_wanim_overflow_x_hidden');
$scrollingElement[0].classList.add('o_wanim_overflow_xy_hidden');
this.$target.css('animation-name', '');
this.$target.one('webkitAnimationEnd oanimationend msAnimationEnd animationend', () => {
$scrollingElement[0].classList.remove('o_wanim_overflow_x_hidden');
$scrollingElement[0].classList.remove('o_wanim_overflow_xy_hidden');
this.$target.removeClass('o_animating');
});
},
+4 -1
View File
@@ -1511,8 +1511,11 @@ ul.o_checklist > li.o_checked::after {
.o_animate_preview {
visibility: visible;
}
.o_wanim_overflow_x_hidden {
.o_wanim_overflow_xy_hidden {
overflow-x: hidden !important;
.o_footer_slideout {
overflow-y: hidden !important;
}
}
.o_animated_text {
display: inline-block;