Эх сурвалжийг харах

Show attachments in issues/comments and add preview for images

Justin Nuß 10 жил өмнө
parent
commit
43e5de7f83

+ 7 - 8
cmd/web.go

@@ -238,14 +238,6 @@ func runWeb(*cli.Context) {
 			r.Post("/:index/label", repo.UpdateIssueLabel)
 			r.Post("/:index/milestone", repo.UpdateIssueMilestone)
 			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/edit", bindIgnErr(auth.CreateLabelForm{}), repo.UpdateLabel)
 			r.Post("/labels/delete", repo.DeleteLabel)
@@ -262,6 +254,13 @@ func runWeb(*cli.Context) {
 		r.Get("/releases/edit/:tagname", repo.EditRelease)
 	}, 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) {
 		r.Post("/releases/new", bindIgnErr(auth.NewReleaseForm{}), repo.NewReleasePost)
 		r.Post("/releases/edit/:tagname", bindIgnErr(auth.EditReleaseForm{}), repo.EditReleasePost)

+ 25 - 0
public/css/gogs.css

@@ -1794,4 +1794,29 @@ body {
     color: #444;
     font-weight: bold;
     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;
 }

+ 55 - 0
public/js/app.js

@@ -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() {
         var $attached = $("#attached");
         var $attachments = $("input[name=attachments]");

+ 38 - 8
routers/repo/issue.go

@@ -709,6 +709,12 @@ func Comment(ctx *middleware.Context, params martini.Params) {
 	attachments := strings.Split(params["attachments"], ",")
 
 	for _, a := range attachments {
+		a = strings.Trim(a, " ")
+
+		if len(a) == 0 {
+			continue
+		}
+
 		aId, err := base.StrTo(a).Int64()
 
 		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) {
-	issueId, _ := base.StrTo(params["index"]).Int64()
+	index, _ := base.StrTo(params["index"]).Int64()
 
-	if issueId == 0 {
+	if index == 0 {
 		ctx.JSON(400, map[string]interface{}{
 			"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
@@ -1089,7 +1106,7 @@ func IssuePostAttachment(ctx *middleware.Context, params martini.Params) {
 		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 {
 		ctx.JSON(500, map[string]interface{}{
@@ -1121,16 +1138,29 @@ func IssueGetAttachment(ctx *middleware.Context, params martini.Params) {
 		return
 	}
 
+	log.Error("path=%s name=%s", attachment.Path, attachment.Name)
+
 	ctx.ServeFile(attachment.Path, attachment.Name)
 }
 
 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{}{
 			"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
@@ -1189,7 +1219,7 @@ func IssueDeleteAttachment(ctx *middleware.Context, params martini.Params) {
 		return
 	}
 
-	if attachment.IssueId != issueId {
+	if attachment.IssueId != issue.Id {
 		ctx.JSON(400, map[string]interface{}{
 			"ok":    false,
 			"error": "attachment not associated with the given issue",

+ 20 - 8
templates/repo/issue/view.tmpl

@@ -45,13 +45,19 @@
                                         <div class="tab-pane issue-preview-content" id="issue-edit-preview">Loading...</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>
                     {{range .Comments}}
                     {{/* 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE, 4 = COMMIT, 5 = PULL */}}
@@ -68,11 +74,17 @@
                             <div class="panel-body markdown">
                                 {{str2html .Content}}
                             </div>
+                            {{with $attachments := .Attachments}}
+                            {{if $attachments}}
                             <div class="attachments">
-                                {{range .Attachments}}
-                                <a class="attachment" href="{{.IssueId}}/attachment/{{.Id}}">{{.Name}}</a>
+                                <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>
                     {{else if eq .Type 1}}