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() {
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 * Initialize the hands on table on the given
* element with the specified data. * element with the specified data.
@ -7,11 +38,12 @@
function initializeHandsonTable(el) { function initializeHandsonTable(el) {
var input = el.siblings('input.hot-table-contents'); var input = el.siblings('input.hot-table-contents');
var inputObj = JSON.parse(input.attr('value')); 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 data = inputObj.data;
var headers; var headers;
var parentEl; var parentEl;
var order; var order;
var metadata;
// Special handling if this is a repository table // Special handling if this is a repository table
if (input.hasClass('hot-repository-items')) { if (input.hasClass('hot-repository-items')) {
@ -32,15 +64,16 @@
el.handsontable('getInstance').getPlugin('columnSorting').sort(3, order); el.handsontable('getInstance').getPlugin('columnSorting').sort(3, order);
} else { } else {
metadata = JSON.parse(metadataJson.val() || '{}');
el.handsontable({ el.handsontable({
disableVisualSelection: true, disableVisualSelection: true,
rowHeaders: true, rowHeaders: tableRowHeaders(metadata.plateTemplate),
colHeaders: true, colHeaders: tableColHeaders(metadata.plateTemplate),
editor: false, editor: false,
copyPaste: false, copyPaste: false,
formulas: true, formulas: true,
data: data, 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) before_action :load_table, only: %i(update destroy duplicate)
def create 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] name = if predefined_table_dimensions[0] == predefined_table_dimensions[1]
t('protocols.steps.table.default_name', t('protocols.steps.table.default_name',
position: @step.step_tables.length + 1) position: @step.step_tables.length + 1)
@ -18,6 +18,7 @@ module StepElements
name: name, name: name,
contents: { data: Array.new(predefined_table_dimensions[0], contents: { data: Array.new(predefined_table_dimensions[0],
Array.new(predefined_table_dimensions[1], '')) }.to_json, Array.new(predefined_table_dimensions[1], '')) }.to_json,
metadata: { plateTemplate: create_table_params[:plateTemplate] == 'true' },
created_by: current_user, created_by: current_user,
team: @step.protocol.team team: @step.protocol.team
)) ))
@ -36,7 +37,9 @@ module StepElements
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
@table.assign_attributes(table_params.except(:metadata)) @table.assign_attributes(table_params.except(:metadata))
begin 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 rescue JSON::ParserError
@table.metadata = {} @table.metadata = {}
end end
@ -79,6 +82,10 @@ module StepElements
params.permit(:name, :contents, :metadata) params.permit(:name, :contents, :metadata)
end end
def create_table_params
params.permit(:plateTemplate, tableDimensions: [])
end
def load_table def load_table
@table = @step.tables.find_by(id: params[:id]) @table = @step.tables.find_by(id: params[:id])
return render_404 unless @table return render_404 unless @table

View file

@ -76,7 +76,7 @@
<span class="caret"></span> <span class="caret"></span>
<ul class="dropdown-submenu"> <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) }} {{ i18n.t(option.label) }}
</li> </li>
</ul> </ul>
@ -437,8 +437,8 @@
} }
}); });
}, },
createElement(elementType, tableDimensions = [5,5]) { createElement(elementType, tableDimensions = [5,5], plateTemplate = false) {
$.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions }, (result) => { $.post(this.urls[`create_${elementType}_url`], { tableDimensions: tableDimensions, plateTemplate: plateTemplate }, (result) => {
result.data.isNew = true; result.data.isNew = true;
this.elements.push(result.data) this.elements.push(result.data)
this.$emit('stepUpdated') this.$emit('stepUpdated')

View file

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

View file

@ -10,31 +10,10 @@
<%= stylesheet_link_tag 'layouts/print_protocol', media: 'print, screen' %> <%= stylesheet_link_tag 'layouts/print_protocol', media: 'print, screen' %>
<body> <body>
<%= yield %> <%= yield %>
<script> <div id="handson"
$("[data-role='hot-table']").each(function() { data-init-rows-cnt="<%= Constants::HANDSONTABLE_INIT_ROWS_CNT %>"
var $container = $(this).find("[data-role='step-hot-table']"); data-init-cols-cnt="<%= Constants::HANDSONTABLE_INIT_COLS_CNT %>"
var contents = $(this).find('.hot-contents'); ></div>
var metadata = $(this).find('.hot-metadata'); <%= javascript_include_tag 'protocols/handson', nonce: true %>
$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>
</body> </body>
</html> </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/eln_table.js)
Rails.application.config.assets.precompile += %w(protocols/import_export/import.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/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(layouts/print_protocol.css)
Rails.application.config.assets.precompile += %w(datatables.js) Rails.application.config.assets.precompile += %w(datatables.js)
Rails.application.config.assets.precompile += %w(search/index.js) Rails.application.config.assets.precompile += %w(search/index.js)