Skip to content

Commit

Permalink
Merge pull request #409 from cidgoh/issue-#408
Browse files Browse the repository at this point in the history
Update to Handsontable 13.0.1 to enable batch() quick render.
  • Loading branch information
kennethbruskiewicz committed Sep 15, 2023
2 parents 0238e0d + a030c60 commit 858e368
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 101 deletions.
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

0 comments on commit 858e368

Please sign in to comment.