Delete comments functionality

stable
Jesús Espino 2014-09-11 17:55:34 +02:00 committed by Andrey Antukh
parent 576ac5074f
commit f326d6f12e
5 changed files with 198 additions and 32 deletions

View File

@ -32,19 +32,16 @@ module = angular.module("taigaCommon")
class HistoryController extends taiga.Controller
@.$inject = ["$scope", "$tgRepo"]
@.$inject = ["$scope", "$tgRepo", "$tgResources"]
constructor: (@scope, @repo) ->
constructor: (@scope, @repo, @rs) ->
initialize: (type, objectId) ->
@.type = type
@.objectId = objectId
getHistory: (type, objectId) ->
return @repo.queryOneRaw("history/#{type}", objectId)
loadHistory: ->
return @.getHistory(@.type, @.objectId).then (history) =>
loadHistory: (type, objectId) ->
return @rs.history.get(type, objectId).then (history) =>
for historyResult in history
# If description was modified take only the description_html field
if historyResult.values_diff.description_diff?
@ -56,6 +53,12 @@ class HistoryController extends taiga.Controller
@scope.history = history
@scope.comments = _.filter(history, (item) -> item.comment != "")
deleteComment: (type, objectId, activityId) ->
return @rs.history.deleteComment(type, objectId, activityId).then => @.loadHistory(type, objectId)
undeleteComment: (type, objectId, activityId) ->
return @rs.history.undeleteComment(type, objectId, activityId).then => @.loadHistory(type, objectId)
HistoryDirective = ($log) ->
templateChangeDiff = _.template("""
@ -128,6 +131,21 @@ HistoryDirective = ($log) ->
</div>
""")
templateDeletedComment = _.template("""
<div class="activity-single comment deleted-comment">
<div>
<span>Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %></span>
<a href="" title="Show comment" class="show-deleted-comment">(Show deleted comment)</a>
<a href="" title="Show comment" class="hide-deleted-comment hidden">(Hide deleted comment)</a>
<div class="comment-body wysiwyg"><%= deleteComment %></div>
</div>
<a href="" class="comment-restore" data-activity-id="<%- activityId %>">
<span class="icon icon-reload"></span>
<span>Restore comment</span>
</a>
</div>
""")
templateActivity = _.template("""
<div class="activity-single <%- mode %>">
<div class="activity-user">
@ -146,9 +164,17 @@ HistoryDirective = ($log) ->
</div>
<% if (comment.length > 0) { %>
<div class="comment wysiwyg">
<%= comment %>
</div>
<% if ((deleteCommentDate || deleteCommentUser)) { %>
<div class="deleted-comment">
<span>Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %></span>
</div>
<% } %>
<div class="comment wysiwyg">
<%= comment %>
</div>
<% if (!deleteCommentDate && mode !== "activity") { %>
<a href="" class="icon icon-delete comment-delete" data-activity-id="<%- activityId %>"></a>
<% } %>
<% } %>
<% if(changes.length > 0) { %>
@ -170,6 +196,7 @@ HistoryDirective = ($log) ->
""")
templateBaseEntries = _.template("""
<% if (showMore > 0) { %>
<a href="" title="Show more" class="show-more show-more-comments">
+ Show previous entries (<%- showMore %> more)
@ -226,7 +253,7 @@ HistoryDirective = ($log) ->
objectId = model.id
$ctrl.initialize(type, objectId)
$ctrl.loadHistory()
$ctrl.loadHistory(type, objectId)
# Helpers
getHumanizedFieldName = (field) ->
@ -332,6 +359,14 @@ HistoryDirective = ($log) ->
return "Made #{size} changes" # TODO: i18n
renderComment = (comment) ->
if (comment.delete_comment_date or comment.delete_comment_user)
return templateDeletedComment({
deleteCommentDate: moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm")
deleteCommentUser: getUserFullName(comment.delete_comment_user)
deleteComment: comment.comment_html
activityId: comment.id
})
return templateActivity({
avatar: getUserAvatar(comment.user.pk)
userFullName: getUserFullName(comment.user.pk)
@ -340,6 +375,9 @@ HistoryDirective = ($log) ->
changesText: renderChangesHelperText(comment)
changes: renderChangeEntries(comment, false)
mode: "comment"
deleteCommentDate: moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm") if comment.delete_comment_date
deleteCommentUser: getUserFullName(comment.delete_comment_user) if comment.delete_comment_user
activityId: comment.id
})
renderChange = (change) ->
@ -351,6 +389,9 @@ HistoryDirective = ($log) ->
changes: renderChangeEntries(change, false)
changesText: ""
mode: "activity"
deleteCommentDate: moment(change.delete_comment_date).format("DD MMM YYYY HH:mm") if change.delete_comment_date
deleteCommentUser: getUserFullName(change.delete_comment_user) if change.delete_comment_user
activityId: change.id
})
renderHistory = (entries, totalEntries) ->
@ -388,7 +429,7 @@ HistoryDirective = ($log) ->
$scope.$watch("comments", renderComments)
$scope.$watch("history", renderActivity)
$scope.$on("history:reload", -> $ctrl.loadHistory())
$scope.$on("history:reload", -> $ctrl.loadHistory(type, objectId))
# Events
@ -397,7 +438,7 @@ HistoryDirective = ($log) ->
$el.find(".comment-list").addClass("activeanimation")
onSuccess = ->
$ctrl.loadHistory()
$ctrl.loadHistory(type, objectId)
onError = ->
$confirm.notify("error")
@ -416,6 +457,20 @@ HistoryDirective = ($log) ->
showAllComments = not showAllComments
renderComments()
$el.on "click", ".show-deleted-comment", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
target.parents('.activity-single').find('.hide-deleted-comment').show()
target.parents('.activity-single').find('.show-deleted-comment').hide()
target.parents('.activity-single').find('.comment-body').show()
$el.on "click", ".hide-deleted-comment", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
target.parents('.activity-single').find('.hide-deleted-comment').hide()
target.parents('.activity-single').find('.show-deleted-comment').show()
target.parents('.activity-single').find('.comment-body').hide()
$el.on "click", ".changes-title", (event) ->
event.preventDefault()
target = angular.element(event.currentTarget)
@ -428,6 +483,16 @@ HistoryDirective = ($log) ->
$el.find(".history-tabs li a").toggleClass("active")
$el.find(".history section").toggleClass("hidden")
$el.on "click", ".comment-delete", (event) ->
target = angular.element(event.currentTarget)
activityId = target.data('activity-id')
$ctrl.deleteComment(type, objectId, activityId)
$el.on "click", ".comment-restore", (event) ->
target = angular.element(event.currentTarget)
activityId = target.data('activity-id')
$ctrl.undeleteComment(type, objectId, activityId)
$scope.$on "$destroy", ->
$el.off()

View File

@ -130,5 +130,6 @@ module.run([
"$tgSearchResourcesProvider",
"$tgAttachmentsResourcesProvider",
"$tgMdRenderResourcesProvider",
"$tgHistoryResourcesProvider",
initResources
])

View File

@ -0,0 +1,50 @@
###
# Copyright (C) 2014 Andrey Antukh <niwi@niwi.be>
# Copyright (C) 2014 Jesús Espino Garcia <jespinog@gmail.com>
# Copyright (C) 2014 David Barragán Merino <bameda@dbarragan.com>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# File: modules/resources/history.coffee
###
taiga = @.taiga
resourceProvider = ($repo, $http, $urls) ->
service = {}
service.get = (type, objectId) ->
return $repo.queryOneRaw("history/#{type}", objectId)
service.deleteComment = (type, objectId, activityId) ->
url = $urls.resolve("history/#{type}")
url = "#{url}/#{objectId}/delete_comment"
params = {id: activityId}
return $http.post(url, null, params).then (data) =>
return data.data
service.undeleteComment = (type, objectId, activityId) ->
url = $urls.resolve("history/#{type}")
url = "#{url}/#{objectId}/undelete_comment"
params = {id: activityId}
return $http.post(url, null, params).then (data) =>
return data.data
return (instance) ->
instance.history = service
module = angular.module("taigaResources")
module.factory("$tgHistoryResourcesProvider", ["$tgRepo", "$tgHttp", "$tgUrls", resourceProvider])

View File

@ -4,7 +4,7 @@ $black: #000;
$blackish: #050505;
$gray: #555;
$grayer: #444;
$gray-light: #cdcdcd;
$gray-light: #b8b8b8;
$whitish: #f5f5f5;
$very-light-gray: #fcfcfc;
$white: #fff;

View File

@ -2,26 +2,23 @@
margin-bottom: 1rem;
padding: 0 1rem;
}
.changes-title {
display: block;
padding: .5rem;
&:hover {
.icon {
@include transform(rotate(180deg));
@include transition(all.2s linear);
@include transition(all .2s linear);
color: $green-taiga;
}
}
.icon {
@include transform(rotate(0));
@include transition(all.2s linear);
@include transition(all .2s linear);
color: $grayer;
float: right;
}
}
.change-entry {
@include table-flex;
border-bottom: 1px solid $gray-light;
@ -40,7 +37,6 @@
@extend %small;
}
}
.history-tabs {
@extend %title;
border-bottom: 3px solid $gray-light;
@ -68,7 +64,6 @@
margin-right: .5rem;
}
}
.add-comment {
@include clearfix;
textarea {
@ -94,7 +89,6 @@
}
}
}
a.show-more-comments {
@extend %small;
border-bottom: 1px solid $gray-light;
@ -107,7 +101,6 @@ a.show-more-comments {
background: lighten($green-taiga, 60%);
}
}
.more-comments {
@extend %small;
border-bottom: 1px solid $gray-light;
@ -119,7 +112,6 @@ a.show-more-comments {
margin-left: .5rem;
}
}
.comment-list {
&.activeanimation {
.comment-single.ng-enter:last-child,
@ -136,15 +128,66 @@ a.show-more-comments {
}
}
}
.activity-single {
@include table-flex;
border-bottom: 2px solid $gray-light;
border-bottom: 1px solid $gray-light;
padding: 2rem 0;
position: relative;
&:hover {
.comment-delete {
@include transition(opacity .2s linear);
opacity: 1;
}
.comment-restore {
@include transition(opacity .2s linear);
opacity: 1;
}
}
&:first-child {
margin-top: 0;
}
&:last-child {
border-bottom: 0;
}
&.deleted-comment,
.deleted-comment {
@extend %small;
color: $gray-light;
padding: .5rem;
a {
color: $gray-light;
margin-left: .3rem;
&:hover {
@include transition(color .2s linear);
color: $green-taiga;
}
}
img {
@include filter(grayscale(100%));
opacity: .5;
}
.comment-body {
display: none;
margin: .2rem 0 .5rem;
p {
@extend %medium;
}
}
}
.comment-restore {
@extend %small;
color: $gray-light;
position: absolute;
right: 0;
top: .4rem;
.icon {
vertical-align: baseline;
}
&:hover {
@include transition(color .2s linear);
color: $green-taiga;
}
}
.username {
color: $green-taiga;
margin-bottom: .5rem;
@ -158,18 +201,16 @@ a.show-more-comments {
}
.activity-username {
color: $green-taiga;
margin-bottom: 1rem;
margin-bottom: .5rem;
}
.activity-content {
@include table-flex-child(20, 150px, 0);
}
.changes {
background: $whitish;
.change-entry {
display: none;
&.active {
display: flex;
}
@ -180,18 +221,27 @@ a.show-more-comments {
color: $gray-light;
margin-left: 1rem;
}
.wysiwyg {
margin-bottom: 0;
}
.comment-delete {
@include transition(all .2s linear);
color: $red;
opacity: 0;
position: absolute;
right: 0;
top: 2rem;
&:hover {
@include transition(color .2s linear);
color: $red-light;
}
}
&.activity {
.change-entry {
display: flex;
}
}
}
.more-activity {
@extend %small;
border-bottom: 1px solid $gray-light;