javascript how to determine what is cancelling an event - javascript

I have jquery, bootstrap included in a page I'm writing. It's a complex page. The problem I'm having is with Internet Explorer not seeing mousedown event. Chrome and FF both see the event just fine but not IE.
I wrote a test page with the event and it worked just fine in IE. So my question is...
Is there a way through the developer tools to determine what is cancelling an event?
I have a suspicion that one of the many .js files I've included is cancelling the mousedown event and IE isn't seeing it anymore. Chrome and FF does though. So I'm not 100% that it's being cancelled but it's my only guess I can come up with.
Code is really irrelevant since it's all of jquery and bootstrap. However, I am playing with divs that are draggable and resizeable. That's why I need to use jquery. The bootstrap is used because I also have a wysiwyg editor on the page.
Please don't recommend click. I need mousedown. When the mouse is down the border around the draggable and resizeable div turns red and I have some code that selects that div to capture top, left, width, and height as it's being moved and resized.
If click was selected as the event, the user would have to click the div box first then click and hold to move it. That's not a user friendly interface.
Any help is greatly appreciated.

What do you exactly mean as cancel, .preventDefault() or .stopPropagation? If we are talking about preventDefault - you should still be able to add event listener to parent container and then see your event object - it might have some data to traceback. Alternative would to override jQuery .on method and see who actually subscribes to the event.
After little more thinking - add another listener BEFORE the malicious one, to do that insert document-ready handler with event binding right after jquery loading code. In your new mousedown handler try to override problematic method of the event.
UPDATE:
you should try to check all events attached to your element one by one. To do that - check this post jQuery find events handlers registered with an object
In short - try using jQuery._data( elem, "events" ); to see attached event listeners and inspect their code in your code base. After you find the reason it will be much easier to reach the desired functionality. Before that it is just a guesswork.

Related

HTML onClick VS jQuery mousedown Timing

I'm working with legacy HTML pages written ~10 years ago. That being said, it should be explicitly known that refactoring old code is not only NOT time effective, but also a risky endeavor.
A legacy webpage has many buttons which activate JavaScript event(s) using the onClick="myFunction()" tag. I've been tasked with interfacing a JavaScript file (which uses jQuery) into these legacy webpages. I've added the JavaScript file in question and jQuery 1.9.1 source and attached them to the legacy HTML pages prior to the closing body tag, ex:
<script src="jquery-1.9.1.min.js"></script>
This JavaScript source file (which uses jQuery) activates a mousedown event on the buttons with the attached class "getStats", ex:
$(document).on('mousedown', '.getStats', function (event) {
//Stuff
});
However, when the jQuery activates, it does NOT perform the redirect the button is supposed to do through the HTML onClick event.
I can't find any information online on how the HTML onClick and jQuery mousedown event timings happen to understand whether or not I'm encountering a race condition. Both the HTML onClick redirect and jQuery mousedown events need to happen, and I can't just simply go back and edit all the legacy HTML onClick events to be done in jQuery either as that would take months of work.
Sample jsFiddle:
https://jsfiddle.net/koa2hsbp/
The jQuery works right off the bat. If you comment out the jQuery mousedown function, then the HTML onClick works. But I have to make it to where both parts activate (preferably jQuery mousedown prior to HTML onClick), without changing the HTML's functionality. (Again, changing the legacy code is a costly endeavor in and of itself.)
Some explanation about events:
mousedown - triggered immediately after mouse button pushed down while focusing element.
mouseup - triggered immediately after mouse button goes up while focusing element
click - triggered when you have consecutive mousedown+mouse up on the same element.
So in your example - you push mouse down and this immediately triggers code which produce alert. Then you release mouse button, but web paged is focused on alert, not on our element as alert window by nature blocks everything else and interrupt javascript. Since there is no mouseup event - there is no click event as well, so legacy code is not invoked.
Try following to prove I am right - push mouse down and hold it. Then click enter button - this will remove alert. Then release mouse button while on top of element. This will trigger click.
Unfortunately it is hard to mix mousedown click and alert in same example. Consider moving jQuery handler to click if you need alerts. That of cause will invoke jQuery after legacy handler.

How can one clone elements and preserve the event listeners?

I am making a chrome extension to add javascript encryption to Gmail for my buddies and I personal use. I have most of it working except for when I try to clone a button already in the Gmail interface by doing $('#elmId').clone(true), it doesn't clone the event listeners. Also, $('#elmId').data('events') comes up with nothing. I know that the button has multiple event listeners because when I inspect element the developer tools shows it has click, mouseover, etc. under the "Event Listeners" tab (see http://i.stack.imgur.com/9KnIW.png & http://i.imgur.com/1sszQ.png). Is this even possible? I'v done quite a bit of searching and have come up with nothing. Any ideas on how to do this or if it is even possible?
Even if cloning the event listener is technically possible it doesn't mean it's meaningful. The listener may be a closure that knows about the element, using the same closure on a different element is not going to work... for example
x.onclick = function(){document.body.removeChild(x);}
in this case the onclick handler removes the element x, but if you copy the element and the handler clicking the copy would still close the original.

What's the most efficient way to handle displaying a dialog/modal in JavaScript?

[UPDATE:] here is a link to test (if you don't want to clone the repo) http://jsfiddle.net/integralist/g9EPu/
I've got a lot of dialogs/modals that need to be displayed when mousing over certain links in a web app.
Table of content (tl;dr)
How I used to do handle it
How I've tried it recently
Which is better?
What about mouseenter/leave?
How I used to do handle it
The way I usually do this is to use event delegation.
So I add one event handler to a container and then check for the relevant element to become the target and then display the relevant dialog.
I normally have one dialog which I change the content for and re-position (saves having lots of different HTML mark-up).
If the mouseover event (for the link) gets triggered then I display the dialog.
If the mouseout event (for the link) gets triggered then I hide the dialog.
If I mouseout of the link which triggered the event handler then I normally need to set a timer to delay hiding the dialog (just long enough) so I can then mouseover the dialog which itself clears the timer set by the mouseout of the link.
I then have a mouseout event bound to the dialog so I can then hide the dialog when the user rolls their mouse off the dialog.
There are two problems I've encountered at this stage, the first happens practically all the time and the other is an edge case I noticed recently which prompted me to try and find a better solution...
The dialog has 'x' number of child elements and rolling the mouse over a child element causes the mouseout event for the dialog to be triggered hence I need to put in checks to see if the element has a parent which is the dialog itself and if so then don't try to hide the dialog.
When using this technique on a <table> element I've found that when the mouse moves too quickly the mouseout/over events don't get triggered.
How I've tried it recently
For example code see: https://github.com/Integralist/Mouse-Over-Out-Script (you should be able to just clone the repo and run the index.html file locally to see what's happening)
But to give a brief explanation...
We bind a mousemove event to the document.documentElement element (but you could do it on the document.body if you wanted) and then we store the x/y co-ordinates of the mouse position. We provide public API access to a 'check' method which lets us know if the position of the mouse is over the element we've provided to 'check' (we measure the elements dimensions and add those onto its x/y co-ordinates).
In the above repo we have a calendar which shows a dialog whenever a particular date has an event on. We're storing all <td>'s that have an event and we set-up a timer for each of those <td>'s (this is because we need to keep calling the 'check' method to see if that <td> has the mouse over it).
So potentially there could be 31+ (because we're showing the first few days of the following month) opportunities for a dialog to be shown and so 31+ timers set!
This example repo works now, where as the first version where I was using event delegation wasn't.
Which is better?
I'm worried about performance on the mousemove version because it can potentially use a lot of timers (depending on how many dialogs you need in a single page). In my calendar example above there is up to 31+ timers that could be running!
What about mouseenter/leave?
I know these events exist and if all browsers supported it then I could safely use the first version and not have to check for child elements causing erroneous mouseout/over events to be triggered. But regardless I don't believe this would have fixed the example with the event calendar where moving the mouse too quickly was meaning the mouseout/over events for the <td>'s weren't being triggered by the browser. Either way, I know you can polyfill this as jQuery provides mouseenter/leave events but looking through their code I couldn't get that to work for my script (as I don't use jQuery or any other general purpose library - ps, and I don't wish to, so please do not suggest that as an option).
Many thanks for any help/advice or guidance someone can provide me.
The dialog has 'x' number of child elements and rolling the mouse over a child element causes the mouseout event for the dialog to be triggered hence I need to put in checks to see if the element has a parent which is the dialog itself and if so then dont try to hide the dialog.
To solve this: in your event code, simply use the function "isAncestor" (see below)
/*
* element = the "target" in your mouseout event handler
* other = the node you really want to check if you're over
*/
isAncestor: function(element, other)
{
while ( element && element != other ) element = element.parentNode;
return ( element != null && element != undefined );
}
So in your mouseout code for your element (let's call it "itemElement"), you'd check it like:
//We're really mousing out, close dialog
if ( !isAncestor( mouseOutEvent.target, itemElement ) )
{
...do something ...
}

JQuery dropping click events

I'm currently experiencing click events intermittently not firing. Anyone else ever had this problem?
Code is simple:
<ul class="iconButtons ui-widget ui-helper-clearfix">
<li class="ui-state-default ui-corner-all" title="Save">
<span class="btnSave ui-icon ui-icon-disk"></span>
</li>
</ul>
$(document).ready(function() {
$(".btnSave").click(function() {
alert("Sometimes I never get called!");
});
});
Occurs frequently in all browsers. Using live demonstrates the same behaviour.
I would venture to say that there is some other complication going on to prevent what you are doing.
Here are some possibilities:
Unless you give that empty span display:block; then on some browsers it will have a width and height of 0px and be unclickable. Keep in mind just adding width and height to a span won't actually work on inline elements.
You are ajax'ing content in, and not rebinding the click handler. You can check at any time by doing $(".btnSave").data("events") in your firebug or chrome console to see the number of events to that element.
Another event is usurping your event, using the technique in #2 may help reveal this.
Your click handle is being called, but not returning the right result causing to believe it wasn't being called. Have you tried adding an alert('called') to the very top of the click handler?
Are you certain the element exists in the DOM prior to appending the click element to it? You can check by doing an alert($(".btnSave").length) at the line JUST before you bind the click handler.
I would suggest you use an anchor instead of a span for your button it will fire for sure.
Put
$(".btnSave").click(function(event){
event.preventDefault();
alert("Clicked");
});
In IE, you also have to have content inside an anchor for it to work: background image / background color/ text (maybe also with big negative text-indent)
Your code will hook up event handlers to all elements with that class that already exist when the code is called. If you add more later, they won't get the handler because, well, you haven't asked that they do. :-) Options:
You could use live instead, if you add and remove these elements dynamically. live (and the related delegate) use event delegation to watch for events rather than actually attaching the handlers to the elements in question. live uses the document itself. Since click bubbles, document sees all clicks (that aren't cancelled), and so jQuery's document-wide handler can see if the click was on a .btnSave element and fire your handler if so.
You could put your script at the bottom of the page (just before the closing </body> element), so that all of the elements are there when you hook up your handler.
You could use jQuery's ready function to ensure the DOM is ready before you hook up your handlers.
Alternately, as quoted your span is pretty darned hard to click on (what with being completely empty) unless there's some CSS giving it dimensions you haven't shown... ;-)
Update: You've said the span has dimensions, and that the handler is being hooked up fine (you didn't say how you know that). The only thing left is if something is hooking the click event on those elements and cancelling them (e.g., via stopImmediatePropagation, like this), and it happens that they're earlier in the event handler list than your handler is. It seems more likely that there's an issue hooking things up, though.
There may be many different reasons for that, eg.:
the JS code you are referring to is not executed correctly (does not bind the event in the correct moment in time), try executing it when the DOM is ready:
jQuery(function(){
// your code goes here
});
you may be creating this element dynamically (if you bind it first, then create element, then this element will not have the specific event). The solution is to use .delegate() or .live() jQuery functions.
the event may be unbound somewhere in your code. Try searching for usage of .unbind() jQuery's function within JS code (or even HTML).
It turns out the span which the click event was being added to only occupied the central part of the button's graphic. Clicking directly on the glyph always fired the event, but clicking slightly outside (although seemingly still inside the button) would not raise the event.
I hope this helps anyone else using mini JQuery buttons in the same way they are presented on the JQuery UI ThemeRoller page.
I'm running jquery-ui-1.10.3 and I'm having the same intermittent issue with .toggle buttons -- they just aren't very responsive. I think it's inherent in jquery-ui because even on their demo page the toggle button feels less-than-awesome in terms of tactile response. If I click very slowly and deliberately I can usually get the button to toggle on and off but fast clicking is very hit or miss. I've tried all the tips to speed up jquery-ui but none have worked.

Focus and blur events for HTMLDivElement?

I implemented a custom drop down with HTML, CSS and JavaScript. It works well now, but I am not happy with the way I am doing "blurring" right now. When you open the list, and then click somewhere else, it should collapse. What I did was that I added an event listener (mousedown) to the window after expanding the list, and removing the listener after collapsing. The event basically checks whether the DOM event happened on the right element using target and if not, then blur the drop down control.
I know about focus and blur. However, they only seem to work on form elements, which I find quite understandable. They also support other scenarios like when "tabbing" away.
Anyway, I am asking you if there is a better way of doing what I am doing right now. What I do just feels stupid.
Maybe you could have a dummy input and focus that when the control is active. Then watch the blur and close the list. It would not be able to be display:none but maybe opacity:0, or just out-of-view.
What I do is use mouseout to close my custom lists. I create a bounding box around my drop down. That box has the onmouseout event attached to it that closes the drop down when the mouse moves outside of it. This way you can have a little padding outside your list that would give your users a little better functionality then just mouseout on your basic list.
If you want to do it using click events, I would have a global function, like it seems you have setup, and call that function on any click events on the page.

Categories