Fossil SCM

Implemented "downwards" loading of diff context (appending to previous chunk). Fixed HTML escaping of loaded lines so that it works together with the existing colorized diff content.

stephan 2021-09-10 22:55 diff-js-refactoring
Commit 621ef5b7e8a33cb29e256c2efe7c32cfbaeafccccc6d30f8d0394cae80dce546
1 file changed +65 -12
+65 -12
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -23,11 +23,11 @@
2323
window.fossil.onPageLoad(function(){
2424
const F = window.fossil, D = F.dom;
2525
const Diff = F.diff = {
2626
e:{/*certain cached DOM elements*/},
2727
config: {
28
- chunkLoadLines: 20,
28
+ chunkLoadLines: 30,
2929
chunkFetch: {
3030
/* Default callack handlers for Diff.fetchArtifactChunk(),
3131
unless overridden by options passeed to that function. */
3232
beforesend: function(){},
3333
aftersend: function(){},
@@ -282,10 +282,12 @@
282282
}
283283
if(this.pos.next){
284284
btnUp = this.createButton(-1);
285285
}
286286
}
287
+ //this.e.btnUp = btnUp;
288
+ //this.e.btnDown = btnDown;
287289
if(btnDown) D.append(this.e.btnWrapper, btnDown);
288290
if(btnUp) D.append(this.e.btnWrapper, btnUp);
289291
/* For debugging only... */
290292
this.e.posState = D.span();
291293
D.append(this.e.btnWrapper, this.e.posState);
@@ -347,34 +349,50 @@
347349
delete this.e.tr;
348350
delete this.e;
349351
delete this.pos;
350352
},
351353
352
- injectResponse: function(direction/*as for fetchChunk()*/,
353
- urlParam/*from fetchChunk()*/,
354
- lines/*response lines*/){
354
+ injectResponse: function f(direction/*as for fetchChunk()*/,
355
+ urlParam/*from fetchChunk()*/,
356
+ lines/*response lines*/){
357
+ if(!lines.length){
358
+ /* No more data to load */
359
+ this.destroy();
360
+ return this;
361
+ }
355362
console.debug("Loading line range ",urlParam.from,"-",urlParam.to);
356363
const lineno = [],
357364
trPrev = this.e.tr.previousElementSibling,
358365
trNext = this.e.tr.nextElementSibling,
359
- doAppend = !!trPrev /* true to append to previous TR, else prepend to NEXT TR */;
366
+ doAppend = (!!trPrev && direction>=0) /* true to append to previous TR, else prepend to NEXT TR */;
360367
const tr = trPrev || trNext;
361
- if(0!==direction){
368
+ if(direction<0){
362369
console.error("this case is not yet handled",arguments);
363370
return this;
364371
}
365372
const joinTr = (
366373
0===direction && trPrev && trNext
367374
) ? trNext : false
368375
/* Truthy if we want to combine trPrev, the new content, and
369376
trNext into trPrev and remove trNext. */;
370377
let i, td;
378
+
379
+ if(!f.convertLines){
380
+ f.convertLines = function(li){
381
+ return li.join('\n')
382
+ .replaceAll('&','&amp;')
383
+ .replaceAll('<','&lt;')+'\n';
384
+ };
385
+ }
371386
372387
if(1){ // LHS line numbers...
373388
const selector = '.difflnl > pre';
374389
td = tr.querySelector(selector);
375
- for( i = urlParam.from; i <= urlParam.to; ++i ){
390
+ const lnTo = Math.min(urlParam.to,
391
+ urlParam.from +
392
+ lines.length - 1/*b/c request range is inclusive*/);
393
+ for( i = urlParam.from; i <= lnTo; ++i ){
376394
lineno.push(i);
377395
}
378396
const lineNoTxt = lineno.join('\n')+'\n';
379397
const content = [td.innerHTML];
380398
if(doAppend) content.push(lineNoTxt);
@@ -386,11 +404,11 @@
386404
}
387405
388406
if(1){// code block(s)...
389407
const selector = '.difftxt > pre';
390408
td = tr.querySelectorAll(selector);
391
- const code = D.append(D.div(),lines.join('\n')+'\n').innerText;
409
+ const code = f.convertLines(lines);
392410
let joinNdx = 0;
393411
td.forEach(function(e){
394412
const content = [e.innerHTML];
395413
if(doAppend) content.push(code);
396414
else content.unshift(code);
@@ -441,10 +459,39 @@
441459
td.innerHTML = content.join('');
442460
if(joinTr) D.remove(joinTr);
443461
Diff.checkTableWidth(true);
444462
this.destroy();
445463
return this;
464
+ }else if(1===direction){
465
+ /* Expanding previous TR downwards. */
466
+ // RHS line numbers...
467
+ let startLnR = this.pos.prev.endRhs+1;
468
+ lineno.length = lines.length;
469
+ for( i = startLnR; i < startLnR + lines.length; ++i ){
470
+ lineno[i-startLnR] = i;
471
+ }
472
+ console.debug("lineno.length =",lineno.length);
473
+ console.debug("lines.length =",lineno.length);
474
+ this.pos.startLhs += lines.length;
475
+ this.pos.prev.endRhs += lines.length;
476
+ this.pos.prev.endLhs += lines.length;
477
+ const selector = '.difflnr > pre';
478
+ td = tr.querySelector(selector);
479
+ const lineNoTxt = lineno.join('\n')+'\n';
480
+ lineno.length = 0;
481
+ const content = [td.innerHTML];
482
+ if(doAppend) content.push(lineNoTxt);
483
+ else content.unshift(lineNoTxt);
484
+ td.innerHTML = content.join('');
485
+ if(lines.length < (urlParam.to - urlParam.from)){
486
+ /* No more data. */
487
+ this.destroy();
488
+ }else{
489
+ this.updatePosDebug();
490
+ }
491
+ Diff.checkTableWidth(true);
492
+ return this;
446493
}else{
447494
console.debug("TODO: handle load of partial next/prev");
448495
this.updatePosDebug();
449496
}
450497
},
@@ -487,27 +534,33 @@
487534
aftersend: ()=>delete this.$isFetching,
488535
onload: (list)=>this.injectResponse(direction,up,list)
489536
};
490537
const up = fOpt.urlParams;
491538
if(direction===0){
539
+ /* Easiest case: filling a whole gap. */
492540
up.from = this.pos.startLhs;
493541
up.to = this.pos.endLhs;
494542
}else if(1===direction){
495543
/* Expand previous TR downwards. */
496544
if(!this.pos.prev){
497545
console.error("Attempt to fetch next diff lines but don't have any.");
498546
return this;
499547
}
500
- console.debug("fetchChunk(",direction,")");
501
- return this;
548
+ up.from = this.pos.prev.endLhs + 1;
549
+ up.to = up.from +
550
+ Diff.config.chunkLoadLines - 1/*b/c request range is inclusive*/;
551
+ if( this.pos.next && this.pos.next.startLhs <= up.to ){
552
+ up.to = this.pos.next.startLhs - 1;
553
+ direction = 0;
554
+ }
502555
}else{
503556
/* Expand next TR upwards */
504
- console.debug("fetchChunk(",direction,")");
557
+ console.debug("fetchChunk(",direction,")",up);
505558
return this;
506559
}
507
-
508560
this.$isFetching = true;
561
+ console.debug("fetchChunk(",direction,")",up);
509562
Diff.fetchArtifactChunk(fOpt);
510563
return this;
511564
}
512565
};
513566
514567
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -23,11 +23,11 @@
23 window.fossil.onPageLoad(function(){
24 const F = window.fossil, D = F.dom;
25 const Diff = F.diff = {
26 e:{/*certain cached DOM elements*/},
27 config: {
28 chunkLoadLines: 20,
29 chunkFetch: {
30 /* Default callack handlers for Diff.fetchArtifactChunk(),
31 unless overridden by options passeed to that function. */
32 beforesend: function(){},
33 aftersend: function(){},
@@ -282,10 +282,12 @@
282 }
283 if(this.pos.next){
284 btnUp = this.createButton(-1);
285 }
286 }
 
 
287 if(btnDown) D.append(this.e.btnWrapper, btnDown);
288 if(btnUp) D.append(this.e.btnWrapper, btnUp);
289 /* For debugging only... */
290 this.e.posState = D.span();
291 D.append(this.e.btnWrapper, this.e.posState);
@@ -347,34 +349,50 @@
347 delete this.e.tr;
348 delete this.e;
349 delete this.pos;
350 },
351
352 injectResponse: function(direction/*as for fetchChunk()*/,
353 urlParam/*from fetchChunk()*/,
354 lines/*response lines*/){
 
 
 
 
 
355 console.debug("Loading line range ",urlParam.from,"-",urlParam.to);
356 const lineno = [],
357 trPrev = this.e.tr.previousElementSibling,
358 trNext = this.e.tr.nextElementSibling,
359 doAppend = !!trPrev /* true to append to previous TR, else prepend to NEXT TR */;
360 const tr = trPrev || trNext;
361 if(0!==direction){
362 console.error("this case is not yet handled",arguments);
363 return this;
364 }
365 const joinTr = (
366 0===direction && trPrev && trNext
367 ) ? trNext : false
368 /* Truthy if we want to combine trPrev, the new content, and
369 trNext into trPrev and remove trNext. */;
370 let i, td;
 
 
 
 
 
 
 
 
371
372 if(1){ // LHS line numbers...
373 const selector = '.difflnl > pre';
374 td = tr.querySelector(selector);
375 for( i = urlParam.from; i <= urlParam.to; ++i ){
 
 
 
376 lineno.push(i);
377 }
378 const lineNoTxt = lineno.join('\n')+'\n';
379 const content = [td.innerHTML];
380 if(doAppend) content.push(lineNoTxt);
@@ -386,11 +404,11 @@
386 }
387
388 if(1){// code block(s)...
389 const selector = '.difftxt > pre';
390 td = tr.querySelectorAll(selector);
391 const code = D.append(D.div(),lines.join('\n')+'\n').innerText;
392 let joinNdx = 0;
393 td.forEach(function(e){
394 const content = [e.innerHTML];
395 if(doAppend) content.push(code);
396 else content.unshift(code);
@@ -441,10 +459,39 @@
441 td.innerHTML = content.join('');
442 if(joinTr) D.remove(joinTr);
443 Diff.checkTableWidth(true);
444 this.destroy();
445 return this;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446 }else{
447 console.debug("TODO: handle load of partial next/prev");
448 this.updatePosDebug();
449 }
450 },
@@ -487,27 +534,33 @@
487 aftersend: ()=>delete this.$isFetching,
488 onload: (list)=>this.injectResponse(direction,up,list)
489 };
490 const up = fOpt.urlParams;
491 if(direction===0){
 
492 up.from = this.pos.startLhs;
493 up.to = this.pos.endLhs;
494 }else if(1===direction){
495 /* Expand previous TR downwards. */
496 if(!this.pos.prev){
497 console.error("Attempt to fetch next diff lines but don't have any.");
498 return this;
499 }
500 console.debug("fetchChunk(",direction,")");
501 return this;
 
 
 
 
 
502 }else{
503 /* Expand next TR upwards */
504 console.debug("fetchChunk(",direction,")");
505 return this;
506 }
507
508 this.$isFetching = true;
 
509 Diff.fetchArtifactChunk(fOpt);
510 return this;
511 }
512 };
513
514
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -23,11 +23,11 @@
23 window.fossil.onPageLoad(function(){
24 const F = window.fossil, D = F.dom;
25 const Diff = F.diff = {
26 e:{/*certain cached DOM elements*/},
27 config: {
28 chunkLoadLines: 30,
29 chunkFetch: {
30 /* Default callack handlers for Diff.fetchArtifactChunk(),
31 unless overridden by options passeed to that function. */
32 beforesend: function(){},
33 aftersend: function(){},
@@ -282,10 +282,12 @@
282 }
283 if(this.pos.next){
284 btnUp = this.createButton(-1);
285 }
286 }
287 //this.e.btnUp = btnUp;
288 //this.e.btnDown = btnDown;
289 if(btnDown) D.append(this.e.btnWrapper, btnDown);
290 if(btnUp) D.append(this.e.btnWrapper, btnUp);
291 /* For debugging only... */
292 this.e.posState = D.span();
293 D.append(this.e.btnWrapper, this.e.posState);
@@ -347,34 +349,50 @@
349 delete this.e.tr;
350 delete this.e;
351 delete this.pos;
352 },
353
354 injectResponse: function f(direction/*as for fetchChunk()*/,
355 urlParam/*from fetchChunk()*/,
356 lines/*response lines*/){
357 if(!lines.length){
358 /* No more data to load */
359 this.destroy();
360 return this;
361 }
362 console.debug("Loading line range ",urlParam.from,"-",urlParam.to);
363 const lineno = [],
364 trPrev = this.e.tr.previousElementSibling,
365 trNext = this.e.tr.nextElementSibling,
366 doAppend = (!!trPrev && direction>=0) /* true to append to previous TR, else prepend to NEXT TR */;
367 const tr = trPrev || trNext;
368 if(direction<0){
369 console.error("this case is not yet handled",arguments);
370 return this;
371 }
372 const joinTr = (
373 0===direction && trPrev && trNext
374 ) ? trNext : false
375 /* Truthy if we want to combine trPrev, the new content, and
376 trNext into trPrev and remove trNext. */;
377 let i, td;
378
379 if(!f.convertLines){
380 f.convertLines = function(li){
381 return li.join('\n')
382 .replaceAll('&','&amp;')
383 .replaceAll('<','&lt;')+'\n';
384 };
385 }
386
387 if(1){ // LHS line numbers...
388 const selector = '.difflnl > pre';
389 td = tr.querySelector(selector);
390 const lnTo = Math.min(urlParam.to,
391 urlParam.from +
392 lines.length - 1/*b/c request range is inclusive*/);
393 for( i = urlParam.from; i <= lnTo; ++i ){
394 lineno.push(i);
395 }
396 const lineNoTxt = lineno.join('\n')+'\n';
397 const content = [td.innerHTML];
398 if(doAppend) content.push(lineNoTxt);
@@ -386,11 +404,11 @@
404 }
405
406 if(1){// code block(s)...
407 const selector = '.difftxt > pre';
408 td = tr.querySelectorAll(selector);
409 const code = f.convertLines(lines);
410 let joinNdx = 0;
411 td.forEach(function(e){
412 const content = [e.innerHTML];
413 if(doAppend) content.push(code);
414 else content.unshift(code);
@@ -441,10 +459,39 @@
459 td.innerHTML = content.join('');
460 if(joinTr) D.remove(joinTr);
461 Diff.checkTableWidth(true);
462 this.destroy();
463 return this;
464 }else if(1===direction){
465 /* Expanding previous TR downwards. */
466 // RHS line numbers...
467 let startLnR = this.pos.prev.endRhs+1;
468 lineno.length = lines.length;
469 for( i = startLnR; i < startLnR + lines.length; ++i ){
470 lineno[i-startLnR] = i;
471 }
472 console.debug("lineno.length =",lineno.length);
473 console.debug("lines.length =",lineno.length);
474 this.pos.startLhs += lines.length;
475 this.pos.prev.endRhs += lines.length;
476 this.pos.prev.endLhs += lines.length;
477 const selector = '.difflnr > pre';
478 td = tr.querySelector(selector);
479 const lineNoTxt = lineno.join('\n')+'\n';
480 lineno.length = 0;
481 const content = [td.innerHTML];
482 if(doAppend) content.push(lineNoTxt);
483 else content.unshift(lineNoTxt);
484 td.innerHTML = content.join('');
485 if(lines.length < (urlParam.to - urlParam.from)){
486 /* No more data. */
487 this.destroy();
488 }else{
489 this.updatePosDebug();
490 }
491 Diff.checkTableWidth(true);
492 return this;
493 }else{
494 console.debug("TODO: handle load of partial next/prev");
495 this.updatePosDebug();
496 }
497 },
@@ -487,27 +534,33 @@
534 aftersend: ()=>delete this.$isFetching,
535 onload: (list)=>this.injectResponse(direction,up,list)
536 };
537 const up = fOpt.urlParams;
538 if(direction===0){
539 /* Easiest case: filling a whole gap. */
540 up.from = this.pos.startLhs;
541 up.to = this.pos.endLhs;
542 }else if(1===direction){
543 /* Expand previous TR downwards. */
544 if(!this.pos.prev){
545 console.error("Attempt to fetch next diff lines but don't have any.");
546 return this;
547 }
548 up.from = this.pos.prev.endLhs + 1;
549 up.to = up.from +
550 Diff.config.chunkLoadLines - 1/*b/c request range is inclusive*/;
551 if( this.pos.next && this.pos.next.startLhs <= up.to ){
552 up.to = this.pos.next.startLhs - 1;
553 direction = 0;
554 }
555 }else{
556 /* Expand next TR upwards */
557 console.debug("fetchChunk(",direction,")",up);
558 return this;
559 }
 
560 this.$isFetching = true;
561 console.debug("fetchChunk(",direction,")",up);
562 Diff.fetchArtifactChunk(fOpt);
563 return this;
564 }
565 };
566
567

Keyboard Shortcuts

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