2024-07-07 18:32:30 +03:00
import { handleReply } from './repo-issue.ts' ;
2024-10-23 05:48:04 +03:00
import { getComboMarkdownEditor , initComboMarkdownEditor , ComboMarkdownEditor } from './comp/ComboMarkdownEditor.ts' ;
2024-07-07 18:32:30 +03:00
import { POST } from '../modules/fetch.ts' ;
import { showErrorToast } from '../modules/toast.ts' ;
2024-11-06 23:21:53 +03:00
import { hideElem , querySingleVisibleElem , showElem } from '../utils/dom.ts' ;
2024-07-07 18:32:30 +03:00
import { attachRefIssueContextPopup } from './contextpopup.ts' ;
import { initCommentContent , initMarkupContent } from '../markup/content.ts' ;
2024-10-23 05:48:04 +03:00
import { triggerUploadStateChanged } from './comp/EditorUpload.ts' ;
2024-11-07 06:57:07 +03:00
import { convertHtmlToMarkdown } from '../markup/html2markdown.ts' ;
2024-04-11 21:22:59 +03:00
2024-11-07 06:57:07 +03:00
async function tryOnEditContent ( e ) {
const clickTarget = e . target . closest ( '.edit-content' ) ;
if ( ! clickTarget ) return ;
2024-04-11 21:22:59 +03:00
2024-11-07 06:57:07 +03:00
e . preventDefault ( ) ;
const segment = clickTarget . closest ( '.header' ) . nextElementSibling ;
2024-04-11 21:22:59 +03:00
const editContentZone = segment . querySelector ( '.edit-content-zone' ) ;
const renderContent = segment . querySelector ( '.render-content' ) ;
const rawContent = segment . querySelector ( '.raw-content' ) ;
2024-10-23 05:48:04 +03:00
let comboMarkdownEditor : ComboMarkdownEditor ;
2024-04-11 21:22:59 +03:00
const cancelAndReset = ( e ) = > {
e . preventDefault ( ) ;
showElem ( renderContent ) ;
hideElem ( editContentZone ) ;
2024-06-26 20:01:20 +03:00
comboMarkdownEditor . dropzoneReloadFiles ( ) ;
2024-04-11 21:22:59 +03:00
} ;
const saveAndRefresh = async ( e ) = > {
e . preventDefault ( ) ;
2024-06-26 20:01:20 +03:00
renderContent . classList . add ( 'is-loading' ) ;
2024-04-11 21:22:59 +03:00
showElem ( renderContent ) ;
hideElem ( editContentZone ) ;
try {
const params = new URLSearchParams ( {
content : comboMarkdownEditor.value ( ) ,
context : editContentZone.getAttribute ( 'data-context' ) ,
2024-05-27 18:34:18 +03:00
content_version : editContentZone.getAttribute ( 'data-content-version' ) ,
2024-04-11 21:22:59 +03:00
} ) ;
2024-06-26 20:01:20 +03:00
for ( const file of comboMarkdownEditor . dropzoneGetFiles ( ) ? ? [ ] ) {
params . append ( 'files[]' , file ) ;
}
2024-04-11 21:22:59 +03:00
const response = await POST ( editContentZone . getAttribute ( 'data-update-url' ) , { data : params } ) ;
const data = await response . json ( ) ;
2024-05-27 18:34:18 +03:00
if ( response . status === 400 ) {
showErrorToast ( data . errorMessage ) ;
return ;
}
editContentZone . setAttribute ( 'data-content-version' , data . contentVersion ) ;
2024-04-11 21:22:59 +03:00
if ( ! data . content ) {
2024-06-10 23:49:33 +03:00
renderContent . innerHTML = document . querySelector ( '#no-content' ) . innerHTML ;
2024-04-11 21:22:59 +03:00
rawContent . textContent = '' ;
} else {
renderContent . innerHTML = data . content ;
rawContent . textContent = comboMarkdownEditor . value ( ) ;
const refIssues = renderContent . querySelectorAll ( 'p .ref-issue' ) ;
attachRefIssueContextPopup ( refIssues ) ;
}
const content = segment ;
if ( ! content . querySelector ( '.dropzone-attachments' ) ) {
if ( data . attachments !== '' ) {
content . insertAdjacentHTML ( 'beforeend' , data . attachments ) ;
}
} else if ( data . attachments === '' ) {
content . querySelector ( '.dropzone-attachments' ) . remove ( ) ;
} else {
content . querySelector ( '.dropzone-attachments' ) . outerHTML = data . attachments ;
}
2024-06-26 20:01:20 +03:00
comboMarkdownEditor . dropzoneSubmitReload ( ) ;
2024-04-11 21:22:59 +03:00
initMarkupContent ( ) ;
initCommentContent ( ) ;
} catch ( error ) {
2024-06-26 20:01:20 +03:00
showErrorToast ( ` Failed to save the content: ${ error } ` ) ;
2024-04-11 21:22:59 +03:00
console . error ( error ) ;
2024-06-26 20:01:20 +03:00
} finally {
renderContent . classList . remove ( 'is-loading' ) ;
2024-04-11 21:22:59 +03:00
}
} ;
2024-11-06 23:21:53 +03:00
// Show write/preview tab and copy raw content as needed
showElem ( editContentZone ) ;
hideElem ( renderContent ) ;
2024-04-11 21:22:59 +03:00
comboMarkdownEditor = getComboMarkdownEditor ( editContentZone . querySelector ( '.combo-markdown-editor' ) ) ;
if ( ! comboMarkdownEditor ) {
2024-06-10 23:49:33 +03:00
editContentZone . innerHTML = document . querySelector ( '#issue-comment-editor-template' ) . innerHTML ;
2024-11-06 23:21:53 +03:00
const saveButton = querySingleVisibleElem < HTMLButtonElement > ( editContentZone , '.ui.primary.button' ) ;
const cancelButton = querySingleVisibleElem < HTMLButtonElement > ( editContentZone , '.ui.cancel.button' ) ;
2024-04-11 21:22:59 +03:00
comboMarkdownEditor = await initComboMarkdownEditor ( editContentZone . querySelector ( '.combo-markdown-editor' ) ) ;
2024-10-23 05:48:04 +03:00
const syncUiState = ( ) = > saveButton . disabled = comboMarkdownEditor . isUploading ( ) ;
comboMarkdownEditor . container . addEventListener ( ComboMarkdownEditor . EventUploadStateChanged , syncUiState ) ;
2024-11-06 23:21:53 +03:00
cancelButton . addEventListener ( 'click' , cancelAndReset ) ;
2024-10-23 05:48:04 +03:00
saveButton . addEventListener ( 'click' , saveAndRefresh ) ;
2024-04-11 21:22:59 +03:00
}
2024-06-26 20:01:20 +03:00
// FIXME: ideally here should reload content and attachment list from backend for existing editor, to avoid losing data
2024-04-11 21:22:59 +03:00
if ( ! comboMarkdownEditor . value ( ) ) {
comboMarkdownEditor . value ( rawContent . textContent ) ;
}
2024-06-22 12:25:04 +03:00
comboMarkdownEditor . switchTabToEditor ( ) ;
2024-04-11 21:22:59 +03:00
comboMarkdownEditor . focus ( ) ;
2024-10-23 05:48:04 +03:00
triggerUploadStateChanged ( comboMarkdownEditor . container ) ;
2024-04-11 21:22:59 +03:00
}
2024-11-07 06:57:07 +03:00
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 ( ) ;
}
2024-04-11 21:22:59 +03:00
export function initRepoIssueCommentEdit() {
2024-11-07 06:57:07 +03:00
document . addEventListener ( 'click' , ( e ) = > {
tryOnEditContent ( e ) ; // Edit issue or comment content
tryOnQuoteReply ( e ) ; // Quote reply to the comment editor
2024-04-11 21:22:59 +03:00
} ) ;
}