Allow editing thumbnail data

pull/460/head
ElementalAlchemist 6 days ago committed by Christopher Usher
parent ea6d256b6d
commit f4d303147d

@ -126,35 +126,302 @@ window.addEventListener("DOMContentLoaded", async (event) => {
}
});
function addTemplate(index, template) {
function generateTemplateDOM(index, template) {
const { name, description, attribution, crop, location } = template;
const editForm = document.createElement("form");
editForm.id = `template-data-edit-form-${index}`;
const nameCell = document.createElement("td");
nameCell.innerText = name;
const nameReadCell = document.createElement("div");
nameReadCell.classList.add("template-data-view");
nameReadCell.innerText = name;
const nameEditCell = document.createElement("div");
nameEditCell.classList.add("template-data-edit", "hidden");
const nameEditField = document.createElement("input");
nameEditField.type = "text";
nameEditField.name = "name";
nameEditField.value = name;
nameEditField.form = editForm.id;
nameEditCell.appendChild(nameEditField);
nameCell.appendChild(nameReadCell);
nameCell.appendChild(nameEditCell);
const descriptionCell = document.createElement("td");
descriptionCell.innerText = description;
const descriptionReadCell = document.createElement("div");
descriptionReadCell.classList.add("template-data-view");
descriptionReadCell.innerText = description;
const descriptionEditCell = document.createElement("div");
descriptionEditCell.classList.add("template-data-edit", "hidden");
const descriptionEditField = document.createElement("textarea");
descriptionEditField.name = "description";
descriptionEditField.value = description;
descriptionEditField.form = editForm.id;
descriptionEditCell.appendChild(descriptionEditField);
descriptionCell.appendChild(descriptionReadCell);
descriptionCell.appendChild(descriptionEditCell);
const attributionCell = document.createElement("td");
attributionCell.innerText = attribution;
const attributionReadCell = document.createElement("div");
attributionReadCell.classList.add("template-data-view");
attributionReadCell.innerText = attribution;
const attributionEditCell = document.createElement("div");
attributionEditCell.classList.add("template-data-edit", "hidden");
const attributionEditField = document.createElement("input");
attributionEditField.type = "text";
attributionEditField.name = "attribution";
attributionEditField.value = attribution;
attributionEditField.form = editForm.id;
attributionEditCell.appendChild(attributionEditField);
attributionCell.appendChild(attributionReadCell);
attributionCell.appendChild(attributionEditCell);
const cropCell = document.createElement("td");
cropCell.innerText = `(${crop[0]}, ${crop[1]}) to (${crop[2]}, ${crop[3]})`;
const cropReadCell = document.createElement("div");
cropReadCell.classList.add("template-data-view");
cropReadCell.innerText = `(${crop[0]}, ${crop[1]}) to (${crop[2]}, ${crop[3]})`;
const cropEditCell = document.createElement("div");
cropEditCell.classList.add("template-data-edit", "hidden");
const cropXStartField = document.createElement("input");
cropXStartField.name = "cropxstart";
setCoordNumberFieldProps(cropXStartField, "X");
cropXStartField.value = crop[0];
cropXStartField.form = editForm.id;
const cropYStartField = document.createElement("input");
cropYStartField.name = "cropystart";
setCoordNumberFieldProps(cropYStartField, "Y");
cropYStartField.value = crop[1];
cropYStartField.form = editForm.id;
const cropXEndField = document.createElement("input");
cropXEndField.name = "cropxend";
setCoordNumberFieldProps(cropXEndField, "X");
cropXEndField.value = crop[2];
cropXEndField.form = editForm.id;
const cropYEndField = document.createElement("input");
cropYEndField.name = "cropyend";
setCoordNumberFieldProps(cropYEndField, "Y");
cropYEndField.value = crop[3];
cropYEndField.form = editForm.id;
cropEditCell.appendChild(document.createTextNode("("));
cropEditCell.appendChild(cropXStartField);
cropEditCell.appendChild(document.createTextNode(", "));
cropEditCell.appendChild(cropYStartField);
cropEditCell.appendChild(document.createTextNode(") to ("));
cropEditCell.appendChild(cropXEndField);
cropEditCell.appendChild(document.createTextNode(", "));
cropEditCell.appendChild(cropYEndField);
cropEditCell.appendChild(document.createTextNode(")"));
cropCell.appendChild(cropReadCell);
cropCell.appendChild(cropEditCell);
const locationCell = document.createElement("td");
locationCell.innerText = `(${location[0]}, ${location[1]}) to (${location[2]}, ${location[3]})`;
const locationReadCell = document.createElement("div");
locationReadCell.classList.add("template-data-view");
locationReadCell.innerText = `(${location[0]}, ${location[1]}) to (${location[2]}, ${location[3]})`;
const locationEditCell = document.createElement("div");
locationEditCell.classList.add("template-data-edit", "hidden");
const locationXStartField = document.createElement("input");
locationXStartField.name = "locxstart";
setCoordNumberFieldProps(locationXStartField, "X");
locationXStartField.value = location[0];
locationXStartField.form = editForm.id;
const locationYStartField = document.createElement("input");
locationYStartField.name = "locystart";
setCoordNumberFieldProps(locationYStartField, "Y");
locationYStartField.value = location[1];
locationYStartField.form = editForm.id;
const locationXEndField = document.createElement("input");
locationXEndField.name = "locxend";
setCoordNumberFieldProps(locationXEndField, "X");
locationXEndField.value = location[2];
locationXEndField.form = editForm.id;
const locationYEndField = document.createElement("input");
locationYEndField.name = "locyend";
setCoordNumberFieldProps(locationYEndField, "Y");
locationYEndField.value = location[3];
locationYEndField.form = editForm.id;
locationEditCell.appendChild(document.createTextNode("("));
locationEditCell.appendChild(locationXStartField);
locationEditCell.appendChild(document.createTextNode(", "));
locationEditCell.appendChild(locationYStartField);
locationEditCell.appendChild(document.createTextNode(") to ("));
locationEditCell.appendChild(locationXEndField);
locationEditCell.appendChild(document.createTextNode(", "));
locationEditCell.appendChild(locationYEndField);
locationEditCell.appendChild(document.createTextNode(")"));
locationCell.appendChild(locationReadCell);
locationCell.appendChild(locationEditCell);
const previewCell = document.createElement("td");
const previewReadCell = document.createElement("div");
previewReadCell.id = `template-list-preview-${index}`;
previewReadCell.classList.add("template-data-view");
const previewLink = document.createElement("a");
previewLink.href = `javascript:showPreview(${index})`;
previewLink.innerText = "Preview";
previewCell.appendChild(previewLink);
previewCell.id = `template-list-preview-${index}`;
previewReadCell.appendChild(previewLink);
const previewEditCell = document.createElement("div");
previewEditCell.classList.add("template-data-edit", "hidden");
const imageEditField = document.createElement("input");
imageEditField.name = "image";
imageEditField.type = "file";
imageEditField.accept = "image/png";
imageEditField.form = editForm.id;
previewEditCell.appendChild(imageEditField);
previewCell.appendChild(previewReadCell);
previewCell.appendChild(previewEditCell);
const editCell = document.createElement("td");
const editReadCell = document.createElement("div");
editReadCell.classList.add("template-data-view");
const switchToEditButton = document.createElement("button");
switchToEditButton.type = "button";
switchToEditButton.innerText = "Edit"
editReadCell.appendChild(switchToEditButton);
const editEditCell = document.createElement("div");
editEditCell.classList.add("template-data-edit", "hidden");
const editSubmitButton = document.createElement("button");
editSubmitButton.type = "submit";
editSubmitButton.innerText = "Submit";
const editErrors = document.createElement("ul");
editErrors.id = `template-data-edit-errors-${index}`;
editErrors.classList.add("template-data-edit-errors");
editForm.appendChild(editSubmitButton);
editForm.appendChild(editErrors);
editEditCell.appendChild(editForm);
editCell.appendChild(editReadCell);
editCell.appendChild(editEditCell);
const templateRow = document.createElement("tr");
templateRow.id = `template-list-data-${index}`;
templateRow.appendChild(nameCell);
templateRow.appendChild(descriptionCell);
templateRow.appendChild(attributionCell);
templateRow.appendChild(cropCell);
templateRow.appendChild(locationCell);
templateRow.appendChild(previewCell);
templateRow.appendChild(editCell);
switchToEditButton.addEventListener("click", (event) => {
for (const element of templateRow.getElementsByClassName("template-data-view")) {
element.classList.add("hidden");
}
for (const element of templateRow.getElementsByClassName("template-data-edit")) {
element.classList.remove("hidden");
}
});
templateRow.addEventListener("submit", async (event) => {
event.preventDefault();
editErrors.innerHTML = "";
const name = nameEditField.value;
const description = descriptionEditField.value;
const attribution = attributionEditField.value;
const cropXStart = parseInt(cropXStartField.value, 10);
const cropYStart = parseInt(cropYStartField.value, 10);
const cropXEnd = parseInt(cropXEndField.value, 10);
const cropYEnd = parseInt(cropYEndField.value, 10);
const locXStart = parseInt(locationXStartField.value, 10);
const locYStart = parseInt(locationYStartField.value, 10);
const locXEnd = parseInt(locationXEndField.value, 10);
const locYEnd = parseInt(locationYEndField.value, 10);
if (
isNaN(cropXStart) ||
isNaN(cropYStart) ||
isNaN(cropXEnd) ||
isNaN(cropYEnd) ||
isNaN(locXStart) ||
isNaN(locXEnd) ||
isNaN(locYStart) ||
isNaN(locYEnd)
) {
const parseNumbersError = document.createElement("li");
parseNumbersError.innerText = "All crop and location information must be entered";
editErrors.appendChild(parseNumbersError);
}
const submitData = {
name: name,
description: description,
attribution: attribution,
crop: [cropXStart, cropYStart, cropXEnd, cropYEnd],
location: [locXStart, locYStart, locXEnd, locYEnd]
};
const imageFiles = imageEditField.files;
if (imageFiles.length > 0) {
const fileReader = new FileReader();
const fileReaderCompletePromise = new Promise((resolve, reject) => {
fileReader.addEventListener("loadend", (event) => resolve());
});
fileReader.readAsDataURL(imageFile);
await fileReaderCompletePromise;
const imageDataURL = fileReader.result;
if (imageDataURL.startsWith("data:image/png;base64,")) {
submitData.image = imageDataURL.substring(22);
} else {
const imageError = document.createElement("li");
imageError.innerText = "Failed to process image as PNG";
editErrors.appendChild(imageError);
}
}
if (googleUser) {
submitData.token = googleUser.getAuthResponse().id_token;
}
if (editErrors.hasChildNodes()) {
return;
}
const origName = templateData[index].name;
const encodedName = encodeURIComponent(origName);
const submitResponse = await fetch(`/thrimshim/update-template/${encodedName}`, { method: "POST", body: JSON.stringify(submitData), headers: { "Content-Type": "application/json" }});
if (!submitResponse.ok) {
const submitError = document.createElement("li");
submitError.innerText = await submitResponse.text();
editErrors.appendChild(submitError);
return;
}
templateData[index].name = name;
if (submitData.hasOwnProperty("image")) {
templateData[index].image = submitData.image;
}
templateData[index].description = description;
templateData[index].attribution = attribution;
templateData[index].crop = submitData.crop;
templateData[index].location = submitData.location;
const templateDOM = generateTemplateDOM(index, templateData[index]);
templateRow.replaceWith(templateDOM);
});
return templateRow;
}
function addTemplate(index, template) {
const templateDOM = generateTemplateDOM(index, template);
document.getElementById("template-list-data").appendChild(templateDOM);
}
document.getElementById("template-list-data").appendChild(templateRow);
function setCoordNumberFieldProps(field, direction) {
field.type = "number";
field.placeholder = direction;
field.min = 0;
field.step = 1;
field.classList.add("template-coord");
}
function showPreview(index) {

@ -2,6 +2,10 @@
display: none;
}
table > form {
display: table-row;
}
#template-list-data {
border-collapse: collapse;
}
@ -15,7 +19,7 @@
width: 480px;
}
#template-new-errors {
#template-new-errors, .template-data-edit-errors {
color: #c00;
}
@ -29,7 +33,7 @@
display: contents;
}
.template-new-coord {
.template-coord {
width: 50px;
}

@ -23,6 +23,7 @@
<th>Crop Coordinates</th>
<th>Location Coordinates</th>
<th>Preview</th>
<th></th>
</tr>
</table>
</div>
@ -53,7 +54,7 @@
<span>
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-crop-x-start"
name="cropxstart"
placeholder="X"
@ -63,7 +64,7 @@
/>
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-crop-y-start"
name="cropystart"
placeholder="Y"
@ -74,7 +75,7 @@
to
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-crop-x-end"
name="cropxend"
placeholder="X"
@ -84,7 +85,7 @@
/>
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-crop-y-end"
name="cropyend"
placeholder="Y"
@ -99,7 +100,7 @@
<span>
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-location-x-start"
name="locxstart"
placeholder="X"
@ -109,7 +110,7 @@
/>
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-location-y-start"
name="locystart"
placeholder="Y"
@ -120,7 +121,7 @@
to
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-location-x-end"
name="locxend"
placeholder="X"
@ -130,7 +131,7 @@
/>
<input
type="number"
class="template-new-coord"
class="template-coord"
id="template-new-location-y-end"
name="locyend"
placeholder="Y"

Loading…
Cancel
Save