Fossil SCM

Experiment to implement a click-queue for the buttons dynamically loading diff context. See [forum:c8919e12dd | Forum Post c8919e12dd] for comments and potential TODOs.

florian 2021-09-24 12:04 trunk
Commit c714f2515e06d0011e3fc06938bd48a6446fe175c8bd6487afd12799d885a9e5
1 file changed +30 -9
--- 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,11 +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
+ NextUp: -1,
216
+ /** Process the next queued action. */
217
+ ProcessQueue: 0x7fffffff
215218
},
216219
config: {
217220
/*
218221
glyphUp: '⇡', //'&#uarr;',
219222
glyphDown: '⇣' //'&#darr;'
@@ -262,10 +265,11 @@
262265
},
263266
264267
/* Attempt to clean up resources and remove some circular references to
265268
that GC can do the right thing. */
266269
destroy: function(){
270
+ delete this.$fetchQueue;
267271
D.remove(this.e.tr);
268272
delete this.e.tr.$chunker;
269273
delete this.e.tr;
270274
delete this.e;
271275
delete this.pos;
@@ -282,10 +286,13 @@
282286
maybeReplaceButtons: function(){
283287
if(this.pos.next && this.pos.prev
284288
&& (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){
285289
D.clearElement(this.e.btnWrapper);
286290
D.append(this.e.btnWrapper, this.createButton(this.FetchType.FillGap));
291
+ if( this.$fetchQueue && this.$fetchQueue.length>0 ){
292
+ this.$fetchQueue = [this.FetchType.FillGap];
293
+ }
287294
}
288295
return this;
289296
},
290297
291298
/**
@@ -501,28 +508,40 @@
501508
This is an async operation. While it is in transit, any calls
502509
to this function will have no effect except (possibly) to emit
503510
a warning. Returns this object.
504511
*/
505512
fetchChunk: function(fetchType){
513
+ if( !this.$fetchQueue ) return this; // HACKHACK: are we destroyed?
514
+ if( fetchType==this.FetchType.ProcessQueue ){
515
+ if( this.$fetchQueue.length==0 ) return this;
516
+ //console.log('fetchChunk: processing queue ...');
517
+ }
518
+ else{
519
+ this.$fetchQueue.push(fetchType);
520
+ if( this.$fetchQueue.length!=1 ) return this;
521
+ //console.log('fetchChunk: processing user input ...');
522
+ }
523
+ fetchType = this.$fetchQueue[0];
506524
/* Forewarning, this is a bit confusing: when fetching the
507525
previous lines, we're doing so on behalf of the *next* diff
508526
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
- }
512527
if(fetchType===this.FetchType.NextUp && !this.pos.next
513528
|| fetchType===this.FetchType.PrevDown && !this.pos.prev){
514529
console.error("Attempt to fetch diff lines but don't have any.");
515530
return this;
516531
}
517
- this.msg(false,"Fetching diff chunk...");
532
+ this.msg(false);
518533
const fOpt = {
519534
urlParams:{
520535
name: this.fileHash, from: 0, to: 0
521536
},
522
- aftersend: ()=>delete this.$isFetching,
523
- onload: (list)=>this.injectResponse(fetchType,up,list)
537
+ onload: function(list){
538
+ this.injectResponse(fetchType,up,list);
539
+ if( !this.$fetchQueue || this.$fetchQueue.length==0 ) return;
540
+ this.$fetchQueue.shift();
541
+ setTimeout(this.fetchChunk.bind(this,this.FetchType.ProcessQueue));
542
+ }.bind(this)
524543
};
525544
const up = fOpt.urlParams;
526545
if(fetchType===this.FetchType.FillGap){
527546
/* Easiest case: filling a whole gap. */
528547
up.from = this.pos.startLhs;
@@ -551,13 +570,15 @@
551570
if( this.pos.prev && this.pos.prev.endLhs >= up.from ){
552571
up.from = this.pos.prev.endLhs + 1;
553572
fetchType = this.FetchType.FillGap;
554573
}
555574
}
556
- this.$isFetching = true;
557575
//console.debug("fetchChunk(",fetchType,")",up);
558
- fOpt.onerror = (err)=>this.msg(true,err.message);
576
+ fOpt.onerror = function(err){
577
+ this.msg(true,err.message);
578
+ this.$fetchQueue = [];
579
+ }.bind(this);
559580
Diff.fetchArtifactChunk(fOpt);
560581
return this;
561582
}
562583
};
563584
564585
--- 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,11 +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;'
@@ -262,10 +265,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 +286,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 +508,40 @@
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 +570,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
--- 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,11 +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 config: {
220 /*
221 glyphUp: '⇡', //'&#uarr;',
222 glyphDown: '⇣' //'&#darr;'
@@ -262,10 +265,11 @@
265 },
266
267 /* Attempt to clean up resources and remove some circular references to
268 that GC can do the right thing. */
269 destroy: function(){
270 delete this.$fetchQueue;
271 D.remove(this.e.tr);
272 delete this.e.tr.$chunker;
273 delete this.e.tr;
274 delete this.e;
275 delete this.pos;
@@ -282,10 +286,13 @@
286 maybeReplaceButtons: function(){
287 if(this.pos.next && this.pos.prev
288 && (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){
289 D.clearElement(this.e.btnWrapper);
290 D.append(this.e.btnWrapper, this.createButton(this.FetchType.FillGap));
291 if( this.$fetchQueue && this.$fetchQueue.length>0 ){
292 this.$fetchQueue = [this.FetchType.FillGap];
293 }
294 }
295 return this;
296 },
297
298 /**
@@ -501,28 +508,40 @@
508 This is an async operation. While it is in transit, any calls
509 to this function will have no effect except (possibly) to emit
510 a warning. Returns this object.
511 */
512 fetchChunk: function(fetchType){
513 if( !this.$fetchQueue ) return this; // HACKHACK: are we destroyed?
514 if( fetchType==this.FetchType.ProcessQueue ){
515 if( this.$fetchQueue.length==0 ) return this;
516 //console.log('fetchChunk: processing queue ...');
517 }
518 else{
519 this.$fetchQueue.push(fetchType);
520 if( this.$fetchQueue.length!=1 ) return this;
521 //console.log('fetchChunk: processing user input ...');
522 }
523 fetchType = this.$fetchQueue[0];
524 /* Forewarning, this is a bit confusing: when fetching the
525 previous lines, we're doing so on behalf of the *next* diff
526 chunk (this.pos.next), and vice versa. */
 
 
 
527 if(fetchType===this.FetchType.NextUp && !this.pos.next
528 || fetchType===this.FetchType.PrevDown && !this.pos.prev){
529 console.error("Attempt to fetch diff lines but don't have any.");
530 return this;
531 }
532 this.msg(false);
533 const fOpt = {
534 urlParams:{
535 name: this.fileHash, from: 0, to: 0
536 },
537 onload: function(list){
538 this.injectResponse(fetchType,up,list);
539 if( !this.$fetchQueue || this.$fetchQueue.length==0 ) return;
540 this.$fetchQueue.shift();
541 setTimeout(this.fetchChunk.bind(this,this.FetchType.ProcessQueue));
542 }.bind(this)
543 };
544 const up = fOpt.urlParams;
545 if(fetchType===this.FetchType.FillGap){
546 /* Easiest case: filling a whole gap. */
547 up.from = this.pos.startLhs;
@@ -551,13 +570,15 @@
570 if( this.pos.prev && this.pos.prev.endLhs >= up.from ){
571 up.from = this.pos.prev.endLhs + 1;
572 fetchType = this.FetchType.FillGap;
573 }
574 }
 
575 //console.debug("fetchChunk(",fetchType,")",up);
576 fOpt.onerror = function(err){
577 this.msg(true,err.message);
578 this.$fetchQueue = [];
579 }.bind(this);
580 Diff.fetchArtifactChunk(fOpt);
581 return this;
582 }
583 };
584
585

Keyboard Shortcuts

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