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'm looking for some code to place on my website, which detects if the user is on a mobile device, opens a pop-up and offers to add an icon on the home screen linking to the website. (Just like adding the website to your favorites and placing an icon on the home screen). Ideally it should work on Android & iPhone. Any help would be much appreciated.
What you can do is create a div somewhere on your page, with the exact text you want. In your CSS, you then make the div display:none and add a media query so when the device is a mobile phone you display the div again.
.mobile-div {
display: none;
}
#media (max-width:767px) {
.mobile-div {
display: block;
}
}
Ofcourse you can expand on this by having a javascript function checking for the screen width, and use functions to open a popup when a certain width is reached (and is thus considered a mobile phone).
<script type="text/javascript">
(function () {
var width = $(window).width();
if (width < 400) {
// do something
}
})();
</script>
You can then search Google for a way of actually making the icon, for example this script might help you: https://github.com/h5bp/mobile-boilerplate/wiki/Mobile-Bookmark-Bubble. Although I think it is not possible in iOS to do this, you might have to consider creating an app that basically launches your website, or something similar. Ofcourse this will mean you have to pay for your app being displayed in the store, so it comes down to you: Do you really need this functionality, or not?
I know there are questions on this issue, but I tried everything and do not fix my mistake! X__X
I have a mobile application (astronomical) for Android and when I use to load another html, in the transition makes a white flash that I can't remove (I tried removing the transitions "slide" to use and nothing, background: # 000000! important, etc. ..). I use jQuery mobile 1.3.1 and Phonegap 2.9.0.
I'll share a video where you can see better the problem: http://www.youtube.com/watch?v=ykjCN03nOCM
Any help??
Regards,
Daniela.
CSS :
.ui-page {
-webkit-backface-visibility: hidden;
}
Code :
The CSS solution from this thread didn't work for me (Android 2.x).
I disabled the transistion with data-transition="none" in all links and everything was ok. It should also work when set on page-level, but it didn't work for me (jQuery Mobile 1.0). This is the code:
// turn off animated transitions for Android
if (navigator.userAgent.indexOf("Android") != -1)
{
$("a").attr("data-transition", "none");
}
Another (the better) way would be to set the default transitions for jQuery Mobile:
$(document).bind("mobileinit", function()
{
if (navigator.userAgent.indexOf("Android") != -1)
{
$.mobile.defaultPageTransition = 'none';
$.mobile.defaultDialogTransition = 'none';
}
});
iPhone performs the transitions hardware-accelerated, while the other platforms perform it per software. This explains why only iPhone performs smooth transitions.
Try this one here: here
Maybe your transitions will be more smoothly then.
I have the following setup (view in a narrow window, <750px wide): http://codepen.io/darrylhein/pen/oFalc
The problem is that the hide/show of the navigation doesn't work in Android's default browser. It seems to work pretty much everywhere else. (It does work in Firefox on Android.)
Basically I'm using input:checked ~ .class { height: 16em; } to show the nav.
I've tried removing the transition and a variety of other things and it doesn't seem to work.
Any ideas?
I'd like to avoid using JS, but if I have to I will.
So, 2 parts to the solution:
1) The problem occurs on Android <4.1.2. The solution is to add a fake animation on the body:
body { -webkit-animation: bugfix infinite 1s; }
#-webkit-keyframes bugfix {
from { padding:0; }
to { padding:0; }
}
2) There is also a problem on iOS <6 where labels do not check checkbox. The solution is to add an onclick to the label:
<label for="checkbox" onclick>Menu</label>
I found the solutions here: http://timpietrusky.com/advanced-checkbox-hack
I've also updated the codepen: http://codepen.io/darrylhein/pen/oFalc
I'd like to be able to mimic the behavior of the :active pseudo class on all elements in Android webkit. Currently, the :active syntax only works on a elements (links). Nearly all of the actionable elements in the app I'm working on are something other than a standard link tag. iOS webkit supports :active on all elements.
/* works on both android iOS webkit */
a:active {
color: blue;
}
/* works on iOS webkit, does not work on android webkit */
div:active {
color: red;
}
I've found a couple of resources [1,2] that solve similar problems, but they're both a bit heavy, and I'm wondering if there's a lighter weight solution that I'm just not able to find.
http://cubiq.org/remove-onclick-delay-on-webkit-for-iphone
http://code.google.com/intl/ro-RO/mobile/articles/fast_buttons.html
Based on what #caffein said, here's a full implementation of this:
For all :active code, write CSS rules that look like this.
my-button:active, .my-button.fake-active {
background-color: blue;
}
Then in your document ready event add this code:
if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
$(".my-button")
.bind("touchstart", function () {
$(this).addClass("fake-active");
})
.bind("touchend", function() {
$(this).removeClass("fake-active");
});
}
This has the advantage of using the fast native :active class on iOS, and dropping back to JavaScript on Android.
Taken from my blog at http://pervasivecode.blogspot.com/2011/11/android-phonegap-active-css-pseudo.html
EDIT: I've since discovered that buttons can occasionally 'stick' in the fake-active state. The fix for this is to also handle the touchcancel event. E.g. add this to the above..
.bind("touchcancel",
function() {
var $this = $(this);
$this.removeClass("fake-active");
});
If you don't want to use any script, which adds and removes class for active state of an element, just add empty touchstart event to the body tag:
<body ontouchstart="">
This will tell the android device to handle touch events and pseudo class :active will work correctly on all elements.
No-jQuery version based on Ben Clayton's solution.
EDIT: added "touchmove" event.
function hasClass(ele,cls) {
return ele.className.match(new RegExp("(\\s|^)"+cls+"(\\s|$)"));
}
function addClass(ele,cls) {
if (!this.hasClass(ele,cls)) ele.className += " "+cls;
}
function removeClass(ele,cls) {
if (hasClass(ele,cls)) {
var reg = new RegExp("(\\s|^)"+cls+"(\\s|$)");
ele.className=ele.className.replace(reg," ");
}
}
window.onload = function() {
if (navigator.userAgent.toLowerCase().indexOf("android") > -1) {
var elements = document.getElementsByClassName("my-button");
for(var i = 0; i < elements.length; i++) {
var elm = elements[i];
elm.addEventListener("touchstart", function() {
addClass(this, "fake-active");}, false);
elm.addEventListener("touchmove", function() {
removeClass(this, "fake-active");}, false);
elm.addEventListener("touchend", function() {
removeClass(this, "fake-active");}, false);
elm.addEventListener("touchcancel", function() {
removeClass(this, "fake-active");}, false);
}
}
}
The ":active " pseudo class is triggered when you actually click or press an element.
A workaround for smartphones is to use the Javascript events: "ontouchstart" & "ontouchend".
Try using ontouchstart to modify the style and ontouchend to actually trigger the action.
Since I can't comment, I'm going to add another answer here.
Nadzeya suggested the following solution:
<body ontouchstart="">
This does work as described, but I believe it may also have an unintended consequence.
There has been a problem on our site where buttons would occasionally stop working. In fact, the button would change colors (as if it was pressed) but the click event wouldn't fire. Even submit buttons on forms would fail to submit the form (no Javascript involved), even after appearing pressed.
Today, I saw the problem again. On a whim, I removed this attribute and the problem went away. I then added it again and the problem came back.
Since I can't reproduce the problem reliably, I can't be certain that this was the cause, but for now I'm going to leave the tag off and solve the :active problem another way.
try this. It works for me perfectly on Android
.my-button {
-webkit-tap-highlight-color: blue;
}
Trying add this code to your HTML:
<script>
document.body.addEventlistener('touchstart',function(){},false);
</script>
I got an easy alternate solution. This however requires you to change from div tag to a tag.
<a class="html5logo" href="javascript:void(0);" ontouchstart="return true;"></a>
.html5logo {
display: block;
width: 128px;
height: 128px;
background: url(/img/html5-badge-128.png) no-repeat;
-webkit-tap-highlight-color: rgba(0,0,0,0);
-webkit-tap-highlight-color: transparent; /* For some Androids */
}
.html5logo:active {
-webkit-transform: scale3d(0.9, 0.9, 1);
}
Please find the source at phone gap tutorial
you just need put this code in your document:
<script type="application/x-javascript">document.addEventListener('touchmove', function(e){e.preventDefault();}, false);</script>