-// QuanLib: eBook Library
-// (C) 2017 by Christian Jaekl (cejaekl@yahoo.com)
+//QuanLib: eBook Library
+//(C) 2017 by Christian Jaekl (cejaekl@yahoo.com)
g_state = {
- cache: {},
- count: 0,
- first: 0,
- ids: [],
- last: (-1),
- pageSize: 9
+ cache: [],
+ count: 0,
+ first: 0,
+ ids: [],
+ last: (-1),
+ map: {}, // map from book.Id to index into cache[]
+ pageSize: 9,
+ tooltip: {
+ bookId: undefined,
+ milliSecs: 500, // time to wait before displaying tooltip
+ timer: undefined
+ }
}
function adjustPos(setting) {
- var value = parseInt(setting)
-
- if (g_state.first === value) {
- // No change
- return;
- }
+ var value = parseInt(setting)
- var maxFirst = g_state.count - g_state.pageSize;
+ if (g_state.first === value) {
+ // No change
+ return;
+ }
- if (value < 0) {
- g_state.first = 0;
- } else if (value > maxFirst) {
- g_state.first = maxFirst;
- } else {
- g_state.first = value;
- }
+ var maxFirst = g_state.count - g_state.pageSize;
- g_state.last = g_state.first + g_state.pageSize - 1;
- if (g_state.last >= g_state.count) {
- g_state.last = g_state.count - 1;
- }
+ if (value < 0) {
+ g_state.first = 0;
+ } else if (value > maxFirst) {
+ g_state.first = maxFirst;
+ } else {
+ g_state.first = value;
+ }
- refreshData();
+ g_state.last = g_state.first + g_state.pageSize - 1;
+ if (g_state.last >= g_state.count) {
+ g_state.last = g_state.count - 1;
+ }
+
+ document.getElementById('slider').value = setting;
+
+ refreshData();
+}
+
+function bookHtml(book) {
+ var result = '<div class="book">'
+ + '<table>'
+ + '<tr>'
+ + '<td><a href="/book/' + book.Id + '">';
+ if (0 == book.CoverId) {
+ result += '(No cover available)'
+ } else {
+ result += '<img class="cover-thumb" src="/download/' + book.CoverId + '"/>'
+ }
+ result += '</a></td>'
+ + '<td onclick="displayDetails(' + book.Id + ');" '
+ + ' onmouseout="stopTooltipTimer(); hideDetails();" '
+ + ' onmouseover="startTooltipTimer(' + book.Id + ');">'
+ + '<p><b>' + book.Title + '</b></p>'
+ + '<p>'
+ + '<i>' + book.AuthorReading + '</i>';
+ if (typeof(book.SeriesName) !== 'undefined' && book.SeriesName.length > 0) {
+ result += '<br/><i>' + book.SeriesName + ' ' + book.Volume + '</i>';
+ }
+ result += '</p>'
+ + '</td>'
+ + '</tr>'
+ + '</table>'
+ + '</div>';
+ return result;
+}
+
+//ce(s): "clear if empty()"
+//return s, unless it's undefined, in which case return an empty ("clear") string
+function ce(s) {
+ if (typeof s !== 'undefined') {
+ return s;
+ }
+ return '';
}
function constructSearchUrl() {
- var url = window.location.protocol + '//' + window.location.host + '/search/';
-
- var firstTime = true;
- var terms = ['aut', 'tit', 'ser'];
-
- for (idx in terms) {
- var term = terms[idx];
- var elem = document.getElementById(term);
- if (null === elem) {
- console.log('Error: could not find form element for search term "' + term + '".');
- continue;
- }
-
- var value = elem.value;
- if (value.length > 0) {
- if (firstTime) {
- url += '?';
- firstTime = false;
- }
- else {
- url += '&';
- }
- url += term + '=' + encodeURIComponent('%' + value + '%');
- }
- }
-
- return url;
+ var url = window.location.protocol + '//' + window.location.host + '/search/';
+
+ var firstTime = true;
+ var terms = ['aut', 'tit', 'ser'];
+
+ for (idx in terms) {
+ var term = terms[idx];
+ var elem = document.getElementById(term);
+ if (null === elem) {
+ console.log('Error: could not find form element for search term "' + term + '".');
+ continue;
+ }
+
+ var value = elem.value;
+ if (value.length > 0) {
+ if (firstTime) {
+ url += '?';
+ firstTime = false;
+ }
+ else {
+ url += '&';
+ }
+ url += term + '=' + encodeURIComponent('%' + value + '%');
+ }
+ }
+
+ return url;
+}
+
+// Set the book ID for the details pane, and then show it
+function displayDetails(bookId) {
+ console.log('displayDetails()', bookId);
+ g_state.tooltip.bookId = bookId;
+ showDetails();
+}
+
+function hideDetails() {
+ var elem = document.getElementById('details');
+ elem.innerHtml = '';
+ elem.style.display = 'none';
}
function onNext() {
- if (g_state.last < (g_state.count - 1)) {
- adjustPos(g_state.first + g_state.pageSize);
- }
+ if (g_state.last < (g_state.count - 1)) {
+ adjustPos(g_state.first + g_state.pageSize);
+ }
}
function onPrev() {
- if (g_state.first > 0) {
- adjustPos(g_state.first - g_state.pageSize);
- }
+ if (g_state.first > 0) {
+ adjustPos(g_state.first - g_state.pageSize);
+ }
}
function onSlide(value) {
- adjustPos(value);
+ adjustPos(value);
}
function onSearch() {
- console.log('onSearch()');
-
- var url = constructSearchUrl();
-
- report('Loading data from server, please wait...')
- console.log('Fetching: "' + url + '"...')
-
- fetch(url, {method:'GET', cache:'default'})
- .then(response => response.json())
- .then((jsonValue) => {
- console.log('JSON response: ', jsonValue);
- g_state.ids = jsonValue
- g_state.count = g_state.ids.length;
- g_state.first = (-1)
-
- var elem = document.getElementById('slider');
- elem.max = g_state.count;
- elem.value = '0'
-
- adjustPos(0);
- })
- .catch(err => {
- var msg = 'Error fetching JSON from URL: ' + url + ': ' + err + ':' + err.stack;
- console.log(msg);
- report(msg);
- });
+ console.log('onSearch()');
+
+ var url = constructSearchUrl();
+
+ report('Loading data from server, please wait...')
+ console.log('Fetching: "' + url + '"...')
+
+ fetch(url, {method:'GET', cache:'default'})
+ .then(response => response.json())
+ .then((jsonValue) => {
+ console.log('JSON response: ', jsonValue);
+ g_state.ids = jsonValue
+ g_state.count = g_state.ids.length;
+ g_state.first = (-1)
+
+ var elem = document.getElementById('slider');
+ elem.max = g_state.count;
+
+ adjustPos(0);
+ })
+ .catch(err => {
+ var msg = 'Error fetching JSON from URL: ' + url + ': ' + err + ':' + err.stack;
+ console.log(msg);
+ report(msg);
+ });
}
function refreshData() {
- report('Loading details for books ' + g_state.first + ' through ' + g_state.last + ', please wait...');
-
- var i;
- var url = '/info/?ids=';
- for (i = g_state.first; i <= g_state.last; ++i) {
- if (i > g_state.first) {
- url += ',';
- }
- url += g_state.ids[i];
- }
-
- fetch(url, {method:'GET', cache:'default'})
- .then(response => response.json())
- .then((jsonValue) => {
- console.log('JSON response for info: ', jsonValue);
- report('');
- g_state.cache = jsonValue;
- refreshLayout();
- })
- .catch(err => {
- var msg = 'Error fetching book details via URL: ' + url + ': ' + err;
- console.log(msg, err.stack);
- report(msg);
- });
+ report('Loading details for books ' + g_state.first + ' through ' + g_state.last + ', please wait...');
+
+ var i;
+ var url = '/info/?ids=';
+ g_state.map = {};
+ for (i = g_state.first; i <= g_state.last; ++i) {
+ if (i > g_state.first) {
+ url += ',';
+ }
+ var id = g_state.ids[i];
+ url += id;
+ g_state.map[id] = i - g_state.first;
+ }
+
+ fetch(url, {method:'GET', cache:'default'})
+ .then(response => response.json())
+ .then((jsonValue) => {
+ console.log('JSON response for info: ', jsonValue);
+ report('');
+ g_state.cache = jsonValue;
+ refreshLayout();
+ })
+ .catch(err => {
+ var msg = 'Error fetching book details via URL: ' + url + ': ' + err;
+ console.log(msg, err.stack);
+ report(msg);
+ });
}
function refreshLayout() {
- var i;
- var html = '';
- var limit = g_state.last - g_state.first;
- for (i = 0; i <= limit; ++i) {
- var book = g_state.cache[i];
- html += bookHtml(book);
- }
-
- document.getElementById('books').innerHTML = html;
- document.getElementById('first').innerHTML = (g_state.first + 1);
- document.getElementById('last').innerHTML = (g_state.last + 1);
- document.getElementById('count').innerHTML = g_state.count;
+ var i;
+ var html = '';
+ var limit = g_state.last - g_state.first;
+ for (i = 0; i <= limit; ++i) {
+ var book = g_state.cache[i];
+ html += bookHtml(book);
+ }
+
+ document.getElementById('books').innerHTML = html;
+ document.getElementById('first').innerHTML = (g_state.first + 1);
+ document.getElementById('last').innerHTML = (g_state.last + 1);
+ document.getElementById('count').innerHTML = g_state.count;
}
function report(message) {
- document.getElementById('books').innerHTML = message;
+ document.getElementById('books').innerHTML = message;
}
-function bookHtml(book) {
- console.log('bookHtml(): ', book);
- var result = '<div class="book">'
- + '<table>'
- + '<tr>'
- + '<td><a href="/book/' + book.Id + '">';
- if (0 == book.CoverId) {
- result += '(No cover available)'
- } else {
- result += '<img class="cover-thumb" src="/download/' + book.CoverId + '"/>'
- }
- result += '</a></td>'
- + '<td>'
- + '<p><b>' + book.Title + '</b></p>'
- + '<p>'
- + '<i>' + book.AuthorReading + '</i>';
- if (typeof(book.SeriesName) !== 'undefined' && book.SeriesName.length > 0) {
- result += '<br/><i>' + book.SeriesName + ' ' + book.Volume + '</i>';
- }
- result += '</p>'
- + '</td>'
- + '</tr>'
- + '</table>'
- + '</div>';
- return result;
+function showDetails() {
+ console.log('showDetails()', g_state.tooltip.bookId);
+
+ var id = g_state.tooltip.bookId;
+ var elem = document.getElementById('details');
+ var index = g_state.map[id];
+ var book = g_state.cache[index];
+ var html = '<div><p><b>' + book.Title + '</b></p>'
+ + '<p><i>' + ce(book.AuthorReading) + '<br/>' + ce(book.Series) + ' ' + ce(book.Volume) + '</i></p></div><div>'
+ + ce(book.Description)
+ + '</div>';
+
+ elem.innerHTML = html;
+ elem.style.display = 'block';
+}
+
+function startTooltipTimer(bookId) {
+ if (typeof g_state.tooltip.timer !== 'undefined') {
+ clearTimer(g_state.tooltip.timer);
+ }
+ g_state.tooltip.bookId = bookId;
+ g_state.tooltip.timer = setTimeout(showDetails, g_state.tooltip.milliSecs);
+}
+
+function stopTooltipTimer() {
+ if (typeof g_state.tooltip.timer === 'undefined') {
+ return;
+ }
+ clearTimeout(g_state.tooltip.timer);
+ g_state.tooltip.timer = undefined;
+ hideDetails();
}