Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | Re-enable side-by-side diff sync scrolling and add a client-side persistent toggle for the preference, accessible as a checkbox in various pages which render sbs diffs. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA3-256: |
c03ce0f4d43197a3932123d7b7bbe225 |
| User & Date: | stephan 2024-09-03 11:48:40.364 |
References
|
2024-09-06
| ||
| 14:37 | Add fossil.storage to the fossil.diff JS bundle dependencies, which should have been part of [c03ce0f4d43197a]. Resolves the report in [forum:3e1b1f82d1 | forum post 3e1b1f82d1] but does not explain why it worked for me locally before this fix (it should not have). Edit: it worked locally because my server was using jsmode:bundled. This fix makes it also work with jsmode:separate or jsmode:inline. ... (check-in: 59b383ae14 user: stephan tags: trunk) | |
Context
|
2024-09-03
| ||
| 11:55 | Reuse scroll-related callbacks where possible instead of redefining them on a per-element basis. ... (check-in: ddeba72d13 user: stephan tags: trunk) | |
| 11:48 | Re-enable side-by-side diff sync scrolling and add a client-side persistent toggle for the preference, accessible as a checkbox in various pages which render sbs diffs. ... (check-in: c03ce0f4d4 user: stephan tags: trunk) | |
| 11:45 | Correct handling of keyboard-based diff scrolling. ... (Closed-Leaf check-in: 0ef89983b8 user: stephan tags: diff-scroll-sync) | |
| 09:47 | In /setup_uinfo, correct the URL parameter passed from the 'edit' link to /setup_uedit: id instead of uid. ... (check-in: a84b669e52 user: stephan tags: trunk) | |
Changes
Changes to src/default.css.
| ︙ | ︙ | |||
1349 1350 1351 1352 1353 1354 1355 |
(e.g. DIV) so that certain nesting constructs are legal.
*/
.input-with-label {
border: 1px inset rgba(128, 128, 128, 0.5);
border-radius: 0.25em;
padding: 0.1em;
margin: 0 0.5em;
| | > > > > > > > > | 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 |
(e.g. DIV) so that certain nesting constructs are legal.
*/
.input-with-label {
border: 1px inset rgba(128, 128, 128, 0.5);
border-radius: 0.25em;
padding: 0.1em;
margin: 0 0.5em;
display: inline-block
/* We would really like flex layout but changing that
currently introduces a good deal of UI breakage
to chase down. The advantage would be better alignment
of the contained elements. */;
cursor: default;
white-space: nowrap;
}
.submenu .input-with-label {
border: none;
}
.input-with-label > * {
vertical-align: middle;
}
.input-with-label > label {
display: inline; /* some skins set label display to block! */
cursor: pointer;
white-space: nowrap;
}
.input-with-label > input {
margin: 0;
}
.input-with-label > button {
margin: 0;
}
|
| ︙ | ︙ |
Changes to src/fossil.bootstrap.js.
| ︙ | ︙ | |||
135 136 137 138 139 140 141 |
};
/**
repoUrl( repoRelativePath [,urlParams] )
Creates a URL by prepending this.rootPath to the given path
(which must be relative from the top of the site, without a
leading slash). If urlParams is a string, it must be
| | | 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
};
/**
repoUrl( repoRelativePath [,urlParams] )
Creates a URL by prepending this.rootPath to the given path
(which must be relative from the top of the site, without a
leading slash). If urlParams is a string, it must be
parameters encoded in the form "key=val&key2=val2..." WITHOUT
a leading '?'. If it's an object, all of its properties get
appended to the URL in that form.
*/
F.repoUrl = function(path,urlParams){
if(!urlParams) return this.rootPath+path;
const url=[this.rootPath,path];
url.push('?');
|
| ︙ | ︙ |
Changes to src/fossil.diff.js.
| ︙ | ︙ | |||
618 619 620 621 622 623 624 |
new ChunkLoadControls(D.addClass(tr, 'jchunk'));
});
});
return F;
};
Diff.setupDiffContextLoad();
});
| > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 |
new ChunkLoadControls(D.addClass(tr, 'jchunk'));
});
});
return F;
};
Diff.setupDiffContextLoad();
});
/*
** For a side-by-side diff, ensure that horizontal scrolling of either
** side of the diff is synchronized with the other side.
*/
window.fossil.onPageLoad(function(){
const F = window.fossil, D = F.dom, Diff = F.diff;
/* Look for a parent element to hold the sbs-sync-scroll toggle
checkbox. This differs per page. If we don't find one, simply
elide that toggle and use whatever preference the user last
specified (defaulting to on). */
let cbSync /* scroll-sync checkbox */;
let eToggleParent /* element to put the sync-scroll checkbox in */;
const potentialParents = [ /* possible parents for the checkbox */
/* Put the most likely pages at the end, as array.pop() is more
efficient than array.shift() (see loop below). */
/* /filedit */ 'body.cpage-fileedit #fileedit-tab-diff-buttons',
/* /wikiedit */ 'body.cpage-wikiedit #wikiedit-tab-diff-buttons',
/* /vdiff */ 'body.vdiff form div.submenu',
/* /info, /vinfo */ 'body.vinfo div.sectionmenu.info-changes-menu'
];
while( potentialParents.length ){
if( (eToggleParent = document.querySelector(potentialParents.pop())) ){
break;
}
}
const keySbsScroll = 'sync-diff-scroll' /* F.storage key */;
if( eToggleParent ){
/* Add a checkbox to toggle sbs scroll sync. Remember that in
order to be UI-consistent in the /vdiff page we have to ensure
that the checkbox is to the LEFT of of its label. We store the
sync-scroll preference in F.storage (not a cookie) so that it
persists across page loads and different apps. */
cbSync = D.checkbox(keySbsScroll, F.storage.getBool(keySbsScroll,true));
D.append(eToggleParent, D.append(
D.addClass(D.create('span'), 'input-with-label'),
D.append(D.create('label'),
cbSync, "Sync side-by-side scrolling?")
));
cbSync.addEventListener('change', function(e){
F.storage.set(keySbsScroll, e.target.checked);
});
}
const useSync = cbSync ? ()=>cbSync.checked : ()=>F.storage.getBool(keySbsScroll,true);
/* Now set up the events to enable syncronized scrolling... */
const scrollLeft = function(event){
const table = this.parentElement/*TD*/.parentElement/*TR*/.
parentElement/*TBODY*/.parentElement/*TABLE*/;
if( useSync() ){
table.$txtPres.forEach((e)=>(e===this) ? 1 : (e.scrollLeft = this.scrollLeft));
}
return false;
};
const SCROLL_LEN = 64/* pixels to scroll for keyboard events */;
const keycodes = Object.assign(Object.create(null),{
37/*cursor left*/: -SCROLL_LEN, 39/*cursor right*/: SCROLL_LEN
});
/**
Sets up synchronized scrolling of table.splitdiff element
`diff`. If passed no argument, it scans the dom for elements to
initialize. The second argument is for this function's own
internal use.
It's okay (but wasteful) to pass the same element to this
function multiple times: it will only be set up for sync
scrolling the first time it's passed to this function.
Note that this setup is ignorant of the cbSync toggle: the toggle
is checked when scrolling, not when initializing the sync-scroll
capability.
*/
const initTableDiff = function f(diff, unifiedDiffs){
if(!diff){
let i, diffs;
diffs = document.querySelectorAll('table.splitdiff');
for(i=0; i<diffs.length; ++i){
f.call(this, diffs[i], false);
}
diffs = document.querySelectorAll('table.udiff');
for(i=0; i<diffs.length; ++i){
f.call(this, diffs[i], true);
}
return this;
}
diff.$txtCols = diff.querySelectorAll('td.difftxt');
diff.$txtPres = diff.querySelectorAll('td.difftxt pre');
if(!unifiedDiffs){
diff.$txtPres.forEach(function(e){
if(!e.classList.contains('scroller')){
D.addClass(e, 'scroller');
e.addEventListener('scroll', scrollLeft, false);
}
});
diff.tabIndex = 0;
if(!diff.classList.contains('scroller')){
/* Keyboard-based scrolling requires special-case handling to
ensure that we scroll the proper side of the diff when sync
is off. */
D.addClass(diff, 'scroller');
diff.addEventListener('keydown', function(e){
const len = keycodes[e.keyCode];
if( !len ) return false;
if( useSync() ){
this.$txtPres[0].scrollLeft += len;
}else if( diff.$preCurrent ){
this.$preCurrent.scrollLeft += len;
}
return false;
}, false);
diff.$txtPres.forEach((e)=>{
e.addEventListener('click', function(ev){
diff.$preCurrent = this /* NOT ev.target, which is probably a child element */;
}, false);
})
}
}
return this;
}
window.fossil.page.tweakSbsDiffs = function(){
document.querySelectorAll('table.splitdiff').forEach((e)=>initTableDiff(e));
};
initTableDiff();
}, false);
|
Changes to src/fossil.page.fileedit.js.
| ︙ | ︙ | |||
1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 |
D.parseHtml(D.clearElement(target),[
"<div>Diff <code>[",
self.finfo.checkin,
"]</code> → Local Edits</div>",
c||'No changes.'
].join(''));
F.diff.setupDiffContextLoad();
F.message('Updated diff.');
self.tabs.switchToTab(self.e.tabs.diff);
}
});
return this;
};
| > | 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 |
D.parseHtml(D.clearElement(target),[
"<div>Diff <code>[",
self.finfo.checkin,
"]</code> → Local Edits</div>",
c||'No changes.'
].join(''));
F.diff.setupDiffContextLoad();
if(sbs) P.tweakSbsDiffs();
F.message('Updated diff.');
self.tabs.switchToTab(self.e.tabs.diff);
}
});
return this;
};
|
| ︙ | ︙ |
Changes to src/fossil.page.wikiedit.js.
| ︙ | ︙ | |||
1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 |
D.parseHtml(D.clearElement(target), [
"<div>Diff <code>[",
self.winfo.name,
"]</code> → Local Edits</div>",
c||'No changes.'
].join(''));
F.diff.setupDiffContextLoad();
F.message('Updated diff.');
self.tabs.switchToTab(self.e.tabs.diff);
}
});
return this;
};
| > | 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 |
D.parseHtml(D.clearElement(target), [
"<div>Diff <code>[",
self.winfo.name,
"]</code> → Local Edits</div>",
c||'No changes.'
].join(''));
F.diff.setupDiffContextLoad();
if(sbs) P.tweakSbsDiffs();
F.message('Updated diff.');
self.tabs.switchToTab(self.e.tabs.diff);
}
});
return this;
};
|
| ︙ | ︙ |
Changes to src/info.c.
| ︙ | ︙ | |||
889 890 891 892 893 894 895 |
}
render_backlink_graph(zUuid,
"<div class=\"section accordion\">References</div>\n");
@ <div class="section accordion">Context</div><div class="accordion_panel">
render_checkin_context(rid, 0, 0, 0);
@ </div><div class="section accordion">Changes</div>
@ <div class="accordion_panel">
| | > | 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 |
}
render_backlink_graph(zUuid,
"<div class=\"section accordion\">References</div>\n");
@ <div class="section accordion">Context</div><div class="accordion_panel">
render_checkin_context(rid, 0, 0, 0);
@ </div><div class="section accordion">Changes</div>
@ <div class="accordion_panel">
@ <div class="sectionmenu info-changes-menu">
/* ^^^ .info-changes-menu is used by diff scroll sync */
pCfg = construct_diff_flags(diffType, &DCfg);
DCfg.pRe = pRe;
zW = (DCfg.diffFlags&DIFF_IGNORE_ALLWS)?"&w":"";
if( diffType!=0 ){
@ %z(chref("button","%R/%s/%T?diff=0",zPageHide,zName))\
@ Hide Diffs</a>
}
|
| ︙ | ︙ |