1/*! 2 By André Rinas, www.andrerinas.de 3 Documentation, www.simplelightbox.de 4 Available for use under the MIT License 5 1.17.1 6*/ 7;( function( $, window, document, undefined ) 8{ 9 'use strict'; 10 11$.fn.simpleLightbox = function( options ) 12{ 13 14 var options = $.extend({ 15 sourceAttr: 'href', 16 overlay: true, 17 spinner: true, 18 nav: true, 19 navText: ['‹', '›'], 20 captions: true, 21 captionDelay: 0, 22 captionSelector: 'img', 23 captionType: 'attr', 24 captionsData: 'title', 25 captionPosition: 'bottom', 26 captionClass: '', 27 close: true, 28 closeText: 'Ã', 29 swipeClose: true, 30 showCounter: true, 31 fileExt: 'png|jpg|jpeg|gif|webp', 32 animationSlide: true, 33 animationSpeed: 250, 34 preloading: true, 35 enableKeyboard: true, 36 loop: true, 37 rel: false, 38 docClose: true, 39 swipeTolerance: 50, 40 className: 'simple-lightbox', 41 widthRatio: 0.85, 42 heightRatio: 0.9, 43 scaleImageToRatio: false, 44 disableRightClick: false, 45 disableScroll: true, 46 alertError: true, 47 alertErrorMessage: 'Image not found, next image will be loaded', 48 additionalHtml: false, 49 history: true, 50 throttleInterval: 0, 51 doubleTapZoom: 2, 52 maxZoom: 10, 53 htmlClass: 'has-lightbox' 54 }, options); 55 56 // global variables 57 var touchDevice = ( 'ontouchstart' in window ), 58 pointerEnabled = window.navigator.pointerEnabled || window.navigator.msPointerEnabled, 59 touched = function( event ){ 60 if( touchDevice ) return true; 61 if( !pointerEnabled || typeof event === 'undefined' || typeof event.pointerType === 'undefined' ) return false; 62 if( typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined' ) { 63 if( event.MSPOINTER_TYPE_MOUSE != event.pointerType ) return true; 64 } 65 else { 66 if( event.pointerType != 'mouse' ) return true; 67 } 68 return false; 69 }, 70 swipeDiff = 0, 71 swipeYDiff = 0, 72 curImg = $(), 73 transPrefix = function(){ 74 var s = document.body || document.documentElement; 75 s = s.style; 76 if( s.WebkitTransition === '' ) return '-webkit-'; 77 if( s.MozTransition === '' ) return '-moz-'; 78 if( s.OTransition === '' ) return '-o-'; 79 if( s.transition === '' ) return ''; 80 return false; 81 }, 82 opened = false, 83 loaded = [], 84 getRelated = function(rel, jqObj) { 85 var $related = jqObj.filter(function () { 86 return ($(this).attr('rel') === rel); 87 }); 88 return $related; 89 }, 90 objects = (options.rel && options.rel !== false) ? getRelated(options.rel, $(this)) : this, 91 tagname = objects.get()[0].tagName, 92 transPrefix = transPrefix(), 93 globalScrollbarwidth = 0, 94 canTransisions = (transPrefix !== false) ? true : false, 95 supportsPushState = ('pushState' in history), 96 historyhasChanged = false, 97 historyUpdateTimeout, 98 winLoc = window.location, 99 getHash = function(){ 100 return winLoc.hash.substring(1); 101 }, 102 initialHash = getHash(), 103 updateHash = function(){ 104 var hash = getHash(), 105 newHash = 'pid='+(index+1); 106 var newURL = winLoc.href.split('#')[0] + '#' + newHash; 107 108 if(supportsPushState){ 109 history[historyhasChanged ? 'replaceState' : 'pushState']('', document.title, newURL); 110 }else { 111 if(historyhasChanged) { 112 winLoc.replace( newURL ); 113 } else { 114 winLoc.hash = newHash; 115 } 116 } 117 historyhasChanged = true; 118 }, 119 resetHash = function() { 120 if (supportsPushState) { 121 history.pushState('', document.title, winLoc.pathname + winLoc.search ); 122 } else { 123 winLoc.hash = ''; 124 } 125 clearTimeout(historyUpdateTimeout); 126 127 }, 128 updateURL = function(){ 129 if(!historyhasChanged) { 130 updateHash(); // first time 131 } else { 132 historyUpdateTimeout = setTimeout(updateHash, 800); 133 } 134 }, 135 throttle = function(func, limit) { 136 var inThrottle; 137 return function() { 138 var args = arguments; 139 var context = this; 140 if (!inThrottle) { 141 func.apply(context, args); 142 inThrottle = true; 143 setTimeout(function() { 144 return inThrottle = false; 145 }, limit); 146 } 147 }; 148 }, 149 prefix = 'simplelb', 150 overlay = $('<div>').addClass('sl-overlay'), 151 closeBtn = $('<button>').addClass('sl-close').html(options.closeText),
152 spinner = $('<div>').addClass('sl-spinner').html('<div></div>'), 153 nav = $('<div>').addClass('sl-navigation').html('<button class="sl-prev">'+options.navText[0]+'</button><button class="sl-next">'+options.navText[1]+'</button>'), 154 counter = $('<div>').addClass('sl-counter').html('<span class="sl-current"></span>/<span class="sl-total"></span>'), 155 animating = false, 156 index = 0, 157 startIndex = 0, 158 caption = $('<div>').addClass('sl-caption '+options.captionClass+' pos-'+options.captionPosition), 159 image = $('<div>').addClass('sl-image'), 160 wrapper = $('<div>').addClass('sl-wrapper').addClass(options.className), 161 isValidLink = function( element ){ 162 if(!options.fileExt) return true; 163 var filEext = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gmi; 164 var testExt = $( element ).attr( options.sourceAttr ).match(filEext); 165 return testExt && $( element ).prop( 'tagName' ).toUpperCase() == tagname && ( new RegExp( '\.(' + options.fileExt + ')$', 'i' ) ).test( testExt ); 166 }, 167 setup = function(){ 168 if(options.close) closeBtn.appendTo(wrapper); 169 if(options.showCounter){ 170 if(objects.length > 1){ 171 counter.appendTo(wrapper); 172 counter.find('.sl-total').text(objects.length); 173 } 174 } 175 if(options.nav) nav.appendTo(wrapper); 176 if(options.spinner) spinner.appendTo(wrapper); 177 }, 178 openImage = function(elem){ 179 elem.trigger($.Event('show.simplelightbox')); 180 if(options.disableScroll) globalScrollbarwidth = handleScrollbar('hide'); 181 if(options.htmlClass && options.htmlClass != '') $('html').addClass(options.htmlClass); 182 wrapper.appendTo('body'); 183 image.appendTo(wrapper); 184 if(options.overlay) overlay.appendTo($('body')); 185 animating = true; 186 index = objects.index(elem); 187 curImg = $( '<img/>' ) 188 .hide() 189 .attr('src', elem.attr(options.sourceAttr)) 190 .attr('data-scale', 1) 191 .attr('data-translate-x', 0) 192 .attr('data-translate-y', 0); 193 if(loaded.indexOf(elem.attr(options.sourceAttr)) == -1){ 194 loaded.push(elem.attr(options.sourceAttr)); 195 } 196 image.html('').attr('style',''); 197 curImg.appendTo(image); 198 addEvents(); 199 overlay.fadeIn('fast'); 200 $('.sl-close').fadeIn('fast'); 201 spinner.show(); 202 nav.fadeIn('fast'); 203 $('.sl-wrapper .sl-counter .sl-current').text(index +1); 204 counter.fadeIn('fast'); 205 adjustImage(); 206 if(options.preloading) preload(); 207 setTimeout( function(){ elem.trigger($.Event('shown.simplelightbox')); } ,options.animationSpeed); 208 }, 209 adjustImage = function(dir){ 210 if(!curImg.length) return; 211 var tmpImage = new Image(), 212 windowWidth = window.innerWidth * options.widthRatio, 213 windowHeight = window.innerHeight * options.heightRatio; 214 tmpImage.src = curImg.attr( 'src' ); 215 curImg.data('scale',1); 216 curImg.data('translate-x',0); 217 curImg.data('translate-y',0); 218 zoomPanElement(0,0,1); 219 $(tmpImage).on('error',function(ev){ 220 //no image was found 221 objects.eq(index).trigger($.Event('error.simplelightbox')); 222 animating = false; 223 opened = true; 224 spinner.hide(); 225 var dirDefinined = (dir == 1 || dir == -1); 226 if(startIndex === index && dirDefinined){ 227 close(); 228 return; 229 } 230 if(options.alertError){ 231 alert(options.alertErrorMessage); 232 } 233 if(dirDefinined){ 234 loadImage(dir); 235 } else { 236 loadImage(1); 237 } 238 return; 239 }); 240 241 242 tmpImage.onload = function() { 243 if (typeof dir !== 'undefined') { 244 objects.eq(index) 245 .trigger($.Event('changed.simplelightbox')) 246 .trigger($.Event( (dir===1?'nextDone':'prevDone')+'.simplelightbox')); 247 } 248 249 // history 250 if(options.history){ 251 updateURL(); 252 } 253 254 if(loaded.indexOf(curImg.attr( 'src' )) == -1){ 255 loaded.push(curImg.attr( 'src' )); 256 } 257 var imageWidth = tmpImage.width, 258 imageHeight = tmpImage.height; 259 260 if( options.scaleImageToRatio || imageWidth > windowWidth || imageHeight > windowHeight ){ 261 var ratio = imageWidth / imageHeight > windowWidth / windowHeight ? imageWidth / windowWidth : imageHeight / windowHeight; 262 imageWidth /= ratio; 263 imageHeight /= ratio; 264 } 265 266 $('.sl-image').css({ 267 'top': ( window.innerHeight - imageHeight ) / 2 + 'px', 268 'left': ( window.innerWidth - imageWidth - globalScrollbarwidth)/ 2 + 'px', 269 'width': imageWidth + 'px', 270 'height': imageHeight + 'px' 271 }); 272 spinner.hide(); 273 curImg 274 .fadeIn('fast'); 275 opened = true; 276 var cSel = (options.captionSelector == 'self') ? objects.eq(index) : objects.eq(index).find(options.captionSelector); 277 var captionText; 278 if(options.captionType == 'data'){ 279 captionText = cSel.data(options.captionsData); 280 } else if(options.captionType == 'text'){ 281 captionText = cSel.html(); 282 } else { 283 captionText = cSel.prop(options.captionsData); 284 } 285 286 if(!options.loop) { 287 if(index === 0){ $('.sl-prev').hide();} 288 if(index >= objects.length -1) {$('.sl-next').hide();} 289 if(index > 0){ $('.sl-prev').show(); } 290 if(index < objects.length -1){ $('.sl-next').show(); } 291 } 292 293 if(objects.length == 1) $('.sl-prev, .sl-next').hide(); 294 295 if(dir == 1 || dir == -1){ 296 var css = { 'opacity': 1.0 }; 297 if( options.animationSlide ) { 298 if( canTransisions ) { 299 slide(0, 100 * dir + 'px'); 300 setTimeout( function(){ slide( options.animationSpeed / 1000, 0 + 'px'); }, 50 ); 301 } 302 else { 303 css.left = parseInt( $('.sl-image').css( 'left' ) ) + 100 * dir + 'px'; 304 } 305 } 306 307 $('.sl-image').animate( css, options.animationSpeed, function(){ 308 animating = false;
309 setCaption(captionText, imageWidth); 310 }); 311 } else { 312 animating = false; 313 setCaption(captionText, imageWidth); 314 } 315 if(options.additionalHtml && $('.sl-additional-html').length === 0){ 316 $('<div>').html(options.additionalHtml).addClass('sl-additional-html').appendTo($('.sl-image')); 317 } 318 }; 319 }, 320 setCaption = function(captiontext, imageWidth){ 321 if(captiontext !== '' && typeof captiontext !== "undefined" && options.captions){ 322 caption.html(captiontext).css({'width': imageWidth + 'px'}).hide().appendTo($('.sl-image')).delay(options.captionDelay).fadeIn('fast'); 323 } 324 }, 325 slide = function(speed, pos){ 326 var styles = {}; 327 styles[transPrefix + 'transform'] = 'translateX(' + pos + ')'; 328 styles[transPrefix + 'transition'] = transPrefix + 'transform ' + speed + 's linear'; 329 $('.sl-image').css(styles); 330 }, 331 zoomPanElement = function(targetOffsetX, targetOffsetY, targetScale) { 332 var styles = {}; 333 styles[transPrefix + 'transform'] = 'translate(' + targetOffsetX + ',' + targetOffsetY+ ') scale('+targetScale+')'; 334 curImg.css(styles); 335 }, 336 minMax = function(value, min, max) { 337 return (value < min) ? min : (value > max) ? max : value; 338 }, 339 setZoomData = function(initialScale,targetOffsetX,targetOffsetY) { 340 curImg.data('scale',initialScale); 341 curImg.data('translate-x',targetOffsetX); 342 curImg.data('translate-y',targetOffsetY); 343 }, 344 addEvents = function(){ 345 // resize/responsive 346 $( window ).on( 'resize.'+prefix, adjustImage ); 347 348 // close lightbox on close btn 349 $( document ).on('click.'+prefix+ ' touchstart.'+prefix, '.sl-close', function(e){ 350 e.preventDefault(); 351 if(opened){ close();} 352 }); 353 354 if(options.history){ 355 setTimeout(function() { 356 $(window).on('hashchange.'+prefix,function(){ 357 if(opened){ 358 if(getHash() === initialHash) { 359 close(); 360 return; 361 } 362 } 363 }); 364 }, 40); 365 } 366 367 // nav-buttons 368 nav.on('click.'+prefix, 'button', throttle(function(e){ 369 e.preventDefault(); 370 swipeDiff = 0; 371 loadImage( $(this).hasClass('sl-next') ? 1 : -1 ); 372 }, options.throttleInterval)); 373 374 // touch helpers 375 var swipeStart = 0, 376 swipeEnd = 0, 377 swipeYStart = 0, 378 swipeYEnd = 0, 379 zoomed = false, 380 mousedown = false, 381 imageLeft = 0, 382 containerHeight, 383 containerWidth, 384 containerOffsetX, 385 containerOffsetY, 386 imgHeight, 387 imgWidth, 388 capture = false, 389 initialOffsetX, 390 initialOffsetY, 391 initialPointerOffsetX, 392 initialPointerOffsetY, 393 initialPointerOffsetX2, 394 initialPointerOffsetY2, 395 initialScale = minMax(1, 1, options.maxZoom), 396 initialPinchDistance, 397 pointerOffsetX, 398 pointerOffsetY, 399 pointerOffsetX2, 400 pointerOffsetY2, 401 targetOffsetX, 402 targetOffsetY, 403 targetScale, 404 pinchOffsetX, 405 pinchOffsetY, 406 limitOffsetX, 407 limitOffsetY, 408 scaleDifference, 409 targetPinchDistance, 410 touchCount, 411 doubleTapped = false, 412 touchmoveCount = 0; 413 414 image 415 .on( 'touchstart.'+prefix+' mousedown.'+prefix, function(e) 416 { 417 if (e.target.tagName === 'A' && e.type == 'touchstart') { 418 return true; 419 } 420 e = e.originalEvent; 421 if(e.type == 'mousedown') { 422 initialPointerOffsetX = e.clientX; 423 initialPointerOffsetY = e.clientY; 424 containerHeight = image.height(); 425 containerWidth = image.width(); 426 imgHeight = curImg.height(); 427 imgWidth = curImg.width(); 428 containerOffsetX = image.position().left; 429 containerOffsetY = image.position().top; 430 431 initialOffsetX = parseFloat(curImg.data('translate-x')); 432 initialOffsetY = parseFloat(curImg.data('translate-y')); 433 434 capture = true; 435 } else { 436 touchCount = e.touches.length; 437 initialPointerOffsetX = e.touches[0].clientX; 438 initialPointerOffsetY = e.touches[0].clientY; 439 containerHeight = image.height(); 440 containerWidth = image.width(); 441 imgHeight = curImg.height(); 442 imgWidth = curImg.width(); 443 containerOffsetX = image.position().left; 444 containerOffsetY = image.position().top; 445 446 if (touchCount === 1) /* Single touch */ { 447 if(!doubleTapped) { 448 doubleTapped = true; 449 setTimeout(function(){ 450 doubleTapped = false;
451 }, 300); 452 } else { 453 curImg.addClass('sl-transition'); 454 if(!zoomed) { 455 initialScale = options.doubleTapZoom; 456 setZoomData(0,0, initialScale); 457 zoomPanElement(0 + "px", 0 + "px", initialScale); 458 $('.sl-caption').fadeOut(200); 459 zoomed = true; 460 } else { 461 initialScale = 1; 462 setZoomData(0,0,initialScale); 463 zoomPanElement(0 + "px", 0 + "px", initialScale); 464 zoomed = false; 465 } 466 467 setTimeout(function(){ 468 curImg.removeClass('sl-transition'); 469 }, 200); 470 return false; 471 } 472 473 initialOffsetX = parseFloat(curImg.data('translate-x')); 474 initialOffsetY = parseFloat(curImg.data('translate-y')); 475 } 476 else if (touchCount === 2) /* Pinch */ { 477 initialPointerOffsetX2 = e.touches[1].clientX; 478 initialPointerOffsetY2 = e.touches[1].clientY; 479 initialOffsetX = parseFloat(curImg.data('translate-x')); 480 initialOffsetY = parseFloat(curImg.data('translate-y')); 481 pinchOffsetX = (initialPointerOffsetX + initialPointerOffsetX2) / 2; 482 pinchOffsetY = (initialPointerOffsetY + initialPointerOffsetY2) / 2; 483 initialPinchDistance = Math.sqrt(((initialPointerOffsetX - initialPointerOffsetX2) * (initialPointerOffsetX - initialPointerOffsetX2)) + ((initialPointerOffsetY - initialPointerOffsetY2) * (initialPointerOffsetY - initialPointerOffsetY2))); 484 } 485 capture = true; 486 } 487 488 if(mousedown) return true; 489 if( canTransisions ) imageLeft = parseInt( image.css( 'left' ) ); 490 mousedown = true; 491 swipeDiff = 0; 492 swipeYDiff = 0; 493 swipeStart = e.pageX || e.touches[ 0 ].pageX; 494 swipeYStart = e.pageY || e.touches[ 0 ].pageY; 495 return false; 496 }) 497 .on( 'touchmove.'+prefix+' mousemove.'+prefix+' MSPointerMove', function(e) 498 { 499 if(!mousedown) return true; 500 e.preventDefault(); 501 e = e.originalEvent; 502 /* Initialize helpers */ 503 if(e.type == 'touchmove') { 504 if(capture === false) return false; 505 pointerOffsetX = e.touches[0].clientX; 506 pointerOffsetY = e.touches[0].clientY; 507 touchCount = e.touches.length; 508 touchmoveCount++; 509 510 if (touchCount > 1) /* Pinch */ { 511 pointerOffsetX2 = e.touches[1].clientX; 512 pointerOffsetY2 = e.touches[1].clientY; 513 targetPinchDistance = Math.sqrt(((pointerOffsetX - pointerOffsetX2) * (pointerOffsetX - pointerOffsetX2)) + ((pointerOffsetY - pointerOffsetY2) * (pointerOffsetY - pointerOffsetY2))); 514 if (initialPinchDistance === null) { 515 initialPinchDistance = targetPinchDistance; 516 } 517 518 if (Math.abs(initialPinchDistance - targetPinchDistance) >= 1) { 519 /* Initialize helpers */ 520 targetScale = minMax(targetPinchDistance / initialPinchDistance * initialScale, 1, options.maxZoom); 521 limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2; 522 limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2; 523 scaleDifference = targetScale - initialScale; 524 targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0: minMax(initialOffsetX - ((((((pinchOffsetX - containerOffsetX) - (containerWidth / 2)) - initialOffsetX) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetX * (-1), limitOffsetX); 525 targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(initialOffsetY - ((((((pinchOffsetY - containerOffsetY) - (containerHeight / 2)) - initialOffsetY) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetY * (-1), limitOffsetY); 526 527 zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale); 528 529 if (targetScale > 1) { 530 zoomed = true; 531 $('.sl-caption').fadeOut(200); 532 } 533 534 initialPinchDistance = targetPinchDistance; 535 initialScale = targetScale; 536 initialOffsetX = targetOffsetX; 537 initialOffsetY = targetOffsetY; 538 } 539 } else { 540 targetScale = initialScale; 541 limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2; 542 limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2; 543 targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX); 544 targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY); 545 546 if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) { 547 initialOffsetX = targetOffsetX; 548 initialPointerOffsetX = pointerOffsetX; 549 } 550 551 if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) { 552 initialOffsetY = targetOffsetY; 553 initialPointerOffsetY = pointerOffsetY; 554 } 555 556 setZoomData(initialScale,targetOffsetX,targetOffsetY); 557 zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale); 558 } 559 } 560 /* Mouse Move implementation */ 561 if(e.type == 'mousemove' && mousedown){ 562 if(e.type == 'touchmove') return true; 563 if(capture === false) return false;
564 pointerOffsetX = e.clientX; 565 pointerOffsetY = e.clientY; 566 targetScale = initialScale; 567 limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2; 568 limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2; 569 targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX); 570 targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY); 571 572 if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) { 573 initialOffsetX = targetOffsetX; 574 initialPointerOffsetX = pointerOffsetX; 575 } 576 577 if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) { 578 initialOffsetY = targetOffsetY; 579 initialPointerOffsetY = pointerOffsetY; 580 } 581 582 setZoomData(initialScale,targetOffsetX,targetOffsetY); 583 zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale); 584 } 585 if(!zoomed) { 586 swipeEnd = e.pageX || e.touches[ 0 ].pageX; 587 swipeYEnd = e.pageY || e.touches[ 0 ].pageY; 588 swipeDiff = swipeStart - swipeEnd; 589 swipeYDiff = swipeYStart - swipeYEnd; 590 if( options.animationSlide ) { 591 if( canTransisions ) slide( 0, -swipeDiff + 'px' ); 592 else image.css( 'left', imageLeft - swipeDiff + 'px' ); 593 } 594 } 595 }) 596 .on( 'touchend.'+prefix+' mouseup.'+prefix+' touchcancel.'+prefix+' mouseleave.'+prefix+' pointerup pointercancel MSPointerUp MSPointerCancel',function(e) 597 { 598 e = e.originalEvent; 599 if(touchDevice && e.type =='touchend') { 600 touchCount = e.touches.length; 601 if (touchCount === 0) /* No touch */ { 602 /* Set attributes */ 603 setZoomData(initialScale,targetOffsetX,targetOffsetY); 604 if(initialScale == 1) { 605 zoomed = false; 606 $('.sl-caption').fadeIn(200); 607 } 608 initialPinchDistance = null; 609 capture = false; 610 } else if (touchCount === 1) /* Single touch */ { 611 initialPointerOffsetX = e.touches[0].clientX; 612 initialPointerOffsetY = e.touches[0].clientY; 613 } else if (touchCount > 1) /* Pinch */ { 614 initialPinchDistance = null; 615 } 616 } 617 618 if(mousedown){ 619 mousedown = false; 620 var possibleDir = true; 621 if(!options.loop) { 622 if(index === 0 && swipeDiff < 0){ possibleDir = false; } 623 if(index >= objects.length -1 && swipeDiff > 0) { possibleDir = false; } 624 } 625 if( Math.abs( swipeDiff ) > options.swipeTolerance && possibleDir ) { 626 loadImage( swipeDiff > 0 ? 1 : -1 ); 627 } 628 else if( options.animationSlide ) 629 { 630 if( canTransisions ) slide( options.animationSpeed / 1000, 0 + 'px' ); 631 else image.animate({ 'left': imageLeft + 'px' }, options.animationSpeed / 2 ); 632 } 633 634 if( options.swipeClose && Math.abs(swipeYDiff) > 50 && Math.abs( swipeDiff ) < options.swipeTolerance) { 635 close(); 636 } 637 } 638 }) 639 /** Detect Double click on image*/ 640 .on( 'dblclick', function(e) 641 { 642 initialPointerOffsetX = e.clientX; 643 initialPointerOffsetY = e.clientY; 644 containerHeight = image.height(); 645 containerWidth = image.width(); 646 imgHeight = curImg.height(); 647 imgWidth = curImg.width(); 648 containerOffsetX = image.position().left; 649 containerOffsetY = image.position().top; 650 651 curImg.addClass('sl-transition'); 652 if(!zoomed) { 653 initialScale = options.doubleTapZoom; 654 setZoomData(0,0, initialScale); 655 zoomPanElement(0 + "px", 0 + "px", initialScale); 656 $('.sl-caption').fadeOut(200); 657 zoomed = true; 658 } else { 659 initialScale = 1; 660 setZoomData(0,0,initialScale); 661 zoomPanElement(0 + "px", 0 + "px", initialScale); 662 zoomed = false; 663 } 664 665 setTimeout(function(){ 666 curImg.removeClass('sl-transition'); 667 }, 200); 668 capture = true; 669 return false; 670 }); 671 }, 672 removeEvents = function(){ 673 nav.off('click', 'button'); 674 $( document ).off('click.'+prefix, '.sl-close'); 675 $( window ).off( 'resize.'+prefix); 676 $( window ).off( 'hashchange.'+prefix); 677 }, 678 preload = function(){ 679 var next = (index+1 < 0) ? objects.length -1: (index+1 >= objects.length -1) ? 0 : index+1, 680 prev = (index-1 < 0) ? objects.length -1: (index-1 >= objects.length -1) ? 0 : index-1; 681 $( '<img />' ).attr( 'src', objects.eq(next).attr( options.sourceAttr ) ).on('load', function(){ 682 if(loaded.indexOf($(this).attr('src')) == -1){ 683 loaded.push($(this).attr('src')); 684 } 685 objects.eq(index).trigger($.Event('nextImageLoaded.simplelightbox')); 686 }); 687 $( '<img />' ).attr( 'src', objects.eq(prev).attr( options.sourceAttr ) ).on('load', function(){ 688 if(loaded.indexOf($(this).attr('src')) == -1){ 689 loaded.push($(this).attr('src')); 690 } 691 objects.eq(index).trigger($.Event('prevImageLoaded.simplelightbox')); 692 }); 693 694 }, 695 loadImage = function(dir){ 696 objects.eq(index) 697 .trigger($.Event('change.simplelightbox')) 698 .trigger($.Event( (dir===1?'next':'prev')+'.simplelightbox')); 699 700 var newIndex = index + dir; 701 if(animating || (newIndex < 0 || newIndex >= objects.length) && options.loop === false ) return; 702 index = (newIndex < 0) ? objects.length -1: (newIndex > objects.length -1) ? 0 : newIndex; 703 $('.sl-wrapper .sl-counter .sl-current').text(index +1); 704 var css = { 'opacity': 0 }; 705 if( options.animationSlide ) { 706 if( canTransisions ) slide(options.animationSpeed / 1000, ( -100 * dir ) - swipeDiff + 'px'); 707 else css.left = parseInt( $('.sl-image').css( 'left' ) ) + -100 * dir + 'px'; 708 } 709 710 $('.sl-image').animate( css, options.animationSpeed, function(){ 711 setTimeout( function(){ 712 // fadeout old image 713 var elem = objects.eq(index); 714 curImg 715 .attr('src', elem.attr(options.sourceAttr)); 716 717 if(loaded.indexOf(elem.attr(options.sourceAttr)) == -1){ 718 spinner.show(); 719 } 720 $('.sl-caption').remove(); 721 adjustImage(dir); 722 if(options.preloading) preload(); 723 }, 100); 724 }); 725 }, 726 close = function(){ 727 if(animating) return; 728 var elem = objects.eq(index), 729 triggered = false;
730 731 elem.trigger($.Event('close.simplelightbox')); 732 if(options.history){ 733 resetHash(); 734 } 735 $('.sl-image img, .sl-overlay, .sl-close, .sl-navigation, .sl-image .sl-caption, .sl-counter').fadeOut('fast', function(){ 736 if(options.disableScroll) handleScrollbar('show'); 737 if(options.htmlClass && options.htmlClass != '') $('html').removeClass(options.htmlClass); 738 $('.sl-wrapper, .sl-overlay').remove(); 739 removeEvents(); 740 if(!triggered) elem.trigger($.Event('closed.simplelightbox')); 741 triggered = true; 742 }); 743 curImg = $(); 744 opened = false; 745 animating = false; 746 }, 747 handleScrollbar = function(type){ 748 var scrollbarWidth = 0; 749 if(type == 'hide'){ 750 var fullWindowWidth = window.innerWidth; 751 if (!fullWindowWidth) { 752 var documentElementRect = document.documentElement.getBoundingClientRect(); 753 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left); 754 } 755 if(document.body.clientWidth < fullWindowWidth){ 756 var scrollDiv = document.createElement('div'), 757 padding = parseInt($('body').css('padding-right'),10); 758 scrollDiv.className = 'sl-scrollbar-measure'; 759 $('body').append(scrollDiv); 760 scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; 761 $(document.body)[0].removeChild(scrollDiv); 762 $('body').data('padding',padding); 763 if(scrollbarWidth > 0){ 764 $('body').addClass('hidden-scroll').css({'padding-right':padding+scrollbarWidth}); 765 } 766 } 767 } else { 768 $('body').removeClass('hidden-scroll').css({'padding-right':$('body').data('padding')}); 769 } 770 return scrollbarWidth; 771 }; 772 773 // events 774 setup(); 775 776 // open lightbox 777 objects.on( 'click.'+prefix, function( e ){ 778 if(isValidLink(this)){ 779 e.preventDefault(); 780 if(animating) return false; 781 var elem = $(this); 782 startIndex = objects.index(elem); 783 openImage(elem); 784 } 785 }); 786 787 // close on click on doc 788 $( document ).on('click.'+prefix+ ' touchstart.'+prefix, function(e){ 789 if(opened){ 790 if((options.docClose && $(e.target).closest('.sl-image').length === 0 && $(e.target).closest('.sl-navigation').length === 0)){ 791 close(); 792 } 793 } 794 }); 795 796 // disable rightclick 797 if(options.disableRightClick){ 798 $( document ).on('contextmenu', '.sl-image img', function(e){ 799 return false; 800 }); 801 } 802 803 804 // keyboard-control 805 if( options.enableKeyboard ){ 806 $( document ).on( 'keyup.'+prefix, throttle(function( e ){ 807 swipeDiff = 0; 808 // keyboard control only if lightbox is open 809 var key = e.keyCode; 810 if(animating && key == 27) { 811 curImg.attr('src', ''); 812 animating = false; 813 close(); 814 } 815 816 if(opened){ 817 e.preventDefault(); 818 if( key == 27 ) { 819 close(); 820 } 821 if( key == 37 || e.keyCode == 39 ) { 822 loadImage( e.keyCode == 39 ? 1 : -1 ); 823 } 824 } 825 }, options.throttleInterval)); 826 } 827 828 // Public methods 829 this.open = function(elem){ 830 elem = elem || $(this[0]); 831 startIndex = objects.index(elem); 832 openImage(elem); 833 }; 834 835 this.next = function(){ 836 loadImage( 1 ); 837 }; 838 839 this.prev = function(){ 840 loadImage( -1 ); 841 }; 842 843 this.close = function(){ 844 close(); 845 }; 846 847 this.destroy = function(){ 848 $( document ).off('click.'+prefix).off('keyup.'+prefix); 849 close(); 850 $('.sl-overlay, .sl-wrapper').remove(); 851 this.off('click'); 852 }; 853 854 this.refresh = function(){ 855 this.destroy(); 856 $(this).simpleLightbox(options); 857 }; 858 859 return this; 860 861}; 862})( jQuery, window, document );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.