PageSourceSearch

https://www.les-diamants.com/wp-content/plugins/gallery-by-supsyst…/assets/js/jquery.photobox.js?ver=1.15.12

js les-diamants.com collected 2026-10-10 02:10:30 UTC 44,370 bytes, 1,022 lines download raw bytes

1/*!
2    photobox v1.9.9
3    (c) 2013 Yair Even Or <http://dropthebit.com>
4
5    MIT-style license.
6*/
7
8
9;(function($, doc, win){
10    "use strict";
11
12    var Photobox, photobox, options, images=[], imageLinks, activeImage = -1, activeURL, lastActive, activeType, prevImage, nextImage, thumbsStripe, docElm, APControl, changeImage,
13        transitionend = "transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",
14        isOldIE = !('placeholder' in doc.createElement('input')),
15        noPointerEvents = (function(){ var el = $('<p>')[0]; el.style.cssText = 'pointer-events:auto'; return !el.style.pointerEvents})(),
16        isTouchDevice = false, // assume "false" unless there's a touch
17        thumbsContainerWidth, thumbsTotalWidth, activeThumb = $(),
18        blankImg = "data:image/gif;base64,R0lGODlhAQABAIAAAP///////yH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==",
19        transformOrigin = getPrefixed('transformOrigin'),
20        transition = getPrefixed('transition'),
21          // Normalize rAF
22        raf = window.requestAnimationFrame
23           || window.webkitRequestAnimationFrame
24           || window.mozRequestAnimationFrame
25           || window.msRequestAnimationFrame
26           || function(cb) { return window.setTimeout(cb, 1000 / 60); },
27
28        // Preload images
29        preload = {}, preloadPrev = new Image(), preloadNext = new Image(),
30        // DOM elements
31        closeBtn, image, video, prevBtn, nextBtn, thumbsToggler, caption, captionText, pbLoader, autoplayBtn, thumbs, wrapper,
32
33        defaults = {
34            single        : false,        // if "true" - gallery will only show a single image, with no way to navigate
35            beforeShow    : null,         // Callback before showing an image
36            afterClose    : null,         // Callback after closing the gallery
37            getTitle      : null,         // Callback for getting title
38            loop          : true,         // Allows to navigate between first and last images
39            thumb         : null,         // A relative path from the link to the thumbnail (if it's not inside the link)
40            thumbs        : true,         // Show gallery thumbnails below the presented photo
41            thumbAttr     : 'data-src',   // Attribute to get the image for the thumbnail from
42            counter       : "(A/B)",      // Counts which piece of content is being viewed, relative to the total count of items in the photobox set. ["false","String"]
43            title         : true,         // show the original alt or title attribute of the image's thumbnail. (path to image, relative to the element which triggers photobox)
44            autoplay      : false,        // should autoplay on first time or not
45            time          : 3000,         // autoplay interval, in miliseconds (less than 1000 will hide the autoplay button)
46            history       : false,        // should use history hashing if possible (HTML5 API)
47            hideFlash     : true,         // Hides flash elements on the page when photobox is activated. NOTE: flash elements must have wmode parameter set to "opaque" or "transparent" if this is set to false
48            zoomable      : true,         // disable/enable mousewheel image zooming
49            wheelNextPrev : true,         // change image using mousewheel left/right
50            keys          : {
51                close : [27, 88, 67],    // keycodes to close photobox, default: esc (27), 'x' (88), 'c' (67)
52                prev  : [37, 80],        // keycodes to navigate to the previous image, default: Left arrow (37), 'p' (80)
53                next  : [39, 78]         // keycodes to navigate to the next image, default: Right arrow (39), 'n' (78)
54            }
55        },
56
57        // DOM structure
58        overlay =   $('<div id="pbOverlay">').append(
59                        thumbsToggler = $('<input type="checkbox" id="pbThumbsToggler" checked hidden>'),
60                        pbLoader = $('<div class="pbLoader"><b></b><b></b><b></b></div>'),
61                        prevBtn = $('<div id="pbPrevBtn" class="prevNext"><b></b></div>').on('click', next_prev),
62                        nextBtn = $('<div id="pbNextBtn" class="prevNext"><b></b></div>').on('click', next_prev),
63                        wrapper = $('<div class="pbWrapper">').append(  // gives Perspective
64                            image = $('<img>'),
65                            video = $('<div>')
66                        ),
67                        closeBtn = $('<div id="pbCloseBtn">').on('click', close)[0],
68                        autoplayBtn = $('<div id="pbAutoplayBtn">').append(
69                            $('<div class="pbProgress">')
70                        ),
71                        caption = $('<div id="pbCaption">').append(
72                            '<label for="pbThumbsToggler" title="thumbnails on/off"></label>',
73                            captionText = $('<div class="pbCaptionText">').append('<div class="title"></div><div class="counter">'),
74                            thumbs = $('<div>').addClass('pbThumbs')
75                        )
76                    );
77
78    ///////////////////////////////////////////////
79    // Should remove this and use underscore/lodash if possible
80
81    function throttle(callback, duration){
82        var wait = false;
83        return function(){
84            if( !wait ){
85                callback.call();
86                wait = true;
87                setTimeout(function(){wait = false; }, duration);
88            }
89        }
90    }
91
92    ///////////////////////////////////////////////
93    // Initialization (on DOM ready)
94
95    function prepareDOM(){
96        noPointerEvents && overlay.hide();
97
98		$(doc).on('touchstart.testMouse', function(){
99			$(doc).off('touchstart.testMouse');
100			isTouchDevice = true;
101			overlay.addClass('mobile');
102		});
103
104        autoplayBtn.off().on('click', APControl.toggle);
105        // attach a delegated event on the thumbs container
106        thumbs.off().on('click', 'a', thumbsStripe.click);
107        // if useragent is IE < 10 (user deserves a slap on the face, but I gotta support them still...)
108        isOldIE && overlay.addClass('msie');
109
110        // cancel prorogation up to the overlay container so it won't close
111        overlay.off().on('click', 'img', function(e){
112            e.stopPropagation();
113        });
114
115        $(doc.body).append(overlay);
116
117        // need this for later:
118        docElm = doc.documentElement;
119    }
120
121    // @param [List of elements to work on, Custom settings, Callback after image is loaded]
122    $.fn.photobox = function(target, settings, callback){
123        return this.each(function(){
124            var o,
125                PB_data = $(this).data('_photobox');
126
127            if( PB_data ){ // don't initiate the plugin more than once on the same element
128                if( target === 'destroy')
129                    PB_data.destroy();
130
131                return this;
132            }
133
134            if( typeof target != 'string' )
135                target = 'a';
136
137            if( target === 'prepareDOM' ){
138                prepareDOM();
139                return this;
140            }
141
142            // disable contextmenu
143            if (settings.isDisableRightClick) {
144                overlay.off('contextmenu').on('contextmenu', function(e){return false;});
145            }
146
147            o = $.extend({}, defaults, settings || {});
148            photobox = new Photobox(o, this, target);
149
150            // Saves the insance on the gallery's target element
151            $(this).data('_photobox', photobox);
152            // add a callback to the specific gallery
153            photobox.callback = callback;
154        });
155    }
156
157    Photobox = function(_options, object, target){
158        this.options = $.extend({}, _options);
159        this.target = target;
160        this.selector = $(object || doc);
161
162        this.thumbsList = null;
163        // filter the links which actually HAS an image as a child
164        var filtered = this.imageLinksFilter( this.selector.find(target) );
165        this.imageLinks = filtered[0];  // Array of jQuery links
166        this.images = filtered[1];      // 2D Array of image URL & title
167        this.init();
168    };
169
170    Photobox.prototype = {
171        init : function(){
172            var that = this;
173
174            if(!that.thumbsList) {
175                that.thumbsList = thumbsStripe.generate.apply(that);
176            }
177
178            this.selector.on('click.photobox', this.target, function(e){
179                e.preventDefault();
180                that.open(this);
181            });
182
183            // if any node was added or removed from the Selector of the gallery
184            this.observerTimeout = null;
185
186            if( this.selector[0].nodeType == 1 ) // observe normal nodes
187                this.observeDOM( this.selector[0], this.onDOMchanges.bind(this));
188        },
189
190        onDOMchanges : function(){
191            var that = this;
192             // use a timeout to prevent more than one DOM change event firing at once, and also to overcome the fact that IE's DOMNodeRemoved is fired BEFORE elements were actually removed
193            clearTimeout(this.observerTimeout);
194            that.observerTimeout = setTimeout( function(){
195                var filtered = that.imageLinksFilter( that.selector.find(that.target) ),
196                    activeIndex = 0,
197                    isActiveUrl = false,
198                    i;
199
200                // Make sure that ONLY DOM changes in the photobox number of items will trigger a change
201                if(that.imageLinks.length == filtered[0].length)
202                    return;
203
204                that.imageLinks = filtered[0];
205                that.images = filtered[1];
206
207                // if photobox is opened
208                if( photobox ){
209                    // if gallery which was changed is the currently viewed one:
210                    if( that.selector == photobox.selector ){
211                        images = that.images;
212                        imageLinks = that.imageLinks;
213                        // check if the currently VIEWED photo has been detached from a photobox set
214                        // if so, remove navigation arrows
215                        // TODO: fix the "images" to be an object and not an array.
216                        for( i = images.length; i--; ){
217                            if( images[i][0] == activeURL )
218                                isActiveUrl = true;
219                            // if not exits any more
220                        }
221                       // if( isActiveUrl ){
222                       //     overlay.removeClass('hasArrows');
223                       // }
224                    }
225                }
226
227                // if this gallery has thumbs
228                //if( that.options.thumbs ){
229                    that.thumbsList = thumbsStripe.generate.apply(that);
230                    thumbs.html( that.thumbsList );
231                //}
232
233                if( that.images.length && activeURL && that.options.thumbs ){
234                    activeIndex = that.thumbsList.find('a[href="'+activeURL+'"]').eq(0).parent().index();
235
236                    if( activeIndex == -1 )
237                        activeIndex = 0;
238
239                    // updateIndexes(activeIndex);
240                    thumbsStripe.changeActive(activeIndex, 0);
241                }
242            }, 50);
243        },
244
245        open : function(link){
246
247            var startImage = $.inArray(link, this.imageLinks);
248            // if image link does not exist in the imageLinks array (probably means it's not a valid part of the gallery)
249            if( startImage == -1 )
250                return false;
251
252            // load the right gallery selector...
253            options = this.options;
254            images = this.images;
255            imageLinks = this.imageLinks;
256
257            photobox = this;
258            this.setup(1);
259
260
261            overlay.on(transitionend, function(){
262                overlay.off(transitionend).addClass('on'); // class 'on' is set when the initial fade-in of the overlay is done
263                changeImage(startImage, true);
264            }).addClass('show');
265
266
267
268            if( isOldIE )
269                overlay.trigger('MSTransitionEnd');
270
271            return false;
272
273        },
274
275        imageLinksFilter : function(obj){
276            var that = this,
277                images = [],
278                caption = {},
279                captionlink;
280
281            return [obj.filter(function(i){
282                // search for the thumb inside the link, if not found then see if there's a 'that.settings.thumb' pointer to the thumbnail
283                var link = $(this),
284                    thumbImg,
285                    thumbSrc = '';
286
287                caption.content = link[0].getAttribute('title') || '';
288
289                if( that.options.thumb && typeof that.options.thumb === 'string' )
290                    thumbImg = link.find(that.options.thumb)[0];
291
292                if( typeof that.options.thumb === 'function' && link && link.length && link.closest) {
293                    var funcRetThumbs = that.options.thumb(link);
294                    if(funcRetThumbs) {
295                        thumbImg = funcRetThumbs;
296                    }
297                }
298
299                // try a direct child lookup
300                if( !that.options.thumb || !thumbImg )
301                    thumbImg = link.find('img')[0];
302
303                // if no img child found in the link
304                if( thumbImg ){
305                    captionlink = thumbImg.getAttribute('data-pb-captionlink');
306                    thumbSrc = thumbImg.getAttribute(that.options.thumbAttr) || thumbImg.getAttribute('src');
307
308                    caption.content = (thumbImg.getAttribute('title') || thumbImg.getAttribute('alt') ||  '');
309                }
310
311
312                // if there is a caption link to be added:
313                if( captionlink ){
314                    captionlink = captionlink.split('[');
315                    // parse complex links: text[www.site.com]
316                    if( captionlink.length == 2 ){
317                        caption.linkText = captionlink[0];
318                        caption.linkHref = captionlink[1].slice(0,-1);
319                    }
320                    else{
321                        caption.linkText = captionlink;
322                        caption.linkHref = captionlink;
323                    }
324                    caption.content += ' <a href="'+ caption.linkHref +'">' + caption.linkText + '</a>';
325                }
326
327                images.push( [link[0].href, caption.content, thumbSrc] );
328
329                return true;
330            }), images];
331        },
332
333        //check if DOM nodes were added or removed, to re-build the imageLinks and thumbnails
334        observeDOM : (function(){
335            var MutationObserver = win.MutationObserver || win.WebKitMutationObserver,
336                eventListenerSupported = win.addEventListener;
337
338            return function(obj, callback){
339                if( MutationObserver ){
340                    var that = this;
341                    // define a new observer
342                    var obs = new MutationObserver(function(mutations, observer){
343                        if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
344                            callback(that);
345                    });
346                    // have the observer observe for changes in children
347                    obs.observe( obj, { childList:true, subtree:true });
348                }
349                else if( eventListenerSupported ){
350                    obj.addEventListener('DOMNodeInserted', callback.bind(that), false);
351                    obj.addEventListener('DOMNodeRemoved', callback.bind(that), false);
352                }
353            }
354        })(),
355
356        // things that should happen every time the gallery opens or closes (some messed up code below..)
357        setup : function (open){
358            var fn = open ? "on" : "off";
359
360            // a hack to change the image src to nothing, because you can't do that in CHROME
361            image[0].src = blankImg;
362
363            // thumbs stuff
364            if( options.thumbs ){
365                if( !isTouchDevice ){
366                    thumbs[fn]('mouseenter.photobox', thumbsStripe.calc)
367                          [fn]('mousemove.photobox', thumbsStripe.move);
368                }
369            }
370
371            if( open ){
372                image.css({'transition':'0s'}).removeAttr('style'); // reset any transition that might be on the element (yes it's ugly)
373                overlay.show();
374                // Clean up if another gallery was viewed before, which had a thumbsList
375                thumbs
376                    .html( this.thumbsList )
377                    .trigger('mouseenter.photobox');
378
379                if( options.thumbs ){
380                    overlay.addClass('thumbs');
381                }
382                else{
383                    thumbsToggler.prop('checked', false);
384                    overlay.removeClass('thumbs');
385                }
386
387                // things to hide if there are less than 2 images
388                if( this.images.length < 2 ||  options.single )
389                    overlay.removeClass('thumbs hasArrows hasCounter hasAutoplay');
390                else{
391                    overlay.addClass('hasArrows hasCounter')
392
393                    // check is the autoplay button should be visible (per gallery) and if so, should it autoplay or not.
394                    if( options.time > 1000 ){
395                        overlay.addClass('hasAutoplay');
396                        if( options.autoplay )
397                            APControl.progress.start();
398                        else
399                            APControl.pause();
400                    }
401                    else
402                        overlay.removeClass('hasAutoplay');
403                }
404
405                options.hideFlash && $('iframe, object, embed').css('visibility', 'hidden');
406
407            } else {
408                $(win).off('resize.photobox');
409            }
410
411            $(doc).off("keydown.photobox")[fn]({ "keydown.photobox": keyDown });
412
413            if( isTouchDevice ){
414                //overlay.removeClass('hasArrows'); // no need for Arrows on touch-enabled
415                wrapper[fn]('swipe', onSwipe);
416            }
417
418            if( options.zoomable ){
419                overlay[fn]({"mousewheel.photobox": scrollZoom });
420                if( !isOldIE) thumbs[fn]({"mousewheel.photobox": thumbsResize });
421            }
422
423            if( !options.single && options.wheelNextPrev ){
424                overlay[fn]({"mousewheel.photobox": throttle(wheelNextPrev,1000) });
425            }
426        },
427
428        destroy : function(){
429            options = this.options;
430            this.selector
431                .off('click.photobox', this.target)
432                .removeData('_photobox');
433
434            close();
435        }
436    }
437
438    // on touch-devices only
439    function onSwipe(e, Dx, Dy){
440        if( Dx == 1 ){
441            image.css({transform:'translateX(25%)', transition:'.2s', opacity:0}
441);
442            setTimeout(function(){ changeImage(prevImage) }, 200);
443        }
444        else if( Dx == -1 ){
445            image.css({transform:'translateX(-25%)', transition:'.2s', opacity:0});
446            setTimeout(function(){ changeImage(nextImage) }, 200);
447        }
448
449        if( Dy == 1 )
450            thumbsToggler.prop('checked', true);
451        else if( Dy == -1 )
452            thumbsToggler.prop('checked', false);
453    }
454
455    // manage the (bottom) thumbs strip
456    thumbsStripe = (function(){
457        var containerWidth   = 0,
458            scrollWidth      = 0,
459            posFromLeft      = 0,    // Stripe position from the left of the screen
460            stripePos        = 0,    // When relative mouse position inside the thumbs stripe
461            animated         = null,
462            padding,                 // in percentage to the containerWidth
463            el, $el, ratio, scrollPos, pos;
464
465        return{
466            // returns a <ul> element which is populated with all the gallery links and thumbs
467            generate : function(){
468                var thumbsList = $('<ul>'),
469                    elements   = [],
470                    len        = this.imageLinks.length,
471                    title, thumbSrc, link, type, i;
472
473                for( i = 0; i < len; i++ ){
474                    link = this.imageLinks[i];
475
476                    thumbSrc = this.images[i][2];
477                    // continue if has thumb
478                    if( !thumbSrc )
479                        continue;
480
481                    title = this.images[i][1];
482                    type = link.rel ? " class='" + link.rel +"'" : '';
483                    elements.push('<li'+ type +'><a href="'+ link.href +'"><img src="'+ thumbSrc +'" alt="" title="'+ $('<div />').html(title).text() +'" /></a></li>');
484                };
485                thumbsList.html( elements.join('') );
486                return thumbsList;
487            },
488
489            click : function(e){
490                e.preventDefault();
491
492                activeThumb.removeClass('active');
493				$(document).trigger('pboxPreviewClicked');
494                activeThumb = $(this).parent().addClass('active');
495
496                var imageIndex = $(this.parentNode).index();
497                return changeImage(imageIndex, 0, 1);
498            },
499
500            changeActiveTimeout : null,
501            /** Highlights the thumb which represents the photo and centres the thumbs viewer on it.
502            **  @thumbClick - if a user clicked on a thumbnail, don't center on it
503            */
504            changeActive : function(index, delay, thumbClick){
505                if( !options.thumbs )
506                    return;
507
508                var lastIndex = activeThumb.index();
509                activeThumb.removeClass('active');
510                activeThumb = thumbs.find('li').eq(index).addClass('active');
511
512                if( thumbClick || !activeThumb[0] ) return;
513                // set the scrollLeft position of the thumbs list to show the active thumb
514                clearTimeout(this.changeActiveTimeout);
515                // give the images time to to settle on their new sizes (because of css transition) and then calculate the center...
516                this.changeActiveTimeout = setTimeout(
517                    function(){
518                        var pos = activeThumb[0].offsetLeft + activeThumb[0].clientWidth/2 - docElm.clientWidth/2;
519                        delay ? thumbs.delay(800) : thumbs.stop();
520                        thumbs.animate({scrollLeft: pos}, 500, 'swing');
521                    }, 200);
522            },
523
524            // calculate the thumbs container width, if the window has been resized
525            calc : function(e){
526                el = thumbs[0];
527
528                containerWidth       = el.clientWidth;
529                scrollWidth          = el.scrollWidth;
530                padding              = 0.15 * containerWidth;
531
532                posFromLeft          = thumbs.offset().left;
533                stripePos            = e.pageX - padding - posFromLeft;
534                pos                  = stripePos / (containerWidth - padding*2);
535                scrollPos            = (scrollWidth - containerWidth ) * pos;
536
537                thumbs.animate({scrollLeft:scrollPos}, 200);
538
539                clearTimeout(animated);
540                animated = setTimeout(function(){
541                    animated = null;
542                }, 200);
543
544                return this;
545            },
546
547            // move the stripe left or right according to mouse position
548            move : function(e){
549                // don't move anything until initial movement on 'mouseenter' has finished
550                if( animated ) return;
551
552                var ratio     = scrollWidth / containerWidth,
553                    stripePos = e.pageX - padding - posFromLeft, // the mouse X position, "normalized" to the carousel position
554                    pos, scrollPos;
555
556                if( stripePos < 0) stripePos = 0; //
557
558                pos = stripePos / (containerWidth - padding*2); // calculated position between 0 to 1
559                // calculate the percentage of the mouse position within the carousel
560                scrollPos = (scrollWidth - containerWidth ) * pos;
561
562                raf(function(){
563                    el.scrollLeft = scrollPos;
564                });
565            }
566        }
567    })();
568
569    // Autoplay controller
570    APControl = {
571        autoPlayTimer : false,
572        play : function(){
573            APControl.autoPlayTimer = setTimeout(function(){ changeImage(nextImage) }, options.time);
574            APControl.progress.start();
575            autoplayBtn.removeClass('play');
576            APControl.setTitle('Click to stop autoplay');
577            options.autoplay = true;
578        },
579        pause : function(){
580            clearTimeout(APControl.autoPlayTimer);
581            APControl.progress.reset();
582            autoplayBtn.addClass('play');
583            APControl.setTitle('Click to resume autoplay');
584            options.autoplay = false;
585        },
586        progress : {
587            reset : function(){
588                autoplayBtn.find('div').removeAttr('style');
589                setTimeout(function(){ autoplayBtn.removeClass('playing') },200);
590            },
591            start : function(){
592                if( !isOldIE)
593                    autoplayBtn.find('div').css(transition, options.time+'ms');
594                autoplayBtn.addClass('playing');
595            }
596        },
597        // sets the button Title property
598        setTitle : function(text){
599            if(text)
600                autoplayBtn.prop('title', text + ' (every ' + options.time/1000 + ' seconds)' );
601        },
602        // the button onClick handler
603        toggle : function(e){
604            e.stopPropagation();
605            APControl[ options.autoplay ? 'pause' : 'play']();
606        }
607    }
608
609    function getPrefixed(prop){
610        var i, s = doc.createElement('p').style, v = ['ms','O','Moz','Webkit'];
611        if( s[prop] == '' ) return prop;
612        prop = prop.charAt(0).toUpperCase() + prop.slice(1);
613        for( i = v.length; i--; )
614            if( s[v[i] + prop] == '' )
615                return (v[i] + prop);
616    }
617
618    function keyDown(event){
619        var code = event.keyCode, ok = options.keys, result;
620        // Prevent default keyboard action (like navigating inside the page)
621        return $.inArray(code, ok.close) >= 0 && close() ||
622               $.inArray(code, ok.next) >= 0 && !options.single && loophole(nextImage) ||
623               $.inArray(code, ok.prev) >= 0 && !options.single && loophole(prevImage) || true;
624    }
625
626    function wheelNextPrev(e, dY, dX){
627        if( dX == 1 )
628            loophole(nextImage);
629        else if( dX == -1 )
630            loophole(prevImage);
631    }
632
633
634    // serves as a callback for pbPrevBtn / pbNextBtn buttons but also is called on keypress events
635    function next_prev(){
636        // don't get crazy when user clicks next or prev buttons rapidly
637        //if( !image.hasClass('zoomable') )
638        //  return false;
639
640        var idx = (this.id == 'pbPrevBtn') ? prevImage : nextImage;
641
642        loophole(idx);
643        return false;
644    }
645
646    function updateIndexes(idx){
647        lastActive = activeImage;
648        activeImage = idx;
649        activeURL = images[idx][0];
650        prevImage = (activeImage || (options.loop ? images.length : 0)) - 1;
651        nextImage = ((activeImage + 1) % images.length) || (options.loop ? 0 : -1);
652    }
653
654    // check if looping is allowed before changing image/video.
655    // A pre-changeImage function, only for linear changes
656    function loophole(idx){
657        if( !options.loop ){
658            var afterLast = activeImage == images.length-1 && idx == nextImage,
659                beforeFirst = activeImage == 0 && idx == prevImage;
660
661            if( afterLast || beforeFirst )
662                return;
663        }
664
665        changeImage(idx);
666    }
667
668    changeImage = (function(){
669        var timer;
670
671        return function(imageIndex, firstTime, thumbClick){
672            // throttle mechanism
673            if( timer )
674                return;
675
676            timer = setTimeout(function(){
677                timer = null;
678            }, 150);
679
680            if( !imageIndex || imageIndex < 0 )
681                imageIndex = 0;
682
683            // hide/show next-prev buttons
684            if( !options.loop ){
685                nextBtn[ imageIndex == images.length-1 ? 'addClass' : 'removeClass' ]('hide');
686                prevBtn[ imageIndex == 0 ? 'addClass' : 'removeClass' ]('hide');
687            }
688
689            // if there's a callback for this point:
690            if( typeof options.beforeShow == "function")
691                options.beforeShow(imageLinks[imageIndex]);
692
693            overlay.removeClass('error').addClass( imageIndex > activeImage ? 'next' : 'prev' );
694
695            updateIndexes(imageIndex);
696
697            // reset things
698            stop();
699            video.empty();
700            preload.onerror = null;
701            image.add(video).data('zoom', 1);
702
703            activeType = imageLinks[imageIndex].rel == 'video' ? 'video' : 'image';
704
705            // check if current link is a video
706            if( activeType == 'video' ){
707				if($(imageLinks[activeImage]).attr('href').match(/<iframe(.+)<\/iframe>/i)){
708					video.html( newVideo(true) ).addClass('hide').attr('data-iframe', 'original_frame');
709				}else{
710					video.html( newVideo() ).addClass('hide');
711                }
712
713                showContent(firstTime);
714            }
715            else{
716                // give a tiny delay to the preloader, so it won't be showed when images load very quickly
717                var loaderTimeout = setTimeout(function(){ overlay.addClass('pbLoading'); }, 50);
718
719                if( isOldIE ) overlay.addClass('hide'); // should wait for the image onload. just hide the image while old IE display the preloader
720
721                options.autoplay && APControl.progress.reset();
722                preload = new Image();
723                preload.onload = function(){
724                    preload.onload = null;
725
726                    if( prevImage >= 0 ) preloadPrev.src = images[prevImage][0];
727                    if( nextImage >= 0 ) preloadNext.src = images[nextImage][0];
728
729                    clearTimeout(loaderTimeout);
730                    showContent(firstTime);
731                };
732                preload.onerror = imageError;
733                preload.src = activeURL;
734            }
735
736            // Show Caption text
737            captionText.on(transitionend, captionTextChange).addClass('change');
738            if( firstTime || isOldIE ) captionTextChange();
739
740
741            thumbsStripe.changeActive(imageIndex, firstTime, thumbClick);
742            // Save url hash for current image
743            history.save();
744        }
745    })();
746
747	function newVideo(iframe){
748		if(!iframe) {
749			iframe = false
750		}
751        if(iframe){
752			var url = $(imageLinks[activeImage]).attr('href');
753			return url;
754        }
755
756        var url = images[activeImage][0],
757            sign = $('<a>').prop('href',images[activeImage][0])[0].search ? '&' : '?';
758        url += sign + 'vq=hd720&wmode=opaque';
759
760        return $("<iframe>").prop({ scrolling:'no', frameborder:0, allowTransparency:true, src:url }).attr({webkitAllowFullScreen:true, mozallowfullscreen:true, allowFullScreen:true});
761    }
762
763    // show the item's Title & Counter
764    function captionTextChange(){
765        captionText.off(transitionend).removeClass('change');
766        // change caption's text
767        if( options.counter ){
768            try{
769                var value = options.counter.replace('A', activeImage + 1).replace('B', images.length);
770            }
771            // if, for some reason, the above has failed from a bad "counter" value, reset and retry
772            catch(err){
773                options.counter = '(A/B)';
774                captionTextChange();
775            }
776            caption.find('.counter').text(value);
777        }
778        var title = images[activeImage][1];
779        // if there's a callback for this point:
780        if( typeof options.getTitle == "function")
781            title = options.getTitle(imageLinks[activeImage]);
782
783        if( options.title )
784            caption.find('.title').html('<span>' + title + '</span>');
785    }
786
787    // Handles the history states when changing images
788    var history = {
789        save : function(){
790            // only save to history urls which are not already in the hash
791            if('pushState' in window.history && decodeURIComponent(window.location.hash.slice(1)) != activeURL && options.history ){
792                window.history.pushState( 'photobox', doc.title + '-' + images[activeImage][1], window.location.pathname + window.location.search + '#' + encodeURIComponent(activeURL) );
793            }
794        },
795        load : function(){
796            if( options && !options.history ) return false;
797            var hash = decodeURIComponent( window.location.hash.slice(1) ), i, j;
798            if( !hash && overlay.hasClass('show') )
799                close();
800
801			$('a[href="' + hash + '"]').trigger('click.photobox');
802        },
803        clear : function(){
804            if( options.history && 'pushState' in window.history )
805                window.history.pushState('photobox', doc.title, window.location.pathname + window.location.search);
806        }
807    };
808
809    // Add Photobox special `onpopstate` to the `onpopstate` function
810    window.onpopstate = (function(){
811        var cached = window.onpopstate;
812        return function(event){
813            cached && cached.apply(this, arguments);
814            if( event.state == 'photobox' )
815                history.load();
816        }
817    })();
818
819    // handles all image loading error (if image is dead)
820    function imageError(){
821        overlay.addClass('error');
822        image[0].src = blankImg; // set the source to a blank image
823        preload.onerror = null;
824    }
825
826    function getImages() {
827		return images;
828	}
829
830    // Shows the content (image/video) on the screen
831    function showContent(firstTime){
832        var out, showSaftyTimer;
833        showSaftyTimer = setTimeout(show, 2000);
834
835        // hides the current image and prepare ground for an image change
836        pbLoader.fadeOut(300, function(){
837            overlay.removeClass("pbLoading");
838            pbLoader.removeAttr('style');
839        });
840        overlay.addClass('hide');
841
842        image.add(video).removeAttr('style').removeClass('zoomable'); // while transitioning an image, do not apply the 'zoomable' class
843
844        // check which element needs to transition-out:
845        if( !firstTime && imageLinks[lastActive].rel == 'video' ){
846            out = video;
847            image.addClass('prepare');
848        }
849        else
850            out = image;
851
852        if( firstTime || isOldIE )
853            show();
854        else
855            out.on(transitionend, show);
856
857        // in case the 'transitionend' didn't fire
858        // after hiding the last seen image, show the new one
859        function show(){
860            clearTimeout(showSaftyTimer);
861            out.off(transitionend).css({'transition':'none'});
862            overlay.removeClass('video');
863            if( activeType == 'video' ){
864                image[0].src = blankImg;
865                video.addClass('prepare');
866                overlay.addClass('video');
867            }
868            else
869                image.prop({ 'src':activeURL, 'class':'prepare' });
870
871            // filthy hack for the transitionend event, but cannot work without it:
872            setTimeout(function(){
873                image.add(video).removeAttr('style').removeClass('prepare');
874                overlay.removeClass('hide next prev');
875                setTimeout(function(){
876                    image.add(video).on(transitionend, showDone);
877                    if(isOldIE) showDone(); // IE9 and below don't support transitionEnd...
878                }, 0);
879            },50);
880        }
881    }
882
883    // a callback whenever a transition of an image or a video is done
884    function showDone(){
885        image.add(video).off(transitionend).addClass('zoomable');
886        if( activeType == 'video' )
887            video.removeClass('hide');
888        else{
889            autoplayBtn && options.autoplay && APControl.play();
890		}
891        if(photobox && typeof photobox.callback == 'function' )
892            photobox.callback.apply(imageLinks[activeImage]);
893    }
894
895    function scrollZoom(e, deltaY, deltaX){
896        if( deltaX ) return false;
897
898        if( activeType == 'video' ){
899            var zoomLevel = video.data('zoom') || 1;
900            zoomLevel += (deltaY / 10);
901            if( zoomLevel < 0.5 )
902                return false;
903
904            video.data('zoom', zoomLevel).css({width:624*zoomLevel, height:351*zoomLevel});
905        }
906        else{
907            var zoomLevel = image.data('zoom') || 1,
908                getSize = image[0].getBoundingClientRect();
909
910            zoomLevel += (deltaY / 10);
911
912            if( zoomLevel < 0.1 )
913                zoomLevel = 0.1;
914
915            raf(function() {
916                image.data('zoom', zoomLevel).css({'transform':'scale('+ zoomLevel +')'});
917            });
918
919            // check if image (by mouse) movement should take effect (if image is larger than the window
920            if( getSize.height > docElm.clientHeight || getSize.width > docElm.clientWidth ){
921                $(doc).on('mousemove.photobox', imageReposition);
922            }
923            else{
924                $(doc).off('mousemove.photobox');
925                image[0].style[transformOrigin] = '50% 50%';
926            }
927        }
928        return false;
929    }
930
931    function thumbsResize(e, delta){
932        e.preventDefault();
933        e.stopPropagation(); // stop the event from bubbling up to the Overlay and enlarge the content itself
934        var thumbList = photobox.thumbsList, h;
935        thumbList.css('height', thumbList[0].clientHeight + (delta * 10) );
936        h = caption[0].clientHeight / 2;
937        wrapper[0].style.cssText = "margin-top: -"+ h +"px; padding: "+ h +"px 0;";
938        thumbs.hide().show(0);
939        //thumbs.trigger('mouseenter').trigger('mousemove');
940    }
941
942    // moves the image around during zoom mode on mousemove event
943    function imageReposition(e){
944        var y = (e.clientY / docElm.clientHeight) * (docElm.clientHeight + 200) - 100, // extend the range of the Y axis by 100 each side
945            yDelta = y / docElm.clientHeight * 100,
946            xDelta = e.clientX / docElm.clientWidth * 100,
947            origin = xDelta.toFixed(2)+'% ' + yDelta.toFixed(2) +'%';
948
949        raf(function() {
950            image[0].style[transformOrigin] = origin;
951        });
952    }
953
954    function stop(){
955        clearTimeout(APControl.autoPlayTimer);
956        $(doc).off('mousemove.photobox');
957        preload.onload = function(){};
958        preload.src = preloadPrev.src = preloadNext.src = activeURL;
959    }
960
961    function close(){
962            if( !overlay.hasClass('show') )
963                return false;
964
965            stop();
966            video.find('iframe').prop('src','').empty();
967            Photobox.prototype.setup();
968            history.clear();
969
970            overlay.removeClass('on video').addClass('hide');
971
972            image.on(transitionend, hide);
973            isOldIE && hide();
974
975            // the "photobox" instance might be needed for async transitionEnd functions, so give it some time before clearing it
976            setTimeout(function(){
977                photobox = null;
978            },1000);
979
980            function hide(){
981                if( overlay[0].className == '' ) return; // if already hidden
982                overlay.removeClass('show hide error pbLoading');
983                image.removeAttr('class').removeAttr('style').off().data('zoom',1);
984                caption.find('.title').empty();
985
986                if(noPointerEvents) // pointer-events lack support in IE, so just hide the overlay
987                    setTimeout(function(){ overlay.hide(); }, 200);
988
989                options.hideFlash && $('iframe, object, embed').css('visibility', 'visible');
990            }
991
992            // fall-back if the 'transitionend' event didn't fire
993            setTimeout(hide, 500);
994            // callback after closing the gallery
995            if( typeof options.afterClose === 'function' )
996                options.afterClose(overlay);
997    }
998
999    /*! Copyright (c) 2013 Brandon Aaron (http://brandon.aaron.sh)
1000     * Licensed under the MIT License (LICENSE.txt).
1001     *
1002     * Version: 3.1.11
1003     *
1004     * Requires: jQuery 1.2.2+
1005     */
1006    !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports&&typeof module!='undefined'&&module.exports?module.exports=a:a(jQuery)}(function(a){function b(b){var g=b||window.event,h=i.call(arguments,1),j=0,l=0,m=0,n=0,o=0,p=0;if(b=a.event.fix(g),b.type="mousewheel","detail"in g&&(m=-1*g.detail),"wheelDelta"in g&&(m=g.wheelDelta),"wheelDeltaY"in g&&(m=g.wheelDeltaY),"wheelDeltaX"in g&&(l=-1*g.wheelDeltaX),"axis"in g&&g.axis===g.HORIZONTAL_AXIS&&(l=-1*m,m=0),j=0===m?l:m,"deltaY"in g&&(m=-1*g.deltaY,j=m),"deltaX"in g&&(l=g.deltaX,0===m&&(j=-1*l)),0!==m||0!==l){if(1===g.deltaMode){var q=a.data(this,"mousewheel-line-height");j*=q,m*=q,l*=q}else if(2===g.deltaMode){var r=a.data(this,"mousewheel-page-height");j*=r,m*=r,l*=r}if(n=Math.max(Math.abs(m),Math.abs(l)),(!f||f>
vendor: 2,181 bytes, lines 1006-1022
1006n)&&(f=n,d(g,n)&&(f/=40)),d(g,n)&&(j/=40,l/=40,m/=40),j=Math[j>=1?"floor":"ceil"](j/f),l=Math[l>=1?"floor":"ceil"](l/f),m=Math[m>=1?"floor":"ceil"](m/f),k.settings.normalizeOffset&&this.getBoundingClientRect){var s=this.getBoundingClientRect();o=b.clientX-s.left,p=b.clientY-s.top}return b.deltaX=l,b.deltaY=m,b.deltaFactor=f,b.offsetX=o,b.offsetY=p,b.deltaMode=0,h.unshift(b,j,l,m),e&&clearTimeout(e),e=setTimeout(c,200),(a.event.dispatch||a.event.handle).apply(this,h)}}function c(){f=null}function d(a,b){return k.settings.adjustOldDeltas&&"mousewheel"===a.type&&b%120===0}var e,f,g=["wheel","mousewheel","DOMMouseScroll","MozMousePixelScroll"],h="onwheel"in document||document.documentMode>=9?["wheel"]:["mousewheel","DomMouseScroll","MozMousePixelScroll"],i=Array.prototype.slice;if(a.event.fixHooks)for(var j=g.length;j;)a.event.fixHooks[g[--j]]=a.event.mouseHooks;var k=a.event.special.mousewheel={version:"3.1.11",setup:function(){if(this.addEventListener)for(var c=h.length;c;)this.addEventListener(h[--c],b,!1);else this.onmousewheel=b;a.data(this,"mousewheel-line-height",k.getLineHeight(this)),a.data(this,"mousewheel-page-height",k.getPageHeight(this))},teardown:function(){if(this.removeEventListener)for(var c=h.length;c;)this.removeEventListener(h[--c],b,!1);else this.onmousewheel=null;a.removeData(this,"mousewheel-line-height"),a.removeData(this,"mousewheel-page-height")},getLineHeight:function(b){var c=a(b)["offsetParent"in a.fn?"offsetParent":"parent"]();return c.length||(c=a("body")),parseInt(c.css("fontSize"),10)},getPageHeight:function(b){return a(b).height()},settings:{adjustOldDeltas:!0,normalizeOffset:!0}};a.fn.extend({mousewheel:function(a){return a?this.bind("mousewheel",a):this.trigger("mousewheel")},unmousewheel:function(a){return this.unbind("mousewheel",a)}})});
1007
1008    ////////////// ON DOCUMENT READY /////////////////
1009    $(doc).ready(prepareDOM);
1010
1011    // Expose:
1012    window._photobox = {
1013        DOM        : {
1014            overlay : overlay
1015        },
1016        close    : close,
1017		getImages: getImages,
1018		changeImage: changeImage,
1019        history  : history,
1020        defaults : defaults
1021    };
1022})(jQuery, document, window);

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.