Skip to content

Commit e9481e1

Browse files
Fix line-button issue after file selection in file tree (#34574) (#34576)
Backport #34574 --------- Co-authored-by: Kerwin Bryant <[email protected]>
1 parent 8965c06 commit e9481e1

File tree

3 files changed

+31
-10
lines changed

3 files changed

+31
-10
lines changed

web_src/css/base.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -867,6 +867,7 @@ overflow-menu .ui.label {
867867
}
868868

869869
.file-view tr.active .lines-num,
870+
.file-view tr.active .lines-escape,
870871
.file-view tr.active .lines-code {
871872
background: var(--color-highlight-bg) !important;
872873
}

web_src/js/features/repo-code.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,15 @@ function showLineButton() {
110110
}
111111

112112
export function initRepoCodeView() {
113-
if (!document.querySelector('.code-view .lines-num')) return;
113+
// When viewing a file or blame, there is always a ".file-view" element,
114+
// but the ".code-view" class is only present when viewing the "code" of a file; it is not present when viewing a PDF file.
115+
// Since the ".file-view" will be dynamically reloaded when navigating via the left file tree (eg: view a PDF file, then view a source code file, etc.)
116+
// the "code-view" related event listeners should always be added when the current page contains ".file-view" element.
117+
if (!document.querySelector('.repo-view-container .file-view')) return;
114118

119+
// "file code view" and "blame" pages need this "line number button" feature
115120
let selRangeStart: string;
116-
addDelegatedEventListener(document, 'click', '.lines-num span', (el: HTMLElement, e: KeyboardEvent) => {
121+
addDelegatedEventListener(document, 'click', '.code-view .lines-num span', (el: HTMLElement, e: KeyboardEvent) => {
117122
if (!selRangeStart || !e.shiftKey) {
118123
selRangeStart = el.getAttribute('id');
119124
selectRange(selRangeStart);
@@ -125,12 +130,14 @@ export function initRepoCodeView() {
125130
showLineButton();
126131
});
127132

133+
// apply the selected range from the URL hash
128134
const onHashChange = () => {
129135
if (!window.location.hash) return;
136+
if (!document.querySelector('.code-view .lines-num')) return;
130137
const range = window.location.hash.substring(1);
131138
const first = selectRange(range);
132139
if (first) {
133-
// set scrollRestoration to 'manual' when there is a hash in url, so that the scroll position will not be remembered after refreshing
140+
// set scrollRestoration to 'manual' when there is a hash in the URL, so that the scroll position will not be remembered after refreshing
134141
if (window.history.scrollRestoration !== 'manual') window.history.scrollRestoration = 'manual';
135142
first.scrollIntoView({block: 'start'});
136143
showLineButton();

web_src/js/modules/tippy.ts

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ export function createTippy(target: Element, opts: TippyOpts = {}): Instance {
4040
}
4141
}
4242
visibleInstances.add(instance);
43+
target.setAttribute('aria-controls', instance.popper.id);
4344
return onShow?.(instance);
4445
},
4546
arrow: arrow ?? (theme === 'bare' ? false : arrowSvg),
@@ -180,13 +181,25 @@ export function initGlobalTooltips(): void {
180181
}
181182

182183
export function showTemporaryTooltip(target: Element, content: Content): void {
183-
// if the target is inside a dropdown, the menu will be hidden soon
184-
// so display the tooltip on the dropdown instead
185-
target = target.closest('.ui.dropdown') || target;
186-
const tippy = target._tippy ?? attachTooltip(target, content);
187-
tippy.setContent(content);
188-
if (!tippy.state.isShown) tippy.show();
189-
tippy.setProps({
184+
// if the target is inside a dropdown or tippy popup, the menu will be hidden soon
185+
// so display the tooltip on the "aria-controls" element or dropdown instead
186+
let refClientRect: DOMRect;
187+
const popupTippyId = target.closest(`[data-tippy-root]`)?.id;
188+
if (popupTippyId) {
189+
// for example, the "Copy Permalink" button in the "File View" page for the selected lines
190+
target = document.body;
191+
refClientRect = document.querySelector(`[aria-controls="${CSS.escape(popupTippyId)}"]`)?.getBoundingClientRect();
192+
refClientRect = refClientRect ?? new DOMRect(0, 0, 0, 0); // fallback to empty rect if not found, tippy doesn't accept null
193+
} else {
194+
// for example, the "Copy Link" button in the issue header dropdown menu
195+
target = target.closest('.ui.dropdown') ?? target;
196+
refClientRect = target.getBoundingClientRect();
197+
}
198+
const tooltipTippy = target._tippy ?? attachTooltip(target, content);
199+
tooltipTippy.setContent(content);
200+
tooltipTippy.setProps({getReferenceClientRect: () => refClientRect});
201+
if (!tooltipTippy.state.isShown) tooltipTippy.show();
202+
tooltipTippy.setProps({
190203
onHidden: (tippy) => {
191204
// reset the default tooltip content, if no default, then this temporary tooltip could be destroyed
192205
if (!attachTooltip(target)) {

0 commit comments

Comments
 (0)