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