mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 16:40:24 +08:00 
			
		
		
		
	Show attachments in issues/comments and add preview for images
This commit is contained in:
		
							
								
								
									
										15
									
								
								cmd/web.go
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								cmd/web.go
									
									
									
									
									
								
							@@ -238,14 +238,6 @@ func runWeb(*cli.Context) {
 | 
				
			|||||||
			r.Post("/:index/label", repo.UpdateIssueLabel)
 | 
								r.Post("/:index/label", repo.UpdateIssueLabel)
 | 
				
			||||||
			r.Post("/:index/milestone", repo.UpdateIssueMilestone)
 | 
								r.Post("/:index/milestone", repo.UpdateIssueMilestone)
 | 
				
			||||||
			r.Post("/:index/assignee", repo.UpdateAssignee)
 | 
								r.Post("/:index/assignee", repo.UpdateAssignee)
 | 
				
			||||||
 | 
					 | 
				
			||||||
			m.Group("/:index/attachment", func(r martini.Router) {
 | 
					 | 
				
			||||||
				r.Get("/:id", repo.IssueGetAttachment)
 | 
					 | 
				
			||||||
				r.Post("/", repo.IssuePostAttachment)
 | 
					 | 
				
			||||||
				r.Post("/:comment", repo.IssuePostAttachment)
 | 
					 | 
				
			||||||
				r.Delete("/:comment/:id", repo.IssueDeleteAttachment)
 | 
					 | 
				
			||||||
			})
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
 | 
								r.Post("/labels/new", bindIgnErr(auth.CreateLabelForm{}), repo.NewLabel)
 | 
				
			||||||
			r.Post("/labels/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
 | 
								r.Post("/labels/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
 | 
				
			||||||
			r.Post("/labels/delete", repo.DeleteLabel)
 | 
								r.Post("/labels/delete", repo.DeleteLabel)
 | 
				
			||||||
@@ -262,6 +254,13 @@ func runWeb(*cli.Context) {
 | 
				
			|||||||
		r.Get("/releases/edit/:tagname", repo.EditRelease)
 | 
							r.Get("/releases/edit/:tagname", repo.EditRelease)
 | 
				
			||||||
	}, reqSignIn, middleware.RepoAssignment(true))
 | 
						}, reqSignIn, middleware.RepoAssignment(true))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						m.Group("/:username/:reponame/issues/:index/attachment", func(r martini.Router) {
 | 
				
			||||||
 | 
							r.Get("/:id", repo.IssueGetAttachment)
 | 
				
			||||||
 | 
							r.Post("/", repo.IssuePostAttachment)
 | 
				
			||||||
 | 
							r.Post("/:comment", repo.IssuePostAttachment)
 | 
				
			||||||
 | 
							r.Delete("/:comment/:id", repo.IssueDeleteAttachment)
 | 
				
			||||||
 | 
						}, reqSignIn, middleware.RepoAssignment(true), middleware.Toggle(&middleware.ToggleOptions{DisableCsrf: true}))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	m.Group("/:username/:reponame", func(r martini.Router) {
 | 
						m.Group("/:username/:reponame", func(r martini.Router) {
 | 
				
			||||||
		r.Post("/releases/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
 | 
							r.Post("/releases/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
 | 
				
			||||||
		r.Post("/releases/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
 | 
							r.Post("/releases/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1794,4 +1794,29 @@ body {
 | 
				
			|||||||
    color: #444;
 | 
					    color: #444;
 | 
				
			||||||
    font-weight: bold;
 | 
					    font-weight: bold;
 | 
				
			||||||
    line-height: 30px;
 | 
					    line-height: 30px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.issue-main .attachments {
 | 
				
			||||||
 | 
					    margin: 0px 10px 10px 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.issue-main .attachments .attachment-label {
 | 
				
			||||||
 | 
					    margin-right: 5px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.attachment-preview {
 | 
				
			||||||
 | 
					    position: absolute;
 | 
				
			||||||
 | 
					    top: 0px;
 | 
				
			||||||
 | 
					    bottom: 0px;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    margin: 5px;
 | 
				
			||||||
 | 
					    padding: 8px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    background: #fff;
 | 
				
			||||||
 | 
					    border: 1px solid #d8d8d8;
 | 
				
			||||||
 | 
					    box-shadow: 0 0 5px 1px #d8d8d8;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.attachment-preview-img {
 | 
				
			||||||
 | 
					    border: 1px solid #d8d8d8;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -520,6 +520,61 @@ function initIssue() {
 | 
				
			|||||||
        });
 | 
					        });
 | 
				
			||||||
    }());
 | 
					    }());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Preview for images.
 | 
				
			||||||
 | 
					    (function() {
 | 
				
			||||||
 | 
					        var $hoverElement = $("<div></div>");
 | 
				
			||||||
 | 
					        var $hoverImage = $("<img />");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $hoverElement.addClass("attachment-preview");
 | 
				
			||||||
 | 
					        $hoverElement.hide();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $hoverImage.addClass("attachment-preview-img");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $hoverElement.append($hoverImage);
 | 
				
			||||||
 | 
					        $(document.body).append($hoverElement); 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var over = function() {
 | 
				
			||||||
 | 
					            var $this = $(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($this.text().match(/\.(png|jpg|jpeg|gif)$/) == false) {
 | 
				
			||||||
 | 
					                return;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ($hoverImage.attr("src") != $this.attr("href")) {
 | 
				
			||||||
 | 
					                $hoverImage.attr("src", $this.attr("href"));
 | 
				
			||||||
 | 
					                $hoverImage.load(function() {
 | 
				
			||||||
 | 
					                    var height = this.height;
 | 
				
			||||||
 | 
					                    var width = this.width;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if (height > 300) {
 | 
				
			||||||
 | 
					                        var factor = 300 / height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                        height = factor * height;
 | 
				
			||||||
 | 
					                        width = factor * width;
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    $hoverImage.css({"height": height, "width": width});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    var offset = $this.offset();
 | 
				
			||||||
 | 
					                    var left = offset.left, top = offset.top + $this.height() + 5;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    $hoverElement.css({"top": top + "px", "left": left + "px"});
 | 
				
			||||||
 | 
					                    $hoverElement.css({"height": height + 16, "width": width + 16});
 | 
				
			||||||
 | 
					                    $hoverElement.show();
 | 
				
			||||||
 | 
					                });            
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                $hoverElement.show();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        var out = function() {
 | 
				
			||||||
 | 
					            $hoverElement.hide();
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        $(".issue-main .attachments .attachment").hover(over, out);
 | 
				
			||||||
 | 
					    }());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Upload.
 | 
				
			||||||
    (function() {
 | 
					    (function() {
 | 
				
			||||||
        var $attached = $("#attached");
 | 
					        var $attached = $("#attached");
 | 
				
			||||||
        var $attachments = $("input[name=attachments]");
 | 
					        var $attachments = $("input[name=attachments]");
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -709,6 +709,12 @@ func Comment(ctx *middleware.Context, params martini.Params) {
 | 
				
			|||||||
	attachments := strings.Split(params["attachments"], ",")
 | 
						attachments := strings.Split(params["attachments"], ",")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for _, a := range attachments {
 | 
						for _, a := range attachments {
 | 
				
			||||||
 | 
							a = strings.Trim(a, " ")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if len(a) == 0 {
 | 
				
			||||||
 | 
								continue
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		aId, err := base.StrTo(a).Int64()
 | 
							aId, err := base.StrTo(a).Int64()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -1002,12 +1008,23 @@ func UpdateMilestonePost(ctx *middleware.Context, params martini.Params, form au
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func IssuePostAttachment(ctx *middleware.Context, params martini.Params) {
 | 
					func IssuePostAttachment(ctx *middleware.Context, params martini.Params) {
 | 
				
			||||||
	issueId, _ := base.StrTo(params["index"]).Int64()
 | 
						index, _ := base.StrTo(params["index"]).Int64()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if issueId == 0 {
 | 
						if index == 0 {
 | 
				
			||||||
		ctx.JSON(400, map[string]interface{}{
 | 
							ctx.JSON(400, map[string]interface{}{
 | 
				
			||||||
			"ok":    false,
 | 
								"ok":    false,
 | 
				
			||||||
			"error": "invalid issue id",
 | 
								"error": "invalid issue index",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.JSON(400, map[string]interface{}{
 | 
				
			||||||
 | 
								"ok":    false,
 | 
				
			||||||
 | 
								"error": "invalid comment id",
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -1089,7 +1106,7 @@ func IssuePostAttachment(ctx *middleware.Context, params martini.Params) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	a, err := models.CreateAttachment(issueId, commentId, header.Filename, out.Name())
 | 
						a, err := models.CreateAttachment(issue.Id, commentId, header.Filename, out.Name())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		ctx.JSON(500, map[string]interface{}{
 | 
							ctx.JSON(500, map[string]interface{}{
 | 
				
			||||||
@@ -1121,16 +1138,29 @@ func IssueGetAttachment(ctx *middleware.Context, params martini.Params) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						log.Error("path=%s name=%s", attachment.Path, attachment.Name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ctx.ServeFile(attachment.Path, attachment.Name)
 | 
						ctx.ServeFile(attachment.Path, attachment.Name)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func IssueDeleteAttachment(ctx *middleware.Context, params martini.Params) {
 | 
					func IssueDeleteAttachment(ctx *middleware.Context, params martini.Params) {
 | 
				
			||||||
	issueId, _ := base.StrTo(params["index"]).Int64()
 | 
						index, _ := base.StrTo(params["index"]).Int64()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if issueId == 0 {
 | 
						if index == 0 {
 | 
				
			||||||
		ctx.JSON(400, map[string]interface{}{
 | 
							ctx.JSON(400, map[string]interface{}{
 | 
				
			||||||
			"ok":    false,
 | 
								"ok":    false,
 | 
				
			||||||
			"error": "invalid issue id",
 | 
								"error": "invalid issue index",
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							ctx.JSON(400, map[string]interface{}{
 | 
				
			||||||
 | 
								"ok":    false,
 | 
				
			||||||
 | 
								"error": "invalid comment id",
 | 
				
			||||||
		})
 | 
							})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
@@ -1189,7 +1219,7 @@ func IssueDeleteAttachment(ctx *middleware.Context, params martini.Params) {
 | 
				
			|||||||
		return
 | 
							return
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if attachment.IssueId != issueId {
 | 
						if attachment.IssueId != issue.Id {
 | 
				
			||||||
		ctx.JSON(400, map[string]interface{}{
 | 
							ctx.JSON(400, map[string]interface{}{
 | 
				
			||||||
			"ok":    false,
 | 
								"ok":    false,
 | 
				
			||||||
			"error": "attachment not associated with the given issue",
 | 
								"error": "attachment not associated with the given issue",
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,13 +45,19 @@
 | 
				
			|||||||
                                        <div class="tab-pane issue-preview-content" id="issue-edit-preview">Loading...</div>
 | 
					                                        <div class="tab-pane issue-preview-content" id="issue-edit-preview">Loading...</div>
 | 
				
			||||||
                                    </div>
 | 
					                                    </div>
 | 
				
			||||||
                                </div>
 | 
					                                </div>
 | 
				
			||||||
                            </div>
 | 
					                            </div>                        
 | 
				
			||||||
                            <div class="attachments">
 | 
					 | 
				
			||||||
                                {{range .Attachments}}
 | 
					 | 
				
			||||||
                                <a class="attachment" href="{{.IssueId}}/attachment/{{.Id}}">{{.Name}}</a>
 | 
					 | 
				
			||||||
                                {{end}}
 | 
					 | 
				
			||||||
                            </div>                            
 | 
					 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        {{with $attachments := .Issue.Attachments}}
 | 
				
			||||||
 | 
					                        {{if $attachments}}
 | 
				
			||||||
 | 
					                        <div class="attachments">
 | 
				
			||||||
 | 
					                            <span class="attachment-label label label-info">Attachments:</span>
 | 
				
			||||||
 | 
					                                
 | 
				
			||||||
 | 
					                            {{range $attachments}}
 | 
				
			||||||
 | 
					                            <a class="attachment label label-default" href="{{.IssueId}}/attachment/{{.Id}}">{{.Name}}</a>
 | 
				
			||||||
 | 
					                            {{end}}
 | 
				
			||||||
 | 
					                        </div>
 | 
				
			||||||
 | 
					                        {{end}}
 | 
				
			||||||
 | 
					                        {{end}}    
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                    {{range .Comments}}
 | 
					                    {{range .Comments}}
 | 
				
			||||||
                    {{/* 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE, 4 = COMMIT, 5 = PULL */}}
 | 
					                    {{/* 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE, 4 = COMMIT, 5 = PULL */}}
 | 
				
			||||||
@@ -68,11 +74,17 @@
 | 
				
			|||||||
                            <div class="panel-body markdown">
 | 
					                            <div class="panel-body markdown">
 | 
				
			||||||
                                {{str2html .Content}}
 | 
					                                {{str2html .Content}}
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
 | 
					                            {{with $attachments := .Attachments}}
 | 
				
			||||||
 | 
					                            {{if $attachments}}
 | 
				
			||||||
                            <div class="attachments">
 | 
					                            <div class="attachments">
 | 
				
			||||||
                                {{range .Attachments}}
 | 
					                                <span class="attachment-label label label-info">Attachments:</span>
 | 
				
			||||||
                                <a class="attachment" href="{{.IssueId}}/attachment/{{.Id}}">{{.Name}}</a>
 | 
					
 | 
				
			||||||
 | 
					                                {{range $attachments}}
 | 
				
			||||||
 | 
					                                <a class="attachment label label-default" href="{{.IssueId}}/attachment/{{.Id}}">{{.Name}}</a>
 | 
				
			||||||
                                {{end}}
 | 
					                                {{end}}
 | 
				
			||||||
                            </div>
 | 
					                            </div>
 | 
				
			||||||
 | 
					                            {{end}}
 | 
				
			||||||
 | 
					                            {{end}}
 | 
				
			||||||
                        </div>
 | 
					                        </div>
 | 
				
			||||||
                    </div>
 | 
					                    </div>
 | 
				
			||||||
                    {{else if eq .Type 1}}
 | 
					                    {{else if eq .Type 1}}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user