PageSourceSearch

https://www.edelsfeld.de/rd/108004/javascripts/media-boxes/jquery.mediaBoxes.js

js edelsfeld.de collected 2026-10-02 18:05:00 UTC 105,104 bytes, 2,292 lines download raw bytes

1    
2/* ======================================================= 
3 *
4 *      Media Boxes     
5 *      Version: 3.7.4
6 *      By castlecode
7 *
8 *      Contact: http://codecanyon.net/user/castlecode
9 *      Created: March 11, 2014
10 *
11 *      Copyright (c) 2013, castlecode. All rights reserved.
12 *      Available only in http://codecanyon.net/
13 *      
14 *      ---------------------------------
15 *      CONTENTS
16 *      ---------------------------------
17 *
18 *      [A] MEDIA BOXES CLASS
19 *      [B] DEFAULTS
20 *      [C] INIT
21 *          [1] SETUP
22 *          [2] GRID METHODS
23 *          [3] EXTENDING ISOTOPE
24 *          [4] FILTERING ISOTOPE
25 *          [5] LOAD MORE BOXES
26 *          [6] FILTER
27 *          [7] SEARCH
28 *          [8] SORTING
29 *          [9] THUMBNAIL OVERLAY EFFECT
30 *          [10] IFRAME ON GRID
31 *          [11] INIT POPUP
32 *          [12] FANCYBOX
33 *          [13] MAGNIFIC POPUP
34 *          [14] DEEP LINKING
35 *          [15] SOCIAL IN MAGNIFIC POPUP
36 *      [D] DESTROY
37 *      [E] INSERT
38 *      [F] INSERT IN FLOW
39 *      [G] REFRESH
40 *      [H] RESIZE
41 *      [I] MEDIA BOXES PLUGIN
42 *      
43 * ======================================================= */
44
45(function( window, $, undefined ){
46
47    "use strict";
48
49/* ====================================================================== *
50        [A] MEDIA BOXES CLASS
51 * ====================================================================== */    
52
53    var MediaBoxes = function(container, options){
54        this.init(container, options);
55    }
56
57/* ====================================================================== *
58        [B] DEFAULTS
59 * ====================================================================== */    
60    
61    MediaBoxes.DEFAULTS = {
62        boxesToLoadStart                : 8,
63        boxesToLoad                     : 4,
64        minBoxesPerFilter               : 0,
65        lazyLoad                        : true,
66        horizontalSpaceBetweenBoxes     : 15,
67        verticalSpaceBetweenBoxes       : 15,
68        columnWidth                     : 'auto',
69        columns                         : 4,
70        resolutions                     :   [
71                                                {
72                                                    maxWidth: 960,
73                                                    columnWidth: 'auto',
74                                                    columns: 3,
75                                                },
76                                                {
77                                                    maxWidth: 650,
78                                                    columnWidth: 'auto',
79                                                    columns: 2,
80                                                    horizontalSpaceBetweenBoxes: 10,
81                                                    verticalSpaceBetweenBoxes: 10,
82                                                },
83                                                {
84                                                    maxWidth: 450,
85                                                    columnWidth: 'auto',
86                                                    columns: 1,
87                                                    horizontalSpaceBetweenBoxes: 10,
88                                                    verticalSpaceBetweenBoxes: 10,
89                                                },
90                                            ],
91        multipleFilterLogic             : 'AND',
92        filterContainer                 : '#filter',
93        search                          : '', // i.e. #search
94        searchTarget                    : '.media-box-title',
95        sortContainer                   : '', // i.e. #sort
96        getSortData                     :   {
97                                              title: '.media-box-title',
98                                              text: '.media-box-text',
99                                            }, 
100        waitUntilThumbWithRatioLoads    : true, // When they have dimensions specified
101        waitForAllThumbsNoMatterWhat    : false, // Wait for all the thumbnails to load even if they got dimensions specified
102        noEmptySpaceOnThumbWithRatio    : true, // Make thumbnail automatically adapt to the 100% of its container (so no black space)
103        thumbnailOverlay                : true, //Show the overlay on mouse over
104        overlayEffect                   : 'fade', // 'push-up', 'push-down', 'push-up-100%', 'push-down-100%', 'reveal-top', 'reveal-bottom', 'reveal-top-100%', 'reveal-bottom-100%', 'direction-aware', 'direction-aware-fade', 'direction-right', 'direction-left', 'direction-top', 'direction-bottom', 'fade'
105        overlaySpeed                    : 200,
106        overlayEasing                   : 'default',
107        showOnlyVisibleBoxesInPopup     : false,
108        considerFilteringInPopup        : true,
109        deepLinkingOnPopup              : true,
110        deepLinkingOnFilter             : true,
111        deepLinkingOnSearch             : false,
112        LoadingWord                     : 'Loading...',
113        loadMoreWord                    : 'Load More',
114        noMoreEntriesWord               : 'No More Entries',
115        percentage                      : false,
116
117        popup                           : 'magnificpopup', // fancybox, magnificpopup, none
118        magnificpopup                   :   {
119                                                gallery: false,
120                                                alignTop: false,
121                                                preload: [0,2],    
122                                            },
123        fancybox                        :   {
124                                                loop                : false, // Enable infinite gallery navigation 
125                                                margin              : [44, 0], // Space around image, ignored if zoomed-in or viewport smaller than 800px
126                                                keyboard            : true, // Enable keyboard navigation
127                                                arrows              : true, // Should display navigation arrows at the screen edges
128                                                infobar             : false, // Should display infobar (counter and arrows at the top)
129                                                toolbar             : true, // Should display toolbar (buttons at the top)
130                                                buttons             :   [ // What buttons should appear in the top right corner.
131                                                                            'slideShow',
132                                                                            'fullScreen',
133                                                                            'thumbs',
134                                                                            'close'
135                                                                        ],
136                                                idleTime            : 999999999, // Detect "idle" time in seconds
137                                                protect             : false, // Disable right-click and use simple image protection for images
138                                                animationEffect     : 'zoom', // Open/close animation type, it could be: false, 'zoom', 'fade', 'zoom-in-out'
139                                                animationDuration   : 330, // Duration in ms for open/close animation
140                                                transitionEffect    : 'fade', // ransition effect between slides, it could be: false, 'fade', 'slide', 'circular', 'tube', 'zoom-in-out', 'rotate'
141                                                transitionDuration  : 330, // Duration in ms for transition animation
142                                                slideShow           : { autoStart : false, speed : 4000 }, // slideshow settings
143                                                fullScreen          : { autoStart : false, }, // activate or deactivate fullscreen when open
144                                                thumbs              : { autoStart : false, hideOnClose : true },    // Display thumbnails on opening/closing
145                                                touch               : { vertical : true, momentum : true }, // Allow to drag content
146                                                compensateScrollbar : '.fancybox-compensate-for-scrollbar',
147                                            },
148
149        animation_on_thumbnail_overlay_hover : [
150                                                    // { item : '.fa', animation : 'zoom-out' } // zoom-out, zoom-in, from-top, from-bottom, from-left, from-right
151                                                ],                                        
152        
153        //some sharing hidden options (for magnific popup only) :D
154        /*
155        facebook                        : true,
156        twitter                         : true,
157        googleplus                      : true,
158        pinterest                       : true,
159        */
160
161        /* Events */
162        onLayoutFinish : function(){},
163        onPopupStart : function(){},
164        onPopupClose : function(){},
165    };    
166
167/* ====================================================================== *
168        [C] INIT
169 * ====================================================================== */    
170
171    MediaBoxes.prototype.init = function(container, options){   
172        
173    /* ====================================================================== *
174            [1] SETUP
175     * ====================================================================== */
176
177        /* SETTINGS */
178        var settings                    = $.extend(true, {}, MediaBoxes.DEFAULTS, options);
179
180        if(options!=undefined && options.resolutions!=undefined){ // the extend propety do not replace arrays it merges them
181            settings.resolutions = options.resolutions;
182        }
183
184        /* VARS */
185        var $container                  = $(container).addClass('media-boxes-container');        
186        var itemSelector                = '.media-box';
187        var boxImageSelector            = '.media-box-image';
188        var itemClass                   = 'media-box'; /* same as itemSelector but without the '.' */
189        var itemHiddenClass             = 'media-box-hidden';
190        var animation                   = Modernizr.csstransitions?'transition':'animate'; /* CSS3 transition or jQuery animate depending on the browser support */
191        var filters                     = {};
192        var loadingsCounter             = 0; /* When there's more than one loading at the same time */
193        var filtersContainers           = $(settings.filterContainer);
194
195        if( settings.overlayEasing == 'default' ){
196            settings.overlayEasing      = (animation=='transition')?'_default':'swing'; /* 'default' is for CSS3 and 'swing' for jQuery animate */
197        }
198
199        /* SET GLOBAL VARS, USED FOR "OUTSIDE" METHODS */
200        this.container                  = $container;
201        this.container_clone            = $container.clone().removeClass('media-boxes-container');
202        
203        /* Load more button */
204        var loadMoreButton              = $('<div class="media-boxes-load-more media-boxes-load-more-button"></div>').insertAfter($container);
205
206        /* Sort the resolutions from lower to higher */
207        settings.resolutions.sort(function(a,b){ return a.maxWidth - b.maxWidth; });
208
209        /* Save the settings in the container */
210        $container.data('settings', settings);
211        
212        /* Fix the margins for the container (for horizontal and vertical space)  */
213        //$container.css('margin-left', -settings.horizontalSpaceBetweenBoxes);
214
215        /* Hide all boxes */
216        $container.find(itemSelector).removeClass(itemClass).addClass(itemHiddenClass);
217
218        /* default sort selected */
219        var defSortElem = $(settings.sortContainer).find('*[data-sort-by]').filter('.selected');
220        var defSort     = defSortElem.attr('data-sort-by');
221        var defAsc      = getSortDirection(defSortElem);
222
223        /* Add the sizer for defining the width of isotope */
224        $container.append('<div class="media-boxes-grid-sizer"></div>');
225
226        /* Initialize isotope plugin */
227        $container.isotopeMB({
228            itemSelector    : itemSelector,   
229            transitionDuration: '0.5s',
230            hiddenStyle: { opacity: 0, transform: 'scale(0.7)' },
231            visibleStyle: { opacity: 1, transform: 'scale(1)' },
232            masonry: {
233                columnWidth: '.media-boxes-grid-sizer'
234            },
235            getSortData: settings.getSortData,
236            sortBy: defSort, 
237            sortAscending: defAsc,   
238        }); 
239
240        /* If the filter item is hidden AND if its was marked as "selected by default" then fallback to "all" */
241        filtersContainers.find('[data-filter]').addBack('[data-filter]').each(function(){
242            var $this       = $(this);
243
244            if($this.attr('data-visible-only-if') != undefined){ // if the filter item visibility is based on another item
245                var $visible    = $($this.attr('data-visible-only-if'));
246
247                // if it is a checkbox
248                if($visible.is(':checkbox')){
249                    if($visible.is(':checked') == false){ // If the element is unchecked, then uncheck the item
250                        $this.prop('checked', false);
251                    }
252                }
253
254                // if it is a dropdown or inline
255                if(!$visible.is(':checkbox') && !$visible.is('select')){
256                    if($visible.hasClass('selected') == false){ // if the element is not selected, then unselect the item (and select the "all" item)
257                        $this.removeClass('selected');
258                        $this.parents(settings.filterContainer).find('[data-filter="*"]').addClass('selected');
259                    }
260                }
261
262            }
263        });
264
265        /* default filters */
266        filtersContainers.each(function(){
267            /* current items */
268            var current_filterContainer = $(this);
269            var filterValue             = '';
270
271            /* if its a checkbox */
272            if(current_filterContainer.is(':checkbox')){
273                filterValue         = current_filterContainer.is(':checked') ? current_filterContainer.attr('data-filter') : '*';
274            }else{
275                var current_filter  = current_filterContainer.find('*[data-filter]').filter('.selected');
276                filterValue         = current_filter[0] !== undefined ? current_filter.attr('data-filter') : '*';
277            }
278
279            show_hide_filters();
280
281            /* Filter isotope */
282            var filterGroup         = current_filterContainer.data("id") != undefined ? current_filterContainer.data("id") : "filter"; // take the id of the filter container if exists, if not just a string
283            filters[ filterGroup ]  = filterValue;
284            
285            $container.isotopeMB({ filter: combineFilters(filters) });
286
287            updateFilterClasses();
288        });
289
290    /* ====================================================================== *
291            [2] GRID METHODS
292     * ====================================================================== */
293
294        /* ****** Add div with margins (for horizontal and vertical space) ****** */
295        function addWrapperForMargins(container){
296            /*var wrapper = $('<div class="media-box-container"></div').css({
297                                    'margin-left'       : container.data('settings').horizontalSpaceBetweenBoxes,
298                                    'margin-bottom'     : container.data('settings').verticalSpaceBetweenBoxes
299                                });*/
300
301            var wrapper = $('<div class="media-box-container"></div');
302            container.find(itemSelector+':not([data-wrapper-added])').attr('data-wrapper-added', 'yes').wrapInner( wrapper );
303        }
304
305        /* ****** FadeIn the thumbnail or show broken thumbnail only for the ones with ratio specified ****** */
306        function fadeInOrBroken(container, imageObj){
307            var image           = $(imageObj.img);
308            var thumbnailDiv    = image.parents('.image-with-dimensions');
309            
310            /* it has already been loaded or broken so skip it */
311
312            if(image.hasClass('done')){ 
313                return;
314            }
315            image.addClass('done');
316
317            /* if the media-box is fully scaled (100%) then no need for the delay, fadeIn right away */
318
319            var delay               = 200;
320            var media_box           = image.parents(itemSelector);
321            var transform_matrix    = media_box.css("-webkit-transform") || media_box.css("-moz-transform") || media_box.css("-ms-transform") || media_box.css("-o-transform") || media_box.css("transform");
322            if(transform_matrix == 'none'){
323                delay = 0;
324            }
325
326            /* Load or broken */
327
328            //return; // HEREE
329
330            setTimeout(function(){
331
332                if( imageObj.isLoaded ){
333
334                    noEmptySpaceOnThumbnails(container);
335
336                    thumbnailDiv.find('.media-boxes-loading-animation').fadeOut(700);
337                    image.fadeIn(500, function(){ /* This will only be trigger if you hide the image above (if the "waitUntilThumbWithRatioLoads" settings is true) */
338                        thumbnailDiv.removeClass('image-with-dimensions'); 
339                    }); 
340                    
341                }else{
342                    thumbnailDiv.find('.media-boxes-loading-animation').fadeOut(500);
343                    thumbnailDiv.removeClass('image-with-dimensions');
344                    image.hide(); /* hide image since you are going to show a broken logo */
345                    thumbnailDiv.addClass('broken-image-here');
346                }
347
348            }, delay);
349        }
350
351        /* ****** No empty space on thumbnails (fill height or width) ****** */
352        function noEmptySpaceOnThumbnails(container){
353            if(container.data('settings') && container.data('settings').noEmptySpaceOnThumbWithRatio){
354
355                container.find(itemSelector+', .'+itemHiddenClass).each(function(){
356                    var $this               = $(this);
357                    var thumbnailDiv        = $this.find('div[data-width][data-height]');
358                    var image               = thumbnailDiv.find('img');
359
360                    if(thumbnailDiv[0]!= undefined){
361
362                        var thumbnailDiv_ratio  = parseFloat(thumbnailDiv.data('width')) / parseFloat(thumbnailDiv.data('height'));
363                        var image_ratio         = parseFloat(image.width()) / parseFloat(image.height());
364
365                        //thumbnailDiv_ratio      = Math.floor(thumbnailDiv_ratio*100)/100;
366                        //image_ratio             = Math.floor(image_ratio*100)/100;
367
368                        thumbnailDiv_ratio      = thumbnailDiv_ratio.toFixed(2);
369                        image_ratio             = image_ratio.toFixed(2);
370
371                        if(thumbnailDiv_ratio < image_ratio){
372                            thumbnailDiv.addClass('media-box-fill-height');
373                            //console.log(thumbnailDiv_ratio +" < "+ image_ratio);
374                        }else{
375                            thumbnailDiv.removeClass('media-box-fill-height');
376                        }
377
378                    }
379                });
380
381            }
382        }
383
384        /* ****** Load images with dimensions ****** */
385        function loadImagesWithDimensions(container){
386            /* FadeIn thumbnails that have dimensions specified if you want to show them after they have been loaded */
387            container.find('.image-with-dimensions').imagesLoadedMB()
388                .always(function(instance){
389                    /* In case the progress event don't get to show the images (this happens sometimes when you refresh the page) */
390                    for(var index in instance.images){
391                        var imageObj = instance.images[index];
392                        fadeInOrBroken(container, imageObj);
393                    }
394                })
395                .progress(function(instance, imageObj) {
396                    fadeInOrBroken(container, imageObj);
397                });
398        }
399
400        /* ****** Convert the divs with the URL specified to real images ****** */
401        function convertDivsIntoImages(container, imagesWithDimensions){
402            container.find(itemSelector).find(boxImageSelector+':not([data-imageconverted])').each(function(){
403                var boxImage        = $(this);
404                var thumbnailDiv    = boxImage.find('div[data-thumbnail]').eq(0); /* only one thumb allowed */
405                var thumbnailSrc    = thumbnailDiv.attr('data-thumbnail');
406                var thumbnailTitle  = thumbnailDiv.attr('data-title') != undefined ? thumbnailDiv.attr('data-title') : "";
407                var thumbnailAlt    = thumbnailDiv.attr('data-alt') != undefined ? thumbnailDiv.attr('data-alt') : "";
408                var gotDimensions   = thumbnailDiv.attr('data-width') != undefined && thumbnailDiv.attr('data-height') != undefined;
409                var waitForAll      = container.data('settings').waitForAllThumbsNoMatterWhat;
410
411                if(thumbnailSrc == 'none'){ // if there's no URL then don't load an image
412                    return true; // same as "continue"
413                }
414
415                if(imagesWithDimensions == false && gotDimensions == true && waitForAll == false){
416                    /* when the plugin wants the images WITHOUT dimensions, only ignore the images WITH dimensions if option "waitForAll..." is false */
417                    return;
418                }
419
420                var imgHTML         = $('<img alt="'+thumbnailAlt+'" title="'+thumbnailTitle+'" src="'+thumbnailSrc+'" />');
421
422                if(imagesWithDimensions == true){
423                    /* If the dimensions are specified in the images then ignore them in the imagesLoaded plugin when you insert new items */
424                    imgHTML.attr('data-dont-wait-for-me', 'yes');
425                    thumbnailDiv.addClass('image-with-dimensions');
426                    thumbnailDiv.prepend('<div class="media-boxes-loading-animation"></div>');
427
428                    if( container.data('settings').waitUntilThumbWithRatioLoads ){
429                        imgHTML.hide();
430                    }
431                }
432
433                boxImage.attr('data-imageconverted', 'yes');
434                thumbnailDiv.addClass('media-box-thumbnail-container').prepend(imgHTML);
435            });
436
437            loadImagesWithDimensions(container);
438        }
439
440        /* ****** Set the width and height for the media-box-image div, this is helpful for some overlay effects ****** */
441        function setDimensionsToImageContainer(container){
442            container.find(itemSelector).find(boxImageSelector).each(function(){
443                var boxImage        = $(this);
444                var box             = boxImage.parents(itemSelector);
445                var hiddenBox       = box.css('display') == 'none';
446                var thumbnailDiv    = boxImage.find('div[data-thumbnail]').eq(0); // only one thumb allowed
447
448                if(thumbnailDiv[0] != undefined){ // if you haven't specified a thumbnail then ignore
449                    if(hiddenBox){// If it is hidden, display 'none' wont give you the right height so you need to do this trick
450                        box.css('margin-top', 99999999999999).show();
451                    }
452
453                    boxImage.width( thumbnailDiv[0].offsetWidth ); // now using offsetWidth, since jQuery3.width() changed to getBoundingClientRect()
454                    boxImage.height( thumbnailDiv[0].offsetHeight );
455
456                    if(hiddenBox){
457                        box.css('margin-top', 0).hide();
458                    }
459                }
460            });
461        }
462
463        /* ****** Calculate the right dimensions for the thumbnails ****** */
464        function setStaticDimensionsOfThumbnails(container){
465            container.find(itemSelector).find(boxImageSelector).each(function(){
466                var boxImage        = $(this);
467                var box             = boxImage.parents(itemSelector);
468                var hiddenBox       = box.css('display') == 'none';
469                var thumbnailDiv    = boxImage.find('div[data-thumbnail]').eq(0); /* only one thumb allowed */
470                var gotDimensions   = thumbnailDiv.attr('data-width') != undefined && thumbnailDiv.attr('data-height') != undefined;
471
472                var imgWidth        = parseFloat( thumbnailDiv.data('width') );
473                var imgHeight       = parseFloat( thumbnailDiv.data('height') );
474
475                if(hiddenBox){// If it is hidden, display 'none' wont give you the right height so you need to do this trick
476                    box.css('margin-top', 99999999999999).show();
477                }
478
479                var newWidth        = box[0].offsetWidth - container.data('current_horizontalSpaceBetweenBoxes'); // now using offsetWidth, since jQuery3.width() changed to getBoundingClientRect()
480                var newHeight       = (imgHeight * newWidth)/imgWidth;
481
482                if(hiddenBox){
483                    box.css('margin-top', 0).hide();
484                }
485                
486                thumbnailDiv.css('width', newWidth);
487
488                /* Set the height only to those thumbs with width and height specified */ 
489                if( gotDimensions ){
490                    if(box.attr('data-current-columns')>1 && box.attr('data-extra-height')){
491                        newHeight = newHeight + parseFloat(box.attr('data-extra-height'));
492                    }
493                    thumbnailDiv.css('height', Math.floor(newHeight));
494                }
495            });
496        }
497        
498        /* ****** Set the width of the columns according to the settings specified ****** */
499        function setColumnWidth(container, columnWidth, columns){
500            var newWidth    = 0;
501            var percentage  = container.data('settings').percentage;
502            var symbol      = '';
503
504            if( columnWidth == 'auto' ){
505                if(percentage){
506                    newWidth    = 100/columns;
507                    symbol      = '%';
508                }else{
509                    newWidth    = Math.floor(  Math.floor(container.width())/columns ); // minus 1px because some resolutions don't fit perfectly
510                }
511            }else{
512                newWidth = columnWidth;
513            }
514
515            /* the width that the isotope logic will use for each column of the grid */
516            container.find('.media-boxes-grid-sizer').css( 'width' , newWidth + symbol );
517            
518            container.find(itemSelector).each(function(index){
519                var box         = $(this);
520                var boxColumns  = box.data('columns');
521
522                /* if the box has columns asigned, check that it doesn't have more than the number of columns in the grid */
523                if(boxColumns != undefined && parseInt(boxColumns)>parseInt(columns)){
524                    boxColumns = columns;
525                }
526
527                /* for columns that don't have data-columns specified */
528                if(boxColumns == undefined){
529                    boxColumns = 1;
530                }
531
532                /* number of columns for this item */
533                box.attr('data-current-columns', boxColumns);
534                
535                /* Adjust the width */
536                box.css( 'width' , (parseFloat(newWidth)*parseInt(boxColumns)) + symbol );
537            });
538        }
539        
540        /* ****** Get viewport dimensions ****** */
541        function viewport() {
542            var e = window, a = 'inner';
543            if (!('innerWidth' in window )) {
544                a = 'client';
545                e = document.documentElement || document.body;
546            }
547            return { width : e[ a+'Width' ] , height : e[ a+'Height' ] };
548        }
549        
550        /* ****** Set new horizontal and vertical space between boxes ****** */
551        function setSpaceBetweenBoxes(container, horizontal, vertical){
552            container.data('current_horizontalSpaceBetweenBoxes', horizontal);
553            container.data('current_verticalSpaceBetweenBoxes', vertical);
554
555            container.css('margin-left', -horizontal);
556            /*container.find('.media-box-container').css({
557                                    'margin-left'       : horizontal,
558                                    'margin-bottom'     : vertical
559                                });*/
560            container.find('.media-box-container').each(function(){
561                this.style.setProperty( 'margin-left', horizontal+"px", 'important' );
562                this.style.setProperty( 'margin-bottom', vertical+"px", 'important' );
563            });
564
565
566        }
567
568        /* ****** Get and set the correct columnWidth for the current resolution ****** */
569        function getAndSetColumnWidth(container){
570            var resolutionFound = false;
571            for (var key in container.data('settings').resolutions) {
572                var value = container.data('settings').resolutions[key];
573                
574                if( value.maxWidth >= viewport().width ){
575                    if(value.horizontalSpaceBetweenBoxes != undefined && value.verticalSpaceBetweenBoxes != undefined){
576                        setSpaceBetweenBoxes(container, value.horizontalSpaceBetweenBoxes, value.verticalSpaceBetweenBoxes);
577                    }else{
578                        setSpaceBetweenBoxes(container, container.data('settings').horizontalSpaceBetweenBoxes, container.data('settings').verticalSpaceBetweenBoxes);
579                    }
580                    setColumnWidth(container, value.columnWidth, value.columns);
581                    resolutionFound = true;
582                    break;
583                }
584            }
585            
586            /* If there wasn't a match then use the default one */
587            if( resolutionFound == false ){
588                setSpaceBetweenBoxes(container, container.data('settings').horizontalSpaceBetweenBoxes, container.data('settings').verticalSpaceBetweenBoxes);
589                setColumnWidth(container, container.data('settings').columnWidth, container.data('settings').columns);
590            }
591        }
592
593        /* ****** Hide overlays when resizing ****** */
594        function hideOverlaysOnResize(container){
595            var boxes = container.find(itemSelector);
596
597            boxes.each(function(){
598                var box         = $(this);
599                var boxImage    = box.find(boxImageSelector);
600                var effect      = container.data('settings').overlayEffect;
601                if(effect.indexOf('100') >= 0 && effect.indexOf('100%') == -1){ // if its missing the % sign at the end then just add it
602                    effect = effect.split('100').join('100%');
603                }
604
605                if( effect.substr(0, 9) == 'direction' ){
606                    boxImage.find('.thumbnail-overlay').hide();
607                }
608            });
609
610            /* reload isotope for the new width */
611            container.isotopeMB('layout');
612        }
613
614    /* ====================================================================== *
615            [3] EXTENDING ISOTOPE
616     * ====================================================================== */
617
618        /* ****** Extending Isotope on resize event ****** */
619        $.extend( IsotopeMB.prototype, {
620            resize : function() {
621                /* Hack for seting the grid */
622                var container = $(this.element);
623                getAndSetColumnWidth(container);
624                setStaticDimensionsOfThumbnails(container);
625                setDimensionsToImageContainer(container);
626                hideOverlaysOnResize(container);
627                /* End hack */
628                
629                // don't trigger if size did not change
630                // or if resize was unbound. See #9
631                if ( !this.isResizeBound || !this.needsResizeLayout() ) {
632                    return;
633                }
634
635                this.layout();
636            }
637        });
638        
639        /* ****** Extending Isotope so when it does set the container width the plugin can refresh the lazy load feature ****** */
640        $.extend( IsotopeMB.prototype, {
641            _setContainerMeasure : function( measure, isWidth ) {
642                if ( measure === undefined ) {
643                    return;
644                }
645
646                var elemSize = this.size;
647                // add padding and border width if border box
648                if ( elemSize.isBorderBox ) {
649                    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +
650                    elemSize.borderLeftWidth + elemSize.borderRightWidth :
651                    elemSize.paddingBottom + elemSize.paddingTop +
652                    elemSize.borderTopWidth + elemSize.borderBottomWidth;
653                }
654
655                measure = Math.max( measure, 0 );
656                this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';
657
658                /* Hack to refresh the lazy load */
659                var container = $(this.element);
660                setTimeout(function(){ container.addClass('lazy-load-ready'); }, 10); // delay 10 ms
661                /* End hack */
662
663                /* Remove this class since the grid has been resized due to the filtering system */
664                container.removeClass('filtering-isotope');
665                /* End Remove this class */
666            }
667        });
668
669        /* ****** Extending Isotope so when you insert items they got the right settings (like columnWidth, staticDimensions, convertDivsIntoImages, etc.) ****** */
670        $.extend( IsotopeMB.prototype, {
671            insert : function( elems, callback ) {
672                
673                var container   = $(this.element);
674
675                if(!container.hasClass('first_time')){
676                    container.addClass('first_time');
677                    this._isLayoutInited = false; // if a filter othan than all is selected, this will remove an "effect" of hidding boxes that doesn't belong to the current filter, only the first time it loads
678                }
679
680                /* Make sure the new boxes got all the sorting targets, this must be before the items are passed to isotope */
681                container.find(itemSelector).each(function(){
682                    var mb = $(this);
683                    for (var key in container.data('settings').getSortData) {
684                        var obj = container.data('settings').getSortData[key];
685                        if(typeof obj === 'string' && mb.find(obj)[0] == undefined){
686                            mb.append($('<div class="'+obj.substring(1)+'" style="display:none !important;" data-comment="This is added in JS because it needs it for sorting">ZZ</div>'));
687                        }
688                    }
689                });
690                
691                var items = this.addItems( elems );
692                if ( !items.length ) {
693                    /* Callback for inserting items, I added this 3 lines */
694                    if (typeof callback === 'function'){
695                        callback();
696                    }
697                    return;
698                }   
699
700                // append item elements
701                var i, item, firstHiddenBox = container.find('.'+itemHiddenClass)[0];
702                var len = items.length;
703                for ( i=0; i < len; i++ ) {
704                    item = items[i];
705                    if(firstHiddenBox != undefined){
706                        this.element.insertBefore( item.element, firstHiddenBox );
707                    }else{
708                        this.element.appendChild( item.element );
709                    }
710                }
711
712                var isotopeDefaultLogic = function(){
713
714                    // filter new stuff
715                    var filteredInsertItems = this._filter( items ).matches;
716                    // hide all newitems
717                    this._noTransition( function() {
718                      this.hide( filteredInsertItems );
719                    });
720                    // set flag
721                    for ( i=0; i < len; i++ ) {
722                      items[i].isLayoutInstant = true;
723                    }
724                    this.arrange();
725                    // reset flag
726                    for ( i=0; i < len; i++ ) {
727                      delete items[i].isLayoutInstant;
728                    }
729                    this.reveal( filteredInsertItems );
730
731                }
732
733                /* ======== Hack when inserting new boxes so they are properly converted ======== */
734                var checkForBrokenImages = function(image){
735                    var $image          = $(image.img);
736                    var thumbnailDiv    = $image.parents('div[data-thumbnail], div[data-popup]');
737
738                    if( image.isLoaded == false ){
739                        $image.hide();
740                        thumbnailDiv.addClass('broken-image-here');
741                    }
742                }
743
744                var instance    = this;
745
746                
747                addPopupTrigger(container);                /* Add popup trigger */
748                addWrapperForMargins(container);            /* Set the vertical and horizontal space between boxes */
749                getAndSetColumnWidth(container);            /* Set the column width */
750                setStaticDimensionsOfThumbnails(container);
750 /* Set the static ratio to the thumbnailDiv */
751                convertDivsIntoImages(container, false);    /* Only the ones that have NO width and height */
752
753                container.find('img:not([data-dont-wait-for-me])').imagesLoadedMB()
754                    .always(function(){
755                        if( container.data('settings').waitForAllThumbsNoMatterWhat == false ){
756                            convertDivsIntoImages(container, true);                 /* the ones left that have width and height */                  
757                        }else{
758                            setTimeout(function(){
759                                noEmptySpaceOnThumbnails(container);
760                            }, 0);
761                        }
762
763                        container.find(itemSelector).addClass('media-box-loaded');  /* Add the class to show the box */
764                        $(container.data('settings').search).trigger('keyup');      /* Show or hide according to the searching criteria */
765                        isotopeDefaultLogic.call(instance);                         /* Now you can call the default logic of the insert method from Isotope */
766                        setDimensionsToImageContainer(container);                   /* Set the same dimensions of the thumbnail to the container (for caption purposes) */
767                        setupOverlayForHoverEffect(container);                      /* Get ready for the overlay effect */
768
769                        /* Callback for inserting items */
770                        if (typeof callback === 'function'){
771                            callback();
772
773                            setTimeout(function(){
774                                container.data('settings').onLayoutFinish();
775                            }, 501);
776                        }
777
778                        /* In case the progress event don't get to check for broken images (this happens sometimes when you refresh the page) */
779                        for(index in instance.images){
780                            var image = instance.images[index];
781                            checkForBrokenImages(image);
782                        }
783                    })
784                    .progress(function( instance, image ) {
785                        /* For broken images */
786                        checkForBrokenImages(image);        
787                    });
788                
789                /* ======== End Hack ======== */
790            }                  
791        });
792
793    /* ====================================================================== *
794            [4] FILTERING ISOTOPE
795     * ====================================================================== */
796
797        function updateFilterClasses(){
798            var boxes         = $container.find(itemSelector+', .'+itemHiddenClass);   
799            
800            var filter = getCurrentFilter();
801            boxes.filter( filter ).removeClass('hidden-media-boxes-by-filter').addClass('visible-media-boxes-by-filter');
802            boxes.not( filter ).addClass('hidden-media-boxes-by-filter').removeClass('visible-media-boxes-by-filter');
803        }
804
805        function filterTheBoxes(filterValue, filterGroup){
806
807            /* Add a class until it resizes the grid */
808            $container.addClass('filtering-isotope');
809
810            // Combined the filters and filter isotope
811            goAndFilterIsotope(filterValue, filterGroup);
812
813            // update some CSS classes 
814            updateFilterClasses();
815
816            // Fix some details, like the loading button, the minBoxesPerFilter
817            seeItFiltered();
818        }
819
820        function seeItFiltered(){
821            // fix load more button
822            if( getLoadingBoxesInCurrentFilter().length > 0 ){
823                loading();
824            }else{
825                fixLoadMoreButton();
826            }
827
828            // load more boxes if neccessary 
829            checkMinBoxesPerFilter();
830        }
831
832        function goAndFilterIsotope(filterValue, filterGroup){
833            // set filter for group
834            filters[ filterGroup ] = filterValue;
835            
836            // set filters for Isotope
837            $container.isotopeMB({ filter: combineFilters(filters) });
838        }
839
840        function combineFilters( filters ) {
841
842            var output = [];
843
844            for ( var prop in filters ) {
845                var selector        = filters[prop];
846                var selector_clean  = selector.split(" ").join(""); // Remove empty spaces, so if we have this: .red, .blue it should be: .red,.blue
847                var selector_split  = selector_clean.split(",")     
848
849                /* ###### AND ###### */
850                if(settings.multipleFilterLogic == 'AND'){
851                    
852                    if(selector_clean != '*'){
853                        if(output.length == 0){
854                            output = selector_split;                        
855                        }else{
856                            output = allPossibleCases([ output, selector_split ]);                        
857                        }
858                    }
859
860                }
861
862                /* ###### OR ###### */
863                else if(settings.multipleFilterLogic == 'OR'){
864                    if(selector_clean != '*' && selector_clean != '.search-match'){
865                        if('search' in filters){ // if the search f
865ilter is enable, then combine it with the current selector
866                            var mixed = allPossibleCases([ ['.search-match'], selector_split ]);
867                            output.push( mixed.join(',') );
868                        }else{
869                            output.push( selector_split.join(',') );             
870                        }
871                    }
872                }
873
874            }
875
876            var combined = output.length > 0 ? output.join(',') : '*'; // if output is empty, is probably because all filters were '*'
877
878            /* [start] when using OR if all filters where set to ALL and you type something in the search field, it was NOT filtering anything */
879            if(combined == '*' && settings.multipleFilterLogic == 'OR'){ // if the logic is OR and all filters were '*'
880                if('search' in filters){ // if the search filter is enable, then only filter by the "search-filter"
881                    combined = '.search-match';
882                }
883            }
884            /* [end] when using OR if all filters where set to ALL and you type something in the search field, it was NOT filtering anything */
885
886            return combined;
887        }
888
889        function allPossibleCases(arr) {
890            if (arr.length == 1) {
891                return arr[0];
892            } else {
893                var result = [];
894                var allCasesOfRest = allPossibleCases(arr.slice(1));  // recur with the rest of array
895                for (var i = 0; i < allCasesOfRest.length; i++) {
896                    for (var j = 0; j < arr[0].length; j++) {
897                        result.push(arr[0][j] + allCasesOfRest[i]);
898                    }
899                }
900                return result;
901            }
902        }
903
904    /* ====================================================================== *
905            [5] LOAD MORE BOXES
906     * ====================================================================== */
907
908        function checkMinBoxesPerFilter(){
909
910            var filter  = getCurrentFilter();
911            var in_all  = false;
912            if( filter == '*' || (filter == '.search-match' && $(settings.search).val() == '') ){
913                in_all = true;
914            }
915            
916            if(in_all == false){//only execute the minBoxesPerFilter when is not showing all the boxes
917
918                var boxesInCurrentCategory  = getBoxesInCurrentFilter().length;
919
920                /* Also check if there's boxes waiting to get load from that category, because maybe there isn't and there's no case to try to load them */
921                if( boxesInCurrentCategory < settings.minBoxesPerFilter && hiddenBoxesWaitingToLoad().length > 0 ){
922                    /* Load the boxes that are missing */
923                    loadMore( settings.minBoxesPerFilter - boxesInCurrentCategory );
924
925                    return true;
926                }
927
928            }
929
930            return false;
931        }
932
933        function getBoxesInCurrentFilter(){
934            var boxes = $container.find(itemSelector);   
935            var filter = getCurrentFilter();
936            if( filter != '*' ){
937                boxes = boxes.filter( filter );
938            }
939
940            return boxes;
941        }
942
943        function getLoadingBoxesInCurrentFilter(){
944            var boxes = getBoxesInCurrentFilter().not('.media-box-loaded');   
945
946            return boxes;
947        }
948
949        function getCurrentFilter(){
950            var filter = $container.data('isotopeMB').options.filter;
951            if( filter == '' || filter == undefined ){
952                filter = '*';
953            }
954
955            return filter;
956        }
957
958        function hiddenBoxesWaitingToLoad(ignoreFilter){ /* Number of hidden boxes waiting to get load, depending on the filter */
959            var boxes = $container.find('.'+itemHiddenClass);   
960
961            var filter = getCurrentFilter();
962            if( filter != '*' && ignoreFilter == undefined){
963                boxes = boxes.filter( filter );
964            }
965
966            return boxes;
967        }
968
969        function loading(){
970            loadMoreButton.html(settings.LoadingWord);
971            loadMoreButton.removeClass('media-boxes-load-more');
972            loadMoreButton.addClass('media-boxes-loading');
973        }
974
975        function startLoading(){
976            loadingsCounter++;
977            loading();
978        }
979
980        function finishLoading(){
981            loadingsCounter--;
982            if(loadingsCounter == 0){
983                fixLoadMoreButton();
984            }
985        }
986
987        function fixLoadMoreButton(){
988            loadMoreButton.removeClass('media-boxes-load-more');
989            loadMoreButton.removeClass('media-boxes-loading');
990            loadMoreButton.removeClass('media-boxes-no-more-entries');
991
992            if( hiddenBoxesWaitingToLoad().length > 0 ){
993                loadMoreButton.html(settings.loadMoreWord);
994                loadMoreButton.addClass('media-boxes-load-more'); 
995            }else{
996                loadMoreButton.html(settings.noMoreEntriesWord); 
997                loadMoreButton.addClass('media-boxes-no-more-entries');
998            }
999        }
1000
1001        function loadMore( boxesToLoad, ignoreFilter){
1002            if( loadMoreButton.hasClass('media-boxes-no-more-entries') == true ){ /* Only if it is the "load more" button or the "loading...", no the "no more entries" button */
1003                return;
1004            }
1005
1006            /* Loading... */
1007            startLoading();
1008
1009            /* The new boxes */
1010            var newBoxes = [];
1011
1012            /* Boxes that will be loaded as part of isotope */
1013            hiddenBoxesWaitingToLoad(ignoreFilter).each(function(index){
1014                var $this = $(this);
1015                if( (index+1) <=  boxesToLoad){ 
1016                    $this.removeClass(itemHiddenClass).addClass(itemClass);
1017                    $this.hide();
1018                    newBoxes.push(this);
1019                }
1020            }); 
1021            
1022            $container.isotopeMB( 'insert', $(newBoxes), function(){
1023                /* Fix Load More Button */   
1024                finishLoading();
1025
1026                /* Force a relayout of Isotope */
1027                $container.isotopeMB('layout');
1028            });
1029        }
1030        loadMore( settings.boxesToLoadStart, true );
1031        checkMinBoxesPerFilter();
1032        
1033        /* Load more boxes when you click the button */
1034        loadMoreButton.on('click', function(){
1035            loadMore( settings.boxesToLoad );
1036        });
1037
1038        function loadMoreIfButtonIsVisible(){
1039            if(loadMoreButton.filter(':visible')[0] !== undefined && loadMoreButton.filter(':visible').visible( true )){
1040                if( $container.hasClass('lazy-load-ready') ){
1041                    if( $container.hasClass('filtering-isotope') == false){
1042                        $container.removeClass('lazy-load-ready');
1043                        loadMore( settings.boxesToLoad );
1044                    }
1045                }
1046            }
1047        }
1048
1049        if( settings.lazyLoad ){
1050            $(window).scroll(function(){
1051                loadMoreIfButtonIsVisible();
1052            });
1053        }
1054
1055    /* ====================================================================== *
1056            [6] FILTER
1057     * ====================================================================== */   
1058
1059        /* DEFAULT FILTERS SELECTED (SAVE ORIGINAL SELECTED FILTER) */
1060
1061        filtersContainers.each(function(){
1062            var $this = $(this);
1063
1064            if($this.is(':checkbox')){
1065                $this.attr('default-value', $this.is(':checked') ? $this.attr('data-filter') : '*' ); // set default value 
1066            }else{
1067                $this.attr('default-value', $this.find('*[data-filter]').filter('.selected').attr('data-filter')); // set default value 
1068            }
1069        });
1070
1071        /* INIT DEFAULT FILTERING */
1072
1073        setTimeout(function(){
1074
1075            // filtersContainers.each(function(){
1076            //     /* current items */
1077            //     var current_filterContainer = $(this);
1078            //     var filterValue             = '';
1079
1080            //     /* if its a checkbox */
1081            //     if(current_filterContainer.is(':checkbox')){
1082            //         filterValue         = current_filterContainer.is(':checked') ? current_filterContainer.attr('data-filter') : '*';
1083            //     }else{
1084            //         var current_filter  = current_filterContainer.find('*[data-filter]').filter('.selected');
1085            //         filterValue         = current_filter[0] !== undefined ? current_filter.attr('data-filter') : '*';
1086            //     }
1087
1088            //     /* initialize the filtering */
1089            //     init_filtering(filterValue, current_filterContainer, 'default');
1090            // });
1091
1092        }, 1); // this to fixes the following: when a selected filter is other than all when the page loads, the thumbnail-overlay of the first item in the grid was not working correctly, because some hidden boxes were on top of it, as if they were not fully hidden
1093        
1094        /* EVENT IF THE FILTER IS A SELECT */
1095
1096        filtersContainers.on('change', function(){
1097            if($(this).is('select')){ // check if its a select element 
1098                /* current items */
1099                var current_filterContainer = $(this);
1100                
1101                /* initialize the filtering */
1102                init_filtering(current_filterContainer.val(), current_filterContainer);
1103            }
1104        });
1105
1106        /* EVENT FOR WHEN CLICKING A FILTER NAVIGATION BAR OR A DROPDOWN MENU */
1107
1108        filtersContainers.on('click', '*[data-filter]', function(e){
1109            if(!$(this).is('option') && !$(this).is(':checkbox')){ // check if its not an option from a select element or if its not a checkbox
1110                /* current items */
1111                var current_filter          = $(this);
1112                var current_filterContainer = $(this).parents(settings.filterContainer);
1113
1114                /* Remove selected class from others and add selected to current */
1115                current_filterContainer.find('*[data-filter]').removeClass('selected');
1116                current_filter.addClass('selected');
1117                
1118                /* initialize the filtering */
1119                init_filtering(current_filter.attr('data-filter'), current_filterContainer);
1120
1121                e.preventDefault();
1122            }
1123        });
1124
1125        /* EVENT FOR WHEN CLICKING A CHECKBOX */
1126
1127        $('body').on('change', settings.filterContainer, function(){
1128            if($(this).is(':checkbox')){
1129                /* current items */
1130                var current_filterContainer = $(this);
1131                
1132                /* initialize the filtering */
1133                init_filtering(current_filterContainer.is(':checked') ? current_filterContainer.attr('data-filter') : '*', current_filterContainer);
1134            }
1135        });
1136
1137        /* FILTERING */
1138
1139        function init_filtering(filterValue, current_filterContainer){
1140            show_hide_filters();
1141
1142            /* Filter isotope */
1143            var filterGroup     = current_filterContainer.data("id") != undefined ? current_filterContainer.data("id") : "filter"; // take the id of the filter container if exists, if not just a string
1144            var is_default      = current_filterContainer.attr('default-value') == filterValue;
1145
1146            /* Hash on filter change (this is not executed when the plugin first load with a default filter) */
1147            set_hash_on_filter_change(filterValue, filterGroup, is_default);
1148
1149            /* Filter the boxes */
1150            filterTheBoxes( filterValue , filterGroup);
1151        }
1152
1153        /* SHOW-HIDE FILTERS (WHEN THE VISIBILITY OF A FILTER DEPENDS O
1153N ANOTHER) */
1154
1155        function show_hide_filters(){
1156            filtersContainers.find('[data-filter]').addBack('[data-filter]').each(function(){
1157                var $this       = $(this);
1158
1159                if($this.attr('data-visible-only-if') != undefined){
1160                    var $visible    = $($this.attr('data-visible-only-if'));
1161
1162                    // If its a checkbox
1163                    if($visible.is(':checkbox')){
1164                        if($visible.is(':checked')){ // show item
1165                            $this.removeClass('visibility_hidden');
1166                            $this.parents('.media-boxes-checkboxes-label').show();
1167                        }else{ // hide item
1168                            $this.addClass('visibility_hidden');
1169                            $this.parents('.media-boxes-checkboxes-label').hide();
1170
1171                            if($this.is(':checked')){ // if when hidding, the checkbox was "checked" then go back to "all"
1172                                setTimeout(function(){
1173                                    $this.prop('checked', false).trigger('change'); // uncheck if its checked
1174                                }, 1);
1175                            }
1176                        }
1177                    }
1178
1179                    // If its a dropdown or inline 
1180                    if(!$visible.is(':checkbox') && !$visible.is('select')){
1181                        if($visible.hasClass('selected')){ // show item
1182                            $this.show().removeClass('visibility_hidden');
1183                        }else{ // hide item
1184                            $this.hide().addClass('visibility_hidden');
1185
1186                            if($this.hasClass('selected')){ // if when hidding, the item was "selected" then go back to all
1187                                $this.parents(settings.filterContainer).find('[data-filter="*"]').trigger('click');
1188                            }
1189                        }
1190                    }
1191
1192                }
1193            });
1194
1195            show_hide_filter_container();
1196        }
1197
1198        function show_hide_filter_container(){
1199            $('.media-boxes-drop-down, .media-boxes-filter, .media-boxes-checkboxes').each(function(){
1200                var $this = $(this);
1201                var items = $this.find('[data-filter]').not('.visibility_hidden');
1202
1203                if($this.find('[data-filter]')[0] == undefined) return; // only do this if there are filters
1204
1205                if(!$this.hasClass('media-boxes-checkboxes')){
1206                    items = items.not('[data-filter="*"]');
1207                }
1208
1209                if(items.length <= 0){
1210                    $this.hide();
1211                }else{
1212                    $this.show();
1213                }
1214            })
1215        }
1216
1217    /* ====================================================================== *
1218            [7] SEARCH
1219     * ====================================================================== */     
1220
1221        function search(value){
1222            if(value == undefined) return;
1223
1224            var allBoxes = $container.find('.'+itemClass+', .'+itemHiddenClass);
1225            if(value == ''){
1226                /* If there's nothing in the input text field then show all the boxes */
1227                allBoxes.addClass('search-match');
1228            }else{
1229                allBoxes.removeClass('search-match');
1230
1231                $container.find(settings.searchTarget).each(function(){
1232                    var $this = $(this);
1233                    var box   = $this.parents('.'+itemClass+', .'+itemHiddenClass);
1234                    if( $this.text().toLowerCase().indexOf(value.toLowerCase()) !== -1 ){
1235                        box.addClass('search-match');
1236                    }
1237                });
1238            }
1239
1240            var is_default      = $(settings.search).attr('default-value') == value;
1241
1242            setTimeout( function() {
1243                // Hash on filter change
1244                set_hash_on_filter_change(value, 'search', is_default);
1245
1246                // Filter the boxes
1247                filterTheBoxes('.search-match', 'search');
1248            }, 100 );
1249        }
1250
1251        $(settings.search).on('keyup', function(){
1252            search( $(this).val() );
1253        });
1254
1255        /* set default value */
1256        $(settings.search).attr('default-value', $(settings.search).attr('value') === undefined ? "" : $(settings.search).attr('value'));
1257
1258        /* default search  selected */
1259        search( $(settings.search).val() );
1260
1261        $('body').on('click', '.media-boxes-clear', function(){
1262            $(this).parents('.media-boxes-search').find('input').val('').trigger('keyup').focus();
1263        });
1264
1265    /* ====================================================================== *
1266            [8] SORTING
1267     * ====================================================================== */     
1268
1269        function getSortDirection($this){
1270            var direction = $this.data('sort-ascending');
1271            if(direction == undefined){
1272                direction = true;
1273            }
1274
1275            if($this.data('sort-toggle') && $this.data('sort-toggle') == true){
1276                $this.data('sort-ascending', !direction);
1277            }
1278
1279            /* if there's a sort order button then use the value from there */
1280            var sort_order = $this.parents('.media-boxes-sort').find('.media-boxes-sort-order').find('.selected');
1281            if(sort_order[0] !== undefined){
1282                direction = sort_order.data('sort-ascending');
1283            }
1284
1285            /* if the sort option is "original-order" then always true (ascending) */
1286            if($this.attr('data-sort-by') == 'original-order'){
1287                direction = true;
1288            }
1289
1290            return direction;
1291        }
1292
1293        /* Clicking on the different sort options */
1294
1295        $(settings.sortContainer).find('*[data-sort-by]').on('click', function(e){
1296            var $this = $(this);
1297
1298            /* Remove selected class from others */
1299            $this.parents(settings.sortContainer).find('*[data-sort-by]').removeClass('selected');
1300            
1301            /* Add class of selected */
1302            $this.addClass('selected');
1303
1304            /* Sort isotope */
1305            var sortValue = $this.attr('data-sort-by');
1306            $container.isotopeMB({ sortBy: sortValue, sortAscending: getSortDirection($this) });
1307
1308            e.preventDefault();
1309        });
1310
1311        /* Clicking on the sort order button */
1312
1313        $(settings.sortContainer).parents('.media-boxes-sort').find('.media-boxes-sort-order').on('click', function(e){
1314            var $this = $(this);
1315            
1316            /* change sort order */
1317            $this.find('.selected').removeClass('selected').siblings('span').addClass('selected');
1318
1319            /* selected sort-by option */
1320            var sort_by = $this.parents('.media-boxes-sort').find('.selected[data-sort-by]');
1321
1322            /* apply new sort order to isotope */
1323            $container.isotopeMB({ sortAscending: getSortDirection(sort_by) });
1324        });
1325
1326    /* ====================================================================== *
1327            [9] THUMBNAIL OVERLAY EFFECT
1328     * ====================================================================== */    
1329
1330        /* ****** Set the overlay depending on the overlay effect before the hover event is trigger ****** */
1331        function setupOverlayForHoverEffect(container){
1332            if( container.data('settings').thumbnailOverlay == false ) return;
1333
1334            var boxes = container.find(itemSelector+':not([data-set-overlay-for-hover-effect])').attr('data-set-overlay-for-hover-effect', 'yes');
1335
1336            /* Add extra divs for vertical alignment */
1337            boxes.find('.thumbnail-overlay').wrapInner( "<div class='aligment'><div class='aligment'></div></div>" );
1338
1339            boxes.each(function(){
1340
1341                var box         = $(this);
1342                var boxImage    = box.find(boxImageSelector);
1343                var effect      = container.data('settings').overlayEffect;
1344                if(boxImage.data('overlay-effect') != undefined){
1345                    effect = boxImage.data('overlay-effect');
1346
1347                    if(effect.indexOf('100') >= 0 && effect.indexOf('100%') == -1){
1348                        effect = effect.split('100').join('100%');
1349                    }
1350                }
1351
1352                /* Add wrapper for some effects */
1353                if( effect == 'push-up' || effect == 'push-down' || effect == 'push-up-100%' || effect == 'push-down-100%'  ){
1354                    
1355                        var thumbnailDiv        = boxImage.find('.media-box-thumbn
1355ail-container');
1356                        var thumbnailOverlay    = boxImage.find('.thumbnail-overlay').css('position', 'relative');
1357                        if( effect == 'push-up-100%' || effect == 'push-down-100%' ){/* set the height of the overlay to the same of the thumbnail */
1358                            thumbnailOverlay.outerHeight( thumbnailDiv.outerHeight(false) );
1359                        }
1360                        var heightOverlay       = thumbnailOverlay.outerHeight(false);
1361
1362                        var wrapper             = $('<div class="wrapper-for-some-effects"></div');
1363
1364                        if( effect == 'push-up' || effect == 'push-up-100%' ){
1365                            thumbnailOverlay.appendTo(boxImage);    
1366                        }else if( effect == 'push-down' || effect == 'push-down-100%'  ){
1367                            thumbnailOverlay.prependTo(boxImage);    
1368                            wrapper.css('margin-top', -heightOverlay);
1369                        }
1370                
1371                        boxImage.wrapInner( wrapper );
1372
1373                }
1374                /* Set some CSS style for this effects */
1375                else if( effect == 'reveal-top' || effect == 'reveal-top-100%' ){
1376                    
1377                    box.addClass('position-reveal-effect');
1378                    
1379                    var overlay = box.find('.thumbnail-overlay').css('top', 0);
1380                    if( effect == 'reveal-top-100%' ){
1381                        overlay.css('height', '100%');
1382                    }
1383
1384                }else if( effect == 'reveal-bottom' || effect == 'reveal-bottom-100%' ){
1385                    
1386                    box.addClass('position-reveal-effect').addClass('position-bottom-reveal-effect');
1387                    
1388                    var overlay = box.find('.thumbnail-overlay').css('bottom', 0);
1389                    if( effect == 'reveal-bottom-100%' ){
1390                        overlay.css('height', '100%');
1391                    }
1392
1393                }else if( effect.substr(0, 9) == 'direction'){ // 'direction-aware', 'direction-aware-fade', 'direction-right', 'direction-left', 'direction-top', 'direction-bottom'
1394
1395                    /* Set the height to 100% if not it would be just the default height of the overlay */
1396                    box.find('.thumbnail-overlay').css('height', '100%');
1397
1398                }else if( effect == 'fade' ){
1399                    
1400                    var thumbOverlay = box.find('.thumbnail-overlay').hide();
1401                    thumbOverlay.css({
1402                                        'height' : '100%',
1403                                        'top'    : '0',
1404                                        'left'   : '0',
1405                                    });
1406                    //thumbOverlay.find("[class^='fa-'],div[class*=' fa-']").css({ scale : 1.4 });
1407
1408                }
1409
1410                /* Init effect on overlay-thumbnail hover */
1411                container.data('settings').animation_on_thumbnail_overlay_hover.forEach(function(row){
1412                    var item    = box.find('.thumbnail-overlay').find(row.item);
1413                    
1414                    if(row.animation == 'zoom-out'){
1415                        item.css({ scale: 1.4 }); 
1416                    }else if(row.animation == 'zoom-in'){
1417                        item.css({ scale : 0.6 });
1418                    }else if(row.animation == 'from-top'){
1419                        item.transition({ y : '-30px' }, 0);
1420                    }else if(row.animation == 'from-bottom'){
1421                        item.transition({ y : '30px' }, 0);
1422                    }else if(row.animation == 'from-left'){
1423                        item.transition({ x : '-30px' }, 0);
1424                    }else if(row.animation == 'from-right'){
1425                        item.transition({ x : '30px' }, 0);
1426                    }
1427
1428                });
1429
1430            });
1431
1432        }
1433
1434        /* ****** Hide element when done ****** */
1435        function hideWhenDone(element){
1436            if( element.attr('data-stop') != undefined ){
1437                element.hide();
1438                element.removeAttr('data-stop');
1439            }
1440        }
1441
1442        /* ****** Trigger the overlay effect ****** */
1443        $container.on( 'mouseenter.hoverdir, mouseleave.hoverdir', boxImageSelector, function(event){
1444            if( settings.thumbnailOverlay == false ) return;
1445
1446            var boxImage            = $(this);
1447            var effect              = settings.overlayEffect;
1448            if(boxImage.data('overlay-effect') != undefined){
1449                effect = boxImage.data('overlay-effect');
1450
1451                if(effect.indexOf('100') >= 0 && effect.indexOf('100%') == -1){ // if its missing the % sign at the end then just add it
1452                    effect = effect.split('100').join('100%');
1453                }
1454            }
1455            
1456            var eventType           = event.type;
1457            var thumbnailDiv        = boxImage.find('.media-box-thumbn
1457ail-container');
1458            var thumbnailOverlay    = boxImage.find('.thumbnail-overlay') ;
1459            var heightOverlay       = thumbnailOverlay.outerHeight(false);
1460            
1461            /* The effects */
1462            if( effect == 'push-up' || effect == 'push-up-100%' ){
1463                var wrapper = boxImage.find('div.wrapper-for-some-effects');
1464
1465                if( eventType === 'mouseenter' ) {
1466                    wrapper.stop().show()[animation]({ 'margin-top': -heightOverlay }, settings.overlaySpeed, settings.overlayEasing); 
1467                }else{
1468                    wrapper.stop()[animation]({ 'margin-top': 0 }, settings.overlaySpeed, settings.overlayEasing); 
1469                }
1470            }
1471
1472            else if( effect == 'push-down' || effect == 'push-down-100%' ){
1473                var wrapper = boxImage.find('div.wrapper-for-some-effects');
1474
1475                if( eventType === 'mouseenter' ) {
1476                    wrapper.stop().show()[animation]({ 'margin-top': 0 }, settings.overlaySpeed, settings.overlayEasing); 
1477                }else{
1478                    wrapper.stop()[animation]({ 'margin-top': -heightOverlay }, settings.overlaySpeed, settings.overlayEasing); 
1479                }
1480            }
1481
1482            else if( effect == 'reveal-top' || effect == 'reveal-top-100%' ){
1483                if( eventType === 'mouseenter' ) {
1484                    thumbnailDiv.stop().show()[animation]({ 'margin-top': heightOverlay }, settings.overlaySpeed, settings.overlayEasing); 
1485                }else{
1486                    thumbnailDiv.stop()[animation]({ 'margin-top': 0 }, settings.overlaySpeed, settings.overlayEasing); 
1487                }   
1488            }
1489
1490            else if( effect == 'reveal-bottom' || effect == 'reveal-bottom-100%' ){
1491                if( eventType === 'mouseenter' ) {
1492                    thumbnailDiv.stop().show()[animation]({ 'margin-top': -heightOverlay }, settings.overlaySpeed, settings.overlayEasing); 
1493                }else{
1494                    thumbnailDiv.stop()[animation]({ 'margin-top': 0 }, settings.overlaySpeed, settings.overlayEasing); 
1495                }   
1496            }
1497
1498            else if( effect.substr(0, 9) == 'direction' ){ // 'direction-aware', 'direction-aware-fade', 'direction-right', 'direction-left', 'direction-top', 'direction-bottom'
1499                var direction   = _getDir( boxImage, { x : event.pageX, y : event.pageY } );
1500                
1501                if( effect == 'direction-top' ){
1502                    direction   = 0;
1503                }else if( effect == 'direction-bottom' ){
1504                    direction   = 2;
1505                }else if( effect == 'direction-right' ){
1506                    direction   = 1;
1507                }else if( effect == 'direction-left' ){
1508                    direction   = 3
1509                }
1510
1511                var cssPos      = _getPosition( direction, boxImage );
1512
1513                if( eventType == 'mouseenter' ){
1514                    thumbnailOverlay.css( { 'left' : cssPos.from, 'top' : cssPos.to } );
1515
1516                    thumbnailOverlay.stop().show().fadeTo(0, 1, function(){
1517                                                                    $(this).stop()[animation]({ 'left' : 0, 'top' : 0 }, settings.overlaySpeed, settings.overlayEasing); 
1518                                                                });
1519                }else{
1520                    if( effect == 'direction-aware-fade' ){
1521                        thumbnailOverlay.fadeOut(700);
1522                    }else{
1523                        thumbnailOverlay.stop()[animation]({ 'left' : cssPos.from, 'top' : cssPos.to }, settings.overlaySpeed, settings.overlayEasing ); 
1524                    }
1525                }
1526            }
1527
1528            else if( effect == 'fade' ){
1529
1530                if( eventType == 'mouseenter' ){
1531                    thumbnailOverlay.stop().fadeOut(0);
1532                    thumbnailOverlay.fadeIn( settings.overlaySpeed );
1533                }else{
1534                    thumbnailOverlay.stop().fadeIn(0);
1535                    thumbnailOverlay.fadeOut( settings.overlaySpeed );
1536                }
1537
1538            }
1539
1540            /* Init effect on overlay-thumbnail hover */
1541            settings.animation_on_thumbnail_overlay_hover.forEach(function(row){
1542                var item    = thumbnailOverlay.find(row.item);
1543
1544                if( eventType == 'mouseenter' ){
1545
1546                    if(row.animation == 'zoom-out'){
1547                        item.css({ scale : 1.4 });
1548                        item[animation]({ scale: 1 }, 200);
1549                    }else if(row.animation == 'zoom-in'){
1550                        item.css({ scale: 0.6 }); 
1551                        item[animation]({ scale: 1 }, 200); 
1552                    }else if(row.animation == 'from-top'){
1553                        item.transition({ y : '-30px' }, 0); 
1554                        item.transition({ y : '0px' }, 200); 
1555                    }else if(row.animation == 'from-bottom'){
1556                        item.transition({ y : '30px' }, 0); 
1557                        item.transition({ y : '0px' }, 200); 
1558                    }else if(row.animation == 'from-left'){
1559                        item.transition({ x : '-30px' }, 0); 
1560                        item.transition({ x : '0px' }, 200); 
1561                    }else if(row.animation == 'from-right'){
1562                        item.transition({ x : '30px' }, 0); 
1563                        item.transition({ x : '0px' }, 200); 
1564                    }
1565
1566                }else{
1567
1568                    if(row.animation == 'zoom-out'){
1569                        item.css({ scale: 1 }); 
1570                        item[animation]({ scale: 1.4 }, 200); 
1571                    }else if(row.animation == 'zoom-in'){
1572                        item.css({ scale : 1 });
1573                        item[animation]({ scale: 0.6 }, 200);
1574                    }else if(row.animation == 'from-top'){
1575                        item.transition({ y : '0px' }, 0); 
1576                        item.transition({ y: '-30px' }, 200); 
1577                    }else if(row.animation == 'from-bottom'){
1578                        item.transition({ y : '0px' }, 0); 
1579                        item.transition({ y: '30px' }, 200); 
1580                    }else if(row.animation == 'from-left'){
1581                        item.transition({ x : '0px' }, 0); 
1582                        item.transition({ x : '-30px' }, 200); 
1583                    }else if(row.animation == 'from-right'){
1584                        item.transition({ x : '0px' }, 0); 
1585                        item.transition({ x : '30px' }, 200); 
1586                    }
1587
1588                }
1589
1590            });
1591
1592        });   
1593
1594        /* ****** Methods for the direction-aware hover effect ****** */
1595        var _getDir = function( $el, coordinates ) {
1596            /** the width and height of the current div **/
1597            var w = $el.width(),
1598                h = $el.height(),
1599
1600                /** calculate the x and y to get an angle to the center of the div from that x and y. **/
1601                /** gets the x value relative to the center of the DIV and "normalize" it **/
1602                x = ( coordinates.x - $el.offset().left - ( w/2 )) * ( w > h ? ( h/w ) : 1 ),
1603                y = ( coordinates.y - $el.offset().top  - ( h/2 )) * ( h > w ? ( w/h ) : 1 ),
1604            
1605                /** the angle and the direction from where the mouse 
1605came in/went out clockwise (TRBL=0123);**/
1606                /** first calculate the angle of the point, 
1607                add 180 deg to get rid of the negative values
1608                divide by 90 to get the quadrant
1609                add 3 and do a modulo by 4  to shift the quadrants to a proper clockwise TRBL (top/right/bottom/left) **/
1610                direction = Math.round( ( ( ( Math.atan2(y, x) * (180 / Math.PI) ) + 180 ) / 90 ) + 3 )  % 4;
1611            
1612            return direction;
1613            
1614        };
1615
1616        var _getPosition = function( direction, $el ) {
1617            var fromLeft, fromTop;
1618            switch( direction ) {
1619                case 0:
1620                    // from top
1621                    if ( !settings.reverse ) { 
1622                            fromLeft = 0, fromTop = - $el.height() 
1623                    }else {  
1624                            fromLeft = 0, fromTop = - $el.height()  
1625                    }
1626                    break;
1627                case 1:
1628                    // from right
1629                    if ( !settings.reverse ) { 
1630                            fromLeft = $el.width()  , fromTop = 0
1631                    }else {  
1632                            fromLeft = - $el.width() , fromTop = 0 
1633                    }
1634                    break;
1635                case 2:
1636                    // from bottom
1637                    if ( !settings.reverse ) { 
1638                            fromLeft = 0 , fromTop = $el.height() 
1639                    }
1640                    else {  
1641                            fromLeft = 0, fromTop = - $el.height()  
1642                    }
1643                    break;
1644                case 3:
1645                    // from left
1646                    if ( !settings.reverse ) {
1647                            fromLeft = -$el.width()  , fromTop = 0
1648                    }
1649                    else {  
1650                            fromLeft =  $el.width(), fromTop = 0 
1651                    }
1652                    break;
1653            };
1654            return { from : fromLeft, to: fromTop };
1655        }; 
1656
1657    /* ====================================================================== *
1658            [10] IFRAME ON GRID
1659     * ====================================================================== */
1660
1661        /* Instead of openning the youtube/vimeo video in the popup open it in the grid  */
1662        $container.on('click', '.iframe-on-grid', function(){
1663            var $this   = $(this);
1664            var mbImage = $this.parents(itemSelector).find(boxImageSelector);
1665            
1666            show_video_on_grid(mbImage, $this.attr('data-src'));
1667        });
1668
1669        function show_video_on_grid(mbImage, src){
1670            var iframeContainer  = "";
1671
1672            if(mbImage.find('.iframe-on-grid-container')[0] != undefined){
1673                iframeContainer = mbImage.find('.iframe-on-grid-container');
1674            }else{
1675
1676                if(src.indexOf('vimeo.com/') > -1){
1677                    src = src.split('vimeo.com/').pop();
1678                    src = 'https://player.vimeo.com/video/'+src+'?autoplay=1';
1679                }else if(src.indexOf('youtube.com/') > -1){
1680                    src = src.split('?v=').pop();
1681                    src = 'https://www.youtube.com/embed/'+src+'?autoplay=1';
1682                }
1683
1684                iframeContainer = $('<div class="iframe-on-grid-container"><iframe src="'+src+'" allowfullscreen></iframe></div>').appendTo(mbImage);
1685
1686                iframeContainer.find('iframe').load(function(){
1687                    $(this).fadeIn(100);
1688                });
1689            }
1690
1691            iframeContainer.fadeIn(300);
1692        }
1693
1694    /* ====================================================================== *
1695            [11] INIT POPUP
1696     * ====================================================================== */
1697
1698        function addPopupTrigger(container){
1699
1700            container.find(itemSelector+', .'+itemHiddenClass).find('.mb-open-popup:not(.popup-trigger-added)').each(function(){
1701                
1702                var $this            = $(this).addClass('popup-trigger-added');
1703                var attr_src         = $this.attr('data-src');
1704                var attr_type        = $this.attr('data-type'); // image, iframe, inline, and ajax
1705                var attr_title       = $this.attr('data-title') != undefined ? $this.attr('data-title') : "";
1706                var attr_alt         = $this.attr('data-alt') != undefined ? $this.attr('data-alt') : "";
1707
1708                // Add data-thumb if is not specified (fancybox needs this for creating the thumbnails/small-gallery in the popup, sometimes it worked, because it was autodetecting the thumbnails if the thumbnails were inside the mb-open-popup)
1709
1710                if($this.attr('data-thumb') === undefined){
1711                    var box             = $(this).parents(itemSelector);
1712                    var thumbnailDiv    = box.find('div[data-thumbnail]').eq(0); // only one thumb allowed
1713                    
1714                    $this.attr('data-thumb', thumbnailDiv.attr('data-thumbnail'));
1715                }
1716
1717                // Instead of openning the iframe in the popup open it in the grid
1718
1719                if( $this.hasClass('iframe-on-grid') && attr_type == 'iframe' ){
1720                    return;
1721                }
1722
1723                // If the data-src is not specified, then ignore
1724
1725                if(attr_src == undefined){
1726                    return;
1727                }
1728
1729                if(attr_src == ''){
1730                    $this.removeClass('mb-open-popup');
1731                    $this.removeAttr('data-src');
1732                    $this.removeAttr('data-type');
1733                    $this.removeAttr('data-title');
1734                    $this.removeAttr('data-alt');
1735                }
1736
1737                // Check if type is valid
1738
1739                if(attr_type == 'iframe' || attr_type == 'inline' || attr_type == 'ajax'){
1740                    // all good                    
1741                }else{
1742                    $this.removeAttr('data-type'); // remove invalid type
1743                }
1744
1745                // Fancybox Attribures
1746
1747                if(settings.popup == 'fancybox'){ 
1748
1749                    $this.attr('data-caption', attr_title);
1750                    if(attr_src.indexOf('youtube') >= 0 || attr_src.indexOf('vimeo') >= 0){
1751                        $this.removeAttr('data-type');
1752                    }
1753
1754                }
1755
1756                // Magnific Popup Attributes
1757
1758                if(settings.popup == 'magnificpopup'){ 
1759
1760                    var type = 'mfp-image';
1761                    if(attr_type == 'iframe'){
1762                        type = 'mfp-iframe';
1763                    }else if(attr_type == 'inline'){
1764                        type = 'mfp-inline';
1765                    }else if(attr_type == 'ajax'){
1766                        type = 'mfp-ajax';
1767                    }
1768
1769                    $this.attr('data-mfp-src', attr_src);
1770                    $this.addClass(type);
1771                    $this.attr('mfp-title', attr_title);
1772                    $this.attr('mfp-alt', attr_alt);
1773
1774                }
1775                
1776            });
1777
1778        }
1779
1780        if(settings.popup == 'fancybox' || settings.popup == 'magnificpopup'){
1781            var selector = '.mb-open-popup[data-src]';
1782            if(settings.considerFilteringInPopup){
1783                selector = itemSelector+':not(.hidden-media-boxes-by-filter) .mb-open-popup[data-src], .'+itemHiddenClass+':not(.hidden-media-boxes-by-filter) .mb-open-popup[data-src]';
1784            }
1785            if(settings.showOnlyVisibleBoxesInPopup){
1786                selector = itemSelector+':visible .mb-open-popup[data-src]';
1787            }
1788
1789            if(settings.popup == 'fancybox'){
1790                /*  
1791                    Example on how to have a gallery popup per media-box
1792                    Add these in a media-box for extra popup items:
1793                    <div class="mb-open-popup" data-src="gallery/img-37.jpg"></div>
1794                    <div class="mb-open-popup" data-src="gallery/img-38.jpg"></div>
1795                */
1796                /*
1797                $container.find('.media-box, .media-box-hidden').each(function(){
1798                    selector = ".mb-open-popup[data-src]";
1799                    startFancybox($(this), selector);    
1800                }); 
1801                */
1802                startFancybox($container, selector);
1803            }
1804            if(settings.popup == 'magnificpopup'){
1805                startMagnificpopup($container, selector);
1806            }
1807            
1808        }
1809
1810    /* ====================================================================== *
1811            [12] FANCYBOX
1812     * ====================================================================== */      
1813
1814        function startFancybox(container, selector){
1815
1816            container.on('click', '.mb-open-popup', function(){
1817                var visibleLinks = container.find(selector);
1818
1819                $.fancyboxMB.open( 
1820                    visibleLinks, 
1821                    {
1822                        loop                : settings.fancybox.loop,
1823                        margin              : settings.fancybox.margin,
1824                        keyboard            : settings.fancybox.keyboard,
1825                        arrows              : settings.fancybox.arrows,
1826                        infobar             : settings.fancybox.infobar,
1827                        toolbar             : settings.fancybox.toolbar,
1828                        buttons             : settings.fancybox.buttons,
1829                        share               : settings.fancybox.share,
1830                        idleTime            : settings.fancybox.idleTime,
1831                        protect             : settings.fancybox.protect,
1832                        animationEffect     : settings.fancybox.animationEffect,
1833                        animationDuration   : settings.fancybox.animationDuration,
1834                        transitionEffect    : settings.fancybox.transitionEffect,
1835                        transitionDuration  : settings.fancybox.transitionDuration,
1836
1837                        // ====== MODULES =====>
1838
1839                        slideShow           : settings.fancybox.slideShow,
1840                        fullScreen          : settings.fancybox.fullScreen,
1841                        thumbs              : settings.fancybox.thumbs,
1842                        touch               : settings.fancybox.touch,
1843
1844                        // ====== EVENTS =====>
1845
1846                        afterShow : function(instance, slide){
1847
1848                            // Add alt attribute to lightbox image
1849
1850                            if(slide.opts.$orig.attr('data-alt') != undefined){
1851                                slide.$image.attr('alt', slide.opts.$orig.attr('data-alt'));
1852                            }
1853
1854                            // Add hash to URL
1855
1856                            set_hash_on_popup_change(slide.opts.$orig.attr('data-src'));
1857
1858                        },
1859
1860                        beforeClose : function(instance, slide){
1861
1862                            // Remove hash from URL
1863
1864                            if(settings.deepLinkingOnPopup){
1865                                remove_from_hash('('+slide.opts.$orig.parents('.media-boxes-container').attr('id')+'|popup)=');
1866                            }
1867
1868                        },
1869
1870                        onInit : function(){
1871
1872                            settings.onPopupStart();
1873
1874                            $(settings.fancybox.compensateScrollbar).each(function(){
1875                                $(this).css('padding-right', '+='+$('body').css('margin-right'));
1876                            });
1877
1878                        },
1879
1880                        afterClose : function(){
1881
1882                            settings.onPopupClose();
1883                            
1884                            $(settings.fancybox.compensateScrollbar).each(function(){
1885                                $(this).css('padding-right', '-='+$('body').css('margin-right'));
1886                            });
1887
1888                        },
1889
1890                    }, 
1891                    visibleLinks.index( this ) 
1892                );
1893
1894                return false;
1895            });
1896
1897            $.fancyboxMB.defaults.hash = false;   
1898
1899        }    
1900
1901    /* ====================================================================== *
1902            [13] MAGNIFIC POPUP
1903     * ====================================================================== */            
1904
1905        function startMagnificpopup(container, selector){
1906            
1907            container.magnificPopup({
1908                delegate            : selector, // child items selector, by clicking on it popup will open
1909                type                : 'image',
1910                removalDelay        : 200,
1911                closeOnContentClick : false,
1912                alignTop            : settings.magnificpopup.alignTop,
1913                preload             : settings.magnificpopup.preload,
1914                tLoading            : 'loading...',
1915                mainClass           : 'my-mfp-slide-bottom',
1916                gallery             : { enabled : settings.magnificpopup.gallery },
1917                closeMarkup         : '<button title="%title%" class="mfp-close"></button>',
1918                titleSrc            : 'title',
1919                autoFocusLast       : false, // in the new version of Magnific Popup on IE it jumps to the element that triggered the popup, which looks odd, so we better disable it 
1920                iframe              : {
1921                    patterns : {
1922                        youtube: {
1923                          index: 'youtube.com/', // String that detects type of video (in this case YouTube). Simply via url.indexOf(index).
1924                          id: 'v=', // String that splits URL in a two parts, second part should be %id%
1925                          src: 'https://www.youtube.com/embed/%id%?autoplay=1' // URL that will be set as a source for iframe. 
1926                        },
1927                        vimeo: {
1928                          index: 'vimeo.com/',
1929                          id: '/',
1930                          src: 'https://player.vimeo.com/video/%id%?autoplay=1'
1931                        },
1932                    },
1933                    markup : '<div class="mfp-iframe-scaler">'+
1934                                    '<div class="mfp-close"></div>'+
1935                                    '<iframe class="mfp-iframe" frameborder="0" allowfullscreen></iframe>'+
1936                                    '<div class="mfp-bottom-bar" style="margin-top:4px;"><div class="mfp-title"></div><div class="mfp-counter"></div></div>'+
1937                             '</div>'                      
1938                },
1939                callbacks           : {
1940                    change : function() {
1941                        var item    = $(this.currItem.el);
1942
1943                        setTimeout(function(){ 
1944                            $('.mfp-title').html(item.attr('mfp-title'));    
1945                            $('.mfp-img').attr('alt', item.attr('mfp-alt'));    
1946
1947                            addSocialButtons(item)
1948                        }, 5);
1949
1950                        set_hash_on_popup_change(item.attr('data-src'));
1951                    },
1952                    close: function () {
1953                        if(settings.deepLinkingOnPopup){
1954                            var item    = $(this.currItem.el);
1955                            remove_from_hash('('+item.parents('.media-boxes-container').attr('id')+'|popup)=');
1956                        }
1957                    },
1958                    // FIX SO THE BACKGROUND DOESN'T MOVE 
1959                    beforeOpen: function() {
1960                        this.container.data('scrollTop', parseInt($(window).scrollTop()));
1961                    },
1962                    open: function(){
1963                        $('html, body').scrollTop( this.container.data('scrollTop') );
1964                    },
1965                },
1966            });
1967
1968        }
1969
1970    /* ====================================================================== *
1971            [14] DEEP LINKING
1972     * ====================================================================== */
1973
1974        /* ### SET HAS WHEN FILTER, SEARCH OR POPUP CHANGE ### */
1975
1976        function set_hash_on_filter_change(filterValue, filterGroup, is_default){
1977            if( (filterGroup=='search' && settings.deepLinkingOnSearch) || (filterGroup!='search' && settings.deepLinkingOnFilter) ){
1978                if(is_default === true){
1979                    remove_from_hash('('+$container.attr('id')+'|'+filterGroup+')=');
1980                }else{
1981                    set_key_and_value_in_hash('('+$container.attr('id')+'|'+filterGroup+')=', filterValue);
1982                }
1983            }
1984        }
1985
1986        function set_hash_on_popup_change(value){
1987            if(settings.deepLinkingOnPopup){
1988                set_key_and_value_in_hash('('+$container.attr('id')+'|popup)=', value); /* with the "src" of the image and the "id" of the container */
1989            }
1990        }
1991
1992        /* ### INIT SEARCH, FILTER AND POPUP ### */
1993
1994        function trigger_search(){
1995            if(settings.deepLinkingOnSearch){
1996                var key             = '('+$container.attr('id')+'|search)=';
1997                var hash_value      = get_value_from_hash(key);
1998
1999                if(hash_value != ''){
2000                    $(settings.search).val(hash_value).trigger('keyup');
2001                }
2002            }
2003        }
2004
2005        trigger_search();
2006
2007        function trigger_filter(){
2008            if(settings.deepLinkingOnFilter){
2009                $(settings.filterContainer).each(function(){
2010                    var current_filterContainer = $(this);
2011                    var filterGroup             = current_filterContainer.data("id") != undefined ? current_filterContainer.data("id") : "filter"; // take the id of the filter container if exists, if not just a string
2012                    var key                     = '('+$container.attr('id')+'|'+filterGroup+')=';
2013                    var hash_value              = get_value_from_hash(key);
2014                    
2015                    if(hash_value != ''){
2016                        if(current_filterContainer.is("select")){ // check if its a select element 
2017                            var val = current_filterContainer.find('*[data-filter="'+hash_value+'"]').val();
2018                            current_filterContainer.val(val).trigger('change');
2019                        }else if(current_filterContainer.is(":checkbox")){ // checkbox
2020                            if(hash_value == '*'){
2021                                current_filterContainer.prop('checked', false).trigger('change');
2022                            }else{
2023                                current_filterContainer.prop('checked', true).trigger('change');
2024                            }
2025                            //current_filterContainer.attr('data-filter', hash_value).trigger('click');
2026                        }else{ // dropdown menu or inline menu
2027                            current_filterContainer.find('*[data-filter="'+hash_value+'"]').trigger('click');
2028                        }
2029                    }
2030                });
2031            }
2032        }
2033
2034        trigger_filter();
2035
2036        function trigger_popup(){
2037            if(settings.deepLinkingOnPopup){
2038                var key             = '('+$container.attr('id')+'|popup)=';
2039                var hash_value      = get_value_from_hash(key);
2040
2041                if(hash_value != ''){
2042                    setTimeout(function(){
2043                        $container.find('.mb-open-popup[data-src="'+ hash_value +'"]').trigger('click');    
2044                    }, 50);
2045                }
2046            }
2047        }
2048
2049        trigger_popup();
2050
2051        /* ### HELPFUL METHODS ### */
2052
2053        function set_hash(new_hash){
2054            if(new_hash === '' || new_hash === '#' || new_hash === '!'){
2055                /* if the hash will be empty then use this following peace of code, otherwise it will jump back to the top of the page if you set an empty result for the hash */
2056                if(history.pushState) { 
2057                    history.pushState(null, null, ' ');
2058                }else{ 
2059                    location.hash = '#!'; 
2060                }
2061            }else{
2062                location.hash = '#' + new_hash;
2063
2064                /* This may be helpful later on (I found in a site it jumps to the beginning of the page the first time you change the hash, but in the examples is working like a charm)
2065                if(history.pushState) { 
2066                    history.pushState(null, null, '#'+ new_hash); 
2067                }else{ 
2068                    location.hash = '#!'+ new_hash; 
2069                }
2070                */
2071            }
2072        }
2073
2074        function replace_in_hash(old_value, new_value){
2075            var hash        = get_hash();
2076
2077            if(hash.indexOf(old_value) > -1 && old_value != ""){ // if the old value exists, then just replace it
2078                set_hash( hash.split(old_value).join(new_value) );
2079            }else{ // if the old value doesn't exists then just add the new one
2080                set_hash( hash+new_value );
2081            }
2082        }
2083
2084        function get_hash(){
2085            if(location.href.indexOf("#") != -1){
2086                //return decodeURI( location.href.split("#")[1] ); // this wouldn't work if there are more # in the hash
2087                return decodeURI( location.href.substring(location.href.indexOf('#')+1) );
2088            }else{
2089                return '';
2090            }
2091        }
2092
2093        function get_value_and_key_from_hash(start){
2094            var hash            = get_hash();
2095            var output          = '';
2096            var index_start     = hash.indexOf(start);
2097            
2098            if(index_start > -1 && hash.indexOf(';', index_start) > -1){
2099                output = hash.substring(index_start, hash.indexOf(';', index_start)+1);
2100            }
2101
2102            return output;
2103        }
2104
2105        function get_value_from_hash(start){
2106            var hash            = get_hash();
2107            var output          = '';
2108            var index_start     = hash.indexOf(start);
2109            
2110            if(index_start > -1 && hash.indexOf(';', index_start) > -1){
2111                output = hash.substring(index_start+(start.length), hash.indexOf(';', index_start))
2112            }
2113
2114            return output;
2115        }
2116
2117        function remove_from_hash(start){
2118            var new_hash    = get_hash().split( get_value_and_key_from_hash(start) ).join('');
2119            set_hash(new_hash);
2120        }
2121
2122        function set_key_and_value_in_hash(start, value){
2123            if(get_value_from_hash(start) == value){
2124                // do nothing, since there's no change in the hash
2125            }else{
2126                var old_value   = get_value_and_key_from_hash(start);
2127                var new_value   = start + value + ';'; // i.e. // (grid|popup)=some_image.png;
2128                replace_in_hash(old_value, new_value);
2129            }
2130        }
2131
2132    /* ====================================================================== *
2133            [15] SOCIAL IN MAGNIFIC POPUP
2134     * ====================================================================== */
2135
2136        function addSocialButtons(item){
2137            var FullURL             = location.href; // the url of your page
2138            var URLWithoutHash      = location.href.replace(location.hash,""); // the url of your page without the hashtag
2139            var imageURL            = item.attr('data-src'); // the image URL
2140
2141            // which URL do you want to share of the 3 options above?
2142            // var sharingURL = URLWithoutHash+"/"+imageURL;
2143            var sharingURL = FullURL;
2144
2145            var social = "<div class='media-boxes-social-container'>";
2146            if(settings.facebook != undefined){//FB
2147              social+="<div class='media-boxes-facebook fa fa-facebook-square' data-url='"+sharingURL+"'></div>";
2148            }
2149            if(settings.twitter != undefined){//Twitter
2150              social+="<div class='media-boxes-twitter fa fa-twitter-square' data-url='"+sharingURL+"'></div>";
2151            }
2152            if(settings.googleplus != undefined){//Google+
2153              social+="<div class='media-boxes-googleplus fa fa-google-plus-square' data-url='"+sharingURL+"'></div>";
2154            }
2155            if(settings.pinterest != undefined){//Pintrest
2156              social+="<div class='media-boxes-pinterest fa fa-pinterest-square' data-url='"+sharingURL+"'></div>";
2157            }
2158            social+="</div>";
2159
2160            var oldHTML = $('.mfp-title').html();
2161            $('.mfp-title').html(oldHTML+social);
2162        }
2163
2164        // OPEN WINDOWS FOR SHARING :D
2165        var openWindow = function(url){
2166            var w = window.open(url, "ftgw", "location=1,status=1,scrollbars=1,width=600,height=400");
2167            w.moveTo((screen.width / 2) - (300), (screen.height / 2) - (200));
2168        }
2169
2170        //FACEBOOK SHARE
2171        $('body').on('click', 'div.media-boxes-facebook', function(){
2172            var $this = $(this);
2173            var url = encodeURIComponent($this.data('url'));
2174            url = 'https://www.facebook.com/sharer/sharer.php?u=' + url;
2175            openWindow(url);
2176        });
2177        //TWITTER SHARE
2178        $('body').on('click', 'div.media-boxes-twitter', function(){
2179            var $this = $(this);
2180            var url = encodeURIComponent($this.data('url'));
2181            url = "https://twitter.com/intent/tweet?url=&text=" + url;
2182            openWindow(url);
2183        });
2184        //GOOGLE PLUS
2185        $('body').on('click', 'div.media-boxes-googleplus', function(){
2186            var $this = $(this);
2187            var url = encodeURIComponent($this.data('url'));
2188            url = 'https://plus.google.com/share?url=' + url
2189            openWindow(url);
2190        });
2191        //PINTREST
2192        $('body').on('click', 'div.media-boxes-pinterest', function(){
2193            var $this = $(this);
2194            var url = encodeURIComponent($this.data('url'));
2195            url = 'http://pinterest.com/pin/create/button/?url=' + url + '&media=' + url;
2196            openWindow(url);
2197        });
2198
2199    /* ====================================================================== *
2200            [D] DESTROY
2201     * ====================================================================== */
2202
2203        this.destroy = function () { // Destroy grid and put it back as it were before being initialized
2204
2205            this.container_clone.insertBefore(this.container).removeData('mediaBoxes');
2206
2207            this.container.removeClass(); // remove all classes! (if I don't the lazy load gets triggered)
2208            this.container.next('.media-boxes-load-more-button').remove();
2209            this.container.isotopeMB('destroy');
2210            this.container.remove();
2211
2212        }   
2213
2214    /* ====================================================================== *
2215            [E] INSERT
2216     * ====================================================================== */
2217
2218        this.insert = function (content, callback) { // insert and load all content into the grid
2219
2220            var $container = this.container;
2221
2222            $container.isotopeMB( 'insert', $(content), function(){
2223                callback();
2224                $container.isotopeMB('layout'); 
2225            });  
2226
2227        }      
2228
2229    /* ====================================================================== *
2230            [F] INSERT IN FLOW
2231     * ====================================================================== */    
2232
2233        this.insert_in_flow = function (content, callback) { // insert more boxes and continue with the loadMore/lazyLoad effect
2234
2235            var $container = this.container;
2236
2237            $container.append( $(content).removeClass(itemClass).addClass(itemHiddenClass) );
2238
2239            loadMoreButton.removeClass('media-boxes-no-more-entries');
2240
2241            loadMore( settings.boxesToLoadStart, true );
2242
2243            callback();
2244
2245        }  
2246
2247    /* ====================================================================== *
2248            [G] REFRESH
2249     * ====================================================================== */
2250
2251        this.refresh = function () { // refresh layout grid only
2252
2253            this.container.isotopeMB('layout'); 
2254
2255        }     
2256
2257    /* ====================================================================== *
2258            [H] RESIZE
2259     * ====================================================================== */
2260
2261        this.resize = function () { // refresh all the variables and things, its like resizing the browser width
2262
2263            this.container.isotopeMB('resize'); 
2264
2265        }           
2266
2267    };//END OF INIT   
2268
2269/* ====================================================================== *
2270        [I] MEDIA BOXES PLUGIN
2271 * ====================================================================== */
2272
2273    $.fn.mediaBoxes = function(options, content, callback) {
2274
2275        return this.each(function(key, value){
2276            var $this   = $(this);
2277            var data    = $this.data('mediaBoxes')
2278            
2279            // Initialize plugin
2280            if (!data && typeof options != 'string'){
2281                $this.data('mediaBoxes', new MediaBoxes(this, options));
2282            }
2283
2284            // Call method
2285            if (data && typeof options == 'string'){
2286                data[options](content, callback);    
2287            }
2288        });
2289
2290    };      
2291    
2292})( window, jQuery );

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.