Skip to content

Commit 7aa68d6

Browse files
GiteaBotwxiaoguang
andauthored
Split issue edit code from repo-legacy.js into its own file (#30419) (#30422)
Backport #30419 by wxiaoguang Follow Split `index.js` to separate files (#17315) It's time to move some code away from the messy "legacy" file. Co-authored-by: wxiaoguang <[email protected]>
1 parent 81b5938 commit 7aa68d6

File tree

2 files changed

+209
-204
lines changed

2 files changed

+209
-204
lines changed
Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
import $ from 'jquery';
2+
import {handleReply} from './repo-issue.js';
3+
import {getComboMarkdownEditor, initComboMarkdownEditor} from './comp/ComboMarkdownEditor.js';
4+
import {createDropzone} from './dropzone.js';
5+
import {GET, POST} from '../modules/fetch.js';
6+
import {hideElem, showElem} from '../utils/dom.js';
7+
import {attachRefIssueContextPopup} from './contextpopup.js';
8+
import {initCommentContent, initMarkupContent} from '../markup/content.js';
9+
10+
const {csrfToken} = window.config;
11+
12+
async function onEditContent(event) {
13+
event.preventDefault();
14+
15+
const segment = this.closest('.header').nextElementSibling;
16+
const editContentZone = segment.querySelector('.edit-content-zone');
17+
const renderContent = segment.querySelector('.render-content');
18+
const rawContent = segment.querySelector('.raw-content');
19+
20+
let comboMarkdownEditor;
21+
22+
/**
23+
* @param {HTMLElement} dropzone
24+
*/
25+
const setupDropzone = async (dropzone) => {
26+
if (!dropzone) return null;
27+
28+
let disableRemovedfileEvent = false; // when resetting the dropzone (removeAllFiles), disable the "removedfile" event
29+
let fileUuidDict = {}; // to record: if a comment has been saved, then the uploaded files won't be deleted from server when clicking the Remove in the dropzone
30+
const dz = await createDropzone(dropzone, {
31+
url: dropzone.getAttribute('data-upload-url'),
32+
headers: {'X-Csrf-Token': csrfToken},
33+
maxFiles: dropzone.getAttribute('data-max-file'),
34+
maxFilesize: dropzone.getAttribute('data-max-size'),
35+
acceptedFiles: ['*/*', ''].includes(dropzone.getAttribute('data-accepts')) ? null : dropzone.getAttribute('data-accepts'),
36+
addRemoveLinks: true,
37+
dictDefaultMessage: dropzone.getAttribute('data-default-message'),
38+
dictInvalidFileType: dropzone.getAttribute('data-invalid-input-type'),
39+
dictFileTooBig: dropzone.getAttribute('data-file-too-big'),
40+
dictRemoveFile: dropzone.getAttribute('data-remove-file'),
41+
timeout: 0,
42+
thumbnailMethod: 'contain',
43+
thumbnailWidth: 480,
44+
thumbnailHeight: 480,
45+
init() {
46+
this.on('success', (file, data) => {
47+
file.uuid = data.uuid;
48+
fileUuidDict[file.uuid] = {submitted: false};
49+
const input = document.createElement('input');
50+
input.id = data.uuid;
51+
input.name = 'files';
52+
input.type = 'hidden';
53+
input.value = data.uuid;
54+
dropzone.querySelector('.files').append(input);
55+
});
56+
this.on('removedfile', async (file) => {
57+
document.getElementById(file.uuid)?.remove();
58+
if (disableRemovedfileEvent) return;
59+
if (dropzone.getAttribute('data-remove-url') && !fileUuidDict[file.uuid].submitted) {
60+
try {
61+
await POST(dropzone.getAttribute('data-remove-url'), {data: new URLSearchParams({file: file.uuid})});
62+
} catch (error) {
63+
console.error(error);
64+
}
65+
}
66+
});
67+
this.on('submit', () => {
68+
for (const fileUuid of Object.keys(fileUuidDict)) {
69+
fileUuidDict[fileUuid].submitted = true;
70+
}
71+
});
72+
this.on('reload', async () => {
73+
try {
74+
const response = await GET(editContentZone.getAttribute('data-attachment-url'));
75+
const data = await response.json();
76+
// do not trigger the "removedfile" event, otherwise the attachments would be deleted from server
77+
disableRemovedfileEvent = true;
78+
dz.removeAllFiles(true);
79+
dropzone.querySelector('.files').innerHTML = '';
80+
for (const el of dropzone.querySelectorAll('.dz-preview')) el.remove();
81+
fileUuidDict = {};
82+
disableRemovedfileEvent = false;
83+
84+
for (const attachment of data) {
85+
const imgSrc = `${dropzone.getAttribute('data-link-url')}/${attachment.uuid}`;
86+
dz.emit('addedfile', attachment);
87+
dz.emit('thumbnail', attachment, imgSrc);
88+
dz.emit('complete', attachment);
89+
fileUuidDict[attachment.uuid] = {submitted: true};
90+
dropzone.querySelector(`img[src='${imgSrc}']`).style.maxWidth = '100%';
91+
const input = document.createElement('input');
92+
input.id = attachment.uuid;
93+
input.name = 'files';
94+
input.type = 'hidden';
95+
input.value = attachment.uuid;
96+
dropzone.querySelector('.files').append(input);
97+
}
98+
if (!dropzone.querySelector('.dz-preview')) {
99+
dropzone.classList.remove('dz-started');
100+
}
101+
} catch (error) {
102+
console.error(error);
103+
}
104+
});
105+
},
106+
});
107+
dz.emit('reload');
108+
return dz;
109+
};
110+
111+
const cancelAndReset = (e) => {
112+
e.preventDefault();
113+
showElem(renderContent);
114+
hideElem(editContentZone);
115+
comboMarkdownEditor.attachedDropzoneInst?.emit('reload');
116+
};
117+
118+
const saveAndRefresh = async (e) => {
119+
e.preventDefault();
120+
showElem(renderContent);
121+
hideElem(editContentZone);
122+
const dropzoneInst = comboMarkdownEditor.attachedDropzoneInst;
123+
try {
124+
const params = new URLSearchParams({
125+
content: comboMarkdownEditor.value(),
126+
context: editContentZone.getAttribute('data-context'),
127+
});
128+
for (const fileInput of dropzoneInst?.element.querySelectorAll('.files [name=files]')) params.append('files[]', fileInput.value);
129+
130+
const response = await POST(editContentZone.getAttribute('data-update-url'), {data: params});
131+
const data = await response.json();
132+
if (!data.content) {
133+
renderContent.innerHTML = document.getElementById('no-content').innerHTML;
134+
rawContent.textContent = '';
135+
} else {
136+
renderContent.innerHTML = data.content;
137+
rawContent.textContent = comboMarkdownEditor.value();
138+
const refIssues = renderContent.querySelectorAll('p .ref-issue');
139+
attachRefIssueContextPopup(refIssues);
140+
}
141+
const content = segment;
142+
if (!content.querySelector('.dropzone-attachments')) {
143+
if (data.attachments !== '') {
144+
content.insertAdjacentHTML('beforeend', data.attachments);
145+
}
146+
} else if (data.attachments === '') {
147+
content.querySelector('.dropzone-attachments').remove();
148+
} else {
149+
content.querySelector('.dropzone-attachments').outerHTML = data.attachments;
150+
}
151+
dropzoneInst?.emit('submit');
152+
dropzoneInst?.emit('reload');
153+
initMarkupContent();
154+
initCommentContent();
155+
} catch (error) {
156+
console.error(error);
157+
}
158+
};
159+
160+
comboMarkdownEditor = getComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor'));
161+
if (!comboMarkdownEditor) {
162+
editContentZone.innerHTML = document.getElementById('issue-comment-editor-template').innerHTML;
163+
comboMarkdownEditor = await initComboMarkdownEditor(editContentZone.querySelector('.combo-markdown-editor'));
164+
comboMarkdownEditor.attachedDropzoneInst = await setupDropzone(editContentZone.querySelector('.dropzone'));
165+
editContentZone.querySelector('.cancel.button').addEventListener('click', cancelAndReset);
166+
editContentZone.querySelector('.save.button').addEventListener('click', saveAndRefresh);
167+
}
168+
169+
// Show write/preview tab and copy raw content as needed
170+
showElem(editContentZone);
171+
hideElem(renderContent);
172+
if (!comboMarkdownEditor.value()) {
173+
comboMarkdownEditor.value(rawContent.textContent);
174+
}
175+
comboMarkdownEditor.focus();
176+
}
177+
178+
export function initRepoIssueCommentEdit() {
179+
// Edit issue or comment content
180+
$(document).on('click', '.edit-content', onEditContent);
181+
182+
// Quote reply
183+
$(document).on('click', '.quote-reply', async function (event) {
184+
event.preventDefault();
185+
const target = $(this).data('target');
186+
const quote = $(`#${target}`).text().replace(/\n/g, '\n> ');
187+
const content = `> ${quote}\n\n`;
188+
let editor;
189+
if ($(this).hasClass('quote-reply-diff')) {
190+
const $replyBtn = $(this).closest('.comment-code-cloud').find('button.comment-form-reply');
191+
editor = await handleReply($replyBtn);
192+
} else {
193+
// for normal issue/comment page
194+
editor = getComboMarkdownEditor($('#comment-form .combo-markdown-editor'));
195+
}
196+
if (editor) {
197+
if (editor.value()) {
198+
editor.value(`${editor.value()}\n\n${content}`);
199+
} else {
200+
editor.value(content);
201+
}
202+
editor.focus();
203+
editor.moveCursorToEnd();
204+
}
205+
});
206+
}

0 commit comments

Comments
 (0)