[#369] project issue page: comments and so on

This commit is contained in:
Alexander Machehin 2014-12-04 22:11:50 +05:00
parent f4c83ac86a
commit 8d9ec48ff9
22 changed files with 271 additions and 106 deletions

View File

@ -0,0 +1,29 @@
commentService = ($http) ->
getPath = (kind, project, commentable, id) ->
if commentable.kind is 'issue'
if kind is 'remove' or kind is 'update'
return Routes.project_issue_comment_path(project, commentable.id, id)
else if kind is 'add'
return Routes.project_issue_comments_path(project, commentable.id)
{
add: (project, commentable, body) ->
path = getPath('add', project, commentable)
params = { comment: { body: body }}
$http.post(path, params)
update: (project, commentable, id) ->
path = getPath('update', project, commentable, id)
params = { comment: { body: $('#comment-'+id+'-body').val() }}
$http.put(path, params)
remove: (project, commentable, id) ->
path = getPath('remove', project, commentable, id)
$http.delete(path)
}
angular
.module("RosaABF")
.factory "Comment", commentService
commentService.$inject = ['$http']

View File

@ -0,0 +1,104 @@
CommentsController = (Comment, Preview, confirmMessage, $compile, $scope) ->
comments_list = $('#comments_list')
vm = this
vm.isDisabledNewCommentButton = ->
vm.processing || vm.new_body is '' || !vm.new_body
vm.previewBody = (id) ->
if id is 'new-comment'
body = vm.new_body
else
body = $('#'+id+'-body').val()
if body is '' or !body
vm.preview_body = ''
return false
if body is Preview.old_text
return false
return false if vm.processing
vm.processing = true
Preview.old_text = ''
promise = Preview.get_preview(vm.project, body)
promise.success( (response) ->
vm.preview_body = response
Preview.old_text = body
).error( (response) ->
vm.preview_body = 'Error :('
)
vm.processing = false
false
vm.toggleEditForm = (id) ->
$('.open-comment').addClass('hidden')
form = $('.open-comment.comment-'+id)
if form.length is 1
form.removeClass('hidden')
true
else
false
vm.add = () ->
new_id = null
vm.processing = true
promise = Comment.add(vm.project, vm.commentable, vm.new_body)
promise.then (response) ->
template = angular.element(response.data)
linkFn = $compile(template)
element = linkFn($scope)
comments_list.append(element)
vm.new_body = ''
new_id = comments_list.find('div.panel.panel-default:last').attr('id')
location.hash = "#" + new_id;
vm.processing = false
false
vm.remove = (id) ->
return false unless confirmMessage.show()
vm.processing = true
promise = Comment.remove(vm.project, vm.commentable, id)
promise.then () ->
$('#comment'+id).remove()
vm.processing = false
false
vm.update = (id) ->
vm.processing = true
promise = Comment.update(vm.project, vm.commentable, id)
promise.then (response) ->
form = $('#comment'+id+ ' .md_and_cm.cm-s-default').html(response.data.body)
vm.processing = false
form = $('.open-comment.comment-'+id)
if form.length is 1
form.addClass('hidden')
return true
else
return false
vm.init = (project, commentable = {}) ->
vm.project = project
vm.commentable = commentable
vm.processing = false
true
angular
.module("RosaABF")
.controller "CommentsController", CommentsController
CommentsController.$inject = [
'Comment'
'Preview'
'confirmMessage'
'$compile'
'$scope'
]

View File

@ -4,7 +4,7 @@ issueService = ($http) ->
{ {
issue: { issue: {
title: $('#issue_title').val() title: $('#issue_title').val()
body: $('#issue_body').val() body: $('#issue-body').val()
} }
} }
else if kind is 'labels' else if kind is 'labels'

View File

@ -34,19 +34,20 @@ IssueController = (dataservice, $http, Issue, $rootScope, Preview, Label, confir
vm = this vm = this
vm.previewBody = -> vm.previewBody = ->
if vm.body is '' or !vm.body body = $('#issue-body').val()
if body is '' or !body
vm.preview_body = '' vm.preview_body = ''
return false return false
if vm.body is Preview.old_text if body is Preview.old_text
return false return false
return false if vm.processing return false if vm.processing
vm.processing = true vm.processing = true
promise = Preview.get_preview(vm.project, vm.body) promise = Preview.get_preview(vm.project, body)
promise.success( (response) -> promise.success( (response) ->
vm.preview_body = response vm.preview_body = response
Preview.old_text = vm.body Preview.old_text = body
).error( (response) -> ).error( (response) ->
vm.preview_body = 'Error :(' vm.preview_body = 'Error :('
) )

View File

@ -8,17 +8,17 @@ class Projects::CommentsController < Projects::BaseController
include CommentsHelper include CommentsHelper
def create def create
anchor = ''
if !@comment.set_additional_data params if !@comment.set_additional_data params
flash[:error] = I18n.t("flash.comment.save_error") render online: I18n.t("flash.comment.save_error"), layout: false
elsif @comment.save elsif @comment.save
flash[:notice] = I18n.t("flash.comment.saved") locals = {
anchor = view_context.comment_anchor(@comment) comment: @comment,
data: { project: @project, commentable: @commentable }
}
render partial: 'projects/comments/comment', locals: locals, layout: false
else else
flash[:error] = I18n.t("flash.comment.save_error") render online: I18n.t("flash.comment.save_error"), layout: false
flash[:warning] = @comment.errors.full_messages.join('. ')
end end
redirect_to "#{project_commentable_path(@project, @commentable)}##{anchor}"
end end
def edit def edit
@ -28,15 +28,14 @@ class Projects::CommentsController < Projects::BaseController
status, message = if @comment.update_attributes(params[:comment]) status, message = if @comment.update_attributes(params[:comment])
[200, view_context.markdown(@comment.body)] [200, view_context.markdown(@comment.body)]
else else
[400, view_context.local_alert(@comment.errors.full_messages.join('. '))] [422, 'error']
end end
render inline: message, status: status render json: {body: message}, status: status
end end
def destroy def destroy
@comment.destroy @comment.destroy
flash[:notice] = t("flash.comment.destroyed") render json: nil
redirect_to project_commentable_path(@project, @commentable)
end end
def new_line def new_line

View File

@ -54,15 +54,21 @@ class CommentPresenter < ApplicationPresenter
def buttons def buttons
project, commentable = options[:project], options[:commentable] project, commentable = options[:project], options[:commentable]
path = helpers.project_commentable_comment_path(project, commentable, comment)
res = [link_to(content_tag(:i, nil, class: 'fa fa-link'), "#{helpers.project_commentable_path(project, commentable)}##{comment_anchor}", class: "#{@options[:in_discussion].present? ? 'in_discussion_' : ''}link_to_comment").html_safe] link_to_comment = "#{helpers.project_commentable_path(project, commentable)}##{comment_anchor}"
klass = "#{@options[:in_discussion].present? ? 'in_discussion_' : ''}link_to_comment"
res = [ link_to(content_tag(:i, nil, class: 'fa fa-link'),
link_to_comment,
class: klass).html_safe ]
if controller.can? :update, @comment if controller.can? :update, @comment
res << link_to(content_tag(:i, nil, class: 'fa fa-edit'), path, id: "comment-#{comment.id}", class: "edit_comment").html_safe res << link_to(content_tag(:i, nil, class: 'fa fa-edit'),
"#update-comment#{comment.id}",
'ng-click' => "commentsCtrl.toggleEditForm(#{comment_id})" ).html_safe
end end
if controller.can? :destroy, @comment if controller.can? :destroy, @comment
res << link_to(content_tag(:i, nil, class: 'fa fa-close'), path, method: "delete", res << link_to(content_tag(:i, nil, class: 'fa fa-close'),
data: { confirm: t('layout.comments.confirm_delete') }).html_safe '',
'ng-click' => "commentsCtrl.remove(#{comment_id})").html_safe
end end
res res
end end

View File

@ -1,32 +1,20 @@
h3 h3
= t('layout.comments.new_header') = t('layout.comments.new_header')
- if Comment.issue_comment?(commentable.class)
- new_path = project_issue_comments_path(project, commentable)
- is_subscribed = commentable.subscribes.exists?(user_id: current_user.id)
- subscribe_path = is_subscribed ? project_issue_subscribe_path(project, commentable, current_user.id) : project_issue_subscribes_path(project, commentable)
- else Comment.commit_comment?(commentable.class)
- new_path = project_commit_comments_path(project, commentable)
- is_subscribed = Subscribe.subscribed_to_commit?(project, current_user, commentable)
- subscribe_path = is_subscribed ? unsubscribe_commit_path(project, commentable) : subscribe_commit_path(project, commentable)
= simple_form_for Comment.new, url: new_path, html: { method: :post } do |f| = simple_form_for Comment.new, url: '', html: { method: :post } do |f|
.panel.panel-info ng-controller = 'IssueController as issueCtrl' ng-cloak = true .panel.panel-info ng-controller = 'IssueController as issueCtrl' ng-cloak = true
.panel-heading .panel-heading
h3.panel-title h3.panel-title
- t('activerecord.attributes.issue.body')
= f.label :body = f.label :body
.pull-right= render 'projects/comments/button_md_help' .pull-right= render 'projects/comments/button_md_help'
.panel-body .panel-body
= render 'projects/comments/body', f: f = render 'projects/comments/body', f: f, id: 'new-comment', ctrl: 'commentsCtrl',
ang_model: 'commentsCtrl.new_body'
hr hr
= f.button :submit, t('layout.create') button.btn.btn-primary[ ng-disabled = 'commentsCtrl.isDisabledNewCommentButton()'
ng-click = 'commentsCtrl.add()' ]
= t('layout.create')
.panel-footer .panel-footer
=> t('layout.comments.notifications_are') => t('layout.comments.notifications_are')
- if is_subscribed
span.label.label-success> == render 'projects/subscribes/subscribe_status', project: @project, commentable: @issue
= t('layout.turned_on')
= link_to t('layout.commits.unsubscribe_btn'), subscribe_path, method: :delete
- else
span.label.label-danger>
= t('layout.turned_off')
= link_to t('layout.commits.subscribe_btn'), subscribe_path, method: :post

View File

@ -1,13 +1,18 @@
tabset tabset
tab heading = t('layout.edit') tab heading = t('layout.edit')
.offset10 ng-init="issueCtrl.body = '#{f.object.body}'" .offset10
- if defined?(ang_model)
= f.input :body, label: false, = f.input :body, label: false,
input_html: { rows: 10, ng_model: 'issueCtrl.body' } input_html: { rows: 10, id: "#{id}-body",
'ng-model' => ang_model, 'ng-value' => ang_model }
- else
= f.input :body, label: false,
input_html: { rows: 10, id: "#{id}-body" }
tab[ heading = t('layout.preview') tab[ heading = t('layout.preview')
select = 'issueCtrl.previewBody()' ] select = "#{ctrl}.previewBody('#{id}')" ]
.offset10 .offset10
i.fa.fa-spinner.fa-spin.fa-lg ng-show = 'issueCtrl.processing' i.fa.fa-spinner.fa-spin.fa-lg ng-show = "#{ctrl}.processing"
div[ ng-bind-html = 'issueCtrl.preview_body' div[ ng-bind-html = "#{ctrl}.preview_body"
ng-show = '!issueCtrl.processing' ] ng-show = "!#{ctrl}.processing" ]

View File

@ -1,11 +0,0 @@
- CommentPresenter.present(comment, data) do |presenter|
= render 'shared/feed_message', presenter: presenter
-unless comment.automatic
#open-comment.comment.hidden{class: "comment-#{comment.id}"}
=render 'projects/comments/button_md_help'
%h3.tmargin0= t("layout.comments.edit_header")
= simple_form_for comment, url: project_commentable_comment_path(data[:project], data[:commentable], comment), html: { class: 'form edit_comment' } do |f|
= render "projects/comments/form", f: f, id: "#{data[:add_id]}edit_#{comment.id}"
.comment-left
=link_to t('layout.cancel'), '#', id: "comment-#{comment.id}", class: 'cancel_edit_comment button'
.both

View File

@ -0,0 +1,20 @@
- CommentPresenter.present(comment, data) do |presenter|
== render 'shared/feed_message', presenter: presenter
-unless comment.automatic
.open-comment.hidden class = "comment-#{comment.id}" id = "update-comment#{comment.id}"
h3.tmargin0= t("layout.comments.edit_header")
= simple_form_for comment, url: project_commentable_comment_path(data[:project], data[:commentable], comment) do |f|
.panel.panel-info
.panel-heading
h3.panel-title
= f.label :body
.pull-right== render 'projects/comments/button_md_help'
.panel-body
== render 'projects/comments/body', f: f, id: "comment-#{comment.id}",
ctrl: 'commentsCtrl'
- anchor = "#comment#{comment.id}"
a.btn.btn-primary[ ng-disabled = 'commentsCtrl.processing'
href = anchor
ng-click = "commentsCtrl.update(#{comment.id})" ]
= t('layout.update')
=< link_to t('layout.cancel'), anchor

View File

@ -1,2 +1,2 @@
=render 'projects/comments/body', f: f, id: id =render 'projects/comments/body', f: f, id: id
.comment-right= submit_tag t('layout.save'), data: {'disable-with' => t('layout.saving')} /.comment-right= submit_tag t('layout.save'), data: {'disable-with' => t('layout.saving')}

View File

@ -1,10 +0,0 @@
%a{ name: "comments" }
.hr
%h3#block-list= t("layout.comments.comments_header")
- list.each do |comment|
-unless comment.created_from_commit_hash
= render 'projects/comments/comment', comment: comment, data: {project: project, commentable: commentable}
-else
- GitPresenters::CommitAsMessagePresenter.present(nil, comment: comment) do |presenter|
= render 'shared/feed_message', presenter: presenter, item_no: "-#{comment.id}"
= render "projects/comments/markdown_help"

View File

@ -0,0 +1,12 @@
a name = 'comments'
h3#block-list= t("layout.comments.comments_header")
#comments_list
- list.each do |comment|
-unless comment.created_from_commit_hash
== render 'projects/comments/comment', comment: comment,
data: { project: project, commentable: commentable }
-else
- GitPresenters::CommitAsMessagePresenter.present(nil, comment: comment) do |presenter|
== render 'shared/feed_message', presenter: presenter, item_no: "-#{comment.id}"
== render "projects/comments/markdown_help"

View File

@ -72,6 +72,7 @@
br br
| without syntax highlighting: | without syntax highlighting:
br br
br
| def foo: | def foo:
br br
| if not bar: | if not bar:

View File

@ -7,4 +7,4 @@
= f.label :body = f.label :body
.pull-right= render 'projects/comments/button_md_help' .pull-right= render 'projects/comments/button_md_help'
.panel-body .panel-body
= render 'projects/comments/body', f: f = render 'projects/comments/body', f: f, id: 'issue', ctrl: 'issueCtrl'

View File

@ -35,10 +35,15 @@
== render 'closed_by' == render 'closed_by'
== render 'choose_assignee' == render 'choose_assignee'
== render "projects/comments/list", list: @issue.comments, project: @project, commentable: @issue - params = "{ kind: 'issue', id: #{@issue.serial_id} }"
div[ ng-controller = 'CommentsController as commentsCtrl'
ng-init = "commentsCtrl.init('#{@project.name_with_owner}', #{params})" ]
== render "projects/comments/list", list: @issue.comments,
project: @project, commentable: @issue
- if current_user - if current_user
hr hr
== render "projects/comments/add", project: @project, commentable: @issue if current_user == render "projects/comments/add", project: @project, commentable: @issue
.col-md-9.col-sm-8.offset20 ng-show='issueCtrl.edit' .col-md-9.col-sm-8.offset20 ng-show='issueCtrl.edit'
h3= t('layout.issues.edit_header') h3= t('layout.issues.edit_header')

View File

@ -0,0 +1,15 @@
- if Comment.issue_comment?(commentable.class)
- is_subscribed = commentable.subscribes.exists?(user_id: current_user.id)
- subscribe_path = is_subscribed ? project_issue_subscribe_path(project, commentable, current_user.id) : project_issue_subscribes_path(project, commentable)
- else Comment.commit_comment?(commentable.class)
- is_subscribed = Subscribe.subscribed_to_commit?(project, current_user, commentable)
- subscribe_path = is_subscribed ? unsubscribe_commit_path(project, commentable) : subscribe_commit_path(project, commentable)
- if is_subscribed
span.label.label-success>
= t('layout.turned_on')
= link_to t('layout.commits.unsubscribe_btn'), subscribe_path, method: :delete
- else
span.label.label-danger>
= t('layout.turned_off')
= link_to t('layout.commits.subscribe_btn'), subscribe_path, method: :post

View File

@ -1,29 +0,0 @@
-if !presenter.is_reference_to_issue || can?(:show, presenter.reference_project)
.panel.panel-default{id: presenter.comment_id? ? presenter.comment_anchor : ''}
.panel-body
.pull-left.roffset5
%img{ alt: 'avatar', src: presenter.image }
.pull-left
%strong= presenter.header
- if presenter.buttons?
%span.pull-right
&nbsp;
= raw presenter.buttons.join(' ').html_safe
= "(#{datetime_moment(presenter.date, tag: :strong)})".html_safe
- if presenter.caption?
.clearfix
%span= presenter.caption
- if presenter.expandable? and presenter.content?
%span.data-expander.collapsed{id: "expand#{item_no}"} &nbsp;
.clearfix
- if presenter.content?
%div
=presenter.issue_referenced_state if presenter.issue_referenced_state?
.fulltext{class: "#{presenter.expandable? ? "hidden" : ''} #{presenter.caption? ? "" : "alone"}",
id: presenter.expandable? ? "content-expand#{item_no}" : ''}
.md_and_cm{class: presenter.is_reference_to_issue ? '' : 'cm-s-default'}
= preserve do
= presenter.is_reference_to_issue ? presenter.content : markdown(presenter.content)
.clearfix

View File

@ -0,0 +1,30 @@
-if !presenter.is_reference_to_issue || can?(:show, presenter.reference_project)
.panel.panel-default[ id = (presenter.comment_id? ? presenter.comment_anchor : '') ]
.panel-body
.pull-left.roffset5
img alt = 'avatar' src = presenter.image
- if presenter.buttons?
.pull-right
| &nbsp;
= raw presenter.buttons.join(' ').html_safe
.pull-left
strong= presenter.header
p= datetime_moment(presenter.date, tag: :strong)
- if presenter.caption?
.clearfix
span= presenter.caption
- if presenter.expandable? and presenter.content?
span.data-expander.collapsed[ id = "expand#{item_no}"] &nbsp;
.clearfix
- if presenter.content?
.offset10
=presenter.issue_referenced_state if presenter.issue_referenced_state?
.fulltext[ class = "#{presenter.expandable? ? "hidden" : ''} #{presenter.caption? ? "" : "alone"}"
id = (presenter.expandable? ? "content-expand#{item_no}" : '') ]
.md_and_cm[ class = (presenter.is_reference_to_issue ? '' : 'cm-s-default') ]
= presenter.is_reference_to_issue ? presenter.content : markdown(presenter.content)
.clearfix