Reuse inline editing logic

This commit is contained in:
Anton Ignatov 2019-04-25 11:14:55 +02:00
parent e52b985e7b
commit 0779ed598b
4 changed files with 271 additions and 308 deletions

View file

@ -5,6 +5,7 @@ var Comments = (function() {
* Initializes the comments
*
*/
function initializeComments(){
var comments;
if ( $('.step-comment') && $('.step-comment').length > 0 ) {
@ -32,7 +33,6 @@ var Comments = (function() {
initCommentsLink(that);
initCommentsLinkNew(that);
initDeleteCommentNew(that);
initEditCommentNew(that);
var scrollItem = that.find('.content-comments'); // Check for new version of comments
if (that.hasClass('content-comments')) {
@ -41,6 +41,7 @@ var Comments = (function() {
scrollBottom(scrollItem);
});
}
initInlineEditing('comment')
}
// scroll to the botttom
@ -222,6 +223,8 @@ var Comments = (function() {
var currnetCount = $('#counter-' + stepId).html()
$('#counter-' + stepId).html(parseInt(currnetCount) + 1)
initInlineEditing('comment')
initDeleteCommentNew($el)
}
})
.on('ajax:error', function (ev, xhr) {
@ -344,8 +347,7 @@ 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();
$(parents).find('.delete-button').off('click').on('click', function(e) {
var $this = $(this)
if (confirm($this.attr('data-confirm-message'))) {
@ -354,7 +356,7 @@ var Comments = (function() {
type: 'DELETE',
dataType: 'json',
success: function(data) {
var commentEl = $this.closest('.comment-row').hide()
var commentEl = $this.closest('.comment-container').hide()
commentEl.remove();
var stepID = $this.attr('data-step-id')
@ -367,6 +369,8 @@ var Comments = (function() {
}
});
}
e.preventDefault();
e.stopPropagation();
});
}
@ -456,110 +460,12 @@ 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,

View file

@ -1,63 +1,99 @@
/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "initInlineEditing" }]*/
function initInlineEditing(title) {
var editBlock = $('.' + title + '-editable-field');
var inputString = editBlock.find('input');
var editBlocks = $('.' + title + '-editable-field');
$.each(editBlocks, function(i, element) {
var editBlock = element;
var $editBlock = $(editBlock);
var $inputString = $editBlock.find('input');
var inputString;
if (editBlock.dataset.editMode !== undefined) return true;
editBlock.dataset.editMode = 0;
$editBlock.addClass('inline-edit-active');
if ($inputString.length === 0) {
$inputString = $editBlock.find('textarea');
$inputString.off('keydown').on('keydown', function() {
var el = this;
setTimeout(() => {
el.style.cssText = 'height:0px; padding:0';
el.style.cssText = 'height:' + (el.scrollHeight + 10) + 'px';
}, 0);
});
$inputString.keydown();
}
inputString = $inputString[0]
function cancelAllEditFields() {
$('.inline-edit-active').find('.cancel-button').click();
}
function updateField() {
var params = {};
if (inputString[0].value === editBlock[0].dataset.originalName) {
inputString[0].disabled = true;
if (inputString.value === editBlock.dataset.originalName) {
inputString.disabled = true;
editBlock.dataset.editMode = 0;
return false;
}
params[editBlock[0].dataset.paramsGroup] = {};
params[editBlock[0].dataset.paramsGroup][editBlock[0].dataset.fieldToUpdate] = inputString[0].value;
params[editBlock.dataset.paramsGroup] = {};
params[editBlock.dataset.paramsGroup][editBlock.dataset.fieldToUpdate] = inputString.value;
$.ajax({
url: editBlock[0].dataset.pathToUpdate,
url: editBlock.dataset.pathToUpdate,
type: 'PUT',
dataType: 'json',
data: params,
success: function() {
editBlock[0].dataset.originalName = inputString[0].value;
editBlock[0].dataset.error = false;
inputString[0].disabled = true;
editBlock.dataset.originalName = inputString.value;
editBlock.dataset.error = false;
inputString.disabled = true;
editBlock.dataset.editMode = 0;
},
error: function(response) {
var errors = response.responseJSON;
editBlock[0].dataset.error = true;
editBlock.dataset.error = true;
if (response.responseJSON.errors === undefined) {
errors = errors[editBlock[0].dataset.fieldToUpdate][0];
errors = errors[editBlock.dataset.fieldToUpdate][0];
} else {
errors = errors.errors[editBlock[0].dataset.fieldToUpdate][0];
errors = errors.errors[editBlock.dataset.fieldToUpdate][0];
}
editBlock.find('.error-block')[0].innerHTML = errors;
inputString.focus();
$editBlock.find('.error-block')[0].innerHTML = errors;
$inputString.focus();
}
});
return true;
}
editBlock.click(e => {
if (inputString[0].disabled) {
inputString[0].disabled = false;
inputString.focus();
$editBlock.click(e => {
cancelAllEditFields();
if (inputString.disabled) {
editBlock.dataset.editMode = 1;
inputString.disabled = false;
$inputString.focus();
}
e.stopPropagation();
});
$(window).click(() => {
if (inputString[0].disabled === false) {
if (inputString.disabled === false) {
updateField();
}
editBlock.dataset.editMode = 0;
});
$(editBlock.find('.save-button')).click(e => {
$($editBlock.find('.save-button')).click(e => {
updateField();
e.stopPropagation();
});
$(editBlock.find('.cancel-button')).click(e => {
inputString[0].disabled = true;
editBlock[0].dataset.error = false;
inputString[0].value = editBlock[0].dataset.originalName;
$($editBlock.find('.cancel-button')).click(e => {
inputString.disabled = true;
editBlock.dataset.editMode = 0;
editBlock.dataset.error = false;
inputString.value = editBlock.dataset.originalName;
$inputString.keydown();
e.stopPropagation();
});
return true;
});
}

View file

@ -1,6 +1,11 @@
// Place all the styles related to the Steps controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
// scss-lint:disable SelectorDepth
// scss-lint:disable NestingDepth
// scss-lint:disable SelectorFormat
// scss-lint:disable ImportantRule
@import "constants";
#new_step,
@ -102,17 +107,17 @@
}
&.new {
background-color: rgba(95, 95, 95, 0.1);
background-color: rgba(95, 95, 95, .1);
}
&:hover {
box-shadow: 0 1px 5px 0 rgba(0,0,0,0.18);
box-shadow: 0 1px 5px 0 rgba(0, 0, 0, .18);
}
.attachment-thumbnail {
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.15);
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .15);
height: 160px;
margin: 16px auto 5px auto;
margin: 16px auto 5px;
overflow: hidden;
text-align: center;
width: 113px;
@ -128,11 +133,11 @@
}
.no-shadow {
box-shadow: 0 0 0 0 rgba(0,0,0,0.15);
box-shadow: 0 0 0 0 rgba(0, 0, 0, .15);
}
.attachment-label {
color: #40A1D7;
color: #40a1d7;
font-family: Lato;
font-size: 16px;
height: 39px;
@ -192,66 +197,13 @@
color: $color-emperor;
}
// Comment item
.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 {
.avatar-placehodler {
height: 30px;
width: 30px;
@ -260,52 +212,148 @@
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;
.content-placeholder {
padding-left: 10px;
}
width: calc(100% - 30px);
.comment-actions {
.comment-name {
color: $color-silver-chalice;
float: left;
font-size: 16px;
line-height: 30px;
padding-left: 5px;
width: 50%;
}
.comment-message {
float: left;
width: 100%;
textarea {
border: 1px solid $color-silver;
border-radius: $border-radius-small;
height: 22px;
line-height: 16px;
overflow: hidden;
padding: 2px 5px;
width: 100%;
&:focus {
outline: 0;
}
&:disabled {
background: transparent;
border: 1px solid transparent;
user-select: none;
}
}
}
.error-block {
color: $brand-danger;
display: none;
float: left;
}
.comment-right {
color: $color-silver-chalice;
float: right;
height: 30px;
line-height: 30px;
overflow: hidden;
position: relative;
transition: .3s;
width: 120px;
.comment-datetime {
float: left;
font-size: 12px;
line-height: 30px;
width: 120px;
}
.comment-actions {
left: 120px;
position: absolute;
width: 100px;
.view-buttons,
.edit-buttons {
display: none;
font-size: 16px;
margin-right: 20px;
.action-icon-delete {
margin-left: 20px;
* {
cursor: pointer;
}
.edit-label {
font-size: 14px;
margin-left: 3px;
.edit-button,
.save-button {
display: inline-block;
width: 80px;
}
.delete-button,
.cancel-button {
float: right;
padding-right: 5px;
width: 20px;
}
a {
color: inherit;
}
span {
.fas {
margin-right: 5px;
}
}
}
}
}
}
&[data-edit-mode="0"]:hover,
&[data-edit-mode="1"] {
.comment-right {
width: 220px;
}
textarea:disabled {
border: 1px solid $color-gainsboro;
cursor: pointer;
}
}
&[data-edit-mode="0"]:hover {
cursor: pointer;
.comment-actions {
.view-buttons {
display: inline;
}
}
}
&[data-edit-mode="1"] {
.comment-actions {
.edit-buttons {
display: inline !important;
}
}
}
&[data-error="true"] {
.error-block {
display: block;
}
}
}

View file

@ -1,70 +1,43 @@
<div class="row comment-row" id="comment-<%= comment.id %>" data-comment-id="<%= comment.id %>">
<div class="comment-container">
<% user_comment = comment.user == current_user %>
<div
class="comment-container <%= user_comment ? 'comment-editable-field' : '' %>"
data-field-to-update="message"
data-params-group="comment"
data-path-to-update="<%= step_step_comment_path(comment.step, comment, format: :json) %>"
data-original-name="<%= comment.message %>"
error="false"
>
<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 class="comment-name"><%= comment.user.full_name %></div>
<div class="comment-right">
<div class="comment-datetime"><%= l(comment.created_at, format: :full) %></div>
<% if user_comment %>
<div class="comment-actions">
<div class="edit-buttons">
<span class="save-button"><i class="fas fa-save"></i><%= t('general.save') %></span>
<span class="cancel-button"><i class="fas fa-times"></i></span>
</div>
<% if comment.user == current_user %>
<div class="comment-actions pull-right">
<div class="view-buttons">
<span class="edit-button"><i class="fas fa-pen"></i><%= t('general.edit') %></span>
<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"
class="delete-button"
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>
</div>
<% end %>
</div>
<div class="comment-message">
<%= text_area_tag 'message', comment.message, disabled: true %>
</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 class="error-block"></div>
</div>
</div>
</div>
</div>
</div>