1+ import $ from 'jquery' ;
2+ import { handleReply } from './repo-issue.ts' ;
3+ import { getComboMarkdownEditor , initComboMarkdownEditor } from './comp/ComboMarkdownEditor.ts' ;
4+ import { POST } from '../modules/fetch.ts' ;
5+ import { showErrorToast } from '../modules/toast.ts' ;
6+ import { hideElem , showElem } from '../utils/dom.ts' ;
7+ import { attachRefIssueContextPopup } from './contextpopup.ts' ;
8+ import { initCommentContent , initMarkupContent } from '../markup/content.ts' ;
9+
10+ export function initRepoConversationCommentEdit ( ) {
11+ // Edit issue or comment content
12+ $ ( document ) . on ( 'click' , '.edit-content' , onEditContent ) ;
13+
14+ // Quote reply
15+ $ ( document ) . on ( 'click' , '.quote-reply' , async function ( event ) {
16+ event . preventDefault ( ) ;
17+ const target = this . getAttribute ( 'data-target' ) ;
18+ const quote = document . querySelector ( `#${ target } ` ) . textContent . replace ( / \n / g, '\n> ' ) ;
19+ const content = `> ${ quote } \n\n` ;
20+
21+ let editor ;
22+ if ( this . classList . contains ( 'quote-reply-diff' ) ) {
23+ const replyBtn = this . closest ( '.comment-code-cloud' ) . querySelector ( 'button.comment-form-reply' ) ;
24+ editor = await handleReply ( replyBtn ) ;
25+ } else {
26+ // for normal issue/comment page
27+ editor = getComboMarkdownEditor ( $ ( '#comment-form .combo-markdown-editor' ) ) ;
28+ }
29+ if ( editor ) {
30+ if ( editor . value ( ) ) {
31+ editor . value ( `${ editor . value ( ) } \n\n${ content } ` ) ;
32+ } else {
33+ editor . value ( content ) ;
34+ }
35+ editor . focus ( ) ;
36+ editor . moveCursorToEnd ( ) ;
37+ }
38+ } ) ;
39+ }
40+
41+ async function onEditContent ( event ) {
42+ event . preventDefault ( ) ;
43+
44+ const segment = this . closest ( '.header' ) . nextElementSibling ;
45+ const editContentZone = segment . querySelector ( '.edit-content-zone' ) ;
46+ const renderContent = segment . querySelector ( '.render-content' ) ;
47+ const rawContent = segment . querySelector ( '.raw-content' ) ;
48+
49+ let comboMarkdownEditor ;
50+
51+ const cancelAndReset = ( e ) => {
52+ e . preventDefault ( ) ;
53+ showElem ( renderContent ) ;
54+ hideElem ( editContentZone ) ;
55+ comboMarkdownEditor . dropzoneReloadFiles ( ) ;
56+ } ;
57+
58+ const saveAndRefresh = async ( e ) => {
59+ e . preventDefault ( ) ;
60+ renderContent . classList . add ( 'is-loading' ) ;
61+ showElem ( renderContent ) ;
62+ hideElem ( editContentZone ) ;
63+ try {
64+ const params = new URLSearchParams ( {
65+ content : comboMarkdownEditor . value ( ) ,
66+ context : editContentZone . getAttribute ( 'data-context' ) ,
67+ content_version : editContentZone . getAttribute ( 'data-content-version' ) ,
68+ } ) ;
69+ for ( const file of comboMarkdownEditor . dropzoneGetFiles ( ) ?? [ ] ) {
70+ params . append ( 'files[]' , file ) ;
71+ }
72+
73+ const response = await POST ( editContentZone . getAttribute ( 'data-update-url' ) , { data : params } ) ;
74+ const data = await response . json ( ) ;
75+ if ( response . status === 400 ) {
76+ showErrorToast ( data . errorMessage ) ;
77+ return ;
78+ }
79+ editContentZone . setAttribute ( 'data-content-version' , data . contentVersion ) ;
80+ if ( ! data . content ) {
81+ renderContent . innerHTML = document . querySelector ( '#no-content' ) . innerHTML ;
82+ rawContent . textContent = '' ;
83+ } else {
84+ renderContent . innerHTML = data . content ;
85+ rawContent . textContent = comboMarkdownEditor . value ( ) ;
86+ const refIssues = renderContent . querySelectorAll ( 'p .ref-issue' ) ;
87+ attachRefIssueContextPopup ( refIssues ) ;
88+ }
89+ const content = segment ;
90+ if ( ! content . querySelector ( '.dropzone-attachments' ) ) {
91+ if ( data . attachments !== '' ) {
92+ content . insertAdjacentHTML ( 'beforeend' , data . attachments ) ;
93+ }
94+ } else if ( data . attachments === '' ) {
95+ content . querySelector ( '.dropzone-attachments' ) . remove ( ) ;
96+ } else {
97+ content . querySelector ( '.dropzone-attachments' ) . outerHTML = data . attachments ;
98+ }
99+ comboMarkdownEditor . dropzoneSubmitReload ( ) ;
100+ initMarkupContent ( ) ;
101+ initCommentContent ( ) ;
102+ } catch ( error ) {
103+ showErrorToast ( `Failed to save the content: ${ error } ` ) ;
104+ console . error ( error ) ;
105+ } finally {
106+ renderContent . classList . remove ( 'is-loading' ) ;
107+ }
108+ } ;
109+
110+ comboMarkdownEditor = getComboMarkdownEditor ( editContentZone . querySelector ( '.combo-markdown-editor' ) ) ;
111+ if ( ! comboMarkdownEditor ) {
112+ editContentZone . innerHTML = document . querySelector ( '#issue-comment-editor-template' ) . innerHTML ;
113+ comboMarkdownEditor = await initComboMarkdownEditor ( editContentZone . querySelector ( '.combo-markdown-editor' ) ) ;
114+ editContentZone . querySelector ( '.ui.cancel.button' ) . addEventListener ( 'click' , cancelAndReset ) ;
115+ editContentZone . querySelector ( '.ui.primary.button' ) . addEventListener ( 'click' , saveAndRefresh ) ;
116+ }
117+
118+ // Show write/preview tab and copy raw content as needed
119+ showElem ( editContentZone ) ;
120+ hideElem ( renderContent ) ;
121+ // FIXME: ideally here should reload content and attachment list from backend for existing editor, to avoid losing data
122+ if ( ! comboMarkdownEditor . value ( ) ) {
123+ comboMarkdownEditor . value ( rawContent . textContent ) ;
124+ }
125+ comboMarkdownEditor . switchTabToEditor ( ) ;
126+ comboMarkdownEditor . focus ( ) ;
127+ }
0 commit comments