<!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> <script type="text/javascript" src="js/lodash.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/tabletop.js/1.5.1/tabletop.min.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 publicSpreadsheetUrl = "https://docs.google.com/spreadsheets/d/1w5Dc57wV0_rrKFsG7KM-qdPWEpqYk6lFu3JzAA0cSv0/pubhtml"; var sortState = { sortBy: "authorLast", sortOrder: "asc", }; function init() { Tabletop.init({ key: publicSpreadsheetUrl, callback: showInfo, simpleSheet: true, }); } function showInfo(data, tabletop) { $("#reloadLink").unbind("click"); $("#reloadLink").on("click", function () { init(); }); $("#search").unbind("input"); $("#search").on("input", function (e) { search(data, e.target.value); }); $.each(data, function (key, value) { value.sortTitle = titleCleaner(value.title); if (!value["isbn-10"] && value["isbn-13"]) { value["isbn-10"] = generateISBNfromEAN(value["isbn-13"]); } if (!value.coverurl && value["isbn-10"]) { value.coverurl = generateAmazonCoverUrl(value["isbn-10"]); } }); renderTable(data); } function search(data, searchString) { searchBy = searchString .toLowerCase() .replace('"', "") .replace(":", "") .replace("'", "") .replace(" ", ""); relevantFields = [ "title", "author", "genre", "publisher", "series", "year", ]; if (!searchString) { renderTable(data); return false; } renderTable( _.filter(data, function (book) { return _.find(_.pick(book, relevantFields), function (field) { return ( field .toLowerCase() .replace('"', "") .replace(":", "") .replace("'", "") .replace(" ", "") .indexOf(searchBy) !== -1 ); }); }) ); } function renderTable(data, sortField) { if (sortField) { if (sortState.sortBy === sortField) { sortState.sortOrder = sortState.sortOrder === "asc" ? "desc" : "asc"; // swap if we're looping } else { sortState.sortOrder = "asc"; // reset if we've changed columns } sortState.sortBy = sortField; } data = _.orderBy( data, function (o) { return ( o[sortState.sortBy].toLowerCase() + o["sortTitle"].toLowerCase() ); }, sortState.sortOrder ); $.each(data, function (key, value) { value.rowNumber = key; // re-key for new sort }); var template = $("#Table").html(); var rendered = Mustache.render(template, { books: data }); $("#books").html(rendered); $("#books tbody tr") .not(":first") .on("click", function () { updateCurrentBook(data[$(this)[0].id]); // ignore the headers }); $("#books tbody tr th[data-sort-by]").on("click", function () { renderTable(data, $(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 updateCurrentBook(book) { var template = $("#View").html(); var rendered = Mustache.render(template, { book: book }); $("#current").html(rendered); } function titleCleaner(title) { return title .replace('"', "") .replace(":", "") .replace(/^(An?|The)\s/i, ""); } function generateAmazonCoverUrl(ISBN) { return ( "https://images-na.ssl-images-amazon.com/images/P/" + ISBN + ".01.LZZ.jpg" ); } function generateISBNfromEAN(EAN) { ISBN = EAN.slice(3, 12); var checkdigit = (11 - (_.reduce( ISBN.split(""), function (sum, num, key) { return sum + num * (10 - key); }, 0 ) % 11)) % 11; return ISBN + (checkdigit == 10 ? "X" : checkdigit); } 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> <th data-sort-by="authorLast" 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}} <tr class="tRow {{#onLoan}}onLoan{{/onLoan}}" id="{{rowNumber}}"> <td class="title"> {{title}} {{#signed}}<span class="signed" title="Signed by the author" >✒</span >︎{{/signed}} </td> <td class="author">{{author}}</td> <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> <h2>{{author}}</h2> <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>