Adds unit test framework and a first unit test.
[quanweb.git] / js / src / ToolTip.js
diff --git a/js/src/ToolTip.js b/js/src/ToolTip.js
new file mode 100644 (file)
index 0000000..e622e2a
--- /dev/null
@@ -0,0 +1,123 @@
+// =======
+// 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 = Browser.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.stopTooltipTimer();
+            my.hideDetails();
+        }
+    };
+
+    // Show the details pane
+    my.showDetails = function () {
+        var id = bookId;
+        var elem = Browser.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;
+    };
+    
+    // ===============
+    // 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;
+})();