Add attachments for PR reviews (#16075)
* First step for multiple dropzones per page. * Allow attachments on review comments. * Lint. * Fixed accidental initialize of the review textarea. * Initialize SimpleMDE textarea. Co-authored-by: techknowlogick <techknowlogick@gitea.io>
This commit is contained in:
parent
0adcea9ba6
commit
ebf253b841
15 changed files with 87 additions and 47 deletions
|
@ -762,6 +762,8 @@ func updateCommentInfos(e *xorm.Session, opts *CreateCommentOptions, comment *Co
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fallthrough
|
fallthrough
|
||||||
|
case CommentTypeReview:
|
||||||
|
fallthrough
|
||||||
case CommentTypeComment:
|
case CommentTypeComment:
|
||||||
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
|
if _, err = e.Exec("UPDATE `issue` SET num_comments=num_comments+1 WHERE id=?", opts.Issue.ID); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -347,7 +347,7 @@ func IsContentEmptyErr(err error) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
||||||
func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool) (*Review, *Comment, error) {
|
func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, commitID string, stale bool, attachmentUUIDs []string) (*Review, *Comment, error) {
|
||||||
sess := x.NewSession()
|
sess := x.NewSession()
|
||||||
defer sess.Close()
|
defer sess.Close()
|
||||||
if err := sess.Begin(); err != nil {
|
if err := sess.Begin(); err != nil {
|
||||||
|
@ -419,12 +419,13 @@ func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, comm
|
||||||
}
|
}
|
||||||
|
|
||||||
comm, err := createComment(sess, &CreateCommentOptions{
|
comm, err := createComment(sess, &CreateCommentOptions{
|
||||||
Type: CommentTypeReview,
|
Type: CommentTypeReview,
|
||||||
Doer: doer,
|
Doer: doer,
|
||||||
Content: review.Content,
|
Content: review.Content,
|
||||||
Issue: issue,
|
Issue: issue,
|
||||||
Repo: issue.Repo,
|
Repo: issue.Repo,
|
||||||
ReviewID: review.ID,
|
ReviewID: review.ID,
|
||||||
|
Attachments: attachmentUUIDs,
|
||||||
})
|
})
|
||||||
if err != nil || comm == nil {
|
if err != nil || comm == nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
|
|
@ -359,7 +359,7 @@ func CreatePullReview(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create review and associate all pending review comments
|
// create review and associate all pending review comments
|
||||||
review, _, err := pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, opts.CommitID)
|
review, _, err := pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, opts.CommitID, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
|
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
|
||||||
return
|
return
|
||||||
|
@ -447,7 +447,7 @@ func SubmitPullReview(ctx *context.APIContext) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// create review and associate all pending review comments
|
// create review and associate all pending review comments
|
||||||
review, _, err = pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, headCommitID)
|
review, _, err = pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, pr.Issue, reviewType, opts.Body, headCommitID, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
|
ctx.Error(http.StatusInternalServerError, "SubmitReview", err)
|
||||||
return
|
return
|
||||||
|
|
|
@ -694,6 +694,10 @@ func ViewPullFiles(ctx *context.Context) {
|
||||||
getBranchData(ctx, issue)
|
getBranchData(ctx, issue)
|
||||||
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
|
ctx.Data["IsIssuePoster"] = ctx.IsSigned && issue.IsPoster(ctx.User.ID)
|
||||||
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
ctx.Data["HasIssuesOrPullsWritePermission"] = ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull)
|
||||||
|
|
||||||
|
ctx.Data["IsAttachmentEnabled"] = setting.Attachment.Enabled
|
||||||
|
upload.AddUploadContext(ctx, "comment")
|
||||||
|
|
||||||
ctx.HTML(http.StatusOK, tplPullFiles)
|
ctx.HTML(http.StatusOK, tplPullFiles)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
"code.gitea.io/gitea/modules/base"
|
"code.gitea.io/gitea/modules/base"
|
||||||
"code.gitea.io/gitea/modules/context"
|
"code.gitea.io/gitea/modules/context"
|
||||||
"code.gitea.io/gitea/modules/log"
|
"code.gitea.io/gitea/modules/log"
|
||||||
|
"code.gitea.io/gitea/modules/setting"
|
||||||
"code.gitea.io/gitea/modules/web"
|
"code.gitea.io/gitea/modules/web"
|
||||||
"code.gitea.io/gitea/services/forms"
|
"code.gitea.io/gitea/services/forms"
|
||||||
pull_service "code.gitea.io/gitea/services/pull"
|
pull_service "code.gitea.io/gitea/services/pull"
|
||||||
|
@ -211,7 +212,12 @@ func SubmitReview(ctx *context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, comm, err := pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, issue, reviewType, form.Content, form.CommitID)
|
var attachments []string
|
||||||
|
if setting.Attachment.Enabled {
|
||||||
|
attachments = form.Files
|
||||||
|
}
|
||||||
|
|
||||||
|
_, comm, err := pull_service.SubmitReview(ctx.User, ctx.Repo.GitRepo, issue, reviewType, form.Content, form.CommitID, attachments)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if models.IsContentEmptyErr(err) {
|
if models.IsContentEmptyErr(err) {
|
||||||
ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
|
ctx.Flash.Error(ctx.Tr("repo.issues.review.content.empty"))
|
||||||
|
|
|
@ -587,6 +587,7 @@ type SubmitReviewForm struct {
|
||||||
Content string
|
Content string
|
||||||
Type string `binding:"Required;In(approve,comment,reject)"`
|
Type string `binding:"Required;In(approve,comment,reject)"`
|
||||||
CommitID string
|
CommitID string
|
||||||
|
Files []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates the fields
|
// Validate validates the fields
|
||||||
|
|
|
@ -100,7 +100,7 @@ func CreateCodeComment(doer *models.User, gitRepo *git.Repository, issue *models
|
||||||
|
|
||||||
if !isReview && !existsReview {
|
if !isReview && !existsReview {
|
||||||
// Submit the review we've just created so the comment shows up in the issue view
|
// Submit the review we've just created so the comment shows up in the issue view
|
||||||
if _, _, err = SubmitReview(doer, gitRepo, issue, models.ReviewTypeComment, "", latestCommitID); err != nil {
|
if _, _, err = SubmitReview(doer, gitRepo, issue, models.ReviewTypeComment, "", latestCommitID, nil); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -215,7 +215,7 @@ func createCodeComment(doer *models.User, repo *models.Repository, issue *models
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
// SubmitReview creates a review out of the existing pending review or creates a new one if no pending review exist
|
||||||
func SubmitReview(doer *models.User, gitRepo *git.Repository, issue *models.Issue, reviewType models.ReviewType, content, commitID string) (*models.Review, *models.Comment, error) {
|
func SubmitReview(doer *models.User, gitRepo *git.Repository, issue *models.Issue, reviewType models.ReviewType, content, commitID string, attachmentUUIDs []string) (*models.Review, *models.Comment, error) {
|
||||||
pr, err := issue.GetPullRequest()
|
pr, err := issue.GetPullRequest()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
|
@ -240,7 +240,7 @@ func SubmitReview(doer *models.User, gitRepo *git.Repository, issue *models.Issu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
review, comm, err := models.SubmitReview(doer, issue, reviewType, content, commitID, stale)
|
review, comm, err := models.SubmitReview(doer, issue, reviewType, content, commitID, stale, attachmentUUIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,11 @@
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<textarea name="content" tabindex="0" rows="2" placeholder="{{$.i18n.Tr "repo.diff.review.placeholder"}}"></textarea>
|
<textarea name="content" tabindex="0" rows="2" placeholder="{{$.i18n.Tr "repo.diff.review.placeholder"}}"></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
{{if .IsAttachmentEnabled}}
|
||||||
|
<div class="field">
|
||||||
|
{{template "repo/upload" .}}
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<button type="submit" name="type" value="approve" {{ if and $.IsSigned ($.Issue.IsPoster $.SignedUser.ID) }} disabled {{ end }} class="ui submit green tiny button btn-submit">{{$.i18n.Tr "repo.diff.review.approve"}}</button>
|
<button type="submit" name="type" value="approve" {{ if and $.IsSigned ($.Issue.IsPoster $.SignedUser.ID) }} disabled {{ end }} class="ui submit green tiny button btn-submit">{{$.i18n.Tr "repo.diff.review.approve"}}</button>
|
||||||
<button type="submit" name="type" value="comment" class="ui submit tiny basic button btn-submit">{{$.i18n.Tr "repo.diff.review.comment"}}</button>
|
<button type="submit" name="type" value="comment" class="ui submit tiny basic button btn-submit">{{$.i18n.Tr "repo.diff.review.comment"}}</button>
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="files"></div>
|
|
||||||
{{template "repo/upload" .}}
|
{{template "repo/upload" .}}
|
||||||
</div>
|
</div>
|
||||||
{{template "repo/editor/commit_form" .}}
|
{{template "repo/editor/commit_form" .}}
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
</div>
|
</div>
|
||||||
{{if .IsAttachmentEnabled}}
|
{{if .IsAttachmentEnabled}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="files"></div>
|
|
||||||
{{template "repo/upload" .}}
|
{{template "repo/upload" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -197,7 +197,6 @@
|
||||||
</div>
|
</div>
|
||||||
{{if .IsAttachmentEnabled}}
|
{{if .IsAttachmentEnabled}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="comment-files"></div>
|
|
||||||
{{template "repo/upload" .}}
|
{{template "repo/upload" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -449,6 +449,9 @@
|
||||||
<span class="no-content">{{$.i18n.Tr "repo.issues.no_content"}}</span>
|
<span class="no-content">{{$.i18n.Tr "repo.issues.no_content"}}</span>
|
||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
|
{{if .Attachments}}
|
||||||
|
{{template "repo/issue/view_content/attachments" Dict "ctx" $ "Attachments" .Attachments "Content" .RenderedContent}}
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -76,7 +76,6 @@
|
||||||
{{end}}
|
{{end}}
|
||||||
{{if .IsAttachmentEnabled}}
|
{{if .IsAttachmentEnabled}}
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<div class="files"></div>
|
|
||||||
{{template "repo/upload" .}}
|
{{template "repo/upload" .}}
|
||||||
</div>
|
</div>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<div
|
<div
|
||||||
class="ui dropzone"
|
class="ui dropzone"
|
||||||
id="dropzone"
|
|
||||||
data-link-url="{{.UploadLinkUrl}}"
|
data-link-url="{{.UploadLinkUrl}}"
|
||||||
data-upload-url="{{.UploadUrl}}"
|
data-upload-url="{{.UploadUrl}}"
|
||||||
data-remove-url="{{.UploadRemoveUrl}}"
|
data-remove-url="{{.UploadRemoveUrl}}"
|
||||||
|
@ -11,4 +10,6 @@
|
||||||
data-invalid-input-type="{{.i18n.Tr "dropzone.invalid_input_type"}}"
|
data-invalid-input-type="{{.i18n.Tr "dropzone.invalid_input_type"}}"
|
||||||
data-file-too-big="{{.i18n.Tr "dropzone.file_too_big"}}"
|
data-file-too-big="{{.i18n.Tr "dropzone.file_too_big"}}"
|
||||||
data-remove-file="{{.i18n.Tr "dropzone.remove_file"}}"
|
data-remove-file="{{.i18n.Tr "dropzone.remove_file"}}"
|
||||||
></div>
|
>
|
||||||
|
<div class="files"></div>
|
||||||
|
</div>
|
||||||
|
|
|
@ -327,11 +327,11 @@ function getPastedImages(e) {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function uploadFile(file) {
|
async function uploadFile(file, uploadUrl) {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', file, file.name);
|
formData.append('file', file, file.name);
|
||||||
|
|
||||||
const res = await fetch($('#dropzone').data('upload-url'), {
|
const res = await fetch(uploadUrl, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'X-Csrf-Token': csrf},
|
headers: {'X-Csrf-Token': csrf},
|
||||||
body: formData,
|
body: formData,
|
||||||
|
@ -345,24 +345,33 @@ function reload() {
|
||||||
|
|
||||||
function initImagePaste(target) {
|
function initImagePaste(target) {
|
||||||
target.each(function () {
|
target.each(function () {
|
||||||
this.addEventListener('paste', async (e) => {
|
const dropzone = this.querySelector('.dropzone');
|
||||||
for (const img of getPastedImages(e)) {
|
if (!dropzone) {
|
||||||
const name = img.name.substr(0, img.name.lastIndexOf('.'));
|
return;
|
||||||
insertAtCursor(this, `![${name}]()`);
|
}
|
||||||
const data = await uploadFile(img);
|
const uploadUrl = dropzone.dataset.uploadUrl;
|
||||||
replaceAndKeepCursor(this, `![${name}]()`, `![${name}](${AppSubUrl}/attachments/${data.uuid})`);
|
const dropzoneFiles = dropzone.querySelector('.files');
|
||||||
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
for (const textarea of this.querySelectorAll('textarea')) {
|
||||||
$('.files').append(input);
|
textarea.addEventListener('paste', async (e) => {
|
||||||
}
|
for (const img of getPastedImages(e)) {
|
||||||
}, false);
|
const name = img.name.substr(0, img.name.lastIndexOf('.'));
|
||||||
|
insertAtCursor(textarea, `![${name}]()`);
|
||||||
|
const data = await uploadFile(img, uploadUrl);
|
||||||
|
replaceAndKeepCursor(textarea, `![${name}]()`, `![${name}](${AppSubUrl}/attachments/${data.uuid})`);
|
||||||
|
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||||
|
dropzoneFiles.appendChild(input[0]);
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initSimpleMDEImagePaste(simplemde, files) {
|
function initSimpleMDEImagePaste(simplemde, dropzone, files) {
|
||||||
|
const uploadUrl = dropzone.dataset.uploadUrl;
|
||||||
simplemde.codemirror.on('paste', async (_, e) => {
|
simplemde.codemirror.on('paste', async (_, e) => {
|
||||||
for (const img of getPastedImages(e)) {
|
for (const img of getPastedImages(e)) {
|
||||||
const name = img.name.substr(0, img.name.lastIndexOf('.'));
|
const name = img.name.substr(0, img.name.lastIndexOf('.'));
|
||||||
const data = await uploadFile(img);
|
const data = await uploadFile(img, uploadUrl);
|
||||||
const pos = simplemde.codemirror.getCursor();
|
const pos = simplemde.codemirror.getCursor();
|
||||||
simplemde.codemirror.replaceRange(`![${name}](${AppSubUrl}/attachments/${data.uuid})`, pos);
|
simplemde.codemirror.replaceRange(`![${name}](${AppSubUrl}/attachments/${data.uuid})`, pos);
|
||||||
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||||
|
@ -381,7 +390,7 @@ function initCommentForm() {
|
||||||
autoSimpleMDE = setCommentSimpleMDE($('.comment.form textarea:not(.review-textarea)'));
|
autoSimpleMDE = setCommentSimpleMDE($('.comment.form textarea:not(.review-textarea)'));
|
||||||
initBranchSelector();
|
initBranchSelector();
|
||||||
initCommentPreviewTab($('.comment.form'));
|
initCommentPreviewTab($('.comment.form'));
|
||||||
initImagePaste($('.comment.form textarea'));
|
initImagePaste($('.comment.form'));
|
||||||
|
|
||||||
// Listsubmit
|
// Listsubmit
|
||||||
function initListSubmits(selector, outerSelector) {
|
function initListSubmits(selector, outerSelector) {
|
||||||
|
@ -993,8 +1002,7 @@ async function initRepository() {
|
||||||
|
|
||||||
let dz;
|
let dz;
|
||||||
const $dropzone = $editContentZone.find('.dropzone');
|
const $dropzone = $editContentZone.find('.dropzone');
|
||||||
const $files = $editContentZone.find('.comment-files');
|
if ($dropzone.length === 1) {
|
||||||
if ($dropzone.length > 0) {
|
|
||||||
$dropzone.data('saved', false);
|
$dropzone.data('saved', false);
|
||||||
|
|
||||||
const filenameDict = {};
|
const filenameDict = {};
|
||||||
|
@ -1020,7 +1028,7 @@ async function initRepository() {
|
||||||
submitted: false
|
submitted: false
|
||||||
};
|
};
|
||||||
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||||
$files.append(input);
|
$dropzone.find('.files').append(input);
|
||||||
});
|
});
|
||||||
this.on('removedfile', (file) => {
|
this.on('removedfile', (file) => {
|
||||||
if (!(file.name in filenameDict)) {
|
if (!(file.name in filenameDict)) {
|
||||||
|
@ -1042,7 +1050,7 @@ async function initRepository() {
|
||||||
this.on('reload', () => {
|
this.on('reload', () => {
|
||||||
$.getJSON($editContentZone.data('attachment-url'), (data) => {
|
$.getJSON($editContentZone.data('attachment-url'), (data) => {
|
||||||
dz.removeAllFiles(true);
|
dz.removeAllFiles(true);
|
||||||
$files.empty();
|
$dropzone.find('.files').empty();
|
||||||
$.each(data, function () {
|
$.each(data, function () {
|
||||||
const imgSrc = `${$dropzone.data('link-url')}/${this.uuid}`;
|
const imgSrc = `${$dropzone.data('link-url')}/${this.uuid}`;
|
||||||
dz.emit('addedfile', this);
|
dz.emit('addedfile', this);
|
||||||
|
@ -1055,7 +1063,7 @@ async function initRepository() {
|
||||||
};
|
};
|
||||||
$dropzone.find(`img[src='${imgSrc}']`).css('max-width', '100%');
|
$dropzone.find(`img[src='${imgSrc}']`).css('max-width', '100%');
|
||||||
const input = $(`<input id="${this.uuid}" name="files" type="hidden">`).val(this.uuid);
|
const input = $(`<input id="${this.uuid}" name="files" type="hidden">`).val(this.uuid);
|
||||||
$files.append(input);
|
$dropzone.find('.files').append(input);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1075,7 +1083,9 @@ async function initRepository() {
|
||||||
$simplemde = setCommentSimpleMDE($textarea);
|
$simplemde = setCommentSimpleMDE($textarea);
|
||||||
commentMDEditors[$editContentZone.data('write')] = $simplemde;
|
commentMDEditors[$editContentZone.data('write')] = $simplemde;
|
||||||
initCommentPreviewTab($editContentForm);
|
initCommentPreviewTab($editContentForm);
|
||||||
initSimpleMDEImagePaste($simplemde, $files);
|
if ($dropzone.length === 1) {
|
||||||
|
initSimpleMDEImagePaste($simplemde, $dropzone[0], $dropzone.find('.files'));
|
||||||
|
}
|
||||||
|
|
||||||
$editContentZone.find('.cancel.button').on('click', () => {
|
$editContentZone.find('.cancel.button').on('click', () => {
|
||||||
$renderContent.show();
|
$renderContent.show();
|
||||||
|
@ -1087,7 +1097,7 @@ async function initRepository() {
|
||||||
$editContentZone.find('.save.button').on('click', () => {
|
$editContentZone.find('.save.button').on('click', () => {
|
||||||
$renderContent.show();
|
$renderContent.show();
|
||||||
$editContentZone.hide();
|
$editContentZone.hide();
|
||||||
const $attachments = $files.find('[name=files]').map(function () {
|
const $attachments = $dropzone.find('.files').find('[name=files]').map(function () {
|
||||||
return $(this).val();
|
return $(this).val();
|
||||||
}).get();
|
}).get();
|
||||||
$.post($editContentZone.data('update-url'), {
|
$.post($editContentZone.data('update-url'), {
|
||||||
|
@ -1369,6 +1379,13 @@ function initPullRequestReview() {
|
||||||
$simplemde.codemirror.focus();
|
$simplemde.codemirror.focus();
|
||||||
assingMenuAttributes(form.find('.menu'));
|
assingMenuAttributes(form.find('.menu'));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const $reviewBox = $('.review-box');
|
||||||
|
if ($reviewBox.length === 1) {
|
||||||
|
setCommentSimpleMDE($reviewBox.find('textarea'));
|
||||||
|
initImagePaste($reviewBox);
|
||||||
|
}
|
||||||
|
|
||||||
// The following part is only for diff views
|
// The following part is only for diff views
|
||||||
if ($('.repository.pull.diff').length === 0) {
|
if ($('.repository.pull.diff').length === 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -1656,6 +1673,10 @@ $.fn.getCursorPosition = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
function setCommentSimpleMDE($editArea) {
|
function setCommentSimpleMDE($editArea) {
|
||||||
|
if ($editArea.length === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const simplemde = new SimpleMDE({
|
const simplemde = new SimpleMDE({
|
||||||
autoDownloadFontAwesome: false,
|
autoDownloadFontAwesome: false,
|
||||||
element: $editArea[0],
|
element: $editArea[0],
|
||||||
|
@ -1827,7 +1848,8 @@ function initReleaseEditor() {
|
||||||
const $files = $editor.parent().find('.files');
|
const $files = $editor.parent().find('.files');
|
||||||
const $simplemde = setCommentSimpleMDE($textarea);
|
const $simplemde = setCommentSimpleMDE($textarea);
|
||||||
initCommentPreviewTab($editor);
|
initCommentPreviewTab($editor);
|
||||||
initSimpleMDEImagePaste($simplemde, $files);
|
const dropzone = $editor.parent().find('.dropzone')[0];
|
||||||
|
initSimpleMDEImagePaste($simplemde, dropzone, $files);
|
||||||
}
|
}
|
||||||
|
|
||||||
function initOrganization() {
|
function initOrganization() {
|
||||||
|
@ -2610,11 +2632,10 @@ $(document).ready(async () => {
|
||||||
initLinkAccountView();
|
initLinkAccountView();
|
||||||
|
|
||||||
// Dropzone
|
// Dropzone
|
||||||
const $dropzone = $('#dropzone');
|
for (const el of document.querySelectorAll('.dropzone')) {
|
||||||
if ($dropzone.length > 0) {
|
|
||||||
const filenameDict = {};
|
const filenameDict = {};
|
||||||
|
const $dropzone = $(el);
|
||||||
await createDropzone('#dropzone', {
|
await createDropzone(el, {
|
||||||
url: $dropzone.data('upload-url'),
|
url: $dropzone.data('upload-url'),
|
||||||
headers: {'X-Csrf-Token': csrf},
|
headers: {'X-Csrf-Token': csrf},
|
||||||
maxFiles: $dropzone.data('max-file'),
|
maxFiles: $dropzone.data('max-file'),
|
||||||
|
@ -2633,7 +2654,7 @@ $(document).ready(async () => {
|
||||||
this.on('success', (file, data) => {
|
this.on('success', (file, data) => {
|
||||||
filenameDict[file.name] = data.uuid;
|
filenameDict[file.name] = data.uuid;
|
||||||
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
const input = $(`<input id="${data.uuid}" name="files" type="hidden">`).val(data.uuid);
|
||||||
$('.files').append(input);
|
$dropzone.find('.files').append(input);
|
||||||
});
|
});
|
||||||
this.on('removedfile', (file) => {
|
this.on('removedfile', (file) => {
|
||||||
if (file.name in filenameDict) {
|
if (file.name in filenameDict) {
|
||||||
|
|
Reference in a new issue