Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to Handsontable 13.0.1 to enable batch() quick render. #409

Merged
merged 5 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 59 additions & 42 deletions lib/DataHarmonizer.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class DataHarmonizer {
// Currently selected cell range[row,col,row2,col2]
current_selection = [null, null, null, null];
field_settings = {};
fields = [];
template_unique_keys = [];

constructor(root, options = {}) {
Expand Down Expand Up @@ -364,15 +365,15 @@ class DataHarmonizer {
this.setExportField(new_field, true);

/* https://linkml.io/linkml-model/docs/structured_pattern/
https://github.com/linkml/linkml/issues/674
Look up its parts in "settings", and assemble a regular
expression for them to compile into "pattern" field.
This augments basic datatype validation
structured_pattern:
syntax: "{float} {unit.length}"
interpolated: true ## all {...}s are replaced using settings
partial_match: false
*/
https://github.com/linkml/linkml/issues/674
Look up its parts in "settings", and assemble a regular
expression for them to compile into "pattern" field.
This augments basic datatype validation
structured_pattern:
syntax: "{float} {unit.length}"
interpolated: true ## all {...}s are replaced using settings
partial_match: false
*/
if ('structured_pattern' in new_field) {
switch (new_field.structured_pattern.syntax) {
case '{UPPER_CASE}':
Expand Down Expand Up @@ -413,6 +414,8 @@ class DataHarmonizer {
this.template[ptr]['children'].sort((a, b) => a.rank - b.rank);
}

this.fields = this.getFields();

this.createHot();
}

Expand Down Expand Up @@ -522,18 +525,18 @@ class DataHarmonizer {
self.helpSidebar.setContent(helpContent);
}
},
afterRender: () => {
// Bit of a hackey way to RESTORE classes to secondary headers. They are
// removed by Handsontable when re-rendering main table.
$('.secondary-header-text').each((_, e) => {
const $cellElement = $(e).closest('th');
$cellElement.addClass('secondary-header-cell');
if ($(e).hasClass('required')) {
$cellElement.addClass('required');
} else if ($(e).hasClass('recommended')) {
$cellElement.addClass('recommended');
// Bit of a hackey way to RESTORE classes to secondary headers. They are
// removed by Handsontable when re-rendering main table.
afterGetColHeader: (column, TH, headerlev) => {
if (headerlev == 1) {
// Enables double-click listener for column help
$(TH).addClass('secondary-header-cell');
if (column > -1) {
const field = self.fields[column];
if (field.recommended) $(TH).addClass('recommended');
else if (field.required) $(TH).addClass('required');
}
});
}
},
afterRenderer: (TD, row, col) => {
if (Object.prototype.hasOwnProperty.call(self.invalid_cells, row)) {
Expand All @@ -559,14 +562,19 @@ class DataHarmonizer {

addRowsToBottom(numRows) {
this.runBehindLoadingScreen(() => {
this.hot.alter('insert_row', this.hot.countRows() - 1 + numRows, numRows);
this.hot.alter(
'insert_row_below',
this.hot.countRows() - 1 + numRows,
numRows
);
});
}

showAllColumns() {
this.hot.scrollViewportTo(0, 1);
const hiddenColsPlugin = this.hot.getPlugin('hiddenColumns');
hiddenColsPlugin.showColumns(hiddenColsPlugin.hiddenColumns);
const hidden = hiddenColsPlugin.getHiddenColumns();
if (hidden) hiddenColsPlugin.showColumns(hidden);
this.hot.render();
}

Expand Down Expand Up @@ -626,7 +634,8 @@ class DataHarmonizer {

// Un-hide all currently hidden cols
const hiddenRowsPlugin = this.hot.getPlugin('hiddenRows');
hiddenRowsPlugin.showRows(hiddenRowsPlugin.hiddenRows);
const hidden = hiddenRowsPlugin.getHiddenRows();
hiddenRowsPlugin.showRows(hidden);

// Hide user-specified rows
const rows = [...Array(this.hot.countRows()).keys()];
Expand Down Expand Up @@ -818,8 +827,9 @@ class DataHarmonizer {
* @param {Object} hot Handsontable instance of grid.
*/
scrollTo(row, column) {
const hiddenCols = this.hot.getPlugin('hiddenColumns').hiddenColumns;
if (hiddenCols.includes(column)) {
const hiddenColsPlugin = this.hot.getPlugin('hiddenColumns');
const hidden = hiddenColsPlugin.getHiddenColumns();
if (hidden.includes(column)) {
// If user wants to scroll to a hidden column, make all columns unhidden
this.showAllColumns();
}
Expand Down Expand Up @@ -1671,9 +1681,9 @@ class DataHarmonizer {
}
// This will output a list of fields added to exportHeaders by way of template specification which haven't been included in export.js
//if (field_message)
// console.log('Export fields added by template:', field_message)
// console.log('Export fields added by template:', field_message)
//if (field_export_message)
// console.log('Export fields stated in export.js):', field_export_message)
// console.log('Export fields stated in export.js):', field_export_message)
}

/**
Expand Down Expand Up @@ -2049,15 +2059,15 @@ class DataHarmonizer {
}

/**
* Adjust given dateString date to match year or month granularity given by
* dateGranularity parameter. If month unit required but not supplied, then
* a yyyy-__-01 will be supplied to indicate that month needs attention.
*
* @param {String} dateGranularity, either 'year' or 'month'
* @param {String} ISO 8601 date string or leading part, possibly just YYYY or
YYYY-MM
* @return {String} ISO 8601 date string.
*/
* Adjust given dateString date to match year or month granularity given by
* dateGranularity parameter. If month unit required but not supplied, then
* a yyyy-__-01 will be supplied to indicate that month needs attention.
*
* @param {String} dateGranularity, either 'year' or 'month'
* @param {String} ISO 8601 date string or leading part, possibly just YYYY or
YYYY-MM
* @return {String} ISO 8601 date string.
*/
setDateChange(dateGranularity, dateString, dateBlank = '__') {
var dateParts = dateString.split('-');
// Incomming date may have nothing in it.
Expand Down Expand Up @@ -2189,7 +2199,7 @@ class DataHarmonizer {
timeFormat: this.timeFormat,
});

let provenanceChanges = [];
let cellChanges = [];
const indexToRowMap = new Map();
const rowToIndexMap = new Map();
let index = 0;
Expand Down Expand Up @@ -2225,7 +2235,7 @@ class DataHarmonizer {
// 1st row of provenance datatype field is forced to have a
// 'DataHarmonizer Version: 0.13.0' etc. value. Change happens silently.
if (datatype === 'Provenance') {
checkProvenance(provenanceChanges, full_version, cellVal, row, col);
checkProvenance(cellChanges, full_version, cellVal, row, col);
}

let valid = false;
Expand Down Expand Up @@ -2335,7 +2345,7 @@ class DataHarmonizer {

valid = vocabValid;
if (update) {
this.hot.setDataAtCell(row, col, update, 'thisChange');
cellChanges.push([row, col, update, 'thisChange']);
}
} else {
const [vocabValid, update] = validateValAgainstVocab(
Expand All @@ -2344,7 +2354,7 @@ class DataHarmonizer {
);
valid = vocabValid;
if (update) {
this.hot.setDataAtCell(row, col, update, 'thisChange');
cellChanges.push([row, col, update, 'thisChange']);
}
}
// Hardcoded case: If field is xsd:token, and 1st picklist is
Expand Down Expand Up @@ -2373,6 +2383,7 @@ class DataHarmonizer {
} // row loop end

// Check row uniqueness for identifier fields and unique_key sets
// This is not affected by a column's datatype.
const doUniqueValidation = (columnNumbers) => {
const values = columnNumbers.map((columnNumber) => {
if (columnNumber < 0) {
Expand All @@ -2397,22 +2408,28 @@ class DataHarmonizer {
});
};

// Returns FIRST index for a field marked as an .identifier
const identifierFieldCol = fields.findIndex(
(field) => field.identifier && field.identifier === true
);
if (identifierFieldCol >= 0) {
doUniqueValidation([identifierFieldCol]);
}

// .template_unique_keys contains an object of 0 or more unique keys,
// each key being a combination of one or more .unique_key_slots names.
// Does unique validation on each unique key combo.
for (const unique_key of this.template_unique_keys) {
const uniqueKeyCols = unique_key.unique_key_slots.map((fieldName) => {
return fields.findIndex((field) => field.name === fieldName);
});
doUniqueValidation(uniqueKeyCols);
}

// Here an array of (row, column, value)... is being passed
if (provenanceChanges.length) this.hot.setDataAtCell(provenanceChanges);
// Here an array of (row, column, value)... is being passed, which causes
// rendering operations to happen like .batch(), after all setDataAtCell()
// operations are completed.
if (cellChanges.length) this.hot.setDataAtCell(cellChanges);

return invalidCells;
}
Expand Down
6 changes: 3 additions & 3 deletions lib/editors/FlatpickrEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,14 @@ class FlatpickrEditor extends Handsontable.editors.TextEditor {
*/
const eventManager = new Handsontable.EventManager(this);
eventManager.addEventListener(this.datePicker, 'mousedown', (event) => {
Handsontable.dom.stopPropagation(event);
Handsontable.dom.stopImmediatePropagation(event);
});
eventManager.addEventListener(this.datePicker, 'keydown', (event) => {
Handsontable.dom.stopPropagation(event);
Handsontable.dom.stopImmediatePropagation(event);
});
eventManager.addEventListener(this.TEXTAREA, 'keydown', (event) => {
if (event.keyCode === Handsontable.helper.KEY_CODES.ENTER) {
Handsontable.dom.stopPropagation(event);
Handsontable.dom.stopImmediatePropagation(event);
}
});
this.hideDatepicker();
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"date-fns": "^2.28.0",
"file-saver": "^2.0.5",
"flatpickr": "^4.6.13",
"handsontable": "^7.4.2",
"handsontable": "13.1.0",
"sifter": "^0.5.4",
"xlsx": "^0.18.5"
},
Expand Down
Loading
Loading