From b5a100b0cce7b377b83e5d2dada36f6515a93f09 Mon Sep 17 00:00:00 2001 From: Julian Rubisch Date: Mon, 18 Sep 2023 11:45:58 +0200 Subject: [PATCH] feat: Also track document.visibilityState --- javascript/elements/updates_for_element.js | 24 +++++++++---------- javascript/observers/appearance_observer.js | 26 ++++++++++++++++++++- 2 files changed, 37 insertions(+), 13 deletions(-) diff --git a/javascript/elements/updates_for_element.js b/javascript/elements/updates_for_element.js index fec69741..08630fac 100644 --- a/javascript/elements/updates_for_element.js +++ b/javascript/elements/updates_for_element.js @@ -40,8 +40,8 @@ export default class UpdatesForElement extends SubscribingElement { this.appearanceObserver = new AppearanceObserver(this) - this.intersecting = false - this.didTransitionToIntersecting = false + this.visible = false + this.didTransitionToVisible = false } async connectedCallback () { @@ -94,7 +94,7 @@ export default class UpdatesForElement extends SubscribingElement { // first element in the DOM *at any given moment* updates all of the others // if the element becomes visible though, we have to overrule and load it - if (blocks[0].element !== this && !this.didTransitionToIntersecting) { + if (blocks[0].element !== this && !this.didTransitionToVisible) { this.triggerElementLog.push( `${new Date().toLocaleString()}: ${Log.cancel( this.lastUpdateTimestamp, @@ -146,16 +146,16 @@ export default class UpdatesForElement extends SubscribingElement { } appearedInViewport () { - if (!this.intersecting) { - // transition from non-intersecting to intersecting forces update - this.didTransitionToIntersecting = true + if (!this.visible) { + // transition from invisible to visible forces update + this.didTransitionToVisible = true this.update({}) } - this.intersecting = true + this.visible = true } disappearedFromViewport () { - this.intersecting = false + this.visible = false } get query () { @@ -220,7 +220,7 @@ class Block { onBeforeElUpdated: shouldMorph(operation), onElUpdated: _ => { this.element.removeAttribute('updating') - this.element.didTransitionToIntersecting = false + this.element.didTransitionToVisible = false dispatch(this.element, 'cable-ready:after-update', operation) assignFocus(operation.focusSelector) } @@ -275,7 +275,7 @@ class Block { return ( !this.ignoresInnerUpdates && this.hasChangesSelectedForUpdate(data) && - (!this.observeAppearance || this.intersecting) + (!this.observeAppearance || this.visible) ) } @@ -312,8 +312,8 @@ class Block { return this.element.query } - get intersecting () { - return this.element.intersecting + get visible () { + return this.element.visible } get observeAppearance () { diff --git a/javascript/observers/appearance_observer.js b/javascript/observers/appearance_observer.js index 7b5dba32..6cf64b96 100644 --- a/javascript/observers/appearance_observer.js +++ b/javascript/observers/appearance_observer.js @@ -3,6 +3,7 @@ export class AppearanceObserver { this.delegate = delegate this.element = element || delegate this.started = false + this.intersecting = false this.intersectionObserver = new IntersectionObserver(this.intersect) } @@ -11,6 +12,7 @@ export class AppearanceObserver { if (!this.started) { this.started = true this.intersectionObserver.observe(this.element) + this.observeVisibility() } } @@ -18,18 +20,40 @@ export class AppearanceObserver { if (this.started) { this.started = false this.intersectionObserver.unobserve(this.element) + this.unobserveVisibility() } } + observeVisibility = () => { + document.addEventListener('visibilitychange', this.handleVisibilityChange) + } + + unobserveVisibility = () => { + document.removeEventListener( + 'visibilitychange', + this.handleVisibilityChange + ) + } + intersect = entries => { entries.forEach(entry => { if (entry.target === this.element) { - if (entry.isIntersecting) { + if (entry.isIntersecting && document.visibilityState === 'visible') { + this.intersecting = true this.delegate.appearedInViewport() } else { + this.intersecting = false this.delegate.disappearedFromViewport() } } }) } + + handleVisibilityChange = event => { + if (document.visibilityState === 'visible' && this.intersecting) { + this.delegate.appearedInViewport() + } else { + this.delegate.disappearedFromViewport() + } + } }