Fossil SCM

In /chat-generated notifications (typically error messages), add a button to the drop-down options to delete all notifications. That replaces the 'delete all poller notifications' button which previously only showed up only on those message types. Add a mention of the backoff timer to chat.md.

stephan 2025-04-11 20:29 trunk
Commit da1c351b6ef56f36a6c43fd7f0bd8d32ae69e94e974635aef5ba2956401ec8d7
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -1326,17 +1326,18 @@
13261326
const self = this;
13271327
btnDeleteLocal.addEventListener('click', function(){
13281328
self.hide();
13291329
Chat.deleteMessageElem(eMsg)
13301330
});
1331
- if( eMsg.classList.contains('poller-connection') ){
1332
- const btnDeletePoll = D.button("Delete poller messages?");
1331
+ if( eMsg.classList.contains('notification') ){
1332
+ const btnDeletePoll = D.button("Delete /chat notifications?");
13331333
D.append(toolbar, btnDeletePoll);
13341334
btnDeletePoll.addEventListener('click', function(){
13351335
self.hide();
1336
- Chat.e.viewMessages.querySelectorAll('.message-widget.poller-connection')
1337
- .forEach(e=>Chat.deleteMessageElem(e, true));
1336
+ Chat.e.viewMessages.querySelectorAll(
1337
+ '.message-widget.notification:not(.resend-message)'
1338
+ ).forEach(e=>Chat.deleteMessageElem(e, true));
13381339
});
13391340
}
13401341
if(Chat.userMayDelete(eMsg)){
13411342
const btnDeleteGlobal = D.button("Delete globally");
13421343
D.append(toolbar, btnDeleteGlobal);
@@ -1646,11 +1647,11 @@
16461647
reader.onload = (e)=>img.setAttribute('src', e.target.result);
16471648
reader.readAsDataURL(blob);
16481649
}
16491650
};
16501651
Chat.e.inputFile.addEventListener('change', function(ev){
1651
- updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
1652
+ updateDropZoneContent(this?.files[0])
16521653
});
16531654
/* Handle image paste from clipboard. TODO: figure out how we can
16541655
paste non-image binary data as if it had been selected via the
16551656
file selection element. */
16561657
const pasteListener = function(event){
@@ -1726,10 +1727,11 @@
17261727
D.span(),"This message was not successfully sent to the server:"
17271728
));
17281729
if(state.msg){
17291730
const ta = D.textarea();
17301731
ta.value = state.msg;
1732
+ ta.setAttribute('readonly','true');
17311733
D.append(w,ta);
17321734
}
17331735
if(state.blob){
17341736
D.append(w,D.append(D.span(),"Attachment: ",(state.blob.name||"unnamed")));
17351737
//console.debug("blob = ",state.blob);
@@ -1744,11 +1746,11 @@
17441746
if(state.msg) Chat.inputValue(state.msg);
17451747
if(state.blob) BlobXferState.updateDropZoneContent(state.blob);
17461748
const theMsg = findMessageWidgetParent(w);
17471749
if(theMsg) Chat.deleteMessageElem(theMsg);
17481750
}));
1749
- Chat.reportErrorAsMessage(w);
1751
+ D.addClass(Chat.reportErrorAsMessage(w).e.body, "resend-message");
17501752
};
17511753
17521754
/* Assume the connection has been established, reset the
17531755
Chat.timer.tidReconnect, and (if showMsg and
17541756
!!Chat.e.eMsgPollError) alert the user that the outage appears to
@@ -1755,11 +1757,12 @@
17551757
be over. Also schedule Chat.poll() to run in the very near
17561758
future. */
17571759
const reportConnectionOkay = function(dbgContext, showMsg = true){
17581760
if(Chat.beVerbose){
17591761
console.warn('reportConnectionOkay', dbgContext,
1760
- 'Chat.e.pollErrorMarker =',Chat.e.pollErrorMarker,
1762
+ 'Chat.e.pollErrorMarker classes =',
1763
+ Chat.e.pollErrorMarker.classList,
17611764
'Chat.timer.tidReconnect =',Chat.timer.tidReconnect,
17621765
'Chat.timer =',Chat.timer);
17631766
}
17641767
setTimeout( Chat.poll, Chat.timer.resetDelay() );
17651768
if( Chat.timer.errCount ){
17661769
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -1326,17 +1326,18 @@
1326 const self = this;
1327 btnDeleteLocal.addEventListener('click', function(){
1328 self.hide();
1329 Chat.deleteMessageElem(eMsg)
1330 });
1331 if( eMsg.classList.contains('poller-connection') ){
1332 const btnDeletePoll = D.button("Delete poller messages?");
1333 D.append(toolbar, btnDeletePoll);
1334 btnDeletePoll.addEventListener('click', function(){
1335 self.hide();
1336 Chat.e.viewMessages.querySelectorAll('.message-widget.poller-connection')
1337 .forEach(e=>Chat.deleteMessageElem(e, true));
 
1338 });
1339 }
1340 if(Chat.userMayDelete(eMsg)){
1341 const btnDeleteGlobal = D.button("Delete globally");
1342 D.append(toolbar, btnDeleteGlobal);
@@ -1646,11 +1647,11 @@
1646 reader.onload = (e)=>img.setAttribute('src', e.target.result);
1647 reader.readAsDataURL(blob);
1648 }
1649 };
1650 Chat.e.inputFile.addEventListener('change', function(ev){
1651 updateDropZoneContent(this.files && this.files[0] ? this.files[0] : undefined)
1652 });
1653 /* Handle image paste from clipboard. TODO: figure out how we can
1654 paste non-image binary data as if it had been selected via the
1655 file selection element. */
1656 const pasteListener = function(event){
@@ -1726,10 +1727,11 @@
1726 D.span(),"This message was not successfully sent to the server:"
1727 ));
1728 if(state.msg){
1729 const ta = D.textarea();
1730 ta.value = state.msg;
 
1731 D.append(w,ta);
1732 }
1733 if(state.blob){
1734 D.append(w,D.append(D.span(),"Attachment: ",(state.blob.name||"unnamed")));
1735 //console.debug("blob = ",state.blob);
@@ -1744,11 +1746,11 @@
1744 if(state.msg) Chat.inputValue(state.msg);
1745 if(state.blob) BlobXferState.updateDropZoneContent(state.blob);
1746 const theMsg = findMessageWidgetParent(w);
1747 if(theMsg) Chat.deleteMessageElem(theMsg);
1748 }));
1749 Chat.reportErrorAsMessage(w);
1750 };
1751
1752 /* Assume the connection has been established, reset the
1753 Chat.timer.tidReconnect, and (if showMsg and
1754 !!Chat.e.eMsgPollError) alert the user that the outage appears to
@@ -1755,11 +1757,12 @@
1755 be over. Also schedule Chat.poll() to run in the very near
1756 future. */
1757 const reportConnectionOkay = function(dbgContext, showMsg = true){
1758 if(Chat.beVerbose){
1759 console.warn('reportConnectionOkay', dbgContext,
1760 'Chat.e.pollErrorMarker =',Chat.e.pollErrorMarker,
 
1761 'Chat.timer.tidReconnect =',Chat.timer.tidReconnect,
1762 'Chat.timer =',Chat.timer);
1763 }
1764 setTimeout( Chat.poll, Chat.timer.resetDelay() );
1765 if( Chat.timer.errCount ){
1766
--- src/fossil.page.chat.js
+++ src/fossil.page.chat.js
@@ -1326,17 +1326,18 @@
1326 const self = this;
1327 btnDeleteLocal.addEventListener('click', function(){
1328 self.hide();
1329 Chat.deleteMessageElem(eMsg)
1330 });
1331 if( eMsg.classList.contains('notification') ){
1332 const btnDeletePoll = D.button("Delete /chat notifications?");
1333 D.append(toolbar, btnDeletePoll);
1334 btnDeletePoll.addEventListener('click', function(){
1335 self.hide();
1336 Chat.e.viewMessages.querySelectorAll(
1337 '.message-widget.notification:not(.resend-message)'
1338 ).forEach(e=>Chat.deleteMessageElem(e, true));
1339 });
1340 }
1341 if(Chat.userMayDelete(eMsg)){
1342 const btnDeleteGlobal = D.button("Delete globally");
1343 D.append(toolbar, btnDeleteGlobal);
@@ -1646,11 +1647,11 @@
1647 reader.onload = (e)=>img.setAttribute('src', e.target.result);
1648 reader.readAsDataURL(blob);
1649 }
1650 };
1651 Chat.e.inputFile.addEventListener('change', function(ev){
1652 updateDropZoneContent(this?.files[0])
1653 });
1654 /* Handle image paste from clipboard. TODO: figure out how we can
1655 paste non-image binary data as if it had been selected via the
1656 file selection element. */
1657 const pasteListener = function(event){
@@ -1726,10 +1727,11 @@
1727 D.span(),"This message was not successfully sent to the server:"
1728 ));
1729 if(state.msg){
1730 const ta = D.textarea();
1731 ta.value = state.msg;
1732 ta.setAttribute('readonly','true');
1733 D.append(w,ta);
1734 }
1735 if(state.blob){
1736 D.append(w,D.append(D.span(),"Attachment: ",(state.blob.name||"unnamed")));
1737 //console.debug("blob = ",state.blob);
@@ -1744,11 +1746,11 @@
1746 if(state.msg) Chat.inputValue(state.msg);
1747 if(state.blob) BlobXferState.updateDropZoneContent(state.blob);
1748 const theMsg = findMessageWidgetParent(w);
1749 if(theMsg) Chat.deleteMessageElem(theMsg);
1750 }));
1751 D.addClass(Chat.reportErrorAsMessage(w).e.body, "resend-message");
1752 };
1753
1754 /* Assume the connection has been established, reset the
1755 Chat.timer.tidReconnect, and (if showMsg and
1756 !!Chat.e.eMsgPollError) alert the user that the outage appears to
@@ -1755,11 +1757,12 @@
1757 be over. Also schedule Chat.poll() to run in the very near
1758 future. */
1759 const reportConnectionOkay = function(dbgContext, showMsg = true){
1760 if(Chat.beVerbose){
1761 console.warn('reportConnectionOkay', dbgContext,
1762 'Chat.e.pollErrorMarker classes =',
1763 Chat.e.pollErrorMarker.classList,
1764 'Chat.timer.tidReconnect =',Chat.timer.tidReconnect,
1765 'Chat.timer =',Chat.timer);
1766 }
1767 setTimeout( Chat.poll, Chat.timer.resetDelay() );
1768 if( Chat.timer.errCount ){
1769
+18
--- www/chat.md
+++ www/chat.md
@@ -164,10 +164,28 @@
164164
setting.
165165
166166
This mechanism is similar to [email notification](./alerts.md) except that
167167
the notification is sent via chat instead of via email.
168168
169
+## Quirks
170
+
171
+ - There is no message-editing capability. This is by design and
172
+ desire of `/chat`'s developers.
173
+
174
+ - When `/chat` has problems connecting to the message poller (see
175
+ the next section) it will provide a subtle visual indicator of the
176
+ connection problem - a dotted line along the top of the input
177
+ field. If the connection recovers within a short time, that
178
+ indicator will go away, otherwise it will pop up a loud message
179
+ signifying that the connection to the poller is down and how long
180
+ it will wait to retry (progressively longer, up to some
181
+ maximum). `/chat` will recover automatically when the server is
182
+ reachable. Trying to send messages while the poller connection is
183
+ down is permitted, and the poller will attempt to recover
184
+ immediately if sending of a message succeeds. That applies to any
185
+ operations which send traffic, e.g. if the per-message "toggle
186
+ text mode" button is activated or a message is globally deleted.
169187
170188
## Implementation Details
171189
172190
*You do not need to understand how Fossil chat works in order to use it.
173191
But many developers prefer to know how their tools work.
174192
--- www/chat.md
+++ www/chat.md
@@ -164,10 +164,28 @@
164 setting.
165
166 This mechanism is similar to [email notification](./alerts.md) except that
167 the notification is sent via chat instead of via email.
168
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
170 ## Implementation Details
171
172 *You do not need to understand how Fossil chat works in order to use it.
173 But many developers prefer to know how their tools work.
174
--- www/chat.md
+++ www/chat.md
@@ -164,10 +164,28 @@
164 setting.
165
166 This mechanism is similar to [email notification](./alerts.md) except that
167 the notification is sent via chat instead of via email.
168
169 ## Quirks
170
171 - There is no message-editing capability. This is by design and
172 desire of `/chat`'s developers.
173
174 - When `/chat` has problems connecting to the message poller (see
175 the next section) it will provide a subtle visual indicator of the
176 connection problem - a dotted line along the top of the input
177 field. If the connection recovers within a short time, that
178 indicator will go away, otherwise it will pop up a loud message
179 signifying that the connection to the poller is down and how long
180 it will wait to retry (progressively longer, up to some
181 maximum). `/chat` will recover automatically when the server is
182 reachable. Trying to send messages while the poller connection is
183 down is permitted, and the poller will attempt to recover
184 immediately if sending of a message succeeds. That applies to any
185 operations which send traffic, e.g. if the per-message "toggle
186 text mode" button is activated or a message is globally deleted.
187
188 ## Implementation Details
189
190 *You do not need to understand how Fossil chat works in order to use it.
191 But many developers prefer to know how their tools work.
192

Keyboard Shortcuts

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