Skip to content

Commit

Permalink
Toggle valid rows (#18)
Browse files Browse the repository at this point in the history
* Allow row visibility toggle

* Organize CSS

* toggle dropdown visibility

* Improve case change performance on edit

* Better dropdown choices

* Clean up
  • Loading branch information
ivansg44 authored Jun 1, 2020
1 parent 912a798 commit 4e22fb1
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 73 deletions.
66 changes: 29 additions & 37 deletions main.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,67 +2,45 @@
@import 'libraries/bootstrap.min.css';
@import 'libraries/chosen.css';

.dropdown-item:hover {
cursor: pointer;
}

#grid .secondary-header-cell:hover {
cursor: pointer;
}

#grid {
overflow: hidden;
}

/* Toolbar */
#header-row {
visibility: hidden;
}

#footer-row {
visibility: hidden;
}

.listbox {
white-space: pre !important;
.dropdown-item:hover {
cursor: pointer;
}

#open-file-input {
display: none;
}

/* Grid */
#grid {
overflow: hidden;
}
#grid .secondary-header-cell:hover {
cursor: pointer;
}
#grid td.invalid-cell {
background-color: #ffcccb !important;
}

#grid .htAutocompleteArrow {
color: gray;
}

.secondary-header {
cursor:pointer;
#grid th {
text-align: left;
}

#grid th.required {
background-color:yellow;
}
#grid th.recommended {
background-color:plum;
}

/* Primary and secondary headers */
#grid th {
text-align: left;
}

/* Fixed col */
#grid th.overlayEdge {
border-right: medium solid gray;
}
#grid table.htCore > tbody > tr td:nth-child(2) {
border-right: medium solid gray;
/* Autocomplete */
.listbox {
white-space: pre !important;
}

/* Dropdown selection box choices */
.handsontable.listbox td {
border-radius:3px;
border:1px solid silver;
Expand All @@ -74,3 +52,17 @@
.handsontable.listbox td.current.highlight {
background-color: lightblue !important;
}

/* Fixed col */
#grid th.overlayEdge {
border-right: medium solid gray;
}
#grid table.htCore > tbody > tr td:nth-child(2) {
border-right: medium solid gray;
}


/* Below grid */
#footer-row {
visibility: hidden;
}
11 changes: 7 additions & 4 deletions main.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
<span class="dropdown-item" data-toggle="modal" data-target="#save-as-modal">Save As...</span>
</div>
</div>
<div class="btn-group" role="group">
<div class="btn-group" id="settings-dropdown-btn-group" role="group">
<button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Settings</button>
<div class="dropdown-menu">
<span class="dropdown-item" id="show-all-dropdown-item">Show all</span>
<span class="dropdown-item" id="show-required-dropdown-item">Show required</span>
<span class="dropdown-item disabled">Version 0.3.0</span>
<span class="dropdown-item hidden-dropdown-item" id="show-all-cols-dropdown-item">Show all columns</span>
<span class="dropdown-item hidden-dropdown-item" id="show-required-cols-dropdown-item">Show required columns</span>
<span class="dropdown-item hidden-dropdown-item" id="show-all-rows-dropdown-item">Show all rows</span>
<span class="dropdown-item hidden-dropdown-item" id="show-valid-rows-dropdown-item">Show valid rows</span>
<span class="dropdown-item hidden-dropdown-item" id="show-invalid-rows-dropdown-item">Show invalid rows</span>
<span class="dropdown-item disabled" id="version-dropdown-item">Version 0.3.0</span>
</div>
</div>
<button type="button" class="btn btn-primary" id="validate-btn">Validate</button>
Expand Down
137 changes: 105 additions & 32 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,41 @@
* Functionality for uploading, downloading and validating data.
*/

/**
* Controls what dropdown options are visible depending on grid settings.
* @param {Object} hot Handonstable grid instance.
* @param {Object<Number, Set<Number>>} invalidCells See `getInvalidCells`
* return value.
*/
const toggleDropdownVisibility = (hot, invalidCells) => {
$('.hidden-dropdown-item').hide();

$('#settings-dropdown-btn-group')
.on('show.bs.dropdown', () => {
const hiddenCols = HOT.getSettings().hiddenColumns.columns;
const hiddenRows = HOT.getSettings().hiddenRows.rows;

if (hiddenCols.length) {
$('#show-all-cols-dropdown-item').show();
} else {
$('#show-required-cols-dropdown-item').show();
}

if (hiddenRows.length) {
$('#show-all-rows-dropdown-item').show();
}

// Invalid cells present
if (!jQuery.isEmptyObject(INVALID_CELLS)) {
$('#show-valid-rows-dropdown-item').show();
$('#show-invalid-rows-dropdown-item').show();
}
})
.on('hide.bs.dropdown', () => {
$('.hidden-dropdown-item').hide();
});
};

/**
* Post-processing of values in `data.js` at runtime.
* TODO: this logic should be in the python script that creates `data.json`
Expand Down Expand Up @@ -88,17 +123,18 @@ const createHot = (data) => {
indicators: true,
columns: [],
},
hiddenRows: {
rows: [],
},
// Handsontable's validation is extremely slow with large datasets
invalidCellClassName: '',
licenseKey: 'non-commercial-and-evaluation',
afterChange: function(changes, source) {
if (source === 'capitalizationChange') return;
beforeChange: function(changes, source) {
if (!changes) return;
for (const change of changes) {
const row = change[0];
const col = change[1];
const newVal = changeCase(change[3], fields[col].capitalize);
this.setDataAtCell(row, col, newVal, 'capitalizationChange');
change[3] = changeCase(change[3], fields[col].capitalize);
}
},
afterRender: () => {
Expand Down Expand Up @@ -384,6 +420,52 @@ const changeCases = (matrix, hot, data) => {
return matrix;
}

/**
* Modify visibility of columns in grid. This function should only be called
* after clicking a DOM element used to toggle column visibilities.
* @param {String} id Id of element clicked to trigger this function.
* @param {Object} data See `data.js`.
* @param {Object} hot Handsontable instance of grid.
*/
const changeColVisibility = (id, data, hot) => {
const hiddenColumns = [];
if (id === 'show-required-cols-dropdown-item') {
getFields(data).forEach(function(field, i) {
if (field.requirement !== 'required') hiddenColumns.push(i);
});
}
hot.updateSettings({
hiddenColumns: {
copyPasteEnabled: true,
indicators: true,
columns: hiddenColumns,
},
});
};

/**
* Modify visibility of rows in grid. This function should only be called
* after clicking a DOM element used to toggle row visibilities.
* @param {String} id Id of element clicked to trigger this function.
* @param {Object<Number, Set<Number>>} invalidCells See `getInvalidCells`
* return value.
* @param {Object} hot Handsontable instance of grid.
*/
const changeRowVisibility = (id, invalidCells, hot) => {
let hiddenRows = [];

if (id === 'show-valid-rows-dropdown-item') {
const rows = [...Array(HOT.countRows()).keys()];
hiddenRows = Object.keys(INVALID_CELLS).map(Number);
} else if (id === 'show-invalid-rows-dropdown-item') {
const rows = [...Array(HOT.countRows()).keys()];
const invalidRowsSet = new Set(Object.keys(INVALID_CELLS).map(Number));
hiddenRows = rows.filter(row => !invalidRowsSet.has(row));
}

HOT.updateSettings({hiddenRows: {rows: hiddenRows}});
}

/**
* Get a collection of all invalid cells in the grid.
* @param {Object} hot Handsontable instance of grid.
Expand Down Expand Up @@ -460,29 +542,6 @@ const validateMultiple = (valsCsv, source) => {
return true;
};

/**
* Modify visibility of fields in grid. This function should only be called
* after clicking a DOM element used to toggle field visibilities.
* @param {String} id Id of element clicked to trigger this function.
* @param {Object} data See `data.js`.
* @param {Object} hot Handsontable instance of grid.
*/
const showFields = (id, data, hot) => {
const hiddenColumns = [];
if (id === 'show-required-dropdown-item') {
getFields(data).forEach(function(field, i) {
if (field.requirement !== 'required') hiddenColumns.push(i);
});
}
hot.updateSettings({
hiddenColumns: {
copyPasteEnabled: true,
indicators: true,
columns: hiddenColumns,
},
});
};

/**
* Get an HTML string that describes a field.
* @param {Object} field Any object under `children` in `data.js`.
Expand All @@ -501,6 +560,8 @@ $(document).ready(() => {

window.INVALID_CELLS = {};

toggleDropdownVisibility(HOT, INVALID_CELLS);

// File -> New
$('#new-dropdown-item, #clear-data-confirm-btn').click((e) => {
if (e.target.id === 'new-dropdown-item') {
Expand Down Expand Up @@ -552,6 +613,23 @@ $(document).ready(() => {
$('#base-name-save-as-input').val('');
});

// Settings -> Show ... columns
const showColsSelectors =
['#show-all-cols-dropdown-item', '#show-required-cols-dropdown-item'];
$(showColsSelectors.join(',')).click((e) => {
changeColVisibility(e.target.id, DATA, HOT);
});

// Settings -> Show ... rows
const showRowsSelectors = [
'#show-all-rows-dropdown-item',
'#show-valid-rows-dropdown-item',
'#show-invalid-rows-dropdown-item',
];
$(showRowsSelectors.join(',')).click((e) => {
changeRowVisibility(e.target.id, INVALID_CELLS, HOT);
});

// Validate
$('#validate-btn').click(() => {
window.INVALID_CELLS = getInvalidCells(HOT, DATA);
Expand All @@ -566,11 +644,6 @@ $(document).ready(() => {
HOT.render();
});

// Show fields
$('#show-all-dropdown-item, #show-required-dropdown-item').click(function(e) {
showFields(e.target.id, DATA, HOT);
});

// Field descriptions. Need to account for dynamically rendered
// cells.
$('#grid').on('dblclick', '.secondary-header-cell', (e) => {
Expand Down

0 comments on commit 4e22fb1

Please sign in to comment.