Team:AUC TURKEY/HumanPractices/iGEMism/Posters
From 2013hs.igem.org
(Difference between revisions)
Line 19: | Line 19: | ||
* Much thanks to primary contributer Ponticlaro (http://www.ponticlaro.com) | * 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); | ||
</script> | </script> | ||
<style type="text/css"> | <style type="text/css"> | ||
Line 269: | Line 1,238: | ||
<ul class="thumbs noscript"> | <ul class="thumbs noscript"> | ||
<li> | <li> | ||
- | <a class="thumb" name="pic-1" href="https://static.igem.org/mediawiki/2013hs/a/a1/AUC_TURKEY_POSTER_HOUSE.jpg | + | <a class="thumb" name="pic-1" href="https://static.igem.org/mediawiki/2013hs/a/a1/AUC_TURKEY_POSTER_HOUSE.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/5/5a/AUC_TURKEY_POSTER_HOUSE_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/5/5a/AUC_TURKEY_POSTER_HOUSE_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 279: | Line 1,248: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-2" href="https://static.igem.org/mediawiki/2013hs/2/27/AUC_TURKEY_POSTER_IGEMISMTV.jpg | + | <a class="thumb" name="pic-2" href="https://static.igem.org/mediawiki/2013hs/2/27/AUC_TURKEY_POSTER_IGEMISMTV.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/a/a4/AUC_TURKEY_POSTER_IGEMISMTV_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/a/a4/AUC_TURKEY_POSTER_IGEMISMTV_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 289: | Line 1,258: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-3" href="https://static.igem.org/mediawiki/2013hs/9/91/AUC_TURKEY_POSTER_KILIM.jpg | + | <a class="thumb" name="pic-3" href="https://static.igem.org/mediawiki/2013hs/9/91/AUC_TURKEY_POSTER_KILIM.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/f/f9/AUC_TURKEY_POSTER_KILIM_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/f/f9/AUC_TURKEY_POSTER_KILIM_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 299: | Line 1,268: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-4" href="https://static.igem.org/mediawiki/2013hs/b/b5/AUC_TURKEY_POSTER_LAST_HOPE.jpg | + | <a class="thumb" name="pic-4" href="https://static.igem.org/mediawiki/2013hs/b/b5/AUC_TURKEY_POSTER_LAST_HOPE.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/f/fd/AUC_TURKEY_POSTER_LAST_HOPE_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/f/fd/AUC_TURKEY_POSTER_LAST_HOPE_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 309: | Line 1,278: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-5" href="https://static.igem.org/mediawiki/2013hs/f/f7/AUC_TURKEY_POSTER_LOTR.png | + | <a class="thumb" name="pic-5" href="https://static.igem.org/mediawiki/2013hs/f/f7/AUC_TURKEY_POSTER_LOTR.png"> |
<img src="https://static.igem.org/mediawiki/2013hs/5/5d/AUC_TURKEY_POSTER_LOTR_THUMB.png"/> | <img src="https://static.igem.org/mediawiki/2013hs/5/5d/AUC_TURKEY_POSTER_LOTR_THUMB.png"/> | ||
</a> | </a> | ||
Line 320: | Line 1,289: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-6" href="https://static.igem.org/mediawiki/2013hs/a/a1/AUC_TURKEY_POSTER_OLYMPIAD.jpg | + | <a class="thumb" name="pic-6" href="https://static.igem.org/mediawiki/2013hs/a/a1/AUC_TURKEY_POSTER_OLYMPIAD.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/0/03/AUC_TURKEY_POSTER_OLYMPIAD_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/0/03/AUC_TURKEY_POSTER_OLYMPIAD_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 330: | Line 1,299: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-7" href="https://static.igem.org/mediawiki/2013hs/5/5d/AUC_TURKEY_POSTER_PIPETTA.jpg | + | <a class="thumb" name="pic-7" href="https://static.igem.org/mediawiki/2013hs/5/5d/AUC_TURKEY_POSTER_PIPETTA.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/1/10/AUC_TURKEY_POSTER_PIPETTA_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/1/10/AUC_TURKEY_POSTER_PIPETTA_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 340: | Line 1,309: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-8" href="https://static.igem.org/mediawiki/2013hs/1/12/AUC_TURKEY_POSTER_TURKISH_COFFEE.JPG | + | <a class="thumb" name="pic-8" href="https://static.igem.org/mediawiki/2013hs/1/12/AUC_TURKEY_POSTER_TURKISH_COFFEE.JPG"> |
<img src="https://static.igem.org/mediawiki/2013hs/c/c6/AUC_TURKEY_POSTER_TURKISH_COFFEE_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/c/c6/AUC_TURKEY_POSTER_TURKISH_COFFEE_THUMB.jpg"/> | ||
</a> | </a> | ||
Line 350: | Line 1,319: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-9" href="https://static.igem.org/mediawiki/2013hs/1/1b/AUC_TURKEY_POSTER_UNCLE_SAM.png | + | <a class="thumb" name="pic-9" href="https://static.igem.org/mediawiki/2013hs/1/1b/AUC_TURKEY_POSTER_UNCLE_SAM.png"> |
<img src="https://static.igem.org/mediawiki/2013hs/2/26/AUC_TURKEY_POSTER_UNCLE_SAM_THUMB.png"/> | <img src="https://static.igem.org/mediawiki/2013hs/2/26/AUC_TURKEY_POSTER_UNCLE_SAM_THUMB.png"/> | ||
</a> | </a> | ||
Line 360: | Line 1,329: | ||
</div> | </div> | ||
</li><li> | </li><li> | ||
- | <a class="thumb" name="pic-10" href="https://static.igem.org/mediawiki/2013hs/9/97/AUC_TURKEY_POSTER_UNITED_WE_STAND.jpg | + | <a class="thumb" name="pic-10" href="https://static.igem.org/mediawiki/2013hs/9/97/AUC_TURKEY_POSTER_UNITED_WE_STAND.jpg"> |
<img src="https://static.igem.org/mediawiki/2013hs/7/7d/AUC_TURKEY_POSTER_UNITED_WE_STAND_THUMB.jpg"/> | <img src="https://static.igem.org/mediawiki/2013hs/7/7d/AUC_TURKEY_POSTER_UNITED_WE_STAND_THUMB.jpg"/> | ||
</a> | </a> |
Revision as of 17:03, 21 June 2013