Support quote selected comments to reply (#32431)

Many existing tests were quite hacky, these could be improved later.

<details>

![image](https://github.com/user-attachments/assets/93aebb4f-9de5-4cb8-910b-50c64cbcd25a)

</details>
This commit is contained in:
wxiaoguang 2024-11-07 11:57:07 +08:00 committed by GitHub
parent 276500c314
commit 145e266987
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 255 additions and 70 deletions

View file

@ -1,4 +1,3 @@
import $ from 'jquery';
import {handleReply} from './repo-issue.ts';
import {getComboMarkdownEditor, initComboMarkdownEditor, ComboMarkdownEditor} from './comp/ComboMarkdownEditor.ts';
import {POST} from '../modules/fetch.ts';
@ -7,11 +6,14 @@ import {hideElem, querySingleVisibleElem, showElem} from '../utils/dom.ts';
import {attachRefIssueContextPopup} from './contextpopup.ts';
import {initCommentContent, initMarkupContent} from '../markup/content.ts';
import {triggerUploadStateChanged} from './comp/EditorUpload.ts';
import {convertHtmlToMarkdown} from '../markup/html2markdown.ts';
async function onEditContent(event) {
event.preventDefault();
async function tryOnEditContent(e) {
const clickTarget = e.target.closest('.edit-content');
if (!clickTarget) return;
const segment = this.closest('.header').nextElementSibling;
e.preventDefault();
const segment = clickTarget.closest('.header').nextElementSibling;
const editContentZone = segment.querySelector('.edit-content-zone');
const renderContent = segment.querySelector('.render-content');
const rawContent = segment.querySelector('.raw-content');
@ -102,33 +104,53 @@ async function onEditContent(event) {
triggerUploadStateChanged(comboMarkdownEditor.container);
}
function extractSelectedMarkdown(container: HTMLElement) {
const selection = window.getSelection();
if (!selection.rangeCount) return '';
const range = selection.getRangeAt(0);
if (!container.contains(range.commonAncestorContainer)) return '';
// todo: if commonAncestorContainer parent has "[data-markdown-original-content]" attribute, use the parent's markdown content
// otherwise, use the selected HTML content and respect all "[data-markdown-original-content]/[data-markdown-generated-content]" attributes
const contents = selection.getRangeAt(0).cloneContents();
const el = document.createElement('div');
el.append(contents);
return convertHtmlToMarkdown(el);
}
async function tryOnQuoteReply(e) {
const clickTarget = (e.target as HTMLElement).closest('.quote-reply');
if (!clickTarget) return;
e.preventDefault();
const contentToQuoteId = clickTarget.getAttribute('data-target');
const targetRawToQuote = document.querySelector<HTMLElement>(`#${contentToQuoteId}.raw-content`);
const targetMarkupToQuote = targetRawToQuote.parentElement.querySelector<HTMLElement>('.render-content.markup');
let contentToQuote = extractSelectedMarkdown(targetMarkupToQuote);
if (!contentToQuote) contentToQuote = targetRawToQuote.textContent;
const quotedContent = `${contentToQuote.replace(/^/mg, '> ')}\n`;
let editor;
if (clickTarget.classList.contains('quote-reply-diff')) {
const replyBtn = clickTarget.closest('.comment-code-cloud').querySelector('button.comment-form-reply');
editor = await handleReply(replyBtn);
} else {
// for normal issue/comment page
editor = getComboMarkdownEditor(document.querySelector('#comment-form .combo-markdown-editor'));
}
if (editor.value()) {
editor.value(`${editor.value()}\n\n${quotedContent}`);
} else {
editor.value(quotedContent);
}
editor.focus();
editor.moveCursorToEnd();
}
export function initRepoIssueCommentEdit() {
// Edit issue or comment content
$(document).on('click', '.edit-content', onEditContent);
// Quote reply
$(document).on('click', '.quote-reply', async function (event) {
event.preventDefault();
const target = this.getAttribute('data-target');
const quote = document.querySelector(`#${target}`).textContent.replace(/\n/g, '\n> ');
const content = `> ${quote}\n\n`;
let editor;
if (this.classList.contains('quote-reply-diff')) {
const replyBtn = this.closest('.comment-code-cloud').querySelector('button.comment-form-reply');
editor = await handleReply(replyBtn);
} else {
// for normal issue/comment page
editor = getComboMarkdownEditor($('#comment-form .combo-markdown-editor'));
}
if (editor) {
if (editor.value()) {
editor.value(`${editor.value()}\n\n${content}`);
} else {
editor.value(content);
}
editor.focus();
editor.moveCursorToEnd();
}
document.addEventListener('click', (e) => {
tryOnEditContent(e); // Edit issue or comment content
tryOnQuoteReply(e); // Quote reply to the comment editor
});
}