vendor: 4,106 bytes, lines 1-105
1/*! 2 * Lightbox v2.8.1 3 * by Lokesh Dhakar 4 * 5 * More info: 6 * http://lokeshdhakar.com/projects/lightbox2/ 7 * 8 * Copyright 2007, 2015 Lokesh Dhakar 9 * Released under the MIT license 10 * https://github.com/lokesh/lightbox2/blob/master/LICENSE 11 */ 12 13// Uses Node, AMD or browser globals to create a module. 14(function (root, factory) { 15 if (typeof define === 'function' && define.amd) { 16 // AMD. Register as an anonymous module. 17 define(['jquery'], factory); 18 } else if (typeof exports === 'object') { 19 // Node. Does not work with strict CommonJS, but 20 // only CommonJS-like environments that support module.exports, 21 // like Node. 22 module.exports = factory(require('jquery')); 23 } else { 24 // Browser globals (root is window) 25 root.lightbox = factory(root.jQuery); 26 } 27}(this, function ($) { 28 29 function Lightbox(options) { 30 this.album = []; 31 this.currentImageIndex = void 0; 32 this.init(); 33 34 // options 35 this.options = $.extend({}, this.constructor.defaults); 36 this.option(options); 37 } 38 39 // Descriptions of all options available on the demo site: 40 // http://lokeshdhakar.com/projects/lightbox2/index.html#options 41 Lightbox.defaults = { 42 albumLabel: 'Image %1 of %2', 43 alwaysShowNavOnTouchDevices: false, 44 fadeDuration: 500, 45 fitImagesInViewport: true, 46 // maxWidth: 800, 47 // maxHeight: 600, 48 positionFromTop: 50, 49 resizeDuration: 700, 50 showImageNumberLabel: true, 51 wrapAround: false 52 }; 53 54 Lightbox.prototype.option = function(options) { 55 $.extend(this.options, options); 56 }; 57 58 Lightbox.prototype.imageCountLabel = function(currentImageNum, totalImages) { 59 return this.options.albumLabel.replace(/%1/g, currentImageNum).replace(/%2/g, totalImages); 60 }; 61 62 Lightbox.prototype.init = function() { 63 this.enable(); 64 this.build(); 65 }; 66 67 // Loop through anchors and areamaps looking for either data-lightbox attributes or rel attributes 68 // that contain 'lightbox'. When these are clicked, start lightbox. 69 Lightbox.prototype.enable = function() { 70 var self = this; 71 $('body').on('click', 'a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]', function(event) { 72 self.start($(event.currentTarget)); 73 return false; 74 }); 75 }; 76 77 // Build html for the lightbox and the overlay. 78 // Attach event handlers to the new DOM elements. click click click 79 Lightbox.prototype.build = function() { 80 var self = this; 81 $('<div id="lightboxOverlay" class="lightboxOverlay"></div><div id="lightbox" class="lightbox"><div class="lb-outerContainer"><div class="lb-container"><img class="lb-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" /><div class="lb-nav"><a class="lb-prev" href="" ></a><a class="lb-next" href="" ></a></div><div class="lb-loader"><a class="lb-cancel"></a></div></div></div><div class="lb-dataContainer"><div class="lb-data"><div class="lb-details"><span class="lb-caption"></span><span class="lb-number"></span></div><div class="lb-closeContainer"><a class="lb-close"></a></div></div></div></div>').appendTo($('body')); 82 83 // Cache jQuery objects 84 this.$lightbox = $('#lightbox'); 85 this.$overlay = $('#lightboxOverlay'); 86 this.$outerContainer = this.$lightbox.find('.lb-outerContainer'); 87 this.$container = this.$lightbox.find('.lb-container'); 88 89 // Store css values for future lookup 90 this.containerTopPadding = parseInt(this.$container.css('padding-top'), 10); 91 this.containerRightPadding = parseInt(this.$container.css('padding-right'), 10); 92 this.containerBottomPadding = parseInt(this.$container.css('padding-bottom'), 10); 93 this.containerLeftPadding = parseInt(this.$container.css('padding-left'), 10); 94 95 // Attach event handlers to the newly minted DOM elements 96 this.$overlay.hide().on('click', function() { 97 self.end(); 98 return false; 99 }); 100 101 this.$lightbox.hide().on('click', function(event) { 102 if ($(event.target).attr('id') === 'lightbox') { 103 self.end(); 104 } 105 return false;
106 }); 107 108 this.$outerContainer.on('click', function(event) { 109 if ($(event.target).attr('id') === 'lightbox') { 110 self.end(); 111 } 112 return false; 113 }); 114 115 this.$lightbox.find('.lb-prev').on('click', function() { 116 if (self.currentImageIndex === 0) { 117 self.changeImage(self.album.length - 1); 118 } else { 119 self.changeImage(self.currentImageIndex - 1); 120 } 121 return false; 122 }); 123 124 this.$lightbox.find('.lb-next').on('click', function() { 125 if (self.currentImageIndex === self.album.length - 1) { 126 self.changeImage(0); 127 } else { 128 self.changeImage(self.currentImageIndex + 1); 129 } 130 return false; 131 }); 132 133 this.$lightbox.find('.lb-loader, .lb-close').on('click', function() { 134 self.end(); 135 return false; 136 }); 137 }; 138 139 // Show overlay and lightbox. If the image is part of a set, add siblings to album array. 140 Lightbox.prototype.start = function($link) { 141 var self = this; 142 var $window = $(window); 143 144 $window.on('resize', $.proxy(this.sizeOverlay, this)); 145 146 $('select, object, embed').css({ 147 visibility: 'hidden' 148 }); 149 150 this.sizeOverlay(); 151 152 this.album = []; 153 var imageNumber = 0; 154 155 function addToAlbum($link) { 156 self.album.push({ 157 link: $link.attr('href'), 158 title: $link.attr('data-title') || $link.attr('title') 159 }); 160 } 161 162 // Support both data-lightbox attribute and rel attribute implementations 163 var dataLightboxValue = $link.attr('data-lightbox'); 164 var $links; 165 166 if (dataLightboxValue) { 167 $links = $($link.prop('tagName') + '[data-lightbox="' + dataLightboxValue + '"]'); 168 for (var i = 0; i < $links.length; i = ++i) { 169 addToAlbum($($links[i])); 170 if ($links[i] === $link[0]) { 171 imageNumber = i; 172 } 173 } 174 } else { 175 if ($link.attr('rel') === 'lightbox') { 176 // If image is not part of a set 177 addToAlbum($link); 178 } else { 179 // If image is part of a set 180 $links = $($link.prop('tagName') + '[rel="' + $link.attr('rel') + '"]'); 181 for (var j = 0; j < $links.length; j = ++j) { 182 addToAlbum($($links[j])); 183 if ($links[j] === $link[0]) { 184 imageNumber = j; 185 } 186 } 187 } 188 } 189 190 // Position Lightbox 191 var top = $window.scrollTop() + this.options.positionFromTop; 192 var left = $window.scrollLeft(); 193 this.$lightbox.css({ 194 top: top + 'px', 195 left: left + 'px' 196 }).fadeIn(this.options.fadeDuration); 197 198 this.changeImage(imageNumber); 199 }; 200 201 // Hide most UI elements in preparation for the animated resizing of the lightbox. 202 Lightbox.prototype.changeImage = function(imageNumber) { 203 var self = this; 204 205 this.disableKeyboardNav(); 206 var $image = this.$lightbox.find('.lb-image'); 207 208 this.$overlay.fadeIn(this.options.fadeDuration); 209 210 $('.lb-loader').fadeIn('slow'); 211 this.$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide(); 212 213 this.$outerContainer.addClass('animating'); 214 215 // When image to show is preloaded, we send the width and height to sizeContainer() 216 var preloader = new Image(); 217 preloader.onload = function() { 218 var $preloader; 219 var imageHeight; 220 var imageWidth; 221 var maxImageHeight; 222 var maxImageWidth; 223 var windowHeight; 224 var windowWidth; 225 226 $image.attr('src', self.album[imageNumber].link); 227 228 $preloader = $(preloader); 229 230 $image.width(preloader.width); 231 $image.height(preloader.height); 232 233 if (self.options.fitImagesInViewport) { 234 // Fit image inside the viewport. 235 // Take into account the border around the image and an additional 10px gutter on each side. 236 237 windowWidth = $(window).width(); 238 windowHeight = $(window).height(); 239 maxImageWidth = windowWidth - self.containerLeftPadding - self.containerRightPadding - 20; 240 maxImageHeight = windowHeight - self.containerTopPadding - self.containerBottomPadding - 120; 241 242 // Check if image size is larger then maxWidth|maxHeight in settings 243 if (self.options.maxWidth && self.options.maxWidth < maxImageWidth) { 244 maxImageWidth = self.options.maxWidth; 245 } 246 if (self.options.maxHeight && self.options.maxHeight < maxImageWidth) { 247 maxImageHeight = self.options.maxHeight; 248 } 249 250 // Is there a fitting issue? 251 if ((preloader.width > maxImageWidth) || (preloader.height > maxImageHeight)) { 252 if ((preloader.width / maxImageWidth) > (preloader.height / maxImageHeight)) { 253 imageWidth = maxImageWidth; 254 imageHeight = parseInt(preloader.height / (preloader.width / imageWidth), 10); 255 $image.width(imageWidth); 256 $image.height(imageHeight); 257 } else { 258 imageHeight = maxImageHeight; 259 imageWidth = parseInt(preloader.width / (preloader.height / imageHeight), 10); 260 $image.width(imageWidth); 261 $image.height(imageHeight); 262 } 263 } 264 } 265 self.sizeContainer($image.width(), $image.height()); 266 }; 267 268 preloader.src = this.album[imageNumber].link; 269 this.currentImageIndex = imageNumber; 270 }; 271 272 // Stretch overlay to fit the viewport 273 Lightbox.prototype.sizeOverlay = function() { 274 this.$overlay 275 .width($(window).width()) 276 .height($(document).height()); 277 }; 278 279 // Animate the size of the lightbox to fit the image we are showing 280 Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) { 281 var self = this; 282 283 var oldWidth = this.$outerContainer.outerWidth(); 284 var oldHeight = this.$outerContainer.outerHeight(); 285 var newWidth = imageWidth + this.containerLeftPadding + this.containerRightPadding; 286 var newHeight = imageHeight + this.containerTopPadding + this.containerBottomPadding; 287 288 function postResize() { 289 self.$lightbox.find('.lb-dataContainer').width(newWidth); 290 self.$lightbox.find('.lb-prevLink').height(newHeight); 291 self.$lightbox.find('.lb-nextLink').height(newHeight); 292 self.showImage(); 293 } 294 295 if (oldWidth !== newWidth || oldHeight !== newHeight) { 296 this.$outerContainer.animate({ 297 width: newWidth, 298 height: newHeight 299 }, this.options.resizeDuration, 'swing', function() { 300 postResize(); 301 }); 302 } else { 303 postResize(); 304 } 305 }; 306 307 // Display the image and its details and begin preload neighboring images. 308 Lightbox.prototype.showImage = function() { 309 this.$lightbox.find('.lb-loader').stop(true).hide(); 310 this.$lightbox.find('.lb-image').fadeIn('slow'); 311 312 this.updateNav(); 313 this.updateDetails(); 314 this.preloadNeighboringImages(); 315 this.enableKeyboardNav(); 316 }; 317 318 // Display previous and next navigation if appropriate. 319 Lightbox.prototype.updateNav = function() { 320 // Check to see if the browser supports touch events. If so, we take the conservative approach 321 // and assume that mouse hover events are not supported and always show prev/next navigation 322 // arrows in image sets. 323 var alwaysShowNav = false;
324 try { 325 document.createEvent('TouchEvent'); 326 alwaysShowNav = (this.options.alwaysShowNavOnTouchDevices) ? true : false; 327 } catch (e) {} 328 329 this.$lightbox.find('.lb-nav').show(); 330 331 if (this.album.length > 1) { 332 if (this.options.wrapAround) { 333 if (alwaysShowNav) { 334 this.$lightbox.find('.lb-prev, .lb-next').css('opacity', '1'); 335 } 336 this.$lightbox.find('.lb-prev, .lb-next').show(); 337 } else { 338 if (this.currentImageIndex > 0) { 339 this.$lightbox.find('.lb-prev').show(); 340 if (alwaysShowNav) { 341 this.$lightbox.find('.lb-prev').css('opacity', '1'); 342 } 343 } 344 if (this.currentImageIndex < this.album.length - 1) { 345 this.$lightbox.find('.lb-next').show(); 346 if (alwaysShowNav) { 347 this.$lightbox.find('.lb-next').css('opacity', '1'); 348 } 349 } 350 } 351 } 352 }; 353 354 // Display caption, image number, and closing button. 355 Lightbox.prototype.updateDetails = function() { 356 var self = this; 357 358 // Enable anchor clicks in the injected caption html. 359 // Thanks Nate Wright for the fix. @https://github.com/NateWr 360 if (typeof this.album[this.currentImageIndex].title !== 'undefined' && 361 this.album[this.currentImageIndex].title !== '') { 362 this.$lightbox.find('.lb-caption') 363 .html(this.album[this.currentImageIndex].title) 364 .fadeIn('fast') 365 .find('a').on('click', function(event) { 366 if ($(this).attr('target') !== undefined) { 367 window.open($(this).attr('href'), $(this).attr('target')); 368 } else { 369 location.href = $(this).attr('href'); 370 } 371 }); 372 } 373 374 if (this.album.length > 1 && this.options.showImageNumberLabel) { 375 var labelText = this.imageCountLabel(this.currentImageIndex + 1, this.album.length); 376 this.$lightbox.find('.lb-number').text(labelText).fadeIn('fast'); 377 } else { 378 this.$lightbox.find('.lb-number').hide(); 379 } 380 381 this.$outerContainer.removeClass('animating'); 382 383 this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() { 384 return self.sizeOverlay(); 385 }); 386 }; 387 388 // Preload previous and next images in set. 389 Lightbox.prototype.preloadNeighboringImages = function() { 390 if (this.album.length > this.currentImageIndex + 1) { 391 var preloadNext = new Image(); 392 preloadNext.src = this.album[this.currentImageIndex + 1].link; 393 } 394 if (this.currentImageIndex > 0) { 395 var preloadPrev = new Image(); 396 preloadPrev.src = this.album[this.currentImageIndex - 1].link; 397 } 398 }; 399 400 Lightbox.prototype.enableKeyboardNav = function() { 401 $(document).on('keyup.keyboard', $.proxy(this.keyboardAction, this)); 402 }; 403 404 Lightbox.prototype.disableKeyboardNav = function() { 405 $(document).off('.keyboard'); 406 }; 407 408 Lightbox.prototype.keyboardAction = function(event) { 409 var KEYCODE_ESC = 27; 410 var KEYCODE_LEFTARROW = 37; 411 var KEYCODE_RIGHTARROW = 39; 412 413 var keycode = event.keyCode; 414 var key = String.fromCharCode(keycode).toLowerCase(); 415 if (keycode === KEYCODE_ESC || key.match(/x|o|c/)) { 416 this.end(); 417 } else if (key === 'p' || keycode === KEYCODE_LEFTARROW) { 418 if (this.currentImageIndex !== 0) { 419 this.changeImage(this.currentImageIndex - 1); 420 } else if (this.options.wrapAround && this.album.length > 1) { 421 this.changeImage(this.album.length - 1); 422 } 423 } else if (key === 'n' || keycode === KEYCODE_RIGHTARROW) { 424 if (this.currentImageIndex !== this.album.length - 1) { 425 this.changeImage(this.currentImageIndex + 1); 426 } else if (this.options.wrapAround && this.album.length > 1) { 427 this.changeImage(0); 428 } 429 } 430 }; 431 432 // Closing time. :-( 433 Lightbox.prototype.end = function() { 434 this.disableKeyboardNav(); 435 $(window).off('resize', this.sizeOverlay); 436 this.$lightbox.fadeOut(this.options.fadeDuration); 437 this.$overlay.fadeOut(this.options.fadeDuration); 438 $('select, object, embed').css({ 439 visibility: 'visible' 440 }); 441 }; 442 443 return new Lightbox(); 444}));
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.