Thumbnail grid with expanding preview navigation - javascript

I have implemented the grid into a site and it's all working great! I have added a previous and next button using the JavaScript file to append them but can't seem to get them to cycle previous and next.
I notice Google's image search you can use the arrow keys to cycle through them but would like to use these buttons to do it. I know you can target the name attribute and cycle through the images but in this particular grid there is only the data-largesrc which I can't seem to target (I can target the img src of the thumbs. The images are in <li> so maybe that could be targeted? Any ideas would be appreciated. The JavaScript file is a bit big...
/*
* debouncedresize: special jQuery event that happens once after a window resize
*
* latest version and complete README available on Github:
* https://github.com/louisremi/jquery-smartresize/blob/master/jquery.debouncedresize.js
*
* Copyright 2011 #louis_remi
* Licensed under the MIT license.
*/
var $jevent = $j.event,
$jspecial,
resizeTimeout;
$jspecial = $jevent.special.debouncedresize = {
setup: function() {
$j( this ).on( "resize", $jspecial.handler );
},
teardown: function() {
$j( this ).off( "resize", $jspecial.handler );
},
handler: function( event, execAsap ) {
// Save the context
var context = this,
args = arguments,
dispatch = function() {
// set correct event type
event.type = "debouncedresize";
$jevent.dispatch.apply( context, args );
};
if ( resizeTimeout ) {
clearTimeout( resizeTimeout );
}
execAsap ?
dispatch() :
resizeTimeout = setTimeout( dispatch, $jspecial.threshold );
},
threshold: 250
};
// ======================= imagesLoaded Plugin ===============================
// https://github.com/desandro/imagesloaded
// $j('#my-container').imagesLoaded(myFunction)
// execute a callback when all images have loaded.
// needed because .load() doesn't work on cached images
// callback function gets image collection as argument
// this is the container
// original: MIT license. Paul Irish. 2010.
// contributors: Oren Solomianik, David DeSandro, Yiannis Chatzikonstantinou
// blank image data-uri bypasses webkit log warning (thx doug jones)
var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
$j.fn.imagesLoaded = function( callback ) {
var $jthis = this,
deferred = $j.isFunction($j.Deferred) ? $j.Deferred() : 0,
hasNotify = $j.isFunction(deferred.notify),
$jimages = $jthis.find('img').add( $jthis.filter('img') ),
loaded = [],
proper = [],
broken = [];
// Register deferred callbacks
if ($j.isPlainObject(callback)) {
$j.each(callback, function (key, value) {
if (key === 'callback') {
callback = value;
} else if (deferred) {
deferred[key](value);
}
});
}
function doneLoading() {
var $jproper = $j(proper),
$jbroken = $j(broken);
if ( deferred ) {
if ( broken.length ) {
deferred.reject( $jimages, $jproper, $jbroken );
} else {
deferred.resolve( $jimages );
}
}
if ( $j.isFunction( callback ) ) {
callback.call( $jthis, $jimages, $jproper, $jbroken );
}
}
function imgLoaded( img, isBroken ) {
// don't proceed if BLANK image, or image is already loaded
if ( img.src === BLANK || $j.inArray( img, loaded ) !== -1 ) {
return;
}
// store element in loaded images array
loaded.push( img );
// keep track of broken and properly loaded images
if ( isBroken ) {
broken.push( img );
} else {
proper.push( img );
}
// cache image and its state for future calls
$j.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } );
// trigger deferred progress method if present
if ( hasNotify ) {
deferred.notifyWith( $j(img), [ isBroken, $jimages, $j(proper), $j(broken) ] );
}
// call doneLoading and clean listeners if all images are loaded
if ( $jimages.length === loaded.length ){
setTimeout( doneLoading );
$jimages.unbind( '.imagesLoaded' );
}
}
// if no images, trigger immediately
if ( !$jimages.length ) {
doneLoading();
} else {
$jimages.bind( 'load.imagesLoaded error.imagesLoaded', function( event ){
// trigger imgLoaded
imgLoaded( event.target, event.type === 'error' );
}).each( function( i, el ) {
var src = el.src;
// find out if this image has been already checked for status
// if it was, and src has not changed, call imgLoaded on it
var cached = $j.data( el, 'imagesLoaded' );
if ( cached && cached.src === src ) {
imgLoaded( el, cached.isBroken );
return;
}
// if complete is true and browser supports natural sizes, try
// to check for image status manually
if ( el.complete && el.naturalWidth !== undefined ) {
imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 );
return;
}
// cached images don't fire load sometimes, so we reset src, but only when
// dealing with IE, or image is complete (loaded) and failed manual check
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
if ( el.readyState || el.complete ) {
el.src = BLANK;
el.src = src;
}
});
}
return deferred ? deferred.promise( $jthis ) : $jthis;
};
var Grid = (function() {
// list of items
var $jgrid = $j( '#og-grid' ),
// the items
$jitems = $jgrid.children( 'li' ),
// current expanded item's index
current = -1,
// position (top) of the expanded item
// used to know if the preview will expand in a different row
previewPos = -1,
// extra amount of pixels to scroll the window
scrollExtra = 0,
// extra margin when expanded (between preview overlay and the next items)
marginExpanded = 10,
$jwindow = $j( window ), winsize,
$jbody = $j( 'html, body' ),
// transitionend events
transEndEventNames = {
'WebkitTransition' : 'webkitTransitionEnd',
'MozTransition' : 'transitionend',
'OTransition' : 'oTransitionEnd',
'msTransition' : 'MSTransitionEnd',
'transition' : 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ],
// support for csstransitions
support = Modernizr.csstransitions,
// default settings
settings = {
minHeight : 500,
speed : 350,
easing : 'ease'
};
function init( config ) {
// the settings..
settings = $j.extend( true, {}, settings, config );
// preload all images
$jgrid.imagesLoaded( function() {
// save item´s size and offset
saveItemInfo( true );
// get window´s size
getWinSize();
// initialize some events
initEvents();
} );
}
// saves the item´s offset top and height (if saveheight is true)
function saveItemInfo( saveheight ) {
$jitems.each( function() {
var $jitem = $j( this );
$jitem.data( 'offsetTop', $jitem.offset().top );
if( saveheight ) {
$jitem.data( 'height', $jitem.height() );
}
} );
}
function initEvents() {
// when clicking an item, show the preview with the item´s info and large image.
// close the item if already expanded.
// also close if clicking on the item´s cross
$jitems.on( 'click', 'span.og-close', function() {
hidePreview();
return false;
} ).children( 'a' ).on( 'click', function(e) {
var $jitem = $j( this ).parent();
// check if item already opened
current === $jitem.index() ? hidePreview() : showPreview( $jitem );
return false;
} );
// on window resize get the window´s size again
// reset some values..
$jwindow.on( 'debouncedresize', function() {
scrollExtra = 0;
previewPos = -1;
// save item´s offset
saveItemInfo();
getWinSize();
var preview = $j.data( this, 'preview' );
if( typeof preview != 'undefined' ) {
hidePreview();
}
} );
}
function getWinSize() {
winsize = { width : $jwindow.width(), height : $jwindow.height() };
}
function showPreview( $jitem ) {
var preview = $j.data( this, 'preview' ),
// item´s offset top
position = $jitem.data( 'offsetTop' );
scrollExtra = 0;
// if a preview exists and previewPos is different (different row) from item´s top then close it
if( typeof preview != 'undefined' ) {
// not in the same row
if( previewPos !== position ) {
// if position > previewPos then we need to take te current preview´s height in consideration when scrolling the window
if( position > previewPos ) {
scrollExtra = preview.height;
}
hidePreview();
}
// same row
else {
preview.update( $jitem );
return false;
}
}
// update previewPos
previewPos = position;
// initialize new preview for the clicked item
preview = $j.data( this, 'preview', new Preview( $jitem ) );
// expand preview overlay
preview.open();
}
function hidePreview() {
current = -1;
var preview = $j.data( this, 'preview' );
preview.close();
$j.removeData( this, 'preview' );
}
// the preview obj / overlay
function Preview( $jitem ) {
this.$jitem = $jitem;
this.expandedIdx = this.$jitem.index();
this.create();
this.update();
}
Preview.prototype = {
create : function() {
// create Preview structure:
this.$jtitle = $j( '<h3></h3>' );
this.$jdescription = $j( '<p></p>' );
this.$jhref = $j( 'Go To Contact Page...' );
this.$jdetails = $j( '<div class="og-details"></div>' ).append( this.$jtitle, this.$jdescription, this.$jhref );
this.$jloading = $j( '<div class="og-loading"></div>' );
this.$jfullimage = $j( '<div class="og-fullimg"></div>' ).append( this.$jloading );
this.$jclosePreview = $j( '<span class="og-close"></span>' );
this.$jprevious = $j( '<span class="og-previous"></span>' );
this.$jnext = $j( '<span class="og-next"></span>' );
this.$jpreviewInner = $j( '<div class="og-expander-inner"></div>' ).append( this.$jclosePreview, this.$jprevious, this.$jnext, this.$jfullimage, this.$jdetails );
this.$jpreviewEl = $j( '<div class="og-expander"></div>' ).append( this.$jpreviewInner );
// append preview element to the item
this.$jitem.append( this.getEl() );
// set the transitions for the preview and the item
if( support ) {
this.setTransition();
}
},
update : function( $jitem ) {
if( $jitem ) {
this.$jitem = $jitem;
}
// if already expanded remove class "og-expanded" from current item and add it to new item
if( current !== -1 ) {
var $jcurrentItem = $jitems.eq( current );
$jcurrentItem.removeClass( 'og-expanded' );
this.$jitem.addClass( 'og-expanded' );
// position the preview correctly
this.positionPreview();
}
// update current value
current = this.$jitem.index();
// update preview´s content
var $jitemEl = this.$jitem.children( 'a' ),
eldata = {
href : $jitemEl.attr( 'href' ),
largesrc : $jitemEl.data( 'largesrc' ),
title : $jitemEl.data( 'title' ),
description : $jitemEl.data( 'description' )
};
this.$jtitle.html( eldata.title );
this.$jdescription.html( eldata.description );
this.$jhref.attr( 'href', eldata.href );
var self = this;
// remove the current image in the preview
if( typeof self.$jlargeImg != 'undefined' ) {
self.$jlargeImg.remove();
}
// preload large image and add it to the preview
// for smaller screens we don´t display the large image (the media query will hide the fullimage wrapper)
if( self.$jfullimage.is( ':visible' ) ) {
this.$jloading.show();
$j( '<img/>' ).load( function() {
var $jimg = $j( this );
if( $jimg.attr( 'src' ) === self.$jitem.children('a').data( 'largesrc' ) ) {
self.$jloading.hide();
self.$jfullimage.find( 'img' ).remove();
self.$jlargeImg = $jimg.fadeIn( 350 );
self.$jfullimage.append( self.$jlargeImg );
}
} ).attr( 'src', eldata.largesrc );
}
},
open : function() {
setTimeout( $j.proxy( function() {
// set the height for the preview and the item
this.setHeights();
// scroll to position the preview in the right place
this.positionPreview();
}, this ), 25 );
},
close : function() {
var self = this,
onEndFn = function() {
if( support ) {
$j( this ).off( transEndEventName );
}
self.$jitem.removeClass( 'og-expanded' );
self.$jpreviewEl.remove();
};
setTimeout( $j.proxy( function() {
if( typeof this.$jlargeImg !== 'undefined' ) {
this.$jlargeImg.fadeOut( 'fast' );
}
this.$jpreviewEl.css( 'height', 0 );
// the current expanded item (might be different from this.$jitem)
var $jexpandedItem = $jitems.eq( this.expandedIdx );
$jexpandedItem.css( 'height', $jexpandedItem.data( 'height' ) ).on( transEndEventName, onEndFn );
if( !support ) {
onEndFn.call();
}
}, this ), 25 );
return false;
},
calcHeight : function() {
var heightPreview = winsize.height - this.$jitem.data( 'height' ) - marginExpanded,
itemHeight = winsize.height;
if( heightPreview < settings.minHeight ) {
heightPreview = settings.minHeight;
itemHeight = settings.minHeight + this.$jitem.data( 'height' ) + marginExpanded;
}
this.height = heightPreview;
this.itemHeight = itemHeight;
},
setHeights : function() {
var self = this,
onEndFn = function() {
if( support ) {
self.$jitem.off( transEndEventName );
}
self.$jitem.addClass( 'og-expanded' );
};
this.calcHeight();
this.$jpreviewEl.css( 'height', this.height );
this.$jitem.css( 'height', this.itemHeight ).on( transEndEventName, onEndFn );
if( !support ) {
onEndFn.call();
}
},
positionPreview : function() {
// scroll page
// case 1 : preview height + item height fits in window´s height
// case 2 : preview height + item height does not fit in window´s height and preview height is smaller than window´s height
// case 3 : preview height + item height does not fit in window´s height and preview height is bigger than window´s height
var position = this.$jitem.data( 'offsetTop' ),
previewOffsetT = this.$jpreviewEl.offset().top - scrollExtra,
scrollVal = this.height + this.$jitem.data( 'height' ) + marginExpanded <= winsize.height ? position : this.height < winsize.height ? previewOffsetT - ( winsize.height - this.height ) : previewOffsetT;
$jbody.animate( { scrollTop : scrollVal }, settings.speed );
},
setTransition : function() {
this.$jpreviewEl.css( 'transition', 'height ' + settings.speed + 'ms ' + settings.easing );
this.$jitem.css( 'transition', 'height ' + settings.speed + 'ms ' + settings.easing );
},
getEl : function() {
return this.$jpreviewEl;
}
}
return { init : init };
})();
Here is the HTML...
<ul id="og-grid" class="og-grid">
<!-- The Entrance -->
<li>
<a href="http://www.thebarnandpinncottage.co.uk/contact" data-largesrc="/images/cottage-images/entrance/image-entrance.jpg" data-title="The Entrance" data-description="The Barn and Pinn Cottage">
<img src="/images/cottage-images/entrance/image-entrance-thumb.jpg" alt="img01"/>
</a>
</li>
<li>
<a href="http://www.thebarnandpinncottage.co.uk/contact" data-largesrc="/images/cottage-images/entrance/image-entrance-2.jpg" data-title="The Entrance" data-description="The Barn and Pinn Cottage">
<img src="/images/cottage-images/entrance/image-entrance-2-thumb.jpg" alt="img01"/>
</a>
</li>
<li>
<a href="http://www.thebarnandpinncottage.co.uk/contact" data-largesrc="/images/cottage-images/entrance/image-entrance-3.jpg" data-title="The Entrance" data-description="The Barn and Pinn Cottage">
<img src="/images/cottage-images/entrance/image-entrance-3-thumb.jpg" alt="img01"/>
</a>
</li>
<li>
<a href="http://www.thebarnandpinncottage.co.uk/contact" data-largesrc="/images/cottage-images/entrance/image-entrance-4.jpg" data-title="The Entrance" data-description="The Barn and Pinn Cottage">
<img src="/images/cottage-images/entrance/image-entrance-4-thumb.jpg" alt="img01"/>
</a>
</li>
<li>
<a href="http://www.thebarnandpinncottage.co.uk/contact" data-largesrc="/images/cottage-images/entrance/image-entrance-5.jpg" data-title="The Entrance" data-description="The Barn and Pinn Cottage">
<img src="/images/cottage-images/entrance/image-entrance-5-thumb.jpg" alt="img01" name="VCRImage"/>
</a>
</li>
Here is the CSS...
.og-grid {
list-style: none;
padding: 20px 0;
margin: 0 auto;
text-align: center;
width: 100%;
}
.og-grid li {
display: inline-block;
margin: 10px 5px 0 5px;
vertical-align: top;
height: 250px;
}
.og-grid li > a,
.og-grid li > a img {
border: none;
outline: none;
display: block;
position: relative;
}
.og-grid li.og-expanded > a::after {
top: auto;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-bottom-color: #B3BCC6;
border-width: 15px;
left: 50%;
margin: -20px 0 0 -15px;
}
.og-expander {
position: absolute;
background: #B3BCC6;
top: auto;
left: 0;
width: 88.888888%;
margin-top: 10px;
text-align: left;
height: 0;
overflow: hidden;
}
.og-expander-inner {
padding: 80px 30px;
height: 100%;
}
.og-close {
position: absolute;
width: 40px;
height: 40px;
top: 20px;
right: 20px;
cursor: pointer;
}
.og-close::before,
.og-close::after {
content: '';
position: absolute;
width: 100%;
top: 50%;
height: 1px;
background: white;
-webkit-transform: rotate(45deg);
-moz-transform: rotate(45deg);
transform: rotate(45deg);
}
.og-close::after {
-webkit-transform: rotate(-45deg);
-moz-transform: rotate(-45deg);
transform: rotate(-45deg);
}
.og-close:hover::before,
.og-close:hover::after {
background: #333;
}
.og-previous {
position: absolute;
width: 40px;
height: 40px;
top: 20px;
right: 200px;
cursor: pointer;
}
.og-previous::before {
content: '<<';
position: absolute;
width: 100%;
top: 50%;
color: white;
}
.og-next {
position: absolute;
width: 40px;
height: 40px;
top: 20px;
right: 100px;
cursor: pointer;
}
.og-next::before {
content: '>>';
position: absolute;
width: 100%;
top: 50%;
color: white;
}
.og-details {
padding: 0 40px 0 20px;
}
.og-fullimg {
text-align: center;
}
.og-fullimg img {
display: inline-block;
max-height: 100%;
max-width: 100%;
}
.og-details h3 {
font-weight: 300;
font-size: 1.6em;
padding: 0;
margin: 0 0 1em 0;
color: #4B77B1;
}
.og-details p {
font-weight: 400;
font-size: 16px;
line-height: 22px;
color: white;
}
.og-details a {
font-weight: 700;
font-size: 16px;
color: #4B77B1;
text-transform: uppercase;
letter-spacing: 2px;
padding: 10px 20px;
border: 3px solid #4B77B1;
display: inline-block;
margin: 30px 0 0;
outline: none;
}
.og-details a::before {
content: '\2192';
display: inline-block;
margin-right: 10px;
}
.og-details a:hover {
border-color: white;
color: white;
}
.og-loading {
width: 20px;
height: 20px;
border-radius: 50%;
background: #ddd;
box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ccc;
position: absolute;
top: 50%;
left: 50%;
margin: -25px 0 0 -25px;
-webkit-animation: loader 0.5s infinite ease-in-out both;
-moz-animation: loader 0.5s infinite ease-in-out both;
animation: loader 0.5s infinite ease-in-out both;
}
#-webkit-keyframes loader {
0% { background: #ddd; }
33% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ddd; }
66% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ddd, -15px 30px 1px #ccc; }
}
#-moz-keyframes loader {
0% { background: #ddd; }
33% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ddd; }
66% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ddd, -15px 30px 1px #ccc; }
}
#keyframes loader {
0% { background: #ddd; }
33% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ccc, -15px 30px 1px #ddd; }
66% { background: #ccc; box-shadow: 0 0 1px #ccc, 15px 30px 1px #ddd, -15px 30px 1px #ccc; }
}

Related

Removing dotted bottom border from CSS tool tip's title text

I would like to remove the dotted bottom border from the text linked to the tool tip. This code is being used within Qualtrics to modify a survey for a client. Would it be best to edit the text decoration in this case? I need it to be stable across browsers. Admittedly I am not trained in coding - just self taught, so please provide context to your answers so that I can either look up more information regarding your directions or parse it together with what I already know.
jQuery( function()
{
var targets = jQuery( '[rel~=tooltip]' ),
target = false,
tooltip = false,
title = false;
targets.bind( 'mouseenter', function()
{
target = jQuery( this );
tip = target.attr( 'title' );
tooltip = jQuery( '<div id="tooltip"></div>' );
if( !tip || tip == '' )
return false;
target.removeAttr( 'title' );
tooltip.css( 'opacity', 0 )
.html( tip )
.appendTo( 'body' );
var init_tooltip = function()
{
if( jQuery( window ).width() < tooltip.outerWidth() * 1.5 )
tooltip.css( 'max-width', jQuery( window ).width() / 2 );
else
tooltip.css( 'max-width', 340 );
var pos_left = target.offset().left + ( target.outerWidth() / 2 ) - ( tooltip.outerWidth() / 2 ),
pos_top = target.offset().top - tooltip.outerHeight() - 20;
if( pos_left < 0 )
{
pos_left = target.offset().left + target.outerWidth() / 2 - 20;
tooltip.addClass( 'left' );
}
else
tooltip.removeClass( 'left' );
if( pos_left + tooltip.outerWidth() > jQuery( window ).width() )
{
pos_left = target.offset().left - tooltip.outerWidth() + target.outerWidth() / 2 + 20;
tooltip.addClass( 'right' );
}
else
tooltip.removeClass( 'right' );
if( pos_top < 0 )
{
var pos_top = target.offset().top + target.outerHeight();
tooltip.addClass( 'top' );
}
else
tooltip.removeClass( 'top' );
tooltip.css( { left: pos_left, top: pos_top } )
.animate( { top: '+=10', opacity: 1 }, 50 );
};
init_tooltip();
jQuery( window ).resize( init_tooltip );
var remove_tooltip = function()
{
tooltip.animate( { top: '-=10', opacity: 0 }, 50, function()
{
jQuery( this ).remove();
});
target.attr( 'title', tip );
};
target.bind( 'mouseleave', remove_tooltip );
tooltip.bind( 'click', remove_tooltip );
});
});
#tooltip
{
text-align: center;
color: #FFFFFF;
font-family: sans-serif;
background: #008CAE;
position: absolute;
z-index: 100;
padding: 15px;
}
#tooltip:after /* triangle decoration */
{
width: 0;
height: 0;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #111;
content: '';
position: absolute;
left: 50%;
bottom: -10px;
margin-left: -10px;
}
#tooltip.top:after
{
border-top-color: transparent;
border-bottom: 10px solid #111;
top: -20px;
bottom: auto;
}
#tooltip.left:after
{
left: 10px;
margin: 0;
}
#tooltip.right:after
{
right: 10px;
left: auto;
margin: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<abbr rel="tooltip" title="The curricula available for teacher use provides guidance for how to differentiate lessons, activities, and assessments; includes the principles of Universal Design for Learning; and teachers are trained in implementation of the curriculum.">General education teachers have access to a curriculum that promotes differentiated instruction for all students. </abbr>
Text decoration seems like the way to go either by targeting the tag or by adding a class and targeting that:
abbr {
text-decoration: none;
}
Might consider the accessibility considerations too while you're implementing this. It's usually a good idea to give users an indication of some kind when something is interactive. I wonder if removing the underline will remove any indication that there is a tooltip available?

jQuery prev/next button in polaroid gallery plugin

I am using a polaroid image gallery plugin. The way it works, the polaroid images are scattered in a div and it has some circle nav buttons at the bottom that can be clicked to make the selected image active and moves it to the middle.
Instead of having circle nav buttons for selecting each image, I wanted to use prev/next buttons (this way it won't show 20+ circle nav icons when the gallery has more than 20 photos).
I was able to add some prev/next buttons and get them working, but there is one slight issue I cannot figure out. When the gallery loads, if you select the prev/next buttons, the gallery works as intended, it will switch the photos as necessary when the buttons are clicked. However, if the user clicks anywhere in the gallery (not on the buttons) it will shuffle all of the photos (it should not shuffle), then once a user does this, the prev/next buttons no longer work until the page is refreshed.
I am still learning jQuery/js and I cannot figure out what is causing this. I need to restrict the shuffling and selecting of the photos only when the prev/next buttons are selected because if a user accidentally clicks anywhere in the gallery, the buttons break.
I created a jsfiddle here.
The html is pretty straight forward, here is an example with the prev/next buttons I added:
<section id="photostack-1" class="photostack photostack-start">
<div>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/5.jpg" alt="img05"/>
<figcaption>
<h2 class="photostack-title">Speed Racer</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/2.jpg" alt="img02"/>
<figcaption>
<h2 class="photostack-title">Happy Days</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/3.jpg" alt="img03"/>
<figcaption>
<h2 class="photostack-title">Beautywood</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/1.jpg" alt="img01"/>
<figcaption>
<h2 class="photostack-title">Serenity Beach</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/4.jpg" alt="img04"/>
<figcaption>
<h2 class="photostack-title">Heaven of time</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/6.jpg" alt="img06"/>
<figcaption>
<h2 class="photostack-title">Forever this</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/7.jpg" alt="img07"/>
<figcaption>
<h2 class="photostack-title">Lovely Green</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/8.jpg" alt="img08"/>
<figcaption>
<h2 class="photostack-title">Wonderful</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/9.jpg" alt="img09"/>
<figcaption>
<h2 class="photostack-title">Love Addict</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/10.jpg" alt="img10"/>
<figcaption>
<h2 class="photostack-title">Friendship</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/11.jpg" alt="img11"/>
<figcaption>
<h2 class="photostack-title">White Nights</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/12.jpg" alt="img12"/>
<figcaption>
<h2 class="photostack-title">Serendipity</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/13.jpg" alt="img13"/>
<figcaption>
<h2 class="photostack-title">Pure Soul</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/14.jpg" alt="img14"/>
<figcaption>
<h2 class="photostack-title">Winds of Peace</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/15.jpg" alt="img15"/>
<figcaption>
<h2 class="photostack-title">Shades of blue</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/16.jpg" alt="img16"/>
<figcaption>
<h2 class="photostack-title">Lightness</h2>
</figcaption>
</figure>
</div>
<!-- Next and Previous controls -->
<div id="imageControls">
<button id="leftArrowGallery" class="btnGallery"><i class="fa fa-chevron-left"></i></button>
<button id="rightArrowGallery" class="btnGallery"><i class="fa fa-chevron-right"></i></button>
</div>
</section>
The custom jQuery used to add the prev/next buttons and remove the circle nav icons is:
var ps = new Photostack( document.getElementById( 'photostack-1' ), {});
$("#leftArrowGallery").prependTo($(".photostack > nav"));
$("#rightArrowGallery").appendTo($(".photostack > nav"));
$("#leftArrowGallery").on("click", function () {
ps.navigate('prev');
});
$("#rightArrowGallery").on("click", function () {
ps.navigate('next');
});
$(".photostack > nav > span").each(function(){ $(this).remove(); });
You can view all of the js for the plugin in the jsfiddle.
Screenshot example of original gallery with circle nav icons:
Screenshot example of gallery with custom prev/next buttons added:
Again, the buttons are working correctly, I just need to prevent when someone clicks anywhere in the gallery, it shuffles the images then the prev/next buttons break and no longer work until the page is refreshed.
Thank you for your help!
I read your code and I found out that the biggest problem when you put photostack-start class is that every time you click on photostack stage you schuffle your photos twice: once in _photoShow function and once in open function (open function is triggered every time). To resolve your problem, a solution could be to stop one schuffled action. To do this I created a variable and I put it in open function:
if( this.open ) {
return false;
}
this.open = true;
Now, _open function is triggered only once (when you click on button "view gallery") and after that only _photoShow works so your code works finally as you want.
BE CAREFUL: In this example I removed some pics 'cause I have a character limit here (30000), but the code will work anyway also with more pics.
A fiddle with more pics: https://jsfiddle.net/m46cxkhg/217/ (tested with Chrome and Firefox)
;( function( window ) {
'use strict';
Modernizr.addTest('csstransformspreserve3d', function () {
var prop = Modernizr.prefixed('transformStyle');
var val = 'preserve-3d';
var computedStyle;
if(!prop) return false;
prop = prop.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
Modernizr.testStyles('#modernizr{' + prop + ':' + val + ';}', function (el, rule) {
computedStyle = window.getComputedStyle ? getComputedStyle(el, null).getPropertyValue(prop) : '';
});
return (computedStyle === val);
});
var support = {
transitions : Modernizr.csstransitions,
preserve3d : Modernizr.csstransformspreserve3d
},
transEndEventNames = {
'WebkitTransition': 'webkitTransitionEnd',
'MozTransition': 'transitionend',
'OTransition': 'oTransitionEnd',
'msTransition': 'MSTransitionEnd',
'transition': 'transitionend'
},
transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ];
function extend( a, b ) {
for( var key in b ) {
if( b.hasOwnProperty( key ) ) {
a[key] = b[key];
}
}
return a;
}
function shuffleMArray( marray ) {
var arr = [], marrlen = marray.length, inArrLen = marray[0].length;
for(var i = 0; i < marrlen; i++) {
arr = arr.concat( marray[i] );
}
arr = shuffleArr( arr );
var newmarr = [], pos = 0;
for( var j = 0; j < marrlen; j++ ) {
var tmparr = [];
for( var k = 0; k < inArrLen; k++ ) {
tmparr.push( arr[ pos ] );
pos++;
}
newmarr.push( tmparr );
}
return newmarr;
}
function shuffleArr( array ) {
var m = array.length, t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
function Photostack( el, options ) {
this.el = el;
this.inner = this.el.querySelector( 'div' );
this.allItems = [].slice.call( this.inner.children );
this.allItemsCount = this.allItems.length;
if( !this.allItemsCount ) return;
this.items = [].slice.call( this.inner.querySelectorAll( 'figure:not([data-dummy])' ) );
this.itemsCount = this.items.length;
this.options = extend( {}, this.options );
extend( this.options, options );
this.current = this.options.start;
this._init();
var ps = this;
return {
showPhoto: function(idx) {
ps._showPhoto.call(ps, idx);
},
open: function() {
ps._open.call(ps, true);
},
navigate: function(dir) {
ps._navigate.call(ps, dir);
},
}
}
Photostack.prototype.options = {
start: 0,
showNavigation: true,
afterInit: null,
afterShowPhoto: null,
afterNavigate: null
};
Photostack.prototype._init = function() {
this.currentItem = this.items[ this.current ];
if(this.options.showNavigation) {
this._addNavigation();
}
this._getSizes();
this._initEvents();
if(this.options.afterInit) {
this.options.afterInit(this);
}
}
Photostack.prototype._addNavigation = function() {
// add nav dots
this.nav = document.createElement( 'nav' )
var inner = '';
for( var i = 0; i < this.itemsCount; ++i ) {
inner += '<span></span>';
}
this.nav.innerHTML = inner;
this.el.appendChild( this.nav );
this.navDots = [].slice.call( this.nav.children );
}
Photostack.prototype._open = function( beforeStep ) {
/* I added this */
if( this.open ) {
return false;
}
this.open = true;
/* End of change */
var self = this,
el = this.el;
var setTransition = function() {
if( support.transitions ) {
classie.addClass( el, 'photostack-transition' );
}
}
if( beforeStep ) {
el.removeEventListener( 'click', open );
classie.removeClass( el, 'photostack-start' );
setTransition();
}
else {
self.openDefault = true;
setTimeout( setTransition, 25 );
}
self.started = true;
self._showPhoto( self.current );
};
Photostack.prototype._initEvents = function() {
if(this.options.clickToFlip == 'true')
{
this.items.forEach(function(img, idx){
img.addEventListener('click', function(event){
event.preventDefault();
if( idx === self.current ) {
self._rotateItem();
}
})
});
}
var self = this,
beforeStep = classie.hasClass( this.el, 'photostack-start' );
if( beforeStep ) {
this._shuffle();
this.el.addEventListener( 'click', function() {
self._open(beforeStep);
});
}
else {
this._open(beforeStep);
}
if(this.options.showNavigation) {
this.navDots.forEach( function( dot, idx ) {
dot.addEventListener( 'click', function() {
if( idx === self.current ) {
self._rotateItem();
}
else {
// if the photo is flipped then rotate it back before shuffling again
var callback = function() { self._showPhoto( idx ); }
if( self.flipped ) {
self._rotateItem( callback );
}
else {
callback();
}
}
} );
} );
}
window.addEventListener( 'resize', function() { self._resizeHandler(); } );
}
Photostack.prototype._resizeHandler = function() {
var self = this;
function delayed() {
self._resize();
self._resizeTimeout = null;
}
if ( this._resizeTimeout ) {
clearTimeout( this._resizeTimeout );
}
this._resizeTimeout = setTimeout( delayed, 100 );
}
Photostack.prototype._resize = function() {
var self = this, callback = function() { self._shuffle( true ); }
this._getSizes();
if( this.started && this.flipped ) {
this._rotateItem( callback );
}
else {
callback();
}
}
Photostack.prototype._showPhoto = function( pos ) {
if( this.isShuffling ) {
return false;
}
this.isShuffling = true;
// if there is something behind..
if( classie.hasClass( this.currentItem, 'photostack-flip' ) ) {
this._removeItemPerspective();
if(this.options.showNavigation) {
classie.removeClass( this.navDots[ this.current ], 'flippable' );
}
}
if(this.options.showNavigation) {
classie.removeClass( this.navDots[ this.current ], 'current' );
}
classie.removeClass( this.currentItem, 'photostack-current' );
// change current
this.current = pos;
this.currentItem = this.items[ this.current ];
if(this.options.showNavigation) {
classie.addClass( this.navDots[ this.current ], 'current' );
}
// if there is something behind..
if( this.options.showNavigation && this.currentItem.querySelector( '.photostack-back' ) ) {
// nav dot gets class flippable
classie.addClass( this.navDots[ pos ], 'flippable' );
}
// shuffle a bit
this._shuffle();
if(this.options.afterShowPhoto) {
this.options.afterShowPhoto(this);
}
}
// display items (randomly)
Photostack.prototype._shuffle = function( resize ) {
var iter = resize ? 1 : this.currentItem.getAttribute( 'data-shuffle-iteration' ) || 1;
if( iter <= 0 || !this.started || this.openDefault ) { iter = 1; }
// first item is open by default
if( this.openDefault ) {
// change transform-origin
classie.addClass( this.currentItem, 'photostack-flip' );
this.openDefault = false;
this.isShuffling = false;
}
var overlapFactor = .5,
// lines & columns
lines = Math.ceil(this.sizes.inner.width / (this.sizes.item.width * overlapFactor) ),
columns = Math.ceil(this.sizes.inner.height / (this.sizes.item.height * overlapFactor) ),
// since we are rounding up the previous calcs we need to know how much more we are adding to the calcs for both x and y axis
addX = lines * this.sizes.item.width * overlapFactor + this.sizes.item.width/2 - this.sizes.inner.width,
addY = columns * this.sizes.item.height * overlapFactor + this.sizes.item.height/2 - this.sizes.inner.height,
// we will want to center the grid
extraX = addX / 2,
extraY = addY / 2,
// max and min rotation angles
maxrot = 35, minrot = -35,
self = this,
// translate/rotate items
moveItems = function() {
--iter;
// create a "grid" of possible positions
var grid = [];
// populate the positions grid
for( var i = 0; i < columns; ++i ) {
var col = grid[ i ] = [];
for( var j = 0; j < lines; ++j ) {
var xVal = j * (self.sizes.item.width * overlapFactor) - extraX,
yVal = i * (self.sizes.item.height * overlapFactor) - extraY,
olx = 0, oly = 0;
if( self.started && iter === 0 ) {
var ol = self._isOverlapping( { x : xVal, y : yVal } );
if( ol.overlapping ) {
olx = ol.noOverlap.x;
oly = ol.noOverlap.y;
var r = Math.floor( Math.random() * 3 );
switch(r) {
case 0 : olx = 0; break;
case 1 : oly = 0; break;
}
}
}
col[ j ] = { x : xVal + olx, y : yVal + oly };
}
}
// shuffle
grid = shuffleMArray(grid);
var l = 0, c = 0, cntItemsAnim = 0;
self.allItems.forEach( function( item, i ) {
// pick a random item from the grid
if( l === lines - 1 ) {
c = c === columns - 1 ? 0 : c + 1;
l = 1;
}
else {
++l
}
var randXPos = Math.floor( Math.random() * lines ),
randYPos = Math.floor( Math.random() * columns ),
gridVal = grid[c][l-1],
translation = { x : gridVal.x, y : gridVal.y },
onEndTransitionFn = function() {
++cntItemsAnim;
if( support.transitions ) {
this.removeEventListener( transEndEventName, onEndTransitionFn );
}
if( cntItemsAnim === self.allItemsCount ) {
if( iter > 0 ) {
moveItems.call();
}
else {
// change transform-origin
classie.addClass( self.currentItem, 'photostack-flip' );
// all done..
self.isShuffling = false;
if( typeof self.options.callback === 'function' ) {
self.options.callback( self.currentItem );
}
}
}
};
if(self.items.indexOf(item) === self.current && self.started && iter === 0) {
self.currentItem.style.WebkitTransform = 'translate(' + self.centerItem.x + 'px,' + self.centerItem.y + 'px) rotate(0deg)';
self.currentItem.style.msTransform = 'translate(' + self.centerItem.x + 'px,' + self.centerItem.y + 'px) rotate(0deg)';
self.currentItem.style.transform = 'translate(' + self.centerItem.x + 'px,' + self.centerItem.y + 'px) rotate(0deg)';
// if there is something behind..
if( self.currentItem.querySelector( '.photostack-back' ) ) {
self._addItemPerspective();
}
classie.addClass( self.currentItem, 'photostack-current' );
}
else {
item.style.WebkitTransform = 'translate(' + translation.x + 'px,' + translation.y + 'px) rotate(' + Math.floor( Math.random() * (maxrot - minrot + 1) + minrot ) + 'deg)';
item.style.msTransform = 'translate(' + translation.x + 'px,' + translation.y + 'px) rotate(' + Math.floor( Math.random() * (maxrot - minrot + 1) + minrot ) + 'deg)';
item.style.transform = 'translate(' + translation.x + 'px,' + translation.y + 'px) rotate(' + Math.floor( Math.random() * (maxrot - minrot + 1) + minrot ) + 'deg)';
}
if( self.started ) {
if( support.transitions ) {
item.addEventListener( transEndEventName, onEndTransitionFn );
}
else {
onEndTransitionFn();
}
}
} );
};
moveItems.call();
}
Photostack.prototype._navigate = function(dir) {
var current = this.current,
itemsCount = this.itemsCount,
lastItem = itemsCount - 1,
idx = 0;
if(dir == 'next') {
idx = current < lastItem ? current + 1 : 0
} else if(dir == 'prev') {
idx = current > 0 ? current - 1 : lastItem;
}
this._showPhoto(idx);
if(this.options.afterNavigate) {
this.options.afterNavigate(this);
}
}
Photostack.prototype._getSizes = function() {
this.sizes = {
inner : { width : this.inner.offsetWidth, height : this.inner.offsetHeight },
item : { width : this.currentItem.offsetWidth, height : this.currentItem.offsetHeight }
};
// translation values to center an item
this.centerItem = { x : this.sizes.inner.width / 2 - this.sizes.item.width / 2, y : this.sizes.inner.height / 2 - this.sizes.item.height / 2 };
}
Photostack.prototype._isOverlapping = function( itemVal ) {
var dxArea = this.sizes.item.width + this.sizes.item.width / 3, // adding some extra avoids any rotated item to touch the central area
dyArea = this.sizes.item.height + this.sizes.item.height / 3,
areaVal = { x : this.sizes.inner.width / 2 - dxArea / 2, y : this.sizes.inner.height / 2 - dyArea / 2 },
dxItem = this.sizes.item.width,
dyItem = this.sizes.item.height;
if( !(( itemVal.x + dxItem ) < areaVal.x ||
itemVal.x > ( areaVal.x + dxArea ) ||
( itemVal.y + dyItem ) < areaVal.y ||
itemVal.y > ( areaVal.y + dyArea )) ) {
// how much to move so it does not overlap?
// move left / or move right
var left = Math.random() < 0.5,
randExtraX = Math.floor( Math.random() * (dxItem/4 + 1) ),
randExtraY = Math.floor( Math.random() * (dyItem/4 + 1) ),
noOverlapX = left ? (itemVal.x - areaVal.x + dxItem) * -1 - randExtraX : (areaVal.x + dxArea) - (itemVal.x + dxItem) + dxItem + randExtraX,
noOverlapY = left ? (itemVal.y - areaVal.y + dyItem) * -1 - randExtraY : (areaVal.y + dyArea) - (itemVal.y + dyItem) + dyItem + randExtraY;
return {
overlapping : true,
noOverlap : { x : noOverlapX, y : noOverlapY }
}
}
return {
overlapping : false
}
}
Photostack.prototype._addItemPerspective = function() {
classie.addClass( this.el, 'photostack-perspective' );
}
Photostack.prototype._removeItemPerspective = function() {
classie.removeClass( this.el, 'photostack-perspective' );
classie.removeClass( this.currentItem, 'photostack-flip' );
}
Photostack.prototype._rotateItem = function( callback ) {
if( classie.hasClass( this.el, 'photostack-perspective' ) && !this.isRotating && !this.isShuffling ) {
this.isRotating = true;
var self = this, onEndTransitionFn = function() {
if( support.transitions && support.preserve3d ) {
this.removeEventListener( transEndEventName, onEndTransitionFn );
}
self.isRotating = false;
if( typeof callback === 'function' ) {
callback();
}
};
if( this.flipped ) {
if(this.options.showNavigation) {
classie.removeClass( this.navDots[ this.current ], 'flip' );
}
if( support.preserve3d ) {
this.currentItem.style.WebkitTransform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) rotateY(0deg)';
this.currentItem.style.transform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) rotateY(0deg)';
}
else {
classie.removeClass( this.currentItem, 'photostack-showback' );
}
}
else {
if(this.options.showNavigation) {
classie.addClass( this.navDots[ this.current ], 'flip' );
}
if( support.preserve3d ) {
this.currentItem.style.WebkitTransform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) translate(' + this.sizes.item.width + 'px) rotateY(-179.9deg)';
this.currentItem.style.transform = 'translate(' + this.centerItem.x + 'px,' + this.centerItem.y + 'px) translate(' + this.sizes.item.width + 'px) rotateY(-179.9deg)';
}
else {
classie.addClass( this.currentItem, 'photostack-showback' );
}
}
this.flipped = !this.flipped;
if( support.transitions && support.preserve3d ) {
this.currentItem.addEventListener( transEndEventName, onEndTransitionFn );
}
else {
onEndTransitionFn();
}
}
}
// add to global namespace
window.Photostack = Photostack;
})( window );
var ps = new Photostack( document.getElementById( 'photostack-1' ), {});
$("#leftArrowGallery").prependTo($(".photostack > nav"));
$("#rightArrowGallery").appendTo($(".photostack > nav"));
$("#leftArrowGallery").on("click", function () {
ps.navigate('prev');
});
$("#rightArrowGallery").on("click", function () {
ps.navigate('next');
});
$(".photostack > nav > span").each(function(){ $(this).remove(); });
.photostack {
background: #ddd;
position: relative;
text-align: center;
overflow: hidden;
}
.js .photostack {
height: 580px;
}
.photostack-start {
cursor: pointer;
}
.photostack > div {
width: 100%;
height: 100%;
margin: 0 auto;
}
.photostack figure {
width: 320px;
height: 360px;
position: relative;
display: inline-block;
background: #fff;
padding: 40px;
text-align: center;
margin: 5px;
}
.js .photostack figure {
position: absolute;
display: block;
margin: 0;
}
.photostack figcaption h2 {
margin: 20px 0 0 0;
color: #a7a0a2;
font-size: 16px;
}
.photostack-img {
outline: none;
width: 240px;
height: 240px;
background: #f9f9f9;
}
.photostack-back {
display: none;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
background: #fff;
font-family: "Give You Glory", cursive;
color: #a7a0a2;
padding: 50px 40px;
text-align: left;
font-size: 22px;
line-height: 1.25;
z-index: 1;
}
.photostack-back p {
margin: 0;
}
.photostack-back p span {
text-decoration: line-through;
}
.photostack nav {
position: absolute;
width: 100%;
bottom: 30px;
z-index: 90;
text-align: center;
left: 0;
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
}
.photostack-start nav {
opacity: 0;
}
.photostack nav span {
position: relative;
display: inline-block;
margin: 0 5px;
width: 30px;
height: 30px;
cursor: pointer;
background: #aaa;
border-radius: 50%;
text-align: center;
-webkit-transition: -webkit-transform 0.6s ease-in-out, background 0.3s;
transition: transform 0.6s ease-in-out, background 0.3s;
-webkit-transform: scale(0.48);
transform: scale(0.48);
}
.photostack nav span:last-child {
margin-right: 0;
}
.photostack nav span::after {
content: "\e600";
font-family: 'icons';
font-size: 80%;
speak: none;
display: inline-block;
vertical-align: top;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 30px;
color: #fff;
opacity: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.photostack nav span.current {
background: #888;
-webkit-transform: scale(1);
transform: scale(1);
}
.photostack nav span.current.flip {
-webkit-transform: scale(1) rotateY(-180deg) translateZ(-1px);
transform: scale(1) rotateY(-180deg) translateZ(-1px);
background: #555;
}
.photostack nav span.flippable::after {
opacity: 1;
-webkit-transition-delay: 0.4s;
transition-delay: 0.4s;
}
.js .photostack::before {
content: '';
position: absolute;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
top: 0;
left: 0;
z-index: 100;
-webkit-transition: opacity 0.3s, visibility 0s 0.3s;
transition: opacity 0.3s, visibility 0s 0.3s;
}
.js .photostack-start::before {
-webkit-transition: opacity 0.3s;
transition: opacity 0.3s;
}
.js .photostack::after {
content: 'View Gallery';
font-weight: 400;
position: absolute;
border: 3px solid #fff;
text-align: center;
white-space: nowrap;
left: 50%;
top: 50%;
-webkit-transform: translateY(-50%) translateX(-50%);
transform: translateY(-50%) translateX(-50%);
padding: 10px 20px;
color: #fff;
text-transform: uppercase;
letter-spacing: 1px;
cursor: pointer;
z-index: 101;
}
.js .photostack::before,
.js .photostack::after {
opacity: 0;
visibility: hidden;
}
.js .photostack-start::before,
.js .photostack-start:hover::after,
.touch .photostack-start::after {
opacity: 1;
visibility: visible;
}
.photostack figure::after {
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
visibility: visible;
opacity: 1;
background: rgba(0,0,0,0.05);
-webkit-transition: opacity 0.6s;
transition: opacity 0.6s;
}
figure.photostack-current::after {
-webkit-transition: opacity 0.6s, visibility 0s 0.6s;
transition: opacity 0.6s, visibility 0s 0.6s;
opacity: 0;
visibility: hidden;
}
.photostack-transition figure {
-webkit-transition: -webkit-transform 0.6s ease-in-out;
transition: transform 0.6s ease-in-out;
}
.photostack-perspective {
-webkit-perspective: 1800px;
perspective: 1800px;
}
.photostack-perspective > div,
.photostack-perspective figure {
-webkit-transform-style: preserve-3d;
transform-style: preserve-3d;
}
.photostack-perspective figure,
.photostack-perspective figure div {
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.photostack-perspective figure.photostack-flip {
-webkit-transform-origin: 0% 50%;
transform-origin: 0% 50%;
}
.csstransformspreserve3d figure.photostack-flip .photostack-back {
-webkit-transform: rotateY(180deg);
transform: rotateY(180deg);
display: block;
}
.no-csstransformspreserve3d figure.photostack-showback .photostack-back {
display: block;
}
.no-js .photostack figure {
box-shadow: -2px 2px 0 rgba(0,0,0,0.05);
}
.no-js .photostack figure::after {
display: none;
}
.no-js .photostack figure:nth-child(3n) {
-webkit-transform: translateX(-10%) rotate(5deg);
transform: translateX(-10%) rotate(5deg);
}
.no-js .photostack figure:nth-child(3n-2) {
-webkit-transform: translateY(10%) rotate(-3deg);
transform: translateY(10%) rotate(-3deg);
}
#photostack-1 nav span.current {
background: #888;
-webkit-transform: scale(0.61);
transform: scale(0.61);
}
#leftArrowGallery {
margin-right: 10px;
}
#rightArrowGallery {
margin-left: 10px;
}
#rightArrowGallery i {
padding-left: 5px;
}
#leftArrowGallery i {
padding-right: 5px;
}
.btnGallery {
background-color: #da2c33;
border: medium none;
color: #FFFFFF;
cursor: pointer;
display: inline-block;
font: 12px;
padding: 3px 6px;
text-decoration: none;
white-space: nowrap;
border-radius: 5px;
}
.btnGallery:hover {
background-color: #b20a11;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/modernizr/2.7.1/modernizr.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/classie/1.0.1/classie.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" media="all" type="text/css" rel="stylesheet">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="photostack-1" class="photostack photostack-start">
<div>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/5.jpg" alt="img05"/>
<figcaption>
<h2 class="photostack-title">Speed Racer</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/2.jpg" alt="img02"/>
<figcaption>
<h2 class="photostack-title">Happy Days</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/3.jpg" alt="img03"/>
<figcaption>
<h2 class="photostack-title">Beautywood</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/1.jpg" alt="img01"/>
<figcaption>
<h2 class="photostack-title">Serenity Beach</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/4.jpg" alt="img04"/>
<figcaption>
<h2 class="photostack-title">Heaven of time</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/6.jpg" alt="img06"/>
<figcaption>
<h2 class="photostack-title">Forever this</h2>
</figcaption>
</figure>
<figure>
<img src="https://tympanus.net/Development/ScatteredPolaroidsGallery/img/7.jpg" alt="img07"/>
<figcaption>
<h2 class="photostack-title">Lovely Green</h2>
</figcaption>
</figure>
</div>
<div id="imageControls">
<button id="leftArrowGallery" class="btnGallery"><i class="fa fa-chevron-left"></i></button>
<button id="rightArrowGallery" class="btnGallery"><i class="fa fa-chevron-right"></i></button>
</div>
</section>

Trying to add an additional title animation to my jquery slideshow

So I downloaded a slideshow for my home page. It comes with 2 animated text titles (H2 and H3) that slide in from the left of the screen to center. I am now trying to add an additional line of text (H4) that should slide in from the right... with a few seconds delay.
I already edited the webpage and .css file accordingly, but the javascript I am not too sure I know exactly what to do, and I don't wanna mess it up all together.
I will paste here part of the js file where the title animation is being handled (if necessary I also stick the whole file at the bottom of this post).
// titles animation
$nextSlide.find('div.ei-title > h2')
.css( 'margin-right', 50 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 },
this.options.titlespeed, this.options.titleeasing )
.end()
.find('div.ei-title > h3')
.css( 'margin-right', -50 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 },
this.options.titlespeed, this.options.titleeasing )
And here's the css file (already edited to include the added text as 'H4'):
.ei-slider{
position: relative;
width: 100%;
max-width: 1999px;
height: 500px;
margin: 0 auto;
}
.ei-slider-loading{
width: 100%;
height: 100%;
position: absolute;
top: 0px;
left: 0px;
z-index:999;
background: rgba(0,0,0,0.9);
color: #fff;
text-align: center;
line-height: 400px;
}
.ei-slider-large{
height: 100%;
width: 100%;
position:relative;
overflow: hidden;
}
.ei-slider-large li{
position: absolute;
top: 20px;
left: 0px;
overflow: hidden;
height: 100%;
width: 100%;
}
.ei-slider-large li img{
width: 100%;
}
.ei-title h4{
position: absolute;
left: 50%;
margin-right: 13%;
top: 30%;
}
.ei-title h2, h3{
position: absolute;
right: 50%;
margin-right: 13%;
top: 30%;
}
.ei-title h2, .ei-title h3{
text-align: right;
}
.ei-title h4 {
text-align: left;
}
.ei-title h2{
font-size: 40px;
line-height: 50px;
font-family: 'Playfair Display', serif;
font-style: italic;
color: #b5b5b5;
}
.ei-title h3{
font-size: 20px;
line-height: 20px;
font-family: 'Open Sans Condensed', sans-serif;
text-transform: uppercase;
color: #000;
}
.ei-title h4{
font-size: 10px;
line-height: 20px;
font-family: 'sans-serif'; italic;
text-transform: uppercase;
color: #f0ffff;
}
/* the thumbs... */
.ei-slider-thumbs{
height: 1px;
margin: 0 auto;
position: relative;
}
.ei-slider-thumbs li{
position: relative;
float: left;
height: 10%;
}
.ei-slider-thumbs li.ei-slider-element{
top: 0px;
left: 0px;
position: absolute;
height: 10%;
z-index: 10;
text-indent: -9000px;
background: #000;
background: rgba(0,0,0,0.9);
}
.ei-slider-thumbs li a{
display: block;
text-indent: -9000px;
background: #666 ;
width: 100%;
height: 100%;
cursor: pointer;
-webkit-box-shadow:
0px 1px 1px 0px rgba(0,0,0,0.3),
0px 1px 0px 1px rgba(255,255,255,0.5);
-moz-box-shadow:
0px 1px 1px 0px rgba(0,0,0,0.3),
0px 1px 0px 1px rgba(255,255,255,0.5);
box-shadow:
0px 1px 1px 0px rgba(0,0,0,0.3),
0px 1px 0px 1px rgba(255,255,255,0.5);
-webkit-transition: background 0.2s ease;
-moz-transition: background 0.2s ease;
-o-transition: background 0.2s ease;
-ms-transition: background 0.2s ease;
transition: background 0.2s ease;
}
.ei-slider-thumbs li a:hover{
background-color: #f0f0f0;
}
.ei-slider-thumbs li img{
position: absolute;
bottom: 10px;
opacity: 0;
z-index: 999;
max-width: 100%;
-webkit-transition: all 0.4s ease;
-moz-transition: all 0.4s ease;
-o-transition: all 0.4s ease;
-ms-transition: all 0.4s ease;
transition: all 0.4s ease;
-webkit-box-reflect:
below 0px -webkit-gradient(
linear,
left top,
left bottom,
from(transparent),
color-stop(50%, transparent),
to(rgba(255,255,255,0.3))
);
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
}
.ei-slider-thumbs li:hover img{
opacity: -1;
bottom: -1px;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";
}
#media screen and (max-width: 830px) {
.ei-title{
position: absolute;
right: 0px;
margin-right: 0px;
width: 100%;
text-align: center;
top: auto;
bottom: 10px;
background: #fff;
background: rgba(255,255,255,0.9);
padding: 5px 0;
}
.ei-title h2, .ei-title h3, .ei-title h4 {
text-align: center;
}
.ei-title h2{
font-size: 30px;
line-height: 24px;
}
.ei-title h3{
font-size: 20px;
line-height: 20px;
}
.ei-title h4{
font-size: 10px;
line-height: 20px;
}
}
And the html/js code on the webpage:
<div class="wrapper">
<div id="ei-slider" class="ei-slider">
<ul class="ei-slider-large">
<li>
<img src="uploads/2016/01/slider-3.jpg" alt="image01">
<div class="ei-title">
<h2>High end Management Tools</h2>
<h3>Available at your fingertips!</h3>
<h4>With the available technologies, we provide the methods and tools that will help society to excel to new heights</h4>
</div>
</li>
<li>
<img src="uploads/2016/01/about-1.jpg" alt="image02" />
<div class="ei-title">
<h2>Enterprises, Administration Managers</h2>
<h3>Improve your Performance!</h3>
<h4>Regardless of your position, we have the solutions for all levels of professionals, and students alike.... </h4>
</div>
</li>
<li>
<img src="uploads/2016/01/home-parallax.jpg" alt="image03" />
<div class="ei-title">
<h2>Stunning Solutions</h2>
<h3>For Remarkable results!</h3>
<h4>We are bringing today's technology to assist the traditional family with promising results.</h4>
</div>
</li>
</ul><!-- ei-slider-large -->
</div><!-- ei-slider -->
</div><!-- wrapper -->
</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js"></script>
<script type="text/javascript" src="js/jquery.eislideshow.js"></script>
<script type="text/javascript" src="js/jquery.easing.1.3.js"></script>
<script type="text/javascript">
$(function() {
$('#ei-slider').eislideshow({
animation : 'center',
autoplay : true,
slideshow_interval : 6000,
titlesFactor : 0
});
});
</script>
Oh, and finally, the entire javascript file:
(function( window, $, undefined ) {
/*
* smartresize: debounced resize event for jQuery
*
* latest version and complete README available on Github:
* https://github.com/louisremi/jquery.smartresize.js
*
* Copyright 2011 #louis_remi
* Licensed under the MIT license.
*/
var $event = $.event, resizeTimeout;
$event.special.smartresize = {
setup: function() {
$(this).bind( "resize", $event.special.smartresize.handler );
},
teardown: function() {
$(this).unbind( "resize", $event.special.smartresize.handler );
},
handler: function( event, execAsap ) {
// Save the context
var context = this,
args = arguments;
// set correct event type
event.type = "smartresize";
if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
resizeTimeout = setTimeout(function() {
jQuery.event.handle.apply( context, args );
}, execAsap === "execAsap"? 0 : 100 );
}
};
$.fn.smartresize = function( fn ) {
return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
};
$.Slideshow = function( options, element ) {
this.$el = $( element );
/***** images ****/
// list of image items
this.$list = this.$el.find('ul.ei-slider-large');
// image items
this.$imgItems = this.$list.children('li');
// total number of items
this.itemsCount = this.$imgItems.length;
// images
this.$images = this.$imgItems.find('img:first');
/***** thumbs ****/
// thumbs wrapper
this.$sliderthumbs = this.$el.find('ul.ei-slider-thumbs').hide();
// slider elements
this.$sliderElems = this.$sliderthumbs.children('li');
// sliding div
this.$sliderElem = this.$sliderthumbs.children('li.ei-slider-element');
// thumbs
this.$thumbs = this.$sliderElems.not('.ei-slider-element');
// initialize slideshow
this._init( options );
};
$.Slideshow.defaults = {
// animation types:
// "sides" : new slides will slide in from left / right
// "center": new slides will appear in the center
animation : 'sides', // sides || center
// if true the slider will automatically slide, and it will only stop if the user clicks on a thumb
autoplay : false,
// interval for the slideshow
slideshow_interval : 3000,
// speed for the sliding animation
speed : 1000,
// easing for the sliding animation
easing : '',
// percentage of speed for the titles animation. Speed will be speed * titlesFactor
titlesFactor : 0.60,
// titles animation speed
titlespeed : 900,
// titles animation easing
titleeasing : '',
// maximum width for the thumbs in pixels
thumbMaxWidth : 150
};
$.Slideshow.prototype = {
_init : function( options ) {
this.options = $.extend( true, {}, $.Slideshow.defaults, options );
// set the opacity of the title elements and the image items
this.$imgItems.css( 'opacity', 0 );
this.$imgItems.find('div.ei-title > *').css( 'opacity', 0 );
// index of current visible slider
this.current = 0;
var _self = this;
// preload images
// add loading status
this.$loading = $('<div class="ei-slider-loading">Loading</div>').prependTo( _self.$el );
$.when( this._preloadImages() ).done( function() {
// hide loading status
_self.$loading.hide();
// calculate size and position for each image
_self._setImagesSize();
// configure thumbs container
_self._initThumbs();
// show first
_self.$imgItems.eq( _self.current ).css({
'opacity' : 1,
'z-index' : 10
}).show().find('div.ei-title > *').css( 'opacity', 1 );
// if autoplay is true
if( _self.options.autoplay ) {
_self._startSlideshow();
}
// initialize the events
_self._initEvents();
});
},
_preloadImages : function() {
// preloads all the large images
var _self = this,
loaded = 0;
return $.Deferred(
function(dfd) {
_self.$images.each( function( i ) {
$('<img/>').load( function() {
if( ++loaded === _self.itemsCount ) {
dfd.resolve();
}
}).attr( 'src', $(this).attr('src') );
});
}
).promise();
},
_setImagesSize : function() {
// save ei-slider's width
this.elWidth = this.$el.width();
var _self = this;
this.$images.each( function( i ) {
var $img = $(this);
imgDim = _self._getImageDim( $img.attr('src') );
$img.css({
width : imgDim.width,
height : imgDim.height,
marginLeft : imgDim.left,
marginTop : imgDim.top
});
});
},
_getImageDim : function( src ) {
var $img = new Image();
$img.src = src;
var c_w = this.elWidth,
c_h = this.$el.height(),
r_w = c_h / c_w,
i_w = $img.width,
i_h = $img.height,
r_i = i_h / i_w,
new_w, new_h, new_left, new_top;
if( r_w > r_i ) {
new_h = c_h;
new_w = c_h / r_i;
}
else {
new_h = c_w * r_i;
new_w = c_w;
}
return {
width : new_w,
height : new_h,
left : ( c_w - new_w ) / 2,
top : ( c_h - new_h ) / 2
};
},
_initThumbs : function() {
// set the max-width of the slider elements to the one set in the plugin's options
// also, the width of each slider element will be 100% / total number of elements
this.$sliderElems.css({
'max-width' : this.options.thumbMaxWidth + 'px',
'width' : 100 / this.itemsCount + '%'
});
// set the max-width of the slider and show it
this.$sliderthumbs.css( 'max-width', this.options.thumbMaxWidth * this.itemsCount + 'px' ).show();
},
_startSlideshow : function() {
var _self = this;
this.slideshow = setTimeout( function() {
var pos;
( _self.current === _self.itemsCount - 1 ) ? pos = 0 : pos = _self.current + 1;
_self._slideTo( pos );
if( _self.options.autoplay ) {
_self._startSlideshow();
}
}, this.options.slideshow_interval);
},
// shows the clicked thumb's slide
_slideTo : function( pos ) {
// return if clicking the same element or if currently animating
if( pos === this.current || this.isAnimating )
return false;
this.isAnimating = true;
var $currentSlide = this.$imgItems.eq( this.current ),
$nextSlide = this.$imgItems.eq( pos ),
_self = this,
preCSS = {zIndex : 10},
animCSS = {opacity : 1};
// new slide will slide in from left or right side
if( this.options.animation === 'sides' ) {
preCSS.left = ( pos > this.current ) ? -1 * this.elWidth : this.elWidth;
animCSS.left = 0;
}
// titles animation
$nextSlide.find('div.ei-title > h2')
.css( 'margin-right', 50 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 }, this.options.titlespeed, this.options.titleeasing )
.end()
.find('div.ei-title > h3')
.css( 'margin-right', -50 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 }, this.options.titlespeed, this.options.titleeasing )
$.when(
// fade out current titles
$currentSlide.css( 'z-index' , 1 ).find('div.ei-title > *').stop().fadeOut( this.options.speed / 2, function() {
// reset style
$(this).show().css( 'opacity', 0 );
}),
// animate next slide in
$nextSlide.css( preCSS ).stop().animate( animCSS, this.options.speed, this.options.easing ),
// "sliding div" moves to new position
this.$sliderElem.stop().animate({
left : this.$thumbs.eq( pos ).position().left
}, this.options.speed )
).done( function() {
// reset values
$currentSlide.css( 'opacity' , 0 ).find('div.ei-title > *').css( 'opacity', 0 );
_self.current = pos;
_self.isAnimating = false;
});
},
_initEvents : function() {
var _self = this;
// window resize
$(window).on( 'smartresize.eislideshow', function( event ) {
// resize the images
_self._setImagesSize();
// reset position of thumbs sliding div
_self.$sliderElem.css( 'left', _self.$thumbs.eq( _self.current ).position().left );
});
// click the thumbs
this.$thumbs.on( 'click.eislideshow', function( event ) {
if( _self.options.autoplay ) {
clearTimeout( _self.slideshow );
_self.options.autoplay = false;
}
var $thumb = $(this),
idx = $thumb.index() - 1; // exclude sliding div
_self._slideTo( idx );
return false;
});
}
};
var logError = function( message ) {
if ( this.console ) {
console.error( message );
}
};
$.fn.eislideshow = function( options ) {
if ( typeof options === 'string' ) {
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function() {
var instance = $.data( this, 'eislideshow' );
if ( !instance ) {
logError( "cannot call methods on eislideshow prior to initialization; " +
"attempted to call method '" + options + "'" );
return;
}
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
logError( "no such method '" + options + "' for eislideshow instance" );
return;
}
instance[ options ].apply( instance, args );
});
}
else {
this.each(function() {
var instance = $.data( this, 'eislideshow' );
if ( !instance ) {
$.data( this, 'eislideshow', new $.Slideshow( options, this ) );
}
});
}
return this;
};
})( window, jQuery );
My slider in action
The jQuery code of your plugin, the first snipped you attached, is looking for each element (h2 and h3) and animating them one after the other.
Just add the same code for the h4 afterwards, and apply any changes you want to the pixel values.
// titles animation
$nextSlide.find('div.ei-title > h2')
.css( 'margin-right', 50 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 },
this.options.titlespeed, this.options.titleeasing )
.end()
.find('div.ei-title > h3')
.css( 'margin-right', -50 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 },
this.options.titlespeed, this.options.titleeasing )
.end()
.find('div.ei-title > h4')
.css( 'margin-right', -150 + 'px' )
.stop()
.delay( this.options.speed * this.options.titlesFactor )
.animate({ marginRight : 0 + 'px', opacity : 1 },
this.options.titlespeed, this.options.titleeasing )
As you can see, I told it to set margin-right to -150px, to apply the same difference between h3 and h4 as there is between h2 and h3, but you can choose the value that suits your needs best.

Creating active state for thumbnails

I'm using a full-screen image gallery on my website, however I'm trying to style the thumbnails that allow me to navigate true the different images. The tumbnails are generated with the JS file. I managed to style them as triangle's with a normal and hover state.
My question, I want to add an ACTIVE to this that shows a black triangle when that certain images is displayed. How can I do this?
JS file
<script type="text/javascript">
var slider;
var images = [
"images/productie/1.jpg",
"images/productie/2.jpg",
"images/productie/3.jpg",
"images/productie/4.jpg",
"images/productie/5.jpg"
];
var index = 0;
var transitionSpeed = 500;
var imageIntervals = 5000;
var startIntervals;
var intervalSetTime;
var contentOpen = false;
$(document).ready(function(){
slider = $('#slider1').bxSlider({
mode: 'fade',
controls: false,
pause: imageIntervals
});
for (i=0;i<=images.length - 1;i++){
$('#thumb-container').append('<img src="'+ images[i] +'?size=thumb" alt="Image '+ i +'" />');
}
$(function() {
$.preload(images, {
init: function(loaded, total) {
$("#indicator").html("<img src='images/load.gif' />");
},
loaded_all: function(loaded, total) {
$('#indicator').fadeOut('slow', function() {
$('#left-side').fadeIn('slow');
$('#thumb-container').fadeIn('slow');
$.backstretch(images[index], {speed: transitionSpeed});
startIntervals = function (){
intervalSetTime = setInterval(function() {
index = (index >= images.length - 1) ? 0 : index + 1;
$.backstretch(images[index]);
slider.goToNextSlide()
}, imageIntervals)};
startIntervals();
});
}
});
});
});
function goToContent(slideNum){
clearInterval(intervalSetTime);
index = slideNum;
$.backstretch(images[index]);
slider.goToSlide(slideNum);
if (contentOpen == false){
startIntervals();
}
};
function showContent(){
$('.content-bg').fadeIn('slow');
clearInterval(intervalSetTime);
contentOpen = true;
};
function closeContent(){
$('.content-bg').fadeOut('slow');
startIntervals();
contentOpen = false;
};
</script>
CSS
#thumb-container{
display:none;
}
#thumb-container img{
float:left;
border:0;
width: 0;
height: 0;
margin:2px;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 20px solid #fff;
}
#thumb-container img:hover{
float:left;
border:0;
width: 0;
height: 0;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 20px solid #000;
}
With the last clarification comment on the question, I believe you should add and remove the respective CSS class (e.g. displayed) from the thumbnail image, using JavaScript. And modify the last rule selector to be:
#thumb-container img:hover, #thumb-container img.displayed
Question is answered by Shefqet Avdullau
Javascript
var slider;
var images = [
"IMAGES LINK",
"IMAGES LINK",
"IMAGES LINK"
];
var index = 0;
var transitionSpeed = 500;
var imageIntervals = 5000;
var startIntervals;
var intervalSetTime;
var contentOpen = false;
$(document).ready(function(){
slider = $('#slider1').bxSlider({
mode: 'fade',
controls: false,
pause: imageIntervals
});
for (i=0;i<=images.length - 1;i++){
$('#thumb-container').append('<img src="'+ images[i] +'?size=thumb" alt="Image '+ i +'" />');
}
$(function() {
$.preload(images, {
init: function(loaded, total) {
$("#indicator").html("<img src='images/load.gif' />");
},
loaded_all: function(loaded, total) {
$('#indicator').fadeOut('slow', function() {
$('#left-side').fadeIn('slow');
$('#thumb-container').fadeIn('slow');
/* added by Shefqet Avdullau */
$('#thumb-container a').removeClass('current_anchor').eq(index).addClass('current_anchor');
$.backstretch(images[index], {speed: transitionSpeed});
startIntervals = function (){
intervalSetTime = setInterval(function() {
index = (index >= images.length - 1) ? 0 : index + 1;
/* added by me */
$('#thumb-container a').removeClass('current_anchor').eq(index).addClass('current_anchor');
$.backstretch(images[index]);
slider.goToNextSlide()
}, imageIntervals)};
startIntervals();
});
}
});
});
});
function goToContent(slideNum){
clearInterval(intervalSetTime);
index = slideNum;
/* added by Shefqet Avdullau */
$('#thumb-container a').removeClass('current_anchor').eq(index).addClass('current_anchor');
$.backstretch(images[index]);
slider.goToSlide(slideNum);
if (contentOpen == false){
startIntervals();
}
};
function showContent(){
$('.content-bg').fadeIn('slow');
clearInterval(intervalSetTime);
contentOpen = true;
};
function closeContent(){
$('.content-bg').fadeOut('slow');
startIntervals();
contentOpen = false;
};
CSS
/* THUMB SECTION */
#thumb-container{
display:none;
}
#thumb-container img{
float:left;
border:0;
width: 0;
height: 0;
margin:2px;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 20px solid #fff;
}
/* added by Shefqet Avdullau */
#thumb-container a.current_anchor img,
#thumb-container img:hover,
#thumb-container img.displayed {
float:left;
border:0;
width: 0;
height: 0;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-left: 20px solid #6bcade;
}

How to recover an active div

I try to use the jquery flip to display information on an div flip.
JSFIDDLE
I have a first div called "workListId", under a second div called "workId".
Under the div workId, two another div called "workDataId" and "workFlipId".
Under the div workDataId, two another div called "workDescriptionId" and "workURLId"
I have a problem with the div workDescriptionID.
If I flip the div in the order, I see the description in order too.
But if Iflip the third div(for example), I see the description of the first div.
I think the problem is about this line but I don't know to resolve it :
elt.html($('.workData').html());
So see my code below :
$(function(){
// A - CONSTRUCT THE DIV
for ( var i in works ){
// work div
$('<div/>', {
'id' : 'workId' + i,
'class' : 'work'
}).appendTo("#workListId");
// workFlip div
$('<div/>', {
'id' : 'workFlipId' + i,
'class' : 'workFlip'
}).appendTo("#workId" + i);
// workData div
$('<div/>', {
'id' : 'workDataId' + i,
'class' : 'workData'
}).appendTo("#workId" + i);
// workDescription div
$('<div/>', {
'id' : 'workDescriptionId' + i,
'class' : 'workDescription'
}).appendTo("#workDataId" + i);
// workURL div
$('<div/>', {
'id' : 'workURLId' + i,
'class' : 'workURL'
}).appendTo("#workDataId" + i);
// Insert the content in each div
$("#workFlipId" + i).html(path.pathBegin + works[i].image + path.pathEnd);
$("#workDescriptionId" + i).html('<p>' + works[i].description + '</p>');
$("#workURLId" + i).html('Read more...');
}//End for
// B - CONSTRUCT THE DIV FLIP
/* The code is executed once the DOM is loaded */
$('.work').bind("click",function(){
// $(this) point to the clicked .workFlip element (caching it in elem for speed):
var elt = $(this);
// data('flipped') is a flag we set when we flip the element:
if(elt.data('flipped'))
{
// If the element has already been flipped, use the revertFlip method
// defined by the plug-in to revert to the default state automatically:
elt.revertFlip();
// Setting the flag:
elt.data('flipped',true);
}// End if
else
{
// Using the flip method defined by the plugin:
elt.flip({
direction: params.direction,
color: params.color,
speed: params.speed,
onBefore: function(){
// Insert the contents of the .workData div (hidden from view with display:none)
// into the clicked .workFlip div before the flipping animation starts:
elt.html($('.workFlip').siblings('.workData').html());
}
});// End $this.flip
// Setting the flag:
elt.data('flipped',true);
}// End else
});// End function work
});// End function
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
<script src="Scripts/jquery-ui-1.8.16.min.js" type="text/javascript"></script>
<script type="text/javascript">
eval(function (p, a, c, k, e, r) { e = function (c) { return (c < a ? '' : e(parseInt(c / a))) + ((c = c % a) > 35 ? String.fromCharCode(c + 29) : c.toString(36)) }; if (!''.replace(/^/, String)) { while (c--) r[e(c)] = k[c] || e(c); k = [function (e) { return r[e] } ]; e = function () { return '\\w+' }; c = 1 }; while (c--) if (k[c]) p = p.replace(new RegExp('\\b' + e(c) + '\\b', 'g'), k[c]); return p } ('(5($){5 H(a){a.1D.1f[a.1E]=1F(a.1G,10)+a.1H}6 j=5(a){1I({1J:"1g.Z.1K 1L 1M",1N:a})};6 k=5(){7(/*#1O!#*/11&&(1P 1Q.1h.1f.1R==="1S"))};6 l={1T:[0,4,4],1U:[1i,4,4],1V:[1j,1j,1W],1X:[0,0,0],1Y:[0,0,4],1Z:[1k,1l,1l],20:[0,4,4],21:[0,0,A],22:[0,A,A],23:[12,12,12],24:[0,13,0],26:[27,28,1m],29:[A,0,A],2a:[2b,1m,2c],2d:[4,1n,0],2e:[2f,2g,2h],2i:[A,0,0],2j:[2k,2l,2m],2n:[2o,0,R],2p:[4,0,4],2q:[4,2r,0],2s:[0,t,0],2t:[2u,0,2v],2w:[1i,1o,1n],2x:[2y,2z,1o],2A:[1p,4,4],2B:[1q,2C,1q],2D:[R,R,R],2E:[4,2F,2G],2H:[4,4,1p],2I:[0,4,0],2J:[4,0,4],2K:[t,0,0],2L:[0,0,t],2M:[t,t,0],2N:[4,1k,0],2O:[4,S,2P],2Q:[t,0,t],2R:[t,0,t],2S:[4,0,0],2T:[S,S,S],2U:[4,4,4],2V:[4,4,0],9:[4,4,4]};6 m=5(a){T(a&&a.1r("#")==-1&&a.1r("(")==-1){7"2W("+l[a].2X()+")"}2Y{7 a}};$.2Z($.30.31,{u:H,v:H,w:H,x:H});$.1s.32=5(){7 U.1t(5(){6 a=$(U);a.Z(a.B(\'1u\'))})};$.1s.Z=5(i){7 U.1t(5(){6 c=$(U),3,$8,C,14,15,16=k();T(c.B(\'V\')){7 11}6 e={I:(5(a){33(a){W"X":7"Y";W"Y":7"X";W"17":7"18";W"18":7"17";34:7"Y"}})(i.I),y:m(i.D)||"#E",D:m(i.y)||c.z("19-D"),1v:c.J(),F:i.F||1w,K:i.K||5(){},L:i.L||5(){},M:i.M||5(){}};c.B(\'1u\',e).B(\'V\',1).B(\'35\',e);3={s:c.s(),n:c.n(),y:m(i.y)||c.z("19-D"),1x:c.z("36-37")||"38",I:i.I||"X",G:m(i.D)||"#E",F:i.F||1w,o:c.1y().o,p:c.1y().p,1z:i.1v||39,9:"9",1a:i.1a||11,K:i.K||5(){},L:i.L||5(){},M:i.M||5(){}};16&&(3.9="#3a");$8=c.z("1b","3b").8(3c).B(\'V\',1).3d("1h").J("").z({1b:"1A",3e:"3f",p:3.p,o:3.o,3g:0,3h:3i});6 f=5(){7{1B:3.9,1x:0,3j:0,u:0,w:0,x:0,v:0,N:3.9,O:3.9,P:3.9,Q:3.9,19:"3k",3l:\'3m\',n:0,s:0}};6 g=5(){6 a=(3.n/13)*25;6 b=f();b.s=3.s;7{"q":b,"1c":{u:0,w:a,x:a,v:0,N:\'#E\',O:\'#E\',o:(3.o+(3.n/2)),p:(3.p-a)},"r":{v:0,u:0,w:0,x:0,N:3.9,O:3.9,o:3.o,p:3.p}}};6 h=5(){6 a=(3.n/13)*25;6 b=f();b.n=3.n;7{"q":b,"1c":{u:a,w:0,x:0,v:a,P:\'#E\',Q:\'#E\',o:3.o-a,p:3.p+(3.s/2)},"r":{u:0,w:0,x:0,v:0,P:3.9,Q:3.9,o:3.o,p:3.p}}};14={"X":5(){6 d=g();d.q.u=3.n;d.q.N=3.y;d.r.v=3.n;d.r.O=3.G;7 d},"Y":5(){6 d=g();d.q.v=3.n;d.q.O=3.y;d.r.u=3.n;d.r.N=3.G;7 d},"17":5(){6 d=h();d.q.w=3.s;d.q.P=3.y;d.r.x=3.s;d.r.Q=3.G;7 d},"18":5(){6 d=h();d.q.x=3.s;d.q.Q=3.y;d.r.w=3.s;d.r.P=3.G;7 d}};C=14[3.I]();16&&(C.q.3n="3o(D="+3.9+")");15=5(){6 a=3.1z;7 a&&a.1g?a.J():a};$8.1d(5(){3.K($8,c);$8.J(\'\').z(C.q);$8.1e()});$8.1C(C.1c,3.F);$8.1d(5(){3.M($8,c);$8.1e()});$8.1C(C.r,3.F);$8.1d(5(){T(!3.1a){c.z({1B:3.G})}c.z({1b:"1A"});6 a=15();T(a){c.J(a)}$8.3p();3.L($8,c);c.3q(\'V\');$8.1e()})})}})(3r);', 62, 214, '|||flipObj|255|function|var|return|clone|transparent||||||||||||||height|top|left|start|second|width|128|borderTopWidth|borderBottomWidth|borderLeftWidth|borderRightWidth|bgColor|css|139|data|dirOption|color|999|speed|toColor|int_prop|direction|html|onBefore|onEnd|onAnimation|borderTopColor|borderBottomColor|borderLeftColor|borderRightColor|211|192|if|this|flipLock|case|tb|bt|flip||false|169|100|dirOptions|newContent|ie6|lr|rl|background|dontChangeColor|visibility|first|queue|dequeue|style|jquery|body|240|245|165|42|107|140|230|224|144|indexOf|fn|each|flipRevertedSettings|content|500|fontSize|offset|target|visible|backgroundColor|animate|elem|prop|parseInt|now|unit|throw|name|js|plugin|error|message|cc_on|typeof|document|maxHeight|undefined|aqua|azure|beige|220|black|blue|brown|cyan|darkblue|darkcyan|darkgrey|darkgreen||darkkhaki|189|183|darkmagenta|darkolivegreen|85|47|darkorange|darkorchid|153|50|204|darkred|darksalmon|233|150|122|darkviolet|148|fuchsia|gold|215|green|indigo|75|130|khaki|lightblue|173|216|lightcyan|lightgreen|238|lightgrey|lightpink|182|193|lightyellow|lime|magenta|maroon|navy|olive|orange|pink|203|purple|violet|red|silver|white|yellow|rgb|toString|else|extend|fx|step|revertFlip|switch|default|flipSettings|font|size|12px|null|123456|hidden|true|appendTo|position|absolute|margin|zIndex|9999|lineHeight|none|borderStyle|solid|filter|chroma|remove|removeData|jQuery'.split('|'), 0, {}))
$(document).ready(function () {
//******************* SETTING THE FLIP ********************//
// direction : Set the direction of the flipped div
// lr : Left to right
// rl : Right to left
// tb : Top to bottom
// bt : Bottom to top
//
// color : Set the color of your div
// speed : Set the time speed to flip (default : 300)
//*********************************************************//
var params = {
direction: 'lr',
color: 'black',
speed: 220
};
//******************* SETTING THE WORKS ********************//
// title : Set the title of your work
// image : Set the image of your work
// description : Set the description of your work
// website : Set the link of your work or your full size image
//
// How to create many works ?
// Simply copy and paste the lines : " title1 : { ... }, "
// after your last works and complete the setting.
//*********************************************************//
var works = {
title1: {
image: 'facebook.png',
description: 'Description One.',
website: 'http://www.facebook.com'
}, // End title1
title2: {
image: 'google.png',
description: 'Description Two.',
website: 'http://www.google.com'
}, // End title2
title3: {
image: 'adobe.png',
description: 'Description Three.',
website: 'http://www.adobe.com'
}// End title3
}; // End var works
//******************* SETTING THE PATH OF WORKS ************//
// pathBegin : Set the path of your works
// pathEnd : DOES NOT CHANGE
//*********************************************************//
var path = {
pathBegin: '<img src="img/works/',
pathEnd: '"/>'
};
// A - CONSTRUCT THE DIV
$.each(works, function (i, work) {
// work div
$('<div/>', {
'id': 'workId' + i,
'class': 'work'
}).appendTo("#workListId");
// workFlip div
$('<div/>', {
'id': 'workFlipId' + i,
'class': 'workFlip'
}).appendTo("#workId" + i);
// workData div
$('<div/>', {
'id': 'workDataId' + i,
'class': 'workData'
}).appendTo("#workId" + i);
// workDescription div
$('<div/>', {
'id': 'workDescriptionId' + i,
'class': 'workDescription'
}).appendTo("#workDataId" + i);
// workURL div
$('<div/>', {
'id': 'workURLId' + i,
'class': 'workURL'
}).appendTo("#workDataId" + i);
// Insert the content in each div
$("#workFlipId" + i).html(path.pathBegin + work.image + path.pathEnd);
$("#workDescriptionId" + i).html('<p>' + work.description + '</p>');
$("#workURLId" + i).html('Read more...');
}); //End foreach
// B - CONSTRUCT THE DIV FLIP
/* The code is executed once the DOM is loaded */
$('.work').bind("click", function () {
// $(this) point to the clicked .workFlip element (caching it in elem for speed):
var elt = $(this);
// data('flipped') is a flag we set when we flip the element:
if (elt.data('flipped')) {
// If the element has already been flipped, use the revertFlip method
// defined by the plug-in to revert to the default state automatically:
elt.revertFlip();
// Unsetting the flag:
elt.data('flipped', true);
} // End if
else {
// Using the flip method defined by the plugin:
elt.flip({
direction: params.direction,
color: params.color,
speed: params.speed,
onBefore: function () {
// Insert the contents of the .workData div (hidden from view with display:none)
// into the clicked .workFlip div before the flipping animation starts:
//elt.html($('.workFlip').siblings('.workData').html()); //This Code Will Take only first div workDescription only.
elt.html(elt.find('.workFlip').siblings('.workData').html());
}
}); // End elt.flip
// Setting the flag:
elt.data('flipped', true);
} // End else
}); // End function work
});
</script>
<style type="text/css">
*
{
/* Resetting the default styles of the page */
margin: 0;
padding: 0;
}
body
{
/* Setting default text color, background and a font stack */
font-size: 0.825em;
color: white;
background-color: #fff;
font-family: Arial, Helvetica, sans-serif;
}
.workList
{
position: relative;
margin: 30px auto;
width: 950px;
}
.work
{
width: 180px;
height: 180px;
float: left;
margin: 5px; /* Giving the work div a relative positioning: */
position: relative;
cursor: pointer;
}
.workFlip
{
/* The work div will be positioned absolutely with respect
to its parent .work div and fill it in entirely */
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
border: 1px solid #ddd;
background: url("../img/background.jpg") no-repeat center center #f9f9f9;
}
.workFlip:hover
{
border: 1px solid #999; /* CSS3 inset shadow: */
-moz-box-shadow: 0 0 30px #999 inset;
-webkit-box-shadow: 0 0 30px #999 inset;
box-shadow: 0 0 30px #999 inset;
}
.workFlip img
{
/* Centering the logo image in the middle of the workFlip div */
position: absolute;
top: 50%;
left: 50%;
margin: -70px 0 0 -70px;
}
.workData
{
/* Hiding the .workData div */
display: none;
}
.workDescription
{
font-size: 11px;
padding: 30px 10px 20px 20px;
font-style: italic;
}
.workURL
{
font-size: 10px;
font-weight: bold;
padding-left: 20px;
}
/* The styles below are only necessary for the styling of the demo page: */
#main
{
position: relative;
margin: 0 auto;
width: 100%;
}
h1
{
padding: 30px 0;
text-align: center;
text-shadow: 0 1px 1px white;
margin-bottom: 30px;
background: url("../img/page_bg.gif") repeat-x bottom #f8f8f8;
}
h1, h2
{
font-family: "Myriad Pro" ,Arial,Helvetica,sans-serif;
}
h2
{
font-size: 14px;
font-weight: normal;
text-align: center;
position: absolute;
right: 40px;
top: 40px;
}
a, a:visited
{
color: #0196e3;
text-decoration: none;
outline: none;
}
a:hover
{
text-decoration: underline;
}
a img
{
border: none;
}
</style>
</head>
<body>
<header></header>
<nav></nav>
<!-- BEGIN CONTENT -->
<div id="main">
<!-- Content of portfolio -->
<div id="workListId" class="workList">
</div>
</div>
<!-- End div id main -->
<!-- END CONTENT -->
<footer></footer>
</body>
</html>

Categories