1/* 2 Based on Simple Lightbox by André Rinas, www.andrerinas.de 3 https://github.com/andreknieriem/simplelightbox 4 Available for use under the MIT License 5 1.15.1 6*/ 7;( function( $, window, document, undefined ) 8{ 9 'use strict'; 10 11 window.jetslothLightboxDefaults = gform.applyFilters('gfic_lightbox_defaults', { 12 sourceAttr: 'href', 13 overlay: true, 14 spinner: true, 15 nav: true, 16 navText: ['‹', '›'], 17 captions: true, 18 captionDelay: 0, 19 captionSelector: 'self', 20 captionType: 'attr', 21 captionsData: 'title', 22 captionPosition: 'bottom', 23 captionClass: '', 24 close: true, 25 closeText: 'Ã', 26 swipeClose: true, 27 showCounter: true, 28 fileExt: 'png|jpg|jpeg|gif|webp', 29 animationSlide: true, 30 animationSpeed: 250, 31 preloading: true, 32 enableKeyboard: true, 33 enableSwipe: true, 34 loop: true, 35 rel: false, 36 docClose: true, 37 swipeTolerance: 50, 38 className: 'jetsloth-lightbox', 39 widthRatio: 0.8, 40 heightRatio: 0.9, 41 scaleImageToRatio: false, 42 disableRightClick: false, 43 disableScroll: true, 44 alertError: true, 45 alertErrorMessage: 'Image not found, next image will be loaded', 46 additionalHtml: false, 47 history: true, 48 throttleInterval: 0 49 }); 50
51$.fn.jetslothLightbox = function( options ) 52{ 53 54 var options = $.extend(window.jetslothLightboxDefaults, 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 transPrefix = transPrefix(), 92 globalScrollbarwidth = 0, 93 canTransisions = (transPrefix !== false) ? true : false, 94 supportsPushState = ('pushState' in history), 95 historyhasChanged = false, 96 historyUpdateTimeout, 97 winLoc = window.location, 98 getHash = function(){ 99 return winLoc.hash.substring(1); 100 }, 101 initialHash = getHash(), 102 updateHash = function(){ 103 var hash = getHash(), 104 newHash = 'pid='+(index+1); 105 var newURL = winLoc.href.split('#')[0] + '#' + newHash; 106 107 if(supportsPushState){ 108 history[historyhasChanged ? 'replaceState' : 'pushState']('', document.title, newURL); 109 }else { 110 if(historyhasChanged) { 111 winLoc.replace( newURL ); 112 } else { 113 winLoc.hash = newHash; 114 } 115 } 116 historyhasChanged = true; 117 }, 118 resetHash = function() { 119 if (supportsPushState) { 120 history.pushState('', document.title, winLoc.pathname + winLoc.search ); 121 } else { 122 winLoc.hash = ''; 123 } 124 clearTimeout(historyUpdateTimeout); 125 126 }, 127 updateURL = function(){ 128 if(!historyhasChanged) { 129 updateHash(); // first time 130 } else { 131 historyUpdateTimeout = setTimeout(updateHash, 800); 132 } 133 }, 134 throttle = function(func, limit) { 135 var inThrottle; 136 return function() { 137 var args = arguments; 138 var context = this; 139 if (!inThrottle) { 140 func.apply(context, args); 141 inThrottle = true; 142 setTimeout(function() { 143 return inThrottle = false; 144 }, limit); 145 } 146 }; 147 }, 148 prefix = 'jetslothlb', 149 overlay = $('<div>').addClass('jl-overlay'), 150 closeBtn = $('<button>').addClass('jl-close').html(options.closeText),
151 spinner = $('<div>').addClass('jl-spinner').html('<div></div>'), 152 nav = $('<div>').addClass('jl-navigation').html('<button class="jl-prev">'+options.navText[0]+'</button><button class="jl-next">'+options.navText[1]+'</button>'), 153 counter = $('<div>').addClass('jl-counter').html('<span class="jl-current"></span>/<span class="jl-total"></span>'), 154 animating = false, 155 index = 0, 156 startIndex = 0, 157 caption = $('<div>').addClass('jl-caption '+options.captionClass+' pos-'+options.captionPosition), 158 image = $('<div>').addClass('jl-image'), 159 wrapper = $('<div>').addClass('jl-wrapper').addClass(options.className), 160 isValidLink = function( element ){ 161 if(!options.fileExt) return true; 162 var filEext = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gmi; 163 var testExt = $( element ).attr( options.sourceAttr ).match(filEext); 164 return testExt && $( element ).prop( 'tagName' ).toLowerCase() == 'a' && ( new RegExp( '\.(' + options.fileExt + ')$', 'i' ) ).test( testExt ); 165 }, 166 setup = function(){ 167 if(options.close) closeBtn.appendTo(wrapper); 168 if(options.showCounter){ 169 if(objects.length > 1){ 170 counter.appendTo(wrapper); 171 counter.find('.jl-total').text(objects.length); 172 } 173 } 174 if(options.nav) nav.appendTo(wrapper); 175 if(options.spinner) spinner.appendTo(wrapper); 176 }, 177 openImage = function(elem){ 178 elem.trigger($.Event('show.jetslothlightbox')); 179 if(options.disableScroll) globalScrollbarwidth = handleScrollbar('hide'); 180 wrapper.appendTo('body'); 181 image.appendTo(wrapper); 182 if(options.overlay) overlay.appendTo($('body')); 183 animating = true; 184 index = objects.index(elem); 185 curImg = $( '<img/>' ) 186 .hide() 187 .attr('src', elem.attr(options.sourceAttr)); 188 if(loaded.indexOf(elem.attr(options.sourceAttr)) == -1){ 189 loaded.push(elem.attr(options.sourceAttr)); 190 } 191 image.html('').attr('style',''); 192 curImg.appendTo(image); 193 addEvents(); 194 overlay.fadeIn('fast'); 195 $('.jl-close').fadeIn('fast'); 196 spinner.show(); 197 nav.fadeIn('fast'); 198 $('.jl-wrapper .jl-counter .jl-current').text(index +1); 199 counter.fadeIn('fast'); 200 adjustImage(); 201 if(options.preloading) preload(); 202 setTimeout( function(){ elem.trigger($.Event('shown.jetslothlightbox')); } ,options.animationSpeed); 203 }, 204 adjustImage = function(dir){ 205 if(!curImg.length) return; 206 var tmpImage = new Image(), 207 windowWidth = window.innerWidth * options.widthRatio, 208 windowHeight = window.innerHeight * options.heightRatio; 209 tmpImage.src = curImg.attr( 'src' ); 210 211 $(tmpImage).on('error',function(ev){ 212 //no image was found 213 objects.eq(index).trigger($.Event('error.jetslothlightbox')); 214 animating = false; 215 opened = true; 216 spinner.hide(); 217 var dirDefinined = (dir == 1 || dir == -1); 218 if(startIndex === index && dirDefinined){ 219 close(); 220 return; 221 } 222 if(options.alertError){ 223 alert(options.alertErrorMessage); 224 } 225 if(dirDefinined){ 226 loadImage(dir); 227 } else { 228 loadImage(1); 229 } 230 return; 231 }); 232 233 234 tmpImage.onload = function() { 235 if (typeof dir !== 'undefined') { 236 objects.eq(index) 237 .trigger($.Event('changed.jetslothlightbox')) 238 .trigger($.Event( (dir===1?'nextDone':'prevDone')+'.jetslothlightbox')); 239 } 240 241 // history 242 if(options.history){ 243 updateURL(); 244 } 245 246 if(loaded.indexOf(curImg.attr( 'src' )) == -1){ 247 loaded.push(curImg.attr( 'src' )); 248 } 249 var imageWidth = tmpImage.width, 250 imageHeight = tmpImage.height; 251 252 if( options.scaleImageToRatio || imageWidth > windowWidth || imageHeight > windowHeight ){ 253 var ratio = imageWidth / imageHeight > windowWidth / windowHeight ? imageWidth / windowWidth : imageHeight / windowHeight; 254 imageWidth /= ratio; 255 imageHeight /= ratio; 256 } 257 258 $('.jl-image').css({ 259 'top': ( window.innerHeight - imageHeight ) / 2 + 'px', 260 'left': ( window.innerWidth - imageWidth - globalScrollbarwidth)/ 2 + 'px' 261 }); 262 spinner.hide(); 263 curImg 264 .css({ 265 'width': imageWidth + 'px', 266 'height': imageHeight + 'px' 267 }) 268 .fadeIn('fast'); 269 opened = true; 270 var cSel = (options.captionSelector == 'self') ? objects.eq(index) : objects.eq(index).find(options.captionSelector); 271 var captionText; 272 if(options.captionType == 'data'){ 273 captionText = cSel.data(options.captionsData); 274 } else if(options.captionType == 'text'){ 275 captionText = cSel.html(); 276 } else { 277 captionText = cSel.prop(options.captionsData); 278 } 279 280 if(!options.loop) { 281 if(index === 0){ $('.jl-prev').hide();} 282 if(index >
282= objects.length -1) {$('.jl-next').hide();} 283 if(index > 0){ $('.jl-prev').show(); } 284 if(index < objects.length -1){ $('.jl-next').show(); } 285 } 286 287 if(objects.length == 1) $('.jl-prev, .jl-next').hide(); 288 289 if(dir == 1 || dir == -1){ 290 var css = { 'opacity': 1.0 }; 291 if( options.animationSlide ) { 292 if( canTransisions ) { 293 slide(0, 100 * dir + 'px'); 294 setTimeout( function(){ slide( options.animationSpeed / 1000, 0 + 'px'); }, 50 ); 295 } 296 else { 297 css.left = parseInt( $('.jl-image').css( 'left' ) ) + 100 * dir + 'px'; 298 } 299 } 300 301 $('.jl-image').animate( css, options.animationSpeed, function(){ 302 animating = false; 303 setCaption(captionText, imageWidth); 304 }); 305 } else { 306 animating = false; 307 setCaption(captionText, imageWidth); 308 } 309 if(options.additionalHtml && $('.jl-additional-html').length === 0){ 310 $('<div>').html(options.additionalHtml).addClass('jl-additional-html').appendTo($('.jl-image')); 311 } 312 }; 313 }, 314 setCaption = function(captiontext, imageWidth){ 315 if(captiontext !== '' && typeof captiontext !== "undefined" && options.captions){ 316 caption.html(captiontext).css({'width': imageWidth + 'px'}).hide().appendTo($('.jl-image')).delay(options.captionDelay).fadeIn('fast'); 317 } 318 }, 319 slide = function(speed, pos){ 320 var styles = {}; 321 styles[transPrefix + 'transform'] = 'translateX(' + pos + ')'; 322 styles[transPrefix + 'transition'] = transPrefix + 'transform ' + speed + 's linear'; 323 $('.jl-image').css(styles); 324 }, 325 addEvents = function(){ 326 // resize/responsive 327 $( window ).on( 'resize.'+prefix, adjustImage ); 328 329 // close lightbox on close btn 330 $( document ).on('click.'+prefix+ ' touchstart.'+prefix, '.jl-close', function(e){ 331 e.preventDefault(); 332 if(opened){ close();} 333 }); 334 335 if(options.history){ 336 setTimeout(function() { 337 $(window).on('hashchange.'+prefix,function(){ 338 if(opened){ 339 if(getHash() === initialHash) { 340 close(); 341 return; 342 } 343 } 344 }); 345 }, 40); 346 } 347 348 // nav-buttons 349 nav.on('click.'+prefix, 'button', throttle(function(e){ 350 e.preventDefault(); 351 swipeDiff = 0; 352 loadImage( $(this).hasClass('jl-next') ? 1 : -1 ); 353 }, options.throttleInterval)); 354 355 // touchcontrols 356 var swipeStart = 0, 357 swipeEnd = 0, 358 swipeYStart = 0, 359 swipeYEnd = 0, 360 mousedown = false, 361 imageLeft = 0; 362 363 if ( options.enableSwipe ) { 364 365 image 366 .on( 'touchstart.'+prefix+' mousedown.'+prefix, function(e) 367 { 368 if(mousedown) return true; 369 if( canTransisions ) imageLeft = parseInt( image.css( 'left' ) ); 370 mousedown = true; 371 swipeDiff = 0; 372 swipeYDiff = 0; 373 swipeStart = e.originalEvent.pageX || e.originalEvent.touches[ 0 ].pageX; 374 swipeYStart = e.originalEvent.pageY || e.originalEvent.touches[ 0 ].pageY; 375 return false; 376 }) 377 .on( 'touchmove.'+prefix+' mousemove.'+prefix+' pointermove MSPointerMove', function(e) 378 { 379 if(!mousedown) return true; 380 e.preventDefault(); 381 swipeEnd = e.originalEvent.pageX || e.originalEvent.touches[ 0 ].pageX; 382 swipeYEnd = e.originalEvent.pageY || e.originalEvent.touches[ 0 ].pageY; 383 swipeDiff = swipeStart - swipeEnd; 384 swipeYDiff = swipeYStart - swipeYEnd; 385 if( options.animationSlide ) { 386 if( canTransisions ) slide( 0, -swipeDiff + 'px' ); 387 else image.css( 'left', imageLeft - swipeDiff + 'px' ); 388 } 389 }) 390 .on( 'touchend.'+prefix+' mouseup.'+prefix+' touchcancel.'+prefix+' mouseleave.'+prefix+' pointerup pointercancel MSPointerUp MSPointerCancel',function(e) 391 { 392 if(mousedown){ 393 mousedown = false; 394 var possibleDir = true; 395 if(!options.loop) { 396 if(index === 0 && swipeDiff < 0){ possibleDir = false; } 397 if(index >= objects.length -1 && swipeDiff > 0) { possibleDir = false; } 398 } 399 if( Math.abs( swipeDiff ) > options.swipeTolerance && possibleDir ) { 400 loadImage( swipeDiff > 0 ? 1 : -1 ); 401 } 402 else if( options.animationSlide ) 403 { 404 if( canTransisions ) slide( options.animationSpeed / 1000, 0 + 'px' ); 405 else image.animate({ 'left': imageLeft + 'px' }, options.animationSpeed / 2 ); 406 } 407 408 if( options.swipeClose && Math.abs(swipeYDiff) > 50 && Math.abs( swipeDiff ) < options.swipeTolerance) { 409 close(); 410 } 411 } 412 }); 413 414 } 415 416 }, 417 removeEvents = function(){ 418 nav.off('click', 'button'); 419 $( document ).off('click.'+prefix, '.jl-close'); 420 $( window ).off( 'resize.'+prefix); 421 $( window ).off( 'hashchange.'+prefix); 422 }, 423 preload = function(){ 424 var next = (index+1 < 0) ? objects.length -1: (index+1 >= objects.length -1) ? 0 : index+1, 425 prev = (index-1 < 0) ? objects.length -1: (index-1 >= objects.length -1) ? 0 : index-1; 426 $( '<img />' ).attr( 'src', objects.eq(next).attr( options.sourceAttr ) ).on('load', function(){ 427 if(loaded.indexOf($(this).attr('src')) == -1){ 428 loaded.push($(this).attr('src')); 429 } 430 objects.eq(index).trigger($.Event('nextImageLoaded.jetslothlightbox')); 431 }); 432 $( '<img />' ).attr( 'src', objects.eq(prev).attr( options.sourceAttr ) ).on('load', function(){ 433 if(loaded.indexOf($(this).attr('src')) == -1){ 434 loaded.push($(this).attr('src')); 435 } 436 objects.eq(index).trigger($.Event('prevImageLoaded.jetslothlightbox')); 437 }); 438 439 }, 440 loadImage = function(dir){ 441 objects.eq(index) 442 .trigger($.Event('change.jetslothlightbox')) 443 .trigger($.Event( (dir===1?'next':'prev')+'.jetslothlightbox')); 444 445 var newIndex = index + dir; 446 if(animating || (newIndex < 0 || newIndex >= objects.length) && options.loop === false ) return; 447 index = (newIndex < 0) ? objects.length -1: (newIndex > objects.length -1) ? 0 : newIndex; 448 $('.jl-wrapper .jl-counter .jl-current').text(index +1); 449 var css = { 'opacity': 0 }; 450 if( options.animationSlide ) { 451 if( canTransisions ) slide(options.animationSpeed / 1000, ( -100 * dir ) - swipeDiff + 'px'); 452 else css.left = parseInt( $('.jl-image').css( 'left' ) ) + -100 * dir + 'px'; 453 } 454
455 $('.jl-image').animate( css, options.animationSpeed, function(){ 456 setTimeout( function(){ 457 // fadeout old image 458 var elem = objects.eq(index); 459 curImg 460 .attr('src', elem.attr(options.sourceAttr)); 461 if(loaded.indexOf(elem.attr(options.sourceAttr)) == -1){ 462 spinner.show(); 463 } 464 $('.jl-caption').remove(); 465 adjustImage(dir); 466 if(options.preloading) preload(); 467 }, 100); 468 }); 469 }, 470 close = function(){ 471 if(animating) return; 472 var elem = objects.eq(index), 473 triggered = false; 474 475 elem.trigger($.Event('close.jetslothlightbox')); 476 if(options.history){ 477 resetHash(); 478 } 479 $('.jl-image img, .jl-overlay, .jl-close, .jl-navigation, .jl-image .jl-caption, .jl-counter').fadeOut('fast', function(){ 480 if(options.disableScroll) handleScrollbar('show'); 481 $('.jl-wrapper, .jl-overlay').remove(); 482 removeEvents(); 483 if(!triggered) elem.trigger($.Event('closed.jetslothlightbox')); 484 triggered = true; 485 }); 486 curImg = $(); 487 opened = false; 488 animating = false; 489 }, 490 handleScrollbar = function(type){ 491 var scrollbarWidth = 0; 492 if(type == 'hide'){ 493 var fullWindowWidth = window.innerWidth; 494 if (!fullWindowWidth) { 495 var documentElementRect = document.documentElement.getBoundingClientRect(); 496 fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left); 497 } 498 if(document.body.clientWidth < fullWindowWidth){ 499 var scrollDiv = document.createElement('div'), 500 padding = parseInt($('body').css('padding-right'),10); 501 scrollDiv.className = 'jl-scrollbar-measure'; 502 $('body').append(scrollDiv); 503 scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth; 504 $(document.body)[0].removeChild(scrollDiv); 505 $('body').data('padding',padding); 506 if(scrollbarWidth > 0){ 507 $('body').addClass('hidden-scroll').css({'padding-right':padding+scrollbarWidth}); 508 } 509 } 510 } else { 511 $('body').removeClass('hidden-scroll').css({'padding-right':$('body').data('padding')}); 512 } 513 return scrollbarWidth; 514 }; 515 516 // events 517 setup(); 518 519 // open lightbox 520 objects.on( 'click.'+prefix, function( e ){ 521 if(isValidLink(this)){ 522 e.preventDefault(); 523 if(animating) return false; 524 var elem = $(this); 525 startIndex = objects.index(elem); 526 openImage(elem); 527 } 528 }); 529 530 // close on click on doc 531 $( document ).on('click.'+prefix+ ' touchstart.'+prefix, function(e){ 532 if(opened){ 533 if((options.docClose && $(e.target).closest('.jl-image').length === 0 && $(e.target).closest('.jl-navigation').length === 0)){ 534 close(); 535 } 536 } 537 }); 538 539 // disable rightclick 540 if(options.disableRightClick){ 541 $( document ).on('contextmenu', '.jl-image img', function(e){ 542 return false; 543 }); 544 } 545 546 547 // keyboard-control 548 if( options.enableKeyboard ){ 549 $( document ).on( 'keyup.'+prefix, throttle(function( e ){ 550 swipeDiff = 0; 551 // keyboard control only if lightbox is open 552 var key = e.keyCode; 553 if(animating && key == 27) { 554 curImg.attr('src', ''); 555 animating = false; 556 close(); 557 } 558 559 if(opened){ 560 e.preventDefault(); 561 if( key == 27 ) { 562 close(); 563 } 564 if( key == 37 || e.keyCode == 39 ) { 565 loadImage( e.keyCode == 39 ? 1 : -1 ); 566 } 567 } 568 }, options.throttleInterval)); 569 } 570 571 // Public methods 572 this.open = function(elem){ 573 elem = elem || $(this[0]); 574 startIndex = objects.index(elem); 575 openImage(elem); 576 }; 577 578 this.next = function(){ 579 loadImage( 1 ); 580 }; 581 582 this.prev = function(){ 583 loadImage( -1 ); 584 }; 585 586 this.close = function(){ 587 close(); 588 }; 589 590 this.destroy = function(){ 591 $( document ).off('click.'+prefix).off('keyup.'+prefix); 592 close(); 593 $('.jl-overlay, .jl-wrapper').remove(); 594 this.off('click'); 595 }; 596 597 this.refresh = function(){ 598 this.destroy(); 599 $(this).jetslothLightbox(options); 600 }; 601 602 return this; 603 604}; 605})( jQuery, window, document ); 606 607 608
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.