Fossil SCM

Merged in trunk. /chat changed jump-to-message animation to fade out/in, per requests. Added HTML5 history to /chat clicks on #NNN message references but it's disabled because it's behaving unexpectedly.

stephan 2021-09-28 11:06 markdown-tagrefs merge
Commit 99b23d0fa357acce0f9445f6192284cd8008e8500e1dab0e432f869d55a80a1d
+2 -3
--- src/chat.c
+++ src/chat.c
@@ -217,24 +217,23 @@
217217
/* Always in-line the javascript for the chat page */
218218
@ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
219219
/* We need an onload handler to ensure that window.fossil is
220220
initialized before the chat init code runs. */
221221
@ window.addEventListener('load', function(){
222
- @ document.body.classList.add('chat')
222
+ @ document.body.classList.add('chat');
223223
@ /*^^^for skins which add their own BODY tag */;
224224
@ window.fossil.config.chat = {
225225
@ fromcli: %h(PB("cli")?"true":"false"),
226226
@ alertSound: "%h(zAlert)",
227227
@ initSize: %d(db_get_int("chat-initial-history",50)),
228228
@ imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
229229
@ };
230230
ajax_emit_js_preview_modes(0);
231231
chat_emit_alert_list();
232
- cgi_append_content(builtin_text("chat.js"),-1);
233232
@ }, false);
234233
@ </script>
235
-
234
+ builtin_request_js("fossil.page.chat.js");
236235
style_finish_page();
237236
}
238237
239238
/* Definition of repository tables used by chat
240239
*/
241240
242241
DELETED src/chat.js
--- src/chat.c
+++ src/chat.c
@@ -217,24 +217,23 @@
217 /* Always in-line the javascript for the chat page */
218 @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
219 /* We need an onload handler to ensure that window.fossil is
220 initialized before the chat init code runs. */
221 @ window.addEventListener('load', function(){
222 @ document.body.classList.add('chat')
223 @ /*^^^for skins which add their own BODY tag */;
224 @ window.fossil.config.chat = {
225 @ fromcli: %h(PB("cli")?"true":"false"),
226 @ alertSound: "%h(zAlert)",
227 @ initSize: %d(db_get_int("chat-initial-history",50)),
228 @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
229 @ };
230 ajax_emit_js_preview_modes(0);
231 chat_emit_alert_list();
232 cgi_append_content(builtin_text("chat.js"),-1);
233 @ }, false);
234 @ </script>
235
236 style_finish_page();
237 }
238
239 /* Definition of repository tables used by chat
240 */
241
242 ELETED src/chat.js
--- src/chat.c
+++ src/chat.c
@@ -217,24 +217,23 @@
217 /* Always in-line the javascript for the chat page */
218 @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
219 /* We need an onload handler to ensure that window.fossil is
220 initialized before the chat init code runs. */
221 @ window.addEventListener('load', function(){
222 @ document.body.classList.add('chat');
223 @ /*^^^for skins which add their own BODY tag */;
224 @ window.fossil.config.chat = {
225 @ fromcli: %h(PB("cli")?"true":"false"),
226 @ alertSound: "%h(zAlert)",
227 @ initSize: %d(db_get_int("chat-initial-history",50)),
228 @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
229 @ };
230 ajax_emit_js_preview_modes(0);
231 chat_emit_alert_list();
 
232 @ }, false);
233 @ </script>
234 builtin_request_js("fossil.page.chat.js");
235 style_finish_page();
236 }
237
238 /* Definition of repository tables used by chat
239 */
240
241 ELETED src/chat.js
+2 -3
--- src/chat.c
+++ src/chat.c
@@ -217,24 +217,23 @@
217217
/* Always in-line the javascript for the chat page */
218218
@ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
219219
/* We need an onload handler to ensure that window.fossil is
220220
initialized before the chat init code runs. */
221221
@ window.addEventListener('load', function(){
222
- @ document.body.classList.add('chat')
222
+ @ document.body.classList.add('chat');
223223
@ /*^^^for skins which add their own BODY tag */;
224224
@ window.fossil.config.chat = {
225225
@ fromcli: %h(PB("cli")?"true":"false"),
226226
@ alertSound: "%h(zAlert)",
227227
@ initSize: %d(db_get_int("chat-initial-history",50)),
228228
@ imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
229229
@ };
230230
ajax_emit_js_preview_modes(0);
231231
chat_emit_alert_list();
232
- cgi_append_content(builtin_text("chat.js"),-1);
233232
@ }, false);
234233
@ </script>
235
-
234
+ builtin_request_js("fossil.page.chat.js");
236235
style_finish_page();
237236
}
238237
239238
/* Definition of repository tables used by chat
240239
*/
241240
242241
DELETED src/chat.js
--- src/chat.c
+++ src/chat.c
@@ -217,24 +217,23 @@
217 /* Always in-line the javascript for the chat page */
218 @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
219 /* We need an onload handler to ensure that window.fossil is
220 initialized before the chat init code runs. */
221 @ window.addEventListener('load', function(){
222 @ document.body.classList.add('chat')
223 @ /*^^^for skins which add their own BODY tag */;
224 @ window.fossil.config.chat = {
225 @ fromcli: %h(PB("cli")?"true":"false"),
226 @ alertSound: "%h(zAlert)",
227 @ initSize: %d(db_get_int("chat-initial-history",50)),
228 @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
229 @ };
230 ajax_emit_js_preview_modes(0);
231 chat_emit_alert_list();
232 cgi_append_content(builtin_text("chat.js"),-1);
233 @ }, false);
234 @ </script>
235
236 style_finish_page();
237 }
238
239 /* Definition of repository tables used by chat
240 */
241
242 ELETED src/chat.js
--- src/chat.c
+++ src/chat.c
@@ -217,24 +217,23 @@
217 /* Always in-line the javascript for the chat page */
218 @ <script nonce="%h(style_nonce())">/* chat.c:%d(__LINE__) */
219 /* We need an onload handler to ensure that window.fossil is
220 initialized before the chat init code runs. */
221 @ window.addEventListener('load', function(){
222 @ document.body.classList.add('chat');
223 @ /*^^^for skins which add their own BODY tag */;
224 @ window.fossil.config.chat = {
225 @ fromcli: %h(PB("cli")?"true":"false"),
226 @ alertSound: "%h(zAlert)",
227 @ initSize: %d(db_get_int("chat-initial-history",50)),
228 @ imagesInline: !!%d(db_get_boolean("chat-inline-images",1))
229 @ };
230 ajax_emit_js_preview_modes(0);
231 chat_emit_alert_list();
 
232 @ }, false);
233 @ </script>
234 builtin_request_js("fossil.page.chat.js");
235 style_finish_page();
236 }
237
238 /* Definition of repository tables used by chat
239 */
240
241 ELETED src/chat.js
D src/chat.js
-16
--- a/src/chat.js
+++ b/src/chat.js
@@ -1,16 +0,0 @@
1
-f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2
- body > div.mainmenu'),'),
3
- body > #hbdrop'),
4
- body > div.footer')
5
- ];
6
- const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
7
- user:8@8Lu,S: activeTag: undefined,
8
- f@1ds,p: return !this.activeTag || this.activeTag===uname;
9
-N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
10
- hashtag:8@8Lu,u: activeTag: undefined,
11
- match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
12
-N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
13
- current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
14
- && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
15
- 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16
-A@BVF,a:).for
--- a/src/chat.js
+++ b/src/chat.js
@@ -1,16 +0,0 @@
1 f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2 body > div.mainmenu'),'),
3 body > #hbdrop'),
4 body > div.footer')
5 ];
6 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
7 user:8@8Lu,S: activeTag: undefined,
8 f@1ds,p: return !this.activeTag || this.activeTag===uname;
9 N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
10 hashtag:8@8Lu,u: activeTag: undefined,
11 match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
12 N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
13 current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
14 && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
15 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16 A@BVF,a:).for
--- a/src/chat.js
+++ b/src/chat.js
@@ -1,16 +0,0 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -280,15 +280,17 @@
280280
}
281281
return this;
282282
};
283283
284284
/**
285
- Sets the innerText of the page's TITLE tag to
286
- the given text and returns this object.
285
+ Sets the innerText of the page's TITLE tag to the given text and
286
+ returns this object. If passed a falsy value then the title is
287
+ reverted to its page-load-time value.
287288
*/
288
- F.page.setPageTitle = function(title){
289
+ F.page.setPageTitle = function f(title){
289290
const t = document.querySelector('title');
290
- if(t) t.innerText = title;
291
+ if(t) t.innerText = title || f.$orig;
291292
return this;
292293
};
293
-
294
+ F.onPageLoad(()=>F.page.setPageTitle.$orig
295
+ = document.querySelector('title').innerText);
294296
})(window);
295297
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -280,15 +280,17 @@
280 }
281 return this;
282 };
283
284 /**
285 Sets the innerText of the page's TITLE tag to
286 the given text and returns this object.
 
287 */
288 F.page.setPageTitle = function(title){
289 const t = document.querySelector('title');
290 if(t) t.innerText = title;
291 return this;
292 };
293
 
294 })(window);
295
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -280,15 +280,17 @@
280 }
281 return this;
282 };
283
284 /**
285 Sets the innerText of the page's TITLE tag to the given text and
286 returns this object. If passed a falsy value then the title is
287 reverted to its page-load-time value.
288 */
289 F.page.setPageTitle = function f(title){
290 const t = document.querySelector('title');
291 if(t) t.innerText = title || f.$orig;
292 return this;
293 };
294 F.onPageLoad(()=>F.page.setPageTitle.$orig
295 = document.querySelector('title').innerText);
296 })(window);
297
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -280,15 +280,17 @@
280280
}
281281
return this;
282282
};
283283
284284
/**
285
- Sets the innerText of the page's TITLE tag to
286
- the given text and returns this object.
285
+ Sets the innerText of the page's TITLE tag to the given text and
286
+ returns this object. If passed a falsy value then the title is
287
+ reverted to its page-load-time value.
287288
*/
288
- F.page.setPageTitle = function(title){
289
+ F.page.setPageTitle = function f(title){
289290
const t = document.querySelector('title');
290
- if(t) t.innerText = title;
291
+ if(t) t.innerText = title || f.$orig;
291292
return this;
292293
};
293
-
294
+ F.onPageLoad(()=>F.page.setPageTitle.$orig
295
+ = document.querySelector('title').innerText);
294296
})(window);
295297
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -280,15 +280,17 @@
280 }
281 return this;
282 };
283
284 /**
285 Sets the innerText of the page's TITLE tag to
286 the given text and returns this object.
 
287 */
288 F.page.setPageTitle = function(title){
289 const t = document.querySelector('title');
290 if(t) t.innerText = title;
291 return this;
292 };
293
 
294 })(window);
295
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -280,15 +280,17 @@
280 }
281 return this;
282 };
283
284 /**
285 Sets the innerText of the page's TITLE tag to the given text and
286 returns this object. If passed a falsy value then the title is
287 reverted to its page-load-time value.
288 */
289 F.page.setPageTitle = function f(title){
290 const t = document.querySelector('title');
291 if(t) t.innerText = title || f.$orig;
292 return this;
293 };
294 F.onPageLoad(()=>F.page.setPageTitle.$orig
295 = document.querySelector('title').innerText);
296 })(window);
297
+31 -14
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -117,10 +117,11 @@
117117
example of which, for use as a model, is:
118118
119119
https://github.com/msteveb/autosetup/commit/235925e914a52a542
120120
*/
121121
const ChunkLoadControls = function(tr){
122
+ this.$fetchQueue = [];
122123
this.e = {/*DOM elements*/
123124
tr: tr,
124125
table: tr.parentElement/*TBODY*/.parentElement
125126
};
126127
this.isSplit = this.e.table.classList.contains('splitdiff')/*else udiff*/;
@@ -209,17 +210,13 @@
209210
/** Fill a complete gap between the previous/next diff chunks
210211
or at the start of the next chunk or end of the previous
211212
chunks. */
212213
FillGap: 0,
213214
/** Prepend context to the start of the next diff chunk. */
214
- NextUp: -1
215
- },
216
- config: {
217
- /*
218
- glyphUp: '⇡', //'&#uarr;',
219
- glyphDown: '⇣' //'&#darr;'
220
- */
215
+ NextUp: -1,
216
+ /** Process the next queued action. */
217
+ ProcessQueue: 0x7fffffff
221218
},
222219
223220
/**
224221
Creates and returns a button element for fetching a chunk in
225222
the given fetchType (as documented for fetchChunk()).
@@ -262,10 +259,11 @@
262259
},
263260
264261
/* Attempt to clean up resources and remove some circular references to
265262
that GC can do the right thing. */
266263
destroy: function(){
264
+ delete this.$fetchQueue;
267265
D.remove(this.e.tr);
268266
delete this.e.tr.$chunker;
269267
delete this.e.tr;
270268
delete this.e;
271269
delete this.pos;
@@ -282,10 +280,13 @@
282280
maybeReplaceButtons: function(){
283281
if(this.pos.next && this.pos.prev
284282
&& (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){
285283
D.clearElement(this.e.btnWrapper);
286284
D.append(this.e.btnWrapper, this.createButton(this.FetchType.FillGap));
285
+ if( this.$fetchQueue && this.$fetchQueue.length>0 ){
286
+ this.$fetchQueue = [this.FetchType.FillGap];
287
+ }
287288
}
288289
return this;
289290
},
290291
291292
/**
@@ -501,28 +502,42 @@
501502
This is an async operation. While it is in transit, any calls
502503
to this function will have no effect except (possibly) to emit
503504
a warning. Returns this object.
504505
*/
505506
fetchChunk: function(fetchType){
507
+ if( !this.$fetchQueue ) return this; // HACKHACK: are we destroyed?
508
+ if( fetchType==this.FetchType.ProcessQueue ){
509
+ if( this.$fetchQueue.length==0 ) return this;
510
+ //console.log('fetchChunk: processing queue ...');
511
+ }
512
+ else{
513
+ this.$fetchQueue.push(fetchType);
514
+ if( this.$fetchQueue.length!=1 ) return this;
515
+ //console.log('fetchChunk: processing user input ...');
516
+ }
517
+ fetchType = this.$fetchQueue[0];
506518
/* Forewarning, this is a bit confusing: when fetching the
507519
previous lines, we're doing so on behalf of the *next* diff
508520
chunk (this.pos.next), and vice versa. */
509
- if(this.$isFetching){
510
- return this.msg(true,"Cannot load chunk while a load is pending.");
511
- }
512521
if(fetchType===this.FetchType.NextUp && !this.pos.next
513522
|| fetchType===this.FetchType.PrevDown && !this.pos.prev){
514523
console.error("Attempt to fetch diff lines but don't have any.");
515524
return this;
516525
}
517526
this.msg(false,"Fetching diff chunk...");
527
+ const self = this;
518528
const fOpt = {
519529
urlParams:{
520530
name: this.fileHash, from: 0, to: 0
521531
},
522
- aftersend: ()=>delete this.$isFetching,
523
- onload: (list)=>this.injectResponse(fetchType,up,list)
532
+ aftersend: ()=>this.msg(false),
533
+ onload: function(list){
534
+ self.injectResponse(fetchType,up,list);
535
+ if( !self.$fetchQueue || self.$fetchQueue.length==0 ) return;
536
+ self.$fetchQueue.shift();
537
+ setTimeout(self.fetchChunk.bind(self,self.FetchType.ProcessQueue));
538
+ }
524539
};
525540
const up = fOpt.urlParams;
526541
if(fetchType===this.FetchType.FillGap){
527542
/* Easiest case: filling a whole gap. */
528543
up.from = this.pos.startLhs;
@@ -551,13 +566,15 @@
551566
if( this.pos.prev && this.pos.prev.endLhs >= up.from ){
552567
up.from = this.pos.prev.endLhs + 1;
553568
fetchType = this.FetchType.FillGap;
554569
}
555570
}
556
- this.$isFetching = true;
557571
//console.debug("fetchChunk(",fetchType,")",up);
558
- fOpt.onerror = (err)=>this.msg(true,err.message);
572
+ fOpt.onerror = function(err){
573
+ self.msg(true,err.message);
574
+ self.$fetchQueue = [];
575
+ };
559576
Diff.fetchArtifactChunk(fOpt);
560577
return this;
561578
}
562579
};
563580
564581
565582
ADDED src/fossil.page.chat.js
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -117,10 +117,11 @@
117 example of which, for use as a model, is:
118
119 https://github.com/msteveb/autosetup/commit/235925e914a52a542
120 */
121 const ChunkLoadControls = function(tr){
 
122 this.e = {/*DOM elements*/
123 tr: tr,
124 table: tr.parentElement/*TBODY*/.parentElement
125 };
126 this.isSplit = this.e.table.classList.contains('splitdiff')/*else udiff*/;
@@ -209,17 +210,13 @@
209 /** Fill a complete gap between the previous/next diff chunks
210 or at the start of the next chunk or end of the previous
211 chunks. */
212 FillGap: 0,
213 /** Prepend context to the start of the next diff chunk. */
214 NextUp: -1
215 },
216 config: {
217 /*
218 glyphUp: '⇡', //'&#uarr;',
219 glyphDown: '⇣' //'&#darr;'
220 */
221 },
222
223 /**
224 Creates and returns a button element for fetching a chunk in
225 the given fetchType (as documented for fetchChunk()).
@@ -262,10 +259,11 @@
262 },
263
264 /* Attempt to clean up resources and remove some circular references to
265 that GC can do the right thing. */
266 destroy: function(){
 
267 D.remove(this.e.tr);
268 delete this.e.tr.$chunker;
269 delete this.e.tr;
270 delete this.e;
271 delete this.pos;
@@ -282,10 +280,13 @@
282 maybeReplaceButtons: function(){
283 if(this.pos.next && this.pos.prev
284 && (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){
285 D.clearElement(this.e.btnWrapper);
286 D.append(this.e.btnWrapper, this.createButton(this.FetchType.FillGap));
 
 
 
287 }
288 return this;
289 },
290
291 /**
@@ -501,28 +502,42 @@
501 This is an async operation. While it is in transit, any calls
502 to this function will have no effect except (possibly) to emit
503 a warning. Returns this object.
504 */
505 fetchChunk: function(fetchType){
 
 
 
 
 
 
 
 
 
 
 
506 /* Forewarning, this is a bit confusing: when fetching the
507 previous lines, we're doing so on behalf of the *next* diff
508 chunk (this.pos.next), and vice versa. */
509 if(this.$isFetching){
510 return this.msg(true,"Cannot load chunk while a load is pending.");
511 }
512 if(fetchType===this.FetchType.NextUp && !this.pos.next
513 || fetchType===this.FetchType.PrevDown && !this.pos.prev){
514 console.error("Attempt to fetch diff lines but don't have any.");
515 return this;
516 }
517 this.msg(false,"Fetching diff chunk...");
 
518 const fOpt = {
519 urlParams:{
520 name: this.fileHash, from: 0, to: 0
521 },
522 aftersend: ()=>delete this.$isFetching,
523 onload: (list)=>this.injectResponse(fetchType,up,list)
 
 
 
 
 
524 };
525 const up = fOpt.urlParams;
526 if(fetchType===this.FetchType.FillGap){
527 /* Easiest case: filling a whole gap. */
528 up.from = this.pos.startLhs;
@@ -551,13 +566,15 @@
551 if( this.pos.prev && this.pos.prev.endLhs >= up.from ){
552 up.from = this.pos.prev.endLhs + 1;
553 fetchType = this.FetchType.FillGap;
554 }
555 }
556 this.$isFetching = true;
557 //console.debug("fetchChunk(",fetchType,")",up);
558 fOpt.onerror = (err)=>this.msg(true,err.message);
 
 
 
559 Diff.fetchArtifactChunk(fOpt);
560 return this;
561 }
562 };
563
564
565 DDED src/fossil.page.chat.js
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -117,10 +117,11 @@
117 example of which, for use as a model, is:
118
119 https://github.com/msteveb/autosetup/commit/235925e914a52a542
120 */
121 const ChunkLoadControls = function(tr){
122 this.$fetchQueue = [];
123 this.e = {/*DOM elements*/
124 tr: tr,
125 table: tr.parentElement/*TBODY*/.parentElement
126 };
127 this.isSplit = this.e.table.classList.contains('splitdiff')/*else udiff*/;
@@ -209,17 +210,13 @@
210 /** Fill a complete gap between the previous/next diff chunks
211 or at the start of the next chunk or end of the previous
212 chunks. */
213 FillGap: 0,
214 /** Prepend context to the start of the next diff chunk. */
215 NextUp: -1,
216 /** Process the next queued action. */
217 ProcessQueue: 0x7fffffff
 
 
 
 
218 },
219
220 /**
221 Creates and returns a button element for fetching a chunk in
222 the given fetchType (as documented for fetchChunk()).
@@ -262,10 +259,11 @@
259 },
260
261 /* Attempt to clean up resources and remove some circular references to
262 that GC can do the right thing. */
263 destroy: function(){
264 delete this.$fetchQueue;
265 D.remove(this.e.tr);
266 delete this.e.tr.$chunker;
267 delete this.e.tr;
268 delete this.e;
269 delete this.pos;
@@ -282,10 +280,13 @@
280 maybeReplaceButtons: function(){
281 if(this.pos.next && this.pos.prev
282 && (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){
283 D.clearElement(this.e.btnWrapper);
284 D.append(this.e.btnWrapper, this.createButton(this.FetchType.FillGap));
285 if( this.$fetchQueue && this.$fetchQueue.length>0 ){
286 this.$fetchQueue = [this.FetchType.FillGap];
287 }
288 }
289 return this;
290 },
291
292 /**
@@ -501,28 +502,42 @@
502 This is an async operation. While it is in transit, any calls
503 to this function will have no effect except (possibly) to emit
504 a warning. Returns this object.
505 */
506 fetchChunk: function(fetchType){
507 if( !this.$fetchQueue ) return this; // HACKHACK: are we destroyed?
508 if( fetchType==this.FetchType.ProcessQueue ){
509 if( this.$fetchQueue.length==0 ) return this;
510 //console.log('fetchChunk: processing queue ...');
511 }
512 else{
513 this.$fetchQueue.push(fetchType);
514 if( this.$fetchQueue.length!=1 ) return this;
515 //console.log('fetchChunk: processing user input ...');
516 }
517 fetchType = this.$fetchQueue[0];
518 /* Forewarning, this is a bit confusing: when fetching the
519 previous lines, we're doing so on behalf of the *next* diff
520 chunk (this.pos.next), and vice versa. */
 
 
 
521 if(fetchType===this.FetchType.NextUp && !this.pos.next
522 || fetchType===this.FetchType.PrevDown && !this.pos.prev){
523 console.error("Attempt to fetch diff lines but don't have any.");
524 return this;
525 }
526 this.msg(false,"Fetching diff chunk...");
527 const self = this;
528 const fOpt = {
529 urlParams:{
530 name: this.fileHash, from: 0, to: 0
531 },
532 aftersend: ()=>this.msg(false),
533 onload: function(list){
534 self.injectResponse(fetchType,up,list);
535 if( !self.$fetchQueue || self.$fetchQueue.length==0 ) return;
536 self.$fetchQueue.shift();
537 setTimeout(self.fetchChunk.bind(self,self.FetchType.ProcessQueue));
538 }
539 };
540 const up = fOpt.urlParams;
541 if(fetchType===this.FetchType.FillGap){
542 /* Easiest case: filling a whole gap. */
543 up.from = this.pos.startLhs;
@@ -551,13 +566,15 @@
566 if( this.pos.prev && this.pos.prev.endLhs >= up.from ){
567 up.from = this.pos.prev.endLhs + 1;
568 fetchType = this.FetchType.FillGap;
569 }
570 }
 
571 //console.debug("fetchChunk(",fetchType,")",up);
572 fOpt.onerror = function(err){
573 self.msg(true,err.message);
574 self.$fetchQueue = [];
575 };
576 Diff.fetchArtifactChunk(fOpt);
577 return this;
578 }
579 };
580
581
582 DDED src/fossil.page.chat.js
--- a/src/fossil.page.chat.js
+++ b/src/fossil.page.chat.js
@@ -1,5 +1,5 @@
11
f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2
- body > div.mainmenu'),'),
2
+ body > div.mainmenu'),
33
body > #hbdrop'),
44
body > div.footer')
55
];
@@ -13,4 +13,85 @@
1313
current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
1414
&& !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
1515
8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16
-A@BVF,a:).for
16
+A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
17
+ For each Chat.MessageWidget element (X.message-widget) for
18
+9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
19
+ added. If predicate is falsy, 'hidden' is removed from all
20
+ elements. After filtering, it will try to scroll the last
21
+ not-filsage into view, but exactly where it
22
+ scrolls into view (top, middle, button) is
23
+ unpredictableM@5GB,2C:
24
+
25
+ The argument may optionally be an object from this.filter,
26
+ in which case its matchElem() method becomes the predicate.
27
+
28
+9@Jkj,2i:Note that this does not encapsulate certain filter-specific
29
+ logic which applies changes to elements other than the
30
+ main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
31
+ /* assume Chat.filter objectK@77z,F:p = predicate;
32
+A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
33
+X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
34
+ n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
35
+ if(!f.elemsToCount){
36
+d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
37
+ d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
38
+ inputSingsingle'),
39
+inputMultimulti'),
40
+ inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
41
+ body > div.mainmenu'),
42
+ body > #hbdrop'),
43
+ body > div.footer')
44
+ ];
45
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
46
+ user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
47
+ }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
48
+ }refif(0)ole.debug("onpopstate event",event.state, event);
49
+ if(event.state && event.state.msgIevent.state.msgId+'"]');
50
+ event.state//F.page.setPageTitle("Fossi1?"console.debug("History length =f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
51
+ body > div.mainmenu'),
52
+ body > #hbdrop'),
53
+ body > div.footer')
54
+ ];
55
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
56
+ user:8@8Lu,S: activeTag: undefined,
57
+ f@1ds,p: return !this.activeTag || this.activeTag===uname;
58
+N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
59
+ hashtag:8@8Lu,u: activeTag: undefined,
60
+ match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
61
+N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
62
+ current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
63
+ && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
64
+ 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
65
+A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
66
+ For each Chat.MessageWidget element (X.message-widget) for
67
+9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
68
+ added. If predicate is falsy, 'hidden' is removed from all
69
+ elements. After filtering, it will try to scroll the last
70
+ not-filsage into view, but exactly where it
71
+ scrolls into view (top, middle, button) is
72
+ unpredictableM@5GB,2C:
73
+
74
+ The argument may optionally be an object from this.filter,
75
+ in which case its matchElem() method becomes the predicate.
76
+
77
+9@Jkj,2i:Note that this does not encapsulate certain filter-specific
78
+ logic which applies changes to elements other than the
79
+ main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
80
+ /* assume Chat.filter objectK@77z,F:p = predicate;
81
+A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
82
+X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
83
+ n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
84
+ if(!f.elemsToCount){
85
+d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
86
+ d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
87
+ inputSingsingle'),
88
+inputMultimulti'),
89
+ inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
90
+ body > div.mainmenu'),
91
+ body > #hbdrop'),
92
+ body > div.footer')
93
+ ];
94
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
95
+ user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
96
+ }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
97
+ }
--- a/src/fossil.page.chat.js
+++ b/src/fossil.page.chat.js
@@ -1,5 +1,5 @@
1 f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2 body > div.mainmenu'),'),
3 body > #hbdrop'),
4 body > div.footer')
5 ];
@@ -13,4 +13,85 @@
13 current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
14 && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
15 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16 A@BVF,a:).for
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/fossil.page.chat.js
+++ b/src/fossil.page.chat.js
@@ -1,5 +1,5 @@
1 f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2 body > div.mainmenu'),
3 body > #hbdrop'),
4 body > div.footer')
5 ];
@@ -13,4 +13,85 @@
13 current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
14 && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
15 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16 A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
17 For each Chat.MessageWidget element (X.message-widget) for
18 9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
19 added. If predicate is falsy, 'hidden' is removed from all
20 elements. After filtering, it will try to scroll the last
21 not-filsage into view, but exactly where it
22 scrolls into view (top, middle, button) is
23 unpredictableM@5GB,2C:
24
25 The argument may optionally be an object from this.filter,
26 in which case its matchElem() method becomes the predicate.
27
28 9@Jkj,2i:Note that this does not encapsulate certain filter-specific
29 logic which applies changes to elements other than the
30 main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
31 /* assume Chat.filter objectK@77z,F:p = predicate;
32 A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
33 X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
34 n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
35 if(!f.elemsToCount){
36 d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
37 d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
38 inputSingsingle'),
39 inputMultimulti'),
40 inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
41 body > div.mainmenu'),
42 body > #hbdrop'),
43 body > div.footer')
44 ];
45 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
46 user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
47 }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
48 }refif(0)ole.debug("onpopstate event",event.state, event);
49 if(event.state && event.state.msgIevent.state.msgId+'"]');
50 event.state//F.page.setPageTitle("Fossi1?"console.debug("History length =f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
51 body > div.mainmenu'),
52 body > #hbdrop'),
53 body > div.footer')
54 ];
55 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
56 user:8@8Lu,S: activeTag: undefined,
57 f@1ds,p: return !this.activeTag || this.activeTag===uname;
58 N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
59 hashtag:8@8Lu,u: activeTag: undefined,
60 match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
61 N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
62 current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
63 && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
64 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
65 A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
66 For each Chat.MessageWidget element (X.message-widget) for
67 9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
68 added. If predicate is falsy, 'hidden' is removed from all
69 elements. After filtering, it will try to scroll the last
70 not-filsage into view, but exactly where it
71 scrolls into view (top, middle, button) is
72 unpredictableM@5GB,2C:
73
74 The argument may optionally be an object from this.filter,
75 in which case its matchElem() method becomes the predicate.
76
77 9@Jkj,2i:Note that this does not encapsulate certain filter-specific
78 logic which applies changes to elements other than the
79 main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
80 /* assume Chat.filter objectK@77z,F:p = predicate;
81 A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
82 X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
83 n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
84 if(!f.elemsToCount){
85 d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
86 d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
87 inputSingsingle'),
88 inputMultimulti'),
89 inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
90 body > div.mainmenu'),
91 body > #hbdrop'),
92 body > div.footer')
93 ];
94 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
95 user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
96 }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
97 }
--- a/src/fossil.page.chat.js
+++ b/src/fossil.page.chat.js
@@ -0,0 +1,97 @@
1
+f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2
+ body > div.mainmenu'),
3
+ body > #hbdrop'),
4
+ body > div.footer')
5
+ ];
6
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
7
+ user:8@8Lu,S: activeTag: undefined,
8
+ f@1ds,p: return !this.activeTag || this.activeTag===uname;
9
+N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
10
+ hashtag:8@8Lu,u: activeTag: undefined,
11
+ match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
12
+N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
13
+ current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
14
+ && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
15
+ 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16
+A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
17
+ For each Chat.MessageWidget element (X.message-widget) for
18
+9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
19
+ added. If predicate is falsy, 'hidden' is removed from all
20
+ elements. After filtering, it will try to scroll the last
21
+ not-filsage into view, but exactly where it
22
+ scrolls into view (top, middle, button) is
23
+ unpredictableM@5GB,2C:
24
+
25
+ The argument may optionally be an object from this.filter,
26
+ in which case its matchElem() method becomes the predicate.
27
+
28
+9@Jkj,2i:Note that this does not encapsulate certain filter-specific
29
+ logic which applies changes to elements other than the
30
+ main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
31
+ /* assume Chat.filter objectK@77z,F:p = predicate;
32
+A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
33
+X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
34
+ n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
35
+ if(!f.elemsToCount){
36
+d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
37
+ d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
38
+ inputSingsingle'),
39
+inputMultimulti'),
40
+ inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
41
+ body > div.mainmenu'),
42
+ body > #hbdrop'),
43
+ body > div.footer')
44
+ ];
45
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
46
+ user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
47
+ }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
48
+ }refif(0)ole.debug("onpopstate event",event.state, event);
49
+ if(event.state && event.state.msgIevent.state.msgId+'"]');
50
+ event.state//F.page.setPageTitle("Fossi1?"console.debug("History length =f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
51
+ body > div.mainmenu'),
52
+ body > #hbdrop'),
53
+ body > div.footer')
54
+ ];
55
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
56
+ user:8@8Lu,S: activeTag: undefined,
57
+ f@1ds,p: return !this.activeTag || this.activeTag===uname;
58
+N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
59
+ hashtag:8@8Lu,u: activeTag: undefined,
60
+ match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
61
+N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
62
+ current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
63
+ && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
64
+ 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
65
+A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
66
+ For each Chat.MessageWidget element (X.message-widget) for
67
+9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
68
+ added. If predicate is falsy, 'hidden' is removed from all
69
+ elements. After filtering, it will try to scroll the last
70
+ not-filsage into view, but exactly where it
71
+ scrolls into view (top, middle, button) is
72
+ unpredictableM@5GB,2C:
73
+
74
+ The argument may optionally be an object from this.filter,
75
+ in which case its matchElem() method becomes the predicate.
76
+
77
+9@Jkj,2i:Note that this does not encapsulate certain filter-specific
78
+ logic which applies changes to elements other than the
79
+ main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
80
+ /* assume Chat.filter objectK@77z,F:p = predicate;
81
+A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
82
+X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
83
+ n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
84
+ if(!f.elemsToCount){
85
+d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
86
+ d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
87
+ inputSingsingle'),
88
+inputMultimulti'),
89
+ inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
90
+ body > div.mainmenu'),
91
+ body > #hbdrop'),
92
+ body > div.footer')
93
+ ];
94
+ const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
95
+ user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
96
+ }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
97
+ }
--- a/src/fossil.page.chat.js
+++ b/src/fossil.page.chat.js
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/src/fossil.page.chat.js
+++ b/src/fossil.page.chat.js
@@ -0,0 +1,97 @@
1 f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
2 body > div.mainmenu'),
3 body > #hbdrop'),
4 body > div.footer')
5 ];
6 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
7 user:8@8Lu,S: activeTag: undefined,
8 f@1ds,p: return !this.activeTag || this.activeTag===uname;
9 N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
10 hashtag:8@8Lu,u: activeTag: undefined,
11 match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
12 N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
13 current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
14 && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
15 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
16 A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
17 For each Chat.MessageWidget element (X.message-widget) for
18 9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
19 added. If predicate is falsy, 'hidden' is removed from all
20 elements. After filtering, it will try to scroll the last
21 not-filsage into view, but exactly where it
22 scrolls into view (top, middle, button) is
23 unpredictableM@5GB,2C:
24
25 The argument may optionally be an object from this.filter,
26 in which case its matchElem() method becomes the predicate.
27
28 9@Jkj,2i:Note that this does not encapsulate certain filter-specific
29 logic which applies changes to elements other than the
30 main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
31 /* assume Chat.filter objectK@77z,F:p = predicate;
32 A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
33 X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
34 n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
35 if(!f.elemsToCount){
36 d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
37 d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
38 inputSingsingle'),
39 inputMultimulti'),
40 inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
41 body > div.mainmenu'),
42 body > #hbdrop'),
43 body > div.footer')
44 ];
45 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
46 user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
47 }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
48 }refif(0)ole.debug("onpopstate event",event.state, event);
49 if(event.state && event.state.msgIevent.state.msgId+'"]');
50 event.state//F.page.setPageTitle("Fossi1?"console.debug("History length =f =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
51 body > div.mainmenu'),
52 body > #hbdrop'),
53 body > div.footer')
54 ];
55 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
56 user:8@8Lu,S: activeTag: undefined,
57 f@1ds,p: return !this.activeTag || this.activeTag===uname;
58 N@Bul,9:matchElemP@IXT,x: return !this.activeTag || this.activeTag===e.dataset.xfromN@IvG,I:,
59 hashtag:8@8Lu,u: activeTag: undefined,
60 match: function(tag){J@JU~,f: !this.activeTag || tag===this.activeTag;
61 N@Bul,9:matchElemP@IXT,O: return !this.activeTag8@HYy,11: || !!e.querySelector('[data-hashtag="'+this.activeTag+'"]'O@A5G,11:,
62 current: undefined/*gets set to current active filter*/J@4n~,vt@1fm,12:this.filter.current
63 && !this.filter.current.matchElem(eoe@2bG,3:[];K@G8C,H@KVF,5:
64 8@35A,J:["body > div.headerG@120,K:"body > div.mainmenuG@120,I:"body > div.footerG@120,B:"#debugMsg"9@H1C,G: ].join(',')
65 A@BVF,a:).forEach((e)=>f.elemsToToggle.push(e1L6@3Ql,8:D.removeN@5vE,Ha@4mY,J:.user.activeTag===uH@APW,By@53h,15:
66 For each Chat.MessageWidget element (X.message-widget) for
67 9@9NF,u:which predicate(elem) returns true, the 'hidden' class isA@5NB,5A:removed from that message. For all others, 'hidden' is
68 added. If predicate is falsy, 'hidden' is removed from all
69 elements. After filtering, it will try to scroll the last
70 not-filsage into view, but exactly where it
71 scrolls into view (top, middle, button) is
72 unpredictableM@5GB,2C:
73
74 The argument may optionally be an object from this.filter,
75 in which case its matchElem() method becomes the predicate.
76
77 9@Jkj,2i:Note that this does not encapsulate certain filter-specific
78 logic which applies changes to elements other than the
79 main message list or this.e.btnClearFiltJ@3O0,b:applyMessageFilter: function(predicateB@HBh,R@AzV,J@5aF,o:console.debug("applyMessageFilter(",predicate,")");9@3rt,E:if(!predicate)Q@3VT,4:this1c@5bA0 ?){} : (function fif('function'!==typeof predicateH@BFG,~:&& predicate.matchElem){
80 /* assume Chat.filter objectK@77z,F:p = predicate;
81 A@Af6,T:predicate = (e)=>p.matchElem(M@2Ul,B:if(predicatJ@6_l,l@5bB,U@KV~,K: if(predicate(eG@J_W,3: eJ@Jpy,I@HoF,H: eLast = e;
82 X@AoW,Z@2bU,S@5gS,a: D.removeClass(this.e.btnClearFilterL@9x~,6:}
83 n@DS9,1Q@5gz,e@4dl,A:Clears theG@5X0,X: filter, if any, a */
84 if(!f.elemsToCount){
85 d.tf =tru//li.f =tru//li.push(ggle.push(e1L6@3Ql,8:D.removggle.push(e1L6@3Ql,8:D.removeN@5v#hbdrop'),
86 d.tf =tru//li.push( d.t/li.f =tru//li.pumessage-submit'),
87 inputSingsingle'),
88 inputMultimulti'),
89 inputCpreview-buttonvaluevalue-clear-filterD8@1R8,Hf =tru//li.push( d.tf =tru//li.push( d.t/li.pusbody > div.header'),
90 body > div.mainmenu'),
91 body > #hbdrop'),
92 body > div.footer')
93 ];
94 const contentArea = E1('div.content')divf =tru//li.push( d.t E1('#chat-clear-filterD8@1R8,H:: {
95 user:8@8Lu,S: acCurrent-clear-filterD8@1R8,H:f =tru//li.push( d.tToggleSingleMulticonst old = this.e.inputCurrentcontentArea = E1('f =tru//li.inputCurrent = this.e.inputMulti;inputLinesingle-lineul,9:matchElemP@IXTf =tru//li.push( d.tf =tru//li.pusru//li.push( d.tf =ti.push( d.t/li.pusbody > diChat.e.inputSinglkeydown@3VT,4:this1c@5bA0 ?if(13===ev.keyCode/*ENTER*/}
96 }inputMultikeydown@3VT,4:this1c@5bA0 ?if(ev.ctrlKey && }
97 }
+1 -1
--- src/main.mk
+++ src/main.mk
@@ -214,11 +214,10 @@
214214
$(SRCDIR)/accordion.js \
215215
$(SRCDIR)/alerts/bflat2.wav \
216216
$(SRCDIR)/alerts/bflat3.wav \
217217
$(SRCDIR)/alerts/bloop.wav \
218218
$(SRCDIR)/alerts/plunk.wav \
219
- $(SRCDIR)/chat.js \
220219
$(SRCDIR)/ci_edit.js \
221220
$(SRCDIR)/copybtn.js \
222221
$(SRCDIR)/default.css \
223222
$(SRCDIR)/diff.js \
224223
$(SRCDIR)/diff.tcl \
@@ -229,10 +228,11 @@
229228
$(SRCDIR)/fossil.diff.js \
230229
$(SRCDIR)/fossil.dom.js \
231230
$(SRCDIR)/fossil.fetch.js \
232231
$(SRCDIR)/fossil.numbered-lines.js \
233232
$(SRCDIR)/fossil.page.brlist.js \
233
+ $(SRCDIR)/fossil.page.chat.js \
234234
$(SRCDIR)/fossil.page.fileedit.js \
235235
$(SRCDIR)/fossil.page.forumpost.js \
236236
$(SRCDIR)/fossil.page.pikchrshow.js \
237237
$(SRCDIR)/fossil.page.whistory.js \
238238
$(SRCDIR)/fossil.page.wikiedit.js \
239239
--- src/main.mk
+++ src/main.mk
@@ -214,11 +214,10 @@
214 $(SRCDIR)/accordion.js \
215 $(SRCDIR)/alerts/bflat2.wav \
216 $(SRCDIR)/alerts/bflat3.wav \
217 $(SRCDIR)/alerts/bloop.wav \
218 $(SRCDIR)/alerts/plunk.wav \
219 $(SRCDIR)/chat.js \
220 $(SRCDIR)/ci_edit.js \
221 $(SRCDIR)/copybtn.js \
222 $(SRCDIR)/default.css \
223 $(SRCDIR)/diff.js \
224 $(SRCDIR)/diff.tcl \
@@ -229,10 +228,11 @@
229 $(SRCDIR)/fossil.diff.js \
230 $(SRCDIR)/fossil.dom.js \
231 $(SRCDIR)/fossil.fetch.js \
232 $(SRCDIR)/fossil.numbered-lines.js \
233 $(SRCDIR)/fossil.page.brlist.js \
 
234 $(SRCDIR)/fossil.page.fileedit.js \
235 $(SRCDIR)/fossil.page.forumpost.js \
236 $(SRCDIR)/fossil.page.pikchrshow.js \
237 $(SRCDIR)/fossil.page.whistory.js \
238 $(SRCDIR)/fossil.page.wikiedit.js \
239
--- src/main.mk
+++ src/main.mk
@@ -214,11 +214,10 @@
214 $(SRCDIR)/accordion.js \
215 $(SRCDIR)/alerts/bflat2.wav \
216 $(SRCDIR)/alerts/bflat3.wav \
217 $(SRCDIR)/alerts/bloop.wav \
218 $(SRCDIR)/alerts/plunk.wav \
 
219 $(SRCDIR)/ci_edit.js \
220 $(SRCDIR)/copybtn.js \
221 $(SRCDIR)/default.css \
222 $(SRCDIR)/diff.js \
223 $(SRCDIR)/diff.tcl \
@@ -229,10 +228,11 @@
228 $(SRCDIR)/fossil.diff.js \
229 $(SRCDIR)/fossil.dom.js \
230 $(SRCDIR)/fossil.fetch.js \
231 $(SRCDIR)/fossil.numbered-lines.js \
232 $(SRCDIR)/fossil.page.brlist.js \
233 $(SRCDIR)/fossil.page.chat.js \
234 $(SRCDIR)/fossil.page.fileedit.js \
235 $(SRCDIR)/fossil.page.forumpost.js \
236 $(SRCDIR)/fossil.page.pikchrshow.js \
237 $(SRCDIR)/fossil.page.whistory.js \
238 $(SRCDIR)/fossil.page.wikiedit.js \
239
--- src/style.chat.css
+++ src/style.chat.css
@@ -444,5 +444,13 @@
444444
}
445445
@keyframes fade-out {
446446
from { opacity: 1; }
447447
to { opacity: 0; }
448448
}
449
+
450
+body.chat .anim-fade-out-in {
451
+ animation: fade-out-in 1000ms linear;
452
+}
453
+@keyframes fade-out-in {
454
+ 0%,100% { opacity: 0 }
455
+ 50% { opacity: 1 }
456
+}
449457
--- src/style.chat.css
+++ src/style.chat.css
@@ -444,5 +444,13 @@
444 }
445 @keyframes fade-out {
446 from { opacity: 1; }
447 to { opacity: 0; }
448 }
 
 
 
 
 
 
 
 
449
--- src/style.chat.css
+++ src/style.chat.css
@@ -444,5 +444,13 @@
444 }
445 @keyframes fade-out {
446 from { opacity: 1; }
447 to { opacity: 0; }
448 }
449
450 body.chat .anim-fade-out-in {
451 animation: fade-out-in 1000ms linear;
452 }
453 @keyframes fade-out-in {
454 0%,100% { opacity: 0 }
455 50% { opacity: 1 }
456 }
457
--- src/style.chat.css
+++ src/style.chat.css
@@ -444,5 +444,13 @@
444444
}
445445
@keyframes fade-out {
446446
from { opacity: 1; }
447447
to { opacity: 0; }
448448
}
449
+
450
+body.chat .anim-fade-out-in {
451
+ animation: fade-out-in 1000ms linear;
452
+}
453
+@keyframes fade-out-in {
454
+ 0%,100% { opacity: 0 }
455
+ 50% { opacity: 1 }
456
+}
449457
--- src/style.chat.css
+++ src/style.chat.css
@@ -444,5 +444,13 @@
444 }
445 @keyframes fade-out {
446 from { opacity: 1; }
447 to { opacity: 0; }
448 }
 
 
 
 
 
 
 
 
449
--- src/style.chat.css
+++ src/style.chat.css
@@ -444,5 +444,13 @@
444 }
445 @keyframes fade-out {
446 from { opacity: 1; }
447 to { opacity: 0; }
448 }
449
450 body.chat .anim-fade-out-in {
451 animation: fade-out-in 1000ms linear;
452 }
453 @keyframes fade-out-in {
454 0%,100% { opacity: 0 }
455 50% { opacity: 1 }
456 }
457
--- test/tester.tcl
+++ test/tester.tcl
@@ -305,10 +305,11 @@
305305
diff-command \
306306
dont-push \
307307
dotfiles \
308308
editor \
309309
email-admin \
310
+ email-renew-interval \
310311
email-self \
311312
email-send-command \
312313
email-send-db \
313314
email-send-dir \
314315
email-send-method \
@@ -331,10 +332,11 @@
331332
localauth \
332333
lock-timeout \
333334
main-branch \
334335
mainmenu \
335336
manifest \
337
+ max-cache-entry \
336338
max-loadavg \
337339
max-upload \
338340
mimetypes \
339341
mtime-changes \
340342
pgp-command \
341343
--- test/tester.tcl
+++ test/tester.tcl
@@ -305,10 +305,11 @@
305 diff-command \
306 dont-push \
307 dotfiles \
308 editor \
309 email-admin \
 
310 email-self \
311 email-send-command \
312 email-send-db \
313 email-send-dir \
314 email-send-method \
@@ -331,10 +332,11 @@
331 localauth \
332 lock-timeout \
333 main-branch \
334 mainmenu \
335 manifest \
 
336 max-loadavg \
337 max-upload \
338 mimetypes \
339 mtime-changes \
340 pgp-command \
341
--- test/tester.tcl
+++ test/tester.tcl
@@ -305,10 +305,11 @@
305 diff-command \
306 dont-push \
307 dotfiles \
308 editor \
309 email-admin \
310 email-renew-interval \
311 email-self \
312 email-send-command \
313 email-send-db \
314 email-send-dir \
315 email-send-method \
@@ -331,10 +332,11 @@
332 localauth \
333 lock-timeout \
334 main-branch \
335 mainmenu \
336 manifest \
337 max-cache-entry \
338 max-loadavg \
339 max-upload \
340 mimetypes \
341 mtime-changes \
342 pgp-command \
343
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -623,11 +623,10 @@
623623
$(SRCDIR)/accordion.js \
624624
$(SRCDIR)/alerts/bflat2.wav \
625625
$(SRCDIR)/alerts/bflat3.wav \
626626
$(SRCDIR)/alerts/bloop.wav \
627627
$(SRCDIR)/alerts/plunk.wav \
628
- $(SRCDIR)/chat.js \
629628
$(SRCDIR)/ci_edit.js \
630629
$(SRCDIR)/copybtn.js \
631630
$(SRCDIR)/default.css \
632631
$(SRCDIR)/diff.js \
633632
$(SRCDIR)/diff.tcl \
@@ -638,10 +637,11 @@
638637
$(SRCDIR)/fossil.diff.js \
639638
$(SRCDIR)/fossil.dom.js \
640639
$(SRCDIR)/fossil.fetch.js \
641640
$(SRCDIR)/fossil.numbered-lines.js \
642641
$(SRCDIR)/fossil.page.brlist.js \
642
+ $(SRCDIR)/fossil.page.chat.js \
643643
$(SRCDIR)/fossil.page.fileedit.js \
644644
$(SRCDIR)/fossil.page.forumpost.js \
645645
$(SRCDIR)/fossil.page.pikchrshow.js \
646646
$(SRCDIR)/fossil.page.whistory.js \
647647
$(SRCDIR)/fossil.page.wikiedit.js \
648648
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -623,11 +623,10 @@
623 $(SRCDIR)/accordion.js \
624 $(SRCDIR)/alerts/bflat2.wav \
625 $(SRCDIR)/alerts/bflat3.wav \
626 $(SRCDIR)/alerts/bloop.wav \
627 $(SRCDIR)/alerts/plunk.wav \
628 $(SRCDIR)/chat.js \
629 $(SRCDIR)/ci_edit.js \
630 $(SRCDIR)/copybtn.js \
631 $(SRCDIR)/default.css \
632 $(SRCDIR)/diff.js \
633 $(SRCDIR)/diff.tcl \
@@ -638,10 +637,11 @@
638 $(SRCDIR)/fossil.diff.js \
639 $(SRCDIR)/fossil.dom.js \
640 $(SRCDIR)/fossil.fetch.js \
641 $(SRCDIR)/fossil.numbered-lines.js \
642 $(SRCDIR)/fossil.page.brlist.js \
 
643 $(SRCDIR)/fossil.page.fileedit.js \
644 $(SRCDIR)/fossil.page.forumpost.js \
645 $(SRCDIR)/fossil.page.pikchrshow.js \
646 $(SRCDIR)/fossil.page.whistory.js \
647 $(SRCDIR)/fossil.page.wikiedit.js \
648
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -623,11 +623,10 @@
623 $(SRCDIR)/accordion.js \
624 $(SRCDIR)/alerts/bflat2.wav \
625 $(SRCDIR)/alerts/bflat3.wav \
626 $(SRCDIR)/alerts/bloop.wav \
627 $(SRCDIR)/alerts/plunk.wav \
 
628 $(SRCDIR)/ci_edit.js \
629 $(SRCDIR)/copybtn.js \
630 $(SRCDIR)/default.css \
631 $(SRCDIR)/diff.js \
632 $(SRCDIR)/diff.tcl \
@@ -638,10 +637,11 @@
637 $(SRCDIR)/fossil.diff.js \
638 $(SRCDIR)/fossil.dom.js \
639 $(SRCDIR)/fossil.fetch.js \
640 $(SRCDIR)/fossil.numbered-lines.js \
641 $(SRCDIR)/fossil.page.brlist.js \
642 $(SRCDIR)/fossil.page.chat.js \
643 $(SRCDIR)/fossil.page.fileedit.js \
644 $(SRCDIR)/fossil.page.forumpost.js \
645 $(SRCDIR)/fossil.page.pikchrshow.js \
646 $(SRCDIR)/fossil.page.whistory.js \
647 $(SRCDIR)/fossil.page.wikiedit.js \
648
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -565,11 +565,10 @@
565565
"$(SRCDIR)\accordion.js" \
566566
"$(SRCDIR)\alerts\bflat2.wav" \
567567
"$(SRCDIR)\alerts\bflat3.wav" \
568568
"$(SRCDIR)\alerts\bloop.wav" \
569569
"$(SRCDIR)\alerts\plunk.wav" \
570
- "$(SRCDIR)\chat.js" \
571570
"$(SRCDIR)\ci_edit.js" \
572571
"$(SRCDIR)\copybtn.js" \
573572
"$(SRCDIR)\default.css" \
574573
"$(SRCDIR)\diff.js" \
575574
"$(SRCDIR)\diff.tcl" \
@@ -580,10 +579,11 @@
580579
"$(SRCDIR)\fossil.diff.js" \
581580
"$(SRCDIR)\fossil.dom.js" \
582581
"$(SRCDIR)\fossil.fetch.js" \
583582
"$(SRCDIR)\fossil.numbered-lines.js" \
584583
"$(SRCDIR)\fossil.page.brlist.js" \
584
+ "$(SRCDIR)\fossil.page.chat.js" \
585585
"$(SRCDIR)\fossil.page.fileedit.js" \
586586
"$(SRCDIR)\fossil.page.forumpost.js" \
587587
"$(SRCDIR)\fossil.page.pikchrshow.js" \
588588
"$(SRCDIR)\fossil.page.whistory.js" \
589589
"$(SRCDIR)\fossil.page.wikiedit.js" \
@@ -1174,11 +1174,10 @@
11741174
echo "$(SRCDIR)\accordion.js" >> $@
11751175
echo "$(SRCDIR)\alerts/bflat2.wav" >> $@
11761176
echo "$(SRCDIR)\alerts/bflat3.wav" >> $@
11771177
echo "$(SRCDIR)\alerts/bloop.wav" >> $@
11781178
echo "$(SRCDIR)\alerts/plunk.wav" >> $@
1179
- echo "$(SRCDIR)\chat.js" >> $@
11801179
echo "$(SRCDIR)\ci_edit.js" >> $@
11811180
echo "$(SRCDIR)\copybtn.js" >> $@
11821181
echo "$(SRCDIR)\default.css" >> $@
11831182
echo "$(SRCDIR)\diff.js" >> $@
11841183
echo "$(SRCDIR)\diff.tcl" >> $@
@@ -1189,10 +1188,11 @@
11891188
echo "$(SRCDIR)\fossil.diff.js" >> $@
11901189
echo "$(SRCDIR)\fossil.dom.js" >> $@
11911190
echo "$(SRCDIR)\fossil.fetch.js" >> $@
11921191
echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
11931192
echo "$(SRCDIR)\fossil.page.brlist.js" >> $@
1193
+ echo "$(SRCDIR)\fossil.page.chat.js" >> $@
11941194
echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
11951195
echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
11961196
echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@
11971197
echo "$(SRCDIR)\fossil.page.whistory.js" >> $@
11981198
echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
11991199
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -565,11 +565,10 @@
565 "$(SRCDIR)\accordion.js" \
566 "$(SRCDIR)\alerts\bflat2.wav" \
567 "$(SRCDIR)\alerts\bflat3.wav" \
568 "$(SRCDIR)\alerts\bloop.wav" \
569 "$(SRCDIR)\alerts\plunk.wav" \
570 "$(SRCDIR)\chat.js" \
571 "$(SRCDIR)\ci_edit.js" \
572 "$(SRCDIR)\copybtn.js" \
573 "$(SRCDIR)\default.css" \
574 "$(SRCDIR)\diff.js" \
575 "$(SRCDIR)\diff.tcl" \
@@ -580,10 +579,11 @@
580 "$(SRCDIR)\fossil.diff.js" \
581 "$(SRCDIR)\fossil.dom.js" \
582 "$(SRCDIR)\fossil.fetch.js" \
583 "$(SRCDIR)\fossil.numbered-lines.js" \
584 "$(SRCDIR)\fossil.page.brlist.js" \
 
585 "$(SRCDIR)\fossil.page.fileedit.js" \
586 "$(SRCDIR)\fossil.page.forumpost.js" \
587 "$(SRCDIR)\fossil.page.pikchrshow.js" \
588 "$(SRCDIR)\fossil.page.whistory.js" \
589 "$(SRCDIR)\fossil.page.wikiedit.js" \
@@ -1174,11 +1174,10 @@
1174 echo "$(SRCDIR)\accordion.js" >> $@
1175 echo "$(SRCDIR)\alerts/bflat2.wav" >> $@
1176 echo "$(SRCDIR)\alerts/bflat3.wav" >> $@
1177 echo "$(SRCDIR)\alerts/bloop.wav" >> $@
1178 echo "$(SRCDIR)\alerts/plunk.wav" >> $@
1179 echo "$(SRCDIR)\chat.js" >> $@
1180 echo "$(SRCDIR)\ci_edit.js" >> $@
1181 echo "$(SRCDIR)\copybtn.js" >> $@
1182 echo "$(SRCDIR)\default.css" >> $@
1183 echo "$(SRCDIR)\diff.js" >> $@
1184 echo "$(SRCDIR)\diff.tcl" >> $@
@@ -1189,10 +1188,11 @@
1189 echo "$(SRCDIR)\fossil.diff.js" >> $@
1190 echo "$(SRCDIR)\fossil.dom.js" >> $@
1191 echo "$(SRCDIR)\fossil.fetch.js" >> $@
1192 echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
1193 echo "$(SRCDIR)\fossil.page.brlist.js" >> $@
 
1194 echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
1195 echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
1196 echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@
1197 echo "$(SRCDIR)\fossil.page.whistory.js" >> $@
1198 echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
1199
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -565,11 +565,10 @@
565 "$(SRCDIR)\accordion.js" \
566 "$(SRCDIR)\alerts\bflat2.wav" \
567 "$(SRCDIR)\alerts\bflat3.wav" \
568 "$(SRCDIR)\alerts\bloop.wav" \
569 "$(SRCDIR)\alerts\plunk.wav" \
 
570 "$(SRCDIR)\ci_edit.js" \
571 "$(SRCDIR)\copybtn.js" \
572 "$(SRCDIR)\default.css" \
573 "$(SRCDIR)\diff.js" \
574 "$(SRCDIR)\diff.tcl" \
@@ -580,10 +579,11 @@
579 "$(SRCDIR)\fossil.diff.js" \
580 "$(SRCDIR)\fossil.dom.js" \
581 "$(SRCDIR)\fossil.fetch.js" \
582 "$(SRCDIR)\fossil.numbered-lines.js" \
583 "$(SRCDIR)\fossil.page.brlist.js" \
584 "$(SRCDIR)\fossil.page.chat.js" \
585 "$(SRCDIR)\fossil.page.fileedit.js" \
586 "$(SRCDIR)\fossil.page.forumpost.js" \
587 "$(SRCDIR)\fossil.page.pikchrshow.js" \
588 "$(SRCDIR)\fossil.page.whistory.js" \
589 "$(SRCDIR)\fossil.page.wikiedit.js" \
@@ -1174,11 +1174,10 @@
1174 echo "$(SRCDIR)\accordion.js" >> $@
1175 echo "$(SRCDIR)\alerts/bflat2.wav" >> $@
1176 echo "$(SRCDIR)\alerts/bflat3.wav" >> $@
1177 echo "$(SRCDIR)\alerts/bloop.wav" >> $@
1178 echo "$(SRCDIR)\alerts/plunk.wav" >> $@
 
1179 echo "$(SRCDIR)\ci_edit.js" >> $@
1180 echo "$(SRCDIR)\copybtn.js" >> $@
1181 echo "$(SRCDIR)\default.css" >> $@
1182 echo "$(SRCDIR)\diff.js" >> $@
1183 echo "$(SRCDIR)\diff.tcl" >> $@
@@ -1189,10 +1188,11 @@
1188 echo "$(SRCDIR)\fossil.diff.js" >> $@
1189 echo "$(SRCDIR)\fossil.dom.js" >> $@
1190 echo "$(SRCDIR)\fossil.fetch.js" >> $@
1191 echo "$(SRCDIR)\fossil.numbered-lines.js" >> $@
1192 echo "$(SRCDIR)\fossil.page.brlist.js" >> $@
1193 echo "$(SRCDIR)\fossil.page.chat.js" >> $@
1194 echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@
1195 echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@
1196 echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@
1197 echo "$(SRCDIR)\fossil.page.whistory.js" >> $@
1198 echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@
1199
--- www/changes.wiki
+++ www/changes.wiki
@@ -28,11 +28,11 @@
2828
the --verbose option.
2929
* Add the <tt>close</tt>, <tt>reopen</tt>, <tt>hide</tt>, and
3030
</tt>unhide</tt> subcommands to [/help?cmd=branch|the branch command].
3131
* The "-p" option to [/help?cmd=branch|fossil branch list] shows only
3232
private branches.
33
- * The [/mdrules|Markdown formatter] now interprets the content of
33
+ * The [/md_rules|Markdown formatter] now interprets the content of
3434
block HTML markup (such as &lt;table&gt;) in most cases. Only content
3535
of &lt;pre&gt; and &lt;script&gt; is passed through verbatim.
3636
* The [/help?cmd=wiki|wiki list command] no longer lists "deleted"
3737
pages by default. Use the new <tt>--all</tt> option to include deleted
3838
pages in the output.
3939
--- www/changes.wiki
+++ www/changes.wiki
@@ -28,11 +28,11 @@
28 the --verbose option.
29 * Add the <tt>close</tt>, <tt>reopen</tt>, <tt>hide</tt>, and
30 </tt>unhide</tt> subcommands to [/help?cmd=branch|the branch command].
31 * The "-p" option to [/help?cmd=branch|fossil branch list] shows only
32 private branches.
33 * The [/mdrules|Markdown formatter] now interprets the content of
34 block HTML markup (such as &lt;table&gt;) in most cases. Only content
35 of &lt;pre&gt; and &lt;script&gt; is passed through verbatim.
36 * The [/help?cmd=wiki|wiki list command] no longer lists "deleted"
37 pages by default. Use the new <tt>--all</tt> option to include deleted
38 pages in the output.
39
--- www/changes.wiki
+++ www/changes.wiki
@@ -28,11 +28,11 @@
28 the --verbose option.
29 * Add the <tt>close</tt>, <tt>reopen</tt>, <tt>hide</tt>, and
30 </tt>unhide</tt> subcommands to [/help?cmd=branch|the branch command].
31 * The "-p" option to [/help?cmd=branch|fossil branch list] shows only
32 private branches.
33 * The [/md_rules|Markdown formatter] now interprets the content of
34 block HTML markup (such as &lt;table&gt;) in most cases. Only content
35 of &lt;pre&gt; and &lt;script&gt; is passed through verbatim.
36 * The [/help?cmd=wiki|wiki list command] no longer lists "deleted"
37 pages by default. Use the new <tt>--all</tt> option to include deleted
38 pages in the output.
39

Keyboard Shortcuts

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