Mercurial > repos > brasset_jensen > srnapipe
diff test-data/res_files/js/jquery.galleriffic.js @ 61:9185ca0a7b43 draft
Updated package according to recommendations.
author | pierre.pouchin |
---|---|
date | Wed, 16 Jan 2019 08:18:13 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test-data/res_files/js/jquery.galleriffic.js Wed Jan 16 08:18:13 2019 -0500 @@ -0,0 +1,979 @@ +/** + * 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) + */ +;(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'); + + // 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 + }; + + // 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"><a class="advance-link" rel="history" href="#'+this.data[nextIndex].hash+'" title="'+imageData.title+'"> </a></span>') + .find('span.current').css('opacity', '0'); + + newSlide.find('a') + .append(imageData.image) + .click(function(e) { + gallery.clickHandler(e, this); + }); + + 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">…</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">…</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);