Fossil

Check-in [609bcd32c8]
Login

Check-in [609bcd32c8]

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

Overview
Comment:/chat experiment, per chat discussion: when a given user posts multiple messages in a row, indent the 2nd and subsequent messages.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | chat-indent-messages
Files: files | file ages | folders
SHA3-256: 609bcd32c85fd10f5492a515ff7835c7f67c6d96ab6426983656e84660302da2
User & Date: stephan 2021-04-07 14:46:04.446
Context
2021-04-07
14:46
/chat experiment, per chat discussion: when a given user posts multiple messages in a row, indent the 2nd and subsequent messages. ... (Closed-Leaf check-in: 609bcd32c8 user: stephan tags: chat-indent-messages)
10:09
The 'placeholder' attribute of the two /chat text input fields how includes the project name to help avoid confusion about which /chat one is typing into without requiring new screen real estate for a project-name label. ... (check-in: 69135e4f61 user: stephan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/chat.js.
224
225
226
227
228
229
230































231
232
233
234
235
236
237






238
239
240
241
242
243
244
            'load', ()=>(this.e.newestMessage || eMsg).scrollIntoView(false)
          );
        }else{
          eMsg.scrollIntoView(false);
        }
        return this;
      },































      /* Injects element e as a new row in the chat, at the top of the
         list if atEnd is falsy, else at the end of the list, before
         the load-history widget. */
      injectMessageElem: function f(e, atEnd){
        const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
              holder = this.e.messagesWrapper,
              prevMessage = this.e.newestMessage;






        if(atEnd){
          const fe = mip.nextElementSibling;
          if(fe) mip.parentNode.insertBefore(e, fe);
          else D.append(mip.parentNode, e);
        }else{
          D.append(holder,e);
          this.e.newestMessage = e;







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|
|




>
>
>
>
>
>







224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
            'load', ()=>(this.e.newestMessage || eMsg).scrollIntoView(false)
          );
        }else{
          eMsg.scrollIntoView(false);
        }
        return this;
      },
      /**
         Recalculates the ".subsequent" CSS class tag for all
         messages.  When a user posts multiple messages in a row, the
         2nd and subsequent ones get the "subsequent" tag added to
         them for additional styling. We cannot do this easily as
         messages arrive in batch mode because they can arrive out of
         order (they arrive, and are processed, in reverse order for
         the "load older messages" buttons). We do this handling in
         injectMessageElem() for "interactive" use but have to
         recalculate them en mass after receiving a batch of messages
         right after this app loads or via the "load older messages"
         buttons.
      */
      recalcMessageIndents: function(){
        var prevXFrom;
        this.e.messagesWrapper.querySelectorAll('.message-widget').forEach(function(e,ndx){
          if(e.classList.contains('notification')){
            // Obligatory special case.
            prevXFrom = undefined;
            D.removeClass(e, 'subsequent');
            return;
          }
          const xfrom = e.dataset.xfrom;
          if(ndx && xfrom === prevXFrom){
              D.addClass(e,'subsequent');
          }else{
            D.removeClass(e, 'subsequent');
          }
          prevXFrom = xfrom;
        });
      },
      /* Injects element e as a new row in the chat, at the oldest end
         of the list if atEnd is truthy, else at the newest end of the
         list. */
      injectMessageElem: function f(e, atEnd){
        const mip = atEnd ? this.e.loadOlderToolbar : this.e.messageInjectPoint,
              holder = this.e.messagesWrapper,
              prevMessage = this.e.newestMessage;
        if(!atEnd && !this._isBatchLoading
           && e.dataset.xfrom && !e.classList.contains('notification')){
          if(prevMessage && prevMessage.dataset.xfrom===e.dataset.xfrom){
            D.addClass(e, 'subsequent');
          }
        }
        if(atEnd){
          const fe = mip.nextElementSibling;
          if(fe) mip.parentNode.insertBefore(e, fe);
          else D.append(mip.parentNode, e);
        }else{
          D.append(holder,e);
          this.e.newestMessage = e;
1145
1146
1147
1148
1149
1150
1151

1152
1153
1154
1155
1156
1157
1158
          let gotMessages = x.msgs.length;
          newcontent(x,true);
          Chat._isBatchLoading = false;
          if(Chat._gotServerError){
            Chat._gotServerError = false;
            return;
          }

          if(n<0/*we asked for all history*/
             || 0===gotMessages/*we found no history*/
             || (n>0 && gotMessages<n /*we got fewer history entries than requested*/)
             || (n===0 && gotMessages<Chat.loadMessageCount
                 /*we asked for default amount and got fewer than that.*/)){
            /* We've loaded all history. Permanently disable the
               history-load toolbar and keep it from being re-enabled







>







1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
          let gotMessages = x.msgs.length;
          newcontent(x,true);
          Chat._isBatchLoading = false;
          if(Chat._gotServerError){
            Chat._gotServerError = false;
            return;
          }
          Chat.recalcMessageIndents();
          if(n<0/*we asked for all history*/
             || 0===gotMessages/*we found no history*/
             || (n>0 && gotMessages<n /*we got fewer history entries than requested*/)
             || (n===0 && gotMessages<Chat.loadMessageCount
                 /*we asked for default amount and got fewer than that.*/)){
            /* We've loaded all history. Permanently disable the
               history-load toolbar and keep it from being re-enabled
1192
1193
1194
1195
1196
1197
1198

1199
1200
1201
1202
1203
1204
1205
  })()/*end history loading widget setup*/;

  const afterFetch = function f(){
    if(true===f.isFirstCall){
      f.isFirstCall = false;
      Chat.ajaxEnd();
      Chat.e.messagesWrapper.classList.remove('loading');

      setTimeout(function(){
        Chat.scrollMessagesTo(1);
      }, 250);
    }
    if(Chat._gotServerError && Chat.intervalTimer){
      clearInterval(Chat.intervalTimer);
      Chat.reportErrorAsMessage(







>







1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
  })()/*end history loading widget setup*/;

  const afterFetch = function f(){
    if(true===f.isFirstCall){
      f.isFirstCall = false;
      Chat.ajaxEnd();
      Chat.e.messagesWrapper.classList.remove('loading');
      Chat.recalcMessageIndents();
      setTimeout(function(){
        Chat.scrollMessagesTo(1);
      }, 250);
    }
    if(Chat._gotServerError && Chat.intervalTimer){
      clearInterval(Chat.intervalTimer);
      Chat.reportErrorAsMessage(
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
        console.error(err);
        /* ^^^ we don't use Chat.reportError() here b/c the polling
           fails exepectedly when it times out, but is then immediately
           resumed, and reportError() produces a loud error message. */
        afterFetch();
      },
      onload:function(y){
        newcontent(y);
        Chat._isBatchLoading = false;
        afterFetch();
      }
    });
  };
  poll.isFirstCall = true;
  Chat._gotServerError = poll.running = false;
  if( window.fossil.config.chat.fromcli ){
    Chat.chatOnlyMode(true);
  }
  Chat.intervalTimer = setInterval(poll, 1000);
  F.page.chat = Chat/* enables testing the APIs via the dev tools */;
})();







|













1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
        console.error(err);
        /* ^^^ we don't use Chat.reportError() here b/c the polling
           fails exepectedly when it times out, but is then immediately
           resumed, and reportError() produces a loud error message. */
        afterFetch();
      },
      onload:function(y){
        newcontent(y); 
        Chat._isBatchLoading = false;
        afterFetch();
      }
    });
  };
  poll.isFirstCall = true;
  Chat._gotServerError = poll.running = false;
  if( window.fossil.config.chat.fromcli ){
    Chat.chatOnlyMode(true);
  }
  Chat.intervalTimer = setInterval(poll, 1000);
  F.page.chat = Chat/* enables testing the APIs via the dev tools */;
})();
Changes to src/default.css.
1516
1517
1518
1519
1520
1521
1522

















1523
1524
1525
1526
1527
1528
1529
  padding: 0 0.5em 0.15em 0.5em;
  cursor: pointer;
  white-space: nowrap;
}
body.chat .fossil-tooltip.help-buttonlet-content {
  font-size: 80%;
}

















/* The popup element for displaying message timestamps
   and deletion controls. */
body.chat .chat-message-popup {
  font-family: monospace;
  font-size: 0.8em;
  text-align: left;
  display: flex;







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







1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
  padding: 0 0.5em 0.15em 0.5em;
  cursor: pointer;
  white-space: nowrap;
}
body.chat .fossil-tooltip.help-buttonlet-content {
  font-size: 80%;
}
body.chat .message-widget.subsequent {
  /* When a single user posts multiple messages in a row,
     the 2nd and subsequent ones get the 'subsequent' class
     added to them. */
  margin-left: 2.5em;
  margin-right: 2.5em;
}
body.chat .message-widget.subsequent .message-widget-tab:before {
  content: "↳ ";
}
body.chat.my-messages-right .message-widget.subsequent.mine .message-widget-tab:before {
  content: revert;
}
body.chat.my-messages-right .message-widget.subsequent.mine .message-widget-tab:after {
  content: " ↲";
}

/* The popup element for displaying message timestamps
   and deletion controls. */
body.chat .chat-message-popup {
  font-family: monospace;
  font-size: 0.8em;
  text-align: left;
  display: flex;