+// =======
+// ToolTip
+
+var ToolTip = (function () {
+ // =================
+ // Private variables
+ var my = {},
+ 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;
+
+ // ================
+ // Public variables
+ my.booksModel = undefined;
+
+ // ==============
+ // Public Methods
+
+ // Set the book ID for the details pane, and then show it
+ my.displayDetails = function (newBookId) {
+ bookId = newBookId;
+ my.showDetails();
+ };
+
+ // Hide the details pane, if it is currently visible
+ my.hideDetails = function () {
+ mousePos.x = undefined;
+ mousePos.y = undefined;
+
+ var elem = document.getElementById('details');
+ elem.innerHTML = '';
+ elem.style.display = 'none';
+ };
+
+ my.mouseMoved = function (x, y) {
+ // Is there an active tooltip?
+ if (typeof mousePos.x === 'undefined') {
+ // No active tooltip, so nothing further to do
+ return;
+ }
+
+ var deltaX = Math.abs(x - mousePos.x);
+ var deltaY = Math.abs(y - mousePos.y);
+
+ if ( deltaX > threshold
+ || deltaY > threshold )
+ {
+ my.hideDetails();
+ }
+ };
+
+ // Show the details pane
+ my.showDetails = function () {
+ var id = bookId;
+ var elem = document.getElementById('details');
+ var index = BooksModel.map[id];
+ var book = BooksModel.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.
+ mousePos.x = g_state.mousePos.x;
+ 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 = mousePos.x;
+ var y = 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';
+ };
+
+ my.startTooltipTimer = function (newBookId) {
+ if (typeof timer !== 'undefined') {
+ clearTimeout(timer);
+ }
+ bookId = newBookId;
+ timer = setTimeout(my.showDetails, milliSecs);
+ };
+
+ my.stopTooltipTimer = function () {
+ if (typeof timer === 'undefined') {
+ return;
+ }
+
+ clearTimeout(timer);
+ timer = undefined;
+ my.hideDetails();
+ };
+
+ // ===============
+ // Private methods
+
+ // 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 '';
+ }
+
+ return my;
+})();