all. I am building a full screen jQuery gallery for a project I am working on, and am running in to a small hiccup.
to see a demo of what is happening, please visit http://www.idealbrandon.com/gallery.html.
Basically, I am loading the bg-image for each slide using a custom attribute, data-background. This works fine the first time through, however whenever a slide is loaded for a second time, it does not load. The HTML for a slide is:
<div class="slide" data-background="/img/gallery/2.jpg">
<div class="location">Magical Aqua Ducks</div>
<div class="verse"></div>
</div>
the Javascript in question is
for(var i = 0; i < totalSlides; i++){
$pagerList
.append('<li class="page" data-target="'+i+'"></li>');
if ($slides.eq(i).attr("data-background") != null){
$slides.eq(i).css("background-image", "url("+$slides.eq(i).attr("data-background")+")");
};
};
and the entire javascript file is
(function($){
function prefix(el){
var prefixes = ["Webkit", "Moz", "O", "ms"];
for (var i = 0; i < prefixes.length; i++){
if (prefixes[i] + "Transition" in el.style){
return '-'+prefixes[i].toLowerCase()+'-';
};
};
return "transition" in el.style ? "" : false;
};
var methods = {
init: function(settings){
return this.each(function(){
var config = {
slideDur: 7000,
fadeDur: 800
};
if(settings){
$.extend(config, settings);
};
this.config = config;
var $container = $(this),
slideSelector = '.slide',
fading = false,
slideTimer,
activeSlide,
newSlide,
$slides = $container.find(slideSelector),
totalSlides = $slides.length,
$pagerList = $container.find('.pager_list');
prefix = prefix($container[0]);
function animateSlides(activeNdx, newNdx){
function cleanUp(){
$slides.eq(activeNdx).removeAttr('style');
activeSlide = newNdx;
fading = false;
waitForNext();
};
if(fading || activeNdx == newNdx){
return false;
};
fading = true;
$pagers.removeClass('active').eq(newSlide).addClass('active');
$slides.eq(activeNdx).css('z-index', 3);
$slides.eq(newNdx).css({
'z-index': 2,
'opacity': 1
});
if(!prefix){
$slides.eq(activeNdx).animate({'opacity': 0}, config.fadeDur,
function(){
cleanUp();
});
} else {
var styles = {};
styles[prefix+'transition'] = 'opacity '+config.fadeDur+'ms';
styles['opacity'] = 0;
$slides.eq(activeNdx).css(styles);
//$slides.eq(activeNdx).css("background-image", "url("+$slides.eq(activeNdx).attr("data-background")+")");
var fadeTimer = setTimeout(function(){
cleanUp();
},config.fadeDur);
};
};
function changeSlides(target){
if(target == 'next'){
newSlide = (activeSlide * 1) + 1;
if(newSlide > totalSlides - 1){
newSlide = 0;
}
} else if(target == 'prev'){
newSlide = activeSlide - 1;
if(newSlide < 0){
newSlide = totalSlides - 1;
};
} else {
newSlide = target;
};
animateSlides(activeSlide, newSlide);
};
function waitForNext(){
slideTimer = setTimeout(function(){
changeSlides('next');
},config.slideDur);
};
for(var i = 0; i < totalSlides; i++){
$pagerList
.append('<li class="page" data-target="'+i+'"></li>');
if ($slides.eq(i).attr("data-background") != null){
$slides.eq(i).css("background-image", "url("+$slides.eq(i).attr("data-background")+")");
//alert($slides.eq(i).attr("data-background"));
};
};
$container.find('.page').bind('click',function(){
var target = $(this).attr('data-target');
clearTimeout(slideTimer);
changeSlides(target);
});
var $pagers = $pagerList.find('.page');
$slides.eq(0).css('opacity', 1);
$pagers.eq(0).addClass('active');
activeSlide = 0;
waitForNext();
});
}
};
$.fn.easyFader = function(settings){
return methods.init.apply(this, arguments);
};
})(jQuery);
Thanks in advance
Having had a look at your gallery.js file you have the following function that is called on your fade transition: cleanUp()
In this function you remove the style attribute from your $slides:
$slides.eq(activeNdx).removeAttr('style');
Which is removing the background-image style too. This is then never set again.
After the above line where you remove the styles you may want to then include:
$slides.eq(activeNdx).css("background-image", "url("+$slides.eq(activeNdx).data("background")+")");
Related
I'm currently facing an issue and could not solve it..
I have 3 slideshows located on one page, where only one slideshow is visible and the other 2 are hidden, based on which slideshow the user selects.
The visible slideshow auto-plays the slides and can be navigated with arrows, but at the moment when I try to change from slideshow 1 to slideshow 2 and then back again to slideshow 1, the function on slideshow 1 gets executed 2 times and sometimes even 3 or 4 times (depending on how often I change slideshows back and forth) making me unable to navigate it.. How do I "cancel" the function that keeps running on the previous slideshow, at the moment when I change from slideshow 1 to 2 and prevent it from executing multiple times?
Thank you in advance and I hope there's someone that can help me out on this one!
function Slider() {
this.slider = document.getElementsByClassName("image_slideshow");
if (typeof(this.slider) !== 'undefined' && this.slider !== null){
this.radio = document.getElementsByName("room");
this.room_labels = document.getElementsByClassName("selected_room")[0];
this.label = this.room_labels.getElementsByTagName("label");
this.slideIndex = 1;
this.timer = null;
this.initEvents();
}
}
Slider.prototype = {
initEvents : function(){
var room_labels = this.room_labels, label = this.label, slider;
for (var k = 0; k < label.length; k++) {
var radio = document.getElementById(label[k].className);
if(radio.checked){
slider = document.getElementById(radio.id + "_room").getElementsByClassName("image_slideshow")[0];
this.playSlider(this.slideIndex, slider);
}
}
room_labels.addEventListener("click", function(event){ event = event || window.event;
var target = event.target;
if (target && target !== undefined && target !== null){
if (target.nodeName === "LABEL") {
slider = document.getElementById(target.className + "_room").getElementsByClassName("image_slideshow")[0];
this.playSlider(this.slideIndex,slider);
}
return;
}
}.bind(this));
},
playSlider : function(n, slider){
var prev = slider.getElementsByClassName('prev')[0],
next = slider.getElementsByClassName('next')[0];
prev.addEventListener("click", function() {
this.showSlides(this.slideIndex -= 1,slider);
}.bind(this));
next.addEventListener("click", function() {
this.showSlides(this.slideIndex += 1,slider);
}.bind(this));
this.showSlides(this.slideIndex,slider);
},
showSlides : function(n, slider){
var self = this, slides = slider.getElementsByTagName("figure"),
bullets = slider.getElementsByClassName("indicator")[0].children;
if (n > slides.length) {this.slideIndex = 1;}
if (n < 1) {this.slideIndex = slides.length;}
for (var i=0; i < slides.length; i++) {
slides[i].className = "";
bullets[i].className = " bullet";
}
slides[this.slideIndex - 1].className += "active";
bullets[this.slideIndex - 1].className += " active";
clearTimeout(this.timer);
this.timer = setTimeout(function() {
self.showSlides(self.slideIndex += 1,slider);}, 7000);}
};
window.Slider = new Slider();
I am having trouble creating a slider that pauses on hover, because I execute the animation function again on mouse off, if I flick the mouse over it rapidly (thereby calling the function multiple times) it starts to play up, I would like it so that the function is only called if the other function is complete, otherwise it does not call at all (to avoid queue build up and messy animations)
What's the easiest/best way to do this?
$(document).ready(function() {
//get variables
var slide_width = $('.slider_container').width();
var number_of_slides = $('.slider_container .slide').length;
var slider_width = slide_width*number_of_slides;
//set element dimensions
$('.slide').width(slide_width);
$('.slider').width(slider_width);
var n = 1;
$('.slider_container').hover(function() {
//Mouse on
n = 0;
$('.slider').stop(true, false);
}, function() {
//Mouse off
n = 1;
if (fnct == 0) sliderLoop();
});
//Called in Slide Loop
function animateSlider() {
$('.slider').delay(3000).animate({ marginLeft: -(slide_width * i) }, function() {
i++;
sliderLoop();
});
}
var i = 0;
var fnct = 0
//Called in Doc Load
function sliderLoop() {
fnct = 1
if(n == 1) {
if (i < number_of_slides) {
animateSlider();
}
else
{
i = 0;
sliderLoop();
}
}
fnct = 0
}
sliderLoop();
});
The slider works fine normally, but if I quickly move my mouse on and off it, then the slider starts jolting back and forth rapidly...been trying to come up with a solution for this for hours now..
Here's what fixed it, works a charm!
$(document).ready(function() {
//get variables
var slide_width = $('.slider_container').width();
var number_of_slides = $('.slider_container .slide').length;
var slider_width = slide_width*number_of_slides;
//set element dimensions
$('.slide').width(slide_width);
$('.slider').width(slider_width);
var n = 1;
var t = 0;
$('.slider_container').hover(function() {
clearInterval(t);
}, function() {
t = setInterval(sliderLoop,3000);
});
var marginSize = i = 1;
var fnctcmp = 0;
//Called in Doc Load
function sliderLoop() {
if (i < number_of_slides) {
marginSize = -(slide_width * i++);
}
else
{
marginSize = i = 1;
}
$('.slider').animate({ marginLeft: marginSize });
}
t = setInterval(sliderLoop,3000);
});
I am attempting to create a responsive slider, that will change to a simple set of dot points when in mobile mode (< 940).
The issue I am facing is in my else statement I am unable to clearintervals that were made in the if statement, because t comes up as undefined. I have resorted to using
for (var i = 1; i < 99999; i++) window.clearInterval(i); to clear the interval which works, but I don't like it because it's ugly and cumbersome, is there another way of accomplishing this?
$(document).ready(function() {
function rePosition() {
//get responsive width
var container_width = $('.container').width();
//Slider for desktops only
if(container_width >= 940) {
//get variables
var slide_width = $('.slider_container').width();
var number_of_slides = $('.slider_container .slide').length;
var slider_width = slide_width*number_of_slides;
//set element dimensions
$('.slide').width(slide_width);
$('.slider').width(slider_width);
var n = 1;
var t = 0;
$('.slider_container').hover(function() {
clearInterval(t);
}, function() {
t = setInterval(sliderLoop,6000);
});
var marginSize = i = 1;
//Called in Doc Load
function sliderLoop(trans_speed) {
if (trans_speed) {
var trans_speed = trans_speed;
}
else
{
var trans_speed = 3000;
}
if (i < number_of_slides) {
marginSize = -(slide_width * i++);
}
else
{
marginSize = i = 1;
}
$('.slider').animate({ marginLeft: marginSize }, trans_speed);
}
t = setInterval(sliderLoop,6000);
$('.items li').hover(function() {
$('.slider').stop();
clearInterval(t);
var item_numb = $(this).index();
i = item_numb;
sliderLoop(500);
}, function() {
t = setInterval(sliderLoop,6000);
});
}
else
{
for (var i = 1; i < 99999; i++)
window.clearInterval(i);
$('.slider').stop(true, true);
$('.slider').css('margin-left', '0px');
//rearrange content
if($('.slider .slide .slide_title').length < 1) {
$('.items ul li').each(function() {
var item_numb = $(this).index();
var content = $(this).text();
$('.slider .slide:eq(' + item_numb + ')').prepend('<div class="title slide_title">' + content + '</div>')
});
}
}
}
rePosition();
$(window).resize(function() {
rePosition();
});
});
Teemu's comment is correct. I'll expand on it. Make an array available to all of the relevant code (just remember that globals are bad).
$(document).ready(function() {
var myIntervalArray = [];
Now, whenever you create an interval you will need to reference later, do this:
var t = setInterval();//etc
myIntervalArray.push(t); //or just put the interval directly in.
Then to clear them, just loop the array and clear each interval.
for (var i=0; i<myIntervalArray.length; i++)
clearInterval(myIntervalArray[i]);
}
Umm, wouldn't t only be defined when the if part ran... as far as I can tell, this is going to run and be done... the scope will be destroyed. If you need to maintain the scope across calls, you'll need to move your var statements outside of reposition(), like so:
$(document).ready(function() {
var t = 0;
...
function rePosition() { ... }
});
I'm facing a bit of a jQuery conundrum, and I'd appreciate someone helping me to solve it.
I want to fade in a web page, using jQuery, after all the text and images have loaded. So I set body style inline as "display:none" and then fade in the body using this basic snippet:
<script type="text/javascript">
$(window).load(function() {
$('body').fadeIn(300);
});
</script>
This achieves exactly what I want in Firefox, Safari and Chrome. However, Internet Explorer and Opera present a challenge: when the body fades in, all the elements of the JQuery gallery, included in the page, appear simultaneously, instead of rotating, as they do in "normal" browsers.
I'm posting the entire gallery script here:
/* Gallery */
jQuery.fn.gallery = function(_options){
// defaults options
var _options = jQuery.extend({
duration: 600,
autoSlide: false,
slideElement: 1,
effect: false,
fadeEl: 'ul',
switcher: 'ul > li',
disableBtn: false,
next: 'a.link-next, a.btn-next, a.next',
prev: 'a.link-prev, a.btn-prev, a.prev',
circle: true
},_options);
return this.each(function(){
var _hold = $(this);
if (!_options.effect) var _speed = _options.duration;
else var _speed = $.browser.msie ? 0 : _options.duration;
var _timer = _options.autoSlide;
var _sliderEl = _options.slideElement;
var _wrap = _hold.find(_options.fadeEl);
var _el = _hold.find(_options.switcher);
var _next = _hold.find(_options.next);
var _prev = _hold.find(_options.prev);
var _count = _el.index(_el.filter(':last'));
var _w = _el.outerWidth(true);
var _wrapHolderW = Math.ceil(_wrap.parent().width()/_w);
if (((_wrapHolderW-1)*_w + _w/2) > _wrap.parent().width()) _wrapHolderW--;
if (_timer) var _t;
var _active = _el.index(_el.filter('.active:eq(0)'));
if (_active < 0) _active = 0;
var _last = _active;
if (!_options.effect) var rew = _count - _wrapHolderW + 1;
else var rew = _count;
if (!_options.effect) _wrap.css({marginLeft: -(_w * _active)});
else {
_wrap.css({opacity: 0}).removeClass('active').eq(_active).addClass('active').css({opacity: 1}).css('opacity', 'auto');
_el.removeClass('active').eq(_active).addClass('active');
}
if (_options.disableBtn) {
if (_count < _wrapHolderW) _next.addClass(_options.disableBtn);
_prev.addClass(_options.disableBtn);
}
function fadeElement(){
_wrap.eq(_last).animate({opacity:0}, {queue:false, duration: _speed});
_wrap.removeClass('active').eq(_active).addClass('active').animate({
opacity:1
}, {queue:false, duration: _speed, complete: function(){
$(this).css('opacity','auto');
}});
_el.removeClass('active').eq(_active).addClass('active');
_last = _active;
}
function scrollEl(){
_wrap.animate({marginLeft: -(_w * _active)}, {queue:false, duration: _speed});
}
function toPrepare(){
if ((_active == rew) && _options.circle) _active = -_sliderEl;
for (var i = 0; i < _sliderEl; i++){
_active++;
if (_active > rew) {
_active--;
if (_options.disableBtn &&(_count > _wrapHolderW)) _next.addClass(_options.disableBtn);
}
};
if (_active == rew) if (_options.disableBtn &&(_count > _wrapHolderW)) _next.addClass(_options.disableBtn);
if (!_options.effect) scrollEl();
else fadeElement();
}
function runTimer(){
_t = setInterval(function(){
toPrepare();
}, _timer);
}
_next.click(function(){
if(_t) clearTimeout(_t);
if (_options.disableBtn &&(_count > _wrapHolderW)) _prev.removeClass(_options.disableBtn);
toPrepare();
return false;
});
_prev.click(function(){
if(_t) clearTimeout(_t);
if (_options.disableBtn &&(_count > _wrapHolderW)) _next.removeClass(_options.disableBtn);
if ((_active == 0) && _options.circle) _active = rew + _sliderEl;
for (var i = 0; i < _sliderEl; i++){
_active--;
if (_active < 0) {
_active++;
if (_options.disableBtn &&(_count > _wrapHolderW)) _prev.addClass(_options.disableBtn);
}
};
if (_active == 0) if (_options.disableBtn &&(_count > _wrapHolderW)) _prev.addClass(_options.disableBtn);
if (!_options.effect) scrollEl();
else fadeElement();
return false;
});
if (_options.effect) _el.click(function(){
_active = _el.index($(this));
if(_t) clearTimeout(_t);
fadeElement();
return false;
});
if (_timer) runTimer();
});
}
$(document).ready(function(){
$('div#gallery').gallery({
duration: 2000,
effect: 'fade',
fadeEl: 'ul.gall-inner > li',
next: 'a#next-btn',
prev: 'a#prev-btn',
autoSlide: 6000,
switcher: '.brands-list ul > li'
});
});
Could some knowledgeable person please help me to find a solution or a workaround? I'd be truly grateful!
I have the following script:
(function($) {
$.fn.easyPaginate = function(options){
var defaults = {
step: 4,
delay: 100,
numeric: true,
nextprev: true,
controls: 'pagination',
current: 'current'
};
var options = $.extend(defaults, options);
var step = options.step;
var lower, upper;
var children = $(this).children();
var count = children.length;
var obj, next, prev;
var page = 1;
var timeout;
var clicked = false;
function show(){
clearTimeout(timeout);
lower = ((page-1) * step);
upper = lower+step;
$(children).each(function(i){
var child = $(this);
child.hide();
if(i>=lower && i<upper){ setTimeout(function(){ child.fadeIn('fast') }, ( i-( Math.floor(i/step) * step) )*options.delay ); }
if(options.nextprev){
if(upper >= count) { next.addClass('stop'); } else { next.removeClass('stop'); };
if(lower >= 1) { prev.removeClass('stop'); } else { prev.addClass('stop'); };
};
});
$('li','#'+ options.controls).removeClass(options.current);
$('li[data-index="'+page+'"]','#'+ options.controls).addClass(options.current);
if(options.auto){
if(options.clickstop && clicked){}else{ timeout = setTimeout(auto,options.pause); };
};
};
function auto(){
if(upper <= count){ page++; show(); }
else { page--; show(); }
};
this.each(function(){
obj = this;
if(count>step){
var pages = Math.floor(count/step);
if((count/step) > pages) pages++;
var ol = $('<ol id="'+ options.controls +'" class="pagin"></ol>').insertAfter(obj);
if(options.nextprev){
prev = $('<li class="prev">prev</li>')
.appendTo(ol)
.bind('click', function() {
//check to see if there are any more pages in the negative direction
if (page > 1) {
clicked = true;
page--;
show();
}
});
}
if(options.numeric){
for(var i=1;i<=pages;i++){
$('<li data-index="'+ i +'">'+ i +'</li>')
.appendTo(ol)
.click(function(){
clicked = true;
page = $(this).attr('data-index');
show();
});
};
};
if(options.nextprev){
next = $('<li class="next">next</li>')
.appendTo(ol)
.bind('click', function() {
//check to see if there are any pages in the positive direction
if (page < (count / 4)) {
clicked = true;
page++;
show();
}
});
}
show();
};
});
};
})(jQuery);
jQuery(function($){
$('ul.news').easyPaginate({step:4});
});
which is a carousel-like plugin that produces this html structure for the navigation:
<ol id="pagination" class="pagin"><li class="prev">prev</li><li data-index="1" class="">1</li><li data-index="2" class="">2</li><li data-index="3" class="current">3</li><li class="next stop">next</li></ol>
And all I want is to enclose this list in a div. Seems simple, but appendTo doesn't want to cooperate with me, or I'm doing something wrong (I'd appreciate if you would help me understand what that is..)
So I'm modifying as such:
var ol = $('<ol id="'+ options.controls +'" class="pagin"></ol>');
var tiv = $('<div id="lala"></div>');
ol.appendTo('#lala');
tiv.insertAfter(obj);
I know how to chain, but I'm in "debugging" mode trying to understand why I don't get the result I imagine I would get:
<div id="lala>
<ol id="pagination><li>...... </li></ol>
</div>
I tried putting some console.log's to see the status of my variables but couldn't find something useful.. I guess there's something with DOM insertion I don't get.
You're appending the <ol> element to #lala before adding the latter to the document. There's nothing wrong with this, but since you're using an id selector, and the target element is not part of the document yet, the selector will not match anything.
To fix this, you can write:
var ol = $('<ol id="'+ options.controls +'" class="pagin"></ol>');
var tiv = $('<div id="lala"></div>');
ol.appendTo(tiv);
tiv.insertAfter(obj);
Or:
var ol = $('<ol id="'+ options.controls +'" class="pagin"></ol>');
var tiv = $('<div id="lala"></div>');
tiv.insertAfter(obj);
ol.appendTo('#lala');