How to modify this jQuery plugin slider for scrolling and orientation? - javascript

I found a jQuery slider plugin that does almost what I need. I need to change the tabs so it is on the right side (by adding an option). Also, I would like to add scrolling to the tabs in case there is more than 3 tabs (also by an option). I am trying to make it look like this which is an artist mock up:
http://i.stack.imgur.com/nR8RY.png
This is the script I am trying to modify with the code below it:
http://jqueryglobe.com/labs/feature_list/
/*
* FeatureList - simple and easy creation of an interactive "Featured Items" widget
* Examples and documentation at: http://jqueryglobe.com/article/feature_list/
* Version: 1.0.0 (01/09/2009)
* Copyright (c) 2009 jQueryGlobe
* Licensed under the MIT License: http://en.wikipedia.org/wiki/MIT_License
* Requires: jQuery v1.3+
*/
;(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options) {
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 5000;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
})(jQuery);
This is the CSS:
body {
background: #EEE;
font-family: "Trebuchet MS",Verdana,Arial,sans-serif;
font-size: 14px;
line-height: 1.6;
}
#content {
width: 750px;
margin: 50px auto;
padding: 20px;
background: #FFF;
border: 1px solid #CCC;
}
h1 {
margin: 0;
}
hr {
border: none;
height: 1px; line-height: 1px;
background: #CCC;
margin-bottom: 20px;
padding: 0;
}
p {
margin: 0;
padding: 7px 0;
}
.clear {
clear: both;
line-height: 1px;
font-size: 1px;
}
a {
outline-color: #888;
}
Can anyone help with this?

Answer: jsFiddle: features box that slides and scrolls
Features:
Slides over time
Click next and previous
Support for lots of slides
Smooth scrolling
Move to item on click
Stop movement on hover
Easily extended because it uses the cycle plug-in.
Time spent on project: 4hrs

Ok, no fancy scrollbars or anything, but it will iterate through each one bringing it to the top index. I spent ages getting this working properly.
You can test it by adding additional items to the Lists.
/*
* FeatureList - simple and easy creation of an interactive "Featured Items" widget
* Examples and documentation at: http://jqueryglobe.com/article/feature_list/
* Version: 1.0.0 (01/09/2009)
* Copyright (c) 2009 jQueryGlobe
* Licensed under the MIT License: http://en.wikipedia.org/wiki/MIT_License
* Requires: jQuery v1.3+
*/
;(function($) {
$.fn.featureList = function(options) {
var tabs = $(this);
var output = $(options.output);
new jQuery.featureList(tabs, output, options);
return this;
};
$.featureList = function(tabs, output, options)
{
function slide(nr) {
if (typeof nr == "undefined") {
nr = visible_item + 1;
nr = nr >= total_items ? 0 : nr;
}
tabs.removeClass('current').filter(":eq(" + nr + ")").addClass('current');
output.stop(true, true).filter(":visible").fadeOut();
output.filter(":eq(" + nr + ")").fadeIn(function() {
visible_item = nr;
});
$(tabs[(nr - 1 + total_items) % total_items]).parent().slideUp(500,function(){
var order = "";
for(var i = total_items; i > 0; i--)
{
var nextInd = ((nr - 1) + i) % total_items;
var tab = $(tabs[nextInd]);
if(i == total_items)
tab.parent().slideDown(500);
tab.parent().prependTo(tab.parent().parent());
order += nextInd + ", ";
}
});
}
var options = options || {};
var total_items = tabs.length;
var visible_item = options.start_item || 0;
options.pause_on_hover = options.pause_on_hover || true;
options.transition_interval = options.transition_interval || 2000;
output.hide().eq( visible_item ).show();
tabs.eq( visible_item ).addClass('current');
tabs.click(function() {
if ($(this).hasClass('current')) {
return false;
}
slide( tabs.index( this) );
});
if (options.transition_interval > 0) {
var timer = setInterval(function () {
slide();
}, options.transition_interval);
if (options.pause_on_hover) {
tabs.mouseenter(function() {
clearInterval( timer );
}).mouseleave(function() {
clearInterval( timer );
timer = setInterval(function () {
slide();
}, options.transition_interval);
});
}
}
};
})(jQuery);

To increase the height of the box simply change the height of div#feature_list and to add additional items simply add an additional li item in both the ul's within feature_list

Related

Change If Statement to display none if text not number

I'm trying to pull through a value from the dataLayer to fire a piece of HTML. All pulling through fine, however if the value is 'undefined' rather than an actual number I don't want it to fire.
How can I solve this? Tried everything but it's returning true/false rather than not firing.
$(document).ready(function () {
for (var i = 0, len = dataLayer.length; i < len; i++) {
if (dataLayer[i].event === "productView")
var viewed = dataLayer[i].P2;
}
function isOnScreen(element) {
var curPos = element.offset();
var curTop = curPos.top - $(window).scrollTop();
var screenHeight = $(window).height();
return (curTop > screenHeight) ? false : true;
}
var intervalId = setInterval(function () {
var addtocart = $('#add-to-cart');
if (isOnScreen(addtocart) === true) {
$('.product-image.main-image').before("<div id='social-overlay' style='color: #fff;text-transform: uppercase;font-family: Muli,Arial,Helvetica,sans-serif; font-size: 11px; font-weight: 800;background: #867dae; opacity: 0.8; padding-top: 10px; padding-bottom: 10px; position: absolute;z-index: 1; width: 100%;'>" + viewed + " people viewed item in the last 24 hours</div>")
setTimeout(function () {
$('#social-overlay').fadeOut(1000);
}, 7000);
clearInterval(intervalId);
}
}, 500);
});
Check if the variable 'viewed' is undefined in the setInterval function you have and add the html value using before function only if the viewed is valid.
var intervalId = setInterval(function() {
var addtocart = $('#add-to-cart');
if ( typeof viewed !== 'undefined' && isOnScreen(addtocart) === true) {
$('.product-image.main-image').before("<div id='social-overlay' style='color: #fff;text-transform: uppercase;font-family: Muli,Arial,Helvetica,sans-serif; font-size: 11px; font-weight: 800;background: #867dae; opacity: 0.8; padding-top: 10px; padding-bottom: 10px; position: absolute;z-index: 1; width: 100%;'>" + viewed + " people viewed item in the last 24 hours</div>") ;
setTimeout(function(){
$('#social-overlay').fadeOut(1000);
}, 7000);
clearInterval(intervalId);
}
}, 500);

How to automatically place "read more" when characters hit X amount

I'm currently using a nice bit of open source code which pulls Google reviews.
Issue is, if a review is very long... it makes my site look weird. I need to set a max amount of characters, but give the user the option to read the full review. I'm not sure if this should be done through jQuery, CSS or what... Looking for some guidance.
See my issue here:
My code is here:
jQuery(document).ready(function( $ ) {
$("#google-reviews").googlePlaces({
placeId: 'place ID' //Find placeID #: https://developers.google.com/places/place-id
, render: ['reviews']
, min_rating: 5
, max_rows:3
});
});
/* https://github.com/peledies/google-places */
(function($) {
$.googlePlaces = function(element, options) {
var defaults = {
placeId: 'place ID' // placeId provided by google api documentation
, render: ['reviews']
, min_rating: 0
, max_rows: 0
, rotateTime: false
};
var plugin = this;
plugin.settings = {}
var $element = $(element),
element = element;
plugin.init = function() {
plugin.settings = $.extend({}, defaults, options);
$element.html("<div id='map-plug'></div>"); // create a plug for google to load data into
initialize_place(function(place){
plugin.place_data = place;
// render specified sections
if(plugin.settings.render.indexOf('reviews') > -1){
renderReviews(plugin.place_data.reviews);
if(!!plugin.settings.rotateTime) {
initRotation();
}
}
});
}
var initialize_place = function(c){
var map = new google.maps.Map(document.getElementById('map-plug'));
var request = {
placeId: plugin.settings.placeId
};
var service = new google.maps.places.PlacesService(map);
service.getDetails(request, function(place, status) {
if (status == google.maps.places.PlacesServiceStatus.OK) {
c(place);
}
});
}
var sort_by_date = function(ray) {
ray.sort(function(a, b){
var keyA = new Date(a.time),
keyB = new Date(b.time);
// Compare the 2 dates
if(keyA < keyB) return -1;
if(keyA > keyB) return 1;
return 0;
});
return ray;
}
var filter_minimum_rating = function(reviews){
for (var i = reviews.length -1; i >= 0; i--) {
if(reviews[i].rating < plugin.settings.min_rating){
reviews.splice(i,1);
}
}
return reviews;
}
var renderReviews = function(reviews){
reviews = sort_by_date(reviews);
reviews = filter_minimum_rating(reviews);
var html = "";
var row_count = (plugin.settings.max_rows > 0)? plugin.settings.max_rows - 1 : reviews.length - 1;
// make sure the row_count is not greater than available records
row_count = (row_count > reviews.length-1)? reviews.length -1 : row_count;
for (var i = row_count; i >= 0; i--) {
var stars = renderStars(reviews[i].rating);
var date = convertTime(reviews[i].time);
html = html+"<div class='review-item'><div class='review-meta'><span class='review-author'>"+reviews[i].author_name+"</span><span class='review-sep'>, </span><span class='review-date'>"+date+"</span></div>"+stars+"<p class='review-text'>"+reviews[i].text+"</p></div>"
};
$element.append(html);
}
var initRotation = function() {
var $reviewEls = $element.children('.review-item');
var currentIdx = $reviewEls.length > 0 ? 0 : false;
$reviewEls.hide();
if(currentIdx !== false) {
$($reviewEls[currentIdx]).show();
setInterval(function(){
if(++currentIdx >= $reviewEls.length) {
currentIdx = 0;
}
$reviewEls.hide();
$($reviewEls[currentIdx]).fadeIn('slow');
}, plugin.settings.rotateTime);
}
}
var renderStars = function(rating){
var stars = "<div class='review-stars'><ul>";
// fill in gold stars
for (var i = 0; i < rating; i++) {
stars = stars+"<li><i class='star'></i></li>";
};
// fill in empty stars
if(rating < 5){
for (var i = 0; i < (5 - rating); i++) {
stars = stars+"<li><i class='star inactive'></i></li>";
};
}
stars = stars+"</ul></div>";
return stars;
}
var convertTime = function(UNIX_timestamp){
var a = new Date(UNIX_timestamp * 1000);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var time = months[a.getMonth()] + ' ' + a.getDate() + ', ' + a.getFullYear();
return time;
}
plugin.init();
}
$.fn.googlePlaces = function(options) {
return this.each(function() {
if (undefined == $(this).data('googlePlaces')) {
var plugin = new $.googlePlaces(this, options);
$(this).data('googlePlaces', plugin);
}
});
}
})(jQuery);
#map-plug {display:none;}
#google-reviews {
display:flex;
flex-wrap:wrap;
//display: grid;
//grid-template-columns: repeat( auto-fit, minmax(320px, 1fr));
}
.review-item {
margin:0 auto;
padding:1em;
flex: 1 1 20%;
}
#media ( max-width:1200px) {
.review-item { flex: 1 1 40%; }
}
#media ( max-width:450px) {
.review-item { flex: 1 1 90%; }
}
.review-meta, .review-stars {text-align:center; font-size:115%;}
.review-author { text-transform: capitalize; font-weight:bold; }
.review-date {opacity:.6; display:block;}
.review-text { line-height:1.55; text-align:left; max-width:32em; margin:auto;}
.review-stars ul {
display: inline-block;
list-style: none;
margin:0; padding:0;
}
.review-stars ul li {
float: left;
margin-right: 1px;
line-height:1;
}
.review-stars ul li i {
color: #E4B248;
font-size: 1.4em;
font-style:normal;
}
.review-stars ul li i.inactive { color: #c6c6c6;}
.star:after { content: "\2605"; }
<div id="google-reviews"></div>
The substr method will return the part of a string between the start index and a number of characters after it and will truncate your text.
Ex:
reviews[i].text.substr(0, 100 /* amount of characters */) + " read more..."

Why isn't it possible to change max-height with % in javascript?

I'm trying to build a responsive menu, with a hamburger icon. I want the menu list to slide in and out, no jquery - pure javascript only.
HTML :
<div id="animation">
</div>
<button id="toggle">Toggle</button>
CSS :
div {
width: 300px;
height: 300px;
background-color: blue;
}
Javascript :
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback){
var inter = -1, start = 100, end = 0;
if(type==true){
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function(){
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if(start == end){
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function(){
animate(hidden, function(){
hidden = (hidden == false) ? true : false;
});
}
div.style.maxHeight = "50%";
The problem is that proportional height in an element needs a fixed height on the parent, and you didn't provided any parent with a fixed height because for the maxHeight property too the % Defines the maximum height in % of the parent element.
You have to put your div in a parent container with a fixed height, this is your working code:
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function(type, callback) {
var inter = -1,
start = 100,
end = 0;
if (type) {
inter = 1;
start = 0;
end = 100;
}
var si = setInterval(function() {
console.log('maxheight');
div.style.maxHeight = (start + inter) + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
}
var hidden = false;
but.onclick = function() {
animate(hidden, function() {
hidden = !hidden ;
});
}
div.style.maxHeight = "50%";
#animation {
width: 300px;
height: 300px;
background-color: blue;
}
#parent {
width: 500px;
height: 500px;
}
<div id="parent">
<div id="animation">
</div>
<button id="toggle">Toggle</button>
</div>
Note:
As stated in comments there are some statements in your JavaScript code that need to be adjusted:
if(type==true) can be written as if(type).
hidden = (hidden == false) ? true : false; can be shortened to hidden = !hidden
There seems to be a few errors with your code. I have fixed the js and added comments to what I have changed
var but = document.getElementById('toggle');
var div = document.getElementById('animation');
var animate = function (type, callback) {
var start = 100,
end = 0;
if (type) {
start = 0;
end = 100;
}
var si = setInterval(function () {
if (type) { // check whether to open or close animation
start++;
} else {
start--
}
div.style.maxHeight = start + '%';
if (start == end) {
clearInterval(si);
}
}, 10);
callback.call(this); // do the callback function
}
var hidden = false;
but.onclick = function () {
animate(hidden, function () {
hidden = !hidden; // set hidden to opposite
});
}
/*make sure parent container has a height set or max height won't work*/
html, body {
height:100%;
margin:0;
padding:0;
}
div {
width: 300px;
height: 300px;
background-color: blue;
}
<div id="animation"></div>
<button id="toggle">Toggle</button>
Example Fiddle

get Slot Machine Effect using jquery

I am trying to create a slot machine using the following jquery plugin: jquery slot machine
I started with the simple Demo und entered my own list. The Problem I am having is that I need more than just that block which shows 1 line of the list. I need to show what is above and beneath the middle line of the lists. So I made the jSlotsWrapper box bigger.
Now I have the problem that when the lists spin, at the end of the list you see empty space. How can I make that the list has no end? So where the last item in the list is, I want to start again with the list.
EDIT
here is my html file
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Datengut Spielautomat</title>
<style type="text/css">
body {
text-align: center;
position: absolute;
height: 600px;
margin: auto;
top: 0; left: 0; bottom: 0; right: 0;
}
ul {
padding: 0;
margin: 0;
list-style: none;
}
li {
height: 62px;
}
.jSlots-wrapper {
overflow: hidden;
text-align: center;
font-family:arial,helvetica,sans-serif;
font-size: 40px;
text-shadow: 2px 2px 2px #888888;
height: 600px;
width: 1242px;
margin: 10px auto;
border: 2px solid;
border-color: #ffa500;
box-shadow: 5px 5px 5px #888888;
box-shadow: inset 0 200px 100px -100px #555555, inset 0 -200px 100px -100px #555555;
}
.jSlots-wrapper::after {
content: "";
background:url("blumen.jpg");
opacity: 0.5;
z-index: -1;
}
.slot {
z-index: -1;
width: 410px;
text-align: center;
margin-left: 5px auto;
margin-right: 5px auto;
float: left;
border-left: 2px solid;
border-right: 2px solid;
border-color: #ffa500;
}
.line {
width: 410px;
height: 2px;
-webkit-transform:
translateY(-20px)
translateX(5px)
}
</style>
</head>
<body>
<ul class="slot">
<li>Bauakte</li>
<li></li>
<li>Bautagebuch</li>
<li></li>
<li>Mängelverwaltung</li>
<li></li>
<li>Störungsverwaltung</li>
<li></li>
<li>Personalakte</li>
<li></li>
<li>Maschinenakte</li>
<li></li>
</ul>
<script src="jquery.1.6.4.min.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery.easing.1.3.js" type="text/javascript" charset="utf-8"></script>
<script src="jquery.jSlots.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" charset="utf-8">
// normal example
$('.slot').jSlots({
number : 3,
spinner : 'body',
spinEvent : 'keypress',
easing: 'easeOutSine',
time : 7000,
loops : 6,
});
</script>
</body>
</html>
and here is my js file:
(function($){
$.jSlots = function(el, options){
var base = this;
base.$el = $(el);
base.el = el;
base.$el.data("jSlots", base);
base.init = function() {
base.options = $.extend({},$.jSlots.defaultOptions, options);
base.setup();
base.bindEvents();
};
// --------------------------------------------------------------------- //
// DEFAULT OPTIONS
// --------------------------------------------------------------------- //
$.jSlots.defaultOptions = {
number : 3, // Number: number of slots
winnerNumber : 1, // Number or Array: list item number(s) upon which to trigger a win, 1-based index, NOT ZERO-BASED
spinner : '', // CSS Selector: element to bind the start event to
spinEvent : 'click', // String: event to start slots on this event
onStart : $.noop, // Function: runs on spin start,
onEnd : $.noop, // Function: run on spin end. It is passed (finalNumbers:Array). finalNumbers gives the index of the li each slot stopped on in order.
onWin : $.noop, // Function: run on winning number. It is passed (winCount:Number, winners:Array)
easing : 'swing', // String: easing type for final spin
time : 7000, // Number: total time of spin animation
loops : 6 // Number: times it will spin during the animation
};
// --------------------------------------------------------------------- //
// HELPERS
// --------------------------------------------------------------------- //
base.randomRange = function(low, high) {
return Math.floor( Math.random() * (1 + high - low) ) + low;
};
// --------------------------------------------------------------------- //
// VARS
// --------------------------------------------------------------------- //
base.isSpinning = false;
base.spinSpeed = 0;
base.winCount = 0;
base.doneCount = 0;
base.$liHeight = 0;
base.$liWidth = 0;
base.winners = [];
base.allSlots = [];
// --------------------------------------------------------------------- //
// FUNCTIONS
// --------------------------------------------------------------------- //
base.setup = function() {
// set sizes
var $list = base.$el;
var $li = $list.find('li').first();
base.$liHeight = $li.outerHeight();
base.$liWidth = $li.outerWidth();
base.liCount = base.$el.children().length;
base.listHeight = base.$liHeight * base.liCount;
base.increment = (base.options.time / base.options.loops) / base.options.loops;
$list.css('position', 'relative');
$li.clone().appendTo($list);
base.$wrapper = $list.wrap('<div class="jSlots-wrapper"></div>').parent();
// remove original, so it can be recreated as a Slot
base.$el.remove();
// clone lists
for (var i = base.options.number - 1; i >= 0; i--){
base.allSlots.push( new base.Slot() );
}
};
base.bindEvents = function() {
$(base.options.spinner).bind(base.options.spinEvent, function(event) {
if (event.which == 32) {
if (!base.isSpinning) {
base.playSlots();
}
}
});
};
// Slot constructor
base.Slot = function() {
this.spinSpeed = 0;
this.el = base.$el.clone().appendTo(base.$wrapper)[0];
this.$el = $(this.el);
this.loopCount = 0;
this.number = 0;
};
base.Slot.prototype = {
// do one rotation
spinEm : function() {
var that = this;
that.$el
.css( 'top', -base.listHeight )
.animate( { 'top' : '0px' }, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
},
lowerSpeed : function() {
this.spinSpeed += base.increment;
this.loopCount++;
if ( this.loopCount < base.options.loops ) {
this.spinEm();
} else {
this.finish();
}
},
// final rotation
finish : function() {
var that = this;
var endNum = base.randomRange( 1, base.liCount );
while (endNum % 2 == 0) {
endNum = base.randomRange( 1, base.liCount );
}
var finalPos = - ( (base.$liHeight * endNum) - base.$liHeight );
var finalSpeed = ( (this.spinSpeed * 0.5) * (base.liCount) ) / endNum;
that.$el
.css( 'top', -base.listHeight )
.animate( {'top': finalPos}, finalSpeed, base.options.easing, function() {
base.checkWinner(endNum, that);
});
}
};
base.checkWinner = function(endNum, slot) {
base.doneCount++;
// set the slot number to whatever it ended on
slot.number = endNum;
// if its in the winners array
if (
( $.isArray( base.options.winnerNumber ) && base.options.winnerNumber.indexOf(endNum) > -1 ) ||
endNum === base.options.winnerNumber
) {
// its a winner!
base.winCount++;
base.winners.push(slot.$el);
}
if (base.doneCount === base.options.number) {
var finalNumbers = [];
$.each(base.allSlots, function(index, val) {
finalNumbers[index] = val.number;
});
if ( $.isFunction( base.options.onEnd ) ) {
base.options.onEnd(finalNumbers);
}
if ( base.winCount && $.isFunction(base.options.onWin) ) {
base.options.onWin(base.winCount, base.winners, finalNumbers);
}
base.isSpinning = false;
}
};
base.playSlots = function() {
base.isSpinning = true;
base.winCount = 0;
base.doneCount = 0;
base.winners = [];
if ( $.isFunction(base.options.onStart) ) {
base.options.onStart();
}
$.each(base.allSlots, function(index, val) {
this.spinSpeed = 250*index;
this.loopCount = 0;
this.spinEm();
});
};
base.onWin = function() {
if ( $.isFunction(base.options.onWin) ) {
base.options.onWin();
}
};
// Run initializer
base.init();
};
// --------------------------------------------------------------------- //
// JQUERY FN
// --------------------------------------------------------------------- //
$.fn.jSlots = function(options){
if (this.length) {
return this.each(function(){
(new $.jSlots(this, options));
});
}
};
})(jQuery);
The core functionality is the same as in the github repository.
The important part, I think, is the function spinEm:
spinEm : function() {
var that = this;
that.$el
.css( 'top', -base.listHeight )
.animate( { 'top' : '0px' }, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
}
here the list is placed above the jSlotsWrapper and with the animate function it moves down. Now what I need is for the animation to continue, and not to place the list at the top again. How can I achieve that.
EDIT
Ok, i tried the following to avoid the empty space, everytime the animation has finished:
spinEm : function() {
var that = this;
that.$el
.css( 'bottom', $("body").height() )
.animate( { 'top' : '0px' }, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
}
I try to place the list at the bottom of the box and move it down until the top appears. But somehow the list doesn't really move. It just moves for 1 word and then stops comletely. What is wrong in the animation code?
EDIT
Ok I found the solution to my problem. Apparently, I can't use bottom in the css function. Instead, I used top and calculated the position of the top border of the list. That way I have an animation without all the empty space at the beginning. To avoid the jumping from the bottom to the top of the list I modified the height of the jSlots-Wrapper and the order of the list items, so that the items that are displayed before and after the jump are the same. That way, the user doesn't see the list jumping.
here is my new animate function.
spinEm : function() {
var that = this;
that.$el
.css( 'top', -(base.listHeight - $("body").height()) )
.animate( { 'top' : '0px'}, that.spinSpeed, 'linear', function() {
that.lowerSpeed();
});
}
I found a way to make the animation so that the user doesn't see the jumping. What I did, is, I configured the list in a way so that the beginning and the end are the same. So that when the end of the list is reached and it jumps to the beginning again, there is no difference. The jump is still there, but not visible for the user.

Multiple instances of jQuery plugin on same page is not working

I have searched on this site but did not get what I need.
My issue is that I have created a jquery plugin for carousels, its working fine on 1 instance, but if I created multiple instance its only working on last.
ex:
$('#one').smartCarousel(); // its not working
$('#two').smartCarousel(); // its working
Here is the plugin code:
;(function($){
// default options
var defaults = {
slide : 1,
autoPlay : false,
autoPlayTime : 3000,
speed : 400,
next : false,
prev : false,
reverse : false,
show : 4
}
// function
function sc(el, o){
this.config = $.extend({}, defaults, o);
this.el = el;
this.init();
return this;
}
// set init configurations
sc.prototype.init = function(){
$this = this;
// get children
$this.children = $this.el.children();
// wrape element, add basic css properties
$this.el.wrap('<div class="smartCarouselWrapper clearfix"></div>')
.css({
position: 'absolute',
}).parent().css({
height: $this.el.outerHeight(true), // Height is setting on line 57
width: '100%',
overflow: 'hidden',
position: 'relative'
});
// Show element by config
// Calculate width by deviding wraper width
// Set width of items
$elw = $this.el.parent().width()/$this.config.show;
$this.children.each(function(index, el) {
$(this).width($elw);
});
w = $elw*$this.config.slide; // init width
// get width, hadle diffrent width
$this.children.each(function(index, el) {
w += $(this).outerWidth(true);
});
// set lement width
$this.el.width(w);
// Set height for wrapper
$this.el.parent().height($this.el.outerHeight(true));
// check if next handle assigned
if ($this.config.next != false ) {
$(this.config.next).click(function(e) {
e.preventDefault()
$this.next();
});
};
// check if prev handle assigned
if ($this.config.prev != false ) {
$(this.config.prev).click(function(e) {
e.preventDefault()
$this.prev();
});
};
$this.ready();
} // end of inti
sc.prototype.autoPlay = function(){
// if reverse enabled
if (this.config.reverse != false) { this.prev(); } else { this.next(); };
}
// do stuffs when ready
sc.prototype.ready = function(){
if(this.config.autoPlay != false){
this.timeOut = setTimeout('$this.autoPlay()', this.config.autoPlayTime);
}
}
sc.prototype.next = function(){
$this = this;
clearTimeout($this.timeOut);
l = 0; // left
i = 0; // index
// Add width to l from each element, limiting through slide
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
l -= $(this).outerWidth(true);
//Clone first item after last for smooth animation
$this.el.append($this.children.eq(i).clone());
$this.children = $this.el.children();
};
i++;
});
// animat to show next items and appent prev items to end
$this.el.stop().animate({
left: l},
$this.config.speed, function() {
i = 0; // index
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
$this.children.last().remove();
$this.children = $this.el.children();
};
i++;
});
i = 0;
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
$(this).appendTo($this.el);
$this.el.css('left', parseInt($this.el.css('left'))+$(this).outerWidth(true));
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of next
sc.prototype.prev = function(){
$this = this;
clearTimeout($this.timeOut);
l = 0; // left
i = 0; // index
//move last item to first through slide
$this.children.each(function(index, el) {
if (i < $this.config.slide) {
//Clone first item after last for smooth animation
$this.el.prepend($this.children.eq(($this.children.length-1)-i).clone());
l -= $this.children.eq(($this.children.length-1)-i).outerWidth(true);
$this.el.css('left', l);
console.log(1);
};
i++;
});
console.log(l);
$this.children = $this.el.children();
// animate back to 0
$this.el.stop().animate({left: 0}, $this.config.speed, function(){
i = 0;
$this.children.each(function(index, el) {
if (i <= $this.config.slide) {
$this.children.eq($this.children.length-i).remove();
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of prev
// plugin
if (typeof $.smartCarousel != 'function') {
$.fn.smartCarousel = function(o){
if (this.length > 0) {
new sc(this.first(), o);
};
return this;
}
}else{
console.log('Function already declared.');
return this;
}
}(jQuery))
Here the html:
<ul class="smart-carousel-list clearfix" id="one">
<li><!-- Image here -->
<h3>Premium Quality DATES</h3>
</li>
<li><!-- Image here -->
<h3>Variety of Export Quality RICE</h3>
</li>
<li><!-- Image here -->
<h3>Sports Goods</h3>
</li>
<li><!-- Image here -->
<h3>Surgical Items</h3>
</li>
<li><!-- Image here -->
<h3>Bad Sheets</h3>
</li>
<li><!-- Image here -->
<h3>Towals</h3>
</li>
<li><!-- Image here -->
<h3>Fruits & Vegetable</h3>
</li>
</ul>
HERE IS THE CSS:
`
.smart-carousel{
width: 100%;
position: relative;
}
.smart-carousel-list{
list-style: none;
margin: 0;
padding: 0;
}
.smart-carousel-list li {
float: left;
-webkit-box-sizing: border-box !important; /* Safari/Chrome, other WebKit */
-moz-box-sizing: border-box !important; /* Firefox, other Gecko */
box-sizing: border-box !important; /* Opera/IE 8+ */
}
.smart-carousel-nav{
position: absolute;
top: 0;
z-index: 1000;
opacity: 0;
transition: opacity 0.4s;
width: 100%;
}
.smart-carousel:hover .smart-carousel-nav{
opacity: 1;
}
.smart-carousel-nav a{
display: block;
width: 29px;
height: 28px;
text-indent: -999999px;
outline: none;
}
.smart-carousel-nav a.sc_next{
background-image: url('next.png');
margin-right: 10px;
float: right;
}
.smart-carousel-nav a.sc_prev{
background-image: url('prev.png');
margin-left: 10px;
float: left;
}
/**
* STYLE FOR TYPE : Images;
*/
.smart-carousel.type-images .smart-carousel-list li img{
max-width: 100%;
display: block;
margin: 0 auto;
}
/**
* STYLE FOR TYPE : Products;
*/
.smart-carousel.type-products .smart-carousel-list li{
border: solid 1px #efefef;
}
.smart-carousel.type-products .smart-carousel-list li img{
max-width: 100%;
display: block;
margin: 0 auto;
}
.smart-carousel.type-products .smart-carousel-list li h3{
width: 100%;
font-size: 18px;
margin: 0;
padding: 0;
}
.smart-carousel.type-products .smart-carousel-list li h3 a{
display: block;
padding: 10px;
font-weight: bold;
}
.smart-carousel.type-products .smart-carousel-list li h3 a span{
float: right;
font-weight: normal;
}
/**
* STYLE FOR TYPE : Posts;
*/
.smart-carousel.type-posts .smart-carousel-list li{
/*border: solid 1px #efefef;*/
}
.smart-carousel.type-posts .smart-carousel-list li img{
max-width: 100%;
display: block;
margin: 0 auto;
}
.smart-carousel.type-posts .smart-carousel-list li h3{
width: 100%;
font-size: 18px;
margin: 0;
padding: 0;
}
.smart-carousel.type-posts .smart-carousel-list li h3 a{
display: block;
padding: 10px;
font-weight: bold;
text-align: center;
}
.smart-carousel.type-posts .smart-carousel-list li h3 a span{
float: right;
font-weight: normal;
}
`
Your plugin is written to only connect to a single jQuery element at a time. You can improve that like this:
// plugin
if (typeof $.smartCarousel != 'function') {
$.fn.smartCarousel = function (o) {
this.each(function(){
// Connect to each jQuery element
new sc($(this), o);
});
return this;
}
} else {
console.log('Function already declared.');
return this;
}
As for the other problems, you have a single global $this shared all over the place. I added all the missing var $this where required for you and correctly reference it in the timer (via an anonymous function wrapper, so that I can reference the local $this):
JSFiddle: http://jsfiddle.net/TrueBlueAussie/b7u4635x/4/
;
(function ($) {
// default options
var defaults = {
slide: 1,
autoPlay: true,
autoPlayTime: 1000,
speed: 400,
next: false,
prev: false,
reverse: false,
show: 4
}
// function
function sc(el, o) {
this.config = $.extend({}, defaults, o);
this.el = el;
this.init();
return this;
}
// set init configurations
sc.prototype.init = function () {
var $this = this;
// get children
$this.children = $this.el.children();
// wrape element, add basic css properties
$this.el.wrap('<div class="smartCarouselWrapper clearfix"></div>')
.css({
position: 'absolute',
}).parent().css({
height: $this.el.outerHeight(true), // Height is setting on line 57
width: '100%',
overflow: 'hidden',
position: 'relative'
});
// Show element by config
// Calculate width by deviding wraper width
// Set width of items
var $elw = $this.el.parent().width() / $this.config.show;
$this.children.each(function (index, el) {
$(this).width($elw);
});
var w = $elw * $this.config.slide; // init width
// get width, hadle diffrent width
$this.children.each(function (index, el) {
w += $(this).outerWidth(true);
});
// set lement width
$this.el.width(w);
// Set height for wrapper
$this.el.parent().height($this.el.outerHeight(true));
// check if next handle assigned
if ($this.config.next != false) {
$(this.config.next).click(function (e) {
e.preventDefault()
$this.next();
});
};
// check if prev handle assigned
if ($this.config.prev != false) {
$(this.config.prev).click(function (e) {
e.preventDefault()
$this.prev();
});
};
$this.ready();
} // end of inti
sc.prototype.autoPlay = function () {
var $this = this;
// if reverse enabled
if ($this.config.reverse != false) {
$this.prev();
} else {
$this.next();
};
}
// do stuffs when ready
sc.prototype.ready = function () {
var $this = this;
if ($this.config.autoPlay != false) {
$this.timeOut = setTimeout(function(){$this.autoPlay();}, $this.config.autoPlayTime);
}
}
sc.prototype.next = function () {
var $this = this;
clearTimeout($this.timeOut);
var l = 0; // left
var i = 0; // index
// Add width to l from each element, limiting through slide
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
l -= $(this).outerWidth(true);
//Clone first item after last for smooth animation
$this.el.append($this.children.eq(i).clone());
$this.children = $this.el.children();
};
i++;
});
// animat to show next items and appent prev items to end
$this.el.stop().animate({
left: l
},
$this.config.speed, function () {
i = 0; // index
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
$this.children.last().remove();
$this.children = $this.el.children();
};
i++;
});
i = 0;
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
$(this).appendTo($this.el);
$this.el.css('left', parseInt($this.el.css('left')) + $(this).outerWidth(true));
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of next
sc.prototype.prev = function () {
var $this = this;
clearTimeout($this.timeOut);
var l = 0; // left
var i = 0; // index
//move last item to first through slide
$this.children.each(function (index, el) {
if (i < $this.config.slide) {
//Clone first item after last for smooth animation
$this.el.prepend($this.children.eq(($this.children.length - 1) - i).clone());
l -= $this.children.eq(($this.children.length - 1) - i).outerWidth(true);
$this.el.css('left', l);
console.log(1);
};
i++;
});
console.log(l);
$this.children = $this.el.children();
// animate back to 0
$this.el.stop().animate({
left: 0
}, $this.config.speed, function () {
i = 0;
$this.children.each(function (index, el) {
if (i <= $this.config.slide) {
$this.children.eq($this.children.length - i).remove();
};
i++;
});
$this.children = $this.el.children();
$this.ready();
});
} // end of prev
// plugin
if (typeof $.smartCarousel != 'function') {
$.fn.smartCarousel = function (o) {
this.each(function () {
new sc($(this), o);
});
return this;
}
} else {
console.log('Function already declared.');
return this;
}
}(jQuery));
//$('.smart-carousel-list').smartCarousel();
$('#one').smartCarousel();
$('#two').smartCarousel();
You have a global variable in your plugin, thus making it impossible for the plugin to work with more than one element because each call to the plugin will overwrite the $this for the previous instance to target the new element.
you simply need to add var in each location where it is missing.
var $this = this;
This will of course break any other place where you attempted to use a global $this (such as the setTimeout('$this.autoplay()',200), so you will need to re-write that portion of the code to not execute autoplay() in that way.

Categories