1 line
19 KiB
JavaScript
1 line
19 KiB
JavaScript
"use strict";'serviceWorker'in navigator&&(console.log("Registering service worker"),navigator.serviceWorker.register('/sw.js'));class CsvxmlValidator{fieldList;toValidate;errors;constructor(c,d){this.errors={parsing:[],mandatoryTags:[],duplicateInvNos:[],dependentColumns:[],controlledLists:[],mainImageResource:[]},this.fieldList=Object.freeze(c);const a=Papa.parse(d.trim(),{delimiter:";",escapeChar:'"',skipEmptyLines:!0,header:!0});if(a.errors.length!==0){console.log("Errors encountered: "),console.error(a.errors);let b='';for(let c of a.errors)b+=c.type+': '+c.message+"\n";window.alert(b)}let b=a.data;this.toValidate=b,b.length===0&&alert("Error: No lines of content identified"),this.validate()}validate(){this.validateMandatoryTagsPresent(),this.validateInvalidTagsPresent(),this.checkDuplicateInvNos(),this.checkDependentColumns(),this.checkControlledLists()}validateMandatoryTagsPresent(){let a=[];for(let b in this.fieldList)this.fieldList[b].required===!0&&a.push(b);console.log(this.toValidate);let b=1;for(let c of this.toValidate){for(let d of a)(c[d]===void 0||c[d]===null||c[d]==='')&&this.errors.mandatoryTags.push("Missing or empty mandatory tag "+d+" on line "+b);b++}}validateInvalidTagsPresent(){const a=Object.keys(this.toValidate[0]);for(let b of a)this.fieldList[b]===void 0&&this.errors.parsing.push("Invalid column "+b+" detected! Please remove this column or use the appropriate name!")}checkDuplicateInvNos(){let a=[],b=1;for(let c of this.toValidate)a.includes(c.inventory_number)&&this.errors.duplicateInvNos.push("Duplicate inventory number "+c.inventory_number+" on line "+b),a.push(c.inventory_number),b++}checkDependentColumns(){const a=Object.keys(this.toValidate[0]);for(let b of a){if(this.fieldList[b]===void 0||this.fieldList[b].dependsOn===void 0||this.fieldList[b].dependsOn===null)continue;let c=this.fieldList[b].dependsOn;for(let d of c)a.includes(d)===!1&&(console.error("Dependency issue at column "+b+": Corresponding column "+d+" is missing"),console.log(a),this.errors.dependentColumns.push("Dependency issue at column "+b+": Corresponding column "+d+" is missing"))}let b=1;for(let a of this.toValidate){for(let c in a){if(a[c]==='')continue;if(this.fieldList[c]===void 0)continue;const d=this.fieldList[c].dependsOn;if(d===void 0)continue;for(let e of d)a[e]===''&&(console.error("Dependency issue at column "+c+": Corresponding column "+e+" is missing [on line "+b+"]"),console.log(a),this.errors.dependentColumns.push("Dependency issue at column "+c+" (current value: "+a[c]+"): Corresponding column "+e+" is empty [on line "+b+"]"))}b++}}checkControlledLists(){let a=1;for(let b of this.toValidate){for(let c in b){if(this.fieldList[c]===void 0){console.log("Undefined but requested field "+c);continue}const d=this.fieldList[c].allowedValues;if(d===void 0||d===null)continue;if(Object.values(d).length===0||Object.values(d).includes(b[c]))continue;if(b[c]==='')continue;this.errors.controlledLists.push("Disallowed value used for column "+c+" at line "+a+" (Allowed values are: "+Object.values(d).join(", ")+"; current value is "+b[c]+")")}a++}}checkMainImageResource(){}isValid(){for(let a in this.errors)if(this.errors[a].length!==0)return!1;return!0}generateXml(){let a=[],b=document.implementation.createDocument(null,"record");for(let c of this.toValidate){let d=b.createElement("record");for(let a in c){const e=b.createElement(a);e.textContent=c[a],d.appendChild(e)}a.push(d)}return a}}class CsvxmlTooltip{static getDirection(b,a){window.innerHeight<b.clientY+a.clientHeight?(a.style.top="",a.style.bottom=window.innerHeight-b.clientY+"px"):(a.style.bottom="",a.style.top=b.clientY+4+"px"),window.innerWidth<b.clientX+a.clientWidth?(a.style.left="",a.style.right=window.innerWidth-b.clientX+"px"):(a.style.right="",a.style.left=b.clientX+3+"px")}static positionMobile(a){window.matchMedia&&window.matchMedia('(max-width:75em)').matches&&(a.style.left="",a.style.right="",a.style.top="",a.style.bottom="",a.classList.contains("atBottom")===!1&&a.classList.add("atBottom"))}static triggerMouseMove(b){const a=document.getElementById("newToolTipMain");if(a===void 0||a===null)return;CsvxmlTooltip.getDirection(b,a),CsvxmlTooltip.positionMobile(a)}static triggerMouseOut(b){const a=document.getElementById("newToolTipMain");a!==void 0&&a!==null&&(a.classList.remove("visible"),document.body.removeChild(a)),b.target.removeEventListener('mouseout',CsvxmlTooltip.triggerMouseOut)}static bindTooltipToElement(a,b,c){a.addEventListener('mouseover',function(e){let d=document.getElementById("newToolTipMain");if(d!==null)return;d=document.createElement("div"),d.classList.add("newToolTip"),d.id="newToolTipMain",d.setAttribute("data-title",b),d.appendChild(c),document.body.appendChild(d),d.classList.add("visible"),CsvxmlTooltip.getDirection(e,d),CsvxmlTooltip.positionMobile(d),d.addEventListener("mouseout",function(b){const a=document.getElementById("newToolTipMain");a!==void 0&&a!==null&&(a.classList.remove("visible"),document.body.removeChild(a))}),a.addEventListener("mouseout",CsvxmlTooltip.triggerMouseOut)},{passive:!0}),a.addEventListener("mousemove",CsvxmlTooltip.triggerMouseMove,{passive:!0})}}class CsvxmlDialogue{static closeDialogue(b){b!==void 0&&(b.preventDefault(),b.stopPropagation());let a=document.getElementById("dialogueArea");if(a!==null&&a!==!1){while(a.firstChild)a.removeChild(a.firstChild);a.parentElement.removeChild(a),document.removeEventListener('keydown',CsvxmlDialogue.closeDialogueByEscape,!1)}}static closeDialogueByEscape(a){a.keyCode===27&&CsvxmlDialogue.closeDialogue(a)}static drawDialogue(c){let b=document.createElement("div");b.id="dialogueArea";let a=document.createElement("div");return a.id="dialogue",a.appendChild(c),b.appendChild(a),document.body.appendChild(b),document.addEventListener('keydown',CsvxmlDialogue.closeDialogueByEscape),a}}class CsvxmlPage{fieldList;fieldListFlat;tls;domHelpWrapper;domUploaderWrapper;domMainWrapper;selectedFields;csvBySelectionButton;unsetSelectionButton;constructor(a,e){this.fieldList=Object.freeze(a);let b={};for(let c in a)b=Object.assign(b,a[c]);this.fieldListFlat=Object.freeze(b),this.tls=Object.freeze(e);let d=document.createElement("div");d.id="helpSection",this.domHelpWrapper=d;let c=document.createElement("div");c.id="uploader",c.classList.add("uploader"),this.domUploaderWrapper=c;let f=document.createElement("main");this.domMainWrapper=f,this.selectedFields=[]}generateCsv(b=[]){let d=[],e=[],c=[];for(let a in this.fieldListFlat){if(console.log(a),console.log(b),b.length!==0&&b.includes(a)===!1)continue;const f=this.fieldListFlat[a];if(d.push(a),e.push(f.name_human_readable),f.allowedValues!==void 0){let a=[];for(let b in f.allowedValues)a.push(f.allowedValues[b]);c.push(a.join(","))}else c.push("")}const f='"'+d.join('";"')+'"',g='"'+e.join('";"')+'"',h='"'+c.join('";"')+'"',i=f+"\n"+g+"\n"+h,a=document.createElement('a');a.setAttribute('href','data:text/plain;charset=utf-8,'+encodeURIComponent(i)),a.setAttribute('download',"csvxml_museum-digital_template.csv"),a.style.display='none',document.body.appendChild(a),a.click(),document.body.removeChild(a)}zipUploadToXml(b){function a(){let a=new JSZip,d=b.generateXml();const e=new XMLSerializer;let c=0;for(let b of d)a.file(c+".xml",e.serializeToString(b)),c++;a.generateAsync({type:"blob"}).then(function(b){const a=document.createElement('a');a.href=window.URL.createObjectURL(b),a.setAttribute('download',"csvxml.zip"),a.style.display='none',document.body.appendChild(a),a.click(),document.body.removeChild(a)})}if(typeof JSZip=="undefined"){const b=document.createElement("script");b.setAttribute("src","assets/js/jszip/dist/jszip.min.js"),b.addEventListener('load',function(){a()},{passive:!0,once:!0}),document.body.appendChild(b)}else a()}generateDialogueCloseButton(){const a=document.createElement("a");return a.classList.add("icons"),a.classList.add("iconsClose"),a.classList.add("dialogueCloseX"),a.id="dialogueClose",a.textContent="X",a.title="Close",a.href="#"+location.href,a.addEventListener('click',CsvxmlDialogue.closeDialogue),a}listValidationErrors(a){console.log("Listing validation errors");const b=document.createElement("div"),d=document.createElement("h3");d.textContent=this.tls.validation_errors,d.appendChild(this.generateDialogueCloseButton()),b.appendChild(d);const e=document.createElement("div");for(let b in a.errors){if(a.errors[b].length===0)continue;const c=document.createElement("h4");c.textContent=this.tls['errors_'+b]+" ("+a.errors[b].length+")",c.style.cursor="pointer",e.appendChild(c);const d=document.createElement("ul");for(let e of a.errors[b]){const c=document.createElement("li");c.textContent=e,d.appendChild(c)}c.addEventListener('click',function(){d.classList.toggle("minimized")}),e.appendChild(d)}b.appendChild(e);const f=document.createElement("div"),c=document.createElement("span");c.textContent=this.tls.download,c.classList.add("buttonLike");let g=this;c.addEventListener('click',function(){g.zipUploadToXml(a)}),f.appendChild(c),b.appendChild(f),dialogue=CsvxmlDialogue.drawDialogue(b)}uploadFileForValidation(d){const a=new FileReader;let c=!0;a.readAsText(d,c?'UTF-8':'CP1251');let b=this;document.body.classList.add("loading"),a.onload=function(){function d(){(async function(){const b=a.result;c&&b.includes('<27>')&&window.alert('The file encoding appears to not be UTF-8!\n\nTry exporting the file using the format "CSV (UTF-8)" if you use MS Excel or set the encoding to UTF-8 when exporting through LibreOffice!')})(),console.log("Read file");let d=new CsvxmlValidator(b.fieldListFlat,a.result);document.body.classList.remove("loading"),d.isValid()===!0?(alert("Document is valid. Press ok to download."),b.zipUploadToXml(d)):(console.log("Identified invalid upload document"),b.listValidationErrors(d))}if(console.log("Postload papaparse"),typeof Papa=="undefined"){const a=document.createElement("script");a.setAttribute("src","assets/js/papaparse/papaparse.min.js"),a.addEventListener('load',function(){d()},{passive:!0,once:!0}),document.body.appendChild(a)}else d()},a.onerror=function(){alert(a.error)}}renderGenHeader(){const b=document.createElement("header");b.id="mainHeader";const a=document.createElement("a");a.id="logoArea",a.href="https://www.museum-digital.org/";const d=document.createElement("img");d.src="assets/img/mdlogo-code-128px.png",d.alt="Logo of museum-digital",a.appendChild(d);const l=document.createElement("h2");l.textContent="museum-digital",a.appendChild(l),b.appendChild(a);const c=document.createElement("nav"),f=document.createElement("a");f.href="https://en.about.museum-digital.org/about",f.textContent=this.tls.about,c.appendChild(f);const g=document.createElement("div"),h=document.createElement("a");h.textContent=this.tls.contact,h.href="https://en.about.museum-digital.org/contact/",g.appendChild(h);const i=document.createElement("div"),e=document.createElement("a");e.textContent=this.tls.imprint,e.href="https://en.about.museum-digital.org/impressum",i.appendChild(e);const j=document.createElement("a");j.textContent=this.tls.privacy_policy,j.href="https://en.about.museum-digital.org/privacy/",i.appendChild(j),g.appendChild(i),c.appendChild(g);const k=document.createElement("a");k.textContent=this.tls.news,k.href="https://blog.museum-digital.org/",c.appendChild(k),b.appendChild(c),document.body.appendChild(b)}renderHeader(){const c=document.createElement("header"),b=document.createElement("h1"),a=document.createElement("img");a.width="70",a.height="70",a.src="assets/img/mdlogo-csvxml.svg",a.alt="",b.appendChild(a);const d=document.createElement("span");d.textContent="museum-digital:csvxml",b.appendChild(d),c.appendChild(b),document.body.appendChild(c)}renderHelpTexts(){let a=this;(async function(){function c(d,e){const c=document.createElement("div");c.classList.add("qaDiv");const b=document.createElement("h3");return b.textContent=d,b.style.cursor="pointer",c.appendChild(b),b.addEventListener('click',function(){console.log("Listing validation errors");const b=document.createElement("div"),c=document.createElement("h3");c.textContent=d,c.appendChild(a.generateDialogueCloseButton()),b.appendChild(c);const f=document.createElement("div");f.textContent=e,b.appendChild(f),CsvxmlDialogue.drawDialogue(b)}),c}const b=document.createElement("div");b.appendChild(c(a.tls.help_where_am_i,a.tls.help_where_am_i_content)),b.appendChild(c(a.tls.help_what_is_csv,a.tls.help_what_is_csv_content)),b.appendChild(c(a.tls.help_how_to_format_csv,a.tls.help_how_to_format_csv_content)),a.domHelpWrapper.appendChild(b)})(),document.body.appendChild(this.domHelpWrapper)}renderUploader(){let a=this;(async function(){const e=document.createElement("h2");e.textContent=a.tls.upload,a.domUploaderWrapper.appendChild(e);const c=document.createElement("form"),d=document.createElement("label");d.textContent=a.tls.select_csv_file_for_upload,d.setAttribute("for","fileToUpload"),c.appendChild(d);const b=document.createElement("input");b.type="file",b.id="fileToUpload",b.setAttribute("tabindex","1"),b.accept=".csv",b.required="required",b.addEventListener('change',async function(){a.uploadFileForValidation(b.files[0])}),c.appendChild(b),a.domUploaderWrapper.appendChild(c)})(),document.body.appendChild(this.domUploaderWrapper)}doForFieldList(b){let a=document.getElementsByClassName("fieldList");for(let c=0,e=a.length;c<e;c++){let d=a[c].getElementsByTagName("li");for(let a=0,c=d.length;a<c;a++)b(d[a])}}toggleListFieldSelectionState(a){let d=this,c=a.getAttribute("data-alt");if(a.setAttribute("data-alt",a.textContent),a.textContent=c,a.classList.toggle("humanTLToggled"),a.classList.contains("humanTLToggled")===!1)return;let b=this.fieldListFlat[a.id].dependsOn;if(b!==void 0&&b!==null){let b=this.fieldListFlat[a.id].dependsOn;for(let a=0,d=b.length;a<d;a++){let c=document.getElementById(b[a]);if(c.classList.contains("humanTLToggled")===!0)continue;this.toggleListFieldSelectionState(c)}}}checkCSVBySelectionAccessibility(){let a=document.getElementsByClassName("humanTLToggled");a.length===0?(this.csvBySelectionButton.classList.add("invisible"),this.unsetSelectionButton.classList.add("invisible")):(this.csvBySelectionButton.classList.remove("invisible"),this.unsetSelectionButton.classList.remove("invisible"))}getOptionsSection(){function c(c,d,b=""){const a=document.createElement("span");return a.id=c,a.setAttribute("tabindex","1"),a.textContent=d,a.classList.add("buttonLike"),b!==""&&(a.href=b),a}const b=document.createElement("div");b.classList.add("options");const a=this,d=c("dlAll",this.tls.download_csv_all);d.cursor="pointer",d.addEventListener('click',function(b){b.preventDefault(),a.generateCsv()}),b.appendChild(d),this.csvBySelectionButton=c("csvBySelection",this.tls.download_csv_by_selection),this.csvBySelectionButton.classList.add("invisible"),b.appendChild(this.csvBySelectionButton);const e=c("selectRequired",this.tls.select_required_fields);b.appendChild(e);const f=c("selectAll",this.tls.select_all_fields);return b.appendChild(f),this.unsetSelectionButton=c("unsetSelection",this.tls.unset_selection),this.unsetSelectionButton.classList.add("invisible"),b.appendChild(this.unsetSelectionButton),this.csvBySelectionButton.addEventListener('click',function(d){d.preventDefault();let b=document.getElementsByClassName("humanTLToggled"),c=[];for(let a=0,d=b.length;a<d;a++)c+=b[a].getAttribute("data-value");a.generateCsv(c)}),e.addEventListener('click',function(b){b.preventDefault(),a.doForFieldList(function(b){if(b.classList.contains("requiredField")===!1)return;if(b.classList.contains("humanTLToggled")===!0)return;a.toggleListFieldSelectionState(b),a.checkCSVBySelectionAccessibility()})}),f.addEventListener('click',function(b){b.preventDefault(),a.doForFieldList(function(b){if(b.classList.contains("humanTLToggled")===!0)return;a.toggleListFieldSelectionState(b),a.checkCSVBySelectionAccessibility()})}),this.unsetSelectionButton.addEventListener('click',function(b){b.preventDefault(),a.doForFieldList(function(b){if(b.classList.contains("humanTLToggled")===!1)return;a.toggleListFieldSelectionState(b),a.checkCSVBySelectionAccessibility()})}),b}renderMain(){const a=document.createElement("h2");a.textContent=this.tls.currently_approved_tags,this.domMainWrapper.appendChild(a),this.domMainWrapper.appendChild(this.getOptionsSection());for(let c in this.fieldList){const a=document.createElement("div"),d=document.createElement("h3");d.textContent=c,a.appendChild(d);const b=document.createElement("ul");b.classList.add("fieldList");const e=this.fieldList[c];for(let f in e){const a=e[f],c=document.createElement("li");c.textContent=f,c.id=f,c.setAttribute("data-alt",a.name_human_readable),c.setAttribute("data-value",f),a.required===!0&&c.classList.add("requiredField"),b.appendChild(c);const d=document.createElement("div"),g=document.createElement("p");if(g.textContent=a.explica,d.appendChild(g),a.remarks!==void 0&&a.remarks!==''){const b=document.createElement("h4");b.textContent=this.tls.remarks,d.appendChild(b);const c=document.createElement("p");c=a.remarks,d.appendChild(c)}if(a.allowedValues!==void 0&&Object.values(a.allowedValues).length!==0){const b=document.createElement("h4");b.textContent=this.tls.allowed_values,d.appendChild(b);const c=document.createElement("p");c.textContent=Object.values(a.allowedValues).join(', '),d.appendChild(c)}CsvxmlTooltip.bindTooltipToElement(c,a.name_human_readable,d)}a.appendChild(b),this.domMainWrapper.appendChild(a)}document.body.appendChild(this.domMainWrapper);let b=this;this.doForFieldList(function(a){a.addEventListener('click',function(c){b.toggleListFieldSelectionState(a),b.checkCSVBySelectionAccessibility()})})}renderFooter(){const a=document.createElement("footer"),d=document.createElement("p");d.textContent="This work is licensed under the GNU Affero Public License Version 3.",a.appendChild(d);const b=document.createElement("div"),c=document.createElement("a");if(c.textContent="Source code",c.href="https://gitea.armuli.eu/museum-digital/csvxml",b.appendChild(c),'serviceWorker'in navigator){const a=document.createElement("span");a.textContent="Reload application",a.setAttribute("tabindex",1),a.addEventListener('click',function(a){Promise.all(['csvxml-cache-v1'].map(function(a){caches.has(a).then(function(b){b===!0&&caches.delete(a).then(function(a){})})})),location.reload()},{passive:!0,once:!0}),b.appendChild(a)}a.appendChild(b),document.body.appendChild(a)}}(async function(){function f(){const b=document.documentElement.getAttribute("data-allowed-langs").split(',');if(navigator.language===void 0)return'en';const a=navigator.language.toLowerCase().substr(0,2);return console.log(a),b.includes(a)?a:'en'}const b=f();document.documentElement.setAttribute("lang",b),document.body.classList.add("loading");let a=0,c,d;function e(){document.body.classList.remove("loading");const a=new CsvxmlPage(c,d);a.renderGenHeader(),a.renderHeader(),a.renderHelpTexts(),a.renderUploader(),a.renderMain(),a.renderFooter()}window.fetch('/json/fields.'+b+'.json',{method:'GET',cache:'no-cache',credentials:'same-origin'}).then(function(a){return a.json()}).then(function(b){c=b,a++,a===2&&e()}),window.fetch('/json/tls.'+b+'.json',{method:'GET',cache:'no-cache',credentials:'same-origin'}).then(function(a){return a.json()}).then(function(b){d=b,a++,a===2&&e()})})() |