/** * gamma.js v1.0.0 * http://www.codrops.com * * Licensed under the MIT license. * http://www.opensource.org/licenses/mit-license.php * * Copyright 2012, Codrops * http://www.codrops.com */ /** * Return a new JSON object of the old string. * Turns: * file.js?a=1&b.c=3.0&b.d=four&a_false_value=false&a_null_value=null * Into: * {"a":1,"b":{"c":3,"d":"four"},"a_false_value":false,"a_null_value":null} * @version 1.1.0 * @date July 16, 2010 * @since 1.0.0, June 30, 2010 * @package jquery-sparkle {@link http://www.balupton/projects/jquery-sparkle} * @author Benjamin "balupton" Lupton {@link http://www.balupton.com} * @copyright (c) 2009-2010 Benjamin Arthur Lupton {@link http://www.balupton.com} * @license GNU Affero General Public License version 3 {@link http://www.gnu.org/licenses/agpl-3.0.html} */ String.prototype.queryStringToJSON = String.prototype.queryStringToJSON || function ( ) { // Turns a params string or url into an array of params // Prepare var params = String(this); // Remove url if need be params = params.substring(params.indexOf('?')+1); // params = params.substring(params.indexOf('#')+1); // Change + to %20, the %20 is fixed up later with the decode params = params.replace(/\+/g, '%20'); // Do we have JSON string if ( params.substring(0,1) === '{' && params.substring(params.length-1) === '}' ) { // We have a JSON string return eval(decodeURIComponent(params)); } // We have a params string params = params.split(/\&(amp\;)?/); var json = {}; // We have params for ( var i = 0, n = params.length; i < n; ++i ) { // Adjust var param = params[i] || null; if ( param === null ) { continue; } param = param.split('='); if ( param === null ) { continue; } // ^ We now have "var=blah" into ["var","blah"] // Get var key = param[0] || null; if ( key === null ) { continue; } if ( typeof param[1] === 'undefined' ) { continue; } var value = param[1]; // ^ We now have the parts // Fix key = decodeURIComponent(key); value = decodeURIComponent(value); try { // value can be converted value = eval(value); } catch ( e ) { // value is a normal string } // Set // window.console.log({'key':key,'value':value}, split); var keys = key.split('.'); if ( keys.length === 1 ) { // Simple json[key] = value; } else { // Advanced (Recreating an object) var path = '', cmd = ''; // Ensure Path Exists $.each(keys,function(ii,key){ path += '["'+key.replace(/"/g,'\\"')+'"]'; jsonCLOSUREGLOBAL = json; // we have made this a global as closure compiler struggles with evals cmd = 'if ( typeof jsonCLOSUREGLOBAL'+path+' === "undefined" ) jsonCLOSUREGLOBAL'+path+' = {}'; eval(cmd); json = jsonCLOSUREGLOBAL; delete jsonCLOSUREGLOBAL; }); // Apply Value jsonCLOSUREGLOBAL = json; // we have made this a global as closure compiler struggles with evals valueCLOSUREGLOBAL = value; // we have made this a global as closure compiler struggles with evals cmd = 'jsonCLOSUREGLOBAL'+path+' = valueCLOSUREGLOBAL'; eval(cmd); json = jsonCLOSUREGLOBAL; delete jsonCLOSUREGLOBAL; delete valueCLOSUREGLOBAL; } // ^ We now have the parts added to your JSON object } return json; }; // checks if an element is partially inside the viewport // inspired by James Padolsey's snippet (http://remysharp.com/2009/01/26/element-in-view-event-plugin/#comment-127058) $.extend( $.expr[':'], { inViewport : function( el ) { var scrollTop = ( document.documentElement.scrollTop || document.body.scrollTop ), elOffsetTop = $( el ).offset().top, elH = $( el ).height() winH = ( window.innerHeight && window.innerHeight < $( window ).height() ) ? window.innerHeight : $( window ).height(); return ( elOffsetTop + elH ) > scrollTop && elOffsetTop < ( scrollTop + winH ); } }); // HTML5 PageVisibility API // http://www.html5rocks.com/en/tutorials/pagevisibility/intro/ // by Joe Marini (@joemarini) function getHiddenProp(){ var prefixes = ['webkit','moz','ms','o']; // if 'hidden' is natively supported just return it if ('hidden' in document) return 'hidden'; // otherwise loop over all the known prefixes until we find one for (var i = 0; i < prefixes.length; i++){ if ((prefixes[i] + 'Hidden') in document) return prefixes[i] + 'Hidden'; } // otherwise it's not supported return null; } function isHidden() { var prop = getHiddenProp(); if (!prop) return false; return document[prop]; } var Gamma = (function() { var $window = $( window ), $body = $( 'body' ), $document = $( document ), Modernizr = window.Modernizr, // https://github.com/twitter/bootstrap/issues/2870 transEndEventNames = { 'WebkitTransition' : 'webkitTransitionEnd', 'MozTransition' : 'transitionend', 'OTransition' : 'oTransitionEnd', 'msTransition' : 'MSTransitionEnd', 'transition' : 'transitionend' }, transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], // default settings defaults = { // default value for masonry column count columns : ( $(window).width() > 900 ? 4 : 2 ), // transition properties for the images in ms (transition to/from singleview) speed : 300, easing : 'ease', // if set to true the overlay's opacity will animate (transition to/from singleview) overlayAnimated : true, // if true, the navigate next function is called when the image (singleview) is clicked nextOnClickImage : true, // circular navigation circular : true, // transition settings for the image in the single view. // These includes: // - ajusting its position and size when the window is resized // - fading out the image when navigating svImageTransitionSpeedFade : 300, svImageTransitionEasingFade : 'ease-in-out', svImageTransitionSpeedResize : 300, svImageTransitionEasingResize : 'ease-in-out', svMarginsVH : { vertical : 0, horizontal :0 }, // allow keybord and swipe navigation keyboard : true, swipe : true, // slideshow interval (ms) interval : 4000, // if History API is not supported this value will turn false historyapi : true }, init = function( settings, callback ) { Gamma.settings = $.extend( true, {}, defaults, settings ); // cache some elements.. _config(); // build the layout _layout(); // init masonry _initMasonry( function() { // remove loading status Gamma.container.removeClass( 'gamma-loading' ); // show items Gamma.items.show(); // opens the single view if an image id is passed in the url // we will assume for this demo that the id is the index of the item // where the image is // example: http://www.sitename.com/gamma/?img=12 if( Gamma.settings.historyapi ) { _goto(); } // init window events _initEvents( 'window' ); if( callback ) { callback.call(); } } ); }, _config = function() { Gamma.container = $( '#gamma-container' ); Gamma.overlay = Gamma.container.find( 'div.gamma-overlay' ); Gamma.controls = Gamma.container.children( 'div.gamma-options' ); Gamma.gallery = Gamma.container.children( 'ul.gamma-gallery' ); Gamma.items = Gamma.gallery.children(); Gamma.itemsCount = Gamma.items.length; Gamma.columns = Gamma.settings.columns; // true if any animation (including preloading an image) running Gamma.isAnimating = true; Gamma.svMargins = Gamma.settings.svMarginsVH; var History = window.History; // Note: We are using a capital H instead of a lower h if ( !History.enabled && Gamma.settings.historyapi ) { Gamma.settings.historyapi = false; } Gamma.supportTransitions = Modernizr.csstransitions; }, _createSingleView = function() { // the single view will include the image, navigation buttons and close, play, and pause buttons if( !Gamma.singleview ) { $( '
' ) .appendTo( Gamma.container ); Gamma.singleview = Gamma.container.children( 'div.gamma-single-view' ); Gamma.svclose = Gamma.singleview.find( 'button.gamma-btn-close' ); _initEvents( 'singleview' ); _createSingleViewNavigation(); } else if( !Gamma.nav ) { _createSingleViewNavigation(); } }, _createSingleViewNavigation = function() { if( Gamma.itemsCount > 1 ) { Gamma.svplay = $( '' ).insertAfter( Gamma.svclose ); Gamma.nav = $( '' ).appendTo( Gamma.singleview ); Gamma.svnavnext = Gamma.nav.find( 'span.gamma-next' ); Gamma.svnavprev = Gamma.nav.find( 'span.gamma-prev' ); _initEvents( 'singleviewnavigation' ); } }, // controller: "goes to" a specific image or back to the grid _goto = function( anim, id ) { if( Gamma.settings.historyapi ) { // get the url from history state (e.g. id=3) and extract the id id = id || History.getState().url.queryStringToJSON().id; } var isSingleview = ( id != undefined ), anim = anim || false; // back history to a state with no id if( Gamma.settings.historyapi && Gamma.isSV && id === undefined ) { _closesingleview(); } if( isSingleview ) { var $item = Gamma.items.eq( Math.abs( id ) ); if( $item.length ) { if( Gamma.svImage ) { // navigating if( Gamma.supportTransitions ) { _setTransition( Gamma.svImage , 'all', Gamma.settings.svImageTransitionSpeedFade , Gamma.settings.svImageTransitionEasingFade ); } _applyAnimation( Gamma.svImage, { opacity : 0 }, Gamma.settings.svImageTransitionSpeedFade, Gamma.supportTransitions, function() { $( this ).remove(); anim = false; _singleviewitem( $item, anim ); } ); if( Gamma.svDescription ) { _applyAnimation( Gamma.svDescription, { opacity : 0 }, 400, Gamma.supportTransitions ); } } else { if( Gamma.svDescription ) { Gamma.svDescription.empty(); } _singleviewitem( $item, anim ); } } } }, // saves the history state / or if history not supported goes to specific image _saveState = function( id ) { if( !Gamma.settings.historyapi && id != undefined ) { Gamma.isSV ? _goto( false, id ) : _goto( true, id ); } else if( id === undefined ) { History.pushState( null, null, url('protocol') + '://' + url('hostname') + url('path') ); } // adds a new state to the history object // this will trigger the statechange on the window else if( History.getState().url.queryStringToJSON().id !== id ) { History.pushState( null, null, '?id=' + id ); } }, // transform initial html structure into a list of images (well mostly) _layout = function( $items ) { if( Gamma.itemsCount > 0 ) { _createSingleView(); } _setMasonry(); var $items = $items || Gamma.items.hide(); // replace each div element with an image element with the right source $items.each( function() { var $item = $( this ), $picEl = $item.children(), sources = _getImgSources( $picEl ), source = _chooseImgSource( sources, $item.outerWidth( true ) ), description = $picEl.data( 'description' ); // data is saved in the
  • element $item.data( { description : description, source : sources, maxwidth : $picEl.data( 'maxWidth' ), maxheight : $picEl.data( 'maxHeight' ) } ); $( '
    ' ).addClass( 'gamma-description' ).html( description ).insertAfter( $picEl ); $( '' ).attr( { alt : $picEl.data( 'alt' ), title : $picEl.data( 'title' ), src : source.src } ).insertAfter( $picEl ); $picEl.remove(); } ); }, // gets all possible image sources of an element _getImgSources = function( $el ) { var theSources = []; $el.children( 'div' ).each( function( i ) { var $source = $( this ); theSources.push( { width : $source.data( 'minWidth' ) || 0, src : $source.data( 'src' ), pos : i } ); } ); return theSources; }, // change the number of masonry columns based on the current container's width and the settings.viewport configuration _setMasonry = function() { var containerW = Gamma.container.width(); if( Gamma.settings.viewport ) { for( var i = 0, len = Gamma.settings.viewport.length; i < len; ++i ) { var viewport = Gamma.settings.viewport[i]; if( containerW > viewport.width ) { Gamma.columns = viewport.columns; break; } } } // set the widths (%) for each of the
  • Gamma.items.css( 'width', Math.floor( containerW / Gamma.columns ) * 100 / containerW + '%' ); }, // initialize masonry _initMasonry = function( callback ) { Gamma.gallery.imagesLoaded( function() { Gamma.gallery.masonry( { itemSelector : 'li', columnWidth : function( containerWidth ) { return containerWidth / Gamma.columns; } } ); if( callback ) { callback.call(); } } ); }, // reloads masonry grid _reloadMasonry = function( timeout ) { clearTimeout( Gamma.masonrytimeout ); timeout = timeout || 0; Gamma.masonrytimeout = setTimeout( function() { Gamma.gallery.masonry( 'reload' ); }, timeout ); }, // choose a source based on the item's size and on the configuration set by the user in the initial HTML _chooseImgSource = function( sources, w ) { if( w <= 0 ) { w = 1; } for( var i = 0, len = sources.length; i < len; ++i ) { var source = sources[i]; if( w > source.width ) { return source; } } }, // show or hide a specific control button _toggleControl = function( $control, status, animStyle ) { animStyle ? $control.css( animStyle ) : status === 'on' ? $control.show() : $control.hide(); }, // triggered on the events for the nav buttons, keyboard, swipe _onnavigate = function( dir ) { if( !Gamma.slideshow ) { _navigate( dir ); } }, // goes to next or previous image _navigate = function( dir ) { if( !Gamma.isSV || Gamma.isAnimating ) { return false; } var current = Gamma.current; if( dir === 'next' ) { Gamma.current = Gamma.current < Gamma.itemsCount - 1 ? ++Gamma.current : Gamma.settings.circular ? 0 : Gamma.current; } else if( dir === 'prev' ) { Gamma.current = Gamma.current > 0 ? --Gamma.current : Gamma.settings.circular ? Gamma.itemsCount - 1 : Gamma.current; } if( current === Gamma.current ) { return false; } Gamma.isAnimating = true; // get positions, dimentions and source for the new item _saveState( Gamma.current ); }, // resize the window event _resize = function() { _setMasonry(); _resizeGrid(); // change the size, position and source of the image (single view) accordingly if( Gamma.isSV ) { _svResizeImage(); } // seems that sometimes the masonry columns stay out of order. // just to make sure this doesnt happen _reloadMasonry( 200 ); }, // resizes the masonry grid // change the source of the images (grid) accordingly _resizeGrid = function() { Gamma.items.each( function() { var $item = $( this ), source = _chooseImgSource( $item.data( 'source' ), Gamma.items.outerWidth( true ) ); $item.find( 'img' ).attr( 'src', source.src ); } ); } // resize and chooses (if necessary) a new source for the image in the single view _svResizeImage = function( callback ) { // need to know which source to load for the image. // also need to know the final size and position. var finalConfig = _getFinalImgConfig( { sources : Gamma.svImage.data( 'source' ), imgMaxW : Gamma.svImage.data( 'maxwidth' ), imgMaxH : Gamma.svImage.data( 'maxheight' ), wrapper : { width : $window.width() - Gamma.svMargins.horizontal, height : $window.height() - Gamma.svMargins.vertical }, image : { width : Gamma.svImage.width(), height : Gamma.svImage.height() } } ), source = finalConfig.source, finalSizePosition = finalConfig.finalSizePosition, currentSrc = Gamma.svImage.attr('src'), finalStyle = { width : finalSizePosition.width, height : finalSizePosition.height, left : finalSizePosition.left + Gamma.svMargins.horizontal / 2, top : finalSizePosition.top + Gamma.svMargins.vertical / 2 }; _applyAnimation( Gamma.svImage, finalStyle, Gamma.settings.svImageTransitionSpeedResize, Gamma.supportTransitions, function() { if( Gamma.supportTransitions ) { $( this ).off( transEndEventName ); } // if source changes, change reset Gamma.svImage if( currentSrc !== source.src ) { // going to load a new image.. Gamma.isAnimating = true; var w = Gamma.svImage.width(), h = Gamma.svImage.height(), l = Gamma.svImage.position().left, t = Gamma.svImage.position().top; Gamma.svImage = $( '' ).load( function() { var $img = $( this ); if( Gamma.supportTransitions ) { _setTransition( $img , 'all', Gamma.settings.svImageTransitionSpeedResize , Gamma.settings.svImageTransitionEasingResize ); } _applyAnimation( $img.next(), { opacity : 0 }, 500, Gamma.supportTransitions, function() { var $img = $( this ); if( Gamma.supportTransitions ) { $( this ).off( transEndEventName ); } $img.remove(); Gamma.isAnimating = false; } ); } ) .css( { width : w, height : h, left : l, top : t } ) .data( Gamma.svImage.data() ) .insertBefore( Gamma.svImage ) .attr( 'src', source.src ); } if( callback ) { callback.call(); } } ); }, // gets the position and sizes of the image given its container properties _getFinalImgConfig = function( properties ) { var sources = properties.sources, imgMaxW = properties.imgMaxW || 0, imgMaxH = properties.imgMaxH || 0, source = _chooseImgSource( sources, properties.wrapper.width ), // calculate final size and position of image finalSizePosition = _getFinalSizePosition( properties.image, properties.wrapper ); // check for new source if( finalSizePosition.checksource ) { source = _chooseImgSource( sources, finalSizePosition.width ); } // we still need to check one more detail: // if the source is the largest one provided in the html rules, // then we need to check if the final width/height are eventually bigger // than the original image sizes. If so, we will show the image // with its original size, avoiding like this that the image gets pixelated if( source.pos === 0 && ( imgMaxW !== 0 && finalSizePosition.width > imgMaxW || imgMaxH !== 0 && finalSizePosition.height > imgMaxH ) ) { if( imgMaxW !== 0 && finalSizePosition.width > imgMaxW ) { var ratio = finalSizePosition.width / imgMaxW; finalSizePosition.width = imgMaxW; finalSizePosition.height /= ratio; } else if( imgMaxH !== 0 && finalSizePosition.height > imgMaxH ) { var ratio = finalSizePosition.height / imgMaxH; finalSizePosition.height = imgMaxH; finalSizePosition.width /= ratio; } finalSizePosition.left = properties.wrapper.width / 2 - finalSizePosition.width / 2; finalSizePosition.top = properties.wrapper.height / 2 - finalSizePosition.height / 2; } return { source : source, finalSizePosition : finalSizePosition }; }, // triggered when one grid image is clicked _singleview = function() { var id = $( this ).index(); _saveState( id ); }, // shows the item _singleviewitem = function( $item, anim ) { Gamma.isSV = true; var id = $item.index(), data = $item.data(), $img = $item.children( 'img' ); if( anim ) { Gamma.fly = $( '' ).attr( 'src', $img.attr( 'src' ) ).addClass( 'gamma-img-fly' ).css( { width : $img.width(), height : $img.height(), left : $item.offset().left + ( $item.outerWidth( true ) - $item.width() ) / 2, top : $item.offset().top + ( $item.outerHeight( true ) - $item.height() ) / 2 } ).appendTo( $body ); if( Gamma.supportTransitions ) { _setTransition( Gamma.fly ); } } // need to know which source to load for the image. // also need to know the final size and position. var finalConfig = _getFinalImgConfig( { sources : $item.data( 'source' ), imgMaxW : $item.data( 'maxwidth' ), imgMaxH : $item.data( 'maxheight' ), wrapper : { width : $window.width() - Gamma.svMargins.horizontal, height : $window.height() - Gamma.svMargins.vertical }, image : { width : $img.width(), height : $img.height() } } ), source = finalConfig.source, finalSizePosition = finalConfig.finalSizePosition; Gamma.current = id; // transition: overlay opacity Gamma.overlay.show(); if( Gamma.settings.overlayAnimated && anim && Gamma.supportTransitions ) { _setTransition( Gamma.overlay , 'opacity' ); } setTimeout( function() { _applyAnimation( Gamma.overlay, { 'opacity' : 1 }, Gamma.settings.speed, Gamma.supportTransitions || !anim, function() { if( !Gamma.isSV ) { return false; } if( Gamma.supportTransitions ) { $( this ).off( transEndEventName ); } // set the overflow-y to hidden $body.css( 'overflow-y', 'hidden' ); // force repaint. Chrome in Windows does not remove overflow.. // http://stackoverflow.com/a/3485654/989439 var el = Gamma.overlay[0]; el.style.display='none'; el.offsetHeight; // no need to store this anywhere, the reference is enough el.style.display='block'; } ); $item.css( 'visibility', 'hidden' ); if( !anim ) { _loadSVItemFromGrid( data, finalSizePosition, source.src ); } else { var styleCSS = { width : finalSizePosition.width, height : finalSizePosition.height, left : finalSizePosition.left + $window.scrollLeft() + Gamma.svMargins.horizontal / 2, top : finalSizePosition.top + $window.scrollTop() + Gamma.svMargins.vertical / 2 }, cond = Gamma.supportTransitions; _applyAnimation( Gamma.fly, styleCSS, Gamma.settings.speed, cond, function() { if( cond ) { $( this ).off( transEndEventName ); } _loadSVItemFromGrid( data, finalSizePosition, source.src ); } ); } }, 25 ); }, // load new image for the new item to show _loadSVItemFromGrid = function( data, position, src ) { // show single view Gamma.singleview.show(); // add description if( !Gamma.svDescription ) { Gamma.svDescription = $( '
    ' ) .addClass( 'gamma-description' ) .appendTo( Gamma.singleview ).wrap( '
    ' ); if( Gamma.supportTransitions ) { _setTransition( Gamma.svDescription , 'opacity', Gamma.settings.svImageTransitionSpeedFade / 2 , Gamma.settings.svImageTransitionEasingFade ); } } Gamma.svDescription.html( data.description ); // loading status: give a little amount of time before displaying it var loadingtimeout = setTimeout( function() { Gamma.singleview.addClass( 'gamma-loading' ); }, Gamma.settings.svImageTransitionSpeedFade + 250 ); // preload the new image Gamma.svImage = $( '' ).load( function() { var $img = $( this ); // remove loading status clearTimeout( loadingtimeout ); Gamma.singleview.removeClass( 'gamma-loading' ); setTimeout( function() { _applyAnimation( Gamma.svDescription, { 'opacity' : 1 }, Gamma.settings.svImageTransitionSpeedFade / 2, Gamma.supportTransitions ); }, 25 ); // check proportion /* var prop = position.height / position.width; var nwidth = $(window).height() / prop; var nleft = ($(window).width() - nwidth ) / 2; $img.css( { width : nwidth, height : $(window).height(), left : nleft, top : 0 } ).appendTo( Gamma.singleview ); */ // original code $img.css( { width : position.width, height : position.height, left : position.left + Gamma.svMargins.horizontal / 2, top : position.top + Gamma.svMargins.vertical / 2 } ).appendTo( Gamma.singleview ); if( Gamma.supportTransitions ) { _setTransition( $img , 'all', Gamma.settings.svImageTransitionSpeedResize , Gamma.settings.svImageTransitionEasingResize ); } if( Gamma.fly ) { if( Gamma.supportTransitions ) { _setTransition( Gamma.fly, 'opacity', 1000 ); } setTimeout( function() { _applyAnimation( Gamma.fly, { 'opacity' : 0 }, 1000, Gamma.supportTransitions, function() { var $this = $( this ); if( Gamma.supportTransitions ) { $this.off( transEndEventName ); } $this.remove(); Gamma.fly = null; Gamma.isAnimating = false; } ); }, 25 ); } else { Gamma.isAnimating = false; } } ).data( data ).attr( 'src', src ); }, // given the wrapper's width and height, calculates the final width, height, left and top for the image to fit inside _getFinalSizePosition = function( imageSize, wrapperSize ) { // image size var imgW = imageSize.width, imgH = imageSize.height, // container size wrapperW = wrapperSize.width, wrapperH = wrapperSize.height, finalW, finalH, finalL, finalT, // flag to indicate we could check for another source (smaller) for the image checksource = false; // check which image side is bigger if( imgW > imgH ) { finalW = wrapperW; // calculate the height given the finalW var ratio = imgW / wrapperW; finalH = imgH / ratio; if( finalH > wrapperH ) { checksource = true; ratio = finalH / wrapperH; finalW /= ratio; finalH = wrapperH; } } else { finalH = wrapperH; // calculate the width given the finalH var ratio = imgH / wrapperH; finalW = imgW / ratio; checksource = true; if( finalW > wrapperW ) { checksource = false; ratio = finalW / wrapperW; finalW = wrapperW; finalH /= ratio; } } return { width : finalW, height : finalH, left : wrapperW / 2 - finalW / 2, top : wrapperH / 2 - finalH / 2, checksource : checksource }; }, // closes the single view _closesingleview = function() { if( Gamma.isAnimating || Gamma.fly ) { return false; } Gamma.isSV = false; if( Gamma.slideshow ) { _stopSlideshow(); } var $item = Gamma.items.eq( Gamma.current ), $img = $item.children( 'img' ); Gamma.items.not( $item ).css( 'visibility', 'visible' ); // scroll window to item's position if item is not "partially" visible var wst = $window.scrollTop(); if( !$item.is( ':inViewport' ) ) { wst = $item.offset().top + ( $item.outerHeight( true ) - $item.height() ) / 2; var diff = $document.height() - $window.height(); if( wst > diff ) { wst = diff; } $window.scrollTop( wst ); } var l = Gamma.svImage.position().left + $window.scrollLeft(), t = Gamma.svImage.position().top + wst; Gamma.svImage.appendTo( $body ).css( { position : 'absolute', zIndex : 10000, left : l, top : t } ); if( Gamma.supportTransitions ) { _setTransition( Gamma.svImage ); } Gamma.singleview.hide(); Gamma.svDescription.empty().css( 'opacity', 0 ); $body.css( 'overflow-y', 'scroll' ); setTimeout( function() { var styleCSS = { width : $img.width(), height : $img.height(), left : $item.offset().left + ( $item.outerWidth( true ) - $item.width() ) / 2, top : $item.offset().top + ( $item.outerHeight( true ) - $item.height() ) / 2 } _applyAnimation( Gamma.svImage, styleCSS, Gamma.settings.speed, Gamma.supportTransitions, function() { $item.css( 'visibility', 'visible' ); $( this ).remove(); Gamma.svImage = null; } ); // transition: overlay opacity if( Gamma.settings.overlayAnimated ) { if( Gamma.supportTransitions ) { _setTransition( Gamma.overlay , 'opacity' ); } _applyAnimation( Gamma.overlay, { 'opacity' : 0 }, Gamma.settings.speed, Gamma.supportTransitions, function() { var $this = $( this ); if( Gamma.supportTransitions ) { $this.off( transEndEventName ); } $this.hide(); } ); } else { Gamma.overlay.hide(); } _saveState(); }, 25 ); }, // the slideshow is active only if the page is visible _visChange = function() { if( Gamma.slideshow ) { isHidden() ? ( _stopSlideshow( true ), Gamma.slideshow = true ) : _prepareSlideshow(); } }, // before slideshow starts _prepareSlideshow = function() { if( Gamma.isAnimating && !Gamma.slideshow ) { return false; } Gamma.isAnimating = true; clearTimeout( Gamma.slideshowtimeout ); Gamma.slideshow = true; // container is the window Gamma.svMargins = { vertical : 0, horizontal : 0 }; _toggleControl( Gamma.svclose, 'off' ); _toggleControl( Gamma.svnavprev, 'off', { left : -40 } ); _toggleControl( Gamma.svnavnext, 'off', { right : -40 } ); _svResizeImage( function() { Gamma.isAnimating = false; Gamma.svplay.addClass( 'gamma-btn-sspause' ); _startSlideshow(); } ); }, _preloadNext = function() { // preload image for Gamma.current + 1 var next = Gamma.current < Gamma.itemsCount - 1 ? Gamma.current + 1 : Gamma.settings.circular ? 0 : Gamma.current, $item = Gamma.items.eq( next ), $img = $item.children( 'img' ), finalConfig = _getFinalImgConfig( { sources : $item.data( 'source' ), imgMaxW : $item.data( 'maxwidth' ), imgMaxH : $item.data( 'maxheight' ), wrapper : { width : $window.width() - Gamma.svMargins.horizontal, height : $window.height() - Gamma.svMargins.vertical }, image : { width : $img.width(), height : $img.height() } } ), source = finalConfig.source; $( '' ).attr( 'src', source.src ); }, // starts slideshow _startSlideshow = function() { _preloadNext(); Gamma.slideshowtimeout = setTimeout( function() { _navigate( 'next' ); _startSlideshow(); }, Gamma.settings.interval ); }, // stops slideshow _stopSlideshow = function( pause ) { if( Gamma.isAnimating ) { return false; } Gamma.isAnimating = true; clearTimeout( Gamma.slideshowtimeout ); if( !pause ) { Gamma.slideshow = false; Gamma.svplay.removeClass( 'gamma-btn-sspause' ); Gamma.svMargins = Gamma.settings.svMarginsVH; _toggleControl( Gamma.svclose, 'on' ); _toggleControl( Gamma.svnavprev, 'on', { left : 20 } ); _toggleControl( Gamma.svnavnext, 'on', { right : 20 } ); _svResizeImage( function() { Gamma.isAnimating = false; } ); } }, // initializes events according to type _initEvents = function( type ) { switch( type ) { case 'window' : if( Gamma.settings.historyapi ) { $window.on( 'statechange.gamma', function() { _goto( true ); } ); } $window.on( 'smartresize.gamma', _resize ); // use the property name to generate the prefixed event name var visProp = getHiddenProp(); // HTML5 PageVisibility API // http://www.html5rocks.com/en/tutorials/pagevisibility/intro/ // by Joe Marini (@joemarini) if (visProp) { var evtname = visProp.replace(/[H|h]idden/,'') + 'visibilitychange'; document.addEventListener(evtname, _visChange); } break; case 'singleview' : Gamma.gallery.on( 'click.gamma', 'li', _singleview ); Gamma.svclose.on( 'click.gamma', _closesingleview ); break; case 'singleviewnavigation' : Gamma.svnavnext.on( 'click.gamma', function() { _onnavigate( 'next' ); } ); Gamma.svnavprev.on( 'click.gamma', function() { _onnavigate( 'prev' ); } ); if( Gamma.settings.nextOnClickImage ) { Gamma.singleview.on( 'click.gamma', 'img', function() { _onnavigate( 'next' ); } ); } if ( Gamma.settings.keyboard ) { $document.on( 'keydown.gamma', function( event ) { var keyCode = event.keyCode || event.which, arrow = { left: 37, up: 38, right: 39, down: 40 }; switch (keyCode) { case arrow.left : _onnavigate( 'prev' ); break; case arrow.right : _onnavigate( 'next' ); break; } } ); } if( Gamma.settings.swipe ) { Gamma.singleview.on( { 'swipeleft.gamma' : function() { _onnavigate( 'next' ); }, 'swiperight.gamma' : function() { _onnavigate( 'prev' ); } } ); } Gamma.svplay.on( 'click.gamma', function() { if( Gamma.slideshow ) { _stopSlideshow(); } else if( !Gamma.isAnimating ) { _prepareSlideshow(); } } ); break; }; }, // sets a transition for an element _setTransition = function( el , property, speed, easing ) { if( !property ) { property = 'all'; } if( !speed ) { speed = Gamma.settings.speed; } if( !easing ) { easing = Gamma.settings.easing; } el.css( 'transition', property + ' ' + speed + 'ms ' + easing ); }, // apply a transition or fallback to jquery animate based on condition (cond) _applyAnimation = function( el, styleCSS, speed, cond, fncomplete ) { $.fn.applyStyle = cond ? $.fn.css : $.fn.animate; if( fncomplete && cond ) { el.on( transEndEventName, fncomplete ); } fncomplete = fncomplete || function() { return false; }; el.stop().applyStyle( styleCSS, $.extend( true, [], { duration : speed + 'ms', complete : fncomplete } ) ); }, // public method: adds more items add = function( $newitems ) { Gamma.gallery.append( $newitems ); Gamma.items = Gamma.gallery.children(); Gamma.itemsCount = Gamma.items.length; _layout( $newitems ); _reloadMasonry(); }; return { init : init, add : add } })();