Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SimpleMDE and Fix Image Paste for Issue/Comment Editor #9197

Merged
merged 7 commits into from
Dec 16, 2019
Merged
1 change: 1 addition & 0 deletions routers/repo/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,7 @@ func ViewIssue(ctx *context.Context) {
ctx.Data["RequireHighlightJS"] = true
ctx.Data["RequireDropzone"] = true
ctx.Data["RequireTribute"] = true
ctx.Data["RequireSimpleMDE"] = true
renderAttachmentSettings(ctx)

if err = issue.LoadAttributes(); err != nil {
Expand Down
59 changes: 58 additions & 1 deletion web_src/js/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ let csrf;
let suburl;
let previewFileModes;
let simpleMDEditor;
const commentMDEditors = {};
let codeMirrorEditor;

// Disable Dropzone auto-discover because it's manually initialized
Expand Down Expand Up @@ -304,11 +305,27 @@ function initImagePaste(target) {
});
}

function initSimpleMDEImagePaste(simplemde, files) {
simplemde.codemirror.on('paste', (_, event) => {
retrieveImageFromClipboardAsBlob(event, (img) => {
const name = img.name.substr(0, img.name.lastIndexOf('.'));
uploadFile(img, (res) => {
const data = JSON.parse(res);
const pos = simplemde.codemirror.getCursor();
simplemde.codemirror.replaceRange(`![${name}](${suburl}/attachments/${data.uuid})`, pos);
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
files.append(input);
});
});
});
}

function initCommentForm() {
if ($('.comment.form').length === 0) {
return;
}

setCommentSimpleMDE($('.comment.form textarea'));
initBranchSelector();
initCommentPreviewTab($('.comment.form'));
initImagePaste($('.comment.form textarea'));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't initImagePaste has done that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I didn't understand what you mean. Do you mean why I create a new function initSimpleMDEImagePaste to fix the image paste problem? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lunny, if you are asking why there is a new initSimpleMDEImagePaste, the reasons are:

  1. The initImagePaste always attached the uploaded file input $('.files'), which is not the correct DOM element for comment. So I need a new function to allow caller providing correct DOM element to attach file.

  2. When I trying to re-use initImagePaste for comment editor, it's weird that the CodeMirror input-field fails to insert image (![img](http://url). Therefore I have to insert the image markdown with simplemde.codemirror.replaceRange.

Expand Down Expand Up @@ -836,6 +853,7 @@ function initRepository() {
const $renderContent = $segment.find('.render-content');
const $rawContent = $segment.find('.raw-content');
let $textarea;
let $simplemde;

// Setup new form
if ($editContentZone.html().length === 0) {
Expand Down Expand Up @@ -920,8 +938,10 @@ function initRepository() {
$tabMenu.find('.preview.item').attr('data-tab', $editContentZone.data('preview'));
$editContentForm.find('.write.segment').attr('data-tab', $editContentZone.data('write'));
$editContentForm.find('.preview.segment').attr('data-tab', $editContentZone.data('preview'));

$simplemde = setCommentSimpleMDE($textarea);
commentMDEditors[$editContentZone.data('write')] = $simplemde;
initCommentPreviewTab($editContentForm);
initSimpleMDEImagePaste($simplemde, $files);

$editContentZone.find('.cancel.button').click(() => {
$renderContent.show();
Expand Down Expand Up @@ -968,15 +988,18 @@ function initRepository() {
});
} else {
$textarea = $segment.find('textarea');
$simplemde = commentMDEditors[$editContentZone.data('write')];
}

// Show write/preview tab and copy raw content as needed
$editContentZone.show();
$renderContent.hide();
if ($textarea.val().length === 0) {
$textarea.val($rawContent.text());
$simplemde.value($rawContent.text());
}
$textarea.focus();
$simplemde.codemirror.focus();
event.preventDefault();
});

Expand Down Expand Up @@ -1442,6 +1465,40 @@ function setSimpleMDE($editArea) {
return true;
}

function setCommentSimpleMDE($editArea) {
const simplemde = new SimpleMDE({
autoDownloadFontAwesome: false,
element: $editArea[0],
forceSync: true,
renderingConfig: {
singleLineBreaks: false
},
indentWithTabs: false,
tabSize: 4,
spellChecker: false,
toolbar: ['bold', 'italic', 'strikethrough', '|',
'heading-1', 'heading-2', 'heading-3', 'heading-bigger', 'heading-smaller', '|',
'code', 'quote', '|',
'unordered-list', 'ordered-list', '|',
'link', 'image', 'table', 'horizontal-rule', '|',
'clean-block']
});
simplemde.codemirror.setOption('extraKeys', {
Enter: () => {
if (!(issuesTribute.isActive || emojiTribute.isActive)) {
return CodeMirror.Pass;
}
},
Backspace: (cm) => {
cm.getInputField().trigger('input');
cm.execCommand('delCharBefore');
}
});
issuesTribute.attach(simplemde.codemirror.getInputField());
emojiTribute.attach(simplemde.codemirror.getInputField());
return simplemde;
}

function setCodeMirror($editArea) {
if (simpleMDEditor) {
simpleMDEditor.toTextArea();
Expand Down