228 lines
6.3 KiB
JavaScript
228 lines
6.3 KiB
JavaScript
const button = document.querySelector(".save")
|
|
const infoRow = document.querySelector(".info-row")
|
|
const info = document.querySelector(".table-guide")
|
|
const container = document.querySelector(".handsontable-container")
|
|
const table = document.getElementById('handsontable');
|
|
const addVariable = document.querySelector(".add-variable")
|
|
const inputOverlay = document.querySelector(".input-overlay")
|
|
const addColumn = document.querySelector(".add-column")
|
|
|
|
const newVariable = document.querySelector(".heading")
|
|
|
|
const proceed = document.querySelector(".proceed")
|
|
|
|
|
|
|
|
let values = data["values"]
|
|
let headers = data["headers"]
|
|
let hot;
|
|
let savedChanges = True;
|
|
|
|
|
|
// If the table has not yet been created then we want to hide the DOM elements
|
|
if(headers.length == 0){
|
|
container.classList.add("invisible")
|
|
infoRow.classList.add("invisible")
|
|
} else{
|
|
// Edge case: handsontable needs a 2d array. If 'values' is empty it needs converting
|
|
if (values.length == 0){
|
|
values = [[]]
|
|
}
|
|
inputOverlay.classList.add("invisible")
|
|
renderTable(values, headers)
|
|
}
|
|
|
|
addColumn.addEventListener('click', function () {
|
|
triggerModal()
|
|
});
|
|
|
|
|
|
function triggerModal(){
|
|
// Allow user to submit a column field simply by pressing enter
|
|
$(document).unbind("keyup").keyup(function(e){
|
|
// Get the key code
|
|
let code = e.which;
|
|
// If it is equal to 13 then click the confirm button
|
|
if(code==13)
|
|
{
|
|
$("#confirm").click();
|
|
}
|
|
});
|
|
|
|
if(newVariable.value == ""){
|
|
// If the user tries to enter in an empty string, modal remains open with warning class
|
|
newVariable.classList.add("is-invalid")
|
|
}else{
|
|
// Remove the warning box class if the user has previously tried to enter an empty string
|
|
newVariable.classList.remove("is-invalid")
|
|
// Add new column heading
|
|
headers.push(newVariable.value)
|
|
// Close the modal and reset the input box to be empty
|
|
$('#new-column-modal').modal('toggle');
|
|
newVariable.value = ""
|
|
// If the table does not yet exist, we need to remove the overlay and make the table visible
|
|
if(hot == undefined){
|
|
container.classList.remove("invisible")
|
|
infoRow.classList.remove("invisible")
|
|
inputOverlay.classList.add("invisible")
|
|
// Intialise empty 2d array to represent the cells in the table
|
|
values=[[]]
|
|
// Render the table
|
|
renderTable(values, headers)
|
|
// If table already exists we can simply update it
|
|
}else{
|
|
hot.alter('insert_col', headers.length, 1)
|
|
// Necessary, since 'insert_col' will add an an 'undefined' header to the header list
|
|
// (which is not needed since we have already added the header with the specified name)
|
|
headers.pop()
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function columnData(headers){
|
|
let columns = []
|
|
headers.forEach(header => {
|
|
columns.push({data: header})
|
|
})
|
|
return columns
|
|
}
|
|
|
|
|
|
function renderTable(values, headers){
|
|
hot = new Handsontable(table, {
|
|
data: values,
|
|
// 23 rows will fill up the view for the user
|
|
minRows: 23,
|
|
minCols: 1,
|
|
stretchH: 'all',
|
|
rowHeaders: true,
|
|
colHeaders: true,
|
|
minSpareRows: 1,
|
|
allowEmpty: false,
|
|
filters: true,
|
|
colHeaders: headers,
|
|
licenseKey: 'non-commercial-and-evaluation',
|
|
columnSorting: true,
|
|
dropdownMenu: {
|
|
items: [
|
|
{
|
|
key:'rename_column',
|
|
name: 'Rename column',
|
|
callback: (key, option) => {
|
|
cellIndex = option[0].end.col
|
|
var newColHeader = prompt('Pick new name');
|
|
if(newColHeader){
|
|
headers[cellIndex] = newColHeader
|
|
hot.render()
|
|
}
|
|
}
|
|
},
|
|
'---------',
|
|
'remove_col',
|
|
'---------',
|
|
'col_left',
|
|
'---------',
|
|
'col_right'
|
|
]
|
|
},
|
|
afterChange: function (change, source) {
|
|
if (source !== 'loadData') {
|
|
info.innerHTML = "You have unsaved changes"
|
|
info.style.color = "red"
|
|
savedChanges = False;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
function removeEmptyRows(){
|
|
let data = hot.getData()
|
|
let emptyRows = []
|
|
data.forEach((row, i) => {
|
|
if(hot.isEmptyRow(i)){
|
|
emptyRows.push([i, 1])
|
|
}
|
|
})
|
|
let newHot = hot.alter("remove_row", emptyRows, 1)
|
|
return newHot
|
|
}
|
|
|
|
|
|
|
|
|
|
// Put all of our standalone jquery function inside a document ready check
|
|
$(document).ready(function(){
|
|
// A function that prompts the user to save if they have not done so before moving to home
|
|
$('#proceed').click(function(event) {
|
|
if(!savedChanges){
|
|
event.preventDefault();
|
|
$('#save-changes-modal').modal('toggle');
|
|
}
|
|
});
|
|
|
|
|
|
// Prevent form auto submitting when a user presses Enter
|
|
$(document).on("keydown", "form", function(event) {
|
|
return event.key != "Enter";
|
|
});
|
|
|
|
|
|
// Function responsible for form submission
|
|
$('form').submit(function (e) {
|
|
// Remove any extra rows before saving (so they are not also submitted)
|
|
hot.updateSettings({
|
|
minSpareRows: 0,
|
|
minRows:0
|
|
})
|
|
// Remove empty rows (if any)
|
|
let newHot = removeEmptyRows();
|
|
|
|
// Get the export plugin on the newHot (if it exists) else on the old hot
|
|
let exportPlugin = newHot != undefined ? newHot.getPlugin('exportFile') : hot.getPlugin('exportFile')
|
|
|
|
const string = exportPlugin.exportAsString('csv', {
|
|
columnHeaders: true,
|
|
});
|
|
// Post the data has a string to the server
|
|
postData(string)
|
|
// Prevent default form submission
|
|
e.preventDefault();
|
|
|
|
// Change spare rows back to 1 and min back to 23 if user wants to continue editing
|
|
hot.updateSettings({
|
|
minSpareRows: 1,
|
|
minRows:23
|
|
})
|
|
// Update the html to display that the changes have been submitted
|
|
info.innerHTML = "Up to date"
|
|
info.style.color = "green"
|
|
savedChanges = True;
|
|
});
|
|
});
|
|
|
|
|
|
// Post the table as a string to the server (with the title)
|
|
function postData(dataString){
|
|
$.ajaxSetup({
|
|
beforeSend: function(xhr, settings) {
|
|
if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
|
|
xhr.setRequestHeader("X-CSRFToken", csrf)
|
|
}
|
|
}
|
|
})
|
|
var postData = $('form').serializeArray()
|
|
postData.push({name: "table", value: dataString})
|
|
$.ajax({
|
|
type: "POST",
|
|
url: url,
|
|
data: postData,
|
|
success: function (data) {
|
|
// The server returns the id of the survey (if it is new) so we can update our URL
|
|
url = Flask.url_for("surveys.input", {"survey_id": data})
|
|
}
|
|
});
|
|
}
|