PageSourceSearch

https://saxonwebsites.co.uk/wp-content/themes/enigma/js/jquery.pho…?ver=7282a56542631ebb434e1a0548020e51

js saxonwebsites.co.uk collected 2026-09-25 23:06:31 UTC 42,965 bytes, 968 lines download raw bytes

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