-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
Add pull request files line selections #36014
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
| {{else}} | ||
| {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} | ||
| <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||
| <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"{{if $line.LeftIdx}} id="diff-{{$.FileNameHash}}L{{$line.LeftIdx}}"{{end}}></span></td> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why duplicate rel= and id=?
| {{else}} | ||
| {{$inlineDiff := $.section.GetComputedInlineDiffFor $line ctx.Locale}} | ||
| <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"></span></td> | ||
| <td class="lines-num lines-num-old" data-line-num="{{if $line.LeftIdx}}{{$line.LeftIdx}}{{end}}"><span rel="{{if $line.LeftIdx}}diff-{{$.FileNameHash}}L{{$line.LeftIdx}}{{end}}"{{if $line.LeftIdx}} id="diff-{{$.FileNameHash}}L{{$line.LeftIdx}}"{{end}}></span></td> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not have a clear defination like diff-{hash}-{L|R}xxx?
| function changeHash(hash: string) { | ||
| if (window.history.pushState) { | ||
| window.history.pushState(null, null, hash); | ||
| } else { | ||
| window.location.hash = hash; | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it stays, it should be moved to web_src/js/utils/dom.ts as a general DOM utility.
But I think it's pointless to test for existance window.history.pushState, every browser released in the last 15 years should have that function, so we can just assume it's there, and in which case this function makes no sense and it should just use window.history.pushState directly.
Oh and please pass '' as second argument to it, typescript wants it that way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh and likely this should use window.history.replaceState (see other comment below).
| } | ||
|
|
||
| export function parseDiffHashRange(hashValue: string): DiffSelectionRange | null { | ||
| if (!hashValue.startsWith('diff-')) return null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not the first time see the same logic startsWith('diff-' ....
| } | ||
| } | ||
|
|
||
| if (!applyDiffLineSelection(container, range, {updateHash: false})) return false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updateHash option is an over-design.
You can simply:
if (!applyDiffLineSelection(container, range)) return false;
updateHash(.....);
| // Scroll to the first selected line (scroll to the tr element, not the span) | ||
| // The span is an inline element inside td, we need to scroll to the tr for better visibility | ||
| await sleep(10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't be right
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it needs a sleep(0) or requestAnimationFrame? Both should flush the JS event loop of pending tasks with the latter being faster.
| // Ignore clicks on or inside code-expander-buttons | ||
| const target = e.target as HTMLElement; | ||
| if (target.closest('.code-expander-button') || target.closest('.code-expander-buttons') || | ||
| target.closest('button, a, input, select, textarea, summary, [role="button"]')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where the list comes from? Won't it miss something?
| initImageDiff(); | ||
| initDiffHeaderPopup(); | ||
| // Re-apply hash selection in case the target was just loaded | ||
| await highlightDiffSelectionFromHash(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you should follow the TODO, but not keep adding unwanted code.
| const range = parseDiffHashRange(hashValue); | ||
| if (range) { | ||
| // This is a line selection hash, try to highlight it first | ||
| const success = await highlightDiffSelectionFromHash(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should merge the old logic targetElement.scrollIntoView(); into highlightDiffSelectionFromHash
| const targetId = `${range.fragment}${range.startSide}${range.startLine}`; | ||
| // eslint-disable-next-line unicorn/prefer-query-selector | ||
| targetElement = document.getElementById(targetId); | ||
| if (targetElement) { | ||
| // Try again to highlight and scroll now that the element is loaded | ||
| await highlightDiffSelectionFromHash(); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't seem right.
What if then "endLine" is still not loaded.
| return {anchor, fragment, side, line}; | ||
| } | ||
|
|
||
| function applyDiffLineSelection(container: HTMLElement, range: DiffSelectionRange, options?: {updateHash?: boolean}): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All the complex logic needs tests if it is testable in frontend unit test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Basic DOM interactions should be testable, thought I'm not sure if it's really worth it for this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you can fully understand the logic and confirm its right, then not worth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replicating the DOM structure in a unit test will be hard. Ideally we should have e2e tests for this kind of stuff, but we don't (yet). If possible, extract testable functions here which ideally have no DOM interaction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah such non-DOM logic is easily testable and should be tested.
| // Expand the file using the setFileFolding utility | ||
| setFileFolding(container, foldBtn, false); | ||
| // Wait a bit for the expansion animation | ||
| await sleep(100); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can use https://developer.mozilla.org/en-US/docs/Web/API/Element/transitionend_event to detect when a transition has finished but it may be better to make setFileFolding return a Promise that resolves when the transition has ended.
| await sleep(10); | ||
| const targetTr = targetSpan.closest('tr'); | ||
| if (targetTr) { | ||
| targetTr.scrollIntoView({behavior: 'smooth', block: 'center'}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally hate smooth scrolling, maybe scroll instantly?
| window.history.pushState(null, null, window.location.pathname + window.location.search); | ||
| } else { | ||
| window.location.hash = ''; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe you actually want to use window.history.replaceState? I hate sites that push useless history entries because it pollutes the "back" stack, making the user hit the back button more than is necessary.


This PR allows select multiple lines on the pull request files view page.