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.
Commit
3ef1d06bd6aedd6363144b28df987ea8b5cb3caf6e56ded8447935020722c199
Parent
abeb57d28e44c2f…
2 files changed
+1
-1
+58
+1
-1
| --- src/fossil.bootstrap.js | ||
| +++ src/fossil.bootstrap.js | ||
| @@ -137,11 +137,11 @@ | ||
| 137 | 137 | repoUrl( repoRelativePath [,urlParams] ) |
| 138 | 138 | |
| 139 | 139 | Creates a URL by prepending this.rootPath to the given path |
| 140 | 140 | (which must be relative from the top of the site, without a |
| 141 | 141 | 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 | |
| 143 | 143 | a leading '?'. If it's an object, all of its properties get |
| 144 | 144 | appended to the URL in that form. |
| 145 | 145 | */ |
| 146 | 146 | F.repoUrl = function(path,urlParams){ |
| 147 | 147 | if(!urlParams) return this.rootPath+path; |
| 148 | 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 | 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 |
+58
| --- src/fossil.diff.js | ||
| +++ src/fossil.diff.js | ||
| @@ -620,5 +620,63 @@ | ||
| 620 | 620 | }); |
| 621 | 621 | return F; |
| 622 | 622 | }; |
| 623 | 623 | Diff.setupDiffContextLoad(); |
| 624 | 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); | |
| 625 | 683 |
| --- 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 |