2021-06-26 18:08:35 +00:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
<html>
|
|
|
|
|
<head>
|
|
|
|
|
<title>Library</title>
|
|
|
|
|
<script type="text/javascript" src="js/jquery.js"></script>
|
|
|
|
|
<script type="text/javascript" src="js/mustache.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 = {
|
2021-08-01 23:05:40 +00:00
|
|
|
|
sortBy: "sortAuthor",
|
2021-06-26 18:08:35 +00:00
|
|
|
|
sortOrder: "asc",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function init() {
|
2021-08-01 23:05:40 +00:00
|
|
|
|
fetch("/api")
|
|
|
|
|
.then((response) => response.json())
|
|
|
|
|
.then(showInfo);
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
function showInfo(books) {
|
|
|
|
|
books.forEach((book) => {
|
|
|
|
|
book.sortTitle = titleCleaner(book.title);
|
|
|
|
|
if (!book["isbn-10"] && book["isbn-13"]) {
|
|
|
|
|
book["isbn-10"] = ISBNfromEAN(book["isbn-13"]);
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
2021-08-03 01:31:54 +00:00
|
|
|
|
if (!book.coverurl && book["isbn-10"]) {
|
|
|
|
|
book.coverurl = amazonCoverUrl(book["isbn-10"]);
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
$("#search")
|
|
|
|
|
.unbind("input")
|
|
|
|
|
.on("input", (e) => {
|
|
|
|
|
search(books, e.target.value);
|
|
|
|
|
});
|
2021-06-26 18:08:35 +00:00
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
$("#reloadLink")
|
|
|
|
|
.unbind("click")
|
|
|
|
|
.on("click", () => {
|
|
|
|
|
init();
|
|
|
|
|
});
|
2021-06-26 18:08:35 +00:00
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
renderTable(books);
|
|
|
|
|
}
|
2021-06-26 18:08:35 +00:00
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
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);
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
function renderTable(books, sortField) {
|
2021-06-26 18:08:35 +00:00
|
|
|
|
if (sortField) {
|
2021-08-03 01:31:54 +00:00
|
|
|
|
if (sortState.sortBy === sortField && sortState.sortOrder === "asc") {
|
|
|
|
|
sortState.sortOrder = "desc";
|
2021-06-26 18:08:35 +00:00
|
|
|
|
} else {
|
2021-08-03 01:31:54 +00:00
|
|
|
|
sortState.sortOrder = "asc";
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
sortState.sortBy = sortField;
|
|
|
|
|
}
|
2021-08-03 01:31:54 +00:00
|
|
|
|
books.sort((one, two) =>
|
|
|
|
|
(one[sortState.sortBy] + one["sortTitle"]).localeCompare(
|
|
|
|
|
two[sortState.sortBy] + two["sortTitle"]
|
|
|
|
|
)
|
2021-06-26 18:08:35 +00:00
|
|
|
|
);
|
2021-08-03 01:31:54 +00:00
|
|
|
|
if (sortState.sortOrder === "desc") {
|
|
|
|
|
books.reverse();
|
|
|
|
|
}
|
|
|
|
|
books.forEach((e, i) => (e.rowNumber = i)); // re-key for new sort
|
2021-06-26 18:08:35 +00:00
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
$("#books").html(Mustache.render($("#Table").html(), { books }));
|
2021-06-26 18:08:35 +00:00
|
|
|
|
$("#books tbody tr")
|
2021-08-03 01:31:54 +00:00
|
|
|
|
.not(":first") // ignore the headers
|
2021-06-26 18:08:35 +00:00
|
|
|
|
.on("click", function () {
|
2021-08-03 01:31:54 +00:00
|
|
|
|
updateCurrentBook(books[$(this)[0].id]);
|
2021-06-26 18:08:35 +00:00
|
|
|
|
});
|
|
|
|
|
$("#books tbody tr th[data-sort-by]").on("click", function () {
|
2021-08-03 01:31:54 +00:00
|
|
|
|
renderTable(books, $(this).data("sortBy")); // only add callback when there's a sortBy attribute
|
2021-06-26 18:08:35 +00:00
|
|
|
|
});
|
|
|
|
|
$("#books tbody tr th[data-sort-by=" + sortState.sortBy + "]").addClass(
|
|
|
|
|
sortState.sortOrder
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function updateCurrentBook(book) {
|
2021-08-03 01:31:54 +00:00
|
|
|
|
$("#current").html(Mustache.render($("#View").html(), { book }));
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function titleCleaner(title) {
|
|
|
|
|
return title
|
|
|
|
|
.replace('"', "")
|
|
|
|
|
.replace(":", "")
|
|
|
|
|
.replace(/^(An?|The)\s/i, "");
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
function searchCleaner(str) {
|
|
|
|
|
return str
|
|
|
|
|
.toLowerCase()
|
|
|
|
|
.replace('"', "")
|
|
|
|
|
.replace(":", "")
|
|
|
|
|
.replace("'", "")
|
|
|
|
|
.replace(" ", "");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function amazonCoverUrl(ISBN) {
|
|
|
|
|
return `https://images-na.ssl-images-amazon.com/images/P/${ISBN}.01.LZZ.jpg`;
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-03 01:31:54 +00:00
|
|
|
|
function ISBNfromEAN(EAN) {
|
2021-06-26 18:08:35 +00:00
|
|
|
|
ISBN = EAN.slice(3, 12);
|
|
|
|
|
var checkdigit =
|
|
|
|
|
(11 -
|
2021-08-03 01:31:54 +00:00
|
|
|
|
(ISBN.split("").reduce((s, n, k) => s + n * (10 - k), 0) % 11)) %
|
2021-06-26 18:08:35 +00:00
|
|
|
|
11;
|
2021-08-03 01:31:54 +00:00
|
|
|
|
return ISBN + (checkdigit === 10 ? "X" : checkdigit);
|
2021-06-26 18:08:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
>
|
|
|
|
|
<a id="reloadLink" href="#">reload</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>
|
|
|
|
|
|
|
|
|
|
<script id="Table" type="text/html">
|
|
|
|
|
<table class="bookTable">
|
|
|
|
|
<tr>
|
|
|
|
|
<th data-sort-by="sortTitle" class="tHeader title">Title</th>
|
2021-08-01 23:05:40 +00:00
|
|
|
|
<th data-sort-by="sortAuthor" class="tHeader author">Author</th>
|
2021-06-26 18:08:35 +00:00
|
|
|
|
<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}}
|
|
|
|
|
<tr class="tRow {{#onLoan}}onLoan{{/onLoan}}" id="{{rowNumber}}">
|
|
|
|
|
<td class="title">
|
|
|
|
|
{{title}} {{#signed}}<span
|
|
|
|
|
class="signed"
|
|
|
|
|
title="Signed by the author"
|
|
|
|
|
>✒</span
|
|
|
|
|
>︎{{/signed}}
|
|
|
|
|
</td>
|
2021-08-01 23:05:40 +00:00
|
|
|
|
<td class="author">{{authors}}</td>
|
2021-06-26 18:08:35 +00:00
|
|
|
|
<td class="publisher">{{publisher}}</td>
|
|
|
|
|
<td class="year">{{year}}</td>
|
|
|
|
|
<td class="isbn">{{isbn-13}}</td>
|
|
|
|
|
</tr>
|
|
|
|
|
{{/books}}
|
|
|
|
|
</table>
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
<script id="View" type="text/html">
|
|
|
|
|
{{#book}}
|
|
|
|
|
{{#coverurl}}
|
|
|
|
|
<img src="{{coverurl}}"/>
|
|
|
|
|
{{/coverurl}}
|
|
|
|
|
<h1 {{#onLoan}}class="onLoan" {{/onLoan}}>{{title}}</h1>
|
2021-08-01 23:05:40 +00:00
|
|
|
|
<h2>{{authors}}</h2>
|
2021-06-26 18:08:35 +00:00
|
|
|
|
<span>{{isbn-13}}</span><br/>
|
|
|
|
|
<span>{{publisher}}, {{year}}</span><br/>
|
|
|
|
|
{{#series}}
|
|
|
|
|
<span>{{series}}{{#volume}}, Volume {{volume}}</span>{{/volume}}<br/>
|
|
|
|
|
{{/series}}
|
|
|
|
|
{{#signed}}
|
|
|
|
|
<span>Signed by the author ✒</span><br/>
|
|
|
|
|
{{/signed}}
|
|
|
|
|
<span>{{format}}</span>
|
|
|
|
|
{{#onLoan}}
|
|
|
|
|
<h2 class="onLoan">On loan to {{onLoan}}</h2>
|
|
|
|
|
{{/onLoan}}
|
|
|
|
|
<div class="description">
|
|
|
|
|
<p>{{description}}</p>
|
|
|
|
|
{{#notes}}
|
|
|
|
|
<span>Notes:</span>
|
|
|
|
|
<p>{{notes}}</p>
|
|
|
|
|
{{/notes}}
|
|
|
|
|
</div>
|
|
|
|
|
{{/book}}
|
|
|
|
|
</script>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|