1// 2// By Osvaldas Valutis, www.osvaldas.info 3// Available for use under the MIT License 4// 5(function ($, window, document) { 6 'use strict'; 7 // COMPONENTS // 8 var $activityObject = $('<div/>') 9 .attr('class','imagelightbox-loading') 10 .append($('<div/>')), 11 $arrowLeftObject = $('<button/>',{ 12 type: 'button', 13 class: 'imagelightbox-arrow imagelightbox-arrow-left'}), 14 $arrowRightObject = $('<button/>',{ 15 type: 'button', 16 class: 'imagelightbox-arrow imagelightbox-arrow-right'}), 17 $arrows = $arrowLeftObject.add($arrowRightObject), 18 $captionObject = $('<div/>', { 19 class: 'imagelightbox-caption', 20 html: ' ' 21 }), 22 $buttonObject = $('<a/>', { 23 class: 'imagelightbox-close' 24 }), 25 $overlayObject = $('<div/>', { 26 class:'imagelightbox-overlay' 27 }), 28 $navItem = $('<a/>', { 29 href:'#', 30 class:'imagelightbox-navitem' 31 }), 32 $navObject = $('<div/>', { 33 class: 'imagelightbox-nav' 34 }), 35 $wrapper = $('<div/>', { 36 class: 'imagelightbox-wrapper' 37 }); 38 39 var cssTransitionSupport = function () { 40 var s = document.body || document.documentElement; 41 s = s.style; 42 if (s.WebkitTransition === '') { 43 return '-webkit-'; 44 } 45 if (s.MozTransition === '') { 46 return '-moz-'; 47 } 48 if (s.OTransition === '') { 49 return '-o-'; 50 } 51 if (s.transition === '') { 52 return ''; 53 } 54 return false; 55 }, 56 57 hasCssTransitionSupport = cssTransitionSupport() !== false, 58 59 cssTransitionTranslateX = function (element, positionX, speed) { 60 var options = {}, prefix = cssTransitionSupport(); 61 options[prefix + 'transform'] = 'translateX(' + positionX + ')'; 62 options[prefix + 'transition'] = prefix + 'transform ' + speed + 's linear'; 63 element.css(options); 64 }, 65 66 hasTouch = ( 'ontouchstart' in window ), 67 hasPointers = window.navigator.pointerEnabled || window.navigator.msPointerEnabled, 68 wasTouched = function (event) { 69 if (hasTouch) { 70 return true; 71 } 72 73 if (!hasPointers || typeof event === 'undefined' || typeof event.pointerType === 'undefined') { 74 return false; 75 } 76 77 if (typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined') { 78 if (event.MSPOINTER_TYPE_MOUSE !== event.pointerType) { 79 return true; 80 } 81 } 82 else if (event.pointerType !== 'mouse') { 83 return true; 84 } 85 86 return false; 87 }; 88 89 $.fn.imageLightbox = function (opts) { 90 var options = $.extend({ 91 selector: 'a[data-imagelightbox]', 92 id: 'imagelightbox', 93 allowedTypes: 'png|jpg|jpeg|gif', // TODO make it work again 94 animationSpeed: 250, 95 activity: false, 96 arrows: false, 97 button: false, 98 caption: false, 99 enableKeyboard: true, 100 lockBody: false, 101 navigation: false, 102 overlay: false, 103 preloadNext: true, 104 quitOnEnd: false, 105 quitOnImgClick: false, 106 quitOnDocClick: true, 107 quitOnEscKey: true 108 }, opts), 109 _onStart = function () { 110 if (options.arrows) { 111 arrowsOn(this); 112 } 113 if (options.navigation) { 114 navigationOn(); 115 } 116 if (options.overlay) { 117 overlayOn(); 118 } 119 if (options.button) { 120 closeButtonOn(); 121 } 122 if (options.caption) { 123 $wrapper.append($captionObject); 124 } 125 }, 126 _onLoadStart = function () { 127 if (options.activity) { 128 activityIndicatorOn(); 129 } 130 if (options.caption) { 131 captionReset(); 132 } 133 }, 134 _onLoadEnd = function () { 135 if (options.activity) { 136 activityIndicatorOff(); 137 } 138 if (options.arrows) { 139 $arrows.css('display', 'block'); 140 } 141 }, 142 _previousTarget = function () { 143 var targetIndex = targets.index(target) - 1; 144 if (targetIndex < 0) { 145 if (options.quitOnEnd === true) { 146 _quitImageLightbox(); 147 return false;
148 } 149 else { 150 targetIndex = targets.length - 1; 151 } 152 } 153 target = targets.eq(targetIndex); 154 $wrapper.trigger('previous.ilb2'); 155 _loadImage(-1); 156 }, 157 _nextTarget = function () { 158 var targetIndex = targets.index(target) + 1; 159 if (targetIndex >= targets.length) { 160 if (options.quitOnEnd === true) { 161 _quitImageLightbox(); 162 return false; 163 } 164 else { 165 targetIndex = 0; 166 } 167 } 168 target = targets.eq(targetIndex); 169 $wrapper.trigger('next.ilb2'); 170 _loadImage(+1); 171 }, 172 activityIndicatorOn = function () { 173 $wrapper.append($activityObject); 174 }, 175 activityIndicatorOff = function () { 176 $('.imagelightbox-loading').remove(); 177 }, 178 overlayOn = function () { 179 $wrapper.append($overlayObject); 180 }, 181 closeButtonOn = function () { 182 $buttonObject.appendTo($wrapper).on('click.ilb7', function () { 183 _quitImageLightbox(); 184 return false; 185 }); 186 }, 187 captionReset = function () { 188 $captionObject.html(' '); 189 if ($(target).data('ilb2-caption')) { 190 $captionObject.html($(target).data('ilb2-caption')); 191 } else if ($(target).find('img').length > 0) { 192 $captionObject.html($(target).find('img').attr('alt')); 193 } 194 }, 195 navigationOn = function () { 196 if (targets.length) { 197 for (var i = 0; i < targets.length; i++) { 198 $navObject.append($navItem.clone()); 199 } 200 var $navItems = $navObject.children('a'); 201 $navItems.eq(targets.index(target)).addClass('active'); 202 203 // 204 $wrapper.on('previous.ilb2 next.ilb2', function () { 205 $navItems.removeClass('active').eq(targets.index(target)).addClass('active'); 206 }); 207 $wrapper.append($navObject); 208 //// 209 $navObject 210 .on('click.ilb7 touchend.ilb7', function () { 211 return false; 212 }) 213 .on('click.ilb7 touchend.ilb7', 'a', function () { 214 var $this = $(this); 215 if (targets.eq($this.index()).attr('href') !== $('.imagelightbox').attr('src')) { 216 var tmpTarget = targets.eq($this.index()); 217 if (tmpTarget.length) { 218 currentIndex = targets.index(target); 219 target = tmpTarget; 220 _loadImage($this.index() < currentIndex ? -1 : 1); 221 } 222 } 223 $this.addClass('active').siblings().removeClass('active'); 224 }); 225 } 226 }, 227 arrowsOn = function () { 228 $wrapper.append($arrows); 229 $arrows.on('click.ilb7 touchend.ilb7', function (e) { 230 e.stopImmediatePropagation(); 231 e.preventDefault(); 232 if ($(this).hasClass('imagelightbox-arrow-left')) { 233 _previousTarget(); 234 } else { 235 _nextTarget(); 236 } 237 return false; 238 }); 239 }, 240 targetSet = '', 241 targets = $([]), 242 target = $(), 243 image = $(), 244 imageWidth = 0, 245 imageHeight = 0, 246 swipeDiff = 0, 247 inProgress = false, 248 currentIndex = 0, 249 250 isTargetValid = function (validImage) { 251 var allowedTypes = options.allowedTypes; 252 253 //test that RegExp is restricted to disjunction format 254 var isGoodRE = /^(?!\|)[\w\|]+(?!\|)$/.test(allowedTypes); 255 // 256 if (!isGoodRE) { 257 //allowedTypes = 'png|jpg|jpeg|gif'; 258 return false;
259 } 260 // 261 var URL = validImage.attr('href'); 262 var ext = parseURL(URL).pathname; 263 var re = new RegExp(allowedTypes,'i'); 264 // 265 var isAllowed = re.test(ext); 266 // function by Cory LaViska 267 function parseURL(url) { 268 var parser = document.createElement('a'), 269 searchObject = {}, 270 queries, split, i; 271 // Let the browser do the work 272 parser.href = url; 273 // Convert query string to object 274 queries = parser.search.replace(/^\?/, '').split('&'); 275 for( i = 0; i < queries.length; i++ ) { 276 split = queries[i].split('='); 277 searchObject[split[0]] = split[1]; 278 } 279 return { 280 protocol: parser.protocol, 281 host: parser.host, 282 hostname: parser.hostname, 283 port: parser.port, 284 pathname: parser.pathname, 285 search: parser.search, 286 searchObject: searchObject, 287 hash: parser.hash 288 }; 289 } 290 return isAllowed; 291 }, 292 // TODO make it work again 293 // isTargetValid = function (element) { 294 // var classic = $(element).prop('tagName').toLowerCase() === 'a' && ( new RegExp('.(' + options.allowedTypes + ')$', 'i') ).test($(element).attr('href')); 295 // var html5 = $(element).attr('data-lightbox') !== undefined; 296 // return classic || html5; 297 // }, 298 299 _setImage = function () { 300 if (!image.length) { 301 return true; 302 } 303 var captionHeight = $captionObject.outerHeight(); 304 305 var screenWidth = $(window).width() * 0.8, 306 wHeight = ((window.innerHeight) ? window.innerHeight : $(window).height()) - captionHeight, 307 screenHeight = wHeight * 0.9, 308 tmpImage = new Image(); 309 310 tmpImage.src = image.attr('src'); 311 tmpImage.onload = function () { 312 imageWidth = tmpImage.width; 313 imageHeight = tmpImage.height; 314 315 if (imageWidth > screenWidth || imageHeight > screenHeight) { 316 var ratio = imageWidth / imageHeight > screenWidth / screenHeight ? imageWidth / screenWidth : imageHeight / screenHeight; 317 imageWidth /= ratio; 318 imageHeight /= ratio; 319 } 320 321 image.css({ 322 'width': imageWidth + 'px', 323 'height': imageHeight + 'px', 324 'top': ( wHeight - imageHeight ) / 2 + 'px', 325 'left': ( $(window).width() - imageWidth ) / 2 + 'px' 326 }); 327 }; 328 }, 329 330 _loadImage = function (direction) { 331 if (inProgress) { 332 return false; 333 } 334 335 if (image.length) { 336 var params = {'opacity': 0}; 337 if (hasCssTransitionSupport) { 338 cssTransitionTranslateX(image, ( 100 * direction ) - swipeDiff + 'px', options.animationSpeed / 1000); 339 } 340 else { 341 params.left = parseInt(image.css('left')) + 100 * direction + 'px'; 342 } 343 image.animate(params, options.animationSpeed, function () { 344 _removeImage(); 345 }); 346 swipeDiff = 0; 347 } 348 349 inProgress = true; 350 _onLoadStart(); 351 352 setTimeout(function () { 353 var imgPath = target.attr('href'); 354 // if ( imgPath === undefined ) { 355 // imgPath = target.attr( 'data-lightbox' ); 356 // } 357 image = $('<img id="' + options.id + '" />') 358 .attr('src', imgPath) 359 .on('load.ilb7', function () { 360 $wrapper.trigger('loaded.ilb2'); 361 var params = {'opacity': 1}; 362 363 image.appendTo($wrapper); 364 _setImage(); 365 image.css('opacity', 0); 366 if (hasCssTransitionSupport) { 367 cssTransitionTranslateX(image, -100 * direction + 'px', 0); 368 setTimeout(function () { 369 cssTransitionTranslateX(image, 0 + 'px', options.animationSpeed / 1000); 370 }, 50); 371 } else { 372 var imagePosLeft = parseInt(image.css('left')); 373 params.left = imagePosLeft + 'px'; 374 image.css('left', imagePosLeft - 100 * direction + 'px'); 375 } 376 377 image.animate(params, options.animationSpeed, function () { 378 inProgress = false;
379 _onLoadEnd(); 380 }); 381 if (options.preloadNext) { 382 var nextTarget = targets.eq(targets.index(target) + 1); 383 if (!nextTarget.length) { 384 nextTarget = targets.eq(0); 385 } 386 $('<img />').attr('src', nextTarget.attr('href')); 387 } 388 }) 389 .on('error.ilb7', function () { 390 _onLoadEnd(); 391 }); 392 393 var swipeStart = 0, 394 swipeEnd = 0, 395 imagePosLeft = 0; 396 397 image.on(hasPointers ? 'pointerup.ilb7 MSPointerUp.ilb7' : 'click.ilb7', function (e) { 398 e.preventDefault(); 399 if (options.quitOnImgClick) { 400 _quitImageLightbox(); 401 return false; 402 } 403 if (wasTouched(e.originalEvent)) { 404 return true; 405 } 406 var posX = ( e.pageX || e.originalEvent.pageX ) - e.target.offsetLeft; 407 if (imageWidth / 2 > posX) { 408 _previousTarget(); 409 } else { 410 _nextTarget(); 411 } 412 }) 413 .on('touchstart.ilb7 pointerdown.ilb7 MSPointerDown.ilb7', function (e) { 414 if (!wasTouched(e.originalEvent) || options.quitOnImgClick) { 415 return true; 416 } 417 if (hasCssTransitionSupport) { 418 imagePosLeft = parseInt(image.css('left')); 419 } 420 swipeStart = e.originalEvent.pageX || e.originalEvent.touches[0].pageX; 421 }) 422 .on('touchmove.ilb7 pointermove.ilb7 MSPointerMove.ilb7', function (e) { 423 if ((!hasPointers && e.type === 'pointermove') || !wasTouched(e.originalEvent) || options.quitOnImgClick) { 424 return true; 425 } 426 e.preventDefault(); 427 swipeEnd = e.originalEvent.pageX || e.originalEvent.touches[0].pageX; 428 swipeDiff = swipeStart - swipeEnd; 429 if (hasCssTransitionSupport) { 430 cssTransitionTranslateX(image, -swipeDiff + 'px', 0); 431 } else { 432 image.css('left', imagePosLeft - swipeDiff + 'px'); 433 } 434 }) 435 .on('touchend.ilb7 touchcancel.ilb7 pointerup.ilb7 pointercancel.ilb7 MSPointerUp.ilb7 MSPointerCancel.ilb7', function (e) { 436 if (!wasTouched(e.originalEvent) || options.quitOnImgClick) { 437 return true; 438 } 439 if (Math.abs(swipeDiff) > 50) { 440 if (swipeDiff < 0) { 441 _previousTarget(); 442 } else { 443 _nextTarget(); 444 } 445 } else { 446 if (hasCssTransitionSupport) { 447 cssTransitionTranslateX(image, 0 + 'px', options.animationSpeed / 1000); 448 } else { 449 image.animate({'left': imagePosLeft + 'px'}, options.animationSpeed / 2); 450 } 451 } 452 }); 453 454 }, options.animationSpeed + 100); 455 }, 456 _removeImage = function () { 457 if (!image.length) { 458 return false;
459 } 460 image.remove(); 461 image = $(); 462 }, 463 464 _openImageLightbox = function ($target) { 465 if (inProgress) { 466 return false; 467 } 468 inProgress = false; 469 target = $target; 470 _onStart(); 471 $('body').append($wrapper); 472 if (options.lockBody) { 473 $('body').addClass('imagelightbox-scroll-lock'); 474 } 475 $wrapper.trigger('start.ilb2'); 476 _loadImage(0); 477 }, 478 479 _quitImageLightbox = function () { 480 $wrapper.trigger('quit.ilb2'); 481 if (options.lockBody) { 482 $('body').removeClass('imagelightbox-scroll-lock'); 483 } 484 if (!image.length) { 485 return false; 486 } 487 image.animate({'opacity': 0}, options.animationSpeed, function () { 488 _removeImage(); 489 inProgress = false; 490 targets = $([]); 491 $wrapper.remove().find('*').remove(); 492 }); 493 }, 494 495 _addTargets = function( newTargets ) { 496 newTargets.on('click.ilb7', {set: targetSet}, function (e) { 497 e.preventDefault(); 498 targetSet = $(e.currentTarget).data('imagelightbox'); 499 filterTargets(); 500 if (targets.length < 1) { 501 _quitImageLightbox(); 502 } else { 503 _openImageLightbox($(this)); 504 } 505 }); 506 function filterTargets () { 507 newTargets 508 .filter(function () { 509 return $(this).data('imagelightbox') === targetSet; 510 }) 511 .filter(function () { 512 return isTargetValid($(this)); 513 }) 514 .each(function () { 515 targets = targets.add($(this)); 516 }); 517 } 518 }; 519 520 $(window).on('resize.ilb7', _setImage); 521 522 $(document).ready(function() { 523 if (options.quitOnDocClick) { 524 $(document).on(hasTouch ? 'touchend.ilb7' : 'click.ilb7', function (e) { 525 if (image.length && !$(e.target).is(image)) { 526 e.preventDefault(); 527 _quitImageLightbox(); 528 } 529 }); 530 } 531 532 if (options.lockBody) { 533 $(document).on('keydown.ilb7', function (e) { 534 if (!image.length) { 535 return true; 536 } 537 if([9,32,38,40].indexOf(e.which) > -1) { 538 e.preventDefault(); 539 return false; 540 } 541 }); 542 } 543 544 if (options.enableKeyboard) { 545 $(document).on('keyup.ilb7', function (e) { 546 if (!image.length) { 547 return true; 548 } 549 e.preventDefault(); 550 if ([27].indexOf(e.which) > -1 && options.quitOnEscKey) { 551 _quitImageLightbox(); 552 } 553 if ([37].indexOf(e.which) > -1) { 554 _previousTarget(); 555 } else if ([39].indexOf(e.which) > -1) { 556 _nextTarget(); 557 } 558 }); 559 } 560 }); 561 562 $(document).off('click', options.selector); 563 564 _addTargets($(this)); 565 566 this.addToImageLightbox = function(elements) { 567 _addTargets(elements); 568 }; 569 570 this.loadPreviousImage = function () { 571 _previousTarget(); 572 }; 573 574 this.loadNextImage = function () { 575 _nextTarget(); 576 }; 577 578 this.quitImageLightbox = function () { 579 _quitImageLightbox(); 580 return this; 581 }; 582 583 this.startImageLightbox = function () { 584 $(this).trigger('click.ilb7'); 585 }; 586 587 return this; 588 }; 589})(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.