@@ -42,6 +42,7 @@ import java.util.*; | |||
import static com.avaje.ebean.Expr.icontains; | |||
import static controllers.MigrationApp.composePlainCommentsJson; | |||
import static play.libs.Json.toJson; | |||
import static utils.JodaDateUtil.getOptionalShortDate; | |||
public class BoardApp extends AbstractPostingApp { | |||
public static class SearchCondition extends AbstractPostingApp.SearchCondition { | |||
@@ -412,11 +413,28 @@ public class BoardApp extends AbstractPostingApp { | |||
return redirect(routes.BoardApp.post(project.owner, project.name, number)); | |||
} | |||
if(StringUtils.isNotEmpty(comment.parentCommentId)){ | |||
comment.setParentComment(PostingComment.find.byId(Long.valueOf(comment.parentCommentId))); | |||
} | |||
if(posting.comments.size() == 0) { | |||
User user = User.find.byId(posting.authorId); | |||
comment.previousContents = getPrevious("Original issue", posting.body, posting.updatedDate, user.loginId); | |||
} else { | |||
Comment previousComment = posting.comments.get(posting.comments.size() - 1); | |||
User user = User.find.byId(previousComment.authorId); | |||
comment.previousContents = getPrevious("Previous comment", previousComment.contents, previousComment.createdDate, user.loginId); | |||
} | |||
Comment savedComment = saveComment(project, posting, comment); | |||
return redirect(RouteUtil.getUrl(savedComment)); | |||
} | |||
private static String getPrevious(String templateTitle, String contents, Date updatedDate, String authorLoginId) { | |||
return "\n\n<br />\n\n--- " + templateTitle + " from @" + authorLoginId + " " + getOptionalShortDate(updatedDate) + " ---\n\n<br />\n\n" + contents; | |||
} | |||
// Just made for compatibility. No meanings. | |||
public static Result updateComment(String ownerName, String projectName, Long number, Long commentId) throws IOException { | |||
return newComment(ownerName, projectName, number); | |||
@@ -14,6 +14,7 @@ | |||
@import play.libs.Json.toJson | |||
@import utils.Markdown | |||
@import controllers.api.IssueApi | |||
@import models.enumeration.ResourceType | |||
@isAuthorComment(commentId: String) = @{ | |||
if(commentId == UserApp.currentUser().loginId) {"author"} | |||
@@ -26,48 +27,52 @@ | |||
<ul class="comments"> | |||
@for(comment <-post.comments){ | |||
@defining(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.UPDATE)) { isAllowedUpdate => | |||
<li class="comment @isAuthorComment(comment.authorLoginId)" id="comment-@comment.id"> | |||
<div class="comment-avatar"> | |||
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> | |||
<img src="@User.findByLoginId(comment.authorLoginId).avatarUrl(64)" width="32" height="32" alt="@comment.authorLoginId"> | |||
</a> | |||
</div> | |||
<div class="media-body"> | |||
<div class="meta-info"> | |||
<span class="comment_author"> | |||
<span class="resp-comment-avatar"> | |||
<a href="@userInfo(comment.authorLoginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> | |||
<img src="@User.findByLoginId(comment.authorLoginId).avatarUrl(64)" width="32" height="32" alt="@comment.authorName"> | |||
</a> | |||
</span> | |||
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" data-toggle="tooltip" data-placement="top" title="@comment.authorLoginId"><strong>@comment.authorName</strong></a> | |||
</span> | |||
<span class="ago-date"> | |||
<a href="#comment-@comment.id" class="ago" title="@JodaDateUtil.getDateString(comment.createdDate)">@utils.TemplateHelper.agoOrDateString(comment.createdDate)</a> | |||
</span> | |||
<span class="act-row pull-right"> | |||
@if(StringUtils.isNotBlank(IssueApi.TRANSLATION_API)){ | |||
<button type="button" class="icon btn-transparent ml10 comment-translate" data-toggle="tooltip" data-comment-id="@comment.id" title="@Messages("button.translation")"><i class="yobicon-lang"></i></button> | |||
} | |||
@if(comment.getParentComment == null){ | |||
<li class="comment @isAuthorComment(comment.authorLoginId)" id="comment-@comment.id"> | |||
@common.childCommentsAnchorDiv(post, comment) | |||
<div class="comment-avatar"> | |||
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> | |||
<img src="@User.findByLoginId(comment.authorLoginId).avatarUrl(64)" width="32" height="32" alt="@comment.authorLoginId"> | |||
</a> | |||
</div> | |||
<div class="media-body"> | |||
<div class="meta-info"> | |||
<span class="comment_author"> | |||
<span class="resp-comment-avatar"> | |||
<a href="@userInfo(comment.authorLoginId)" class="avatar-wrap" data-toggle="tooltip" data-placement="top" title="@comment.authorName"> | |||
<img src="@User.findByLoginId(comment.authorLoginId).avatarUrl(64)" width="32" height="32" alt="@comment.authorName"> | |||
</a> | |||
</span> | |||
<a href="@routes.UserApp.userInfo(comment.authorLoginId)" data-toggle="tooltip" data-placement="top" title="@comment.authorLoginId"><strong>@comment.authorName</strong></a> | |||
</span> | |||
<span class="ago-date"> | |||
<a href="#comment-@comment.id" class="ago" title="@JodaDateUtil.getDateString(comment.createdDate)">@utils.TemplateHelper.agoOrDateString(comment.createdDate)</a> | |||
</span> | |||
<span class="act-row pull-right"> | |||
@if(StringUtils.isNotBlank(IssueApi.TRANSLATION_API)){ | |||
<button type="button" class="icon btn-transparent ml10 comment-translate" data-toggle="tooltip" data-comment-id="@comment.id" title="@Messages("button.translation")"><i class="yobicon-lang"></i></button> | |||
} | |||
@if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.READ)) { | |||
<button type="button" class="btn-transparent ml10" data-toggle="comment-edit" data-comment-id="@comment.id" title="@Messages("common.comment.edit")"><i class="yobicon-edit-2"></i></button> | |||
} | |||
@if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.DELETE)) { | |||
<button type="button" class="btn-transparent ml6" data-toggle="comment-delete" data-request-uri="@routes.BoardApp.deleteComment(project.owner, project.name, post.getNumber, comment.id)" title="@Messages("common.comment.delete")"><i class="yobicon-trash"></i></button> | |||
} | |||
</span> | |||
</div> | |||
@if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.READ)) { | |||
<button type="button" class="btn-transparent ml10" data-toggle="comment-edit" data-comment-id="@comment.id" title="@Messages("common.comment.edit")"><i class="yobicon-edit-2"></i></button> | |||
} | |||
@if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.DELETE)) { | |||
<button type="button" class="btn-transparent ml6" data-toggle="comment-delete" data-request-uri="@routes.BoardApp.deleteComment(project.owner, project.name, post.getNumber, comment.id)" title="@Messages("common.comment.delete")"><i class="yobicon-trash"></i></button> | |||
} | |||
</span> | |||
</div> | |||
@common.commentUpdateForm(comment, routes.BoardApp.newComment(project.owner, project.name, post.getNumber).toString(), comment.contents, isAllowedUpdate) | |||
@common.commentUpdateForm(comment, routes.BoardApp.newComment(project.owner, project.name, post.getNumber).toString(), comment.contents, isAllowedUpdate) | |||
<div id="comment-body-@comment.id"> | |||
@common.tasklistBar() | |||
<div class="comment-body markdown-wrap" data-via-email="@OriginalEmail.exists(comment.asResource)" data-allowed-update="@isAllowedUpdate" >@Html(Markdown.render(comment.contents, project))</div> | |||
<div class="attachments pull-right" data-attachments="@toJson(AttachmentApp.getFileList(ResourceType.NONISSUE_COMMENT.toString(), comment.id.toString()))"></div> | |||
</div> | |||
</div> | |||
</li> | |||
<div id="comment-body-@comment.id"> | |||
@common.tasklistBar() | |||
<div class="comment-body markdown-wrap" data-via-email="@OriginalEmail.exists(comment.asResource)" data-allowed-update="@isAllowedUpdate" >@Html(Markdown.render(comment.contents, project))</div> | |||
<div class="attachments pull-right" data-attachments="@toJson(AttachmentApp.getFileList(ResourceType.NONISSUE_COMMENT.toString(), comment.id.toString()))"></div> | |||
</div> | |||
</div> | |||
@common.childComments(post, comment, ResourceType.NONISSUE_COMMENT) | |||
</li> | |||
} | |||
} | |||
} | |||
</ul> |
@@ -211,6 +211,7 @@ | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/lib/elevator/jquery.elevator.js")"></script> | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/common/yona.Sha1.js")"></script> | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/common/yona.Tasklist.js")"></script> | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/common/yona.SubComment.js")"></script> | |||
<script type="text/javascript"> | |||
$(document).ready(function(){ | |||
$yobi.loadModule("board.View", { | |||
@@ -464,6 +464,7 @@ | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/service/yona.issue.Sharer.js")"></script> | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/common/yona.Sha1.js")"></script> | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/common/yona.Tasklist.js")"></script> | |||
<script type="text/javascript" src="@routes.Assets.at("javascripts/common/yona.SubComment.js")"></script> | |||
<script type="text/javascript"> | |||
$(function(){ | |||
// yobi.issue.View | |||
@@ -575,53 +576,6 @@ | |||
.addClass($yobi.getContrastColor($this.css('background-color'))) | |||
}); | |||
// Releated with one line sub-comment feature | |||
$(".add-a-comment").on("click", function(e){ | |||
var parent = $(this).parents(".comment"); | |||
// Show input form | |||
parent.find(".child-comment-input-form").toggle(); | |||
parent.find("textarea").on('keypress', function(e) { | |||
// Enter to submit | |||
if ((e.keyCode || e.which) === 13) { | |||
$(this).parents('form').submit(); | |||
return false; | |||
} | |||
}).on('keyup', function(e) { | |||
// Cancel input | |||
if ((e.keyCode || e.which) === 27) { | |||
$(".child-comment-input-form").css("display", "none").css("visibility", "hidden"); | |||
$(".add-a-comment").show(); | |||
} | |||
}).focus(); | |||
}); | |||
$(".comment").on("mouseenter tab", function () { | |||
$(this).find(".add-a-comment").fadeIn(300); | |||
}).on("mouseleave", function () { | |||
$(this).find(".add-a-comment").fadeOut(300); | |||
}); | |||
// Releated with one line sub-comment feature | |||
$(".subcomment-author").each(function addAuthorToLastParagraphOfOnelineComment(index, el){ | |||
// append Author and addtionals to mardkown rendered contents | |||
var $el = $(el); | |||
// Remove spaces | |||
var trimmed = $el.html().replace(/\s\s+/g, ' '); | |||
// Find parent element | |||
var $closest = $el.closest('.contents'); | |||
var normalTextRenderedParagraph = $closest.find('p').last(); | |||
// Remove unused author and addtional text | |||
$el.remove(); | |||
if(normalTextRenderedParagraph.length === 0){ | |||
$closest.append(trimmed); | |||
} else { | |||
normalTextRenderedParagraph.append(trimmed); | |||
} | |||
}); | |||
$.elevator({ | |||
shape: 'rounded', | |||
tooltips: true | |||
@@ -0,0 +1,55 @@ | |||
$(function(){ | |||
// timeline label text color adjusting | |||
$(".event > .label").each(function() { | |||
var $this = $(this); | |||
$this.removeClass("dimgray white") | |||
.addClass($yobi.getContrastColor($this.css('background-color'))) | |||
}); | |||
// Releated with one line sub-comment feature | |||
$(".add-a-comment").on("click", function(e){ | |||
var parent = $(this).parents(".comment"); | |||
// Show input form | |||
parent.find(".child-comment-input-form").toggle(); | |||
parent.find("textarea").on('keypress', function(e) { | |||
// Enter to submit | |||
if ((e.keyCode || e.which) === 13) { | |||
$(this).parents('form').submit(); | |||
return false; | |||
} | |||
}).on('keyup', function(e) { | |||
// Cancel input | |||
if ((e.keyCode || e.which) === 27) { | |||
$(".child-comment-input-form").css("display", "none").css("visibility", "hidden"); | |||
$(".add-a-comment").show(); | |||
} | |||
}).focus(); | |||
}); | |||
$(".comment").on("mouseenter tab", function () { | |||
$(this).find(".add-a-comment").fadeIn(300); | |||
}).on("mouseleave", function () { | |||
$(this).find(".add-a-comment").fadeOut(300); | |||
}); | |||
// Releated with one line sub-comment feature | |||
$(".subcomment-author").each(function addAuthorToLastParagraphOfOnelineComment(index, el){ | |||
// append Author and addtionals to mardkown rendered contents | |||
var $el = $(el); | |||
// Remove spaces | |||
var trimmed = $el.html().replace(/\s\s+/g, ' '); | |||
// Find parent element | |||
var $closest = $el.closest('.contents'); | |||
var normalTextRenderedParagraph = $closest.find('p').last(); | |||
// Remove unused author and addtional text | |||
$el.remove(); | |||
if(normalTextRenderedParagraph.length === 0){ | |||
$closest.append(trimmed); | |||
} else { | |||
normalTextRenderedParagraph.append(trimmed); | |||
} | |||
}); | |||
}); |