iOS automatic hover fix? - javascript

Is there a jQuery plugin or JavaScript script that automagically loops through each CSS hover (found in an external stylesheet) and binds it with a double touchdown event?
Touchdown 1 - CSS :hover is triggered
Touchdown 2 - Click (link following or form action)
If there isn't something like this yet, can it be made and how (guidelines)?
EDIT:
To be clear, I am not in search of a double tap. Touchdown 1 is a single tab just like Touchdown 2 is. There can be as less as 0 seconds between both or as much as 3 minutes, that's the user's choice.
No touch:
:hover -> element becomes visible
click -> following link or other action
Touch (iOS):
touchdown 1 -> element becomes visible
touchdown 2 -> following link or other action

Try this:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>iPad Experiment</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
if(navigator.platform == "iPad") {
$("a").each(function() { // have to use an `each` here - either a jQuery `each` or a `for(...)` loop
var onClick; // this will be a function
var firstClick = function() {
onClick = secondClick;
return false;
};
var secondClick = function() {
onClick = firstClick;
return true;
};
onClick = firstClick;
$(this).click(function() {
return onClick();
});
});
}
});
</script>
<style type="text/css">
a:hover {
color:white;
background:#FF00FF;
}
</style>
<body>
Google
stackoverflow.com
</body>
</html>
... or check out the demo on my web site. Note that it's set up to only work its magic on the iPad - detecting all versions of the iOS is another question in my books ;)
It works on the basis of the fact that...
After you click a link on the iphone or ipad, it leaves a simulated mouse hover that triggers the a:hover css styling on that link. If the link has a javascript handler that keeps you on same page, the hover state will not change until you click on another link.
Citation: Safari iphone/ipad “mouse hover” on new link after prior one is replaced with javascript

I've used this:
$(document).ready(function() {
$('.hover').bind('touchstart touchend', function(e) {
e.preventDefault();
$(this).toggleClass('hover_effect');
});
});
Before, to allow hover on certain elements. Obviously you'll need to tweak it for your own use, but it's a nice way to allow a touch and hold hover effect.

Here is a further optimized version that also handles closing the :hover
You'll have to encapsulate your site with a
<div id="container"></div>
for it to work. Just putting the closing event on the body did nothing
var bodyBound = false;
var container;
if (navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/iPad/i))
{
container = $("#container");
// Provoke iOS :hover event
$("a.someLink").on("mouseover", handleHoverClick);
}
function handleClose(event)
{
container.off("click", handleClose);
bodyBound = false;
}
function handleHoverClick(event)
{
if (!bodyBound)
{
bodyBound = true;
// Somehow, just calling this function—even if empty—closes the :hover
container.on("click", handleClose);
}
}

I created this update apon Richard JP Le Guens solution. It works GREAT, but my version fixes the issue recognized by DADU.
Also I fixed his workaround to detect iPads. My solution detects any other touch devices too (except IE10 on MS surface, I didn't remember the MS special treatment).
My fix is not a 100% perfect solution, but it resets the hover fix at least when hovering another link.
<!DOCTYPE html>
<html>
<head>
<title>TouchDevice Experiment</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
if(document.createEvent("TouchEvent")) { // using document.createEvent is more reliable than navigator (Modernizr uses this practice)
$("a").each(function() { // have to use an `each` here - either a jQuery `each` or a `for(...)` loop
var onClick; // this will be a function
var firstClick = function() {
$("a").trigger("JWUnhover"); // triggering hoverfix reset if any link gets touched
onClick = secondClick;
return false;
};
secondClick = function() {
onClick = firstClick;
return true;
};
onClick = firstClick;
$(this).click(function() {
return onClick();
});
$(this).bind('JWUnhover', function(){ onClick = firstClick; });
});
}
});
</script>
<style type="text/css">
a:hover {
color:white;
background:#FF00FF;
}
</style>
</head>
<body>
Google
stackoverflow.com
</body>
</html>

There is no jQuery plugin that I know of to do such a thing.
You cannot trigger a css psuedo class such as ":hover". You can however loop through the anchor elements and add a css class ".hover" on touchstart and touchend events as follows:
var pageLinks = document.getElementsByTagName('a');
for(var i = 0; i < pageLinks.length; i++){
pageLinks[i].addEventListener('touchstart', function(){this.className = "hover";}, false);
pageLinks[i].addEventListener('touchend', function(){this.className = "";}, false);
}
To add a double finger tap gesture recognizer, you can use a plugin such as:
http://plugins.jquery.com/project/multiswipe

This worked for me!
// Ipad Navigation Hover Support
$('#header .nav li a').bind('touchstart touchend', function(e) {
if( $(this).attr("href") != "" ){
window.location = $(this).attr("href");
}
});

Here's an optimized version of the jQuery code provided by Richard JP Le Guen:
$(document).ready(function() {
$('a').each(function() {
var clicked = false;
$(this).bind('click', function() {
if(!clicked) return !(clicked = true);
});
});
});

There is a more simpler way to fix the issue with iOS and hover states, using CSS. For the link you have an issue with set the cursor property to pointer and the hover state will be ignored on iOS. For all links to function as expected, see below:
a
{cursor: pointer;}

Related

iphone keyboard not hiding when tapping the screen

I have an input field with number type
<input type="number" pattern="[0-9]*"/>
In normal browsers, I'm typing some numbers and I'm tapping the screen, it hides iphone/ipad keyboard.
But this is not working if it is inside iframe. we need to click done button explicitly. This issue is only for iphone/ipad
This is an iframe issue. Any fix using Javascript/Jquery would be highly appreciated.
Updated
Tried
document.activeElement.blur();
and focusout when event triggered in javascript. none of them are working..
$(document).on('focusin', function(){
$('input').css("background-color", "green");
console.log('focusin!')
});
$(document).on('focusout', function(){
console.log('focusout!')
$('input').css("background-color", "yellow");
$('input').blur();
});
focusout is not calling inside iframe!
My question is **How to force close ipad/iphone keypad when input element is not focused using Javascript/Jquery?**
Answers will be rewarded as stated!
To remove the keyboard you need to lose the focus on your input.
document.activeElement.blur();
With this line you remove the focus and the keyboard disappear.
In your case, it's possible to add an event on your body, and stop this event if you click on an input.
$(document).ready(function () {
$('body').click(function () {
document.activeElement.blur();
console.log("blur");
});
$('input').click(function (event) {
event.stopPropagation();
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="text"/>
Update
I found this answer to get an active element into an iframe.
/**
* Return the active element in the main web or iframes
* #return HTMLElement
**/
function getActiveElement() {
var focused = false;
// Check if the active element is in the main web or no
if (document.body === document.activeElement ||
document.activeElement instanceof HTMLIFrameElement) {
// Search in iframes
$('iframe').each(function() {
var element = this.contentWindow.document.activeElement;
// If there is a active element
if (element !== this.contentWindow.document.body) {
focused = element;
return false; // Stop searching
}
});
} else focused = document.activeElement;
return focused; // Return element
}
With this function you can get the active element on the document or into an iframe.
After, you need to remove the focus on this element to hide the keyboard.
getActiveElement().blur();
html target <input> and <textarea>, iphone and ipad will not hide keyboard when taping on blank area ;but android will! we need to hide keyboard by hand -- it means to set the input blur;
here gose the code
$(function(){
var cacheInput = null;
var timer = null;
if(!isApple()){
return false;
}
$(document).on('focus','input',function(e){
cacheInput = e.target;
})
$(document).on('focus','textarea',function(e){
cacheInput = e.target;
})
$(document).on('touchend',function(e){
if(e.target.tagName!=='INPUT'&&e.target.tagName!=='TEXTAREA'){
if(cacheInput!==null){
timer = setTimeout(function(){
cacheInput.blur();
clearTimeout(timer);
},300)
}
}
})
function isApple(){
var ua = navigator.userAgent.toUpperCase();
var
ipad = ua.indexOf('IPAD')>-1,
ipod = ua.indexOf('IPOD')>-1,
iphone = ua.indexOf('IPHONE')>-1 ;
return ipad || ipod || iphone ;
}
})
github: https://github.com/wikieswan/iphone-input-blur
demo: http://wikieswan.github.io/iphone-input-blur
In an ionic application I used a directive on the body that intercepts the inputs.
MyApp.directive('dismissIosKeyboardOnClick', function () {
return function (scope, element, attrs) {
if (cordova.platformId=="ios") {
element.on("touchstart", function(e) {
var keyboardDoms = new Set(["INPUT","TEXTAREA","SELECT"]);
if( keyboardDoms.has(document.activeElement.nodeName) &&
!keyboardDoms.has(e.target.nodeName) )
document.activeElement.blur();
});
}
};
});
Index.html
<body ... dismiss-ios-keyboard-on-click></body>
Hope this'll solve your issue, it simply removes the focus on active element.
Using Javascript
document.activeElement.blur();
Using jQuery
$("#Clicked_button_id").click(function() {
$("#input_field_id").blur();
});
Try this.
This detects when you tab any element but the input and then blurs it.
$("html").children().not("#input_field_id").click(function(){
$("#input_field_id").blur();
});
I might possibly have a solution for your issue on iOS. My configuration is safari on iOS 8.3/5C.
From my experiments it seems to me that body element in Safari/iOS is not receptive to any click events. I am not able to explain why but it seems so.
So, what I have done is: put a wrapper div just inside body and allow it to receive the click.
Main.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>keyboard hide issue</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
//!SOLUTION
$('#body-wrapper').click(function(e) {
console.log('I got clicked');
});
});
</script>
<style>
/* ignore this. Its just styles. ... */
div#body-wrapper {
height: 200px;
width: 100%;
background-color: red;
}
input {
margin: 10px;
}
</style>
</head>
<body>
<div id="body-wrapper">
<input type="text" id="main-input1"/>
<input type="number" id="main-input2"/>
<input type="email" id="main-input3"/>
</div>
<iframe src="blur.html"></iframe>
</body>
</html>
blur.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Blur iFrame</title>
<script
src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
//!SOLUTION
$('#wrapper').click(function(e) {
//do nothing
});
});
</script>
<style>
/* ignore this. Its just styles. ... */
div#wrapper {
height: 100px;
width: 100%;
background-color: yellow;
}
</style>
</head>
<body>
<div id="wrapper">
<input type="number" pattern="[0-9]*" id="main-input"/>
</div>
</body>
</html>
In both files I am able to hide the keyboard just fine. Again, I don't know the underlying reason but do let me know if you aren't able to replicate the solution.
I have not tried it on an iPad. Thanks ...
Well... You can give me that reward cause I just solved this problem using a very SIMPLE solution.
Step 1
:
Check if the input is currently in focus. I'll explain later why we need to add a delay on changing the value of inputFocused variable.
var inputFocused = false;
$('input').focus(function(){
setTimeout(function(){
inputFocused = true;
},100);
});
Step 2: Add an event listener if the screen or $(window) is tapped or clicked. If the window was tapped or clicked, check if the input is currently in focus. If true you must focus the window $(window).focus(), after focusing the window, the blur() function will now work! so you can now unfocus the input element then the keyboard will now hide automatically, then set the inputFocused variable to false again.
$(window).click(function(){
if(inputFocused == true){
$(window).focus();
var input = $('input');
input.blur();
inputFocused = false;
}
});`
SetTimeout explanation:
The $(window).click() event will trigger if the user tap or click anywhere on the screen (e.g. Button click, Input click, tap or click screen, etc). If you tap the input, at the same time setting the inputFocused to true, the $(window).click() event triggers then check if inputFocused is true then will run the code which hides the virtual keyboard. So it means that whenever you focus an input field the keyboard will hide and that'll be a problem.
That's why we're adding a delay so that the code inside if(inputFocused == true) will not run while we're focusing the input field and it will only run if the input field is currently on focus.
TRIED AND TESTED!

Javascript: Eventhandler not functioning, works in JSFiddle

So this is an answer to another question I posted and I think it is the correct solution. However, while it works wonderfully in jsfiddle it does not function whatsoever outside of that environment. I have tried multiple combinations and I cannot get this thing to work right.
I've tried onLoad in the body, Window.onload both in the header wrapping around the function and separately calling it at the base of the page after all the elements have loaded. Nothing works.
I always get this issue:
Uncaught TypeError: Cannot call method 'addEventListener' of null
Which is frustrating, because all other solutions to this error I have seen revolve around ensuring you do in fact have the specified ID the handler triggers off of in your HTML. Which I do.
I know its probably overkill to make a post here on this but I'm yanking my hair out.
Here's the JSfiddle: http://jsfiddle.net/fFW5r/1/
Here's a mockup page I made to test the concept (which never works):
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
<script type="text/javascript">
var link_container = document.getElementById('links');
function myFunction(){ link_container.addEventListener('click', function(e){
if(e.target.nodeName === "A"){
var href = e.target.getAttribute('href'),
selfhost = window.location.hostname;
if(href.indexOf(selfhost) !== -1){
alert('Inbound link clicked');
} else {
alert('Outbound link clicked');
}
}
}, false);
}
</script>
</head>
<body onload="myFunction()">
<div id="links">
Inbound Link
Outbout Link
</div>
<script>window.onload=myFunction()</script>
</body>
</html>
This particular iteration I was trying to test it with the onload call at the bottom of the page after everything had loaded.
var link_container = document.getElementById('links'); need to be executed on document.onload so it has to be inside myFunction
In jsfiddle, the code is executed on load by default. in the fiddle at the left side panel > second select box if you select no wrap - in head you can recreate the problem.
Demo: Fiddle
<script type="text/javascript">
function myFunction(){
var link_container = document.getElementById('links'); // <<-- Move it inside `myFunction()`
link_container.addEventListener('click', function(e){
if(e.target.nodeName === "A"){
var href = e.target.getAttribute('href'),
selfhost = window.location.hostname;
if(href.indexOf(selfhost) !== -1){
alert('Inbound link clicked');
} else {
alert('Outbound link clicked');
}
}
}, false);
}
</script>
The reason it doesn't work is that you are initializing link_container before the DOM is ready. Then when myFunction() runs, link_container has been initialized to undefined. Which causes it to fail. Initializing it in the function (after the DOM has loaded) should fix the issue
Put declare link_container inside the function.
var link_container = document.getElementById('links');
function myFunction(){
link_container.addEventListener('click', function(e){
if(e.target.nodeName === "A"){
var href = e.target.getAttribute('href'),
selfhost = window.location.hostname;
if(href.indexOf(selfhost) !== -1){
alert('Inbound link clicked');
} else {
alert('Outbound link clicked');
}
}
}, false);
}

Optimizing jQuery Spoiler Button

HTML
<!doctype html>
<html>
<head>
</head>
<body>
<button id="b1" type="button">Show Spoiler</button>
<p id="p1" style="display:none"> This is a damn paragraph.</p>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript" src="js/script.js"></script>
</body>
</html>
JS
function bindEvent(element, eventName, eventHandler) {
var el = $(element)[0];
if (el.addEventListener) {
el.addEventListener(eventName, eventHandler, false)
} else if (el.attachEvent) {
el.attachEvent('on'+eventName, eventHandler);
}
}
bindEvent('#b1', 'click', function() {
$('#p1').toggle('blind');
if ($('#b1').text() == 'Show Spoiler') {
$('#b1').text('Hide Spoiler');
} else if ($('#b1').text() == 'Hide Spoiler') {
$('#b1').text('Show Spoiler');
}
});
I'm new to jQuery and Javascript so I made this simple script to show and hide a paragraph and to change the button texts whenever clicked. My problem is that this seems a bit clunky. Is there a better, shorter, and simpler way to achieve the same result?
First of all, jQuery already normalizes DOM event listeners for you across browsers, so your bindEvent function isn't necessary anymore. Here's the short way, using some stuff you can look up yourself in the jQuery API, to do what you're doing.
var $b1 = $('#b1')
, $p1 = $('#p1')
, hideText = 'Hide Spoiler'
, showText = 'Show Spoiler'
$b1.on('click',function() {
var text = $b1.text()
, newText = text === showText ? hideText : showText
$p1.toggle('blind')
$b1.text(newText)
})
Here are a few things to notice:
Your example function assumes a single spoiler #p1 and a single reveal button #b1. In production, this will probably be based on classes, like .spoiler and .spoiler-trigger, and there will be multiple spoilers on a page. In that case, you'll need to get the value of this. In this example let's assume that the reveal button is always a sibling of the spoiler itself.
$('.spoiler-trigger').on('click',function() {
var $this = $(this)
, $thisSpoiler = $this.siblings('.spoiler').eq(0)
, text = $this.text()
, newText = text === showText ? hideText : showText
$thisSpoiler.toggle('blind')
$this.text(newText)
})
The jQuery .on method is the cross-browser event listener function that you'll want to start using.
jQuery selectors we use repeatedly, like $(this) or $('#b1'), should be cached in local variables for performance.
I'm using a ternary conditional instead of an if statement to determine what the show/hide text should be, because in this very simple case I consider it more readable.
You can make this work with simple 3 lines of code using awesome jquery. trigger the button click event, and on click -> toggle the element 'P'. This should help : working demo
$("#b1").click(function () {
$("#p1").toggle('slow');
});​

JQuery - also trigger change on click away

I have a basic JQuery script that changes a few divs when you click - thus showing them - via toggle.
<script type="text/javascript">
$('#content_display').click(function() {
$(this).toggleClass('selected');
$('#content_display_selector_container').toggle();
});
</script>
However - to call the even you need to click only on the first main div with the ID of "content_display".
My question is this: how can I hide these changes using JQuery if the user also clicks on BODY - i.e. if you click away, the divs go back to their original hidden state?
Thanks for helping a JQuery clutz!
Something like this should work:
$('body').click(function(e) {
if (!$(e.target).is('#content_display')) {
$('#content_display').removeClass('selected');
$('content_display_selector_container').hide();
}
});
Hey - found a way to do this - does anyone think there's a better way?
Here's the result:
<script type="text/javascript">
var mousetrap = false;
$('body').click(function() {
if (mousetrap == false) {
$('#content_display').removeClass('selected');
$('#content_display_selector_container').hide();
}
});
$('#content_display').hover(function() {
mousetrap = true;
},function(){
mousetrap = false;
});
$('#content_display').click(function() {
$(this).toggleClass('selected');
$('#content_display_selector_container').toggle();
});
</script>

How to close a javascript menu

I'm creating pulldown menus that must be clicked on to open. This code lets the user opening menus just fine. The only problem is I haven't figured out how to close the menus yet by clicking outside the menus. I tried adding the "document.onclick" shown, but it takes effect even in the menus.
I think I need to prevent document.onclick from being captured by other elements, but am not sure how to do this cross-platform. Can someone please show me how?
<script type="text/javascript">
var lastOpenedMenuId = null;
function showMenu(menuId) {
if (lastOpenedMenuId != null && lastOpenedMenuId != menuId) {
hideLastOpenedMenu();
}
setMenuVisibility(menuId, 'visible');
lastOpenedMenuId = menuId;
}
function hideMenu(menuId) {
setMenuVisibility(menuId, 'hidden');
}
function hideLastOpenedMenu() {
if (lastOpenedMenuId != null) {
hideMenu(lastOpenedMenuId);
}
}
function setMenuVisibility(menuId, visibleOrHidden) {
var menuElement = document.getElementById(menuId);
menuElement.style.visibility = visibleOrHidden;
}
document.onclick = hideLastOpenedMenu;
</script>
<div onmousedown="showMenu('foodmenu')"><a>FOOD</a></div>
<div id="foodmenu" onmouseup="hideMenu('foodmenu');">
Meat
Tofu
</div>
Thanks in advance.
I have made some progress and have reformulated the question here:
How to stop onclick event in div from propagating to the document?
Depending on whether you have a page layout like this:
<body>
<div id="menu"><!--Menu Stuff--></div>
<div id="main"><!--Main page stuff--></div>
</body>
you could put the onClick handler to close the menu on the div with the id "main" which should work
Someone pointed me to a solution that uses addEventListener. Say, the div is the menu. This code allows the user to click on the document outside the div to do something, such as close the menu. Clicking on the div (say, on a link) will not propagate to the document.
<head>
<script>
function menuHandler(event) {
alert("div clicked");
// Don't propogate the event to the document
if (event.stopPropagation) {
event.stopPropagation(); // W3C model
} else {
event.cancelBubble = true; // IE model
}
}
document.onclick = function() {
alert('document clicked');
};
function addListener() {
var foodMenuElement = document.getElementById('foodmenu');
if (foodMenuElement.addEventListener) {
foodMenuElement.addEventListener('click', menuHandler, false);
} else {
foodMenuElement.attachEvent('onclick', menuHandler);
}
}
</script>
</head>
<body onload="addListener()">
<div id="foodmenu" style="border: 1px solid red;">Click inside this div</div>
or click outside the div.
</body>
Note that the third argument "false" to addEventListener means "fire the event during the capturing phase", but the value doesn't matter because the event propagation is canceled in menuHandler.
This solution works, but I'd like to do the same thing more simply, without addEventListener, so have posted a question at How to stop onclick event in div from propagating to the document?

Categories