mirror of
				https://github.com/go-gitea/gitea.git
				synced 2025-10-31 10:56:10 +01:00 
			
		
		
		
	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:
		| @@ -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 { | ||||||
| @@ -425,6 +425,7 @@ func SubmitReview(doer *User, issue *Issue, reviewType ReviewType, content, comm | |||||||
| 		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'); | ||||||
|  |     if (!dropzone) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |     const uploadUrl = dropzone.dataset.uploadUrl; | ||||||
|  |     const dropzoneFiles = dropzone.querySelector('.files'); | ||||||
|  |     for (const textarea of this.querySelectorAll('textarea')) { | ||||||
|  |       textarea.addEventListener('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('.')); | ||||||
|         insertAtCursor(this, `![${name}]()`); |           insertAtCursor(textarea, `![${name}]()`); | ||||||
|         const data = await uploadFile(img); |           const data = await uploadFile(img, uploadUrl); | ||||||
|         replaceAndKeepCursor(this, `![${name}]()`, ``); |           replaceAndKeepCursor(textarea, `![${name}]()`, ``); | ||||||
|           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); |           dropzoneFiles.appendChild(input[0]); | ||||||
|         } |         } | ||||||
|       }, false); |       }, 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(``, pos); |       simplemde.codemirror.replaceRange(``, 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 New Issue
	
	Block a user