@ -26,22 +26,38 @@ class CsvxmlValidator {
|
||||
|
||||
const lines = csvRaw.trim().replace("\r\n", "\n").split("\n");
|
||||
|
||||
const SEPARATOR = ';';
|
||||
let separator;
|
||||
let delimiter;
|
||||
if (csvRaw.substr(0, 1) === '"') {
|
||||
separator = '";"';
|
||||
delimiter = '"'
|
||||
}
|
||||
else {
|
||||
separator = ';';
|
||||
delimiter = '';
|
||||
}
|
||||
|
||||
// Gets first line
|
||||
let headers = lines.shift().split(SEPARATOR);
|
||||
let headersFields = lines.shift();
|
||||
let headers;
|
||||
if (delimiter === "") headers = headersFields.split(separator);
|
||||
else headers = headersFields.substr(1, headersFields.length - 2).split(separator);
|
||||
let expectedFieldCount = headers.length;
|
||||
|
||||
let toValidate = [];
|
||||
let lineCounter = 1;
|
||||
for (let line of lines) {
|
||||
|
||||
if (delimiter !== '') {
|
||||
line = line.substr(1, line.length - 2);
|
||||
}
|
||||
|
||||
// Remove fully empty lines (both without content and those with fields set up,
|
||||
// but without content there.
|
||||
if (line.length <= headers.length) continue;
|
||||
|
||||
let lineContents = {};
|
||||
let fields = line.split(SEPARATOR);
|
||||
let fields = line.split(separator);
|
||||
|
||||
if (fields.length !== headers.length) {
|
||||
this.errors.parsing.push("Number of columns in line " + lineCounter + " does not match number of headers");
|
||||
@ -55,11 +71,13 @@ class CsvxmlValidator {
|
||||
lineContents[headers[i]] = fields[i];
|
||||
}
|
||||
|
||||
// Skip totally empty lines
|
||||
if (Object.values(lineContents).join("").length === 0) continue;
|
||||
|
||||
toValidate.push(lineContents);
|
||||
lineCounter++;
|
||||
}
|
||||
|
||||
console.log(toValidate);
|
||||
this.toValidate = toValidate;
|
||||
|
||||
if (toValidate.length === 0) {
|
||||
@ -120,7 +138,7 @@ class CsvxmlValidator {
|
||||
const headers = Object.keys(this.toValidate[0]);
|
||||
|
||||
for (let header of headers) {
|
||||
if (this.fieldList[header].dependsOn === undefined || this.fieldList[header].dependsOn === null) continue;
|
||||
if (this.fieldList[header] === undefined || this.fieldList[header].dependsOn === undefined || this.fieldList[header].dependsOn === null) continue;
|
||||
|
||||
let dependencies = this.fieldList[header].dependsOn;
|
||||
for (let dep of dependencies) {
|
||||
@ -138,12 +156,17 @@ class CsvxmlValidator {
|
||||
for (let line of this.toValidate) {
|
||||
for (let fieldName in line) {
|
||||
|
||||
if (this.fieldList[fieldName] === undefined) {
|
||||
console.log("Undefined but requested field " + fieldName);
|
||||
continue;
|
||||
}
|
||||
|
||||
let allowedValues = this.fieldList[fieldName].allowedValues;
|
||||
|
||||
// No error if the field doesn't have a controlled list
|
||||
if (allowedValues === undefined || allowedValues === null) continue;
|
||||
// No error if the line's content is in the list
|
||||
if (Object.values(allowedValues).length === 0 || Object.values(allowedValues).includes(line.fieldName)) {
|
||||
if (Object.values(allowedValues).length === 0 || Object.values(allowedValues).includes(line[fieldName])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -161,7 +184,7 @@ class CsvxmlValidator {
|
||||
isValid() {
|
||||
|
||||
for (let errorClass in this.errors) {
|
||||
if (errorClass.length !== 0) return false;
|
||||
if (this.errors[errorClass].length !== 0) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -270,9 +293,7 @@ class CsvxmlTooltip {
|
||||
|
||||
newMain.setAttribute("data-title", tooltipTitle);
|
||||
|
||||
const tooltipDesc = document.createElement("p");
|
||||
tooltipDesc.textContent = tooltipContent;
|
||||
newMain.appendChild(tooltipDesc);
|
||||
newMain.appendChild(tooltipContent);
|
||||
|
||||
document.body.appendChild(newMain);
|
||||
newMain.classList.add("visible");
|
||||
@ -297,15 +318,75 @@ class CsvxmlTooltip {
|
||||
|
||||
}
|
||||
|
||||
class CsvxmlDialogue {
|
||||
|
||||
static closeDialogue(e) {
|
||||
|
||||
if (e !== undefined) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
|
||||
let dialogueArea = document.getElementById("dialogueArea");
|
||||
if (dialogueArea !== null && dialogueArea !== false) {
|
||||
while (dialogueArea.firstChild) {
|
||||
dialogueArea.removeChild(dialogueArea.firstChild);
|
||||
}
|
||||
dialogueArea.parentElement.removeChild(dialogueArea);
|
||||
|
||||
document.removeEventListener('keydown', CsvxmlDialogue.closeDialogueByEscape, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static closeDialogueByEscape(e) {
|
||||
|
||||
if (e.keyCode === 27) { // 27 = Esc
|
||||
|
||||
CsvxmlDialogue.closeDialogue(e);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Function for drawing a dialogue and attaching it to the body elem.
|
||||
*
|
||||
* @param {DOMElement} contents Contents.
|
||||
*/
|
||||
static drawDialogue(contents) {
|
||||
let dialogueArea = document.createElement("div");
|
||||
dialogueArea.id = "dialogueArea";
|
||||
|
||||
let dialogue = document.createElement("div");
|
||||
dialogue.id = "dialogue";
|
||||
|
||||
dialogue.appendChild(contents);
|
||||
dialogueArea.appendChild(dialogue);
|
||||
|
||||
document.body.appendChild(dialogueArea);
|
||||
|
||||
document.addEventListener('keydown', CsvxmlDialogue.closeDialogueByEscape);
|
||||
|
||||
return dialogue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CsvxmlPage {
|
||||
|
||||
fieldList;
|
||||
tls;
|
||||
domUploaderWrapper;
|
||||
domMainWrapper;
|
||||
selectedFields;
|
||||
|
||||
csvBySelectionButton;
|
||||
unsetSelectionButton;
|
||||
|
||||
constructor(fieldList) {
|
||||
this.fieldList = Object.freeze(fieldList);
|
||||
this.tls = Object.freeze(JSON.parse(document.body.getAttribute("data-tls")));
|
||||
|
||||
let domUploaderWrapper = document.createElement("div");
|
||||
domUploaderWrapper.id = "uploader";
|
||||
@ -394,6 +475,70 @@ class CsvxmlPage {
|
||||
|
||||
}
|
||||
|
||||
listValidationErrors(validator) {
|
||||
|
||||
const dialogueContent = document.createElement("div");
|
||||
|
||||
const headline = document.createElement("h3");
|
||||
headline.textContent = this.tls.validation_errors;
|
||||
|
||||
const cancelB = document.createElement("a");
|
||||
cancelB.classList.add("icons");
|
||||
cancelB.classList.add("iconsClose");
|
||||
cancelB.classList.add("dialogueCloseX");
|
||||
cancelB.id = "dialogueClose";
|
||||
cancelB.textContent = "X";
|
||||
cancelB.title = "Close";
|
||||
cancelB.href = "#" + location.href;
|
||||
cancelB.addEventListener('click', CsvxmlDialogue.closeDialogue);
|
||||
headline.appendChild(cancelB);
|
||||
|
||||
dialogueContent.appendChild(headline);
|
||||
|
||||
const domErrorsSection = document.createElement("div");
|
||||
|
||||
for (let errorType in validator.errors) {
|
||||
|
||||
if (validator.errors[errorType].length === 0) continue;
|
||||
|
||||
const ulHl = document.createElement("h4");
|
||||
ulHl.textContent = this.tls['errors_' + errorType] + " (" + validator.errors[errorType].length + ")";
|
||||
ulHl.style.cursor = "pointer";
|
||||
domErrorsSection.appendChild(ulHl);
|
||||
|
||||
const ul = document.createElement("ul");
|
||||
|
||||
for (let error of validator.errors[errorType]) {
|
||||
const li = document.createElement("li");
|
||||
li.textContent = error;
|
||||
ul.appendChild(li);
|
||||
}
|
||||
|
||||
ulHl.addEventListener('click', function() {
|
||||
ul.classList.toggle("minimized");
|
||||
});
|
||||
|
||||
domErrorsSection.appendChild(ul);
|
||||
|
||||
}
|
||||
|
||||
dialogueContent.appendChild(domErrorsSection);
|
||||
|
||||
const domDlSection = document.createElement("div");
|
||||
const domDlA = document.createElement("span");
|
||||
domDlA.textContent = this.tls.download;
|
||||
domDlA.classList.add("buttonLike");
|
||||
let app = this;
|
||||
domDlA.addEventListener('click', function() {
|
||||
app.zipUploadToXml(validator);
|
||||
});
|
||||
domDlSection.appendChild(domDlA);
|
||||
dialogueContent.appendChild(domDlSection);
|
||||
|
||||
dialogue = CsvxmlDialogue.drawDialogue(dialogueContent);
|
||||
|
||||
}
|
||||
|
||||
uploadFileForValidation(file) {
|
||||
|
||||
const reader = new FileReader();
|
||||
@ -408,15 +553,13 @@ class CsvxmlPage {
|
||||
// Validate the file
|
||||
let validator = new CsvxmlValidator(app.fieldList, reader.result);
|
||||
if (validator.isValid() === true) {
|
||||
alert("Document is valid");
|
||||
alert("Document is valid. Press ok to download.");
|
||||
app.zipUploadToXml(validator);
|
||||
}
|
||||
else {
|
||||
console.log(validator.errors);
|
||||
alert("Document is not valid. Errors are " + validator.errors);
|
||||
app.listValidationErrors(validator);
|
||||
}
|
||||
|
||||
app.zipUploadToXml(validator);
|
||||
|
||||
};
|
||||
reader.onerror = function() {
|
||||
alert(reader.error);
|
||||
@ -432,7 +575,7 @@ class CsvxmlPage {
|
||||
const form = document.createElement("form");
|
||||
|
||||
const label = document.createElement("label");
|
||||
label.textContent = "Please select a CSV file to create XML files"; // TODO
|
||||
label.textContent = app.tls.select_csv_file_for_upload;
|
||||
label.setAttribute("for", "fileToUpload");
|
||||
form.appendChild(label);
|
||||
|
||||
@ -446,10 +589,12 @@ class CsvxmlPage {
|
||||
});
|
||||
form.appendChild(input);
|
||||
|
||||
/*
|
||||
const button = document.createElement("button");
|
||||
button.textContent = "Upload"; // TODO
|
||||
button.type = "submit";
|
||||
form.appendChild(button);
|
||||
*/
|
||||
|
||||
app.domUploaderWrapper.appendChild(form);
|
||||
|
||||
@ -459,6 +604,58 @@ class CsvxmlPage {
|
||||
|
||||
}
|
||||
|
||||
// Takes a callback function
|
||||
doForFieldList(callback) {
|
||||
let fieldLists = document.getElementsByClassName("fieldList");
|
||||
for (let i = 0, max = fieldLists.length; i < max; i++) {
|
||||
|
||||
let fields = fieldLists[i].getElementsByTagName("li");
|
||||
for (let j = 0, maxj = fields.length; j < maxj; j++) {
|
||||
|
||||
callback(fields[j]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
toggleListFieldSelectionState(field) {
|
||||
|
||||
let app = this;
|
||||
|
||||
let newValue = field.getAttribute("data-alt");
|
||||
field.setAttribute("data-alt", field.textContent);
|
||||
field.textContent = newValue;
|
||||
field.classList.toggle("humanTLToggled");
|
||||
|
||||
if (field.classList.contains("humanTLToggled") === false) return;
|
||||
|
||||
let dependencies = field.getAttribute("data-dependencies");
|
||||
if (dependencies !== undefined && dependencies !== null) {
|
||||
let linkedFields = dependencies.split(";");
|
||||
for (let i = 0, max = linkedFields.length; i < max; i++) {
|
||||
let linkedField = document.getElementById(linkedFields[i]);
|
||||
if (linkedField.classList.contains("humanTLToggled") === true) continue;
|
||||
app.toggleListFieldSelectionState(linkedField);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
checkCSVBySelectionAccessibility() {
|
||||
|
||||
let selected = document.getElementsByClassName("humanTLToggled");
|
||||
if (selected.length === 0) {
|
||||
this.csvBySelectionButton.classList.add("invisible");
|
||||
this.unsetSelectionButton.classList.add("invisible");
|
||||
}
|
||||
else {
|
||||
this.csvBySelectionButton.classList.remove("invisible");
|
||||
this.unsetSelectionButton.classList.remove("invisible");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
getOptionsSection() {
|
||||
|
||||
function genButton(id, text, link = "") {
|
||||
@ -477,93 +674,28 @@ class CsvxmlPage {
|
||||
|
||||
const app = this;
|
||||
|
||||
const dlAllButton = genButton("dlAll", "Download all");
|
||||
const dlAllButton = genButton("dlAll", this.tls.download_csv_all);
|
||||
dlAllButton.cursor = "pointer";
|
||||
dlAllButton.addEventListener('click', function() {
|
||||
app.generateCsv();
|
||||
});
|
||||
options.appendChild(dlAllButton); // TODO
|
||||
options.appendChild(dlAllButton);
|
||||
|
||||
const csvBySelectionButton = genButton("csvBySelection", "Csv by selection");
|
||||
csvBySelectionButton.classList.add("invisible");
|
||||
// TODO: Add toggle via event listener
|
||||
options.appendChild(csvBySelectionButton);
|
||||
this.csvBySelectionButton = genButton("csvBySelection", this.tls.download_csv_by_selection);
|
||||
this.csvBySelectionButton.classList.add("invisible");
|
||||
options.appendChild(this.csvBySelectionButton);
|
||||
|
||||
const optionSelectRequired = genButton("selectRequired", "Select required");
|
||||
const optionSelectRequired = genButton("selectRequired", this.tls.select_required_fields);
|
||||
options.appendChild(optionSelectRequired);
|
||||
|
||||
const optionSelectAll = genButton("selectAll", "Select all");
|
||||
const optionSelectAll = genButton("selectAll", this.tls.select_all_fields);
|
||||
options.appendChild(optionSelectAll);
|
||||
|
||||
const unsetSelectionButton = genButton("unsetSelection", "Unset selection");
|
||||
unsetSelectionButton.classList.add("invisible");
|
||||
// TODO: Add toggle via event listener
|
||||
options.appendChild(unsetSelectionButton);
|
||||
this.unsetSelectionButton = genButton("unsetSelection", this.tls.unset_selection);
|
||||
this.unsetSelectionButton.classList.add("invisible");
|
||||
options.appendChild(this.unsetSelectionButton);
|
||||
|
||||
function checkCSVBySelectionAccessibility() {
|
||||
|
||||
let selected = document.getElementsByClassName("humanTLToggled");
|
||||
if (selected.length === 0) {
|
||||
csvBySelectionButton.classList.add("invisible");
|
||||
unsetSelectionButton.classList.add("invisible");
|
||||
}
|
||||
else {
|
||||
csvBySelectionButton.classList.remove("invisible");
|
||||
unsetSelectionButton.classList.remove("invisible");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Takes a callback function
|
||||
function doForFieldList(callback) {
|
||||
let fieldLists = document.getElementsByClassName("fieldList");
|
||||
for (let i = 0, max = fieldLists.length; i < max; i++) {
|
||||
|
||||
let fields = fieldLists[i].getElementsByTagName("li");
|
||||
for (let j = 0, maxj = fields.length; j < maxj; j++) {
|
||||
|
||||
callback(fields[j]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function toggleListFieldSelectionState(field) {
|
||||
|
||||
let newValue = field.getAttribute("data-alt");
|
||||
field.setAttribute("data-alt", field.textContent);
|
||||
field.textContent = newValue;
|
||||
field.classList.toggle("humanTLToggled");
|
||||
|
||||
if (field.classList.contains("humanTLToggled") === false) return;
|
||||
|
||||
let dependencies = field.getAttribute("data-dependencies");
|
||||
if (dependencies !== undefined && dependencies !== null) {
|
||||
let linkedFields = dependencies.split(";");
|
||||
for (let i = 0, max = linkedFields.length; i < max; i++) {
|
||||
let linkedField = document.getElementById(linkedFields[i]);
|
||||
if (linkedField.classList.contains("humanTLToggled") === true) continue;
|
||||
toggleListFieldSelectionState(linkedField);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
doForFieldList(function(field) {
|
||||
|
||||
// Each field should switch its visible content and human-readable
|
||||
// translation on a click.
|
||||
field.addEventListener('click', function(e) {
|
||||
|
||||
toggleListFieldSelectionState(field);
|
||||
checkCSVBySelectionAccessibility();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
csvBySelectionButton.addEventListener('click', function(e) {
|
||||
this.csvBySelectionButton.addEventListener('click', function(e) {
|
||||
|
||||
let selected = document.getElementsByClassName("humanTLToggled");
|
||||
let selectedFields = [];
|
||||
@ -576,12 +708,12 @@ class CsvxmlPage {
|
||||
|
||||
optionSelectRequired.addEventListener('click', function(e) {
|
||||
|
||||
doForFieldList(function(field) {
|
||||
app.doForFieldList(function(field) {
|
||||
if (field.classList.contains("requiredField") === false) return;
|
||||
if (field.classList.contains("humanTLToggled") === true) return;
|
||||
|
||||
toggleListFieldSelectionState(field);
|
||||
checkCSVBySelectionAccessibility();
|
||||
app.toggleListFieldSelectionState(field);
|
||||
app.checkCSVBySelectionAccessibility();
|
||||
|
||||
});
|
||||
|
||||
@ -589,23 +721,23 @@ class CsvxmlPage {
|
||||
|
||||
optionSelectAll.addEventListener('click', function(e) {
|
||||
|
||||
doForFieldList(function(field) {
|
||||
app.doForFieldList(function(field) {
|
||||
if (field.classList.contains("humanTLToggled") === true) return;
|
||||
|
||||
toggleListFieldSelectionState(field);
|
||||
checkCSVBySelectionAccessibility();
|
||||
app.toggleListFieldSelectionState(field);
|
||||
app.checkCSVBySelectionAccessibility();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
unsetSelectionButton.addEventListener('click', function(e) {
|
||||
this.unsetSelectionButton.addEventListener('click', function(e) {
|
||||
|
||||
doForFieldList(function(field) {
|
||||
app.doForFieldList(function(field) {
|
||||
if (field.classList.contains("humanTLToggled") === false) return;
|
||||
|
||||
toggleListFieldSelectionState(field);
|
||||
checkCSVBySelectionAccessibility();
|
||||
app.toggleListFieldSelectionState(field);
|
||||
app.checkCSVBySelectionAccessibility();
|
||||
|
||||
});
|
||||
|
||||
@ -618,7 +750,7 @@ class CsvxmlPage {
|
||||
renderMain() {
|
||||
|
||||
const domH2 = document.createElement("h2");
|
||||
domH2.textContent = "Currently approved tags (column names) for md:import";
|
||||
domH2.textContent = this.tls.currently_approved_tags;
|
||||
this.domMainWrapper.appendChild(domH2);
|
||||
|
||||
this.domMainWrapper.appendChild(this.getOptionsSection());
|
||||
@ -634,8 +766,6 @@ class CsvxmlPage {
|
||||
const domUl = document.createElement("ul");
|
||||
domUl.classList.add("fieldList");
|
||||
|
||||
console.log(sectionName);
|
||||
|
||||
const sectionFields = this.fieldList[sectionName];
|
||||
for (let fieldName in sectionFields) {
|
||||
const field = sectionFields[fieldName];
|
||||
@ -648,7 +778,32 @@ class CsvxmlPage {
|
||||
if (field.required === true) domLi.classList.add("requiredField");
|
||||
domUl.appendChild(domLi);
|
||||
|
||||
CsvxmlTooltip.bindTooltipToElement(domLi, field.name_human_readable, field.explica);
|
||||
const tooltipContent = document.createElement("div");
|
||||
const explicaP = document.createElement("p");
|
||||
explicaP.textContent = field.explica;
|
||||
tooltipContent.appendChild(explicaP);
|
||||
|
||||
if (field.remarks !== undefined && field.remarks !== '') {
|
||||
|
||||
const remarkHl = document.createElement("h4");
|
||||
remarkHl.textContent = this.tls.remarks;
|
||||
tooltipContent.appendChild(remarkHl)
|
||||
const remarkCont = document.createElement("p");
|
||||
remarkCont = field.remarks;
|
||||
tooltipContent.appendChild(remarkCont);
|
||||
|
||||
}
|
||||
|
||||
if (field.allowedValues !== undefined && Object.values(field.allowedValues).length !== 0) {
|
||||
const allowedHl = document.createElement("h4");
|
||||
allowedHl.textContent = this.tls.allowed_values;
|
||||
tooltipContent.appendChild(allowedHl);
|
||||
const allowedList = document.createElement("p");
|
||||
allowedList.textContent = Object.values(field.allowedValues).join(', ');
|
||||
tooltipContent.appendChild(allowedList);
|
||||
}
|
||||
|
||||
CsvxmlTooltip.bindTooltipToElement(domLi, field.name_human_readable, tooltipContent);
|
||||
|
||||
}
|
||||
|
||||
@ -660,6 +815,20 @@ class CsvxmlPage {
|
||||
|
||||
document.body.appendChild(this.domMainWrapper);
|
||||
|
||||
let app = this;
|
||||
this.doForFieldList(function(field) {
|
||||
|
||||
// Each field should switch its visible content and human-readable
|
||||
// translation on a click.
|
||||
field.addEventListener('click', function(e) {
|
||||
|
||||
app.toggleListFieldSelectionState(field);
|
||||
app.checkCSVBySelectionAccessibility();
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user