560 lines
17 KiB
JavaScript
560 lines
17 KiB
JavaScript
"use strict";
|
|
|
|
const MAX_INPUT_SIZE = 1048576;
|
|
|
|
if ('serviceWorker' in navigator) {
|
|
console.log("Registering service worker");
|
|
navigator.serviceWorker.register('/sw.js');
|
|
}
|
|
|
|
class ConcPage {
|
|
|
|
lang;
|
|
tls;
|
|
domWrapper;
|
|
domUploaderWrapper;
|
|
domResultsWrapper;
|
|
domMainWrapper;
|
|
|
|
constructor(lang, tls) {
|
|
|
|
this.lang = lang;
|
|
this.tls = Object.freeze(tls);
|
|
|
|
let wrapper = document.createElement("div");
|
|
wrapper.id = "contentWrapper";
|
|
this.domWrapper = wrapper;
|
|
|
|
let domUploaderWrapper = document.createElement("div");
|
|
domUploaderWrapper.id = "uploader";
|
|
domUploaderWrapper.classList.add("uploader");
|
|
this.domUploaderWrapper = domUploaderWrapper;
|
|
|
|
let domResultsWrapper = document.createElement("div");
|
|
domResultsWrapper.id = "results";
|
|
domResultsWrapper.classList.add("results");
|
|
this.domResultsWrapper = domResultsWrapper;
|
|
|
|
let domMainWrapper = document.createElement("main");
|
|
this.domMainWrapper = domMainWrapper;
|
|
}
|
|
|
|
downloadFromString(filename, text) {
|
|
|
|
const blob = new Blob([text], { type: "text/plain" });
|
|
const link = document.createElement("a");
|
|
|
|
link.download = filename;
|
|
link.href = window.URL.createObjectURL(blob);
|
|
link.dataset.downloadurl = ["text/plain", link.download, link.href].join(":");
|
|
|
|
const evt = new MouseEvent("click", {
|
|
view: window,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
});
|
|
|
|
link.dispatchEvent(evt);
|
|
link.remove()
|
|
|
|
}
|
|
|
|
renderGenHeader() {
|
|
|
|
const header = document.createElement("header");
|
|
header.id = "mainHeader";
|
|
|
|
const logoArea = document.createElement("a");
|
|
logoArea.id = "logoArea";
|
|
logoArea.href = "https://www.museum-digital.org/";
|
|
|
|
const logoImg = document.createElement("img");
|
|
logoImg.src = "/static/img/mdlogo-code.svg";
|
|
logoImg.alt = "Logo of museum-digital";
|
|
logoArea.appendChild(logoImg);
|
|
|
|
const h2 = document.createElement("h2");
|
|
h2.textContent = "museum-digital";
|
|
logoArea.appendChild(h2);
|
|
|
|
header.appendChild(logoArea);
|
|
|
|
// Right side of the header
|
|
const nav = document.createElement("nav");
|
|
|
|
const lAbout = document.createElement("a");
|
|
lAbout.href = "https://en.about.museum-digital.org/about";
|
|
lAbout.textContent = this.tls.about;
|
|
nav.appendChild(lAbout);
|
|
|
|
const lContactList = document.createElement("div");
|
|
|
|
const lContact = document.createElement("a");
|
|
lContact.textContent = this.tls.contact;
|
|
lContact.href = "https://en.about.museum-digital.org/contact/";
|
|
lContactList.appendChild(lContact);
|
|
|
|
const lContactDiv = document.createElement("div");
|
|
|
|
const lImprint = document.createElement("a");
|
|
lImprint.textContent = this.tls.imprint;
|
|
lImprint.href = "https://en.about.museum-digital.org/impressum";
|
|
lContactDiv.appendChild(lImprint);
|
|
|
|
const lPrivacy = document.createElement("a");
|
|
lPrivacy.textContent = this.tls.privacy_policy;
|
|
lPrivacy.href = "https://en.about.museum-digital.org/privacy/";
|
|
lContactDiv.appendChild(lPrivacy);
|
|
|
|
lContactList.appendChild(lContactDiv);
|
|
nav.appendChild(lContactList);
|
|
|
|
const lNews = document.createElement("a")
|
|
lNews.textContent = this.tls.news;
|
|
lNews.href = "https://blog.museum-digital.org/";
|
|
nav.appendChild(lNews);
|
|
|
|
header.appendChild(nav);
|
|
document.body.appendChild(header);
|
|
|
|
}
|
|
|
|
renderHeader() {
|
|
|
|
const appHeader = document.createElement("header");
|
|
appHeader.id = "appHeader";
|
|
|
|
const h1 = document.createElement("h1");
|
|
|
|
const img = document.createElement("img");
|
|
img.width = "70";
|
|
img.height = "70";
|
|
img.src = "/static/img/mdlogo-code.svg";
|
|
img.alt = "";
|
|
h1.appendChild(img);
|
|
|
|
h1.appendChild(this.createPlainTextElem("span", "museum-digital:" + this.tls.concordance_checker));
|
|
|
|
appHeader.appendChild(h1);
|
|
|
|
document.body.appendChild(appHeader);
|
|
|
|
}
|
|
|
|
createP(text) {
|
|
const output = document.createElement("p");
|
|
output.textContent = text;
|
|
return output;
|
|
}
|
|
|
|
createPlainTextElem(type, text) {
|
|
const output = document.createElement(type);
|
|
output.textContent = text;
|
|
return output;
|
|
}
|
|
|
|
renderText() {
|
|
|
|
const domH2 = document.createElement("h2");
|
|
domH2.textContent = this.tls.quality_assessment_tools;
|
|
this.domMainWrapper.appendChild(domH2);
|
|
|
|
this.domMainWrapper.appendChild(this.createP(this.tls.intro));
|
|
|
|
this.domWrapper.appendChild(this.domMainWrapper);
|
|
|
|
}
|
|
|
|
generateBoilerplateForTableSection(hl) {
|
|
|
|
const passedSec = document.createElement("div");
|
|
|
|
const passedHl = document.createElement("h3");
|
|
passedHl.textContent = hl;
|
|
passedSec.appendChild(passedHl);
|
|
|
|
const passedTable = document.createElement("table");
|
|
|
|
const passedThead = document.createElement("thead");
|
|
passedTable.appendChild(passedThead);
|
|
|
|
const passedTBody = document.createElement("tbody");
|
|
passedTable.appendChild(passedTBody);
|
|
|
|
passedSec.appendChild(passedTable);
|
|
|
|
return {
|
|
section: passedSec,
|
|
thead: passedThead,
|
|
tbody: passedTBody,
|
|
};
|
|
|
|
}
|
|
|
|
generateListResponse(context, listOptionsEn, listOptions, elements) {
|
|
|
|
// Empty
|
|
while (this.domResultsWrapper.firstChild) {
|
|
this.domResultsWrapper.removeChild(this.domResultsWrapper.firstChild);
|
|
}
|
|
|
|
// Fill passed entries
|
|
|
|
if (elements.passed.length === undefined) {
|
|
|
|
const passedSec = this.generateBoilerplateForTableSection(this.tls.passed);
|
|
|
|
// TL TODO
|
|
const theadTr = document.createElement("tr");
|
|
for (const theadname of ['Input', 'Match']) {
|
|
const theadTd = document.createElement("th");
|
|
theadTd.textContent = theadname;
|
|
theadTr.appendChild(theadTd);
|
|
}
|
|
passedSec.thead.appendChild(theadTr);
|
|
|
|
for (const passedKey in elements.passed) {
|
|
const passedValue = elements.passed[passedKey];
|
|
const tr = document.createElement("tr");
|
|
|
|
tr.appendChild(this.createPlainTextElem("td", passedKey));
|
|
|
|
if (listOptions[passedValue]) {
|
|
tr.appendChild(this.createPlainTextElem("td", listOptions[passedValue]));
|
|
}
|
|
else {
|
|
valueTd.textContent = passedValue;
|
|
tr.appendChild(this.createPlainTextElem("td", passedValue));
|
|
}
|
|
|
|
passedSec.tbody.appendChild(tr);
|
|
}
|
|
|
|
this.domResultsWrapper.appendChild(passedSec.section);
|
|
|
|
}
|
|
|
|
// Fill unpassed entries
|
|
const app = this;
|
|
|
|
if (elements.not_passed.length !== 0) {
|
|
|
|
const nonpassedSec = this.generateBoilerplateForTableSection(this.tls.not_yet_matched);
|
|
|
|
const ntheadTr = document.createElement("tr");
|
|
for (const theadname of ['Input', 'Select Your Match']) {
|
|
const theadTd = document.createElement("th");
|
|
theadTd.textContent = theadname;
|
|
ntheadTr.appendChild(theadTd);
|
|
}
|
|
nonpassedSec.thead.appendChild(ntheadTr);
|
|
|
|
let matchSelects = [];
|
|
for (let nonpassedName of elements.not_passed) {
|
|
const tr = document.createElement("tr");
|
|
|
|
tr.appendChild(this.createPlainTextElem("td", nonpassedName));
|
|
|
|
const valueTd = document.createElement("td");
|
|
|
|
const valueSelect = document.createElement("select");
|
|
valueSelect.setAttribute('data-input', nonpassedName);
|
|
|
|
for (const key in listOptions) {
|
|
const opt = document.createElement("option");
|
|
opt.value = key;
|
|
opt.textContent = listOptions[key];
|
|
valueSelect.appendChild(opt);
|
|
}
|
|
|
|
matchSelects.push(valueSelect);
|
|
valueTd.appendChild(valueSelect);
|
|
|
|
tr.appendChild(valueTd);
|
|
|
|
nonpassedSec.tbody.appendChild(tr);
|
|
}
|
|
|
|
this.domResultsWrapper.appendChild(nonpassedSec.section);
|
|
|
|
const convertB = document.createElement("button");
|
|
convertB.textContent = this.tls.generate_code_snippet;
|
|
nonpassedSec.section.appendChild(convertB);
|
|
|
|
const resultsWrap = document.createElement("div");
|
|
convertB.addEventListener('click', function() {
|
|
|
|
let lines = [];
|
|
let keysAreNumeric = false;
|
|
if (listOptions[1] !== undefined && listOptions[1] !== null) {
|
|
keysAreNumeric = true;
|
|
}
|
|
|
|
for (let m of matchSelects) {
|
|
|
|
let line = ("'" + m.getAttribute("data-input") + "'").padEnd(40, " ") + " => ";
|
|
if (keysAreNumeric === true) {
|
|
line += m.value + ",";
|
|
}
|
|
else {
|
|
line += "'" + m.value + "',";
|
|
}
|
|
line += ' // ' + listOptionsEn[m.value];
|
|
lines.push(line);
|
|
|
|
m.setAttribute("readonly", "readonly");
|
|
}
|
|
|
|
const output = " ".repeat(8) + lines.join("\n" + " ".repeat(8));
|
|
console.log(output);
|
|
|
|
// Present output online
|
|
|
|
const resultsP = app.createP(output);
|
|
resultsP.id = "resultsP";
|
|
resultsP.style.fontFamily = "Monospace, Courier";
|
|
resultsP.style.whiteSpace = "pre-wrap";
|
|
|
|
resultsWrap.appendChild(resultsP);
|
|
resultsP.scrollIntoView({block: "start", behavior: "smooth"});
|
|
|
|
// Download
|
|
app.downloadFromString("new-concordance-" + context + '.htm', output);
|
|
|
|
});
|
|
|
|
this.domResultsWrapper.appendChild(resultsWrap);
|
|
|
|
}
|
|
|
|
this.domResultsWrapper.scrollIntoView({block: "start", behavior: "smooth"});
|
|
|
|
//
|
|
|
|
}
|
|
|
|
// Setup
|
|
renderUploader() {
|
|
|
|
const listSelect = document.createElement("select");
|
|
|
|
const listOptions = document.documentElement.getAttribute("data-lists").split(',');
|
|
|
|
for (const lOpt of listOptions) {
|
|
const opt = document.createElement("option");
|
|
opt.textContent = this.tls[lOpt];
|
|
opt.value = lOpt;
|
|
listSelect.appendChild(opt);
|
|
}
|
|
this.domUploaderWrapper.appendChild(listSelect);
|
|
|
|
const textarea = document.createElement("textarea");
|
|
textarea.placeholder = this.tls.one_line_per_entry;
|
|
this.domUploaderWrapper.appendChild(textarea);
|
|
|
|
const submitB = document.createElement("button");
|
|
submitB.textContent = this.tls.submit;
|
|
this.domUploaderWrapper.appendChild(submitB);
|
|
|
|
const app = this;
|
|
|
|
submitB.addEventListener('click', async function(e) {
|
|
e.stopPropagation();
|
|
e.preventDefault();
|
|
|
|
// Load translations in English
|
|
const listResponseEn = await window.fetch('/static/json/tls.' + listSelect.value + '.en.json', {
|
|
method: 'GET', cache: 'no-cache',
|
|
});
|
|
|
|
if (listResponseEn.status !== 200) {
|
|
const text = await response.text();
|
|
window.alert(text);
|
|
}
|
|
const tListOptionsEn = await listResponseEn.json();
|
|
|
|
// Load translations
|
|
const listResponse = await window.fetch('/static/json/tls.' + listSelect.value + '.' + app.lang + '.json', {
|
|
method: 'GET', cache: 'no-cache',
|
|
});
|
|
|
|
if (listResponse.status !== 200) {
|
|
const text = await response.text();
|
|
window.alert(text);
|
|
}
|
|
const tListOptions = await listResponse.json();
|
|
|
|
// Get API output
|
|
|
|
let requestBody = [];
|
|
requestBody.push('terms=' + encodeURIComponent(textarea.value));
|
|
const response = await window.fetch('/api/evaluate/' + listSelect.value, {
|
|
method: 'POST', cache: 'no-cache',
|
|
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
|
body: requestBody.join("&"),
|
|
});
|
|
|
|
if (response.status !== 200) {
|
|
const text = await response.text();
|
|
window.alert(text);
|
|
}
|
|
const elements = await response.json();
|
|
|
|
app.generateListResponse(listSelect.value, tListOptionsEn, tListOptions, elements);
|
|
|
|
});
|
|
|
|
this.domWrapper.appendChild(this.domUploaderWrapper);
|
|
this.domWrapper.appendChild(this.domResultsWrapper);
|
|
|
|
}
|
|
|
|
renderFooter() {
|
|
|
|
const footer = document.createElement("footer");
|
|
|
|
/*
|
|
|
|
const licenseStatement = document.createElement("p");
|
|
licenseStatement.textContent = "This work is licensed under the GNU Affero Public License Version 3.";
|
|
footer.appendChild(licenseStatement);
|
|
|
|
*/
|
|
|
|
const footerOptions = document.createElement("div");
|
|
|
|
/*
|
|
const codeLink = document.createElement("a");
|
|
codeLink.textContent = "Source code";
|
|
codeLink.href = "https://gitea.armuli.eu/museum-digital/csvxml";
|
|
footerOptions.appendChild(codeLink);
|
|
*/
|
|
|
|
/*
|
|
const codeLink = document.createElement("a");
|
|
codeLink.textContent = "API"; // TODO
|
|
codeLink.href = "/swagger";
|
|
footerOptions.appendChild(codeLink);
|
|
*/
|
|
|
|
if ('serviceWorker' in navigator) {
|
|
const refreshB = document.createElement("span");
|
|
refreshB.textContent = this.tls.reload_application;
|
|
refreshB.setAttribute("tabindex", 1);
|
|
refreshB.addEventListener('click', function(e) {
|
|
|
|
Promise.all(['conc-cache-v1'].map(function(cache) {
|
|
caches.has(cache).then(function(hasCache) {
|
|
if (hasCache === true) {
|
|
caches.delete(cache).then(function(deletionStatus) {});
|
|
}
|
|
})
|
|
}))
|
|
location.reload()
|
|
|
|
}, {passive: true, once: true});
|
|
footerOptions.appendChild(refreshB);
|
|
}
|
|
|
|
const allowedLangs = document.documentElement.getAttribute("data-allowed-langs").split(',');
|
|
const langSel = document.createElement("div");
|
|
for (let lang of allowedLangs) {
|
|
const l = document.createElement("a");
|
|
l.href = "#" + lang;
|
|
l.textContent = lang;
|
|
l.style.textTranform = "uppercase";
|
|
l.addEventListener('click', function(e) {
|
|
e.preventDefault();
|
|
sessionStorage.setItem("lang", lang);
|
|
location.reload();
|
|
});
|
|
langSel.appendChild(l);
|
|
}
|
|
footerOptions.appendChild(langSel);
|
|
|
|
footer.appendChild(footerOptions);
|
|
|
|
const licenseLine = document.createElement("p");
|
|
|
|
const license = document.createElement("a");
|
|
license.textContent = "MIT-Licensed";
|
|
license.href = "https://opensource.org/license/mit";
|
|
licenseLine.appendChild(license);
|
|
|
|
licenseLine.appendChild(this.createPlainTextElem("span", " @ "));
|
|
|
|
const author = document.createElement("a");
|
|
author.textContent = "Joshua Ramon Enslin";
|
|
author.href = "https://www.jrenslin.de";
|
|
author.setAttribute("rel", "author");
|
|
licenseLine.appendChild(author);
|
|
|
|
licenseLine.appendChild(this.createPlainTextElem("span", ", "));
|
|
|
|
const attributionYear = document.createElement("span");
|
|
attributionYear.textContent = "2023";
|
|
licenseLine.appendChild(attributionYear);
|
|
|
|
footer.appendChild(licenseLine);
|
|
|
|
document.body.appendChild(footer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(async function() {
|
|
|
|
function getLang() {
|
|
|
|
const allowedLangs = document.documentElement.getAttribute("data-allowed-langs").split(',');
|
|
|
|
const langFromSession = sessionStorage.getItem("lang");
|
|
if (langFromSession !== undefined && allowedLangs.includes(langFromSession)) {
|
|
return langFromSession;
|
|
}
|
|
|
|
if (navigator.language === undefined) return 'en';
|
|
|
|
const browserLang = navigator.language.toLowerCase().substr(0, 2);
|
|
console.log(browserLang);
|
|
|
|
if (allowedLangs.includes(browserLang)) return browserLang;
|
|
else return 'en';
|
|
|
|
}
|
|
|
|
const lang = getLang();
|
|
document.documentElement.setAttribute("lang", lang);
|
|
|
|
document.body.classList.add("loading");
|
|
|
|
let loaded = 0;
|
|
|
|
let tls;
|
|
|
|
function loadPage() {
|
|
|
|
document.body.classList.remove("loading");
|
|
|
|
const page = new ConcPage(lang, tls);
|
|
page.renderGenHeader();
|
|
page.renderHeader();
|
|
page.renderText();
|
|
page.renderUploader();
|
|
document.body.appendChild(page.domWrapper);
|
|
page.renderFooter();
|
|
|
|
}
|
|
|
|
window.fetch('/static/json/tls.' + lang + '.json', {
|
|
method: 'GET', cache: 'no-cache', credentials: 'same-origin',
|
|
}).then(function(response) {
|
|
return response.json();
|
|
}).then(function(elements) {
|
|
tls = elements;
|
|
loadPage();
|
|
});
|
|
|
|
})();
|