I have this demo
However the mouse over when dragged to left or right stops the toogle.
The hover() event didn't solve the problem.
Any idea ?
div.fileinputs {
position: relative;
display: none;
}
#show {
width: 200px;
height: 40px;
background-color: red;
z-index: -2px;
position: absolute;
}
<div id="show"></div>
<div class="fileinputs">Visible Panel Div</div>
$('#show').mouseover(function() {
$('.fileinputs').toggle();
});
Given that you want to simply show the element on mouseover and then hide it on mouseout, you should also use mouseout() to define the desired behavior you want when the mouse is removed:
$("#show")
.mouseover(function(){
$(".fileinputs").toggle();
})
.mouseout(function(){
$(".fileinputs").toggle();
});
Example. (It's choppy because fileinputs is a separate element, and it's not counting hovering over that as hovering over the show div).
But you should use hover, just to make it easier:
$("#show").hover(function(){
$(".fileinputs").show();
}, function(){
$(".fileinputs").hide();
});
Example. (Choppy for the same reason as above).
Since your desired behavior is definite, we'll just use show() for when the mouse is over it and hide() when it is removed.
By the way, it is preferred that you bind events using delegate() (for older versions of jQuery) or on() (for jQuery 1.7+):
$(document).on("mouseover mouseout", "#show", function(){
$(".fileinputs").toggle();
});
Example.
Though, you really should just use CSS for this. You can place fileinputs inside of show and use a child selector:
#show:hover > .fileinputs {
display: block;
}
Example. This one doesn't flicker because the element is inside the one that's getting the hover declarations attached to it, and CSS considers it as though you are still hovering over the parent element (because you technically are, as the target of the hover is within the boundaries of the parent [it would still work if it was outside the boundaries because the element is still nested]).
I think it's because you set your z-index on show to be -2. Once the fileInputs div is visible, it becomes on top of show, and as a result, mouseover for show no longer responds.
If you notice, if you hover from left to right over the red show div, but just below where the text is, the fileinputs div does in fact toggle.
If you add a border around the fileinputs div, the cause of the behavior will be clearer.
See: http://jsfiddle.net/pS9L8/
Moving your cursor over the region where the two divs overlap triggers a mouseover event, showing the hidden fileinputs div. Since that div is now displayed on top of show, your cursor is no longer directly over the original show div. You then continue to move your cursor, and as it moves outside the fileinputs region, that move is seen as another entrance to the underlying show div. Which again triggers the .toggle(), re-hiding the fileinputs div.
One quick fix is to switch to the jQuery custom event mouseEnter instead of mouseover (although you may get some jerky artifacts as jQuery reasons about the meaning of "over"). Depending on what you're trying to achieve, another option would be to reorder the two divs by z-index.
Related
Using the Google Chrome browser, I need to drag-and-drop an item from a menu, in a way so that the menu will automatically close/hide/collapse/disappear/(or something similar) as soon as the dragstart event fires. This has to be done in a way such that the DOM space is freed up, so approaches using "visibility" and "opacity" for instance while possible are not good for this situation.
Instead, it is necessary to do something like display:none or pushing the menu off of the web page (without scrollbar). However, I've gotten stuck trying to accomplish this and could use some help (or if an alternative approach comes to mind that accomplishes the same, please let me know. I also tried a z-index approach without success.):
Approach 1 - Trying to hide dragged item's parent element via absolute positioning
https://jsfiddle.net/gratiafide/4m5r186v/
function dragstart_handler(ev) {
ev.dataTransfer.setData("text/plain", ev.target.id);
ev.currentTarget.parentElement.style.cssText = "position:absolute; right:-5000px;";
}
Approach 2 - Trying to hide dragged item's parent via setting display:none
https://jsfiddle.net/gratiafide/Luj7d089/
function drag(event) {
event.dataTransfer.setData("Text", event.target.id);
document.getElementById('parent').style.display = 'none';
}
You will see in both approaches, the dragged item gets dropped in both instances as soon as the CSS rule gets applied to the dragged item's parent element. I just want to be able to keep dragging the element even though I've hidden or moved the parent element out of sight. Thanks in advance for your help!
You seem to want your parents to disappear by dragging your child's element as it is.
The child element is influenced by the CSS style attribute of the parent element. If parents are erased through css properties such as "display", "visibility", and "opacity", the child element is not visible unconditionally.
Hiding using the "absolute" property(but not z-index -1) is also a way, but unwanted scrollbars may occur depending on the "overflow" attribute of the parent element, and the child element position must be added in reverse and recalculated.
As a result of my test, a dragend event occurred in Chrome when the parent element of the element to be dragged was redrawn. But in Firefox, both of your examples work.
Anyway, to explain based on how it works in Chrome, it is to separate the relationship between Child and Parent and use it as a sibling. Modify your HTML as follows.
<div id='relative_div'>
<div id="parent"></div>
<p id="source" ondragstart="dragstart_handler(event);" draggable="true">Drag me to the Drop Zone below</p>
</div>
Next update your CSS as follows. #parent should serve as a background for filling in #relative_div.
#relative_div {
position: relative;
overflow: hidden;
width: 200px;
height: 100px;
padding: 2em;
}
#parent {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
background-color: lightgrey;
}
#source {
position: relative;
cursor: grab;
color: blue;
border: 1px solid black;
}
Now, regardless of whether you use #parent's "position" to push it away, or hide it using "display", "opaicty", or "visibility", #source drag does not stop.
ok, I think my comment was wrong and that you want to remove the space on the page occupied by the origin element (rather than freeing up memory).
To achieve this, add document.body.removeChild(document.getElementById('parent')); to your drop handler. I've made a js fiddle to demonstrate (with the id=spacer div removed and an extra paragraph below it to show the element is removed):
https://jsfiddle.net/dj825rbo/
(revision following comment clarifying that the origin element should disappear as the drag begins)
This is horrible, but works (horrible because you can't see the text while it is being dragged). It relies on a hidden element into which the origin's content is stored while the drag is proceeding. Replacing the 'drop' event listener with a 'mouseup' listeners, allows the content of the temp (hidden element to be transferred to the target where the mouse click was released)
https://jsfiddle.net/dj825rbo/1/
I wish to have two slimscrolled div and be able to drag and drop elements between them. The latter is tested, and is working perfectly with the sortable method, but when I apply the slimscrolls, the two divs receive the overflow: hidden attribute, which makes the dragged elements disappear when moved outside of the div. As per documentation I saw no option to modify the slimscroll's overflow attribute, which I would like to change to overflow-x: visible and overflow-y: hidden, for obvious reasons. The CSS attribute is applied on element level, so workaround with CSS rules are not an option afaik.
I want the slimscroll to be functional, but I want to be able to drag and drop elements between the two slimscrolled divs. How to proceed?
EDIT
In hope of receiving answer I add a code example:
<div id="container1">
<ul><li>...</li></ul>
</div>
<div id="container2">
<ul><li>...</li></ul>
</div>
<script>
$('#container1').slimScroll({...});
$('#container2').slimScroll({...});
$('#container1').sortable({
connectWith: "#container2",
});
</script>
In the above example, elements from #container1 should be dragged to #container2, but due to the overflow:hidden property applied by the slimScroll(), the dragged element will disappear when dragged outside of the area of #container1. I wish to be able to drag the element and also see the element I am dragging.
The issue was a setting in jquery.slimscroll.js. In v1.3.8 starting from the 160th line I did the following;
// wrap content
var wrapper = $(divS)
.addClass(o.wrapperClass)
.css({
position: 'relative',
overflow: 'visible', // <--- change this from 'hidden' to 'visible' !!!
width: o.width,
height: o.height
});
After applying the above change, the problem I described ceased to exist.
I have to use more than one tooltip inside a small div element.
Moreover, since this div is "overflow: auto", Popper.js automatically forces the tooltip to keep inside that element.
When this is the case, the tooltip opens on the element and since there is a cursor there, it falls into a vicious circle, opening and closing tens of times a second.
After the tooltip is opened, I want it to stay open even if we move the cursor on it.
Is there a settings or hack for this?
Add to the tooltip pointer-events: none; css rule, like
.tooltip {
pointer-events: none;
}
This will prevent tooltip from being target for mouse events and will resolve the issue.
Consider a simple element, and its associated CSS:
<div id="content">Hover me !</div>
#content {
width: 100px;
height: 100px;
}
#content:hover {
transform: translateY(500px);
transition: transform 1s 500ms;
}
JSFiddle
The principle is straightforward: while the element is hovered, it must go down. The problem is, when the mouse doesn't move, that the :hover state is maintained even if the element is not physically below the mouse anymore (due to the translation). The state seems to be updated only after an mouse move.
Notice the cursor (a pointer) and its relative position with the element!
That's a real problem when a JavaScript function must be executed only if the mouse is on an element, after a timeout:
// The mouseleave event will not be called during the transition,
// unless the mouse move !
element.on('mouseenter', executeAfterTimeout);
element.on('mouseleave', cancelTimeout);
So here are my questions:
Is this behaviour normal (compliant with the norms)?
What are the solutions to avoid this problem?
Edit : To give you a context, here is what I want to do concretely: with JavaScript, I display a tooltip when the mouse is on an element (and hide it when the mouse leaves it). But the same element can be transform-ed when the user click on it. If the user simply clicks without moving the mouse, the tooltip will remain displayed, which is a real problem. How can I detect that the element is gone?
Part 1 of your question:
The principle is straightforward: while the element is hovered, it
must go down. The problem is, when the mouse doesn't move, that the
:hover state is maintained even if the element is not physically below
the mouse anymore (due to the translation). The state seems to be
updated only after an mouse move.
So here are my questions:
Is this behaviour normal (compliant with the norms)?
Yes. This behaviour is normal. Although not specified verbatim in the standards, it is mentioned in detail here: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105
Take this fiddle as reference: http://jsfiddle.net/Blackhole/h7tb9/3/
The upper div has mouse-events bound to it directly. The lower div has mouse-event bound to its parent. Pick up the lower one. Move the mouse slowly at one edge and watch the console to see what happens.
You touch the edge and mouseover and mouseenter are fired in quick succession (hover).
As a result the inner div translates.
Do nothing. No event is fired and so nothing happens.
Move the mouse inside the outer div. mousemove fires and the inner div is still translated.
Slowly move the mouse out. mouseout and mouseleave are fired in quick succession and the inner div translates back to its original position.
This is described here: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#events-mouseevents under the section Mouse Event Order.
Step 3 above is important. Because you are doing nothing, no event is fired and hence nothing happens. If the inner div were to bounce back to its original position in this step, then it would mean that an activation happened without any event!
This is in line with the definition of event as the document in this section: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#glossary-event says:
An event is the representation of some occurrence (such as a mouse
click on the presentation of an element, the removal of child node
from an element, or any number of other possibilities) which is
associated with its event target. Each event is an instantiation of
one specific event type.
Now have a look at the document here: http://www.w3.org/TR/2013/WD-DOM-Level-3-Events-20131105/#event-flow, just before the section 3.2 starts, it says:
After an event completes all the phases of its propagation path, its
Event.currentTarget must be set to null and the Event.eventPhase must
be set to 0 (NONE). All other attributes of the Event (or interface
derived from Event) are unchanged (including the Event.target
attribute, which must continue to reference the event target).
The last line (in parentheses) is important. The event.target continues to reference the event target even after the event completes.
Now pick the upper div in the fiddle for reference. On mouseenter the div itself is translated. It does not matter if it moves away from below the mouse pointer. The event.target is still referencing to it and if no other mouse event occurs, nothing happens and it remains translated. The moment you move your mouse (anywhere in or out), the activation occurs on the event.target (which is still this div) and now the user-agent finds that the mouse pointer is no longer over the element and immediately mouseout and mouseleave events fire (after firing mousemove of course) causing the div to translate back.
Part 2 of your question:
2.What are the solutions to avoid this problem?
Edit : To give you a context, here is what I want to do concretely:
with JavaScript, I display a tooltip when the mouse is on an element
(and hide it when the mouse leaves it). But the same element can be
transform-ed when the user click on it. If the user simply clicks
without moving the mouse, the tooltip will remain displayed, which is
a real problem. How can I detect that the element is gone?
If you look at the implementation in the lower div in this fiddle: http://jsfiddle.net/abhitalks/h7tb9/2/ ; as compared to the upper div, there is no flutter/jitter when mousing over. This is because rather than the div itself, the events are being handled on the parent.
So, that could be one solution for your use case.
See this demo: http://jsfiddle.net/Blackhole/nR8t9/9/
This addresses your edit. Tooltip gets displayed on mouseover. Tooltip gets hidden on mouseleave. The same element can be transform-ed when you click. If you simply click without moving the mouse, the tooltip hides.
Here, if you click, the element is being translated and then no further hover action would happen. The tooltip itself is implemented using a :before pseudo-element. This separates out the tooltip and the element which you want to change after click. You still handle events on the element itself. No need for timeout as it is handled by the css itself. If you mouseout, the tooltip will hide after a delay.
Hope that helps.
It's a solution to use JavaScript and a class to indicate the status. In your case, you could use mouseover event to toggle a class like this:
$('#content').on('mouseover', function() {
$(this).toggleClass('down');
});
CSS
#content.down {
background-color: deepskyblue;
transform:translateY(300px);
-webkit-transform: translateY(300px);
}
jsFiddle
The other solution is to use a wrapper as hover block
<div id="container">
<div id="wrapper">
<div id="content">Hover me !</div>
</div>
</div>
CSS
#wrapper:hover #content {
background-color: deepskyblue;
transform:translateY(300px);
-webkit-transform: translateY(300px);
}
jsFiddle
Notice, this two solutions have different behaviors for different requirements.
My suggestion is to look at this problem another way: if an element is going to be transitioned when you click on it. Why not just execute your callback on click instead of mouseleave?
I am assuming the tooltip has some connection to the element you mouseenter, in which case mouseleave and click are effectively the same - they both cause mouse pointer to not be over the element anymore (regardless of how browser behaves).
PS: note that in your example, how mouseenter and mouseleave fire also depends on whether you set the transition as default property or as a :hover state property, since this looks like an area where browser vendors are free to optimize as they please, you should probably avoid they in the first place.
http://jsfiddle.net/U44Zf/13/ - transition on #content:hover
http://jsfiddle.net/U44Zf/14/ - transition on #content
This behavior is normal to prevent the element from bouncing under the cursor. Imagine the transition would revert as soon as the element is away from the cursor. As soon as the cursor has left the element, it would go back, so the cursor is again above the element and it moves down. This way it would bounce up and down at the edge of the cursor.
One solution would be to implement the transition with JavaScript instead of CSS, then the element will "bounce". But is this really the desired behavior? What exactly are you trying to do?
This behavior is normal and can not be changed. It is correctly implemented according to the specification #Stasik linked to.
If you have to change this behavior, you could use javascript with jquery instead of css pseudo classes. I created a jsfiddle to demonstrate a possible approach using the .ismouseover() jQuery extension by #Ivan Castellanos provided here.
Check if this is the behaviour you want to accomplish. Some are example styles, adjust as you please.
http://jsfiddle.net/U44Zf/9/
.tooltip {
background-color: white;
border: 1px solid black;
padding: 10px;
opacity: 0;
transition: 1s 500ms;
transition-property: transform, opacity;
position: absolute;
right: 0;
top: 0;
}
#content:hover .tooltip {
display: block;
opacity: 1;
transform:translateX(100px);
-webkit-transform: translateX(100px);
}
#content {
transition: 1s 500ms;
transition-property: background-color, color;
cursor: pointer;
position: relative;
}
#content.active {
background-color: blue;
color: white;
}
#content.active .tooltip {
opacity: 0;
transform: none;
-webkit-transform: none;
}
I've added this javascript snippet to control the click state
$('#content').click(function () {
$(this).toggleClass('active');
});
I just saw a demo that had this jquery code to show and hide a dive on hover, can't this be done with just regualr css though? And if you can do it with css is there any advantage of doing it with javascript?
$('.comment').hover(function() {
$(this).children('.delete').show();
}, function() {
$(this).children('.delete').hide();
});
CSS hover works fine with anchor tags, but IE6 does not recognize hover events on things like li tags.
If you were using an anchor tag, however, you could achieve the same effect in CSS:
a.comment .delete { display: none; }
a.comment:hover .delete { display: block; }
You can do this with CSS but IE6 only supports the :hover pseudo-class on anchor tags (A), so it's not as common.
Jody is correct. Check out the docs for the CSS Display property.
There is more functionality that the .hover will do. If you provide it more than 2 functions it will cycle through all the functions.
Example
$('.comment').hover(
function(){$(this).children('.delete.first').show()},
function(){$(this).children('.delete.first').hide()},
function(){$(this).children('.delete.second').show()},
function(){$(this).children('.delete.second').hide()}
);
That would show one set of children the first time they hover, then hide, and the next time show a different set of children.
The hover function also works over multiple elements, and only fires if the mouse has left all the elements (not just when it leaves one and moves to another)
I dynamically create something like this on the server side. I'm sure there is a more efficient/prettier way but this usually serves my needs. Basically hides all the divs and un-hides the one that needs to be shown (passed as arg in function from onClick event).
function toggleTab(id)
{
document.getElementById('divEnrollment').style.display='none';
document.getElementById('divSearch').style.display='none';
document.getElementById('divMeeting').style.display='none';
document.getElementById('divBenefit').style.display='none';
document.getElementById('div' + id).style.display='block';
document.getElementById('spnEnrollment').style.color='blue';
document.getElementById('spnSearch').style.color='blue';
document.getElementById('spnMeeting').style.color='blue';
document.getElementById('spnBenefit').style.color='blue';
document.getElementById('spn'+id).style.color = 'red';
}