PageSourceSearch

https://www.ous.ac.jp/common/js/lightbox/lightbox.js

js ous.ac.jp collected 2026-09-24 09:33:34 UTC 18,406 bytes, 516 lines download raw bytes

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

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.