Fossil SCM

When filling a whole gap with loaded jchunk lines, merge the previous and following TR elements together with the new content, providing a seamless fill, eliminating the extraneous scrollbars. This means we cannot style the newly-loaded chunk differently (like github does), but it looks much, much nicer than before. Partial-chunk loads are still pending.

stephan 2021-09-09 22:41 diff-js-refactoring
Commit 11a981ead041010ad59befd46db13f2e4ad5311048302117a0db7fbbde3cdc5b
--- src/default.css
+++ src/default.css
@@ -545,13 +545,10 @@
545545
vertical-align: top;
546546
}
547547
table.diff pre {
548548
margin: 0 0 0 0;
549549
}
550
-table.diff tr.fetched {
551
- opacity: 0.7;
552
-}
553550
tr.diffskip.jchunk {
554551
/* jchunk gets added from JS to diffskip rows when they are
555552
plugged into the /jchunk route and removed after that data
556553
is fetched. */
557554
background-color: aliceblue;
558555
--- src/default.css
+++ src/default.css
@@ -545,13 +545,10 @@
545 vertical-align: top;
546 }
547 table.diff pre {
548 margin: 0 0 0 0;
549 }
550 table.diff tr.fetched {
551 opacity: 0.7;
552 }
553 tr.diffskip.jchunk {
554 /* jchunk gets added from JS to diffskip rows when they are
555 plugged into the /jchunk route and removed after that data
556 is fetched. */
557 background-color: aliceblue;
558
--- src/default.css
+++ src/default.css
@@ -545,13 +545,10 @@
545 vertical-align: top;
546 }
547 table.diff pre {
548 margin: 0 0 0 0;
549 }
 
 
 
550 tr.diffskip.jchunk {
551 /* jchunk gets added from JS to diffskip rows when they are
552 plugged into the /jchunk route and removed after that data
553 is fetched. */
554 background-color: aliceblue;
555
+78 -22
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -344,27 +344,28 @@
344344
so). Returns an object containing the TR element and various TD
345345
elements which will likely be needed by the routine which
346346
called this. See this code for details.
347347
*/
348348
newTR: function(){
349
- const tr = D.addClass(D.tr(),'fetched'), rc = {
349
+ const tr = D.tr(), rc = {
350350
tr,
351351
preLnL: D.pre(),
352
- preLnR: D.pre()
352
+ preLnR: D.pre(),
353
+ preSep: D.pre()
353354
};
354355
if(this.isSplit){
355356
D.append(D.addClass( D.td(tr), 'diffln', 'difflnl' ), rc.preLnL);
356357
rc.preTxtL = D.pre();
357358
D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtl' ), rc.preTxtL);
358
- D.addClass( D.td(tr), 'diffsep' );
359
+ D.append(D.addClass( D.td(tr), 'diffsep' ), rc.preSep);
359360
D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), rc.preLnR);
360361
rc.preTxtR = D.pre();
361362
D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtr' ), rc.preTxtR);
362363
}else{
363364
D.append(D.addClass( D.td(tr), 'diffln', 'difflnl' ), rc.preLnL);
364365
D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), rc.preLnR);
365
- D.addClass( D.td(tr), 'diffsep' );
366
+ D.append(D.addClass( D.td(tr), 'diffsep' ), rc.preSep);
366367
rc.preTxtU = D.pre();
367368
D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtu' ), rc.preTxtU);
368369
}
369370
return rc;
370371
},
@@ -371,24 +372,65 @@
371372
372373
injectResponse: function(direction/*as for fetchChunk()*/,
373374
urlParam/*from fetchChunk()*/,
374375
lines/*response lines*/){
375376
console.debug("Loading line range ",urlParam.from,"-",urlParam.to);
376
- const row = this.newTR();
377
- const lineno = [];
378
- let i;
379
- for( i = urlParam.from; i <= urlParam.to; ++i ){
380
- /* TODO: space-pad numbers, but we don't know the proper length from here. */
381
- lineno.push(i);
382
- }
383
- row.preLnL.innerText = lineno.join('\n')+'\n';
384
- if(row.preTxtU){//unified diff
385
- row.preTxtU.innerText = lines.join('\n')+'\n';
386
- }else{//split diff
387
- const code = lines.join('\n')+'\n';
388
- row.preTxtL.innerText = code;
389
- row.preTxtR.innerText = code;
377
+ const lineno = [],
378
+ trPrev = this.e.tr.previousElementSibling,
379
+ trNext = this.e.tr.nextElementSibling,
380
+ doAppend = !!trPrev /* true to append to previous TR, else prepend to NEXT TR */;
381
+ const tr = trPrev || trNext;
382
+ if(0!==direction){
383
+ console.error("this case is not yet handled",arguments);
384
+ return this;
385
+ }
386
+ const joinTr = (0===direction && trPrev && trNext);
387
+ let i, td;
388
+ if(1){ // LHS line numbers...
389
+ const selector = '.difflnl > pre';
390
+ td = tr.querySelector(selector);
391
+ for( i = urlParam.from; i <= urlParam.to; ++i ){
392
+ lineno.push(i);
393
+ }
394
+ const lineNoTxt = lineno.join('\n')+'\n';
395
+ const content = [];
396
+ if(doAppend) content.push(td.innerHTML, lineNoTxt);
397
+ else content.push(lineNoTxt, td.innerHTML);
398
+ if(joinTr){
399
+ content.push(trNext.querySelector(selector).innerHTML);
400
+ }
401
+ td.innerHTML = content.join('');
402
+ }
403
+
404
+ if(1){// code block...
405
+ const selector = '.difftxt > pre';
406
+ td = tr.querySelectorAll(selector);
407
+ const code = D.append(D.div(),lines.join('\n')+'\n').innerText;
408
+ let joinNdx = 0;
409
+ td.forEach(function(e){
410
+ const content = [];
411
+ if(doAppend) content.push(e.innerHTML, code);
412
+ else content.push(code, e.innerHTML);
413
+ if(joinTr){
414
+ content.push(trNext.querySelectorAll(selector)[joinNdx++].innerHTML)
415
+ }
416
+ e.innerHTML = content.join('');
417
+ });
418
+ }
419
+ if(1){
420
+ // Add blank lines in (.diffsep>pre)
421
+ const selector = '.diffsep > pre';
422
+ td = tr.querySelector(selector);
423
+ for(i = 0; i < lineno.length; ++i) lineno[i] = '';
424
+ const blanks = lineno.join('\n')+'\n';
425
+ const content = [];
426
+ if(doAppend) content.push(td.innerHTML, blanks);
427
+ else content.push(blanks, td.innerHTML);
428
+ if(joinTr){
429
+ content.push(trNext.querySelector(selector).innerHTML);
430
+ }
431
+ td.innerHTML = content.join('');
390432
}
391433
if(0===direction){
392434
/* Closing the whole gap between two chunks or a whole gap
393435
at the start or end of a diff. */
394436
let startLnR = this.pos.prev
@@ -398,22 +440,36 @@
398440
lineno.length = 0;
399441
for( i = startLnR; i < startLnR + lines.length; ++i ){
400442
/* TODO? space-pad numbers, but we don't know the proper length from here. */
401443
lineno.push(i);
402444
}
403
- row.preLnR.innerText = lineno.join('\n')+'\n';
404
- this.e.tr.parentNode.insertBefore(row.tr, this.e.tr);
405
- Diff.initTableDiff(this.e.table/*fix scrolling*/).checkTableWidth(true);
445
+ const selector = '.difflnr > pre';
446
+ td = tr.querySelector(selector);
447
+ const lineNoTxt = lineno.join('\n')+'\n';
448
+ const content = [];
449
+ if(doAppend) content.push(td.innerHTML, lineNoTxt);
450
+ else content.push(lineNoTxt, td.innerHTML);
451
+ if(joinTr){
452
+ content.push(trNext.querySelector(selector).innerHTML);
453
+ }
454
+ td.innerHTML = content.join('');
455
+ if(joinTr){
456
+ D.remove(joinTr);
457
+ }
458
+ Diff.checkTableWidth(true);
406459
this.destroy();
407460
return this;
408461
}else{
409462
console.debug("TODO: handle load of partial next/prev");
410463
this.updatePosDebug();
411464
}
412465
},
413466
414
- fetchChunk: function(direction/*-1=prev, 1=next, 0=both*/){
467
+ fetchChunk: function(direction/*-1=down from prev chunk,
468
+ 1=up from next chunk,
469
+ 0=full-gap filler for any neighoring
470
+ chunk(s)*/){
415471
/* Forewarning, this is a bit confusing: when fetching the
416472
previous lines, we're doing so on behalf of the *next* diff
417473
chunk (this.pos.next), and vice versa. */
418474
if(this.$isFetching){
419475
console.debug("Cannot load chunk while a load is pending.");
420476
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -344,27 +344,28 @@
344 so). Returns an object containing the TR element and various TD
345 elements which will likely be needed by the routine which
346 called this. See this code for details.
347 */
348 newTR: function(){
349 const tr = D.addClass(D.tr(),'fetched'), rc = {
350 tr,
351 preLnL: D.pre(),
352 preLnR: D.pre()
 
353 };
354 if(this.isSplit){
355 D.append(D.addClass( D.td(tr), 'diffln', 'difflnl' ), rc.preLnL);
356 rc.preTxtL = D.pre();
357 D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtl' ), rc.preTxtL);
358 D.addClass( D.td(tr), 'diffsep' );
359 D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), rc.preLnR);
360 rc.preTxtR = D.pre();
361 D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtr' ), rc.preTxtR);
362 }else{
363 D.append(D.addClass( D.td(tr), 'diffln', 'difflnl' ), rc.preLnL);
364 D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), rc.preLnR);
365 D.addClass( D.td(tr), 'diffsep' );
366 rc.preTxtU = D.pre();
367 D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtu' ), rc.preTxtU);
368 }
369 return rc;
370 },
@@ -371,24 +372,65 @@
371
372 injectResponse: function(direction/*as for fetchChunk()*/,
373 urlParam/*from fetchChunk()*/,
374 lines/*response lines*/){
375 console.debug("Loading line range ",urlParam.from,"-",urlParam.to);
376 const row = this.newTR();
377 const lineno = [];
378 let i;
379 for( i = urlParam.from; i <= urlParam.to; ++i ){
380 /* TODO: space-pad numbers, but we don't know the proper length from here. */
381 lineno.push(i);
382 }
383 row.preLnL.innerText = lineno.join('\n')+'\n';
384 if(row.preTxtU){//unified diff
385 row.preTxtU.innerText = lines.join('\n')+'\n';
386 }else{//split diff
387 const code = lines.join('\n')+'\n';
388 row.preTxtL.innerText = code;
389 row.preTxtR.innerText = code;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
390 }
391 if(0===direction){
392 /* Closing the whole gap between two chunks or a whole gap
393 at the start or end of a diff. */
394 let startLnR = this.pos.prev
@@ -398,22 +440,36 @@
398 lineno.length = 0;
399 for( i = startLnR; i < startLnR + lines.length; ++i ){
400 /* TODO? space-pad numbers, but we don't know the proper length from here. */
401 lineno.push(i);
402 }
403 row.preLnR.innerText = lineno.join('\n')+'\n';
404 this.e.tr.parentNode.insertBefore(row.tr, this.e.tr);
405 Diff.initTableDiff(this.e.table/*fix scrolling*/).checkTableWidth(true);
 
 
 
 
 
 
 
 
 
 
 
406 this.destroy();
407 return this;
408 }else{
409 console.debug("TODO: handle load of partial next/prev");
410 this.updatePosDebug();
411 }
412 },
413
414 fetchChunk: function(direction/*-1=prev, 1=next, 0=both*/){
 
 
 
415 /* Forewarning, this is a bit confusing: when fetching the
416 previous lines, we're doing so on behalf of the *next* diff
417 chunk (this.pos.next), and vice versa. */
418 if(this.$isFetching){
419 console.debug("Cannot load chunk while a load is pending.");
420
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -344,27 +344,28 @@
344 so). Returns an object containing the TR element and various TD
345 elements which will likely be needed by the routine which
346 called this. See this code for details.
347 */
348 newTR: function(){
349 const tr = D.tr(), rc = {
350 tr,
351 preLnL: D.pre(),
352 preLnR: D.pre(),
353 preSep: D.pre()
354 };
355 if(this.isSplit){
356 D.append(D.addClass( D.td(tr), 'diffln', 'difflnl' ), rc.preLnL);
357 rc.preTxtL = D.pre();
358 D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtl' ), rc.preTxtL);
359 D.append(D.addClass( D.td(tr), 'diffsep' ), rc.preSep);
360 D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), rc.preLnR);
361 rc.preTxtR = D.pre();
362 D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtr' ), rc.preTxtR);
363 }else{
364 D.append(D.addClass( D.td(tr), 'diffln', 'difflnl' ), rc.preLnL);
365 D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), rc.preLnR);
366 D.append(D.addClass( D.td(tr), 'diffsep' ), rc.preSep);
367 rc.preTxtU = D.pre();
368 D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtu' ), rc.preTxtU);
369 }
370 return rc;
371 },
@@ -371,24 +372,65 @@
372
373 injectResponse: function(direction/*as for fetchChunk()*/,
374 urlParam/*from fetchChunk()*/,
375 lines/*response lines*/){
376 console.debug("Loading line range ",urlParam.from,"-",urlParam.to);
377 const lineno = [],
378 trPrev = this.e.tr.previousElementSibling,
379 trNext = this.e.tr.nextElementSibling,
380 doAppend = !!trPrev /* true to append to previous TR, else prepend to NEXT TR */;
381 const tr = trPrev || trNext;
382 if(0!==direction){
383 console.error("this case is not yet handled",arguments);
384 return this;
385 }
386 const joinTr = (0===direction && trPrev && trNext);
387 let i, td;
388 if(1){ // LHS line numbers...
389 const selector = '.difflnl > pre';
390 td = tr.querySelector(selector);
391 for( i = urlParam.from; i <= urlParam.to; ++i ){
392 lineno.push(i);
393 }
394 const lineNoTxt = lineno.join('\n')+'\n';
395 const content = [];
396 if(doAppend) content.push(td.innerHTML, lineNoTxt);
397 else content.push(lineNoTxt, td.innerHTML);
398 if(joinTr){
399 content.push(trNext.querySelector(selector).innerHTML);
400 }
401 td.innerHTML = content.join('');
402 }
403
404 if(1){// code block...
405 const selector = '.difftxt > pre';
406 td = tr.querySelectorAll(selector);
407 const code = D.append(D.div(),lines.join('\n')+'\n').innerText;
408 let joinNdx = 0;
409 td.forEach(function(e){
410 const content = [];
411 if(doAppend) content.push(e.innerHTML, code);
412 else content.push(code, e.innerHTML);
413 if(joinTr){
414 content.push(trNext.querySelectorAll(selector)[joinNdx++].innerHTML)
415 }
416 e.innerHTML = content.join('');
417 });
418 }
419 if(1){
420 // Add blank lines in (.diffsep>pre)
421 const selector = '.diffsep > pre';
422 td = tr.querySelector(selector);
423 for(i = 0; i < lineno.length; ++i) lineno[i] = '';
424 const blanks = lineno.join('\n')+'\n';
425 const content = [];
426 if(doAppend) content.push(td.innerHTML, blanks);
427 else content.push(blanks, td.innerHTML);
428 if(joinTr){
429 content.push(trNext.querySelector(selector).innerHTML);
430 }
431 td.innerHTML = content.join('');
432 }
433 if(0===direction){
434 /* Closing the whole gap between two chunks or a whole gap
435 at the start or end of a diff. */
436 let startLnR = this.pos.prev
@@ -398,22 +440,36 @@
440 lineno.length = 0;
441 for( i = startLnR; i < startLnR + lines.length; ++i ){
442 /* TODO? space-pad numbers, but we don't know the proper length from here. */
443 lineno.push(i);
444 }
445 const selector = '.difflnr > pre';
446 td = tr.querySelector(selector);
447 const lineNoTxt = lineno.join('\n')+'\n';
448 const content = [];
449 if(doAppend) content.push(td.innerHTML, lineNoTxt);
450 else content.push(lineNoTxt, td.innerHTML);
451 if(joinTr){
452 content.push(trNext.querySelector(selector).innerHTML);
453 }
454 td.innerHTML = content.join('');
455 if(joinTr){
456 D.remove(joinTr);
457 }
458 Diff.checkTableWidth(true);
459 this.destroy();
460 return this;
461 }else{
462 console.debug("TODO: handle load of partial next/prev");
463 this.updatePosDebug();
464 }
465 },
466
467 fetchChunk: function(direction/*-1=down from prev chunk,
468 1=up from next chunk,
469 0=full-gap filler for any neighoring
470 chunk(s)*/){
471 /* Forewarning, this is a bit confusing: when fetching the
472 previous lines, we're doing so on behalf of the *next* diff
473 chunk (this.pos.next), and vice versa. */
474 if(this.$isFetching){
475 console.debug("Cannot load chunk while a load is pending.");
476

Keyboard Shortcuts

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