library/frontend/files/app.js

263 lines
7.0 KiB
JavaScript
Raw Normal View History

2021-11-01 00:00:04 +00:00
var sortState = {
sortBy: "sortAuthor",
sortOrder: "asc",
};
2024-01-03 01:52:21 +00:00
var admin = false;
2021-11-01 00:00:04 +00:00
function init() {
2024-01-03 01:52:21 +00:00
fetch("/api/mode")
.then((response) => response.json())
.then((resp) => (admin = resp.Admin))
.then(() => {
if (admin) {
var element = document.getElementById("addBook");
element.addEventListener("click", (e) => {
e.preventDefault();
renderAddBookView();
});
element.classList.remove("hidden");
}
});
2022-03-13 22:04:09 +00:00
fetch("/api/books")
2021-11-01 00:00:04 +00:00
.then((response) => response.json())
.then((books) => {
// prepare response
books.forEach(apiResponseParsing);
2023-10-14 21:01:22 +00:00
document.getElementById("search").addEventListener("input", (e) => {
renderTable(
search(
books,
e.target.value,
document.getElementById("childrens").checked
)
);
});
document.getElementById("childrens").addEventListener("change", (e) => {
renderTable(
search(
books,
document.getElementById("search").value,
e.target.checked
)
);
});
2023-10-08 19:05:15 +00:00
renderTable(
search(books, "", document.getElementById("childrens").checked)
);
2021-11-01 00:00:04 +00:00
});
}
2024-01-03 01:52:21 +00:00
function renderAddBookView() {
document.getElementById("current").innerHTML = AddBookTemplate();
}
2021-11-01 00:00:04 +00:00
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);
2023-02-05 01:51:40 +00:00
var bookCount = document.getElementById("bookCount");
bookCount.innerHTML = `${books.length} books`;
2021-11-01 00:00:04 +00:00
// 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"]);
}
2022-01-15 20:46:59 +00:00
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;
}
2023-10-08 19:05:15 +00:00
function search(books, searchBy, includeChildrensBooks) {
2021-11-01 00:00:04 +00:00
searchBy = searchCleaner(searchBy);
books = books.filter(
({ title, authors, genre, publisher, series, year, childrens }) => {
var inSearch = true;
if (searchBy !== "") {
inSearch = Object.values({
2021-11-01 00:00:04 +00:00
title,
authors: authors.join(" "),
genre,
publisher,
series,
year,
}).find((field) => searchCleaner(field).indexOf(searchBy) !== -1);
}
if (!includeChildrensBooks) {
return inSearch && !childrens;
}
return inSearch;
}
);
2021-11-01 00:00:04 +00:00
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,
2023-10-14 19:37:36 +00:00
"isbn-10": isbn10,
2021-11-01 00:00:04 +00:00
authors,
2022-01-15 20:46:59 +00:00
coverURL,
2021-11-01 00:00:04 +00:00
description,
format,
notes,
publisher,
series,
signed,
title,
volume,
year,
}) {
2023-02-05 02:30:18 +00:00
return `<img ${coverURL ? `src="${coverURL}"` : ``}/>
<div class="bookDetails">
<h1>${title}</h1>
<h2>${authors}</h2>
2023-10-14 20:42:46 +00:00
<span>${[isbn10, isbn13].filter((v) => v != "").join(" / ")}</span><br/>
2023-02-05 02:30:18 +00:00
<span>${publisher}, ${year}</span><br/>
${
series
? `<span>${series}${volume ? `, Volume ${volume}` : ""}</span><br/>`
: ""
}
${signed ? "<span>Signed by the author ✒</span><br/>" : ""}
<span>${format}</span>
2024-01-03 01:52:21 +00:00
${admin ? `<a href="#">Edit Book</a>` : ""}
2021-11-01 00:00:04 +00:00
</div>`;
}
function TableRowTemplate({
"isbn-13": isbn13,
2023-10-14 19:37:36 +00:00
"isbn-10": isbn10,
2021-11-01 00:00:04 +00:00
authors,
publisher,
rowNumber,
signed,
title,
year,
}) {
2022-05-07 19:46:56 +00:00
return `<tr class="tRow" id="${rowNumber}">
2021-11-01 00:00:04 +00:00
<td class="title">
${title} ${
2023-02-05 02:30:18 +00:00
signed ? '<span class="signed" title="Signed by the author" >✒</span>' : ""
2021-11-01 00:00:04 +00:00
}
</td>
<td class="author">${authors}</td>
<td class="publisher">${publisher}</td>
<td class="year">${year}</td>
2023-10-14 19:37:36 +00:00
<td class="isbn">${isbn13 ? isbn13 : isbn10}</td>
2021-11-01 00:00:04 +00:00
</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>`;
}
2024-01-03 01:52:21 +00:00
function AddBookTemplate() {
return `<div class="addBookView">
<form>${[
{ name: "ISBN10", type: "text" },
{ name: "ISBN13", type: "text" },
{ name: "Title", type: "text" },
{ name: "Authors", type: "text" },
{ name: "SortAuthor", type: "text" },
{ name: "Format", type: "text" },
{ name: "Genre", type: "text" },
{ name: "Publisher", type: "text" },
{ name: "Series", type: "text" },
{ name: "Volume", type: "text" },
{ name: "Year", type: "text" },
{ name: "Signed", type: "checkbox" },
// { name: "Description", type: "text" },
// { name: "Notes", type: "text" },
{ name: "CoverURL", type: "text" },
{ name: "Childrens", type: "checkbox" },
].reduce((acc, field) => {
return acc.concat(
`<label>${field.name} <input type="${field.type}" name="${field.name.toLowerCase}"/></label><br/>`
);
}, "")}
</form>
</div>`;
}