I try to make a select box whose entries are opened after clicking into the input box. After selecting one of the items, the dropdown should be closed again.
I want to achieve the open/close part of the dropdown without the use of javascript.
The html looks like this:
<div id="outer">
<input type="text" id="input">
<div id="results">
<div>Test 1 </div>
<div>Test 2 </div>
<div>Test 3 </div>
<div>Test 4 </div>
</div>
</div>
<div id="label">
</div>
After clicking onto an item, the selected value should appear below the #outer div (just for demonstration purposes).
The Javascript for assigning click events to the dropdown values:
document.querySelectorAll("#results div").forEach(setClick);
function setClick(node) {
node.addEventListener("click", setText.bind(null, node.innerHTML))
}
function setText(t) {
document.getElementById("label").innerHTML = t;
}
Now I will show you my first draft of css code:
#outer {
width: 200px;
position: relative;
}
#input {
width: 100%;
}
#results {
position: absolute;
width: 100%;
display: block;
visibility: hidden;
background-color: white;
}
#results > div:hover {
background-color: lightblue;
cursor: pointer;
}
#outer:focus-within #results, #results:hover {
visibility: visible;
}
This works like a charm but fails in one point:
After clicking an item, the dropdown is not closed. This is because of the #results:hover selector which is needed to keep the dropdown open after clicking onto an item. The click takes the focus out of the input field, thus the focus-within selector is not applied anymore. As the focus is removed from the input before the click occurs, the dropdown is hidden when the final click arrives in the document (this is my understanding of the problem).
Thus I use the hover selector which forces the div to keep open as long as the mouse is above the div.
You can test this here:
https://jsfiddle.net/hcetz1og/3/
My solution for this was a transition that hides the dropdown after the focus has been taken away:
#outer:not(:focus-within) #results:hover {
visibility: hidden;
transition-property: visibility;
/*use 10 ms and the clicked value in the drop down won't be shown */
transition-delay: 100ms;
transition-timing-function: step-end;
}
This works on my machine when I use 100ms as a delay. If I use 10ms, I have the same problem again. It seems that the click event is triggered "very" late.
Feel free to test it here:
https://jsfiddle.net/hcetz1og/2
Question:
How long will it take until the click event arrives at the document? Is there a fixed time span I have to wait or can the delay depend on every machine?
If so, I am forced to not use plain CSS but must use javascript for this I think.
Edit:
Feel free to post an alternative solution using plain css. But please be aware that I mainly want to focus on getting an answer to this question, not alternative solutions.
As #Mark Baijens said in the comments, using timeouts is a bad practice, so here is a pretty clean solution.
I used JavaScript to render the dropdown, not the CSS, because the CSS is where Your issue is coming from.
I don't know why would You want to set the innerHTML, but not some other property, like style.visibility for example. It just doesn't make sense to me, so with that in mind, let's get our hands on this :)
Working demo >> HERE <<.
Step 1 - remove the #outer...:hover parts of CSS
So, You are left with this:
#outer {
width: 200px;
position: relative;
}
#input {
width: 100%;
}
#results {
position: absolute;
width: 100%;
display: block;
visibility: hidden;
background-color: white;
}
#results > div:hover {
background-color: lightblue;
cursor: pointer;
}
Step 2 - add the onfocus event to the input field
Just assign a function call to the onfocus attribute of the input. Everything else in the HTML stays the same.
<div id="outer">
<input type="text" id="input" onfocus="showElements()">
<div id="results">
<div>Test 1 </div>
<div>Test 2 </div>
<div>Test 3 </div>
<div>Test 4 </div>
</div>
</div>
<div id="label">
</div>
Step 3 - create the showElements and hideElements function:
function showElements() {
document.getElementById("results").style.visibility = 'visible';
}
function hideElements() {
document.getElementById("results").style.visibility = 'hidden';
}
Step 4 - call the hideElements() when clicked outside the input element
There are two cases for the click outside the input element:
Case 1 - we clicked on one of the divs inside the #results wrapper
Case 2 - clicking outside the input field, but not on one of the divs inside the #results wrapper
In the first case, we will modify the assignment of the onclick handler like this:
document.querySelectorAll("#results div").forEach(setClick);
function setClick(node) {
node.addEventListener("click", setTextAndHideElements.bind(null, node.innerHTML));
}
So, the setText function now becomes setTextAndHideElements and looks like this:
function setTextAndHideElements(t) {
document.getElementById("label").innerHTML = t;
hideElements();
}
For the second case (clicking outside the input field, but not on one of the divs inside the #results wrapper), we must watch for the click on the whole page (document element), and respond to the action like this:
document.onclick = function(e) {
if (e.target.id !== 'input'){
hideElements();
}
}
Note: this will override any previously assigned onclick events assigned to the document element.
As mentioned in the beginning, working demo is >> HERE (codepen.io) <<.
I tried another solution which requires no setting of additional JS events.
See: https://jsfiddle.net/hcetz1og/4/
I gave every result item a tabindex of "0" to ensure, those items can be focusable.
Then i removed the #outer:not() part from the css and replaced the hover selector with this: #results:focus-within. Additional I called node.blur() on the node after clicking onto them.
Summary:
Change in HTML:
<div tabindex="0">Test 1 </div>
Change in JS:
function setText(t, node) {
document.getElementById("label").innerHTML = t;
node.blur();
}
Change in CSS:
#outer:focus-within #results, #results:focus-within {
visibility: visible;
}
What do you think about this one? Should be stable I think because the focus onto the #results div is set before the click event is triggered onto the result item.
Event order should be (based on my observation):
input focus -> input blur -> item focus -> item click
Not sure if the step between blur and focus can lead to a visible problem. Theoretically, the results div must be hidden and shown again in a very small amount of time.
But I investigated this with chrome's performance timeline and did not recognize a new render between both events. One can see, that the result item is focused (outline is set onto it) and then it disappears as expected.
Related
For some reason I need to use contenteditable div instead of normal text input for inputting text. (for some javascript library) It works fine until I found that when I set the contenteditable div using display: inline-block, it gives focus to the div even if I click outside the div!
I need it to be giving focus to the div only when the user clicks right onto the div but not around it. Currently, I found that when the user clicks elsewhere and then click at position that is the same row as the div, it gives focus to it.
A simple example to show the problem:
HTML:
<div class="outside">
<div class="text-input" contenteditable="true">
Input 1
</div>
<div class="text-input" contenteditable="true">
Input 2
</div>
<div class="unrelated">This is some unrelated content<br>
This is some more unrelated content
This is just some space to shows that clicking here doesn't mess with the contenteditable div
but clicking the side mess with it.
</div>
</div>
CSS:
div.outside {
margin: 30px;
}
div.text-input {
display:inline-block;
background-color: black;
color: white;
width: 300px;
}
The JSFiddle for displaying the problem
Is there a way (CSS or javascript are both acceptable) to make the browser only give focus to div when it is clicked instead of clicking the same row?
P.S. I noticed that there are similar problem (link to other related post), but the situation is a bit different and the solution provided is not working for me.
Explanation (if you don't care, skip to the Workarounds below)
When you click in an editable element, the browser places a cursor (a.k.a. insertion point) in the nearest text node that is within the clicked element, on the same line as your click. The text node may be either directly within the clicked element, or in one of its child elements. You can verify this by running the code snippet below and clicking around in the large blue box.
.container {width: auto; padding: 20px; background: cornflowerblue;}
.container * {margin: 4px; padding: 4px;}
div {width: 50%; background: gold;}
span {background: orange;}
span > span {background: gold;}
span > span > span {background: yellow;}
<div class="container" contenteditable>
text in an editable element
<div>
text in a nested div
</div>
<span><span><span>text in a deeply nested span</span></span></span></div>
Notice that you can get an insertion point by clicking above the first line or below the last. This is because the "hitbox" of these lines extends to the top and bottom of the container, respectively. Some of the other answers don't account for this!
The blue box is a <div> with the contenteditable attribute, and the inner orange/yellow boxes are nested child elements. Notice that if you click near (but not in) one of the child elements, the cursor ends up inside it, even though you clicked outside. This is not a bug. Since the element you clicked on (the blue box) is editable and the child element is part of its content, it makes sense to place the cursor in the child element if that's where the nearest text node happens to be.
The problem is that Webkit browsers (Chrome, Safari, Opera) exhibit this same behavior when contenteditable is set on the child instead of the parent. The browser shouldn't even bother looking for the nearest text node in this case since the element you actually clicked on isn't editable. But Webkit does, and if that text node happens to be in the editable child, you get a blinking cursor. I'd consider that a bug; Webkit browsers are doing this:
on click:
find nearest text node within clicked element;
if text node is editable:
add insertion point;
...when they should be doing this:
on click:
if clicked element is editable:
find nearest text node within clicked element;
add insertion point;
Block elements (such as divs) don't seem to be affected by the bug, which makes me think #GOTO 0's answer is correct in implicating text selection-- at least insofar as it seems to be governed by the same logic that controls insertion point placement. Multi-clicking outside an inline element highlights the text within it, but not so for block elements. It's probably no coincidence that you also don't get an insertion point when you click outside a block. The first workaround below makes use of this exception.
Workaround 1 (nested div)
Since blocks aren't affected by the bug, I think the best solution is to nest a div in the inline-block and make it editable instead. Inline-blocks already behave like blocks internally, so the div should have no effect on its behavior.
div.outside {
margin: 30px;
}
div.text-input {
display:inline-block;
background-color: black;
color: white;
width: 300px;
}
<div class="outside">
<div class="text-input">
<div contenteditable>
Input 1
</div>
</div>
<div class="text-input">
<div contenteditable>
Input 2
</div>
</div>
<div class="unrelated">This is some unrelated content<br>
This is some more unrelated content
This is just some space to shows that clicking here doesn't mess with the contenteditable div
but clicking the side mess with it.
</div>
</div>
Workaround 2 (invisible characters)
If you must put the contenteditable attribute on the inline-blocks, this solution will allow it. It works by surrounding the inline-blocks with invisible characters (specifically, zero-width spaces) which shield them from external clicks. (GOTO 0's answer uses the same principle, but it still had some problems last I checked).
div.outside {
margin: 30px;
}
div.text-input {
display:inline-block;
background-color: black;
color: white;
width: 300px;
white-space: normal;
}
.input-container {white-space: nowrap;}
<div class="outside">
<span class="input-container"><div class="text-input" contenteditable>
Input 1
</div></span>
<span class="input-container"><div class="text-input" contenteditable>
Input 2
</div></span>
<div class="unrelated">This is some unrelated content<br>
This is some more unrelated content
This is just some space to shows that clicking here doesn't mess with the contenteditable div
but clicking the side mess with it.
</div>
</div>
Workaround 3 (javascript)
If you absolutely can't change your markup, then this JavaScript-based solution could work as a last resort (inspired by this answer). It sets contentEditable to true when the inline-blocks are clicked, and false when they lose focus.
(function() {
var inputs = document.querySelectorAll('.text-input');
for(var i = inputs.length; i--;) {
inputs[i].addEventListener('click', function(e) {
e.target.contentEditable = true;
e.target.focus();
});
inputs[i].addEventListener('blur', function(e) {
e.target.contentEditable = false;
});
}
})();
div.outside {
margin: 30px;
}
div.text-input {
display:inline-block;
background-color: black;
color: white;
width: 300px;
}
<div class="outside">
<div class="text-input">
Input 1
</div>
<div class="text-input">
Input 2
</div>
<div class="unrelated">This is some unrelated content<br>
This is some more unrelated content
This is just some space to shows that clicking here doesn't mess with the contenteditable div
but clicking the side mess with it.
</div>
</div>
I was able to reproduce this behavior only in Chrome and Safari, suggesting that this may be a Webkit related issue.
It's hard to tell what's going on without inspecting the code but we can at least suspect that the problem lies in some faulty mechanism that triggers text selection in the browser.
For analogy, if the divs were not contenteditable, clicking in the same line of text after the last character would trigger a text selection starting at the end of the line.
The workaround is to wrap the contenteditable divs into a container element and style the container with -webkit-user-select: none to make it unselectable.
As Alex Char points out in a comment, this will not prevent a mouse click outside the container to trigger a selection at the start of the text inside it, since there is no static text between the first contenteditable div and the (selectable) ancestor container around it.
There are likely more elegant solutions, but a way to overcome this problem is to insert an invisible, nonempty span of text of zero width just before the first contenteditable div to capture the unwanted text selection.
Why non empty?: Because empty elements are ignored upon text selection.
Why zero width?: Because we don't want to see it...
Why invisible?: Because we don't want the content to be copied to the clipboard with, say Ctrl+A, Ctrl+C.
div.outside {
margin: 30px;
}
div.text-input {
display:inline-block;
background-color: black;
color: white;
width: 300px;
}
div.text-input-container {
-webkit-user-select: none;
}
.invisible {
visibility: hidden;
}
<div class="outside">
<div class="text-input-container">
<span class="invisible"></span><div class="text-input" contenteditable="true">
Input 1
</div>
<div class="text-input" contenteditable="true">
Input 2
</div>
</div>
<div class="unrelated">This is some unrelated content<br>
This is some more unrelated content
This is just some space to shows that clicking here doesn't mess with the contenteditable div
but clicking the side mess with it.
</div>
</div>
Even in normal circumstances it is generally a good idea to keep adjacent inline-block elements in a separate container rather than next to a block element (like the unrelated div) to prevent unexpected layout effects in case the order of the sibling elements changes.
If it's not needed to use display: inline-block, I would recommend using float. Here is the example.
Based on your example, the new CSS would be:
div.text-input {
display: block;
background-color: black;
color: white;
width: 300px;
float: left;
margin-right: 10px;
}
div.unrelated {
clear: both;
}
Disable text selection in container... should fix that.
For example:
* {
-ms-user-select: none; /* IE 10+ */
-moz-user-select: -moz-none;
-khtml-user-select: none;
-webkit-user-select: none;
user-select: none;
}
How about a little jQuery?
$(".outside").click(function(e){
$(e.target).siblings(".text-input").blur();
window.getSelection().removeAllRanges();
});
And if IRL you need to account for clicks on contenteditable=true siblings' children:
$(".outside").click(function(e){
if ($(e.target).siblings(".text-input").length != 0){
$(e.target).siblings(".text-input").blur();
window.getSelection().removeAllRanges();
}
else {
$(e.target).parentsUntil(".outside").last().siblings(".text-input").blur();
window.getSelection().removeAllRanges();
}
});
window.getSelection().removeAllRanges();"The trick is to remove all ranges after calling blur"
I am trying to hide a popup (implemented as a "ul") when the user clicks on it.
This popup is only made visible when its parent node detects the mouse :hover.
In my onclick() handler, I call blur() on every conceivable node above the DOM element I pass to my onclick() handler and it's not hiding the popup.
Here's the code:
// the html....
<ul class="ul_nestedPopups">
<li>Breakfast choices
<ul class="ul_nestedPopups">
<li>Apple</li>
<li>Orange</li>
<li>Banana</li>
</ul>
</li>
</ul>
.ul_nestedPopups {
display: inline-table;
}
// I tried using visibility instead of display -- no real difference
.ul_nestedPopups ul {
/*visibility: hidden;*/
display: none;
}
.ul_nestedPopups li:hover > ul {
/*visibility: visible;*/
/*visibility: visible !important;*/
/*display: block !important;*/
display: block;
}
// onclick handler......
function setBreakfast(theNestedAnchor)
{
// yes I experimented
theNestedAnchor.blur();
theNestedAnchor.parentNode.blur();
theNestedAnchor.parentNode.parentNode.blur();
theNestedAnchor.parentNode.parentNode.parentNode.blur();
theNestedAnchor.parentNode.parentNode.parentNode.parentNode.blur();
// NOW, DO SOMETHING WITH THE USER'S CHOSEN POPUP HERE...
// ........some code.........
}
The way it currently works: When the user hovers the mouse over the "Breakfast choices" list item, the list with the three breakfast choices (unordered list with 3 list items) appears. When the user clicks one of the 3 breakfast choices Apple, or Orange, or Banana -- I have verified that the onclick() handler gets called, but the onblur() calls there do nothing -- the 3 breakfast choices UL stays visible.
So I'm guessing the blur() might get ignored because when the user clicks the mouse on the popup, the mouse is still hovering so the onclick handler's attempt to call blur() is ignored.
So I thought about structuring the onclick handler this way but don't think it will work and I suspect that there's a better/easier way:
// onclick handler......
function setBreakfast(theNestedAnchor)
{
1. change the class to a different class that has no :hover selector
2. then call blur() to make the popup disappear
3. then change the class back to the original one with the :hover selector
to re-enable the :hover behavior for next time
}
Is there an easier/better way to make the popup that appears on :hover -- disappear
when the user clicks on it?
The hover event is for when you want something to happen on mouseover, and then to un-happen on mouseout. Correct me if I have this wrong, but what you are describing is to open the popup on mouseover, then close it when it is clicked. So you don't care about mouseout, so you do not want to be using hover.
I think you want this. See fiddle: http://jsfiddle.net/DLYwV/
You'll prob want to restyle to fit your needs, but the logic is all here.
HTML
<div id='hoverOver' onMouseOver='showPopup();'>Hover over me to open the popup</div>
<div id='popup'><br>I'm a popup.<br>Click
<a href=javascript:closePopup();>here</a>
to close.</div>
JS
function showPopup()
{
document.getElementById('popup').style.visibility='visible';
}
function closePopup()
{
document.getElementById('popup').style.visibility='hidden';
}
CSS
#hoverOver{
display:inline-block;
background:red;
}
#popup{
visibility:hidden;
position:absolute;
top:0;
background:white;
height:200px;
width:400px;
border:2px solid black;
}
I am implementing this effect with HTML, bootstrap2, and JS.
Sorry I don't have a working example yet, and did not find an example could demo anywhere, so I will just describe what I want to do in detail.
It is a plain HTML page visually contains two "cards" aligned vertically. The card could be just a div contains a textbox and a button. Initially only one card is visible and the other one is hidden, and I hope the page size fits only one card. After I click the button on card 1, the page hight should get greater to fit in two cards, and card two shows up.
My uncertain part would be: How do I hide a div initially and show it by clicking a button? (I want the page size fits any number of cards) I am not too familiar with web development, so a working example will be very helpful!
Thank you!
Here is a nice example I have just cooked up.
You should already have your HTML & CSS set up, but here is what I used.
HTML
<!-- Card 1 -->
<div>
<textarea></textarea>
<button id="clickMe">Show second card</button>
</div>
<!-- Card 2 -->
<div style="display: none;" id="newCard">
<textarea></textarea>
<button>Do nothing</button>
</div>
CSS:
div{ /* A bit of random styling */
box-sizing: border-box;
width: 70%;
margin: 30px 15%;
background: skyblue;
border: 2px solid #EEE;
text-align:center;
padding: 50px;
}
Vanilla Javascript
var button = document.getElementById('clickMe'); // 1
var newCard = document.getElementById('newCard'); // 2
button.addEventListener('click', function() { // 3
newCard.style.display = 'block'; // 4
});
INFO
Get the element that has a ID of clickMe
Get the element that has a ID of newCard
Listen for when the clickMe element is clicked
When clickMe is clicked set the display of newCard to block
Working Demo: http://jsfiddle.net/T4yxz/
You could rely jQuery to show/hide elements. Set a div element to hidden and onclick event of a button should hide/show your elements.
Take a look at jQuery's api:
http://api.jquery.com/show/
http://api.jquery.com/hide/
http://api.jquery.com/toggle/
Simple example:
http://jsfiddle.net/mrkre/KKLZ4/
$('#HideHidden').click(function() {
$(".hidden-div").hide();
});
$('#ShowHidden').click(function() {
$(".hidden-div").show();
});
You would then need to manipulate the css for height elements.
On Page load you start out with the div hidden, by setting the css styling for that element as display:none. When you want to show that element, add a .show() event to the button click function.
There is the following code:
<div id="main">
<div id="first">
First item
</div>
<div id="second">
Second item
</div>
<div id="third">
Third item
</div>
</div>
CSS styles:
#first {
background-color: yellow;
}
#second {
background-color: blue;
}
#third {
background-color: green;
}
html, body, #main, #first, #second, #third {
height: 100%;
}
There are 3 div in main div and user scrolls in order to go to the bottom of the screen. I want to do the following thing: when user scrolls with mousewheel the first time he goes to "second" div, the second time - "third" div. This feature has been realized on the following site: some site. Please, tell me some advice. Thanks.
Living demo: http://jsfiddle.net/xz2DN/1/
Update for IE: http://jsfiddle.net/xz2DN/6/
(html element is scrolled, as the body contains the css property overflow:hidden which makes it impossible to scroll for IE)
You need to:
Disable the scrolling bar on the site
Detect the mousewheel event (not working in old browsers)
Have knowledge of which section are you in before scrolling up or down
Update that status once you move from one to another section
You could try to look for each of this points by separate and you will get it working :)
Disabling scrolling bar and default scrolling
body,html{
overflow:hidden;
}
Detecting mouse wheel:
http://www.sitepoint.com/html5-javascript-mouse-wheel/
Having knowledge of which section are we in
I would recommend you to create an array with a pair of values id, status. The id would be the id tag of the current section and the status would indicate you if is the current "slide"/section or not.
You could do something like this:
var sections = {};
var numberSections = 0;
$('.section').each(function(index, element){
//current slide is active
if(!index){
sections[$(this).attr('id')] = 1;
}
else{
sections[$(this).attr('id')] = 0;
}
numberSections++;
});
And then you should define two functions, one to move update the status of the array when the user scrolls up, and the other for the case in which they scroll down.
I have a calendar, and when the user hovers over a cell, a large-ish info box appears with details for that date. I am having some trouble though making the info box disappear when the user moves away.
I basically want it so that when the mouse cursor moves out of the calendar cell which is hidden by the info box it will disappear. But I'm having trouble with this because mouseenter and mouseleave get messed up by having the info box as the top element.
So I tried to get around this by using "placeholder" divs that are transparent, have the same shape and location as the calendar cell beneath it, and have a z-index of 1000 so they are above the info box. I then apply the mouseenter and mouseleave events to these divs instead.
There's two problems with this though. One, I have now messed up my HTML semantically. The divs have no purpose but to get around what seems to be a limitation. And secondly, they mess up my jQuery UI selection (I've applied it to the calendar cells - a click no longer selects a cell).
Is there a clean way to handle displaying an info box? There will be no user interaction with the info box -- it's just to display information.
EDIT: Here is some code:
<li>
<div class="day-content">
</div>
<div class="day-content-placeholder">
</div>
</li>
and CSS
li
{ position: absolute; width: 15%; height: 20%; top: ... left: ... }
.day-content
{ position: absolute; width: 100%; height: 100%; }
.day-content-placeholder
{ position: absolute; width: 100%; height: 100%; z-index: 1000; }
.popup
{ position: absolute; width: 300%; height: 300%; left: -150%; top: -150%; z-index: 500; }
and Javascript
var popup;
$('.week-content-placeholder')
.mouseenter(function()
{
popup = $('<div class="popup">'+a_lot_of_text+'</div>').insertAfter(this);
})
.mouseleave(function()
{
popup.remove();
});
That's not the exact code, but you get the idea. This works okay, but like I said, since .week-content-placeholder is above .week-content, the selection capability with jQuery UI doesn't work properly on .week-content.
You could modify your solution with the transparent "placeholder" divs in the following way:
Have the "placeholder" dive underneath the "calendar cell", using {zIndex: -1}.
When you enter a calendar cell, unhide the large "content" div and set {zIndex: 1000} on the "placeholder" div to bring it to the top.
Have a "mouseout" event on the placeholder div that will hide the "content" div and set {zIndex: -1} for the the "placeholder" cell.
Rather than create the "placeholder" cells in the HTML, you could create one in the javascript and move it to the postion of each "calendar" cell as you "mouseIn" it. You could also duplicate any "click" events on the "calendar cell" onto this one as well.
Let me know if this works.
The trick here is to make the info box a child of the cell:
<div id='box'>
Normal content
<div id='inner'>
This big box obscures everything in the cell!
</div>
</div>
The inner box is hidden until the hover occurs. Notice how with CSS we can make the box bigger than the cell itself with negative margins.
#box
{
width:100px;
height:100px;
margin:100px;
border:solid 2px darkblue;
position:relative;
}
#box #inner
{
display:none;
position:absolute;
background-color:#eeee00;
top:-10px;
left:-10px;
width:120px;
height:120px;
}
And you can use normal jquery hover because the hover covers box the box and it's child:
$('#box').hover(function(){
$('#inner').show();
},function(){
$('#inner').hide();
});
Here's it running:
http://jsfiddle.net/RbqCT/
You can create the info box dynamically as you do in your code.
Here's 15 different plugins that let you do this with jquery:
http://www.webdesignbooth.com/15-jquery-plugins-to-create-an-user-friendly-tooltip/
You could track mousemouse and use the offsetLeft + width and offsetTop + height of your hover trigger against the event.pageX and event.pageY to compare.
If you make this work as you described a tiny mouse movement that remains within the calendar cell (which is not even visible) leaves the popup in place, but a slightly larger movement that exits the cell makes the popup disappear.
The user sees only movement within the popup itself — small movement within the popup leaves it in place; large movement makes it go away.
I suggest triggering the disappearance of the popup on exiting the popup div itself. Any movement that remains within the "tip" panel leaves it up. I think that (1) this is better usability and (2) it avoids the whole problem with the obscured calendar cell event handling.
You could do that by adding a .mouseleave() handler to the div when you create it.