fix(web): match loaded lines to a selection by file key, keep the focus on a closing menu, close menus with escape on every page and restore the hunk header contrast
- commit
- 32e9fe75d911f4768e499992c6eb8716e5562f14
- author
- brice · · 2026-10-19 15:52 UTC
- parent
- 4277264
- signature
- GPG Verified
CD88F9E564E0102646FB6077A1A07C7C7C3E349D· arch-gpg Verified for the committer email
13 files · +267 -244
M internal/adapters/web/diff.templ +1 -1
| @@ -221,7 +221,7 @@ templ DiffFileView(f DiffFile, p DiffView) { | |||
| 221 | 221 | <details | |
| 222 | 222 | class={ "dfile", "lnw-" + itoa(f.Digits) } | |
| 223 | 223 | id={ f.ID } | |
| 224 | - | data-file | |
| 224 | + | data-file={ f.Key } | |
| 225 | 225 | if f.Open { | |
| 226 | 226 | open | |
| 227 | 227 | } | |
| @@ -221,7 +221,7 @@ templ DiffFileView(f DiffFile, p DiffView) { | |||||
| 221 | <details | 221 | <details | ||
| 222 | class={ "dfile", "lnw-" + itoa(f.Digits) } | 222 | class={ "dfile", "lnw-" + itoa(f.Digits) } | ||
| 223 | id={ f.ID } | 223 | id={ f.ID } | ||
| 224 | - | data-file | 224 | + | data-file={ f.Key } |
| 225 | if f.Open { | 225 | if f.Open { | ||
| 226 | open | 226 | open | ||
| 227 | } | 227 | } | ||
M internal/adapters/web/diff_templ.go +229 -216 generated file: collapsed
M internal/adapters/web/static/css/50-code.css +1 -1
| @@ -82,7 +82,7 @@ | |||
| 82 | 82 | /* the hunk headers and the hidden lines stay quiet: a faint band between | |
| 83 | 83 | the code, so that the eye keeps reading */ | |
| 84 | 84 | & .hunk td, & .gap td { background: color-mix(in srgb, var(--paper-alt) 35%, var(--paper)); } | |
| 85 | - | & .hunk td { color: color-mix(in srgb, var(--ink-mute) 70%, transparent); padding: 0 1ch; } | |
| 85 | + | & .hunk td { color: var(--ink-mute); padding: 0 1ch; } | |
| 86 | 86 | /* a run of hidden lines: the whole row loads them */ | |
| 87 | 87 | & .gap td { padding: 0; } | |
| 88 | 88 | & .gap button { | |
| @@ -82,7 +82,7 @@ | |||||
| 82 | /* the hunk headers and the hidden lines stay quiet: a faint band between | 82 | /* the hunk headers and the hidden lines stay quiet: a faint band between | ||
| 83 | the code, so that the eye keeps reading */ | 83 | the code, so that the eye keeps reading */ | ||
| 84 | & .hunk td, & .gap td { background: color-mix(in srgb, var(--paper-alt) 35%, var(--paper)); } | 84 | & .hunk td, & .gap td { background: color-mix(in srgb, var(--paper-alt) 35%, var(--paper)); } | ||
| 85 | - | & .hunk td { color: color-mix(in srgb, var(--ink-mute) 70%, transparent); padding: 0 1ch; } | 85 | + | & .hunk td { color: var(--ink-mute); padding: 0 1ch; } |
| 86 | /* a run of hidden lines: the whole row loads them */ | 86 | /* a run of hidden lines: the whole row loads them */ | ||
| 87 | & .gap td { padding: 0; } | 87 | & .gap td { padding: 0; } | ||
| 88 | & .gap button { | 88 | & .gap button { | ||
M internal/adapters/web/static/js/ermite.js +20 -4
| @@ -407,7 +407,8 @@ | |||
| 407 | 407 | // The loaded rows are context lines, the same on both sides. | |
| 408 | 408 | function selectLoaded(file, rows) { | |
| 409 | 409 | const m = /^(new|old):(?:(\d+)-)?(\d+):(.+)$/.exec(new URLSearchParams(location.search).get('on') || ''); | |
| 410 | - | if (!m || file.querySelector('summary .p')?.textContent !== m[4]) return; | |
| 410 | + | // data-file is the path comments name (the new path of a rename), as ?on= | |
| 411 | + | if (!m || file.dataset.file !== m[4]) return; | |
| 411 | 412 | const end = Number(m[3]); | |
| 412 | 413 | const start = m[2] ? Number(m[2]) : end; | |
| 413 | 414 | for (const r of rows) { | |
| @@ -593,6 +594,21 @@ | |||
| 593 | 594 | return { toggle, apply }; | |
| 594 | 595 | })(); | |
| 595 | 596 | ||
| 597 | + | // The menus of the bars (<details class="menu">: the diff view, the merge | |
| 598 | + | // menu): closing one hands the focus back to its button when it was inside, | |
| 599 | + | // so that a keyboard user keeps their place. | |
| 600 | + | function closeMenu(d) { | |
| 601 | + | const had = d.contains(document.activeElement); | |
| 602 | + | d.open = false; | |
| 603 | + | if (had) $('summary', d)?.focus(); | |
| 604 | + | } | |
| 605 | + | // closeMenus closes every open menu (escape); true when one was open. | |
| 606 | + | function closeMenus() { | |
| 607 | + | const open = $$('details.menu[open]'); | |
| 608 | + | for (const d of open) closeMenu(d); | |
| 609 | + | return open.length > 0; | |
| 610 | + | } | |
| 611 | + | ||
| 596 | 612 | // 1. Keys. | |
| 597 | 613 | const single = { j: 'j', k: 'k', G: 'bottom', '/': 'filter', '?': 'help', b: 'refs', f: 'cmd', ':': 'cmd', y: 'permalink', | |
| 598 | 614 | s: 's', t: 't', c: 'c', r: 'r', m: 'm', i: 'i', n: 'next', h: 'left', l: 'right', d: 'split', u: 'unified', x: 'collapse', w: 'wide', e: 'expand', E: 'expandAll', Enter: 'open', Escape: 'esc', | |
| @@ -611,7 +627,7 @@ | |||
| 611 | 627 | const mr = window.ermiteMR; | |
| 612 | 628 | if (e.key === 'Escape') { | |
| 613 | 629 | pending = 0; | |
| 614 | - | if (mr?.closeMenus() || mr?.leaveFiles()) return; | |
| 630 | + | if (closeMenus() || mr?.leaveFiles()) return; | |
| 615 | 631 | if (typing) e.target.blur(); | |
| 616 | 632 | return ermite.fire('esc'); | |
| 617 | 633 | } | |
| @@ -651,9 +667,9 @@ | |||
| 651 | 667 | if (!el || e.button || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; | |
| 652 | 668 | e.preventDefault(); | |
| 653 | 669 | ermite.fire(el.dataset.fire); | |
| 654 | - | // A choice in a menu closes it. | |
| 670 | + | // A choice in a menu closes it; the focus goes back to its button. | |
| 655 | 671 | const menu = el.closest('details.menu'); | |
| 656 | - | if (menu) menu.open = false; | |
| 672 | + | if (menu) closeMenu(menu); | |
| 657 | 673 | }); | |
| 658 | 674 | // A click outside an open menu closes it. | |
| 659 | 675 | addEventListener('click', (e) => { | |
| @@ -407,7 +407,8 @@ | |||||
| 407 | // The loaded rows are context lines, the same on both sides. | 407 | // The loaded rows are context lines, the same on both sides. | ||
| 408 | function selectLoaded(file, rows) { | 408 | function selectLoaded(file, rows) { | ||
| 409 | const m = /^(new|old):(?:(\d+)-)?(\d+):(.+)$/.exec(new URLSearchParams(location.search).get('on') || ''); | 409 | const m = /^(new|old):(?:(\d+)-)?(\d+):(.+)$/.exec(new URLSearchParams(location.search).get('on') || ''); | ||
| 410 | - | if (!m || file.querySelector('summary .p')?.textContent !== m[4]) return; | 410 | + | // data-file is the path comments name (the new path of a rename), as ?on= |
| 411 | + | if (!m || file.dataset.file !== m[4]) return; | |||
| 411 | const end = Number(m[3]); | 412 | const end = Number(m[3]); | ||
| 412 | const start = m[2] ? Number(m[2]) : end; | 413 | const start = m[2] ? Number(m[2]) : end; | ||
| 413 | for (const r of rows) { | 414 | for (const r of rows) { | ||
| @@ -593,6 +594,21 @@ | |||||
| 593 | return { toggle, apply }; | 594 | return { toggle, apply }; | ||
| 594 | })(); | 595 | })(); | ||
| 595 | 596 | ||||
| 597 | + | // The menus of the bars (<details class="menu">: the diff view, the merge | |||
| 598 | + | // menu): closing one hands the focus back to its button when it was inside, | |||
| 599 | + | // so that a keyboard user keeps their place. | |||
| 600 | + | function closeMenu(d) { | |||
| 601 | + | const had = d.contains(document.activeElement); | |||
| 602 | + | d.open = false; | |||
| 603 | + | if (had) $('summary', d)?.focus(); | |||
| 604 | + | } | |||
| 605 | + | // closeMenus closes every open menu (escape); true when one was open. | |||
| 606 | + | function closeMenus() { | |||
| 607 | + | const open = $$('details.menu[open]'); | |||
| 608 | + | for (const d of open) closeMenu(d); | |||
| 609 | + | return open.length > 0; | |||
| 610 | + | } | |||
| 611 | + | ||||
| 596 | // 1. Keys. | 612 | // 1. Keys. | ||
| 597 | const single = { j: 'j', k: 'k', G: 'bottom', '/': 'filter', '?': 'help', b: 'refs', f: 'cmd', ':': 'cmd', y: 'permalink', | 613 | const single = { j: 'j', k: 'k', G: 'bottom', '/': 'filter', '?': 'help', b: 'refs', f: 'cmd', ':': 'cmd', y: 'permalink', | ||
| 598 | s: 's', t: 't', c: 'c', r: 'r', m: 'm', i: 'i', n: 'next', h: 'left', l: 'right', d: 'split', u: 'unified', x: 'collapse', w: 'wide', e: 'expand', E: 'expandAll', Enter: 'open', Escape: 'esc', | 614 | s: 's', t: 't', c: 'c', r: 'r', m: 'm', i: 'i', n: 'next', h: 'left', l: 'right', d: 'split', u: 'unified', x: 'collapse', w: 'wide', e: 'expand', E: 'expandAll', Enter: 'open', Escape: 'esc', | ||
| @@ -611,7 +627,7 @@ | |||||
| 611 | const mr = window.ermiteMR; | 627 | const mr = window.ermiteMR; | ||
| 612 | if (e.key === 'Escape') { | 628 | if (e.key === 'Escape') { | ||
| 613 | pending = 0; | 629 | pending = 0; | ||
| 614 | - | if (mr?.closeMenus() || mr?.leaveFiles()) return; | 630 | + | if (closeMenus() || mr?.leaveFiles()) return; |
| 615 | if (typing) e.target.blur(); | 631 | if (typing) e.target.blur(); | ||
| 616 | return ermite.fire('esc'); | 632 | return ermite.fire('esc'); | ||
| 617 | } | 633 | } | ||
| @@ -651,9 +667,9 @@ | |||||
| 651 | if (!el || e.button || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; | 667 | if (!el || e.button || e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return; | ||
| 652 | e.preventDefault(); | 668 | e.preventDefault(); | ||
| 653 | ermite.fire(el.dataset.fire); | 669 | ermite.fire(el.dataset.fire); | ||
| 654 | - | // A choice in a menu closes it. | 670 | + | // A choice in a menu closes it; the focus goes back to its button. |
| 655 | const menu = el.closest('details.menu'); | 671 | const menu = el.closest('details.menu'); | ||
| 656 | - | if (menu) menu.open = false; | 672 | + | if (menu) closeMenu(menu); |
| 657 | }); | 673 | }); | ||
| 658 | // A click outside an open menu closes it. | 674 | // A click outside an open menu closes it. | ||
| 659 | addEventListener('click', (e) => { | 675 | addEventListener('click', (e) => { | ||
M internal/adapters/web/static/js/mr.js +1 -7
| @@ -196,12 +196,6 @@ window.ermiteMR = (() => { | |||
| 196 | 196 | $('[data-default]', m)?.focus(); | |
| 197 | 197 | return true; | |
| 198 | 198 | } | |
| 199 | - | function closeMenus() { | |
| 200 | - | const open = $$('details.menu[open]'); | |
| 201 | - | for (const d of open) d.open = false; | |
| 202 | - | if (open.length) $('summary', open[0])?.focus(); | |
| 203 | - | return open.length > 0; | |
| 204 | - | } | |
| 205 | 199 | // menuKey handles a key while the merge menu is open; true when it used it. | |
| 206 | 200 | function menuKey(e) { | |
| 207 | 201 | const m = menu(); | |
| @@ -313,7 +307,7 @@ window.ermiteMR = (() => { | |||
| 313 | 307 | }); | |
| 314 | 308 | } | |
| 315 | 309 | ||
| 316 | - | return { core, start, load, reveal, openMerge, closeMenus, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile }; | |
| 310 | + | return { core, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile }; | |
| 317 | 311 | })(); | |
| 318 | 312 | ||
| 319 | 313 | if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start()); | |
| @@ -196,12 +196,6 @@ window.ermiteMR = (() => { | |||||
| 196 | $('[data-default]', m)?.focus(); | 196 | $('[data-default]', m)?.focus(); | ||
| 197 | return true; | 197 | return true; | ||
| 198 | } | 198 | } | ||
| 199 | - | function closeMenus() { | |||
| 200 | - | const open = $$('details.menu[open]'); | |||
| 201 | - | for (const d of open) d.open = false; | |||
| 202 | - | if (open.length) $('summary', open[0])?.focus(); | |||
| 203 | - | return open.length > 0; | |||
| 204 | - | } | |||
| 205 | // menuKey handles a key while the merge menu is open; true when it used it. | 199 | // menuKey handles a key while the merge menu is open; true when it used it. | ||
| 206 | function menuKey(e) { | 200 | function menuKey(e) { | ||
| 207 | const m = menu(); | 201 | const m = menu(); | ||
| @@ -313,7 +307,7 @@ window.ermiteMR = (() => { | |||||
| 313 | }); | 307 | }); | ||
| 314 | } | 308 | } | ||
| 315 | 309 | ||||
| 316 | - | return { core, start, load, reveal, openMerge, closeMenus, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile }; | 310 | + | return { core, start, load, reveal, openMerge, menuKey, markRead, focusFiles, stepFiles, leaveFiles, foldFiles, openFile }; |
| 317 | })(); | 311 | })(); | ||
| 318 | 312 | ||||
| 319 | if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start()); | 313 | if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', () => window.ermiteMR.start()); | ||
M internal/app/testdata/web/commit-big.html +1 -1
| @@ -143,7 +143,7 @@ | |||
| 143 | 143 | </div> | |
| 144 | 144 | <p class="notice">this diff is incomplete: 1 file is too large to show. the totals above count everything; clone the repository to read the rest.</p> | |
| 145 | 145 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 146 | - | <details class="dfile lnw-2" id="f1" data-file> | |
| 146 | + | <details class="dfile lnw-2" id="f1" data-file="big.txt"> | |
| 147 | 147 | <summary> | |
| 148 | 148 | <span class="st">A</span> | |
| 149 | 149 | <span class="p">big.txt</span> | |
| @@ -143,7 +143,7 @@ | |||||
| 143 | </div> | 143 | </div> | ||
| 144 | <p class="notice">this diff is incomplete: 1 file is too large to show. the totals above count everything; clone the repository to read the rest.</p> | 144 | <p class="notice">this diff is incomplete: 1 file is too large to show. the totals above count everything; clone the repository to read the rest.</p> | ||
| 145 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 145 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 146 | - | <details class="dfile lnw-2" id="f1" data-file> | 146 | + | <details class="dfile lnw-2" id="f1" data-file="big.txt"> |
| 147 | <summary> | 147 | <summary> | ||
| 148 | <span class="st">A</span> | 148 | <span class="st">A</span> | ||
| 149 | <span class="p">big.txt</span> | 149 | <span class="p">big.txt</span> | ||
M internal/app/testdata/web/commit-binary.html +1 -1
| @@ -138,7 +138,7 @@ | |||
| 138 | 138 | </details> | |
| 139 | 139 | </div> | |
| 140 | 140 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 141 | - | <details class="dfile lnw-2" id="f1" data-file> | |
| 141 | + | <details class="dfile lnw-2" id="f1" data-file="logo.bin"> | |
| 142 | 142 | <summary> | |
| 143 | 143 | <span class="st">M</span> | |
| 144 | 144 | <span class="p">logo.bin</span> | |
| @@ -138,7 +138,7 @@ | |||||
| 138 | </details> | 138 | </details> | ||
| 139 | </div> | 139 | </div> | ||
| 140 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 140 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 141 | - | <details class="dfile lnw-2" id="f1" data-file> | 141 | + | <details class="dfile lnw-2" id="f1" data-file="logo.bin"> |
| 142 | <summary> | 142 | <summary> | ||
| 143 | <span class="st">M</span> | 143 | <span class="st">M</span> | ||
| 144 | <span class="p">logo.bin</span> | 144 | <span class="p">logo.bin</span> | ||
M internal/app/testdata/web/commit-merge.html +1 -1
| @@ -137,7 +137,7 @@ | |||
| 137 | 137 | </details> | |
| 138 | 138 | </div> | |
| 139 | 139 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 140 | - | <details class="dfile lnw-2" id="f1" data-file open> | |
| 140 | + | <details class="dfile lnw-2" id="f1" data-file="side.txt" open> | |
| 141 | 141 | <summary> | |
| 142 | 142 | <span class="st">A</span> | |
| 143 | 143 | <span class="p">side.txt</span> | |
| @@ -137,7 +137,7 @@ | |||||
| 137 | </details> | 137 | </details> | ||
| 138 | </div> | 138 | </div> | ||
| 139 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 139 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 140 | - | <details class="dfile lnw-2" id="f1" data-file open> | 140 | + | <details class="dfile lnw-2" id="f1" data-file="side.txt" open> |
| 141 | <summary> | 141 | <summary> | ||
| 142 | <span class="st">A</span> | 142 | <span class="st">A</span> | ||
| 143 | <span class="p">side.txt</span> | 143 | <span class="p">side.txt</span> | ||
M internal/app/testdata/web/commit-modify-split.html +2 -2
| @@ -144,7 +144,7 @@ And <b>html</b> & "quotes".</pre> | |||
| 144 | 144 | </details> | |
| 145 | 145 | </div> | |
| 146 | 146 | <div id="diffs" data-diff="split"> | |
| 147 | - | <details class="dfile lnw-2" id="f1" data-file open> | |
| 147 | + | <details class="dfile lnw-2" id="f1" data-file="a.txt" open> | |
| 148 | 148 | <summary> | |
| 149 | 149 | <span class="st">M</span> | |
| 150 | 150 | <span class="p">a.txt</span> | |
| @@ -284,7 +284,7 @@ And <b>html</b> & "quotes".</pre> | |||
| 284 | 284 | </table> | |
| 285 | 285 | </div> | |
| 286 | 286 | </details> | |
| 287 | - | <details class="dfile lnw-2" id="f2" data-file> | |
| 287 | + | <details class="dfile lnw-2" id="f2" data-file="run.sh"> | |
| 288 | 288 | <summary> | |
| 289 | 289 | <span class="st">M</span> | |
| 290 | 290 | <span class="p">run.sh</span> | |
| @@ -144,7 +144,7 @@ And <b>html</b> & "quotes".</pre> | |||||
| 144 | </details> | 144 | </details> | ||
| 145 | </div> | 145 | </div> | ||
| 146 | <div id="diffs" data-diff="split"> | 146 | <div id="diffs" data-diff="split"> | ||
| 147 | - | <details class="dfile lnw-2" id="f1" data-file open> | 147 | + | <details class="dfile lnw-2" id="f1" data-file="a.txt" open> |
| 148 | <summary> | 148 | <summary> | ||
| 149 | <span class="st">M</span> | 149 | <span class="st">M</span> | ||
| 150 | <span class="p">a.txt</span> | 150 | <span class="p">a.txt</span> | ||
| @@ -284,7 +284,7 @@ And <b>html</b> & "quotes".</pre> | |||||
| 284 | </table> | 284 | </table> | ||
| 285 | </div> | 285 | </div> | ||
| 286 | </details> | 286 | </details> | ||
| 287 | - | <details class="dfile lnw-2" id="f2" data-file> | 287 | + | <details class="dfile lnw-2" id="f2" data-file="run.sh"> |
| 288 | <summary> | 288 | <summary> | ||
| 289 | <span class="st">M</span> | 289 | <span class="st">M</span> | ||
| 290 | <span class="p">run.sh</span> | 290 | <span class="p">run.sh</span> | ||
M internal/app/testdata/web/commit-modify.html +2 -2
| @@ -144,7 +144,7 @@ And <b>html</b> & "quotes".</pre> | |||
| 144 | 144 | </details> | |
| 145 | 145 | </div> | |
| 146 | 146 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 147 | - | <details class="dfile lnw-2" id="f1" data-file open> | |
| 147 | + | <details class="dfile lnw-2" id="f1" data-file="a.txt" open> | |
| 148 | 148 | <summary> | |
| 149 | 149 | <span class="st">M</span> | |
| 150 | 150 | <span class="p">a.txt</span> | |
| @@ -284,7 +284,7 @@ And <b>html</b> & "quotes".</pre> | |||
| 284 | 284 | </table> | |
| 285 | 285 | </div> | |
| 286 | 286 | </details> | |
| 287 | - | <details class="dfile lnw-2" id="f2" data-file> | |
| 287 | + | <details class="dfile lnw-2" id="f2" data-file="run.sh"> | |
| 288 | 288 | <summary> | |
| 289 | 289 | <span class="st">M</span> | |
| 290 | 290 | <span class="p">run.sh</span> | |
| @@ -144,7 +144,7 @@ And <b>html</b> & "quotes".</pre> | |||||
| 144 | </details> | 144 | </details> | ||
| 145 | </div> | 145 | </div> | ||
| 146 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 146 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 147 | - | <details class="dfile lnw-2" id="f1" data-file open> | 147 | + | <details class="dfile lnw-2" id="f1" data-file="a.txt" open> |
| 148 | <summary> | 148 | <summary> | ||
| 149 | <span class="st">M</span> | 149 | <span class="st">M</span> | ||
| 150 | <span class="p">a.txt</span> | 150 | <span class="p">a.txt</span> | ||
| @@ -284,7 +284,7 @@ And <b>html</b> & "quotes".</pre> | |||||
| 284 | </table> | 284 | </table> | ||
| 285 | </div> | 285 | </div> | ||
| 286 | </details> | 286 | </details> | ||
| 287 | - | <details class="dfile lnw-2" id="f2" data-file> | 287 | + | <details class="dfile lnw-2" id="f2" data-file="run.sh"> |
| 288 | <summary> | 288 | <summary> | ||
| 289 | <span class="st">M</span> | 289 | <span class="st">M</span> | ||
| 290 | <span class="p">run.sh</span> | 290 | <span class="p">run.sh</span> | ||
M internal/app/testdata/web/commit-rename.html +2 -2
| @@ -138,7 +138,7 @@ | |||
| 138 | 138 | </details> | |
| 139 | 139 | </div> | |
| 140 | 140 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 141 | - | <details class="dfile lnw-2" id="f1" data-file> | |
| 141 | + | <details class="dfile lnw-2" id="f1" data-file="docs-old.txt"> | |
| 142 | 142 | <summary> | |
| 143 | 143 | <span class="st">R</span> | |
| 144 | 144 | <span class="p">old.txt → docs-old.txt</span> | |
| @@ -148,7 +148,7 @@ | |||
| 148 | 148 | </summary> | |
| 149 | 149 | <p class="note pad">renamed, 100% similar</p> | |
| 150 | 150 | </details> | |
| 151 | - | <details class="dfile lnw-2" id="f2" data-file open> | |
| 151 | + | <details class="dfile lnw-2" id="f2" data-file="gone.txt" open> | |
| 152 | 152 | <summary> | |
| 153 | 153 | <span class="st">D</span> | |
| 154 | 154 | <span class="p">gone.txt</span> | |
| @@ -138,7 +138,7 @@ | |||||
| 138 | </details> | 138 | </details> | ||
| 139 | </div> | 139 | </div> | ||
| 140 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 140 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 141 | - | <details class="dfile lnw-2" id="f1" data-file> | 141 | + | <details class="dfile lnw-2" id="f1" data-file="docs-old.txt"> |
| 142 | <summary> | 142 | <summary> | ||
| 143 | <span class="st">R</span> | 143 | <span class="st">R</span> | ||
| 144 | <span class="p">old.txt → docs-old.txt</span> | 144 | <span class="p">old.txt → docs-old.txt</span> | ||
| @@ -148,7 +148,7 @@ | |||||
| 148 | </summary> | 148 | </summary> | ||
| 149 | <p class="note pad">renamed, 100% similar</p> | 149 | <p class="note pad">renamed, 100% similar</p> | ||
| 150 | </details> | 150 | </details> | ||
| 151 | - | <details class="dfile lnw-2" id="f2" data-file open> | 151 | + | <details class="dfile lnw-2" id="f2" data-file="gone.txt" open> |
| 152 | <summary> | 152 | <summary> | ||
| 153 | <span class="st">D</span> | 153 | <span class="st">D</span> | ||
| 154 | <span class="p">gone.txt</span> | 154 | <span class="p">gone.txt</span> | ||
M internal/app/testdata/web/commit-root.html +5 -5
| @@ -136,7 +136,7 @@ | |||
| 136 | 136 | </details> | |
| 137 | 137 | </div> | |
| 138 | 138 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 139 | - | <details class="dfile lnw-2" id="f1" data-file open> | |
| 139 | + | <details class="dfile lnw-2" id="f1" data-file="a.txt" open> | |
| 140 | 140 | <summary> | |
| 141 | 141 | <span class="st">A</span> | |
| 142 | 142 | <span class="p">a.txt</span> | |
| @@ -258,7 +258,7 @@ | |||
| 258 | 258 | </table> | |
| 259 | 259 | </div> | |
| 260 | 260 | </details> | |
| 261 | - | <details class="dfile lnw-2" id="f2" data-file open> | |
| 261 | + | <details class="dfile lnw-2" id="f2" data-file="gone.txt" open> | |
| 262 | 262 | <summary> | |
| 263 | 263 | <span class="st">A</span> | |
| 264 | 264 | <span class="p">gone.txt</span> | |
| @@ -308,7 +308,7 @@ | |||
| 308 | 308 | </table> | |
| 309 | 309 | </div> | |
| 310 | 310 | </details> | |
| 311 | - | <details class="dfile lnw-2" id="f3" data-file> | |
| 311 | + | <details class="dfile lnw-2" id="f3" data-file="logo.bin"> | |
| 312 | 312 | <summary> | |
| 313 | 313 | <span class="st">A</span> | |
| 314 | 314 | <span class="p">logo.bin</span> | |
| @@ -318,7 +318,7 @@ | |||
| 318 | 318 | </summary> | |
| 319 | 319 | <p class="note pad">binary file: no text diff</p> | |
| 320 | 320 | </details> | |
| 321 | - | <details class="dfile lnw-2" id="f4" data-file open> | |
| 321 | + | <details class="dfile lnw-2" id="f4" data-file="old.txt" open> | |
| 322 | 322 | <summary> | |
| 323 | 323 | <span class="st">A</span> | |
| 324 | 324 | <span class="p">old.txt</span> | |
| @@ -404,7 +404,7 @@ | |||
| 404 | 404 | </table> | |
| 405 | 405 | </div> | |
| 406 | 406 | </details> | |
| 407 | - | <details class="dfile lnw-2" id="f5" data-file open> | |
| 407 | + | <details class="dfile lnw-2" id="f5" data-file="run.sh" open> | |
| 408 | 408 | <summary> | |
| 409 | 409 | <span class="st">A</span> | |
| 410 | 410 | <span class="p">run.sh</span> | |
| @@ -136,7 +136,7 @@ | |||||
| 136 | </details> | 136 | </details> | ||
| 137 | </div> | 137 | </div> | ||
| 138 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 138 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 139 | - | <details class="dfile lnw-2" id="f1" data-file open> | 139 | + | <details class="dfile lnw-2" id="f1" data-file="a.txt" open> |
| 140 | <summary> | 140 | <summary> | ||
| 141 | <span class="st">A</span> | 141 | <span class="st">A</span> | ||
| 142 | <span class="p">a.txt</span> | 142 | <span class="p">a.txt</span> | ||
| @@ -258,7 +258,7 @@ | |||||
| 258 | </table> | 258 | </table> | ||
| 259 | </div> | 259 | </div> | ||
| 260 | </details> | 260 | </details> | ||
| 261 | - | <details class="dfile lnw-2" id="f2" data-file open> | 261 | + | <details class="dfile lnw-2" id="f2" data-file="gone.txt" open> |
| 262 | <summary> | 262 | <summary> | ||
| 263 | <span class="st">A</span> | 263 | <span class="st">A</span> | ||
| 264 | <span class="p">gone.txt</span> | 264 | <span class="p">gone.txt</span> | ||
| @@ -308,7 +308,7 @@ | |||||
| 308 | </table> | 308 | </table> | ||
| 309 | </div> | 309 | </div> | ||
| 310 | </details> | 310 | </details> | ||
| 311 | - | <details class="dfile lnw-2" id="f3" data-file> | 311 | + | <details class="dfile lnw-2" id="f3" data-file="logo.bin"> |
| 312 | <summary> | 312 | <summary> | ||
| 313 | <span class="st">A</span> | 313 | <span class="st">A</span> | ||
| 314 | <span class="p">logo.bin</span> | 314 | <span class="p">logo.bin</span> | ||
| @@ -318,7 +318,7 @@ | |||||
| 318 | </summary> | 318 | </summary> | ||
| 319 | <p class="note pad">binary file: no text diff</p> | 319 | <p class="note pad">binary file: no text diff</p> | ||
| 320 | </details> | 320 | </details> | ||
| 321 | - | <details class="dfile lnw-2" id="f4" data-file open> | 321 | + | <details class="dfile lnw-2" id="f4" data-file="old.txt" open> |
| 322 | <summary> | 322 | <summary> | ||
| 323 | <span class="st">A</span> | 323 | <span class="st">A</span> | ||
| 324 | <span class="p">old.txt</span> | 324 | <span class="p">old.txt</span> | ||
| @@ -404,7 +404,7 @@ | |||||
| 404 | </table> | 404 | </table> | ||
| 405 | </div> | 405 | </div> | ||
| 406 | </details> | 406 | </details> | ||
| 407 | - | <details class="dfile lnw-2" id="f5" data-file open> | 407 | + | <details class="dfile lnw-2" id="f5" data-file="run.sh" open> |
| 408 | <summary> | 408 | <summary> | ||
| 409 | <span class="st">A</span> | 409 | <span class="st">A</span> | ||
| 410 | <span class="p">run.sh</span> | 410 | <span class="p">run.sh</span> | ||
M internal/app/testdata/web/commit-trojan.html +1 -1
| @@ -140,7 +140,7 @@ | |||
| 140 | 140 | </div> | |
| 141 | 141 | <p class="notice">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class="inv"><U+XXXX></span> markers, never applied.</p> | |
| 142 | 142 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | |
| 143 | - | <details class="dfile lnw-2" id="f1" data-file open> | |
| 143 | + | <details class="dfile lnw-2" id="f1" data-file="evil.go" open> | |
| 144 | 144 | <summary> | |
| 145 | 145 | <span class="st">A</span> | |
| 146 | 146 | <span class="p">evil.go</span> | |
| @@ -140,7 +140,7 @@ | |||||
| 140 | </div> | 140 | </div> | ||
| 141 | <p class="notice">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class="inv"><U+XXXX></span> markers, never applied.</p> | 141 | <p class="notice">this diff holds invisible characters (direction controls, zero-width characters). They are shown as <span class="inv"><U+XXXX></span> markers, never applied.</p> | ||
| 142 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | 142 | <div id="diffs" data-diff="unified" hx-live="this.dataset.diff = sessionStorage.getItem('diff') || this.dataset.diff"> | ||
| 143 | - | <details class="dfile lnw-2" id="f1" data-file open> | 143 | + | <details class="dfile lnw-2" id="f1" data-file="evil.go" open> |
| 144 | <summary> | 144 | <summary> | ||
| 145 | <span class="st">A</span> | 145 | <span class="st">A</span> | ||
| 146 | <span class="p">evil.go</span> | 146 | <span class="p">evil.go</span> | ||