+++ /dev/null
-//QuanLib: eBook Library
-//(C) 2017 by Christian Jaekl (cejaekl@yahoo.com)
-
-'use strict';
-
-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: 20,
- 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);
-
- if (g_state.first === value) {
- // No change
- return;
- }
-
- 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;
- }
-
- 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 + ');" '
- + ' 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 (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();
-}
-
-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';
-}
-
-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();
- }
-}
-
-function onNext() {
- 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);
- }
-}
-
-function onSlide(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);
- });
-}
-
-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);
- });
-}
-
-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;
-}
-
-function report(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';
-}
-
-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);
-}
-
-function stopTooltipTimer() {
- if (typeof g_state.tooltip.timer === 'undefined') {
- return;
- }
-
- clearTimeout(g_state.tooltip.timer);
- g_state.tooltip.timer = undefined;
- hideDetails();
-}
-
BooksView.init(BooksModel);
PagingController.init(BooksModel);
+SearchController.init(BooksModel);
// ================
// Global functions
document.getElementById('books').innerHTML = message;
}
-function constructSearchUrl() {
- 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;
-}
-
function onMouseMove(event) {
if (typeof event === 'undefined') {
return;
}
function onSearch() {
- var url = constructSearchUrl();
-
- fetch(url, {method:'GET', cache:'default'})
- .then(response => response.json())
- .then((jsonValue) => {
- // console.log('JSON response: ', jsonValue);
- BooksModel.ids = jsonValue;
- BooksModel.count = BooksModel.ids.length;
- BooksModel.first = (-1);
-
- var elem = document.getElementById('slider');
- elem.max = BooksModel.count;
-
- PagingController.adjustPos(0);
- })
- .catch(err => {
- var msg = 'Error fetching JSON from URL: ' + url + ': ' + err + ':' + err.stack;
- console.log(msg);
- report(msg);
- });
+ SearchController.onSearch();
}
--- /dev/null
+// ================
+// SearchController
+
+var SearchController = (function () {
+ var my = {},
+ booksModel = undefined;
+
+ const terms = ['aut', 'tit', 'ser'];
+
+ // ==============
+ // Public methods
+
+ my.init = function(linkedBooksModel) {
+ booksModel = linkedBooksModel;
+
+ for (var idx in terms) {
+ addEnterListener(terms[idx]);
+ }
+ };
+
+ my.onSearch = function() {
+ var url = constructSearchUrl();
+
+ fetch(url, {method:'GET', cache:'default'})
+ .then(response => response.json())
+ .then((jsonValue) => {
+ // console.log('JSON response: ', jsonValue);
+ booksModel.ids = jsonValue;
+ booksModel.count = booksModel.ids.length;
+ booksModel.first = (-1);
+
+ var elem = document.getElementById('slider');
+ elem.max = booksModel.count;
+
+ PagingController.adjustPos(0);
+ })
+ .catch(err => {
+ var msg = 'Error fetching JSON from URL: ' + url + ': ' + err + ':' + err.stack;
+ console.log(msg);
+ report(msg);
+ });
+ };
+
+ // ===============
+ // Private methods
+
+ // KeyUp listener. If the key is [Enter], then trigger a click on the [Search] button.
+ function addEnterListener(ctrlId) {
+ document.getElementById(ctrlId).addEventListener('keyup', function(event) {
+ event.preventDefault();
+ if (event.keyCode === 13) {
+ document.getElementById('search').click();
+ }
+ });
+ }
+
+ function constructSearchUrl() {
+ var url = window.location.protocol + '//' + window.location.host + '/search/';
+
+ var firstTime = true;
+
+ 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;
+ }
+
+ return my;
+})();