//= require jquery-ui/widgets/sortable // Extend datatables API with searchable options // (http://stackoverflow.com/questions/39912395/datatables-dynamically-set-columns-searchable) $.fn.dataTable.Api.register('isColumnSearchable()', function(colSelector) { var idx = this.column(colSelector).index(); return this.settings()[0].aoColumns[idx].bSearchable; }); $.fn.dataTable.Api.register('setColumnSearchable()', function(colSelector, value) { if (value !== this.isColumnSearchable(colSelector)) { var idx = this.column(colSelector).index(); this.settings()[0].aoColumns[idx].bSearchable = value; if (value === true) { this.rows().invalidate(); } } return value; }); var rowsSelected = []; // Tells whether we're currently viewing or editing table var currentMode = 'viewMode'; // Tells what action will execute by pressing on save button (update/create) var saveAction = 'update'; var selectedSample; // Helps saving correct table state var myData; var loadFirstTime = true; var table; var originalHeader; var view_assigned; function dataTableInit() { // Make a copy of original samples table header originalHeader = $('#samples thead').children().clone(); view_assigned = 'assigned'; table = $('#samples').DataTable({ order: [[2, 'desc']], dom: "R<'row'<'col-sm-9-custom toolbar'l><'col-sm-3-custom'f>>tpi", stateSave: true, processing: true, serverSide: true, sScrollX: '100%', sScrollXInner: '100%', scrollY: '64vh', scrollCollapse: true, colReorder: { fixedColumnsLeft: 2, realtime: false }, destroy: true, ajax: { url: $('#samples').data('source'), data: function ( d ) { d.assigned = view_assigned; }, global: false, type: 'POST' }, columnDefs: [{ targets: 0, searchable: false, orderable: false, className: 'dt-body-center', sWidth: '1%', render: function() { return ""; } }, { targets: 1, searchable: false, orderable: true, sWidth: '1%' }, { targets: 2, render: function(data, type, row) { return "" + data + ''; } }], rowCallback: function(row, data) { // Get row ID var rowId = data.DT_RowId; // If row ID is in the list of selected row IDs if ($.inArray(rowId, rowsSelected) !== -1) { $(row).find('input[type="checkbox"]').prop('checked', true); $(row).addClass('selected'); } }, columns: (function() { var numOfColumns = $('#samples').data('num-columns'); var columns = []; for (var i = 0; i < numOfColumns; i++) { var visible = (i <= 6); columns.push({ data: String(i), defaultContent: '', visible: visible, searchable: visible }); } return columns; })(), fnDrawCallback: function() { animateSpinner(this, false); changeToViewMode(); updateButtons(); // Show number of selected samples info $('#samples_info').append(''); $('#selected_info').html(' ('+rowsSelected.length+' entries selected)'); }, preDrawCallback: function() { rowsSelected = []; animateSpinner(this); $('.sample-info-link').off('click'); }, stateLoadCallback: function(settings) { // Send an Ajax request to the server to get the data. Note that // this is a synchronous request since the data is expected back from the // function var team = $('#samples').attr('data-team-id'); var user = $('#samples').attr('data-user-id'); $.ajax({ url: '/state_load/' + team + '/' + user, data: {team: team}, async: false, dataType: 'json', type: 'POST', success: function(json) { myData = json.state; } }); return myData; }, stateSaveCallback: function(settings, data) { // Send an Ajax request to the server with the state object var team = $('#samples').attr('data-team-id'); var user = $('#samples').attr('data-user-id'); // Save correct data if (loadFirstTime == true) { data = myData; } $.ajax({ url: '/state_save/' + team + '/' + user, data: {team: team, state: data}, dataType: 'json', type: 'POST' }); loadFirstTime = false; }, fnInitComplete: function(oSettings, json) { // Reload correct column order and visibility (if you refresh page) for (var i = 0; i < table.columns()[0].length; i++) { var visibility = false; if (myData.columns[i]) { visibility = myData.columns[i].visible; } if (typeof (visibility) === 'string') { visibility = (visibility === 'true'); } table.column(i).visible(visibility); table.setColumnSearchable(i, visibility); } oSettings._colReorder.fnOrder(myData.ColReorder); table.on('mousedown', function() { $('#samples-columns-dropdown').removeClass('open'); }); initHeaderTooltip(); } }); // Append button to inner toolbar in table $('div.toolbarButtons').appendTo('div.toolbar'); $('div.toolbarButtons').show(); $('.delete_samples_submit').click(function() { animateLoading(); }); $('#assignSamples, #unassignSamples').click(function() { animateLoading(); }); // Handle click on table cells with checkboxes $('#samples').on('click', 'tbody td, thead th:first-child', function(e) { if (!$(e.target).is('.sample-info-link')) { // Skip if clicking on samples info link $(this).parent().find('input[type="checkbox"]').trigger('click'); } }); // Handle clicks on checkbox $('#samples tbody').on('click', "input[type='checkbox']", function(e) { if (currentMode !== 'viewMode') { return false; } // Get row ID var $row = $(this).closest('tr'); var data = table.row($row).data(); var rowId = data.DT_RowId; // Determine whether row ID is in the list of selected row IDs var index = $.inArray(rowId, rowsSelected); // If checkbox is checked and row ID is not in list of selected row IDs if (this.checked && index === -1) { rowsSelected.push(rowId); // Otherwise, if checkbox is not checked and row ID is in list of selected row IDs } else if (!this.checked && index !== -1) { rowsSelected.splice(index, 1); } if (this.checked) { $row.addClass('selected'); } else { $row.removeClass('selected'); } updateDataTableSelectAllCtrl(table); e.stopPropagation(); updateButtons(); // Update number of selected samples info $('#selected_info').html(' ('+ rowsSelected.length +' entries selected)'); }); // Handle click on "Select all" control $('.dataTables_scrollHead input[name="select_all"]').on('click', function(e) { if (this.checked) { $('#samples tbody input[type="checkbox"]:not(:checked)').trigger('click'); } else { $('#samples tbody input[type="checkbox"]:checked').trigger('click'); } // Prevent click event from propagating to parent e.stopPropagation(); }); // Handle table draw event table.on('draw', function() { updateDataTableSelectAllCtrl(table); sampleInfoListener(); // Prevent sample row toggling when selecting user smart annotation link SmartAnnotation.preventPropagation('.atwho-user-popover'); }); table.on('column-reorder', function() { sampleInfoListener(); }); return table; } table = dataTableInit(); // Timeout for table header scrolling setTimeout(function () { table.columns.adjust(); }, 10); // Updates "Select all" control in a data table function updateDataTableSelectAllCtrl(table) { var $table = table.table().node(); var $header = table.table().header(); var $chkbox_all = $('tbody input[type="checkbox"]', $table); var $chkbox_checked = $('tbody input[type="checkbox"]:checked', $table); var chkbox_select_all = $('input[name="select_all"]', $header).get(0); // If none of the checkboxes are checked if($chkbox_checked.length === 0){ chkbox_select_all.checked = false; if('indeterminate' in chkbox_select_all){ chkbox_select_all.indeterminate = false; } // If all of the checkboxes are checked } else if ($chkbox_checked.length === $chkbox_all.length){ chkbox_select_all.checked = true; if('indeterminate' in chkbox_select_all){ chkbox_select_all.indeterminate = false; } // If some of the checkboxes are checked } else { chkbox_select_all.checked = true; if('indeterminate' in chkbox_select_all){ chkbox_select_all.indeterminate = true; } } } // Append selected samples to form $("form#form-samples").submit(function(e){ var form = this; if (currentMode == "viewMode") appendSamplesIdToForm(form); }); // Append selected samples and headers form $("form#form-export").submit(function(e){ var form = this; if (currentMode == "viewMode") { // Remove all hidden fields $("#form-export").find("input[name=sample_ids\\[\\]]").remove(); $("#form-export").find("input[name=header_ids\\[\\]]").remove(); // Append samples appendSamplesIdToForm(form); // Append visible column information $("table#samples thead tr").children("th").each(function(i) { var th = $(this); var val; if ($(th).attr("id") == "sample-name") val = -1; else if ($(th).attr("id") == "sample-type") val = -2; else if ($(th).attr("id") == "sample-group") val = -3; else if ($(th).attr("id") == "added-by") val = -4; else if ($(th).attr("id") == "added-on") val = -5; else if ($(th).hasClass("custom-field")) val = th.attr("id"); if (val) $(form).append( $('') .attr('type', 'hidden') .attr('name', 'header_ids[]') .val(val) ); }); } }); function appendSamplesIdToForm(form) { $.each(rowsSelected, function(index, rowId){ $(form).append( $('') .attr('type', 'hidden') .attr('name', 'sample_ids[]') .val(rowId) ); }); } function initHeaderTooltip() { // Fix compatibility of fixed table header and column names modal-tooltip $('.modal-tooltip').off(); $('.modal-tooltip').hover(function() { var $tooltip = $(this).find('.modal-tooltiptext'); var offsetLeft = $tooltip.offset().left; (offsetLeft + 200) > $(window).width() ? offsetLeft -= 150 : offsetLeft; var offsetTop = $tooltip.offset().top; $('body').append($tooltip); $tooltip.css('background-color', '#d2d2d2'); $tooltip.css('border-radius', '6px'); $tooltip.css('color', '#333'); $tooltip.css('display', 'block'); $tooltip.css('left', offsetLeft + 'px'); $tooltip.css('padding', '5px'); $tooltip.css('position', 'absolute'); $tooltip.css('text-align', 'center'); $tooltip.css('top', offsetTop + 'px'); $tooltip.css('visibility', 'visible'); $tooltip.css('width', '200px'); $tooltip.css('word-wrap', 'break-word'); $(this).data('dropdown-tooltip', $tooltip); }, function() { $(this).append($(this).data('dropdown-tooltip')); $(this).data('dropdown-tooltip').removeAttr('style'); }); } //Show sample info function sampleInfoListener() { $(".sample_info").on("click", function(e){ $("#modal-info-sample").remove(); var that = $(this); $.ajax({ method: "GET", url: that.attr("data-href") + '.json', dataType: "json" }).done(function(xhr, settings, data) { $("body").append($.parseHTML(data.responseJSON.html)); $("#modal-info-sample").modal('show',{ backdrop: true, keyboard: false, }).on('hidden.bs.modal', function () { $(this).find(".modal-body #sample-info-table").DataTable().destroy(); $(this).remove(); }); $('#sample-info-table').DataTable({ dom: "RBltpi", stateSave: false, buttons: [], processing: true, colReorder: { fixedColumnsLeft: 1000000 // Disable reordering }, columnDefs: [{ targets: 0, searchable: false, orderable: false }], fnDrawCallback: function(settings, json) { animateSpinner(this, false); }, preDrawCallback: function(settings) { animateSpinner(this); } }); }).fail(function(error){ // TODO }).always(function(data){ // TODO }); e.preventDefault(); return false; }); } // Edit sample function onClickEdit() { if (rowsSelected.length != 1) return; var row = table.row("#" + rowsSelected[0]); var node = row.node(); var rowData = row.data(); $(node).find("td input").trigger("click"); selectedSample = node; clearAllErrors(); changeToEditMode(); updateButtons(); saveAction = "update"; $.ajax({ url: rowData["sampleEditUrl"], type: "GET", dataType: "json", success: function (data) { // Show save and cancel buttons in first two columns $(node).children("td").eq(0).html($("#saveSample").clone()); $(node).children("td").eq(1).html($("#cancelSave").clone()); // Sample name column var colIndex = getColumnIndex("#sample-name"); if (colIndex) { $(node).children("td").eq(colIndex).html(changeToInputField("sample", "name", data["sample"]["name"])); } // Sample type column var colIndex = getColumnIndex("#sample-type"); if (colIndex) { var selectType = createSampleTypeSelect(data["sample_types"], data["sample"]["sample_type"]); $(node).children("td").eq(colIndex).html(selectType); $("select[name=sample_type_id]").selectpicker(); } // Sample group column var colIndex = getColumnIndex("#sample-group"); if (colIndex) { var selectGroup = createSampleGroupSelect(data["sample_groups"], data["sample"]["sample_group"]); $(node).children("td").eq(colIndex).html(selectGroup); $("select[name=sample_group_id]").selectpicker(); } // Take care of custom fields var cfields = data["sample"]["custom_fields"]; $(node).children("td").each(function(i) { var td = $(this); var rawIndex = table.column.index("fromVisible", i); var colHeader = table.column(rawIndex).header(); if ($(colHeader).hasClass("custom-field")) { // Check if custom field on this sample exists var cf = cfields[$(colHeader).attr("id")]; if (cf) td.html(changeToInputField("sample_custom_fields", cf["sample_custom_field_id"], cf["value"])); else td.html(changeToInputField("custom_fields", $(colHeader).attr("id"), "")); } }); // initialize smart annotation SmartAnnotation.init($('[data-object="sample_custom_fields"]')); _.each($('[data-object="custom_fields"]'), function(el) { if(_.isUndefined($(el).data('atwho'))) { SmartAnnotation.init(el); } }); // Adjust columns width in table header adjustTableHeader(); }, error: function (e, data, status, xhr) { if (e.status == 403) { HelperModule.flashAlertMsg( I18n.t('samples.js.permission_error'), e.responseJSON.style ); changeToViewMode(); updateButtons(); } } }); } // Save sample function onClickSave() { if (saveAction == "update") { var row = table.row(selectedSample); var node = row.node(); var rowData = row.data(); } else if (saveAction == "create") var node = selectedSample; // First fetch all the data in input fields data = { request_url: $('#samples').data('current-uri'), sample_id: $(selectedSample).attr("id"), sample: {}, custom_fields: {}, // These fields are not currently bound to this sample sample_custom_fields: {} // These fields are already in database (linked to this sample) }; // Direct sample attributes // Sample name $(node).find("td input[data-object = sample]").each(function() { data["sample"][$(this).attr("name")] = $(this).val(); }); // Sample type $(node).find("td select[name = sample_type_id]").each(function() { data["sample"]["sample_type_id"] = $(this).val(); }); // Sample group $(node).find("td select[name = sample_group_id]").each(function() { data["sample"]["sample_group_id"] = $(this).val(); }); // Custom fields (new fields) $(node).find("td input[data-object = custom_fields]").each(function () { // Send data only and only if string is not empty if ($(this).val().trim()) { data["custom_fields"][$(this).attr("name")] = $(this).val(); } }); // Sample custom fields (existent fields) $(node).find("td input[data-object = sample_custom_fields]").each(function () { data["sample_custom_fields"][$(this).attr("name")] = $(this).val(); }); var url = (saveAction == "update" ? rowData["sampleUpdateUrl"] : $("table#samples").data("create-sample")) var type = (saveAction == "update" ? "PUT" : "POST") $.ajax({ url: url, type: type, dataType: "json", data: data, success: function (data) { HelperModule.flashAlertMsg(data.flash, 'success'); onClickCancel(); }, error: function (e, eData, status, xhr) { var data = e.responseJSON; clearAllErrors(); if (e.status == 404) { HelperModule.flashAlertMsg( I18n.t('samples.js.not_found_error'), 'danger' ); changeToViewMode(); updateButtons(); } else if (e.status == 403) { HelperModule.flashAlertMsg( I18n.t('samples.js.permission_error'), 'danger' ); changeToViewMode(); updateButtons(); } else if (e.status == 400) { if (data["init_fields"]) { var init_fields = data["init_fields"]; // Validate sample name if (init_fields["name"]) { var input = $(selectedSample).find("input[name=name]"); if (input) { input.closest(".form-group").addClass("has-error"); input.parent().append("" + init_fields["name"] + "
"); } } }; // Validate custom fields $.each(data["custom_fields"] || [], function(key, val) { $.each(val, function(key, val) { var input = $(selectedSample).find("input[name=" + key + "]"); if (input) { input.closest(".form-group").addClass("has-error"); input.parent().append("" + val["value"][0] + "
"); } }); }); // Validate sample custom fields $.each(data["sample_custom_fields"] || [], function(key, val) { $.each(val, function(key, val) { var input = $(selectedSample).find("input[name=" + key + "]"); if (input) { input.closest(".form-group").addClass("has-error"); input.parent().append("" + val["value"][0] + "
"); } }); }); } } }); } // Enable/disable edit button function updateButtons() { if (currentMode=="viewMode") { $("#importSamplesButton").removeClass("disabled"); $("#importSamplesButton").prop("disabled",false); $("#addSample").removeClass("disabled"); $("#addSample").prop("disabled",false); $("#addNewColumn").removeClass("disabled"); $("#addNewColumn").prop("disabled",false); $('#samples-columns-dropdown') .find('.dropdown-toggle') .prop("disabled",false); $("th").removeClass('disable-click'); if (rowsSelected.length == 1) { $("#editSample").prop("disabled", false); $("#editSample").removeClass("disabled"); $("#deleteSamplesButton").prop("disabled", false); $("#deleteSamplesButton").removeClass("disabled"); $("#exportSamplesButton").removeClass("disabled"); $("#exportSamplesButton").prop("disabled",false); $("#exportSamplesButton").on("click", function() { $('#modal-export-samples-success') .modal('show') .on('hidden.bs.modal', function() { animateSpinner(null, true); $('#form-export').submit(); }); }); $("#assignSamples").removeClass("disabled"); $("#assignSamples").prop("disabled", false); $("#unassignSamples").removeClass("disabled"); $("#unassignSamples").prop("disabled", false); } else if (rowsSelected.length == 0) { $("#editSample").prop("disabled", true); $("#editSample").addClass("disabled"); $("#deleteSamplesButton").prop("disabled", true); $("#deleteSamplesButton").addClass("disabled"); $("#exportSamplesButton").addClass("disabled"); $("#exportSamplesButton").prop("disabled",true); $("#exportSamplesButton").off("click"); $("#assignSamples").addClass("disabled"); $("#assignSamples").prop("disabled", true); $("#unassignSamples").addClass("disabled"); $("#unassignSamples").prop("disabled", true); } else { $("#editSample").prop("disabled", true); $("#editSample").addClass("disabled"); $("#deleteSamplesButton").prop("disabled", false); $("#deleteSamplesButton").removeClass("disabled"); $("#exportSamplesButton").removeClass("disabled"); $("#exportSamplesButton").prop("disabled",false); $("#exportSamplesButton").on("click", function() { $('#modal-export-samples-success') .modal('show') .on('hidden.bs.modal', function() { animateSpinner(null, true); $('#form-export').submit(); }); }); $("#assignSamples").removeClass("disabled"); $("#assignSamples").prop("disabled", false); $("#unassignSamples").removeClass("disabled"); $("#unassignSamples").prop("disabled", false); } } else if (currentMode=="editMode") { $("#importSamplesButton").addClass("disabled"); $("#importSamplesButton").prop("disabled",true); $("#addSample").addClass("disabled"); $("#addSample").prop("disabled",true); $("#editSample").addClass("disabled"); $("#editSample").prop("disabled",true); $("#addNewColumn").addClass("disabled"); $("#addNewColumn").prop("disabled", true); $("#exportSamplesButton").addClass("disabled"); $("#exportSamplesButton").off("click"); $("#deleteSamplesButton").addClass("disabled"); $("#deleteSamplesButton").prop("disabled",true); $("#assignSamples").addClass("disabled"); $("#assignSamples").prop("disabled", true); $("#unassignSamples").addClass("disabled"); $("#unassignSamples").prop("disabled", true); $('#samples-columns-dropdown') .find('.dropdown-toggle') .prop("disabled",true); $("th").addClass('disable-click'); } } // Clear all has-error tags function clearAllErrors() { // Remove any validation errors $(selectedSample).find(".has-error").each(function() { $(this).removeClass("has-error"); $(this).find("span").remove(); }); // Remove any alerts $("#alert-container").find("div").remove(); } // Restore previous table function onClickCancel() { table.draw('page'); changeToViewMode(); updateButtons(); } function onClickAddSample() { changeToEditMode(); updateButtons(); saveAction = "create"; $.ajax({ url: $("table#samples").data("new-sample"), type: "GET", dataType: "json", success: function (data) { var tr = document.createElement("tr") $("table#samples thead tr").children("th").each(function(i) { var th = $(this); if ($(th).attr("id") == "checkbox") { var td = createTdElement(""); $(td).html($("#saveSample").clone()); tr.appendChild(td); } else if ($(th).attr("id") == "assigned") { var td = createTdElement(""); $(td).html($("#cancelSave").clone()); tr.appendChild(td); } else if ($(th).attr("id") == "sample-name") { var input = changeToInputField("sample", "name", ""); tr.appendChild(createTdElement(input)); } else if ($(th).attr("id") == "sample-type") { var colIndex = getColumnIndex("#sample-type") if (colIndex) { var selectType = createSampleTypeSelect(data["sample_types"]); var td = createTdElement(""); td.appendChild(selectType[0]); tr.appendChild(td); } } else if ($(th).attr("id") == "sample-group") { var colIndex = getColumnIndex("#sample-group") if (colIndex) { var selectGroup = createSampleGroupSelect(data["sample_groups"]); var td = createTdElement(""); td.appendChild(selectGroup[0]); tr.appendChild(td); } } else if ($(th).hasClass("custom-field")) { var input = changeToInputField("custom_fields", th.attr("id"), ""); tr.appendChild(createTdElement(input)); } else { // Column we don't care for, just add empty td tr.appendChild(createTdElement("")); } }); $("table#samples").prepend(tr); selectedSample = tr; // Init dropdown with icons $("select[name=sample_group_id]").selectpicker(); $("select[name=sample_type_id]").selectpicker(); // initialize smart annotation _.each($('[data-object="custom_fields"]'), function(el) { if(_.isUndefined($(el).data('atwho'))) { SmartAnnotation.init(el); } }); // Adjust columns width in table header adjustTableHeader(); }, error: function (e, eData, status, xhr) { if (e.status == 403) HelperModule.flashAlertMsg( I18n.t('samples.js.permission_error'), 'danger' ); changeToViewMode(); updateButtons(); } }); } $('#assignedSamples').on('click', function () { view_assigned = 'assigned'; table.draw(); }); $('#allSamples').on('click', function () { view_assigned = 'all'; table.draw(); }); // Handle enter key $(document).off('keypress').keypress(function(event) { var keycode = (event.keyCode ? event.keyCode : event.which); if (currentMode === 'editMode' && keycode === '13') { $('#saveSample').click(); return false; } }); // Helper functions function getColumnIndex(id) { if (id < 0) { return false; } return table.column(id).index('visible'); } // Takes object and surrounds it with input function changeToInputField(object, name, value) { return "
"; } // Return td element with content function createTdElement(content) { var td = document.createElement('td'); td.innerHTML = content; return td; } // Adjust columns width in table header function adjustTableHeader() { table.columns.adjust(); $('.dropdown-menu').parent().on('shown.bs.dropdown hidden.bs.dropdown', function () { table.columns.adjust(); }); } /** * Creates select dropdown for sample type * @param {Object[]} data List of sample types * @param {number} selected Selected sample type id * @return {Object} select dropdown */ function createSampleTypeSelect(data, selected) { var $selectType = $('') .attr('name', 'sample_type_id').addClass('show-tick'); $option = $('') .attr('value', -1).text(I18n.t('samples.table.no_type')) $selectType.append($option); $.each(data, function(i, val) { var $option = $('') .attr('value', val.id).text(val.name); if(val.id === selected) { $option.attr('selected', true); } $selectType.append($option); }); return $selectType; } /** * Creates select dropdown for sample group * @param data List of sample groups * @param selected Selected sample group id */ function createSampleGroupSelect(data, selected) { var $selectGroup = $('') .attr('name', 'sample_group_id').addClass('show-tick'); $option = $('') .attr('value', -1).text(I18n.t('samples.table.no_group')) .attr('data-icon', 'fas fa-asterisk'); $selectGroup.append($option); $.each(data, function(i, val) { var $span = $('').addClass('fas fa-asterisk') .css('color', val.color); var $option = $('') .attr('value', val.id).text(val.name) .attr('data-content', $span.prop('outerHTML') + ' ' + val.name); if(val.id === selected) { $option.attr('selected', true); } $selectGroup.append($option); }); return $selectGroup; } function changeToViewMode() { currentMode = 'viewMode'; // $("#saveCancel").hide(); // Table specific stuff table.button(0).enable(true); } function changeToEditMode() { currentMode = 'editMode'; // $("#saveCancel").show(); // Table specific stuff table.button(0).enable(false); } /* * Sample columns dropdown */ (function(table) { 'use strict'; var dropdown = $('#samples-columns-dropdown'); var dropdownList = $('#samples-columns-list'); var columnEditMode = false; function createNewColumn() { // Make an Ajax request to custom_fields_controller var url = $('#new-column-form').data('action'); var columnName = $('#new-column-name').val(); if (columnName.length > 0) { $.ajax({ method: 'POST', dataType: 'json', data: {custom_field: {name: columnName}}, error: function(data) { var form = $('#new-column-form'); form.addClass('has-error'); form.find('.help-block').remove(); form.append('' + data.responseJSON.name + ''); }, success: function(data) { var form = $('#new-column-form'); form.find('.help-block').remove(); if (form.hasClass('has-error')) { form.removeClass('has-error'); } $('#new-column-name').val(''); form.append('' + I18n.t('samples.js.column_added') + ''); // Preserve save/delete buttons as we need them after new table // will be created $('div.toolbarButtons').appendTo('div.samples-table'); $('div.toolbarButtons').hide(); // Destroy datatable table.destroy(); // Add number of columns $('#samples').data('num-columns', $('#samples').data('num-columns') + 1); // Add column to table (=table header) originalHeader.append( '' + generateColumnNameTooltip(data.name) + ''); // Remove all event handlers as we re-initialize them later with // new table $('#samples').off(); $('#samples thead').empty(); $('#samples thead').append(originalHeader); // Re-initialize datatable table = dataTableInit(); table.on('init.dt', function() { loadColumnsNames(); dropdownOverflow(); }); }, url: url }); } else { var form = $('#new-column-form'); form.addClass('has-error'); form.find('.help-block').remove(); form.append('' + I18n.t('samples.js.empty_column_name') + ''); } } function initNewColumnForm() { $('#samples-columns-dropdown').on('show.bs.dropdown', function() { // Clear input and errors when dropdown is opened var input = $(this).find('input#new-column-name'); input.val(''); var form = $('#new-column-form'); if (form.hasClass('has-error')) { form.removeClass('has-error'); } form.find('.help-block').remove(); }); $('#add-new-column-button').click(function(e) { e.stopPropagation(); createNewColumn(); }); $('#new-column-name').keydown(function(e) { if (e.keyCode === 13) { e.preventDefault(); createNewColumn(); } }); } // loads the columns names in the dropdown list function loadColumnsNames() { // 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) { var colIndex = $(el).attr('data-column-index'); var visible = table.column(colIndex).visible(); var editable = $(el).is('[data-editable]'); var deletable = $(el).is('[data-deletable]'); var visClass = (visible) ? 'fa-eye' : 'fa-eye-slash'; var visLi = (visible) ? '' : 'col-invisible'; var editClass = (editable) ? '' : 'disabled'; var delClass = (deletable) ? '' : 'disabled'; var thederName; if ($(el).find('.modal-tooltiptext').length > 0) { thederName = $(el).find('.modal-tooltiptext').text(); } else { thederName = el.innerText; } var html = '
  • ' + ' ' + '' + generateColumnNameTooltip(thederName) + ' ' + '' + '' + '' + '' + '"> ' + '">' + '">' + '
  • '; dropdownList.append(html); } }); // Restore scroll position dropdownList.scrollTop(scrollPosition); toggleColumnVisibility(); // toggles grip img customLiHoverEffect(); } function customLiHoverEffect() { var liEl = dropdownList.find('li'); liEl.mouseover(function() { $(this) .find('.grippy') .addClass('grippy-img'); }).mouseout(function() { $(this) .find('.grippy') .removeClass('grippy-img'); }); } function toggleColumnVisibility() { var lis = dropdownList.find('.vis'); lis.on('click', function(event) { event.stopPropagation(); var self = $(this); var li = self.closest('li'); var column = table.column(li.attr('data-position')); if (column.visible()) { self.addClass('fa-eye-slash'); self.removeClass('fas fa-eye'); li.addClass('col-invisible'); column.visible(false); table.setColumnSearchable(column.index(), false); } else { self.addClass('fas fa-eye'); self.removeClass('fa-eye-slash'); li.removeClass('col-invisible'); column.visible(true); table.setColumnSearchable(column.index(), true); initHeaderTooltip(); } // Re-filter/search if neccesary var searchText = $('div.dataTables_filter input').val(); if (!_.isEmpty(searchText)) { table.search(searchText).draw(); } sampleInfoListener(); }); } function initSorting() { dropdownList.sortable({ items: 'li:not(.add-new-column-form)', cancel: '.new-samples-column', axis: 'y', update: function() { var reorderer = table.colReorder; var listIds = []; // We skip first two columns listIds.push(0, 1); dropdownList.find('li[data-position]').each(function() { listIds.push($(this).first().data('position')); }); reorderer.order(listIds, false); loadColumnsNames(); } }); } function initEditColumns() { function cancelEditMode() { dropdownList.find('.text-edit').hide(); dropdownList.find('.controls .ok,.cancel').hide(); dropdownList.find('.text').css('display', ''); // show() doesn't work dropdownList.find('.controls .vis,.edit,.del').css('display', ''); // show() doesn't work columnEditMode = false; } function editColumn(li) { var id = li.attr('data-id'); var text = li.find('.text'); var textEdit = li.find('.text-edit'); var newName = textEdit.val().trim(); var url = li.attr('data-update-url'); $.ajax({ url: url, type: 'PUT', data: {custom_field: {name: newName}}, dataType: 'json', success: function() { dropdownList.sortable('enable'); $(li).clearFormErrors(); text.html(generateColumnNameTooltip(newName)); $(table.columns().header()).filter('#' + id) .html(generateColumnNameTooltip(newName)); originalHeader.find('#' + id).html(newName); cancelEditMode(); initHeaderTooltip(); }, error: function(xhr) { dropdownList.sortable('disable'); $(li).clearFormErrors(); var msg = $.parseJSON(xhr.responseText); renderFormError(xhr, $(li).find('.text-edit'), Object.keys(msg)[0] + ' ' + msg.name.toString()); var verticalHeight = $(li).offset().top; dropdownList.scrollTo(verticalHeight,0); } }); } // On edit buttons click (bind onto master dropdown list) dropdownList.on('click', '.edit:not(.disabled)', function(event) { event.stopPropagation(); // Clear all input errors _.each(dropdownList, function(el) { $(el).clearFormErrors(); }); cancelEditMode(); var li = $(this).closest('li'); var url = li.attr('data-edit-url'); ajaxCallEvent(); function ajaxCallEvent(){ $.ajax({ url: url, success: function() { var text, textEdit, controls, controlsEdit; text = li.find('.text'); if ($(text).find('.modal-tooltiptext').length > 0) { text = $(text).find('.modal-tooltiptext'); } textEdit = li.find('.text-edit'); controls = li.find('.controls .vis,.edit,.del'); controlsEdit = li.find('.controls .ok,.cancel'); // Toggle edit mode columnEditMode = true; li.addClass('editing'); // Set the text-edit's value textEdit.val(text.text().trim()); // Toggle elements text.hide(); controls.hide(); textEdit.css('display', ''); // show() doesn't work controlsEdit.css('display', ''); // show() doesn't work dropdownList.sortable('disable'); dropdownList.on('click', function(ev) { ev.stopPropagation(); }); // Focus input textEdit.focus(); }, error: function(e) { $(li).clearFormErrors(); var msg = $.parseJSON(e.responseText); renderFormError(undefined, $(li).find('.text-edit'), msg.name.toString()); var verticalHeight = $(li).offset().top; dropdownList.scrollTo(verticalHeight,0); setTimeout(function() { $(li).clearFormErrors(); }, 5000); } }); } }); // On hiding dropdown, cancel edit mode throughout dropdown dropdown.on('hidden.bs.dropdown', function() { cancelEditMode(); }); // On ok buttons click dropdownList.on('click', '.ok', function(event) { event.stopPropagation(); dropdownList.sortable('enable'); var self = $(this); var li = self.closest('li'); $(li).clearFormErrors(); editColumn(li); }); // On enter click while editing column text dropdownList.on('keydown', 'input.text-edit', function(event) { if (event.keyCode === 13) { event.preventDefault(); dropdownList.sortable('enable'); var self = $(this); var li = self.closest('li'); $(li).clearFormErrors(); editColumn(li); } }); // On cancel buttons click dropdownList.on('click', '.cancel', function(event) { event.stopPropagation(); dropdownList.sortable('enable'); var self = $(this); var li = self.closest('li'); $(li).clearFormErrors(); columnEditMode = false; li.removeClass('editing'); li.find('.text-edit').hide(); li.find('.controls .ok,.cancel').hide(); li.find('.text').css('display', ''); // show() doesn't work li.find('.controls .vis,.edit,.del').css('display', ''); // show() doesn't work }); } function initDeleteColumns() { var modal = $('#deleteCustomField'); dropdownList.on('click', '.del', function(event) { event.stopPropagation(); 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'); // Inject the body's HTML into modal modalBody.html(data.html); // Show the modal modal.modal('show'); }, error: function(xhr) { dropdownList.sortable('disable'); $(li).clearFormErrors(); var msg = $.parseJSON(xhr.responseText); renderFormError(undefined, $(li).find('.text-edit'), msg.name.toString()); var verticalHeight = $(li).offset().top; dropdownList.scrollTo(verticalHeight,0); setTimeout(function() { $(li).clearFormErrors(); }, 5000); } }); }); modal.find('.modal-footer [data-action=delete]').on('click', function() { var modalBody = modal.find('.modal-body'); var form = modalBody.find('[data-role=destroy-custom-field-form]'); var id = form.attr('data-id'); form .on('ajax:success', function() { // Preserve save/delete buttons as we need them after new table // will be created $('div.toolbarButtons').appendTo('div.samples-table'); $('div.toolbarButtons').hide(); // Destroy datatable table.destroy(); // Subtract number of columns $('#samples').data( 'num-columns', $('#samples').data('num-columns') - 1 ); // Remove column from table (=table header) & rows var th = originalHeader.find('#' + id); var index = th.index(); th.remove(); $('#samples tbody td:nth-child(' + (index + 1) + ')').remove(); // Remove all event handlers as we re-initialize them later with // new table $('#samples').off(); $('#samples thead').empty(); $('#samples thead').append(originalHeader); // Re-initialize datatable table = dataTableInit(); loadColumnsNames(); // Hide modal modal.modal('hide'); }) .on('ajax:error', function() { // TODO }); form.submit(); }); modal.on('hidden.bs.modal', function() { // Remove event handlers, clear contents var modalBody = modal.find('.modal-body'); modalBody.off(); modalBody.html(''); }); } // 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() { initNewColumnForm(); initSorting(); toggleColumnVisibility(); initEditColumns(); initDeleteColumns(); }); $('#samples-columns-dropdown').on('show.bs.dropdown', function() { loadColumnsNames(); dropdownList.sortable('enable'); }); $('#samples-columns-dropdown').on('shown.bs.dropdown', function() { dropdownOverflow(); }) } initDropdown(); })(table);