Finish full JS rewrite (in index_new.php fr now)

See #14
This commit is contained in:
Joshua Ramon Enslin 2022-11-06 23:23:02 +01:00
parent 77aeebd90a
commit a141b23608
Signed by: jrenslin
GPG Key ID: 46016F84501B70AE
5 changed files with 397 additions and 134 deletions

View File

@ -1,4 +1,17 @@
@import 'editMenu.css'; @import 'editMenu.css';
@import 'dialogue.css';
:root {
--color-bg-normal: #FFF;
--color-bg-raised: #EEE;
--color-bg-raised2: #FAFAFA;
--color-fg-normal: #000;
--color-fg-less: #212121;
--color-borders: #D6D6D6;
--color-borders-dark: #646464;
--color-accent-normal: #FFCCBC;
--color-accent-hover: #CB9B8C;
}
/* ============== /* ==============
| Load fonts | Load fonts
@ -18,16 +31,17 @@
* { box-sizing: border-box; z-index: 1; } * { box-sizing: border-box; z-index: 1; }
body { margin: 2em; background: #FFF; body { margin: 2em; background: var(--color-bg-normal);
font-family: sourceSansPro, Arial, Helvetica, Times; font-size: 1.2em; line-height: 1.5em; } font-family: sourceSansPro, Arial, Helvetica, Times; font-size: 1.2em; line-height: 1.5em; }
a { text-decoration: none; color: inherit; } a { text-decoration: none; color: inherit; }
h1 { display: block; max-width: 600px; margin: 0 auto 1.5em auto; } h1 { display: block; max-width: 600px; margin: 0 auto 1.5em auto; }
h1 > * { display: inline-block; vertical-align: middle; color: #212121; } h1 > * { display: inline-block; vertical-align: middle; color: var(--color-fg-less); }
h1 img { height: 2em; margin-right: .2em; border-radius: .1em; opacity: .7; transition: opacity .4s; } h1 img { height: 2em; margin-right: .2em; border-radius: .1em; opacity: .7; transition: opacity .4s; }
h1 img:hover { opacity: 1; } h1 img:hover { opacity: 1; }
main,
body > div, body > div,
body > form { display: block; max-width: 90vw; margin: 0 auto 3em auto; padding-bottom: 3em; } body > form { display: block; max-width: 90vw; margin: 0 auto 3em auto; padding-bottom: 3em; }
@ -40,8 +54,8 @@ label { display: block; font-weight: bold; margin-bottom: .5em; }
select, select,
button, button,
textarea, textarea,
input { display: block; width: 100%; padding: .5em .5em; border: 2.5px solid #EEE; input { display: block; width: 100%; padding: .5em .5em; border: 2.5px solid var(--color-bg-raised);
background: inherit; color: #424242; font-family: roboto; font-size: 1em; background: inherit; color: var(--color-fg-less); font-family: roboto; font-size: 1em;
border-radius: .2em; transition: border .2s; } border-radius: .2em; transition: border .2s; }
.buttonLike { display: inline-block; text-align: center; } .buttonLike { display: inline-block; text-align: center; }
@ -49,7 +63,7 @@ input[type="submit"],
button { padding: .5em .8em; } button { padding: .5em .8em; }
.buttonLike, .buttonLike,
input[type="submit"], input[type="submit"],
button { background: #FFCCBC; color: #424242; border: none; font-weight: bold; text-transform: uppercase; transition: background .2s, color .2s; } button { background: var(--color-accent-normal); color: var(--color-fg-less); border: none; font-weight: bold; text-transform: uppercase; transition: background .2s, color .2s; }
textarea { line-height: 1.2em; } textarea { line-height: 1.2em; }
select:hover, select:hover,
@ -61,7 +75,7 @@ input[type="submit"]:focus,
button:focus, button:focus,
.buttonLike:hover, .buttonLike:hover,
input[type="submit"]:hover, input[type="submit"]:hover,
button:hover { background: #CB9B8C; color: #000; } button:hover { background: var(--color-accent-hover); color: #000; }
aside .buttonLike + .buttonLike, aside .buttonLike + .buttonLike,
aside button + button { margin-top: .5em; } aside button + button { margin-top: .5em; }
@ -69,7 +83,7 @@ aside > h4:first-child { margin-top: 0; }
select:focus, select:focus,
textarea:focus, textarea:focus,
input:focus { border-color: #CB9B8C; box-shadow: none; } input:focus { border-color: var(--color-accent-hover); box-shadow: none; }
textarea:invalid, textarea:invalid,
input:invalid { box-shadow: none; } input:invalid { box-shadow: none; }
@ -80,29 +94,29 @@ textarea { min-height: 30vh; }
table { width: 100%; max-height: 60vh; margin: 2em 0; border-collapse: collapse; overflow: auto; } table { width: 100%; max-height: 60vh; margin: 2em 0; border-collapse: collapse; overflow: auto; }
th { padding: .3em .5em; text-align: left; border-bottom: 2px solid #424242; } th { padding: .3em .5em; text-align: left; border-bottom: 2px solid var(--color-fg-less); }
tbody > tr:nth-child(2n + 1) { background: #F2F2F2; } tbody > tr:nth-child(2n + 1) { background: var(--color-bg-raised2); }
td { padding: .3em .5em; border-bottom: 1px solid #D6D6D6; } td { padding: .3em .5em; border-bottom: 1px solid var(--color-borders); }
body > div.uploader { background: #F2F2F2; border: 2px solid #EEE; padding: 1em 1em; } body > div.uploader { background: var(--color-bg-raised2); border: 2px solid var(--color-bg-raised); padding: 1em 1em; }
ul.fieldList { display: block; margin: .5em 0; padding: 0 0; list-style: none; } ul.fieldList { display: block; margin: .5em 0; padding: 0 0; list-style: none; }
ul.fieldList > li { display: inline-block; padding: .3em; margin: .1em; border: 1px solid #D6D6D6; background: #FAFAFA; cursor: pointer; transition: background .4s, border .4s, box-shadow .4s;; } ul.fieldList > li { display: inline-block; padding: .3em; margin: .1em; border: 1px solid var(--color-borders); background: var(--color-bg-raised2); cursor: pointer; transition: background .4s, border .4s, box-shadow .4s;; }
ul.fieldList > li:hover { background: #FFF; border-color: #212121; } ul.fieldList > li:hover { background: var(--color-bg-normal); border-color: var(--color-fg-less); }
ul.fieldList > li.requiredField:before { display: inline-block; content: " \002612 "; margin-right: .5em; } ul.fieldList > li.requiredField:before { display: inline-block; content: " \002612 "; margin-right: .5em; }
ul.fieldList > li.humanTLToggled { border-color: #CB9B8C; background: #CB9B8C; box-shadow: 0 8px 6px -6px black; } ul.fieldList > li.humanTLToggled { border-color: var(--color-accent-hover); background: var(--color-accent-hover); box-shadow: 0 8px 6px -6px black; }
.options > a.buttonLike { display: inline-block; width: auto; .options > a.buttonLike { display: inline-block; width: auto;
margin: .15em 0; padding: .4em .5em; margin: .15em 0; padding: .4em .5em;
text-transform: inherit; cursor: pointer; text-transform: inherit; cursor: pointer;
background: initial; border: 2px solid #D6D6D6; background: initial; border: 2px solid var(--color-borders);
opacity: 1; opacity: 1;
transition: background .4s, opacity .4s; } transition: background .4s, opacity .4s; }
.options > a.buttonLike:hover { background: #D6D6D6; } .options > a.buttonLike:hover { background: var(--color-borders); }
.actionList { margin: 1em 0 1em 1em; padding: .5em 0; } .actionList { margin: 1em 0 1em 1em; padding: .5em 0; }
.actionList > li a { display: inline-block; padding: .3em; border-radius: .3em; transition: background .4s; } .actionList > li a { display: inline-block; padding: .3em; border-radius: .3em; transition: background .4s; }
.actionList > li a:hover { background: #CB9B8C; } .actionList > li a:hover { background: var(--color-accent-hover); }
/* ============= /* =============
| Dark mode | Dark mode

View File

@ -0,0 +1,40 @@
/* ========
| Reference overlay
|= ======== */
#dialogueArea { display: block; position: fixed; left: 0; top: 0;
width: 100%; height: 100%;
max-width: initial; max-height: initial;
background: rgba(0,0,0,.7); backdrop-filter: blur(3px);
z-index: 10000; }
#dialogue { display: block; position: absolute; left: 50%; top: 50%;
transform: translate(-50%, -50%); min-width: 60vw; min-height: 2em;
max-width: 90vw; max-height: 90vh; overflow-y: auto;
padding: 1.5em 1em;
background: var(--color-bg-normal); border-radius: .3em;
box-shadow: 2px 2px 4px var(--color-fg-less), -2px -2px 4px var(--color-fg-less); }
#dialogue h3 { margin-top: 0; padding-top: 0; text-transform: initial; color: var(--color-fg-less); }
#confirmButtons { text-align: right; }
#dialogue .buttonLike { margin: .5em 0 .2em .5em; background: transparent; transition: background .4s, color .4s; }
#dialogue .buttonLike:hover { background: var(--color-borders-dark); color: var(--color-bg-normal); }
#dialogue input[type="text"],
#dialogue textarea { padding: .5em; border-radius: .1em; border: 2px solid var(--color-borders); transition: border .4s; }
#dialogue input[type="text"]:hover,
#dialogue textarea:hover { border-color: var(--color-fg-normal); }
#dialogue button { padding: .6em .8em; font-size: .8em; background: var(--color-bg-normal); border: 1px solid var(--color-borders);
transition: .4s; }
#dialogue button:focus,
#dialogue button:hover { background: var(--color-fg-less); color: var(--color-bg-normal); border-color: var(--color-fg-less); }
#dialogue form > * { display: block; width: 100%; }
#dialogue form label { font-weight: bold; color: var(--color-fg-less); }
#dialogueClose { float: right; display: inline-block; padding: 0 .6em .2em .6em; background: var(--color-bg-raised);
border-radius: 100%; cursor: pointer; transition: .4s; }
#dialogueClose:hover { background: var(--color-fg-less); color: var(--color-bg-normal); }
#dialogue ul { margin-left: 1em; padding-left: 0; transition: .4s; }
#dialogue ul.minimized { height: 20px; background-color: var(--color-accent-normal);
background-size: 20px 20px;
background-image: repeating-linear-gradient(to right, var(--color-fg-normal), var(--color-fg-normal) 1px, var(--color-accent-normal) 1px, var(--color-accent-normal)); }
#dialogue ul.minimized > * { display: none; }

View File

@ -3,11 +3,11 @@
|= ======== */ |= ======== */
.newToolTip { position: fixed; display: none !important; min-width: 300px !important; max-width: 600px; .newToolTip { position: fixed; display: none !important; min-width: 300px !important; max-width: 600px;
background: #212121 !important; color: #FFF; text-align: left; font-size: .95rem; background: var(--color-fg-less) !important; color: var(--color-bg-normal); text-align: left; font-size: .95rem;
border-radius: .2em; box-shadow: 1px 1px 4px #646464; z-index: 3000; white-space: initial !important; } border-radius: .2em; box-shadow: 1px 1px 4px var(--color-borders-dark); z-index: 3000; white-space: initial !important; }
#newToolTipMain:before { content: attr(data-title); display: block; padding: .5em 1em; max-width: 598px; #newToolTipMain:before { content: attr(data-title); display: block; padding: .5em 1em; max-width: 598px;
background: #212121; color: #BDBDBD; font-weight: bold; background: var(--color-fg-less); color: var(--color-bg-raised2); font-weight: bold;
box-shadow: 0px 4px 2px -2px #646464; } box-shadow: 0px 4px 2px -2px var(--color-borders-dark); }
#newToolTipMain > * { padding: .5rem 1rem !important; } #newToolTipMain > * { padding: .5rem 1rem !important; }
#newToolTipMain > table td { padding: .5rem 1em; vertical-align: top; } #newToolTipMain > table td { padding: .5rem 1em; vertical-align: top; }
@media screen and (min-width:75em) { @media screen and (min-width:75em) {
@ -21,10 +21,6 @@ dl#newToolTipMain dd { margin: -1em 0 0 0; padding: 0 0 0 0; }
.newToolTipMain p + .toolTipHierarchy { padding-bottom: 0 !important; } .newToolTipMain p + .toolTipHierarchy { padding-bottom: 0 !important; }
#newToolTipMain > h5 { padding: 0 1rem !important; margin: -.5rem 0 !important; } #newToolTipMain > h5 { padding: 0 1rem !important; margin: -.5rem 0 !important; }
.toolTipHierarchy { margin: 0; padding: 0; border-top: 1px solid #424242; list-style: none; }
.toolTipHierarchy ul { margin: 0; padding: .2em 0 .2em 0; list-style: none; }
.toolTipHierarchy ul ul { padding: .1em 0 .1em 1.2em; }
.toolTipHierarchy ul > li:before { content: " \002514 "; display: inline-block; padding-right: .4em; }
.copyToDialogue { cursor: pointer; } .copyToDialogue { cursor: pointer; }

View File

@ -26,22 +26,38 @@ class CsvxmlValidator {
const lines = csvRaw.trim().replace("\r\n", "\n").split("\n"); 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 // 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 expectedFieldCount = headers.length;
let toValidate = []; let toValidate = [];
let lineCounter = 1; let lineCounter = 1;
for (let line of lines) { 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, // Remove fully empty lines (both without content and those with fields set up,
// but without content there. // but without content there.
if (line.length <= headers.length) continue; if (line.length <= headers.length) continue;
let lineContents = {}; let lineContents = {};
let fields = line.split(SEPARATOR); let fields = line.split(separator);
if (fields.length !== headers.length) { if (fields.length !== headers.length) {
this.errors.parsing.push("Number of columns in line " + lineCounter + " does not match number of headers"); 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]; lineContents[headers[i]] = fields[i];
} }
// Skip totally empty lines
if (Object.values(lineContents).join("").length === 0) continue;
toValidate.push(lineContents); toValidate.push(lineContents);
lineCounter++; lineCounter++;
} }
console.log(toValidate);
this.toValidate = toValidate; this.toValidate = toValidate;
if (toValidate.length === 0) { if (toValidate.length === 0) {
@ -120,7 +138,7 @@ class CsvxmlValidator {
const headers = Object.keys(this.toValidate[0]); const headers = Object.keys(this.toValidate[0]);
for (let header of headers) { 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; let dependencies = this.fieldList[header].dependsOn;
for (let dep of dependencies) { for (let dep of dependencies) {
@ -138,12 +156,17 @@ class CsvxmlValidator {
for (let line of this.toValidate) { for (let line of this.toValidate) {
for (let fieldName in line) { for (let fieldName in line) {
if (this.fieldList[fieldName] === undefined) {
console.log("Undefined but requested field " + fieldName);
continue;
}
let allowedValues = this.fieldList[fieldName].allowedValues; let allowedValues = this.fieldList[fieldName].allowedValues;
// No error if the field doesn't have a controlled list // No error if the field doesn't have a controlled list
if (allowedValues === undefined || allowedValues === null) continue; if (allowedValues === undefined || allowedValues === null) continue;
// No error if the line's content is in the list // 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; continue;
} }
@ -161,7 +184,7 @@ class CsvxmlValidator {
isValid() { isValid() {
for (let errorClass in this.errors) { for (let errorClass in this.errors) {
if (errorClass.length !== 0) return false; if (this.errors[errorClass].length !== 0) return false;
} }
return true; return true;
@ -270,9 +293,7 @@ class CsvxmlTooltip {
newMain.setAttribute("data-title", tooltipTitle); newMain.setAttribute("data-title", tooltipTitle);
const tooltipDesc = document.createElement("p"); newMain.appendChild(tooltipContent);
tooltipDesc.textContent = tooltipContent;
newMain.appendChild(tooltipDesc);
document.body.appendChild(newMain); document.body.appendChild(newMain);
newMain.classList.add("visible"); 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 { class CsvxmlPage {
fieldList; fieldList;
tls;
domUploaderWrapper; domUploaderWrapper;
domMainWrapper; domMainWrapper;
selectedFields; selectedFields;
csvBySelectionButton;
unsetSelectionButton;
constructor(fieldList) { constructor(fieldList) {
this.fieldList = Object.freeze(fieldList); this.fieldList = Object.freeze(fieldList);
this.tls = Object.freeze(JSON.parse(document.body.getAttribute("data-tls")));
let domUploaderWrapper = document.createElement("div"); let domUploaderWrapper = document.createElement("div");
domUploaderWrapper.id = "uploader"; 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) { uploadFileForValidation(file) {
const reader = new FileReader(); const reader = new FileReader();
@ -408,15 +553,13 @@ class CsvxmlPage {
// Validate the file // Validate the file
let validator = new CsvxmlValidator(app.fieldList, reader.result); let validator = new CsvxmlValidator(app.fieldList, reader.result);
if (validator.isValid() === true) { if (validator.isValid() === true) {
alert("Document is valid"); alert("Document is valid. Press ok to download.");
app.zipUploadToXml(validator);
} }
else { else {
console.log(validator.errors); app.listValidationErrors(validator);
alert("Document is not valid. Errors are " + validator.errors);
} }
app.zipUploadToXml(validator);
}; };
reader.onerror = function() { reader.onerror = function() {
alert(reader.error); alert(reader.error);
@ -432,7 +575,7 @@ class CsvxmlPage {
const form = document.createElement("form"); const form = document.createElement("form");
const label = document.createElement("label"); 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"); label.setAttribute("for", "fileToUpload");
form.appendChild(label); form.appendChild(label);
@ -446,10 +589,12 @@ class CsvxmlPage {
}); });
form.appendChild(input); form.appendChild(input);
/*
const button = document.createElement("button"); const button = document.createElement("button");
button.textContent = "Upload"; // TODO button.textContent = "Upload"; // TODO
button.type = "submit"; button.type = "submit";
form.appendChild(button); form.appendChild(button);
*/
app.domUploaderWrapper.appendChild(form); 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() { getOptionsSection() {
function genButton(id, text, link = "") { function genButton(id, text, link = "") {
@ -477,93 +674,28 @@ class CsvxmlPage {
const app = this; const app = this;
const dlAllButton = genButton("dlAll", "Download all"); const dlAllButton = genButton("dlAll", this.tls.download_csv_all);
dlAllButton.cursor = "pointer"; dlAllButton.cursor = "pointer";
dlAllButton.addEventListener('click', function() { dlAllButton.addEventListener('click', function() {
app.generateCsv(); app.generateCsv();
}); });
options.appendChild(dlAllButton); // TODO options.appendChild(dlAllButton);
const csvBySelectionButton = genButton("csvBySelection", "Csv by selection"); this.csvBySelectionButton = genButton("csvBySelection", this.tls.download_csv_by_selection);
csvBySelectionButton.classList.add("invisible"); this.csvBySelectionButton.classList.add("invisible");
// TODO: Add toggle via event listener options.appendChild(this.csvBySelectionButton);
options.appendChild(csvBySelectionButton);
const optionSelectRequired = genButton("selectRequired", "Select required"); const optionSelectRequired = genButton("selectRequired", this.tls.select_required_fields);
options.appendChild(optionSelectRequired); options.appendChild(optionSelectRequired);
const optionSelectAll = genButton("selectAll", "Select all"); const optionSelectAll = genButton("selectAll", this.tls.select_all_fields);
options.appendChild(optionSelectAll); options.appendChild(optionSelectAll);
const unsetSelectionButton = genButton("unsetSelection", "Unset selection"); this.unsetSelectionButton = genButton("unsetSelection", this.tls.unset_selection);
unsetSelectionButton.classList.add("invisible"); this.unsetSelectionButton.classList.add("invisible");
// TODO: Add toggle via event listener options.appendChild(this.unsetSelectionButton);
options.appendChild(unsetSelectionButton);
function checkCSVBySelectionAccessibility() { this.csvBySelectionButton.addEventListener('click', function(e) {
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) {
let selected = document.getElementsByClassName("humanTLToggled"); let selected = document.getElementsByClassName("humanTLToggled");
let selectedFields = []; let selectedFields = [];
@ -576,12 +708,12 @@ class CsvxmlPage {
optionSelectRequired.addEventListener('click', function(e) { optionSelectRequired.addEventListener('click', function(e) {
doForFieldList(function(field) { app.doForFieldList(function(field) {
if (field.classList.contains("requiredField") === false) return; if (field.classList.contains("requiredField") === false) return;
if (field.classList.contains("humanTLToggled") === true) return; if (field.classList.contains("humanTLToggled") === true) return;
toggleListFieldSelectionState(field); app.toggleListFieldSelectionState(field);
checkCSVBySelectionAccessibility(); app.checkCSVBySelectionAccessibility();
}); });
@ -589,23 +721,23 @@ class CsvxmlPage {
optionSelectAll.addEventListener('click', function(e) { optionSelectAll.addEventListener('click', function(e) {
doForFieldList(function(field) { app.doForFieldList(function(field) {
if (field.classList.contains("humanTLToggled") === true) return; if (field.classList.contains("humanTLToggled") === true) return;
toggleListFieldSelectionState(field); app.toggleListFieldSelectionState(field);
checkCSVBySelectionAccessibility(); 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; if (field.classList.contains("humanTLToggled") === false) return;
toggleListFieldSelectionState(field); app.toggleListFieldSelectionState(field);
checkCSVBySelectionAccessibility(); app.checkCSVBySelectionAccessibility();
}); });
@ -618,7 +750,7 @@ class CsvxmlPage {
renderMain() { renderMain() {
const domH2 = document.createElement("h2"); 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(domH2);
this.domMainWrapper.appendChild(this.getOptionsSection()); this.domMainWrapper.appendChild(this.getOptionsSection());
@ -634,8 +766,6 @@ class CsvxmlPage {
const domUl = document.createElement("ul"); const domUl = document.createElement("ul");
domUl.classList.add("fieldList"); domUl.classList.add("fieldList");
console.log(sectionName);
const sectionFields = this.fieldList[sectionName]; const sectionFields = this.fieldList[sectionName];
for (let fieldName in sectionFields) { for (let fieldName in sectionFields) {
const field = sectionFields[fieldName]; const field = sectionFields[fieldName];
@ -648,7 +778,32 @@ class CsvxmlPage {
if (field.required === true) domLi.classList.add("requiredField"); if (field.required === true) domLi.classList.add("requiredField");
domUl.appendChild(domLi); 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); 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();
});
});
} }
} }

View File

@ -7,6 +7,30 @@
* @author Joshua Ramon Enslin <joshua@museum-digital.de> * @author Joshua Ramon Enslin <joshua@museum-digital.de>
*/ */
declare(strict_types = 1); declare(strict_types = 1);
require_once __DIR__ . "/../functions/functions.php";
$allowed_langs = ['ar', 'de', 'en', 'hu', 'id', 'it', 'pl', 'pt'];
$lang = MD_STD::get_user_lang($allowed_langs, "en");
$tlLoader = new MDTlLoader("csxml_start_v2", $lang);
$outFormat = MD_STD_IN::get_http_input_text("output", "html", ['html', 'json']);
if ($outFormat === 'json') {
$fieldsGetter = new CsvxmlAvailableFields($lang);
$availableFields = $fieldsGetter->getFields();
header('Cache-Control: no-cache, no-store, must-revalidate, max-age=0'); // HTTP/1.1
header('Pragma: no-cache'); // HTTP/1.0
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET");
header("Access-Control-Allow-Headers: X-PINGOTHER, Content-Type, Accept-Encoding, cache-control");
header("Access-Control-Max-Age: 86400");
header('content-type: application/json');
echo json_encode($availableFields);
return;
}
echo ' echo '
<!DOCTYPE HTML> <!DOCTYPE HTML>
@ -18,7 +42,7 @@ echo '
<meta name="description" content="Validate import CSV files for museum-digital" /> <meta name="description" content="Validate import CSV files for museum-digital" />
<script src="assets/js/jszip/dist/jszip.min.js" type="text/javascript" async defer></script> <script src="assets/js/jszip/dist/jszip.min.js" type="text/javascript" async defer></script>
<link rel="stylesheet" type="text/css" href="assets/css/csvxml.min.css" /> <link rel="stylesheet" type="text/css" href="assets/css/csvxml.css" />
<meta name="theme-color" content="#aa4400" /> <meta name="theme-color" content="#aa4400" />
<link rel="shortcut icon" sizes="128x128" href="assets/img/mdlogo-csvxml.svg" /> <link rel="shortcut icon" sizes="128x128" href="assets/img/mdlogo-csvxml.svg" />
<meta name="robots" content="noindex" /> <meta name="robots" content="noindex" />
@ -29,14 +53,34 @@ echo '
</head> </head>
<body class="loading"> <body class="loading" data-tls="' . htmlspecialchars(MD_STD::json_encode([
'remarks' => $tlLoader->tl('basis', 'basis', 'remarks'),
'download' => $tlLoader->tl('export', 'export', 'download'),
'upload' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'upload'),
'select_csv_file_for_upload' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'select_csv_file_for_upload'),
'currently_approved_tags' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'currently_approved_tags'),
'download_csv_all' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'download_csv_all'),
'download_csv_by_selection' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'download_csv_by_selection'),
'select_required_fields' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'select_required_fields'),
'select_all_fields' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'select_all_fields'),
'unset_selection' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'unset_selection'),
'file_format' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'file_format'),
'validation_errors' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'validation_errors'),
'errors_parsing' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'errors_parsing'),
'errors_mandatoryTags' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'errors_mandatoryTags'),
'errors_duplicateInvNos' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'errors_duplicateInvNos'),
'errors_dependentColumns' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'errors_dependentColumns'),
'errors_controlledLists' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'errors_controlledLists'),
'errors_mainImageResource' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'errors_mainImageResource'),
'allowed_values' => $tlLoader->tl("csvxml-overview", "csvxml_overview", 'allowed_values'),
])) . '">
<h1> <h1>
<img src="assets/img/mdlogo-csvxml.svg" alt="" /> <img src="assets/img/mdlogo-csvxml.svg" alt="" />
<span>museum-digital:csvxml</span> <span>museum-digital:csvxml</span>
</h1> </h1>
<script src="assets/js/csvxmlV2.js" type="text/javascript" defer></script> <script src="assets/js/csvxmlV2.js" type="text/javascript" async></script>
</body> </body>
</html>'; </html>';