PageSourceSearch

https://www.hotelflamingo.it/wp-content/plugins/blueimp-lightbox/js/blueimp-gallery.js?ver=1.0.0

js hotelflamingo.it collected 2026-10-04 13:26:18 UTC 53,947 bytes, 1,341 lines download raw bytes

1/*
2 * blueimp Gallery JS 2.14.0
3 * https://github.com/blueimp/Gallery
4 *
5 * Copyright 2013, Sebastian Tschan
6 * https://blueimp.net
7 *
8 * Swipe implementation based on
9 * https://github.com/bradbirdsall/Swipe
10 *
11 * Licensed under the MIT license:
12 * http://www.opensource.org/licenses/MIT
13 */
14
15/* global define, window, document, DocumentTouch */
16
17(function (factory) {
18    'use strict';
19    if (typeof define === 'function' && define.amd) {
20        // Register as an anonymous AMD module:
21        define(['./blueimp-helper'], factory);
22    } else {
23        // Browser globals:
24        window.blueimp = window.blueimp || {};
25        window.blueimp.Gallery = factory(
26            window.blueimp.helper || window.jQuery
27        );
28    }
29}(function ($) {
30    'use strict';
31
32    function Gallery(list, options) {
33        if (document.body.style.maxHeight === undefined) {
34            // document.body.style.maxHeight is undefined on IE6 and lower
35            return null;
36        }
37        if (!this || this.options !== Gallery.prototype.options) {
38            // Called as function instead of as constructor,
39            // so we simply return a new instance:
40            return new Gallery(list, options);
41        }
42        if (!list || !list.length) {
43            this.console.log(
44                'blueimp Gallery: No or empty list provided as first argument.',
45                list
46            );
47            return;
48        }
49        this.list = list;
50        this.num = list.length;
51        this.initOptions(options);
52        this.initialize();
53    }
54
55    $.extend(Gallery.prototype, {
56
57        options: {
58            // The Id, element or querySelector of the gallery widget:
59            container: '#blueimp-gallery',
60            // The tag name, Id, element or querySelector of the slides container:
61            slidesContainer: 'div',
62            // The tag name, Id, element or querySelector of the title element:
63            titleElement: 'h3',
64            // The class to add when the gallery is visible:
65            displayClass: 'blueimp-gallery-display',
66            // The class to add when the gallery controls are visible:
67            controlsClass: 'blueimp-gallery-controls',
68            // The class to add when the gallery only displays one element:
69            singleClass: 'blueimp-gallery-single',
70            // The class to add when the left edge has been reached:
71            leftEdgeClass: 'blueimp-gallery-left',
72            // The class to add when the right edge has been reached:
73            rightEdgeClass: 'blueimp-gallery-right',
74            // The class to add when the automatic slideshow is active:
75            playingClass: 'blueimp-gallery-playing',
76            // The class for all slides:
77            slideClass: 'slide',
78            // The slide class for loading elements:
79            slideLoadingClass: 'slide-loading',
80            // The slide class for elements that failed to load:
81            slideErrorClass: 'slide-error',
82            // The class for the content element loaded into each slide:
83            slideContentClass: 'slide-content',
84            // The class for the "toggle" control:
85            toggleClass: 'toggle',
86            // The class for the "prev" control:
87            prevClass: 'prev',
88            // The class for the "next" control:
89            nextClass: 'next',
90            // The class for the "close" control:
91            closeClass: 'close',
92            // The class for the "play-pause" toggle control:
93            playPauseClass: 'play-pause',
94            // The list object property (or data attribute) with the object type:
95            typeProperty: 'type',
96            // The list object property (or data attribute) with the object title:
97            titleProperty: 'title',
98            // The list object property (or data attribute) with the object URL:
99            urlProperty: 'href',
100            // The gallery listens for transitionend events before triggering the
101            // opened and closed events, unless the following option is set to false:
102            displayTransition: true,
103            // Defines if the gallery slides are cleared from the gallery modal,
104            // or reused for the next gallery initialization:
105            clearSlides: true,
106            // Defines if images should be stretched to fill the available space,
107            // while maintaining their aspect ratio (will only be enabled for browsers
108            // supporting background-size="contain", which excludes IE < 9).
109            // Set to "cover", to make images cover all available space (requires
110            // support for background-size="cover", which excludes IE < 9):
111            stretchImages: false,
112            // Toggle the controls on pressing the Return key:
113            toggleControlsOnReturn: true,
114            // Toggle the automatic slideshow interval on pressing the Space key:
115            toggleSlideshowOnSpace: true,
116            // Navigate the gallery by pressing left and right on the keyboard:
117            enableKeyboardNavigation: true,
118            // Close the gallery on pressing the Esc key:
119            closeOnEscape: true,
120            // Close the gallery when clicking on an empty slide area:
121            closeOnSlideClick: true,
122            // Close the gallery by swiping up or down:
123            closeOnSwipeUpOrDown: true,
124            // Emulate touch events on mouse-pointer devices such as desktop browsers:
125            emulateTouchEvents: true,
126            // Stop touch events from bubbling up to ancestor elements of the Gallery:
127            stopTouchEventsPropagation: false,
128            // Hide the page scrollbars: 
129            hidePageScrollbars: true,
130            // Stops any touches on the container from scrolling the page:
131            disableScroll: true,
132            // Carousel mode (shortcut for carousel specific options):
133            carousel: false,
134            // Allow continuous navigation, moving from last to first
135            // and from first to last slide:
136            continuous: true,
137            // Remove elements outside of the preload range from the DOM:
138            unloadElements: true,
139            // Start with the automatic slideshow:
140            startSlideshow: false,
141            // Delay in milliseconds between slides for the automatic slideshow:
142            slideshowInterval: 5000,
143            // The starting index as integer.
144            // Can also be an object of the given list,
145            // or an equal object with the same url property:
146            index: 0,
147            // The number of elements to load around the current index:
148            preloadRange: 2,
149            // The transition speed between slide changes in milliseconds:
150            transitionSpeed: 400,
151            // The transition speed for automatic slide changes, set to an integer
152            // greater 0 to override the default transition speed:
153            slideshowTransitionSpeed: undefined,
154            // The event object for which the default action will be canceled
155            // on Gallery initialization (e.g. the click event to open the Gallery):
156            event: undefined,
157            // Callback function executed when the Gallery is initialized.
158            // Is called with the gallery instance as "this" object:
159            onopen: undefined,
160            // Callback function executed when the Gallery has been initialized
161            // and the initialization transition has been completed.
162            // Is called with the gallery instance as "this" object:
163            onopened: undefined,
164            // Callback function executed on slide change.
165            // Is called with the gallery instance as "this" object and the
166            // current index and slide as arguments:
167            onslide: undefined,
168            // Callback function executed after the slide change transition.
169            // Is called with the gallery instance as "this" object and the
170            // current index and slide as arguments:
171            onslideend: undefined,
172            // Callback function executed on slide content load.
173            // Is called with the gallery instance as "this" object and the
174            // slide index and slide element as arguments:
175            onslidecomplete: undefined,
176            // Callback function executed when the Gallery is about to be closed.
177            // Is called with the gallery instance as "this" object:
178            onclose: undefined,
179            // Callback function executed when the Gallery has been closed
180            // and the closing transition has been completed.
181            // Is called with the gallery instance as "this" object:
182            onclosed: undefined
183        },
184
185        carouselOptions: {
186            hidePageScrollbars: false,
187            toggleControlsOnReturn: false,
188            toggleSlideshowOnSpace: false,
189            enableKeyboardNavigation: false,
190            closeOnEscape: false,
191            closeOnSlideClick: false,
192            closeOnSwipeUpOrDown: false,
193            disableScroll: false,
194            startSlideshow: true
195        },
196
197        console: window.console && typeof window.console.log === 'function' ?
198            window.console :
199            {log: function () {}},
200
201        // Detect touch, transition, transform and background-size support:
202        support: (function (element) {
203            var support = {
204                    touch: window.ontouchstart !== undefined ||
205                        (window.DocumentTouch && document instanceof DocumentTouch)
206                },
207                transitions = {
208                    webkitTransition: {
209                        end: 'webkitTransitionEnd',
210                        prefix: '-webkit-'
211                    },
212                    MozTransition: {
213                        end: 'transitionend',
214                        prefix: '-moz-'
215                    },
216                    OTransition: {
217                        end: 'otransitionend',
218                        prefix: '-o-'
219                    },
220                    transition: {
221                        end: 'transitionend',
222                        prefix: ''
223                    }
224                },
225                elementTests = function () {
226                    var transition = support.transition,
227                        prop,
228                        translateZ;
229                    document.body.appendChild(element);
230                    if (transition) {
231                        prop = transition.name.slice(0, -9) + 'ransform';
232                        if (element.style[prop] !== undefined) {
233                            element.style[prop] = 'translateZ(0)';
234                            translateZ = window.getComputedStyle(element)
235                                .getPropertyValue(transition.prefix + 'transform');
236                            support.transform = {
237                                prefix: transition.prefix,
238                                name: prop,
239                                translate: true,
240                                translateZ: !!translateZ && translateZ !== 'none'
241                            };
242                        }
243                    }
244                    if (element.style.backgroundSize !== undefined) {
245                        support.backgroundSize = {};
246                        element.style.backgroundSize = 'contain';
247                        support.backgroundSize.contain = window
248                                .getComputedStyle(element)
249                                .getPropertyValue('background-size') === 'contain';
250                        element.style.backgroundSize = 'cover';
251                        support.backgroundSize.cover = window
252                                .getComputedStyle(element)
253                                .getPropertyValue('background-size') === 'cover';
254                    }
255                    document.body.removeChild(element);
256                };
257            (function (support, transitions) {
258                var prop;
259                for (prop in transitions) {
260                    if (transitions.hasOwnProperty(prop) &&
261                            element.style[prop] !== undefined) {
262                        support.transition = transitions[prop];
263                        support.transition.name = prop;
264                        break;
265                    }
266                }
267            }(support, transitions));
268            if (document.body) {
269                elementTests();
270            } else {
271                $(document).on('DOMContentLoaded', elementTests);
272            }
273            return support;
274            // Test element, has to be standard HTML and must not be hidden
275            // for the CSS3 tests using window.getComputedStyle to be applicable:
276        }(document.createElement('div'))),
277
278        requestAnimationFrame: window.requestAnimationFrame ||
279            window.webkitRequestAnimationFrame ||
280            window.mozRequestAnimationFrame,
281
282        initialize: function () {
283            this.initStartIndex();
284            if (this.initWidget() === false) {
285                return false;
286            }
287            this.initEventListeners();
288            // Load the slide at the given index:
289            this.onslide(this.index);
290            // Manually trigger the slideend event for the initial slide:
291            this.ontransitionend();
292            // Start the automatic slideshow if applicable:
293            if (this.options.startSlideshow) {
294                this.play();
295            }
296        },
297
298        slide: function (to, speed) {
299            window.clearTimeout(this.timeout);
300            var index = this.index,
301                direction,
302                naturalDirection,
303                diff;
304            if (index === to || this.num === 1) {
305                return;
306            }
307            if (!speed) {
308                speed = this.options.transitionSpeed;
309            }
310            if (this.support.transition) {
311                if (!this.options.continuous) {
312                    to = this.circle(to);
313                }
314                // 1: backward, -1: forward:
315                direction = Math.abs(index - to) / (index - to);
316                // Get the actual position of the slide:
317                if (this.options.continuous) {
318                    naturalDirection = direction;
319                    direction = -this.positions[this.circle(to)] / this.slideWidth;
320                    // If going forward but to < index, use to = slides.length + to
321                    // If going backward but to > index, use to = -slides.length + to
322                    if (direction !== naturalDirection) {
323                        to = -direction * this.num + to;
324                    }
325                }
326                diff = Math.abs(index - to) - 1;
327                // Move all the slides between index and to in the right direction:
328                while (diff) {
329                    diff -= 1;
330                    this.move(
331                        this.circle((to > index ? to : index) - diff - 1),
332                        this.slideWidth * direction,
333                        0
334                    );
335                }
336                to = this.circle(to);
337                this.move(index, this.slideWidth * direction, speed);
338                this.move(to, 0, speed);
339                if (this.options.continuous) {
340                    this.move(
341                        this.circle(to - direction),
342                        -(this.slideWidth * direction),
343                        0
344                    );
345                }
346            } else {
347                to = this.circle(to);
348                this.animate(index * -this.slideWidth, to * -this.slideWidth, speed);
349            }
350            this.onslide(to);
351        },
352
353        getIndex: function () {
354            return this.index;
355        },
356
357        getNumber: function () {
358            return this.num;
359        },
360
361        prev: function () {
362            if (this.options.continuous || this.index) {
363                this.slide(this.index - 1);
364            }
365        },
366
367        next: function () {
368            if (this.options.continuous || this.index < this.num - 1) {
369                this.slide(this.index + 1);
370            }
371        },
372
373        play: function (time) {
374            var that = this;
375            window.clearTimeout(this.timeout);
376            this.interval = time || this.options.slideshowInterval;
377            if (this.elements[this.index] > 1) {
378                this.timeout = this.setTimeout(
379                    (!this.requestAnimationFrame && this.slide) || function (to, speed) {
380                        that.animationFrameId = that.requestAnimationFrame.call(
381                            window,
382                            function () {
383                                that.slide(to, speed);
384                            }
385                        );
386                    },
387                    [this.index + 1, this.options.slideshowTransitionSpeed],
388                    this.interval
389                );
390            }
391            this.container.addClass(this.options.playingClass);
392        },
393
394        pause: function () {
395            window.clearTimeout(this.timeout);
396            this.interval = null;
397            this.container.removeClass(this.options.playingClass);
398        },
399
400        add: function (list) {
401            var i;
402            if (!list.concat) {
403                // Make a real array out of the list to add:
404                list = Array.prototype.slice.call(list);
405            }
406            if (!this.list.concat) {
407                // Make a real array out of the Gallery list:
408                this.list = Array.prototype.slice.call(this.list);
409            }
410            this.list = this.list.concat(list);
411            this.num = this.list.length;
412            if (this.num > 2 && this.options.continuous === null) {
413                this.options.continuous = true;
414                this.container.removeClass(this.options.leftEdgeClass);
415            }
416            this.container
417                .removeClass(this.options.rightEdgeClass)
418                .removeClass(this.options.singleClass);
419            for (i = this.num - list.length; i < this.num; i += 1) {
420                this.addSlide(i);
421                this.positionSlide(i);
422            }
423            this.positions.length = this.num;
424            this.initSlides(true);
425        },
426
427        resetSlides: function () {
428            this.slidesContainer.empty();
429            this.slides = [];
430        },
431
432        handleClose: function () {
433            var options = this.options;
434            this.destroyEventListeners();
435            // Cancel the slideshow:
436            this.pause();
437            this.container[0].style.display = 'none';
438            this.container
439                .removeClass(options.displayClass)
440                .removeClass(options.singleClass)
441                .removeClass(options.leftEdgeClass)
442                .removeClass(options.rightEdgeClass);
443            if (options.hidePageScrollbars) {
444                document.body.style.overflow = this.bodyOverflowStyle;
445            }
446            if (this.options.clearSlides) {
447                this.resetSlides();
448            }
449            if (this.options.onclosed) {
450                this.options.onclosed.call(this);
451            }
452        },
453
454        close: function () {
455            var that = this,
456                closeHandler = function (event) {
457                    if (event.target === that.container[0]) {
458                        that.container.off(
459                            that.support.transition.end,
460                            closeHandler
461                        );
462                        that.handleClose();
463                    }
464                };
465            if (this.options.onclose) {
466                this.options.onclose.call(this);
467            }
468            if (this.support.transition && this.options.displayTransition) {
469                this.container.on(
470                    this.support.transition.end,
471                    closeHandler
472                );
473                this.container.removeClass(this.options.displayClass);
474            } else {
475                this.handleClose();
476            }
477        },
478
479        circle: function (index) {
480            // Always return a number inside of the slides index range:
481            return (this.num + (index % this.num)) % this.num;
482        },
483
484        move: function (index, dist, speed) {
485            this.translateX(index, dist, speed);
486            this.positions[index] = dist;
487        },
488
489        translate: function (index, x, y, speed) {
490            var style = this.slides[index].style,
491                transition = this.support.transition,
492                transform = this.support.transform;
493            style[transition.name + 'Duration'] = speed + 'ms';
494            style[transform.name] = 'translate(' + x + 'px, ' + y + 'px)' +
495                (transform.translateZ ? ' translateZ(0)' : '');
496        },
497
498        translateX: function (index, x, speed) {
499            this.translate(index, x, 0, speed);
500        },
501
502        translateY: function (index, y, speed) {
503            this.translate(index, 0, y, speed);
504        },
505
506        animate: function (from, to, speed) {
507            if (!speed) {
508                this.slidesContainer[0].style.left = to + 'px';
509                return;
510            }
511            var that = this,
512                start = new Date().getTime(),
513                timer = window.setInterval(function () {
514                    var timeElap = new Date().getTime() - start;
515                    if (timeElap > speed) {
516                        that.slidesContainer[0].style.left = to + 'px';
517                        that.ontransitionend();
518                        window.clearInterval(timer);
519                        return;
520                    }
521                    that.slidesContainer[0].style.left = (((to - from) *
522                        (Math.floor((timeElap / speed) * 100) / 100)) +
523                            from) + 'px';
524                }, 4);
525        },
526
527        preventDefault: function (event) {
528            if (event.preventDefault) {
529                event.preventDefault();
530            } else {
531                event.returnValue = false;
532            }
533        },
534
535        stopPropagation: function (event) {
536            if (event.stopPropagation) {
537                event.stopPropagation();
538            } else {
539                event.cancelBubble = true;
540            }
541        },
542
543        onresize: function () {
544            this.initSlides(true);
545        },
546
547        onmousedown: function (event) {
548            // Trigger on clicks of the left mouse button only
549            // and exclude video elements:
550            if (event.which && event.which === 1 &&
551                    event.target.nodeName !== 'VIDEO') {
552                // Preventing the default mousedown action is required
553                // to make touch emulation work with Firefox:
554                event.preventDefault();
555                (event.originalEvent || event).touches = [{
556                    pageX: event.pageX,
557                    pageY: event.pageY
558                }];
559                this.ontouchstart(event);
560            }
561        },
562
563        onmousemove: function (event) {
564            if (this.touchStart) {
565                (event.originalEvent || event).touches = [{
566                    pageX: event.pageX,
567                    pageY: event.pageY
568                }];
569                this.ontouchmove(event);
570            }
571        },
572
573        onmouseup: function (event) {
574            if (this.touchStart) {
575                this.ontouchend(event);
576                delete this.touchStart;
577            }
578        },
579
580        onmouseout: function (event) {
581            if (this.touchStart) {
582                var target = event.target,
583                    related = event.relatedTarget;
584                if (!related || (related !== target &&
585                        !$.contains(target, related))) {
586                    this.onmouseup(event);
587                }
588            }
589        },
590
591        ontouchstart: function (event) {
592            if (this.options.stopTouchEventsPropagation) {
593                this.stopPropagation(event);
594            }
595            // jQuery doesn't copy touch event properties by default,
596            // so we have to access the originalEvent object:
597            var touches = (event.originalEvent || event).touches[0];
598            this.touchStart = {
599                // Remember the initial touch coordinates:
600                x: touches.pageX,
601                y: touches.pageY,
602                // Store the time to determine touch duration:
603                time: Date.now()
604            };
605            // Helper variable to detect scroll movement:
606            this.isScrolling = undefined;
607            // Reset delta values:
608            this.touchDelta = {};
609        },
610
611        ontouchmove: function (event) {
612            if (this.options.stopTouchEventsPropagation) {
613                this.stopPropagation(event);
614            }
615            // jQuery doesn't copy touch event properties by default,
616            // so we have to access the originalEvent object:
617            var touches = (event.originalEvent || event).touches[0],
618                scale = (event.originalEvent || event).scale,
619                index = this.index,
620                touchDeltaX,
621                indices;
622            // Ensure this is a one touch swipe and not, e.g. a pinch:
623            if (touches.length > 1 || (scale && scale !== 1)) {
624                return;
625            }
626            if (this.options.disableScroll) {
627                event.preventDefault();
628            }
629            // Measure change in x and y coordinates:
630            this.touchDelta = {
631                x: touches.pageX - this.touchStart.x,
632                y: touches.pageY - this.touchStart.y
633            };
634            touchDeltaX = this.touchDelta.x;
635            // Detect if this is a vertical scroll movement (run only once per touch):
636            if (this.isScrolling === undefined) {
637                this.isScrolling = this.isScrolling ||
638                    Math.abs(touchDeltaX) < Math.abs(this.touchDelta.y);
639            }
640            if (!this.isScrolling) {
641                // Always prevent horizontal scroll:
642                event.preventDefault();
643                // Stop the slideshow:
644                window.clearTimeout(this.timeout);
645                if (this.options.continuous) {
646                    indices = [
647                        this.circle(index + 1),
648                        index,
649                        this.circle(index - 1)
650                    ];
651                } else {
652                    // Increase resistance if first slide and sliding left
653                    // or last slide and sliding right:
654                    this.touchDelta.x = touchDeltaX =
655                        touchDeltaX /
656                        (((!index && touchDeltaX > 0) ||
657                            (index === this.num - 1 && touchDeltaX < 0)) ?
658                                (Math.abs(touchDeltaX) / this.slideWidth + 1) : 1);
659                    indices = [index];
660                    if (index) {
661                        indices.push(index - 1);
662                    }
663                    if (index < this.num - 1) {
664                        indices.unshift(index + 1);
665                    }
666                }
667                while (indices.length) {
668                    index = indices.pop();
669                    this.translateX(index, touchDeltaX + this.positions[index], 0
669);
670                }
671            } else if (this.options.closeOnSwipeUpOrDown) {
672                this.translateY(index, this.touchDelta.y + this.positions[index], 0);
673            }
674        },
675
676        ontouchend: function (event) {
677            if (this.options.stopTouchEventsPropagation) {
678                this.stopPropagation(event);
679            }
680            var index = this.index,
681                speed = this.options.transitionSpeed,
682                slideWidth = this.slideWidth,
683                isShortDuration = Number(Date.now() - this.touchStart.time) < 250,
684                // Determine if slide attempt triggers next/prev slide:
685                isValidSlide = (isShortDuration && Math.abs(this.touchDelta.x) > 20) ||
686                    Math.abs(this.touchDelta.x) > slideWidth / 2,
687                // Determine if slide attempt is past start or end:
688                isPastBounds = (!index && this.touchDelta.x > 0) ||
689                        (index === this.num - 1 && this.touchDelta.x < 0),
690                isValidClose = !isValidSlide && this.options.closeOnSwipeUpOrDown &&
691                    ((isShortDuration && Math.abs(this.touchDelta.y) > 20) ||
692                        Math.abs(this.touchDelta.y) > this.slideHeight / 2),
693                direction,
694                indexForward,
695                indexBackward,
696                distanceForward,
697                distanceBackward;
698            if (this.options.continuous) {
699                isPastBounds = false;
700            }
701            // Determine direction of swipe (true: right, false: left):
702            direction = this.touchDelta.x < 0 ? -1 : 1;
703            if (!this.isScrolling) {
704                if (isValidSlide && !isPastBounds) {
705                    indexForward = index + direction;
706                    indexBackward = index - direction;
707                    distanceForward = slideWidth * direction;
708                    distanceBackward = -slideWidth * direction;
709                    if (this.options.continuous) {
710                        this.move(this.circle(indexForward), distanceForward, 0);
711                        this.move(this.circle(index - 2 * direction), distanceBackward, 0);
712                    } else if (indexForward >= 0 &&
713                            indexForward < this.num) {
714                        this.move(indexForward, distanceForward, 0);
715                    }
716                    this.move(index, this.positions[index] + distanceForward, speed);
717                    this.move(
718                        this.circle(indexBackward),
719                        this.positions[this.circle(indexBackward)] + distanceForward,
720                        speed
721                    );
722                    index = this.circle(indexBackward);
723                    this.onslide(index);
724                } else {
725                    // Move back into position
726                    if (this.options.continuous) {
727                        this.move(this.circle(index - 1), -slideWidth, speed);
728                        this.move(index, 0, speed);
729                        this.move(this.circle(index + 1), slideWidth, speed);
730                    } else {
731                        if (index) {
732                            this.move(index - 1, -slideWidth, speed);
733                        }
734                        this.move(index, 0, speed);
735                        if (index < this.num - 1) {
736                            this.move(index + 1, slideWidth, speed);
737                        }
738                    }
739                }
740            } else {
741                if (isValidClose) {
742                    this.close();
743                } else {
744                    // Move back into position
745                    this.translateY(index, 0, speed);
746                }
747            }
748        },
749
750        ontouchcancel: function (event) {
751            if (this.touchStart) {
752                this.ontouchend(event);
753                delete this.touchStart;
754            }
755        },
756
757        ontransitionend: function (event) {
758            var slide = this.slides[this.index];
759            if (!event || slide === event.target) {
760                if (this.interval) {
761                    this.play();
762                }
763                this.setTimeout(
764                    this.options.onslideend,
765                    [this.index, slide]
766                );
767            }
768        },
769
770        oncomplete: function (event) {
771            var target = event.target || event.srcElement,
772                parent = target && target.parentNode,
773                index;
774            if (!target || !parent) {
775                return;
776            }
777            index = this.getNodeIndex(parent);
778            $(parent).removeClass(this.options.slideLoadingClass);
779            if (event.type === 'error') {
780                $(parent).addClass(this.options.slideErrorClass);
781                this.elements[index] = 3; // Fail
782            } else {
783                this.elements[index] = 2; // Done
784            }
785            // Fix for IE7's lack of support for percentage max-height:
786            if (target.clientHeight > this.container[0].clientHeight) {
787                target.style.maxHeight = this.container[0].clientHeight;
788            }
789            if (this.interval && this.slides[this.index] === parent) {
790                this.play();
791            }
792            this.setTimeout(
793                this.options.onslidecomplete,
794                [index, parent]
795            );
796        },
797
798        onload: function (event) {
799            this.oncomplete(event);
800        },
801
802        onerror: function (event) {
803            this.oncomplete(event);
804        },
805
806        onkeydown: function (event) {
807            switch (event.which || event.keyCode) {
808            case 13: // Return
809                if (this.options.toggleControlsOnReturn) {
810                    this.preventDefault(event);
811                    this.toggleControls();
812                }
813                break;
814            case 27: // Esc
815                if (this.options.closeOnEscape) {
816                    this.close();
817                }
818                break;
819            case 32: // Space
820                if (this.options.toggleSlideshowOnSpace) {
821                    this.preventDefault(event);
822                    this.toggleSlideshow();
823                }
824                break;
825            case 37: // Left
826                if (this.options.enableKeyboardNavigation) {
827                    this.preventDefault(event);
828                    this.prev();
829                }
830                break;
831            case 39: // Right
832                if (this.options.enableKeyboardNavigation) {
833                    this.preventDefault(event);
834                    this.next();
835                }
836                break;
837            }
838        },
839
840        handleClick: function (event) {
841            var options = this.options,
842                target = event.target || event.srcElement,
843                parent = target.parentNode,
844                isTarget = function (className) {
845                    return $(target).hasClass(className) ||
846                        $(parent).hasClass(className);
847                };
848            if (isTarget(options.toggleClass)) {
849                // Click on "toggle" control
850                this.preventDefault(event);
851                this.toggleControls();
852            } else if (isTarget(options.prevClass)) {
853                // Click on "prev" control
854                this.preventDefault(event);
855                this.prev();
856            } else if (isTarget(options.nextClass)) {
857                // Click on "next" control
858                this.preventDefault(event);
859                this.next();
860            } else if (isTarget(options.closeClass)) {
861                // Click on "close" control
862                this.preventDefault(event);
863                this.close();
864            } else if (isTarget(options.playPauseClass)) {
865                // Click on "play-pause" control
866                this.preventDefault(event);
867                this.toggleSlideshow();
868            } else if (parent === this.slidesContainer[0]) {
869                // Click on slide background
870                this.preventDefault(event);
871                if (options.closeOnSlideClick) {
872                    this.close();
873                } else {
874                    this.toggleControls();
875                }
876            } else if (parent.parentNode &&
877                    parent.parentNode === this.slidesContainer[0]) {
878                // Click on displayed element
879                this.preventDefault(event);
880                this.toggleControls();
881            }
882        },
883
884        onclick: function (event) {
885            if (this.options.emulateTouchEvents &&
886                    this.touchDelta && (Math.abs(this.touchDelta.x) > 20 ||
887                        Math.abs(this.touchDelta.y) >
887 20)) {
888                delete this.touchDelta;
889                return;
890            }
891            return this.handleClick(event);
892        },
893
894        updateEdgeClasses: function (index) {
895            if (!index) {
896                this.container.addClass(this.options.leftEdgeClass);
897            } else {
898                this.container.removeClass(this.options.leftEdgeClass);
899            }
900            if (index === this.num - 1) {
901                this.container.addClass(this.options.rightEdgeClass);
902            } else {
903                this.container.removeClass(this.options.rightEdgeClass);
904            }
905        },
906
907        handleSlide: function (index) {
908            if (!this.options.continuous) {
909                this.updateEdgeClasses(index);
910            }
911            this.loadElements(index);
912            if (this.options.unloadElements) {
913                this.unloadElements(index);
914            }
915            this.setTitle(index);
916        },
917
918        onslide: function (index) {
919            this.index = index;
920            this.handleSlide(index);
921            this.setTimeout(this.options.onslide, [index, this.slides[index]]);
922        },
923
924        setTitle: function (index) {
925            var text = this.slides[index].firstChild.title,
926                titleElement = this.titleElement;
927            if (titleElement.length) {
928                this.titleElement.empty();
929                if (text) {
930                    titleElement[0].appendChild(document.createTextNode(text));
931                }
932            }
933        },
934
935        setTimeout: function (func, args, wait) {
936            var that = this;
937            return func && window.setTimeout(function () {
938                func.apply(that, args || []);
939            }, wait || 0);
940        },
941
942        imageFactory: function (obj, callback) {
943            var that = this,
944                img = this.imagePrototype.cloneNode(false),
945                url = obj,
946                backgroundSize = this.options.stretchImages,
947                called,
948                element,
949                callbackWrapper = function (event) {
950                    if (!called) {
951                        event = {
952                            type: event.type,
953                            target: element
954                        };
955                        if (!element.parentNode) {
956                            // Fix for IE7 firing the load event for
957                            // cached images before the element could
958                            // be added to the DOM:
959                            return that.setTimeout(callbackWrapper, [event]);
960                        }
961                        called = true;
962                        $(img).off('load error', callbackWrapper);
963                        if (backgroundSize) {
964                            if (event.type === 'load') {
965                                element.style.background = 'url("' + url +
966                                    '") center no-repeat';
967                                element.style.backgroundSize = backgroundSize;
968                            }
969                        }
970                        callback(event);
971                    }
972                },
973                title;
974            if (typeof url !== 'string') {
975                url = this.getItemProperty(obj, this.options.urlProperty);
976                title = this.getItemProperty(obj, this.options.titleProperty);
977            }
978            if (backgroundSize === true) {
979                backgroundSize = 'contain';
980            }
981            backgroundSize = this.support.backgroundSize &&
982                this.support.backgroundSize[backgroundSize] && backgroundSize;
983            if (backgroundSize) {
984                element = this.elementPrototype.cloneNode(false);
985            } else {
986                element = img;
987                img.draggable = false;
988            }
989            if (title) {
990                element.title = title;
991            }
992            $(img).on('load error', callbackWrapper);
993            img.src = url;
994            return element;
995        },
996
997        createElement: function (obj, callback) {
998            var type = obj && this.getItemProperty(obj, this.options.typeProperty),
999                factory = (type && this[type.split('/')[0] + 'Factory']) ||
1000                    this.imageFactory,
1001                element = obj && factory.call(this, obj, callback);
1002            if (!element) {
1003                element = this.elementPrototype.cloneNode(false);
1004                this.setTimeout(callback, [{
1005                    type: 'error',
1006                    target: element
1007                }]);
1008            }
1009            $(element).addClass(this.options.slideContentClass);
1010            return element;
1011        },
1012
1013        loadElement: function (index) {
1014            if (!this.elements[index]) {
1015                if (this.slides[index].firstChild) {
1016                    this.elements[index] = $(this.slides[index])
1017                        .hasClass(this.options.slideErrorClass) ? 3 : 2;
1018                } else {
1019                    this.elements[index] = 1; // Loading
1020                    $(this.slides[index]).addClass(this.options.slideLoadingClass);
1021                    this.slides[index].appendChild(this.createElement(
1022                        this.list[index],
1023                        this.proxyListener
1024                    ));
1025                }
1026            }
1027        },
1028
1029        loadElements: function (index) {
1030            var limit = Math.min(this.num, this.options.preloadRange * 2 + 1),
1031                j = index,
1032                i;
1033            for (i = 0; i < limit; i += 1) {
1034                // First load the current slide element (0),
1035                // then the next one (+1),
1036                // then the previous one (-2),
1037                // then the next after next (+2), etc.:
1038                j += i * (i % 2 === 0 ? -1 : 1);
1039                // Connect the ends of the list to load slide elements for
1040                // continuous navigation:
1041                j = this.circle(j);
1042                this.loadElement(j);
1043            }
1044        },
1045
1046        unloadElements: function (index) {
1047            var i,
1048                slide,
1049                diff;
1050            for (i in this.elements) {
1051                if (this.elements.hasOwnProperty(i)) {
1052                    diff = Math.abs(index - i);
1053                    if (diff > this.options.preloadRange &&
1054                            diff + this.options.preloadRange < this.num) {
1055                        slide = this.slides[i];
1056                        slide.removeChild(slide.firstChild);
1057                        delete this.elements[i];
1058                    }
1059                }
1060            }
1061        },
1062
1063        addSlide: function (index) {
1064            var slide = this.slidePrototype.cloneNode(false);
1065            slide.setAttribute('data-index', index);
1066            this.slidesContainer[0].appendChild(slide);
1067            this.slides.push(slide);
1068        },
1069
1070        positionSlide: function (index) {
1071            var slide = this.slides[index];
1072            slide.style.width = this.slideWidth + 'px';
1073            if (this.support.transition) {
1074                slide.style.left = (index * -this.slideWidth) + 'px';
1075                this.move(index, this.index > index ? -this.slideWidth :
1076                        (this.index < index ? this.slideWidth : 0), 0);
1077            }
1078        },
1079
1080        initSlides: function (reload) {
1081            var clearSlides,
1082                i;
1083            if (!reload) {
1084                this.positions = [];
1085                this.positions.length = this.num;
1086                this.elements = {};
1087                this.imagePrototype = document.createElement('img');
1088                this.elementPrototype = document.createElement('div');
1089                this.slidePrototype = document.createElement('div');
1090                $(this.slidePrototype).addClass(this.options.slideClass);
1091                this.slides = this.slidesContainer[0].children;
1092                clearSlides = this.options.clearSlides ||
1093                    this.slides.length !== this.num;
1094            }
1095            this.slideWidth = this.container[0].offsetWidth;
1096            this.slideHeight = this.container[0].offsetHeight;
1097            this.slidesContainer[0].style.width =
1098                (this.num * this.slideWidth) + 'px';
1099            if (clearSlides) {
1100                this.resetSlides();
1101            }
1102            for (i = 0; i < this.num; i += 1) {
1103                if (clearSlides) {
1104                    this.addSlide(i);
1105                }
1106                this.positionSlide(i);
1107            }
1108            // Reposition the slides before and after the given index:
1109            if (this.options.continuous && this.support.transition) {
1110                this.move(this.circle(this.index - 1), -this.slideWidth, 0);
1111                this.move(this.circle(this.index + 1), this.slideWidth, 0);
1112            }
1113            if (!this.support.transition) {
1114                this.slidesContainer[0].style.left =
1115                    (this.index * -this.slideWidth) + 'px';
1116            }
1117        },
1118
1119        toggleControls: function () {
1120            var controlsClass = this.options.controlsClass;
1121            if (this.container.hasClass(controlsClass)) {
1122                this.container.removeClass(controlsClass);
1123            } else {
1124                this.container.addClass(controlsClass);
1125            }
1126        },
1127
1128        toggleSlideshow: function () {
1129            if (!this.interval) {
1130                this.play();
1131            } else {
1132                this.pause();
1133            }
1134        },
1135
1136        getNodeIndex: function (element) {
1137            return parseInt(element.getAttribute('data-index'), 10);
1138        },
1139
1140        getNestedProperty: function (obj, property) {
1141            property.replace(
1142                // Matches native JavaScript notation in a String,
1143                // e.g. '["doubleQuoteProp"].dotProp[2]'
1144                /\[(?:'([^']+)'|"([^"]+)"|(\d+))\]|(?:(?:^|\.)([^\.\[]+))/g,
1145                function (str, singleQuoteProp, doubleQuoteProp, arrayIndex, dotProp) {
1146                    var prop = dotProp || singleQuoteProp || doubleQuoteProp ||
1147                            (arrayIndex && parseInt(arrayIndex, 10));
1148                    if (str && obj) {
1149                        obj = obj[prop];
1150                    }
1151                }
1152            );
1153            return obj;
1154        },
1155
1156        getDataProperty: function (obj, property) {
1157            if (obj.getAttribute) {
1158                var prop = obj.getAttribute('data-' +
1159                        property.replace(/([A-Z])/g, '-$1').toLowerCase());
1160                if (typeof prop === 'string') {
1161                    if (/^(true|false|null|-?\d+(\.\d+)?|\{[\s\S]*\}|\[[\s\S]*\])$/
1162                            .test(prop)) {
1163                        try {
1164                            return $.parseJSON(prop);
1165                        } catch (ignore) {}
1166                    }
1167                    return prop;
1168                }
1169            }
1170        },
1171
1172        getItemProperty: function (obj, property) {
1173            var prop = obj[property];
1174            if (prop === undefined) {
1175                prop = this.getDataProperty(obj, property);
1176                if (prop === undefined) {
1177                    prop = this.getNestedProperty(obj, property);
1178                }
1179            }
1180            return prop;
1181        },
1182
1183        initStartIndex: function () {
1184            var index = this.options.index,
1185                urlProperty = this.options.urlProperty,
1186                i;
1187            // Check if the index is given as a list object:
1188            if (index && typeof index !== 'number') {
1189                for (i = 0; i < this.num; i += 1) {
1190                    if (this.list[i] === index ||
1191                            this.getItemProperty(this.list[i], urlProperty) ===
1192                                this.getItemProperty(index, urlProperty)) {
1193                        index  = i;
1194                        break;
1195                    }
1196                }
1197            }
1198            // Make sure the index is in the list range:
1199            this.index = this.circle(parseInt(index, 10) || 0);
1200        },
1201
1202        initEventListeners: function () {
1203            var that = this,
1204                slidesContainer = this.slidesContainer,
1205                proxyListener = function (event) {
1206                    var type = that.support.transition &&
1207                            that.support.transition.end === event.type ?
1208                                    'transitionend' : event.type;
1209                    that['on' + type](event);
1210                };
1211            $(window).on('resize', proxyListener);
1212            $(document.body).on('keydown', proxyListener);
1213            this.container.on('click', proxyListener);
1214            if (this.support.touch) {
1215                slidesContainer
1216                    .on('touchstart touchmove touchend touchcancel', proxyListener);
1217            } else if (this.options.emulateTouchEvents &&
1218                    this.support.transition) {
1219                slidesContainer
1220                    .on('mousedown mousemove mouseup mouseout', proxyListener);
1221            }
1222            if (this.support.transition) {
1223                slidesContainer.on(
1224                    this.support.transition.end,
1225                    proxyListener
1226                );
1227            }
1228            this.proxyListener = proxyListener;
1229        },
1230
1231        destroyEventListeners: function () {
1232            var slidesContainer = this.slidesContainer,
1233                proxyListener = this.proxyListener;
1234            $(window).off('resize', proxyListener);
1235            $(document.body).off('keydown', proxyListener);
1236            this.container.off('click', proxyListener);
1237            if (this.support.touch) {
1238                slidesContainer
1239                    .off('touchstart touchmove touchend touchcancel', proxyListener);
1240            } else if (this.options.emulateTouchEvents &&
1241                    this.support.transition) {
1242                slidesContainer
1243                    .off('mousedown mousemove mouseup mouseout', proxyListener);
1244            }
1245            if (this.support.transition) {
1246                slidesContainer.off(
1247                    this.support.transition.end,
1248                    proxyListener
1249                );
1250            }
1251        },
1252
1253        handleOpen: function () {
1254            if (this.options.onopened) {
1255                this.options.onopened.call(this);
1256            }
1257        },
1258
1259        initWidget: function () {
1260            var that = this,
1261                openHandler = function (event) {
1262                    if (event.target === that.container[0]) {
1263                        that.container.off(
1264                            that.support.transition.end,
1265                            openHandler
1266                        );
1267                        that.handleOpen();
1268                    }
1269                };
1270            this.container = $(this.options.container);
1271            if (!this.container.length) {
1272                this.console.log(
1273                    'blueimp Gallery: Widget container not found.',
1274                    this.options.container
1275                );
1276                return false;
1277            }
1278            this.slidesContainer = this.container.find(
1279                this.options.slidesContainer
1280            ).first();
1281            if (!this.slidesContainer.length) {
1282                this.console.log(
1283                    'blueimp Gallery: Slides container not found.',
1284                    this.options.slidesContainer
1285                );
1286                return false;
1287            }
1288            this.titleElement = this.container.find(
1289                this.options.titleElement
1290            ).first();
1291            if (this.num === 1) {
1292                this.container.addClass(this.options.singleClass);
1293            }
1294            if (this.options.onopen) {
1295                this.options.onopen.call(this);
1296            }
1297            if (this.support.transition && this.options.displayTransition) {
1298                this.container.on(
1299                    this.support.transition.end,
1300                    openHandler
1301                );
1302            } else {
1303                this.handleOpen();
1304            }
1305            if (this.options.hidePageScrollbars) {
1306                // Hide the page scrollbars:
1307                this.bodyOverflowStyle = document.body.style.overflow;
1308                document.body.style.overflow = 'hidden';
1309            }
1310            this.container[0].style.display = 'block';
1311            this.initSlides();
1312            this.container.addClass(this.options.displayClass);
1313        },
1314
1315        initOptions: function (options) {
1316            // Create a copy of the prototype options:
1317            this.options = $.extend({}, this.options);
1318            // Check if carousel mode is enabled:
1319            if ((options && options.carousel) ||
1320                    (this.options.carousel && (!options || options.carousel !== false))) {
1321                $.extend(this.options, this.carouselOptions);
1322            }
1323            // Override any given options:
1324            $.extend(this.options, options);
1325            if (this.num < 3) {
1326                // 1 or 2 slides cannot be displayed continuous,
1327                // remember the original option by setting to null instead of false:
1328                this.options.continuous = this.options.continuous ? null : false;
1329            }
1330            if (!this.support.transition) {
1331                this.options.emulateTouchEvents = false;
1332            }
1333            if (this.options.event) {
1334                this.preventDefault(this.options.event);
1335            }
1336        }
1337
1338    });
1339
1340    return Gallery;
1341}));

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.