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();
});
})();