I'm using the following code to create a sliding card effect where each "card" is a list element and they slide across the screen. They are only visible within the "stage" I've set with specific height and width. It's working great -- except that, while the cards slide out nicely to the left, they don't perform the same sliding function inwards from the right. Instead, it simply jumps onto the page and looks a bit startling.
Does anyone know how I could get the next list item to slide in from the right instead of simply appearing?
Thanks!
JS:
window.addEvent('domready', function () {
var totIncrement = 0;
var increment = 968;
var maxRightIncrement = increment * (-303); //this is -303 because there are 303 cards, but the example below only has 3
var fx = new Fx.Style('slider-list', 'margin-left', {
duration: 300,
//transition: Fx.Transitions.Back.easeInOut,
wait: true
});
// EVENTS for the button "previous"
var pbuttons = document.getElementsByClassName('prevButton');
for(i = 0; i < pbuttons.length; i++) {
$(pbuttons[i]).addEvents({
'click': function (event) {
if(totIncrement > maxRightIncrement) {
totIncrement = totIncrement + increment;
fx.stop()
fx.start(totIncrement);
}
}
});
}
//-------------------------------------
// EVENTS for the button "next"
// var buttons = $('.nextButton');
var buttons = document.getElementsByClassName('nextButton');
for(i = 0; i < buttons.length; i++) {
$(buttons[i]).addEvents({
'click': function (event) {
if(totIncrement > maxRightIncrement) {
totIncrement = totIncrement - increment;
fx.stop()
fx.start(totIncrement);
}
}
});
}
});
HTML:
<div id="slider-stage">
<ul id="slider-list">
<li id="l1">
<!-- previous button -->
<div class="prev"><a class="prevButton" href="#">Previous</a></div>
<div>
<!-- content goes here -->
<!-- next button -->
<div class="slider-buttons">
<a class="nextButton" href="#">Next</a>
</div>
</div>
</li>
<li id="l2">
<!-- previous button -->
<div class="prev"><a class="prevButton" href="#">Previous</a></div>
<div>
<!-- content goes here -->
<!-- next button -->
<div class="slider-buttons">
<a class="nextButton" href="#">Next</a>
</div>
</div>
</li>
<li id="l3">
<!-- previous button -->
<div class="prev"><a class="prevButton" href="#">Previous</a></div>
<div>
<!-- content goes here -->
<!-- next button -->
<div class="slider-buttons">
<a class="nextButton" href="#">Next</a>
</div>
</div>
</li>
</ul>
</div>
Related
I am creating frontend using vue 2.
There I have a chat inside tag and have done auto-scroll to the end of chat on updated().
Unfortunately, it scrolls not only inside chat box but also the whole page to this moment. How to override it? (show the whole code for you to recognise that it's impossible to have a ref on last message but not div - loaded_messages is an array from API and dialogs - from WebSocket)
<template>
<div class="box col-md-8" >
<div id="chat-messages" class="chat__order" style="
border: 1px solid grey; overflow-y: scroll;">
<ol class="chat">
<div v-for="m in loaded_messages[0]"
direction="column"
justify-content="start"
align-items="end"
margin-left=2px
:key="m.id">
<li class="self" v-if="m.username == user">
<b-avatar :src="m.get_message_info.get_thumbnail"></b-avatar>
<div class="msg">
<p>{{m.content}} </p>
<time>{{m.get_datetime}}</time>
</div>
</li>
<li class="other" v-else>
<b-avatar :src="m.get_message_info.get_thumbnail"></b-avatar>
<div class="msg">
<p>{{m.content}}</p>
<time>{{m.get_datetime}}</time>
</div>
</li>
</div>
<div v-for="dialog in dialogs"
direction="column"
justify-content="start"
align-items="end"
:key="dialog.id">
<li class="self" v-if="dialog.username == user">
<b-avatar></b-avatar>
<div class="msg">
<p>{{dialog.message}} </p>
<time>{{dialog.datetime}}</time>
</div>
</li>
<li v-else>
<b-avatar></b-avatar>
<div class="msg">
<p> {{dialog.message}} </p>
</div>
</li>
</div>
<div ref="lastMessage"></div>
</ol>
</div>
</div>
</template>
<script>
methods: {
// scroll to the last message
scrollToElement() {
const [el] = this.$refs.lastMessage;
if (el) {
el.scrollIntoView({ behavior: "smooth" });
}
},
},
updated() {
this.scrollToElement();
},
</script>
scrollIntoView method doesn't support scrolling inside a container, it only works with the document viewport, you need to calculate the X distance to the top of the element.
You can use this method.
function scrollParentToChild(parent, child) {
// Where is the parent on page
var parentRect = parent.getBoundingClientRect();
// What can you see?
var parentViewableArea = {
height: parent.clientHeight,
width: parent.clientWidth
};
// Where is the child
var childRect = child.getBoundingClientRect();
// Is the child viewable?
var isViewable = (childRect.top >= parentRect.top) && (childRect.bottom <= parentRect.top + parentViewableArea.height);
// if you can't see the child try to scroll parent
if (!isViewable) {
// Should we scroll using top or bottom? Find the smaller ABS adjustment
const scrollTop = childRect.top - parentRect.top;
const scrollBot = childRect.bottom - parentRect.bottom;
if (Math.abs(scrollTop) < Math.abs(scrollBot)) {
// we're near the top of the list
parent.scrollTop += scrollTop;
} else {
// we're near the bottom of the list
parent.scrollTop += scrollBot;
}
}
}
Background
I made slides which are appeared on a modal, and its main functions are below.
There are "←Prev, Next→" buttons, and it enables to flip the page.
There are page numbers, "1, 2, 3", and it enables to flip the page.
If the shown page is the first or the last one, "←Prev, Next→" buttons are hidden, respectively.
Those functions were working properly when I had only one slide with the code below, but the last funtion doesn't work with multiple slides now.
slide.html.erb
<ul>
<li><div data-target="slide01">Slide1</div>
<div id="slide01" class="modal-wrapper">
<div class="modal">
<div class="close-modal">
<i class="fa fa-2x fa-times"></i>
</div>
<div class="slide-wrapper">
<div class="slide-title">Slide1</div>
<div class="change-btn-wrapper">
<div class="change-btn prev-btn">← Prev</div>
<div class="change-btn next-btn">Next →</div>
</div>
<ul class="slides">
<li class="slide active">A</li>
<li class="slide">B</li>
<li class="slide">C</li>
</ul>
<div class="index-btn-wrapper">
<div class="index-btn">1</div>
<div class="index-btn">2</div>
<div class="index-btn">3</div>
</div>
</div>
</div>
</div>
</li>
<li><div data-target="slide02">Slide2</div>
<div id="slide02" class="modal-wrapper">
<div class="modal">
<div class="close-modal">
<i class="fa fa-2x fa-times"></i>
</div>
<div class="slide-wrapper">
<div class="slide-title">Slide2</div>
<div class="change-btn-wrapper">
<div class="change-btn prev-btn">← Prev</div>
<div class="change-btn next-btn">Next →</div>
</div>
<ul class="slides">
<li class="slide active">D</li>
<li class="slide">E</li>
<li class="slide">F</li>
</ul>
<div class="index-btn-wrapper">
<div class="index-btn">1</div>
<div class="index-btn">2</div>
<div class="index-btn">3</div>
</div>
</div>
</div>
</div>
</li>
</ul>
slide.js
$(document).on('turbolinks:load', function() {
$(function() {
function toggleChangeBtn(){
var slideIndex = $('.slide').index($('.active'));
$('.change-btn').show();
if (slideIndex == 0) {
$('.prev-btn').hide();
} else if (slideIndex == $('.slide').length -1) {
$('.next-btn').hide();
}
$('.index-btn').click(function() {
$('.active').removeClass('active');
var clickedIndex = $('.index-btn').index($(this));
$('.slide').eq(clickedIndex).addClass('active');
toggleChangeBtn();
});
$('.change-btn').click(function() {
var $displaySlide = $('.active');
$displaySlide.removeClass('active');
if ($(this).hasClass('next-btn')) {
$displaySlide.next().addClass('active');
}
else {
$displaySlide.prev().addClass('active');
}
toggleChangeBtn();
});
})
});
Problems
Those codes below check if the shown page is the first or the last one from its index number, and hide "←Prev, Next→" buttons, respectively.
slide.js
var slideIndex = $('.slide').index($('.active'));
$('.change-btn').show();
if (slideIndex == 0) {
$('.prev-btn').hide();
} else if (slideIndex == $('.slide').length -1) {
$('.next-btn').hide();
}
The trouble is that those index numbers are connected when multiple slides are made. As a result, the code above just checks only both of the first page in the first slide and the last page in the last slide.
What I have tried
I tried to use $(this).parents method to narrow down the range of the slide like below. I did not make any change on the view.
slide.js
$(document).on('turbolinks:load', function() {
$(function() {
function toggleChangeBtn(dir){
var dir = $(this).parents('.slide-wrapper'); // Identify the slide.
$('.change-btn').show();
var slideIndex = dir.find('.slide').dir.index('.active');
if (slideIndex == 0) {
dir.find('.prev-btn').hide();
} else if (slideIndex == dir.find('.slide').length -1) {
dir.find('.next-btn').hide();
}
}
$('.index-btn').click(function() {
var dir = $(this).parents('.slide-wrapper');
dir.find('.active').removeClass('active');
var clickedIndex = $('.index-btn').index($(this));
$('.slide').eq(clickedIndex).addClass('active');
toggleChangeBtn(dir);
});
$('.change-btn').click(function() {
var dir = $(this).parents('.slide-wrapper');
var $displaySlide = dir.find('.active');
$displaySlide.removeClass('active');
if ($(this).hasClass('next-btn')) {
$displaySlide.next().addClass('active');
}
else {
$displaySlide.prev().addClass('active');
}
toggleChangeBtn(dir);
});
})
});
However, "←Prev, Next→" buttons are not hidden properly in any slide with this code.
And how "←Prev, Next→" buttons are shown in one slide affects to the other slide too.
I am grateful if anyone gives me some advice.
Versions
ruby 2.6.4p104
RubyGems 3.0.3
Rails 5.2.3
jquery 1.12.4
If both buttons should be independent of each other, why are they made dependant by the if / else if block?
if (slideIndex == 0) {
dir.find('.prev-btn').hide();
} else if (slideIndex == dir.find('.slide').length -1) {
dir.find('.next-btn').hide();
}
To make the .prev-btn and .next-btn appear/disappear independently, make these independant if statements:
var slides = dir.find('.slide');
var slideIndex = slides.length ? slides.dir.index('.active') : 0;
if (slideIndex == 0) {
dir.find('.prev-btn').hide();
}
if (slides.length <= 1 || slideIndex == slides.length - 1) {
dir.find('.next-btn').hide();
}
I have had an issue with placing slideshows in my website. I require more than one slideshow on the same page which has led to multiple problems with the scrolling and such. I finally came across a solution which works almost perfectly however, the indicators do not change color to reflect the current slide.
var w3 = {};
w3.slideshow = function (sel, ms, func) {
var i, ss, x = w3.getElements(sel), l = x.length;
ss = {};
ss.current = 1;
ss.x = x;
ss.ondisplaychange = func;
if (!isNaN(ms) || ms == 0) {
ss.milliseconds = ms;
} else {
ss.milliseconds = 1000;
}
ss.start = function() {
ss.display(ss.current)
if (ss.ondisplaychange) {ss.ondisplaychange();}
if (ss.milliseconds > 0) {
window.clearTimeout(ss.timeout);
ss.timeout = window.setTimeout(ss.next, ss.milliseconds);
}
};
ss.next = function() {
ss.current += 1;
if (ss.current > ss.x.length) {ss.current = 1;}
ss.start();
};
ss.previous = function() {
ss.current -= 1;
if (ss.current < 1) {ss.current = ss.x.length;}
ss.start();
};
ss.display = function (n) {
w3.styleElements(ss.x, "display", "none");
w3.styleElement(ss.x[n - 1], "display", "block");
}
ss.start();
return ss;
};
<html>
<script src="w3.js"></script>
<body>
<div id="2" class="w3-row-padding w3-light-grey w3-padding-64 w3-container">
<div class="w3-content">
<div class="w3-content w3-display-container w3-center">
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<!-- Second slide App Development -->
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<!-- Third slide App Development -->
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<!-- Fourth slide App Development -->
<div class = "Slide2 w3-animate-opacity">
<h1> Slide Content </h1>
</div>
<div class="w3-center w3-container w3-section w3-large w3-text-grey" style="width:100%">
<span class="w3-left w3-hover-text-blue fa fa-arrow-left" onclick="myShow2 .previous()"></span>
<span class="w3-right w3-hover-text-blue fa fa-arrow-right" onclick="myShow2 .next()"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(1)"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(2)"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(3)"></span>
<span class="fa fa-circle demo w3-hover-text-blue w3-transparent" onclick="myShow2 .display(4)"></span>
</div>
</div>
</div>
<script> myShow2 = w3.slideshow(".Slide2", 0); </script>
</div>
</body>
</html>
So the code works well and does what I want except I'm not sure how to make the circle indicators change to blue to reflect the current slide. I have tried completely different approaches except this is the only one that allows multiple slideshows on the same page. Could some please explain to me how I would go about making the circles stay blue when clicked and revert when another is clicked?
I have found a solution to my problem. First I added an extra variable to call a function <script> myShow4 = w3.slideshow(".Slide4", 0, "demo4"); </script>
the "demo4" will be used to find the indicator dots. <span class="fa fa-circle demo4 w3-hover-text-blue w3-transparent" onclick="myShow4 .display(4)"></span>each indicator has the specific class.
`ss.display = function (n) {
ss.current = n;
w3.styleElements(ss.x, "display", "none");
w3.styleElement(ss.x[n - 1], "display", "block");
ss.indicator(demo);
}
ss.indicator = function(n) {
var dots = document.getElementsByClassName(n);
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" w3-text-blue", "");
}
x[ss.current-1].style.display = "block";
dots[ss.current-1].className += " w3-text-blue";
}`
This is the new code in the JS file. on click the display function is called and I edited the function to also call the indicator function which changes the current slide relevant dot to blue while changing the rest to nothing or how they were before. This solution worked for me, adding another function within the called function.
I'm basically new to coding but i have this LONG list of products which i need to filter according to certain criteria plus a show more/less function. The issues are: 1. When i filter elements, some categories have less items than the default set, 2. if the shown element's total height is is shorter i need the container's height to match that height (i set a max-height but then it won't increase when the filter changes the number of products or i try to expand the list to show other hidden products) 3. if a filter is applied and the list is longer than the default lenght shown, if i use the function to show more items, the hidden elements that do not belong to that category become visible.
Here is the actual jquery script, the html is so long i'm not posting it complete, but i'll post an example of the product setup.
jQuery script
$(document).ready(function() {
var productList = $("#product_list:nth-child(3n+1):visible").height(); /*$("#product_list:nth-child(3n+1):visible").each(function(){productList += $(this).height();});*/
var counter = 0;
//filter functions
$("ul#filters li a.button").click(function() {
$("ul#filters li a.button").removeClass("active");
$(this).addClass("active");
if ($(this).hasClass("active") == true) {
var act = $(this).attr("id");
$(".product:not(#" + act + ")").fadeOut(800);
$(".product#" + act + "").fadeIn(800);
$(".products .product:nth-child(4n+1)").css("border-left-width", 0);
$("#product_list:last-child:visible").css("border-right", "2px dashed #008140");
if (act == "all") {
$(".product").fadeIn(800);
} else {
if ($(".product:last:visible") >= $(".product:last")) {
//$("#loadmore").css("display", "none");
$(".product:last:visible").css("border-right", "2px dashed #008140");
}
}
}
});
//show more -show less
$("#loadmore").click(function showNext() {
$("#product_list").animate({
height: productList + 3000
}, 800);
$(".product:hidden:lt(20)").slideDown();
$("#showless").css("display", "block");
counter = counter + 20;
productList = productList + 3000;
if ($(".product:last").is(":visible")) {
$("#product_list").css("max-height", (productList - 2300));
$("#product_list:last-child:visible").css("border-right", "2px dashed #008140");
$("#loadmore").css("display", "none");
}
if ($("."))
});
$("#showless").click(function showLess() {
//$(".product:visible:gt("+(counter-1)+")").slideUp()
$("#product_list").animate({
height: productList - 3000
}, 800);
counter = counter - 20;
productList = productList - 3000;
if (productList == 3000) {
$("#showless").css("display", "none");
}
if ($("#loadmore").css("display", "none")) {
$("#loadmore").css("display", "block");
}
});
});
product HTML
<div class="container">
<!-- Row -->
<div class="row" id="product_list">
<!-- Product -->
<div class="col-xs-6 col-sm-3 product" id="belleza">
<!-- Entry -->
<div class="entry">
<figure class="entry-thumbnail">
<img alt="" src="../resources/images/productos/Shampoo-neutro.png"/>
</figure>
<div class="entry-body">
<h3 class="entry-title">
Shampoo Petra Neutro<br/>
</h3>
<h2 class="entry-title">
<select id="presentaciones">
<option id="shampoo-neutro260">Frasco Dosificador x260ml</option>
</select>
</h2>
<h2 class="entry-title" id="disponible">Disponibles: <span class="unidades" id="shampoo-neutro">10</span>
</h2>
<span class="price"><ins><span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>12.00</span></ins>
<del><span class="woocommerce-Price-amount amount"><span class="woocommerce-Price-currencySymbol">$</span>15.00</span></del></span>
<div class="buttons">
<a class="button add_to_cart_button" rel="nofollow">Add to cart</a>
</div>
</div>
</div>
<!-- End Entry -->
</div>
<!--End Col -->
</div>
</div>
Hi i currently have two toggles, one is on the sidebar and one is in the main body. They currently work together which is annoying, even though i am using to different scripts. The scripts i am using at the moment for the toggles are almost identical, however, even when using completely different scripts they still work together.
what i mean by work together is when i click the toggle on the main body the side bar toggle reacts.
They are toggles which collapse on oclick.
<script>
var divs = ["Menu", "Add"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<script>
$(document).ready(function () {
// set up the click event
$('.body > a').on('click', function(){
$(this).next('div').siblings('div:not(#Menu)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#Menu').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<!-- sidebar toggle-->
<script>
var divs = ["Order", "Rest", "Franc"];
var visibleDivId = null;
function toggleVisibility(divId) {
if(visibleDivId === divId) {
visibleDivId = null;
} else {
visibleDivId = divId;
}
hideNonVisibleDivs();
}
function hideNonVisibleDivs() {
var i, divId, div;
for(i = 0; i < divs.length; i++) {
divId = divs[i];
div = document.getElementById(divId);
if(visibleDivId === divId) {
div.style.display = "block";
} else {
div.style.display = "none";
}
}
}
</script>
<!-- Change color on click-->
<script>
$(document).ready(function() {
$('.sidebar h3').on('click', function() {
$('.sidebar h3').css('color', 'black');
$(this).css('color', 'red');
});
$('h3#open').trigger('click'); //Your account red on page load
});
</script>
<!--Your account toggle open on load -->
<script>
$(document).ready(function () {
// set up the click event
$('.sidebar > a').on('click', function(){
$(this).next('div').siblings('div:not(#Franc)').hide("1");
});
// trigger orders which has id francc, not orders // .show("1") goes between $(this).next('div') + .siblings
// if i want a transition
$('#francc').trigger('click');
// options include >>>, but it's slower // $('a[name="account"]').trigger('click');
});
</script>
<div class="sidebar">
<!-- Orders toggle-->
<a id="order" class="header" href="#" onclick="toggleVisibility('Order');"><h3 id="orderr">Orders</h3></a>
<div id="Order" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Red">Overview</li>
</ul>
</div>
</div>
<!--Restaurant toggle-->
<a id="restt" class ="header"href="#" onclick="toggleVisibility('Rest');"><h3>Your Restaurants</h3></a>
<div id="Rest" style="display: none;"><div>
<ul class="tabs">
<!-- <li id="order" class="rred">restaurant</li>-->
<li id="order" class="rgreen">New restaurant</li>
</ul>
</div>
</div>
<!-- Account toggle-->
<a id="francc" name="account" class ="header" href="#" onclick="toggleVisibility('Franc');"><h3 id="open">Your Account</h3></a>
<div id="Franc" style="display: none;">
<div>
<ul class="tabs">
<li id="order" class="Blue" >Order History</li>
</ul>
</div>
</div>
</div>
<div id=body>
<!-- Menu toggle -->
<div class="container_head"> <!-- red header top of container-->
<a id="Menu" class="header" href="#" onclick="toggleVisibility('Menu');"><h3>Menu Section</h3></a>
</div>
<div id="Menu_form" style="display: none;">
<form id="MenuForm" action ="javascript:void(0);" method="POST">
<!-- <div class="field">-->
<label for="Name">Name</label>
<input type="text" name="Name" id="Name" placeholder="Steaks pattern="[a-zA-Z]"
required tabindex="1">
<br>
<label for="Description">Description</label>
<input type="text" name="Description" id="Description" placeholder="Fresh USDA Choice steaks, seasoned with hickory-smoked sea salt." tabindex="2">
<br>
<div class="field">
<input type="submit" value="Save">
</div>
</form>
</div>
<a id="add_prod" class="header" href="#" onclick="toggleVisibility('Add');"><h3>Orders</h3></a>
<div id="add" style="display: none;">
</div>
Bringing together #j08691 and Leo Farmer's comments, you need to have unique IDs and function names. When you call toggleVisibility(...), it's going to call the second declaration of that method. Also, when you call document.getElementById(...) on something like "order", it's going to stop at the first instance it finds (In your case, the a tag).
Give your functions unique names, give your items unique IDs (if you want them to all do the same thing, you can look at using the same class for each item), and you should be in a better spot.