Skip to content

Commit 5fa9215

Browse files
committed
Add polling for tall elements
The threshold based system just doesn't work with very long messages, and while we could add another even smaller percentage, it seems like a workaround and not a fix. Instead we just keep checking very long messages every second when the user scrolls.
1 parent 39e218d commit 5fa9215

1 file changed

Lines changed: 44 additions & 0 deletions

File tree

app/javascript/controllers/read_status_controller.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export default class extends Controller {
1010
connect() {
1111
this.marked = false
1212
this.timer = null
13+
this.pollInterval = null
1314
this.observe()
1415
}
1516

@@ -23,8 +24,12 @@ export default class extends Controller {
2324
this.observer = new IntersectionObserver(entries => {
2425
entries.forEach(entry => {
2526
if (entry.isIntersecting && this.visibleEnough(entry)) {
27+
this.stopPoll()
2628
this.startTimer()
29+
} else if (entry.isIntersecting && this.needsPollFallback()) {
30+
this.startPoll()
2731
} else {
32+
this.stopPoll()
2833
this.clearTimer()
2934
}
3035
})
@@ -50,6 +55,44 @@ export default class extends Controller {
5055
return ratio >= 0.25 && visiblePx >= 200
5156
}
5257

58+
needsPollFallback() {
59+
return this.element.getBoundingClientRect().height > (window.innerHeight || 800)
60+
}
61+
62+
startPoll() {
63+
if (this.marked || this.pollInterval || this.timer) return
64+
this.pollInterval = setInterval(() => this.checkVisibility(), 1000)
65+
}
66+
67+
stopPoll() {
68+
if (this.pollInterval) {
69+
clearInterval(this.pollInterval)
70+
this.pollInterval = null
71+
}
72+
}
73+
74+
checkVisibility() {
75+
if (this.marked) { this.stopPoll(); return }
76+
77+
const rect = this.element.getBoundingClientRect()
78+
const viewportHeight = window.innerHeight || 800
79+
const visibleTop = Math.max(0, rect.top)
80+
const visibleBottom = Math.min(viewportHeight, rect.bottom)
81+
const visiblePx = Math.max(0, visibleBottom - visibleTop)
82+
83+
if (visiblePx <= 0) {
84+
this.stopPoll()
85+
this.clearTimer()
86+
return
87+
}
88+
89+
const substantialPx = Math.min(viewportHeight * 0.8, 400)
90+
if (visiblePx >= substantialPx) {
91+
this.stopPoll()
92+
this.startTimer()
93+
}
94+
}
95+
5396
startTimer() {
5497
if (this.marked || this.timer) return
5598
const delay = (this.delaySecondsValue || 5) * 1000
@@ -65,6 +108,7 @@ export default class extends Controller {
65108

66109
cleanup() {
67110
this.clearTimer()
111+
this.stopPoll()
68112
if (this.observer) {
69113
this.observer.disconnect()
70114
this.observer = null

0 commit comments

Comments
 (0)