//QuanLib: eBook Library
//(C) 2017 by Christian Jaekl (cejaekl@yahoo.com)
-g_state = {
- cache: [],
- count: 0,
- mousePos: { // Last known position of the mouse cursor
- x: undefined,
- y: undefined
- },
- first: 0,
- ids: [],
- last: (-1),
- map: {}, // map from book.Id to index into cache[]
- pageSize: 48,
- tooltip: {
- bookId: undefined,
- milliSecs: 500, // time to wait before displaying tooltip
- mousePos: {
- x: undefined,
- y: undefined
- },
- threshold: 10, // number of pixels that mouse can move before tip is dismissed
- timer: undefined
- }
-}
+var g_state = {
+ cache: [],
+ count: 0,
+ mousePos: { // Last known position of the mouse cursor
+ x: undefined,
+ y: undefined
+ },
+ first: 0,
+ ids: [],
+ last: (-1),
+ map: {}, // map from book.Id to index into cache[]
+ pageSize: 48,
+ tooltip: {
+ bookId: undefined,
+ milliSecs: 500, // time to wait before displaying tooltip
+ mousePos: {
+ x: undefined,
+ y: undefined
+ },
+ threshold: 10, // number of pixels that mouse can move before tip is dismissed
+ timer: undefined
+ }
+};
document.onmousemove = onMouseMove;
function adjustPos(setting) {
- var value = parseInt(setting)
+ var value = parseInt(setting);
- if (g_state.first === value) {
- // No change
- return;
- }
+ if (g_state.first === value) {
+ // No change
+ return;
+ }
- var maxFirst = Math.max(0, g_state.count - g_state.pageSize);
+ var maxFirst = Math.max(0, g_state.count - g_state.pageSize);
- if (value < 0) {
- g_state.first = 0;
- } else if (value > maxFirst) {
- g_state.first = maxFirst;
- } else {
- g_state.first = value;
- }
+ if (value < 0) {
+ g_state.first = 0;
+ } else if (value > maxFirst) {
+ g_state.first = maxFirst;
+ } else {
+ g_state.first = value;
+ }
- g_state.last = g_state.first + g_state.pageSize - 1;
- if (g_state.last >= g_state.count) {
- g_state.last = g_state.count - 1;
- }
+ 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;
+ document.getElementById('slider').value = setting;
- refreshData();
+ 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 + ');" '
- + ' 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;
+ 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 + ');" '
+ + ' 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 '';
+ 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 (var 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) {
- g_state.tooltip.bookId = bookId;
- showDetails();
+ g_state.tooltip.bookId = bookId;
+ showDetails();
}
function hideDetails() {
- g_state.tooltip.mousePos.x = undefined;
- g_state.tooltip.mousePos.y = undefined;
-
- var elem = document.getElementById('details');
- elem.innerHTML = '';
- elem.style.display = 'none';
+ g_state.tooltip.mousePos.x = undefined;
+ g_state.tooltip.mousePos.y = undefined;
+
+ var elem = document.getElementById('details');
+ elem.innerHTML = '';
+ elem.style.display = 'none';
}
function onMouseMove(event) {
- if (typeof event === 'undefined') {
- return;
- }
-
- var x = event.pageX;
- var y = event.pageY;
-
- if ( x === g_state.mousePos.x
- && y === g_state.mousePos.y)
- {
- // No change from previous known position.
- // Nothing to see (or do) here, move along.
- return;
- }
-
- // Remember current mouse (x,y) position
- g_state.mousePos.x = x;
- g_state.mousePos.y = y;
-
- // Is there an active tooltip?
- if (typeof g_state.tooltip.mousePos.x === 'undefined') {
- // No active tooltip, so nothing further to do
- return;
- }
-
- var deltaX = Math.abs(x - g_state.tooltip.mousePos.x);
- var deltaY = Math.abs(y - g_state.tooltip.mousePos.y);
-
- if ( deltaX > g_state.tooltip.threshold
- || deltaY > g_state.tooltip.threshold )
- {
- hideDetails();
- }
+ if (typeof event === 'undefined') {
+ return;
+ }
+
+ var x = event.pageX;
+ var y = event.pageY;
+
+ if ( x === g_state.mousePos.x
+ && y === g_state.mousePos.y)
+ {
+ // No change from previous known position.
+ // Nothing to see (or do) here, move along.
+ return;
+ }
+
+ // Remember current mouse (x,y) position
+ g_state.mousePos.x = x;
+ g_state.mousePos.y = y;
+
+ // Is there an active tooltip?
+ if (typeof g_state.tooltip.mousePos.x === 'undefined') {
+ // No active tooltip, so nothing further to do
+ return;
+ }
+
+ var deltaX = Math.abs(x - g_state.tooltip.mousePos.x);
+ var deltaY = Math.abs(y - g_state.tooltip.mousePos.y);
+
+ if ( deltaX > g_state.tooltip.threshold
+ || deltaY > g_state.tooltip.threshold )
+ {
+ hideDetails();
+ }
}
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() {
- var url = constructSearchUrl();
-
- 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);
- });
+ var url = constructSearchUrl();
+
+ 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() {
- 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);
- g_state.cache = jsonValue;
- refreshLayout();
- })
- .catch(err => {
- var msg = 'Error fetching book details via URL: ' + url + ': ' + err;
- console.log(msg, err.stack);
- report(msg);
- });
+ 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);
+ 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 showDetails() {
- 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>';
-
- // Remember the current mouse (x,y).
- // If we move the mouse too far from this point, that will trigger hiding the tooltip.
- g_state.tooltip.mousePos.x = g_state.mousePos.x;
- g_state.tooltip.mousePos.y = g_state.mousePos.y;
-
- elem.innerHTML = html;
-
- elem.style.display = 'block'; // show, and calculate size, so that we can query it below
-
- var x = g_state.mousePos.x;
- var y = g_state.mousePos.y;
-
- var bcr = elem.getBoundingClientRect();
-
- var width = bcr.width;
- var height = bcr.height;
-
- x = Math.max(x - (width / 2), 0);
- y = Math.max(y - (height / 2), 0);
-
- elem.style.left = x + 'px';
- elem.style.top = y + 'px';
+ 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>';
+
+ // Remember the current mouse (x,y).
+ // If we move the mouse too far from this point, that will trigger hiding the tooltip.
+ g_state.tooltip.mousePos.x = g_state.mousePos.x;
+ g_state.tooltip.mousePos.y = g_state.mousePos.y;
+
+ elem.innerHTML = html;
+
+ elem.style.display = 'block'; // show, and calculate size, so that we can query it below
+
+ var x = g_state.mousePos.x;
+ var y = g_state.mousePos.y;
+
+ var bcr = elem.getBoundingClientRect();
+
+ var width = bcr.width;
+ var height = bcr.height;
+
+ x = Math.max(x - (width / 2), 0);
+ y = Math.max(y - (height / 2), 0);
+
+ elem.style.left = x + 'px';
+ elem.style.top = y + 'px';
}
function startTooltipTimer(bookId) {
- if (typeof g_state.tooltip.timer !== 'undefined') {
- clearTimeout(g_state.tooltip.timer);
- }
- g_state.tooltip.bookId = bookId;
- g_state.tooltip.timer = setTimeout(showDetails, g_state.tooltip.milliSecs);
+ if (typeof g_state.tooltip.timer !== 'undefined') {
+ clearTimeout(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();
+ if (typeof g_state.tooltip.timer === 'undefined') {
+ return;
+ }
+
+ clearTimeout(g_state.tooltip.timer);
+ g_state.tooltip.timer = undefined;
+ hideDetails();
}