management server listener (#17)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Reviewed-on: #17 Co-authored-by: David Ashby <delta.mu.alpha@gmail.com> Co-committed-by: David Ashby <delta.mu.alpha@gmail.com>
This commit is contained in:
@@ -3,61 +3,130 @@ var sortState = {
|
||||
sortOrder: "asc",
|
||||
};
|
||||
|
||||
function init() {
|
||||
fetch("/api/books")
|
||||
var admin = false;
|
||||
|
||||
var books;
|
||||
|
||||
function checkAdminMode() {
|
||||
fetch("/api/mode")
|
||||
.then((response) => response.json())
|
||||
.then((books) => {
|
||||
// prepare response
|
||||
books.forEach(apiResponseParsing);
|
||||
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
|
||||
)
|
||||
);
|
||||
});
|
||||
renderTable(
|
||||
search(books, "", document.getElementById("childrens").checked)
|
||||
);
|
||||
.then((resp) => (admin = resp.Admin))
|
||||
.then(() => {
|
||||
if (admin) {
|
||||
var element = document.getElementById("addBook");
|
||||
element.addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
renderAddBookView();
|
||||
});
|
||||
element.classList.remove("hidden");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable(books, sortField) {
|
||||
if (sortField) {
|
||||
if (sortState.sortBy === sortField && sortState.sortOrder === "asc") {
|
||||
sortState.sortOrder = "desc";
|
||||
function loadBookList() {
|
||||
fetch("/api/books")
|
||||
.then((response) => response.json())
|
||||
.then((list) => {
|
||||
// prepare response
|
||||
list.forEach(apiResponseParsing);
|
||||
books = list;
|
||||
document.getElementById("search").addEventListener("input", rerender);
|
||||
document.getElementById("childrens").addEventListener("change", rerender);
|
||||
rerender();
|
||||
});
|
||||
}
|
||||
|
||||
function rerender() {
|
||||
var searchValue = document.getElementById("search").value;
|
||||
var childrens = document.getElementById("childrens").checked;
|
||||
renderTable(search(searchValue, childrens));
|
||||
}
|
||||
|
||||
function init() {
|
||||
checkAdminMode();
|
||||
loadBookList();
|
||||
}
|
||||
|
||||
function renderAddBookView() {
|
||||
document.getElementById("current").innerHTML = AddBookTemplate();
|
||||
document.getElementById("lookup").addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
if (document.getElementById("isbn-13").value.length === 13) {
|
||||
getPossibleBooks(document.getElementById("isbn-13").value);
|
||||
} else {
|
||||
sortState.sortOrder = "asc";
|
||||
console.log("no isbn");
|
||||
}
|
||||
});
|
||||
document.getElementById("save").addEventListener("click", (e) => {
|
||||
e.preventDefault();
|
||||
saveBook({
|
||||
title: document.getElementById("title").value,
|
||||
authors: document.getElementById("authors").value.split(";"),
|
||||
sortAuthor: document.getElementById("sortAuthor").value,
|
||||
"isbn-10": document.getElementById("isbn-10").value,
|
||||
"isbn-13": document.getElementById("isbn-13").value,
|
||||
publisher: document.getElementById("publisher").value,
|
||||
format: document.getElementById("format").value,
|
||||
genre: document.getElementById("genre").value,
|
||||
series: document.getElementById("series").value,
|
||||
volume: document.getElementById("volume").value,
|
||||
year: document.getElementById("year").value,
|
||||
coverURL: document.getElementById("coverURL").value,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getPossibleBooks(isbn) {
|
||||
fetch("/api/query", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ "isbn-13": isbn }),
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((json) => {
|
||||
Object.keys(json).forEach((key) => {
|
||||
var elem = document.getElementById(key);
|
||||
if (elem !== null) {
|
||||
elem.value = json[key];
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function saveBook(book) {
|
||||
fetch("/api/books", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(book),
|
||||
}).then(() => {
|
||||
clearAddBookForm();
|
||||
loadBookList();
|
||||
});
|
||||
}
|
||||
|
||||
function renderTable(bookList, sortField) {
|
||||
if (sortField) {
|
||||
sortState.sortOrder =
|
||||
sortState.sortBy === sortField && sortState.sortOrder === "asc"
|
||||
? "desc"
|
||||
: "asc";
|
||||
sortState.sortBy = sortField;
|
||||
}
|
||||
books.sort((one, two) =>
|
||||
bookList.sort((one, two) =>
|
||||
(one[sortState.sortBy] + one["sortTitle"]).localeCompare(
|
||||
two[sortState.sortBy] + two["sortTitle"]
|
||||
)
|
||||
);
|
||||
if (sortState.sortOrder === "desc") {
|
||||
books.reverse();
|
||||
bookList.reverse();
|
||||
}
|
||||
books.forEach((e, i) => (e.rowNumber = i)); // re-key
|
||||
bookList.forEach((e, i) => (e.rowNumber = i)); // re-key
|
||||
|
||||
// rendering
|
||||
var bookElement = document.getElementById("books");
|
||||
bookElement.innerHTML = TableTemplate(books);
|
||||
bookElement.innerHTML = TableTemplate(bookList);
|
||||
|
||||
var bookCount = document.getElementById("bookCount");
|
||||
bookCount.innerHTML = `${books.length} books`;
|
||||
document.getElementById("bookCount").innerHTML = `${bookList.length} books`;
|
||||
|
||||
// add listeners for selecting book to view
|
||||
Array.from(bookElement.querySelectorAll("tbody tr"))
|
||||
@@ -66,7 +135,7 @@ function renderTable(books, sortField) {
|
||||
row.addEventListener("click", (e) => {
|
||||
// add listener to swap current book
|
||||
document.getElementById("current").innerHTML = BookTemplate(
|
||||
books[e.currentTarget.id]
|
||||
bookList[e.currentTarget.id]
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -74,7 +143,8 @@ function renderTable(books, sortField) {
|
||||
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
|
||||
// only add callback when there's a sortBy attribute
|
||||
renderTable(bookList, e.target.dataset.sortBy);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -98,9 +168,9 @@ function apiResponseParsing(book) {
|
||||
return book;
|
||||
}
|
||||
|
||||
function search(books, searchBy, includeChildrensBooks) {
|
||||
function search(searchBy, includeChildrensBooks) {
|
||||
searchBy = searchCleaner(searchBy);
|
||||
books = books.filter(
|
||||
return books.filter(
|
||||
({ title, authors, genre, publisher, series, year, childrens }) => {
|
||||
var inSearch = true;
|
||||
if (searchBy !== "") {
|
||||
@@ -119,7 +189,6 @@ function search(books, searchBy, includeChildrensBooks) {
|
||||
return inSearch;
|
||||
}
|
||||
);
|
||||
return books;
|
||||
}
|
||||
|
||||
function titleCleaner(title) {
|
||||
@@ -145,14 +214,20 @@ function ISBNfromEAN(EAN) {
|
||||
return ISBN + (checkdigit === 10 ? "X" : checkdigit);
|
||||
}
|
||||
|
||||
function clearAddBookForm() {
|
||||
document
|
||||
.getElementById("newBookForm")
|
||||
.childNodes.forEach((node) =>
|
||||
node.nodeName === "LABEL" ? (node.lastChild.value = "") : null
|
||||
);
|
||||
}
|
||||
|
||||
function BookTemplate({
|
||||
"isbn-13": isbn13,
|
||||
"isbn-10": isbn10,
|
||||
authors,
|
||||
coverURL,
|
||||
description,
|
||||
format,
|
||||
notes,
|
||||
publisher,
|
||||
series,
|
||||
signed,
|
||||
@@ -173,6 +248,7 @@ function BookTemplate({
|
||||
}
|
||||
${signed ? "<span>Signed by the author ✒</span><br/>" : ""}
|
||||
<span>${format}</span>
|
||||
${admin ? `<a href="#">Edit Book</a>` : ""}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
@@ -211,3 +287,36 @@ function TableTemplate(books) {
|
||||
return acc.concat(TableRowTemplate(book));
|
||||
}, "")} </table>`;
|
||||
}
|
||||
|
||||
function AddBookTemplate() {
|
||||
return `<div class="addBookView">
|
||||
<div id="newBookForm">
|
||||
${[
|
||||
{ name: "Title", id: "title", type: "text" },
|
||||
{ name: "Authors", id: "authors", type: "text" },
|
||||
{ name: "SortAuthor", id: "sortAuthor", type: "text" },
|
||||
{ name: "ISBN10", id: "isbn-10", type: "text" },
|
||||
{ name: "ISBN13", id: "isbn-13", type: "text" },
|
||||
{ name: "Publisher", id: "publisher", type: "text" },
|
||||
{ name: "Format", id: "format", type: "text" },
|
||||
{ name: "Genre", id: "genre", type: "text" },
|
||||
{ name: "Series", id: "series", type: "text" },
|
||||
{ name: "Volume", id: "volume", type: "text" },
|
||||
{ name: "Year", id: "year", type: "text" },
|
||||
{ name: "CoverURL", id: "coverURL", type: "text" },
|
||||
{ name: "Signed", id: "signed", type: "checkbox" },
|
||||
{ name: "Childrens", id: "childrens", type: "checkbox" },
|
||||
].reduce((acc, field) => {
|
||||
return acc.concat(
|
||||
`<label>${field.name} <input
|
||||
type="${field.type}"
|
||||
name="${field.name.toLowerCase()}"
|
||||
id="${field.id}"
|
||||
/></label><br/>`
|
||||
);
|
||||
}, "")}
|
||||
<input id="lookup" type="submit" value="look up">
|
||||
<input id="save" type="submit" value="save">
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
|
@@ -31,6 +31,7 @@
|
||||
href="https://git.yetaga.in/alazyreader/library"
|
||||
>git</a
|
||||
>
|
||||
<a href="#" id="addBook" class="hidden">add book</a>
|
||||
<div id="searchBox">
|
||||
<label for="childrens" class="bookCount"
|
||||
>Include Childrens Books?</label
|
||||
|
@@ -185,7 +185,7 @@ body {
|
||||
padding-left: 20px;
|
||||
padding-right: 20px;
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
justify-content: space-evenly;
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
overflow: auto;
|
||||
@@ -235,4 +235,4 @@ footer {
|
||||
width: calc(100% - 40px);
|
||||
color: #a29c77;
|
||||
border-top: 2px solid #d8d0a0;
|
||||
}
|
||||
}
|
||||
|
@@ -133,6 +133,10 @@ body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#header {
|
||||
height: 30px;
|
||||
width: calc(100vw - 20px);
|
||||
|
Reference in New Issue
Block a user