From 15aab4d029cc796b49245e732272b55410f7882a Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Wed, 6 Jul 2022 14:55:18 +0800 Subject: [PATCH 01/18] Refactor to use dropzone native methods upload files --- web_src/js/features/common-global.js | 25 ++--- web_src/js/features/comp/EasyMDE.js | 2 +- web_src/js/features/comp/ImagePaste.js | 143 +++++++++--------------- web_src/js/features/comp/QuickSubmit.js | 15 +++ web_src/js/features/repo-issue.js | 3 +- web_src/js/features/repo-legacy.js | 29 +++-- 6 files changed, 101 insertions(+), 116 deletions(-) create mode 100644 web_src/js/features/comp/QuickSubmit.js diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 419c5996dc65..69f23b47c883 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -5,6 +5,9 @@ import createDropzone from './dropzone.js'; import {initCompColorPicker} from './comp/ColorPicker.js'; import {showGlobalErrorMessage} from '../bootstrap.js'; import {attachDropdownAria} from './aria.js'; +import {addUploadedFileToEditor, removeUploadedFileFromEditor} from './comp/ImagePaste.js'; +import {handleGlobalEnterQuickSubmit} from './comp/QuickSubmit.js'; +import {getAttachedEasyMDE} from './comp/EasyMDE.js'; const {appUrl, csrfToken} = window.config; @@ -53,20 +56,6 @@ export function initGlobalEnterQuickSubmit() { }); } -export function handleGlobalEnterQuickSubmit(target) { - const $target = $(target); - const $form = $(target).closest('form'); - if ($form.length) { - // here use the event to trigger the submit event (instead of calling `submit()` method directly) - // otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog - $form.trigger('submit'); - } else { - // if no form, then the editor is for an AJAX request, dispatch an event to the target, let the target's event handler to do the AJAX request. - // the 'ce-' prefix means this is a CustomEvent - $target.trigger('ce-quick-submit'); - } -} - export function initGlobalButtonClickOnEnter() { $(document).on('keypress', '.ui.button', (e) => { if (e.keyCode === 13 || e.keyCode === 32) { // enter key or space bar @@ -199,15 +188,21 @@ export function initGlobalDropzone() { init() { this.on('success', (file, data) => { file.uuid = data.uuid; - const input = $(``).val(data.uuid); + const input = $(``).val(data.uuid); $dropzone.find('.files').append(input); + addUploadedFileToEditor(file.editor, file); }); this.on('removedfile', (file) => { $(`#${file.uuid}`).remove(); + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.parentElement.parentElement.querySelector('textarea')))) { + file.editor = file.editor.codemirror; + } if ($dropzone.data('remove-url')) { $.post($dropzone.data('remove-url'), { file: file.uuid, _csrf: csrfToken, + }).always(() => { + removeUploadedFileFromEditor(file.editor, file.uuid); }); } }); diff --git a/web_src/js/features/comp/EasyMDE.js b/web_src/js/features/comp/EasyMDE.js index 7c1db9a9988d..f1b4b0efc398 100644 --- a/web_src/js/features/comp/EasyMDE.js +++ b/web_src/js/features/comp/EasyMDE.js @@ -1,6 +1,6 @@ import $ from 'jquery'; import attachTribute from '../tribute.js'; -import {handleGlobalEnterQuickSubmit} from '../common-global.js'; +import {handleGlobalEnterQuickSubmit} from './QuickSubmit.js'; /** * @returns {EasyMDE} diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index da41e7611a62..05e5c25d184d 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -1,94 +1,60 @@ import $ from 'jquery'; - -const {csrfToken} = window.config; - -async function uploadFile(file, uploadUrl) { - const formData = new FormData(); - formData.append('file', file, file.name); - - const res = await fetch(uploadUrl, { - method: 'POST', - headers: {'X-Csrf-Token': csrfToken}, - body: formData, - }); - return await res.json(); -} - -function clipboardPastedImages(e) { - if (!e.clipboardData) return []; - - const files = []; - for (const item of e.clipboardData.items || []) { - if (!item.type || !item.type.startsWith('image/')) continue; - files.push(item.getAsFile()); - } - return files; -} - -class TextareaEditor { - constructor(editor) { - this.editor = editor; - } - - insertPlaceholder(value) { - const editor = this.editor; - const startPos = editor.selectionStart; - const endPos = editor.selectionEnd; - editor.value = editor.value.substring(0, startPos) + value + editor.value.substring(endPos); - editor.selectionStart = startPos; - editor.selectionEnd = startPos + value.length; - editor.focus(); +import {getAttachedEasyMDE} from './EasyMDE.js'; + +/** + * + * @param {*} editor + * @param {*} file + */ +export function addUploadedFileToEditor(editor, file) { + if (!editor && file.previewElement && (editor = getAttachedEasyMDE(file.previewElement.parentElement.parentElement.parentElement.querySelector('textarea')))) { + editor = editor.codemirror; } - - replacePlaceholder(oldVal, newVal) { - const editor = this.editor; - const startPos = editor.selectionStart; - const endPos = editor.selectionEnd; - if (editor.value.substring(startPos, endPos) === oldVal) { - editor.value = editor.value.substring(0, startPos) + newVal + editor.value.substring(endPos); - editor.selectionEnd = startPos + newVal.length; + const startPos = editor.selectionStart || editor.getCursor && editor.getCursor('start'), endPos = editor.selectionEnd || editor.getCursor && editor.getCursor('end'), isimage = file.type.startsWith('image/') ? '!' : '', fileName = (isimage ? file.name.replace(/\.[^/.]+$/, '') : file.name); + if (startPos) { + if (editor.setSelection) { + editor.setSelection(startPos, endPos); + editor.replaceSelection(`${isimage}[${fileName}](/attachments/${file.uuid})\n`); } else { - editor.value = editor.value.replace(oldVal, newVal); - editor.selectionEnd -= oldVal.length; - editor.selectionEnd += newVal.length; + editor.value = `${editor.value.substring(0, startPos)}\n${isimage}[${fileName}](/attachments/${file.uuid})\n${editor.value.substring(endPos)}`; } - editor.selectionStart = editor.selectionEnd; - editor.focus(); + } else if (editor.setSelection) { + editor.value(`${editor.value()}\n${isimage}[${fileName}](/attachments/${file.uuid})\n`); + } else { + editor.value += `${editor.value}\n${isimage}[${fileName}](/attachments/${file.uuid})\n`; } } -class CodeMirrorEditor { - constructor(editor) { - this.editor = editor; - } - - insertPlaceholder(value) { - const editor = this.editor; - const startPoint = editor.getCursor('start'); - const endPoint = editor.getCursor('end'); - editor.replaceSelection(value); - endPoint.ch = startPoint.ch + value.length; - editor.setSelection(startPoint, endPoint); - editor.focus(); +/** + * @param editor{EasyMDE} + * @param fileUuid + */ +export function removeUploadedFileFromEditor(editor, fileUuid) { + // the raw regexp is: /!\[[^\]]*]\(\/attachments\/{uuid}\)/ + const re = new RegExp(`(!|)\\[[^\\]]*]\\(/attachments/${fileUuid}\\)`); + if (editor.setValue) { + editor.setValue(editor.getValue().replace(re, '')); // at the moment, we assume the editor is an EasyMDE + } else { + editor.value = editor.value.replace(re, ''); } +} - replacePlaceholder(oldVal, newVal) { - const editor = this.editor; - const endPoint = editor.getCursor('end'); - if (editor.getSelection() === oldVal) { - editor.replaceSelection(newVal); - } else { - editor.setValue(editor.getValue().replace(oldVal, newVal)); - } - endPoint.ch -= oldVal.length; - endPoint.ch += newVal.length; - editor.setSelection(endPoint, endPoint); - editor.focus(); +function clipboardPastedImages(e) { + const data = e.clipboardData || e.dataTransfer; + if (!data) return []; + + const files = [], datafiles = e.clipboardData && e.clipboardData.items || e.dataTransfer && e.dataTransfer.files; + for (const item of datafiles || []) { + const file = (e.clipboardData ? item.getAsFile() : item); + if (file === null || !item.type) continue; + files.push(file); } + return files; } - export function initEasyMDEImagePaste(easyMDE, $dropzone) { + if ($dropzone.length !== 1) throw new Error('invalid dropzone binding for editor'); + const uploadUrl = $dropzone.attr('data-upload-url'); const $files = $dropzone.find('.files'); @@ -103,23 +69,20 @@ export function initEasyMDEImagePaste(easyMDE, $dropzone) { e.stopPropagation(); for (const img of pastedImages) { - const name = img.name.slice(0, img.name.lastIndexOf('.')); - - const placeholder = `![${name}](uploading ...)`; - editor.insertPlaceholder(placeholder); - const data = await uploadFile(img, uploadUrl); - editor.replacePlaceholder(placeholder, `![${name}](/attachments/${data.uuid})`); - - const $input = $(``).attr('id', data.uuid).val(data.uuid); - $files.append($input); + img.editor = editor; + $dropzone[0].dropzone.addFile(img); } }; easyMDE.codemirror.on('paste', async (_, e) => { - return uploadClipboardImage(new CodeMirrorEditor(easyMDE.codemirror), e); + return uploadClipboardImage(easyMDE.codemirror, e); + }); + + easyMDE.codemirror.on('drop', async (_, e) => { + return uploadClipboardImage(easyMDE.codemirror, e); }); - $(easyMDE.element).on('paste', async (e) => { - return uploadClipboardImage(new TextareaEditor(easyMDE.element), e.originalEvent); + $(easyMDE.element).on('paste drop', async (e) => { + return uploadClipboardImage(easyMDE.element, e.originalEvent); }); } diff --git a/web_src/js/features/comp/QuickSubmit.js b/web_src/js/features/comp/QuickSubmit.js new file mode 100644 index 000000000000..43424a949f1e --- /dev/null +++ b/web_src/js/features/comp/QuickSubmit.js @@ -0,0 +1,15 @@ +import $ from 'jquery'; + +export function handleGlobalEnterQuickSubmit(target) { + const $target = $(target); + const $form = $(target).closest('form'); + if ($form.length) { + // here use the event to trigger the submit event (instead of calling `submit()` method directly) + // otherwise the `areYouSure` handler won't be executed, then there will be an annoying "confirm to leave" dialog + $form.trigger('submit'); + } else { + // if no form, then the editor is for an AJAX request, dispatch an event to the target, let the target's event handler to do the AJAX request. + // the 'ce-' prefix means this is a CustomEvent + $target.trigger('ce-quick-submit'); + } +} diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 12900c2455d8..a4b1cb8ad248 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -480,8 +480,7 @@ export function initRepoPullRequestReview() { // the editor's height is too large in some cases, and the panel cannot be scrolled with page now because there is `.repository .diff-detail-box.sticky { position: sticky; }` // the temporary solution is to make the editor's height smaller (about 4 lines). GitHub also only show 4 lines for default. We can improve the UI (including Dropzone area) in future // EasyMDE's options can not handle minHeight & maxHeight together correctly, we have to set max-height for .CodeMirror-scroll in CSS. - const $reviewTextarea = $reviewBox.find('textarea'); - const easyMDE = await createCommentEasyMDE($reviewTextarea, {minHeight: '80px'}); + const easyMDE = await createCommentEasyMDE($reviewBox.find('textarea'), {minHeight: '80px'}); initEasyMDEImagePaste(easyMDE, $reviewBox.find('.dropzone')); })(); } diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 11c97ccfb011..6d8b7850f1e7 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; -import {initEasyMDEImagePaste} from './comp/ImagePaste.js'; +import {initEasyMDEImagePaste, addUploadedFileToEditor, removeUploadedFileFromEditor} from './comp/ImagePaste.js'; import { initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete, @@ -33,7 +33,7 @@ import initRepoPullRequestMergeForm from './repo-issue-pr-form.js'; const {csrfToken} = window.config; export function initRepoCommentForm() { - const $commentForm = $('.comment.form'); + const $commentForm = $('#comment-form, #new-issue'); // for issues and PRs if ($commentForm.length === 0) { return; } @@ -68,8 +68,7 @@ export function initRepoCommentForm() { } (async () => { - const $textarea = $commentForm.find('textarea:not(.review-textarea)'); - const easyMDE = await createCommentEasyMDE($textarea); + const easyMDE = await createCommentEasyMDE($commentForm.find('textarea:not(.review-textarea)')); initEasyMDEImagePaste(easyMDE, $commentForm.find('.dropzone')); })(); @@ -284,7 +283,8 @@ async function onEditContent(event) { if ($dropzone.length === 1) { $dropzone.data('saved', false); - const fileUuidDict = {}; + let disableRemovedfileEvent = false; // when resetting the dropzone (removeAllFiles), disable the removedfile event + let fileUuidDict = {}; // if a comment has been saved, then the uploaded files won't be deleted from server when clicking the Remove in the dropzone dz = await createDropzone($dropzone[0], { url: $dropzone.data('upload-url'), headers: {'X-Csrf-Token': csrfToken}, @@ -303,17 +303,27 @@ async function onEditContent(event) { init() { this.on('success', (file, data) => { file.uuid = data.uuid; - fileUuidDict[file.uuid] = {submitted: false}; - const input = $(``).val(data.uuid); + const input = $(``).val(data.uuid); $dropzone.find('.files').append(input); + fileUuidDict[file.uuid] = {submitted: false}; + addUploadedFileToEditor(file.editor, file); }); this.on('removedfile', (file) => { + if (disableRemovedfileEvent) return; $(`#${file.uuid}`).remove(); - if ($dropzone.data('remove-url') && !fileUuidDict[file.uuid].submitted) { + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.parentElement.parentElement.querySelector('textarea')))) { + file.editor = file.editor.codemirror; + } + if ($dropzone.data('remove-url') && !fileUuidDict[file.uuid]?.submitted) { $.post($dropzone.data('remove-url'), { file: file.uuid, _csrf: csrfToken, + }).always(() => { + removeUploadedFileFromEditor(file.editor, file.uuid); }); + } else { + // for saved comment's attachment's removal, only remove the link in the editor + removeUploadedFileFromEditor(file.editor, file.uuid); } }); this.on('submit', () => { @@ -323,8 +333,11 @@ async function onEditContent(event) { }); this.on('reload', () => { $.getJSON($editContentZone.data('attachment-url'), (data) => { + disableRemovedfileEvent = true; dz.removeAllFiles(true); + disableRemovedfileEvent = false; $dropzone.find('.files').empty(); + fileUuidDict = {}; $.each(data, function () { const imgSrc = `${$dropzone.data('link-url')}/${this.uuid}`; dz.emit('addedfile', this); From 9926ecd0972cd1385e6fc081305bf7197a07ea0d Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Wed, 6 Jul 2022 15:14:45 +0800 Subject: [PATCH 02/18] minor modification --- web_src/js/features/common-global.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 69f23b47c883..ab53a867a8eb 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -188,7 +188,7 @@ export function initGlobalDropzone() { init() { this.on('success', (file, data) => { file.uuid = data.uuid; - const input = $(``).val(data.uuid); + const input = $(``).val(data.uuid); $dropzone.find('.files').append(input); addUploadedFileToEditor(file.editor, file); }); From 41c49c1c08e1d21a6b42b879744a2d558abb02bd Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Thu, 14 Jul 2022 11:39:14 +0800 Subject: [PATCH 03/18] Adjust inline const --- web_src/js/features/comp/ImagePaste.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 05e5c25d184d..517ff099fef2 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -10,7 +10,10 @@ export function addUploadedFileToEditor(editor, file) { if (!editor && file.previewElement && (editor = getAttachedEasyMDE(file.previewElement.parentElement.parentElement.parentElement.querySelector('textarea')))) { editor = editor.codemirror; } - const startPos = editor.selectionStart || editor.getCursor && editor.getCursor('start'), endPos = editor.selectionEnd || editor.getCursor && editor.getCursor('end'), isimage = file.type.startsWith('image/') ? '!' : '', fileName = (isimage ? file.name.replace(/\.[^/.]+$/, '') : file.name); + const startPos = editor.selectionStart || editor.getCursor && editor.getCursor('start'); + const endPos = editor.selectionEnd || editor.getCursor && editor.getCursor('end'); + const isimage = file.type.startsWith('image/') ? '!' : ''; + const fileName = (isimage ? file.name.replace(/\.[^/.]+$/, '') : file.name); if (startPos) { if (editor.setSelection) { editor.setSelection(startPos, endPos); From 30bc9935e642fa2044c93ffc4211a198119a4cff Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 18 Jul 2022 08:16:46 +0800 Subject: [PATCH 04/18] Update web_src/js/features/comp/ImagePaste.js Co-authored-by: silverwind --- web_src/js/features/comp/ImagePaste.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 517ff099fef2..c66b95d180e7 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -46,7 +46,8 @@ function clipboardPastedImages(e) { const data = e.clipboardData || e.dataTransfer; if (!data) return []; - const files = [], datafiles = e.clipboardData && e.clipboardData.items || e.dataTransfer && e.dataTransfer.files; + const files = []; + const datafiles = e.clipboardData?.items || e.dataTransfer?.files; for (const item of datafiles || []) { const file = (e.clipboardData ? item.getAsFile() : item); if (file === null || !item.type) continue; From 8a137c314438da71a1c14960e1804de83b76274a Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 18 Jul 2022 08:16:59 +0800 Subject: [PATCH 05/18] Update web_src/js/features/comp/ImagePaste.js Co-authored-by: silverwind --- web_src/js/features/comp/ImagePaste.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index c66b95d180e7..80b8440e7e10 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -49,7 +49,7 @@ function clipboardPastedImages(e) { const files = []; const datafiles = e.clipboardData?.items || e.dataTransfer?.files; for (const item of datafiles || []) { - const file = (e.clipboardData ? item.getAsFile() : item); + const file = e.clipboardData ? item.getAsFile() : item; if (file === null || !item.type) continue; files.push(file); } From f31eb8e5bac5798b5e2004696a04eeb51ec38698 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 18 Jul 2022 11:52:41 +0800 Subject: [PATCH 06/18] Fix cannot edit on review --- web_src/js/features/repo-legacy.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 6d8b7850f1e7..da3e2b0368b7 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -367,7 +367,9 @@ async function onEditContent(event) { easyMDE = await createCommentEasyMDE($textarea); initCompMarkupContentPreviewTab($editContentForm); - initEasyMDEImagePaste(easyMDE, $dropzone); + if ($dropzone.length) { + initEasyMDEImagePaste(easyMDE, $dropzone); + } const $saveButton = $editContentZone.find('.save.button'); $textarea.on('ce-quick-submit', () => { From ad444d305ddb67065e41474853eb6fb4a225b47d Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Tue, 19 Jul 2022 08:14:20 +0800 Subject: [PATCH 07/18] Use closest find textarea --- web_src/js/features/common-global.js | 2 +- web_src/js/features/comp/ImagePaste.js | 2 +- web_src/js/features/repo-legacy.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index ab53a867a8eb..e535bd4b440a 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -194,7 +194,7 @@ export function initGlobalDropzone() { }); this.on('removedfile', (file) => { $(`#${file.uuid}`).remove(); - if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.parentElement.parentElement.querySelector('textarea')))) { + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.closest('form').querySelector('textarea')))) { file.editor = file.editor.codemirror; } if ($dropzone.data('remove-url')) { diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 80b8440e7e10..39155e7612e5 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -7,7 +7,7 @@ import {getAttachedEasyMDE} from './EasyMDE.js'; * @param {*} file */ export function addUploadedFileToEditor(editor, file) { - if (!editor && file.previewElement && (editor = getAttachedEasyMDE(file.previewElement.parentElement.parentElement.parentElement.querySelector('textarea')))) { + if (!editor && file.previewElement && (editor = getAttachedEasyMDE(file.previewElement.closest('form').querySelector('textarea')))) { editor = editor.codemirror; } const startPos = editor.selectionStart || editor.getCursor && editor.getCursor('start'); diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index da3e2b0368b7..32996f5d4de8 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -311,7 +311,7 @@ async function onEditContent(event) { this.on('removedfile', (file) => { if (disableRemovedfileEvent) return; $(`#${file.uuid}`).remove(); - if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.parentElement.parentElement.querySelector('textarea')))) { + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.closest('form').querySelector('textarea')))) { file.editor = file.editor.codemirror; } if ($dropzone.data('remove-url') && !fileUuidDict[file.uuid]?.submitted) { From 16085bec6a30c910027ec8c2d249b2e1444a7610 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Wed, 27 Jul 2022 15:46:26 +0800 Subject: [PATCH 08/18] Edit comment cannot use closeset find to textarea --- web_src/js/features/repo-legacy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index 32996f5d4de8..da3e2b0368b7 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -311,7 +311,7 @@ async function onEditContent(event) { this.on('removedfile', (file) => { if (disableRemovedfileEvent) return; $(`#${file.uuid}`).remove(); - if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.closest('form').querySelector('textarea')))) { + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.parentElement.parentElement.querySelector('textarea')))) { file.editor = file.editor.codemirror; } if ($dropzone.data('remove-url') && !fileUuidDict[file.uuid]?.submitted) { From 349ee1fa31136d89fd2a8257e472e482a694753f Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Thu, 28 Jul 2022 09:28:13 +0800 Subject: [PATCH 09/18] Adjust pasting additional filename to textarea position below message --- web_src/js/features/comp/ImagePaste.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 39155e7612e5..34698f3c09e2 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -16,10 +16,17 @@ export function addUploadedFileToEditor(editor, file) { const fileName = (isimage ? file.name.replace(/\.[^/.]+$/, '') : file.name); if (startPos) { if (editor.setSelection) { - editor.setSelection(startPos, endPos); - editor.replaceSelection(`${isimage}[${fileName}](/attachments/${file.uuid})\n`); - } else { + if (startPos.line) { + editor.setSelection(startPos, endPos); + editor.replaceSelection(`${isimage}[${fileName}](/attachments/${file.uuid})\n`); + } else { + const val = editor.getValue(); + editor.setValue(`${val}\n${isimage}[${fileName}](/attachments/${file.uuid})`); + } + } else if (startPos) { editor.value = `${editor.value.substring(0, startPos)}\n${isimage}[${fileName}](/attachments/${file.uuid})\n${editor.value.substring(endPos)}`; + } else { + editor.value += `\n${isimage}[${fileName}](/attachments/${file.uuid})`; } } else if (editor.setSelection) { editor.value(`${editor.value()}\n${isimage}[${fileName}](/attachments/${file.uuid})\n`); From 7569d10c813af73e8cd959804847921dd03909f8 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Thu, 28 Jul 2022 12:22:38 +0800 Subject: [PATCH 10/18] Fix lint build failed --- web_src/js/features/comp/ImagePaste.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 34698f3c09e2..be532276d239 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -23,7 +23,7 @@ export function addUploadedFileToEditor(editor, file) { const val = editor.getValue(); editor.setValue(`${val}\n${isimage}[${fileName}](/attachments/${file.uuid})`); } - } else if (startPos) { + } else if (typeof startPos === 'number' && startPos > 0) { editor.value = `${editor.value.substring(0, startPos)}\n${isimage}[${fileName}](/attachments/${file.uuid})\n${editor.value.substring(endPos)}`; } else { editor.value += `\n${isimage}[${fileName}](/attachments/${file.uuid})`; From 3af56720f13fc7b504523a36872c4967e1fe5be5 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 1 Aug 2022 11:26:04 +0800 Subject: [PATCH 11/18] Fix in edit upload file error --- web_src/js/features/comp/ImagePaste.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index be532276d239..a75a73191925 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -7,7 +7,8 @@ import {getAttachedEasyMDE} from './EasyMDE.js'; * @param {*} file */ export function addUploadedFileToEditor(editor, file) { - if (!editor && file.previewElement && (editor = getAttachedEasyMDE(file.previewElement.closest('form').querySelector('textarea')))) { + if (!editor && file.previewElement) { + editor = file.previewElement.closest('form') ? getAttachedEasyMDE(file.previewElement.closest('form').querySelector('textarea')) : getAttachedEasyMDE(file.previewElement.parentElement.parentElement.parentElement.querySelector('textarea')); editor = editor.codemirror; } const startPos = editor.selectionStart || editor.getCursor && editor.getCursor('start'); From ae14b4626c35532020de135088139efbcc37ac6a Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 1 Aug 2022 20:39:23 +0800 Subject: [PATCH 12/18] Fix paste upload file in one line issue --- web_src/js/features/comp/ImagePaste.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index a75a73191925..f0a742704973 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -17,7 +17,7 @@ export function addUploadedFileToEditor(editor, file) { const fileName = (isimage ? file.name.replace(/\.[^/.]+$/, '') : file.name); if (startPos) { if (editor.setSelection) { - if (startPos.line) { + if (startPos.line !== undefined) { editor.setSelection(startPos, endPos); editor.replaceSelection(`${isimage}[${fileName}](/attachments/${file.uuid})\n`); } else { From c2a587c580276cf8785e60a648a26e38297e243b Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Thu, 4 Aug 2022 10:05:04 +0800 Subject: [PATCH 13/18] Refactor again and add upload placeholder --- web_src/js/features/common-global.js | 7 +- web_src/js/features/comp/ImagePaste.js | 132 ++++++++++++++++--------- web_src/js/features/repo-issue.js | 4 +- web_src/js/features/repo-legacy.js | 13 ++- web_src/js/features/repo-release.js | 4 +- 5 files changed, 104 insertions(+), 56 deletions(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 117c3c600e2c..befe2c50ece0 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -186,15 +186,18 @@ export function initGlobalDropzone() { thumbnailWidth: 480, thumbnailHeight: 480, init() { + this.on('addedfile', addUploadedFileToEditor); this.on('success', (file, data) => { file.uuid = data.uuid; const input = $(``).val(data.uuid); $dropzone.find('.files').append(input); - addUploadedFileToEditor(file.editor, file); + const name = file.name.slice(0, file.name.lastIndexOf('.')); + const placeholder = `![${name}](uploading ...)`; + file.editor.replacePlaceholder(placeholder, `![${name}](/attachments/${data.uuid})`); }); this.on('removedfile', (file) => { $(`#${file.uuid}`).remove(); - if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.closest('form').querySelector('textarea')))) { + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.closest('div.comment').querySelector('textarea')))) { file.editor = file.editor.codemirror; } if ($dropzone.data('remove-url')) { diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index f0a742704973..60a9a64c32d1 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -1,56 +1,21 @@ import $ from 'jquery'; import {getAttachedEasyMDE} from './EasyMDE.js'; -/** - * - * @param {*} editor - * @param {*} file - */ -export function addUploadedFileToEditor(editor, file) { - if (!editor && file.previewElement) { - editor = file.previewElement.closest('form') ? getAttachedEasyMDE(file.previewElement.closest('form').querySelector('textarea')) : getAttachedEasyMDE(file.previewElement.parentElement.parentElement.parentElement.querySelector('textarea')); - editor = editor.codemirror; - } - const startPos = editor.selectionStart || editor.getCursor && editor.getCursor('start'); - const endPos = editor.selectionEnd || editor.getCursor && editor.getCursor('end'); - const isimage = file.type.startsWith('image/') ? '!' : ''; - const fileName = (isimage ? file.name.replace(/\.[^/.]+$/, '') : file.name); - if (startPos) { - if (editor.setSelection) { - if (startPos.line !== undefined) { - editor.setSelection(startPos, endPos); - editor.replaceSelection(`${isimage}[${fileName}](/attachments/${file.uuid})\n`); - } else { - const val = editor.getValue(); - editor.setValue(`${val}\n${isimage}[${fileName}](/attachments/${file.uuid})`); - } - } else if (typeof startPos === 'number' && startPos > 0) { - editor.value = `${editor.value.substring(0, startPos)}\n${isimage}[${fileName}](/attachments/${file.uuid})\n${editor.value.substring(endPos)}`; - } else { - editor.value += `\n${isimage}[${fileName}](/attachments/${file.uuid})`; - } - } else if (editor.setSelection) { - editor.value(`${editor.value()}\n${isimage}[${fileName}](/attachments/${file.uuid})\n`); - } else { - editor.value += `${editor.value}\n${isimage}[${fileName}](/attachments/${file.uuid})\n`; - } -} - /** * @param editor{EasyMDE} * @param fileUuid */ export function removeUploadedFileFromEditor(editor, fileUuid) { - // the raw regexp is: /!\[[^\]]*]\(\/attachments\/{uuid}\)/ + // the raw regexp is: /!\[[^\]]*]\(\/attachments\/{uuid}\)/ for remove file text in textarea const re = new RegExp(`(!|)\\[[^\\]]*]\\(/attachments/${fileUuid}\\)`); - if (editor.setValue) { - editor.setValue(editor.getValue().replace(re, '')); // at the moment, we assume the editor is an EasyMDE + if (editor.editor.setValue) { + editor.editor.setValue(editor.editor.getValue().replace(re, '')); // at the moment, we assume the editor is an EasyMDE } else { - editor.value = editor.value.replace(re, ''); + editor.editor.value = editor.editor.value.replace(re, ''); } } -function clipboardPastedImages(e) { +function clipboardPastedFiles(e) { const data = e.clipboardData || e.dataTransfer; if (!data) return []; @@ -64,7 +29,70 @@ function clipboardPastedImages(e) { return files; } -export function initEasyMDEImagePaste(easyMDE, $dropzone) { + +class TextareaEditor { + constructor(editor) { + this.editor = editor; + } + + insertPlaceholder(value) { + const editor = this.editor; + const startPos = editor.selectionStart; + const endPos = editor.selectionEnd; + editor.value = editor.value.substring(0, startPos) + value + editor.value.substring(endPos); + editor.selectionStart = startPos; + editor.selectionEnd = startPos + value.length; + editor.focus(); + } + + replacePlaceholder(oldVal, newVal) { + const editor = this.editor; + const startPos = editor.selectionStart; + const endPos = editor.selectionEnd; + if (editor.value.substring(startPos, endPos) === oldVal) { + editor.value = editor.value.substring(0, startPos) + newVal + editor.value.substring(endPos); + editor.selectionEnd = startPos + newVal.length; + } else { + editor.value = editor.value.replace(oldVal, newVal); + editor.selectionEnd -= oldVal.length; + editor.selectionEnd += newVal.length; + } + editor.selectionStart = editor.selectionEnd; + editor.focus(); + } +} + +class CodeMirrorEditor { + constructor(editor) { + this.editor = editor; + } + + insertPlaceholder(value) { + const editor = this.editor; + const startPoint = editor.getCursor('start'); + const endPoint = editor.getCursor('end'); + editor.replaceSelection(value); + endPoint.ch = startPoint.ch + value.length; + editor.setSelection(startPoint, endPoint); + editor.focus(); + } + + replacePlaceholder(oldVal, newVal) { + const editor = this.editor; + const endPoint = editor.getCursor('end'); + if (editor.getSelection() === oldVal) { + editor.replaceSelection(newVal); + } else { + editor.setValue(editor.getValue().replace(oldVal, newVal)); + } + endPoint.ch -= oldVal.length; + endPoint.ch += newVal.length; + editor.setSelection(endPoint, endPoint); + editor.focus(); + } +} + +export function initEasyMDEFilePaste(easyMDE, $dropzone) { if ($dropzone.length !== 1) throw new Error('invalid dropzone binding for editor'); const uploadUrl = $dropzone.attr('data-upload-url'); @@ -73,7 +101,7 @@ export function initEasyMDEImagePaste(easyMDE, $dropzone) { if (!uploadUrl || !$files.length) return; const uploadClipboardImage = async (editor, e) => { - const pastedImages = clipboardPastedImages(e); + const pastedImages = clipboardPastedFiles(e); if (!pastedImages || pastedImages.length === 0) { return; } @@ -87,14 +115,28 @@ export function initEasyMDEImagePaste(easyMDE, $dropzone) { }; easyMDE.codemirror.on('paste', async (_, e) => { - return uploadClipboardImage(easyMDE.codemirror, e); + return uploadClipboardImage(new CodeMirrorEditor(easyMDE.codemirror), e); }); easyMDE.codemirror.on('drop', async (_, e) => { - return uploadClipboardImage(easyMDE.codemirror, e); + return uploadClipboardImage(new CodeMirrorEditor(easyMDE.codemirror), e); }); $(easyMDE.element).on('paste drop', async (e) => { - return uploadClipboardImage(easyMDE.element, e.originalEvent); + return uploadClipboardImage(new TextareaEditor(easyMDE.element), e.originalEvent); }); } + +export async function addUploadedFileToEditor(file) { + if (!file.editor) { + const editor = getAttachedEasyMDE(file.previewElement.closest('div.comment').querySelector('textarea')); + if (editor.codemirror) { + file.editor = new CodeMirrorEditor(editor.codemirror); + } else { + file.editor = new TextareaEditor(editor); + } + } + const name = file.name.slice(0, file.name.lastIndexOf('.')); + const placeholder = `![${name}](uploading ...)`; + file.editor.insertPlaceholder(placeholder); +} diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index a4b1cb8ad248..58cf81e50c9c 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -2,7 +2,7 @@ import $ from 'jquery'; import {htmlEscape} from 'escape-goat'; import attachTribute from './tribute.js'; import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; -import {initEasyMDEImagePaste} from './comp/ImagePaste.js'; +import {initEasyMDEFilePaste} from './comp/ImagePaste.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; const {appSubUrl, csrfToken} = window.config; @@ -481,7 +481,7 @@ export function initRepoPullRequestReview() { // the temporary solution is to make the editor's height smaller (about 4 lines). GitHub also only show 4 lines for default. We can improve the UI (including Dropzone area) in future // EasyMDE's options can not handle minHeight & maxHeight together correctly, we have to set max-height for .CodeMirror-scroll in CSS. const easyMDE = await createCommentEasyMDE($reviewBox.find('textarea'), {minHeight: '80px'}); - initEasyMDEImagePaste(easyMDE, $reviewBox.find('.dropzone')); + initEasyMDEFilePaste(easyMDE, $reviewBox.find('.dropzone')); })(); } diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index da3e2b0368b7..e2affb789713 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import {createCommentEasyMDE, getAttachedEasyMDE} from './comp/EasyMDE.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; -import {initEasyMDEImagePaste, addUploadedFileToEditor, removeUploadedFileFromEditor} from './comp/ImagePaste.js'; +import {initEasyMDEFilePaste, addUploadedFileToEditor, removeUploadedFileFromEditor} from './comp/ImagePaste.js'; import { initRepoIssueBranchSelect, initRepoIssueCodeCommentCancel, initRepoIssueCommentDelete, @@ -69,7 +69,7 @@ export function initRepoCommentForm() { (async () => { const easyMDE = await createCommentEasyMDE($commentForm.find('textarea:not(.review-textarea)')); - initEasyMDEImagePaste(easyMDE, $commentForm.find('.dropzone')); + initEasyMDEFilePaste(easyMDE, $commentForm.find('.dropzone')); })(); initBranchSelector(); @@ -301,17 +301,20 @@ async function onEditContent(event) { thumbnailWidth: 480, thumbnailHeight: 480, init() { + this.on('addedfile', addUploadedFileToEditor); this.on('success', (file, data) => { file.uuid = data.uuid; const input = $(``).val(data.uuid); $dropzone.find('.files').append(input); fileUuidDict[file.uuid] = {submitted: false}; - addUploadedFileToEditor(file.editor, file); + const name = file.name.slice(0, file.name.lastIndexOf('.')); + const placeholder = `![${name}](uploading ...)`; + file.editor.replacePlaceholder(placeholder, `![${name}](/attachments/${data.uuid})`); }); this.on('removedfile', (file) => { if (disableRemovedfileEvent) return; $(`#${file.uuid}`).remove(); - if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.parentElement.parentElement.querySelector('textarea')))) { + if (!file.editor && (file.editor = getAttachedEasyMDE(this.element.closest('div.comment').querySelector('textarea')))) { file.editor = file.editor.codemirror; } if ($dropzone.data('remove-url') && !fileUuidDict[file.uuid]?.submitted) { @@ -368,7 +371,7 @@ async function onEditContent(event) { initCompMarkupContentPreviewTab($editContentForm); if ($dropzone.length) { - initEasyMDEImagePaste(easyMDE, $dropzone); + initEasyMDEFilePaste(easyMDE, $dropzone); } const $saveButton = $editContentZone.find('.save.button'); diff --git a/web_src/js/features/repo-release.js b/web_src/js/features/repo-release.js index b68a7a6cd530..17a946a63bec 100644 --- a/web_src/js/features/repo-release.js +++ b/web_src/js/features/repo-release.js @@ -1,7 +1,7 @@ import $ from 'jquery'; import attachTribute from './tribute.js'; import {initCompMarkupContentPreviewTab} from './comp/MarkupContentPreview.js'; -import {initEasyMDEImagePaste} from './comp/ImagePaste.js'; +import {initEasyMDEFilePaste} from './comp/ImagePaste.js'; import {createCommentEasyMDE} from './comp/EasyMDE.js'; export function initRepoRelease() { @@ -26,6 +26,6 @@ export function initRepoReleaseEditor() { const easyMDE = await createCommentEasyMDE($textarea); initCompMarkupContentPreviewTab($editor); const $dropzone = $editor.parent().find('.dropzone'); - initEasyMDEImagePaste(easyMDE, $dropzone); + initEasyMDEFilePaste(easyMDE, $dropzone); })(); } From 795b75d9ed637155328208b73184fab67c36a7f0 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Thu, 4 Aug 2022 10:12:54 +0800 Subject: [PATCH 14/18] Fix normal file link issue --- web_src/js/features/common-global.js | 3 ++- web_src/js/features/repo-legacy.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index befe2c50ece0..69f6b2b19fe9 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -193,7 +193,8 @@ export function initGlobalDropzone() { $dropzone.find('.files').append(input); const name = file.name.slice(0, file.name.lastIndexOf('.')); const placeholder = `![${name}](uploading ...)`; - file.editor.replacePlaceholder(placeholder, `![${name}](/attachments/${data.uuid})`); + const isImage = file.type.includes('image') ? '!' : ''; + file.editor.replacePlaceholder(placeholder, `${isImage}[${name}](/attachments/${data.uuid})`); }); this.on('removedfile', (file) => { $(`#${file.uuid}`).remove(); diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index e2affb789713..b9966091f1e5 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -309,7 +309,8 @@ async function onEditContent(event) { fileUuidDict[file.uuid] = {submitted: false}; const name = file.name.slice(0, file.name.lastIndexOf('.')); const placeholder = `![${name}](uploading ...)`; - file.editor.replacePlaceholder(placeholder, `![${name}](/attachments/${data.uuid})`); + const isImage = file.type.includes('image') ? '!' : ''; + file.editor.replacePlaceholder(placeholder, `${isImage}[${name}](/attachments/${data.uuid})`); }); this.on('removedfile', (file) => { if (disableRemovedfileEvent) return; From fa958feaf3bda54ac420ca934631007e1d9c5c37 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 8 Aug 2022 11:38:38 +0800 Subject: [PATCH 15/18] Fix in repo upload file with js error --- web_src/js/features/common-global.js | 4 +++- web_src/js/features/comp/ImagePaste.js | 22 +++++++++++++--------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js index 69f6b2b19fe9..fe780ccf40a8 100644 --- a/web_src/js/features/common-global.js +++ b/web_src/js/features/common-global.js @@ -194,7 +194,9 @@ export function initGlobalDropzone() { const name = file.name.slice(0, file.name.lastIndexOf('.')); const placeholder = `![${name}](uploading ...)`; const isImage = file.type.includes('image') ? '!' : ''; - file.editor.replacePlaceholder(placeholder, `${isImage}[${name}](/attachments/${data.uuid})`); + if (file.editor) { + file.editor.replacePlaceholder(placeholder, `${isImage}[${name}](/attachments/${data.uuid})`); + } }); this.on('removedfile', (file) => { $(`#${file.uuid}`).remove(); diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 60a9a64c32d1..0bc7ab4ad82b 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -7,11 +7,13 @@ import {getAttachedEasyMDE} from './EasyMDE.js'; */ export function removeUploadedFileFromEditor(editor, fileUuid) { // the raw regexp is: /!\[[^\]]*]\(\/attachments\/{uuid}\)/ for remove file text in textarea - const re = new RegExp(`(!|)\\[[^\\]]*]\\(/attachments/${fileUuid}\\)`); - if (editor.editor.setValue) { - editor.editor.setValue(editor.editor.getValue().replace(re, '')); // at the moment, we assume the editor is an EasyMDE - } else { - editor.editor.value = editor.editor.value.replace(re, ''); + if (editor.editor) { + const re = new RegExp(`(!|)\\[[^\\]]*]\\(/attachments/${fileUuid}\\)`); + if (editor.editor.setValue) { + editor.editor.setValue(editor.editor.getValue().replace(re, '')); // at the moment, we assume the editor is an EasyMDE + } else { + editor.editor.value = editor.editor.value.replace(re, ''); + } } } @@ -128,7 +130,7 @@ export function initEasyMDEFilePaste(easyMDE, $dropzone) { } export async function addUploadedFileToEditor(file) { - if (!file.editor) { + if (!file.editor && file.previewElement.closest('div.comment')) { const editor = getAttachedEasyMDE(file.previewElement.closest('div.comment').querySelector('textarea')); if (editor.codemirror) { file.editor = new CodeMirrorEditor(editor.codemirror); @@ -136,7 +138,9 @@ export async function addUploadedFileToEditor(file) { file.editor = new TextareaEditor(editor); } } - const name = file.name.slice(0, file.name.lastIndexOf('.')); - const placeholder = `![${name}](uploading ...)`; - file.editor.insertPlaceholder(placeholder); + if (file.editor) { + const name = file.name.slice(0, file.name.lastIndexOf('.')); + const placeholder = `![${name}](uploading ...)`; + file.editor.insertPlaceholder(placeholder); + } } From 5fde703f38f7612713261d28d27b42462d8c496c Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 8 Aug 2022 14:20:44 +0800 Subject: [PATCH 16/18] Fix repo upload file again --- web_src/js/features/comp/ImagePaste.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index 0bc7ab4ad82b..b5fea868ed98 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -7,7 +7,7 @@ import {getAttachedEasyMDE} from './EasyMDE.js'; */ export function removeUploadedFileFromEditor(editor, fileUuid) { // the raw regexp is: /!\[[^\]]*]\(\/attachments\/{uuid}\)/ for remove file text in textarea - if (editor.editor) { + if (editor && editor.editor) { const re = new RegExp(`(!|)\\[[^\\]]*]\\(/attachments/${fileUuid}\\)`); if (editor.editor.setValue) { editor.editor.setValue(editor.editor.getValue().replace(re, '')); // at the moment, we assume the editor is an EasyMDE From 649e2c6209e8ba93e68cdca0cb159c237194a568 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Mon, 5 Sep 2022 10:54:13 +0800 Subject: [PATCH 17/18] Fix in repos upload file js error --- web_src/js/features/comp/ImagePaste.js | 27 +++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index b5fea868ed98..03f64fe0dbdf 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -130,17 +130,22 @@ export function initEasyMDEFilePaste(easyMDE, $dropzone) { } export async function addUploadedFileToEditor(file) { - if (!file.editor && file.previewElement.closest('div.comment')) { - const editor = getAttachedEasyMDE(file.previewElement.closest('div.comment').querySelector('textarea')); - if (editor.codemirror) { - file.editor = new CodeMirrorEditor(editor.codemirror); - } else { - file.editor = new TextareaEditor(editor); + if (!file.editor) { + const form = file.previewElement.closest('div.comment'); + if (form) { + const editor = getAttachedEasyMDE(form.querySelector('textarea')); + if (editor) { + if (editor.codemirror) { + file.editor = new CodeMirrorEditor(editor.codemirror); + } else { + file.editor = new TextareaEditor(editor); + } + } + if (file.editor) { + const name = file.name.slice(0, file.name.lastIndexOf('.')); + const placeholder = `![${name}](uploading ...)`; + file.editor.insertPlaceholder(placeholder); + } } } - if (file.editor) { - const name = file.name.slice(0, file.name.lastIndexOf('.')); - const placeholder = `![${name}](uploading ...)`; - file.editor.insertPlaceholder(placeholder); - } } From 3aeb946d8839d269c490b711ff8551cba45a9fa4 Mon Sep 17 00:00:00 2001 From: Tyrone Yeh Date: Wed, 14 Sep 2022 11:08:32 +0800 Subject: [PATCH 18/18] Fix lint check issue --- web_src/js/features/repo-legacy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index bde9bc6456e0..722839066a04 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -74,7 +74,7 @@ export function initRepoCommentForm() { continue; } const easyMDE = await createCommentEasyMDE(textarea); - initEasyMDEImagePaste(easyMDE, $commentForm.find('.dropzone')); + initEasyMDEFilePaste(easyMDE, $commentForm.find('.dropzone')); } })();