how to detect native scrollbar's button click event? - javascript

I was wondering if I can detect native scrollbar's left/right or up/down buttons click event. I want to know because I want to give a custom behaviour of the scrollbar, like scroll only in some fixed steps etc. I have used scroll function, but it doesn't exactly give me the smoothness I wanted:
var step = 200;
var nextPos=-1;
var pos;
var scrolltarget;
$(' .scrollable ul').scroll(function(e){
clearTimeout($.data(this, 'scrollTimer'));
scrolltarget=$(this);
$.data(this, 'scrollTimer', setTimeout(function() {
pos=scrolltarget.scrollLeft();
if(pos%step!=0){
if(pos>nextPos){
scrolltarget.animate({
scrollLeft: pos-pos%step+step
},250);
}
else if(pos<nextPos){
scrolltarget.animate({
scrollLeft: pos-pos%step
},250);
}
}
nextPos=scrolltarget.scrollLeft();
}, 250));
});

you can use
$( window ).scroll(function() {
// your java script code
});
i recommend you to see this scroll jquery event.

Related

Loop until Animation finished

I am looking for an way to loop a function as long as an animation is executed.
The reason is: I created an UI-Layout within a parent div. The parent div changes it's width due to an animation. The problem is that the UI-Layout doesn't adjust to the parent's width.
By calling $(window).trigger('resize'); when the animation is finished the UI Layout adjusts to the new width.
But I now want the layout to adjust smoothly to the animation so that the UI-Layout grows in an animated way (just like the parent div).
So my idea was to loop $(window).trigger('resize'); as long as the animation of the width of the parent div is playing.
What is the best way to loop a function while the animation is playing?
Or are there better ways to achieve what I am looking for?
Thanks so much!
You can use the jQuery .animate(properties, options) syntax, which allows you to listen to the progress event.
Example:
$( "#book" ).animate({
width: "+=50px" // whatever CSS properties that are animated...
}, {
duration: 500,
progress: function() { // This gets called several times during the animation
$(window).trigger('resize');
}
complete: function() {
$(window).trigger('resize');
}
});
CSS transitions
If you are using pure CSS transitions, then right after you launch the transition, you could call this function, passing it the element that is being animated:
function manageResize(elem) {
var timer = setInterval(function () {
$(window).trigger('resize');
}, 50);
elem.addEventListener('transitionend', function () {
clearInterval(timer);
}, false);
}
This will resize the window every few milliseconds (adjust as needed) and stop doing that once the transition comes to an end.
If you're using jQuery animation, a way would be:
var animating = true;
$( elem ).animate({
opacity: 0.25,
left: "+=50",
height: "toggle"
}, 5000, function() {
animating = false;
});
var timer = setInterval(function(){
if(animating)
$(window).trigger('resize');
else
clearInterval(timer);
},50);
Or, if you're using CSS animation:
// start animation
var animating = true;
$( elem ).addClass("animating");
$( elem ).one("webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend",
function(event) {
animating = false;
});
var timer = setInterval(function(){
if(animating)
$(window).trigger('resize');
else
clearInterval(timer);
},50);

Execute function only if window width is greater than something else don't

function dropdownHover() {
jQuery('ul.nav li.dropdown').hover(function() {
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
}, function() {
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
});
}
$(window).on('resize', function(event){
var windowSize = $(window).width();
if(windowSize > 992){
dropdownHover();
}
});
I need this function dropdownHover() to fire only when window is greater than 992px, both on load and on resize, else if window is < 992px, both on load or on resize i dont want to fire this function on hover i want regular bootstrap dropdown on click. I tried to do this with css but i cant add animation on dropdown because its just display: none/block. I also tried to add class on resize to fire this function if element has that class else dont but it doesnt work either.
Edit: Final working version
$('.dropdown').on('mouseenter', function(){
if(!$(this).is('.open') && $(window).data('wide'))
$('.dropdown-menu', this).dropdown('toggle').hide()
.stop(true, true)
.delay(200)
.fadeIn(function(){
this.style.display = '';
}).find('a').on('touchstart click', function (e) {
e.stopPropagation();
});
}).on('mouseleave', function(){
if($(this).is('.open') && $(window).data('wide'))
$('.dropdown-menu', this).dropdown('toggle');
});
$('.dropdown').on('click', function(e){
if( $(window).data('wide')) {
$('.dropdown-menu', this).dropdown('toggle');
} else {
$('.dropdown-menu', this)
.stop(true, true).slideToggle()
.closest('.dropdown').removeClass('open');
}
});
// not entirely necessary. Not sure which is faster: this or just checking the width in all three places.
$(window).on('resize', function(){
$(window).data('wide', $(window).width() > 992);
// reset the open menues
$('.dropdown').removeClass('open');
$('.dropdown-menu').css({
display: '',
left: '',
position: '',
});
// because we are checking the width of the window, this should probably go here although this really should be a media query style
$('.dropdown-menu.pull-center').each(function() {
var menuW = $(this).outerWidth();
if ($(window).width() > 1000) {
$(this).css({
left: - menuW / 2 + 60 + 'px',
position: 'absolute'
});
} else {
$(this).css({
left: '',
position: ''
});
}
});
}).trigger('resize');
Initial Solution
Your question is twofold. First, you need it to not show the menu at smaller sizes. For that, you check on resize what the window width is. The problem is that it only works once. It triggers the event listeners for hover and it doesn't kill those event listeners if the screen is then larger at some point. For that, you can set a flag. There are a lot of ways to do this, but for my answer, I've chosen to use jQuery .data() method.
$(window).on('resize', function(event){
var windowSizeWide = $(window).width() > 600; // reduced for testing purposes
jQuery('ul.nav li.dropdown').data('dropdown-enabled', windowSizeWide);
}).trigger('resize');
Then when we listen for the hover events (which are mouseenter and mouseleave events), we simply return out of the function if the screen is too small.
jQuery('ul.nav li.dropdown').on('mouseenter', function() {
if(!jQuery(this).data('dropdown-enabled')) return;
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
}).on('mouseleave', function() {
if(!jQuery(this).data('dropdown-enabled')) return;
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
}).find('.dropdown-menu').hide();
Finally, you also want the event to trigger on load. You can do that by simply adding .trigger('resize') as seen in the first snippet. You can see a functioning demo here: http://jsfiddle.net/jmarikle/xw9Ljshu/
Possible Alternative Solution
Alternatively, you can also use CSS to handle this with media queries. The simplest way to do this is to force display: none on smaller screens. I don't recommend completely hiding the element because it becomes inaccessible at that point, but this is the general idea:
#media(max-width: 600px) {
ul.dropdown-menu {
display:none !important;
}
}
Note that !important is used because jQuery adds inline styles when you fadeIn or fadeOut.
Second demo: http://jsfiddle.net/jmarikle/xw9Ljshu/1
window.screen.availWidth to get the window size. i am yet not tested your code.But i think this will ok.
function dropdownHover() {
jQuery('ul.nav li.dropdown').hover(function() {
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeIn();
}, function() {
jQuery(this).find('.dropdown-menu').stop(true, true).delay(200).fadeOut();
});
}
$(document).ready(function(){
$(window).on('resize', function(event){
var windowSize = window.screen.availWidth;
if(windowSize > 992){
dropdownHover();
}
});
})

give element class when scrolling

I would like to give an element a .class when user scrolls a page. And then take it away (.class) when user stops scrolling.
Simply speaking, I want to give font awesome icon class fa-spin only when page is being scrolled, and when scrolling stops, icon stops spinning.
Would be nice to know how to just generally apply css animation when scrolling.
Thanks
You can use https://github.com/ssorallen/jquery-scrollstop
var $el = $('.element');
$(window).on("scrollstart", function() {
$el.addClass('scrolling')
})
$(window).on("scrollstop", function() {
$el.removeClass('scrolling')
})
You can use addClass and removeClass on scroll event as follow.
This will add class when scrolling and remove it after delay of 100 milliseconds.
$(window).scroll(function() {
$('div').addClass('myClass');
setTimeout(function() {
$('div').removeClass('myClass');
}, 100);
});
DEMO
You can use like this:
$(window).scroll(function() {
$('div').addClass('blue');//add class on scroll
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
$('div').removeClass('blue');//remove class on scrolling stops
}, 250));
});
demo
To add e.g. fadeIn animation on scroll you can do as following:
$(window).scroll(function () {
$('#second').delay(1000).fadeIn('slow');
(delay is optional)
Check example: jsfiddle.net

Preventing Page Scroll - Disabling Drag

Prevent Scroll Script
// left: 37, up: 38, right: 39, down: 40,
// spacebar: 32, pageup: 33, pagedown: 34, end: 35, home: 36
var keys = [37, 38, 39, 40];
function preventDefault(e) {
e = e || window.event;
if (e.preventDefault)
e.preventDefault();
e.returnValue = false;
}
function keydown(e) {
for (var i = keys.length; i--;) {
if (e.keyCode === keys[i]) {
preventDefault(e);
return;
}
}
}
function wheel(e) {
preventDefault(e);
}
function disable_scroll() {
if (window.addEventListener) {
window.addEventListener('DOMMouseScroll', wheel, false);
}
window.onmousewheel = document.onmousewheel = wheel;
document.onkeydown = keydown;
}
function enable_scroll() {
if (window.removeEventListener) {
window.removeEventListener('DOMMouseScroll', wheel, false);
}
window.onmousewheel = document.onmousewheel = document.onkeydown = null;
}
Usage
Call disable_scroll(); to disable the page scrolling and enable_scroll() to enable the scrolling once again.
The Problem
Unlike the Facebook modal box, you are still able to click and drag the page to scroll down.
JSFiddle
Link: http://jsfiddle.net/2rud0aLm/
#Terry's first sentence provides a quick solution. Simply change overflow to 'hidden' on the body to prevent scrolling.
You will also need to keep track of the window's scrolled position, and set it after changing the overflow property.
To prevent the mousewheel from being able to drag, attach a scroll event to the window, which sets scrollTop to the window's position when the modal dialog was opened:
function disable_scroll() {
var top= $(window).scrollTop();
$('body').css({
overflow: 'hidden'
});
$(window).scrollTop(top);
$(window).on('scroll', function() {
$(window).scrollTop(top);
});
}
function enable_scroll() {
var top= $(window).scrollTop();
$('body').css({
overflow: ''
});
$(window).scrollTop(top);
$(window).off('scroll');
}
Because modal_close and modal_2 in your code has href="#", the script will attempt to jump to the top of the page. You can prevent that using preventDefault:
$('a[href=#]').on('click', function(ev) {
ev.preventDefault();
});
Fiddle
Here is a rather rudimentary fix, and I will explain what I have changed in order to make it work:
CSS: For the overlay, you actually do not need to sniff the viewport dimensions. Simply setting to position: fixed with all four offsets, top, left, bottom, and right set to 0 will force it to fill the screen :)
Markup: Wrap all your page content in a container, say <div class="page-wrap">. This element is set to fixed position upon toggling of the modal box to prevent click-drag scrolling.
JS:
Set a global variable as fromTop, which we will use to track the user's scroll position.
When the modal box is opened, update scroll position. Hide vertical overflow of the body element, and vertically translate the entire page content, i.e. .page-wrap to preserve vertical location
When the modal box is closed, reverse what we have done above :) I have decided to use a callback at the end of .fadeOut() to prevent jerking.
With all that done, you don't even need to prevent the scroll event from firing, or listening to keypress events anymore. Without further ado, here is the code (here's the functional demo):
var fromTop;
$('.modal_2').click(function(){
// Disable scroll and fade in modal box
disable_scroll();
$('.block_page').fadeIn();
$('.modal_box').fadeIn();
// Fetch current scroll position
fromTop = $(window).scrollTop();
// Hide overflowing vertical content
$('body').css({
'overflow-y': 'hidden'
});
$('.page-wrap').css({
'transform': 'translateY(-'+fromTop+'px)'
});
});
$('.modal_close').click(function(e){
e.preventDefault();
// Enable scroll and fade out modal box
$('.block_page').fadeOut(function() {
// Wait for modal box to fade out before reversing things
// Hide overflowing vertical content
$('body').css({
'overflow-y': 'visible'
});
$('.page-wrap').css({
'transform': 'translateY(0)'
});
$(window).scrollTop(fromTop);
});
$(this).parent().fadeOut();
enable_scroll();
});
Proof-of-concept fiddle: http://jsfiddle.net/teddyrised/mjq8gv29/
Even better: use jQuery promises to check if fadeOut animations have been completed on both the .block_page element and the parent element. This is exceptionally important if you want to set variable animation durations for either elements:
$('.modal_close').click(function(e){
e.preventDefault();
// Enable scroll and fade out modal box
$('.block_page').fadeOut();
$(this).parent().fadeOut();
// Use jQuery promises to check if all fadeOut animation has completed
var p1 = $('.block_page').promise(),
p2 = $(this).parent().promise();
// When all animations have completed, reverse effects
$.when(p1, p2).done(function() {
// Hide overflowing vertical content
$('body').css({
'overflow-y': 'visible'
});
$('.page-wrap').css({
'transform': 'translateY(0)'
});
$(window).scrollTop(fromTop);
});
});
Advanced fiddle that uses jQuery .promise() deferred object: http://jsfiddle.net/teddyrised/2rud0aLm/6/

Jquery hide/show scroll animation

When I click on any year column (2012, 2011, 2010, etc) it shows the content of each year and hide the other ones.
The problem it's that when I click (2011 column for example), the animation does all the effects at the same time confusing the user, I think I have to do it with animation steps, but I haven't been able to come to a jquery solution.
This is my code:
/* Scroll Function */
function scrollto(position){
$('html, body').stop().animate({
scrollLeft: position
}, 1000);
}
/* Calendar Scroll */
$(".sub_section_title").click( function(e) {
e.preventDefault();
$(".contenido_calendario").hide();
$(this).next(".contenido_calendario").toggle('slow');
scrollto($(this).offset().left - 352)
});
I have tried fixing the effect by using .queue() but it doesn't work, I don't know if the code it's well written also:
$(".sub_section_title").click( function(e) {
e.preventDefault();
$(".contenido_calendario").hide();
$(".contenido_calendario").queue(function() {
scrollto($(this).offset().left - 352);
$(this).dequeue();
});
$(".contenido_calendario").queue(function() {
$(this).next(".contenido_calendario").toggle('slow')
$(this).dequeue();
});
});
The animation should be:
Click 2011 > Scroll 2011 column to the left (hide 2012 content) > show animation of contents
You want to take advantage of the callback features of the jQuery animations. So for hide, for example, you could do:
var outerContainer = $(this);
$(".contenido_calendario").hide(500, function() {
outerContainer.next(".contenido_calendario").toggle('slow', function() {
scrollto(outerContainer.offset().left - 352);
});
});
This will ensure that the animations are run when the previous one is finished.

Categories

Resources