How to manually trigger the mouseleave event on a mobile device - javascript

I want to change a link color to orange on hover.
On a mobile device, when the user touches the link, it becomes orange and will remain orange until the user clicks away. So I want to manually trigger the mouseout event so that the link looses it's hover effect after 1 seconds.
This is what I have tried but the link remains orange after 1 second:
$(window).on('load', function() {
$('a').on('click', function() {
// on a mobile device, I want the hover effect to end after 1 seconds
window.setTimeout(function() {
$('a').trigger('mouseout');
}, 1000);
});
});
a {
font-size: 2rem;
}
a:hover {
color: orange;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a href='#'>Test</a>
</div>
Note: this is a simplified example, in my code I am not using a timer instead I want to trigger the mouseout event on ajaxcomplete
$(document).on('ajaxComplete', function () {
$('a').trigger('mouseout');
});

The problem is trying to force a mouseout event doesn't seem to work on a touch device.
The series of events that is fired on a touch device starts with a touchstart event - see e.g. MDN
If the browser fires both touch and mouse events because of a single user input, the browser must fire a touchstart before any mouse events.
This snippet remembers that the user has started a touch event and instead of acting on mouse events it sets a class which changes the text color. The same is done on mouse events, which are only acted on when the user is not appearing to be using a touch device on this element.
While it would seem logical to look subsequently for the touchend event on the element, it seems that if the user does a long touch on it, given it is an anchor element, the touchend event is not fired on the element when they remove their finger/pointing device. It is however still fired on the window and so we catch that event and remove the hover class.
let usingTouch = false;
const a = document.querySelector('a');
a.addEventListener('touchstart', function() {
usingTouch = true;
a.classList.add('hover');
});
window.addEventListener('touchend', function() {
usingTouch = true;
setTimeout(function() {
a.classList.remove('hover');
}, 1000);
});
a.addEventListener('mouseover', function() {
if (!usingTouch) a.classList.add('hover');
});
a.addEventListener('mouseout', function() {
if (!usingTouch) a.classList.remove('hover');
});
a {
font-size: 2rem;
}
.hover {
color: orange;
}
<div>
<a href='#'>Test</a>
</div>

a {
font-size: 2rem;
}
a:hover {
color: myanimation 1s 1;
-webkit-animation:myanimation 1s 1;
}
#keyframes myanimation
{
0% {color:orange;}
100% {color:orange;}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<a href='#'>Test</a>
</div>
This is solvable via a CSS animation, see the snippet above.

Related

Double click is being triggered when first click is done in an overlay div

I have an overlay div and a button, below, with a double click event attached. When the overlay is clicked, it is supposed to be hidden. If I double click the overlay, with the mouse over the button, the double click event is triggered in the button. Is this the correct behavior? Am i doing anything wrong? Is there any work around to prevent the triggering on the button?
Code example:
var $container = $('#absolute-container');
var $button = $('#button');
// On container click, hide the container
$container.on('click', function (e) {
e.stopPropagation();
e.preventDefault();
$container.hide();
});
$button.on('dblclick', function () {
alert('double click');
});
Here is a jsfiddle with an example:
https://jsfiddle.net/o0qsbd43/18/
Thanks
You'll need to have a very slight delay on firing off the normal click action, which you cancel when the double click event happens.
ref: https://css-tricks.com/snippets/javascript/bind-different-events-to-click-and-double-click/
var $container = $('#absolute-container');
var $button = $('#button');
function doClickAction(e) {
e.stopPropagation();
e.preventDefault();
$container.hide();
}
function doDoubleClickAction(e) {
e.stopPropagation();
e.preventDefault();
}
var timer = 0;
var delay = 200;
var prevent = false;
$container
.on("click", function(e) {
timer = setTimeout(function() {
if (!prevent) {
doClickAction(e);
}
prevent = false;
}, delay);
})
.on("dblclick", function(e) {
clearTimeout(timer);
prevent = true;
doDoubleClickAction(e);
});
$button.on('dblclick', function () {
alert('double click');
});
.absolute-container {
background: black;
opacity: 0.5;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="absolute-container" class="absolute-container" ></div>
<div>
<button id="button">Double Click Button</button>
</div>
I think on click and double click events event is fired when you release the bouse button. Double click is a single event that calculates time between clicks.
In your case you release button on single click but for firing double click browser is still waiting if there will be second click and release of the button within a second or so depending on OS configuration.
So in your case second click release occurs on top of the button and double click event is fired.
Solution I could propose is to make a delay when hiding your overlay layer. For example if you will make 1 second timeout and during this timeout make a fadeout effect or something like this, the time interval the browser is waiting for the second click to fire double click even will expire and you can do your double click on the button. Note sure I explained correctly and intuitively.

Trigger Javascript event on different target

I have a element which adds a child to itself when a mousedown or touchstart event occurs. This child is resizable (jQuery ui widget). I use http://touchpunch.furf.com/ wich enables jquery-ui widgets for touch devices.
I want to resize the child when it gets created without lifting the mouse/touch and clicking again. It works for mouse devices but i fail to trigger it when using a touch device.
Check the snippet (works for mouse, fails with touch).
Mousedown on blue element (red element is created)
Keep mouse down and drag to the right (red element gets resized)
I fail making it work for a touch device.
I create the element on touchstart, but i am not able to resize it whithout lifting my finger.
I basically want to achieve the same with touch as with the mouse. Problem is I don't know how the event must look like which I have to trigger on the resize-handle.
I check if it is a touch event and try to change the event.target but this does not work.
if (event.type === "touchstart") {
console.log("here i am stuck")
event.target = handler[0];
item.trigger(event);
}
$(function(){
$(document).on("mousedown touchstart", ".resizeCreator", function(event){
if ($(this).find("div").length){
return;
}
//Add resizable div
$(this).append("<div>resize me</div>");
$(this).find("div").resizable({handles: "e"});
simulateHandleEvent($(this).find("div"), event)
});
$(document).on("click", "button", function(){
$(".resizeCreator").find("div").remove();
});
})
var simulateHandleEvent = function(item, event){
var handler = item.find(".ui-resizable-e").first();
if (event.type === "touchstart") {
console.log("here i am stuck")
event.target = handler[0];
item.trigger(event);
}else{
handler.trigger("mouseover");
handler.trigger({
type: "mousedown",
which: 1,
pageX: handler.offset().left,
pageY: handler.offset().top
});
}
}
.resizeCreator{
width:200px;
height:200px;
padding:5px;
border:1xp solid black;
background-color:blue;
}
.resizeCreator div{
background-color:red;
display:inline-block;
padding:5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://raw.githubusercontent.com/furf/jquery-ui-touch-punch/master/jquery.ui.touch-punch.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" rel="stylesheet"/>
<div class="resizeCreator">
</div>
<button>reset</button>

Smooth scrolling nor working when element is dynamically wrapped with anchor

For the mobile devices I want to convert all the h1 headings to anchors that can scroll smoothly to their target. To achieve that, when a certain device resize occurs, i just wrap the content of the h1 tag with an a tag and then unwrap the content of the a tag when the device comes back to desktop width.
$(document).ready(function() {
// Add smooth scrolling to all links
$("a").on('click', function(event) {
// Make sure this.hash has a value before overriding default behavior
if (this.hash !== "") {
// Prevent default anchor click behavior
event.preventDefault();
// Store hash
var hash = this.hash;
// Using jQuery's animate() method to add smooth page scroll
// The optional number (800) specifies the number of milliseconds it takes to scroll to the specified area
$('html, body').animate({
scrollTop: $(hash).offset().top
}, 800, function() {
// Add hash (#) to URL when done scrolling (default click behavior)
window.location.hash = hash;
});
} // End if
});
});
//the function to convert the heading to an anchor for devices smaller than 780px
function makeResponsive() {
if ($(window).width() < 780) {
if ($('a').length) {
return true;
} else {
$('h1').each(function() {
$(this).contents().eq(0).wrap('');
});
}
} else {
$('a').contents().unwrap();
}
}
//run on document load and on window resize
$(document).ready(function() {
//on load
makeResponsive()
//on resize
$(window).resize(function() {
makeResponsive();
});
});
body,
html,
.main {
height: 100%;
}
section {
min-height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>
The Heading
</h1>
<div class="main">
<section></section>
</div>
<div class="main" id="section2">
<section style="background-color:blue"></section>
</div>
The problem is that when the h1 content is converted to an anchor, the smooth scrolling is not happening at all and the anchor just jumps to the target.
Your a-Tag doesn´t get the click event, because you add the listener when it doesn´t exist.
Try this
$(document).on('click', 'a', function(event) {...
Instead of wrapping it in anchors, just add 'mobile-anchor' class to those headings. Then, instead of listening for clicks on anchor, listen for clicks on 'mobile-anchor' and change:
$('html, body').animate({
scrollTop: $('#section2').offset().top
}, 800, function() {
Or even a simpler solution - before the very end of your on click function, add a 'return false;' so the browser doesn't scroll the page down by itself.
EDIT: Also, wrap everything in a single documentReady function and execute the makeResponsive() before adding a click listener.

jQuery .bind method not activating the second time?

I have an element, which fills the screen. Under that I have another element which does NOT fill the screen but is hidden. So you can't manually scroll to that.
The first element which is filling the screen has the following CSS properties:
header {
position: relative;
height: 100vh;
background-color: green;
}
And the second element has these CSS properties:
#content {
display: none;
position: relative;
height: 1500px;
width: 100%;
background-color: yellow;
}
I use this code to trace the scrolling:
$('header').bind("DOMMouseScroll mousewheel", function(e) {
...
});
Inside this method I check which panel is activated (by a self created boolean) and which direction I'm scrolling to, by doing this:
$('header').bind("DOMMouseScroll mousewheel", function(e) {
var wheelDelta = e.originalEvent.wheelDelta;
if (active === header && wheelDelta <= 0) {
...
}
});
Inside that if statement I give call a method that displays the #content element below it and smoothly scrolls to it, and when its done scrolling it hides the element where we have scrolled from (header). I'm using this piece of code for that:
$('body').bind("DOMMouseScroll mousewheel", function (e) {
event.preventDefault();
var wheelDelta = e.originalEvent.wheelDelta;
$('header').unbind("DOMMouseScroll mousewheel");
if (active === header && wheelDelta <= 0) {
showScrollHide(500, content, 1000, header, 250, function () {
_window.scrollTop(0);
_scrollBackBtn.fadeIn();
active = content;
});
}
});
This works perfectly, whenever I scroll down on the header element while its active. It smoothly scrolls down to the #content element under it.
There I have a button which scrolls back up the page, I have this code for it:
_scrollBackBtn.on('click', function() {
if (active === content) {
active = header;
scrollBackHide(header, content, 500, 250, function() {
window.location = '#';
});
}
});
Which also works perfectly, it scrolls back to the top of the page.
But whenever I try to scroll down again, it doesn't do anything. How does this come?
I had to add $('header').unbind("DOMMouseScroll mousewheel"); to the code, otherwise it looked very ugly in the end result.
Whenever I added $('header').stop(); in the same section, it didn't make any difference.
So my question is. How can this .bind method be used again for the same thing?
Here's a demo if you don't understand what I mean. Whenever you scroll down on the header element, and scroll back up via the button. Its not doing the same again.
You are unbinding your mousewheel handlers when they run once and then never re-binding them, so there are no event handlers in place to react to mousewheel events after you click the button. Re-binding that event handler when you click the button does the trick.
Here is a fiddle that does that and should point you in the right direction.
I pulled your mousewheel handler out into a function so we can reuse it whenever we need to bind those events:
var handleMouseWheel = function(e){
e.preventDefault();
var wheelDelta = e.originalEvent.wheelDelta;
if (active === header && wheelDelta <= 0) {
$('body').unbind("DOMMouseScroll mousewheel");
showScrollHide(500, content, 1000, header, 250, function () {
_window.scrollTop(0);
_scrollBackBtn.fadeIn();
active = content;
});
}
};
and use that to reattach an event handler when the button is clicked:
_scrollBackBtn.on('click', function () {
if (active === content) {
scrollBackHide(header, content, 500, 250, function () {
window.location = '#';
active = header;
});
$('body').bind("DOMMouseScroll mousewheel", handleMouseWheel);
}
});

javascript/jquery: How to prevent from continuing to fade in and fade out

In my example code/jsfiddle: If you move your mouse back and forth quickly over the word testing to where your mouse leaves the div(#footer_logo_container), hovers the div, leaves the div, etc.....it is like the script counts how many times your mouse goes over it, and the div(#powered_by) fades in/fades out/fades in/fades out over and over again depending on how many times your mouse went over the div.
Question: Is there a way to make it that when the mouse goes over the #footer_logo_container, the #powered_by div appears. I also would like to find out if there is a way to have it so it stays faded in for a minimum amount of time (x seconds) once the mouse moves off #footer_logo_container where if the mouse continues to go in and out of the text, it ignores it until the #powered_by is completely faded out.
JSFIDDLE: http://jsfiddle.net/5jEmc/1/
Script:
$(document).ready(function() {
$("#footer_logo_container").hover(
function() { $(this).find("#powered_by").fadeIn(); },
function() { $(this).find("#powered_by").fadeOut(); }
);
});
HTML:
<div id="footer_logo_container">
Testing<br /><br /><br />
<div id="powered_by">FadeIn</div>
</div>
CSS: #powered_by { display: none; }
You have to use stop() See more
Working Demo
Jquery
$(document).ready(function() {
$("#footer_logo_container").hover(
function() { $(this).find("#powered_by").stop().fadeIn(); },
function() { $(this).find("#powered_by").stop().fadeOut(); }
);
});
If you want delay before executing fadeOut, use this line.
function() { $(this).find("#powered_by").stop()delay(1000).fadeOut(); }
$(document).ready(function() {
$("#footer_logo_container").hover(
function(event) { $(this).find("#powered_by").fadeIn();
event.stopImmediatePropagation()},
function(event) {
$(this).find("#powered_by").fadeOut();
event.stopImmediatePropagation()}
);
});

Categories