Skip to content

Commit c008592

Browse files
committed
fix
1 parent 1144b1d commit c008592

File tree

7 files changed

+103
-37
lines changed

7 files changed

+103
-37
lines changed

templates/repo/issue/search.tmpl

+4-4
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
<input type="hidden" name="assignee" value="{{$.AssigneeID}}">
99
<input type="hidden" name="poster" value="{{$.PosterID}}">
1010
<input name="q" value="{{.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}...">
11-
<button id="hashtag-button" class="ui small icon button gt-hidden" data-tooltip-content="{{.locale.Tr "explore.go_to"}}">{{svg "octicon-hash"}}</button>
12-
<button id="search-button" class="ui small icon button" aria-label="{{.locale.Tr "explore.search"}}">
13-
{{svg "octicon-search"}}
14-
</button>
11+
{{if .PageIsIssueList}}
12+
<button id="issue-list-quick-goto" class="ui small icon button gt-hidden" data-tooltip-content="{{.locale.Tr "explore.go_to"}}" data-repo-link="{{.RepoLink}}">{{svg "octicon-hash"}}</button>
13+
{{end}}
14+
<button class="ui small icon button" aria-label="{{.locale.Tr "explore.search"}}">{{svg "octicon-search"}}</button>
1515
</div>
1616
</form>

templates/user/dashboard/issues.tmpl

+2-2
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@
7878
<input type="hidden" name="sort" value="{{$.SortType}}">
7979
<input type="hidden" name="state" value="{{$.State}}">
8080
<input name="q" value="{{$.Keyword}}" placeholder="{{.locale.Tr "explore.search"}}...">
81-
<button id="hashtag-button" class="ui small icon button gt-hidden" data-tooltip-content="{{.locale.Tr "explore.go_to"}}">{{svg "octicon-hash"}}</button>
82-
<button id="search-button" class="ui small icon button" aria-label="{{.locale.Tr "explore.search"}}">{{svg "octicon-search"}}</button>
81+
<button id="issue-list-quick-goto" class="ui small icon button gt-hidden" data-tooltip-content="{{.locale.Tr "explore.go_to"}}">{{svg "octicon-hash"}}</button>
82+
<button class="ui small icon button" aria-label="{{.locale.Tr "explore.search"}}">{{svg "octicon-search"}}</button>
8383
</div>
8484
</form>
8585
<!-- Sort -->
+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import $ from 'jquery';
2+
import {isElemHidden, toggleElem} from '../utils/dom.js';
3+
const {appSubUrl} = window.config;
4+
5+
const reIssueIndex = /^(\d+)$/; // eg: "123"
6+
const reIssueSharpIndex = /^#(\d+)$/; // eg: "#123"
7+
const reIssueOwnerRepoIndex = /^([-.\w]+)\/([-.\w]+)#(\d+)$/; // eg: "{owner}/{repo}#{index}"
8+
9+
// if the searchText can be parsed to an "issue goto link", return the link, otherwise return empty string
10+
export function parseIssueListQuickGotoLink (repoLink, searchText) {
11+
searchText = searchText.trim();
12+
let targetUrl = '';
13+
if (repoLink) {
14+
// try to parse it in current repo
15+
if (reIssueIndex.test(searchText)) {
16+
targetUrl = `${repoLink}/issues/${searchText}`;
17+
} else if (reIssueSharpIndex.test(searchText)) {
18+
targetUrl = `${repoLink}/issues/${searchText.substr(1)}`;
19+
}
20+
} else {
21+
// try to parse it for a global search (eg: "owner/repo#123")
22+
const matchIssueOwnerRepoIndex = searchText.match(reIssueOwnerRepoIndex);
23+
if (matchIssueOwnerRepoIndex) {
24+
const [_, owner, repo, index] = matchIssueOwnerRepoIndex;
25+
targetUrl = `${appSubUrl}/${owner}/${repo}/issues/${index}`;
26+
}
27+
}
28+
return targetUrl;
29+
}
30+
31+
export function initCommonIssueListQuickGoto() {
32+
const $goto = $('#issue-list-quick-goto');
33+
if (!$goto.length) return;
34+
35+
const $form = $goto.closest('form');
36+
const $input = $form.find('input[name=q]');
37+
const repoLink = $goto.attr('data-repo-link');
38+
39+
$form.on('submit', (e) => {
40+
// if there is no goto button, or the form is submitted by non-quick-goto elements, submit the form directly
41+
let doQuickGoto = !isElemHidden($goto);
42+
const submitter = e.originalEvent.submitter;
43+
if (submitter !== $form[0] && submitter !== $input[0] && submitter !== $goto[0]) doQuickGoto = false;
44+
if (!doQuickGoto) return;
45+
46+
// if there is a goto button, use its link
47+
e.preventDefault();
48+
window.location.href = $goto.attr('data-issue-goto-link');
49+
});
50+
51+
const onInput = async () => {
52+
const searchText = $input.val();
53+
54+
// try to check whether the parsed goto link is valid
55+
let targetUrl = parseIssueListQuickGotoLink(repoLink, searchText);
56+
if (targetUrl) {
57+
const res = await fetch(`${targetUrl}/info`);
58+
if (res.status !== 200) targetUrl = '';
59+
}
60+
61+
// if the input value has changed, then ignore the result
62+
if ($input.val() !== searchText) return;
63+
64+
toggleElem($goto, Boolean(targetUrl));
65+
$goto.attr('data-issue-goto-link', targetUrl);
66+
};
67+
68+
$input.on('input', onInput);
69+
const _ = onInput();
70+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {test, expect} from 'vitest';
2+
import {parseIssueListQuickGotoLink} from './common-issue-list.js';
3+
4+
test('parseIssueListQuickGotoLink', () => {
5+
expect(parseIssueListQuickGotoLink('/link', '')).toEqual('');
6+
expect(parseIssueListQuickGotoLink('/link', 'abc')).toEqual('');
7+
expect(parseIssueListQuickGotoLink('/link', '123')).toEqual('/link/issues/123');
8+
expect(parseIssueListQuickGotoLink('/link', '#123')).toEqual('/link/issues/123');
9+
expect(parseIssueListQuickGotoLink('/link', 'owner/repo#123')).toEqual('');
10+
11+
expect(parseIssueListQuickGotoLink('', '')).toEqual('');
12+
expect(parseIssueListQuickGotoLink('', 'abc')).toEqual('');
13+
expect(parseIssueListQuickGotoLink('', '123')).toEqual('');
14+
expect(parseIssueListQuickGotoLink('', '#123')).toEqual('');
15+
expect(parseIssueListQuickGotoLink('', 'owner/repo#')).toEqual('');
16+
expect(parseIssueListQuickGotoLink('', 'owner/repo#123')).toEqual('/owner/repo/issues/123');
17+
});

web_src/js/features/repo-issue.js

-29
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {showTemporaryTooltip, createTippy} from '../modules/tippy.js';
44
import {hideElem, showElem, toggleElem} from '../utils/dom.js';
55
import {setFileFolding} from './file-fold.js';
66
import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
7-
import {parseIssueHref} from '../utils.js';
87

98
const {appSubUrl, csrfToken} = window.config;
109

@@ -637,31 +636,3 @@ export function initRepoIssueBranchSelect() {
637636
};
638637
$('#branch-select > .item').on('click', changeBranchSelect);
639638
}
640-
641-
export function initRepoIssueGotoID() {
642-
const issueidre = /^(?:\w+\/\w+#\d+|#\d+|\d+)$/;
643-
const isGlobalIssuesArea = $('.repo.name.item').length > 0; // for global issues area or repository issues area
644-
$('form.list-header-search').on('submit', (e) => {
645-
const qval = e.target.q.value;
646-
const aElm = document.activeElement;
647-
if (!$('#hashtag-button').length || aElm.id === 'search-button' || (aElm.name === 'q' && !qval.includes('#')) || (isGlobalIssuesArea && !qval.includes('/')) || !issueidre.test(qval)) return;
648-
const pathname = window.location.pathname;
649-
let gotoUrl = qval.includes('/') ? `${qval.replace('#', '/issues/')}` : `${pathname}/${qval.replace('#', '')}`;
650-
if (appSubUrl.length) {
651-
gotoUrl = qval.includes('/') ? `/${appSubUrl}/${qval.replace('#', '/issues/')}` : `/${appSubUrl}/${pathname}/${qval.replace('#', '')}`;
652-
}
653-
const {owner, repo, type, index} = parseIssueHref(gotoUrl);
654-
if (owner && repo && type && index) {
655-
e.preventDefault();
656-
window.location.href = gotoUrl;
657-
}
658-
});
659-
$('form.list-header-search input[name=q]').on('input', (e) => {
660-
const qval = e.target.value;
661-
if (isGlobalIssuesArea && qval.includes('/') && issueidre.test(qval) || !isGlobalIssuesArea && issueidre.test(qval)) {
662-
showElem($('#hashtag-button'));
663-
} else {
664-
hideElem($('#hashtag-button'));
665-
}
666-
});
667-
}

web_src/js/index.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import {
3030
initRepoIssueWipTitle,
3131
initRepoPullRequestMergeInstruction,
3232
initRepoPullRequestAllowMaintainerEdit,
33-
initRepoPullRequestReview, initRepoIssueSidebarList, initRepoIssueGotoID
33+
initRepoPullRequestReview, initRepoIssueSidebarList
3434
} from './features/repo-issue.js';
3535
import {
3636
initRepoEllipsisButton,
@@ -81,6 +81,7 @@ import {initGlobalTooltips} from './modules/tippy.js';
8181
import {initGiteaFomantic} from './modules/fomantic.js';
8282
import {onDomReady} from './utils/dom.js';
8383
import {initRepoIssueList} from './features/repo-issue-list.js';
84+
import {initCommonIssueListQuickGoto} from './features/common-issue-list.js';
8485

8586
// Init Gitea's Fomantic settings
8687
initGiteaFomantic();
@@ -98,6 +99,7 @@ onDomReady(() => {
9899
initGlobalLinkActions();
99100

100101
initCommonOrganization();
102+
initCommonIssueListQuickGoto();
101103

102104
initCompSearchUserBox();
103105
initCompWebHookEditor();
@@ -175,5 +177,4 @@ onDomReady(() => {
175177
initUserAuthWebAuthnRegister();
176178
initUserSettings();
177179
initRepoDiffView();
178-
initRepoIssueGotoID();
179180
});

web_src/js/utils/dom.js

+7
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@ export function toggleElem(el, force) {
4242
elementsCall(el, toggleShown, force);
4343
}
4444

45+
export function isElemHidden(el) {
46+
const res = [];
47+
elementsCall(el, (e) => res.push(e.classList.contains('gt-hidden')));
48+
if (res.length > 1) throw new Error(`the hidden check doesn't work for multiple elements`);
49+
return res[0];
50+
}
51+
4552
export function onDomReady(cb) {
4653
if (document.readyState === 'loading') {
4754
document.addEventListener('DOMContentLoaded', cb);

0 commit comments

Comments
 (0)