I have long vertical list of links that user can scroll through, and I need to prevent triggering a click event (touch) on this links if user scrolls.
In current scenario, when user start scrolling by tapping over the link, it also triggers a click on link. Which is obviously bad. So, is there any way to prevent such a behavior?
Working fiddle
We could use a flag in this case to prevent click event just during the scroll and enable it after the scroll stop.
To listen on scroll stop you could use jQuery’s data method that gives us the ability to associate arbitrary data with DOM nodes and using setTimeout() function that will check every 250ms if the user still trigger the scroll, and if not it will change the flag :
var disable_click_flag = false;
$(window).scroll(function() {
disable_click_flag = true;
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
disable_click_flag = false;
}, 250));
});
$("body").on("click", "a", function(e) {
if( disable_click_flag ){
e.preventDefault();
}
});
Hope this helps.
Related
I want to make sure when a user is on the page.
Hence, when a user clicks on another window (looses focus) or changes tab, I should stop playing video on my page.
The problem is trying to do both simultaneously.
For example, through this JS plugin (JQuery Visbility), I am able to check whether the tab/window of my page is open.
Here's how it's doing it:
$(document).on({
'show': function() {
console.log('The page gained visibility; the `show` event was triggered.');
},
'hide': function() {
console.log('The page lost visibility; the `hide` event was triggered.');
}
});
But it can't detect whether the page has focus or not. For example, the page might be open, but I may be opening another window separately and keeping my focus there.
The following code takes care of that (taken from here):
function check()
{
if(document.hasFocus() == lastFocusStatus) return;
lastFocusStatus = !lastFocusStatus;
statusEl.innerText = lastFocusStatus ? 'with' : 'without';
}
window.statusEl = document.getElementById('status');
window.lastFocusStatus = document.hasFocus();
check();
setInterval(check, 200);
Now, I am trying to do both simultaneously. Is it possible?
You can add event listeners for the window's focus and blur events.
var hasFocus = true;
$(window).focus(function(){
hasFocus = true;
});
$(window).blur(function(){
hasFocus = false;
});
//check the hasFocus variable to see if the window has focus
I have a button <button class="foo">Foo</button> with an event handler attached to it that expands or collapses a block using .slideToggle()
$('.foo').on('click', function () {
const fooBlock = $(this).next();
fooBlock.slideToggle(() => {
fooBlock.toggleClass('hidden');
});
If a user clicks the button when an animation is in transition then the click is queued. How do I stop the animation if the user clicks the button while the animation is already executing?
A much better solution is to just use stop(true) to clear the queue on successive clicks. This means the UI is still responsive to user input during the animation and also prevents the animations building up. Try this:
$('.foo').on('click', function() {
const fooBlock = $(this).next();
fooBlock.stop(true).slideToggle(() => {
fooBlock.toggleClass('hidden');
});
});
I have a script that refreshes a Div on my website every 20 seconds. The problem is, once it refreshes, it scrolls to the to of the Div. I want it to stay at the last position and not scroll to the top after a refresh. Could someone please look at this script and maybe point out what I'm doing wrong? Thanks in advance!
var time = new Date().getTime();
var refreshTime = 20*1000;
$(document).bind("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error hover change", function(e) {
time = new Date().getTime();
});
var lastScrollPos = 0;
$('#feed1').on('scroll', function() {
lastScrollPos = this.scrollTop;
});
function refresh() {
if(new Date().getTime() - time >= refreshTime)
$('#feed1').load(location.href="/dashboard" , function () {
$(this).scrollTop(lastScrollPos);
});
else
setTimeout(refresh, refreshTime);
}
setTimeout(refresh, refreshTime);
Why don't you use feed1 div only for loading your dashboard contents and handle its position using style.
#feed1 {
height: 150px;
overflow: auto;
}
Add other data outside feed1 div because load method will overwrite feed1's content.
See this example if you are looking for something similar otherwise you can modify this example so that other can understand your requirement/scenario.
If you do location.href="/dashboard", the browser will discard all the page's state (including scripting variables) and load "/dashboard" (assigning a value to location.href is identical to calling location.assign("/dashboard")).
The jQuery load function will probably not even require you to reposition the scroll offset, if you gave it chance to execute!
Try:
$('#feed1').load("/dashboard #feed1");
UPDATE:
It seems the HTTP request fired by jQuery's load mechanism is receiving a truncated response in your case (content-length: 0).
You would have to put the scroll position you want to keep into localStorage. Try:
var time = new Date().getTime();
var refreshTime = 20*1000;
$(document).bind("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error hover change", function(e) {
time = new Date().getTime();
});
var previousScrollPos = localStorage.getItem("lastScrollPos");
if(previousScrollPos)
{
$('#feed1').scrollTop(previousScrollPos);
localStorage.removeItem("lastScrollPos");
}
function refresh() {
if(new Date().getTime() - time >= refreshTime)
{
localStorage.setItem("lastScrollPos", $('#feed1').scrollTop());
location.reload();
}
}
setInterval(refresh, refreshTime);
I'm not 100% sure that you want to bind to the scroll event of #feed1 or just of body, I haven't seen your page. If anybody clicks "load more" on the news feed, those additional items will be hidden again since you're reloading the page. Not ideal at all.
Many users will hate having the page periodically reload, it's also an accessibility failure since this will interfere with screen reading software. It might be a simpler idea to just put a refresh newsfeed icon on the page, which just reloads the whole page, when the user wants to (instead of periodically).
I am working with JavaScript and jQuery in an UIWevView on iOS.
I'v added some javascript event handler that allow me to capture a touch-and-hold event to show a message when someone taps an img for some time:
$(document).ready(function() {
var timeoutId = 0;
var messageAppeared = false;
$('img').on('touchstart', function(event) {
event.preventDefault();
timeoutId = setTimeout(function() {
/* Show message ... */
messageAppeared = true;
}, 1000);
}).on('touchend touchcancel', function(event) {
if (messageAppeared) {
event.preventDefault();
} else {
clearTimeout(timeoutId);
}
messageAppeared = false;
});
});
This works well to show the message. I added the two "event.preventDefault();" lines to stop imgs inside links to trigger the link.
The problem is: This also seems to prevent drag events to scroll the page from happen normally, so that the user wouldn't be able to scroll when his swipe happens to begin on an img.
How could I disable the default link action without interfering with scrolling?
You put me on the right track Stefan, having me think the other way around. For anyone still scratching their head over this, here's my solution.
I was trying to allow visitors to scroll through images horizontally, without breaking vertical scrolling. But I was executing custom functionality and waiting for a vertical scroll to happen. Instead, we should allow regular behavior first and wait for a specific gesture to happen like Stefan did.
For example:
$("img").on("touchstart", function(e) {
var touchStart = touchEnd = e.originalEvent.touches[0].pageX;
var touchExceeded = false;
$(this).on("touchmove", function(e) {
touchEnd = e.originalEvent.touches[0].pageX;
if(touchExceeded || touchStart - touchEnd > 50 || touchEnd - touchStart > 50) {
e.preventDefault();
touchExceeded = true;
// Execute your custom function.
}
});
$(this).on("touchend", function(e) {
$(this).off("touchmove touchend");
});
});
So basically we allow default behavior until the horizontal movement exceeds 50 pixels.
The touchExceeded variable makes sure our function still runs if we re-enter the initial < 50 pixel area.
(Note this is example code, e.originalEvent.touches[0].pageX is NOT cross browser compatible.)
Sometimes you have to ask a question on stack overflow to find the answer yourself. There is indeed a solution to my problem, and it's as follows:
$(document).ready(function() {
var timeoutId = 0;
$('img').on('touchstart', function(event) {
var imgElement = this;
timeoutId = setTimeout(function() {
$(imgElement).one('click', function(event) {
event.preventDefault();
});
/* Show message ... */
}, 1000);
}).on('touchend touchcancel', function(event) {
clearTimeout(timeoutId);
});
});
Explanation
No preventDefault() in the touch event handlers. This brings back scrolling behavior (of course).
Handle a normal click event once if the message appeared, and prevent it's default action.
You could look at a gesture library like hammer.js which covers all of the main gesture events across devices.
I would like to display a helpful DIV that basically shows the user how to accomplish something on a particular page, but only if the user has been idle for a period of time, say, 30seconds.
What I mean by "Idle" is:
Not clicking any links
Not right clicking anywhere
Exceptions:
I would like to exclude the following conditions from the Is User Idle rule:
User has scrolled up or down/left or right
User has pressed mouse button on an empty area on the site/ or on an element which has no source/link for example, an image with no hyperlink.
and, Pressing keyboard buttons
Can this be done? Or can we only detect when a particullar event occurs?
Any thoughts/suggestions/resources will be greatly appreciated.
Thank you
fairly basic...
var trigger = 30000
$.(function(){
setInterval('displayInf()',trigger );
$('body').bind('click dblclick keypress mousemove scroll', function(){
clearDisplayInf();
});
});
function displayInf()
{
$('body').append('<div>Your notification div</div>');
}
function clearDisplayInf()
{
trigger = clearInterval(trigger);
trigger = setInterval('displayInf()', 30000 );
}
that should do the trick - you could add some script to make the div removable and start the timer again once its removed but that just polishing up really..
Event in DOM would bubble from leaf to root, thus add a event listener on document would make sense.
But since we are possibiliy stop bubbling for click event in certain element, register click event on document may not work perfectly, in that case, register mousedown and mouseup event would help:
var timer; // create a timer at first
// restart timer on click
function startIdle() {
timer = setTimeout(function() { /* show div */ }, time);
}
if (document.addEventListener) {
document.addEventListener('mouseup', startIdle, false);
}
else {
document.attachEvent('onmouseup', startIdle);
}
// start the first timer
startIdle();