Adding inline editing to experiment title, project title and task title [SCI-3059] (#1524)

* Adding inline editing to experiment title, project title and task title
This commit is contained in:
aignatov-bio 2019-03-06 09:17:34 +01:00 committed by GitHub
parent 3acf9b71f8
commit b1df8c9aa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 259 additions and 8 deletions

View file

@ -38,6 +38,7 @@
//= require users/settings/teams/invite_users_modal
//= require select2.min
//= require select2_customization
//= require shared/inline_editing
//= require turbolinks

View file

@ -0,0 +1,63 @@
function initInlineEditing(title) {
var editBlock = $('.' + title + '-editable-field');
var inputString = editBlock.find('input');
function updateField() {
var params = {};
if (inputString[0].value === editBlock[0].dataset.originalName) {
inputString[0].disabled = true;
return false;
}
params[editBlock[0].dataset.paramsGroup] = {};
params[editBlock[0].dataset.paramsGroup][editBlock[0].dataset.fieldToUpdate] = inputString[0].value;
$.ajax({
url: editBlock[0].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;
},
error: function(response) {
var errors = response.responseJSON;
editBlock[0].dataset.error = true;
if (response.responseJSON.errors === undefined) {
errors = errors[editBlock[0].dataset.fieldToUpdate][0];
} else {
errors = errors.errors[editBlock[0].dataset.fieldToUpdate][0];
}
editBlock.find('.error-block')[0].innerHTML = errors;
inputString.focus();
}
});
}
editBlock.click(e => {
if (inputString[0].disabled) {
inputString[0].disabled = false;
inputString.focus();
}
e.stopPropagation();
});
$(window).click(() => {
if (inputString[0].disabled === false) {
updateField();
}
});
$(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;
e.stopPropagation();
});
}

View file

@ -0,0 +1,94 @@
@import "constants";
@import "mixins";
.inline-editing-container {
position: relative;
.button-container {
height: 44px;
line-height: 44px;
overflow: hidden;
position: absolute;
right: 0;
top: 0;
width: 72px;
span {
color: $color-silver;
cursor: pointer;
display: inline-block;
position: absolute;
text-align: center;
width: 36px;
&:nth-child(1) {left: 0;}
&:nth-child(2) {right: 0;}
}
}
.error-block {
bottom: 3px;
color: $brand-danger;
display: none;
font-size: $font-size-small;
left: 5px;
line-height: 12px;
position: absolute;
}
&[data-error="true"] {
.error-block {
display: block;
}
input {
padding-bottom: 16px;
padding-top: 0;
}
}
input {
border: 1px solid $color-silver;
border-radius: $border-radius-small;
cursor: pointer;
line-height: 20px;
padding: 8px 5px;
padding-right: 36px;
width: calc(100% - 36px);
&:focus {
outline: 0;
}
&:disabled {
background: transparent;
border: 1px solid transparent;
cursor: pointer;
user-select: none;
+ .button-container {
display: none;
}
&:hover {
border: 1px solid $color-gainsboro;
}
}
}
}
.nav-name.editable {
margin: 0;
.inline-editing-container {
input {
line-height: 26px;
}
}
}

View file

@ -119,24 +119,24 @@ class ExperimentsController < ApplicationController
)
)
@experiment.touch(:workflowimg_updated_at)
flash[:success] = t('experiments.update.success_flash',
experiment: @experiment.name)
respond_to do |format|
format.json do
render json: {}, status: :ok
end
format.html do
flash[:success] = t('experiments.update.success_flash',
experiment: @experiment.name)
redirect_to project_path(@experiment.project)
end
end
else
flash[:alert] = t('experiments.update.error_flash')
respond_to do |format|
format.json do
render json: @experiment.errors, status: :unprocessable_entity
end
format.html do
flash[:alert] = t('experiments.update.error_flash')
redirect_back(fallback_location: root_path)
end
end

View file

@ -1,6 +1,15 @@
<% provide(:head_title, t("experiments.canvas.head_title", project: h(@project.name)).html_safe) %>
<%= render partial: "shared/sidebar", locals: { current_experiment: @experiment, page: 'canvas' } %>
<%= render partial: "shared/secondary_navigation" %>
<%= render partial: "shared/secondary_navigation" , locals: {
editable: {
name: 'title',
active: true,
width: 'calc(100% - 500px)',
params_group: 'experiment',
field_to_udpate: 'name',
path_to_update: experiment_path(@experiment)
}
}%>
<div class="content-pane" id="experiment-canvas">
<div class="row">

View file

@ -0,0 +1,4 @@
<h5>Team</h5>
<select name="team">
<%=options_for_select @teams %>
</select>

View file

@ -0,0 +1,31 @@
<div class="global-activities__container">
<br>
<div class="global-activities__top">
<h2 class="global-activiteis__title">Global activities</h2>
</div>
<div class="global-activities__main">
<div class="global-activities__top-actions">
<span><i class="fas fa-caret-square-down"></i> Expand All</span>
&nbsp;&nbsp;
<span><i class="fas fa-caret-square-up"></i> Colapse All</span>
</div>
<div class="global-activities__search-container">
<div class="input-group">
<input type="text" class="form-control" placeholder="Search..." aria-describedby="basic-addon1">
<span class="input-group-addon" id="basic-addon1">
<i class="fas fa-search"></i>
</span>
</div>
</div>
<div class="global-activities_activities-list">
<h2>list of activities</h2>
</div>
</div>
<div class="global-activities__side">
<%= render "team_selection" %>
</div>
</div>

View file

@ -2,7 +2,16 @@
<%= render partial: 'shared/drag_n_drop_overlay' %>
<%= render partial: "shared/sidebar", locals: { current_task: @my_module, page: 'task' } %>
<%= render partial: "shared/secondary_navigation" %>
<%= render partial: "shared/secondary_navigation", locals: {
editable: {
name: 'title',
active: true,
width: 'calc(100% - 580px)',
params_group: 'my_module',
field_to_udpate: 'name',
path_to_update: my_module_path(@my_module)
}
} %>
<div class="content-pane my-modules-protocols-index">
<%= render partial: "module_header" %>

View file

@ -1,6 +1,15 @@
<% provide(:head_title, t("projects.show.head_title", project: h(@project.name)).html_safe) %>
<%= render partial: "shared/sidebar", locals: { current_project: @project, page: 'project' } %>
<%= render partial: "shared/secondary_navigation" %>
<%= render partial: "shared/secondary_navigation", locals: {
editable: {
name: 'title',
active: true,
width: 'calc(100% - 500px)',
params_group: 'project',
field_to_udpate: 'name',
path_to_update: project_path(@project)
}
}%>
<div class="content-pane" id="project-show">
<div class="row">

View file

@ -0,0 +1,19 @@
<div
class="inline-editing-container <%= name %>-editable-field"
style="width:<%= (defined? width) ? width.html_safe : '100%' %>"
data-field-to-update="<%= field_to_udpate %>"
data-params-group="<%= params_group %>"
data-path-to-update="<%= path_to_update %>"
data-original-name="<%= initial_value %>"
error="false"
>
<input type="text" value="<%= initial_value %>" disabled/>
<div class="button-container">
<span class="save-button"><i class="fas fa-check"></i></span>
<span class="cancel-button"><i class="fas fa-times"></i></span>
</div>
<span class="error-block"></span>
</div>
<script>
initInlineEditing('<%= name %>')
</script>

View file

@ -149,9 +149,21 @@
</ul>
<!-- Secondary navigation title -->
<h4 class="nav-name">
<%= truncate(title_element.name,
<% editable = false if local_assigns[:editable].nil? %>
<h4 class="nav-name <%= (editable && editable[:active]) ? 'editable' : '' %>">
<% if editable && editable[:active] %>
<%= render partial: "shared/inline_editing", locals: {
initial_value: truncate(title_element.name, length: Constants::MAX_EDGE_LENGTH),
width: editable[:width] || '100%',
name: editable[:name],
field_to_udpate: editable[:field_to_udpate],
path_to_update: editable[:path_to_update],
params_group: editable[:params_group]
} %>
<% else %>
<%= truncate(title_element.name,
length: Constants::MAX_EDGE_LENGTH) %>
<% end %>
</h4>
</div>