jquery.ui.touch.punch.js script is preventing input functionality on touch devices - jquery-ui

It took me a little bit, but I figured out that I can't click on my inputs because of the touch.punch script I'm using to enable jquery UI drag functionality on touch devices. Anyone familiar with this script know why that might be? The form actually resides down the tree of the parent object. Does anyone know a way I can override or force through the selection? I'm going to try binding events that force focus to the input right now but maybe someone here has some insight?

JEditable + jQuery UI Sortable + jquery.ui.touch-punch
I have spent all day on this problem and I finally figured out the solution. The solution is very similar to kidwon's answer. However, I was using jeditable which dynamically creates input fields without class names. So I used this conditional statement instead of checking the class name:
//Check if element is an input or a textarea
if ($(touch.target).is("input") || $(touch.target).is("textarea")) {
event.stopPropagation();
} else {
event.preventDefault();
}
I think this is a better solution as it always uses the native functionality for any input or textarea fields.

To anyone who might wind up here with a similar situation using the very handy touch.punch hack, simply forcing the focus through on a click event will work just fine!
$('.input').bind('click', function(){
$(this).focus();
});

Folks, the other two answers here did NOT work for me, but Danwilliger's solution works; however, it's not clear from his answer how exactly to set it up in the Touch Punch JS file. For future answer-seekers, here's what to do. Again, this is Danwilliger's solution -- I'm just clarifying.
Change this section in jquery.ui.touch-punch.js (on approximately line 30):
function simulateMouseEvent (event, simulatedType) {
// Ignore multi-touch events
if (event.originalEvent.touches.length > 1) {
return;
}
event.preventDefault();
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
To this:
function simulateMouseEvent (event, simulatedType) {
// Ignore multi-touch events
if (event.originalEvent.touches.length > 1) {
return;
}
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
//Check if element is an input or a textarea
if ($(touch.target).is("input") || $(touch.target).is("textarea")) {
event.stopPropagation();
} else {
event.preventDefault();
}
Best of luck!

OK here's another solution if your textfield whatever HTML element is ain't focusing,scrolling, selecting words, moving text cursor around the text and whatever different scenarios might come then you may override the jquery.ui.touch.punch.js script.
I assume that your element isn't the draggable one but probably a child of it as my case was.
Put a class on your html element, for example class="useDefault".
Then go to the script file and find that part:
...
function simulateMouseEvent (event, simulatedType) {
// Ignore multi-touch events
if (event.originalEvent.touches.length > 1) {
return;
}
event.preventDefault();
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
....
As you can probably see event.preventDefault(); assures that jquery.ui.touch.punch.js
overrides the default behaviors of the browser. To prevent that for our particular class node, make the following modifications:
if (event.originalEvent.touches.length > 1) {
return;
}
var touch = event.originalEvent.changedTouches[0],
simulatedEvent = document.createEvent('MouseEvents');
//As you can see here is your class element check
if (touch.target.className === "useDefault") {
event.stopPropagation();
} else {
event.preventDefault();
}
This solution is tested with webkit browsers only and jQuery UI Touch Punch 0.2.2 release.
Hope that quick solution helps, BR

Thanks to #Danwilliger and #jeremytripp for the solution. Being that this issue has been known for years and yet has still not been worked into touch-punch author's Git repo, I forked it with the solution added here:
https://github.com/copernicus365/jquery-ui-touch-punch/blob/master/jquery.ui.touch-punch.js
I would be quite happy for the author to incorporate those few lines of a change into the original library and make this one unneeded then, but if that never happens, it's nice to have a single source file to reference.

Jacob's answer worked with a slight modification—I found that using the click event resulted in inconsistent behavior on iPad, ios9 Safari. Sometimes I'd press once on a field and it would focus, other times I had to press three times. Changing click to touchstart solved the problem for me (I also used event delegation since my form was added dynamically):
$('form').on('touchstart', 'input,textarea',function(){
$(this).focus();
});

One solution is to use a handle.
Add an icon inside and use this to drag. Then the inputs work fine.
<li><span class="move">Move</span><input...../></li>
$("#sortableList").sortable({
handle: ".move"
});

I actually tried adding the lines which Danwilliger mentioned, it did not do the trick for me.
What worked for me was
//Check if element is an input or a textarea
if ($(touch.target).is("input") || $(touch.target).is("textarea")) {
event.stopPropagation();
$(touch.target).focus();
} else {
event.preventDefault();
}
I am not really sure why the other answers posted did not work, but for anyone else out there if they have the same issue try my solution out :).

Throttlehead's solution worked for me. Simpler perhaps to just use the JQuery selectors to cover all inputs and textareas:
$('input,textarea').bind('click', function(){
$(this).focus();
});

Related

Material Select blinking on iOS

I am trying to create my website in Material Design, however I found one issue with Material Select regardless whether I use MDB (Material Design for Bootstrap) or Materialize CSS framework. Both are working fine on Windows/OSX/Android , however for some reason when I open Material Select component on my iPad and click on it, there is a blinking cursor showing from the Background of the Dropdown.
Try the following code:
input.select-dropdown {
-webkit-user-select:none;
-moz-user-select:none;
-ms-user-select:none;
-o-user-select:none;
user-select:none;
}
I had the same issue on iOS devices, I am using select dropdown from materialisecss "http://materializecss.com/forms.html".
to fix the blinking cursor issue, I used reference code from below link and slightly modified that code.
Ref Link: https://github.com/Dogfalo/materialize/issues/901 (check comment by "chi-bd commented on 17 Nov 2015")
jQuery('select').material_select();
/*--- Materialize Select dropdown blinking cursor fix for iOS devices ---*/
jQuery('select').siblings('input.select-dropdown').on('mousedown', function(e) {
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
if (e.clientX >= e.target.clientWidth || e.clientY >= e.target.clientHeight) {
e.preventDefault();
}
}
});
jQuery('select').material_select(); to initialize materialise select and rest code is the fix.
the only problem was this was giving problem on desktop view so added mobile detection condition
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
Note: Add this code in document ready $(document).ready(function() { ... });
that's it. I hope this will sort out your issue.
Regards, and have a nice day :)
There is an open issue on github, #StaticBR proposed an approach to solve "Dropdown Broken on iPhone (and Safari in general)" issue, link here.
According to #StaticBR,
"The Issue is that IO13 Safari propagate TouchEnd Events before the Click event is propagated.
So if you have a click listener within an drop down, it is not correctly triggerd, because the Dropwdown is getting closed by the TouchEnd event. After that the click event is at a different position or does not longer exist.
Removing the touch event listener solved this issue for me."
Apologies, the above code works but then it stops the scrolling for drop-down.
For now I am using below fix, but it shows the blinking cursor first and then it hides it. but still this is not the perfect solution, if anyone has better solution please post here :)
function checkDropDown(obj){
var nextObj = jQuery(obj).next();
setTimeout(function(){
if (jQuery(nextObj).is(":visible")){
jQuery("input.select-dropdown").css({
"transition" : "none",
"left" : "-999999px"
});
}else{
jQuery("input.select-dropdown").css({
"left" : 0
});
}
}, 250);
jQuery(document).ready(function(){
jQuery("input.select-dropdown").on("focus", function(){
checkDropDown(jQuery(this));
});
jQuery("input.select-dropdown").on("blur", function(){
checkDropDown(jQuery(this));
});
});

Google Places Autocomplete with Jquery Mobile not working on mobile/touch device

As title suggests I am building a mobile website with JQuery Mobile (1.3.0) and am trying to implement Google Places Autocomplete (API v3) to aid user input of location data.
The autocomplete functions correctly on desktop device, but not when used on a mobile device (I have only tested on iOS 6).
When used on mobile device the dropdown list of relevant locations do appear, but simply disappear when you press one without loading the selection on the map.
I have looked around and seen some solutions that sight the z-index of
.pac-container
as the culprit (see: http://osdir.com/ml/google-maps-js-api-v3/2012-01/msg00823.html).
I have implemented these fixes but to no avail, and I am not convinced that z-index is the problem because I can see that the selected item does change to it's :hover state/colour when pressed on mobile.
Please if anyone has suggestions I am all ears, need any more details let me know.
Saravanan's answer is a bit overkill. To fix the conflict with FastClick and PAC, add the needsclick class to both the pac-item and all its children.
$(document).on({
'DOMNodeInserted': function() {
$('.pac-item, .pac-item span', this).addClass('needsclick');
}
}, '.pac-container');
Thanks Daniel. But the solution I have given has some performance impact.
I have modifed the FastClick library little bit to accomplish that.
First I have added a param to FastClick constructor, where defaultElCls will be the elements which should not implement fastclick.
function FastClick(layer, defaultElCls) {
'use strict';
var oldOnClick, self = this;
this.defaultElCls = defaultElCls;
Then modify needsClick method:
FastClick.prototype.needsClick = function(target) {
'use strict';
var nodeName = target.nodeName.toLowerCase();
if (nodeName === 'button' || nodeName === 'input') {
// File inputs need real clicks on iOS 6 due to a browser bug (issue #68)
// Don't send a synthetic click to disabled inputs (issue #62)
if ((this.deviceIsIOS && target.type === 'file') || target.disabled) {
return true;
}
} else if (nodeName === 'label' || nodeName === 'video') {
return true;
}
return ((/\bneedsclick\b/).test(target.className) || (new RegExp(this.defaultElCls).test(target.className)));
};
Then pass pac-item to the FastClick constructor
new FastClick(document.body, "pac-item");
Hope this will be taken care by FastClick library as well :)
I've also encountered this bug, and determined fastclick to be the culprit. I was originally going to go with Devin Smith's answer, but epegzz's warning about MutationEvents being deprecated led me to MutationObservers, and since I haven't seen a fix involving them I thought I'd share my solution.
var observer_config = { attributes: false, childList: true, subTree: false, characterData: false }
var observer = new MutationObserver( function(mutations) {
var self = this;
mutations.forEach(function(mutation){
// look for the container being added to the DOM
var pac_container_added = $(mutation.addedNodes).hasClass('pac-container');
// if it is, begin observing it
if (pac_container_added){
var pac_container = mutation.addedNodes[0];
self.observe(pac_container, observer_config);
}
// look for pac-items being added (as children of pac_container)
// This will not resolve if the observer on pac-container has not been created
var pac_item_added = $(mutation.addedNodes).hasClass('pac-item');
// when pac items are added, add the needsclick class
if (pac_item_added) {
$('.pac-item, .pac-item span').addClass('needsclick')
}
});
});
observer.observe(document.body, observer_config);
It is more complex than I'd like it to be because we can't just add observer.observe('pac_container') in the top level, since its added asynchronously. Luckily, the solution for that problem is also MutationObservers.
We add another observer to pac_container when it is created. That way, it detects the pac-items being added, and when they are, we add the needsclick class.
This is my first time using MutationObservers, so feedback/improvements would be appreciated. As you can see, I used both jquery, but it should be pretty easy to pull it out.
There is a patch for fastclick that makes it work well with google places autocomplete. See This answer :)
After much hair pulling I have found the problem to be the "FastClick" library I added to my project.
As #Saravanan Shanmugam points out in this comment https://stackoverflow.com/a/16932543/1177832
FastClick seems to interfere with autocomplete. Also see above link for the workaround he has added to get the two to play nice.

Wordpress Foundations submenu not displaying in iPad

i'm still new to the mobile / fluid / responsive game and am having issues with the submenu on this site: http://www.medowsconstruction.com/
the click on mobile should replace the :hover function automagically right? seems to be the case with the standard Foundation theme.
i hadn't changed anything in those mobile specific areas of the framework, so what did I do to mess it up and cause the submenu to not show on iPad / touch?
thanks for any help
It seems that the problem is that this is not a standard pure CSS dropdown menu, as one might assume. Instead, it's been controled by jQuery. You can see it in the app.js file:
$('.nav-bar>li.has-flyout').hover(function() {
$(this).children('.flyout').show();
}, function() {
$(this).children('.flyout').hide();
});
So you should modify the script in order to work with a touch for selected devices (there is a good discussion on that topic here). Here I am using a simple statement. I have not been able to test it in iPad, but you could have good results if you try to use something like (untested!):
if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
$('.nav-bar>li.has-flyout').bind('touch', function() {
$(this).children('.flyout').slideToggle();
});
} else {
$('.nav-bar>li.has-flyout').hover(function() {
$(this).children('.flyout').show();
}, function() {
$(this).children('.flyout').hide();
});
}
This should give you some clues on how to deal with that. Let us know if it works.
There is also a lot of information in this stackoverflow discussion about hover and touch devices.
thanks to #hernan for setting me in the right direction with things.
i ended up fixing it up by mixing the Foundation code with his code with some better selectors. here's what I landed with:
if (navigator.userAgent.match(Modernizr.touch || navigator.userAgent.match(/Windows Phone/i))) {
$('.nav-bar>li.has-flyout').on('click.fndtn touchstart.fndtn', function(e) {
e.preventDefault();
var flyout = $(this).children('.flyout').first();
if (lockNavBar === false) {
$('.nav-bar .flyout').not(flyout).slideUp(500);
flyout.slideToggle(500, function(){
lockNavBar = false;
});
}
else
{
flyout.slideToggle(500);
}
});
i'l definitely be checking into those two links / discussions you mentioned, too, hernan.
thanks again-

jQuery UI drag and drop not working when flowplayer is included

See example here: http://jsfiddle.net/KK36F/2/
How to solve this?
My old answer of:
http://jsfiddle.net/KK36F/5/
I've used jQuery noConflict to work around flowPlayer. As I can't
reproduce your problem (flowPlayer is blocked on my site rrrrr) it's
the best I can do.
Didn't work... I've managed to reproduce the problem and track it down to a line in the flowplayer code:
// skip IE policies
document.ondragstart = function () { return false; };
If you make this safer (as it is a JScript only IE thing), the draggable works again.
if(document.ondragstart) {
document.ondragstart = function () { return false; };
}

Is there any way to control the layout of the close button on a jQuery Mobile custom select menu?

I have a custom select menu (multiple) defined as follows:
<select name="DanceStyles" id="DanceStyles" multiple="multiple" data-native-menu="false">
Everything works fine except that I want to move the header's button icon over to the right AND display the Close text. (I have found some mobile users have a problem either realising what the X icon is for or they have trouble clicking it, so I want it on the right with the word 'Close' making too big to miss.) There don't seem to be any options for doing that on the select since its options apply to the select bar itself.
I have tried intercepting the create event and in there, finding the button anchor and adding a create handler for that, doing something like this (I have tried several variations, as you can see by the commenting out):
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn').button({
create: function (event, ui) {
var $btn = $(this);
$btn.attr('class', $btn.attr('class').replace('ui-btn-left', 'ui-btn-right'));
$btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// $(this).button({ iconpos: 'right' });
// $btn.attr('class', $btn.attr('class').replace('ui-btn-icon-notext', 'ui-btn-icon-left'));
// // $btn.attr('data-iconpos', 'left');
$(this).button('refresh');
}
});
}
});
});
So I have tried resetting the button options and calling refresh (didn't work), and changing the CSS. Neither worked and I got weird formatting issues with the close icon having a line break.
Anyone know the right way to do this?
I got this to work cleanly after looking at the source code for the selectmenu plugin. It is not in fact using a button; the anchor tag is the source for the buttonMarkup plugin, which has already been created (natch) before the Create event fires.
This means that the markup has already been created. My first attempt (see my question) where I try to mangle the existing markup is too messy. It is cleaner and more reliable to remove the buttonMarkup and recreate it with my desired options. Note that the '#search' selector is the id of the JQ page-div, and '#DanceStyles' is the id of my native select element. I could see the latter being used for the id of the menu, which is why I select it first and navigate back up and down to the anchor; I couldn't see any other reliable way to get to the anchor.
$('#search').live('pagecreate', function (event) {
$("#DanceStyles").selectmenu({
create: function (event, ui) {
$('ul#DanceStyles-menu').prev().find('a.ui-btn')
.empty()
.text('Done')
.attr('class', 'ui-btn-right')
.attr("data-" + $.mobile.ns + "iconpos", '')
.attr("data-" + $.mobile.ns + "icon", '')
.attr("title", 'Done')
.buttonMarkup({ iconpos: 'left', icon: 'arrow-l' });
}
});
});
The buttonMarkup plugin uses the A element's text and class values when creating itself but the other data- attributes result from the previous buttonMarkup and have to be removed, as does the inner html that the buttonMarkup creates (child span, etc). The title attribute was not recreated, for some reason, so I set it myself.
PS If anyone knows of a better way to achieve this (buttonMarkup('remove')? for example), please let us know.
the way i achieved it was changing a bit of the jquery mobile code so that the close button always came to the right, without an icon and with the text, "Close"
not the best way i agree. but works..
I got a similar case, and I did some dirty hack about this :P
$("#DanceStyles-button").click(function() {
setTimeout(function(){
$("#DanceStyles-dialog a[role=button]").removeClass("ui-icon-delete").addClass("ui-icon-check");
$("#DanceStyles-dialog .ui-title").html("<span style='float:left;margin-left:25px' id='done'>Done</span>Dance Styles");
$("#DanceStyles-dialog .ui-title #done").click(function() {
$("#DanceStyles").selectmenu("close")
});
},1);
} );

Resources