From ad277ed2a2e5cb1e8f258a51934a4232a142543f Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Sun, 1 Jun 2025 06:14:14 +0000 Subject: [PATCH 1/4] Fix line-button issue after file selection in file tree --- templates/repo/view_file.tmpl | 2 +- web_src/js/features/repo-code.ts | 29 ++++++++++++++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index dc789a2648237..84572980ddaf7 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -114,7 +114,7 @@ {{end}} {{else if .FileSize}} - +
{{range $idx, $code := .FileContent}} {{$line := Eval $idx "+" 1}} diff --git a/web_src/js/features/repo-code.ts b/web_src/js/features/repo-code.ts index c699de59e6b7e..4743109927e3e 100644 --- a/web_src/js/features/repo-code.ts +++ b/web_src/js/features/repo-code.ts @@ -2,6 +2,7 @@ import {svg} from '../svg.ts'; import {createTippy} from '../modules/tippy.ts'; import {toAbsoluteUrl} from '../utils.ts'; import {addDelegatedEventListener} from '../utils/dom.ts'; +import {registerGlobalInitFunc} from '../modules/observer.ts'; function changeHash(hash: string) { if (window.history.pushState) { @@ -110,19 +111,21 @@ function showLineButton() { } export function initRepoCodeView() { - if (!document.querySelector('.code-view .lines-num')) return; - - let selRangeStart: string; - addDelegatedEventListener(document, 'click', '.lines-num span', (el: HTMLElement, e: KeyboardEvent) => { - if (!selRangeStart || !e.shiftKey) { - selRangeStart = el.getAttribute('id'); - selectRange(selRangeStart); - } else { - const selRangeStop = el.getAttribute('id'); - selectRange(`${selRangeStart}-${selRangeStop}`); - } - window.getSelection().removeAllRanges(); - showLineButton(); + registerGlobalInitFunc('initRepoCodeView', (el: HTMLElement) => { + if (!el.querySelector('.lines-num')) return; + + let selRangeStart: string; + addDelegatedEventListener(el, 'click', '.lines-num span', (el: HTMLElement, e: KeyboardEvent) => { + if (!selRangeStart || !e.shiftKey) { + selRangeStart = el.getAttribute('id'); + selectRange(selRangeStart); + } else { + const selRangeStop = el.getAttribute('id'); + selectRange(`${selRangeStart}-${selRangeStop}`); + } + window.getSelection().removeAllRanges(); + showLineButton(); + }); }); const onHashChange = () => { From 25f2da71a3723e590fce88ec01635b36edf9cdab Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 1 Jun 2025 18:04:21 +0800 Subject: [PATCH 2/4] fix --- templates/repo/view_file.tmpl | 2 +- web_src/css/repo/file-view.css | 6 +++++- web_src/js/features/repo-code.ts | 32 ++++++++++++++++---------------- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl index 84572980ddaf7..dc789a2648237 100644 --- a/templates/repo/view_file.tmpl +++ b/templates/repo/view_file.tmpl @@ -114,7 +114,7 @@ {{end}} {{else if .FileSize}} -
+
{{range $idx, $code := .FileContent}} {{$line := Eval $idx "+" 1}} diff --git a/web_src/css/repo/file-view.css b/web_src/css/repo/file-view.css index ec5ea87e3afae..54af5f4602459 100644 --- a/web_src/css/repo/file-view.css +++ b/web_src/css/repo/file-view.css @@ -1,7 +1,10 @@ -.file-view tr.active { +.file-view tr.active .lines-num, +.file-view tr.active .lines-escape, +.file-view tr.active .lines-code { background: var(--color-highlight-bg); } +/* set correct border radius on the last active lines, to avoid border overflow */ .file-view tr.active:last-of-type .lines-code { border-bottom-right-radius: var(--border-radius); } @@ -10,6 +13,7 @@ position: relative; } +/* add a darker "handler" at the beginning of the active line */ .file-view tr.active .lines-num::before { content: ""; position: absolute; diff --git a/web_src/js/features/repo-code.ts b/web_src/js/features/repo-code.ts index 4743109927e3e..148fd95a67e6c 100644 --- a/web_src/js/features/repo-code.ts +++ b/web_src/js/features/repo-code.ts @@ -2,7 +2,6 @@ import {svg} from '../svg.ts'; import {createTippy} from '../modules/tippy.ts'; import {toAbsoluteUrl} from '../utils.ts'; import {addDelegatedEventListener} from '../utils/dom.ts'; -import {registerGlobalInitFunc} from '../modules/observer.ts'; function changeHash(hash: string) { if (window.history.pushState) { @@ -111,25 +110,26 @@ function showLineButton() { } export function initRepoCodeView() { - registerGlobalInitFunc('initRepoCodeView', (el: HTMLElement) => { - if (!el.querySelector('.lines-num')) return; - - let selRangeStart: string; - addDelegatedEventListener(el, 'click', '.lines-num span', (el: HTMLElement, e: KeyboardEvent) => { - if (!selRangeStart || !e.shiftKey) { - selRangeStart = el.getAttribute('id'); - selectRange(selRangeStart); - } else { - const selRangeStop = el.getAttribute('id'); - selectRange(`${selRangeStart}-${selRangeStop}`); - } - window.getSelection().removeAllRanges(); - showLineButton(); - }); + if (!document.querySelector('.file-view.code-view')) return; + + // "file code view" and "blame" pages need this "line number button" feature + let selRangeStart: string; + addDelegatedEventListener(document, 'click', '.code-view .lines-num span', (el: HTMLElement, e: KeyboardEvent) => { + if (!selRangeStart || !e.shiftKey) { + selRangeStart = el.getAttribute('id'); + selectRange(selRangeStart); + } else { + const selRangeStop = el.getAttribute('id'); + selectRange(`${selRangeStart}-${selRangeStop}`); + } + window.getSelection().removeAllRanges(); + showLineButton(); }); + // apply the selected range from the URL hash const onHashChange = () => { if (!window.location.hash) return; + if (!document.querySelector('.code-view .lines-num')) return; const range = window.location.hash.substring(1); const first = selectRange(range); if (first) { From 48bd59ab87ab1985b7bc46590f09467798c0d0d8 Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 1 Jun 2025 18:39:56 +0800 Subject: [PATCH 3/4] fix tippy temp tooltip position --- web_src/js/modules/tippy.ts | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/web_src/js/modules/tippy.ts b/web_src/js/modules/tippy.ts index af715f48b9e36..f7a4b3723bcb1 100644 --- a/web_src/js/modules/tippy.ts +++ b/web_src/js/modules/tippy.ts @@ -40,6 +40,7 @@ export function createTippy(target: Element, opts: TippyOpts = {}): Instance { } } visibleInstances.add(instance); + target.setAttribute('aria-controls', instance.popper.id); return onShow?.(instance); }, arrow: arrow ?? (theme === 'bare' ? false : arrowSvg), @@ -180,13 +181,25 @@ export function initGlobalTooltips(): void { } export function showTemporaryTooltip(target: Element, content: Content): void { - // if the target is inside a dropdown, the menu will be hidden soon - // so display the tooltip on the dropdown instead - target = target.closest('.ui.dropdown') || target; - const tippy = target._tippy ?? attachTooltip(target, content); - tippy.setContent(content); - if (!tippy.state.isShown) tippy.show(); - tippy.setProps({ + // if the target is inside a dropdown or tippy popup, the menu will be hidden soon + // so display the tooltip on the "aria-controls" element or dropdown instead + let refClientRect: DOMRect; + const popupTippyId = target.closest(`[data-tippy-root]`)?.id; + if (popupTippyId) { + // for example, the "Copy Permalink" button in the "File View" page for the selected lines + target = document.body; + refClientRect = document.querySelector(`[aria-controls="${CSS.escape(popupTippyId)}"]`)?.getBoundingClientRect(); + refClientRect = refClientRect ?? new DOMRect(0, 0, 0, 0); // fallback to empty rect if not found, tippy doesn't accept null + } else { + // for example, the "Copy Link" button in the issue header dropdown menu + target = target.closest('.ui.dropdown') ?? target; + refClientRect = target.getBoundingClientRect(); + } + const tooltipTippy = target._tippy ?? attachTooltip(target, content); + tooltipTippy.setContent(content); + tooltipTippy.setProps({getReferenceClientRect: () => refClientRect}); + if (!tooltipTippy.state.isShown) tooltipTippy.show(); + tooltipTippy.setProps({ onHidden: (tippy) => { // reset the default tooltip content, if no default, then this temporary tooltip could be destroyed if (!attachTooltip(target)) { From 3e23e4987b275b0d10714949212947833dd7fa8f Mon Sep 17 00:00:00 2001 From: wxiaoguang Date: Sun, 1 Jun 2025 23:08:34 +0800 Subject: [PATCH 4/4] fine tune comments --- web_src/js/features/repo-code.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/repo-code.ts b/web_src/js/features/repo-code.ts index 148fd95a67e6c..bf7fd762b0b34 100644 --- a/web_src/js/features/repo-code.ts +++ b/web_src/js/features/repo-code.ts @@ -110,7 +110,11 @@ function showLineButton() { } export function initRepoCodeView() { - if (!document.querySelector('.file-view.code-view')) return; + // When viewing a file or blame, there is always a ".file-view" element, + // but the ".code-view" class is only present when viewing the "code" of a file; it is not present when viewing a PDF file. + // 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.) + // the "code-view" related event listeners should always be added when the current page contains ".file-view" element. + if (!document.querySelector('.repo-view-container .file-view')) return; // "file code view" and "blame" pages need this "line number button" feature let selRangeStart: string; @@ -133,7 +137,7 @@ export function initRepoCodeView() { const range = window.location.hash.substring(1); const first = selectRange(range); if (first) { - // set scrollRestoration to 'manual' when there is a hash in url, so that the scroll position will not be remembered after refreshing + // set scrollRestoration to 'manual' when there is a hash in the URL, so that the scroll position will not be remembered after refreshing if (window.history.scrollRestoration !== 'manual') window.history.scrollRestoration = 'manual'; first.scrollIntoView({block: 'start'}); showLineButton();