PageSourceSearch

https://njae.net/Public/Home/Js/lightbox.js

js njae.net collected 2026-10-08 19:04:29 UTC 15,088 bytes, 417 lines download raw bytes

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