PageSourceSearch

https://www.tracker.it/templates/shaper_helix3/js/lightbox.js

js tracker.it collected 2026-09-24 13:28:46 UTC 18,410 bytes, 519 lines download raw bytes

vendor: 4,971 bytes, lines 1-130
1/*!
2 * Lightbox v2.10.0
3 * by Lokesh Dhakar
4 *
5 * More info:
6 * http://lokeshdhakar.com/projects/lightbox2/
7 *
8 * Copyright 2007, 2018 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    $('<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'));
103
104    // Cache jQuery objects
105    this.$lightbox       = $('#lightbox');
106    this.$overlay        = $('#lightboxOverlay');
107    this.$outerContainer = this.$lightbox.find('.lb-outerContainer');
108    this.$container      = this.$lightbox.find('.lb-container');
109    this.$image          = this.$lightbox.find('.lb-image');
110    this.$nav            = this.$lightbox.find('.lb-nav');
111
112    // Store css values for future lookup
113    this.containerPadding = {
114      top: parseInt(this.$container.css('padding-top'), 10),
115      right: parseInt(this.$container.css('padding-right'), 10),
116      bottom: parseInt(this.$container.css('padding-bottom'), 10),
117      left: parseInt(this.$container.css('padding-left'), 10)
118    };
119
120    this.imageBorderWidth = {
121      top: parseInt(this.$image.css('border-top-width'), 10),
122      right: parseInt(this.$image.css('border-right-width'), 10),
123      bottom: parseInt(this.$image.css('border-bottom-width'), 10),
124      left: parseInt(this.$image.css('border-left-width'), 10)
125    };
126
127    // Attach event handlers to the newly minted DOM elements
128    this.$overlay.hide().on('click', function() {
129      self.end();
130      return false;
131    });
132
133    this.$lightbox.hide().on('click', function(event) {
134      if ($(event.target).attr('id') === 'lightbox') {
135        self.end();
136      }
137      return false;
138    });
139
140    this.$outerContainer.on('click', function(event) {
141      if ($(event.target).attr('id') === 'lightbox') {
142        self.end();
143      }
144      return false;
145    });
146
147    this.$lightbox.find('.lb-prev').on('click', function() {
148      if (self.currentImageIndex === 0) {
149        self.changeImage(self.album.length - 1);
150      } else {
151        self.changeImage(self.currentImageIndex - 1);
152      }
153      return false;
154    });
155
156    this.$lightbox.find('.lb-next').on('click', function() {
157      if (self.currentImageIndex === self.album.length - 1) {
158        self.changeImage(0);
159      } else {
160        self.changeImage(self.currentImageIndex + 1);
161      }
162      return false;
163    });
164
165    /*
166      Show context menu for image on right-click
167
168      There is a div containing the navigation that spans the entire image and lives above of it. If
169      you right-click, you are right clicking this div and not the image. This prevents users from
170      saving the image or using other context menu actions with the image.
171
172      To fix this, when we detect the right mouse button is pressed down, but not yet clicked, we
173      set pointer-events to none on the nav div. This is so that the upcoming right-click event on
174      the next mouseup will bubble down to the image. Once the right-click/contextmenu event occurs
175      we set the pointer events back to auto for the nav div so it can capture hover and left-click
176      events as usual.
177     */
178    this.$nav.on('mousedown', function(event) {
179      if (event.which === 3) {
180        self.$nav.css('pointer-events', 'none');
181
182        self.$lightbox.one('contextmenu', function() {
183          setTimeout(function() {
184              this.$nav.css('pointer-events', 'auto');
185          }.bind(self), 0);
186        });
187      }
188    });
189
190
191    this.$lightbox.find('.lb-loader, .lb-close').on('click', function() {
192      self.end();
193      return false;
194    });
195  };
196
197  // Show overlay and lightbox. If the image is part of a set, add siblings to album array.
198  Lightbox.prototype.start = function($link) {
199    var self    = this;
200    var $window = $(window);
201
202    $window.on('resize', $.proxy(this.sizeOverlay, this));
203
204    $('select, object, embed').css({
205      visibility: 'hidden'
206    });
207
208    this.sizeOverlay();
209
210    this.album = [];
211    var imageNumber = 0;
212
213    function addToAlbum($link) {
214      self.album.push({
215        alt: $link.attr('data-alt'),
216        link: $link.attr('href'),
217        title: $link.attr('data-title') || $link.attr('title')
218      });
219    }
220
221    // Support both data-lightbox attribute and rel attribute implementations
222    var dataLightboxValue = $link.attr('data-lightbox');
223    var $links;
224
225    if (dataLightboxValue) {
226      $links = $($link.prop('tagName') + '[data-lightbox="' + dataLightboxValue + '"]');
227      for (var i = 0; i < $links.length; i = ++i) {
228        addToAlbum($($links[i]));
229        if ($links[i] === $link[0]) {
230          imageNumber = i;
231        }
232      }
233    } else {
234      if ($link.attr('rel') === 'lightbox') {
235        // If image is not part of a set
236        addToAlbum($link);
237      } else {
238        // If image is part of a set
239        $links = $($link.prop('tagName') + '[rel="' + $link.attr('rel') + '"]');
240        for (var j = 0; j < $links.length; j = ++j) {
241          addToAlbum($($links[j]));
242          if ($links[j] === $link[0]) {
243            imageNumber = j;
244          }
245        }
246      }
247    }
248
249    // Position Lightbox
250    var top  = $window.scrollTop() + this.options.positionFromTop;
251    var left = $window.scrollLeft();
252    this.$lightbox.css({
253      top: top + 'px',
254      left: left + 'px'
255    }).fadeIn(this.options.fadeDuration);
256
257    // Disable scrolling of the page while open
258    if (this.options.disableScrolling) {
259      $('html').addClass('lb-disable-scrolling');
260    }
261
262    this.changeImage(imageNumber);
263  };
264
265  // Hide most UI elements in preparation for the animated resizing of the lightbox.
266  Lightbox.prototype.changeImage = function(imageNumber) {
267    var self = this;
268
269    this.disableKeyboardNav();
270    var $image = this.$lightbox.find('.lb-image');
271
272    this.$overlay.fadeIn(this.options.fadeDuration);
273
274    $('.lb-loader').fadeIn('slow');
275    this.$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
276
277    this.$outerContainer.addClass('animating');
278
279    // When image to show is preloaded, we send the width and height to sizeContainer()
280    var preloader = new Image();
281    preloader.onload = function() {
282      var $preloader;
283      var imageHeight;
284      var imageWidth;
285      var maxImageHeight;
286      var maxImageWidth;
287      var windowHeight;
288      var windowWidth;
289
290      $image.attr({
291        'alt': self.album[imageNumber].alt,
292        'src': self.album[imageNumber].link
293      });
294
295      $preloader = $(preloader);
296
297      $image.width(preloader.width);
298      $image.height(preloader.height);
299
300      if (self.options.fitImagesInViewport) {
301        // Fit image inside the viewport.
302        // Take into account the border around the image and an additional 10px gutter on each side.
303
304        windowWidth    = $(window).width();
305        windowHeight   = $(window).height();
306        maxImageWidth  = windowWidth - self.containerPadding.left - self.containerPadding.right - self.imageBorderWidth.left - self.imageBorderWidth.right - 20;
307        maxImageHeight = windowHeight - self.containerPadding.top - self.containerPadding.bottom - self.imageBorderWidth.top - self.imageBorderWidth.bottom - 120;
308
309        // Check if image size is larger then maxWidth|maxHeight in settings
310        if (self.options.maxWidth && self.options.maxWidth < maxImageWidth) {
311          maxImageWidth = self.options.maxWidth;
312        }
313        if (self.options.maxHeight && self.options.maxHeight < maxImageWidth) {
314          maxImageHeight = self.options.maxHeight;
315        }
316
317        // Is the current image's width or height is greater than the maxImageWidth or maxImageHeight
318        // option than we need to size down while maintaining the aspect ratio.
319        if ((preloader.width > maxImageWidth) || (preloader.height > maxImageHeight)) {
320          if ((preloader.width / maxImageWidth) > (preloader.height / maxImageHeight)) {
321            imageWidth  = maxImageWidth;
322            imageHeight = parseInt(preloader.height / (preloader.width / imageWidth), 10);
323            $image.width(imageWidth);
324            $image.height(imageHeight);
325          } else {
326            imageHeight = maxImageHeight;
327            imageWidth = parseInt(preloader.width / (preloader.height / imageHeight), 10);
328            $image.width(imageWidth);
329            $image.height(imageHeight);
330          }
331        }
332      }
333      self.sizeContainer($image.width(), $image.height());
334    };
335
336    preloader.src          = this.album[imageNumber].link;
337    this.currentImageIndex = imageNumber;
338  };
339
340  // Stretch overlay to fit the viewport
341  Lightbox.prototype.sizeOverlay = function() {
342    this.$overlay
343      .width($(document).width())
344      .height($(document).height());
345  };
346
347  // Animate the size of the lightbox to fit the image we are showing
348  Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) {
349    var self = this;
350
351    var oldWidth  = this.$outerContainer.outerWidth();
352    var oldHeight = this.$outerContainer.outerHeight();
353    var newWidth  = imageWidth + this.containerPadding.left + this.containerPadding.right + this.imageBorderWidth.left + this.imageBorderWidth.right;
354    var newHeight = imageHeight + this.containerPadding.top + this.containerPadding.bottom + this.imageBorderWidth.top + this.imageBorderWidth.bottom;
355
356    function postResize() {
357      self.$lightbox.find('.lb-dataContainer').width(newWidth);
358      self.$lightbox.find('.lb-prevLink').height(newHeight);
359      self.$lightbox.find('.lb-nextLink').height(newHeight);
360      self.showImage();
361    }
362
363    if (oldWidth !== newWidth || oldHeight !== newHeight) {
364      this.$outerContainer.animate({
365        width: newWidth,
366        height: newHeight
367      }, this.options.resizeDuration, 'swing', function() {
368        postResize();
369      });
370    } else {
371      postResize();
372    }
373  };
374
375  // Display the image and its details and begin preload neighboring images.
376  Lightbox.prototype.showImage = function() {
377    this.$lightbox.find('.lb-loader').stop(true).hide();
378    this.$lightbox.find('.lb-image').fadeIn(this.options.imageFadeDuration);
379
380    this.updateNav();
381    this.updateDetails();
382    this.preloadNeighboringImages();
383    this.enableKeyboardNav();
384  };
385
386  // Display previous and next navigation if appropriate.
387  Lightbox.prototype.updateNav = function() {
388    // Check to see if the browser supports touch events. If so, we take the conservative approach
389    // and assume that mouse hover events are not supported and always show prev/next navigation
390    // arrows in image sets.
391    var alwaysShowNav = false;
392    try {
393      document.createEvent('TouchEvent');
394      alwaysShowNav = (this.options.alwaysShowNavOnTouchDevices) ? true : false;
395    } catch (e) {}
396
397    this.$lightbox.find('.lb-nav').show();
398
399    if (this.album.length > 1) {
400      if (this.options.wrapAround) {
401        if (alwaysShowNav) {
402          this.$lightbox.find('.lb-prev, .lb-next').css('opacity', '1');
403        }
404        this.$lightbox.find('.lb-prev, .lb-next').show();
405      } else {
406        if (this.currentImageIndex > 0) {
407          this.$lightbox.find('.lb-prev').show();
408          if (alwaysShowNav) {
409            this.$lightbox.find('.lb-prev').css('opacity', '1');
410          }
411        }
412        if (this.currentImageIndex < this.album.length - 1) {
413          this.$lightbox.find('.lb-next').show();
414          if (alwaysShowNav) {
415            this.$lightbox.find('.lb-next').css('opacity', '1');
416          }
417        }
418      }
419    }
420  };
421
422  // Display caption, image number, and closing button.
423  Lightbox.prototype.updateDetails = function() {
424    var self = this;
425
426    // Enable anchor clicks in the injected caption html.
427    // Thanks Nate Wright for the fix. @https://github.com/NateWr
428    if (typeof this.album[this.currentImageIndex].title !== 'undefined' &&
429      this.album[this.currentImageIndex].title !== '') {
430      var $caption = this.$lightbox.find('.lb-caption');
431      if (this.options.sanitizeTitle) {
432        $caption.text(this.album[this.currentImageIndex].title);
433      } else {
434        $caption.html(this.album[this.currentImageIndex].title);
435      }
436      $caption.fadeIn('fast')
437        .find('a').on('click', function(event) {
438          if ($(this).attr('target') !== undefined) {
439            window.open($(this).attr('href'), $(this).attr('target'));
440          } else {
441            location.href = $(this).attr('href');
442          }
443        });
444    }
445
446    if (this.album.length > 1 && this.options.showImageNumberLabel) {
447      var labelText = this.imageCountLabel(this.currentImageIndex + 1, this.album.length);
448      this.$lightbox.find('.lb-number').text(labelText).fadeIn('fast');
449    } else {
450      this.$lightbox.find('.lb-number').hide();
451    }
452
453    this.$outerContainer.removeClass('animating');
454
455    this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() {
456      return self.sizeOverlay();
457    });
458  };
459
460  // Preload previous and next images in set.
461  Lightbox.prototype.preloadNeighboringImages = function() {
462    if (this.album.length > this.currentImageIndex + 1) {
463      var preloadNext = new Image();
464      preloadNext.src = this.album[this.currentImageIndex + 1].link;
465    }
466    if (this.currentImageIndex > 0) {
467      var preloadPrev = new Image();
468      preloadPrev.src = this.album[this.currentImageIndex - 1].link;
469    }
470  };
471
472  Lightbox.prototype.enableKeyboardNav = function() {
473    $(document).on('keyup.keyboard', $.proxy(this.keyboardAction, this));
474  };
475
476  Lightbox.prototype.disableKeyboardNav = function() {
477    $(document).off('.keyboard');
478  };
479
480  Lightbox.prototype.keyboardAction = function(event) {
481    var KEYCODE_ESC        = 27;
482    var KEYCODE_LEFTARROW  = 37;
483    var KEYCODE_RIGHTARROW = 39;
484
485    var keycode = event.keyCode;
486    var key     = String.fromCharCode(keycode).toLowerCase();
487    if (keycode === KEYCODE_ESC || key.match(/x|o|c/)) {
488      this.end();
489    } else if (key === 'p' || keycode === KEYCODE_LEFTARROW) {
490      if (this.currentImageIndex !== 0) {
491        this.changeImage(this.currentImageIndex - 1);
492      } else if (this.options.wrapAround && this.album.length > 1) {
493        this.changeImage(this.album.length - 1);
494      }
495    } else if (key === 'n' || keycode === KEYCODE_RIGHTARROW) {
496      if (this.currentImageIndex !== this.album.length - 1) {
497        this.changeImage(this.currentImageIndex + 1);
498      } else if (this.options.wrapAround && this.album.length > 1) {
499        this.changeImage(0);
500      }
501    }
502  };
503
504  // Closing time. :-(
505  Lightbox.prototype.end = function() {
506    this.disableKeyboardNav();
507    $(window).off('resize', this.sizeOverlay);
508    this.$lightbox.fadeOut(this.options.fadeDuration);
509    this.$overlay.fadeOut(this.options.fadeDuration);
510    $('select, object, embed').css({
511      visibility: 'visible'
512    });
513    if (this.options.disableScrolling) {
514      $('html').removeClass('lb-disable-scrolling');
515    }
516  };
517
518  return new Lightbox();
519}));

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.