PageSourceSearch

https://saintgeorgecathedral.com/scripts/media-boxes/plugin/js/jquery.mediaBoxes.js

js saintgeorgecathedral.com collected 2026-10-03 00:58:00 UTC 90,616 bytes, 2,003 lines download raw bytes

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