feat: global shortcut support (#39604)

* Fix #5796

Global shortcuts can be easily introduced by adding "data-shortcut-keys"
to the elements

---------

Signed-off-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
wxiaoguang authored and GitHub committed 2026-10-07 13:35:38 +08:00
1 parent 9b1d6f47f1
commit 4cba1e18ed
10 files changed
+374 -67

No files matched your search

+1 -1
View File
@@ -16,7 +16,6 @@ let i18nTextDeleteFromHistoryConfirm: string;
function showContentHistoryDetail(issueBaseUrl: string, commentId: string, historyId: string, itemTitleHtml: string) {
const elDetailDialog = createElementFromHTML(html`
<div class="ui modal content-history-detail-dialog">
${svgRaw('octicon-x', 16, 'close icon inside')}
<div class="header flex-left-right">
<div>${htmlRaw(itemTitleHtml)}</div>
<div class="ui dropdown dialog-header-options tw-mr-8 tw-hidden">
@@ -26,6 +25,7 @@ function showContentHistoryDetail(issueBaseUrl: string, commentId: string, histo
<div class="item tw-text-red" data-option-item="delete">${i18nTextDeleteFromHistory}</div>
</div>
</div>
${svgRaw('octicon-x', 16, 'close-modal')}
</div>
<div class="comment-diff-data is-loading"></div>
</div>
@@ -0,0 +1,43 @@
import {tryShortcutQuoteReply} from './repo-issue-edit.ts';
test('tryShortcutQuoteReply', () => {
const container = document.createElement('div');
container.innerHTML = `
<div class="comment-container">
<button class="quote-reply">Quote reply</button>
<div class="render-content markup">Comment text</div>
<div class="raw-content">Raw text</div>
</div>
`;
document.body.append(container);
const selection = window.getSelection()!;
onTestFinished(() => {
selection.removeAllRanges();
container.remove();
});
const button = container.querySelector('button')!;
const onClick = vi.fn();
button.addEventListener('click', onClick);
selection.removeAllRanges();
expect(tryShortcutQuoteReply()).toBe(false);
selection.selectAllChildren(container.querySelector('.raw-content')!);
expect(tryShortcutQuoteReply()).toBe(false);
const range = document.createRange();
range.selectNodeContents(container.querySelector('.render-content')!.firstChild!);
selection.removeAllRanges();
selection.addRange(range);
selection.collapseToStart();
expect(tryShortcutQuoteReply()).toBe(false);
expect(onClick).not.toHaveBeenCalled();
selection.removeAllRanges();
selection.addRange(range);
expect(tryShortcutQuoteReply()).toBe(true);
expect(onClick).toHaveBeenCalledTimes(1);
button.remove();
expect(tryShortcutQuoteReply()).toBe(false);
});
+24
View File
@@ -7,6 +7,7 @@ import {errorMessage} from '../modules/errors.ts';
import {triggerUploadStateChanged} from './comp/EditorUpload.ts';
import {convertHtmlToMarkdown} from '../markup/html2markdown.ts';
import {applyAreYouSure} from '../modules/are-you-sure.ts';
import {registerShortcutHandler} from '../modules/shortcut.ts';
async function tryOnEditContent(e: Event) {
const clickTarget = (e.target as HTMLElement).closest('.edit-content');
@@ -150,9 +151,32 @@ async function tryOnQuoteReply(e: Event) {
editor.moveCursorToEnd();
}
export function tryShortcutQuoteReply(): boolean {
const selection = window.getSelection();
if (!selection?.rangeCount || selection.isCollapsed) return false;
const node = selection.getRangeAt(0).commonAncestorContainer;
const el = node instanceof HTMLElement ? node : node.parentElement;
const commentContainer = el?.closest<HTMLElement>('.render-content.markup')?.closest('.comment-container');
if (!commentContainer) return false;
const quoteReplyBtn = commentContainer.querySelector<HTMLElement>('.quote-reply')!;
if (!quoteReplyBtn) return false;
quoteReplyBtn.click();
return true;
}
export function initRepoIssueCommentEdit() {
document.addEventListener('click', (e) => {
tryOnEditContent(e); // Edit issue or comment content
tryOnQuoteReply(e); // Quote reply to the comment editor
});
// TODO: it is not list in the shortcut help modal at the moment, there are many details:
// 1. not every page supports such "r"
// 2. "r" only works when there is a ".quote-reply" menu item, but it is not for a single one
// To make the framework fully support such mechanism correctly, we might also need to consider about dynamically added elements.
// The shortcut "r" was chosen by https://github.com/go-gitea/gitea/issues/5796#issuecomment-5528657082
// and GitLab: https://gitlab.com/gitlab-org/gitlab-foss/-/commit/ca5d0c82509cedb94f9bfa4a40e77706a58faafe
registerShortcutHandler('r', tryShortcutQuoteReply);
}