Fossil SCM

/chat now experimentally keeps track of the timestamp of the most recent message received from each user so that we can eventually integrate that information into the UI to provide a list of currently-active users (noting that we have no way of tracking the existence of lurkers).

stephan 2021-06-14 10:52 trunk
Commit be07b8d1373071d6af457eaa084fde43a4feef7176deab81a0e936bbe239e65d
1 file changed +32 -3
+32 -3
--- src/chat.js
+++ src/chat.js
@@ -121,10 +121,17 @@
121121
notificationBubbleColor: 'white',
122122
totalMessageCount: 0, // total # of inbound messages
123123
//! Number of messages to load for the history buttons
124124
loadMessageCount: Math.abs(F.config.chat.initSize || 20),
125125
ajaxInflight: 0,
126
+ usersLastSeen:{
127
+ /* Map of user names to their most recent message time
128
+ (JS Date object). Only messages received by the chat client
129
+ are considered. */
130
+ /* Reminder: to convert a Julian time J to JS:
131
+ new Date((J - 2440587.5) * 86400000) */
132
+ },
126133
/** Gets (no args) or sets (1 arg) the current input text field value,
127134
taking into account single- vs multi-line input. The getter returns
128135
a string and the setter returns this object. */
129136
inputValue: function(){
130137
const e = this.inputElement();
@@ -1079,17 +1086,33 @@
10791086
the response from /chat-poll. If atEnd is true, the message is
10801087
appended to the end of the chat list (for loading older
10811088
messages), else the beginning (the default). */
10821089
const newcontent = function f(jx,atEnd){
10831090
if(!f.processPost){
1084
- /** Processes chat message m, placing it either the start (if atEnd
1085
- is falsy) or end (if atEnd is truthy) of the chat history. atEnd
1086
- should only be true when loading older messages. */
1091
+ /** Array.sort() callback. Expects an array of user names and
1092
+ sorts them in last-received message order (newest first). */
1093
+ f.sortUsersSeen = function(l,r){
1094
+ l = Chat.usersLastSeen[l];
1095
+ r = Chat.usersLastSeen[r];
1096
+ if(l && r) return r - l;
1097
+ else if(l) return -1;
1098
+ else if(r) return 1;
1099
+ else return 0;
1100
+ };
1101
+ /** Processes chat message m, placing it either at the start (if
1102
+ atEnd is falsy) or end (if atEnd is truthy) of the chat
1103
+ history. atEnd should only be true when loading older
1104
+ messages. */
10871105
f.processPost = function(m,atEnd){
10881106
++Chat.totalMessageCount;
10891107
if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
10901108
if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
1109
+ if(m.xfrom && m.mtime){
1110
+ const d = new Date(m.mtime);
1111
+ const uls = Chat.usersLastSeen[m.xfrom];
1112
+ if(!uls || uls<d) Chat.usersLastSeen[m.xfrom] = d;
1113
+ }
10911114
if( m.mdel ){
10921115
/* A record deletion notice. */
10931116
Chat.deleteMessageElem(m.mdel);
10941117
return;
10951118
}
@@ -1098,10 +1121,16 @@
10981121
}
10991122
const row = new Chat.MessageWidget(m);
11001123
Chat.injectMessageElem(row.e.body,atEnd);
11011124
if(m.isError){
11021125
Chat._gotServerError = m;
1126
+ }else if(false){
1127
+ const users = Object.keys(Chat.usersLastSeen).sort(f.sortUsersSeen);
1128
+ console.debug("Users sorted by most recent activity (newest first):", users);
1129
+ users.forEach(function(u){
1130
+ console.debug(u, Chat.usersLastSeen[u].toISOString());
1131
+ });
11031132
}
11041133
}/*processPost()*/;
11051134
}/*end static init*/
11061135
jx.msgs.forEach((m)=>f.processPost(m,atEnd));
11071136
if('visible'===document.visibilityState){
11081137
--- src/chat.js
+++ src/chat.js
@@ -121,10 +121,17 @@
121 notificationBubbleColor: 'white',
122 totalMessageCount: 0, // total # of inbound messages
123 //! Number of messages to load for the history buttons
124 loadMessageCount: Math.abs(F.config.chat.initSize || 20),
125 ajaxInflight: 0,
 
 
 
 
 
 
 
126 /** Gets (no args) or sets (1 arg) the current input text field value,
127 taking into account single- vs multi-line input. The getter returns
128 a string and the setter returns this object. */
129 inputValue: function(){
130 const e = this.inputElement();
@@ -1079,17 +1086,33 @@
1079 the response from /chat-poll. If atEnd is true, the message is
1080 appended to the end of the chat list (for loading older
1081 messages), else the beginning (the default). */
1082 const newcontent = function f(jx,atEnd){
1083 if(!f.processPost){
1084 /** Processes chat message m, placing it either the start (if atEnd
1085 is falsy) or end (if atEnd is truthy) of the chat history. atEnd
1086 should only be true when loading older messages. */
 
 
 
 
 
 
 
 
 
 
 
1087 f.processPost = function(m,atEnd){
1088 ++Chat.totalMessageCount;
1089 if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
1090 if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
 
 
 
 
 
1091 if( m.mdel ){
1092 /* A record deletion notice. */
1093 Chat.deleteMessageElem(m.mdel);
1094 return;
1095 }
@@ -1098,10 +1121,16 @@
1098 }
1099 const row = new Chat.MessageWidget(m);
1100 Chat.injectMessageElem(row.e.body,atEnd);
1101 if(m.isError){
1102 Chat._gotServerError = m;
 
 
 
 
 
 
1103 }
1104 }/*processPost()*/;
1105 }/*end static init*/
1106 jx.msgs.forEach((m)=>f.processPost(m,atEnd));
1107 if('visible'===document.visibilityState){
1108
--- src/chat.js
+++ src/chat.js
@@ -121,10 +121,17 @@
121 notificationBubbleColor: 'white',
122 totalMessageCount: 0, // total # of inbound messages
123 //! Number of messages to load for the history buttons
124 loadMessageCount: Math.abs(F.config.chat.initSize || 20),
125 ajaxInflight: 0,
126 usersLastSeen:{
127 /* Map of user names to their most recent message time
128 (JS Date object). Only messages received by the chat client
129 are considered. */
130 /* Reminder: to convert a Julian time J to JS:
131 new Date((J - 2440587.5) * 86400000) */
132 },
133 /** Gets (no args) or sets (1 arg) the current input text field value,
134 taking into account single- vs multi-line input. The getter returns
135 a string and the setter returns this object. */
136 inputValue: function(){
137 const e = this.inputElement();
@@ -1079,17 +1086,33 @@
1086 the response from /chat-poll. If atEnd is true, the message is
1087 appended to the end of the chat list (for loading older
1088 messages), else the beginning (the default). */
1089 const newcontent = function f(jx,atEnd){
1090 if(!f.processPost){
1091 /** Array.sort() callback. Expects an array of user names and
1092 sorts them in last-received message order (newest first). */
1093 f.sortUsersSeen = function(l,r){
1094 l = Chat.usersLastSeen[l];
1095 r = Chat.usersLastSeen[r];
1096 if(l && r) return r - l;
1097 else if(l) return -1;
1098 else if(r) return 1;
1099 else return 0;
1100 };
1101 /** Processes chat message m, placing it either at the start (if
1102 atEnd is falsy) or end (if atEnd is truthy) of the chat
1103 history. atEnd should only be true when loading older
1104 messages. */
1105 f.processPost = function(m,atEnd){
1106 ++Chat.totalMessageCount;
1107 if( m.msgid>Chat.mxMsg ) Chat.mxMsg = m.msgid;
1108 if( !Chat.mnMsg || m.msgid<Chat.mnMsg) Chat.mnMsg = m.msgid;
1109 if(m.xfrom && m.mtime){
1110 const d = new Date(m.mtime);
1111 const uls = Chat.usersLastSeen[m.xfrom];
1112 if(!uls || uls<d) Chat.usersLastSeen[m.xfrom] = d;
1113 }
1114 if( m.mdel ){
1115 /* A record deletion notice. */
1116 Chat.deleteMessageElem(m.mdel);
1117 return;
1118 }
@@ -1098,10 +1121,16 @@
1121 }
1122 const row = new Chat.MessageWidget(m);
1123 Chat.injectMessageElem(row.e.body,atEnd);
1124 if(m.isError){
1125 Chat._gotServerError = m;
1126 }else if(false){
1127 const users = Object.keys(Chat.usersLastSeen).sort(f.sortUsersSeen);
1128 console.debug("Users sorted by most recent activity (newest first):", users);
1129 users.forEach(function(u){
1130 console.debug(u, Chat.usersLastSeen[u].toISOString());
1131 });
1132 }
1133 }/*processPost()*/;
1134 }/*end static init*/
1135 jx.msgs.forEach((m)=>f.processPost(m,atEnd));
1136 if('visible'===document.visibilityState){
1137

Keyboard Shortcuts

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