library/frontend/files/app.js

192 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var sortState = {
sortBy: "sortAuthor",
sortOrder: "asc",
};
function init() {
fetch("/api/books")
.then((response) => response.json())
.then((books) => {
// prepare response
books.forEach(apiResponseParsing);
document.getElementById("search").addEventListener("input", (e) => {
renderTable(search(books, e.target.value));
});
renderTable(books);
});
}
function renderTable(books, sortField) {
if (sortField) {
if (sortState.sortBy === sortField && sortState.sortOrder === "asc") {
sortState.sortOrder = "desc";
} else {
sortState.sortOrder = "asc";
}
sortState.sortBy = sortField;
}
books.sort((one, two) =>
(one[sortState.sortBy] + one["sortTitle"]).localeCompare(
two[sortState.sortBy] + two["sortTitle"]
)
);
if (sortState.sortOrder === "desc") {
books.reverse();
}
books.forEach((e, i) => (e.rowNumber = i)); // re-key
// rendering
var bookElement = document.getElementById("books");
bookElement.innerHTML = TableTemplate(books);
// add listeners for selecting book to view
Array.from(bookElement.querySelectorAll("tbody tr"))
.slice(1) // remove header from Array
.forEach((row) => {
row.addEventListener("click", (e) => {
// add listener to swap current book
document.getElementById("current").innerHTML = BookTemplate(
books[e.currentTarget.id]
);
});
});
// add sorting callbacks
Array.from(bookElement.querySelectorAll("tbody tr th[data-sort-by]")).forEach(
(row) => {
row.addEventListener("click", function (e) {
renderTable(books, e.target.dataset.sortBy); // only add callback when there's a sortBy attribute
});
}
);
// mark currently active column
bookElement
.querySelector("tbody tr th[data-sort-by=" + sortState.sortBy + "]")
.classList.add(sortState.sortOrder);
}
function apiResponseParsing(book) {
book.sortTitle = titleCleaner(book.title);
if (!book["isbn-10"] && book["isbn-13"]) {
book["isbn-10"] = ISBNfromEAN(book["isbn-13"]);
}
if (!book.coverURL && book["isbn-10"]) {
book.coverURL =
`https://images-na.ssl-images-amazon.com/images/P/` +
book["isbn-10"] +
`.01.LZZ.jpg`;
}
return book;
}
function search(books, searchBy) {
searchBy = searchCleaner(searchBy);
if (searchBy !== "") {
books = books.filter(
({ title, authors, genre, publisher, series, year }) => {
return Object.values({
title,
authors: authors.join(" "),
genre,
publisher,
series,
year,
}).find((field) => searchCleaner(field).indexOf(searchBy) !== -1);
}
);
}
return books;
}
function titleCleaner(title) {
return title
.replace('"', "")
.replace(":", "")
.replace(/^(An?|The)\s/i, "");
}
function searchCleaner(str) {
return str
.toLowerCase()
.replaceAll('"', "")
.replaceAll(":", "")
.replaceAll("'", "")
.replaceAll(" ", "");
}
function ISBNfromEAN(EAN) {
ISBN = EAN.slice(3, 12);
var checkdigit =
(11 - (ISBN.split("").reduce((s, n, k) => s + n * (10 - k), 0) % 11)) % 11;
return ISBN + (checkdigit === 10 ? "X" : checkdigit);
}
function BookTemplate({
"isbn-13": isbn13,
authors,
coverURL,
description,
format,
notes,
onLoan,
publisher,
series,
signed,
title,
volume,
year,
}) {
return `${coverURL ? `<img src="${coverURL}"/>` : ""}
<h1 ${onLoan ? "class='onLoan' " : ""}>${title}</h1>
<h2>${authors}</h2>
<span>${isbn13}</span><br/>
<span>${publisher}, ${year}</span><br/>
${
series
? `<span>${series}${volume ? `, Volume ${volume}` : ""}</span><br/>`
: ""
}
${signed ? "<span>Signed by the author ✒</span><br/>" : ""}
<span>${format}</span>
${onLoan ? `<h2 class="onLoan">On loan to ${onLoan}</h2>` : ""}
<div class="description">
<p>${description}</p>
${notes ? `<span>Notes:</span><p>${notes}</p>` : ""}
</div>`;
}
function TableRowTemplate({
"isbn-13": isbn13,
authors,
onLoan,
publisher,
rowNumber,
signed,
title,
year,
}) {
return `<tr class="tRow ${onLoan ? "onLoan" : ""}" id="${rowNumber}">
<td class="title">
${title} ${
signed ? '<span class="signed" title="Signed by the author" >✒</span>' : ""
}
</td>
<td class="author">${authors}</td>
<td class="publisher">${publisher}</td>
<td class="year">${year}</td>
<td class="isbn">${isbn13}</td>
</tr>`;
}
function TableTemplate(books) {
return `<table class="bookTable">
<tr>
<th data-sort-by="sortTitle" class="tHeader title">Title</th>
<th data-sort-by="sortAuthor" class="tHeader author">Author</th>
<th data-sort-by="publisher" class="tHeader publisher">Publisher</th>
<th data-sort-by="year" class="tHeader year">Year</th>
<th class="tHeader isbn">ISBN</th>
</tr>${books.reduce((acc, book) => {
return acc.concat(TableRowTemplate(book));
}, "")} </table>`;
}