Check-in [b3f2eee546]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:chat: improved the 'is previous message currently visible' calculation for the 'should we scroll?' heuristic.
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: b3f2eee546f014ead7649c82bc2540388284fe3f4e3299fff6b736480fcdfdca
User & Date: stephan 2020-12-27 18:56:02.238
Context
2020-12-27
20:33
chat: reworked the auto-resize algorithm to account for elements which "incorrectly" report a height of 0. Experimentally removed the 2em bottom gap at the end of the message reportedly required by Safari. check-in: cdc6dec7c7 user: stephan tags: trunk
18:56
chat: improved the 'is previous message currently visible' calculation for the 'should we scroll?' heuristic. check-in: b3f2eee546 user: stephan tags: trunk
18:29
chat: seem to have eliminated the tiny dead-zone between the label and checkbox in the settings menu. check-in: dc8f3a3692 user: stephan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/chat.js.
1
2
3
4
5
6
7
8
9
10
11



12
13
14
15
16
17
18
19
20













21
22
23
24
25
26
27
/**
   This file contains the client-side implementation of fossil's /chat
   application. 
*/
(function(){
  const F = window.fossil, D = F.dom;
  const E1 = function(selector){
    const e = document.querySelector(selector);
    if(!e) throw new Error("missing required DOM element: "+selector);
    return e;
  };



  const isInViewport = function(e) {
    const rect = e.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  };














  (function(){
    let dbg = document.querySelector('#debugMsg');
    if(dbg){
      /* This can inadvertently influence our flexbox layouts, so move
         it out of the way. */
      D.append(document.body,dbg);











>
>
>
|








>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
   This file contains the client-side implementation of fossil's /chat
   application. 
*/
(function(){
  const F = window.fossil, D = F.dom;
  const E1 = function(selector){
    const e = document.querySelector(selector);
    if(!e) throw new Error("missing required DOM element: "+selector);
    return e;
  };
  /**
     Returns true if e is entirely within the bounds of the window's viewport.
  */
  const isEntirelyInViewport = function(e) {
    const rect = e.getBoundingClientRect();
    return (
      rect.top >= 0 &&
      rect.left >= 0 &&
      rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  };

  /**
     Returns true if e's on-screen position vertically overlaps that
     of element v's. Horizontal overlap is ignored (we don't need it
     for our case).
  */
  const overlapsElemView = function(e,v) {
    const r1 = e.getBoundingClientRect(),
          r2 = v.getBoundingClientRect();
    if(r1.top<=r2.bottom && r1.top>=r2.top) return true;
    else if(r1.bottom<=r2.bottom && r1.bottom>=r2.top) return true;
    return false;
  };

  (function(){
    let dbg = document.querySelector('#debugMsg');
    if(dbg){
      /* This can inadvertently influence our flexbox layouts, so move
         it out of the way. */
      D.append(document.body,dbg);
210
211
212
213
214
215
216
217



218
219
220
221
222
223
224
          if(fe) mip.parentNode.insertBefore(e, fe);
          else D.append(mip.parentNode, e);
        }else{
          D.append(holder,e);
          this.e.newestMessage = e;
        }
        if(!atEnd && !this.isBatchLoading
           && e.dataset.xfrom!==this.me && !isInViewport(e)){



          /* If a new non-history message arrives while the user is
             scrolled elsewhere, do not scroll to the latest
             message, but gently alert the user that a new message
             has arrived. */
          F.toast.message("New message has arrived.");
        }else if(!this.isBatchLoading && e.dataset.xfrom===Chat.me){
          this.scheduleScrollOfMsg(e);







|
>
>
>







226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
          if(fe) mip.parentNode.insertBefore(e, fe);
          else D.append(mip.parentNode, e);
        }else{
          D.append(holder,e);
          this.e.newestMessage = e;
        }
        if(!atEnd && !this.isBatchLoading
           && e.dataset.xfrom!==this.me
           && (prevMessage
               ? !overlapsElemView(prevMessage, this.e.messagesWrapper)
               : false)){
          /* If a new non-history message arrives while the user is
             scrolled elsewhere, do not scroll to the latest
             message, but gently alert the user that a new message
             has arrived. */
          F.toast.message("New message has arrived.");
        }else if(!this.isBatchLoading && e.dataset.xfrom===Chat.me){
          this.scheduleScrollOfMsg(e);
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
             yet have enough information to know how far to scroll!
             For such cases we have to delay the scroll until the
             image loads (and we hope it does so before another
             message arrives).
          */
          if(1===+e.dataset.hasImage){
            e.querySelector('img').addEventListener('load',()=>e.scrollIntoView());
          }else if(!prevMessage || (prevMessage && isInViewport(prevMessage))){
            e.scrollIntoView(false);
          }
        }
      },
      /** Returns true if chat-only mode is enabled. */
      isChatOnlyMode: ()=>document.body.classList.contains('chat-only-mode'),
      /**







|







264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
             yet have enough information to know how far to scroll!
             For such cases we have to delay the scroll until the
             image loads (and we hope it does so before another
             message arrives).
          */
          if(1===+e.dataset.hasImage){
            e.querySelector('img').addEventListener('load',()=>e.scrollIntoView());
          }else if(!prevMessage || (prevMessage && isEntirelyInViewport(prevMessage))){
            e.scrollIntoView(false);
          }
        }
      },
      /** Returns true if chat-only mode is enabled. */
      isChatOnlyMode: ()=>document.body.classList.contains('chat-only-mode'),
      /**