diff --git a/app/assets/javascripts/samples/sample_datatable.js b/app/assets/javascripts/samples/sample_datatable.js.erb similarity index 95% rename from app/assets/javascripts/samples/sample_datatable.js rename to app/assets/javascripts/samples/sample_datatable.js.erb index 4e34e8ed4..22c646c98 100644 --- a/app/assets/javascripts/samples/sample_datatable.js +++ b/app/assets/javascripts/samples/sample_datatable.js.erb @@ -138,6 +138,9 @@ function dataTableInit() { table.column(i).visible(visibility); } oSettings._colReorder.fnOrder(myData.ColReorder); + table.on('mousedown', function() { + $('#samples-columns-dropdown').removeClass('open'); + }); } }); @@ -746,7 +749,9 @@ function createSampleTypeSelect(data, selected) { var $selectType = $('') .attr('name', 'sample_type_id').addClass('show-tick'); - var $option = $("") + var sampleTypesLink = $('#samples').attr('data-sample-types-link'); + + var $option = $("") .attr('value', -2) .text(I18n.t('samples.table.add_sample_type')); $selectType.append($option); @@ -774,7 +779,9 @@ function createSampleGroupSelect(data, selected) { var $selectGroup = $('') .attr('name', 'sample_group_id').addClass('show-tick'); - var $option = $("") + var sampleGroupsLink = $('#samples').attr('data-sample-groups-link'); + + var $option = $("") .text(I18n.t('samples.table.add_sample_group')); $selectGroup.append($option); $option = $('') @@ -857,8 +864,7 @@ function changeToEditMode() { 'data-editable data-deletable ' + 'data-edit-url="' + data.edit_url + '" ' + 'data-destroy-html-url="' + data.destroy_html_url + '"' + - '>' + - data.name + ''); + '>' + generateColumnNameTooltip(data.name) + ''); var colOrder = table.colReorder.order(); colOrder.push(colOrder.length); // Remove all event handlers as we re-initialize them later with @@ -873,6 +879,7 @@ function changeToEditMode() { table = dataTableInit(); table.on('init.dt', function() { loadColumnsNames(); + dropdownOverflow(); }); }, url: url @@ -914,7 +921,9 @@ function changeToEditMode() { // loads the columns names in the dropdown list function loadColumnsNames() { - // First, clear the list + // Save scroll position + var scrollPosition = dropdownList.scrollTop(); + // Clear the list dropdownList.find('li[data-position]').remove(); _.each(table.columns().header(), function(el, index) { if (index > 1) { @@ -936,21 +945,20 @@ function changeToEditMode() { 'class="' + visLi + '"' + '>' + ' ' + - '' + el.innerText + ' ' + + '' + generateColumnNameTooltip(el.innerText) + ' ' + '' + '' + '' + '' + ' ' + - '' + - '' + - '' + - '' + - '' + - ''; + '' + + '' + + ''; dropdownList.append(html); } }); + // Restore scroll position + dropdownList.scrollTop(scrollPosition); toggleColumnVisibility(); // toggles grip img customLiHoverEffect(); @@ -1033,9 +1041,11 @@ function changeToEditMode() { dataType: 'json', success: function() { dropdownList.sortable('enable'); - text.text(newName); - $(table.columns().header()).filter('#' + id).text(newName); $(li).clearFormErrors(); + text.html(generateColumnNameTooltip(newName)); + $(table.columns().header()).filter('#' + id) + .html(generateColumnNameTooltip(newName)); + cancelEditMode(); }, error: function(xhr, ajaxOptions, thrownError) { @@ -1142,11 +1152,13 @@ function changeToEditMode() { var self = $(this); var li = self.closest('li'); var url = li.attr('data-destroy-html-url'); + var colIndex = originalHeader.find('#' + li.attr('data-id')).index(); $.ajax({ url: url, type: 'GET', dataType: 'json', + data: {column_index: colIndex}, success: function(data) { var modalBody = modal.find('.modal-body'); @@ -1217,6 +1229,28 @@ function changeToEditMode() { }); } + // calculate the max height of window and adjust dropdown max-height + function dropdownOverflow() { + var windowHeight = $( window ).height(); + var offset = windowHeight - dropdownList.offset().top; + + if(dropdownList.height() >= offset) { + dropdownList.css('maxHeight', offset); + } + } + + function generateColumnNameTooltip(name) { + if( $.trim(name).length > + <%= Constants::NAME_TRUNCATION_LENGTH_DROPDOWN %>) { + return ''; + } else { + return name; + } + } + // initialze dropdown after the table is loaded function initDropdown() { table.on('init.dt', function() { @@ -1230,6 +1264,10 @@ function changeToEditMode() { loadColumnsNames(); dropdownList.sortable('enable'); }); + + $('#samples-columns-dropdown').on('shown.bs.dropdown', function() { + dropdownOverflow(); + }) } initDropdown(); diff --git a/app/assets/javascripts/samples/sample_types_groups.js b/app/assets/javascripts/samples/sample_types_groups.js index ff1fd89f7..8778f26c0 100644 --- a/app/assets/javascripts/samples/sample_types_groups.js +++ b/app/assets/javascripts/samples/sample_types_groups.js @@ -2,6 +2,7 @@ 'use strict'; function showNewSampleTypeGroupForm() { + $('#create-resource').off(); $('#create-resource').on('click', function() { $('.new-resource-form').slideDown(); $('#name-input').focus(); @@ -9,20 +10,15 @@ } function newSampleTypeFormCancel() { + $('#remove').off(); $('#remove').on('click', function() { $('#name-input').val(''); $('.new-resource-form').slideUp(); }); } - function newSampleTypeGroupFormSubmit() { - $('#submit').on('click', function() { - var form = $(this).closest('form'); - form.submit(); - }); - } - - function submitEditSampleTypeGroupForm(button) { + function submitEditSampleTypeGroupForm() { + $('.edit-confirm').off(); $('.edit-confirm').on('click', function() { var form = $(this).closest('form'); form.submit(); @@ -30,11 +26,12 @@ } function abortEditSampleTypeGroupAction() { + $('.abort').off(); $('.abort').on('click', function() { var li = $(this).closest('li'); var href = $(this).attr('data-element'); var id = $(li).attr('data-id'); - + $().clearFormErrors(); $.ajax({ url: href, data: { id: id }, @@ -42,7 +39,7 @@ $(li).replaceWith($.parseHTML(data.html)); editSampleTypeForm(); destroySampleTypeGroup(); - initSampleGroupColor(); + initSampleColorPicker(li) appendCarretToColorPickerDropdown(); editSampleGroupColor(); editSampleGroupForm(); @@ -53,6 +50,7 @@ } function destroySampleTypeGroup() { + $('.delete').off(); $('.delete').on('click', function() { var li = $(this).closest('li'); var href = li.attr('data-delete'); @@ -81,6 +79,7 @@ } function bindNewSampleTypeAction() { + $('#new_sample_type').off(); $('#new_sample_type').bind('ajax:success', function(ev, data) { var li = $.parseHTML(data.html); $('#name-input').val(''); @@ -88,6 +87,7 @@ $(li).insertAfter('.new-resource-form'); editSampleTypeForm(); destroySampleTypeGroup(); + $('#new_sample_type').clearFormErrors(); }).bind('ajax:error', function(ev, error) { $(this).clearFormErrors(); var msg = $.parseJSON(error.responseText); @@ -109,6 +109,7 @@ function editSampleGroupColor() { $(document).ready(function() { + $('.edit_sample_group a.color-btn').off(); $('.edit_sample_group a.color-btn').on('click', function() { var color = $(this).attr('data-value'); var form = $(this).closest('form'); @@ -120,16 +121,18 @@ } function bindNewSampleGroupAction() { + $('#new_sample_group').off(); $('#new_sample_group').bind('ajax:success', function(ev, data) { var li = $.parseHTML(data.html); $('#name-input').val(''); $('.new-resource-form').slideUp(); $(li).insertAfter('.new-resource-form'); - initSampleGroupColor(); + initSampleColorPicker(li); appendCarretToColorPickerDropdown(); editSampleGroupColor(); editSampleGroupForm(); destroySampleTypeGroup(); + $('#new_sample_group').clearFormErrors(); }).bind('ajax:error', function(ev, error) { $(this).clearFormErrors(); var msg = $.parseJSON(error.responseText); @@ -140,7 +143,8 @@ } function editSampleTypeForm() { - $('.edit').on('click', function() { + $('.edit-sample-type').off(); + $('.edit-sample-type').on('click', function() { var li = $(this).closest('li'); $.ajax({ url: li.attr('data-edit'), @@ -150,7 +154,12 @@ submitEditSampleTypeGroupForm(); abortEditSampleTypeGroupAction(); destroySampleTypeGroup(); + $('#edit_sample_type_' + data.id) + .find('[name="sample_type[name]"]') + .focus(); + + $('#edit_sample_type_' + data.id).off(); $('#edit_sample_type_' + data.id) .bind('ajax:success', function(ev, data) { $(this).closest('li').replaceWith($.parseHTML(data.html)); @@ -169,7 +178,8 @@ } function editSampleGroupForm() { - $('.edit').on('click', function() { + $('.edit-sample-group').off(); + $('.edit-sample-group').on('click', function() { var li = $(this).closest('li'); $.ajax({ url: li.attr('data-edit'), @@ -179,16 +189,21 @@ submitEditSampleTypeGroupForm(); abortEditSampleTypeGroupAction(); destroySampleTypeGroup(); - initSampleGroupColor(); + initSampleColorPicker(li); appendCarretToColorPickerDropdown(); editSampleGroupColor(); + $('#edit_sample_group_' + data.id) + .find('[name="sample_group[name]"]') + .focus(); + + $('#edit_sample_group_' + data.id).off(); $('#edit_sample_group_' + data.id) .bind('ajax:success', function(ev, data) { $(this).closest('li').replaceWith($.parseHTML(data.html)); editSampleGroupForm(); destroySampleTypeGroup(); - initSampleGroupColor(); + initSampleColorPicker($(this).closest('li')); appendCarretToColorPickerDropdown(); editSampleGroupColor(); }).bind('ajax:error', function(ev, error){ @@ -212,6 +227,12 @@ }); } + function initSampleColorPicker(el) { + var element = $(el).find('.edit-sample-group-color'); + var color = $(element).closest('[data-color]').attr('data-color'); + $(element).colorselector('setColor', color); + } + /** * Opens adding mode when redirected from samples page, when clicking link for * adding sample type or group link @@ -225,7 +246,6 @@ function initSampleTypesGroups() { showNewSampleTypeGroupForm(); newSampleTypeFormCancel(); - newSampleTypeGroupFormSubmit(); bindNewSampleTypeAction(); editSampleTypeForm(); destroySampleTypeGroup(); diff --git a/app/assets/javascripts/samples/samples.js b/app/assets/javascripts/samples/samples.js index 53488d049..e648e1872 100644 --- a/app/assets/javascripts/samples/samples.js +++ b/app/assets/javascripts/samples/samples.js @@ -1,31 +1,5 @@ //= require datatables -// Create sample group ajax -$("#modal-create-sample-group").on("show.bs.modal", function(event) { - // Clear input when modal is opened - input = $(this).find("input#name-input"); - input.val(""); - input.closest(".form-group").removeClass("has-error"); - input.closest(".form-group").find(".help-block").remove(); -}); - -$("#modal-create-sample-group").on("shown.bs.modal", function(event) { - $(this).find("input#name-input").focus(); -}); - -$("form#new_sample_group").on("ajax:success", function(ev, data, status) { - $("#modal-create-sample-group").modal("hide"); - updateSamplesTypesandGroups(); - sampleAlertMsg(data.flash, "success"); - currentMode = "viewMode"; - updateButtons(); -}); - -$("form#new_sample_group").on("ajax:error", function(e, data, status, xhr) { - $('form').renderFormErrors('sample_group', data.responseJSON, true, e); -}); - - // Create import samples ajax $("#modal-import-samples").on("show.bs.modal", function(event) { formGroup = $(this).find(".form-group"); diff --git a/app/assets/javascripts/sitewide/string_utils.js b/app/assets/javascripts/sitewide/string_utils.js index ff59943e8..44ef3057c 100644 --- a/app/assets/javascripts/sitewide/string_utils.js +++ b/app/assets/javascripts/sitewide/string_utils.js @@ -2,15 +2,24 @@ * Truncate long strings where is necessary. */ function truncateLongString( el, chars ) { - var input = $.trim(el.text()); + if($.type(el) !== 'string'){ + var input = $.trim(el.text()); + } else { + var input = $.trim(el); + } var html = ""; - if( el.children().hasClass("glyphicon") ){ + if( $.type(el) !== 'string' && + el.children().hasClass("glyphicon")) { html = el.children()[0]; } if( input.length >= chars ){ - var newText = el.text().slice(0, chars); + if($.type(el) != 'string') { + var newText = el.text().slice(0, chars); + }else { + var newText = el.slice(0, chars); + } for( var i = newText.length; i > 0; i--){ if(newText[i] === ' ' && i > 10){ newText = newText.slice(0, i); @@ -21,8 +30,14 @@ function truncateLongString( el, chars ) { if ( html ) { el.html(html.outerHTML + newText + '...' ); } else { + if($.type(el) === 'string'){ + return newText + '...'; + } else { el.html(newText + '...' ); + } } + } else { + return el; } } diff --git a/app/assets/stylesheets/sample_types_groups.scss b/app/assets/stylesheets/sample_types_groups.scss index 7ec134c07..c6b41fc7c 100644 --- a/app/assets/stylesheets/sample_types_groups.scss +++ b/app/assets/stylesheets/sample_types_groups.scss @@ -3,6 +3,11 @@ .sample_types_groups_list { margin-top: 50px; + .sample-type-group-name { + display: inline-block; + width: 80%; + } + li { border-bottom: 1px solid $color-alto; padding: 15px 5px; @@ -21,13 +26,16 @@ #remove { margin-left: 5px; - margin-top: 10px; } } + .form-inline .form-group, + .form-inline .form-control { + width: 100%; + } + #name-input { padding: 5px; - width: 203px; } .new-resource-form { @@ -82,26 +90,6 @@ color: $color-black; } } - - .sample-group-controls { - - .edit { - margin-top: 3px; - } - - .delete { - margin-top: 3px; - } - } - - .sample-group-submit { - display: inline-block; - vertical-align: top; - - #submit { - margin-top: 8px; - } - } } #new_sample_group .color-picker { diff --git a/app/assets/stylesheets/themes/scinote.scss b/app/assets/stylesheets/themes/scinote.scss index 78b9085f2..e89f96c92 100644 --- a/app/assets/stylesheets/themes/scinote.scss +++ b/app/assets/stylesheets/themes/scinote.scss @@ -1453,6 +1453,7 @@ html.turbolinks-progress-bar::before { text-align: center; visibility: hidden; width: 200px; + word-wrap: break-word; z-index: $infinity; } } @@ -1596,11 +1597,15 @@ textarea.textarea-sm { // new smart dropdown styles .smart-dropdown { - max-height: 400px; overflow-y: auto; padding: 0; width: 300px; + .modal-tooltiptext { + margin-left: 0; + z-index: 99999999; + } + li { background: $color-white; border: 1px solid $color-alto; @@ -1702,3 +1707,8 @@ textarea.textarea-sm { .add-new-column-form .help-block { margin-left: 0; } + +th.custom-field .modal-tooltiptext { + margin-left: 0; + z-index: 99999999; +} diff --git a/app/controllers/custom_fields_controller.rb b/app/controllers/custom_fields_controller.rb index f549e60a2..04b64a91c 100644 --- a/app/controllers/custom_fields_controller.rb +++ b/app/controllers/custom_fields_controller.rb @@ -53,7 +53,8 @@ class CustomFieldsController < ApplicationController format.json do render json: { html: render_to_string( - partial: 'samples/delete_custom_field_modal_body.html.erb' + partial: 'samples/delete_custom_field_modal_body.html.erb', + locals: { column_index: params[:column_index] } ) } end @@ -61,9 +62,14 @@ class CustomFieldsController < ApplicationController end def destroy + @del_custom_field = @custom_field.dup respond_to do |format| format.json do if @custom_field.destroy + SamplesTable.update_samples_table_state( + @del_custom_field, + params[:custom_field][:column_index] + ) render json: { status: :ok } else render json: { status: :unprocessable_entity } diff --git a/app/controllers/sample_groups_controller.rb b/app/controllers/sample_groups_controller.rb index 62b558055..22433cb53 100644 --- a/app/controllers/sample_groups_controller.rb +++ b/app/controllers/sample_groups_controller.rb @@ -2,6 +2,8 @@ class SampleGroupsController < ApplicationController before_action :load_vars_nested before_action :check_create_permissions before_action :set_sample_group, except: [:create, :index] + before_action :set_project_my_module, only: :index + layout 'fluid' def create @sample_group = SampleGroup.new(sample_group_params) @@ -112,6 +114,15 @@ class SampleGroupsController < ApplicationController private + def set_project_my_module + @project = Project.find_by_id(params[:project_id]) if params[:project_id] + @experiment = Experiment + .find_by_id(params[:experiment_id]) if params[:experiment_id] + @my_module = MyModule + .find_by_id(params[:my_module_id]) if params[:my_module_id] + render_403 unless @project || @my_module + end + def set_sample_group @sample_group = SampleGroup.find_by_id(params[:id]) end diff --git a/app/controllers/sample_types_controller.rb b/app/controllers/sample_types_controller.rb index f726ebf6c..1b0275dee 100644 --- a/app/controllers/sample_types_controller.rb +++ b/app/controllers/sample_types_controller.rb @@ -2,6 +2,8 @@ class SampleTypesController < ApplicationController before_action :load_vars_nested before_action :check_create_permissions before_action :set_sample_type, except: [:create, :index] + before_action :set_project_my_module, only: :index + layout 'fluid' def create @sample_type = SampleType.new(sample_type_params) @@ -112,6 +114,15 @@ class SampleTypesController < ApplicationController private + def set_project_my_module + @project = Project.find_by_id(params[:project_id]) if params[:project_id] + @experiment = Experiment + .find_by_id(params[:experiment_id]) if params[:experiment_id] + @my_module = MyModule + .find_by_id(params[:my_module_id]) if params[:my_module_id] + render_403 unless @project || @my_module + end + def load_vars_nested @organization = Organization.find_by_id(params[:organization_id]) diff --git a/app/controllers/user_samples_controller.rb b/app/controllers/user_samples_controller.rb index 2a3a33959..a499420e1 100644 --- a/app/controllers/user_samples_controller.rb +++ b/app/controllers/user_samples_controller.rb @@ -21,6 +21,7 @@ class UserSamplesController < ApplicationController def load_samples_table_status @samples_table_state = SamplesTable.find_status(current_user, current_organization).first + respond_to do |format| if @samples_table_state format.json do diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c8fa861cd..31990a632 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -11,4 +11,45 @@ module ApplicationHelper controller_name == 'projects' || (controller_name == 'reports' && action_name == 'index') end + + def display_tooltip(message, len = Constants::NAME_TRUNCATION_LENGTH) + if message.strip.length > Constants::NAME_TRUNCATION_LENGTH + "".html_safe + else + truncate(message.strip, length: len) + end + end + + def sample_types_page_project? + controller_name == 'sample_types' && + @my_module.nil? && + @experiment.nil? + end + + def sample_groups_page_project? + controller_name == 'sample_groups' && + @my_module.nil? && + @experiment.nil? + end + + def sample_types_page_my_module? + controller_name == 'sample_types' && !@my_module.nil? + end + + def sample_groups_page_my_module? + controller_name == 'sample_groups' && !@my_module.nil? + end + + def sample_groups_page_experiment? + controller_name == 'sample_groups' && + @my_module.nil? && + !@experiment.nil? + end + + def sample_types_page_expermient? + controller_name == 'sample_types' && + @my_module.nil? && + !@experiment.nil? + end end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index f43975f57..039a0a3aa 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -18,6 +18,6 @@ class CustomField < ActiveRecord::Base after_create :update_samples_table_state def update_samples_table_state - SamplesTable.update_samples_table_state(self) + SamplesTable.update_samples_table_state(self, nil) end end diff --git a/app/models/samples_table.rb b/app/models/samples_table.rb index 40ce10181..1e8775df7 100644 --- a/app/models/samples_table.rb +++ b/app/models/samples_table.rb @@ -5,16 +5,37 @@ class SamplesTable < ActiveRecord::Base belongs_to :organization, inverse_of: :samples_tables scope :find_status, - ->(org, user) { where(user: user, organization: org).pluck(:status) } + ->(user, org) { where(user: user, organization: org).pluck(:status) } - def self.update_samples_table_state(custom_field) + def self.update_samples_table_state(custom_field, column_index) samples_table = SamplesTable.where(user: custom_field.user, organization: custom_field.organization) org_status = samples_table.first['status'] - index = org_status['columns'].count - org_status['columns'][index] = SampleDatatable:: - SAMPLES_TABLE_DEFAULT_STATE['columns'].first - org_status['ColReorder'] << index.to_s + if column_index + org_status['columns'].delete(column_index) + org_status['columns'].keys.each do |index| + p index + if index.to_i > column_index.to_i + org_status['columns'][(index.to_i - 1).to_s] = + org_status['columns'].delete(index) + else + index + end + end + org_status['ColReorder'].delete(column_index) + org_status['ColReorder'].map! do |index| + if index.to_i > column_index.to_i + (index.to_i - 1).to_s + else + index + end + end + else + index = org_status['columns'].count + org_status['columns'][index] = SampleDatatable:: + SAMPLES_TABLE_DEFAULT_STATE['columns'].first + org_status['ColReorder'] << index.to_s + end samples_table.first.update(status: org_status) end diff --git a/app/views/sample_groups/_edit.html.erb b/app/views/sample_groups/_edit.html.erb index 36b1a45b5..5a3582159 100644 --- a/app/views/sample_groups/_edit.html.erb +++ b/app/views/sample_groups/_edit.html.erb @@ -4,28 +4,23 @@ sample_group)%>" data-color="<%= sample_group.color %>">
-
<%= form_for [organization, sample_group], html: { class: 'form-inline' }, remote: true do |f| %> -
- <%= f.text_field :name, value: sample_group.name , class: 'form-control' %> - - +
+
+ <%= f.text_field :name, value: sample_group.name , class: 'form-control' %> +
+
+
+ +
<% end %>
-
- - - <%= bootstrap_form_for [organization, sample_group], remote: true do |f| %> - <%= f.color_picker_select :color, - Constants::TAG_COLORS, - class: 'edit-sample-group-color' %> - <% end %> - - - -
diff --git a/app/views/sample_groups/_sample_group.html.erb b/app/views/sample_groups/_sample_group.html.erb index 3bad4a827..12aae7f98 100644 --- a/app/views/sample_groups/_sample_group.html.erb +++ b/app/views/sample_groups/_sample_group.html.erb @@ -5,7 +5,7 @@ organization_sample_group_destroy_confirmation_path(organization, sample_group) %>" data-color="<%= sample_group.color %>"> - <%= sample_group.name %> + <%= sample_group.name %> <%= bootstrap_form_for [organization, sample_group], remote: true do |f| %> @@ -14,7 +14,7 @@ class: 'edit-sample-group-color' %> <% end %> - + diff --git a/app/views/sample_groups/index.html.erb b/app/views/sample_groups/index.html.erb index 5c388d800..66785d43b 100644 --- a/app/views/sample_groups/index.html.erb +++ b/app/views/sample_groups/index.html.erb @@ -1,14 +1,22 @@ <% provide(:head_title, t('sample_groups.index.head_title')) %> +<%= render partial: "shared/sidebar" %> +<%= render partial: "shared/secondary_navigation" %> <% if current_organization %>
@@ -21,27 +29,25 @@