Various experiments I've carried out indicate that there is no foolproof way of responding to a 'mouseleave' event using jQuery. Two actions appear to not trigger any relevant event:
Moving the pointer away from an element very quickly
Moving the pointer off the element via some browser chrome (or out the the window entirely)
The second is by no means a show-stopper, but the first is a big problem. Is there a solution? Tracking document.mousemove and continually checking whether the cursor is over the target element?
i usually use hoverintent instead of hover to solve problems like this.
Related
I'm making the step-by-step-filled form-like page now (hope it was grammatically correct ☺ ).
The main idea here is quite simple: while step one isn't done, step two is unavailable.
I need it to be truly unavailable, not just CSS-hidden (like opacity: 0; or visibility: hidden;).
So, here is the question: in JavaScript is there any way to dynamically pause (and unpause later) all eventListeners of some element?
P.S.: Event is for example onwheel || onmousewheel.
Here is the image (sorry for cyrillic):
(It's about scoresheet-typing.)
You see the <input type="range"> element here. Mouse scrolling on it will change it's value.
The first step of a form isn't done yet; so the second one have to be unavailable, and mouse scrolling on input range element should not work.
But this time I managed to it with opacity: .3;.
So all works fine, but the picture is kinda translucent, that's all.
It is bad.
It shouldn't react on mouse wheel at all (just usual page-scrolling).
And opacity must be full (opacity: 1;).
So, we return to the initial question.
There is no way in JavaScript to even list all event listeners for an element, so to stop them is an even taller order.
In short, the answer to your question is: there's no general way to pause all event listeners.
However, there are some things you may try that could help achieve your intent.
Plan A - HTML / CSS + a little JS: If your intent is simply to prevent the events from reaching the unactivated step, you may try a hack: create a transparent "blocker" element of the exact same dimensions. When you "disable" your step, "enable" your blocker to be right on top of it - probably using absolute positioning, e.g.
// Disable step 2
step2.style.opacity = '0.3'; // could also be a CSS class toggle, or an JS animation
step2_blocker.style.display = 'block'; // make your blocker show up on top of step2
You may use HTML+CSS to create the blocker, provided you know the position/dimensions. If not, you can use JS to create the blocker at run-time after computing step2's position/dimensions.
Plan B - JS only: If for some reason, you can't change HTML or CSS and you need a JS-only solution that doesn't alter the DOM, or if you are truly trying to solve the generic problem of "How can I pause event listeners?", then you probably only have one solution - keep track of your listeners. Essentially, you will be building your own event-binding/tracking library. The API consists of on(), off(), pause(), resume().
on(HTMLElement, eventType, callback): you should push the listener callback into a registry - an array of listener objects, where listener objects contain HTMLElement and its corresponding eventType and event listener callback.
off(HTMLElement, eventType, callback): remove listener object from registry.
pause(HTMLElement, eventType, callback): find listener object from registry and set it to paused state, i.e. stop the actual listener.
resume(HTMLElement, eventType, callback): find listener object from registry and rebind the element to the event listener.
Of course, the API can be made to be flexible/smart enough to accept different number of parameters (simulate function overloading), so that pause(elem) can pause all events on the element, and pause(elem, 'click') can pause all click events on that element.
Then, rather than use addEventListener() in your code, always remember to use on() in the library you created. You may have to refactor all your event binding and listener code.
This plan is slightly elaborate, but is probably the only way to keep track of event listeners. I have done this before, so I know this really works.
P/S: You may try to take a look at the source of some popular libraries out there to see how they keep track of events. I don't think any of them has any kind of support for pause() and resume() (yet), so it'd only be for some code inspiration.
In the context of a problem, I may just addEventListener after correct passing the step one, of course.
It is not the answer though.
You can set the disabled attribute of the inputs to true initially. Then as each input is filled in and/or validated, you can set the disabled attribute of the next one to false, to make it available.
Edit: given the update to the question, this answer doesn't seem to work. Setting disabled on an <input type="range"> does not seem to prevent wheel events from firing, at least in chrome.
I am researching a problem where a user triggers a scroll event, we process it, and in the process of doing so are somehow triggering a second scroll event. Our code is similar to this. In real life, 'thead' is buried inside many levels of containers, etc.
$(window).on('scroll', function(){
$('thead').css('position','fixed');
})
The triggering action seems to be fixing the position of an element. This causes document.height to change, which makes sense, but such actions do not normally cause a scroll event to occur (from what I can tell).
I can reproduce this in our app (which is a mountain of jQuery) with very specific combinations of browser height and document height (I can't see a pattern to it, though; I just know values that work).
I can't reproduce it in a simple case, and I've been trying to all day.
I am confident that $.ScrollTop() or equivalent functions are not being called, and that the user is only making a single gesture.
The jQuery event object looks to me like it is a second user initiated event, eg. there is nothing to suggest that event #2 was caused by event #1.
This is happening on Chrome, haven't tried other browsers. Any suggestions appreciated.
When you make any element to be position:fixed/absolute, your document's height is changed because changed element become out-of-normal-flow and does not push next elements down (read CSS position property). It's the same as removing element from your page.
So, if you're at the bottom of the page and one of elements is gone, browser scrolls page up to compensate removed element's height (to leave you at the bottom of the page).
as the title says, i would like to know if theres any possibility in javascript (jquery) to check if there is any action in the document, and if not. something like a screensaver should pop up!
if someone is on the page and looks here, looks there and after a while he doesnt do anything, the mouse (or touch finger) stands still, i want to say the document after a minute without activity...
function noactivity() { //after 60000ms start something here }
i want that global for the whole document!
thanks ted
It can be done relatively simply in jquery using:
setTimeout();
http://jsfiddle.net/bernie1227/hNkTy/1/
I had this issue a while back while I was working on an iframe resizing issue. What I wanted was to tell the parent page whenever there is a change in height of the document.
What I found was that jQuery does not give such facility directly. The main reason for this is that there are too many activities happening to DOM which are not visible, when you are watching it (bind). You could however watch for a specific property like mouse moving on a document.
$(document).mousemove(function(e){
console.log(e.pageY);
console.log(e.pageX);
});
But then again that does not at all mean that the user is interacting with your page. That merely signifies that the user is on your page and his mouse is moving. The user might also be not moving the mouse and merely using his keyboard to interact with your page. So now you would have to watch for keyboard interaction aswell.
$(document).keyup(function(e){
console.log('active');
});
Using these you could create a countdown function which checks for a flag after a set interval of time. You could set the flag if user makes an activity. And after a set amount of time that function the 'noactivity()' function id the flag has not been set.
Another approach to watching the document activity could be you watching the DOM subtree being modified.
jQuery(document).bind('DOMSubtreeModified', function() {
console.log('active');
});
This works for Chrome/FireFox/IE8+ but not on Opera (any version). The main reason being that the operation is too heavy on your browser's resources. And I would discourage using this approach because listening for DOM mutation events may harm performance and the relevant W3C working groups are trying to find a better way to do this and deprecate DOM mutation events for this reason - it's hard or impossible to make a good and performant implementation.
I am not saying that the other options that I mentioned above are good either. They are also expensive operations if you are watching document and should be avoided. Another issue with those options is that the iframe content is not particularly the part of your document and these options will not work if user is interacting with iframe content.
So the conclusion is that W3C did not yet finalize a cheap way where user can watch changes in document subtree.
Ok, I know that is a rookie question but is there any way to force a mouse click? To be more specific, say I want to trigger mouse click on random time and I don't know in which element the mouse would rest that time.
You can install a root level event handler on the document object to track the mouse position so you can know where the mouse is at any given time. You can create events in the browser using the code described in this post: Is it possible to trigger a link's (or any element's) click event through JavaScript? which gets its info from this article: http://jehiah.cz/a/firing-javascript-events-properly
Usually, creating raw events is not the most efficient way to solve a problem (unless you're doing some sort of automated tester). Usually it's better to just call the function you want directly or modify the DOM object directly rather than try to cause that change with an event.
No, this is not possible exactly the way you describe.
You can listen to mouseenter for everything and always update a reference to whatever was hovered last.
You can track elements with mouseover/mouseout and trigger their click handlers at any time
Which events are the most resource intensive to have attached? Is a mouseover "worst" than a click? Are there any events that are known to be really harsh on the browser? I have my sights on IE7 mainly, as we are seeing performance issues there. We use event delegation where we can.
Or, how can I profile events which are actually running to determine which have the greatest impact on performance at runtime?
I'm interested in the events themselves, please don't tell me I need to go look into what my functions are doing in those events. Problems may exist there, but that's not my question.
So, to start with, events that fire more often can be more troublesome. So a mouseover event, which fires "continuously" as the mouse moves over an element, could cause a performance impact more easily than a click event, which can only fire as fast as the user can click.
However, it's the code you put in your handler that will have the real performance impact.
If firing speed is an issue, check out the excellent jQuery throttle/debounce plugin: https://github.com/cowboy/jquery-throttle-debounce
I'd imagine a callback's intensity is proportional to how many times it's called.
Events like mouseover or deviceorientation are more demanding than a click or similar 'one time' event.
The more an event have to check (and then throw) the more it consumes i.e. order from the max to the min:
mousemove throws an event at any move
mouseover throws an event at each move if pointing on a relevant item
mouseenter have to watch where is the cursor to then trow something
mouse click only throws an event when you click…