Autoplay two Bootstrap Popover at a time instead of one - javascript

http://jsfiddle.net/umpe9a9j/
Currently it auto-plays 1 Popover at a time in a loop. However, I would like to have it auto played 2 Popover at a time. Of course, in a loop.
More Popovers will be added. How do I get this going?
HTML
<div class="container">
Hover Left |
Hover Right |
Click Me |
Click Me
</div>
JS
$(document).ready(function () {
var time = 1000;
var len = $('.myclass').length;
var count = 0;
var fun = setInterval(function () {
count++;
if (count > len) {
$('.p' + (count - 1)).popover('hide');
count = 1;
//clearInterval(fun);
}
$('.p' + count).popover('show');
if (count > 1) {
var pre = count - 1;
$('.p' + pre).popover('hide');
}
}, time);
});

I got a working example of what you are looking for. You can specify the number of popOver items to simultaneously show, and it will continue down the chain (and loop back if necessary) for each interval. The first thing I changed are the popOver class names. They now go from p0-p1-p2-p3, making it consistent with a 0 index array. This makes for less -1's in the code. So Html looks like:
<div class="container">
Hover Left |
Hover Right |
Click Me |
Click Me
</div>
Now the js function is straight forward but a might be a little confusing to look at. You first important variable is numConcrPopOver, this defines the number of simultaneous popOver items you want shown. Then in the interval function the code fills in 2 arrays of indexes; one for the number of popOver items to show and another for the items to hide that were previously shown. Using a for loop and the numConcrPopOver defined, it creates these lists. Take note of the modulo operator used multiple times in this section, its to ensure that elements to show and hide remain within the length of the total number of popOver items, looping back to the beginning when its over this length.
After these 2 arrays have been populated, first we need to remove any items in the popToHide array that also exist in the popsToShow array. This is done for scenarios where the number of simultaneous items to show is greater than half the total items. In this case because of the way the popsToHide array is first filled, it will contain indices that also belong in the popsToShow array. So we just filter through the popsToHide array and remove the duplicates to only hide popOver items that were previously shown but not also being currently shown.
As an example of the sequence of popOver items; if you have 4 total popOver items, and you want to show 3 at a time. The expected order of shown popOvers per interval is:
0-1-2 -> 1-2-3 -> 2-3-0 -> 3-0-1 ...
The javascript for this is:
$(document).ready(function(){
var time = 1000;
var popOverLength = $('.myclass').length;
var popOverIdx = 0;
var numConcrPopOver = 2;
var fun = setInterval(function(){
var popsToShow = []; //Array that will hold index of popOvver items to show
var popsToHide = []; //Array that will hold index of popOvver items to hide
//Loop for the number of simultanious popOver you want to show
for(var popNum=0; popNum<numConcrPopOver; popNum++){
var currPopIdx = popOverIdx+popNum; //Index o fthe current popOver to show
popsToShow.push(currPopIdx%popOverLength); //Alwyas mod index to keep within lenght of popOver items
var hidePopIdx = popOverIdx-1-popNum; //The index of the previous popOver item to hide
if(hidePopIdx < 0){
hidePopIdx = popOverLength-1-popNum
}
popsToHide.push(hidePopIdx%popOverLength);
}
popOverIdx+=numConcrPopOver;
popOverIdx%=popOverLength;
//Remove from popToHide array any items in the popToShow array.
//This is done for the scenarios where the numebr of popovers to
//Show in greater than half the total number of popovers,
//otherwise will hide immediatly after showing
popsToHide = popsToHide.filter(function(itm) {return popsToShow.indexOf(itm) < 0;});
popsToShow.forEach(function(itm){ //Iteratre of popOver items to show them
$('.p'+itm).popover('show');
});
popsToHide.forEach(function(itm){ //Iteratre of popOver items to hide them
$('.p'+itm).popover('hide');
});
}, time);
});
You can test out diffrent numbers of simultaneous popOvers by altering the numConcrPopOver variable. I've updated yous jsfiddle to include the new code: here

Related

Opacity on first and last element of slider which has ".active" classes using javascript or css

I have owl carousel slider with 5 items. And my problem is that i need first and last element of my slider to be always with opacity. Slider has like 15 elements which 9 cloned, 5 have .active class and one with cloned and .active.
I tryied make it using javascript where i found all ".active" classes in slider, but i don't exactly know what i should do with object which was found.
There is code which found all ".active" classes
var owlCarouselActive = document.getElementById("slider-tour").getElementsByClassName("owl-item active");
I need in order to this .active first and last have :before with my background style when i click on button prev or next.
You could do this with javascript
var owlCarouselActive = document.getElementsByClassName("owl-item active");
var first = owlCarouselActive[0]; //get first item
var last = owlCarouselActive[owlCarouselActive.length - 1]; //get last item
first.style.opacity = 0.8;
last.style.opacity = 0.8;
I'm not at home but try something like this:
function setOpacity() {
var elements = $('.active');
let count = 0;
$(elements).each(function(k,v) {
if (count == 0 || count == elements.length - 1) {
$(v).css('opacity', '0.8');
}
count++;
});
}
$(document).ready(function() {
setOpacity();
});
Run that function everytime you want it to update.
E.G on a button click.
You can use owlCarouselActive [0] to access the first element and owlCarouselActive [owlCarouselActive.length-1] to access the last element. Generally you can access i-th element by owlCarouselActive [i].

JavaScript: image slider changes only once upon clicking

I'm puzzled by the function of my JavaScript image slider since it changes the slide only once upon clicking next (I haven't worked on previous yet, but should be logical enough to re-adjust). The code is given by:
$(".room_mdts").click(function(event){
//get the target
var target = event.currentTarget;
var room = $(target).data("room");
currentIndex = parseInt($(target).attr('data-room'));
//First way, by reuse target (only inside this function)
$('#room_details_holder').show();
//The second, by using selectors
//remove all "selected" classes to all which have both "room" and "selected" classes
$('.room_exp.selected').removeClass("selected");
//add "selected" class to the current room (the selector can also be the target variable)
$('.room_exp[data-room='+room+']').addClass("selected");
});
var currentIndex = 0;
var adjIndex = currentIndex - 1,
items = $('.room_details .room_exp'),
itemAmt = items.length;
function cycleItems() {
var item = $('.room_details .room_exp').eq(currentIndex);
items.hide();
item.css('display','inline-block');
}
$('.room_next').click(function() {
adjIndex += 1;
if (adjIndex > itemAmt - 1) {
adjIndex = 0;
}
cycleItems(adjIndex);
cycleItems(currentIndex);
$('#room_name').text($('.room_exp:nth-child('+(adjIndex+2)+')').attr('title'));
});
$('.room_previous').click(function() {
currentIndex -= 1;
if (currentIndex < 0) {
currentIndex = itemAmt - 1;
}
cycleItems(currentIndex);
$('#room_name').text($('.room_exp:nth-child('+(currentIndex+1)+')').attr('title'));
});
$('#room_name').text($('[style*="inline-block"].room_exp').attr('title'));
});
The reason I had to introduce adjIndex is because without '-1' the slide changed by 2 on the first click, again, no idea why.
The Fiddle: https://jsfiddle.net/80em4drd/2/
Any ideas how to fix that it only changes once? (And also, the #room_name only shows after the click, does not show upon expanding).
Try this I rearranged your code a little bit:
made your currentIndex global and assigned with the adjIndex. If that's ok I will improve my answer:
If you click on the right arrow it goes to the end and comes back to the beginning.
url: https://jsfiddle.net/eugensunic/80em4drd/3
code:
function cycleItems() {
currentIndex=adjIndex;
var item = $('.room_details .room_exp').eq(currentIndex);
items.hide();
item.css('display','inline-block');
}
Okay, great thanks to eugen sunic for the little push that got me thinking!
I have finially cracked all of the pieces, although, I might have some extra unecessary bits of code, duplicates etc, but the functionallity is just perfect!
What I have edited:
I moved one of the closing brackets for the cycleFunction () closing bracket to the end of .click functions, that is to make the variable global (at least for those 3 functions)
I changed the title writing function from: $('#room_name').text($('[style*="inline-block"].room_exp').attr('title'));
to:$('#room_name').text($('.room_exp:nth-child('+(adjIndex+2)+')').attr('title'));
Added a few changes regarding .addClass/.removeClass to the $('.room_details_close').click(function(){.
Now, openning any of the thumbnails shows the title immediately (the right title), clicking '<<' or '>>' changes the slide to next and previous, respectively, while the title changes accordingly. Closing the expanded menu and clicking on a different thumbnail results in re-writing the currentIndex (hence, adjIndex too), so the function starts again with no problem.
Please feel free to use!
The new fiddle is: Fiddle

Javascript - Dynamic Expand/Collapse All

I have a jQuery Tree Report that I am trying to create 'expand/collapse all' buttons for.
The following two pieces of code are fired when the corresponding buttons are pressed and work great:
for (i = 1; i < 100; i++) {
var el = $('#dtt_2597807651112537_table tbody tr')[i - 1];
// store current level
var level = Number($(el).attr('dtt_level'));
// change icon
$(el).find('span.dtt_icon').removeClass('dtt_collapsed_span');
$(el).find('span.dtt_icon').addClass('dtt_expanded_span');
while ($($(el).next()).attr('dtt_level') != null) {
var el = $(el).next();
if ($(el).attr('dtt_level') == (level + 1)) {
// change display
el.removeClass('dtt_collapsed_tr');
el.addClass('dtt_expanded_tr');
} else if ($(el).attr('dtt_level') == level) {
break;
}
}
}
for (i = 1; i < 100; i++) {
// get related table row
var el = $('#dtt_2597807651112537_table tbody tr')[i - 1];
// store current level
var level = Number($(el).attr('dtt_level'));
// change icon
$(el).find('span.dtt_icon').addClass('dtt_collapsed_span');
$(el).find('span.dtt_icon').removeClass('dtt_expanded_span');
while ($($(el).next()).attr('dtt_level') != null) {
var el = $(el).next();
if ($(el).attr('dtt_level') > level) {
// change display
el.addClass('dtt_collapsed_tr');
el.removeClass('dtt_expanded_tr');
// change icon
$(el).find('span.dtt_icon').addClass('dtt_collapsed_span');
$(el).find('span.dtt_icon').removeClass('dtt_expanded_span');
} else if ($(el).attr('dtt_level') == level) {
break;
}
}
};
However, I was wondering if anyone had a nice way to:
1) Get the number of rows that need to be looped through - I just put 100 as a large number to prove my code worked and I don't want to just increase this to an even larger number.
2) Get the class name from the page source - The large number in "dtt_2597807651112537_table" is a report ID generated by the application. This is static for now but I want to eliminate any problems if it changes.
Thanks.
This is all wrong. Well, it's working against how jQuery works, in any case.
jQuery's credo is:
Select elements
Do stuff to them
Drop your loops. You don't need them.
For example. To toggle the icon on all span.dtt_icon in your document, do
var collapsed = true;
$("#dtt_2597807651112537_table span.dtt_icon") // select elements
.toggleClass('dtt_collapsed_span', collapsed) // do stuff to them
.toggleClass('dtt_expanded_span', !collapsed);
or, as a function that can both collapse and expand:
function toggleTree(tree, collapsed) {
$(tree).find("span.dtt_icon")
.toggleClass('dtt_collapsed_span', collapsed)
.toggleClass('dtt_expanded_span', !collapsed);
}
To collapse only the currently expanded ones...
$("#dtt_2597807651112537_table span.dtt_icon.dtt_expanded_span")
.toggleClass('dtt_collapsed_span', true)
.toggleClass('dtt_expanded_span', false);
and so on.
You can boil down your entire code into a few lines that way, and you don't need to write a single loop: Use smart element selection (via jQuery selectors and any of jQuerys find, filter and traversal functions) to single out the elements you want to manipulate and then manipulate them all at once in a single step.
To your second question. There are many ways, pick one:
use known page structure to determine the right table (e.g. $("div.main > table:first") or something to that effect)
use known table contents to determine the right table (e.g. $("table:has(span.dtt_icon)"))
use the table's other classes ($("table.treeReport") maybe?) or for example the table's ID with and a "starts-with" selector ($("table[id^=dtt_]")).
Again it's all about selecting your elements smartly. A dive into the jQuery API documentation, in this case the part about selectors, is recommended.

Javascript to fade text in, one word at a time, works with one div, but not multiple divs?

I'm trying to fade in one word at a time from a div. The below code works fine for one div but when I have multiple divs, it does not do it sequentially.
Here is the fiddle : http://jsfiddle.net/zlud/6czap/110/
Can anyone see an obvious problem? Any suggestions to print one line after the other would be greatly appreciated. (So the text in the second div will be printed after the first div is done.)
<html>
<div class="example">These are some words that </br> should be faded in one after the other.</div>
<div class="example"> No way some words that </br> should be faded in one after the other.</div>
</html>
JavaScript
var $el = $('.example').map(function () {
return this;
}).get();
$el.forEach(function (eachdiv){
var text = $(eachdiv).text(),
words = text.split(" ");
var html = "";
for (var i = 0; i < words.length; i++) {
html += "<span>" + words[i] + " </span>";
$(eachdiv).html(html).children().hide().each(function(i){
return $(this).delay(i*500).fadeIn(700);``
});
}
});
How about this?
I am assuming you dont need a delay in animation, instead you need them to appear one after the other.
var words, $el;
var arrEl = [];
// loop through each div and populate the array with the container (div) element and its text content split
$('.example').each(function(){
var $this = $(this);
arrEl.push({el:$this,words : $.trim($this.text()).split(" ")});
$this.empty();
});
//This will the startup function
function fadeIn(){
var len = arrEl.length, obj = arrEl.shift() || {}; //get the top item from array and remove it from the array using array.shift
$el = obj.el; //get the container from the item
words = obj.words; //get the array of words
//if there are any items in the array start the animation process for this item.
if(len) window.setTimeout(transitionElement, 0);
}
function transitionElement(){
var wlen = words.length,
span = $('<span/>', {'class':'hide'}).append(" " + words.shift()); //remove and get the top text string from the word array wrap it in span with a class "hide" which will hide it by default
window.setTimeout(function(){
if(wlen) //if words are available anymore then call show word
showWord(span);
else //else call fadeIn to process the next container in the arrEl array of items
fadeIn();
},0);
}
function showWord(span){
span.appendTo($el).fadeIn(500, transitionElement); // append the span to the container with an animation duration of 500ms and in the complete callback of this invoke transitionElement to process the next word or next item. Here there is no delay required since this will invoked only when the transition of first word is completed
}
//Start animation process
fadeIn();
Fiddle
fadeIn() callback syntax
Array.shift
Jquerys animation functions have a callback in the parameter list. This callback will be executed after the animation completes. Or maybe it's that i is passed by reference.
You should pick on div at a time to work on and continue to the next one ones the first is done. Now you attach the delay and fade-in to each word in each div at the same time. Initiate the animation of the second div by a trigger when the first one is done or something like that?

JavaScript multiple draggable DIV windows, zIndex on focus

I have multiple JavaScript draggable DIV windows. When clicking a DIV, I want the window to get the highest z-index value. I've made a solution by adding/removing classes to the element in focus, BUT, I would like the windows to keep their "layer" -order (as if the entire DIV window node was re-appended to the DOM when being clicked).
Let's say there are five DIV's in the DOM. div1, div2, div3, div4 and div5. -div5 is closest to the front and div1 is in the back and so on.
When clicking div1, -div1 will get focus and put to front, setting div5 back one step. Then clicking div3, -div3 gets closest to front and div1 and div5 are put back one step like this: div2, div4, div5, div1, div3.
If you don't want to loop through all your divs and don't want to mess up with z-index you can just append again that div to the parent element (the body?) before dragging.
function stepUpNode(elementDragged){
var parentNode = elementDragged.parentNode;
parentNode.appendChild(elementDragged);
}
If you'd like to do this without re-appending the element, my solution when I wrote something similar a while back was to keep track of the maximum z-index. Every time a window is brought forward, the maximum z-index is incremented and the element's z-index is set to the new value. Of course, if someone messes with the windows enough, they might end up having very large z-index values, so this isn't always the best solution.
var maximumZIndex = 1;
var bringForward = function (element) {
maximumZIndex += 1;
element.style.zIndex = maximumZIndex;
}
The first and most likely easiest approach: simply increase the maximum z-index every time a div gets selected. Since the z-index value can become pretty large (2147483647 if I remember correctly) you most likely will never run out of levels...
The following snippets use some jQuery:
var frontmostWindow = null;
var topZIndex = 10;
$('div').click(function() {
if (this != frontmostWindow) {
frontmostWindow = this;
topZIndex++;
$(this).css('zLevel', topZIndex);
// anything else needed to acticate your div
// ...
}
});
If you have restrictions on the z-indices you can use, you will need to re-assign levels every time a different div gets selected, e.g. like this:
// store z-index-ordered divs in an array
var divs = $('div').toArray().sort(function(a, b) {
return parseInt($(a).css('zIndex'), 10) - parseInt($(b).css('zIndex'), 10);
});
// store available z-indices
var zIndices = [];
for (var i = 0; i < divs.length; ++i) {
zIndices.push($(divs[i]).css('zIndex'));
}
// Event listener for clicks
$('div').click(function() {
alert("heyya " + this.id);
var element = this;
var index = divs.indexOf(element);
// check if clicked element is not already the frontmost
if (index < divs.length - 1) {
// remove div from array and insert again at end
divs.splice(index, 1);
divs.push(this);
// re-assign stored z-indices for new div order
for (var i = 0; i < divs.length; ++i) {
$(divs[i]).css('zIndex', zIndices[i]);
}
// anything else needed to acticate your div
// ...
}
});

Categories