mirror of
https://github.com/scinote-eln/scinote-web.git
synced 2024-09-21 07:26:15 +08:00
xMerge branch 'ur-sci-3135-comments-section-changes' of https://github.com/urbanrotnik/scinote-web into urbanrotnik-ur-sci-3135-comments-section-changes
This commit is contained in:
commit
e52b985e7b
|
@ -28,8 +28,17 @@ var Comments = (function() {
|
|||
});
|
||||
}
|
||||
initCommentForm(that);
|
||||
initCommentFormNew(that);
|
||||
initCommentsLink(that);
|
||||
scrollBottom(that.find('.content-comments'));
|
||||
initCommentsLinkNew(that);
|
||||
initDeleteCommentNew(that);
|
||||
initEditCommentNew(that);
|
||||
|
||||
var scrollItem = that.find('.content-comments'); // Check for new version of comments
|
||||
if (that.hasClass('content-comments')) {
|
||||
scrollItem = that
|
||||
}
|
||||
scrollBottom(scrollItem);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -84,6 +93,29 @@ var Comments = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
function initCommentsLinkNew($el) {
|
||||
$el.find('.btn-more-comments-new').off()
|
||||
.on('ajax:success', function (e, data) {
|
||||
if (data.html) {
|
||||
|
||||
var stepId = $(this).data('step-id')
|
||||
var list = $('#comments-list-' + stepId);
|
||||
var moreBtn = $(this);
|
||||
|
||||
list.prepend(data.html);
|
||||
|
||||
if (data.resultsNumber < data.perPage) {
|
||||
moreBtn.remove();
|
||||
} else {
|
||||
moreBtn.attr('href', data.moreUrl);
|
||||
moreBtn.trigger('blur');
|
||||
}
|
||||
} else {
|
||||
$('.btn-more-comments').remove();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Initialize comment form.
|
||||
function initCommentForm($el) {
|
||||
|
||||
|
@ -163,6 +195,55 @@ var Comments = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
function initCommentFormNew($el) {
|
||||
var stepId = $el.data('step-id');
|
||||
var $form = $('#new-message-' + stepId).find('form');
|
||||
var $list = $el.find('.comments-list');
|
||||
var $submitBtn = $form.find('.new-comment-button')
|
||||
|
||||
$submitBtn.on('click', function() {
|
||||
$form.submit();
|
||||
});
|
||||
|
||||
$('.help-block', $form).addClass('hide');
|
||||
|
||||
$form.off().on('ajax:send', function () {
|
||||
$('#comment_message', $form).attr('readonly', true);
|
||||
$submitBtn.off('click');
|
||||
})
|
||||
.on('ajax:success', function (e, data) {
|
||||
if (data.html) {
|
||||
$list.append(data.html).scrollTop(0);
|
||||
scrollBottom($el);
|
||||
$('#comment_message', $form).val('');
|
||||
$('.form-group', $form).removeClass('has-error');
|
||||
$('.help-block', $form).html('').addClass('hide');
|
||||
$submitBtn.removeClass('has-error');
|
||||
|
||||
var currnetCount = $('#counter-' + stepId).html()
|
||||
$('#counter-' + stepId).html(parseInt(currnetCount) + 1)
|
||||
}
|
||||
})
|
||||
.on('ajax:error', function (ev, xhr) {
|
||||
if (xhr.status === 400) {
|
||||
var messageError = xhr.responseJSON.errors.message;
|
||||
|
||||
if (messageError) {
|
||||
$('.form-group', $form).addClass('has-error');
|
||||
$('.help-block', $form).html(messageError[0]).removeClass('hide');
|
||||
$submitBtn.addClass('has-error');
|
||||
}
|
||||
}
|
||||
})
|
||||
.on('ajax:complete', function () {
|
||||
scrollBottom($('#comment_message', $form));
|
||||
$('#comment_message', $form).attr('readonly', false).focus();
|
||||
$submitBtn.on('click', function() {
|
||||
$form.submit();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function initCommentOptions(scrollableContainer, useParentOffset) {
|
||||
if ( ! _.isUndefined(useParentOffset) ) {
|
||||
useParentOffset = useParentOffset;
|
||||
|
@ -260,6 +341,35 @@ var Comments = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
function initDeleteCommentNew($el) {
|
||||
var parents = $el.find('.comments-list')
|
||||
|
||||
$(parents).unbind('click').on('click', '[data-action=delete-comment-new]', function(e) {
|
||||
e.preventDefault();
|
||||
var $this = $(this)
|
||||
|
||||
if (confirm($this.attr('data-confirm-message'))) {
|
||||
$.ajax({
|
||||
url: $this.attr('data-url'),
|
||||
type: 'DELETE',
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
var commentEl = $this.closest('.comment-row').hide()
|
||||
commentEl.remove();
|
||||
|
||||
var stepID = $this.attr('data-step-id')
|
||||
var currnetCount = $('#counter-' + stepID).html()
|
||||
$('#counter-' + stepID).html(parseInt(currnetCount) - 1)
|
||||
},
|
||||
error: function(data) {
|
||||
// Display alert
|
||||
alert(data.responseJSON.message);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initEditComments(parent) {
|
||||
$(parent).unbind('click').on('click', '[data-action=edit-comment]', function() {
|
||||
|
||||
|
@ -346,10 +456,110 @@ var Comments = (function() {
|
|||
});
|
||||
}
|
||||
|
||||
function initEditCommentNew($el) {
|
||||
var editBtnSelector = '[data-action=edit-comment-new]';
|
||||
var cancelBtnSelector = '[data-action=cancel-comment-new]';
|
||||
var saveBtnSelector = '[data-action=save-comment-new]';
|
||||
var commentMessageSelector = '.comment-message';
|
||||
var textareaSelector = '.comment-textarea'
|
||||
|
||||
var parents = $el.find('.comments-list')
|
||||
|
||||
$(parents).on('click', commentMessageSelector, function(e) {
|
||||
var $this = $(this);
|
||||
startEditingMode($this.data('comment-id'))
|
||||
})
|
||||
|
||||
$(parents).on('click', editBtnSelector, function(e) {
|
||||
e.preventDefault();
|
||||
var $this = $(this);
|
||||
startEditingMode($this.closest('.comment-row').data('comment-id'))
|
||||
})
|
||||
|
||||
$(parents).on('click', cancelBtnSelector, function(e) {
|
||||
e.preventDefault();
|
||||
var $this = $(this);
|
||||
var commentId = $this.closest('.comment-row').data('comment-id')
|
||||
var $commentTextArea = $('#comment-textarea-' + commentId);
|
||||
$commentTextArea.val($commentTextArea.data('message'));
|
||||
resetAllEditingModes();
|
||||
})
|
||||
|
||||
$(parents).on('focusout', textareaSelector, function(e) {
|
||||
var $this = $(this);
|
||||
var $comment = $this.closest('.comment-row')
|
||||
var commentId = $comment.data('comment-id');
|
||||
|
||||
if($this[0].dataset.editing == 0) return;
|
||||
|
||||
updateComment(commentId);
|
||||
})
|
||||
|
||||
|
||||
$(parents).on('click', saveBtnSelector, function(e) {
|
||||
e.preventDefault();
|
||||
var commentId = $(this).closest('.comment-row').data('comment-id');
|
||||
updateComment(commentId);
|
||||
});
|
||||
}
|
||||
|
||||
function updateComment(commentId){
|
||||
var $comment = $('#comment-' + commentId);
|
||||
var $form = $comment.find('form');
|
||||
var $textarea = $form.find('textarea');
|
||||
var $commentMessage = $('#comment-message-' + commentId);
|
||||
var $saveBtn = $comment.find('.save-comment-new');
|
||||
|
||||
$form
|
||||
.off('ajax:send').on('ajax:send', function() {
|
||||
$textarea.attr('readonly', true);
|
||||
$saveBtn.addClass('hidden');
|
||||
$textarea[0].dataset.editing = 0;
|
||||
})
|
||||
.off('ajax:success').on('ajax:success', function(ev, data) {
|
||||
$commentMessage.html(data.comment);
|
||||
$textarea.data('message', $textarea.val());
|
||||
resetAllEditingModes();
|
||||
})
|
||||
.off('ajax:error').on('ajax:error', function(ev, xhr) {
|
||||
if (xhr.status === 422) {
|
||||
alert(xhr.responseJSON.errors.message)
|
||||
}
|
||||
else{
|
||||
alert('Error. Cannot update comment!')
|
||||
}
|
||||
})
|
||||
.off('ajax:complete').on('ajax:complete', function() {
|
||||
$textarea.attr('readonly', false).focus();
|
||||
$saveBtn.removeClass('hidden');
|
||||
});
|
||||
|
||||
$form.submit();
|
||||
}
|
||||
|
||||
function startEditingMode(commentId){
|
||||
resetAllEditingModes();
|
||||
var $commentTextArea = $('#comment-textarea-' + commentId);
|
||||
var tempContent = $commentTextArea.val();
|
||||
$commentTextArea[0].dataset.editing = 1;
|
||||
|
||||
$('#comment-'+commentId + ' > .comment-container').addClass('edit');
|
||||
$commentTextArea.focus().val('').val(tempContent);
|
||||
}
|
||||
|
||||
function resetAllEditingModes() {
|
||||
$('.comment-container').removeClass('edit');
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
initialize: initializeComments,
|
||||
scrollBottom: scrollBottom,
|
||||
moreComments: initCommentsLink,
|
||||
initCommentsLinkNew: initCommentsLinkNew,
|
||||
initCommentFormNew: initCommentFormNew,
|
||||
initDeleteCommentNew: initDeleteCommentNew,
|
||||
initEditCommentNew: initEditCommentNew,
|
||||
form: initCommentForm,
|
||||
initCommentOptions: initCommentOptions,
|
||||
initDeleteComments: initDeleteComments,
|
||||
|
|
|
@ -184,5 +184,150 @@
|
|||
}
|
||||
}
|
||||
|
||||
.step .textarea-sm {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.comments-title {
|
||||
color: $color-emperor;
|
||||
}
|
||||
|
||||
.comment-container {
|
||||
display: flex;
|
||||
padding: 5px 0 5px 5px;
|
||||
|
||||
&:hover {
|
||||
background-color: $brand-primary-light;
|
||||
|
||||
.comment-actions {
|
||||
display: inline;
|
||||
|
||||
a {
|
||||
color: $color-silver-chalice;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: $color-dove-gray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.edit {
|
||||
.comment-textarea {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.comment-message {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.edit-actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.editing-actions {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-textarea {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.comment-message {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.edit-actions {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.editing-actions {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-placehodler {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
|
||||
img {
|
||||
border-radius: 30px;
|
||||
position: relative;
|
||||
top: 7px;
|
||||
}
|
||||
}
|
||||
|
||||
.content-placeholder {
|
||||
flex-grow: 1;
|
||||
|
||||
.row-content {
|
||||
margin-left: -25px;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-right {
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.comment-datetime {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.comment-name {
|
||||
color: $color-silver-chalice;
|
||||
font-size: 16px;
|
||||
|
||||
p {
|
||||
margin-bottom: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.comment-message {
|
||||
font-size: 14px;
|
||||
line-height: 17px;
|
||||
margin-top: -4px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.comment-actions {
|
||||
display: none;
|
||||
font-size: 16px;
|
||||
margin-right: 20px;
|
||||
|
||||
.action-icon-delete {
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.edit-label {
|
||||
font-size: 14px;
|
||||
margin-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.step-comments {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.new-comment-button {
|
||||
cursor: pointer;
|
||||
font-size: 18px;
|
||||
left: calc(100% - 29px);
|
||||
position: relative;
|
||||
top: -41px;
|
||||
|
||||
&.has-error {
|
||||
top: -64px;
|
||||
}
|
||||
}
|
||||
|
||||
.new-message-continer {
|
||||
float: left;
|
||||
margin-top: 20px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class StepCommentsController < ApplicationController
|
|||
# messages. 'list' partial is used for showing more
|
||||
# comments.
|
||||
partial = 'index.html.erb'
|
||||
partial = 'list.html.erb' if @last_comment_id.positive?
|
||||
partial = 'steps/comments/list.html.erb' if @last_comment_id.positive?
|
||||
more_url = ''
|
||||
if @comments.size.positive?
|
||||
more_url = url_for(step_step_comments_path(@step,
|
||||
|
@ -57,7 +57,7 @@ class StepCommentsController < ApplicationController
|
|||
format.json {
|
||||
render json: {
|
||||
html: render_to_string(
|
||||
partial: "comment.html.erb",
|
||||
partial: 'steps/comments/item.html.erb',
|
||||
locals: {
|
||||
comment: @comment
|
||||
}
|
||||
|
|
42
app/views/steps/_comments.html.erb
Normal file
42
app/views/steps/_comments.html.erb
Normal file
|
@ -0,0 +1,42 @@
|
|||
<% per_page = Constants::COMMENTS_SEARCH_LIMIT %>
|
||||
<% if can_read_protocol_in_module?(@protocol) %>
|
||||
|
||||
<div class="col-xs-12 comments-title">
|
||||
<h4>
|
||||
<%=t('protocols.steps.comments') %>
|
||||
(<span id="counter-<%= step.id %>"><%= comments_count %></span>)
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 step-comment content-comments"
|
||||
id="new-step-comments-<%= step.id %>"
|
||||
data-href="<%= url_for step_step_comments_path(step_id: step.id, format: :json) %>"
|
||||
data-step-id="<%= step.id %>">
|
||||
<% if comments.size == per_page %>
|
||||
<div class="comment-more text-center">
|
||||
<a class="btn btn-default btn-more-comments-new" id="more-btn-<%=step.id %>"
|
||||
href="<%= url_for(step_step_comments_path(step, format: :json, from: comments.first.id)) %>"
|
||||
data-remote="true",
|
||||
data-step-id="<%= step.id %>">
|
||||
<%=t "general.more_comments" %>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="comments-list" id="comments-list-<%= step.id %>">
|
||||
<%= render partial: 'steps/comments/list.html.erb', locals: { comments: comments} %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="new-message-continer" id="new-message-<%= step.id %>">
|
||||
<% if can_create_comments_in_module?(@protocol.my_module) %>
|
||||
<%= bootstrap_form_for( :comment, url: step_step_comments_path(step, format: :json), html: { method: :post }, remote: true) do |f| %>
|
||||
<%= f.smart_text_area :message,
|
||||
single_line: true,
|
||||
hide_label: true,
|
||||
placeholder: t('general.comment_placeholder_new'),
|
||||
help: '.',
|
||||
data: { 'atwho-edit' => '' } %>
|
||||
<i class="fas fa-paper-plane new-comment-button"></i>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
|
@ -143,17 +143,11 @@
|
|||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<% if can_read_protocol_in_module?(@protocol) %>
|
||||
<div class="row">
|
||||
<div class="step-comment"
|
||||
id="step-comments-<%= step.id %>"
|
||||
data-href="<%= url_for step_step_comments_path(step_id: step.id, format: :json) %>">
|
||||
<%= render partial: "step_comments/index.html.erb",
|
||||
locals: { step: step, comments: step.last_comments, per_page: Constants::COMMENTS_SEARCH_LIMIT } %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<hr>
|
||||
<br>
|
||||
<%= render partial: 'steps/comments.html.erb', locals: { comments: step.last_comments,
|
||||
comments_count: step.step_comments.count,
|
||||
step: step } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
70
app/views/steps/comments/_item.html.erb
Normal file
70
app/views/steps/comments/_item.html.erb
Normal file
|
@ -0,0 +1,70 @@
|
|||
<div class="row comment-row" id="comment-<%= comment.id %>" data-comment-id="<%= comment.id %>">
|
||||
<div class="comment-container">
|
||||
<div class="avatar-placehodler">
|
||||
<%= image_tag avatar_path(comment.user, :icon_small), class: 'avatar' %>
|
||||
</div>
|
||||
<div class="content-placeholder">
|
||||
<div class="row row-content">
|
||||
<div class="col-xs-4 comment-name"><p><%= comment.user.full_name %></p></div>
|
||||
<div class="col-xs-8">
|
||||
<div class="comment-right pull-right">
|
||||
<div class="comment-datetime pull-right">
|
||||
<p><%= l(comment.created_at, format: :full) %></p>
|
||||
</div>
|
||||
<% if comment.user == current_user %>
|
||||
<div class="comment-actions pull-right">
|
||||
<a href="#"
|
||||
data-action="save-comment-new"
|
||||
data-url="<%= step_step_comment_path(comment.step, comment, format: :json) %>"
|
||||
data-turbolinks="false"
|
||||
class="editing-actions">
|
||||
<span class="fas fa-save action-icon"></span><span class="edit-label"><%= t('general.save') %></span>
|
||||
</a>
|
||||
<a href="#"
|
||||
data-action="cancel-comment-new"
|
||||
data-turbolinks="false"
|
||||
class="editing-actions">
|
||||
<span class="fas fa-times action-icon-delete"></span>
|
||||
</a>
|
||||
|
||||
<a href="#"
|
||||
class="edit-actions"
|
||||
data-action="edit-comment-new"
|
||||
data-turbolinks="false">
|
||||
<span class="fas fa-pen action-icon"></span><span class="edit-label"><%= t('general.edit') %></span>
|
||||
</a>
|
||||
|
||||
<a href="#"
|
||||
class="edit-actions"
|
||||
data-action="delete-comment-new"
|
||||
data-url="<%= step_step_comment_path(comment.step, comment, format: :json) %>"
|
||||
data-confirm-message="<%= t('comments.delete_confirm') %>"
|
||||
data-step-id="<%= comment.step.id %>"
|
||||
data-turbolinks="false">
|
||||
<span class="fas fa-trash action-icon-delete"></span>
|
||||
</a>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-xs-12 comment-message" id="comment-message-<%= comment.id %>" data-comment-id="<%= comment.id %>">
|
||||
<%= custom_auto_link(comment.message, team: current_team) %>
|
||||
</div>
|
||||
<%= bootstrap_form_for( :comment, url: step_step_comment_path(comment.step, comment, format: :json),
|
||||
html: { method: :put }, remote: true) do |f| %>
|
||||
<%= f.smart_text_area :message,
|
||||
single_line: true,
|
||||
hide_label: true,
|
||||
value: comment.message,
|
||||
data: { 'atwho-edit': '', message: comment.message },
|
||||
class: 'comment-textarea',
|
||||
id: 'comment-textarea-' + comment.id.to_s %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
4
app/views/steps/comments/_list.html.erb
Normal file
4
app/views/steps/comments/_list.html.erb
Normal file
|
@ -0,0 +1,4 @@
|
|||
<% comments.each do |comment| %>
|
||||
<%= render partial: 'steps/comments/item.html.erb',
|
||||
locals: { comment: comment } %>
|
||||
<% end %>
|
|
@ -1739,6 +1739,7 @@ en:
|
|||
no_description: "This step has no description."
|
||||
tables: "Tables"
|
||||
files: "Attachments (%{count})"
|
||||
comments: "Comments"
|
||||
empty_checklist: "No items"
|
||||
comment_title: "%{user} at %{time}:"
|
||||
options:
|
||||
|
@ -1959,6 +1960,7 @@ en:
|
|||
no_comments: "No comments!"
|
||||
more_comments: "More comments"
|
||||
comment_placeholder: "Your Message"
|
||||
comment_placeholder_new: "Add new comment…"
|
||||
module:
|
||||
one: "task"
|
||||
other: "tasks"
|
||||
|
|
Loading…
Reference in a new issue