<!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> <link rel="stylesheet" href="css/reset.css"></link> <link rel="stylesheet" href="css/style.css"></link> <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(); }, 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://docs.google.com/spreadsheets/d/1w5Dc57wV0_rrKFsG7KM-qdPWEpqYk6lFu3JzAA0cSv0/edit">spreadsheet</a> <a target="_blank" href="https://github.com/deltamualpha/my-library">github</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>