Delete comments functionality
parent
576ac5074f
commit
f326d6f12e
|
@ -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()
|
||||
|
||||
|
|
|
@ -130,5 +130,6 @@ module.run([
|
|||
"$tgSearchResourcesProvider",
|
||||
"$tgAttachmentsResourcesProvider",
|
||||
"$tgMdRenderResourcesProvider",
|
||||
"$tgHistoryResourcesProvider",
|
||||
initResources
|
||||
])
|
||||
|
|
|
@ -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])
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue