[Notice] Announcing the End of Demo Server [Read me]

`Agree` buttons on each comment are added.
Cause: There is a VOC. It needs a function that agrees with comments. Solution: `Agree` buttons which like heart shape are added on each comments. Private-issue: 1035
@75484d64f03ea3fc81204d984cefe4d9b1b71f9e
--- app/assets/stylesheets/less/_page.less
+++ app/assets/stylesheets/less/_page.less
... | ... | @@ -2754,6 +2754,26 @@ |
2754 | 2754 |
color:@yobi-link; |
2755 | 2755 |
.opacity(100); |
2756 | 2756 |
} |
2757 |
+ |
|
2758 |
+ &.vote-heart-disable-hover:hover { |
|
2759 |
+ color:initial; |
|
2760 |
+ opacity:0.2; |
|
2761 |
+ font-size:16px; |
|
2762 |
+ } |
|
2763 |
+ } |
|
2764 |
+ |
|
2765 |
+ .vote-description-people { |
|
2766 |
+ color:#3b5998 |
|
2767 |
+ } |
|
2768 |
+ |
|
2769 |
+ .vote-heart-on { |
|
2770 |
+ font-size:16px; |
|
2771 |
+ color:@yobi-link; |
|
2772 |
+ opacity:1.0; |
|
2773 |
+ } |
|
2774 |
+ |
|
2775 |
+ .vote-heart-off { |
|
2776 |
+ font-size:16px; |
|
2757 | 2777 |
} |
2758 | 2778 |
} |
2759 | 2779 |
|
--- app/assets/stylesheets/less/_yobiUI.less
+++ app/assets/stylesheets/less/_yobiUI.less
... | ... | @@ -1126,6 +1126,14 @@ |
1126 | 1126 |
outline:none; |
1127 | 1127 |
} |
1128 | 1128 |
|
1129 |
+.btn-transparent-with-fontsize-lineheight { |
|
1130 |
+ background:transparent; |
|
1131 |
+ border:0; |
|
1132 |
+ outline:none; |
|
1133 |
+ font-size:0px; |
|
1134 |
+ line-height:normal; |
|
1135 |
+} |
|
1136 |
+ |
|
1129 | 1137 |
.numberic { |
1130 | 1138 |
display:inline-block; |
1131 | 1139 |
margin-left:5px; |
--- app/controllers/VoteApp.java
+++ app/controllers/VoteApp.java
... | ... | @@ -20,8 +20,13 @@ |
20 | 20 |
*/ |
21 | 21 |
package controllers; |
22 | 22 |
|
23 |
+import controllers.annotation.IsAllowed; |
|
23 | 24 |
import models.Issue; |
25 |
+import models.IssueComment; |
|
24 | 26 |
import models.User; |
27 |
+import models.enumeration.Operation; |
|
28 |
+import org.codehaus.jackson.node.ObjectNode; |
|
29 |
+import play.libs.Json; |
|
25 | 30 |
import play.mvc.Call; |
26 | 31 |
import play.mvc.With; |
27 | 32 |
import models.Project; |
... | ... | @@ -31,6 +36,8 @@ |
31 | 36 |
import actions.AnonymousCheckAction; |
32 | 37 |
import models.enumeration.ResourceType; |
33 | 38 |
import controllers.annotation.IsCreatable; |
39 |
+import utils.Constants; |
|
40 |
+import utils.RouteUtil; |
|
34 | 41 |
|
35 | 42 |
import java.util.ArrayList; |
36 | 43 |
import java.util.List; |
... | ... | @@ -52,7 +59,8 @@ |
52 | 59 |
* @return |
53 | 60 |
*/ |
54 | 61 |
@Transactional |
55 |
- @IsCreatable(ResourceType.ISSUE_COMMENT) |
|
62 |
+ @With(AnonymousCheckAction.class) |
|
63 |
+ @IsAllowed(Operation.READ) |
|
56 | 64 |
public static Result vote(String ownerName, String projectName, Long issueNumber) { |
57 | 65 |
|
58 | 66 |
Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
... | ... | @@ -76,7 +84,8 @@ |
76 | 84 |
* @return |
77 | 85 |
*/ |
78 | 86 |
@Transactional |
79 |
- @IsCreatable(ResourceType.ISSUE_COMMENT) |
|
87 |
+ @With(AnonymousCheckAction.class) |
|
88 |
+ @IsAllowed(Operation.READ) |
|
80 | 89 |
public static Result unvote(String ownerName, String projectName, Long issueNumber) { |
81 | 90 |
Project project = Project.findByOwnerAndProjectName(ownerName, projectName); |
82 | 91 |
Issue issue = Issue.findByNumber(project, issueNumber); |
... | ... | @@ -88,6 +97,38 @@ |
88 | 97 |
return redirect(call); |
89 | 98 |
} |
90 | 99 |
|
100 |
+ @Transactional |
|
101 |
+ @With(AnonymousCheckAction.class) |
|
102 |
+ @IsAllowed(Operation.READ) |
|
103 |
+ public static Result voteComment(String user, String project, Long number, Long commentId) { |
|
104 |
+ IssueComment issueComment = IssueComment.find.byId(commentId); |
|
105 |
+ if (issueComment == null) { |
|
106 |
+ return notFound("issue.comment.error.vote"); |
|
107 |
+ } |
|
108 |
+ |
|
109 |
+ issueComment.addVoter(UserApp.currentUser()); |
|
110 |
+ |
|
111 |
+ return redirect(RouteUtil.getUrl(issueComment)); |
|
112 |
+ } |
|
113 |
+ |
|
114 |
+ @Transactional |
|
115 |
+ @With(AnonymousCheckAction.class) |
|
116 |
+ @IsAllowed(Operation.READ) |
|
117 |
+ public static Result unvoteComment(String user, String project, Long number, Long commentId) { |
|
118 |
+ IssueComment issueComment = IssueComment.find.byId(commentId); |
|
119 |
+ if (issueComment == null) { |
|
120 |
+ return notFound("issue.comment.error.unvote"); |
|
121 |
+ } |
|
122 |
+ |
|
123 |
+ if (!issueComment.voters.contains(UserApp.currentUser())) { |
|
124 |
+ return notFound("issue.comment.error.have.not.voted"); |
|
125 |
+ } |
|
126 |
+ |
|
127 |
+ issueComment.removeVoter(UserApp.currentUser()); |
|
128 |
+ |
|
129 |
+ return redirect(RouteUtil.getUrl(issueComment)); |
|
130 |
+ } |
|
131 |
+ |
|
91 | 132 |
public static List<User> getVotersForAvatar(List<User> voters, int size){ |
92 | 133 |
return getSubList(voters, 0, size); |
93 | 134 |
} |
--- app/models/IssueComment.java
+++ app/models/IssueComment.java
... | ... | @@ -22,10 +22,9 @@ |
22 | 22 |
|
23 | 23 |
import models.enumeration.ResourceType; |
24 | 24 |
import models.resource.Resource; |
25 |
-import org.apache.commons.lang3.builder.EqualsBuilder; |
|
26 |
-import org.apache.commons.lang3.builder.HashCodeBuilder; |
|
27 | 25 |
|
28 | 26 |
import javax.persistence.*; |
27 |
+import java.util.List; |
|
29 | 28 |
|
30 | 29 |
@Entity |
31 | 30 |
public class IssueComment extends Comment { |
... | ... | @@ -34,6 +33,14 @@ |
34 | 33 |
|
35 | 34 |
@ManyToOne |
36 | 35 |
public Issue issue; |
36 |
+ |
|
37 |
+ @ManyToMany(cascade = CascadeType.ALL) |
|
38 |
+ @JoinTable( |
|
39 |
+ name = "issue_comment_voter", |
|
40 |
+ joinColumns = @JoinColumn(name = "issue_comment_id"), |
|
41 |
+ inverseJoinColumns = @JoinColumn(name = "user_id") |
|
42 |
+ ) |
|
43 |
+ public List<User> voters; |
|
37 | 44 |
|
38 | 45 |
/** |
39 | 46 |
* @see Comment#getParent() |
... | ... | @@ -69,4 +76,18 @@ |
69 | 76 |
} |
70 | 77 |
}; |
71 | 78 |
} |
79 |
+ |
|
80 |
+ public void addVoter(User user) { |
|
81 |
+ if (!this.voters.contains(user)) { |
|
82 |
+ this.voters.add(user); |
|
83 |
+ this.update(); |
|
84 |
+ } |
|
85 |
+ } |
|
86 |
+ |
|
87 |
+ public void removeVoter(User user) { |
|
88 |
+ if (this.voters.contains(user)) { |
|
89 |
+ this.voters.remove(user); |
|
90 |
+ this.update(); |
|
91 |
+ } |
|
92 |
+ } |
|
72 | 93 |
} |
--- app/views/issue/partial_comments.scala.html
+++ app/views/issue/partial_comments.scala.html
... | ... | @@ -63,6 +63,8 @@ |
63 | 63 |
<strong>@Messages("code.commits") <a href="@routes.CodeHistoryApp.show(project.owner, project.name, commitId)" class="link">@{"@"}@commitId</a></strong> |
64 | 64 |
} |
65 | 65 |
|
66 |
+@VOTER_AVATAR_SHOW_LIMIT = @{ 5 } |
|
67 |
+ |
|
66 | 68 |
<div class="comment-header"><i class="yobicon-comments"></i> <strong>@Messages("common.comment")</strong> <strong class="num">@issue.comments.size</strong></div> |
67 | 69 |
<hr class="nm"> |
68 | 70 |
|
... | ... | @@ -86,12 +88,54 @@ |
86 | 88 |
</span> |
87 | 89 |
<a href="#comment-@comment.id" class="ago" title="@JodaDateUtil.getDateString(comment.createdDate)">@utils.TemplateHelper.agoOrDateString(comment.createdDate)</a> |
88 | 90 |
<span class="act-row pull-right"> |
91 |
+ @if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.READ) && comment.isInstanceOf[IssueComment]) { |
|
92 |
+ @defining(comment.asInstanceOf[IssueComment]) { issueComment => |
|
93 |
+ @if(issueComment.voters.size > VOTER_AVATAR_SHOW_LIMIT) { |
|
94 |
+ <span style="margin-right:2px;" data-toggle="tooltip" data-html="true" title=" |
|
95 |
+ @for(voter <- VoteApp.getVotersForName(issueComment.voters, 0, 5)) { |
|
96 |
+ @voter.name<br> |
|
97 |
+ } |
|
98 |
+ …"> |
|
99 |
+ <a class="vote-description-people" href="#voters-@issueComment.id" data-toggle="modal"> |
|
100 |
+ @if(issueComment.voters.size == 1) { |
|
101 |
+ @Messages("common.comment.vote.agreement", issueComment.voters.size) |
|
102 |
+ } else { |
|
103 |
+ @Messages("common.comment.vote.agreements", issueComment.voters.size) |
|
104 |
+ } |
|
105 |
+ </a> |
|
106 |
+ </span> |
|
107 |
+ |
|
108 |
+ @partial_voter_list("voters-" + issueComment.id, issueComment.voters) |
|
109 |
+ } else { |
|
110 |
+ @for(voter <- issueComment.voters){ |
|
111 |
+ <a href="@routes.UserApp.userInfo(voter.loginId)" class="avatar-wrap smaller" data-toggle="tooltip" data-placement="top" title="@voter.name" style="margin-right:3px;"> |
|
112 |
+ <img src="@User.findByLoginId(voter.loginId).avatarUrl"> |
|
113 |
+ </a> |
|
114 |
+ } |
|
115 |
+ } |
|
116 |
+ |
|
117 |
+ @if(issueComment.voters.contains(UserApp.currentUser())) { |
|
118 |
+ <button type="button" class="btn-transparent-with-fontsize-lineheight" title="@Messages("common.comment.vote")" data-request-type="comment-vote" data-request-uri="@routes.VoteApp.unvoteComment(project.owner, project.name, issue.getNumber, comment.id)"> |
|
119 |
+ <i class="yobicon-hearts vote-heart-on"></i> |
|
120 |
+ </button> |
|
121 |
+ } else { |
|
122 |
+ @if(UserApp.currentUser().isAnonymous()) { |
|
123 |
+ <i class="yobicon-hearts vote-heart-off vote-heart-disable-hover"></i> |
|
124 |
+ } else { |
|
125 |
+ <button type="button" class="btn-transparent-with-fontsize-lineheight" title="@Messages("common.comment.vote")" data-request-type="comment-vote" data-request-uri="@routes.VoteApp.voteComment(project.owner, project.name, issue.getNumber, comment.id)"> |
|
126 |
+ <i class="yobicon-hearts vote-heart-off"></i> |
|
127 |
+ </button> |
|
128 |
+ } |
|
129 |
+ } |
|
130 |
+ } |
|
131 |
+ } |
|
132 |
+ |
|
89 | 133 |
@if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.UPDATE)) { |
90 |
- <button type="button" class="btn-transparent mr10" data-toggle="comment-edit" data-comment-id="@comment.id" title="@Messages("common.comment.edit")"><i class="yobicon-edit-2"></i></button> |
|
134 |
+ <button type="button" class="btn-transparent-with-fontsize-lineheight ml10" data-toggle="comment-edit" data-comment-id="@comment.id" title="@Messages("common.comment.edit")"><i class="yobicon-edit-2"></i></button> |
|
91 | 135 |
} |
92 | 136 |
|
93 | 137 |
@if(isAllowed(UserApp.currentUser(), comment.asResource(), Operation.DELETE)) { |
94 |
- <button type="button" class="btn-transparent" data-toggle="comment-delete" data-request-uri="@routes.IssueApp.deleteComment(project.owner, project.name, issue.getNumber, comment.id)" title="@Messages("common.comment.delete")"><i class="yobicon-trash"></i></button> |
|
138 |
+ <button type="button" class="btn-transparent-with-fontsize-lineheight ml10" data-toggle="comment-delete" data-request-uri="@routes.IssueApp.deleteComment(project.owner, project.name, issue.getNumber, comment.id)" title="@Messages("common.comment.delete")"><i class="yobicon-trash"></i></button> |
|
95 | 139 |
} |
96 | 140 |
</span> |
97 | 141 |
</div> |
+++ app/views/issue/partial_voter_list.scala.html
... | ... | @@ -0,0 +1,47 @@ |
1 | +@** | |
2 | +* Yobi, Project Hosting SW | |
3 | +* | |
4 | +* Copyright 2014 NAVER Corp. | |
5 | +* http://yobi.io | |
6 | +* | |
7 | +* @Author Changsung Kim | |
8 | +* | |
9 | +* Licensed under the Apache License, Version 2.0 (the "License"); | |
10 | +* you may not use this file except in compliance with the License. | |
11 | +* You may obtain a copy of the License at | |
12 | +* | |
13 | +* http://www.apache.org/licenses/LICENSE-2.0 | |
14 | +* | |
15 | +* Unless required by applicable law or agreed to in writing, software | |
16 | +* distributed under the License is distributed on an "AS IS" BASIS, | |
17 | +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
18 | +* See the License for the specific language governing permissions and | |
19 | +* limitations under the License. | |
20 | +**@ | |
21 | + | |
22 | +@(id:String, voters:Collection[User]) | |
23 | + | |
24 | +<div id="@id" class="modal hide voters-dialog"> | |
25 | + <div class="modal-header"> | |
26 | + <button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button> | |
27 | + <h5 class="nm">@Messages("issue.voters")</h5> | |
28 | + </div> | |
29 | + <div class="modal-body"> | |
30 | + <ul class="unstyled"> | |
31 | + @for(voter <- voters){ | |
32 | + <li> | |
33 | + <a href="@routes.UserApp.userInfo(voter.loginId)" class="usf-group" target="_blank"> | |
34 | + <span class="avatar-wrap mlarge"> | |
35 | + <img src="@voter.avatarUrl" width="40" height="40"> | |
36 | + </span> | |
37 | + <strong class="name">@voter.name</strong> | |
38 | + <span class="loginid"> <strong>@{"@"}</strong>@voter.loginId</span> | |
39 | + </a> | |
40 | + </li> | |
41 | + } | |
42 | + </ul> | |
43 | + </div> | |
44 | + <div class="modal-footer"> | |
45 | + <button class="ybtn ybtn-info ybtn-small" data-dismiss="modal" aria-hidden="true">@Messages("button.close")</button> | |
46 | + </div> | |
47 | +</div> |
+++ conf/evolutions/default/89.sql
... | ... | @@ -0,0 +1,15 @@ |
1 | +# --- !Ups | |
2 | + | |
3 | +CREATE TABLE issue_comment_voter ( | |
4 | + issue_comment_id BIGINT NOT NULL, | |
5 | + user_id BIGINT NOT NULL, | |
6 | + CONSTRAINT pk_issue_comment_voter PRIMARY KEY (issue_comment_id, user_id)) | |
7 | +; | |
8 | + | |
9 | +ALTER TABLE issue_comment_voter ADD CONSTRAINT fk_issue_comment_voter_issue FOREIGN KEY (issue_comment_id) REFERENCES issue_comment (id) ON DELETE RESTRICT ON UPDATE RESTRICT; | |
10 | +ALTER TABLE issue_comment_voter ADD CONSTRAINT fk_issue_comment_voter_n4user FOREIGN KEY (user_id) REFERENCES n4user (id) ON DELETE RESTRICT ON UPDATE RESTRICT; | |
11 | + | |
12 | + | |
13 | +# --- !Downs | |
14 | + | |
15 | +DROP TABLE IF EXISTS issue_comment_voter; |
--- conf/messages
+++ conf/messages
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 |
button.back = Back |
42 | 42 |
button.cancel = Cancel |
43 | 43 |
button.cancel.enrollment = Cancel sign-up request. |
44 |
+button.close = Close |
|
44 | 45 |
button.comment.new = Add comments. |
45 | 46 |
button.comment.open = Open comment window |
46 | 47 |
button.commentAndNextState.closed = Comment & Close issue |
... | ... | @@ -140,6 +141,9 @@ |
140 | 141 |
common.comment.delete = Delete comment |
141 | 142 |
common.comment.delete.confirm = Once you delete this comment, you won''t be able to recover it. Are you sure you want to delete this comment? |
142 | 143 |
common.comment.edit = Edit comment |
144 |
+common.comment.vote = Agree |
|
145 |
+common.comment.vote.agreement = {0} Agreement |
|
146 |
+common.comment.vote.agreements = {0} Agreements |
|
143 | 147 |
common.editor.edit = Edit |
144 | 148 |
common.editor.preview = Preview |
145 | 149 |
common.experimental = Experimental function |
... | ... | @@ -221,6 +225,9 @@ |
221 | 225 |
issue.can.not.be.deleted = Failed to delete because of other users'' comments |
222 | 226 |
issue.comment.delete.confirm = Once you delete this comment, you won''t be able to recover this again. Do you still want to delete it? |
223 | 227 |
issue.comment.delete.window = Delete issue comment |
228 |
+issue.comment.error.vote = Failed to agree with the comment because server error has occurred. |
|
229 |
+issue.comment.error.unvote = Failed to disagree with the comment because server error has occurred. |
|
230 |
+issue.comment.error.have.not.voted = Failed to disagree with the comment because you have not voted this. |
|
224 | 231 |
issue.createdDate = Created date |
225 | 232 |
issue.delete = Delete issue |
226 | 233 |
issue.downloadAsExcel = Download as Excel file |
... | ... | @@ -256,7 +263,7 @@ |
256 | 263 |
issue.state.closed = Closed |
257 | 264 |
issue.state.enrolled = Status entered |
258 | 265 |
issue.state.open = In progress |
259 |
-issue.unvote.description = Click here if you no longer sympathize with this issue. |
|
266 |
+issue.unvote.description = Click here if you no longer agree with this issue. |
|
260 | 267 |
issue.unwatch.start = You will no longer get notifications about this issue |
261 | 268 |
issue.update.assignee.id = Update assignee |
262 | 269 |
issue.update.attachLabel = Attach label |
... | ... | @@ -266,8 +273,8 @@ |
266 | 273 |
issue.update.milestone.id = Update milestone |
267 | 274 |
issue.update.state = Update status |
268 | 275 |
issue.vote = Agree |
269 |
-issue.vote.description = Click here if you sympathize with this issue. |
|
270 |
-issue.voters = People who feels sympathies with this |
|
276 |
+issue.vote.description = Click here if you agree with this issue. |
|
277 |
+issue.voters = People who agree with this |
|
271 | 278 |
issue.voters.more = and {0} others |
272 | 279 |
issue.watch.start =Now you will get notifications about this issue |
273 | 280 |
label = Label |
--- conf/messages.ko
+++ conf/messages.ko
... | ... | @@ -41,6 +41,7 @@ |
41 | 41 |
button.back = λμκ°κΈ° |
42 | 42 |
button.cancel = μ·¨μ |
43 | 43 |
button.cancel.enrollment = λ©€λ² λ±λ‘ μμ² μ·¨μνκΈ° |
44 |
+button.close = λ«κΈ° |
|
44 | 45 |
button.comment.new = λκΈ μ λ ₯ |
45 | 46 |
button.comment.open = λκΈ μ λ ₯ μ°½ μ΄κΈ° |
46 | 47 |
button.commentAndNextState.closed = λκΈ μ λ ₯νκ³ μ΄μ λ«κΈ° |
... | ... | @@ -140,6 +141,9 @@ |
140 | 141 |
common.comment.delete = λκΈ μμ |
141 | 142 |
common.comment.delete.confirm = ν΄λΉ λκΈμ΄ μμ λλ©΄ μμν 볡ꡬν μ μμ΅λλ€. κ·Έλλ μμ νμκ² μ΅λκΉ? |
142 | 143 |
common.comment.edit = λκΈ μμ |
144 |
+common.comment.vote = κ³΅κ° |
|
145 |
+common.comment.vote.agreement = {0} κ³΅κ° |
|
146 |
+common.comment.vote.agreements = {0} κ³΅κ° |
|
143 | 147 |
common.editor.edit = νΈμ§ |
144 | 148 |
common.editor.preview = 미리보기 |
145 | 149 |
common.experimental = μ€νμ μΈ κΈ°λ₯ |
... | ... | @@ -222,6 +226,9 @@ |
222 | 226 |
issue.can.not.be.deleted = λ€λ₯Έ μ¬μ©μμ λκΈμ΄ μμ΄ μμ ν μ μμ΅λλ€. |
223 | 227 |
issue.comment.delete.confirm = ν΄λΉ μ΄μμ λκΈμ μμ νμκ² μ΅λκΉ? |
224 | 228 |
issue.comment.delete.window = μ΄μ λκΈ μμ |
229 |
+issue.comment.error.vote = μλ² μ€λ₯κ° λ°μνμ¬ λκΈμ 곡κ°μ ν μ μμ΅λλ€. |
|
230 |
+issue.comment.error.unvote = μλ² μ€λ₯κ° λ°μνμ¬ λκΈμ κ³΅κ° μ·¨μλ₯Ό ν μ μμ΅λλ€. |
|
231 |
+issue.comment.error.have.not.voted = μ΄ λκΈμ 곡κ°νμ§ μμμ κ³΅κ° μ·¨μλ₯Ό ν μ μμ΅λλ€. |
|
225 | 232 |
issue.createdDate = μμ±μΌ |
226 | 233 |
issue.delete = μ΄μ μμ |
227 | 234 |
issue.downloadAsExcel = μμ νμΌλ‘ λ€μ΄λ°κΈ° |
--- conf/routes
+++ conf/routes
... | ... | @@ -281,6 +281,8 @@ |
281 | 281 |
# Vote |
282 | 282 |
POST /:user/:project/issue/:number/vote controllers.VoteApp.vote(user, project, number: Long) |
283 | 283 |
POST /:user/:project/issue/:number/unvote controllers.VoteApp.unvote(user, project, number: Long) |
284 |
+POST /:user/:project/issue/:number/comment/:commentId/vote controllers.VoteApp.voteComment(user, project, number: Long, commentId: Long) |
|
285 |
+POST /:user/:project/issue/:number/comment/:commentId/unvote controllers.VoteApp.unvoteComment(user, project, number: Long, commentId: Long) |
|
284 | 286 |
|
285 | 287 |
# Comment Thread |
286 | 288 |
POST /threads/:id/open controllers.CommentThreadApp.open(id: Long) |
--- docs/ko/technical/access-control.md
+++ docs/ko/technical/access-control.md
... | ... | @@ -18,7 +18,14 @@ |
18 | 18 |
* λ©€λ²: μ μ₯μ μμ (μ΄ κΈ°λ₯μ μμ§ μλ€)λ₯Ό μ μΈν λͺ¨λ κΆν |
19 | 19 |
* κ·Έ μΈμ λͺ¨λ μ¬μ©μ: λͺ¨λ μ½κΈ° κΆν |
20 | 20 |
|
21 |
-μ΄μ, κ²μν |
|
21 |
+μ΄μ |
|
22 |
+--- |
|
23 |
+ |
|
24 |
+* λ©€λ²: λͺ¨λ κΆν |
|
25 |
+* λ‘κ·ΈμΈ μ¬μ©μ: λͺ¨λ μ½κΈ° κΆν, κ²μλ¬Ό/λκΈ λ±λ‘, κ²μλ¬Ό/λκΈ κ³΅κ° |
|
26 |
+* λΉλ‘κ·ΈμΈ μ¬μ©μ: λͺ¨λ μ½κΈ° κΆν |
|
27 |
+ |
|
28 |
+κ²μν |
|
22 | 29 |
------------ |
23 | 30 |
|
24 | 31 |
* λ©€λ²: λͺ¨λ κΆν |
--- public/javascripts/service/yobi.issue.View.js
+++ public/javascripts/service/yobi.issue.View.js
... | ... | @@ -50,7 +50,7 @@ |
50 | 50 |
* |
51 | 51 |
* @private |
52 | 52 |
*/ |
53 |
- function _initElement(){ |
|
53 |
+ function _initElement(options){ |
|
54 | 54 |
elements.uploader = $("#upload"); |
55 | 55 |
elements.textarea = $('textarea[data-editor-mode="comment-body"]'); |
56 | 56 |
|
... | ... | @@ -61,6 +61,8 @@ |
61 | 61 |
elements.timelineList = elements.timelineWrap.find(".timeline-list"); |
62 | 62 |
|
63 | 63 |
elements.dueDate = $("#issueDueDate"); |
64 |
+ |
|
65 |
+ elements.btnVoteComment = $(options.btnVoteComment || '[data-request-type="comment-vote"]'); |
|
64 | 66 |
} |
65 | 67 |
|
66 | 68 |
/** |
... | ... | @@ -94,6 +96,9 @@ |
94 | 96 |
// Watch button |
95 | 97 |
elements.btnWatch.on("click", _onClickBtnWatch); |
96 | 98 |
|
99 |
+ // Vote button on comment |
|
100 |
+ elements.btnVoteComment.on("click", _onClickCommentVote); |
|
101 |
+ |
|
97 | 102 |
// Update issue info |
98 | 103 |
elements.issueInfoWrap.on("change", "[data-toggle=select2]", _onChangeIssueInfo); |
99 | 104 |
elements.issueInfoWrap.on("change", "[data-toggle=calendar]", _onChangeIssueInfo); |
... | ... | @@ -105,6 +110,18 @@ |
105 | 110 |
}); |
106 | 111 |
} |
107 | 112 |
|
113 |
+ function _onClickCommentVote(){ |
|
114 |
+ $.ajax($(this).data("requestUri"), { |
|
115 |
+ "method" : "post", |
|
116 |
+ "success" : function(){ |
|
117 |
+ location.reload(); |
|
118 |
+ }, |
|
119 |
+ "error" : function(res){ |
|
120 |
+ $yobi.notify(Messages(res.responseText), 3000); |
|
121 |
+ } |
|
122 |
+ }); |
|
123 |
+ } |
|
124 |
+ |
|
108 | 125 |
/** |
109 | 126 |
* "change" event handler of issue info select2 fields. |
110 | 127 |
* |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?