making multiple sliders with one set of jQuery code - javascript

I've made a slider with jQuery using html tags which have classes instead of IDs so that I will be able to use the same jQuery code for other duplicated sliders.
The problem is, I want the width of my ul to be calculated based on the number of lis, instead of setting it manually in CSS. When there is only one slider I can set my vars outside of the function, but when I have to use it though event attributes on my html parts so that I will be able to use them for multiple sliders, I have to move the vars inside of my function, which sets the wrong width.
This is my code:
function OLAR(direction,span) {
var OurNexNPrv = $(span);
var Parent_OLAR = OurNexNPrv.parents('.OLAR');
var UL_OF_OLAR = Parent_OLAR.find('.OLAR_CONTENT ul');
var LI_OF_OLAR = UL_OF_OLAR.find('li');
var LI_OF_OLAR_LENGTH = LI_OF_OLAR.length;
var Quantity_OF_OLAR_PAGES = LI_OF_OLAR_LENGTH / 3;
var Max_Margin_LEFT = -(Quantity_OF_OLAR_PAGES - 1) * 576;
UL_OF_OLAR.css('width',LI_OF_OLAR_LENGTH*192);
var AffectedLeftMargin;
var CurrentLeftMargin = UL_OF_OLAR.css('margin-left');
CurrentLeftMargin = parseFloat(CurrentLeftMargin);
if (direction == 'right') {
AffectedLeftMargin = CurrentLeftMargin - 576;
}
if (direction == 'left') {
AffectedLeftMargin = CurrentLeftMargin + 576;
}
if (AffectedLeftMargin < Max_Margin_LEFT) {
AffectedLeftMargin = 0;
}
if (AffectedLeftMargin > 0) {
AffectedLeftMargin = Max_Margin_LEFT;
}
UL_OF_OLAR.animate({'marginLeft': AffectedLeftMargin}, 1000);
}
$('.CIRCLE_LOAD_RIGHT').click(function () {
OLAR('right');
});
$('.CIRCLE_LOAD_LEFT').click(function () {
OLAR('left');
});
How can I set the width for each of my uls individually, through css commands outside of that function?

Okay, my ul tag did not have the absolute position; after giving it the right position and left:0 and bottom:0 or right:0 and bottom:0 (based on your language)the given width which comes from JQuery code can rhyme perfectly with everything else. I've tried it with multiple sliders and it works perfectly :)
So, we need an anchor point in order to make this work. And there is nothing wrong with this JQuery code which has been mentioned above!
Have a great day.

Related

Replacing Bootstrap Dropdown with Dropup (Different activity on two near identical implementations)

I'm working on a project over at github pages, which I replace a bootstrap .dropdown with .dropup if the div's overflow-y: scroll will cause the dropdown menu to be cutoff / overflow. You can see the function working properly at this jsfiddle. Notice if you click on the ellipsis icon to the right on the top rows, it will drop down, if you click on the icon on the bottom rows, it will drop up.
Now, my actual implementation (github page), the code is exactly the same (below), but it wants to replace all .dropdown classes with .dropup when opened, including the top-most row which gets cut off, seen in the photo below.
I've been struggling with this for a week and can't quite figure it out. I've tried a few different things that I thought fixed it but ended up just being a hack and didn't work on mobile, or replaced some but not all etc.
Here is the Javascript / jQuery I'm using, which can be seen in the jsfiddle and my github source here.
$(document).on("shown.bs.dropdown", ".dropdown", function () {
// calculate the required sizes, spaces
var $ul = $(this).children(".dropdown-menu");
var $button = $(this).children(".song-menu");
var ulOffset = $ul.offset();
// how much space would be left on the top if the dropdown opened that direction
var spaceUp = (ulOffset.top - $button.height() - $ul.height()) - $('#playlist').scrollTop();
// how much space is left at the bottom
var spaceDown = $('#playlist').scrollTop() + $('#playlist').height() - ((ulOffset.top + 10) + $ul.height());
// switch to dropup only if there is no space at the bottom AND there is space at the top, or there isn't either but it would be still better fit
if (spaceDown < 0 && (spaceUp >= 0 || spaceUp > spaceDown))
$(this).addClass("dropup");
}).on("hidden.bs.dropdown", ".dropdown", function() {
// always reset after close
$(this).removeClass("dropup");
});
Edit:
To clear up any confusion, here's an example of the behavior without my added .dropup function. jsfiddle Notice when you click the last menu item, it opens the menu but requires scrolling. I specifically want to remove the .dropdown class and add .dropup in this case, so no scrolling is required.
It took some basic math, but I managed to figure out what you desired to do. This code changes the bootstrap classes between dropup and dropdown depending on the room available for a normal dropdown.
I calculated this by detracting the height of the button, dropdownmenu and how far the button was scrolled down in the scrollContainer from the height of the scrollContainer. I got the value how much the div was scrolled down by using the buttons offset and detracting the offset from the scrollContainer.
Here is my jQuery (I selected the .playlist class because this was attached to your scrollContainer, but you should replace it by an id or select it by other means):
$(".dropdown, .dropup").click(function(){
var dropdownClassCheck = $(this).hasClass('dropdown');
var buttonOffset = $(this).offset().top;
var scrollboxOffset = $('.playlist').offset().top;
var buttonHeight = $(this).height();
var scrollBoxHeight = $('.playlist').height();
var dropDownButtonHeight = $(this).children('ul').height();
dropdownSpaceCheck = scrollBoxHeight>buttonOffset-scrollboxOffset+buttonHeight+dropDownButtonHeight;
if(dropdownClassCheck && !dropdownSpaceCheck){
$(this).removeClass('dropdown').addClass('dropup');
}
else if(!dropdownClassCheck && dropdownSpaceCheck){
$(this).removeClass('dropup').addClass('dropdown');
}
});
A working JSFiddle
Let me know if there are parts of the code that could be improved/done easier or if there are any problems with my solution.
I have not thoroughly checked, but .scrollTop() is probably why the code fails when combined with other elements in the DOM, so here is a solution without it:
function checkHeights(){
// LOOP through each dropdown
$('.dropdown,.dropup').each(function(index,element){
var $dropDown = $(element),
$dropDownMenu = $dropDown.find('.dropdown-menu'),
dropDownTop = $dropDown.offset().top,
visibleHeight = $dropDown.height(),
hiddenHeight = $dropDownMenu.height(),
ddTop = dropDownTop - hiddenHeight,
ddBottom = dropDownTop + visibleHeight + hiddenHeight;
// LOOP through all parents
$dropDown.parents().each(function(ix,el){
var $el = $(el);
// CHECK if any of them have overflow property set
if( $el.css('overflow') !== 'visible' ){
var limitTop = $el.offset().top,
limitBottom = limitTop + $el.height();
// CHECK if parent is better fit when dropped upside
if( limitBottom < ddBottom && ( ddTop - limitTop ) > ( limitBottom - ddBottom ) )
$dropDown.removeClass('dropdown').addClass('dropup');
else
$dropDown.removeClass('dropup').addClass('dropdown');
// BREAK LOOP
return false;
}
});
});
}
$(document).ready(function() {
checkHeights();
$('.playlist').scroll(checkHeights);
});
JS Fiddle here.
This one does not require any class or id given to it except for dropdown,dropdown-menu, and dropup (all of which are Bootstrap defaults) and would work fine even if there are multiple playlists on page.
UPDATE
The code is modified and wrapped in a function in order to allow being called when scroll event fires.
I think that the problem it's that you have a big header, and the jsFiddle don't. So ulOffset.top it's always big, and spaceDown is always negative
Replace parent div.dropdown with div.dropup.

How can I have two of these on one page with different variables? (JQuery)

I need to have 2 of these one page but each with different percentages. When I try re-writing the JS or even use different class/ID names it still always pulls from the first SPAN.
http://jsfiddle.net/K62Ra/
<div class="container">
<div class="bw"></div>
<div class="show"></div>
<div id="bar" data-total="100">
<div class="text">Currently at <br/><span>70</span><br><i>Click To Give</div>
</div>
JS and CSS in the Fiddle.
Much Thanks.
This one will work smoothly:
http://jsfiddle.net/K62Ra/7/
$('.bar').each(function() {
var percentStart = 0;
var total = $(this).data('total');
var percent = parseInt($(this).find('span').html());
$(this).find('> div').addClass("load");
var that = this;
var timer = setInterval(function() {
$(that).siblings('.show').css('height', percentStart/total*100+'%');
$(that).css('height', percentStart/total*100+'%');
$(that).find('span').html('%'+percentStart);
if(percentStart<percent) { percentStart=percentStart+1; return; }
clearInterval(timer);
}, 35);
});
The interval has to be terminated as well, or it will run infinitely (though not doing anything).
I've changed your id="bar" into a class. Then I'm running a each loop for the .bar classes. here is the fiddle: http://jsfiddle.net/K62Ra/3/
here is the code:
$('.bar').each(function (index, element) {
percent = $(this).find('span').html();
total = $(this).attr('data-total');
percentStart = 0;
setInterval(function () {
$('.show').css('height', percentStart / total * 100 + '%');
$(this).css('height', percentStart / total * 100 + '%');
$(this).find('span').html('%' + percentStart);
if (percentStart < percent) {
percentStart = percentStart + 1;
}
}, 35);
});
$(".bar div").addClass("load");
Like some of the comments have stated, having duplicate ids is bad design and can cause some weird errors.
You can find a solution to your problem by changing a number of things. One, instead of
referring to divs in you selectors by id'#', you can infer them by class '.' like
$('.bar')
The next step would be to ensure exclusivity for each div with class 'container' by using a closure
$('.container').each(function(){
var x
var y
.
.
});
And finally, avoid 'selecting' elements in the selector directly, but use $(this) and .find() to ensure you are within the current div with class 'container'.
http://jsfiddle.net/K62Ra/5/
$('.container').each(function(){
var percent = $(this).find('div.bar div span').html();
var total = $(this).find('div.bar').attr('data-total');
var percentStart = 0;
var that = $(this);
setInterval(function() {
that.find('.show').css('height',percentStart/total*100+'%');
that.find('div.bar').css('height',percentStart/total*100+'%');
that.find('div.bar div span').html('%'+percentStart);
if(percentStart<percent) {percentStart=percentStart+1;}
},35);
$(this).find("div.bar div").addClass("load");
});
There are already several good answers here. I would recommend validating your html. Also some of your css was causing weirdness when there was scrolling involved (fixed background images weren't scrolling.)
I took a slightly different approach than everyone else. Instead of using a setInterval I went with $.animate and a step function. Like others, I chose a class to target each of the items: 'fill-me-up'.
Fiddle: http://jsfiddle.net/LFbKs/6/
NOTE: Check the fiddle since I modified the HTML (very slightly) and the css to a larger degree.
// for each item we need to "fill up"
$('.fill-me-up').each(function(){
// cache DOM references
var this$ = $(this)
, bar$ = this$.find('.bar')
, show$ = this$.find('.show')
, span$ = bar$.find('div span')
// the target percentage height for this item
, p = span$.text()
// combine '.bar' and '.show' so we can apply the animation to both
, toAnimate = $().add(bar$).add(show$);
// add class causing fade-in
bar$.find('div').addClass('is-visible');
// animate height to target height over 2 seconds and
// at each step, update the span with a truncated value
toAnimate.animate(
{ height: p+'%' },
{
duration: 2000,
step: function( currentStep ) {
span$.html('%'+currentStep.toFixed(0));
}
}
);
});
Cheers

jquery moving element at the end of the list makes container disapper, seems like prepend

I'm trying to make a very simple rotating banners list.
Fiddle is here: http://jsfiddle.net/a9dAm/
if ($("#ads").length > 0) {
var count_banners = $("#ads a").length;
var delay_time = 1000;
var i = 1;
while (count_banners >= i) {
$("#ads a:nth-child("+ i +")").delay(delay_time * i).show(1, function(){
$(this).fadeOut("slow").prepend($("#ads"));
});
i++;
}
}
Prepend breaks everything and #ads disappears all together, what is going on? or what am I doing wrong?
I think you want .prependTo(), not .prepend().
$(this).fadeOut("slow").prependTo($("#ads"));
or just
$(this).fadeOut("slow").prependTo("#ads");
The .prepend() function prepends its argument to the element from which you call it.
It's disappearing because you were using .prepend rather than .prependTo. Basically, you were moving ads instead of the single ad.
Updated fiddle: http://jsfiddle.net/klatzkaj/a9dAm/1/
This is the relevant line: $(this).fadeOut("slow").prependTo($("#ads"));

JavaScript, How to change the background of a div tag every x seconds

I'm trying to make some JavaScript code to change the background of two div tags every X seconds. Here is my code:
HTML
<div id="bg_left"></div>
<div id="bg_right"></div>
CSS
body{
height:100%;
}
#bg_left{
height:100%;
width:50%;
left:0;
position:fixed;
background-position:left;
}
#bg_right{
height:100%;
width:50%;
right:0;
position:fixed;
background-image:url(http://presotto.daterrawebdev.com/d/img/pp_hey_you_bg.png);
background-position:right;
}
JAVA SCRIPT
function carousel_bg(id) {
var bgimgs = [ 'pp_hey_you_bg.png', 'burningman_bg.png' ];
var img1 = bgimgs[id];
var img2 = bgimgs[id+1];
var cnt = 2;
$('#bg_left').css("background-image", "url(http://presotto.daterrawebdev.com/d/img/"+img1+")");
$('#bg_right').css("background-image", "url(http://presotto.daterrawebdev.com/d/img/"+img2+")");
id = id + 1;
if (id==cnt) id = 0;
setTimeout("carousel_bg("+id+")", 10000);
}
$(document).ready(function() {
carousel_bg(0);
});
​
The background-images should be changing randomly, but they don't even change at all.
OK, I see the issue in your jsFiddle. Because you're passing a string to setTimeout() that string will be evaluated only at the top level scope. But, the function name you were passing is not at the top level scope (it's in an onload handler for the jsFiddle). So, I changed the way your JS is positioned in the jsFiddle so it is now at the top level scope. I also fixed up the logic for selecting an image and it now works here: http://jsfiddle.net/jfriend00/awVYP/
And, here's a cleaned up version that does not pass a string to setTimeout() (a much better way to write javascript) that passes a local function and uses a closure to keep track of the current index: http://jsfiddle.net/jfriend00/LVGNN/
function carousel_bg(id) {
var bgimgs = [ 'pp_hey_you_bg.png', 'burningman_bg.png' ]; // add images here..
function next() {
if (id >= bgimgs.length) {
id = 0;
}
var img1 = bgimgs[id];
id++;
if (id >= bgimgs.length){
id = 0;
}
var img2 = bgimgs[id];
$('#bg_left').css("background-image", "url(http://presotto.daterrawebdev.com/d/img/"+img1+")");
$('#bg_right').css("background-image", "url(http://presotto.daterrawebdev.com/d/img/"+img2+")");
setTimeout(next, 1000);
}
next();
}
$(document).ready(function() {
carousel_bg(0);
});
Previous comments on earlier version so of the OP's code:
$('#body')
should be:
$('body')
or even faster:
$(document.body)
Also, your jsFiddle shows a bit of an odd issue. Your CSS has a background image on the HTML tag, but your javascript sets a semi-transparent background image on the body tag. Is that really what you want?
For testing I added another image to the array so that we got some distinction in the sorting.
function carousel_bg(id) {
var bgimgs = [ 'http://presotto.daterrawebdev.com/d/img/pp_hey_you_bg.png', 'http://presotto.daterrawebdev.com/d/img/burningman_bg.png', 'http://gallery.orobouros.net/var/albums/2012/NewYorkComicCon2012/Legend-of-Korra/nycc_20121013_164625_0041.jpg?m=1354760251' ]; // add images here..
var img1 = bgimgs[id+1];
var img2 = bgimgs[id];
var cnt = bgimgs.length; // change this number when adding images..
$('#bg_left').css("background-image", "url("+img1+")");
$('#bg_right').css("background-image", "url("+img2+")");
id = id + 1;
if (id== (cnt - 1) ) id = 0;
setTimeout("carousel_bg("+id+")", 10000);
}
Two changes here:
For your total image count, I am retrieving the total count of images in the array dynamically instead of by hand (bgimgs.length)
In your conditional to reset the id value, subtract the total count by 1. Since JS has zero-based indexes, not doing this will get you an undefined error (a 3 item array will spit out a value of 4 in your original code on the last iteration).
While this code does loop through your array, it's not random. That's another topic.
For those not using JQuery, simply do the following:
document.body.style.backgroundImage="url(images/mybackgroundimage.jpg)";

JavaScript or jQuery image carousel/filmstrim

I am looking for some native JavaScript, or jQuery plugin, that meets the following specification.
Sequentially moves over a set of images (ul/li)
Continuous movement, not paging
Appears infinite, seamlessly restarts at beginning
Ability to pause on hover
Requires no or minimal additional plugins
I realize this sounds simple enough. But I have looked over the web and tried Cycle and jCarousel/Lite with no luck. I feel like one should exist and wanted to pose the question before writing my own.
Any direction is appreciated. Thanks.
you should check out Nivo Slider, I think with the right configuration you can it to do what you want.
You can do that with the jQuery roundabout plugin.
http://fredhq.com/projects/roundabout/
It might require another plugin.
Both answers by MoDFoX and GSto are good. Usually I would use one of these, but these plugins didn't meet the all the requirements. In the end this was pretty basic, so I just wrote my own. I have included the JavaScript below. Essentially it clones an element on the page, presumably a ul and appends it to the parent container. This in effect allows for continuous scrolling, right to left, by moving the element left and then appending it once out of view. Of course you may need to tweak this code depending on your CSS.
// global to store interval reference
var slider_interval = null;
var slider_width = 0;
var overflow = 0;
prepare_slider = function() {
var container = $('.sliderGallery');
if (container.length == 0) {
// no gallery
return false;
}
// add hover event to pause slider
container.hover(function() {clearInterval(slider_interval);}, function() {slider_interval = setInterval("slideleft()", 30);});
// set container styles since we are absolutely positioning elements
var ul = container.children('ul');
container.css('height', ul.outerHeight(true) + 'px');
container.css('overflow', 'hidden')
// set width and overflow of slider
slider_width = ul.width();
overflow = -1 * (slider_width + 10);
// set first slider attributes
ul.attr('id', 'slider1');
ul.css({"position": "absolute", "left": 0, "top": 0});
// clone second slider
var ul_copy = ul.clone();
// set second slider attributes
ul.attr('id', 'slider2');
ul_copy.css("left", slider_width + "px");
container.append(ul_copy);
// start time interval
slider_interval = setInterval("slideleft()", 30);
}
function slideleft() {
var copyspeed = 1;
var slider1 = $('#slider1');
var slider2 = $('#slider2');
slider1_position = parseInt(slider1.css('left'));
slider2_position = parseInt(slider2.css('left'));
// cross fade the sliders
if (slider1_position > overflow) {
slider1.css("left", (slider1_position - copyspeed) + "px");
}
else {
slider1.css("left", (slider2_position + slider_width) + "px");
}
if (slider2_position > overflow) {
slider2.css("left", (slider2_position - copyspeed) + "px");
}
else {
slider2.css("left", (slider1_position + slider_width) + "px");
}
}

Categories