231 lines
6.8 KiB
HTML
231 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
||
<html>
|
||
<head>
|
||
<title>Library</title>
|
||
<script type="text/javascript" src="js/jquery.js"></script>
|
||
<link
|
||
rel="stylesheet"
|
||
href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css"
|
||
/>
|
||
<link rel="stylesheet" href="css/reset.css" />
|
||
<link rel="stylesheet" href="css/style.css" />
|
||
<link rel="icon" href="favicon.ico" type="image/x-icon" />
|
||
<link
|
||
href="https://fonts.googleapis.com/css?family=Libre+Baskerville:400,700"
|
||
rel="stylesheet"
|
||
/>
|
||
<script type="text/javascript">
|
||
var sortState = {
|
||
sortBy: "sortAuthor",
|
||
sortOrder: "asc",
|
||
};
|
||
|
||
function init() {
|
||
fetch("/api")
|
||
.then((response) => response.json())
|
||
.then((books) => {
|
||
// prepare response
|
||
books.forEach((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 books;
|
||
})
|
||
.then((books) => {
|
||
document.getElementById("search").addEventListener("input", (e) => {
|
||
search(books, e.target.value);
|
||
});
|
||
return books;
|
||
})
|
||
.then(renderTable);
|
||
}
|
||
|
||
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);
|
||
}
|
||
);
|
||
}
|
||
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
|
||
document.getElementById("books").innerHTML = TableTemplate(books);
|
||
$("#books tbody tr")
|
||
.not(":first") // ignore the headers
|
||
.on("click", (e) => {
|
||
document.getElementById("current").innerHTML = BookTemplate(
|
||
books[e.currentTarget.id]
|
||
);
|
||
});
|
||
$("#books tbody tr th[data-sort-by]").on("click", function (e) {
|
||
console.log(e);
|
||
renderTable(books, $(this).data("sortBy")); // only add callback when there's a sortBy attribute
|
||
});
|
||
$("#books tbody tr th[data-sort-by=" + sortState.sortBy + "]").addClass(
|
||
sortState.sortOrder
|
||
);
|
||
}
|
||
|
||
function titleCleaner(title) {
|
||
return title
|
||
.replace('"', "")
|
||
.replace(":", "")
|
||
.replace(/^(An?|The)\s/i, "");
|
||
}
|
||
|
||
function searchCleaner(str) {
|
||
return str
|
||
.toLowerCase()
|
||
.replace('"', "")
|
||
.replace(":", "")
|
||
.replace("'", "")
|
||
.replace(" ", "");
|
||
}
|
||
|
||
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>`;
|
||
}
|
||
|
||
window.addEventListener("DOMContentLoaded", () => {
|
||
init();
|
||
});
|
||
</script>
|
||
</head>
|
||
<body>
|
||
<div class="wrapper">
|
||
<div id="header">
|
||
<h1>Library</h1>
|
||
<a target="_blank" href="https://git.yetaga.in/alazyreader/library"
|
||
>git</a
|
||
>
|
||
<div id="searchBox">
|
||
<input
|
||
id="search"
|
||
type="text"
|
||
name="search"
|
||
placeholder="Search..."
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div id="current">No Book Selected</div>
|
||
<div id="books"></div>
|
||
<!-- Table goes here -->
|
||
</div>
|
||
</body>
|
||
</html>
|