Skip to content

Instantly share code, notes, and snippets.

@baldwicc
Last active August 29, 2015 14:26
Show Gist options
  • Save baldwicc/bcbd703d6d7f8c21d1a0 to your computer and use it in GitHub Desktop.
Save baldwicc/bcbd703d6d7f8c21d1a0 to your computer and use it in GitHub Desktop.
Galleriffic is a jQuery photo gallery optimized to handle high volumes of photos while conserving bandwidth (http://www.twospy.com/galleriffic/index.html)
/**
* jQuery Galleriffic plugin
*
* Copyright (c) 2008 Trent Foley (http://trentacular.com)
* Licensed under the MIT License:
* http://www.opensource.org/licenses/mit-license.php
*
* Much thanks to primary contributer Ponticlaro (http://www.ponticlaro.com)
*/
/**
* Updated by Bart Banda
*/
;
(function ($) {
// Globally keep track of all images by their unique hash. Each item is an image data object.
var allImages = {};
var imageCounter = 0;
// Galleriffic static class
$.galleriffic = {
version: '2.0.1',
// Strips invalid characters and any leading # characters
normalizeHash: function (hash) {
return hash.replace(/^.*#/, '').replace(/\?.*$/, '');
},
getImage: function (hash) {
if (!hash)
return undefined;
hash = $.galleriffic.normalizeHash(hash);
return allImages[hash];
},
// Global function that looks up an image by its hash and displays the image.
// Returns false when an image is not found for the specified hash.
// @param {String} hash This is the unique hash value assigned to an image.
gotoImage: function (hash) {
var imageData = $.galleriffic.getImage(hash);
if (!imageData)
return false;
var gallery = imageData.gallery;
gallery.gotoImage(imageData);
return true;
},
// Removes an image from its respective gallery by its hash.
// Returns false when an image is not found for the specified hash or the
// specified owner gallery does match the located images gallery.
// @param {String} hash This is the unique hash value assigned to an image.
// @param {Object} ownerGallery (Optional) When supplied, the located images
// gallery is verified to be the same as the specified owning gallery before
// performing the remove operation.
removeImageByHash: function (hash, ownerGallery) {
var imageData = $.galleriffic.getImage(hash);
if (!imageData)
return false;
var gallery = imageData.gallery;
if (ownerGallery && ownerGallery != gallery)
return false;
return gallery.removeImageByIndex(imageData.index);
}
};
var defaults = {
delay: 3000,
numThumbs: 20,
preloadAhead: 40, // Set to -1 to preload all images
enableTopPager: false,
enableBottomPager: true,
maxPagesToShow: 7,
imageContainerSel: '',
captionContainerSel: '',
controlsContainerSel: '',
loadingContainerSel: '',
renderSSControls: true,
renderNavControls: true,
playLinkText: 'Play',
pauseLinkText: 'Pause',
prevLinkText: 'Previous',
nextLinkText: 'Next',
nextPageLinkText: 'Next ›',
prevPageLinkText: '‹ Prev',
enableHistory: false,
enableKeyboardNavigation: true,
autoStart: false,
syncTransitions: false,
defaultTransitionDuration: 1000,
onSlideChange: undefined, // accepts a delegate like such: function(prevIndex, nextIndex) { ... }
onTransitionOut: undefined, // accepts a delegate like such: function(slide, caption, isSync, callback) { ... }
onTransitionIn: undefined, // accepts a delegate like such: function(slide, caption, isSync) { ... }
onPageTransitionOut: undefined, // accepts a delegate like such: function(callback) { ... }
onPageTransitionIn: undefined, // accepts a delegate like such: function() { ... }
onImageAdded: undefined, // accepts a delegate like such: function(imageData, $li) { ... }
onImageRemoved: undefined // accepts a delegate like such: function(imageData, $li) { ... }
};
// Primary Galleriffic initialization function that should be called on the thumbnail container.
$.fn.galleriffic = function (settings) {
// Extend Gallery Object
$.extend(this, {
// Returns the version of the script
version: $.galleriffic.version,
// Current state of the slideshow
isSlideshowRunning: false,
slideshowTimeout: undefined,
// This function is attached to the click event of generated hyperlinks within the gallery
clickHandler: function (e, link) {
this.pause();
if (!this.enableHistory) {
// The href attribute holds the unique hash for an image
var hash = $.galleriffic.normalizeHash($(link).attr('href'));
$.galleriffic.gotoImage(hash);
e.preventDefault();
}
},
// Appends an image to the end of the set of images. Argument listItem can be either a jQuery DOM element or arbitrary html.
// @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery.
appendImage: function (listItem) {
this.addImage(listItem, false, false);
return this;
},
// Inserts an image into the set of images. Argument listItem can be either a jQuery DOM element or arbitrary html.
// @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery.
// @param {Integer} position The index within the gallery where the item shouold be added.
insertImage: function (listItem, position) {
this.addImage(listItem, false, true, position);
return this;
},
// Adds an image to the gallery and optionally inserts/appends it to the DOM (thumbExists)
// @param listItem Either a jQuery object or a string of html of the list item that is to be added to the gallery.
// @param {Boolean} thumbExists Specifies whether the thumbnail already exists in the DOM or if it needs to be added.
// @param {Boolean} insert Specifies whether the the image is appended to the end or inserted into the gallery.
// @param {Integer} position The index within the gallery where the item shouold be added.
addImage: function (listItem, thumbExists, insert, position) {
var $li = (typeof listItem === "string") ? $(listItem) : listItem;
var $aThumb = $li.find('a.thumb');
var slideUrl = $aThumb.attr('href');
var title = $aThumb.attr('title');
var $caption = $li.find('.caption').remove();
var hash = $aThumb.attr('name');
var rel = $aThumb.attr('rel');
//var videoId = $li.find('.video-id').text();
var yt = $li.find('.fancy-youtube').attr('href');
if (yt) {
var videoId = yt.substring(yt.indexOf('yt=') + 3);
}
var fancyJW = '#' + $li.find('.fancy-jw').attr('id');
var fancyYoutube = '#' + $li.find('.fancy-youtube').attr('id');
var infoHtml = $li.find('.info').html();
// Increment the image counter
imageCounter++;
// Autogenerate a hash value if none is present or if it is a duplicate
if (!hash || allImages['' + hash]) {
hash = imageCounter;
}
// Set position to end when not specified
if (!insert)
position = this.data.length;
var imageData = {
title: title,
slideUrl: slideUrl,
caption: $caption,
hash: hash,
gallery: this,
index: position,
rel: rel,
jw: fancyJW,
youtube: fancyYoutube,
videoid: videoId,
info: infoHtml
};
// Add the imageData to this gallery's array of images
if (insert) {
this.data.splice(position, 0, imageData);
// Reset index value on all imageData objects
this.updateIndices(position);
}
else {
this.data.push(imageData);
}
var gallery = this;
// Add the element to the DOM
if (!thumbExists) {
// Update thumbs passing in addition post transition out handler
this.updateThumbs(function () {
var $thumbsUl = gallery.find('ul.thumbs');
if (insert)
$thumbsUl.children(':eq(' + position + ')').before($li);
else
$thumbsUl.append($li);
if (gallery.onImageAdded)
gallery.onImageAdded(imageData, $li);
});
}
// Register the image globally
allImages['' + hash] = imageData;
// Setup attributes and click handler
$aThumb.attr('rel', 'history')
.attr('href', '#' + hash)
.removeAttr('name')
.click(function (e) {
gallery.clickHandler(e, this);
});
return this;
},
// Removes an image from the gallery based on its index.
// Returns false when the index is out of range.
removeImageByIndex: function (index) {
if (index < 0 || index >= this.data.length)
return false;
var imageData = this.data[index];
if (!imageData)
return false;
this.removeImage(imageData);
return true;
},
// Convenience method that simply calls the global removeImageByHash method.
removeImageByHash: function (hash) {
return $.galleriffic.removeImageByHash(hash, this);
},
// Removes an image from the gallery.
removeImage: function (imageData) {
var index = imageData.index;
// Remove the image from the gallery data array
this.data.splice(index, 1);
// Remove the global registration
delete allImages['' + imageData.hash];
// Remove the image's list item from the DOM
this.updateThumbs(function () {
var $li = gallery.find('ul.thumbs')
.children(':eq(' + index + ')')
.remove();
if (gallery.onImageRemoved)
gallery.onImageRemoved(imageData, $li);
});
// Update each image objects index value
this.updateIndices(index);
return this;
},
// Updates the index values of the each of the images in the gallery after the specified index
updateIndices: function (startIndex) {
for (i = startIndex; i < this.data.length; i++) {
this.data[i].index = i;
}
return this;
},
// Scraped the thumbnail container for thumbs and adds each to the gallery
initializeThumbs: function () {
this.data = [];
var gallery = this;
this.find('ul.thumbs > li').each(function (i) {
gallery.addImage($(this), true, false);
});
return this;
},
isPreloadComplete: false,
// Initalizes the image preloader
preloadInit: function () {
if (this.preloadAhead === 0) return this;
this.preloadStartIndex = this.currentImage.index;
var nextIndex = this.getNextIndex(this.preloadStartIndex);
return this.preloadRecursive(this.preloadStartIndex, nextIndex);
},
// Changes the location in the gallery the preloader should work
// @param {Integer} index The index of the image where the preloader should restart at.
preloadRelocate: function (index) {
// By changing this startIndex, the current preload script will restart
this.preloadStartIndex = index;
return this;
},
// Recursive function that performs the image preloading
// @param {Integer} startIndex The index of the first image the current preloader started on.
// @param {Integer} currentIndex The index of the current image to preload.
preloadRecursive: function (startIndex, currentIndex) {
// Check if startIndex has been relocated
if (startIndex != this.preloadStartIndex) {
var nextIndex = this.getNextIndex(this.preloadStartIndex);
return this.preloadRecursive(this.preloadStartIndex, nextIndex);
}
var gallery = this;
// Now check for preloadAhead count
var preloadCount = currentIndex - startIndex;
if (preloadCount < 0)
preloadCount = this.data.length - 1 - startIndex + currentIndex;
if (this.preloadAhead >= 0 && preloadCount > this.preloadAhead) {
// Do this in order to keep checking for relocated start index
setTimeout(function () {
gallery.preloadRecursive(startIndex, currentIndex);
}, 500);
return this;
}
var imageData = this.data[currentIndex];
if (!imageData)
return this;
// If already loaded, continue
if (imageData.image)
return this.preloadNext(startIndex, currentIndex);
// Preload the image
var image = new Image();
image.onload = function () {
imageData.image = this;
gallery.preloadNext(startIndex, currentIndex);
};
image.alt = imageData.title;
image.src = imageData.slideUrl;
return this;
},
// Called by preloadRecursive in order to preload the next image after the previous has loaded.
// @param {Integer} startIndex The index of the first image the current preloader started on.
// @param {Integer} currentIndex The index of the current image to preload.
preloadNext: function (startIndex, currentIndex) {
var nextIndex = this.getNextIndex(currentIndex);
if (nextIndex == startIndex) {
this.isPreloadComplete = true;
}
else {
// Use setTimeout to free up thread
var gallery = this;
setTimeout(function () {
gallery.preloadRecursive(startIndex, nextIndex);
}, 100);
}
return this;
},
// Safe way to get the next image index relative to the current image.
// If the current image is the last, returns 0
getNextIndex: function (index) {
var nextIndex = index + 1;
if (nextIndex >= this.data.length)
nextIndex = 0;
return nextIndex;
},
// Safe way to get the previous image index relative to the current image.
// If the current image is the first, return the index of the last image in the gallery.
getPrevIndex: function (index) {
var prevIndex = index - 1;
if (prevIndex < 0)
prevIndex = this.data.length - 1;
return prevIndex;
},
// Pauses the slideshow
pause: function () {
this.isSlideshowRunning = false;
if (this.slideshowTimeout) {
clearTimeout(this.slideshowTimeout);
this.slideshowTimeout = undefined;
}
if (this.$controlsContainer) {
this.$controlsContainer
.find('div.ss-controls a').removeClass().addClass('play')
.attr('title', this.playLinkText)
.attr('href', '#play')
.html(this.playLinkText);
}
return this;
},
// Plays the slideshow
play: function () {
this.isSlideshowRunning = true;
if (this.$controlsContainer) {
this.$controlsContainer
.find('div.ss-controls a').removeClass().addClass('pause')
.attr('title', this.pauseLinkText)
.attr('href', '#pause')
.html(this.pauseLinkText);
}
if (!this.slideshowTimeout) {
var gallery = this;
this.slideshowTimeout = setTimeout(function () {
gallery.ssAdvance();
}, this.delay);
}
return this;
},
// Toggles the state of the slideshow (playing/paused)
toggleSlideshow: function () {
if (this.isSlideshowRunning)
this.pause();
else
this.play();
return this;
},
// Advances the slideshow to the next image and delegates navigation to the
// history plugin when history is enabled
// enableHistory is true
ssAdvance: function () {
if (this.isSlideshowRunning)
this.next(true);
return this;
},
// Advances the gallery to the next image.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
next: function (dontPause, bypassHistory) {
this.gotoIndex(this.getNextIndex(this.currentImage.index), dontPause, bypassHistory);
return this;
},
// Navigates to the previous image in the gallery.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
previous: function (dontPause, bypassHistory) {
this.gotoIndex(this.getPrevIndex(this.currentImage.index), dontPause, bypassHistory);
return this;
},
// Navigates to the next page in the gallery.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
nextPage: function (dontPause, bypassHistory) {
var page = this.getCurrentPage();
var lastPage = this.getNumPages() - 1;
if (page < lastPage) {
var startIndex = page * this.numThumbs;
var nextPage = startIndex + this.numThumbs;
this.gotoIndex(nextPage, dontPause, bypassHistory);
}
return this;
},
// Navigates to the previous page in the gallery.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
previousPage: function (dontPause, bypassHistory) {
var page = this.getCurrentPage();
if (page > 0) {
var startIndex = page * this.numThumbs;
var prevPage = startIndex - this.numThumbs;
this.gotoIndex(prevPage, dontPause, bypassHistory);
}
return this;
},
// Navigates to the image at the specified index in the gallery
// @param {Integer} index The index of the image in the gallery to display.
// @param {Boolean} dontPause Specifies whether to pause the slideshow.
// @param {Boolean} bypassHistory Specifies whether to delegate navigation to the history plugin when history is enabled.
gotoIndex: function (index, dontPause, bypassHistory) {
if (!dontPause)
this.pause();
if (index < 0) index = 0;
else if (index >= this.data.length) index = this.data.length - 1;
var imageData = this.data[index];
if (!bypassHistory && this.enableHistory)
$.historyLoad(String(imageData.hash)); // At the moment, historyLoad only accepts string arguments
else
this.gotoImage(imageData);
return this;
},
// This function is garaunteed to be called anytime a gallery slide changes.
// @param {Object} imageData An object holding the image metadata of the image to navigate to.
gotoImage: function (imageData) {
var index = imageData.index;
if (this.onSlideChange)
this.onSlideChange(this.currentImage.index, index);
this.currentImage = imageData;
this.preloadRelocate(index);
this.refresh();
return this;
},
// Returns the default transition duration value. The value is halved when not
// performing a synchronized transition.
// @param {Boolean} isSync Specifies whether the transitions are synchronized.
getDefaultTransitionDuration: function (isSync) {
if (isSync)
return this.defaultTransitionDuration;
return this.defaultTransitionDuration / 2;
},
// Rebuilds the slideshow image and controls and performs transitions
refresh: function () {
var imageData = this.currentImage;
if (!imageData)
return this;
var index = imageData.index;
// Update Controls
if (this.$controlsContainer) {
this.$controlsContainer
.find('div.nav-controls a.prev').attr('href', '#' + this.data[this.getPrevIndex(index)].hash).end()
.find('div.nav-controls a.next').attr('href', '#' + this.data[this.getNextIndex(index)].hash);
}
var previousSlide = this.$imageContainer.find('span.current').addClass('previous').removeClass('current');
var previousCaption = 0;
if (this.$captionContainer) {
previousCaption = this.$captionContainer.find('span.current').addClass('previous').removeClass('current');
}
// Perform transitions simultaneously if syncTransitions is true and the next image is already preloaded
var isSync = this.syncTransitions && imageData.image;
// Flag we are transitioning
var isTransitioning = true;
var gallery = this;
var transitionOutCallback = function () {
// Flag that the transition has completed
isTransitioning = false;
// Remove the old slide
previousSlide.remove();
// Remove old caption
if (previousCaption)
previousCaption.remove();
if (!isSync) {
if (imageData.image && imageData.hash == gallery.data[gallery.currentImage.index].hash) {
gallery.buildImage(imageData, isSync);
}
else {
// Show loading container
if (gallery.$loadingContainer) {
gallery.$loadingContainer.show();
}
}
}
};
if (previousSlide.length === 0) {
// For the first slide, the previous slide will be empty, so we will call the callback immediately
transitionOutCallback();
}
else {
if (this.onTransitionOut) {
this.onTransitionOut(previousSlide, previousCaption, isSync, transitionOutCallback);
}
else {
previousSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0, transitionOutCallback);
if (previousCaption)
previousCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 0.0);
}
}
// Go ahead and begin transitioning in of next image
if (isSync)
this.buildImage(imageData, isSync);
if (!imageData.image) {
var image = new Image();
// Wire up mainImage onload event
image.onload = function () {
imageData.image = this;
// Only build image if the out transition has completed and we are still on the same image hash
if (!isTransitioning && imageData.hash == gallery.data[gallery.currentImage.index].hash) {
gallery.buildImage(imageData, isSync);
}
};
// set alt and src
image.alt = imageData.title;
image.src = imageData.slideUrl;
}
// This causes the preloader (if still running) to relocate out from the currentIndex
this.relocatePreload = true;
return this.syncThumbs();
},
// Called by the refresh method after the previous image has been transitioned out or at the same time
// as the out transition when performing a synchronous transition.
// @param {Object} imageData An object holding the image metadata of the image to build.
// @param {Boolean} isSync Specifies whether the transitions are synchronized.
buildImage: function (imageData, isSync) {
var gallery = this;
var nextIndex = this.getNextIndex(imageData.index);
// Construct new hidden span for the image
var newSlide = this.$imageContainer
.append('<span class="image-wrapper current ' + imageData.rel + '"><a class="advance-link" rel="' + imageData.rel + '" href="#' + this.data[nextIndex].hash + '" title="' + imageData.title + '">&nbsp;</a><strong title="Click to play video" class="play-video"></strong></span>')
.find('span.current').css('opacity', '0');
newSlide.find('a')
.append(imageData.image)
.click(function (e) {
if ($('.player.thumbs-1').length != 1) {
gallery.clickHandler(e, this);
}
});
$('#info-holder').html(imageData.info);
//if(isNaN(imageData.videoid)){
// $('#info-holder .video-Yes').addClass('video-No');
//}
newSlide.find('strong')
.click(function (e) {
if (isNaN(imageData.videoid)) {
//This means that it is a youtube video
$(imageData.youtube).trigger('click');
}
else {
//This means that it is a matrix video
$(imageData.jw).trigger('click');
}
return false;
});
var newCaption = 0;
if (this.$captionContainer) {
// Construct new hidden caption for the image
newCaption = this.$captionContainer
.append('<span class="image-caption current"></span>')
.find('span.current').css('opacity', '0')
.append(imageData.caption);
}
// Hide the loading conatiner
if (this.$loadingContainer) {
this.$loadingContainer.hide();
}
// Transition in the new image
if (this.onTransitionIn) {
this.onTransitionIn(newSlide, newCaption, isSync);
}
else {
newSlide.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0);
if (newCaption)
newCaption.fadeTo(this.getDefaultTransitionDuration(isSync), 1.0);
}
if (this.isSlideshowRunning) {
if (this.slideshowTimeout)
clearTimeout(this.slideshowTimeout);
this.slideshowTimeout = setTimeout(function () {
gallery.ssAdvance();
}, this.delay);
}
return this;
},
// Returns the current page index that should be shown for the currentImage
getCurrentPage: function () {
return Math.floor(this.currentImage.index / this.numThumbs);
},
// Applies the selected class to the current image's corresponding thumbnail.
// Also checks if the current page has changed and updates the displayed page of thumbnails if necessary.
syncThumbs: function () {
var page = this.getCurrentPage();
if (page != this.displayedPage)
this.updateThumbs();
// Remove existing selected class and add selected class to new thumb
var $thumbs = this.find('ul.thumbs').children();
$thumbs.filter('.selected').removeClass('selected');
$thumbs.eq(this.currentImage.index).addClass('selected');
return this;
},
// Performs transitions on the thumbnails container and updates the set of
// thumbnails that are to be displayed and the navigation controls.
// @param {Delegate} postTransitionOutHandler An optional delegate that is called after
// the thumbnails container has transitioned out and before the thumbnails are rebuilt.
updateThumbs: function (postTransitionOutHandler) {
var gallery = this;
var transitionOutCallback = function () {
// Call the Post-transition Out Handler
if (postTransitionOutHandler)
postTransitionOutHandler();
gallery.rebuildThumbs();
// Transition In the thumbsContainer
if (gallery.onPageTransitionIn)
gallery.onPageTransitionIn();
else
gallery.show();
};
// Transition Out the thumbsContainer
if (this.onPageTransitionOut) {
this.onPageTransitionOut(transitionOutCallback);
}
else {
this.hide();
transitionOutCallback();
}
return this;
},
// Updates the set of thumbnails that are to be displayed and the navigation controls.
rebuildThumbs: function () {
var needsPagination = this.data.length > this.numThumbs;
// Rebuild top pager
if (this.enableTopPager) {
var $topPager = this.find('div.top');
if ($topPager.length === 0)
$topPager = this.prepend('<div class="top pagination"></div>').find('div.top');
else
$topPager.empty();
if (needsPagination)
this.buildPager($topPager);
}
// Rebuild bottom pager
if (this.enableBottomPager) {
var $bottomPager = this.find('div.bottom');
if ($bottomPager.length === 0)
$bottomPager = this.append('<div class="bottom pagination"></div>').find('div.bottom');
else
$bottomPager.empty();
if (needsPagination)
this.buildPager($bottomPager);
}
var page = this.getCurrentPage();
var startIndex = page * this.numThumbs;
var stopIndex = startIndex + this.numThumbs - 1;
if (stopIndex >= this.data.length)
stopIndex = this.data.length - 1;
// Show/Hide thumbs
var $thumbsUl = this.find('ul.thumbs');
$thumbsUl.find('li').each(function (i) {
var $li = $(this);
if (i >= startIndex && i <= stopIndex) {
$li.show();
}
else {
$li.hide();
}
});
this.displayedPage = page;
// Remove the noscript class from the thumbs container ul
$thumbsUl.removeClass('noscript');
return this;
},
// Returns the total number of pages required to display all the thumbnails.
getNumPages: function () {
return Math.ceil(this.data.length / this.numThumbs);
},
// Rebuilds the pager control in the specified matched element.
// @param {jQuery} pager A jQuery element set matching the particular pager to be rebuilt.
buildPager: function (pager) {
var gallery = this;
var numPages = this.getNumPages();
var page = this.getCurrentPage();
var startIndex = page * this.numThumbs;
var pagesRemaining = this.maxPagesToShow - 1;
var pageNum = page - Math.floor((this.maxPagesToShow - 1) / 2) + 1;
if (pageNum > 0) {
var remainingPageCount = numPages - pageNum;
if (remainingPageCount < pagesRemaining) {
pageNum = pageNum - (pagesRemaining - remainingPageCount);
}
}
if (pageNum < 0) {
pageNum = 0;
}
// Prev Page Link
if (page > 0) {
var prevPage = startIndex - this.numThumbs;
pager.append('<a rel="history" href="#' + this.data[prevPage].hash + '" title="' + this.prevPageLinkText + '">' + this.prevPageLinkText + '</a>');
}
// Create First Page link if needed
if (pageNum > 0) {
this.buildPageLink(pager, 0, numPages);
if (pageNum > 1)
pager.append('<span class="ellipsis">&hellip;</span>');
pagesRemaining--;
}
// Page Index Links
while (pagesRemaining > 0) {
this.buildPageLink(pager, pageNum, numPages);
pagesRemaining--;
pageNum++;
}
// Create Last Page link if needed
if (pageNum < numPages) {
var lastPageNum = numPages - 1;
if (pageNum < lastPageNum)
pager.append('<span class="ellipsis">&hellip;</span>');
this.buildPageLink(pager, lastPageNum, numPages);
}
// Next Page Link
var nextPage = startIndex + this.numThumbs;
if (nextPage < this.data.length) {
pager.append('<a rel="history" href="#' + this.data[nextPage].hash + '" title="' + this.nextPageLinkText + '">' + this.nextPageLinkText + '</a>');
}
pager.find('a').click(function (e) {
gallery.clickHandler(e, this);
});
return this;
},
// Builds a single page link within a pager. This function is called by buildPager
// @param {jQuery} pager A jQuery element set matching the particular pager to be rebuilt.
// @param {Integer} pageNum The page number of the page link to build.
// @param {Integer} numPages The total number of pages required to display all thumbnails.
buildPageLink: function (pager, pageNum, numPages) {
var pageLabel = pageNum + 1;
var currentPage = this.getCurrentPage();
if (pageNum == currentPage)
pager.append('<span class="current">' + pageLabel + '</span>');
else if (pageNum < numPages) {
var imageIndex = pageNum * this.numThumbs;
pager.append('<a rel="history" href="#' + this.data[imageIndex].hash + '" title="' + pageLabel + '">' + pageLabel + '</a>');
}
return this;
}
});
// Now initialize the gallery
$.extend(this, defaults, settings);
// Verify the history plugin is available
if (this.enableHistory && !$.historyInit)
this.enableHistory = false;
// Select containers
if (this.imageContainerSel) this.$imageContainer = $(this.imageContainerSel);
if (this.captionContainerSel) this.$captionContainer = $(this.captionContainerSel);
if (this.loadingContainerSel) this.$loadingContainer = $(this.loadingContainerSel);
// Initialize the thumbails
this.initializeThumbs();
if (this.maxPagesToShow < 3)
this.maxPagesToShow = 3;
this.displayedPage = -1;
this.currentImage = this.data[0];
var gallery = this;
// Hide the loadingContainer
if (this.$loadingContainer)
this.$loadingContainer.hide();
// Setup controls
if (this.controlsContainerSel) {
this.$controlsContainer = $(this.controlsContainerSel).empty();
if (this.renderSSControls) {
if (this.autoStart) {
this.$controlsContainer
.append('<div class="ss-controls"><a href="#pause" class="pause" title="' + this.pauseLinkText + '">' + this.pauseLinkText + '</a></div>');
}
else {
this.$controlsContainer
.append('<div class="ss-controls"><a href="#play" class="play" title="' + this.playLinkText + '">' + this.playLinkText + '</a></div>');
}
this.$controlsContainer.find('div.ss-controls a')
.click(function (e) {
gallery.toggleSlideshow();
e.preventDefault();
return false;
});
}
if (this.renderNavControls) {
this.$controlsContainer
.append('<div class="nav-controls"><a class="prev" rel="history" title="' + this.prevLinkText + '">' + this.prevLinkText + '</a><a class="next" rel="history" title="' + this.nextLinkText + '">' + this.nextLinkText + '</a></div>')
.find('div.nav-controls a')
.click(function (e) {
gallery.clickHandler(e, this);
});
}
}
var initFirstImage = !this.enableHistory || !location.hash;
if (this.enableHistory && location.hash) {
var hash = $.galleriffic.normalizeHash(location.hash);
var imageData = allImages[hash];
if (!imageData)
initFirstImage = true;
}
// Setup gallery to show the first image
if (initFirstImage)
this.gotoIndex(0, false, true);
// Setup Keyboard Navigation
if (this.enableKeyboardNavigation) {
$(document).keydown(function (e) {
var key = e.charCode ? e.charCode : e.keyCode ? e.keyCode : 0;
switch (key) {
case 32: // space
gallery.next();
e.preventDefault();
break;
case 33: // Page Up
gallery.previousPage();
e.preventDefault();
break;
case 34: // Page Down
gallery.nextPage();
e.preventDefault();
break;
case 35: // End
gallery.gotoIndex(gallery.data.length - 1);
e.preventDefault();
break;
case 36: // Home
gallery.gotoIndex(0);
e.preventDefault();
break;
case 37: // left arrow
gallery.previous();
e.preventDefault();
break;
case 39: // right arrow
gallery.next();
e.preventDefault();
break;
}
});
}
// Auto start the slideshow
if (this.autoStart)
this.play();
// Kickoff Image Preloader after 1 second
setTimeout(function () {
gallery.preloadInit();
}, 1000);
return this;
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment