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