From 25cacaf0aa56bece904c84638fbe126a826c1cd8 Mon Sep 17 00:00:00 2001 From: Kerwin Bryant Date: Tue, 26 Nov 2024 09:24:56 +0800 Subject: [PATCH] Fixed Issue of Review Menu Shown Behind (#32631) Fixed #31144 --------- Co-authored-by: wxiaoguang --- templates/repo/diff/box.tmpl | 30 ++++++++++------------ tests/integration/pull_compare_test.go | 4 +-- web_src/css/modules/tippy.css | 2 ++ web_src/js/features/repo-diff.ts | 12 +++++++++ web_src/js/features/repo-unicode-escape.ts | 12 ++++----- web_src/js/utils/dom.ts | 4 +-- 6 files changed, 38 insertions(+), 26 deletions(-) diff --git a/templates/repo/diff/box.tmpl b/templates/repo/diff/box.tmpl index 26737f110e..20e0c9db66 100644 --- a/templates/repo/diff/box.tmpl +++ b/templates/repo/diff/box.tmpl @@ -164,24 +164,22 @@ {{ctx.Locale.Tr "repo.pulls.has_viewed_file"}} {{end}} - diff --git a/tests/integration/pull_compare_test.go b/tests/integration/pull_compare_test.go index def6506253..ad0be72dcb 100644 --- a/tests/integration/pull_compare_test.go +++ b/tests/integration/pull_compare_test.go @@ -97,7 +97,7 @@ func TestPullCompare_EnableAllowEditsFromMaintainer(t *testing.T) { user2Session := loginUser(t, "user2") resp = user2Session.MakeRequest(t, NewRequest(t, "GET", fmt.Sprintf("%s/files", prURL)), http.StatusOK) htmlDoc := NewHTMLParser(t, resp.Body) - nodes := htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .dropdown .menu a") + nodes := htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .tippy-target a") if assert.Equal(t, 1, nodes.Length()) { // there is only "View File" button, no "Edit File" button assert.Equal(t, "View File", nodes.First().Text()) @@ -121,7 +121,7 @@ func TestPullCompare_EnableAllowEditsFromMaintainer(t *testing.T) { // user2 (admin of repo3) goes to the PR files page again resp = user2Session.MakeRequest(t, NewRequest(t, "GET", fmt.Sprintf("%s/files", prURL)), http.StatusOK) htmlDoc = NewHTMLParser(t, resp.Body) - nodes = htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .dropdown .menu a") + nodes = htmlDoc.doc.Find(".diff-file-box[data-new-filename=\"README.md\"] .diff-file-header-actions .tippy-target a") if assert.Equal(t, 2, nodes.Length()) { // there are "View File" button and "Edit File" button assert.Equal(t, "View File", nodes.First().Text()) diff --git a/web_src/css/modules/tippy.css b/web_src/css/modules/tippy.css index 53c3d5aaea..55b9751cc6 100644 --- a/web_src/css/modules/tippy.css +++ b/web_src/css/modules/tippy.css @@ -77,8 +77,10 @@ align-items: center; padding: 9px 18px; color: inherit; + background: inherit; text-decoration: none; gap: 10px; + width: 100%; } .tippy-box[data-theme="menu"] .item:hover { diff --git a/web_src/js/features/repo-diff.ts b/web_src/js/features/repo-diff.ts index 0d489665a2..f39de96f5b 100644 --- a/web_src/js/features/repo-diff.ts +++ b/web_src/js/features/repo-diff.ts @@ -18,6 +18,7 @@ import { } from '../utils/dom.ts'; import {POST, GET} from '../modules/fetch.ts'; import {fomanticQuery} from '../modules/fomantic/base.ts'; +import {createTippy} from '../modules/tippy.ts'; const {pageData, i18n} = window.config; @@ -140,12 +141,22 @@ export function initRepoDiffConversationNav() { }); } +function initDiffHeaderPopup() { + for (const btn of document.querySelectorAll('.diff-header-popup-btn:not([data-header-popup-initialized])')) { + btn.setAttribute('data-header-popup-initialized', ''); + const popup = btn.nextElementSibling; + if (!popup?.matches('.tippy-target')) throw new Error('Popup element not found'); + createTippy(btn, {content: popup, theme: 'menu', placement: 'bottom', trigger: 'click', interactive: true, hideOnClick: true}); + } +} + // Will be called when the show more (files) button has been pressed function onShowMoreFiles() { initRepoIssueContentHistory(); initViewedCheckboxListenerFor(); countAndUpdateViewedFiles(); initImageDiff(); + initDiffHeaderPopup(); } export async function loadMoreFiles(url) { @@ -221,6 +232,7 @@ export function initRepoDiffView() { initDiffFileList(); initDiffCommitSelect(); initRepoDiffShowMore(); + initDiffHeaderPopup(); initRepoDiffFileViewToggle(); initViewedCheckboxListenerFor(); initExpandAndCollapseFilesButton(); diff --git a/web_src/js/features/repo-unicode-escape.ts b/web_src/js/features/repo-unicode-escape.ts index 7a9bca7a37..0c7d2e8592 100644 --- a/web_src/js/features/repo-unicode-escape.ts +++ b/web_src/js/features/repo-unicode-escape.ts @@ -1,13 +1,13 @@ -import {hideElem, queryElemSiblings, showElem, toggleElem} from '../utils/dom.ts'; +import {addDelegatedEventListener, hideElem, queryElemSiblings, showElem, toggleElem} from '../utils/dom.ts'; export function initUnicodeEscapeButton() { - document.addEventListener('click', (e) => { - const btn = e.target.closest('.escape-button, .unescape-button, .toggle-escape-button'); - if (!btn) return; - + addDelegatedEventListener(document, 'click', '.escape-button, .unescape-button, .toggle-escape-button', (btn, e) => { e.preventDefault(); - const fileContent = btn.closest('.file-content, .non-diff-file-content'); + const fileContentElemId = btn.getAttribute('data-file-content-elem-id'); + const fileContent = fileContentElemId ? + document.querySelector(`#${fileContentElemId}`) : + btn.closest('.file-content, .non-diff-file-content'); const fileView = fileContent?.querySelectorAll('.file-code, .file-view'); if (btn.matches('.escape-button')) { for (const el of fileView) el.classList.add('unicode-escaped'); diff --git a/web_src/js/utils/dom.ts b/web_src/js/utils/dom.ts index 4bbb0c414a..a4c7c0e4c6 100644 --- a/web_src/js/utils/dom.ts +++ b/web_src/js/utils/dom.ts @@ -2,10 +2,10 @@ import {debounce} from 'throttle-debounce'; import type {Promisable} from 'type-fest'; import type $ from 'jquery'; -type ElementArg = Element | string | NodeListOf | Array | ReturnType; +type ArrayLikeIterable = ArrayLike & Iterable; // for NodeListOf and Array +type ElementArg = Element | string | ArrayLikeIterable | ReturnType; type ElementsCallback = (el: T) => Promisable; type ElementsCallbackWithArgs = (el: Element, ...args: any[]) => Promisable; -type ArrayLikeIterable = ArrayLike & Iterable; // for NodeListOf and Array function elementsCall(el: ElementArg, func: ElementsCallbackWithArgs, ...args: any[]) { if (typeof el === 'string' || el instanceof String) {