jQuery .is(":hover") In IE8 - javascript

I am having an issue checking the state of a div in IE8. I want to check if the mouse is currently hovering over some divs or not. Currently in IE8, I get the following error: Syntax error, unrecognized expression: hover. Below is the jQuery that is causing the error:
// This function will close the slideout of widgets
function CloseWidgetPanel()
{
if (!$("#widgets").is(":hover") && !$(".widgetPanel").is(":hover"))
{
if ($("#widgets").is(":animated"))
{
$("#widgets").stop(true, true);
}
$("#widgets").hide("slide", { direction: "right" }, 300);
}
else
{
// We are currently hovering over a panel, so check back in 2 seconds.
setTimeout(CloseWidgetPanel, 2000);
}
}

Alternative way:
$(".widgetPanel, #widgets").hover(function() {
$(this).toggleClass('hover')
});
Then:
if (!$("#widgets").is(":hover") && !$(".widgetPanel").is(":hover"))
change to
if (!$("#widgets").hasClass('hover') && !$(".widgetPanel").hasClass('hover'))

jQuery does not implement the :hover selector and IE8 doesn't support queryselectorall, therefore it fails. You'll have to find another way to detect that the element is currently being hovered over such as a mouseenter and leave event that sets a global (or parent scope) variable or applies a state class/attribute to the element.

Related

jQuery toggle custom animation

How can I make a custom animation?
$('button').toggle(function() {
anim.go("fadeOut slow", $("mydiv"));
}, function() {
anim.go("fadeIn slow", $("mydiv"));
});
Toggle is working, but first appears toggle animation, then mine. How can I disable default toggle anim? Like toggle(0) P.S I've tried to add 0 to my code, but then second function isn't working. Any ideas?
Your issue is because in the modern versions of jQuery toggle() no longer works in the manner you've used, ie. two separate functions called alternately.
Instead you'll need to use click(), check the visibility state of the element and then run the required animation based on that, eg:
$('button').click(function() {
var $div = $('#mydiv');
var action = $div.is(':visible') ? 'fadeOut' : 'fadeIn';
anim.go(action + " slow", $div);
});

if condition checking two selectors for hover, if hover, text line underline

Simplified update, nevermind using a variable. (original question was using one selector as a variable and doing this)
Essentially why will below not work.
Note:: When not declaring || aka second selector this worked fine. But then what it does is doesn't allow the once css natural :hover method on the text, so that is why I'm trying to add the second selector here in the first place. I need to hover an image, and the see the corresponding text link hover, and I also need to maintain hovering over corresponding text link alone to have the hover underline effect. Any suggestions as how to get here if this cannot done with CSS / sass nor using :hover in jQuery as a stable option?
setInterval(function(){
if $("#t1").is(":hover") || $(".thumba").is(":hover")) {
$(".thumba").css("text-decoration", "underline");
}
else {
$(".thumba").css("text-decoration", "none");
}
}, 200);
setInterval(function(){
if $("#t2").is(":hover")) || $(".thumbb").is(":hover")) {
$(".thumbb").css("text-decoration", "underline");
}
else {
$(".thumbb").css("text-decoration", "none");
}
}, 200);
Another example:
You have an image, say image a.)
<img src="[ image a ]">
then you have a paragraph with some text:
<div>blahblahloremipsum clickhere blachhhhhhh</div>
I want to hover over image a and allow click here to have an underline, I would like to 'hover out' and the underline to go away. I would also like this not only on the image but as standard with the text link, basically if you hover over click here and not the image it still will underline.
Another attempt: (but here the underline doesn't unattach after mouse is no longer hover)
$(document).mousemove(function() {
if($('#t1').is(':hover') || $('.thumba').is(':hover')) {
$('.thumba').css({'text-decoration':'underline'});
}
else {
$('.thumba').css({'text-decoration':'none'});
}
});
$(document).mousemove(function() {
if($('#t2').is(':hover') || $('.thumbb').is(':hover')) {
$('.thumbb').css({'text-decoration':'underline'});
}
else {
$('.thumbb').css({'text-decoration':'none'});
}
});
take a look: here (link below) it describes using it if ONE instance, this is why it's likely failing for me and is not the solution; but I don't see a solution on this thread for multiple. "(This only works when the selector matches only 1 element though - See Edit 3 for more)"
Detect IF hovering over element with jQuery
You need to add another parenthesis at the end, as well as remove one after the first condition:
if($thumbone.is(":hover") || $('.thumba').is(":hover")) {
And you might want to refer to this question for checking for hover:
Jquery condition check is(':hover') not working
You can achieve the underline on hover effect on the text link just using CSS:
.thumbb:hover,.thumbb-hover {text-decoration:underline;}
Then you detect the mouseenter and mouseleave events on the images:
$('#t1,#t2')
.on('mouseenter', function() {
$('.thumbb').addClass('thumbb-hover');
})
.on('mouseleave', function() {
$('.thumbb').removeClass('thumbb-hover');
});
Here's a working fiddle. And here's a fiddle with two images
A.O. is right, check the parenthesis. Also, everytime I use jquery on html classes, I make sure I grab the first one. It is the default functionality, but it's always nice to explicitly declare it.
if($thumbone.is(":hover") || $('.thumba').first().is(":hover")) {

use intro.js on bootstrap dropdown element

I cannot figure out how to use intro.js on dropdown elements.
I found a similar question with no answer there: IntroJS Bootstrap Menu doesnt work
If you want to reproduce the error, follow these steps:
http://recherche.utilitaire.melard.fr/#/carto
You have to click on "Aide" (The green button on the top right), the problem occurs for the second step. on the change event, I do:
$scope.ChangeEvent = function (e) {
if (e.id === 'step2') {
document.getElementById('step1').click();
}
console.log("Change Event called");
};
When debugging, everything is working like a charm until that function end: _showElement
After that, I get lost in JQuery events, and the dropdown is closed...
If you want to reproduce, just add a breakpoint at the end of the _showElement function and you will understand what I mean...
Here a clearer solution
function startIntro(){
var intro = introJs();
intro.setOptions({
steps: [
{
element: "#mydropdown",
intro: "This is a dropdown"
},
{
element: '#mydropdownoption',
intro: "This is an option within a dropdown.",
position: 'bottom'
},
]
});
intro.onbeforechange(function(element) {
if (this._currentStep === 1) {
setTimeout(function() {
$("#mydropdown").addClass("open");
});
}
});
intro.start();
};
$(document).ready(function() {
setTimeout(startIntro,1500);
});
Note the setTimeout with no second argument (milliseconds) allows you to queue the function on event loop and run it after all events were processed (including the click closing the dropdown), also, it is better to add the class open to the dropdown if you want to set it to open state
In your template i.e. in
/views/nav/body-create.html
You have a code where ng-disabled is based on !currentPath.name. And the value of currentPath.name is null. Try inspecting the value on the following element. You will see that it is null.
<button class="dropdown-toggle btn btn-sm btn-default no-radius" ng-disabled="!currentPath.name">
Niveau{{currentPath.level?": "+currentPath.level:""}} <strong><b class="caret"></b>
</strong>
</button>
Make sure you have proper name or use different condition - I am not sure what you are trying to do with the condition.
Proof: Inspect the above element in chrome debugger at your recherche.utilitaire.melard.fr/#/carto link. Type the following in console and hit enter.
$scope.currentPath.name='Hello You';
And your "Niveau" menu starts working.
I found a workaround, it's quite ugly, but does the job:
$scope.ChangeEvent = function (e) {
if (e.id === 'step2') {
document.getElementById('step1').click();
setTimeout(function () {
document.getElementById('step2').style.display = 'block';
}, 500);
}
console.log("Change Event called");
};
I set the display attribute to block just after the click event I added in the change event
When clicking executing the click on the element 1, I noticed that jquery set the state of the style.display of the element 2 to '', so I wait a bit after clicking in order to set it back to 'block', I know it's ugly, but I didn't find anything better at the time
This happens because of the fixed position..
By using CSS, change the position for the parent item from fixed to absolute and it works perfectly.
For example:
position of .sidebar is fixed, leave it like that.
change position for .sidebar.introjs-fixParent to absolute.
Hope it helps you

Firefox firing dragleave when dragging over text

I'm attempting to track a dragenter/leave for the entire screen, which is so far working fine in Chrome/Safari, courtesy of the draghover plugin from https://stackoverflow.com/a/10310815/698289 as in:
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
self.on('dragenter', function(e) {
if (collection.size() === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(e.target);
});
self.on('dragleave drop', function(e) {
// timeout is needed because Firefox 3.6 fires the dragleave event on
// the previous element before firing dragenter on the next one
setTimeout( function() {
collection = collection.not(e.target);
if (collection.size() === 0) {
self.trigger('draghoverend');
}
}, 1);
});
});
};
function setText(text) {
$('p.target').text(text);
}
$(document).ready(function() {
$(window).draghover().on({
'draghoverstart': function() {
setText('enter');
},
'draghoverend': function() {
setText('leave');
}
});
});
However Firefox is still giving me problems when I drag over text items, here's a fiddle to demonstrate: http://jsfiddle.net/tusRy/6/
Is this a Firefox bug or can this be tamed with JS? Or is there a more robust method for performing all of this?
Thanks!
UPDATE: Updated fiddle to http://jsfiddle.net/tusRy/6/ to reduce clutter a bit. To explain the expected behavior of the fiddle:
Drag a file into the window and p.target should be "ENTER" colored yellow.
Drag a file out of the window and p.target should be "LEAVE" colored red.
Drop a file in the window and p.target should be "LEAVE" colored red.
In firefox, the LEAVE event is triggered when you drag the file over text.
As of version 22.0 Firefox is still doing this. When you drag over a text node it fires two kinds of dragenter and dragleave events: one where the event target and relatedTarget are BOTH the parent element of the text node, and another where the target is the parent element and the relatedTarget is the actual text node (not even a proper DOM element).
The workaround is just to check for those two kinds of events in your dragenter and dragleave handlers and ignore them:
try {
if(event.relatedTarget.nodeType == 3) return;
} catch(err) {}
if(event.target === event.relatedTarget) return;
I use a try/catch block to check the nodeType because occasionally events fire (inexplicably) from outside the document (eg. in other iframes) and trying to access their nodeType throws a permissions error.
Here's the implementation:
http://jsfiddle.net/9A7te/
1) Your dropzone should have only one child element, which might have everything else you need. Something like
<div id="#dropzone">
<div><!--Your contents here--></div>
</div>
2) Use this CSS:
#dropzone * { pointer-events: none; }
You might need to include the :before and :after since the * don't apply to them.
This should be enough to let the drop work in Firefox and Chrome. In your example, it should be enough to add:
body * { pointer-events: none; }
At the end of the CSS. I've done it here:
http://jsfiddle.net/djsbellini/eKttq/
Other examples:
http://jsfiddle.net/djsbellini/6yZV6/1/
http://jsfiddle.net/djsbellini/yR8t8/
I came up with kind of a solution, yet to test on other browsers other than Chrome and FF but working so far. This is how the setTimeout looks now:
setTimeout( function() {
var isChild = false;
// in order to get permission errors, use the try-catch
// to check if the relatedTarget is a child of the body
try {
isChild = $('body').find(e.relatedTarget).length ? true : isChild;
}
catch(err){} // do nothing
collection = collection.not(e.target);
if (collection.size() === 0 && !isChild) {
self.trigger('draghoverend');
}
}, 1);
The entire code here - http://jsfiddle.net/tusRy/13/.
The idea is to check if the related tag is a child of the body, in which case we are still in the Browsers and the draghoverend event should be not triggered. As this can throw errors when moving out of the windows, I used a try method to avoid it.
Well, perhaps somebody with more skills on JS could improve this :)
I found the answer in a non-selected answer to this SO question asking about dragleave firing on child elements. I have a <div> that has many children elements. An semi-opaque overlay <span> becomes visible over the <div> whenever there's a dragenter on the page. As you found, 'dragover' isn't like mouseover. It triggers dragleave whenever you hover over a child element.
The solution? Dragout It makes dragover work more like mouseover. Very short.

MouseOver/MouseOut EventListener inheriting to child nodes?

Edit: Solution
Thanks to Gaby for the help in finding a solution! Didn't quite work exactly how I wanted it to, found a better solution modified from the answers. What I do is only execute the mouseover/mouseout functions when the two elements (target and related target) do not share a parent.
Just modified Gaby's example a bit and have everything working great. As long as your popup is within the same div element as whatever spawns it (even if it's outside the main contents you can append it with overflow visible) and you don't go between non-shared elements on the way over to it, it'll stay alive.
divContents.addEventListener('mouseover', mouseEnter(showPopup, divContents));
divContents.addEventListener('mouseout', mouseEnter(hidePopup, divContents));
Now, the modified mouseEnter...
function mouseEnter(_fn, _parent) {
return function(_evt) {
if(!shareParent(_evt.target, _evt.relatedTarget, _parent)) {
_fn.call(this, _evt);
}
}
};
function shareParent(_object1, _object2, _parent) {
if (_object1 === _object2) {
return true;
}
while (_object1 && _object1 !== _parent) {
_object1 = _object1.parentNode;
}
while (_object2 && _object2 !== _parent) {
_object2 = _object2.parentNode;
}
return _object1 === _object2;
}
Solved my problem A-OK, because what I want to fire for mouseover and mouseout events will only happen when the elements don't share a parent - exactly how I intended on displaying the popups anyhow.
Thanks again for the code example from Gaby, though!
NOTE: No error checking for parent validity in shareParent function, haven't checked but it should always return true when it gets to the top of the tree (assuming the _parent isn't actually a parent of either _object1 or _object2). So make sure the parent object you pass to it is valid.
Original Question:
I'm having a problem in JavaScript right now.
I'm trying to create a div Element that pops up dynamically when something has a mouseover. The div is created directly adjacent to the object that spawns it.
divCreator.addEventListener('mouseover', createPopup, true);
divCreator.addEventListener('mouseout', hidePopup, true);
That creates the popup. Now, in the popup, when I create it, I run this before I append it to the document:
divPopup.addEventListener('mouseover', createPopup, true);
divPopup.addEventListener('mouseout', hidePopup, true);
This ensures that if I mouseover the popup, it keeps it alive (because the divCreator mouseout will fire) and when I mouseout of the popup it disappears.
However, with this method, whenever I mouseover a child element it detects a mouseout event from the parent element (divPopup) and closes the div.
Can I make the children 'transparent' to Events, so-to-speak?
There are two events that handle this case.
The mouseenter W3 DOM3 docs and mouseleave W3 DOM3 docs but they are currently in the DOM3 Events working draft.
They were introduced by Microsoft IE5.5, and Firefox has added support in v10.
A workaround is to manually check and cancel the execution of your handler if the newly moused-over element is a child of your top level one..
code adapted from http://blog.stchur.com/2007/03/15/mouseenter-and-mouseleave-events-for-firefox-and-other-non-ie-browsers/
divCreator.addEventListener('mouseover', mouseEnter(createPopup), true);
divCreator.addEventListener('mouseout', mouseEnter(hidePopup), true);
function mouseEnter(_fn)
{
return function(_evt)
{
var relTarget = _evt.relatedTarget;
if (this === relTarget || isAChildOf(this, relTarget))
{ return; }
_fn.call(this, _evt);
}
};
function isAChildOf(_parent, _child)
{
if (_parent === _child) { return false; }
while (_child && _child !== _parent)
{ _child = _child.parentNode; }
return _child === _parent;
}
Demo at http://jsfiddle.net/gaby/jMvHv/ (open your console for log messages)

Categories

Resources