PageSourceSearch

https://littlerockhall.com/wp-content/themes/marathonmusicworks-v2/js/lightbox.js?ver=7.0.5

js littlerockhall.com collected 2026-10-01 14:50:47 UTC 20,097 bytes, 554 lines download raw bytes

vendor: 5,639 bytes, lines 1-142
1/*!
2 * Lightbox v2.11.2
3 * by Lokesh Dhakar
4 *
5 * More info:
6 * http://lokeshdhakar.com/projects/lightbox2/
7 *
8 * Copyright Lokesh Dhakar
9 * Released under the MIT license
10 * https://github.com/lokesh/lightbox2/blob/master/LICENSE
11 *
12 * @preserve
13 */
14
15// Uses Node, AMD or browser globals to create a module.
16(function (root, factory) {
17    if (typeof define === 'function' && define.amd) {
18        // AMD. Register as an anonymous module.
19        define(['jquery'], factory);
20    } else if (typeof exports === 'object') {
21        // Node. Does not work with strict CommonJS, but
22        // only CommonJS-like environments that support module.exports,
23        // like Node.
24        module.exports = factory(require('jquery'));
25    } else {
26        // Browser globals (root is window)
27        root.lightbox = factory(root.jQuery);
28    }
29}(this, function ($) {
30
31  function Lightbox(options) {
32    this.album = [];
33    this.currentImageIndex = void 0;
34    this.init();
35
36    // options
37    this.options = $.extend({}, this.constructor.defaults);
38    this.option(options);
39  }
40
41  // Descriptions of all options available on the demo site:
42  // http://lokeshdhakar.com/projects/lightbox2/index.html#options
43  Lightbox.defaults = {
44    albumLabel: 'Image %1 of %2',
45    alwaysShowNavOnTouchDevices: false,
46    fadeDuration: 600,
47    fitImagesInViewport: true,
48    imageFadeDuration: 600,
49    // maxWidth: 800,
50    // maxHeight: 600,
51    positionFromTop: 50,
52    resizeDuration: 700,
53    showImageNumberLabel: true,
54    wrapAround: false,
55    disableScrolling: false,
56    /*
57    Sanitize Title
58    If the caption data is trusted, for example you are hardcoding it in, then leave this to false.
59    This will free you to add html tags, such as links, in the caption.
60
61    If the caption data is user submitted or from some other untrusted source, then set this to true
62    to prevent xss and other injection attacks.
63     */
64    sanitizeTitle: false
65  };
66
67  Lightbox.prototype.option = function(options) {
68    $.extend(this.options, options);
69  };
70
71  Lightbox.prototype.imageCountLabel = function(currentImageNum, totalImages) {
72    return this.options.albumLabel.replace(/%1/g, currentImageNum).replace(/%2/g, totalImages);
73  };
74
75  Lightbox.prototype.init = function() {
76    var self = this;
77    // Both enable and build methods require the body tag to be in the DOM.
78    $(document).ready(function() {
79      self.enable();
80      self.build();
81    });
82  };
83
84  // Loop through anchors and areamaps looking for either data-lightbox attributes or rel attributes
85  // that contain 'lightbox'. When these are clicked, start lightbox.
86  Lightbox.prototype.enable = function() {
87    var self = this;
88    $('body').on('click', 'a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]', function(event) {
89      self.start($(event.currentTarget));
90      return false;
91    });
92  };
93
94  // Build html for the lightbox and the overlay.
95  // Attach event handlers to the new DOM elements. click click click
96  Lightbox.prototype.build = function() {
97    if ($('#lightbox').length > 0) {
98        return;
99    }
100
101    var self = this;
102
103    // The two root notes generated, #lightboxOverlay and #lightbox are given
104    // tabindex attrs so they are focusable. We attach our keyboard event
105    // listeners to these two elements, and not the document. Clicking anywhere
106    // while Lightbox is opened will keep the focus on or inside one of these
107    // two elements.
108    //
109    // We do this so we can prevent propogation of the Esc keypress when
110    // Lightbox is open. This prevents it from intefering with other components
111    // on the page below.
112    //
113    // Github issue: https://github.com/lokesh/lightbox2/issues/663
114    $('<div id="lightboxOverlay" tabindex="-1" class="lightboxOverlay"></div><div id="lightbox" tabindex="-1" class="lightbox"><div class="lb-outerContainer"><div class="lb-container"><img class="lb-image" src="data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==" alt=""/><div class="lb-nav"><a class="lb-prev" aria-label="Previous image" href="" ></a><a class="lb-next" aria-label="Next image" 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'));
115
116    // Cache jQuery objects
117    this.$lightbox       = $('#lightbox');
118    this.$overlay        = $('#lightboxOverlay');
119    this.$outerContainer = this.$lightbox.find('.lb-outerContainer');
120    this.$container      = this.$lightbox.find('.lb-container');
121    this.$image          = this.$lightbox.find('.lb-image');
122    this.$nav            = this.$lightbox.find('.lb-nav');
123
124    // Store css values for future lookup
125    this.containerPadding = {
126      top: parseInt(this.$container.css('padding-top'), 10),
127      right: parseInt(this.$container.css('padding-right'), 10),
128      bottom: parseInt(this.$container.css('padding-bottom'), 10),
129      left: parseInt(this.$container.css('padding-left'), 10)
130    };
131
132    this.imageBorderWidth = {
133      top: parseInt(this.$image.css('border-top-width'), 10),
134      right: parseInt(this.$image.css('border-right-width'), 10),
135      bottom: parseInt(this.$image.css('border-bottom-width'), 10),
136      left: parseInt(this.$image.css('border-left-width'), 10)
137    };
138
139    // Attach event handlers to the newly minted DOM elements
140    this.$overlay.hide().on('click', function() {
141      self.end();
142      return false;
143    });
144
145    this.$lightbox.hide().on('click', function(event) {
146      if ($(event.target).attr('id') === 'lightbox') {
147        self.end();
148      }
149    });
150
151    this.$outerContainer.on('click', function(event) {
152      if ($(event.target).attr('id') === 'lightbox') {
153        self.end();
154      }
155      return false;
156    });
157
158    this.$lightbox.find('.lb-prev').on('click', function() {
159      if (self.currentImageIndex === 0) {
160        self.changeImage(self.album.length - 1);
161      } else {
162        self.changeImage(self.currentImageIndex - 1);
163      }
164      return false;
165    });
166
167    this.$lightbox.find('.lb-next').on('click', function() {
168      if (self.currentImageIndex === self.album.length - 1) {
169        self.changeImage(0);
170      } else {
171        self.changeImage(self.currentImageIndex + 1);
172      }
173      return false;
174    });
175
176    /*
177      Show context menu for image on right-click
178
179      There is a div containing the navigation that spans the entire image and lives above of it. If
180      you right-click, you are right clicking this div and not the image. This prevents users from
181      saving the image or using other context menu actions with the image.
182
183      To fix this, when we detect the right mouse button is pressed down, but not yet clicked, we
184      set pointer-events to none on the nav div. This is so that the upcoming right-click event on
185      the next mouseup will bubble down to the image. Once the right-click/contextmenu event occurs
186      we set the pointer events back to auto for the nav div so it can capture hover and left-click
187      events as usual.
188     */
189    this.$nav.on('mousedown', function(event) {
190      if (event.which === 3) {
191        self.$nav.css('pointer-events', 'none');
192
193        self.$lightbox.one('contextmenu', function() {
194          setTimeout(function() {
195              this.$nav.css('pointer-events', 'auto');
196          }.bind(self), 0);
197        });
198      }
199    });
200
201
202    this.$lightbox.find('.lb-loader, .lb-close').on('click', function() {
203      self.end();
204      return false;
205    });
206  };
207
208  // Show overlay and lightbox. If the image is part of a set, add siblings to album array.
209  Lightbox.prototype.start = function($link) {
210    var self    = this;
211    var $window = $(window);
212
213    $window.on('resize', $.proxy(this.sizeOverlay, this));
214
215    this.sizeOverlay();
216
217    this.album = [];
218    var imageNumber = 0;
219
220    function addToAlbum($link) {
221      self.album.push({
222        alt: $link.attr('data-alt'),
223        link: $link.attr('href'),
224        title: $link.attr('data-title') || $link.attr('title')
225      });
226    }
227
228    // Support both data-lightbox attribute and rel attribute implementations
229    var dataLightboxValue = $link.attr('data-lightbox');
230    var $links;
231
232    if (dataLightboxValue) {
233      $links = $($link.prop('tagName') + '[data-lightbox="' + dataLightboxValue + '"]');
234      for (var i = 0; i < $links.length; i = ++i) {
235        addToAlbum($($links[i]));
236        if ($links[i] === $link[0]) {
237          imageNumber = i;
238        }
239      }
240    } else {
241      if ($link.attr('rel') === 'lightbox') {
242        // If image is not part of a set
243        addToAlbum($link);
244      } else {
245        // If image is part of a set
246        $links = $($link.prop('tagName') + '[rel="' + $link.attr('rel') + '"]');
247        for (var j = 0; j < $links.length; j = ++j) {
248          addToAlbum($($links[j]));
249          if ($links[j] === $link[0]) {
250            imageNumber = j;
251          }
252        }
253      }
254    }
255
256    // Position Lightbox
257    var top  = $window.scrollTop() + this.options.positionFromTop;
258    var left = $window.scrollLeft();
259    this.$lightbox.css({
260      top: top + 'px',
261      left: left + 'px'
262    }).fadeIn(this.options.fadeDuration);
263
264    // Disable scrolling of the page while open
265    if (this.options.disableScrolling) {
266      $('body').addClass('lb-disable-scrolling');
267    }
268
269    this.changeImage(imageNumber);
270  };
271
272  // Hide most UI elements in preparation for the animated resizing of the lightbox.
273  Lightbox.prototype.changeImage = function(imageNumber) {
274    var self = this;
275    var filename = this.album[imageNumber].link;
276    var filetype = filename.split('.').slice(-1)[0];
277    var $image = this.$lightbox.find('.lb-image');
278
279    // Disable keyboard nav during transitions
280    this.disableKeyboardNav();
281
282    // Show loading state
283    this.$overlay.fadeIn(this.options.fadeDuration);
284    $('.lb-loader').fadeIn('slow');
285    this.$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
286    this.$outerContainer.addClass('animating');
287
288    // When image to show is preloaded, we send the width and height to sizeContainer()
289    var preloader = new Image();
290    preloader.onload = function() {
291      var $preloader;
292      var imageHeight;
293      var imageWidth;
294      var maxImageHeight;
295      var maxImageWidth;
296      var windowHeight;
297      var windowWidth;
298
299      $image.attr({
300        'alt': self.album[imageNumber].alt,
301        'src': filename
302      });
303
304      $preloader = $(preloader);
305
306      $image.width(preloader.width);
307      $image.height(preloader.height);
308      windowWidth = $(window).width();
309      windowHeight = $(window).height();
310
311      // Calculate the max image dimensions for the current viewport.
312      // Take into account the border around the image and an additional 10px gutter on each side.
313      maxImageWidth  = windowWidth - self.containerPadding.left - self.containerPadding.right - self.imageBorderWidth.left - self.imageBorderWidth.right - 20;
314      maxImageHeight = windowHeight - self.containerPadding.top - self.containerPadding.bottom - self.imageBorderWidth.top - self.imageBorderWidth.bottom - self.options.positionFromTop - 70;
315
316      /*
317      Since many SVGs have small intrinsic dimensions, but they support scaling
318      up without quality loss because of their vector format, max out their
319      size.
320      */
321      if (filetype === 'svg') {
322        $image.width(maxImageWidth);
323        $image.height(maxImageHeight);
324      }
325
326      // Fit image inside the viewport.
327      if (self.options.fitImagesInViewport) {
328
329        // Check if image size is larger then maxWidth|maxHeight in settings
330        if (self.options.maxWidth && self.options.maxWidth < maxImageWidth) {
331          maxImageWidth = self.options.maxWidth;
332        }
333        if (self.options.maxHeight && self.options.maxHeight < maxImageHeight) {
334          maxImageHeight = self.options.maxHeight;
335        }
336
337      } else {
338        maxImageWidth = self.options.maxWidth || preloader.width || maxImageWidth;
339        maxImageHeight = self.options.maxHeight || preloader.height || maxImageHeight;
340      }
341
342      // Is the current image's width or height is greater than the maxImageWidth or maxImageHeight
343      // option than we need to size down while maintaining the aspect ratio.
344      if ((preloader.width > maxImageWidth) || (preloader.height > maxImageHeight)) {
345        if ((preloader.width / maxImageWidth) > (preloader.height / maxImageHeight)) {
346          imageWidth  = maxImageWidth;
347          imageHeight = parseInt(preloader.height / (preloader.width / imageWidth), 10);
348          $image.width(imageWidth);
349          $image.height(imageHeight);
350        } else {
351          imageHeight = maxImageHeight;
352          imageWidth = parseInt(preloader.width / (preloader.height / imageHeight), 10);
353          $image.width(imageWidth);
354          $image.height(imageHeight);
355        }
356      }
357      self.sizeContainer($image.width(), $image.height());
358    };
359
360    // Preload image before showing
361    preloader.src = this.album[imageNumber].link;
362    this.currentImageIndex = imageNumber;
363  };
364
365  // Stretch overlay to fit the viewport
366  Lightbox.prototype.sizeOverlay = function() {
367    var self = this;
368    /*
369    We use a setTimeout 0 to pause JS execution and let the rendering catch-up.
370    Why do this? If the `disableScrolling` option is set to true, a class is added to the body
371    tag that disables scrolling and hides the scrollbar. We want to make sure the scrollbar is
372    hidden before we measure the document width, as the presence of the scrollbar will affect the
373    number.
374    */
375    setTimeout(function() {
376      self.$overlay
377        .width($(document).width())
378        .height($(document).height());
379
380    }, 0);
381  };
382
383  // Animate the size of the lightbox to fit the image we are showing
384  // This method also shows the the image.
385  Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) {
386    var self = this;
387
388    var oldWidth  = this.$outerContainer.outerWidth();
389    var oldHeight = this.$outerContainer.outerHeight();
390    var newWidth  = imageWidth + this.containerPadding.left + this.containerPadding.right + this.imageBorderWidth.left + this.imageBorderWidth.right;
391    var newHeight = imageHeight + this.containerPadding.top + this.containerPadding.bottom + this.imageBorderWidth.top + this.imageBorderWidth.bottom;
392
393    function postResize() {
394      self.$lightbox.find('.lb-dataContainer').width(newWidth);
395      self.$lightbox.find('.lb-prevLink').height(newHeight);
396      self.$lightbox.find('.lb-nextLink').height(newHeight);
397
398      // Set focus on one of the two root nodes so keyboard events are captured.
399      self.$overlay.focus();
400
401      self.showImage();
402    }
403
404    if (oldWidth !== newWidth || oldHeight !== newHeight) {
405      this.$outerContainer.animate({
406        width: newWidth,
407        height: newHeight
408      }, this.options.resizeDuration, 'swing', function() {
409        postResize();
410      });
411    } else {
412      postResize();
413    }
414  };
415
416  // Display the image and its details and begin preload neighboring images.
417  Lightbox.prototype.showImage = function() {
418    this.$lightbox.find('.lb-loader').stop(true).hide();
419    this.$lightbox.find('.lb-image').fadeIn(this.options.imageFadeDuration);
420
421    this.updateNav();
422    this.updateDetails();
423    this.preloadNeighboringImages();
424    this.enableKeyboardNav();
425  };
426
427  // Display previous and next navigation if appropriate.
428  Lightbox.prototype.updateNav = function() {
429    // Check to see if the browser supports touch events. If so, we take the conservative approach
430    // and assume that mouse hover events are not supported and always show prev/next navigation
431    // arrows in image sets.
432    var alwaysShowNav = false;
433    try {
434      document.createEvent('TouchEvent');
435      alwaysShowNav = (this.options.alwaysShowNavOnTouchDevices) ? true : false;
436    } catch (e) {}
437
438    this.$lightbox.find('.lb-nav').show();
439
440    if (this.album.length > 1) {
441      if (this.options.wrapAround) {
442        if (alwaysShowNav) {
443          this.$lightbox.find('.lb-prev, .lb-next').css('opacity', '1');
444        }
445        this.$lightbox.find('.lb-prev, .lb-next').show();
446      } else {
447        if (this.currentImageIndex > 0) {
448          this.$lightbox.find('.lb-prev').show();
449          if (alwaysShowNav) {
450            this.$lightbox.find('.lb-prev').css('opacity', '1');
451          }
452        }
453        if (this.currentImageIndex < this.album.length - 1) {
454          this.$lightbox.find('.lb-next').show();
455          if (alwaysShowNav) {
456            this.$lightbox.find('.lb-next').css('opacity', '1');
457          }
458        }
459      }
460    }
461  };
462
463  // Display caption, image number, and closing button.
464  Lightbox.prototype.updateDetails = function() {
465    var self = this;
466
467    // Enable anchor clicks in the injected caption html.
468    // Thanks Nate Wright for the fix. @https://github.com/NateWr
469    if (typeof this.album[this.currentImageIndex].title !== 'undefined' &&
470      this.album[this.currentImageIndex].title !== '') {
471      var $caption = this.$lightbox.find('.lb-caption');
472      if (this.options.sanitizeTitle) {
473        $caption.text(this.album[this.currentImageIndex].title);
474      } else {
475        $caption.html(this.album[this.currentImageIndex].title);
476      }
477      $caption.fadeIn('fast');
478    }
479
480    if (this.album.length > 1 && this.options.showImageNumberLabel) {
481      var labelText = this.imageCountLabel(this.currentImageIndex + 1, this.album.length);
482      this.$lightbox.find('.lb-number').text(labelText).fadeIn('fast');
483    } else {
484      this.$lightbox.find('.lb-number').hide();
485    }
486
487    this.$outerContainer.removeClass('animating');
488
489    this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() {
490      return self.sizeOverlay();
491    });
492  };
493
494  // Preload previous and next images in set.
495  Lightbox.prototype.preloadNeighboringImages = function() {
496    if (this.album.length > this.currentImageIndex + 1) {
497      var preloadNext = new Image();
498      preloadNext.src = this.album[this.currentImageIndex + 1].link;
499    }
500    if (this.currentImageIndex > 0) {
501      var preloadPrev = new Image();
502      preloadPrev.src = this.album[this.currentImageIndex - 1].link;
503    }
504  };
505
506  Lightbox.prototype.enableKeyboardNav = function() {
507    this.$lightbox.on('keyup.keyboard', $.proxy(this.keyboardAction, this));
508    this.$overlay.on('keyup.keyboard', $.proxy(this.keyboardAction, this));
509  };
510
511  Lightbox.prototype.disableKeyboardNav = function() {
512    this.$lightbox.off('.keyboard');
513    this.$overlay.off('.keyboard');
514  };
515
516  Lightbox.prototype.keyboardAction = function(event) {
517    var KEYCODE_ESC        = 27;
518    var KEYCODE_LEFTARROW  = 37;
519    var KEYCODE_RIGHTARROW = 39;
520
521    var keycode = event.keyCode;
522    if (keycode === KEYCODE_ESC) {
523      // Prevent bubbling so as to not affect other components on the page.
524      event.stopPropagation();
525      this.end();
526    } else if (keycode === KEYCODE_LEFTARROW) {
527      if (this.currentImageIndex !== 0) {
528        this.changeImage(this.currentImageIndex - 1);
529      } else if (this.options.wrapAround && this.album.length > 1) {
530        this.changeImage(this.album.length - 1);
531      }
532    } else if (keycode === KEYCODE_RIGHTARROW) {
533      if (this.currentImageIndex !== this.album.length - 1) {
534        this.changeImage(this.currentImageIndex + 1);
535      } else if (this.options.wrapAround && this.album.length > 1) {
536        this.changeImage(0);
537      }
538    }
539  };
540
541  // Closing time. :-(
542  Lightbox.prototype.end = function() {
543    this.disableKeyboardNav();
544    $(window).off('resize', this.sizeOverlay);
545    this.$lightbox.fadeOut(this.options.fadeDuration);
546    this.$overlay.fadeOut(this.options.fadeDuration);
547
548    if (this.options.disableScrolling) {
549      $('body').removeClass('lb-disable-scrolling');
550    }
551  };
552
553  return new Lightbox();
554}));

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.