Why does my jQuery triggered keyup event get lost? - javascript

I'm using jQuery 1.7.1
My keyup handler works fine, even though the setup is a little complicated. This is happening in an iframe overlay. The main page does
our.Catalog.makeViewer = function(id) {
var iframe = document.createElement('iframe');
iframe.setAttribute()... // src, id, name, etc. Exact same host and method
document.body.appendChild(iframe);
iframe.contentWindow.focus();
$('html, body').css('overflow', 'hidden');
}
our.Catalog.makeViewer('foo') // actually bound to a click hander
In the iframe <head> we have something like
our.Viewer = function(){
$(document).keyup(function(e){ doSomething() })
// and lots more, of course
}
$(function() {
new our.Viewer();
});
The browser displays the URL of the iframe. I get all the real keyups for the whole browser window which is fine, but for testing I want to be able to simulate keyups from JavaScript. However, whatever I try doesn't work. I've tried
$('body').trigger($.Event('keyup', {keycode: 40}))
$(document).trigger($.Event('keyup', {keycode: 40}))
$(document).keyup()
and none of them triggered my handler. Then I thought maybe the problem was that I'm using iframes, so I tried
$('#frameId').contents().find('body').trigger($.Event('keyup', {keycode: 40}))
Nope, that doesn't work either. I don't think it's any kind of permissions/security issue because $('#frameId').contents().find('body').addClass('test') works fine.
I hope I'm doing something stupid someone can easily correct. How can I simulate keyups from my JavaScript driver?

OK, the code recommended by the jQuery docs works from Selenium. Or at least the one-liner version:
$('body').trigger($.Event('keyup', {keycode: 40, which: 40}))
In my particular case I wasn't seeing it from Selenium because our handler checks e.which not e.keycode and e.which remained undefined until we set it explicitly. Maybe a bug in jQuery 1.7.1? Maybe due to an interaction between jQuery and Selenium? Anyway, setting e.which got the test passing.
On the other hand, getting stuff to work from a browser console was more challenging. From Firebug on Firefox I had to cd(frames[2]) to set the context to the iframe in question. No other way of accessing the iframe from another frame would let me trigger events, probably due to some kind of sandboxing. (I can access the iframe's DOM but not the iframe's jQuery.) In Chrome I have to select the iframe from the popup menu at the bottom of the console. In Safari I have to use
window.frames[2].$('body').trigger($.Event('keyup', {keycode: 40, which: 40}))
So as I expected, something relatively stupid, not setting the iframe context in the console and actually failing the test in Selenium for other reasons.
Thank you #Ian for trying.

try tihis
$(document).on("keyUp",function(){
//your logic
});

.trigger() only works with events binded with .on().
Try binding with:
$(document).on('keyup', function (e) {
doSomething(e.keyCode);
});
And testing with:
$(document).trigger($.Event("keyup", { keyCode: 40 }));

Related

Event handlers not working correctly in jsfiddle

Trying to make a jsfiddle so I can post it on here and get some help with a problem; however, I'm having a problem getting jsfiddle to act as expected, so I'm having a problem trying to document my problem!
http://jsfiddle.net/eidsonator/he4Vc/#base
I'm trying to add a blur event handler to a input with id of "part". My alert fires as soon as the page loads (which it shouldn't) and doesn't fire when focus is lost. This behavior persists in chrome and in firefox (I'm coding for an internal web app, so I can ignore ie!)
$("#part").on('blur', alert('lost focus'));
I've changed the load method, and tried wrapping it in my own $(document).ready(function() {}); as well as using .blur() and different versions of javacript... any clues?
Thanks!
You are calling alert straight away, and passing the return value of it to the .on() method. Instead, you need to pass a reference to a function that can be invoked when the event is received:
$("#part").on('blur', function () {
alert('lost focus')
});
Here's an updated fiddle.
you have written a wrong syntax .see the docs for more info,and change your code to
$("#part").on('blur', function(){
//do something
});

JS code makes IE9 and Safari freezing and does not work in Opera?

I don't know why, but this code makes IE9 and Safari crash, and does not work at all in Opera.
$('#contentPage').on('DOMSubtreeModified', function(){
if($(".iframey[date-current]").length){
$(".iframey:not(.hidden)").prevUntil("iframe").addClass('smaller');
}});
What should I do to make this code work in all browsers?
---edit---
The code in jsfiddle
http://jsfiddle.net/rzP5S/
Working grate in chrome and firefox
You are modifying the dom in a dom modified event handler, you should check if the modification was due to your code in the handler to prevent an endless loop.
Also
Warning! the DOMSubtreeModified event type is defined in this specification for reference and completeness, but this specification deprecates the use of this event type.
http://www.w3.org/TR/DOM-Level-3-Events/#event-type-DOMSubtreeModified
What #Musa is saying is correct. There is an infinite loop. Is there any reason why you need to handle it in DOMSubtreeModified? Can't you just do the work within the click event instead? This seems to behave the same:
$(".onePost").live("click", function() {
$(".onePost").removeClass('smaller');
$("iframe")
.addClass('hidden')
.removeAttr('src')
.removeAttr('date-current');
$(this).nextAll("iframe:eq(0)")
.removeClass('hidden')
.removeAttr('style')
.attr({src: $(this).data('href')})
.attr('date-current', 'here');
if($(".iframey[date-current]").length){
$(".iframey:not(.hidden)").prevUntil(".iframey").addClass('smaller');
}
});
http://jsfiddle.net/rPPSj/

onChange event not firing on a textbox in Chrome

I have the following code to bind some validation logic to be fired when a user updates the value of a textbox. I expect that the //Do some stuff here code will execute when any of the textboxes it is bound to lose focus.
function RegisterHoursValidationHandlers() {
$('.topic-frame-body input[type=text]').live('change', function () {
//Do some stuff here
});
}
This works exactly as I expect in IE, Firefox and Safari. However, the event never fires in Chrome and I have no idea why.
UPDATE: I was able to get the desired effect by changing 'change' to 'blur'. Though this still doesn't explain why it doesn't worh with 'change'.
There's no known quirk about chrome. (the change event is supported across all browsers)
Example with live showing it working against dynamic content.
Test it here:
There is a piece of information or an assumption being made here that makes this unsolvable.
UPDATE: If it works when you change it to blur, it is possible that you are overwriting the previous event or function. By changing it to blur, whatever is overwriting it no longer will because it is a a different event.
This would also explain why you are not seeing any errors. (keep in mind, I believe that jQuery will chain events bound to the same elements, but live() is a bit of a special case - but that fact might point to it being the function, not the event binding)
Try using .delegate() instead http://api.jquery.com/delegate/
I've tried you code in both FF and Chrome - http://jsfiddle.net/B3aRy/ - It worked in both. So maybe its an issue elsewhere in your code?
What version of Jquery are you using?
I can't see the issue myself, but .live does not support the "change" event until jquery 1.4+
Try:
function RegisterHoursValidationHandlers() {
$(".topic-frame-body input[type='text']").live('change', function () {
//Do some stuff here
});
}
With the quotes around 'text' as I have it. Worth a shot.
Or try:
$(".topic-frame-body input:text").live();
The point being, I think the problem is in the details of how you're targeting the input field, rather than in the method.

$(window).mouseup handler in a Chrome extension is breaking Flash

I'm working on a Google Chrome extension that monitors mouse events. For some reason the following javascript code in the extension's content script is causing embedded Flash content to break:
$(window).mouseup(function() {
// do benign stuff
});
If you mousedown inside a Flash element, it never registers the mouseup and it appears as though you're still holding your mouse button down even though you've let go. At first I thought it was some kind of event bubbling issue, that this method was swallowing the event, so I tried returning true (and false for that matter) but it didn't seem to have any effect. Any ideas?
Well, no response from the peanut gallery after a few days, but I figured it out on my lonesome:
// Bad
$(window).mouseup(function() { ... });
// Good
window.addEventListener("mouseup", function(event) { ... });

Is there any way to use window.onbeforeunload on Mobile Safari for iOS devices?

Looks like Apple has disabled the window.onbeforeunload event for iOS devices (iPhone, iPad, iPod Touch). Unfortunately I can't find any documentation as to why this event doesn't work in Mobile Safari.
Does anyone know if there's a reliable alternative to this function? Android's browser appears to support it just fine, and the Safari desktop application also supports the onbeforeunload event without issue.
I see that it's an old question, but i faced this problem recently.
I'm using window.unload and it works fine in ios browsers (although if you look at Apple documentation it seems to be deprecated and they recommend to use document.pagehide)
If you really need it, you cant just get all links, forms and DOM objects that have a handler changing the url and make those wait until you've done what you want.
For the links, you get them by getElementsByTagName, check if the href starts with anything but a # and just add your onbeforeunload function add onclick (which will be invoked before the href is looked at).
Same for the forms but with onsubmit.
And finaly, for the elements changing the href with JavaScript, you should make sure when you add the lsitener that you call your onbeforeunlaod function (or, if you use DOM0 or DOM1 listeners, you can just add some class and then use a global script that checks all elements with the class and adds it to the event listener with a closure.
But you should normaly be able to avoid the use of this event (probably using cookies to store the thing you wanted to send every x seconds and allowing to, in the worst case, have a look at it next time the user loads a page and, in the best case, be able to send an Ajax request at onbeforeunload or onunload which, even if it sends only the http headers, woudl allow you to get what you want).
Based on Xavier's answer, I devised a solution along these lines:
function doStuff() {
// here goes your logic
}
function isSafariMobile() {
return navigator && /Safari/.test(navigator.userAgent) && /iPhone|iPad/.test(navigator.userAgent)
}
function addWatcherToLinks(baseNode) {
if (!baseNode || !baseNode.querySelectorAll) { return; } // ignore comments, text, etc.
for (const link of baseNode.querySelectorAll("a")) {
link.addEventListener('click', doStuff);
}
for (const form of baseNode.querySelectorAll("form")) {
form.addEventListener('submit', doStuff);
}
}
// ...when the page loads...
// we watch the page for beforeunload to call doStuff
// Since Safari mobile does not support this, we attach a listener (watcher) to each link and form and then call doStuff.
// Also, we add such a watcher to all new incoming nodes (DOMNodeInserted).
if (isSafariMobile()) {
addWatcherToLinks(document);
window.addEventListener("DOMNodeInserted", (event) => { addWatcherToLinks(event.target); }, false);
} else {
window.addEventListener('beforeunload', doStuff);
}
This solution has some limitations. The biggest one is that it attaches itself to all forms and all links. Sometimes this might not be desired. If you need it you can skip some nodes (e.g. mark them with a particular data- attribute).
I was having the same problem. it seems safari browser in iphone triggers only focus and blur events and almost every other event is not triggered, e.g.(pagehide, pageshow, visibility change) but the good news is focus and blur event are supported and triggered on iphone, ipad & android mobiles as well.
window.addEventListener('focus', function(){
// do stuff
});
window.addEventListener('blur', function(){
// do stuff
});
hope this helps anyone.

Categories