PageSourceSearch

https://viktur.ru/lightbox/js/lightbox.js

js viktur.ru collected 2026-10-02 10:26:42 UTC 25,661 bytes, 532 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/* WeBi.Ru - Модернизация
11 [email protected]
12 Документация по этому файлу на моем сайте
13 http://webi.ru/webi.ru/webi_files/javascript/image/lightbox.html
14
15 модернизировал Lightbox, добавил кнопку загрузки картинки в оригинальном размере
16 
17 А так же чтобы исключались дубли картинок, когда картинки показываются как галерея.
18 Дубли ищутся по url картинки.
19 !!! ИСКЛЮЧЕНИЕ ДУБЛЕЙ МОЖНО ИСПОЛЬЗОВАТЬ ТОЛЬКО ПРИ ИСПОЛЬЗОВАНИИ ОДНОЙ ССЫЛКИ ДЛЯ КЛИКА. ТО ЕСТЬ ПО КОТОРОЙ КЛИКНУЛ И ЛИСТАЕШЬ ГАЛЕРЕЮ, 
20 !!! И НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ ПРИ КЛИКАХ НА КАЖДОЙ КАРТИНКЕ, ИНАЧЕ ДУБЛИРУЮЩИЕ КАРТИНКИ ОСТАНУТСЯ БЕЗ КЛИКОВОГО ЭФФЕКТА И БУДЕТ ПРОСТО ПЕРЕХОД НА КАРТИНКУ.
21 !!! НАПРИМЕР ЕСТЬ 100 СКРЫТЫХ ССЫЛОК НА КАРТИНКИ И ОДНА ТОЛЬКО ВИДНА, НА НЕЕ КЛИНУЛ И ЛИСТАЕШЬ. В ЭТОМ СЛУЧАЕ МОЖНО ИСКЛЮЧАТЬ ДУБЛИ.     
22 */
23
24/* Для начала функция поиска в массиве */
25
26// Проверяем, поддерживает ли браузер встроенную функцию поиска по массиву.
27// С помощью пустого массива
28if ([].indexOf) { // Если поддерживает то создаем функцию find_webi и сразу возвращаем результат поиска через эту функцию
29    var find_webi = function(array, value) {
30        return array.indexOf(value);
31    };
32} else { // а если встроенной функции поиска по массиву нет, то сделаем свою, с помощью перебора каждого элемента
33    var find_webi = function(array, value) {
34        for (var i = 0; i<array.length; i++) {
35            if (array[i]===value)
36                return i; // если найдено, возвращается номер элемента, может быть первый элемент - 0
37        }
38        return -1; // ну а если ничего не было найдено, возвращается -1
39    };
40}
41
42
43
44
45
46
47(function() {
48    // Use local alias
49    var $ = jQuery;
50
51    var optionWebi =
52            {
53                'duble_off': false, // исключать дубли картинок. Не рекомендуется включать, только после прочтения документации (http://webi.ru/webi.ru/webi_files/javascript/image/lightbox.html)
54                'full_size_button': true, // показывать кнопку увеличения картинки до оригинального размера
55                'fitImages_next_button': true // после нажатия на кнопку вперед или назад переводить в режим подгона по экрану. В противном случае после увеличения все последующие фото будут показываться в реальном масштабе, пока еще раз не нажать на кнопку увеличения.
56            };
57
58
59    var LightboxOptions = (function() {
60        function LightboxOptions() {
61
62            this.fadeDuration = 500;
63            this.fitImagesInViewport = true; // подгоняет размер под экран
64            this.resizeDuration = 700;
65            this.positionFromTop = 50;
66            this.showImageNumberLabel = true;
67            this.alwaysShowNavOnTouchDevices = false;
68            this.wrapAround = true;
69        }
70
71        // Change to localize to non-english language
72        LightboxOptions.prototype.albumLabel = function(curImageNum, albumSize) {
73            return "Изображение "+curImageNum+" из "+albumSize;
74        };
75
76        return LightboxOptions;
77    })();
78
79
80    var Lightbox = (function() {
81        function Lightbox(options) {
82            this.options = options;
83            this.album = [];
84            this.test_webi_mass = []; // массив для хранения url-ов картинок, чтобы исключить дубли
85            this.currentImageIndex = void 0;
86            this.init();
87        }
88
89        Lightbox.prototype.init = function() {
90            this.enable();
91            this.build();
92        };
93
94        // Loop through anchors and areamaps looking for either data-lightbox attributes or rel attributes
95        // that contain 'lightbox'. When these are clicked, start lightbox.
96        Lightbox.prototype.enable = function() {
97            var self = this;
98            $('body').on('click', 'a[rel^=lightbox], area[rel^=lightbox], a[data-lightbox], area[data-lightbox]', function(event) {
99                self.start($(event.currentTarget));
100                return false;
101            });
102        };
103
104        // Build html for the lightbox and the overlay.
105        // Attach event handlers to the new DOM elements. click click click
106        Lightbox.prototype.build = function() {
107            var self = this;
108            var full_size_button = '';
109            // если нужно выводить кнопку полного размера фото
110            if (optionWebi['full_size_button']) {
111                full_size_button = "<a title='Полный размер' class='lb-fullsize' href='' ></a>";
112            }
113            $("<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 title='Закрыть' class='lb-close'></a>"+full_size_button+"</div></div></div></div>").appendTo($('body'));
114
115            // Cache jQuery objects
116            this.$lightbox = $('#lightbox');
117            this.$overlay = $('#lightboxOverlay');
118            this.$outerContainer = this.$lightbox.find('.lb-outerContainer');
119            this.$container = this.$lightbox.find('.lb-container');
120
121            // Store css values for future lookup
122            this.containerTopPadding = parseInt(this.$container.css('padding-top'), 10);
123            this.containerRightPadding = parseInt(this.$container.css('padding-right'), 10);
124            this.containerBottomPadding = parseInt(this.$container.css('padding-bottom'), 10);
125            this.containerLeftPadding = parseInt(this.$container.css('padding-left'), 10);
126
127            // Attach event handlers to the newly minted DOM elements
128            this.$overlay.hide().on('click', function() {
129                // если при листании фото нужно скидывать масштаб до подгона по экрану, сбросим его и при закрытии иначе при открытии новой картинки не будет сброшен масштаб          
130                    if (optionWebi['fitImages_next_button'])
131                    {
132                        self.options.fitImagesInViewport = true; //сброс увеличения при листаии вперед
133                    }
134                self.end();
135                return false;
136            });
137
138            this.$lightbox.hide().on('click', function(event) {
139                if ($(event.target).attr('id')==='lightbox') {
140                    // если при листании фото нужно скидывать масштаб до подгона по экрану, сбросим его и при закрытии иначе при открытии новой картинки не будет сброшен масштаб          
141                    if (optionWebi['fitImages_next_button'])
142                    {
143                        self.options.fitImagesInViewport = true; //сброс увеличения при листаии вперед
144                    }
145                    self.end();
146                }
147                return false;
148            });
149
150            this.$outerContainer.on('click', function(event) {
151                if ($(event.target).attr('id')==='lightbox') {
152                    
153                    self.end();
154                }
155                return false;
156            });
157
158            this.$lightbox.find('.lb-prev').on('click', function() {
159                // если при листании фото нужно скидывать масштаб до подгона по экрану, сбросим
160                if (optionWebi['fitImages_next_button'])
161                {
162                    self.options.fitImagesInViewport = true;
163                }
164                if (self.currentImageIndex===0) {
165                    self.changeImage(self.album.length-1);
166                } else {
167                    self.changeImage(self.currentImageIndex-1);
168                }
169                return false;
170            });
171
172            this.$lightbox.find('.lb-next').on('click', function() {
173
174                // если при листании фото нужно скидывать масштаб до подгона по экрану, сбросим          
175                if (optionWebi['fitImages_next_button'])
176                {
177                    self.options.fitImagesInViewport = true; //сброс увеличения при листаии вперед
178                }
179                if (self.currentImageIndex===self.album.length-1) {
180                    self.changeImage(0);
181                } else {
182                    self.changeImage(self.currentImageIndex+1);
183                }
184                return false;
185            });
186
187
188            this.$lightbox.find('.lb-fullsize').on('click', function() {
189                // нажатие на кнопку полного просмотра фото
190                // в зависимости от того, что было включено, переключаем размер.
191                // если было полное фото, то ставим масштабирование по эрану, либо наоборот
192                // получится кнопка увеличения работает либо уменьшает, либо увеличивает
193                if (self.options.fitImagesInViewport) {
194                    self.options.fitImagesInViewport = false;
195                }
196                else {
197                    self.options.fitImagesInViewport = true;
198                }
199
200                self.changeImage(self.currentImageIndex);// меняем размер текущей картинки
201
202            });
203
204            this.$lightbox.find('.lb-close').on('click', function() {
205                // если при листании фото нужно скидывать масштаб до подгона по экрану, сбросим его и при нажатии на кнопку закрытия иначе при открытии новой картинки не будет сброшен масштаб          
206                if (optionWebi['fitImages_next_button'])
207                {
208                    self.options.fitImagesInViewport = true; //сброс увеличения при листаии вперед
209                }
210                self.end();
211                return false;
212            });
213
214            this.$lightbox.find('.lb-loader').on('click', function() {
215                self.end();
216                return false;
217            });
218        };
219
220        // Show overlay and lightbox. If the image is part of a set, add siblings to album array.
221        Lightbox.prototype.start = function($link) {
222            var self = this;
223            var $window = $(window);
224
225            $window.on('resize', $.proxy(this.sizeOverlay, this));
226
227            $('select, object, embed').css({
228                visibility: "hidden"
229            });
230
231            this.sizeOverlay();
232
233            this.album = [];
234            this.test_webi_mass = [];
235            var imageNumber = 0;
236
237            function addToAlbum($link) {
238                // здесь происходит добавление новой картинки в массив
239                // поэтому проверим, не была ли добавлена такая картинка ранее      
240                if (optionWebi['duble_off']) // если нужно удаление дублей
241                {
242                    // если URL был найден, выходим из функции       
243                    if (find_webi(self.test_webi_mass, $link.attr('href'))!=-1)
244                    {
245                        return false;
246                    }
247
248                    // ну а если url картинки не был найден, то пошло добавление
249                    // сначала добавим URL в тестовый массив, который хранит только URLы картинок для поиска дублей      
250                    self.test_webi_mass.push($link.attr('href'));
251                }
252
253
254                // а дальше пошло добавление как и должно быть, никаких именений дальше нет
255                self.album.push({
256                    link: $link.attr('href'),
257                    title: $link.attr('data-title')||$link.attr('title')
258                });
259
260            }
261
262            // Support both data-lightbox attribute and rel attribute implementations
263            var dataLightboxValue = $link.attr('data-lightbox');
264            var $links;
265
266            if (dataLightboxValue) {
267                $links = $($link.prop("tagName")+'[data-lightbox="'+dataLightboxValue+'"]');
268                for (var i = 0; i<$links.length; i = ++i) {
269                    addToAlbum($($links[i]));
270                    if ($links[i]===$link[0]) {
271                        imageNumber = i;
272                    }
273                }
274            } else {
275                if ($link.attr('rel')==='lightbox') {
276                    // If image is not part of a set
277                    addToAlbum($link);
278                } else {
279                    // If image is part of a set
280                    $links = $($link.prop("tagName")+'[rel="'+$link.attr('rel')+'"]');
281                    for (var j = 0; j<$links.length; j = ++j) {
282                        addToAlbum($($links[j]));
283                        if ($links[j]===$link[0]) {
284                            imageNumber = j;
285                        }
286                    }
287                }
288            }
289
290            // Position Lightbox
291            var top = $window.scrollTop()+this.options.positionFromTop;
292            var left = $window.scrollLeft();
293            this.$lightbox.css({
294                top: top+'px',
295                left: left+'px'
296            }).fadeIn(this.options.fadeDuration);
297
298            this.changeImage(imageNumber);
299        };
300
301        // Hide most UI elements in preparation for the animated resizing of the lightbox.
302        Lightbox.prototype.changeImage = function(imageNumber) {
303            var self = this;
304
305            this.disableKeyboardNav();
306            var $image = this.$lightbox.find('.lb-image');
307
308            this.$overlay.fadeIn(this.options.fadeDuration);
309
310            $('.lb-loader').fadeIn('slow');
311            this.$lightbox.find('.lb-image, .lb-nav, .lb-prev, .lb-next, .lb-dataContainer, .lb-numbers, .lb-caption').hide();
312
313            this.$outerContainer.addClass('animating');
314
315            // When image to show is preloaded, we send the width and height to sizeContainer()
316            var preloader = new Image();
317            preloader.onload = function() {
318                var $preloader, imageHeight, imageWidth, maxImageHeight, maxImageWidth, windowHeight, windowWidth;
319                $image.attr('src', self.album[imageNumber].link);
320
321                $preloader = $(preloader);
322
323                $image.width(preloader.width);
324                $image.height(preloader.height);
325
326                if (self.options.fitImagesInViewport) {
327                    // Fit image inside the viewport.
328                    // Take into account the border around the image and an additional 10px gutter on each side.
329
330                    windowWidth = $(window).width();
331                    windowHeight = $(window).height();
332                    maxImageWidth = windowWidth-self.containerLeftPadding-self.containerRightPadding-20;
333                    maxImageHeight = windowHeight-self.containerTopPadding-self.containerBottomPadding-120;
334
335                    // Is there a fitting issue?
336                    if ((preloader.width>maxImageWidth)||(preloader.height>maxImageHeight)) {
337                        if ((preloader.width/maxImageWidth)>(preloader.height/maxImageHeight)) {
338                            imageWidth = maxImageWidth;
339                            imageHeight = parseInt(preloader.height/(preloader.width/imageWidth), 10);
340                            $image.width(imageWidth);
341                            $image.height(imageHeight);
342                        } else {
343                            imageHeight = maxImageHeight;
344                            imageWidth = parseInt(preloader.width/(preloader.height/imageHeight), 10);
345                            $image.width(imageWidth);
346                            $image.height(imageHeight);
347                        }
348                    }
349                }
350                self.sizeContainer($image.width(), $image.height());
351            };
352
353            preloader.src = this.album[imageNumber].link;
354            this.currentImageIndex = imageNumber;
355        };
356
357        // Stretch overlay to fit the viewport
358        Lightbox.prototype.sizeOverlay = function() {
359            this.$overlay
360                    .width($(window).width())
361                    .height($(document).height());
362        };
363
364        // Animate the size of the lightbox to fit the image we are showing
365        Lightbox.prototype.sizeContainer = function(imageWidth, imageHeight) {
366            var self = this;
367
368            var oldWidth = this.$outerContainer.outerWidth();
369            var oldHeight = this.$outerContainer.outerHeight();
370            var newWidth = imageWidth+this.containerLeftPadding+this.containerRightPadding;
371            var newHeight = imageHeight+this.containerTopPadding+this.containerBottomPadding;
372
373            function postResize() {
374                self.$lightbox.find('.lb-dataContainer').width(newWidth);
375                self.$lightbox.find('.lb-prevLink').height(newHeight);
376                self.$lightbox.find('.lb-nextLink').height(newHeight);
377                self.showImage();
378            }
379
380            if (oldWidth!==newWidth||oldHeight!==newHeight) {
381                this.$outerContainer.animate({
382                    width: newWidth,
383                    height: newHeight
384                }, this.options.resizeDuration, 'swing', function() {
385                    postResize();
386                });
387            } else {
388                postResize();
389            }
390        };
391
392        // Display the image and it's details and begin preload neighboring images.
393        Lightbox.prototype.showImage = function() {
394            this.$lightbox.find('.lb-loader').hide();
395            this.$lightbox.find('.lb-image').fadeIn('slow');
396
397            this.updateNav();
398            this.updateDetails();
399            this.preloadNeighboringImages();
400            this.enableKeyboardNav();
401        };
402
403        // Display previous and next navigation if appropriate.
404        Lightbox.prototype.updateNav = function() {
405            // Check to see if the browser supports touch events. If so, we take the conservative approach
406            // and assume that mouse hover events are not supported and always show prev/next navigation
407            // arrows in image sets.
408            var alwaysShowNav = false;
409            try {
410                document.createEvent("TouchEvent");
411                alwaysShowNav = (this.options.alwaysShowNavOnTouchDevices) ? true : false;
412            } catch (e) {
413            }
414
415            this.$lightbox.find('.lb-nav').show();
416
417            if (this.album.length>1) {
418                if (this.options.wrapAround) {
419                    if (alwaysShowNav) {
420                        this.$lightbox.find('.lb-prev, .lb-next').css('opacity', '1');
421                    }
422                    this.$lightbox.find('.lb-prev, .lb-next').show();
423                } else {
424                    if (this.currentImageIndex>0) {
425                        this.$lightbox.find('.lb-prev').show();
426                        if (alwaysShowNav) {
427                            this.$lightbox.find('.lb-prev').css('opacity', '1');
428                        }
429                    }
430                    if (this.currentImageIndex<this.album.length-1) {
431                        this.$lightbox.find('.lb-next').show();
432                        if (alwaysShowNav) {
433                            this.$lightbox.find('.lb-next').css('opacity', '1');
434                        }
435                    }
436                }
437            }
438        };
439
440        // Display caption, image number, and closing button.
441        Lightbox.prototype.updateDetails = function() {
442            var self = this;
443
444            // Enable anchor clicks in the injected caption html.
445            // Thanks Nate Wright for the fix. @https://github.com/NateWr
446            if (typeof this.album[this.currentImageIndex].title!=='undefined'&&this.album[this.currentImageIndex].title!=="") {
447                this.$lightbox.find('.lb-caption')
448                        .html(this.album[this.currentImageIndex].title)
449                        .fadeIn('fast')
450                        .find('a').on('click', function(event) {
451                    location.href = $(this).attr('href');
452                });
453            }
454
455            if (this.album.length>1&&this.options.showImageNumberLabel) {
456                this.$lightbox.find('.lb-number').text(this.options.albumLabel(this.currentImageIndex+1, this.album.length)).fadeIn('fast');
457            } else {
458                this.$lightbox.find('.lb-number').hide();
459            }
460
461            this.$outerContainer.removeClass('animating');
462
463            this.$lightbox.find('.lb-dataContainer').fadeIn(this.options.resizeDuration, function() {
464                return self.sizeOverlay();
465            });
466        };
467
468        // Preload previous and next images in set.
469        Lightbox.prototype.preloadNeighboringImages = function() {
470            if (this.album.length>this.currentImageIndex+1) {
471                var preloadNext = new Image();
472                preloadNext.src = this.album[this.currentImageIndex+1].link;
473            }
474            if (this.currentImageIndex>0) {
475                var preloadPrev = new Image();
476                preloadPrev.src = this.album[this.currentImageIndex-1].link;
477            }
478        };
479
480        Lightbox.prototype.enableKeyboardNav = function() {
481            $(document).on('keyup.keyboard', $.proxy(this.keyboardAction, this));
482        };
483
484        Lightbox.prototype.disableKeyboardNav = function() {
485            $(document).off('.keyboard');
486        };
487
488        Lightbox.prototype.keyboardAction = function(event) {
489            var KEYCODE_ESC = 27;
490            var KEYCODE_LEFTARROW = 37;
491            var KEYCODE_RIGHTARROW = 39;
492
493            var keycode = event.keyCode;
494            var key = String.fromCharCode(keycode).toLowerCase();
495            if (keycode===KEYCODE_ESC||key.match(/x|o|c/)) {
496                this.end();
497            } else if (key==='p'||keycode===KEYCODE_LEFTARROW) {
498                if (this.currentImageIndex!==0) {
499                    this.changeImage(this.currentImageIndex-1);
500                } else if (this.options.wrapAround&&this.album.length>1) {
501                    this.changeImage(this.album.length-1);
502                }
503            } else if (key==='n'||keycode===KEYCODE_RIGHTARROW) {
504                if (this.currentImageIndex!==this.album.length-1) {
505                    this.changeImage(this.currentImageIndex+1);
506                } else if (this.options.wrapAround&&this.album.length>1) {
507                    this.changeImage(0);
508                }
509            }
510        };
511
512        // Closing time. :-(
513        Lightbox.prototype.end = function() {
514            this.disableKeyboardNav();
515            $(window).off("resize", this.sizeOverlay);
516            this.$lightbox.fadeOut(this.options.fadeDuration);
517            this.$overlay.fadeOut(this.options.fadeDuration);
518            $('select, object, embed').css({
519                visibility: "visible"
520            });
521        };
522
523        return Lightbox;
524
525    })();
526
527    $(function() {
528        var options = new LightboxOptions();
529        var lightbox = new Lightbox(options);
530    });
531
532}).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.