I'm trying to get Hammer update the event.target element while using the "pan" event on mobile Android (so far only checked 4.2).
The problem is if I attach Hammer to the ul and pan along the li elements the event.target is returned correctly on desktop browsers (Chrome in particular - check the console), but mobile Android event.target is always the first one clicked.
The code:
$(document).ready(function() {
console.log('fired up!');
var myParent = document.getElementsByClassName('test')[0];
var mc = new Hammer.Manager(myParent, {domEvents: true});
mc.add( new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, threshold: 0 }) );
mc.on("pan", function(ev) {
console.log(ev.target);
});
});
An example can be found here:
http://designingreen.net/tests/test-hammer.html (just check the source)
Am I doing something wrong or is it a matter of Hammer?
Edit: Apparently this is an issue in Android and "touchmove" event. A good workaround solution is availible here:
How to find out the actual event.target of touchmove javascript event?
Apparently this is an issue in Android with "touchmove" event. A good workaround solution is availible here:
How to find out the actual event.target of touchmove javascript event?
Related
I can locate an iframe in an Android webview, but I need to interact with it. Various pages suggest
query("webView css:'iframe'", :stringByEvaluatingJavaScriptFromString => '...')
but that results in "No such method found: stringByEvaluatingJavaScriptFromString([String])" and it looks like an iOS function, so I'm pretty sure this is an iOS-only solution: I need Android.
I know I can pass javascript queries in by opening them in a URL, but I've only experienced getting stuff out of an Android webview with specially-code Chrome objects linked in to the application.
Any ideas for getting data out?
The iOS responses are correct, you should use javascript to get the contents of an iframe. However, you should use evaluate_javascript(query_string, javascript) to evaluate javascript in Android. e.g
evaluate_javascript("webview", "return document.getElementsByTagName('iframe')[0].contentWindow.document.getElementById('...').getBoundingClientRect();")
Use the coordinates to tap the view.
If the rect is not parsed correctly, you could do something like this:
var boundingBox = document.getElementsByTagName('iframe')[0].contentWindow.document.getElementById('main').getBoundingClientRect();
var rect = {};
rect.width = boundingBox.width;
rect.height = boundingBox.height;
rect.left = boundingBox.left;
rect.top = boundingBox.top;
return rect;
Secondly, query('webView css:#grabby') is not a valid query. query('webView css:"#grabby"') or query("webView css:'#grabby'") is. You are most likely running a (very) old version of Calabash-Android if the test-server is crashing instead of reporting it.
I wrote what amounted to an answer while I was exploring, but I'm posting it here to save someone else time (hopefully).
I can successfully run Javascript in the view:
query("webView index:0", :loadUrl => 'javascript:alert("Hello")')
so I can probably arrange to press buttons plausibly enough for testing:
query("webview index:0", :loadUrl => 'javascript: ifr = document.getElementsByTagName("iframe")[0]; idoc = ifr.contentDocument || ifr.contentWindow.document; idoc.getElementById('myCheck').click(); false')
To get data out again, I can create a DIV and set its title (for example) with some 'return' value:
query("webView index:0", :loadUrl => 'javascript:var idiv = document.createElement("div"); idiv.id="grabby"; document.getElementsByTagName("body")[0].appendChild(idiv); idiv.title="some return value"; false')
(The trailing 'false' in the javascript: command is there to prevent the result of running the javascript: command from replacing the page - that took a while to work out.)
I can look into the iframe too:
query("webView index:0", :loadUrl => 'javascript:var idiv = document.getElementById("grabby"); ifr = document.getElementsByTagName("iframe")[0]; idoc = ifr.contentDocument || ifr.contentWindow.document; idiv.title = idoc.getElementsByTagName("input")[3].id; false')
When I tried to retrieve it with
query('webView css:#grabby')
it hung for a while, then crashed with a timeout:
HTTPClient::ReceiveTimeoutError: execution expired
from /Users/tim./.rvm/gems/ruby-2.1.5/gems/httpclient-2.6.0.1/lib/httpclient/session.rb:876:in `gets'
from /Users/tim./.rvm/gems/ruby-2.1.5/gems/httpclient-2.6.0.1/lib/httpclient/session.rb:876:in `block in parse_header'
from ...
curiously, query('webView css:"*"') mostly seems to work without timeouts, and reports the 'grabby' DIV complete with the title string
query('webView css:"*"').find { |e| e['id'] == 'grabby' }
so that's useful enough. I'll have to write some horrible recursive descent thingy to fish out the iframe's contents - perhaps make the div invisible and just copy the htmlContent there.
I'm really not sure why the direct query crashes.
I am wondering why the backspace/ delete button does not detect a keyup event in jQuery.
I find this odd as it is useful and should be supported. Are there any alternatives to this?
This is only happening in Android - Chrome.
You can actually fix this by attaching an event listener to the input.
var inputBox = document.getElementById('inputId');
inputBox.addEventListener(‘input’, function() {
exampleFunc();
}, false);
Cheers
I am using the localstorage option to set a variable for using it in another page.The platform is Android
Just to simulate the problem, i just created 2 simple JQM pages and set the variable in page 1 and use it in page 2. That works fine for the first time. When i'm going back to page 1 and set a new value for the variable, page 2 tells me that it is the previous value(!). I'm a little bit lost how to use it. Can someone give me a clue how to manage this? The weird thing is that on an old Android version (like 2.3.3) it works fine, but on a new one (like > 4) it fails. I think it has something to do with ready() event?
Page 1 - Main page:
$(document).ready(function () {
$('#Klant_Lijst').delegate('li', 'click', function () { var x = $(this).data('nummer'); localStorage.setItem("Nummer", x);});
});
Page 2 - sub page
$(document).ready(function () {
GetFustInfoKlant(localStorage.getItem('Nummer'));
});
I hope someone can give me an hint in a direction. Thanks!
Please dont use ready() method, use JQM page events like pageshow, pagecreate, pagebeforeshow, etc..
I have a small phonegap application with jquery mobile and backbone.
I'm trying to show popup to user by manually calling .popup() method.
Everything works fine on iOS but on android I got strange issue: popup is showing for few moments and than disappear.
Here the actual code:
var PostView = Backbone.View.extend({
events: {
'touchend .add-comment-button': 'addComment'
},
addComment: function() {
this.$(".comment-popup").popup('open', { history: false });
return false; // Stop bubbling.
}
});
I'm using history: false because this popup is actualy part of subpage.
The code looks very simple, I'm just can't understand why it can disappear, and why this happen only on android devices.
Thanks, and sorry for my bad english.
I spent hours trying to fix this problem.
Finally I ended up doing the following two things that seemed to fix the problem.
1 - Use the uncompressed jqm file. i.e jquery.mobile.1.2.0.js
2 - I was triggering the popup programatically using the 'tap' option - once changed to the 'click' option it worked.
$('.option').live('click', function() {
$('#popup-div').popup('open');
});
I spent hours trying to fix this problem.
Finally I ended up doing the following two things that seemed to fix the problem.
this code snippet may help you ->
$('#testBtn').on('tap',function(e){
console.log("button clicked");
e.preventDefault();
$('#testPOPUP').popup("open");
});
Please note i have used e.perventDefault().
I didn't feel like changing my .tap() events to the click event and I didn't have a case where I could use preventDefault()so I just added a timeout to the popup('open') line. My hoverdelay in jqm is set to 150 so I set this timeout to 600 just to be on the safe side. Works fine, doesn't feel sluggish for the user.
One way to 'fix' it is by setting data-history="false" on the popup div
See also this question
JQuery Mobile popup with history=false autocloses
I have the exact same problem when trying to use popup('open') on an android 2.3 device (both in native browser and in firefox) and it works just fine on browsers on other devices. I'm also using backbone event management to open my popup (used the tap event and no aditionnal options to popup).
What I did to 'correct' the problem is that I removed the backbone event management for this event and added a listener in the render function. In your case this would look something like this :
events: {
// 'touchend .add-comment-button': 'addComment'
},
render: function() {
$(this.el).html(this.template(this.model));
$(this.el).find('.add-comment-button').tap(function(el){
this.addComment(el);
return false;
}.bind(this));
}
I have no idea where the problem comes from (must be some incompatibility between backbone and jquery mobile) and why we only see it on android but for the moment with this workaround my app seems to work fine on any device.
Edit: oops, it turns out that in my case the problem was I was missing "return false;" in the function dealing with the event.
Now that I added it, it works correctly with the backbone event management.
Sadly that doesn't explain why you have the issue and why I was seeing it only on android.
In case it helps anyone, I had the same problem occurring with Bing Maps, with the Microsoft.Maps.Events.addHandler(pin, 'click', callback) method.
Not particularly nice, but instead I stored an ID in pushpin._id and did the following:
$("#page").on('vclick', function (event) {
if (event.target.parentElement.className === "MapPushpinBase") {
$("#stopPopup").popup('open');
}
});
One brute force option is to check whether popup was hidden and reopen it.
In a loop, because the exact time the popup becomes hidden seems to be varied.
var hidden = $('#' + id + '-popup') .hasClass ('ui-popup-hidden')
if (hidden) $('#' + id) .popup ('open')
A working example: http://jsfiddle.net/ArtemGr/hgbdv9s7/
Another option could be to bind to popupafterclose:
var reopener = function() {$('#' + id) .popup ('open')}
$('#' + id) .on ('popupafterclose', reopener)
$('#' + id) .popup ('open')
Like here: http://jsfiddle.net/ArtemGr/gmpczrdm/
But for some reason the popupafterclose binding fails to fire on iPhone 4 half of the time.
Is there a way to prevent scrolling of a rendered HTML page in the Android browser? The following does not appear to have any impact on page scrolling in the Android browser:
var preventDefault = function(e) {
e.preventDefault();
return false;
};
document.addEventListener('touchmove',preventDefault,false);
document.body.addEventListener('touchmove',preventDefault,true);
window.addEventListener('touchmove',preventDefault,true);
(I've tried with bubbling on and off.)
It looks to me like Android Webkit makes the "window" the same length as the document, so scrolling is being done on the browser itself, not on the document body or DOM window object. What's weird is that that's exactly what webkit on iOS does, but the code above still works.
Answering my own question.
The problem ended up being that you need to capture and suppress ontouchstart as well as ontouchmove on document to stop the browser from scrolling. This is definitely different in iOS, but it still works identically on both platforms.
The actual code I ended up using looks sort of like this:
var preventDefault = function(e){
e.preventDefault();
};
var touchstart = function(e) {
document.addEventListener('touchstart', preventDefault,false);
document.addEventListener('touchmove', preventDefault,false);
/*do other stuff*/
};
var touchend = function(e) {
document.removeEventListener('touchstart', preventDefault,false);
document.removeEventListener('touchmove', preventDefault,false);
};
element.addEventListener('touchstart', touchstart, false);
element.addEventListener('touchend', touchend, false);
Not works on Chrome on Android though
But preventing event on window and stopping immediate propagation helps!
Handler should be not passive to do that.
MAY BE adding an event handler on capturing phase would help too
But this snippet below is tested by me
window.addEventListener("touchmove", function(event) {
event.preventDefault();
event.stopImmediatePropagation();
}, { passive: false });
DEMO https://codepen.io/ColCh/full/qvLqoe