From 43e5de7f830a098582b519706f9c5da6eecd2c3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Justin=20Nu=C3=9F?= Date: Thu, 24 Jul 2014 13:50:03 +0200 Subject: [PATCH] Show attachments in issues/comments and add preview for images --- cmd/web.go | 15 +++++----- public/css/gogs.css | 25 ++++++++++++++++ public/js/app.js | 55 ++++++++++++++++++++++++++++++++++ routers/repo/issue.go | 46 +++++++++++++++++++++++----- templates/repo/issue/view.tmpl | 28 ++++++++++++----- 5 files changed, 145 insertions(+), 24 deletions(-) diff --git a/cmd/web.go b/cmd/web.go index 0b7aac33b4..aea0cd86aa 100644 --- a/cmd/web.go +++ b/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) diff --git a/public/css/gogs.css b/public/css/gogs.css index 710d0c20b1..e78d7f940c 100755 --- a/public/css/gogs.css +++ b/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; } \ No newline at end of file diff --git a/public/js/app.js b/public/js/app.js index 16d1d5dab1..3d4ed62362 100644 --- a/public/js/app.js +++ b/public/js/app.js @@ -520,6 +520,61 @@ function initIssue() { }); }()); + // Preview for images. + (function() { + var $hoverElement = $("
"); + var $hoverImage = $(""); + + $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]"); diff --git a/routers/repo/issue.go b/routers/repo/issue.go index 6becb2dff7..903a32d968 100644 --- a/routers/repo/issue.go +++ b/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", diff --git a/templates/repo/issue/view.tmpl b/templates/repo/issue/view.tmpl index a336205415..8c90f312c3 100644 --- a/templates/repo/issue/view.tmpl +++ b/templates/repo/issue/view.tmpl @@ -45,13 +45,19 @@
Loading...
- -
- {{range .Attachments}} - {{.Name}} - {{end}} -
+ + {{with $attachments := .Issue.Attachments}} + {{if $attachments}} +
+ Attachments: + + {{range $attachments}} + {{.Name}} + {{end}} +
+ {{end}} + {{end}} {{range .Comments}} {{/* 0 = COMMENT, 1 = REOPEN, 2 = CLOSE, 3 = ISSUE, 4 = COMMIT, 5 = PULL */}} @@ -68,11 +74,17 @@
{{str2html .Content}}
+ {{with $attachments := .Attachments}} + {{if $attachments}}
- {{range .Attachments}} - {{.Name}} + Attachments: + + {{range $attachments}} + {{.Name}} {{end}}
+ {{end}} + {{end}} {{else if eq .Type 1}}