Fossil SCM

Reinstate synchronized scrolling in side-by-side diff views. TODOs include adding a checkbox to toggle this on and off, and (possibly) reintegrating this with /wikiedit and /fileedit diff views.

stephan 2024-08-21 14:30 trunk
Commit 3ef1d06bd6aedd6363144b28df987ea8b5cb3caf6e56ded8447935020722c199
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -137,11 +137,11 @@
137137
repoUrl( repoRelativePath [,urlParams] )
138138
139139
Creates a URL by prepending this.rootPath to the given path
140140
(which must be relative from the top of the site, without a
141141
leading slash). If urlParams is a string, it must be
142
- paramters encoded in the form "key=val&key2=val2..." WITHOUT
142
+ parameters encoded in the form "key=val&key2=val2..." WITHOUT
143143
a leading '?'. If it's an object, all of its properties get
144144
appended to the URL in that form.
145145
*/
146146
F.repoUrl = function(path,urlParams){
147147
if(!urlParams) return this.rootPath+path;
148148
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -137,11 +137,11 @@
137 repoUrl( repoRelativePath [,urlParams] )
138
139 Creates a URL by prepending this.rootPath to the given path
140 (which must be relative from the top of the site, without a
141 leading slash). If urlParams is a string, it must be
142 paramters encoded in the form "key=val&key2=val2..." WITHOUT
143 a leading '?'. If it's an object, all of its properties get
144 appended to the URL in that form.
145 */
146 F.repoUrl = function(path,urlParams){
147 if(!urlParams) return this.rootPath+path;
148
--- src/fossil.bootstrap.js
+++ src/fossil.bootstrap.js
@@ -137,11 +137,11 @@
137 repoUrl( repoRelativePath [,urlParams] )
138
139 Creates a URL by prepending this.rootPath to the given path
140 (which must be relative from the top of the site, without a
141 leading slash). If urlParams is a string, it must be
142 parameters encoded in the form "key=val&key2=val2..." WITHOUT
143 a leading '?'. If it's an object, all of its properties get
144 appended to the URL in that form.
145 */
146 F.repoUrl = function(path,urlParams){
147 if(!urlParams) return this.rootPath+path;
148
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -620,5 +620,63 @@
620620
});
621621
return F;
622622
};
623623
Diff.setupDiffContextLoad();
624624
});
625
+/*
626
+** For a side-by-side diff, ensure that horizontal scrolling of either
627
+** side of the diff is synchronized with the other side.
628
+*/
629
+window.fossil.onPageLoad(function(){
630
+ const SCROLL_LEN = 25;
631
+ const F = window.fossil, D = F.dom, Diff = F.diff;
632
+ const scrollLeft = function(event){
633
+ const table = this.parentElement/*TD*/.parentElement/*TR*/.
634
+ parentElement/*TBODY*/.parentElement/*TABLE*/;
635
+ table.$txtPres.forEach((e)=>(e===this) ? 1 : (e.scrollLeft = this.scrollLeft));
636
+ return false;
637
+ };
638
+ Diff.initTableDiff = function f(diff, unifiedDiffs){
639
+ if(!diff){
640
+ let i, diffs;
641
+ diffs = document.querySelectorAll('table.splitdiff');
642
+ for(i=0; i<diffs.length; ++i){
643
+ f.call(this, diffs[i], false);
644
+ }
645
+ diffs = document.querySelectorAll('table.udiff');
646
+ for(i=0; i<diffs.length; ++i){
647
+ f.call(this, diffs[i], true);
648
+ }
649
+ return this;
650
+ }
651
+ diff.$txtCols = diff.querySelectorAll('td.difftxt');
652
+ diff.$txtPres = diff.querySelectorAll('td.difftxt pre');
653
+ var width = 0;
654
+ diff.$txtPres.forEach(function(e){
655
+ if(width < e.scrollWidth) width = e.scrollWidth;
656
+ });
657
+ diff.$txtPres.forEach(function(e){
658
+ if(!unifiedDiffs && !e.classList.contains('scroller')){
659
+ D.addClass(e, 'scroller');
660
+ e.addEventListener('scroll', scrollLeft, false);
661
+ }
662
+ });
663
+ if(!unifiedDiffs){
664
+ diff.tabIndex = 0;
665
+ if(!diff.classList.contains('scroller')){
666
+ D.addClass(diff, 'scroller');
667
+ diff.addEventListener('keydown', function(e){
668
+ e = e || event;
669
+ const len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
670
+ if( !len ) return;
671
+ this.$txtPres[0].scrollLeft += len;
672
+ return false;
673
+ }, false);
674
+ }
675
+ }
676
+ return this;
677
+ }
678
+ window.fossil.page.tweakSbsDiffs = function(){
679
+ document.querySelectorAll('table.splitdiff').forEach((e)=>Diff.initTableDiff(e));
680
+ };
681
+ Diff.initTableDiff();
682
+}, false);
625683
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -620,5 +620,63 @@
620 });
621 return F;
622 };
623 Diff.setupDiffContextLoad();
624 });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
625
--- src/fossil.diff.js
+++ src/fossil.diff.js
@@ -620,5 +620,63 @@
620 });
621 return F;
622 };
623 Diff.setupDiffContextLoad();
624 });
625 /*
626 ** For a side-by-side diff, ensure that horizontal scrolling of either
627 ** side of the diff is synchronized with the other side.
628 */
629 window.fossil.onPageLoad(function(){
630 const SCROLL_LEN = 25;
631 const F = window.fossil, D = F.dom, Diff = F.diff;
632 const scrollLeft = function(event){
633 const table = this.parentElement/*TD*/.parentElement/*TR*/.
634 parentElement/*TBODY*/.parentElement/*TABLE*/;
635 table.$txtPres.forEach((e)=>(e===this) ? 1 : (e.scrollLeft = this.scrollLeft));
636 return false;
637 };
638 Diff.initTableDiff = function f(diff, unifiedDiffs){
639 if(!diff){
640 let i, diffs;
641 diffs = document.querySelectorAll('table.splitdiff');
642 for(i=0; i<diffs.length; ++i){
643 f.call(this, diffs[i], false);
644 }
645 diffs = document.querySelectorAll('table.udiff');
646 for(i=0; i<diffs.length; ++i){
647 f.call(this, diffs[i], true);
648 }
649 return this;
650 }
651 diff.$txtCols = diff.querySelectorAll('td.difftxt');
652 diff.$txtPres = diff.querySelectorAll('td.difftxt pre');
653 var width = 0;
654 diff.$txtPres.forEach(function(e){
655 if(width < e.scrollWidth) width = e.scrollWidth;
656 });
657 diff.$txtPres.forEach(function(e){
658 if(!unifiedDiffs && !e.classList.contains('scroller')){
659 D.addClass(e, 'scroller');
660 e.addEventListener('scroll', scrollLeft, false);
661 }
662 });
663 if(!unifiedDiffs){
664 diff.tabIndex = 0;
665 if(!diff.classList.contains('scroller')){
666 D.addClass(diff, 'scroller');
667 diff.addEventListener('keydown', function(e){
668 e = e || event;
669 const len = {37: -SCROLL_LEN, 39: SCROLL_LEN}[e.keyCode];
670 if( !len ) return;
671 this.$txtPres[0].scrollLeft += len;
672 return false;
673 }, false);
674 }
675 }
676 return this;
677 }
678 window.fossil.page.tweakSbsDiffs = function(){
679 document.querySelectorAll('table.splitdiff').forEach((e)=>Diff.initTableDiff(e));
680 };
681 Diff.initTableDiff();
682 }, false);
683

Keyboard Shortcuts

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