Tap Click whatever finger motion event on iPhone 3GS - jquery-mobile

All I want to do is capture the event that a user taps an and clear it. I can't get anything to work with iPhone 3GS.. There is barely any documentation on how to actually use jQuery mobile.. that I can find anyway.. so theese are my guesses mostly:
$("#wrap").live('pageinit', function() {
$('#search_field').live('tap',function(event) {
if ($(this).val() == "Search Applications") {
$(this).val('');
}
});
});
This borks my design and adds a "loading" header at the bottom of the page....
Edit: Seems like it randomly works on the 3GS but the most annoying is that just jQuery mobile destroys my site layout!! my submit button jumps down
()

just looking over you code are you trying to use a place holder and clear it if the user taps it? If so you can simply add an attribute to your HTML5 like this:
<imput type="text" placeholder="Search Applications" />
Live example:
http://jsfiddle.net/KVuvm/
http://jsfiddle.net/KVuvm/1/ (With jQM Look and Feel)
http://jsfiddle.net/KVuvm/14/ (if you still wanted to use JS)

Related

Why/when do I have to tap twice to trigger click on iOS

Ok I feel like I'm crazy...
I'm looking at Mobile Safari on iOs 6.0. I can't seem to establish any rhyme or reason as to when tapping on an element will trigger click. In many cases, it seems I need to tap once to trigger a hover and then again to trigger a click.
The Mobile Safari spec says : "... The flow of events generated by one-finger and two-finger gestures are conditional depending on whether or not the selected element is clickable or scrollable... A clickable element is a link, form element, image map area, or any other element with mousemove, mousedown, mouseup, or onclick handlers... Because of these differences, you might need to change some of your elements to clickable elements..."
It goes on to suggest that the developer "...Add a dummy onclick handler, onclick = "void(0)", so that Safari on iOS recognizes the span element as a clickable element."
However, my testing has shown these statements to be false.
JsFiddle : http://jsfiddle.net/6Ymcy/1/
html
<div id="plain-div" onclick="void(0)">Plain Div</div>
js
document.getElementById('plain-div').addEventListener('click', function() {
alert('click');
});
Try tapping the element on an iPad. Nothing Happens
But I digress. What is important to me is to find out the following question:
Exactly what are the criteria that determine when clicking on an element will fire a 'click' event on the first tap? As opposed to firing a 'hover' event on the first tap and a 'click' event on the second tap.
In my testing, anchor elements are the only elements that I can get to fire a click on the first tap, and then, only occasionally and inconsistently.
Here's where I start to feel crazy. I searched the internet far and wide and found next to nothing about this issue. Is it just me?! Does anybody know where there's been any discussion about the criteria for two-taps and or an approach to dealing with these limitations?
I'm happy to respond to questions/requests.
Thanks!
I had this same issue. The simplest solution is not to bind the mouseenter event on iOS (or any touch enabled target platform). If that is not bound the hover event won't get triggered and click is triggered on the first tap.
iOS will trigger the hover event if an element is "display: none;" in the normal state and "display: block;" or inline-block on :hover.
It is also worthwhile to mention that ':hover' pseudo-class may prevent 'click' event from firing.
As in mobile browsers click is sometimes used to replace hovering action (e.g. to show dropdown menu), they may trigger artificial 'hover' state on first click and then handle click on the second one.
See https://css-tricks.com/annoying-mobile-double-tap-link-issue/ for detailed explanation and examples of that.
I solved this issue by first detecting if it was an iphone, then binding the mouseup event to the function I was trying to call.
if ((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))){
$('foo').on('mouseup', function(){
...
}
}
I tried other events but mouseup seemed to work best. Other events like touchend were firing even if the user was trying to scroll. Mouseup doesn't seem to get fired if you drag your finger after touching.
Credit David Walsh (and ESPN) for the iPhone detection.
http://davidwalsh.name/detect-iphone
I was having this issue using Bootstrap, and I found out that the culprit was the tooltip. Remove the tooltip from the button and you don't need to tap it twice anymore.
my solution was to remove the :hover state from the css, and when you think about it, mobile browsers should not have :hover state, since there is no hover..
if you want to keep the hover state on desktop, you can use media query, like so:
.button {
background: '#000'
}
#media (min-width: 992px) {
.button:hover {
background: '#fff'
}
}
You need #media (hover) { /* Your styles */ }
As far as I can tell, this problem in various forms is still present.
In 2019, most, if not all of the above cases can be now ameliorated using a CSS only solution... it will however, require some stylesheet refactoring.
label {
opacity:0.6
}
label input[type=radio]:checked+span {
opacity:1
}
.myClass::before { } /* Leave me empty to catch all browsers */
a:link { color: blue }
a:visited { color: purple }
a:hover { } /* Leave me empty to catch all browsers */
a:active { font-weight: bold }
/* Your styles */
#media (hover) {
a:hover { color: red }
.myClass::before { background: black }
label:hover {
opacity:0.8
}
}
You can read in more detail here why Fastclick, :pseudo, <span>, just targeting "desktop" resolutions and first tap is hover and second tap is click are all fixed using #media (hover): https://css-tricks.com/annoying-mobile-double-tap-link-issue/
:hover doesn't offer the clarity it once did as stylus input, touch desktops and mobile have a disparate interpretation of the notion.
The display:none; solution mentioned above works on iOS (not tested on later than 9.3.5), but not on Android.
A hacky css-only solution is to hide the link below the element using a minus z-index and to bring the link up to a positive z-index on :hover or first-touch (with a small transition delay). I guess one could achieve the same result with css translate instead of z-index. Works on iOS and Android.
In this way you can display a hover effect on a link on a touch-screen device with the first tap without activating the url until a second tap.
you can use ontouchstart instead of onclick event on element and call the function focus() on this element if it is input :
document.getElementById('plain-div').addEventListener('touchstart', function() {
//write body of your function here
alert(“hi”);
// if input needs double tap
this.focus();
});
I was googling around to see if i could help you out some and found this piece of code. Try modifying it to your likings and see if you can do what your trying. If you have troubles understanding it let me know and i'll elaborate more. Theres also more to it here where i found it
Jquery hover function and click through on tablet
$('clickable_element').live("touchstart",function(e){
if ($(this).data('clicked_once')) {
// element has been tapped (hovered), reset 'clicked_once' data flag and return true
$(this).data('clicked_once', false);
return true;
} else {
// element has not been tapped (hovered) yet, set 'clicked_once' data flag to true
e.preventDefault();
$(this).trigger("mouseenter"); //optional: trigger the hover state, as preventDefault(); breaks this.
$(this).data('clicked_once', true);
}
});
Never figured out the criteria, but this solved my problem by instantly triggering a click as soon as an element is tapped:
https://developers.google.com/mobile/articles/fast_buttons
I had to make a number of additions/modifications to their code to get it working correctly, let me know if you're interested in my method and I will try to post an explanation.
Cheers :)

jQuery mobile fixed footer, iOS web view, and scrollTop issue

I have a mobile application running Backbone.js and jQuery mobile. Because I have Backbone.js and for performance reasons I have disabled all the JQM routing and transitions. I understand that storing scroll location is a feature available in JQM, but I am unable to utilize that (as far as I know).
I have a list view with a potentially long list of items. When the user taps one on the mobile device, it stores the current scroll position and renders a new view. When the user taps the "back" button, it goes back one in the history.
clickLink: ->
window.lastScroll = $(window).scrollTop()
render: ->
...
if window.lastScroll
$.mobile.silentScroll window.lastScroll
window.lastScroll = undefined
This works as desired on desktop Safari, but when I try it using it on iOS Safari (both simulator and the real thing), there is an issue with the fixed footer navbar.
If the user taps back, the listview is scrolled down as intended, but then if they tap the footer navbar, it is as if they tapped under it, whatever list item is under it will be activated instead. If the user scrolls a little bit before tapping the navbar, everything works fine.
Does anyone have any ideas? Perhaps there is a better approach that would avoid this issue all together.
Thanks in advance for the help.
Could it be related to this bug?
Form elements can lose click hit area in position: fixed containers
(linked from here JQuery Mobile 1.1.0 docs )
I see there is a workaround in the first link - worth a try?
Chad Smith Answered this Mobile Safari bug on fixed positioned button after scrollTop programmatically changed...?
His method worked best for me. Here is his response:
I got around it by adding a 101% high div then (almost) immediately removing it.
Try:
<style>
.iosfix {
height: 101%;
overflow: hidden;
}
</style>
and when you scroll:
window.scrollTo(0, _NEW_SCROLLTOP_);
$('body').append($('<div></div>').addClass('iosfix'));
setTimeout(function() {
$('.iosfix').remove();
}, 500);
It also works with jQuery.scrollTo.
See an example here.

webkitfullscreenchange event not firing on iPad

I'm working on some video controls for the iPad. When the user clicks a button, the video plays and immediately goes fullscreen. When the user clicks the "Exit fullscreen" button, I want the video to pause. If I could disable the "Exit fullscreen" button and force the user to use the "Done" button I would, but that doesn't seem to be an option.
My problem is that the webkitfullscreenchange event does not seem to fire on the iPad. It works flawlessly in Chrome on the desktop. I've read that the iPad browser won't run your event if metadata has not been loaded (which doesn't load until the video is played on the iPad - preload is ignored), but I have confirmed that metadata has been loaded before the fullscreen event is firing. Does anyone have any ideas on why the webkitfullscreenchange event will not fire on the iPad?
<script type="text/javascript">
$(document).ready(function() {
$(".jqVidLink").click(function(e) {
e.preventDefault();
var vidId = $(this).attr("name");
playPause(document.getElementById(vidId));
});
$(".jqVideo").each(function() {
this.addEventListener("webkitfullscreenchange", function(){
alert("hi2"); //never fires
if (document.webkitIsFullScreen == false) {
playPause(this);
}
}, false);
this.addEventListener("loadedmetadata", function() {
alert("hi"); //firing
this.webkitEnterFullscreen();
}, false);
});
});
function playPause(myVideo) {
if (myVideo.paused){
myVideo.play();
}
else
myVideo.pause();
}
reminds me of an article calling the iPad the new IE6. Don't expect the iOS browser to behave like desktop safari.
as a workaround you could show the video inline (--> not with native fullscreen) and add your own controls. downside of this approach is that the browser navigation wastes some vertical-space. upside is you can fully control what's happening. following this idea you can imitate fullscreen by putting the video (and your custom controls) inside a container which then has to be positioned fixed and sized to 100% for width and height - i did that by adding a class as you don't have to worry about the previous size when switching back to normal. instead you simply remove the class again.
one other thing to keep in mind if you wanna do this: you cannot move a video-node via JS inside the container on iOS. Instead you either have to provide the full markup in html or clone the video-node, remove the original and insert the cloned one inside your container.
you can try the .element:-webkit-full-screen css property
I was not able to register a fullscreen exit event for iframes on Safari

iPad Safari - Make keyboard disappear

In iPad Safari browser, when I change focus from a textbox to a dropdown, the keyboard still remains... Is there some way (maybe with Javascript) I can hide the keyboard when user blurs from the textbox?
Indirectly speaking, I am looking for a equivalent of (but in Mobile Safari)
[tempTextField resignFirstResponder];
I found the solution for this at http://uihacker.blogspot.com/2011/10/javascript-hide-ios-soft-keyboard.html. Essentially, just do this (it worked for me):
var hideKeyboard = function() {
document.activeElement.blur();
$("input").blur();
};
I had iPad with iOS 5.0.1 not hiding the keyboard after successful login on my site. I solved by simply executing the javascript command
document.activeElement.blur();
after successful login and now the keyboard is correctly hidden :-)
I know this is a slightly older question, but I discovered the answer today for this, and the answer is embarrassingly simple... I spent way more time than I would like to admit figuring this out ;)
To prevent showing the keyboard on:
<input type="text" name="someInput" />
for when you want to do something like use a jQuery UI datepicker...
add a readonly attribute like so:
<input type="text" name="someInput" readonly="readonly" />
If you are trying to be mindful of people with JS turned off, you could always leave off the attribute and add it in your code:
$('[name=someInput]').attr('readonly','readonly');
Hope this helps.
Here is a jsFiddle demonstrating the concept: http://jsfiddle.net/3QLBz/5/
$("#txt").on("focus", function(){
$(this).blur();
});
works with jquery UI datepicker on IPad
Natively, iPad, iPhone keyboard should disappear when the input looses focus.
I figured out on mobile/tablet devices that
Safari only handles click event for elements having cursor:pointer
property.
I've finally added cursor:pointer on the body tag for mobile/tablet devices and it works like a charm.
Little sample
body {
#media (max-width: 1024px) { /* IPad breakpoint */
cursor: pointer; /* Fix iPhone/iPad click issue */
}
}
Version without jQuery:
function hideKeyboard () {
document.activeElement.blur();
Array.prototype.forEach.call(document.querySelectorAll('input, textarea'), function(it) {
it.blur();
});
}
I call .focus() on another textfield and the keyboard disappears. I'm using the Sencha touch framework, the textfield im referring to is an Ext.Text object.
I know this is counter-intuitive, but it seems to work for me
Sample.views.MessageBar.getComponent(0).blur();
document.activeElement.blur();
window.focus();
Sample.views.sendMessageBar.getComponent(0).setDisabled(true);
You can use codes above. First and Forth lines are for that textfield. It works on iphone but it doesnt work on Android. I tried Iphone 3gs and samsung galaxy s2.
According to Apple Safari documentation, when you select a dropdown (select list) the iOS dismisses the keyboard and displays native iOS select control. Make sure you use SELECT element for your dropdown list
and also try adding this to your meta tags for the page
<meta name="apple-mobile-web-app-capable" content="yes" />

Is it possible to force ignore the :hover pseudoclass for iPhone/iPad users?

I have some css menus on my site that expand with :hover (without js)
This works in a semi-broken way on iDevices, for example a tap will activate the :hover rule and expand the menu, but then tapping elsewhere doesn't remove the :hover. Also if there is a link inside the element that is :hover'ed, you have to tap twice to activate the link (first tap triggers :hover, second tap triggers link).
I've been able to make things work nicely on iphone by binding the touchstart event.
The problem is that sometimes mobile safari still chooses to trigger the :hover rule from the css instead of my touchstart events!
I know this is the problem because when I disable all the :hover rules manually in the css, mobile safari works great (but regular browsers obviously don't anymore).
Is there a way to dynamically "cancel" :hover rules for certain elements when the user is on mobile safari?
See and compare iOS behavior here: http://jsfiddle.net/74s35/3/
Note: that only some css properties trigger the two-click behavior, e.g. display:none; but not background: red; or text-decoration: underline;
I found that ":hover" is unpredictable in iPhone/iPad Safari. Sometimes tap on element make that element ":hover", while sometimes it drifts to other elements.
For the time being, I just have a "no-touch" class at body.
<body class="yui3-skin-sam no-touch">
...
</body>
And have all CSS rules with ":hover" below ".no-touch":
.no-touch my:hover{
color: red;
}
Somewhere in the page, I have javascript to remove no-touch class from body.
if ('ontouchstart' in document) {
Y.one('body').removeClass('no-touch');
}
This doesn't look perfect, but it works anyway.
:hover isn't the issue here. Safari for iOS follows a very odd rule. It fires mouseover and mousemove first; if anything is changed during these events, 'click' and related events don't get fired:
mouseenter and mouseleave appear to be included, though they're not specified in the chart.
If you modify anything as a result of these events, click events won't get fired. That includes something higher up in the DOM tree. For example, this will prevent single clicks from working on your website with jQuery:
$(window).on('mousemove', function() {
$('body').attr('rel', Math.random());
});
Edit: For clarification, jQuery's hover event includes mouseenter and mouseleave. These will both prevent click if content is changed.
A better solution, without any JS, css class and viewport check: you can use Interaction Media Features (Media Queries Level 4)
Like this:
#media (hover) {
// properties
my:hover {
color: red;
}
}
iOS Safari supports it
More about:
https://www.jonathanfielding.com/an-introduction-to-interaction-media-features/
The browser feature detection library Modernizer includes a check for touch events.
It’s default behavior is to apply classes to your html element for each feature being detected. You can then use these classes to style your document.
If touch events are not enabled Modernizr can add a class of no-touch:
<html class="no-touch">
And then scope your hover styles with this class:
.no-touch a:hover { /* hover styles here */ }
You can download a custom Modernizr build to include as few or as many feature detections as you need.
Here's an example of some classes that may be applied:
<html class="js no-touch postmessage history multiplebgs
boxshadow opacity cssanimations csscolumns cssgradients
csstransforms csstransitions fontface localstorage sessionstorage
svg inlinesvg no-blobbuilder blob bloburls download formdata">
Some devices (as others have said) have both touch and mouse events. The Microsoft Surface for example has a touch screen, a trackpad AND a stylus which actually raises hover events when it is hovered above the screen.
Any solution that disables :hover based on the presence of 'touch' events will also affect Surface users (and many other similar devices). Many new laptops are touch and will respond to touch events - so disabling hovering is a really bad practice.
This is a bug in Safari, there's absolutely no justification for this terrible behavior. I refuse to sabotage non iOS browsers because of a bug in iOS Safari which has apparently been there for years. I really hope they fix this for iOS8 next week but in the meantime....
My solution:
Some have suggested using Modernizr already, well Modernizr allows you to create your own tests. What I'm basically doing here is 'abstracting' the idea of a browser that supports :hover into a Modernizr test that I can use throughout my code without hardcoding if (iOS) throughout.
Modernizr.addTest('workinghover', function ()
{
// Safari doesn't 'announce' to the world that it behaves badly with :hover
// so we have to check the userAgent
return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) ? false : true;
});
Then the css becomes something like this
html.workinghover .rollover:hover
{
// rollover css
}
Only on iOS will this test fail and disable rollover.
The best part of such abstraction is that if I find it breaks on a certain android or if it's fixed in iOS9 then I can just modify the test.
Adding the FastClick library to your page will cause all taps on a mobile device to be turned into click events (regardless of where the user clicks), so it should also fix the hover issue on mobile devices. I edited your fiddle as an example: http://jsfiddle.net/FvACN/8/.
Just include the fastclick.min.js lib on your page, and activate via:
FastClick.attach(document.body);
As a side benefit, it will also remove the annoying 300ms onClick delay that mobile devices suffer from.
There are a couple of minor consequences to using FastClick that may or may not matter for your site:
If you tap somewhere on the page, scroll up, scroll back down, and then release your finger on the exact same position that you initially placed it, FastClick will interpret that as a "click", even though it's obviously not. At least that's how it works in the version of FastClick that I'm currently using (1.0.0). Someone may have fixed the issue since that version.
FastClick removes the ability for someone to "double click".
There are basically three scenarios:
User only has a mouse/pointer device and can activate :hover
User only has a touchscreen, and can not activate :hover elements
User has both a touchscreen and a pointer device
The originally accepted answer works great if only the first two scenarios are possible, where a user has either pointer or touchscreen. This was common when the OP asked the question 4 years ago. Several users have pointed out that Windows 8 and Surface devices are making the third scenario more likely.
The iOS solution to the problem of not being able to hover on touchscreen devices (as detailed by #Zenexer) is clever, but can cause straightforward code to misbehave (as noted by the OP). Disabling hover only for touchscreen devices means that you will still need to code a touchscreen friendly alternative. Detecting when a user has both pointer and touchscreen further muddies the waters (as explained by #Simon_Weaver).
At this point, the safest solution is to avoid using :hover as the only way a user can interact with your website. Hover effects are a good way of indicating that a link or button is actionable, but a user should not be required to hover an element to perform an action on your website.
Re-thinking “hover” functionality with touchscreens in mind has a good discussion about alternative UX approaches. The solutions provided by the answer there include:
Replacing hover menus with direct actions (always visible links)
Replacing on-hover menus with on-tap menus
Moving large amounts of on-hover content into a separate page
Moving forward, this will probably be the best solution for all new projects. The accepted answer is probably the second best solution, but be sure to account for devices that also have pointer devices. Be careful not to eliminate functionality when a device has a touchscreen just to work around iOS's :hover hack.
The JQuery version
in your .css use
.no-touch .my-element:hover
for all your hover rules
include JQuery and the following script
function removeHoverState(){
$("body").removeClass("no-touch");
}
Then in body tag add
class="no-touch" ontouchstart="removeHoverState()"
as soon as the ontouchstart fires the class for all hover states is removed
I agree disabling hover for touch is the way to go.
However, to save yourself the trouble of re-writing your css, just wrap any :hover items in #supports not (-webkit-overflow-scrolling: touch) {}
.hover, .hover-iOS {
display:inline-block;
font-family:arial;
background:red;
color:white;
padding:5px;
}
.hover:hover {
cursor:pointer;
background:green;
}
.hover-iOS {
background:grey;
}
#supports not (-webkit-overflow-scrolling: touch) {
.hover-iOS:hover {
cursor:pointer;
background:blue;
}
}
<input type="text" class="hover" placeholder="Hover over me" />
<input type="text" class="hover-iOS" placeholder="Hover over me (iOS)" />
Instead of only having hover effects when touch is not available I created a system for handling touch events and that has solved the problem for me. First, I defined an object for testing for "tap" (equivalent to "click") events.
touchTester =
{
touchStarted: false
,moveLimit: 5
,moveCount: null
,isSupported: 'ontouchend' in document
,isTap: function(event)
{
if (!this.isSupported) {
return true;
}
switch (event.originalEvent.type) {
case 'touchstart':
this.touchStarted = true;
this.moveCount = 0;
return false;
case 'touchmove':
this.moveCount++;
this.touchStarted = (this.moveCount <= this.moveLimit);
return false;
case 'touchend':
var isTap = this.touchStarted;
this.touchStarted = false;
return isTap;
default:
return true;
}
}
};
Then, in my event handler I do something like the following:
$('#nav').on('click touchstart touchmove touchend', 'ul > li > a'
,function handleClick(event) {
if (!touchTester.isTap(event)) {
return true;
}
// touch was click or touch equivalent
// nromal handling goes here.
});
Thanks #Morgan Cheng for the answer, however I've slightly modified the JS function for getting the "touchstart" (code taken from #Timothy Perez answer), though, you need jQuery 1.7+ for this
$(document).on({ 'touchstart' : function(){
//do whatever you want here
} });
Given the response provided by Zenexer, a pattern that requires no additional HTML tags is:
jQuery('a').on('mouseover', function(event) {
event.preventDefault();
// Show and hide your drop down nav or other elem
});
jQuery('a').on('click', function(event) {
if (jQuery(event.target).children('.dropdown').is(':visible') {
// Hide your dropdown nav here to unstick
}
});
This method fires off the mouseover first, the click second.
For those with common use case of disabling :hover events on iOS Safari, the simplest way is to use a min-width media query for your :hover events which stays above the screen width of the devices you are avoiding. Example:
#media only screen and (min-width: 1024px) {
.my-div:hover { // will only work on devices larger than iOS touch-enabled devices. Will still work on touch-enabled PCs etc.
background-color: red;
}
}
For someone still looking for a solution if none of the above worked,
Try this,
#media (hover: hover)
{
.Link:hover
{
color:#00d8fe;
}
}
This hover pseudo will only be applied for devices with pointers and works normal on touch devices with just .active classes.
Just look at the screen size....
#media (min-width: 550px) {
.menu ul li:hover > ul {
display: block;
}
}
heres the code you'll want to place it in
// a function to parse the user agent string; useful for
// detecting lots of browsers, not just the iPad.
function checkUserAgent(vs) {
var pattern = new RegExp(vs, 'i');
return !!pattern.test(navigator.userAgent);
}
if ( checkUserAgent('iPad') ) {
// iPad specific stuff here
}

Resources