Merge pull request #5326 from rekonder/aj_SCI_8082

Reverse table header/row numbering for plate templates [SCI-8082]
This commit is contained in:
Alex Kriuchykhin 2023-05-18 09:34:19 +02:00 committed by GitHub
commit 0cc253172f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 135 additions and 37 deletions

View file

@ -0,0 +1,35 @@
/* global tableColRowName*/
(function() {
const handsontableInitDataElem = $('#handson');
const HANDSONTABLE_INIT_ROWS_CNT = handsontableInitDataElem.data('init-rows-cnt');
const HANDSONTABLE_INIT_COLS_CNT = handsontableInitDataElem.data('init-cols-cnt');
$("[data-role='hot-table']").each(function() {
var hot;
var $container = $(this).find("[data-role='step-hot-table']");
var contents = $(this).find('.hot-contents');
var metadataJson = $(this).find('.hot-metadata');
var metadata = JSON.parse(metadataJson.val() || '{}');
$container.handsontable({
startRows: HANDSONTABLE_INIT_ROWS_CNT,
startCols: HANDSONTABLE_INIT_COLS_CNT,
rowHeaders: tableColRowName.tableRowHeaders(metadata.plateTemplate),
colHeaders: tableColRowName.tableColHeaders(metadata.plateTemplate),
fillHandle: false,
formulas: true,
data: JSON.parse(contents.attr('value')).data,
cell: metadata.cells || [],
readOnly: true
});
hot = $container.handsontable('getInstance');
setTimeout(() => {
hot.render();
}, 500);
});
window.print();
}());

View file

@ -1,4 +1,35 @@
(function() {
function tableColHeaders(isPlateTemplate) {
if (isPlateTemplate) {
return function(visualColumnIndex) {
return visualColumnIndex + 1;
};
}
return true;
}
function tableRowHeaders(isPlateTemplate) {
if (isPlateTemplate) {
return function(visualColumnIndex) {
var ordA = 'A'.charCodeAt(0);
var ordZ = 'Z'.charCodeAt(0);
var len = (ordZ - ordA) + 1;
var num = visualColumnIndex;
var colName = '';
while (num >= 0) {
colName = String.fromCharCode((num % len) + ordA) + colName;
num = Math.floor(num / len) - 1;
}
return colName;
};
}
return true;
}
/**
* Initialize the hands on table on the given
* element with the specified data.
@ -7,11 +38,12 @@
function initializeHandsonTable(el) {
var input = el.siblings('input.hot-table-contents');
var inputObj = JSON.parse(input.attr('value'));
var metadata = el.siblings('input.hot-table-metadata');
var metadataJson = el.siblings('input.hot-table-metadata');
var data = inputObj.data;
var headers;
var parentEl;
var order;
var metadata;
// Special handling if this is a repository table
if (input.hasClass('hot-repository-items')) {
@ -32,15 +64,16 @@
el.handsontable('getInstance').getPlugin('columnSorting').sort(3, order);
} else {
metadata = JSON.parse(metadataJson.val() || '{}');
el.handsontable({
disableVisualSelection: true,
rowHeaders: true,
colHeaders: true,
rowHeaders: tableRowHeaders(metadata.plateTemplate),
colHeaders: tableColHeaders(metadata.plateTemplate),
editor: false,
copyPaste: false,
formulas: true,
data: data,
cell: JSON.parse(metadata.val() || '{}').cells || []
cell: metadata.cells || []
});
}
}

View file

@ -0,0 +1,42 @@
/* eslint-disable no-unused-vars, no-use-before-define */
var tableColRowName = (function() {
function tableColHeaders(isPlateTemplate) {
if (isPlateTemplate) {
return function(visualColumnIndex) {
return visualColumnIndex + 1;
};
}
return true;
}
function tableRowHeaders(isPlateTemplate) {
if (isPlateTemplate) {
return function(visualColumnIndex) {
var ordA = 'A'.charCodeAt(0);
var ordZ = 'Z'.charCodeAt(0);
var len = (ordZ - ordA) + 1;
var num = visualColumnIndex;
var colName = '';
while (num >= 0) {
colName = String.fromCharCode((num % len) + ordA) + colName;
num = Math.floor(num / len) - 1;
}
return colName;
};
}
return true;
}
return {
tableColHeaders: function(isPlateTemplate) {
return tableColHeaders(isPlateTemplate);
},
tableRowHeaders: function(isPlateTemplate) {
return tableRowHeaders(isPlateTemplate);
}
};
}());

View file

@ -5,7 +5,7 @@ module StepElements
before_action :load_table, only: %i(update destroy duplicate)
def create
predefined_table_dimensions = params[:tableDimensions].map(&:to_i)
predefined_table_dimensions = create_table_params[:tableDimensions].map(&:to_i)
name = if predefined_table_dimensions[0] == predefined_table_dimensions[1]
t('protocols.steps.table.default_name',
position: @step.step_tables.length + 1)
@ -18,6 +18,7 @@ module StepElements
name: name,
contents: { data: Array.new(predefined_table_dimensions[0],
Array.new(predefined_table_dimensions[1], '')) }.to_json,
metadata: { plateTemplate: create_table_params[:plateTemplate] == 'true' },
created_by: current_user,
team: @step.protocol.team
))
@ -36,7 +37,9 @@ module StepElements
ActiveRecord::Base.transaction do
@table.assign_attributes(table_params.except(:metadata))
begin
@table.metadata = JSON.parse(table_params[:metadata]) if table_params[:metadata].present?
if table_params[:metadata].present?
@table.metadata = @table.metadata.merge(JSON.parse(table_params[:metadata]))
end
rescue JSON::ParserError
@table.metadata = {}
end
@ -79,6 +82,10 @@ module StepElements
params.permit(:name, :contents, :metadata)
end
def create_table_params
params.permit(:plateTemplate, tableDimensions: [])
end
def load_table
@table = @step.tables.find_by(id: params[:id])
return render_404 unless @table

View file

@ -76,7 +76,7 @@
<span class="caret"></span>
<ul class="dropdown-submenu">
<li v-for="option in wellPlateOptions" :key="option.dimensions.toString()" class="action" @click="createElement('table', option.dimensions)">
<li v-for="option in wellPlateOptions" :key="option.dimensions.toString()" class="action" @click="createElement('table', option.dimensions, true)">
{{ i18n.t(option.label) }}
</li>
</ul>
@ -437,8 +437,8 @@
}
});
},
createElement(elementType, tableDimensions = [5,5]) {
$.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions }, (result) => {
createElement(elementType, tableDimensions = [5,5], plateTemplate = false) {
$.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions, plateTemplate: plateTemplate }, (result) => {
result.data.isNew = true;
this.elements.push(result.data)
this.$emit('stepUpdated')

View file

@ -181,13 +181,14 @@
let container = this.$refs.hotTable;
let data = JSON.parse(this.element.attributes.orderable.contents);
let metadata = this.element.attributes.orderable.metadata || {};
this.tableObject = new Handsontable(container, {
data: data.data,
width: '100%',
startRows: 5,
startCols: 5,
rowHeaders: true,
colHeaders: true,
rowHeaders: tableColRowName.tableRowHeaders(metadata.plateTemplate),
colHeaders: tableColRowName.tableColHeaders(metadata.plateTemplate),
cell: metadata.cells || [],
contextMenu: this.editingTable,
formulas: true,

View file

@ -10,31 +10,10 @@
<%= stylesheet_link_tag 'layouts/print_protocol', media: 'print, screen' %>
<body>
<%= yield %>
<script>
$("[data-role='hot-table']").each(function() {
var $container = $(this).find("[data-role='step-hot-table']");
var contents = $(this).find('.hot-contents');
var metadata = $(this).find('.hot-metadata');
$container.handsontable({
startRows: <%= Constants::HANDSONTABLE_INIT_ROWS_CNT %>,
startCols: <%= Constants::HANDSONTABLE_INIT_COLS_CNT %>,
rowHeaders: true,
colHeaders: true,
fillHandle: false,
formulas: true,
data: JSON.parse(contents.attr('value')).data,
cell: JSON.parse(metadata.val() || '{}').cells || [],
readOnly: true
});
var hot = $container.handsontable('getInstance');
setTimeout(() => {
hot.render()
}, 500)
});
window.print();
</script>
<div id="handson"
data-init-rows-cnt="<%= Constants::HANDSONTABLE_INIT_ROWS_CNT %>"
data-init-cols-cnt="<%= Constants::HANDSONTABLE_INIT_COLS_CNT %>"
></div>
<%= javascript_include_tag 'protocols/handson', nonce: true %>
</body>
</html>

View file

@ -63,6 +63,7 @@ Rails.application.config.assets.precompile += %w(protocols/edit.js)
Rails.application.config.assets.precompile += %w(protocols/import_export/eln_table.js)
Rails.application.config.assets.precompile += %w(protocols/import_export/import.js)
Rails.application.config.assets.precompile += %w(protocols/import_export/export.js)
Rails.application.config.assets.precompile += %w(protocols/handson.js)
Rails.application.config.assets.precompile += %w(layouts/print_protocol.css)
Rails.application.config.assets.precompile += %w(datatables.js)
Rails.application.config.assets.precompile += %w(search/index.js)