PageSourceSearch

https://www.kumanoyu.co.jp/lift/lightbox/js/lightbox.js

js kumanoyu.co.jp collected 2026-09-24 23:35:27 UTC 18,089 bytes, 508 lines download raw bytes

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

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.