Commit 4606d6cc authored by malzer's avatar malzer
Browse files

Update handsontable

parent cf9dd3fe
......@@ -38,11 +38,3 @@
height: 20em;
}
/* Overwrite: bigger font in handsontable */
.handsontable.dataTable td {
font-size: 110%;
}
.handsontable.dataTable th .small {
font-size: 110%;
}
......@@ -12,8 +12,7 @@
<link rel="stylesheet" type="text/css" media="screen" href="https://res.de.dariah.eu/dhrep/css/bootstrap-customization.css" />
<link rel="stylesheet" type="text/css" media="screen" href="https://res.de.dariah.eu/dhrep/css/bootstrap-modal.css" />
<link rel="stylesheet" type="text/css" media="screen" href="https://res.de.dariah.eu/dhrep/css/font-awesome.css" />
<link rel="stylesheet" media="screen" href="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/jquery.handsontable.css">
<link rel="stylesheet" media="screen" href="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/lib/jQuery-contextMenu/jquery.contextMenu.css">
<link rel="stylesheet" media="screen" href="https://cdn.jsdelivr.net/npm/handsontable@9.0.0/dist/handsontable.full.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
<link rel="stylesheet" href="https://dariah-de.github.io/status/dariah/embed.css">
<link rel="stylesheet" type="text/css" media="screen" href="./css/dariah.workflow.css" />
......@@ -126,7 +125,7 @@
<button id="howtoButton" class="btn btn-small pull-right" onclick="toggleHowto();" title="Read a small howto to get help filling in the table data.">How to fill the table</button>
<br/>
<p>
<img id="spinningConsoleCompletionFlower" class="hide" src="https://res.de.dariah.eu/dhrep/img/spinning-flower_slow.gif" alt="Geolocation completion running" width="16" />
<img id="spinningConsoleCompletionFlower" class="hide" src="https://res.de.dariah.eu/dhrep/img/spinning-flower_slow.gif" alt="Data table loading..." width="16" />
<span id="console" class="console">&nbsp;</span>
</p>
<div id="dataTable" class="dataTable"></div>
......@@ -320,14 +319,10 @@
<!-- javascript
================================================== -->
<!-- placed at the end of the document so the pages load faster -->
<script src="https://code.jquery.com/jquery-1.8.1.min.js"></script>
<script src="https://code.jquery.com/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/jquery-csv@1.0.21/src/jquery.csv.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/underscore@1.13.1/underscore-umd-min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/jquery.handsontable.js"></script>
<script src="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/lib/jQuery-contextMenu/jquery.contextMenu.js"></script>
<script src="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/lib/jQuery-contextMenu/jquery.ui.position.js"></script>
<script src="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/lib/bootstrap-typeahead.js"></script>
<script src="https://cdn.jsdelivr.net/gh/handsontable/handsontable@0.6.0/lib/jquery.autoresize.js"></script>
<script src="https://cdn.jsdelivr.net/npm/handsontable@9.0.0/dist/handsontable.full.min.js"></script>
<script src="https://res.de.dariah.eu/dhrep/js/bootstrap.js"></script>
<!-- OpenLayers -->
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList"></script>
......
......@@ -6,7 +6,7 @@
* Dump things
*/
function dump() {
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
console.log(arr2csv(arr));
}
......@@ -17,20 +17,24 @@ function dump() {
* function http://www.filosophy.org/bitstream/2011/12/17/js_array_to_csv.html
*/
function arr2csv(arr){
var csv = '';
for(var row in arr){
for(var col in arr[row]){
var value = arr[row][col].replace(/"/g, '""');
csv += '"' + value + '"';
if(col != arr[row].length - 1){
csv += ",";
}
}
csv += "\n";
}
return csv;
var csv = '';
for(var row in arr){
for(var col in arr[row]){
var value = arr[row][col];
if (value) value.replace(/"/g, '""');
else value = '';
csv += '"' + value + '"';
if(col != arr[row].length - 1){
csv += ",";
}
}
csv += "\n";
}
return csv;
}
/**
* Check for empty string.
*/
......
......@@ -15,7 +15,7 @@ var dateTimeSchemaUrl = 'http://books.xmlschemata.org/relaxng/ch19-77049.html';
function checkDates() {
$(".dateAlert").alert('close');
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
var errorInRow = [];
var timeStampCol = findColumn(arr, 'TimeStamp');
......@@ -65,7 +65,7 @@ function isValidDate(rowIndex, rowData, columnNumber) {
if(!isEmptyString(entry)) {
isValid = (xsdGYear.test(entry) || xsdGYearMonth.test(entry) || xsdDateOrDateTime.test(entry));
if(!isValid) {
$('#dataTable').handsontable('getCell', rowIndex, columnNumber).className = 'error';
tableInstance.getCell(rowIndex, columnNumber).className = 'error';
}
}
......
......@@ -29,7 +29,7 @@ function startTGN() {
return;
}
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
$('#tgnList').empty();
......@@ -431,7 +431,7 @@ function showOSMapPlace() {
*/
function checkCoordinates() {
$(".coordAlert").alert('close');
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
var latErrorInRow = [];
var longErrorInRow = [];
......@@ -482,7 +482,7 @@ function jumpToCell(row, col) {
setTimeout (function () {
//timeout is needed because Handsontable normally deselects
//current cell when you click outside the table
$('#dataTable').handsontable("selectCell", row, col);
tableInstance.selectCell(row, col);
}, 50);
}
......@@ -500,7 +500,8 @@ function isValidLat(rowIndex, rowData, columnNumber) {
if (!isEmptyString(entry)) {
isValid = (entry >= -90 && entry <= 90);
if (!isValid) {
$('#dataTable').handsontable('getCell', rowIndex, columnNumber).className = 'error';
tableInstance.selectCell(rowIndex, columnNumber);
tableInstance.getCell(rowIndex, columnNumber).className = 'error';
}
}
......@@ -521,7 +522,8 @@ function isValidLong(rowIndex, rowData, columnNumber) {
if (!isEmptyString(entry)) {
isValid = (entry >= -180 && entry <= 180);
if (!isValid) {
$('#dataTable').handsontable('getCell', rowIndex, columnNumber).className = 'error';
tableInstance.selectCell(rowIndex, columnNumber);
tableInstance.getCell(rowIndex, columnNumber).className = 'error';
}
}
......
......@@ -3,12 +3,10 @@
*/
var dsid; // dariah storage id
var map; // osm
var proj4326; // osm projection
var projmerc; // mercator projection
var locationPickerPoint;
var locationPickerLayer;
var dragFeature;
var locationPickerVector; // marker
var dragAndDrop; // marker interaction
var autosave = true; // Just to turn off autosave while loading datasets.
var tableInstance;
/**
* Stuff to setup when DOM is ready.
......@@ -20,7 +18,8 @@ $(document).ready(function() {
getAuthInfo();
$('#loggedin').attr('href', 'javascript:logout()');
} else {
initReadOnlyTable();
initTable();
setTableReadOnly(true); //read-only table
// Set login menu items.
$('#loggedin').append('<i class="icon-signin icon-white"></i> Login');
$('#loggedin').attr('href', 'javascript:authenticate()');
......@@ -86,8 +85,7 @@ function init() {
// Handle loading files from file dialog or drag'n'drop.
else if (prefix === 'create' && suffix === 'files') {
var fileData = getFiles();
csvToTable(fileData);
postToDariahStorage(fileData);
if (csvToTable(fileData)) postToDariahStorage(fileData);
removeFiles();
}
}
......@@ -162,8 +160,8 @@ function createNew() {
function createNewDataset() {
// Create new dataset from old storage.
if (isOldStorageID(dsid)) {
// Gat data out of table.
var csv = arr2csv($('#dataTable').handsontable('getDataReference'));
// Get data out of table.
var csv = arr2csv(tableInstance.getData());
// Create new data file.
postToDariahStorage(csv);
}
......@@ -171,10 +169,12 @@ function createNewDataset() {
else {
// Re-set ID.
dsid = '';
// Create the new handsontable here.
$('#dataTable').handsontable('loadData', [e4dHeader]);
// Put table to csv array and create CSV structure.
var arr = arr2csv($('#dataTable').handsontable('getDataReference'));
// Fill with initial data.
var initialData = createInitialTableContent();
tableInstance.loadData(initialData);
setTableReadOnly(false);
// Create CSV structure.
var arr = arr2csv(initialData);
// Create new data file.
postToDariahStorage(arr);
setPermanentConsoleMessage('All changes will be autosaved.');
......@@ -222,7 +222,8 @@ var saveTimer;
function autoSave(change) {
if (autosave) {
// Get data.
var arr = $('#dataTable').handsontable('getDataReference');
if (!tableInstance) return;
var arr = tableInstance.getData();
var csv = arr2csv(arr);
// Make sure that not more than one save per 2,5 seconds occur.
clearTimeout(saveTimer);
......@@ -288,8 +289,7 @@ function loadFromFiles(files) {
// TODO Check for allowed text snippets to determine if a loaded file may be a CSV file?
// Validate file to be a valid CSV file here?
if (readToken() !== null) {
csvToTable(data);
postToDariahStorage(data);
if (csvToTable(data)) postToDariahStorage(data);
} else {
// Cache data.
setFiles(data);
......@@ -304,30 +304,34 @@ function loadFromFiles(files) {
*
*/
function csvToTable(data) {
var arr = $.csv.toArrays(data);
// First turn off autosave.
autosave = false;
$('#dataTable').handsontable('loadData', arr);
// colHeaders kind of broken...? this fixes, but what's the reason?
$('#dataTable').handsontable('updateSettings', {colHeaders: true, rowHeaders: true});
// Turn on autosave again.
autosave = true;
hideFirstStartWizard();
setTableReadOnly(false);
var success = true;
try {
var arr = $.csv.toArrays(data);
tableInstance.loadData(arr);
hideFirstStartWizard();
} catch (e){
success = false;
newAlert('error', 'Error reading CSV!', '<p>Could not read local CSV file! Maybe illegal format / illegal characters?</p>');
}
return success;
}
function setTableReadOnly(readOnly){
tableInstance.updateSettings({
cells: function (row, col) {
return handleCells(row, col, readOnly);
}
});
}
/**
*
*/
function csvToReadOnlyTable(data) {
initReadOnlyTable();
setTableReadOnly(true);
var arr = $.csv.toArrays(data);
// First turn off autosave.
autosave = false;
$('#dataTable').handsontable('loadData', arr);
// colHeaders kind of broken...? this fixes, but what's the reason?
$('#dataTable').handsontable('updateSettings', {colHeaders: true, rowHeaders: true});
// We can turn autosave on again, nothing is gonna be saved if not edited.
autosave = true;
tableInstance.loadData(arr);
hideFirstStartWizard();
setPermanentConsoleMessage('This dataset is read-only.');
showMessage('idMessage', 'This dataset was loaded from the old DARIAH-DE Storage and has got the ID');
......@@ -351,7 +355,7 @@ function download() {
document.body.appendChild(fancyA);
fancyA.style = 'display:none';
// Gat data out of table, set URL.
var csv = arr2csv($('#dataTable').handsontable('getDataReference'));
var csv = arr2csv(tableInstance.getData());
// TODO Maybe use csvStorageMimetype here?
var blob = new Blob([csv], {type: 'text/csv;charset=utf-8'});
url = window.URL.createObjectURL(blob);
......
......@@ -5,76 +5,87 @@
* - encapsulate handsontable requests
*/
/**
*
*/
function createInitialTableContent(){
// column titles are placed in the first row, i.e. are no actual column headers
var initialData = [["Name", "Address", "Description", "Longitude", "Latitude", "TimeStamp", "TimeSpan:begin", "TimeSpan:end", "GettyID"]];
for (var i = 0; i < 30; i++) initialData.push(['', '', '', '', '', '', '', '', '']);
return initialData;
}
/**
* Handles cell settings, i.e. read-only, autocomplete and date format
*/
function handleCells(row, col, readOnly) {
if (!readOnly) readOnly = false;
var cellProperties = {readOnly: readOnly};
if (row === 0) { //header
cellProperties.renderer = headerRenderer;
cellProperties.type = 'autocomplete';
cellProperties.trimDropdown = false;
cellProperties.source = e4dHeader;
cellProperties.strict = false;
} else {
var dateColumns = getDateColumns();
if (dateColumns && dateColumns.includes(col)) {
cellProperties.type = 'date';
cellProperties.correctFormat = true;
cellProperties.dateFormat = 'YYYY-MM-DD';
cellProperties.defaultDate = '1900-01-01';
cellProperties.datePickerConfig = {
yearRange: [1000, 2050]
}
}
}
return cellProperties;
}
function initTable() {
$("#dataTable").handsontable({
rows: 33,
cols: 10,
rowHeaders: true, // 123
colHeaders: true, // ABC
minSpareCols: 1, // always keep at least 1 spare row at the right
minSpareRows: 1, // always keep at least 1 spare row at the bottom
contextMenu: true, // menu for add rows or cols,
legend: [
{
match: function(row, col, data) {
return (row === 0); // if it is first row...
},
style: {
color: 'green', // ...make the text green...
fontWeight: 'bold', // ...and bold.
},
title: 'Heading' // make some tooltip
},
],
autoComplete: [
{
match: function(row, col, data) {
//console.log('match called ' + row + '|' + col + '|' + data()[row][col]);
return (row === 0 ); //if it is first column
},
source: function () {
//console.log("sclaaed: " + e4dHeader);
return e4dHeader;
}
}
],
onChange: function(change, source) {
//console.log('onChange called with source: ' + source);
if (source === 'loadData') {
return; // don't save this change
}
autoSave(change);
}
});
var container = document.getElementById('dataTable');
if (tableInstance) {console.log('Destroy'); tableInstance.destroy();}
tableInstance = new Handsontable(container, {
licenseKey: 'non-commercial-and-evaluation',
manualColumnResize: true,
manualRowResize: true,
dropdownMenu: true,
contextMenu: true,
rowHeaders: true, // 123
colHeaders: true, // ABC
minSpareCols: 1, // always keep at least 1 spare row at the right
minSpareRows: 1, // always keep at least 1 spare row at the bottom
cells: handleCells,
afterChange: function (change, source) {
if (source === 'loadData') {
return; // don't save this change
}
autoSave(change);
}
});
}
/**
* Just view the table without being able to edit it, it is read-only!
*/
function initReadOnlyTable() {
$("#dataTable").handsontable({
rows: 33,
cols: 10,
rowHeaders: true,
colHeaders: true,
minSpareCols: 1,
minSpareRows: 1,
contextMenu: true,
legend: [
{
match: function(row, col, data) {
return (row === 0); // if it is first row...
},
style: {
fontWeight: 'bold', // ...and bold.
},
title: 'Heading' // make some tooltip
},
],
});
/**
* Identifies indices of columns that should receive "date" type
*/
function getDateColumns() {
if (!tableInstance) return null;
var data = tableInstance.getData();
var indices = [];
var dateColumnNames = ['TimeStamp', 'TimeSpan:begin', 'TimeSpan:end'];
dateColumnNames.forEach(function(name){
var dateColumn = data[0].findIndex(x => x === name);
if (dateColumn !== -1) indices.push(dateColumn);
});
return indices;
}
function headerRenderer(instance, td, row, col, prop, value, cellProperties) {
Handsontable.renderers.TextRenderer.apply(this, arguments);
td.style.fontWeight = 'bold';
td.style.color = 'green';
}
/**
......@@ -85,17 +96,17 @@ function checkColumnHeadersGeolocation() {
// Close previous column alert.
$(".columnAlert").alert('close');
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
var ready = true;
$('#missingCols').empty();
$(requiredColumnsGeolocation).each(function(index, val) {
ready = findOrAlertCreatableColumn(arr, val) >= 0 && ready;
ready = findOrAlertCreatableColumn(arr, val);
});
$(addableColumns).each(function(index, val) {
ready = findOrAlertCreatableColumn(arr, val) >= 0 && ready;
ready = findOrAlertCreatableColumn(arr, val);
});
return ready;
......@@ -108,13 +119,13 @@ function checkColumnHeadersGeobrowser() {
// Close previous column alert.
$(".columnAlert").alert('close');
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
var ready = true;
$('#missingCols').empty();
$(requiredColumnsGeobrowser).each(function(index, val) {
ready = findOrAlertCreatableColumn(arr, val) >= 0 && ready;
ready = findOrAlertCreatableColumn(arr, val);
});
return ready;
......@@ -135,31 +146,32 @@ function findOrAlertCreatableColumn(arr, columnName) {
if (id < 0) {
var message = '<p>Column name <strong>“' + columnName + '“</strong> is missing. You can either set an existing and matching cell header with this name, or you could create the missing column by clicking the <button class="btn btn-primary btn-small" onclick="createColumn(\'' + columnName + '\');">Create this column</button> button. In both cases: Please try again!</p>';
newAlert('error', 'Missing Column', message, 'columnAlert', getBase64Without(columnName));
return false;
}
return id;
return true;
}
/**
*
*/
function createColumn(columnName) {
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
var id = $.inArray(columnName, arr[0]);
// entry not existing, create
if(id < 0) {
if (id < 0) {
var colId;
// find empty column header
$(arr[0]).each(function(index,val) {
if(val === '') {
colId=index;
// find next empty column
for (var i = 0; i<arr[0].length; i++) {
if(!arr[0][i] || arr[0][i] === '') {
colId=i;
break;
}
});
$('#dataTable').handsontable('selectCell', 0, colId-1);
$('#dataTable').handsontable('alter', 'insert_col', colId-1);
$('#dataTable').handsontable('setDataAtCell', 0, colId-1, columnName);
}
tableInstance.selectCell(0, colId);
if (["TimeStamp", "TimeSpan:begin", "TimeSpan:end"].includes(columnName)){
tableInstance.setCellMeta(0, colId, 'type', 'time');
}
tableInstance.setDataAtCell(0, colId, columnName);
// Delete column alert.
$("#" + getBase64Without(columnName)).alert('close');
}
......@@ -174,13 +186,12 @@ function createColumn(columnName) {
* Getty ID is only overwritten if also not existing!
*/
function updateCoordinates(address, lat, long, gettyId, forceOverwrite, variant) {
// In case variant is not existing or given.
if (!variant) {
variant = "";
}
var arr = $('#dataTable').handsontable('getDataReference');
var arr = tableInstance.getData();
var addressColumn = findColumn(arr, 'Address');
var longColumn = findColumn(arr, 'Longitude');
......@@ -192,9 +203,9 @@ function updateCoordinates(address, lat, long, gettyId, forceOverwrite, variant)
$(arr).each(function(index, val) {
if ($.trim(val[addressColumn]) === $.trim(address) || ($.trim(val[addressColumn]) !== "" && variant.includes($.trim(val[addressColumn])))) {
if (forceOverwrite || (isEmptyString(val[longColumn]) && isEmptyString(val[latColumn]) && isEmptyString(val[gettyColumn]))) {
$('#dataTable').handsontable('setDataAtCell', index, longColumn, long);
$('#dataTable').handsontable('setDataAtCell', index, latColumn, lat);
$('#dataTable').handsontable('setDataAtCell', index, gettyColumn, gettyId);
tableInstance.setDataAtCell(index, longColumn, long);
tableInstance.setDataAtCell(index, latColumn, lat);
tableInstance.setDataAtCell(index, gettyColumn, gettyId);
save = true;
}
}
......
......@@ -12,18 +12,17 @@
<link rel="stylesheet" type="text/css" media="screen" href="https://res.de.dariah.eu/dhrep/css/bootstrap-customization.css" />
<link rel="stylesheet" type="text/css" media="screen" href="https://res.de.dariah.eu/dhrep/css/bootstrap-modal.css" />
<link rel="stylesheet" type="text/css" media="screen" href="https://res.de.dariah.eu/dhrep/css/font-awesome.css" />
<link rel="stylesheet" type="text/css" media="screen" href="./bower_components/handsontable/lib/jQuery-contextMenu/jquery.contextMenu.css" />
<link rel="stylesheet" type="text/css" media="screen" href="./bower_components/handsontable/jquery.handsontable.css" />
<link rel="stylesheet" href="https://dariah-de.github.io/status/dariah/embed.css">
<link rel="stylesheet" type="text/css" media="screen" href="./css/dariah.workflow.css" />
<link rel="shortcut icon" type="image/png" href="https://res.de.dariah.eu/dhrep/img/page_icon.png" />
<!-- DARIAH utils with some login/logout things and storage of course. We do need this right from the start! -->
<script src="../js/dariah.geobro.conf.js"></script>
<script src="../js/sessionStorageWrapper.js"></script>
<script src="./js/dariah.storage.js"></script>
<script src="./js/dariah.storage.list.js"></script>
<script src="./js/dariah.utils.js"></script>
<script src="./js/dariah.workflow.conf.js"></script>
<script src="./bower_components/jquery/jquery.js"></script>
<!-- DARIAH utils with some login/logout things and storage of course. We do need this right from the start! -->
<script src="https://code.jquery.com/jquery.min.js"></script>
<script src="../js/dariah.geobro.conf.js"></script>
<script src="../js/sessionStorageWrapper.js"></script>
<script src="./js/dariah.utils.js"></script>
<script src="./js/dariah.storage.js"></script>
<script src="./js/dariah.storage.list.js"></script>
<script src="./js/dariah.workflow.conf.js"></script>
<script>getEmbeddedDariahStatus();</script>
<script>loadOwnStorageFileList();</script>
<style>
......@@ -151,28 +150,9 @@
<!-- javascript
================================================== -->
<!-- placed at the end of the document so the pages load faster -->