Fossil SCM

chat: improved the 'is previous message currently visible' calculation for the 'should we scroll?' heuristic.

stephan 2020-12-27 18:56 trunk
Commit b3f2eee546f014ead7649c82bc2540388284fe3f4e3299fff6b736480fcdfdca
1 file changed +22 -3
+22 -3
--- src/chat.js
+++ src/chat.js
@@ -7,19 +7,35 @@
77
const E1 = function(selector){
88
const e = document.querySelector(selector);
99
if(!e) throw new Error("missing required DOM element: "+selector);
1010
return e;
1111
};
12
- const isInViewport = function(e) {
12
+ /**
13
+ Returns true if e is entirely within the bounds of the window's viewport.
14
+ */
15
+ const isEntirelyInViewport = function(e) {
1316
const rect = e.getBoundingClientRect();
1417
return (
1518
rect.top >= 0 &&
1619
rect.left >= 0 &&
1720
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
1821
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
1922
);
2023
};
24
+
25
+ /**
26
+ Returns true if e's on-screen position vertically overlaps that
27
+ of element v's. Horizontal overlap is ignored (we don't need it
28
+ for our case).
29
+ */
30
+ const overlapsElemView = function(e,v) {
31
+ const r1 = e.getBoundingClientRect(),
32
+ r2 = v.getBoundingClientRect();
33
+ if(r1.top<=r2.bottom && r1.top>=r2.top) return true;
34
+ else if(r1.bottom<=r2.bottom && r1.bottom>=r2.top) return true;
35
+ return false;
36
+ };
2137
2238
(function(){
2339
let dbg = document.querySelector('#debugMsg');
2440
if(dbg){
2541
/* This can inadvertently influence our flexbox layouts, so move
@@ -212,11 +228,14 @@
212228
}else{
213229
D.append(holder,e);
214230
this.e.newestMessage = e;
215231
}
216232
if(!atEnd && !this.isBatchLoading
217
- && e.dataset.xfrom!==this.me && !isInViewport(e)){
233
+ && e.dataset.xfrom!==this.me
234
+ && (prevMessage
235
+ ? !overlapsElemView(prevMessage, this.e.messagesWrapper)
236
+ : false)){
218237
/* If a new non-history message arrives while the user is
219238
scrolled elsewhere, do not scroll to the latest
220239
message, but gently alert the user that a new message
221240
has arrived. */
222241
F.toast.message("New message has arrived.");
@@ -247,11 +266,11 @@
247266
image loads (and we hope it does so before another
248267
message arrives).
249268
*/
250269
if(1===+e.dataset.hasImage){
251270
e.querySelector('img').addEventListener('load',()=>e.scrollIntoView());
252
- }else if(!prevMessage || (prevMessage && isInViewport(prevMessage))){
271
+ }else if(!prevMessage || (prevMessage && isEntirelyInViewport(prevMessage))){
253272
e.scrollIntoView(false);
254273
}
255274
}
256275
},
257276
/** Returns true if chat-only mode is enabled. */
258277
--- src/chat.js
+++ src/chat.js
@@ -7,19 +7,35 @@
7 const E1 = function(selector){
8 const e = document.querySelector(selector);
9 if(!e) throw new Error("missing required DOM element: "+selector);
10 return e;
11 };
12 const isInViewport = function(e) {
 
 
 
13 const rect = e.getBoundingClientRect();
14 return (
15 rect.top >= 0 &&
16 rect.left >= 0 &&
17 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
18 rect.right <= (window.innerWidth || document.documentElement.clientWidth)
19 );
20 };
 
 
 
 
 
 
 
 
 
 
 
 
 
21
22 (function(){
23 let dbg = document.querySelector('#debugMsg');
24 if(dbg){
25 /* This can inadvertently influence our flexbox layouts, so move
@@ -212,11 +228,14 @@
212 }else{
213 D.append(holder,e);
214 this.e.newestMessage = e;
215 }
216 if(!atEnd && !this.isBatchLoading
217 && e.dataset.xfrom!==this.me && !isInViewport(e)){
 
 
 
218 /* If a new non-history message arrives while the user is
219 scrolled elsewhere, do not scroll to the latest
220 message, but gently alert the user that a new message
221 has arrived. */
222 F.toast.message("New message has arrived.");
@@ -247,11 +266,11 @@
247 image loads (and we hope it does so before another
248 message arrives).
249 */
250 if(1===+e.dataset.hasImage){
251 e.querySelector('img').addEventListener('load',()=>e.scrollIntoView());
252 }else if(!prevMessage || (prevMessage && isInViewport(prevMessage))){
253 e.scrollIntoView(false);
254 }
255 }
256 },
257 /** Returns true if chat-only mode is enabled. */
258
--- src/chat.js
+++ src/chat.js
@@ -7,19 +7,35 @@
7 const E1 = function(selector){
8 const e = document.querySelector(selector);
9 if(!e) throw new Error("missing required DOM element: "+selector);
10 return e;
11 };
12 /**
13 Returns true if e is entirely within the bounds of the window's viewport.
14 */
15 const isEntirelyInViewport = function(e) {
16 const rect = e.getBoundingClientRect();
17 return (
18 rect.top >= 0 &&
19 rect.left >= 0 &&
20 rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
21 rect.right <= (window.innerWidth || document.documentElement.clientWidth)
22 );
23 };
24
25 /**
26 Returns true if e's on-screen position vertically overlaps that
27 of element v's. Horizontal overlap is ignored (we don't need it
28 for our case).
29 */
30 const overlapsElemView = function(e,v) {
31 const r1 = e.getBoundingClientRect(),
32 r2 = v.getBoundingClientRect();
33 if(r1.top<=r2.bottom && r1.top>=r2.top) return true;
34 else if(r1.bottom<=r2.bottom && r1.bottom>=r2.top) return true;
35 return false;
36 };
37
38 (function(){
39 let dbg = document.querySelector('#debugMsg');
40 if(dbg){
41 /* This can inadvertently influence our flexbox layouts, so move
@@ -212,11 +228,14 @@
228 }else{
229 D.append(holder,e);
230 this.e.newestMessage = e;
231 }
232 if(!atEnd && !this.isBatchLoading
233 && e.dataset.xfrom!==this.me
234 && (prevMessage
235 ? !overlapsElemView(prevMessage, this.e.messagesWrapper)
236 : false)){
237 /* If a new non-history message arrives while the user is
238 scrolled elsewhere, do not scroll to the latest
239 message, but gently alert the user that a new message
240 has arrived. */
241 F.toast.message("New message has arrived.");
@@ -247,11 +266,11 @@
266 image loads (and we hope it does so before another
267 message arrives).
268 */
269 if(1===+e.dataset.hasImage){
270 e.querySelector('img').addEventListener('load',()=>e.scrollIntoView());
271 }else if(!prevMessage || (prevMessage && isEntirelyInViewport(prevMessage))){
272 e.scrollIntoView(false);
273 }
274 }
275 },
276 /** Returns true if chat-only mode is enabled. */
277

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button