Fossil SCM
Merged in diff context multi-click load queue on behalf of Florian B., as discussed in/around [forum:c8919e12dd76bf23|forum post c8919e12dd76bf23].
Commit
a49393a9580ebf30562958bb802c28e7828df46a5fc5fe42622919aa46b6bb55
Parent
ce0d61bbae80a04…
2 files changed
+31
-14
+31
-14
+31
-14
| --- src/fossil.diff.js | ||
| +++ src/fossil.diff.js | ||
| @@ -117,10 +117,11 @@ | ||
| 117 | 117 | example of which, for use as a model, is: |
| 118 | 118 | |
| 119 | 119 | https://github.com/msteveb/autosetup/commit/235925e914a52a542 |
| 120 | 120 | */ |
| 121 | 121 | const ChunkLoadControls = function(tr){ |
| 122 | + this.$fetchQueue = []; | |
| 122 | 123 | this.e = {/*DOM elements*/ |
| 123 | 124 | tr: tr, |
| 124 | 125 | table: tr.parentElement/*TBODY*/.parentElement |
| 125 | 126 | }; |
| 126 | 127 | this.isSplit = this.e.table.classList.contains('splitdiff')/*else udiff*/; |
| @@ -209,17 +210,13 @@ | ||
| 209 | 210 | /** Fill a complete gap between the previous/next diff chunks |
| 210 | 211 | or at the start of the next chunk or end of the previous |
| 211 | 212 | chunks. */ |
| 212 | 213 | FillGap: 0, |
| 213 | 214 | /** 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 | |
| 221 | 218 | }, |
| 222 | 219 | |
| 223 | 220 | /** |
| 224 | 221 | Creates and returns a button element for fetching a chunk in |
| 225 | 222 | the given fetchType (as documented for fetchChunk()). |
| @@ -262,10 +259,11 @@ | ||
| 262 | 259 | }, |
| 263 | 260 | |
| 264 | 261 | /* Attempt to clean up resources and remove some circular references to |
| 265 | 262 | that GC can do the right thing. */ |
| 266 | 263 | destroy: function(){ |
| 264 | + delete this.$fetchQueue; | |
| 267 | 265 | D.remove(this.e.tr); |
| 268 | 266 | delete this.e.tr.$chunker; |
| 269 | 267 | delete this.e.tr; |
| 270 | 268 | delete this.e; |
| 271 | 269 | delete this.pos; |
| @@ -282,10 +280,13 @@ | ||
| 282 | 280 | maybeReplaceButtons: function(){ |
| 283 | 281 | if(this.pos.next && this.pos.prev |
| 284 | 282 | && (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){ |
| 285 | 283 | D.clearElement(this.e.btnWrapper); |
| 286 | 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 | + } | |
| 287 | 288 | } |
| 288 | 289 | return this; |
| 289 | 290 | }, |
| 290 | 291 | |
| 291 | 292 | /** |
| @@ -501,28 +502,42 @@ | ||
| 501 | 502 | This is an async operation. While it is in transit, any calls |
| 502 | 503 | to this function will have no effect except (possibly) to emit |
| 503 | 504 | a warning. Returns this object. |
| 504 | 505 | */ |
| 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]; | |
| 506 | 518 | /* Forewarning, this is a bit confusing: when fetching the |
| 507 | 519 | previous lines, we're doing so on behalf of the *next* diff |
| 508 | 520 | 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 | 521 | if(fetchType===this.FetchType.NextUp && !this.pos.next |
| 513 | 522 | || fetchType===this.FetchType.PrevDown && !this.pos.prev){ |
| 514 | 523 | console.error("Attempt to fetch diff lines but don't have any."); |
| 515 | 524 | return this; |
| 516 | 525 | } |
| 517 | 526 | this.msg(false,"Fetching diff chunk..."); |
| 527 | + const self = this; | |
| 518 | 528 | const fOpt = { |
| 519 | 529 | urlParams:{ |
| 520 | 530 | name: this.fileHash, from: 0, to: 0 |
| 521 | 531 | }, |
| 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 | + } | |
| 524 | 539 | }; |
| 525 | 540 | const up = fOpt.urlParams; |
| 526 | 541 | if(fetchType===this.FetchType.FillGap){ |
| 527 | 542 | /* Easiest case: filling a whole gap. */ |
| 528 | 543 | up.from = this.pos.startLhs; |
| @@ -551,13 +566,15 @@ | ||
| 551 | 566 | if( this.pos.prev && this.pos.prev.endLhs >= up.from ){ |
| 552 | 567 | up.from = this.pos.prev.endLhs + 1; |
| 553 | 568 | fetchType = this.FetchType.FillGap; |
| 554 | 569 | } |
| 555 | 570 | } |
| 556 | - this.$isFetching = true; | |
| 557 | 571 | //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 | + }; | |
| 559 | 576 | Diff.fetchArtifactChunk(fOpt); |
| 560 | 577 | return this; |
| 561 | 578 | } |
| 562 | 579 | }; |
| 563 | 580 | |
| 564 | 581 |
| --- 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 |
| --- 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 |
+31
-14
| --- src/fossil.diff.js | ||
| +++ src/fossil.diff.js | ||
| @@ -117,10 +117,11 @@ | ||
| 117 | 117 | example of which, for use as a model, is: |
| 118 | 118 | |
| 119 | 119 | https://github.com/msteveb/autosetup/commit/235925e914a52a542 |
| 120 | 120 | */ |
| 121 | 121 | const ChunkLoadControls = function(tr){ |
| 122 | + this.$fetchQueue = []; | |
| 122 | 123 | this.e = {/*DOM elements*/ |
| 123 | 124 | tr: tr, |
| 124 | 125 | table: tr.parentElement/*TBODY*/.parentElement |
| 125 | 126 | }; |
| 126 | 127 | this.isSplit = this.e.table.classList.contains('splitdiff')/*else udiff*/; |
| @@ -209,17 +210,13 @@ | ||
| 209 | 210 | /** Fill a complete gap between the previous/next diff chunks |
| 210 | 211 | or at the start of the next chunk or end of the previous |
| 211 | 212 | chunks. */ |
| 212 | 213 | FillGap: 0, |
| 213 | 214 | /** 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 | |
| 221 | 218 | }, |
| 222 | 219 | |
| 223 | 220 | /** |
| 224 | 221 | Creates and returns a button element for fetching a chunk in |
| 225 | 222 | the given fetchType (as documented for fetchChunk()). |
| @@ -262,10 +259,11 @@ | ||
| 262 | 259 | }, |
| 263 | 260 | |
| 264 | 261 | /* Attempt to clean up resources and remove some circular references to |
| 265 | 262 | that GC can do the right thing. */ |
| 266 | 263 | destroy: function(){ |
| 264 | + delete this.$fetchQueue; | |
| 267 | 265 | D.remove(this.e.tr); |
| 268 | 266 | delete this.e.tr.$chunker; |
| 269 | 267 | delete this.e.tr; |
| 270 | 268 | delete this.e; |
| 271 | 269 | delete this.pos; |
| @@ -282,10 +280,13 @@ | ||
| 282 | 280 | maybeReplaceButtons: function(){ |
| 283 | 281 | if(this.pos.next && this.pos.prev |
| 284 | 282 | && (this.pos.endLhs - this.pos.startLhs <= Diff.config.chunkLoadLines)){ |
| 285 | 283 | D.clearElement(this.e.btnWrapper); |
| 286 | 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 | + } | |
| 287 | 288 | } |
| 288 | 289 | return this; |
| 289 | 290 | }, |
| 290 | 291 | |
| 291 | 292 | /** |
| @@ -501,28 +502,42 @@ | ||
| 501 | 502 | This is an async operation. While it is in transit, any calls |
| 502 | 503 | to this function will have no effect except (possibly) to emit |
| 503 | 504 | a warning. Returns this object. |
| 504 | 505 | */ |
| 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]; | |
| 506 | 518 | /* Forewarning, this is a bit confusing: when fetching the |
| 507 | 519 | previous lines, we're doing so on behalf of the *next* diff |
| 508 | 520 | 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 | 521 | if(fetchType===this.FetchType.NextUp && !this.pos.next |
| 513 | 522 | || fetchType===this.FetchType.PrevDown && !this.pos.prev){ |
| 514 | 523 | console.error("Attempt to fetch diff lines but don't have any."); |
| 515 | 524 | return this; |
| 516 | 525 | } |
| 517 | 526 | this.msg(false,"Fetching diff chunk..."); |
| 527 | + const self = this; | |
| 518 | 528 | const fOpt = { |
| 519 | 529 | urlParams:{ |
| 520 | 530 | name: this.fileHash, from: 0, to: 0 |
| 521 | 531 | }, |
| 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 | + } | |
| 524 | 539 | }; |
| 525 | 540 | const up = fOpt.urlParams; |
| 526 | 541 | if(fetchType===this.FetchType.FillGap){ |
| 527 | 542 | /* Easiest case: filling a whole gap. */ |
| 528 | 543 | up.from = this.pos.startLhs; |
| @@ -551,13 +566,15 @@ | ||
| 551 | 566 | if( this.pos.prev && this.pos.prev.endLhs >= up.from ){ |
| 552 | 567 | up.from = this.pos.prev.endLhs + 1; |
| 553 | 568 | fetchType = this.FetchType.FillGap; |
| 554 | 569 | } |
| 555 | 570 | } |
| 556 | - this.$isFetching = true; | |
| 557 | 571 | //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 | + }; | |
| 559 | 576 | Diff.fetchArtifactChunk(fOpt); |
| 560 | 577 | return this; |
| 561 | 578 | } |
| 562 | 579 | }; |
| 563 | 580 | |
| 564 | 581 |
| --- 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 |
| --- 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 |