Skip to content

Commit

Permalink
Image upload refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
kompoth committed Apr 9, 2024
1 parent 2c4c8db commit 4df2232
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 51 deletions.
45 changes: 23 additions & 22 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,43 +37,44 @@ <h2>Issue creation</h2>
<form id="generator-form">
<fieldset class="grid-8">
<legend class="col-8">Heading</legend>
<label class="col-8" for="title-input">Title:</label>
<input class="col-7" type="text" maxlength="50" id="title-input" name="title">
<select class="col-1" id="title-font-size-select"></select>
<label class="col-8" for="subtitle-input">Subtitle:</label>
<input class="col-7" type="text" maxlength="50" id="subtitle-input" name="subtitle">
<select class="col-1" id="subtitle-font-size-select"></select>
<label class="col-8">Details:</label>
<input class="col-2" type="text" maxlength="50" id="issue-no-input" name="issue-no" placeholder="№ 22">
<input class="col-3" type="text" maxlength="50" id="issue-date-input" name="issue-date" placeholder="April 1, 2024">
<input class="col-2" type="text" maxlength="50" id="issue-cost-input" name="issue-cost" placeholder="Price $1">
<select class="col-1" id="details-font-size-select"></select>
<label class="col-8" for="title-input">Title:</label>
<input class="col-7" type="text" maxlength="50" id="title-input" name="title">
<select class="col-1" id="title-font-size-select" name="title-font-size"></select>
<label class="col-8" for="subtitle-input">Subtitle:</label>
<input class="col-7" type="text" maxlength="50" id="subtitle-input" name="subtitle">
<select class="col-1" id="subtitle-font-size-select" name="subtitle-font-size"></select>
<label class="col-8">Details:</label>
<input class="col-2" type="text" maxlength="50" id="issue-no-input" name="issue-no" placeholder="№ 22">
<input class="col-3" type="text" maxlength="50" id="issue-date-input" name="issue-date" placeholder="April 1, 2024">
<input class="col-2" type="text" maxlength="50" id="issue-cost-input" name="issue-cost" placeholder="Price $1">
<select class="col-1" id="details-font-size-select" name="details-font-size"></select>
</fieldset>

<fieldset>
<legend>Issue body <span id="body-length-tracker">(0/6,000)</span></legend>
<textarea id="issue-body-textarea" name="issue-body" rows=10 maxlength="6000" onkeyup="trackBodyLenght();" placeholder="See syntax cheatsheet below"></textarea>
<textarea id="issue-body-textarea" name="issue-body" rows=10 maxlength="6000" placeholder="See syntax cheatsheet below"></textarea>
<label for="body-titles-font-size-select">Titles size:
<select id="body-titles-font-size-select"></select>
<select id="body-titles-font-size-select" name="body-titles-font-size"></select>
</label>
<label for="body-subtitles-font-size-select">Subtitles size:
<select id="body-subtitles-font-size-select"></select>
<select id="body-subtitles-font-size-select" name="body-subtitles-font-size"></select>
</label>
<label for="body-text-font-size-select">Text size:
<select id="body-text-font-size-select"></select>
<select id="body-text-font-size-select" name="body-text-font-size"></select>
</label>
</fieldset>

<fieldset>
<legend>Images <span id="image-number-tracker">(0/4)</span></legend>
<p>
Upload an image and insert its tag anywhere in the text:<br>
Upload an image and use this tag to insert it in your article:<br>
<code>![Image caption](image-name.png)</code><br>
Image must not be larger than 2MB.
</p>
<ul id="attached-images-list"></ul>
<button type="button" id="add-image-button" onclick="document.getElementById('image-input').click();">Select images</button>
<input type="file" id="image-input" style="display: none;" multiple accept="image/png,image/jpg,image/jpeg" onchange="updateImageList();"/>
<div class="grid-8" id="image-list">
</div>
<button type="button" id="add-image-button">Add image</button>
<input type="file" id="event-image-input" style="display: none;" accept="image/png,image/jpg,image/jpeg"/>
</fieldset>

<fieldset>
Expand All @@ -94,8 +95,8 @@ <h2>Issue creation</h2>
</label>
</fieldset>

<button type="button" id="print-button" onclick="generatePDF();">Send to print</button>
<button type="button" id="save-button" onclick="saveForm();">Save*</button>
<button type="button" id="print-button">Send to print</button>
<button type="button" id="save-button">Save*</button>
<p style="grid-column: span 2; text-align: right; margin-top: -0.5rem;">
<small>
*Writes inputs to your cache and fills them in on the next page load.
Expand All @@ -120,7 +121,7 @@ <h2>Syntax cheatsheet</h2>
Bold with **asterisks** or __underscores__.

Insert images in your text like this:
![Image caption](image-file-name.png)
![Image caption](image-name.png)

| A | simple | table |
| - | --------------- | ------------------------ |
Expand Down
101 changes: 73 additions & 28 deletions static/main.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,71 @@
var imageStorage = new Map();


/* == On-page routines == */

function formatThousands(val) {
return val.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}

function trackBodyLenght () {
function updateBodyCounter() {
const textarea = document.getElementById("issue-body-textarea");
const curLength = textarea.value.length;
const maxLength = textarea.maxLength;
const countStr = "(" + formatThousands(curLength) + "/" + formatThousands(maxLength) + ")";
document.getElementById("body-length-tracker").innerHTML = countStr;
}

function updateImageList() {
var imageInput = document.getElementById("image-input");
var BreakException = {};
try {
Array.from(imageInput.files).forEach((file) => {
if (file && file.size > 2 * 1024 * 1024) throw BreakException;
});
} catch(exc) {
if (exc != BreakException) throw exc;
imageInput.value = null;
function updateImageCounter() {
const countStr = "(" + imageStorage.size.toString() + "/4)";
document.getElementById("image-number-tracker").innerHTML = countStr;
if (imageStorage.size >= 4) {
document.getElementById("add-image-button").disabled = true;
} else {
document.getElementById("add-image-button").disabled = false;
};
}

function addImage() {
/* Get and validate file */
const file = document.getElementById("event-image-input").files[0];
if (file.size > 2 * 1024 * 1024) {
alert("Image is too chunky!");
throw new Error("Image is too chunky!");
}

const countImages = Math.min(4, imageInput.files.length);
const countStr = "(" + countImages.toString() + "/4)";
document.getElementById("image-number-tracker").innerHTML = countStr;

var imageList = document.getElementById("attached-images-list");
imageList.innerHTML = "";
Array.from(imageInput.files).slice(0, countImages).forEach((file) => {
var li = document.createElement("li");
li.innerHTML = file.name;
imageList.appendChild(li);
/* Append image to storage */
if (imageStorage.has(file.name)) return;
imageStorage.set(file.name, file);

/* Count images and disable input */
updateImageCounter();

/* Prepare IDs */
const buttonId = "remove-image-button-" + imageStorage.size.toString();
const spanId = "image-span-" + imageStorage.size.toString()

/* Prepare remove button */
var removeButton = document.createElement("button");
removeButton.textContent = "Remove";
removeButton.setAttribute("id", buttonId);
removeButton.setAttribute("class", "col-1 inline-button");
removeButton.setAttribute("type", "button");
removeButton.addEventListener("click", () => {
document.getElementById(spanId).remove();
document.getElementById(buttonId).remove();
imageStorage.delete(file.name);
updateImageCounter();
});

/* Prepare image span */
var imageSpan = document.createElement("span");
imageSpan.textContent = file.name;
imageSpan.setAttribute("id", spanId);
imageSpan.setAttribute("class", "col-7");

/* Alter HTML */
document.getElementById("image-list").appendChild(removeButton);
document.getElementById("image-list").appendChild(imageSpan);
}

function saveForm() {
Expand Down Expand Up @@ -83,9 +113,25 @@ function onLoad() {
setFontSizes("body-titles-font-size-select", 8, 18, 2);
setFontSizes("body-subtitles-font-size-select", 8, 18, 2);
setFontSizes("body-text-font-size-select", 8, 18, 2);

reloadForm();
trackBodyLenght();
updateBodyCounter();

document.getElementById("issue-body-textarea").addEventListener(
"keyup", updateBodyCounter
);
document.getElementById("add-image-button").addEventListener(
"click", () => document.getElementById("event-image-input").click()
);
document.getElementById("event-image-input").addEventListener(
"change", addImage
);
document.getElementById("print-button").addEventListener(
"click", generatePDF
);
document.getElementById("save-button").addEventListener(
"click", saveForm
);
}


Expand All @@ -110,7 +156,7 @@ function prepareIssue() {

async function generatePDF() {
document.getElementById("print-button").disabled = true;

var resp;
var respJson;
const resourceUrl = "/api/issue/";
Expand All @@ -126,10 +172,9 @@ async function generatePDF() {
if (resp.ok) var issueId = respJson.issue_id
else throw new Error("Failed to send issue data");

const imageInput = document.getElementById("image-input");
if (imageInput.files.length > 0) {
if (imageStorage.size > 0) {
var formData = new FormData();
Array.from(imageInput.files).slice(0, 4).forEach((file) => {
imageStorage.forEach((file, key, map) => {
formData.append("images", file, file.name);
});
resp = await fetch(resourceUrl + issueId, {
Expand All @@ -139,7 +184,7 @@ async function generatePDF() {
respJson = await resp.json();
if (!resp.ok) throw new Error("Failed to send file");
}

resp = await fetch(resourceUrl + issueId, {method: "GET"});
if (resp.ok) resp.blob().then(
blob => window.open(URL.createObjectURL(blob))
Expand Down
10 changes: 9 additions & 1 deletion static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ form input[type=file] {
form .grid-8 {
display: grid;
grid-template-columns: repeat(8, 1fr);
grid-gap: 0 0.5rem;
grid-gap: 0.5rem 0.5rem;
align-items: center;
}
form .col-8 {
grid-column: span 8 !important;
Expand All @@ -86,3 +87,10 @@ form .col-2 {
fieldset label:has(select) {
white-space: nowrap;
}

/* Inline button for custom grids */
button.inline-button {
display: inline-block;
padding: 2px;
margin-top: 0;
}

0 comments on commit 4df2232

Please sign in to comment.