summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Häggqvist <[email protected]>2014-06-24 22:22:34 +0200
committerVictor Häggqvist <[email protected]>2014-06-24 22:22:34 +0200
commit02f6b14940c011462af11dc165738679716ffcdd (patch)
tree4bd454559dd26c97623a7a2ad741f5679288c281
parentcbcf177bdf0b04e2f3b55f82d1609593e7408920 (diff)
track
-rw-r--r--js/touch-imagelightbox.js332
-rw-r--r--sass/touch-imagelightbox.scss214
2 files changed, 546 insertions, 0 deletions
diff --git a/js/touch-imagelightbox.js b/js/touch-imagelightbox.js
new file mode 100644
index 0000000..d82b133
--- /dev/null
+++ b/js/touch-imagelightbox.js
@@ -0,0 +1,332 @@
+/*jslint browser: true*/
+;( function( $, window, document, undefined ) {
+ 'use strict';
+ var options,
+ cssTransitionSupport = function() {
+ var d = document.body || document.documentElement, s = d.style;
+ if ( s.WebkitTransition === '' )
+ return '-webkit-';
+ if ( s.MozTransition === '' )
+ return '-moz-';
+ if ( s.OTransition === '' )
+ return '-o-';
+ if ( s.transition === '' )
+ return '';
+ return false;
+ },
+
+ isCssTransitionSupport = cssTransitionSupport() === false ? false : true,
+
+ cssTransitionTranslateX = function( element, positionX, speed ) {
+ options = {};
+ var prefix = cssTransitionSupport();
+ options[ prefix + 'transform' ] = 'translateX(' + positionX + ')';
+ options[ prefix + 'transition' ] = prefix + 'transform ' + speed + 's linear';
+ element.css( options );
+ },
+
+ hasTouch = ( 'ontouchstart' in window ),
+ hasPointers = window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
+ wasTouched = function( event ) {
+ if( hasTouch )
+ return true;
+
+ if( !hasPointers || typeof event === 'undefined' || typeof event.pointerType === 'undefined' )
+ return false;
+
+ if( typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined' ) {
+ if( event.MSPOINTER_TYPE_MOUSE !== event.pointerType )
+ return true;
+ } else {
+ if( event.pointerType !== 'mouse' )
+ return true;
+ }
+
+ return false;
+ };
+
+ $.fn.imageLightbox = function( options ) {
+ options = $.extend(
+ {
+ selector: 'id="imagelightbox"',
+ allowedTypes: 'png|jpg|jpeg|gif',
+ animationSpeed: 250,
+ preloadNext: true,
+ enableKeyboard: true,
+ quitOnEnd: false,
+ quitOnImgClick: false,
+ quitOnDocClick: true,
+ onStart: false,
+ onEnd: false,
+ onLoadStart: false,
+ onLoadEnd: false
+ },
+ options);
+
+ var targets = $([]),
+ target = $(),
+ image = $(),
+ imageWidth = 0,
+ imageHeight = 0,
+ swipeDiff = 0,
+ inProgress = false,
+
+ isTargetValid = function( element ) {
+ this.regexValidObject = /(\.(' + options.allowedTypes + ')$)/;
+ return $( element ).prop( 'tagName' ).toLowerCase() === 'a' && this.regexValidObject.test($(element).attr('href') );
+ },
+
+ setImage = function() {
+ if( !image.length ) return false;
+
+ var screenWidth = $( window ).width() * 0.8,
+ screenHeight = $( window ).height() * 0.9,
+ tmpImage = new Image();
+
+ tmpImage.src = image.attr( 'src' );
+ tmpImage.onload = function() {
+ imageWidth = tmpImage.width;
+ imageHeight = tmpImage.height;
+
+ if( imageWidth > screenWidth || imageHeight > screenHeight ) {
+ var ratio = imageWidth / imageHeight > screenWidth / screenHeight ? imageWidth / screenWidth : imageHeight / screenHeight;
+ imageWidth /= ratio;
+ imageHeight /= ratio;
+ }
+
+ image.css(
+ {
+ 'width': imageWidth + 'px',
+ 'height': imageHeight + 'px',
+ 'top': ( $( window ).height() - imageHeight ) / 2 + 'px',
+ 'left': ( $( window ).width() - imageWidth ) / 2 + 'px'
+ }
+ );
+ };
+ },
+
+ loadImage = function( direction ) {
+ if( inProgress ) return false;
+
+ direction = typeof direction === 'undefined' ? false : direction === 'left' ? 1 : -1;
+
+ // BIG if
+ if( image.length ) {
+ if( direction !== false &&
+ ( targets.length < 2 ||
+ ( options.quitOnEnd === true &&
+ (
+ ( direction === -1 &&
+ targets.index( target ) === 0
+ ) ||
+ ( direction === 1 &&
+ targets.index( target ) === targets.length - 1
+ ) ) ) )
+ )
+ {
+ quitLightbox();
+ return false;
+ }
+ var params = { 'opacity': 0 };
+ if( isCssTransitionSupport ){
+ cssTransitionTranslateX( image, ( 100 * direction ) - swipeDiff + 'px', options.animationSpeed / 1000 );
+ } else {
+ params.left = parseInt( image.css( 'left' ) ) + 100 * direction + 'px';
+ }
+ image.animate( params, options.animationSpeed, function(){ removeImage(); });
+ swipeDiff = 0;
+ }
+
+ inProgress = true;
+ if( options.onLoadStart !== false ) options.onLoadStart();
+
+ setTimeout( function() {
+ image = $( '<img ' + options.selector + ' />' )
+ .attr( 'src', target.attr( 'href' ) )
+ .load( function()
+ {
+ image.appendTo( 'body' );
+ setImage();
+
+ var params = { 'opacity': 1 };
+
+ image.css( 'opacity', 0 );
+ if( isCssTransitionSupport )
+ {
+ cssTransitionTranslateX( image, -100 * direction + 'px', 0 );
+ setTimeout( function(){
+ cssTransitionTranslateX( image, 0 + 'px', options.animationSpeed / 1000 );
+ }, 50 );
+ }
+ else
+ {
+ var imagePosLeft = parseInt( image.css( 'left' ) );
+ params.left = imagePosLeft + 'px';
+ image.css( 'left', imagePosLeft - 100 * direction + 'px' );
+ }
+
+ image.animate( params, options.animationSpeed, function()
+ {
+ inProgress = false;
+ if( options.onLoadEnd !== false ) options.onLoadEnd();
+ });
+ if( options.preloadNext )
+ {
+ var nextTarget = targets.eq( targets.index( target ) + 1 );
+ if( !nextTarget.length ) nextTarget = targets.eq( 0 );
+ $( '<img />' ).attr( 'src', nextTarget.attr( 'href' ) ).load();
+ }
+ })
+ .error( function() {
+ if( options.onLoadEnd !== false )
+ options.onLoadEnd();
+ });
+
+ var swipeStart = 0,
+ swipeEnd = 0,
+ imagePosLeft = 0;
+
+ image.on( hasPointers ? 'pointerup MSPointerUp' : 'click', function( e ) {
+ e.preventDefault();
+ if( options.quitOnImgClick ) {
+ quitLightbox();
+ return false;
+ }
+
+ if( wasTouched( e.originalEvent ) )
+ return true;
+
+ var posX = ( e.pageX || e.originalEvent.pageX ) - e.target.offsetLeft;
+ target = targets.eq( targets.index( target ) - ( imageWidth / 2 > posX ? 1 : -1 ) );
+
+ if( !target.length )
+ target = targets.eq( imageWidth / 2 > posX ? targets.length : 0 );
+
+ loadImage( imageWidth / 2 > posX ? 'left' : 'right' );
+ })
+ .on( 'touchstart pointerdown MSPointerDown', function( e ) {
+ if( !wasTouched( e.originalEvent ) || options.quitOnImgClick )
+ return true;
+ if( isCssTransitionSupport )
+ imagePosLeft = parseInt( image.css( 'left' ) );
+
+ swipeStart = e.originalEvent.pageX || e.originalEvent.touches[ 0 ].pageX;
+ })
+ .on( 'touchmove pointermove MSPointerMove', function( e ) {
+ if( !wasTouched( e.originalEvent ) || options.quitOnImgClick )
+ return true;
+
+ e.preventDefault();
+ swipeEnd = e.originalEvent.pageX || e.originalEvent.touches[ 0 ].pageX;
+ swipeDiff = swipeStart - swipeEnd;
+
+ if( isCssTransitionSupport )
+ cssTransitionTranslateX( image, -swipeDiff + 'px', 0 );
+ else
+ image.css( 'left', imagePosLeft - swipeDiff + 'px' );
+ })
+ .on( 'touchend touchcancel pointerup MSPointerUp', function( e ) {
+ if( !wasTouched( e.originalEvent ) || options.quitOnImgClick )
+ return true;
+ if( Math.abs( swipeDiff ) > 50 ) {
+ target = targets.eq( targets.index( target ) - ( swipeDiff < 0 ? 1 : -1 ) );
+
+ if( !target.length )
+ target = targets.eq( swipeDiff < 0 ? targets.length : 0 );
+ loadImage( swipeDiff > 0 ? 'right' : 'left' );
+ } else {
+ if( isCssTransitionSupport )
+ cssTransitionTranslateX( image, 0 + 'px', options.animationSpeed / 1000 );
+ else
+ image.animate({ 'left': imagePosLeft + 'px' }, options.animationSpeed / 2 );
+ }
+ });
+
+ }, options.animationSpeed + 100 );
+ },
+
+ removeImage = function() {
+ if( !image.length )
+ return false;
+ image.remove();
+ image = $();
+ },
+
+ quitLightbox = function() {
+ if( !image.length )
+ return false;
+ image.animate({ 'opacity': 0 }, options.animationSpeed, function() {
+ removeImage();
+ inProgress = false;
+ if( options.onEnd !== false )
+ options.onEnd();
+ });
+ };
+
+ $( window ).on( 'resize', setImage );
+
+ if( options.quitOnDocClick ) {
+ $( document ).on( hasTouch ? 'touchend' : 'click', function( e ) {
+ if( image.length && !$( e.target ).is( image ) ) quitLightbox();
+ });
+ }
+
+ if( options.enableKeyboard ) {
+ $( document ).on( 'keyup', function( e ) {
+ if( !image.length )
+ return true;
+
+ e.preventDefault();
+
+ if( e.keyCode === 27 )
+ quitLightbox();
+
+ if( e.keyCode === 37 || e.keyCode === 39 ) {
+ target = targets.eq( targets.index( target ) - ( e.keyCode === 37 ? 1 : -1 ) );
+
+ if( !target.length )
+ target = targets.eq( e.keyCode === 37 ? targets.length : 0 );
+
+ loadImage( e.keyCode === 37 ? 'left' : 'right' );
+ }
+ });
+ }
+
+ $( document ).on( 'click', this.selector, function( e ) {
+ if( !isTargetValid( this ) )
+ return true;
+ e.preventDefault();
+
+ if( inProgress )
+ return false;
+ inProgress = false;
+
+ if( options.onStart !== false )
+ options.onStart();
+ target = $( this );
+ loadImage();
+ });
+
+ this.each( function() {
+ if( !isTargetValid( this ) ) return true;
+ targets = targets.add( $( this ) );
+ });
+
+ this.switchImageLightbox = function( index ) {
+ var tmpTarget = targets.eq( index );
+ if( tmpTarget.length ) {
+ var currentIndex = targets.index( target );
+ target = tmpTarget;
+ loadImage( index < currentIndex ? 'left' : 'right' );
+ }
+ return this;
+ };
+
+ this.quitImageLightbox = function() {
+ quitLightbox();
+ return this;
+ };
+
+ return this;
+ };
+})( jQuery, window, document );
diff --git a/sass/touch-imagelightbox.scss b/sass/touch-imagelightbox.scss
new file mode 100644
index 0000000..0ae16c0
--- /dev/null
+++ b/sass/touch-imagelightbox.scss
@@ -0,0 +1,214 @@
+@import 'compass/css3';
+@import 'variables';
+
+@mixin touch-action($value) {
+ -ms-touch-action: $value;
+ touch-action: $value;
+}
+
+html {
+ // killing 300ms touch delay in IE
+ @include touch-action(manipulation);
+}
+
+#imagelightbox {
+ @include touch-action(none);
+ @include box-shadow(rgba(0, 0, 0, .75) 0 0 50px);
+ cursor: pointer;
+ position: fixed;
+ z-index: 10000;
+}
+
+// Loading Indication
+#imagelightbox-loading,
+#imagelightbox-loading div {
+ @include border-radius(50%);
+}
+
+#imagelightbox-loading {
+ @include box-shadow(rgba(0, 0, 0, .75) 0 0 $loadingbox-size*2);
+
+ background: #444; // Fallback
+ background: rgba(0, 0, 0, .5);
+ height: $loadingbox-size;
+ left: 50%;
+ margin: -20px 0 0 -20px;
+ padding: 10px;
+ position: fixed;
+ top: 50%;
+ width: $loadingbox-size;
+ z-index: 10003;
+
+ div {
+ -moz-animation: imagelightbox-loading .5s ease infinite;
+ -o-animation: imagelightbox-loading .5s ease infinite;
+ -webkit-animation: imagelightbox-loading .5s ease infinite;
+ animation: imagelightbox-loading .5s ease infinite;
+
+ background-color: #fff;
+ height: 20px;
+ width: 20px;
+ }
+}
+
+@-webkit-keyframes imagelightbox-loading {
+ 0% { opacity: .5; -webkit-transform: scale(.75); }
+ 50% { opacity: 1; -webkit-transform: scale(1); }
+ 100% { opacity: .5; -webkit-transform: scale(.75); }
+}
+
+@-moz-keyframes imagelightbox-loading {
+ 0% { opacity: .5; -moz-transform: scale(.75); }
+ 50% { opacity: 1; -moz-transform: scale(1); }
+ 100% { opacity: .5; -moz-transform: scale(.75); }
+}
+
+@-o-keyframes imagelightbox-loading {
+ 0% { opacity: .5; -o-transform: scale(.75); }
+ 50% { opacity: 1; -o-transform: scale(1); }
+ 100% { opacity: .5; -o-transform: scale(.75); }
+}
+
+@keyframes imagelightbox-loading {
+ 0% { opacity: .5; transform: scale(.75); }
+ 50% { opacity: 1; transform: scale(1); }
+ 100% { opacity: .5; transform: scale(.75); }
+}
+
+#imagelightbox-overlay {
+ background: #fff;
+ background: rgba(255, 255, 255, .9);
+ bottom: 0;
+ left: 0;
+ position: fixed;
+ right: 0;
+ top: 0;
+ z-index: 9998;
+}
+
+
+// Close button
+#imagelightbox-close {
+ @include border-radius(50%);
+
+
+ background-color: #666;
+ height: $closebutton-size;
+ position: fixed;
+ right: $closebutton-size;
+ text-align: left;
+ text-indent: -9999px;
+ top: $closebutton-size;
+ -moz-transition: color .3s ease;
+ -ms-transition: color .3s ease;
+ -o-transition: color .3s ease;
+ -webkit-transition: color .3s ease;
+ transition: color .3s ease;
+ width: $closebutton-size;
+ z-index: 10002;
+
+ &:hover {
+ background-color: #111;
+ }
+
+ &:before,
+ &:after {
+ background-color: #fff;
+ bottom: 20%;
+ content: '';
+ left: 50%;
+ margin-left: -1px;
+ position: absolute;
+ top: 20%;
+ width: 2px;
+ }
+
+ &:before {
+ @include rotate(45deg);
+ }
+
+ &:after {
+ @include rotate(-45deg);
+ }
+}
+
+#imagelightbox-caption {
+ background-color: #666;
+ bottom: 0;
+ color: #fff;
+ left: 0;
+ padding: 10px;
+ position: fixed;
+ right: 0;
+ text-align: center;
+ z-index: 10001;
+}
+
+// The nav bubbles
+#imagelightbox-nav {
+ @include border-radius(20px);
+ @include translateX(-50%);
+
+ background-color: #444;
+ background-color: rgba(0, 0, 0, .5);
+ bottom: 60px; // 60
+ left: 50%;
+ padding: 5px 2px 1px;
+ position: fixed;
+ z-index: 10001;
+
+ a {
+ @include border-radius(50%);
+ border: 1px solid #fff;
+ display: inline-block;
+ height: 20px;
+ margin: 0 5px;
+ width: 20px;
+
+ .active {
+ background-color: #fff;
+ }
+ }
+}
+
+#imagelightbox-loading,
+#imagelightbox-overlay,
+#imagelightbox-close,
+#imagelightbox-caption,
+#imagelightbox-nav {
+ -moz-animation: fade-in .25s linear;
+ -o-animation: fade-in .25s linear;
+ -webkit-animation: fade-in .25s linear;
+ animation: fade-in .25s linear;
+}
+
+@-webkit-keyframes fade-in {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+
+@-moz-keyframes fade-in {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+
+@-o-keyframes fade-in {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+
+@keyframes fade-in {
+ 0% { opacity: 0; }
+ 100% { opacity: 1; }
+}
+
+@media only screen and (max-width: 660px) {
+ #imagelightbox-close {
+ right: 20px;
+ top: 20px;
+ }
+
+ #imagelightbox-nav {
+ bottom: 20px;
+ }
+}