PageSourceSearch

https://www.cofece.mx/wp-content/themes/vamtam-consulting/vamtam/a…/js/jquery.cubeportfolio.js?ver=4.4.1

js cofece.mx collected 2026-10-02 03:26:14 UTC 202,862 bytes, 6,355 lines download raw bytes

1(function($, window, document, undefined) {
2    'use strict';
3
4    function CubePortfolio(obj, options, callback) {
5        /*jshint validthis: true */
6        var t = this;
7
8        if ($.data(obj, 'cubeportfolio')) {
9            throw new Error('cubeportfolio is already initialized. Destroy it before initialize again!');
10        }
11
12        // js element
13        t.obj = obj;
14
15        // jquery element
16        t.$obj = $(obj);
17
18        // attached this instance to obj
19        $.data(t.obj, 'cubeportfolio', t);
20
21        // rename options
22        if (options && (options.sortToPreventGaps !== undefined)) {
23            options.sortByDimension = options.sortToPreventGaps;
24            delete options.sortToPreventGaps;
25        }
26
27        // extend options
28        t.options = $.extend({}, $.fn.cubeportfolio.options, options, t.$obj.data('cbp-options'));
29
30        // store the state of the animation used for filters
31        t.isAnimating = true;
32
33        // default filter for plugin
34        t.defaultFilter = t.options.defaultFilter;
35
36        // registered events (observator & publisher pattern)
37        t.registeredEvents = [];
38
39        // queue for this plugin
40        t.queue = [];
41
42        // has wrapper
43        t.addedWrapp = false;
44
45        // register callback function
46        if ($.isFunction(callback)) {
47            t.registerEvent('initFinish', callback, true);
48        }
49
50        // when there are no .cbp-item
51        var children = t.$obj.children();
52
53        t.$obj.addClass('cbp');
54
55        if (children.length === 0 || children.first().hasClass('cbp-item')) {
56            t.wrapInner(t.obj, 'cbp-wrapper');
57            t.addedWrapp = true;
58        }
59
60        // jquery wrapper element
61        t.$ul = t.$obj.children().addClass('cbp-wrapper');
62
63        // wrap the $ul in a outside wrapper
64        t.wrapInner(t.obj, 'cbp-wrapper-outer');
65
66        t.wrapper = t.$obj.children('.cbp-wrapper-outer');
67
68        t.blocks = t.$ul.children('.cbp-item');
69        t.blocksOn = t.blocks;
70
71        // wrap .cbp-item-wrap div inside .cbp-item
72        t.wrapInner(t.blocks, 'cbp-item-wrapper');
73
74        // register and initialize plugins
75        t.plugins = {};
76        $.each(CubePortfolio.plugins, function(key, value) {
77            var fn = value(t);
78
79            if (fn) {
80                t.plugins[key] = fn;
81            }
82        });
83
84        // used by the filters plugin. @todo - remove from here and create proper API with position for plugins
85        t.triggerEvent('afterPlugins');
86
87        // usful when width & height is defined for an image and to keep the same aspect ratio on all devices
88        // on resize. e.g. from mobile to desktop
89        t.removeAttrAfterStoreData = $.Deferred();
90
91        // wait to load all images and then go further
92        t.loadImages(t.$obj, t.display);
93    }
94
95
96    $.extend(CubePortfolio.prototype, {
97        storeData: function(blocks, indexStart) {
98            var t = this;
99
100            indexStart = indexStart || 0; // used by loadMore
101
102            blocks.each(function(index, el) {
103                var item = $(el),
104                    width = item.width(),
105                    height = item.height();
106
107                item.data('cbp', {
108                    index: indexStart + index, // used when I sort the items and I need them to revert that sorting
109                    indexInitial: indexStart + index, // used for sort.js @todo - move this to sort.js but be carefoul when I add new items to grid
110                    wrapper: item.children('.cbp-item-wrapper'),
111
112                    widthInitial: width,
113                    heightInitial: height,
114
115                    width: width, // used by drag & drop wp @todo - maybe I will use widthAndGap
116                    height: height,
117
118                    widthAndGap: width + t.options.gapVertical,
119                    heightAndGap: height + t.options.gapHorizontal,
120
121                    left: null,
122                    leftNew: null,
123                    top: null,
124                    topNew: null,
125
126                    pack: false,
127                });
128            });
129
130            this.removeAttrAfterStoreData.resolve();
131        },
132
133
134        // http://bit.ly/pure-js-wrap
135        wrapInner: function(items, classAttr) {
136            var t = this,
137                item, i, div;
138
139            classAttr = classAttr || '';
140
141            if (items.length && items.length < 1) {
142                return; // there are no .cbp-item
143            } else if (items.length === undefined) {
144                items = [items];
145            }
146
147            for (i = items.length - 1; i >= 0; i--) {
148                item = items[i];
149
150                div = document.createElement('div');
151
152                div.setAttribute('class', classAttr);
153
154                while (item.childNodes.length) {
155                    div.appendChild(item.childNodes[0]);
156                }
157
158                item.appendChild(div);
159            }
160        },
161
162        removeAttrImage: function(img) {
163            this.removeAttrAfterStoreData.then(function() {
164                img.removeAttribute('style');
165            });
166        },
167
168
169        /**
170         * Wait to load all images
171         */
172        loadImages: function(elems, callback) {
173            var t = this;
174
175            // wait a frame (Safari bug)
176            requestAnimationFrame(function() {
177                var imgs = elems.find('img').map(function(index, el) {
178                    // don't wait for images that have a width & height defined
179                    if (el.hasAttribute('width') && el.hasAttribute('height')) {
180                        el.style.width = el.getAttribute('width') + 'px';
181                        el.style.height = el.getAttribute('height') + 'px';
182
183                        if (el.hasAttribute('data-cbp-src')) {
184                            return null;
185                        }
186
187                        if (t.checkSrc(el) === null) {
188                            t.removeAttrImage(el);
189                        } else {
190                            var img = $('<img>');
191
192                            img.on('load.cbp error.cbp', function() {
193                                $(this).off('load.cbp error.cbp');
194                                t.removeAttrImage(el);
195                            });
196
197                            if (el.srcset) {
198                                img.attr('sizes', el.sizes || '100vw');
199                                img.attr('srcset', el.srcset);
200                            } else {
201                                img.attr('src', el.src);
202                            }
203                        }
204
205                        return null;
206                    } else {
207                        return t.checkSrc(el);
208                    }
209                });
210
211                var imgsLength = imgs.length;
212
213                if (imgsLength === 0) {
214                    callback.call(t);
215                    return;
216                }
217
218                $.each(imgs, function(i, el) {
219                    var img = $('<img>');
220
221                    img.on('load.cbp error.cbp', function() {
222                        $(this).off('load.cbp error.cbp');
223
224                        imgsLength--;
225
226                        if (imgsLength === 0) {
227                            callback.call(t);
228                        }
229                    });
230
231                    // ie8 compatibility
232                    if (el.srcset) {
233                        img.attr('sizes', el.sizes);
234                        img.attr('srcset', el.srcset);
235                    } else {
236                        img.attr('src', el.src);
237                    }
238                });
239            });
240        },
241
242
243        checkSrc: function(el) {
244            var srcset = el.srcset;
245            var src = el.src;
246
247            if (src === '') {
248                return null;
249            }
250
251            var img = $('<img>');
252
253            if (srcset) {
254                img.attr('sizes', el.sizes || '100vw');
255                img.attr('srcset', srcset);
256            } else {
257                img.attr('src', src);
258            }
259
260            var node = img[0];
261
262            if (node.complete && node.naturalWidth !== undefined && node.naturalWidth !== 0) {
263                return null;
264            }
265
266            return node;
267        },
268
269
270        /**
271         * Show the plugin
272         */
273        display: function() {
274            var t = this;
275
276            // update the current grid width
277            t.width = t.$obj.outerWidth();
278
279            t.triggerEvent('initStartRead');
280            t.triggerEvent('initStartWrite');
281
282            if (t.width > 0) {
283                // store to data values of t.blocks
284                t.storeData(t.blocks);
285
286                // make layout
287                t.layoutAndAdjustment();
288            }
289
290            t.triggerEvent('initEndRead');
291            t.triggerEvent('initEndWrite');
292
293            // plugin is ready to show and interact
294            t.$obj.addClass('cbp-ready');
295
296            t.runQueue('delayFrame', t.delayFrame);
297        },
298
299
300        delayFrame: function() {
301            var t = this;
302
303            requestAnimationFrame(function() {
304                t.resizeEvent();
305
306                t.triggerEvent('initFinish');
307
308                // animating is now false
309                t.isAnimating = false;
310
311                // trigger public event initComplete
312                t.$obj.trigger('initComplete.cbp');
313            });
314        },
315
316
317        /**
318         * Add resize event when browser width changes
319         */
320        resizeEvent: function() {
321            var t = this;
322
323            CubePortfolio.private.resize.initEvent({
324                instance: t,
325                fn: function() {
326                    // used by wp fullWidth force option
327                    t.triggerEvent('beforeResizeGrid');
328
329                    var newWidth = t.$obj.outerWidth();
330
331                    if (newWidth && (t.width !== newWidth)) {
332                        // update the current grid width
333                        t.width = newWidth;
334
335                        if (t.options.gridAdjustment === 'alignCenter') {
336                            t.wrapper[0].style.maxWidth = '';
337                        }
338
339                        // reposition the blocks with gridAdjustment set to true
340                        t.layoutAndAdjustment();
341
342                        t.triggerEvent('resizeGrid');
343                    }
344
345                    t.triggerEvent('resizeWindow');
346                }
347            });
348        },
349
350
351        gridAdjust: function() {
352            var t = this;
353
354            // if responsive
355            if (t.options.gridAdjustment === 'responsive') {
356                t.responsiveLayout();
357            } else {
358                // reset the style attribute for all blocks so I can read a new width & height
359                // for the current grid width. This is usefull for the styles defined in css
360                // to create a custom responsive system.
361                // Note: reset height if it was set for addHeightToBlocks
362                t.blocks.removeAttr('style');
363
364                t.blocks.each(function(index, el) {
365                    var data = $(el).data('cbp'),
366                        bound = el.getBoundingClientRect(),
367                        width = t.columnWidthTruncate(bound.right - bound.left),
368                        height = Math.round(bound.bottom - bound.top);
369
370                    data.height = height;
371                    data.heightAndGap = height + t.options.gapHorizontal;
372
373                    data.width = width;
374                    data.widthAndGap = width + t.options.gapVertical;
375                });
376
377                t.widthAvailable = t.width + t.options.gapVertical;
378            }
379
380            // used by slider layoutMode
381            t.triggerEvent('gridAdjust');
382        },
383
384
385        layoutAndAdjustment: function(updateWidth) {
386            var t = this;
387
388            if (updateWidth) {
389                // update the current grid width
390                t.width = t.$obj.outerWidth();
391            }
392
393            t.gridAdjust();
394
395            t.layout();
396        },
397
398
399        /**
400         * Build the layout
401         */
402        layout: function() {
403            var t = this;
404
405            t.computeBlocks(t.filterConcat(t.defaultFilter));
406
407            if (t.options.layoutMode === 'slider') {
408                t.sliderLayoutReset();
409                t.sliderLayout();
410            } else {
411                t.mosaicLayoutReset();
412                t.mosaicLayout();
413            }
414
415            // positionate the blocks
416            t.blocksOff.addClass('cbp-item-off');
417            t.blocksOn.removeClass('cbp-item-off')
418                .each(function(index, el) {
419                    var data = $(el).data('cbp');
420
421                    data.left = data.leftNew;
422                    data.top = data.topNew;
423
424                    el.style.left = data.left + 'px';
425                    el.style.top = data.top + 'px';
426                });
427
428            // resize main container height
429            t.resizeMainContainer();
430        },
431
432
433        computeFilter: function(expression) {
434            var t = this;
435
436            t.computeBlocks(expression);
437
438            t.mosaicLayoutReset();
439            t.mosaicLayout();
440
441            // filter call layout
442            // this method is override by animation{PluginName}
443            t.filterLayout();
444        },
445
446
447        /**
448         *  Default filter layout if nothing overrides
449         */
450        filterLayout: function() {
451            var t = this;
452
453            t.blocksOff.addClass('cbp-item-off');
454
455            t.blocksOn.removeClass('cbp-item-off')
456                .each(function(index, el) {
457                    var data = $(el).data('cbp');
458
459                    data.left = data.leftNew;
460                    data.top = data.topNew;
461
462                    el.style.left = data.left + 'px';
463                    el.style.top = data.top + 'px';
464                });
465
466            // resize main container height
467            t.resizeMainContainer();
468
469            t.filterFinish();
470        },
471
472
473        /**
474         *  Trigger when a filter is finished
475         */
476        filterFinish: function() {
477            var t = this;
478
479            t.isAnimating = false;
480
481            t.$obj.trigger('filterComplete.cbp');
482            t.triggerEvent('filterFinish');
483        },
484
485
486        computeBlocks: function(expression) {
487            var t = this;
488
489            // blocks that are visible before applying the filter
490            t.blocksOnInitial = t.blocksOn;
491
492            // blocks visible after applying the filter
493            t.blocksOn = t.blocks.filter(expression);
494
495            // blocks off after applying the filter
496            t.blocksOff = t.blocks.not(expression);
497
498            t.triggerEvent('computeBlocksFinish', expression);
499        },
500
501
502        /**
503         * Make this plugin responsive
504         */
505        responsiveLayout: function() {
506            var t = this;
507
508            // calculate numbers of cols
509            t.cols = t[(Array.isArray(t.options.mediaQueries) ? 'getColumnsBreakpoints' : 'getColumnsAuto')]();
510
511            t.columnWidth = t.columnWidthTruncate((t.width + t.options.gapVertical) / t.cols);
512
513            t.widthAvailable = t.columnWidth * t.cols;
514
515            if (t.options.layoutMode === 'mosaic') {
516                t.getMosaicWidthReference();
517            }
518
519            t.blocks.each(function(index, el) {
520                var data = $(el).data('cbp'),
521                    cols = 1, // grid & slider layoutMode must be 1
522                    width;
523
524                if (t.options.layoutMode === 'mosaic') {
525                    cols = t.getColsMosaic(data.widthInitial);
526                }
527
528                width = t.columnWidth * cols - t.options.gapVertical;
529
530                el.style.width = width + 'px';
531                data.width = width;
532                data.widthAndGap = width + t.options.gapVertical;
533
534                // reset height if it was set for addHeightToBlocks
535                el.style.height = '';
536            });
537
538            var imgs = [];
539
540            t.blocks.each(function(index, el) {
541                $.each($(el).find('img').filter('[width][height]'), function(index, el) {
542                    var width = 0;
543
544                    $(el).parentsUntil('.cbp-item').each(function(index, el) {
545                        var currentWidth = $(el).width();
546
547                        if (currentWidth > 0) {
548                            width = currentWidth;
549                            return false;
550                        }
551                    });
552
553                    var imgWidth = parseInt(el.getAttribute('width'), 10);
554                    var imgHeight = parseInt(el.getAttribute('height'), 10);
555                    var ratio = parseFloat((imgWidth / imgHeight).toFixed(10));
556
557                    imgs.push({
558                        el: el,
559                        width: width,
560                        height: Math.round(width / ratio),
561                    });
562                });
563            });
564
565            $.each(imgs, function(index, item) {
566                item.el.width = item.width;
567                item.el.height = item.height;
568                item.el.style.width = item.width + 'px';
569                item.el.style.height = item.height + 'px';
570            });
571
572            t.blocks.each(function(index, el) {
573                var data = $(el).data('cbp'),
574                    bound = el.getBoundingClientRect(),
575                    height = Math.round(bound.bottom - bound.top);
576
577                data.height = height;
578                data.heightAndGap = height + t.options.gapHorizontal;
579            });
580        },
581
582
583        getMosaicWidthReference: function() {
584            var t = this,
585                arrWidth = [];
586
587            t.blocks.each(function(index, el) {
588                var data = $(el).data('cbp');
589                arrWidth.push(data.widthInitial);
590            });
591
592            arrWidth.sort(function(a, b) {
593                return a - b;
594            });
595
596            if (arrWidth[0]) {
597                t.mosaicWidthReference = arrWidth[0];
598            } else {
599                t.mosaicWidthReference = t.columnWidth;
600            }
601        },
602
603
604        getColsMosaic: function(widthInitial) {
605            var t = this;
606
607            if (widthInitial === t.width) {
608                return t.cols;
609            }
610
611            var ratio = widthInitial / t.mosaicWidthReference;
612
613            if (ratio % 1 >= 0.79) {
614                ratio = Math.ceil(ratio);
615            } else {
616                ratio = Math.floor(ratio);
617            }
618
619            return Math.min(Math.max(ratio, 1), t.cols);
620        },
621
622
623        /**
624         * Get numbers of columns when t.options.mediaQueries is not an array
625         */
626        getColumnsAuto: function() {
627            var t = this;
628
629            if (t.blocks.length === 0) {
630                return 1;
631            }
632
633            var columnWidth = t.blocks.first().data('cbp').widthInitial + t.options.gapVertical;
634
635            return Math.max(Math.round(t.width / columnWidth), 1);
636        },
637
638
639        /**
640         * Get numbers of columns if t.options.mediaQueries is an array
641         */
642        getColumnsBreakpoints: function() {
643            var t = this,
644                gridWidth = t.width,
645                mediaQuery;
646
647            $.each(t.options.mediaQueries, function(index, obj) {
648                if (gridWidth >= obj.width) {
649                    mediaQuery = obj;
650                    return false;
651                }
652            });
653
654            if (!mediaQuery) {
655                mediaQuery = t.options.mediaQueries[t.options.mediaQueries.length - 1];
656            }
657
658            // the columns breakpoints is triggered
659            t.triggerEvent('onMediaQueries', mediaQuery.options);
660
661            return mediaQuery.cols;
662        },
663
664
665        /**
666         *  Defines how the columns dimension & position (width, left) will be truncated
667         *
668         *  If you use `Math.*` there could be some issues with the items on the right side
669         *  that can have some pixels hidden(1 or 2, depends on the number of columns)
670         *  but this is a known limitation.
671         *
672         *  If you don't use the built-in captions effects (overlay at hover over an item) returning
673         *  the possibly floated values may be a solution for the pixels hidden on the right side.
674         *
675         *  The column width must be an integer because browsers have some visual issues
676         *  with transform properties for caption effects.
677         *
678         *  The initial behaviour was return Math.floor
679         *
680         */
681        columnWidthTruncate: function(value) {
682            return Math.floor(value);
683        },
684
685
686        /**
687         * Resize main container vertically
688         */
689        resizeMainContainer: function() {
690            var t = this,
691                height = Math.max(t.freeSpaces.slice(-1)[0].topStart - t.options.gapHorizontal, 0),
692                maxWidth;
693
694            // set max-width to center the grid if I need to
695            if (t.options.gridAdjustment === 'alignCenter') {
696                maxWidth = 0;
697
698                t.blocksOn.each(function(index, el) {
699                    var data = $(el).data('cbp'),
700                        rightEdge = data.left + data.width;
701
702                    if (rightEdge > maxWidth) {
703                        maxWidth = rightEdge;
704                    }
705                });
706
707                t.wrapper[0].style.maxWidth = maxWidth + 'px';
708            }
709
710            // set container height for `overflow: hidden` to be applied
711            if (height === t.height) {
712                t.triggerEvent('resizeMainContainer');
713                return;
714            }
715
716            t.obj.style.height = height + 'px';
717
718            // if resizeMainContainer is called for the first time skip this event trigger
719            if (t.height !== undefined) {
720                if (CubePortfolio.private.modernBrowser) {
721                    t.$obj.one(CubePortfolio.private.transitionend, function() {
722                        t.$obj.trigger('pluginResize.cbp');
723                    });
724                } else {
725                    t.$obj.trigger('pluginResize.cbp');
726                }
727            }
728
729            t.height = height;
730
731            t.triggerEvent('resizeMainContainer');
732        },
733
734
735        filterConcat: function(filter) {
736            return filter.replace(/\|/gi, '');
737        },
738
739
740        pushQueue: function(name, deferred) {
741            var t = this;
742
743            t.queue[name] = t.queue[name] || [];
744            t.queue[name].push(deferred);
745        },
746
747
748        runQueue: function(name, fn) {
749            var t = this,
750                queue = t.queue[name] || [];
751
752            $.when.apply($, queue).then($.proxy(fn, t));
753        },
754
755
756        clearQueue: function(name) {
757            var t = this;
758
759            t.queue[name] = [];
760        },
761
762
763        /**
764         *  Register event
765         */
766        registerEvent: function(name, callbackFunction, oneTime) {
767            var t = this;
768
769            if (!t.registeredEvents[name]) {
770                t.registeredEvents[name] = [];
771            }
772
773            t.registeredEvents[name].push({
774                func: callbackFunction,
775                oneTime: oneTime || false
776            });
777        },
778
779
780        /**
781         *  Trigger event
782         */
783        triggerEvent: function(name, param) {
784            var t = this,
785                i, len;
786
787            if (t.registeredEvents[name]) {
788                for (i = 0, len = t.registeredEvents[name].length; i < len; i++) {
789                    t.registeredEvents[name][i].func.call(t, param);
790
791                    if (t.registeredEvents[name][i].oneTime) {
792                        t.registeredEvents[name].splice(i, 1);
793                        // function splice change the t.registeredEvents[name] array
794                        // if event is one time you must set the i to the same value
795                        // next time and set the length lower
796                        i--;
797                        len--;
798                    }
799                }
800            }
801        },
802
803
804        addItems: function(items, callback, position) {
805            var t = this;
806
807            // wrap .cbp-item-wrap div inside .cbp-item
808            t.wrapInner(items, 'cbp-item-wrapper');
809
810            t.$ul[position](items.addClass('cbp-item-loading').css({
811                top: '100%',
812                left: 0
813            }));
814
815            if (CubePortfolio.private.modernBrowser) {
816                items.last().one(CubePortfolio.private.animationend, function() {
817                    t.addItemsFinish(items, callback);
818                });
819            } else {
820                t.addItemsFinish(items, callback); // @todo - on ie8 & ie9 callback triggers to early
821            }
822
823            t.loadImages(items, function() {
824                t.$obj.addClass('cbp-updateItems');
825
826                if (position === 'append') {
827                    // push to data values of items
828                    t.storeData(items, t.blocks.length);
829                    $.merge(t.blocks, items);
830                } else {
831                    // push to data values of items
832                    t.storeData(items);
833
834                    var itemsLen = items.length;
835                    t.blocks.each(function(index, el) {
836                        $(el).data('cbp').index = itemsLen + index;
837                    });
838
839                    // push the new items to t.blocks
840                    t.blocks = $.merge(items, t.blocks);
841                }
842
843                t.triggerEvent('addItemsToDOM', items);
844
845                // trigger a sort before layout
846                t.triggerEvent('triggerSort');
847
848                t.layoutAndAdjustment(true);
849
850                // if show count was actived, call show count function again
851                if (t.elems) {
852                    CubePortfolio.public.showCounter.call(t.obj, t.elems);
853                }
854            });
855        },
856
857
858        addItemsFinish: function(items, callback) {
859            var t = this;
860
861            t.isAnimating = false;
862
863            t.$obj.removeClass('cbp-updateItems');
864            items.removeClass('cbp-item-loading');
865
866            if ($.isFunction(callback)) {
867                callback.call(t, items);
868            }
869
870            // trigger public event onAfterLoadMore
871            t.$obj.trigger('onAfterLoadMore.cbp', [items]);
872        },
873
874        removeItems: function(items, callback) {
875            var t = this;
876
877            t.$obj.addClass('cbp-updateItems');
878
879            if (CubePortfolio.private.modernBrowser) {
880                items.last().one(CubePortfolio.private.animationend, function() {
881                    t.removeItemsFinish(items, callback);
882                });
883            } else {
884                t.removeItemsFinish(items, callback); // @todo - on ie8 & ie9 callback triggers to early
885            }
886
887            items.each(function(index, el) {
888                t.blocks.each(function(index2, el2) {
889                    if (el === el2) {
890                        var removeEl = $(el2);
891
892                        // remove element from blocks
893                        t.blocks.splice(index2, 1);
894
895                        if (CubePortfolio.private.modernBrowser) {
896                            removeEl.one(CubePortfolio.private.animationend, function() {
897                                removeEl.remove();
898                            });
899                            removeEl.addClass('cbp-removeItem');
900                        } else {
901                            removeEl.remove();
902                        }
903                    }
904                });
905            });
906
907            t.blocks.each(function(index, el) {
908                $(el).data('cbp').index = index;
909            });
910
911            // trigger a sort before layout
912            t.triggerEvent('triggerSort');
913
914            t.layoutAndAdjustment(true);
915
916            // if show count was actived, call show count function again
917            if (t.elems) {
918                CubePortfolio.public.showCounter.call(t.obj, t.elems);
919            }
920        },
921
922
923        removeItemsFinish: function(items, callback) {
924            var t = this;
925
926            t.isAnimating = false;
927
928            t.$obj.removeClass('cbp-updateItems');
929
930            if ($.isFunction(callback)) {
931                callback.call(t, items);
932            }
933        },
934    });
935
936
937    /**
938     * jQuery plugin initializer
939     */
940    $.fn.cubeportfolio = function(method, options, callback) {
941        return this.each(function() {
942            if (typeof method === 'object' || !method) {
943                return CubePortfolio.public.init.call(this, method, options);
944            } else if (CubePortfolio.public[method]) {
945                return CubePortfolio.public[method].call(this, options, callback);
946            }
947
948            throw new Error('Method ' + method + ' does not exist on jquery.cubeportfolio.js');
949        });
950    };
951
952    CubePortfolio.plugins = {};
953    $.fn.cubeportfolio.constructor = CubePortfolio;
954})(jQuery, window, document);
955
956(function($, window, document, undefined) {
957    'use strict';
958
959    var CubePortfolio = $.fn.cubeportfolio.constructor;
960
961    $.extend(CubePortfolio.prototype, {
962        mosaicLayoutReset: function() {
963            var t = this;
964
965            // flag to be set after the blocks sorting is done
966            t.blocksAreSorted = false;
967
968            // when I start the layout again all blocks must not be positionated
969            // reset height if it was set for addHeightToBlocks
970            t.blocksOn.each(function(index, el) {
971                $(el).data('cbp').pack = false;
972
973                if (t.options.sortByDimension) {
974                    el.style.height = '';
975                }
976            });
977
978            // array of objects where I keep the spaces available in the grid
979            t.freeSpaces = [{
980                leftStart: 0,
981                leftEnd: t.widthAvailable,
982                topStart: 0,
983                topEnd: Math.pow(2, 18) // @todo - optimize
984            }];
985        },
986
987
988        mosaicLayout: function() {
989            var t = this;
990
991            for (var i = 0, blocksLen = t.blocksOn.length; i < blocksLen; i++) {
992                var spaceIndexAndBlock = t.getSpaceIndexAndBlock();
993
994                // if space or block are null then start sorting
995                if (spaceIndexAndBlock === null) {
996                    t.mosaicLayoutReset();
997
998                    // sort blocks to prevent gaps set to true
999                    t.blocksAreSorted = true;
1000
1001                    // sort by the longer width first, followed by a comparison of the shorter height in descending order
1002                    t.sortBlocks(t.blocksOn, 'widthAndGap', 'heightAndGap', true);
1003
1004                    // after the sort is finished start the layout again
1005                    t.mosaicLayout();
1006
1007                    return;
1008                }
1009
1010                t.generateF1F2(spaceIndexAndBlock.spaceIndex, spaceIndexAndBlock.dataBlock);
1011
1012                t.generateG1G2G3G4(spaceIndexAndBlock.dataBlock);
1013
1014                t.cleanFreeSpaces();
1015
1016                t.addHeightToBlocks();
1017            }
1018
1019            // sort blocksOn from top to bottom to add properly delay from animationType and displayType options
1020            if (t.blocksAreSorted) {
1021                t.sortBlocks(t.blocksOn, 'topNew', 'leftNew');
1022            }
1023        },
1024
1025
1026        /**
1027         * Chose from freeSpaces the best space available
1028         * Find block by verifying if it can fit in bestSpace(top-left space available)
1029         * If block doesn't fit in the first space available & t.options.sortByDimension
1030         * is set to true then sort the blocks and start the layout once again
1031         * Decide the free rectangle Fi from F to pack the rectangle R into.
1032         */
1033        getSpaceIndexAndBlock: function() {
1034            var t = this,
1035                spaceIndexAndBlock = null;
1036
1037            $.each(t.freeSpaces, function(index1, space) {
1038                var widthSpace = space.leftEnd - space.leftStart,
1039                    heightSpace = space.topEnd - space.topStart;
1040
1041                t.blocksOn.each(function(index2, block) {
1042                    var data = $(block).data('cbp');
1043
1044                    if (data.pack === true) {
1045                        return;
1046                    }
1047
1048                    if (data.widthAndGap <= widthSpace && data.heightAndGap <= heightSpace) {
1049                        // now the rectagle can be positioned
1050                        data.pack = true;
1051
1052                        spaceIndexAndBlock = {
1053                            spaceIndex: index1,
1054                            dataBlock: data
1055                        };
1056
1057                        data.leftNew = space.leftStart;
1058                        data.topNew = space.topStart;
1059
1060                        // if the block is founded => return from this loop
1061                        return false;
1062                    }
1063                });
1064
1065                // if first space don't have a block and sortByDimension is true => return from loop
1066                if (!t.blocksAreSorted && t.options.sortByDimension && index1 > 0) {
1067                    spaceIndexAndBlock = null;
1068
1069                    return false;
1070                }
1071
1072                // if space & block is founded => return from loop
1073                if (spaceIndexAndBlock !== null) {
1074                    return false;
1075                }
1076            });
1077
1078            return spaceIndexAndBlock;
1079        },
1080
1081
1082        /**
1083         * Use the MAXRECTS split scheme to subdivide Fi(space) into F1 and F2 and
1084         * then remove that space from spaces
1085         * Insert F1 & F2 in F in place of Fi
1086         */
1087        generateF1F2: function(spaceIndex, block) {
1088            var t = this,
1089                space = t.freeSpaces[spaceIndex];
1090
1091            var F1 = {
1092                leftStart: space.leftStart + block.widthAndGap,
1093                leftEnd: space.leftEnd,
1094                topStart: space.topStart,
1095                topEnd: space.topEnd
1096            };
1097
1098            var F2 = {
1099                leftStart: space.leftStart,
1100                leftEnd: space.leftEnd,
1101                topStart: space.topStart + block.heightAndGap,
1102                topEnd: space.topEnd
1103            };
1104
1105            // remove Fi from F
1106            t.freeSpaces.splice(spaceIndex, 1);
1107
1108            if (F1.leftEnd > F1.leftStart && F1.topEnd > F1.topStart) {
1109                t.freeSpaces.splice(spaceIndex, 0, F1);
1110                spaceIndex++;
1111            }
1112
1113            if (F2.leftEnd > F2.leftStart && F2.topEnd > F2.topStart) {
1114                t.freeSpaces.splice(spaceIndex, 0, F2);
1115            }
1116        },
1117
1118
1119        /**
1120         * Generate G1, G2, G3, G4 from intersaction of t.freeSpaces with block
1121         */
1122        generateG1G2G3G4: function(block) {
1123            var t = this;
1124
1125            var spaces = [];
1126
1127            $.each(t.freeSpaces, function(index, space) {
1128                var intersectSpace = t.intersectSpaces(space, block);
1129
1130                // if block & space are the same push space in spaces and return
1131                if (intersectSpace === null) {
1132                    spaces.push(space);
1133                    return;
1134                }
1135
1136                t.generateG1(space, intersectSpace, spaces);
1137                t.generateG2(space, intersectSpace, spaces);
1138                t.generateG3(space, intersectSpace, spaces);
1139                t.generateG4(space, intersectSpace, spaces);
1140            });
1141
1142            t.freeSpaces = spaces;
1143        },
1144
1145
1146        /**
1147         * Return the intersected rectagle of Fi and block
1148         * If the two spaces don't intersect or are the same return null
1149         */
1150        intersectSpaces: function(space1, block) {
1151            var t = this,
1152                space2 = {
1153                    leftStart: block.leftNew,
1154                    leftEnd: block.leftNew + block.widthAndGap,
1155                    topStart: block.topNew,
1156                    topEnd: block.topNew + block.heightAndGap,
1157                };
1158
1159            if (space1.leftStart === space2.leftStart &&
1160                space1.leftEnd === space2.leftEnd &&
1161                space1.topStart === space2.topStart &&
1162                space1.topEnd === space2.topEnd) {
1163                return null;
1164            }
1165
1166            var leftStart = Math.max(space1.leftStart, space2.leftStart),
1167                leftEnd = Math.min(space1.leftEnd, space2.leftEnd),
1168                topStart = Math.max(space1.topStart, space2.topStart),
1169                topEnd = Math.min(space1.topEnd, space2.topEnd);
1170
1171            if (leftEnd <= leftStart || topEnd <= topStart) {
1172                return null;
1173            }
1174
1175            return {
1176                leftStart: leftStart,
1177                leftEnd: leftEnd,
1178                topStart: topStart,
1179                topEnd: topEnd
1180            };
1181        },
1182
1183
1184        /**
1185         * The top subdivide space
1186         */
1187        generateG1: function(space, intersectSpace, spaces) {
1188            if (space.topStart === intersectSpace.topStart) {
1189                return;
1190            }
1191
1192            spaces.push({
1193                leftStart: space.leftStart,
1194                leftEnd: space.leftEnd,
1195                topStart: space.topStart,
1196                topEnd: intersectSpace.topStart
1197            });
1198        },
1199
1200
1201        /**
1202         * The right subdivide space
1203         */
1204        generateG2: function(space, intersectSpace, spaces) {
1205            if (space.leftEnd === intersectSpace.leftEnd) {
1206                return;
1207            }
1208
1209            spaces.push({
1210                leftStart: intersectSpace.leftEnd,
1211                leftEnd: space.leftEnd,
1212                topStart: space.topStart,
1213                topEnd: space.topEnd
1214            });
1215        },
1216
1217
1218        /**
1219         * The bottom subdivide space
1220         */
1221        generateG3: function(space, intersectSpace, spaces) {
1222            if (space.topEnd === intersectSpace.topEnd) {
1223                return;
1224            }
1225
1226            spaces.push({
1227                leftStart: space.leftStart,
1228                leftEnd: space.leftEnd,
1229                topStart: intersectSpace.topEnd,
1230                topEnd: space.topEnd
1231            });
1232        },
1233
1234
1235        /**
1236         * The left subdivide space
1237         */
1238        generateG4: function(space, intersectSpace, spaces) {
1239            if (space.leftStart === intersectSpace.leftStart) {
1240                return;
1241            }
1242
1243            spaces.push({
1244                leftStart: space.leftStart,
1245                leftEnd: intersectSpace.leftStart,
1246                topStart: space.topStart,
1247                topEnd: space.topEnd
1248            });
1249        },
1250
1251
1252        /**
1253         * For every Fi check if is another Fj so Fj contains Fi
1254         * @todo - refactor
1255         */
1256        cleanFreeSpaces: function() {
1257            var t = this;
1258
1259            // sort space from top to bottom and left to right
1260            t.freeSpaces.sort(function(space1, space2) {
1261                if (space1.topStart > space2.topStart) {
1262                    return 1;
1263                } else if (space1.topStart < space2.topStart) {
1264                    return -1;
1265                } else {
1266                    if (space1.leftStart > space2.leftStart) {
1267                        return 1;
1268                    }
1268 else if (space1.leftStart < space2.leftStart) {
1269                        return -1;
1270                    } else {
1271                        return 0;
1272                    }
1273                }
1274            });
1275
1276            t.correctSubPixelValues();
1277
1278            t.removeNonMaximalFreeSpaces();
1279        },
1280
1281
1282        /**
1283         * If topStart values for spaces are <= 1px then align those spaces
1284         */
1285        correctSubPixelValues: function() {
1286            var t = this,
1287                i, len, diff, space1, space2;
1288
1289            for (i = 0, len = t.freeSpaces.length - 1; i < len; i++) {
1290                space1 = t.freeSpaces[i];
1291                space2 = t.freeSpaces[i + 1];
1292
1293                if ((space2.topStart - space1.topStart) <= 1) {
1294                    space2.topStart = space1.topStart;
1295                }
1296            }
1297        },
1298
1299
1300        /**
1301         * Remove spaces that are not maximal
1302         * If Fi contains Fj then remove Fj from F
1303         */
1304        removeNonMaximalFreeSpaces: function() {
1305            var t = this;
1306
1307            t.uniqueFreeSpaces();
1308
1309            t.freeSpaces = $.map(t.freeSpaces, function(space1, index1) {
1310                $.each(t.freeSpaces, function(index2, space2) {
1311                    // don't compare the same free spaces
1312                    if (index1 === index2) {
1313                        return;
1314                    }
1315
1316                    if (space2.leftStart <= space1.leftStart &&
1317                        space2.leftEnd >= space1.leftEnd &&
1318                        space2.topStart <= space1.topStart &&
1319                        space2.topEnd >= space1.topEnd) {
1320
1321                        space1 = null;
1322                        return false;
1323                    }
1324                });
1325
1326                return space1;
1327            });
1328        },
1329
1330
1331        /**
1332         * Remove duplicates spaces from freeSpaces
1333         */
1334        uniqueFreeSpaces: function() {
1335            var t = this,
1336                result = [];
1337
1338            $.each(t.freeSpaces, function(index1, space1) {
1339                $.each(result, function(index2, space2) {
1340                    if (space2.leftStart === space1.leftStart &&
1341                        space2.leftEnd === space1.leftEnd &&
1342                        space2.topStart === space1.topStart &&
1343                        space2.topEnd === space1.topEnd) {
1344
1345                        space1 = null;
1346                        return false;
1347                    }
1348                });
1349
1350                if (space1 !== null) {
1351                    result.push(space1);
1352                }
1353            });
1354
1355            t.freeSpaces = result;
1356        },
1357
1358
1359        /**
1360         * If freeSpaces arrray has only one space and that space overlap the
1361         * height of the bottom blocks with 1px cut those blocks
1362         */
1363        addHeightToBlocks: function() {
1364            var t = this;
1365
1366            $.each(t.freeSpaces, function(indexSpace, space) {
1367                t.blocksOn.each(function(indexBlock, block) {
1368                    var data = $(block).data('cbp');
1369
1370                    if (data.pack !== true) {
1371                        return;
1372                    }
1373
1374                    if (!t.intersectSpaces(space, data)) {
1375                        return;
1376                    }
1377
1378                    var diff = space.topStart - data.topNew - data.heightAndGap;
1379
1380                    if (diff === -1) {
1381                        block.style.height = (data.height - 1) + 'px';
1382                    }
1383                });
1384            });
1385        },
1386
1387        /**
1388         * Generic sort blocks
1389         */
1390        sortBlocks: function(blocks, compare1, compare2, order) {
1391            compare2 = (compare2 === undefined)? 'leftNew' : compare2;
1392            order = (order === undefined)? 1 : -1;
1393
1394            blocks.sort(function(block1, block2) {
1395                var data1 = $(block1).data('cbp'),
1396                    data2 = $(block2).data('cbp');
1397
1398                if (data1[compare1] > data2[compare1]) {
1399                    return order;
1400                } else if (data1[compare1] < data2[compare1]) {
1401                    return -order;
1402                } else {
1403                    if (data1[compare2] > data2[compare2]) {
1404                        return order;
1405                    } else if (data1[compare2] < data2[compare2]) {
1406                        return -order;
1407                    } else {
1408                        // order asc by index
1409                        if (data1.index > data2.index) {
1410                            return order;
1411                        } else if (data1.index < data2.index) {
1412                            return -order;
1413                        }
1414                    }
1415                }
1416            });
1417        }
1418    });
1419})(jQuery, window, document);
1420// Plugin default options
1421jQuery.fn.cubeportfolio.options = {
1422    /**
1423     *  Define the wrapper for filters
1424     *  Values: strings that represent the elements in the document (DOM selector).
1425     */
1426    filters: '',
1427
1428
1429    /**
1430     *  Define the search input element
1431     *  Values: strings that represent the element in the document (DOM selector).
1432     */
1433    search: '',
1434
1435    /**
1436     *  Layout Mode for this instance
1437     *  Values: 'grid', 'mosaic' or 'slider'
1438     */
1439    layoutMode: 'grid',
1440
1441    /**
1442     *  Sort the items by dimension (bigger to smallest) if there are gaps in grid
1443     *  Option available only for `layoutMode: 'mosaic'`
1444     *  Values: true or false
1445     */
1446    sortByDimension: false,
1447
1448    /**
1449     *  Mouse and touch drag support
1450     *  Option available only for `layoutMode: 'slider'`
1451     *  Values: true or false
1452     */
1453    drag: true,
1454
1455    /**
1456     *  Autoplay the slider
1457     *  Option available only for `layoutMode: 'slider'`
1458     *  Values: true or false
1459     */
1460    auto: false,
1461
1462    /**
1463     *  Autoplay interval timeout. Time is set in milisecconds
1464     *  1000 milliseconds equals 1 second.
1465     *  Option available only for `layoutMode: 'slider'`
1466     *  Values: only integers (ex: 1000, 2000, 5000)
1467     */
1468    autoTimeout: 5000,
1469
1470    /**
1471     *  Stops autoplay when user hover the slider
1472     *  Option available only for `layoutMode: 'slider'`
1473     *  Values: true or false
1474     */
1475    autoPauseOnHover: true,
1476
1477    /**
1478     *  Show `next` and `prev` buttons for slider
1479     *  Option available only for `layoutMode: 'slider'`
1480     *  Values: true or false
1481     */
1482    showNavigation: true,
1483
1484    /**
1485     *  Show pagination for slider
1486     *  Option available only for `layoutMode: 'slider'`
1487     *  Values: true or false
1488     */
1489    showPagination: true,
1490
1491    /**
1492     *  Enable slide to first item (last item)
1493     *  Option available only for `layoutMode: 'slider'`
1494     *  Values: true or false
1495     */
1496    rewindNav: true,
1497
1498    /**
1499     *  Scroll by page and not by item. This option affect next/prev buttons and drag support
1500     *  Option available only for `layoutMode: 'slider'`
1501     *  Values: true or false
1502     */
1503    scrollByPage: false,
1504
1505    /**
1506     *  Default filter for plugin
1507     *  Option available only for `layoutMode: 'grid'`
1508     *  Values: strings that represent the filter name(ex: *, .logo, .web-design, .design)
1509     */
1510    defaultFilter: '*',
1511
1512    /**
1513     *  Enable / disable the deeplinking feature when you click on filters
1514     *  Option available only for `layoutMode: 'grid'`
1515     *  Values: true or false
1516     */
1517    filterDeeplinking: false,
1518
1519    /**
1520     *  Defines which animation to use for items that will be shown or hidden after a filter has been activated.
1521     *  Option available only for `layoutMode: 'grid'`
1522     *  The plugin use the best browser features available (css3 transitions and transform, GPU acceleration).
1523     *  Values: - fadeOut
1524     *          - quicksand
1525     *          - bounceLeft
1526     *          - bounceTop
1527     *          - bounceBottom
1528     *          - moveLeft
1529     *          - slideLeft
1530     *          - fadeOutTop
1531     *          - sequentially
1532     *          - skew
1533     *          - slideDelay
1534     *          - rotateSides
1535     *          - flipOutDelay
1536     *          - flipOut
1537     *          - unfold
1538     *          - foldLeft
1539     *          - scaleDown
1540     *          - scaleSides
1541     *          - frontRow
1542     *          - flipBottom
1543     *          - rotateRoom
1544     */
1545    animationType: 'fadeOut',
1546
1547    /**
1548     *  Adjust the layout grid
1549     *  Values: - default (no adjustment applied)
1550     *          - alignCenter (align the grid on center of the page)
1551     *          - responsive (use a fluid algorithm to resize the grid)
1552     */
1553    gridAdjustment: 'responsive',
1554
1555    /**
1556     * Define `media queries` for columns layout.
1557     * Format: [{width: a, cols: d}, {width: b, cols: e}, {width: c, cols: f}],
1558     * where a, b, c are the grid width and d, e, f are the columns displayed.
1559     * e.g. [{width: 1100, cols: 4}, {width: 800, cols: 3}, {width: 480, cols: 2}] means
1560     * if (gridWidth >= 1100) => show 4 columns,
1561     * if (gridWidth >= 800 && gridWidth < 1100) => show 3 columns,
1562     * if (gridWidth >= 480 && gridWidth < 800) => show 2 columns,
1563     * if (gridWidth < 480) => show 2 columns
1564     * Keep in mind that a > b > c
1565     * This option is available only when `gridAdjustment: 'responsive'`
1566     * Values:  - array of objects of format: [{width: a, cols: d}, {width: b, cols: e}]
1567     *          - you can define as many objects as you want
1568     *          - if this option is `false` Cube Portfolio will adjust the items
1569     *            width automatically (default option for backward compatibility)
1570     */
1571    mediaQueries: false,
1572
1573    /**
1574     *  Horizontal gap between items
1575     *  Values: only integers (ex: 1, 5, 10)
1576     */
1577    gapHorizontal: 10,
1578
1579    /**
1580     *  Vertical gap between items
1581     *  Values: only integers (ex: 1, 5, 10)
1582     */
1583    gapVertical: 10,
1584
1585    /**
1586     *  Caption - the overlay that is shown when you put the mouse over an item
1587     *  NOTE: If you don't want to have captions set this option to an empty string ( caption: '')
1588     *  Values: - pushTop
1589     *          - pushDown
1590     *          - revealBottom
1591     *          - revealTop
1592     *          - revealLeft
1593     *          - moveRight
1594     *          - overlayBottom
1595     *          - overlayBottomPush
1596     *          - overlayBottomReveal
1597     *          - overlayBottomAlong
1598     *          - overlayRightAlong
1599     *          - minimal
1600     *          - fadeIn
1601     *          - zoom
1602     *          - opacity
1603     *          - ''
1604     */
1605    caption: 'pushTop',
1606
1607    /**
1608     *  The plugin will display his content based on the following values.
1609     *  Values: - default (the content will be displayed without any animation)
1610     *          - fadeIn (the plugin will fully preload the images before displaying the items with a fadeIn effect)
1611     *          - fadeInToTop (the plugin will fully preload the images before displaying the items with a fadeIn effect from bottom to top)
1612     *          - sequentially (the plugin will fully preload the images before displaying the items with a sequentially effect)
1613     *          - bottomToTop (the plugin will fully preload the images before displaying the items with an animation from bottom to top)
1614     */
1615    displayType: 'fadeIn',
1616
1617    /**
1618     *  Defines the speed of displaying the items (when `displayType: 'default'` this option will have no effect)
1619     *  Values: only integers, values in ms (ex: 200, 300, 500)
1620     */
1621    displayTypeSpeed: 400,
1622
1623    /**
1624     *  This is used to define any clickable elements you wish to use to trigger lightbox popup on click.
1625     *  Values: strings that represent the elements in the document (DOM selector)
1626     */
1627    lightboxDelegate: '.cbp-lightbox',
1628
1629    /**
1630     *  Enable / disable gallery mode
1631     *  Values: true or false
1632     */
1633    lightboxGallery: true,
1634
1635    /**
1636     *  Attribute of the delegate item that contains caption for lightbox
1637     *  Values: html atributte
1638     */
1639    lightboxTitleSrc: 'data-title',
1640
1641    /**
1642     *  Markup of the lightbox counter
1643     *  Values: html markup
1644     */
1645    lightboxCounter: '<div class="cbp-popup-lightbox-counter">{{current}} of {{total}}</div>',
1646
1647    /**
1648     *  This is used to define any clickable elements you wish to use to trigger singlePage popup on click.
1649     *  Values: strings that represent the elements in the document (DOM selector)
1650     */
1651    singlePageDelegate: '.cbp-singlePage',
1652
1653    /**
1654     *  Enable / disable the deeplinking feature for singlePage popup
1655     *  Values: true or false
1656     */
1657    singlePageDeeplinking: true,
1658
1659    /**
1660     *  Enable / disable the sticky navigation for singlePage popup
1661     *  Values: true or false
1662     */
1663    singlePageStickyNavigation: true,
1664
1665    /**
1666     *  Markup of the singlePage counter
1667     *  Values: html markup
1668     */
1669    singlePageCounter: '<div class="cbp-popup-singlePage-counter">{{current}} of {{total}}</div>',
1670
1671    /**
1672     *  Defines which animation to use when singlePage appear
1673     *  Values: - left
1674     *          - fade
1675     *          - right
1676     */
1677    singlePageAnimation: 'left',
1678
1679    /**
1680     *  Use this callback to update singlePage content.
1681     *  The callback will trigger after the singlePage popup is open.
1682     *  Values: function
1683     */
1684    singlePageCallback: null,
1685
1686    /**
1687     *  This is used to define any clickable elements you wish to use to trigger singlePageInline on click.
1688     *  Values: strings that represent the elements in the document (DOM selector)
1689     */
1690    singlePageInlineDelegate: '.cbp-singlePageInline',
1691
1692    /**
1693     *  Enable / disable the deeplinking feature for singlePageInline
1694     *  Values: true or false
1695     */
1696    singlePageInlineDeeplinking: false,
1697
1698    /**
1699     *  This is used to define the position of singlePageInline block
1700     *  Values: - above ( above current element )
1701     *          - below ( below current elemnet)
1702     *          - top ( positon top )
1703     *          - bottom ( positon bottom )
1704     */
1705    singlePageInlinePosition: 'top',
1706
1707    /**
1708     *  Push the open panel in focus and at close go back to the former stage
1709     *  Values: true or false
1710     */
1711    singlePageInlineInFocus: true,
1712
1713    /**
1714     *  Use this callback to update singlePageInline content.
1715     *  The callback will trigger after the singlePageInline is open.
1716     *  Values: function
1717     */
1718    singlePageInlineCallback: null,
1719
1720    /**
1721     *  Used by the plugins registered to set local options for the current instance
1722     *  Values: object
1723     */
1724    plugins: {},
1725};
1726(function($, window, document, undefined) {
1727    'use strict';
1728
1729    var CubePortfolio = $.fn.cubeportfolio.constructor;
1730    var $window = $(window);
1731
1732    CubePortfolio.private = {
1733        publicEvents: function(eventName, time, beforeEventCallback) {
1734            var t = this;
1735
1736            // array of objects: {instance: instance, fn: fn}
1737            t.events = [];
1738
1739            t.initEvent = function(obj) {
1740                if (t.events.length === 0) {
1741                    t.scrollEvent();
1742                }
1743
1744                t.events.push(obj);
1745            };
1746
1747            t.destroyEvent = function(instance) {
1748                t.events = $.map(t.events, function(val, index) {
1749                    if (val.instance !== instance) {
1750                        return val;
1751                    }
1752                });
1753
1754                if (t.events.length === 0) {
1755                    // remove scroll event
1756                    $window.off(eventName);
1757                }
1758            };
1759
1760            t.scrollEvent = function() {
1761                var timeout;
1762
1763                // resize
1764                $window.on(eventName, function() {
1765                    clearTimeout(timeout);
1766
1767                    timeout = setTimeout(function() {
1768                        if ($.isFunction(beforeEventCallback) && beforeEventCallback.call(t)) {
1769                            return;
1770                        }
1771
1772                        $.each(t.events, function(index, val) {
1773                            val.fn.call(val.instance);
1774                        });
1775                    }, time);
1776                });
1777            };
1778        },
1779
1780        /**
1781         * Check if cubeportfolio instance exists on current element
1782         */
1783        checkInstance: function(method) {
1784            var t = $.data(this, 'cubeportfolio');
1785
1786            if (!t) {
1787                throw new Error('cubeportfolio is not initialized. Initialize it before calling ' + method + ' method!');
1788            }
1789
1790            t.triggerEvent('publicMethod');
1791
1792            return t;
1793        },
1794
1795        /**
1796         * Get info about client browser
1797         */
1798        browserInfo: function() {
1799            var t = CubePortfolio.private,
1800                appVersion = navigator.appVersion,
1801                transition, animation, perspective;
1802
1803            if (appVersion.indexOf('MSIE 8.') !== -1) { // ie8
1804                t.browser = 'ie8';
1805            } else if (appVersion.indexOf('MSIE 9.') !== -1) { // ie9
1806                t.browser = 'ie9';
1807            } else if (appVersion.indexOf('MSIE 10.') !== -1) { // ie10
1808                t.browser = 'ie10';
1809            } else if (window.ActiveXObject || 'ActiveXObject' in window) { // ie11
1810                t.browser = 'ie11';
1811            } else if ((/android/gi).test(appVersion)) { // android
1812                t.browser = 'android';
1813            } else if ((/iphone|ipad|ipod/gi).test(appVersion)) { // ios
1814                t.browser = 'ios';
1815            } else if ((/chrome/gi).test(appVersion)) {
1816                t.browser = 'chrome';
1817            } else {
1818                t.browser = '';
1819            }
1820
1821            // check if perspective is available
1822            perspective = t.styleSupport('perspective');
1823
1824            // if perspective is not available => no modern browser
1825            if (typeof perspective === undefined) {
1826                return;
1827            }
1828
1829            transition = t.styleSupport('transition');
1830
1831            t.transitionend = {
1832                WebkitTransition: 'webkitTransitionEnd',
1833                transition: 'transitionend'
1834            }[transition];
1835
1836            animation = t.styleSupport('animation');
1837
1838            t.animationend = {
1839                WebkitAnimation: 'webkitAnimationEnd',
1840                animation: 'animationend'
1841            }[animation];
1842
1843            t.animationDuration = {
1844                WebkitAnimation: 'webkitAnimationDuration',
1845                animation: 'animationDuration'
1846            }[animation];
1847
1848            t.animationDelay = {
1849                WebkitAnimation: 'webkitAnimationDelay',
1850                animation: 'animationDelay'
1851            }[animation];
1852
1853            t.transform = t.styleSupport('transform');
1854
1855            if (transition && animation && t.transform) {
1856                t.modernBrowser = true;
1857            }
1858        },
1859
1860
1861        /**
1862         * Feature testing for css3
1863         */
1864        styleSupport: function(prop) {
1865            var supportedProp,
1866                // capitalize first character of the prop to test vendor prefix
1867                webkitProp = 'Webkit' + prop.charAt(0).toUpperCase() + prop.slice(1),
1868                div = document.createElement('div');
1869
1870            // browser supports standard CSS property name
1871            if (prop in div.style) {
1872                supportedProp = prop;
1873            } else if (webkitProp in div.style) {
1874                supportedProp = webkitProp;
1875            }
1876
1877            // avoid memory leak in IE
1878            div = null;
1879
1880            return supportedProp;
1881        },
1882    };
1883
1884    CubePortfolio.private.browserInfo();
1885
1886    CubePortfolio.private.resize = new CubePortfolio.private.publicEvents('resize.cbp', 50, function() {
1887        if (window.innerHeight == screen.height) {
1888            // this is fulll screen mode. don't need to trigger a resize
1889            return true;
1890        }
1891    });
1892})(jQuery, window, document);
1893(function($, window, document, undefined) {
1894    'use strict';
1895
1896    var CubePortfolio = $.fn.cubeportfolio.constructor;
1897
1898    CubePortfolio.public = {
1899
1900        /*
1901         * Init the plugin
1902         */
1903        init: function(options, callback) {
1904            new CubePortfolio(this, options, callback);
1905        },
1906
1907        /*
1908         * Destroy the plugin
1909         */
1910        destroy: function(callback) {
1911            var t = CubePortfolio.private.checkInstance.call(this, 'destroy');
1912
1913            t.triggerEvent('beforeDestroy');
1914
1915            // remove data
1916            $.removeData(this, 'cubeportfolio');
1917
1918            // remove data from blocks
1919            t.blocks.removeData('cbp');
1920
1921            // remove loading class and .cbp on container
1922            t.$obj.removeClass('cbp-ready').removeAttr('style');
1923
1924            // remove class from ul
1925            t.$ul.removeClass('cbp-wrapper');
1926
1927            // remove resize event
1928            CubePortfolio.private.resize.destroyEvent(t);
1929
1930            t.$obj.off('.cbp');
1931
1932            // reset blocks
1933            t.blocks.removeClass('cbp-item-off').removeAttr('style');
1934
1935            t.blocks.find('.cbp-item-wrapper').each(function(index, el) {
1936                var elem = $(el),
1937                    children = elem.children();
1938
1939                if (children.length) {
1940                    children.unwrap();
1941                } else {
1942                    elem.remove();
1943                }
1944            });
1945
1946            if (t.destroySlider) {
1947                t.destroySlider();
1948            }
1949
1950            // remove .cbp-wrapper-outer
1951            t.$ul.unwrap();
1952
1953            // remove .cbp-wrapper
1954            if (t.addedWrapp) {
1955                t.blocks.unwrap();
1956            }
1957
1958            if (t.blocks.length === 0) {
1959                t.$ul.remove();
1960            }
1961
1962            $.each(t.plugins, function(key, value) {
1963                if (typeof value.destroy === 'function') {
1964                    value.destroy();
1965                }
1966            });
1967
1968            if ($.isFunction(callback)) {
1969                callback.call(t);
1970            }
1971
1972            t.triggerEvent('afterDestroy');
1973        },
1974
1975        /*
1976         * Filter the plugin by filterName
1977         */
1978        filter: function(param, callback) {
1979            var t = CubePortfolio.private.checkInstance.call(this, 'filter'),
1980                expression;
1981
1982            if (t.isAnimating) {
1983                return;
1984            }
1985
1986            t.isAnimating = true;
1987
1988            // register callback function
1989            if ($.isFunction(callback)) {
1990                t.registerEvent('filterFinish', callback, true);
1991            }
1992
1993            if ($.isFunction(param)) {
1994                expression = param.call(t, t.blocks);
1995
1996                if(expression === undefined) {
1997                    throw new Error('When you call cubeportfolio API `filter` method with a param of type function you must return the blocks that will be visible.');
1998                }
1999            } else {
2000                if (t.options.filterDeeplinking) {
2001                    var url = location.href.replace(/#cbpf=(.*?)([#\?&]|$)/gi, '');
2002                    location.href = url + '#cbpf=' + encodeURIComponent(param);
2003
2004                    if (t.singlePage && t.singlePage.url) {
2005                        t.singlePage.url = location.href;
2006                    }
2007                }
2008
2009                t.defaultFilter = param;
2010                expression = t.filterConcat(t.defaultFilter);
2011            }
2012
2013            t.triggerEvent('filterStart', expression);
2014
2015            if (t.singlePageInline && t.singlePageInline.isOpen) {
2016                t.singlePageInline.close('promise', {
2017                    callback: function() {
2018                        t.computeFilter(expression);
2019                    }
2020                });
2021            } else {
2022                t.computeFilter(expression);
2023            }
2024        },
2025
2026        /*
2027         * Show counter for filters
2028         */
2029        showCounter: function(elems, callback) {
2030            var t = CubePortfolio.private.checkInstance.call(this, 'showCounter');
2031
2032            // register callback function
2033            if ($.isFunction(callback)) {
2034                t.registerEvent('showCounterFinish', callback, true);
2035            }
2036
2037            t.elems = elems;
2038
2039            elems.each(function() {
2040                var el = $(this);
2041
2042                var count = t.blocks.filter(el.data('filter')).length;
2043                el.find('.cbp-filter-counter').text(count);
2044            });
2045
2046            t.triggerEvent('showCounterFinish', elems);
2047        },
2048
2049        // alias for append public method
2050        appendItems: function(els, callback) {
2051            CubePortfolio.public.append.call(this, els, callback);
2052        },
2053
2054        /*
2055         * Append elements
2056         */
2057        append: function(els, callback) {
2058            var t = CubePortfolio.private.checkInstance.call(this, 'append'),
2059                items = $(els).filter('.cbp-item');
2060
2061            if (t.isAnimating || items.length < 1) {
2062                if ($.isFunction(callback)) {
2063                    callback.call(t, items);
2064                }
2065
2066                return;
2067            }
2068
2069            t.isAnimating = true;
2070
2071            if (t.singlePageInline && t.singlePageInline.isOpen) {
2072                t.singlePageInline.close('promise', {
2073                    callback: function() {
2074                        t.addItems(items, callback, 'append');
2075                    }
2076                });
2077            } else {
2078                t.addItems(items, callback, 'append');
2079            }
2080        },
2081
2082        /*
2083         * Prepend elements
2084         */
2085        prepend: function(els, callback) {
2086            var t = CubePortfolio.private.checkInstance.call(this, 'prepend'),
2087                items = $(els).filter('.cbp-item');
2088
2089            if (t.isAnimating || items.length < 1) {
2090                if ($.isFunction(callback)) {
2091                    callback.call(t, items);
2092                }
2093
2094                return;
2095            }
2096
2097            t.isAnimating = true;
2098
2099            if (t.singlePageInline && t.singlePageInline.isOpen) {
2100                t.singlePageInline.close('promise', {
2101                    callback: function() {
2102                        t.addItems(items, callback, 'prepend');
2103                    }
2104                });
2105            } else {
2106                t.addItems(items, callback, 'prepend');
2107            }
2108        },
2109
2110        /*
2111         * Remove elements from the instance and DOM.
2112         * els - jQuery DOM Object
2113         */
2114        remove: function(els, callback) {
2115            var t = CubePortfolio.private.checkInstance.call(this, 'remove'),
2116                items = $(els).filter('.cbp-item');
2117
2118            if (t.isAnimating || items.length < 1) {
2119                if ($.isFunction(callback)) {
2120                    callback.call(t, items);
2121                }
2122
2123                return;
2124            }
2125
2126            t.isAnimating = true;
2127
2128            if (t.singlePageInline && t.singlePageInline.isOpen) {
2129                t.singlePageInline.close('promise', {
2130                    callback: function() {
2131                        t.removeItems(items, callback);
2132                    }
2133                });
2134            } else {
2135                t.removeItems(items, callback);
2136            }
2137        },
2138
2139        /*
2140         * Relayout all elements in the current grid.
2141         * Useful when all/some items need to be laid out again, or grid width is changed.
2142         */
2143        layout: function(callback) {
2144            var t = CubePortfolio.private.checkInstance.call(this, 'layout');
2145
2146            // update the current grid width
2147            t.width = t.$obj.outerWidth();
2148
2149            if (t.isAnimating || (t.width <= 0)) {
2150                if ($.isFunction(callback)) {
2151                    callback.call(t);
2152                }
2153
2154                return;
2155            }
2156
2157            if (t.options.gridAdjustment === 'alignCenter') {
2158                t.wrapper[0].style.maxWidth = '';
2159            }
2160
2161            // store to data values of t.blocks
2162            t.storeData(t.blocks);
2163
2164            // reposition the blocks
2165            t.layoutAndAdjustment();
2166
2167            if ($.isFunction(callback)) {
2168                callback.call(t);
2169            }
2170        },
2171    };
2172})(jQuery, window, document);
2173(function($, window, document, undefined) {
2174    'use strict';
2175
2176    var CubePortfolio = $.fn.cubeportfolio.constructor;
2177
2178    // @todo - gandit cum ar trebui sa fac aici ca nu prea ar merge un plugin
2179    // pt slider ca as extinde pe CubePortfolio.prototype la fiecare initializare
2180    $.extend(CubePortfolio.prototype, {
2181        updateSliderPagination: function() {
2182            var t = this,
2183                pages,
2184                i;
2185
2186            if (t.options.showPagination) {
2187                // get number of pages
2188                pages = Math.ceil(t.blocksOn.length / t.cols);
2189                t.navPagination.empty();
2190
2191                for (i = pages - 1; i >= 0; i--) {
2192                    $('<div/>', {
2193                        'class': 'cbp-nav-pagination-item',
2194                        'data-slider-action': 'jumpTo'
2195                    }).appendTo(t.navPagination);
2196                }
2197
2198                t.navPaginationItems = t.navPagination.children();
2199            }
2200
2201            // enable disable the nav
2202            t.enableDisableNavSlider();
2203        },
2204
2205        destroySlider: function() {
2206            var t = this;
2207
2208            if (t.options.layoutMode !== 'slider') {
2209                return;
2210            }
2211
2212            t.$obj.removeClass('cbp-mode-slider');
2213
2214            t.$ul.removeAttr('style');
2215
2216            t.$ul.off('.cbp');
2217
2218            $(document).off('.cbp'); // @todo - don't interfer with the lightbox
2219
2220            if (t.options.auto) {
2221                t.stopSliderAuto();
2222            }
2223        },
2224
2225        nextSlider: function(el) {
2226            var t = this;
2227
2228            if (t.isEndSlider()) {
2229                if (t.isRewindNav()) {
2230                    t.sliderActive = 0;
2231                } else {
2232                    return;
2233                }
2234            } else {
2235                if (t.options.scrollByPage) {
2236                    t.sliderActive = Math.min(t.sliderActive + t.cols, t.blocksOn.length - t.cols);
2237                } else {
2238                    t.sliderActive += 1;
2239                }
2240            }
2241
2242            t.goToSlider();
2243        },
2244
2245        prevSlider: function(el) {
2246            var t = this;
2247
2248            if (t.isStartSlider()) {
2249                if (t.isRewindNav()) {
2250                    t.sliderActive = t.blocksOn.length - t.cols;
2251                } else {
2252                    return;
2253                }
2254            } else {
2255                if (t.options.scrollByPage) {
2256                    t.sliderActive = Math.max(0, t.sliderActive - t.cols);
2257                } else {
2258                    t.sliderActive -= 1;
2259                }
2260            }
2261
2262            t.goToSlider();
2263        },
2264
2265        jumpToSlider: function(el) {
2266            var t = this,
2267                index = Math.min(el.index() * t.cols, t.blocksOn.length - t.cols);
2268
2269            if (index === t.sliderActive) {
2270                return;
2271            }
2272
2273            t.sliderActive = index;
2274
2275            t.goToSlider();
2276        },
2277
2278        jumpDragToSlider: function(pos) {
2279            var t = this,
2280                jumpWidth,
2281                offset,
2282                condition,
2283                index,
2284                dragLeft = (pos > 0) ? true : false;
2285
2286            if (t.options.scrollByPage) {
2287                jumpWidth = t.cols * t.columnWidth;
2288                offset = t.cols;
2289            } else {
2290                jumpWidth = t.columnWidth;
2291                offset = 1;
2292            }
2293
2294            pos = Math.abs(pos);
2295            index = Math.floor(pos / jumpWidth) * offset;
2296
2297            if (pos % jumpWidth > 20) {
2298                index += offset;
2299            }
2300
2301            if (dragLeft) { // drag to left
2302                t.sliderActive = Math.min(t.sliderActive + index, t.blocksOn.length - t.cols);
2303            } else { // drag to right
2304                t.sliderActive = Math.max(0, t.sliderActive - index);
2305            }
2306
2307            t.goToSlider();
2308        },
2309
2310        isStartSlider: function() {
2311            return this.sliderActive === 0;
2312        },
2313
2314        isEndSlider: function() {
2315            var t = this;
2316            return (t.sliderActive + t.cols) > t.blocksOn.length - 1;
2317        },
2318
2319        goToSlider: function() {
2320            var t = this;
2321
2322            // enable disable the nav
2323            t.enableDisableNavSlider();
2324
2325            t.updateSliderPosition();
2326        },
2327
2328        startSliderAuto: function() {
2329            var t = this;
2330
2331            if (t.isDrag) {
2332                t.stopSliderAuto();
2333                return;
2334            }
2335
2336            t.timeout = setTimeout(function() {
2337                // go to next slide
2338                t.nextSlider();
2339
2340                // start auto
2341                t.startSliderAuto();
2342
2343            }, t.options.autoTimeout);
2344        },
2345
2346        stopSliderAuto: function() {
2347            clearTimeout(this.timeout);
2348        },
2349
2350        enableDisableNavSlider: function() {
2351            var t = this,
2352                page,
2353                method;
2354
2355            if (!t.isRewindNav()) {
2356                method = (t.isStartSlider()) ? 'addClass' : 'removeClass';
2357                t.navPrev[method]('cbp-nav-stop');
2358
2359                method = (t.isEndSlider()) ? 'addClass' : 'removeClass';
2360                t.navNext[method]('cbp-nav-stop');
2361            }
2362
2363            if (t.options.showPagination) {
2364                if (t.options.scrollByPage) {
2365                    page = Math.ceil(t.sliderActive / t.cols);
2366                } else {
2367                    if (t.isEndSlider()) {
2368                        page = t.navPaginationItems.length - 1;
2369                    } else {
2370                        page = Math.floor(t.sliderActive / t.cols);
2371                    }
2372                }
2373
2374                // add class active on pagination's items
2375                t.navPaginationItems.removeClass('cbp-nav-pagination-active')
2376                    .eq(page)
2377                    .addClass('cbp-nav-pagination-active');
2378            }
2379
2380            if (t.customPagination) {
2381                if (t.options.scrollByPage) {
2382                    page = Math.ceil(t.sliderActive / t.cols);
2383                } else {
2384                    if (t.isEndSlider()) {
2385                        page = t.customPaginationItems.length - 1;
2386                    } else {
2387                        page = Math.floor(t.sliderActive / t.cols);
2388                    }
2389                }
2390
2391                // add class active on pagination's items
2392                t.customPaginationItems.removeClass(t.customPaginationClass)
2393                    .eq(page)
2394                    .addClass(t.customPaginationClass);
2395            }
2396        },
2397
2398        /**
2399         * If slider loop is enabled don't add classes to `next` and `prev` buttons
2400         */
2401        isRewindNav: function() {
2402            var t = this;
2403
2404            if (!t.options.showNavigation) {
2405                return true;
2406            }
2407
2408            if (t.blocksOn.length <= t.cols) {
2409                return false;
2410            }
2411
2412            if (t.options.rewindNav) {
2413                return true;
2414            }
2415
2416            return false;
2417        },
2418
2419        sliderItemsLength: function() {
2420            return this.blocksOn.length <= this.cols;
2421        },
2422
2423        /**
2424         * Arrange the items in a slider layout
2425         */
2426        sliderLayout: function() {
2427            var t = this;
2428
2429            t.blocksOn.each(function(index, el) {
2430                var data = $(el).data('cbp');
2431
2432                // update the values with the new ones
2433                data.leftNew = t.columnWidth * index;
2434                data.topNew = 0;
2435
2436                t.sliderFreeSpaces.push({
2437                    topStart: data.heightAndGap
2438                });
2439            });
2440
2441            t.getFreeSpacesForSlider();
2442
2443            t.$ul.width(t.columnWidth * t.blocksOn.length - t.options.gapVertical);
2444        },
2445
2446        getFreeSpacesForSlider: function() {
2447            var t = this;
2448
2449            t.freeSpaces = t.sliderFreeSpaces.slice(t.sliderActive, t.sliderActive + t.cols);
2450
2451            t.freeSpaces.sort(function(space1, space2) {
2452                if (space1.topStart > space2.topStart) {
2453                    return 1;
2454                } else if (space1.topStart < space2.topStart) {
2455                    return -1;
2456                }
2457            });
2458        },
2459
2460        updateSliderPosition: function() {
2461            var t = this,
2462                value = -t.sliderActive * t.columnWidth;
2463
2464            if (CubePortfolio.private.modernBrowser) {
2465                t.$ul[0].style[CubePortfolio.private.transform] = 'translate3d(' + value + 'px, 0px, 0)';
2466            } else {
2467                t.$ul[0].style.left = value + 'px';
2468            }
2469
2470            t.getFreeSpacesForSlider();
2471
2472            t.resizeMainContainer();
2473        },
2474
2475        dragSlider: function() {
2476            var t = this,
2477                $document = $(document),
2478                posInitial,
2479                pos,
2480                target,
2481                ulPosition,
2482                ulMaxWidth,
2483                isAnimating = false,
2484                events = {},
2485                isTouch = false,
2486                touchStartEvent,
2487                isHover = false;
2488
2489            t.isDrag = false;
2490
2491            if (('ontouchstart' in window) ||
2492                (navigator.maxTouchPoints > 0) ||
2493                (navigator.msMaxTouchPoints > 0)) {
2494
2495                events = {
2496                    start: 'touchstart.cbp',
2497                    move: 'touchmove.cbp',
2498                    end: 'touchend.cbp'
2499                };
2500
2501                isTouch = true;
2502            } else {
2503                events = {
2504                    start: 'mousedown.cbp',
2505                    move: 'mousemove.cbp',
2506                    end: 'mouseup.cbp'
2507                };
2508            }
2509
2510            function dragStart(e) {
2511                if (t.sliderItemsLength()) {
2512                    return;
2513                }
2514
2515                if (!isTouch) {
2516                    e.preventDefault();
2517                } else {
2518                    touchStartEvent = e;
2519                }
2520
2521                if (t.options.auto) {
2522                    t.stopSliderAuto();
2523                }
2524
2525                if (isAnimating) {
2526                    $(target).one('click.cbp', function() {
2527                        return false;
2528                    });
2529                    return;
2530                }
2531
2532                target = $(e.target);
2533                posInitial = pointerEventToXY(e).x;
2534                pos = 0;
2535                ulPosition = -t.sliderActive * t.columnWidth;
2536                ulMaxWidth = t.columnWidth * (t.blocksOn.length - t.cols);
2537
2538                $document.on(events.move, dragMove);
2539                $document.on(events.end, dragEnd);
2540
2541                t.$obj.addClass('cbp-mode-slider-dragStart');
2542            }
2543
2544            function dragEnd(e) {
2545                t.$obj.removeClass('cbp-mode-slider-dragStart');
2546
2547                // put the state to animate
2548                isAnimating = true;
2549
2550                if (pos !== 0) {
2551                    target.one('click.cbp', function(e) {
2552                        return false;
2553                    });
2554
2555                    // wait a frame to be sure the .cbp-mode-slider-dragStart is removed from the dom
2556                    requestAnimationFrame(function() {
2557                        t.jumpDragToSlider(pos);
2558                        t.$ul.one(CubePortfolio.private.transitionend, afterDragEnd);
2559                    });
2560                } else {
2561                    afterDragEnd.call(t);
2562                }
2563
2564                $document.off(events.move);
2565                $document.off(events.end);
2566            }
2567
2568            function dragMove(e) {
2569                pos = posInitial - pointerEventToXY(e).x;
2570
2571                if (pos > 8 || pos < -8) {
2572                    e.preventDefault();
2573                }
2574
2575                t.isDrag = true;
2576
2577                var value = ulPosition - pos;
2578
2579                if (pos < 0 && pos < ulPosition) { // to right
2580                    value = (ulPosition - pos) / 5;
2581                } else if (pos > 0 && (ulPosition - pos) < -ulMaxWidth) { // to left
2582                    value = -ulMaxWidth + (ulMaxWidth + ulPosition - pos) / 5;
2583                }
2584
2585                if (CubePortfolio.private.modernBrowser) {
2586                    t.$ul[0].style[CubePortfolio.private.transform] = 'translate3d(' + value + 'px, 0px, 0)';
2587                } else {
2588                    t.$ul[0].style.left = value + 'px';
2589                }
2590            }
2591
2592            function afterDragEnd() {
2593                isAnimating = false;
2594                t.isDrag = false;
2595
2596                if (t.options.auto) {
2597                    if (t.mouseIsEntered) {
2598                        return;
2599                    }
2600
2601                    t.startSliderAuto();
2602                }
2603            }
2604
2605            function pointerEventToXY(e) {
2606                if (e.originalEvent !== undefined && e.originalEvent.touches !== undefined) {
2607                    e = e.originalEvent.touches[0];
2608                }
2609
2610                return {
2611                    x: e.pageX,
2612                    y: e.pageY
2613                };
2614            }
2615
2616            t.$ul.on(events.start, dragStart);
2617        },
2618
2619        /**
2620         * Reset the slider layout
2621         */
2622        sliderLayoutReset: function() {
2623            var t = this;
2624
2625            t.freeSpaces = [];
2626
2627            t.sliderFreeSpaces = [];
2628        },
2629    });
2630})(jQuery, window, document);
2631if (typeof Object.create !== 'function') {
2632    Object.create = function(obj) {
2633        function F() {}
2634        F.prototype = obj;
2635        return new F();
2636    };
2637}
2638
2639// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
2640// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
2641// requestAnimationFrame polyfill by Erik M�ller. fixes from Paul Irish and Tino Zijdel
2642// MIT license
2643(function() {
2644    var lastTime = 0;
2645    var vendors = ['moz', 'webkit'];
2646
2647    for (var x = 0; x < vendors.length && !window.requestAnimationFrame; x++) {
2648        window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
2649        window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
2650    }
2651
2652    if (!window.requestAnimationFrame) {
2653        window.requestAnimationFrame = function(callback, element) {
2654            var currTime = new Date().getTime();
2655            var timeToCall = Math.max(0, 16 - (currTime - lastTime));
2656            var id = window.setTimeout(function() {
2657                    callback(currTime + timeToCall);
2658                },
2659                timeToCall);
2660            lastTime = currTime + timeToCall;
2661            return id;
2662        };
2663    }
2664
2665    if (!window.cancelAnimationFrame) {
2666        window.cancelAnimationFrame = function(id) {
2667            clearTimeout(id);
2668        };
2669    }
2670}());
2671(function($, window, document, undefined) {
2672    'use strict';
2673
2674    var CubePortfolio = $.fn.cubeportfolio.constructor;
2675
2676    function Plugin(parent) {
2677        var t = this;
2678
2679        t.parent = parent;
2680
2681        parent.filterLayout = t.filterLayout;
2682
2683        parent.registerEvent('computeBlocksFinish', function(expression) {
2684            parent.blocksOn2On = parent.blocksOnInitial.filter(ex
2684pression);
2685            parent.blocksOn2Off = parent.blocksOnInitial.not(expression);
2686        });
2687    }
2688
2689    // here this value point to parent grid
2690    Plugin.prototype.filterLayout = function() {
2691        var t = this;
2692
2693        t.$obj.addClass('cbp-animation-' + t.options.animationType);
2694
2695        // [1] - blocks that are only moving with translate
2696        t.blocksOn2On.addClass('cbp-item-on2on')
2697            .each(function(index, el) {
2698                var data = $(el).data('cbp');
2699                el.style[CubePortfolio.private.transform] = 'translate3d(' + (data.leftNew - data.left) + 'px, ' + (data.topNew - data.top) + 'px, 0)';
2700            });
2701
2702        // [2] - blocks than intialy are on but after applying the filter are off
2703        t.blocksOn2Off.addClass('cbp-item-on2off');
2704
2705        // [3] - blocks that are off and it will be on
2706        t.blocksOff2On = t.blocksOn
2707            .filter('.cbp-item-off')
2708            .removeClass('cbp-item-off')
2709            .addClass('cbp-item-off2on')
2710            .each(function(index, el) {
2711                var data = $(el).data('cbp');
2712
2713                el.style.left = data.leftNew + 'px';
2714                el.style.top = data.topNew + 'px';
2715            });
2716
2717        if (t.blocksOn2Off.length) {
2718            t.blocksOn2Off.last().data('cbp').wrapper.one(CubePortfolio.private.animationend, animationend);
2719        } else if (t.blocksOff2On.length) {
2720            t.blocksOff2On.last().data('cbp').wrapper.one(CubePortfolio.private.animationend, animationend);
2721        } else if (t.blocksOn2On.length) { // this is used for sort feature to animate the items when sort API is triggered
2722            t.blocksOn2On.last().one(CubePortfolio.private.transitionend, animationend);
2723        } else {
2724            animationend();
2725        }
2726
2727        // resize main container height
2728        t.resizeMainContainer();
2729
2730        function animationend() {
2731            t.blocks.removeClass('cbp-item-on2off cbp-item-off2on cbp-item-on2on')
2732                .each(function(index, el) {
2733                    var data = $(el).data('cbp');
2734
2735                    data.left = data.leftNew;
2736                    data.top = data.topNew;
2737
2738                    el.style.left = data.left + 'px';
2739                    el.style.top = data.top + 'px';
2740
2741                    el.style[CubePortfolio.private.transform] = '';
2742                });
2743
2744            t.blocksOff.addClass('cbp-item-off');
2745
2746            t.$obj.removeClass('cbp-animation-' + t.options.animationType);
2747
2748            t.filterFinish();
2749        }
2750    };
2751
2752    Plugin.prototype.destroy = function() {
2753        var parent = this.parent;
2754        parent.$obj.removeClass('cbp-animation-' + parent.options.animationType);
2755    };
2756
2757    CubePortfolio.plugins.animationClassic = function(parent) {
2758        if (!CubePortfolio.private.modernBrowser || $.inArray(parent.options.animationType, ['boxShadow', 'fadeOut', 'flipBottom', 'flipOut', 'quicksand', 'scaleSides', 'skew']) < 0) {
2759            return null;
2760        }
2761
2762        return new Plugin(parent);
2763    };
2764})(jQuery, window, document);
2765(function($, window, document, undefined) {
2766    'use strict';
2767
2768    var CubePortfolio = $.fn.cubeportfolio.constructor;
2769
2770    function Plugin(parent) {
2771        var t = this;
2772
2773        t.parent = parent;
2774
2775        parent.filterLayout = t.filterLayout;
2776    }
2777
2778    // here this value point to parent grid
2779    Plugin.prototype.filterLayout = function() {
2780        var t = this,
2781            ulClone = t.$ul[0].cloneNode(true);
2782
2783        ulClone.setAttribute('class', 'cbp-wrapper-helper');
2784        t.wrapper[0].insertBefore(ulClone, t.$ul[0]);
2785
2786        requestAnimationFrame(function() {
2787            t.$obj.addClass('cbp-animation-' + t.options.animationType);
2788
2789            t.blocksOff.addClass('cbp-item-off');
2790
2791            t.blocksOn.removeClass('cbp-item-off')
2792                .each(function(index, el) {
2793                    var data = $(el).data('cbp');
2794
2795                    data.left = data.leftNew;
2796                    data.top = data.topNew;
2797
2798                    el.style.left = data.left + 'px';
2799                    el.style.top = data.top + 'px';
2800
2801                    if (t.options.animationType === 'sequentially') {
2802                        data.wrapper[0].style[CubePortfolio.private.animationDelay] = (index * 60) + 'ms';
2803                    }
2804                });
2805
2806            if (t.blocksOn.length) {
2807                t.blocksOn.last().data('cbp').wrapper.one(CubePortfolio.private.animationend, animationend);
2808            } else if (t.blocksOnInitial.length) {
2809                t.blocksOnInitial.last().data('cbp').wrapper.one(CubePortfolio.private.animationend, animationend);
2810            } else {
2811                animationend();
2812            }
2813
2814            // resize main container height
2815            t.resizeMainContainer();
2816        });
2817
2818        function animationend() {
2819            t.wrapper[0].removeChild(ulClone);
2820
2821            if (t.options.animationType === 'sequentially') {
2822                t.blocksOn.each(function(index, el) {
2823                    $(el).data('cbp').wrapper[0].style[CubePortfolio.private.animationDelay] = '';
2824                });
2825            }
2826
2827            t.$obj.removeClass('cbp-animation-' + t.options.animationType);
2828
2829            t.filterFinish();
2830        }
2831    };
2832
2833    Plugin.prototype.destroy = function() {
2834        var parent = this.parent;
2835        parent.$obj.removeClass('cbp-animation-' + parent.options.animationType);
2836    };
2837
2838    CubePortfolio.plugins.animationClone = function(parent) {
2839        if (!CubePortfolio.private.modernBrowser || $.inArray(parent.options.animationType, ['fadeOutTop', 'slideLeft', 'sequentially']) < 0) {
2840            return null;
2841        }
2842
2843        return new Plugin(parent);
2844    };
2845})(jQuery, window, document);
2846(function($, window, document, undefined) {
2847    'use strict';
2848
2849    var CubePortfolio = $.fn.cubeportfolio.constructor;
2850
2851    function Plugin(parent) {
2852        var t = this;
2853
2854        t.parent = parent;
2855
2856        parent.filterLayout = t.filterLayout;
2857    }
2858
2859    // here this value point to parent grid
2860    Plugin.prototype.filterLayout = function() {
2861        var t = this,
2862            ulCloned = t.$ul.clone(true, true);
2863
2864        ulCloned[0].setAttribute('class', 'cbp-wrapper-helper');
2865        t.wrapper[0].insertBefore(ulCloned[0], t.$ul[0]);
2866
2867        // hack for safari osx because it doesn't want to work if I set animationDelay
2868        // on cbp-item-wrapper before I clone the t.$ul
2869        var itemsCloned = ulCloned.find('.cbp-item').not('.cbp-item-off');
2870
2871        if (t.blocksAreSorted) {
2872            t.sortBlocks(itemsCloned, 'top', 'left');
2873        }
2874
2875        itemsCloned.children('.cbp-item-wrapper').each(function(index, el) {
2876            el.style[CubePortfolio.private.animationDelay] = (index * 50) + 'ms';
2877        });
2878
2879        requestAnimationFrame(function() {
2880            t.$obj.addClass('cbp-animation-' + t.options.animationType);
2881
2882            t.blocksOff.addClass('cbp-item-off');
2883
2884            t.blocksOn.removeClass('cbp-item-off')
2885                .each(function(index, el) {
2886                    var data = $(el).data('cbp');
2887
2888                    data.left = data.leftNew;
2889                    data.top = data.topNew;
2890
2891                    el.style.left = data.left + 'px';
2892                    el.style.top = data.top + 'px';
2893
2894                    data.wrapper[0].style[CubePortfolio.private.animationDelay] = (index * 50) + 'ms';
2895                });
2896
2897            var onLength = t.blocksOn.length,
2898                offLength = itemsCloned.length;
2899
2900            if (onLength === 0 && offLength === 0) {
2901                animationend();
2902            } else if (onLength < offLength) {
2903                itemsCloned.last().children('.cbp-item-wrapper').one(CubePortfolio.private.animationend, animationend);
2904            } else {
2905                t.blocksOn.last().data('cbp').wrapper.one(CubePortfolio.private.animationend, animationend);
2906            }
2907
2908            // resize main container height
2909            t.resizeMainContainer();
2910        });
2911
2912        function animationend() {
2913            t.wrapper[0].removeChild(ulCloned[0]);
2914
2915            t.$obj.removeClass('cbp-animation-' + t.options.animationType);
2916
2917            t.blocks.each(function(index, el) {
2918                $(el).data('cbp').wrapper[0].style[CubePortfolio.private.animationDelay] = '';
2919            });
2920
2921            t.filterFinish();
2922        }
2923    };
2924
2925    Plugin.prototype.destroy = function() {
2926        var parent = this.parent;
2927        parent.$obj.removeClass('cbp-animation-' + parent.options.animationType);
2928    };
2929
2930    CubePortfolio.plugins.animationCloneDelay = function(parent) {
2931        if (!CubePortfolio.private.modernBrowser || $.inArray(parent.options.animationType, ['3dflip', 'flipOutDelay', 'foldLeft', 'frontRow', 'rotateRoom', 'rotateSides', 'scaleDown', 'slideDelay', 'unfold']) < 0) {
2932            return null;
2933        }
2934
2935        return new Plugin(parent);
2936    };
2937})(jQuery, window, document);
2938(function($, window, document, undefined) {
2939    'use strict';
2940
2941    var CubePortfolio = $.fn.cubeportfolio.constructor;
2942
2943    function Plugin(parent) {
2944        var t = this;
2945
2946        t.parent = parent;
2947
2948        parent.filterLayout = t.filterLayout;
2949    }
2950
2951    // here this value point to parent grid
2952    Plugin.prototype.filterLayout = function() {
2953        var t = this,
2954            ulCloned = t.$ul[0].cloneNode(true);
2955
2956        ulCloned.setAttribute('class', 'cbp-wrapper-helper');
2957        t.wrapper[0].insertBefore(ulCloned, t.$ul[0]);
2958
2959        requestAnimationFrame(function() {
2960            t.$obj.addClass('cbp-animation-' + t.options.animationType);
2961
2962            t.blocksOff.addClass('cbp-item-off');
2963
2964            t.blocksOn.removeClass('cbp-item-off')
2965                .each(function(index, el) {
2966                    var data = $(el).data('cbp');
2967
2968                    data.left = data.leftNew;
2969                    data.top = data.topNew;
2970
2971                    el.style.left = data.left + 'px';
2972                    el.style.top = data.top + 'px';
2973                });
2974
2975            if (t.blocksOn.length) {
2976                t.$ul.one(CubePortfolio.private.animationend, animationend);
2977            } else if (t.blocksOnInitial.length) {
2978                $(ulCloned).one(CubePortfolio.private.animationend, animationend);
2979            } else {
2980                animationend();
2981            }
2982
2983            // resize main container height
2984            t.resizeMainContainer();
2985        });
2986
2987        function animationend() {
2988            t.wrapper[0].removeChild(ulCloned);
2989
2990            t.$obj.removeClass('cbp-animation-' + t.options.animationType);
2991
2992            t.filterFinish();
2993        }
2994    };
2995
2996    Plugin.prototype.destroy = function() {
2997        var parent = this.parent;
2998        parent.$obj.removeClass('cbp-animation-' + parent.options.animationType);
2999    };
3000
3001    CubePortfolio.plugins.animationWrapper = function(parent) {
3002        if (!CubePortfolio.private.modernBrowser || $.inArray(parent.options.animationType, ['bounceBottom', 'bounceLeft', 'bounceTop', 'moveLeft']) < 0) {
3003            return null;
3004        }
3005
3006        return new Plugin(parent);
3007    };
3008})(jQuery, window, document);
3009(function($, window, document, undefined) {
3010    'use strict';
3011
3012    var CubePortfolio = $.fn.cubeportfolio.constructor;
3013
3014    function Plugin(parent) {
3015        var t = this;
3016        var options = parent.options;
3017
3018        t.parent = parent;
3019
3020        t.captionOn = options.caption;
3021
3022        parent.registerEvent('onMediaQueries', function(opt) {
3023            if (opt && opt.hasOwnProperty('caption')) {
3024                if (t.captionOn !== opt.caption) {
3025                    t.destroy();
3026                    t.captionOn = opt.caption;
3027                    t.init();
3028                }
3029            } else if (t.captionOn !== options.caption) {
3030                t.destroy();
3031                t.captionOn = options.caption;
3032                t.init();
3033            }
3034        });
3035
3036        t.init();
3037    }
3038
3039    Plugin.prototype.init = function() {
3040        var t = this;
3041
3042        // if caption is active
3043        if (t.captionOn == '') {
3044            return;
3045        }
3046
3047        if (t.captionOn !== 'expand' && !CubePortfolio.private.modernBrowser) {
3048            t.parent.options.caption = t.captionOn = 'minimal';
3049        }
3050
3051        // .cbp-caption-active is used only for css
3052        // so it will not generate a big css from sass if a caption is set
3053        t.parent.$obj.addClass('cbp-caption-active cbp-caption-' + t.captionOn);
3054    };
3055
3056    Plugin.prototype.destroy = function() {
3057        this.parent.$obj.removeClass('cbp-caption-active cbp-caption-' + this.captionOn);
3058    };
3059
3060    CubePortfolio.plugins.caption = function(parent) {
3061        return new Plugin(parent);
3062    };
3063})(jQuery, window, document);
3064(function($, window, document, undefined) {
3065    'use strict';
3066
3067    var CubePortfolio = $.fn.cubeportfolio.constructor;
3068
3069    function Plugin(parent) {
3070        var t = this;
3071
3072        t.parent = parent;
3073
3074        parent.registerEvent('initFinish', function() {
3075            parent.$obj.on('click.cbp', '.cbp-caption-defaultWrap', function(e) {
3076                e.preventDefault();
3077
3078                if (parent.isAnimating) {
3079                    return;
3080                }
3081
3082                parent.isAnimating = true;
3083
3084                var defaultWrap = $(this),
3085                    activeWrap = defaultWrap.next(),
3086                    caption = defaultWrap.parent(),
3087                    endStyle = {
3088                        position: 'relative',
3089                        height: activeWrap.outerHeight(true)
3090                    },
3091                    startStyle = {
3092                        position: 'relative',
3093                        height: 0
3094                    };
3095
3096                parent.$obj.addClass('cbp-caption-expand-active');
3097
3098                // swap endStyle & startStyle
3099                if (caption.hasClass('cbp-caption-expand-open')) {
3100                    var temp = startStyle;
3101                    startStyle = endStyle;
3102                    endStyle = temp;
3103                    caption.removeClass('cbp-caption-expand-open');
3104                }
3105
3106                activeWrap.css(endStyle);
3107
3108                parent.$obj.one('pluginResize.cbp', function() {
3109                    parent.isAnimating = false;
3110                    parent.$obj.removeClass('cbp-caption-expand-active');
3111
3112                    if (endStyle.height === 0) {
3113                        caption.removeClass('cbp-caption-expand-open');
3114                        activeWrap.attr('style', '');
3115                    }
3116                });
3117
3118                // reposition the blocks and set param to update width of grid
3119                parent.layoutAndAdjustment(true);
3120
3121                // set activeWrap to 0 so I can start animation in the next frame
3122                activeWrap.css(startStyle);
3123
3124                // delay animation
3125                requestAnimationFrame(function() {
3126                    caption.addClass('cbp-caption-expand-open');
3127
3128                    activeWrap.css(endStyle);
3129
3130                    // used by slider layoutMode
3131                    parent.triggerEvent('gridAdjust');
3132
3133                    parent.triggerEvent('resizeGrid');
3134                });
3135            });
3136        }, true);
3137    }
3138
3139    Plugin.prototype.destroy = function() {
3140        this.parent.$obj.find('.cbp-caption-defaultWrap').off('click.cbp').parent().removeClass('cbp-caption-expand-active');
3141    };
3142
3143    CubePortfolio.plugins.captionExpand = function(parent) {
3144        if (parent.options.caption !== 'expand') {
3145            return null;
3146        }
3147
3148        return new Plugin(parent);
3149    };
3150})(jQuery, window, document);
3151(function($, window, document, undefined) {
3152    'use strict';
3153
3154    var CubePortfolio = $.fn.cubeportfolio.constructor;
3155
3156    function Plugin(parent) {
3157        parent.registerEvent('initEndWrite', function() {
3158            if (parent.width <= 0) {
3159                return;
3160            }
3161
3162            var deferred = $.Deferred();
3163
3164            parent.pushQueue('delayFrame', deferred);
3165
3166            parent.blocksOn.each(function(index, el) {
3167                el.style[CubePortfolio.private.animationDelay] = (index * parent.options.displayTypeSpeed) + 'ms';
3168            });
3169
3170            parent.$obj.addClass('cbp-displayType-bottomToTop');
3171
3172            // get last element
3173            parent.blocksOn.last().one(CubePortfolio.private.animationend, function() {
3174                parent.$obj.removeClass('cbp-displayType-bottomToTop');
3175
3176                parent.blocksOn.each(function(index, el) {
3177                    el.style[CubePortfolio.private.animationDelay] = '';
3178                });
3179
3180                // resolve event after the animation is finished
3181                deferred.resolve();
3182            });
3183        }, true);
3184    }
3185
3186    CubePortfolio.plugins.displayBottomToTop = function(parent) {
3187        if (!CubePortfolio.private.modernBrowser || parent.options.displayType !== 'bottomToTop' || parent.blocksOn.length === 0) {
3188            return null;
3189        }
3190
3191        return new Plugin(parent);
3192    };
3193})(jQuery, window, document);
3194(function($, window, document, undefined) {
3195    'use strict';
3196
3197    var CubePortfolio = $.fn.cubeportfolio.constructor;
3198
3199    function Plugin(parent) {
3200        parent.registerEvent('initEndWrite', function() {
3201            if (parent.width <= 0) {
3202                return;
3203            }
3204
3205            var deferred = $.Deferred();
3206
3207            parent.pushQueue('delayFrame', deferred);
3208
3209            parent.obj.style[CubePortfolio.private.animationDuration] = parent.options.displayTypeSpeed + 'ms';
3210
3211            parent.$obj.addClass('cbp-displayType-fadeIn');
3212
3213            parent.$obj.one(CubePortfolio.private.animationend, function() {
3214                parent.$obj.removeClass('cbp-displayType-fadeIn');
3215
3216                parent.obj.style[CubePortfolio.private.animationDuration] = '';
3217
3218                // resolve event after the animation is finished
3219                deferred.resolve();
3220            });
3221        }, true);
3222    }
3223
3224    CubePortfolio.plugins.displayFadeIn = function(parent) {
3225        if (!CubePortfolio.private.modernBrowser || (parent.options.displayType !== 'lazyLoading' && parent.options.displayType !== 'fadeIn') || parent.blocksOn.length === 0) {
3226            return null;
3227        }
3228
3229        return new Plugin(parent);
3230    };
3231})(jQuery, window, document);
3232(function($, window, document, undefined) {
3233    'use strict';
3234
3235    var CubePortfolio = $.fn.cubeportfolio.constructor;
3236
3237    function Plugin(parent) {
3238        parent.registerEvent('initEndWrite', function() {
3239            if (parent.width <= 0) {
3240                return;
3241            }
3242
3243            var deferred = $.Deferred();
3244
3245            parent.pushQueue('delayFrame', deferred);
3246
3247            parent.obj.style[CubePortfolio.private.animationDuration] = parent.options.displayTypeSpeed + 'ms';
3248
3249            parent.$obj.addClass('cbp-displayType-fadeInToTop');
3250
3251            parent.$obj.one(CubePortfolio.private.animationend, function() {
3252                parent.$obj.removeClass('cbp-displayType-fadeInToTop');
3253
3254                parent.obj.style[CubePortfolio.private.animationDuration] = '';
3255
3256                // resolve event after the animation is finished
3257                deferred.resolve();
3258            });
3259        }, true);
3260    }
3261
3262    CubePortfolio.plugins.displayFadeInToTop = function(parent) {
3263        if (!CubePortfolio.private.modernBrowser || parent.options.displayType !== 'fadeInToTop' || parent.blocksOn.length === 0) {
3264            return null;
3265        }
3266
3267        return new Plugin(parent);
3268    };
3269})(jQuery, window, document);
3270(function($, window, document, undefined) {
3271    'use strict';
3272
3273    var CubePortfolio = $.fn.cubeportfolio.constructor;
3274
3275    function Plugin(parent) {
3276        parent.registerEvent('initEndWrite', function() {
3277            if (parent.width <= 0) {
3278                return;
3279            }
3280
3281            var deferred = $.Deferred();
3282
3283            parent.pushQueue('delayFrame', deferred);
3284
3285            parent.blocksOn.each(function(index, el) {
3286                el.style[CubePortfolio.private.animationDelay] = (index * parent.options.displayTypeSpeed) + 'ms';
3287            });
3288
3289            parent.$obj.addClass('cbp-displayType-sequentially');
3290
3291            // get last element
3292            parent.blocksOn.last().one(CubePortfolio.private.animationend, function() {
3293                parent.$obj.removeClass('cbp-displayType-sequentially');
3294
3295                parent.blocksOn.each(function(index, el) {
3296                    el.style[CubePortfolio.private.animationDelay] = '';
3297                });
3298
3299                // resolve event after the animation is finished
3300                deferred.resolve();
3301            });
3302        }, true);
3303    }
3304
3305    CubePortfolio.plugins.displaySequentially = function(parent) {
3306        if (!CubePortfolio.private.modernBrowser || parent.options.displayType !== 'sequentially' || parent.blocksOn.length === 0) {
3307            return null;
3308        }
3309
3310        return new Plugin(parent);
3311    };
3312})(jQuery, window, document);
3313(function($, window, document, undefined) {
3314    'use strict';
3315
3316    var CubePortfolio = $.fn.cubeportfolio.constructor;
3317
3318    function Plugin(parent) {
3319        var t = this;
3320
3321        t.parent = parent;
3322
3323        t.filters = $(parent.options.filters);
3324        t.filterData = [];
3325
3326        parent.registerEvent('afterPlugins', function(elems) {
3327            // set default filter if it's present in url
3328            t.filterFromUrl();
3329            t.registerFilter();
3330        });
3331
3332        // reset filters active class after the search is used
3333        parent.registerEvent('resetFiltersVisual', function() {
3334            var arr = parent.options.defaultFilter.split('|');
3335
3336            t.filters.each(function(index, el) {
3337                var items = $(el).find('.cbp-filter-item');
3338                items.removeClass('cbp-filter-item-active');
3339
3340                $.each(arr, function(index, val) {
3341                    var item = items.filter('[data-filter="' + val + '"]');
3342                    if (item.length) {
3343                        item.addClass('cbp-filter-item-active');
3344                        arr.splice(index, 1);
3345                        return false;
3346                    }
3347                });
3348            });
3349
3350            parent.defaultFilter = parent.options.defaultFilter;
3351        });
3352    }
3353
3354    Plugin.prototype.registerFilter = function() {
3355        var t = this,
3356            parent = t.parent,
3357            arr = parent.defaultFilter.split('|');
3358
3359        t.wrap = t.filters.find('.cbp-l-filters-dropdownWrap')
3360            .on({
3361                'mouseover.cbp': function() {
3362                    $(this).addClass('cbp-l-filters-dropdownWrap-open');
3363                },
3364                'mouseleave.cbp': function() {
3365                    $(this).removeClass('cbp-l-filters-dropdownWrap-open');
3366                }
3367            });
3368
3369        t.filters.each(function(index, el) {
3370            var filter = $(el),
3371                filterName = '*',
3372                items = filter.find('.cbp-filter-item'),
3373                dropdown = {};
3374
3375            if (filter.hasClass('cbp-l-filters-dropdown')) {
3376                dropdown.wrap = filter.find('.cbp-l-filters-dropdownWrap');
3377                dropdown.header = filter.find('.cbp-l-filters-dropdownHeader');
3378                dropdown.headerText = dropdown.header.text();
3379            }
3380
3381            // activate counter for filters
3382            parent.$obj.cubeportfolio('showCounter', items);
3383
3384            $.each(arr, function(index, val) {
3385                if (items.filter('[data-filter="' + val + '"]').length) {
3386                    filterName = val;
3387                    arr.splice(index, 1);
3388                    return false;
3389                }
3390            });
3391
3392            $.data(el, 'filterName', filterName);
3393            t.filterData.push(el);
3394
3395            t.filtersCallback(dropdown, items.filter('[data-filter="' + filterName + '"]'), items);
3396
3397            var subFilterParent = el.getAttribute('data-filter-parent');
3398            if (subFilterParent) {
3399                filter.removeClass('cbp-l-subfilters--active');
3400
3401                if (subFilterParent === t.parent.defaultFilter) {
3402                    filter.addClass('cbp-l-subfilters--active');
3403                }
3404            }
3405
3406            items.on('click.cbp', function() {
3407                var item = $(this);
3408
3409                if (item.hasClass('cbp-filter-item-active') || parent.isAnimating) {
3410                    return;
3411                }
3412
3413                t.filtersCallback(dropdown, item, items);
3414
3415                $.data(el, 'filterName', item.data('filter'));
3416
3417                var name = $.map(t.filterData, function(el, index) {
3418                    var $el = $(el);
3419
3420                    var isSubfilter = el.getAttribute('data-filter-parent');
3421                    if (isSubfilter) {
3422                        if (isSubfilter === $.data(t.filterData[0], 'filterName')) {
3423                            $el.addClass('cbp-l-subfilters--active');
3424                        } else {
3425                            $el.removeClass('cbp-l-subfilters--active');
3426                            $.data(el, 'filterName', '*');
3427                            $el.find('.cbp-filter-item').removeClass('cbp-filter-item-active');
3428                        }
3429                    }
3430
3431                    var f = $.data(el, 'filterName');
3432                    return (f !== "" && f !== '*') ? f : null;
3433                });
3434
3435                if (name.length < 1) {
3436                    name = ['*'];
3437                }
3438
3439                var filterJoin = name.join('|');
3440
3441                if (parent.defaultFilter !== filterJoin) {
3442                    // filter the items
3443                    parent.$obj.cubeportfolio('filter', filterJoin);
3444                }
3445            });
3446        });
3447    };
3448
3449    Plugin.prototype.filtersCallback = function(dropdown, item, items) {
3450        if (!$.isEmptyObject(dropdown)) {
3451            dropdown.wrap.trigger('mouseleave.cbp');
3452
3453            if (dropdown.headerText) {
3454                dropdown.headerText = '';
3455            } else {
3456                dropdown.header.html(item.html());
3457            }
3458        }
3459
3460        items.removeClass('cbp-filter-item-active');
3461        item.addClass('cbp-filter-item-active');
3462    };
3463
3464    /**
3465     * Check if filters are present in url
3466     */
3467    Plugin.prototype.filterFromUrl = function() {
3468        var match = /#cbpf=(.*?)([#\?&]|$)/gi.exec(location.href);
3469
3470        if (match !== null) {
3471            this.parent.defaultFilter = decodeURIComponent(match[1]);
3472        }
3473    };
3474
3475    Plugin.prototype.destroy = function() {
3476        var t = this;
3477
3478        t.filters.find('.cbp-filter-item').off('.cbp');
3479        t.wrap.off('.cbp');
3480    };
3481
3482    CubePortfolio.plugins.filters = function(parent) {
3483        if (parent.options.filters === '') {
3484            return null;
3485        }
3486
3487        return new Plugin(parent);
3488    };
3489})(jQuery, window, document);
3490
3491(function($, window, document, undefined) {
3492    'use strict';
3493
3494    var CubePortfolio = $.fn.cubeportfolio.constructor;
3495
3496    function Plugin(parent) {
3497        var gapVerticalInitial = parent.options.gapVertical;
3498        var gapHorizontalInitial = parent.options.gapHorizontal;
3499
3500        parent.registerEvent('onMediaQueries', function(opt) {
3501            parent.options.gapVertical = (opt && opt.hasOwnProperty('gapVertical'))? opt.gapVertical : gapVerticalInitial;
3502            parent.options.gapHorizontal = (opt && opt.hasOwnProperty('gapHorizontal'))? opt.gapHorizontal : gapHorizontalInitial;
3503
3504            parent.blocks.each(function(index, el) {
3505                var data = $(el).data('cbp');
3506
3507                data.widthAndGap = data.width + parent.options.gapVertical;
3508                data.heightAndGap = data.height + parent.options.gapHorizontal;
3509            });
3510        });
3511    }
3512
3513    CubePortfolio.plugins.changeGapOnMediaQueries = function(parent) {
3514        return new Plugin(parent);
3515    };
3516})(jQuery, window, document);
3517(function($, window, document, undefined) {
3518    'use strict';
3519
3520    var options = {};
3521
3522    var CubePortfolio = $.fn.cubeportfolio.constructor;
3523
3524    function Plugin(parent) {
3525        var t = this;
3526
3527        t.parent = parent;
3528
3529        t.options = $.extend({}, options, t.parent.options.plugins.inlineSlider);
3530
3531        t.runInit();
3532
3533        parent.registerEvent('addItemsToDOM', function() {
3534            t.runInit();
3535        });
3536
3537    }
3538
3539    function InitSlider(slider) {
3540        var t = this;
3541
3542        if (slider.hasClass('cbp-slider-inline-ready')) {
3543            return;
3544        }
3545
3546        slider.addClass('cbp-slider-inline-ready');
3547
3548        t.items = slider.find('.cbp-slider-wrapper').children('.cbp-slider-item');
3549
3550        t.active = t.items.filter('.cbp-slider-item--active').index();
3551        t.total = t.items.length - 1;
3552
3553        t.updateLeft();
3554
3555        slider.find('.cbp-slider-next').on('click.cbp', function(e) {
3556            e.preventDefault();
3557
3558            if (t.active < t.total) {
3559                t.active++;
3560                t.updateLeft();
3561            } else if (t.active === t.total) {
3562                t.active = 0;
3563                t.updateLeft();
3564            }
3565        });
3566
3567        slider.find('.cbp-slider-prev').on('click.cbp', function(e) {
3568            e.preventDefault();
3569
3570            if (t.active > 0) {
3571                t.active--;
3572                t.updateLeft();
3573            } else if (t.active === 0) {
3574                t.active = t.total;
3575                t.updateLeft();
3576            }
3577        });
3578    };
3579
3580    InitSlider.prototype.updateLeft = function() {
3581        var t = this;
3582
3583        t.items.removeClass('cbp-slider-item--active');
3584        t.items.eq(t.active).addClass('cbp-slider-item--active');
3585
3586        t.items.each(function(index, el) {
3587            el.style.left = (index - t.active) + '00%';
3588        });
3589    };
3590
3591    Plugin.prototype.runInit = function() {
3592        var t = this;
3593
3594        t.parent.$obj.find('.cbp-slider-inline').not('.cbp-slider-inline-ready').each(function(index, el) {
3595            var slider = $(el);
3596            var activeImage = slider.find('.cbp-slider-item--active').find('img')[0];
3597
3598            if (activeImage.hasAttribute('data-cbp-src')) {
3599                t.parent.$obj.on('lazyLoad.cbp', function(e, image) {
3600                    if (image.src === activeImage.src) {
3601                        new InitSlider(slider);
3602                    }
3603                });
3604            } else {
3605                new InitSlider(slider);
3606            }
3607        });
3608    };
3609
3610    Plugin.prototype.destroy = function() {
3611        var t = this;
3612
3613        t.parent.$obj.find('.cbp-slider-next').off('click.cbp');
3614        t.parent.$obj.find('.cbp-slider-prev').off('click.cbp');
3615
3616        t.parent.$obj.off('lazyLoad.cbp');
3617
3618        t.parent.$obj.find('.cbp-slider-inline').each(function(index, el) {
3619            var slider = $(el);
3620
3621            slider.removeClass('cbp-slider-inline-ready');
3622
3623            var items = slider.find('.cbp-slider-item');
3624            items.removeClass('cbp-slider-item--active');
3625
3626            items.removeAttr('style');
3627
3628            items.eq(0).addClass('cbp-slider-item--active');
3629        });
3630    };
3631
3632    CubePortfolio.plugins.inlineSlider = function(parent) {
3633        return new Plugin(parent);
3634    };
3635})(jQuery, window, document);
3636(function($, window, document, undefined) {
3637    'use strict';
3638
3639    var options = {
3640        loadingClass: 'cbp-lazyload',
3641        threshold: 400, // loads images 150px before they're visible
3642    };
3643
3644    var CubePortfolio = $.fn.cubeportfolio.constructor;
3645    var $window = $(window);
3646
3647    // add scroll event to page for lazyLoad
3648    CubePortfolio.private.lazyLoadScroll = new CubePortfolio.private.publicEvents('scroll.cbplazyLoad', 50);
3649
3650    function Plugin(parent) {
3651        var t = this;
3652
3653        t.parent = parent;
3654
3655        t.options = $.extend({}, options, t.parent.options.plugins.lazyLoad);
3656
3657        parent.registerEvent('initFinish', function() {
3658            t.loadImages();
3659
3660            parent.registerEvent('resizeMainContainer', function() {
3661                t.loadImages();
3662            });
3663
3664            parent.registerEvent('filterFinish', function() {
3665                t.loadImages();
3666            });
3667
3668            CubePortfolio.private.lazyLoadScroll.initEvent({
3669                instance: t,
3670                fn: t.loadImages
3671            });
3672        }, true);
3673
3674    }
3675
3676    Plugin.prototype.loadImages = function() {
3677        var t = this;
3678
3679        var imgs = t.parent.$obj.find('img').filter('[data-cbp-src]');
3680
3681        if (imgs.length === 0) {
3682            return;
3683        }
3684
3685        t.screenHeight = $window.height();
3686
3687        imgs.each(function(index, el) {
3688            var parentNode = $(el.parentNode);
3689
3690            if (!t.isElementInScreen(el)) {
3691                parentNode.addClass(t.options.loadingClass);
3692                return;
3693            }
3694
3695            var dataSrc = el.getAttribute('data-cbp-src');
3696
3697            if (t.parent.checkSrc($('<img>').attr('src', dataSrc)) === null) {
3698                t.removeLazyLoad(el, dataSrc);
3699                parentNode.removeClass(t.options.loadingClass);
3700            } else {
3701                parentNode.addClass(t.options.loadingClass);
3702                $('<img>').on('load.cbp error.cbp', function() {
3703                    t.removeLazyLoad(el, dataSrc, parentNode);
3704                }).attr('src', dataSrc); // for ie8
3705            }
3706        });
3707    };
3708
3709    Plugin.prototype.removeLazyLoad = function(el, dataSrc, parentNode) {
3710        var t = this;
3711
3712        el.src = dataSrc;
3713        el.removeAttribute('data-cbp-src');
3714        t.parent.removeAttrImage(el);
3715
3716        // trigger public event
3717        t.parent.$obj.trigger('lazyLoad.cbp', el);
3718
3719        if (parentNode) {
3720            if (CubePortfolio.private.modernBrowser) {
3721                $(el).one(CubePortfolio.private.transitionend, function() {
3722                    parentNode.removeClass(t.options.loadingClass);
3723                });
3724            } else {
3725                parentNode.removeClass(t.options.loadingClass);
3726            }
3727        }
3728    };
3729
3730    Plugin.prototype.isElementInScreen = function(el) {
3731        var t = this;
3732
3733        var bound = el.getBoundingClientRect();
3734        var bottom = bound.bottom + t.options.threshold;
3735        var screenHeight = t.screenHeight + bottom - (bound.top - t.options.threshold);
3736
3737        return bottom >= 0 && bottom <= screenHeight;
3738    };
3739
3740    Plugin.prototype.destroy = function() {
3741        CubePortfolio.private.lazyLoadScroll.destroyEvent(this);
3742    };
3743
3744    CubePortfolio.plugins.lazyLoad = function(parent) {
3745        return new Plugin(parent);
3746    };
3747})(jQuery, window, document);
3748(function($, window, document, undefined) {
3749    'use strict';
3750
3751    var options = {
3752        /**
3753         *  Define the wrapper for loadMore
3754         *  Values: strings that represent the elements in the document (DOM selector).
3755         */
3756        element: '',
3757
3758        /**
3759         *  How the loadMore functionality should behave. Load on click on the button or
3760         *  automatically when you scroll the page
3761         *  Values: - click
3762         *          - auto
3763         */
3764        action: 'click',
3765        /**
3766         * How many items to load when you click on the loadMore button
3767         * Values: positive integer
3768         */
3769        loadItems: 3,
3770    };
3771
3772    var CubePortfolio = $.fn.cubeportfolio.constructor;
3773
3774    function Plugin(parent) {
3775        var t = this;
3776
3777        t.parent = parent;
3778
3779        t.options = $.extend({}, options, t.parent.options.plugins.loadMore);
3780
3781        t.loadMore = $(t.options.element).find('.cbp-l-loadMore-link');
3782
3783        // load click or auto action
3784        if (t.loadMore.length === 0) {
3785            return;
3786        }
3787
3788        t.loadItems = t.loadMore.find('.cbp-l-loadMore-loadItems');
3789
3790        if (t.loadItems.text() === '0') {
3791            t.loadMore.addClass('cbp-l-loadMore-stop');
3792        }
3793
3794        parent.registerEvent('filterStart', function(filter) {
3795            t.populateItems().then(function() {
3796                var itemsLen = t.items.filter(t.parent.filterConcat(filter)).length;
3797
3798                if (itemsLen > 0) {
3799                    t.loadMore.removeClass('cbp-l-loadMore-stop');
3800                    t.loadItems.html(itemsLen);
3801                } else {
3802                    t.loadMore.addClass('cbp-l-loadMore-stop');
3803                }
3804            });
3805        });
3806
3807        t[t.options.action]();
3808    }
3809
3810    Plugin.prototype.populateItems = function() {
3811        var t = this;
3812
3813        if (t.items) {
3814            return $.Deferred().resolve();
3815        }
3816
3817        t.items = $();
3818
3819        // perform ajax request
3820        return $.ajax({
3821            url: t.loadMore.attr('href'),
3822            type: 'GET',
3823            dataType: 'HTML'
3824        }).done(function(result) {
3825            var resultFlat = $.map(result.split(/\r?\n/), function(item, index) {
3826                return $.trim(item);
3827            }).join('');
3828
3829            if (resultFlat.length === 0) {
3830                return;
3831            }
3832
3833            $.each($.parseHTML(resultFlat), function(index, el) {
3834                if ($(el).hasClass('cbp-item')) {
3835                    t.items = t.items.add(el);
3836                } else {
3837                    $.each(el.children, function(index, el2) {
3838                        if ($(el2).hasClass('cbp-item')) {
3839                            t.items = t.items.add(el2);
3840                        }
3841                    });
3842                }
3843            });
3844        }).fail(function() {
3845            t.items = null;
3846            t.loadMore.removeClass('cbp-l-loadMore-loading');
3847        });
3848    };
3849
3850    Plugin.prototype.populateInsertItems = function(callback) {
3851        var t = this;
3852        var insertItems = [];
3853        var filter = t.parent.defaultFilter;
3854
3855        var foundItem = 0;
3856        t.items.each(function(index, el) {
3857            if (foundItem === t.options.loadItems) {
3858                return false;
3859            }
3860
3861            if (!filter || (filter === '*')) {
3862                insertItems.push(el);
3863                t.items[index] = null;
3864
3865                foundItem++;
3866            } else {
3867                if ($(el).filter(t.parent.filterConcat(filter)).length) {
3868                    insertItems.push(el);
3869                    t.items[index] = null;
3870
3871                    foundItem++;
3872                }
3873            }
3874        });
3875
3876        t.items = t.items.map(function(index, el) {
3877            return el;
3878        });
3879
3880        // stop the loadMore
3881        if (insertItems.length === 0) {
3882            t.loadMore.removeClass('cbp-l-loadMore-loading').addClass('cbp-l-loadMore-stop');
3883            return;
3884        }
3885
3886        t.parent.$obj.cubeportfolio('append', insertItems, callback);
3887    }
3888
3889    Plugin.prototype.click = function() {
3890        var t = this;
3891
3892        t.loadMore.on('click.cbp', function(e) {
3893            e.preventDefault();
3894
3895            if (t.parent.isAnimating || t.loadMore.hasClass('cbp-l-loadMore-stop')) {
3896                return;
3897            }
3898
3899            // set loading status
3900            t.loadMore.addClass('cbp-l-loadMore-loading');
3901
3902            t.populateItems().then(function() {
3903                t.populateInsertItems(appendCallback);
3904            });
3905        });
3906
3907        function appendCallback() {
3908            // remove class from t.loadMore
3909            t.loadMore.removeClass('cbp-l-loadMore-loading');
3910
3911            var filter = t.parent.defaultFilter;
3912            var itemsInLoadMore;
3913
3914            if (!filter || (filter === '*')) {
3915                itemsInLoadMore = t.items.length;
3916            } else {
3917                itemsInLoadMore = t.items.filter(t.parent.filterConcat(filter)).length;
3918            }
3919
3920            // check if we have more loadMore
3921            if (itemsInLoadMore === 0) {
3922                t.loadMore.addClass('cbp-l-loadMore-stop');
3923            } else {
3924                t.loadItems.html(itemsInLoadMore);
3925            }
3926        }
3927    };
3928
3929    Plugin.prototype.auto = function() {
3930        var t = this;
3931        var $window = $(window);
3932        var isActive = false;
3933
3934        // add scroll event to page for loadMore
3935        CubePortfolio.private.loadMoreScroll = new CubePortfolio.private.publicEvents('scroll.loadMore', 100);
3936
3937        t.parent.$obj.one('initComplete.cbp', function() {
3938            // add events for scroll
3939            t.loadMore
3940                .addClass('cbp-l-loadMore-loading')
3941                .on('click.cbp', function(e) {
3942                    e.preventDefault();
3943                });
3944
3945            CubePortfolio.private.loadMoreScroll.initEvent({
3946                instance: t,
3947                fn: function() {
3948                    if (!t.parent.isAnimating) {
3949                        // get new items on scroll
3950                        getNewItems();
3951                    }
3952                }
3953            });
3954
3955            // when the filter is completed
3956            t.parent.$obj.on('filterComplete.cbp', function() {
3957                getNewItems();
3958            });
3959
3960            // trigger method
3961            getNewItems();
3962        });
3963
3964        function getNewItems() {
3965            if (isActive || t.loadMore.hasClass('cbp-l-loadMore-stop')) {
3966                return;
3967            }
3968
3969            // add a treshold
3970            var topLoadMore = t.loadMore.offset().top - 200;
3971            var topWindow = $window.scrollTop() + $window.height();
3972
3973            if (topLoadMore > topWindow) {
3974                return;
3975            }
3976
3977            // this job is now busy
3978            isActive = true;
3979
3980            t.populateItems().then(function() {
3981                t.populateInsertItems(appendCallback);
3982            }).fail(function() {
3983                // make the job inactive
3984                isActive = false;
3985            });
3986        }
3987
3988        function appendCallback() {
3989            var itemsInLoadMore;
3990            var filter = t.parent.defaultFilter;
3991
3992            if (!filter || (filter === '*')) {
3993                itemsInLoadMore = t.items.length;
3994            } else {
3995                itemsInLoadMore = t.items.filter(t.parent.filterConcat(filter)).length;
3996            }
3997
3998            // check if we have more loadMore
3999            if (itemsInLoadMore === 0) {
4000                t.loadMore.removeClass('cbp-l-loadMore-loading').addClass('cbp-l-loadMore-stop');
4001            } else {
4002                t.loadItems.html(itemsInLoadMore);
4003
4004                $window.trigger('scroll.loadMore');
4005            }
4006
4007            // make the job inactive
4008            isActive = false;
4009
4010            // remove events
4011            if (t.items.length === 0) {
4012                CubePortfolio.private.loadMoreScroll.destroyEvent(t);
4013                t.parent.$obj.off('filterComplete.cbp');
4014            }
4015        }
4016    };
4017
4018    Plugin.prototype.destroy = function() {
4019        this.loadMore.off('.cbp');
4020
4021        if (CubePortfolio.private.loadMoreScroll) {
4022            CubePortfolio.private.loadMoreScroll.destroyEvent(this);
4023        }
4024    };
4025
4026    CubePortfolio.plugins.loadMore = function(parent) {
4027        var plugins = parent.options.plugins;
4028
4029        // backward compatibility
4030        if (parent.options.loadMore) {
4031            if (!plugins.loadMore) {
4032                plugins.loadMore = {};
4033            }
4034
4035            plugins.loadMore.element = parent.options.loadMore;
4036        }
4037
4038        // backward compatibility
4039        if (parent.options.loadMoreAction) {
4040            if (!plugins.loadMore) {
4041                plugins.loadMore = {};
4042            }
4043
4044            plugins.loadMore.action = parent.options.loadMoreAction;
4045        }
4046
4047        // rename options
4048        if (plugins.loadMore && plugins.loadMore.selector !== undefined) {
4049            plugins.loadMore.element = plugins.loadMore.selector;
4050            delete plugins.loadMore.selector;
4051        }
4052
4053        if (!plugins.loadMore || !plugins.loadMore.element) {
4054            return null;
4055        }
4056
4057        return new Plugin(parent);
4058    };
4059})(jQuery, window, document);
4060(function($, window, document, undefined) {
4061    'use strict';
4062
4063    var CubePortfolio = $.fn.cubeportfolio.constructor;
4064
4065    var options = {
4066        delay: 0,
4067    };
4068
4069    var popup = {
4070        /**
4071         * init function for popup
4072         * @param cubeportfolio = cubeportfolio instance
4073         * @param type =  'lightbox' or 'singlePage'
4074         */
4075        init: function(cubeportfolio, type) {
4076            var t = this,
4077                currentBlock;
4078
4079            // remember cubeportfolio instance
4080            t.cubeportfolio = cubeportfolio;
4081
4082            // remember if this instance is for lightbox or for singlePage
4083            t.type = type;
4084
4085            // remember if the popup is open or not
4086            t.isOpen = false;
4087
4088            t.options = t.cubeportfolio.options;
4089
4090            if (type === 'lightbox') {
4091                t.cubeportfolio.registerEvent('resizeWindow', function() {
4092                    t.resizeImage();
4093                });
4094
4095                t.localOptions = $.extend({}, options, t.cubeportfolio.options.plugins.lightbox);
4096            }
4097
4098            if (type === 'singlePageInline') {
4099                t.height = 0;
4100
4101                // create markup, css and add events for SinglePageInline
4102                t.createMarkupSinglePageInline();
4103
4104                t.cubeportfolio.registerEvent('resizeGrid', function() {
4105                    if (t.isOpen) {
4106                        // @todo must add support for this features in the future
4107                        t.close(); // workaround
4108                    }
4109                });
4110
4111                if (t.options.singlePageInlineDeeplinking) {
4112                    t.url = location.href;
4113
4114                    if (t.url.slice(-1) === '#') {
4115                        t.url = t.url.slice(0, -1);
4116                    }
4117
4118                    var links = t.url.split('#cbpi=');
4119                    var url = links.shift(); // remove first item
4120
4121                    $.each(links, function(index, link) {
4122                        t.cubeportfolio.blocksOn.each(function(index1, el) {
4123                            var singlePageInline = $(el).find(t.options.singlePageInlineDelegate + '[href="' + link + '"]');
4124
4125                            if (singlePageInline.length) {
4126                                currentBlock = singlePageInline;
4127                                return false;
4128                            }
4129                        });
4130
4131                        if (currentBlock) {
4132                            return false;
4133                        }
4134                    });
4135
4136                    if (currentBlock) {
4137                        t.cubeportfolio.registerEvent('initFinish', function() {
4138                            t.openSinglePageInline(t.cubeportfolio.blocksOn, currentBlock[0]);
4139                        }, true);
4140                    }
4141                }
4142
4143                t.localOptions = $.extend({}, options, t.cubeportfolio.options.plugins.singlePageInline);
4144
4145                return;
4146            }
4147
4148            // create markup, css and add events for lightbox and singlePage
4149            t.createMarkup();
4150
4151            if (type === 'singlePage') {
4152                t.cubeportfolio.registerEvent('resizeWindow', function() {
4153                    if (t.options.singlePageStickyNavigation) {
4154
4155                        var width = t.contentWrap[0].clientWidth;
4156
4157                        if (width > 0) {
4158                            t.navigationWrap.width(width);
4159
4160                            // set navigation width='window width' to center the divs
4161                            t.navigation.width(width);
4162                        }
4163
4164                    }
4165                });
4166
4167                if (t.options.singlePageDeeplinking) {
4168                    t.url = location.href;
4169
4170                    if (t.url.slice(-1) === '#') {
4171                        t.url = t.url.slice(0, -1);
4172                    }
4173
4174                    var links = t.url.split('#cbp=');
4175                    var url = links.shift(); // remove first item
4176
4177                    $.each(links, function(index, link) {
4178                        t.cubeportfolio.blocksOn.each(function(index1, el) {
4179                            var singlePage = $(el).find(t.options.singlePageDelegate + '[href="' + link + '"]');
4180
4181                            if (singlePage.length) {
4182                                currentBlock = singlePage;
4183                                return false;
4184                            }
4185                        });
4186
4187                        if (currentBlock) {
4188                            return false;
4189                        }
4190                    });
4191
4192                    if (currentBlock) {
4193                        t.url = url;
4194
4195                        var self = currentBlock,
4196                            gallery = self.attr('data-cbp-singlePage'),
4197                            blocks = [];
4198
4199                        if (gallery) {
4200                            blocks = self.closest($('.cbp-item')).find('[data-cbp-singlePage="' + gallery + '"]');
4201                        } else {
4202                            t.cubeportfolio.blocksOn.each(function(index, el) {
4203                                var item = $(el);
4204
4205                                if (item.not('.cbp-item-off')) {
4206                                    item.find(t.options.singlePageDelegate).each(function(index2, el2) {
4207                                        if (!$(el2).attr('data-cbp-singlePage')) {
4208                                            blocks.push(el2);
4209                                        }
4210                                    });
4211                                }
4212                            });
4213                        }
4214
4215                        t.openSinglePage(blocks, currentBlock[0]);
4216                    } else if (links.length) { // @todo - hack to load items from loadMore
4217                        var fakeLink = document.createElement('a');
4218                        fakeLink.setAttribute('href', links[0]);
4219                        t.openSinglePage([fakeLink], fakeLink);
4220                    }
4221                }
4222
4223                t.localOptions = $.extend({}, options, t.cubeportfolio.options.plugins.singlePage);
4224            }
4225        },
4226
4227        /**
4228         * Create markup, css and add events
4229         */
4230        createMarkup: function() {
4231            var t = this,
4232                animationCls = '';
4233
4234            if (t.type === 'singlePage') {
4235                if (t.options.singlePageAnimation !== 'left') {
4236                    animationCls = ' cbp-popup-singlePage-' + t.options.singlePageAnimation;
4237                }
4238            }
4239
4240            // wrap element
4241            t.wrap = $('<div/>', {
4242                'class': 'cbp-popup-wrap cbp-popup-' + t.type + animationCls,
4243                'data-action': (t.type === 'lightbox') ? 'close' : ''
4244            }).on('click.cbp', function(e) {
4245                if (t.stopEvents) {
4246                    return;
4247                }
4248
4249                var action = $(e.target).attr('data-action');
4250
4251                if (t[action]) {
4252                    t[action]();
4253                    e.preventDefault();
4254                }
4255            });
4256
4257            if (t.type === 'singlePage') {
4258                t.contentWrap = $('<div/>', {
4259                    'class': 'cbp-popup-content-wrap'
4260                }).appendTo(t.wrap);
4261
4262                if (CubePortfolio.private.browser === 'ios') {
4263                    t.contentWrap.css('overflow', 'auto');
4264                }
4265
4266                // content element
4267                t.content = $('<div/>', {
4268                    'class': 'cbp-popup-content'
4269                }).appendTo(t.contentWrap);
4270            } else {
4271                // content element
4272                t.content = $('<div/>', {
4273                    'class': 'cbp-popup-content'
4274                }).appendTo(t.wrap);
4275            }
4276
4277            // append loading div
4278            $('<div/>', {
4279                'class': 'cbp-popup-loadingBox'
4280            }).appendTo(t.wrap);
4281
4282            // add background only for ie8
4283            if (CubePortfolio.private.browser === 'ie8') {
4284                t.bg = $('<div/>', {
4285                    'class': 'cbp-popup-ie8bg',
4286                    'data-action': (t.type === 'lightbox') ? 'close' : ''
4287                }).appendTo(t.wrap);
4288            }
4289
4290            if (t.type === 'singlePage') {
4291                if (t.options.singlePageStickyNavigation === false) {
4292                    // create navigation wrap
4293                    t.navigationWrap = $('<div/>', {
4294                        'class': 'cbp-popup-navigation-wrap'
4295                    }).appendTo(t.contentWrap);
4296                } else {
4297                    // create navigation wrap
4298                    t.navigationWrap = $('<div/>', {
4299                        'class': 'cbp-popup-navigation-wrap'
4300                    }).appendTo(t.wrap);
4301                }
4302            } else {
4303                // create navigation wrap
4304                t.navigationWrap = $('<div/>', {
4305                    'class': 'cbp-popup-navigation-wrap'
4306                }).appendTo(t.wrap);
4307            }
4308
4309            // create navigation block
4310            t.navigation = $('<div/>', {
4311                'class': 'cbp-popup-navigation'
4312            }).appendTo(t.navigationWrap);
4313
4314            // close
4315            t.closeButton = $('<div/>', {
4316                'class': 'cbp-popup-close',
4317                'title': 'Close (Esc arrow key)',
4318                'data-action': 'close'
4319            }).appendTo(t.navigation);
4320
4321            // next
4322            t.nextButton = $('<div/>', {
4323                'class': 'cbp-popup-next',
4324                'title': 'Next (Right arrow key)',
4325                'data-action': 'next'
4326            }).appendTo(t.navigation);
4327
4328
4329            // prev
4330            t.prevButton = $('<div/>', {
4331                'class': 'cbp-popup-prev',
4332                'title': 'Previous (Left arrow key)',
4333                'data-action': 'prev'
4334            }).appendTo(t.navigation);
4335
4336
4337            if (t.type === 'singlePage') {
4338                if (t.options.singlePageCounter) {
4339                    // counter for singlePage
4340                    t.counter = $(t.options.singlePageCounter).appendTo(t.navigation);
4341                    t.counter.text('');
4342                }
4343
4344                t.content.on('click.cbp', t.options.singlePageDelegate, function(e) {
4345                    e.preventDefault();
4346
4347                    var i,
4348                        len = t.dataArray.length,
4349                        href = this.getAttribute('href'),
4350                        indexFound;
4351
4352                    for (i = 0; i < len; i++) {
4353                        if (t.dataArray[i].url === href) {
4354                            indexFound = i;
4355                            break;
4356                        }
4357                    }
4358
4359                    if (indexFound === undefined) {
4360                        var fakeLink = document.createElement('a');
4361                        fakeLink.setAttribute('href', href);
4362
4363                        t.dataArray = [{
4364                            url: href,
4365                            element: fakeLink
4366                        }];
4367
4368                        // total numbers of elements
4369                        t.counterTotal = 1;
4370
4371                        t.nextButton.hide();
4372                        t.prevButton.hide();
4373
4374                        t.singlePageJumpTo(0);
4375                    } else {
4376                        t.singlePageJumpTo(indexFound - t.current);
4377                    }
4378
4379                });
4380
4381                // Test via a getter in the options object to see if the passive property is accessed
4382                // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
4383                var supportsOpts = false;
4384                try {
4385                    var opts = Object.defineProperty({}, 'passive', {
4386                        get: function() {
4387                            supportsOpts = { passive: true };
4388                        }
4389                    });
4390                    window.addEventListener('testPassive', null, opts);
4391                    window.removeEventListener('testPassive', null, opts);
4392                } catch (e) {}
4393
4394                // if there are some events than overrides the default wheel behaviour don't go to them
4395                // https://developer.mozilla.org/en-US/docs/Web/Events/wheel
4396                var wheel = 'onwheel' in document.createElement('div') ? 'wheel' : 'mousewheel';
4397                t.contentWrap[0].addEventListener(wheel, function(e) {
4398                    e.stopImmediatePropagation();
4399                }, supportsOpts);
4400            }
4401
4402            $(document).on('keydown.cbp', function(e) {
4403                // if is not open => return
4404                if (!t.isOpen) {
4405                    return;
4406                }
4407
4408                // if all events are stopped => return
4409                if (t.stopEvents) {
4410                    return;
4411                }
4412
4413                if (lightboxIsOpen) {
4414                    e.stopImmediatePropagation();
4415                }
4416
4417                if (e.keyCode === 37) { // prev key
4418                    t.prev();
4419                } else if (e.keyCode === 39) { // next key
4420                    t.next();
4421                } else if (e.keyCode === 27) { //esc key
4422                    t.close();
4423                }
4424            });
4425        },
4426
4427        createMarkupSinglePageInline: function() {
4428            var t = this;
4429
4430            // wrap element
4431            t.wrap = $('<div/>', {
4432                'class': 'cbp-popup-singlePageInline'
4433            }).on('click.cbp', function(e) {
4434                if (t.stopEvents) {
4435                    return;
4436                }
4437
4438                var action = $(e.target).attr('data-action');
4439
4440                if (action && t[action]) {
4441                    t[action]();
4442                    e.preventDefault();
4443                }
4444            });
4445
4446            // content element
4447            t.content = $('<div/>', {
4448                'class': 'cbp-popup-content'
4449            }).appendTo(t.wrap);
4450
4451            // append loading div
4452            // $('<div/>', {
4453            //     'class': 'cbp-popup-loadingBox'
4454            // }).appendTo(t.wrap);
4455
4456            // create navigation block
4457            t.navigation = $('<div/>', {
4458                'class': 'cbp-popup-navigation'
4459            }).appendTo(t.wrap);
4460
4461            // close
4462            t.closeButton = $('<div/>', {
4463                'class': 'cbp-popup-close',
4464                'title': 'Close (Esc arrow key)',
4465                'data-action': 'close'
4466            }).appendTo(t.navigation);
4467        },
4468
4469        destroy: function() {
4470            var t = this,
4471                body = $('body');
4472
4473            // remove off key down
4474            $(document).off('keydown.cbp');
4475
4476            // external lightbox and singlePageInline
4477            body.off('click.cbp', t.options.lightboxDelegate);
4478            body.off('click.cbp', t.options.singlePageDelegate);
4479
4480            t.content.off('click.cbp', t.options.singlePageDelegate);
4481
4482            t.cubeportfolio.$obj.off('click.cbp', t.options.singlePageInlineDelegate);
4483            t.cubeportfolio.$obj.off('click.cbp', t.options.lightboxDelegate);
4484            t.cubeportfolio.$obj.off('click.cbp', t.options.singlePageDelegate);
4485
4486            t.cubeportfolio.$obj.removeClass('cbp-popup-isOpening');
4487
4488            t.cubeportfolio.$obj.find('.cbp-item').removeClass('cbp-singlePageInline-active');
4489
4490            t.wrap.remove();
4491        },
4492
4493        openLightbox: function(blocks, currentBlock) {
4494            var t = this,
4495                i = 0,
4496                currentBlockHref, tempHref = [],
4497                element;
4498
4499            if (t.isOpen) {
4500                return;
4501            }
4502
4503            lightboxIsOpen = true;
4504
4505            // remember that the lightbox is open now
4506            t.isOpen = true;
4507
4508            // remember to stop all events after the lightbox has been shown
4509            t.stopEvents = false;
4510
4511            // array with elements
4512            t.dataArray = [];
4513
4514            // reset current
4515            t.current = null;
4516
4517            currentBlockHref = currentBlock.getAttribute('href');
4518            if (currentBlockHref === null) {
4519                throw new Error('HEI! Your clicked element doesn\'t have a href attribute.');
4520            }
4521
4522            $.each(blocks, function(index, item) {
4523                var href = item.getAttribute('href'),
4524                    src = href, // default if element is image
4525                    type = 'isImage', // default if element is image
4526                    videoLink;
4527
4528                if ($.inArray(href, tempHref) === -1) {
4529                    if (currentBlockHref === href) {
4530                        t.current = i;
4531                    } else if (!t.options.lightboxGallery) {
4532                        return;
4533                    }
4534
4535                    if (/youtu\.?be/i.test(href)) {
4536                        var indexVideo = href.lastIndexOf('v=') + 2;
4537
4538                        if (indexVideo === 1) {
4539                            indexVideo = href.lastIndexOf('/') + 1;
4540                        }
4541
4542                        videoLink = href.substring(indexVideo);
4543
4544                        if (!(/autoplay=/i.test(videoLink))) {
4545                            videoLink += '&autoplay=1';
4546                        }
4547
4548                        videoLink = videoLink.replace(/\?|&/, '?');
4549
4550                        // create new href
4551                        src = '//www.youtube.com/embed/' + videoLink;
4552
4553                        type = 'isYoutube';
4554                    } else if (/vimeo\.com/i.test(href)) {
4555                        videoLink = href.substring(href.lastIndexOf('/') + 1);
4556
4557                        if (!(/autoplay=/i.test(videoLink))) {
4558                            videoLink += '&autoplay=1';
4559                        }
4560
4561                        videoLink = videoLink.replace(/\?|&/, '?');
4562
4563                        // create new href
4564                        src = '//player.vimeo.com/video/' + videoLink;
4565
4566                        type = 'isVimeo';
4567                    } else if (/www\.ted\.com/i.test(href)) {
4568                        // create new href
4569                        src = 'http://embed.ted.com/talks/' + href.substring(href.lastIndexOf('/') + 1) + '.html';
4570
4571                        type = 'isTed';
4572                    } else if (/soundcloud\.com/i.test(href)) {
4573                        // create new href
4574                        src = href;
4575
4576                        type = 'isSoundCloud';
4577                    } else if (/(\.mp4)|(\.ogg)|(\.ogv)|(\.webm)/i.test(href)) {
4578                        if (href.indexOf('|') !== -1) {
4579                            // create new href
4580                            src = href.split('|');
4581                        } else {
4582                            // create new href
4583                            src = href.split('%7C');
4584                        }
4585
4586                        type = 'isSelfHostedVideo';
4587                    } else if (/\.mp3$/i.test(href)) {
4588                        src = href;
4589                        type = 'isSelfHostedAudio';
4590                    }
4591
4592                    t.dataArray.push({
4593                        src: src,
4594                        title: item.getAttribute(t.options.lightboxTitleSrc),
4595                        type: type
4596                    });
4597
4598                    i++;
4599                }
4600
4601                tempHref.push(href);
4602            });
4603
4604            // total numbers of elements
4605            t.counterTotal = t.dataArray.length;
4606
4607            if (t.counterTotal === 1) {
4608                t.nextButton.hide();
4609                t.prevButton.hide();
4610                t.dataActionImg = '';
4611            } else {
4612                t.nextButton.show();
4613                t.prevButton.show();
4614                t.dataActionImg = 'data-action="next"';
4615            }
4616
4617            // append to body
4618            t.wrap.appendTo(document.body);
4619
4620            t.scrollTop = $(window).scrollTop();
4621
4622            t.originalStyle = $('html').attr('style');
4623
4624            $('html').css({
4625                overflow: 'hidden',
4626                marginRight: window.innerWidth - $(document).width()
4627            });
4628
4629            t.wrap.addClass('cbp-popup-transitionend');
4630
4631            // show the wrapper (lightbox box)
4632            t.wrap.show();
4633
4634            // get the current element
4635            element = t.dataArray[t.current];
4636
4637            // call function if current element is image or video (iframe)
4638            t[element.type](element);
4639        },
4640
4641        openSinglePage: function(blocks, currentBlock) {
4642            var t = this,
4643                i = 0,
4644                currentBlockHref, tempHref = [];
4645
4646            if (t.isOpen) {
4647                return;
4648            }
4649
4650            // check singlePageInline and close it
4651            if (t.cubeportfolio.singlePageInline && t.cubeportfolio.singlePageInline.isOpen) {
4652                t.cubeportfolio.singlePageInline.close();
4653            }
4654
4655            // remember that the lightbox is open now
4656            t.isOpen = true;
4657
4658            // remember to stop all events after the popup has been showing
4659            t.stopEvents = false;
4660
4661            // array with elements
4662            t.dataArray = [];
4663
4664            // reset current
4665            t.current = null;
4666
4667            currentBlockHref = currentBlock.getAttribute('href');
4668            if (currentBlockHref === null) {
4669                throw new Error('HEI! Your clicked element doesn\'t have a href attribute.');
4670            }
4671
4672            $.each(blocks, function(index, item) {
4673                var href = item.getAttribute('href');
4674
4675                if ($.inArray(href, tempHref) === -1) {
4676                    if (currentBlockHref === href) {
4677                        t.current = i;
4678                    }
4679
4680                    t.dataArray.push({
4681                        url: href,
4682                        element: item
4683                    });
4684
4685                    i++;
4686                }
4687
4688                tempHref.push(href);
4689            });
4690
4691            // total numbers of elements
4692            t.counterTotal = t.dataArray.length;
4693
4694            if (t.counterTotal === 1) {
4695                t.nextButton.hide();
4696                t.prevButton.hide();
4697            } else {
4698                t.nextButton.show();
4699                t.prevButton.show();
4700            }
4701
4702            // append to body
4703            t.wrap.appendTo(document.body);
4704
4705            t.scrollTop = $(window).scrollTop();
4706
4707            // go to top of the page (reset scroll)
4708            t.contentWrap.scrollTop(0);
4709
4710            // show the wrapper
4711            t.wrap.show();
4712
4713            // finish the open animation
4714            t.finishOpen = 2;
4715
4716            // if transitionend is not fulfilled
4717            t.navigationMobile = $();
4718            t.wrap.one(CubePortfolio.private.transitionend, function() {
4719                $('html').css({
4720                    overflow: 'hidden',
4721                    marginRight: window.innerWidth - $(document).width()
4722                });
4723
4724                t.wrap.addClass('cbp-popup-transitionend');
4725
4726                // make the navigation sticky
4727                if (t.options.singlePageStickyNavigation) {
4728
4729                    t.wrap.addClass('cbp-popup-singlePage-sticky');
4730                    t.navigationWrap.width(t.contentWrap[0].clientWidth);
4731                }
4732
4733                t.finishOpen--;
4734
4735                if (t.finishOpen <= 0) {
4736                    t.updateSinglePageIsOpen.call(t);
4737                }
4738            });
4739
4740            if (CubePortfolio.private.browser === 'ie8' || CubePortfolio.private.browser === 'ie9') {
4741                $('html').css({
4742                    overflow: 'hidden',
4743                    marginRight: window.innerWidth - $(document).width()
4744                });
4745
4746                t.wrap.addClass('cbp-popup-transitionend');
4747
4748                // make the navigation sticky
4749                if (t.options.singlePageStickyNavigation) {
4750                    t.navigationWrap.width(t.contentWrap[0].clientWidth);
4751
4752                    setTimeout(function() {
4753                        t.wrap.addClass('cbp-popup-singlePage-sticky');
4754                    }, 1000);
4755                }
4756
4757                t.finishOpen--;
4758            }
4759
4760            t.wrap.addClass('cbp-popup-loading');
4761
4762            // force reflow and then add class
4763            t.wrap.offset();
4764            t.wrap.addClass('cbp-popup-singlePage-open');
4765
4766            // change link
4767            if (t.options.singlePageDeeplinking) {
4768                // ignore old #cbp from href
4769                t.url = t.url.split('#cbp=')[0];
4770                location.href = t.url + '#cbp=' + t.dataArray[t.current].url;
4771            }
4772
4773            // run callback function
4774            if ($.isFunction(t.options.singlePageCallback)) {
4775                t.options.singlePageCallback.call(t, t.dataArray[t.current].url, t.dataArray[t.current].element);
4776            }
4777
4778            // ios bug to prevent
4779            // http://stackoverflow.com/questions/9280258/prevent-body-scrolling-but-allow-overlay-scrolling
4780            if (CubePortfolio.private.browser === 'ios') {
4781                var element = t.contentWrap[0];
4782
4783                element.addEventListener('touchstart', function() {
4784                    var top = element.scrollTop,
4785                        totalScroll = element.scrollHeight,
4786                        currentScroll = top + element.offsetHeight;
4787
4788                    if (top === 0) {
4789                        element.scrollTop = 1;
4790                    } else if (currentScroll === totalScroll) {
4791                        element.scrollTop = top - 1;
4792                    }
4793                });
4794            }
4795        },
4796
4797        openSinglePageInline: function(blocks, currentBlock, fromOpen) {
4798            var t = this,
4799                start = 0,
4800                currentBlockHref,
4801                tempCurrent,
4802                cbpitem,
4803                parentElement;
4804
4805            fromOpen = fromOpen || false;
4806
4807            t.fromOpen = fromOpen;
4808
4809            t.storeBlocks = blocks;
4810            t.storeCurrentBlock = currentBlock;
4811
4812            // check singlePageInline and close it
4813            if (t.isOpen) {
4814                tempCurrent = t.cubeportfolio.blocksOn.index($(currentBlock).closest('.cbp-item'));
4815
4816                if ((t.dataArray[t.current].url !== currentBlock.getAttribute('href')) || (t.current !== tempCurrent)) {
4817                    t.cubeportfolio.singlePageInline.close('open', {
4818                        blocks: blocks,
4819                        currentBlock: currentBlock,
4820                        fromOpen: true
4821                    });
4822                } else {
4823                    t.close();
4824                }
4825
4826                return;
4827            }
4828
4829            // remember that the lightbox is open now
4830            t.isOpen = true;
4831
4832            // remember to stop all events after the popup has been showing
4833            t.stopEvents = false;
4834
4835            // array with elements
4836            t.dataArray = [];
4837
4838            // reset current
4839            t.current = null;
4840
4841            currentBlockHref = currentBlock.getAttribute('href');
4842            if (currentBlockHref === null) {
4843                throw new Error('HEI! Your clicked element doesn\'t have a href attribute.');
4844            }
4845
4846            cbpitem = $(currentBlock).closest('.cbp-item')[0];
4847
4848            blocks.each(function(index, el) {
4849                if (cbpitem === el) {
4850                    t.current = index;
4851                }
4852            });
4853
4854            t.dataArray[t.current] = {
4855                url: currentBlockHref,
4856                element: currentBlock
4857            };
4858
4859            parentElement = $(t.dataArray[t.current].element).parents('.cbp-item').addClass('cbp-singlePageInline-active');
4860
4861            // total numbers of elements
4862            t.counterTotal = blocks.length;
4863
4864            t.wrap.insertBefore(t.cubeportfolio.wrapper);
4865
4866            t.topDifference = 0;
4867
4868            if (t.options.singlePageInlinePosition === 'top') {
4869                t.blocksToMove = blocks;
4870                t.top = 0;
4871            } else if (t.options.singlePageInlinePosition === 'bottom') {
4872                t.blocksToMove = $();
4873                t.top = t.cubeportfolio.height;
4874            } else if (t.options.singlePageInlinePosition === 'above') {
4875                var top = $(blocks[t.current]).data('cbp').top;
4876                t.top = top;
4877
4878                // set the top value
4879                blocks.each(function(index, block) {
4880                    var data = $(block).data('cbp');
4881                    var topBlock = data.top;
4882                    var bottomBlock = topBlock + data.heightAndGap;
4883
4884                    if (topBlock >= top) {
4885                        return;
4886                    }
4887
4888                    if (bottomBlock > t.top) {
4889                        t.top = bottomBlock;
4890                        t.topDifference = t.top - top;
4891                    }
4892                });
4893
4894                // set moving blocks
4895                t.blocksToMove = $();
4896                blocks.each(function(index, block) {
4897                    if (index === t.current) {
4898                        t.blocksToMove = t.blocksToMove.add(block);
4899                        return;
4900                    }
4901
4902                    var data = $(block).data('cbp');
4903                    var bottomBlock = data.top + data.heightAndGap;
4904
4905                    if (bottomBlock > t.top) {
4906                        t.blocksToMove = t.blocksToMove.add(block);
4907                    }
4908                });
4909
4910                t.top = Math.max(t.top - t.options.gapHorizontal, 0);
4911            } else { // below
4912                var currentEl = $(blocks[t.current]);
4913                var data = currentEl.data('cbp');
4914                var end = data.top + data.heightAndGap;
4915
4916                t.top = end;
4917
4918                t.blocksToMove = $();
4919
4920                blocks.each(function(index, block) {
4921                    var data = $(block).data('cbp');
4922                    var topEl = data.top;
4923                    var endEl = topEl + data.height;
4924
4925                    if (endEl <= end) {
4926                        return;
4927                    }
4928
4929                    if (topEl >= (end - data.height / 2)) {
4930                        t.blocksToMove = t.blocksToMove.add(block);
4931                        return;
4932                    }
4933
4934                    if ((endEl > end) && (topEl < end)) {
4935                        if (endEl > t.top) {
4936                            t.top = endEl;
4937                        }
4938
4939                        if ((endEl - end) > t.topDifference) {
4940                            t.topDifference = endEl - end;
4941                        }
4942                    }
4943                });
4944            }
4945
4946            t.wrap[0].style.height = t.wrap.outerHeight(true) + 'px';
4947
4948            // debouncer for inline content
4949            t.deferredInline = $.Deferred();
4950
4951            if (t.options.singlePageInlineInFocus) {
4952                t.scrollTop = $(window).scrollTop();
4953
4954                var goToScroll = t.cubeportfolio.$obj.offset().top + t.top - 100;
4955
4956                if (t.scrollTop !== goToScroll) {
4957                    $('html,body').animate({
4958                            scrollTop: goToScroll
4959                        }, 350)
4960                        .promise()
4961                        .then(function() {
4962                            t.resizeSinglePageInline();
4963                            t.deferredInline.resolve();
4964                        });
4965                } else {
4966                    t.resizeSinglePageInline();
4967                    t.deferredInline.resolve();
4968                }
4969            } else {
4970                t.resizeSinglePageInline();
4971                t.deferredInline.resolve();
4972            }
4973
4974            t.cubeportfolio.$obj.addClass('cbp-popup-singlePageInline-open');
4975
4976            t.wrap.css({
4977                top: t.top
4978            });
4979
4980            // change link
4981            if (t.options.singlePageInlineDeeplinking) {
4982                // ignore old #cbpi from href
4983                t.url = t.url.split('#cbpi=')[0];
4984                location.href = t.url + '#cbpi=' + t.dataArray[t.current].url;
4985            }
4986
4987            // register callback function
4988            if ($.isFunction(t.options.singlePageInlineCallback)) {
4989                t.options.singlePageInlineCallback.call(t, t.dataArray[t.current].url, t.dataArray[t.current].element);
4990            }
4991        },
4992
4993        resizeSinglePageInline: function() {
4994            var t = this;
4995
4996            t.height = ((t.top === 0) || (t.top === t.cubeportfolio.height)) ? t.wrap.outerHeight(true) : t.wrap.outerHeight(true) - t.options.gapHorizontal;
4997
4998            t.height += t.topDifference;
4999
5000            t.storeBlocks.each(function(index, el) {
5001                if (CubePortfolio.private.modernBrowser) {
5002                    el.style[CubePortfolio.private.transform] = '';
5003                } else {
5004                    el.style.marginTop = '';
5005                }
5006            });
5007
5008            t.blocksToMove.each(function(index, el) {
5009                if (CubePortfolio.private.modernBrowser) {
5010                    el.style[CubePortfolio.private.transform] = 'translate3d(0px, ' + t.height + 'px, 0)';
5011                } else {
5012                    el.style.marginTop = t.height + 'px';
5013                }
5014            });
5015
5016            t.cubeportfolio.obj.style.height = t.cubeportfolio.height + t.height + 'px';
5017        },
5018
5019        revertResizeSinglePageInline: function() {
5020            var t = this;
5021
5022            // reset deferred object
5023            t.deferredInline = $.Deferred();
5024
5025            t.storeBlocks.each(function(index, el) {
5026                if (CubePortfolio.private.modernBrowser) {
5027                    el.style[CubePortfolio.private.transform] = '';
5028                } else {
5029                    el.style.marginTop = '';
5030                }
5031            });
5032
5033            t.cubeportfolio.obj.style.height = t.cubeportfolio.height + 'px';
5034        },
5035
5036        appendScriptsToWrap: function(scripts) {
5037            var t = this,
5038                index = 0,
5039                loadScripts = function(item) {
5040                    var script = document.createElement('script'),
5041                        src = item.src;
5042
5043                    script.type = 'text/javascript';
5044
5045                    if (script.readyState) { // ie
5046                        script.onreadystatechange = function() {
5047                            if (script.readyState == 'loaded' || script.readyState == 'complete') {
5048                                script.onreadystatechange = null;
5049                                index++;
5050                                if (scripts[index]) {
5051                                    loadScripts(scripts[index]);
5052                                }
5053                            }
5054                        };
5055                    } else {
5056                        script.onload = function() {
5057                            index++;
5058                            if (scripts[index]) {
5059                                loadScripts(scripts[index]);
5060                            }
5061                        };
5062                    }
5063
5064                    if (src) {
5065                        script.src = src;
5066                    } else {
5067                        script.text = item.text;
5068                    }
5069
5070                    t.content[0].appendChild(script);
5071
5072                };
5073
5074            loadScripts(scripts[0]);
5075        },
5076
5077        updateSinglePage: function(html, scripts, isWrap) {
5078            var t = this,
5079                counterMarkup,
5080                animationFinish;
5081
5082            t.content.addClass('cbp-popup-content').removeClass('cbp-popup-content-basic');
5083
5084            if (isWrap === false) {
5085                t.content.removeClass('cbp-popup-content').addClass('cbp-popup-content-basic');
5086            }
5087
5088            // update counter navigation
5089            if (t.counter) {
5090                counterMarkup = $(t.getCounterMarkup(t.options.singlePageCounter, t.current + 1, t.counterTotal));
5091                t.counter.text(counterMarkup.text());
5092            }
5093
5094            t.fromAJAX = {
5095                html: html,
5096                scripts: scripts
5097            };
5098
5099            t.finishOpen--;
5100
5101            if (t.finishOpen <= 0) {
5102                t.updateSinglePageIsOpen.call(t);
5103            }
5104        },
5105
5106        updateSinglePageIsOpen: function() {
5107            var t = this,
5108                selectorSlider;
5109
5110            t.wrap.addClass('cbp-popup-ready');
5111            t.wrap.removeClass('cbp-popup-loading');
5112
5113            t.content.html(t.fromAJAX.html);
5114
5115            if (t.fromAJAX.scripts) {
5116                t.appendScriptsToWrap(t.fromAJAX.scripts);
5117            }
5118
5119            t.fromAJAX = {};
5120
5121
5122            // trigger public event
5123            t.cubeportfolio.$obj.trigger('updateSinglePageStart.cbp');
5124
5125            // instantiate slider if exists
5126            selectorSlider = t.content.find('.cbp-slider');
5127            if (selectorSlider.length) {
5128                selectorSlider.find('.cbp-slider-item').addClass('cbp-item');
5129                t.slider = selectorSlider.cubeportfolio({
5130                    layoutMode: 'slider',
5131                    mediaQueries: [{
5132                        width: 1,
5133                        cols: 1
5134                    }],
5135                    gapHorizontal: 0,
5136                    gapVertical: 0,
5137                    caption: '',
5138                    coverRatio: '', // wp version only
5139                });
5140            } else {
5141                t.slider = null;
5142            }
5143
5144            // check for social share icons
5145            t.checkForSocialLinks(t.content);
5146
5147            // trigger public event
5148            t.cubeportfolio.$obj.trigger('updateSinglePageComplete.cbp');
5149        },
5150
5151        checkForSocialLinks: function(content) {
5152            var t = this;
5153
5154            t.createFacebookShare(content.find('.cbp-social-fb'));
5155            t.createTwitterShare(content.find('.cbp-social-twitter'));
5156            t.createGooglePlusShare(content.find('.cbp-social-googleplus'));
5157            t.createPinterestShare(content.find('.cbp-social-pinterest'));
5158        },
5159
5160        createFacebookShare: function(item) {
5161            if (item.length && !item.attr('onclick')) {
5162                item.attr('onclick', "window.open('http://www.facebook.com/sharer.php?u=" + encodeURIComponent(window.location.href) + "', '_blank', 'top=100,left=100,toolbar=0,status=0,width=620,height=400'); return false;");
5163            }
5164        },
5165
5166        createTwitterShare: function(item) {
5167            if (item.length && !item.attr('onclick')) {
5168                item.attr('onclick', "window.open('https://twitter.com/intent/tweet?source=" + encodeURIComponent(window.location.href) + "&text=" + encodeURIComponent(document.title) + "', '_blank', 'top=100,left=100,toolbar=0,status=0,width=620,height=300'); return false;");
5169            }
5170        },
5171
5172        createGooglePlusShare: function(item) {
5173            if (item.length && !item.attr('onclick')) {
5174                item.attr('onclick', "window.open('https://plus.google.com/share?url=" + encodeURIComponent(window.location.href) + "', '_blank', 'top=100,left=100,toolbar=0,status=0,width=620,height=450'); return false;");
5175            }
5176        },
5177
5178        createPinterestShare: function(item) {
5179            if (item.length && !item.attr('onclick')) {
5180                var media = '';
5181                var firstImg = this.content.find('img')[0];
5182
5183                if (firstImg) {
5184                    media = firstImg.src;
5185                }
5186
5187                item.attr('onclick', "window.open('http://pinterest.com/pin/create/button/?url=" + encodeURIComponent(window.location.href) + "&media=" + media + "', '_blank', 'top=100,left=100,toolbar=0,status=0,width=620,height=400'); return false;");
5188            }
5189        },
5190
5191        updateSinglePageInline: function(html, scripts) {
5192            var t = this;
5193
5194            t.content.html(html);
5195
5196            if (scripts) {
5197                t.appendScriptsToWrap(scripts);
5198            }
5199
5200            // trigger public event
5201            t.cubeportfolio.$obj.trigger('updateSinglePageInlineStart.cbp');
5202
5203            if (t.localOptions.delay !== 0) {
5204                setTimeout(function() {
5205                    t.singlePageInlineIsOpen.call(t);
5206                }, t.localOptions.delay)
5207            } else {
5208                t.singlePageInlineIsOpen.call(t);
5209            }
5210        },
5211
5212        singlePageInlineIsOpen: function() {
5213            var t = this;
5214
5215            function finishLoading() {
5216                t.wrap.addClass('cbp-popup-singlePageInline-ready');
5217                t.wrap[0].style.height = '';
5218
5219                t.resizeSinglePageInline();
5220
5221                // trigger public event
5222                t.cubeportfolio.$obj.trigger('updateSinglePageInlineComplete.cbp');
5223            }
5224
5225            // wait to load all images
5226            t.cubeportfolio.loadImages(t.wrap, function() {
5227                // instantiate slider if exists
5228                var selectorSlider = t.content.find('.cbp-slider');
5229
5230                if (selectorSlider.length) {
5231                    selectorSlider.find('.cbp-slider-item').addClass('cbp-item');
5232
5233                    selectorSlider.one('initComplete.cbp', function() {
5234                        t.deferredInline.done(finishLoading);
5235                    });
5236
5237                    selectorSlider.on('pluginResize.cbp', function() {
5238                        t.deferredInline.done(finishLoading);
5239                    });
5240
5241                    t.slider = selectorSlider.cubeportfolio({
5242                        layoutMode: 'slider',
5243                        displayType: 'default',
5244                        mediaQueries: [{
5245                            width: 1,
5246                            cols: 1
5247                        }],
5248                        gapHorizontal: 0,
5249                        gapVertical: 0,
5250                        caption: '',
5251                        coverRatio: '', // wp version only
5252                    });
5253                } else {
5254                    t.slider = null;
5255                    t.deferredInline.done(finishLoading);
5256                }
5257
5258                // check for social share icons
5259                t.checkForSocialLinks(t.content);
5260            });
5261        },
5262
5263        isImage: function(el) {
5264            var t = this,
5265                img = new Image();
5266
5267            t.tooggleLoading(true);
5268
5269            t.cubeportfolio.loadImages($('<div><img src="' + el.src + '"></div>'), function() {
5270                t.updateImagesMarkup(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5271
5272                t.tooggleLoading(false);
5273            });
5274        },
5275
5276        isVimeo: function(el) {
5277            var t = this;
5278            t.updateVideoMarkup(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5279        },
5280
5281        isYoutube: function(el) {
5282            var t = this;
5283            t.updateVideoMarkup(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5284        },
5285
5286        isTed: function(el) {
5287            var t = this;
5288            t.updateVideoMarkup(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5289        },
5290
5291        isSoundCloud: function(el) {
5292            var t = this;
5293            t.updateVideoMarkup(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5294        },
5295
5296        isSelfHostedVideo: function(el) {
5297            var t = this;
5298            t.updateSelfHostedVideo(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5299        },
5300
5301        isSelfHostedAudio: function(el) {
5302            var t = this;
5303            t.updateSelfHostedAudio(el.src, el.title, t.getCounterMarkup(t.options.lightboxCounter, t.current + 1, t.counterTotal));
5304        },
5305
5306        getCounterMarkup: function(markup, current, total) {
5307            if (!markup.length) {
5308                return '';
5309            }
5310
5311            var mapObj = {
5312                current: current,
5313                total: total
5314            };
5315
5316            return markup.replace(/\{\{current}}|\{\{total}}/gi, function(matched) {
5317                return mapObj[matched.slice(2, -2)];
5318            });
5319        },
5320
5321        updateSelfHostedVideo: function(src, title, counter) {
5322            var t = this,
5323                i;
5324
5325            t.wrap.addClass('cbp-popup-lightbox-isIframe');
5326
5327            var markup = '<div class="cbp-popup-lightbox-iframe">' +
5328                '<video controls="controls" height="auto" style="width: 100%">';
5329
5330            for (i = 0; i < src.length; i++) {
5331                if (/(\.mp4)/i.test(src[i])) {
5332                    markup += '<source src="' + src[i] + '" type="video/mp4">';
5333                } else if (/(\.ogg)|(\.ogv)/i.test(src[i])) {
5334                    markup += '<source src="' + src[i] + '" type="video/ogg">';
5335                } else if (/(\.webm)/i.test(src[i])) {
5336                    markup += '<source src="' + src[i] + '" type="video/webm">';
5337                }
5338            }
5339
5340            markup += 'Your browser does not support the video tag.' +
5341                '</video>' +
5342                '<div class="cbp-popup-lightbox-bottom">' +
5343                ((title) ? '<div class="cbp-popup-lightbox-title">' + title + '</div>' : '') +
5344                counter +
5345                '</div>' +
5346                '</div>';
5347
5348            t.content.html(markup);
5349            t.wrap.addClass('cbp-popup-ready');
5350            t.preloadNearbyImages();
5351        },
5352
5353        updateSelfHostedAudio: function(src, title, counter) {
5354            var t = this,
5355                i;
5356
5357            t.wrap.addClass('cbp-popup-lightbox-isIframe');
5358
5359            var markup = '<div class="cbp-popup-lightbox-iframe">' +
5360                '<div class="cbp-misc-video"><audio controls="controls" height="auto" style="width: 75%">' +
5361                '<source src="' + src + '" type="audio/mpeg">' +
5362                'Your browser does not support the audio tag.' +
5363                '</audio></div>' +
5364                '<div class="cbp-popup-lightbox-bottom">' +
5365                ((title) ? '<div class="cbp-popup-lightbox-title">' + title + '</div>' : '') +
5366                counter +
5367                '</div>' +
5368                '</div>';
5369
5370            t.content.html(markup);
5371            t.wrap.addClass('cbp-popup-ready');
5372            t.preloadNearbyImages();
5373        },
5374
5375        updateVideoMarkup: function(src, title, counter) {
5376            var t = this;
5377            t.wrap.addClass('cbp-popup-lightbox-isIframe');
5378
5379            var markup = '<div class="cbp-popup-lightbox-iframe">' +
5380                '<iframe src="' + src + '" frameborder="0" allowfullscreen scrolling="no"></iframe>' +
5381                '<div class="cbp-popup-lightbox-bottom">' +
5382                ((title) ? '<div class="cbp-popup-lightbox-title">' + title + '</div>' : '') +
5383                counter +
5384                '</div>' +
5385                '</div>';
5386
5387            t.content.html(markup);
5388            t.wrap.addClass('cbp-popup-ready');
5389            t.preloadNearbyImages();
5390        },
5391
5392        updateImagesMarkup: function(src, title, counter) {
5393            var t = this;
5394
5395            t.wrap.removeClass('cbp-popup-lightbox-isIframe');
5396
5397            var markup = '<div class="cbp-popup-lightbox-figure">' +
5398                '<img src="' + src + '" class="cbp-popup-lightbox-img" ' + t.dataActionImg + ' />' +
5399                '<div class="cbp-popup-lightbox-bottom">' +
5400                ((title) ? '<div class="cbp-popup-lightbox-title">' + title + '</div>' : '') +
5401                counter +
5402                '</div>' +
5403                '</div>';
5404
5405            t.content.html(markup);
5406            t.wrap.addClass('cbp-popup-ready');
5407            t.resizeImage();
5408            t.preloadNearbyImages();
5409        },
5410
5411        next: function() {
5412            var t = this;
5413            t[t.type + 'JumpTo'](1);
5414        },
5415
5416        prev: function() {
5417            var t = this;
5418            t[t.type + 'JumpTo'](-1);
5419        },
5420
5421        lightboxJumpTo: function(index) {
5422            var t = this,
5423                el;
5424
5425            t.current = t.getIndex(t.current + index);
5426
5427            // get the current element
5428            el = t.dataArray[t.current];
5429
5430            // call function if current element is image or video (iframe)
5431            t[el.type](el);
5432        },
5433
5434        singlePageJumpTo: function(index) {
5435            var t = this;
5436
5437            t.current = t.getIndex(t.current + index);
5438
5439            // register singlePageCallback function
5440            if ($.isFunction(t.options.singlePageCallback)) {
5441                t.resetWrap();
5442
5443                // go to top of the page (reset scroll)
5444                t.contentWrap.scrollTop(0);
5445
5446                t.wrap.addClass('cbp-popup-loading');
5447
5448                if (t.slider) {
5449                    CubePortfolio.private.resize.destroyEvent($.data(t.slider[0], 'cubeportfolio'));
5450                }
5451
5452                t.options.singlePageCallback.call(t, t.dataArray[t.current].url, t.dataArray[t.current].element);
5453
5454                if (t.options.singlePageDeeplinking) {
5455                    location.href = t.url + '#cbp=' + t.dataArray[t.current].url;
5456                }
5457            }
5458        },
5459
5460        resetWrap: function() {
5461            var t = this;
5462
5463            if (t.type === 'singlePage' && t.options.singlePageDeeplinking) {
5464                location.href = t.url + '#';
5465            }
5466
5467            if (t.type === 'singlePageInline' && t.options.singlePageInlineDeeplinking) {
5468                location.href = t.url + '#';
5469            }
5470        },
5471
5472        getIndex: function(index) {
5473            var t = this;
5474
5475            // go to interval [0, (+ or -)this.counterTotal.length - 1]
5476            index = index % t.counterTotal;
5477
5478            // if index is less then 0 then go to interval (0, this.counterTotal - 1]
5479            if (index < 0) {
5480                index = t.counterTotal + index;
5481            }
5482
5483            return index;
5484        },
5485
5486        close: function(method, data) {
5487            var t = this;
5488
5489            function finishClose() {
5490                // remove resize event
5491                if (t.slider) {
5492                    CubePortfolio.private.resize.destroyEvent($.data(t.slider[0], 'cubeportfolio'));
5493                }
5494
5495                // reset content
5496                t.content.html('');
5497
5498                // hide the wrap
5499                t.wrap.detach();
5500
5501                t.cubeportfolio.$obj.removeClass('cbp-popup-singlePageInline-open cbp-popup-singlePageInline-close');
5502
5503                // now the popup is closed
5504                t.isOpen = false;
5505
5506                if (method === 'promise') {
5507                    if ($.isFunction(data.callback)) {
5508                        data.callback.call(t.cubeportfolio);
5509                    }
5510                }
5511            }
5512
5513            function checkFocusInline() {
5514                // add this to prevent the page to jump after the resetWrap
5515                var scrollTop = $(window).scrollTop();
5516                t.resetWrap();
5517                $(window).scrollTop(scrollTop);
5518
5519                if (t.options.singlePageInlineInFocus && method !== 'promise') {
5520                    $('html,body').animate({
5521                            scrollTop: t.scrollTop
5522                        }, 350)
5523                        .promise()
5524                        .then(function() {
5525                            finishClose();
5526                        });
5527                } else {
5528                    finishClose();
5529                }
5530            }
5531
5532            if (t.type === 'singlePageInline') {
5533                if (method === 'open') {
5534                    t.wrap.removeClass('cbp-popup-singlePageInline-ready');
5535                    $(t.dataArray[t.current].element).closest('.cbp-item').removeClass('cbp-singlePageInline-active');
5536
5537                    // now the popup is closed
5538                    t.isOpen = false;
5539
5540                    t.openSinglePageInline(data.blocks, data.currentBlock, data.fromOpen);
5541                } else {
5542                    t.height = 0;
5543
5544                    t.revertResizeSinglePageInline();
5545                    t.wrap.removeClass('cbp-popup-singlePageInline-ready');
5546                    t.cubeportfolio.$obj.addClass('cbp-popup-singlePageInline-close');
5547                    t.cubeportfolio.$obj.find('.cbp-item').removeClass('cbp-singlePageInline-active');
5548
5549                    if (CubePortfolio.private.modernBrowser) {
5550                        t.wrap.one(CubePortfolio.private.transitionend, function() {
5551                            checkFocusInline();
5552                        });
5553                    } else {
5554                        checkFocusInline();
5555                    }
5556                }
5557
5558            } else if (t.type === 'singlePage') {
5559                t.resetWrap();
5560
5561                t.stopScroll = true;
5562
5563                t.wrap.removeClass('cbp-popup-ready cbp-popup-transitionend cbp-popup-singlePage-open cbp-popup-singlePage-sticky');
5564
5565                $('html').css({
5566                    overflow: '',
5567                    marginRight: '',
5568                    position: ''
5569                });
5570
5571                $(window).scrollTop(t.scrollTop);
5572
5573                if (CubePortfolio.private.browser === 'ie8' || CubePortfolio.private.browser === 'ie9') {
5574                    // remove resize event
5575                    if (t.slider) {
5576                        CubePortfolio.private.resize.destroyEvent($.data(t.slider[0], 'cubeportfolio'));
5577                    }
5578
5579                    // reset content
5580                    t.content.html('');
5581
5582                    // hide the wrap
5583                    t.wrap.detach();
5584
5585                    // now the popup is closed
5586                    t.isOpen = false;
5587                }
5588
5589                t.wrap.one(CubePortfolio.private.transitionend, function() {
5590                    // remove resize event
5591                    if (t.slider) {
5592                        CubePortfolio.private.resize.destroyEvent($.data(t.slider[0], 'cubeportfolio'));
5593                    }
5594
5595                    // reset content
5596                    t.content.html('');
5597
5598                    // hide the wrap
5599                    t.wrap.detach();
5600
5601                    // now the popup is closed
5602                    t.isOpen = false;
5603                });
5604            } else {
5605                lightboxIsOpen = false;
5606
5607                if (t.originalStyle) {
5608                    $('html').attr('style', t.originalStyle);
5609                } else {
5610                    $('html').css({
5611                        overflow: '',
5612                        marginRight: ''
5613                    });
5614                }
5615
5616                $(window).scrollTop(t.scrollTop);
5617
5618                // remove resize event
5619                if (t.slider) {
5620                    CubePortfolio.private.resize.destroyEvent($.data(t.slider[0], 'cubeportfolio'));
5621                }
5622
5623                // reset content
5624                t.content.html('');
5625
5626                // hide the wrap
5627                t.wrap.detach();
5628
5629                // now the popup is closed
5630                t.isOpen = false;
5631            }
5632        },
5633
5634        tooggleLoading: function(state) {
5635            var t = this;
5636
5637            t.stopEvents = state;
5638            t.wrap[(state) ? 'addClass' : 'removeClass']('cbp-popup-loading');
5639        },
5640
5641        resizeImage: function() {
5642            // if lightbox is not open go out
5643            if (!this.isOpen) {
5644                return;
5645            }
5646
5647            var img = this.content.find('img');
5648            var figure = img.parent();
5649            var height = $(window).height() - (figure.outerHeight(true) - figure.height()) - this.content.find('.cbp-popup-lightbox-bottom').outerHeight(true);
5650
5651            img.css('max-height', height + 'px');
5652        },
5653
5654        preloadNearbyImages: function() {
5655            var t = this;
5656            var arr = [
5657                t.getIndex(t.current + 1),
5658                t.getIndex(t.current + 2),
5659                t.getIndex(t.current + 3),
5660                t.getIndex(t.current - 1),
5661                t.getIndex(t.current - 2),
5662                t.getIndex(t.current - 3),
5663            ];
5664
5665            for (var i = arr.length - 1; i >= 0; i--) {
5666                if (t.dataArray[arr[i]].type === 'isImage') {
5667                    t.cubeportfolio.checkSrc(t.dataArray[arr[i]]);
5668                }
5669            }
5670        }
5671    };
5672
5673    function Plugin(parent) {
5674        var t = this;
5675
5676        t.parent = parent;
5677
5678        // if lightboxShowCounter is false, put lightboxCounter to ''
5679        if (parent.options.lightboxShowCounter === false) {
5680            parent.options.lightboxCounter = '';
5681        }
5682
5683        // if singlePageShowCounter is false, put singlePageCounter to ''
5684        if (parent.options.singlePageShowCounter === false) {
5685            parent.options.singlePageCounter = '';
5686        }
5687
5688        // @todo - schedule this in  future
5689        parent.registerEvent('initStartRead', function() {
5690            t.run();
5691        }, true);
5692    }
5693
5694    // little hack for keydown issue when lightbox & singlePage is open
5695    var lightboxIsOpen = false;
5696    var lightboxInit = false;
5697    var singlePageInit = false;
5698
5699    Plugin.prototype.run = function() {
5700        var t = this,
5701            p = t.parent,
5702            body = $(document.body);
5703
5704        // default value for lightbox
5705        p.lightbox = null;
5706
5707        // LIGHTBOX
5708        if (p.options.lightboxDelegate && !lightboxInit) {
5709            // init only one time @todo
5710            lightboxInit = true;
5711
5712            p.lightbox = Object.create(popup);
5713            p.lightbox.init(p, 'lightbox');
5714
5715            body.on('click.cbp', p.options.lightboxDelegate, function(e) {
5716                e.preventDefault();
5717
5718                var self = $(this),
5719                    gallery = self.attr('data-cbp-lightbox'),
5720                    scope = t.detectScope(self),
5721                    cbp = scope.data('cubeportfolio'),
5722                    blocks = [];
5723
5724                // is inside a cbp
5725                if (cbp) {
5726                    cbp.blocksOn.each(function(index, el) {
5727                        var item = $(el);
5728
5729                        if (item.not('.cbp-item-off')) {
5730                            item.find(p.options.lightboxDelegate).each(function(index2, el2) {
5731                                if (gallery) {
5732                                    if ($(el2).attr('data-cbp-lightbox') === gallery) {
5733                                        blocks.push(el2);
5734                                    }
5735                                } else {
5736                                    blocks.push(el2);
5737                                }
5738                            });
5739                        }
5740                    });
5741                } else {
5742                    if (gallery) {
5743                        blocks = scope.find(p.options.lightboxDelegate + '[data-cbp-lightbox=' + gallery + ']');
5744                    } else {
5745                        blocks = scope.find(p.options.lightboxDelegate);
5746                    }
5747                }
5748
5749                p.lightbox.openLightbox(blocks, self[0]);
5750            });
5751        }
5752
5753        // default value for singlePage
5754        p.singlePage = null;
5755
5756        // SINGLEPAGE
5757        if (p.options.singlePageDelegate && !singlePageInit) {
5758            // init only one time @todo
5759            singlePageInit = true;
5760
5761            p.singlePage = Object.create(popup);
5762            p.singlePage.init(p, 'singlePage');
5763
5764            body.on('click.cbp', p.options.singlePageDelegate, function(e) {
5765                e.preventDefault();
5766
5767                var self = $(this),
5768                    gallery = self.attr('data-cbp-singlePage'),
5769                    scope = t.detectScope(self),
5770                    cbp = scope.data('cubeportfolio'),
5771                    blocks = [];
5772
5773                // is inside a cbp
5774                if (cbp) {
5775                    cbp.blocksOn.each(function(index, el) {
5776                        var item = $(el);
5777
5778                        if (item.not('.cbp-item-off')) {
5779                            item.find(p.options.singlePageDelegate).each(function(index2, el2) {
5780                                if (gallery) {
5781                                    if ($(el2).attr('data-cbp-singlePage') === gallery) {
5782                                        blocks.push(el2);
5783                                    }
5784                                } else {
5785                                    blocks.push(el2);
5786                                }
5787                            });
5788                        }
5789                    });
5790                } else {
5791                    if (gallery) {
5792                        blocks = scope.find(p.options.singlePageDelegate + '[data-cbp-singlePage=' + gallery + ']');
5793                    } else {
5794                        blocks = scope.find(p.options.singlePageDelegate);
5795                    }
5796                }
5797
5798                p.singlePage.openSinglePage(blocks, self[0]);
5799            });
5800        }
5801
5802        // default value for singlePageInline
5803        p.singlePageInline = null;
5804
5805        // SINGLEPAGEINLINE
5806        if (p.options.singlePageInlineDelegate) {
5807            p.singlePageInline = Object.create(popup);
5808
5809            p.singlePageInline.init(p, 'singlePageInline');
5810
5811            p.$obj.on('click.cbp', p.options.singlePageInlineDelegate, function(e) {
5812                e.preventDefault();
5813
5814                var oldDate = $.data(this, 'cbp-locked'),
5815                    newDate = $.data(this, 'cbp-locked', +new Date());
5816
5817                if (!oldDate || ((newDate - oldDate) > 300)) {
5818                    p.singlePageInline.openSinglePageInline(p.blocksOn, this);
5819                }
5820            });
5821        }
5822    };
5823
5824    Plugin.prototype.detectScope = function(item) {
5825        var singlePageInline,
5826            singlePage,
5827            cbp;
5828
5829        singlePageInline = item.closest('.cbp-popup-singlePageInline');
5830        if (singlePageInline.length) {
5831            cbp = item.closest('.cbp', singlePageInline[0]);
5832            return (cbp.length) ? cbp : singlePageInline;
5833        }
5834
5835        singlePage = item.closest('.cbp-popup-singlePage');
5836        if (singlePage.length) {
5837            cbp = item.closest('.cbp', singlePage[0]);
5838            return (cbp.length) ? cbp : singlePage;
5839        }
5840
5841        cbp = item.closest('.cbp');
5842        return (cbp.length) ? cbp : $(document.body);
5843
5844    };
5845
5846    Plugin.prototype.destroy = function() {
5847        var p = this.parent;
5848
5849        $(document.body).off('click.cbp');
5850
5851        // @todo - remove these from here
5852        lightboxInit = false;
5853        singlePageInit = false;
5854
5855        // destroy lightbox if enabled
5856        if (p.lightbox) {
5857            p.lightbox.destroy();
5858        }
5859
5860        // destroy singlePage if enabled
5861        if (p.singlePage) {
5862            p.singlePage.destroy();
5863        }
5864
5865        // destroy singlePage inline if enabled
5866        if (p.singlePageInline) {
5867            p.singlePageInline.destroy();
5868        }
5869    };
5870
5871    CubePortfolio.plugins.popUp = function(parent) {
5872        return new Plugin(parent);
5873    };
5874})(jQuery, window, document);
5875(function($, window, document, undefined) {
5876    'use strict';
5877
5878    var CubePortfolio = $.fn.cubeportfolio.constructor;
5879
5880    function Plugin(parent) {
5881        var t = this;
5882
5883        t.parent = parent;
5884
5885        t.searchInput = $(parent.options.search);
5886
5887        t.searchInput.each(function(index, el) {
5888            var selector = el.getAttribute('data-search');
5889
5890            if (!selector) {
5891                selector = '*';
5892            }
5893
5894            $.data(el, 'searchData', {
5895                value: el.value,
5896                el: selector
5897            });
5898        });
5899
5900        var timeout = null;
5901
5902        t.searchInput.on('keyup.cbp paste.cbp', function(e) {
5903            e.preventDefault();
5904
5905            var el = $(this);
5906
5907            clearTimeout(timeout);
5908            timeout = setTimeout(function() {
5909                t.runEvent.call(t, el);
5910            }, 350);
5911        });
5912
5913        t.searchNothing = t.searchInput.siblings('.cbp-search-nothing').detach();
5914        t.searchNothingHeight = null;
5915        t.searchNothingHTML = t.searchNothing.html();
5916
5917        t.searchInput.siblings('.cbp-search-icon').on('click.cbp', function(e) {
5918            e.preventDefault();
5919
5920            t.runEvent.call(t, $(this).prev().val(''));
5921        });
5922    }
5923
5924    Plugin.prototype.runEvent = function(el) {
5925        var t = this,
5926            value = el.val(),
5927            searchData = el.data('searchData'),
5928            reg = new RegExp(value, 'i');
5929
5930        if (searchData.value === value || t.parent.isAnimating) {
5931            return;
5932        }
5933
5934        searchData.value = value;
5935
5936        if (value.length > 0) {
5937            el.attr('value', value);
5938        } else {
5939            el.removeAttr('value');
5940        }
5941
5942        t.parent.$obj.cubeportfolio('filter', function(blocks) {
5943            var blocksNew = blocks.filter(function(index, block) {
5944                var text = $(block).find(searchData.el).text();
5945
5946                if (text.search(reg) > -1) {
5947                    return true;
5948                }
5949            });
5950
5951            if (blocksNew.length === 0 && t.searchNothing.length) {
5952                var innerText = t.searchNothingHTML.replace('{{query}}', value);
5953                t.searchNothing.html(innerText);
5954
5955                t.searchNothing.appendTo(t.parent.$obj);
5956
5957                if (t.searchNothingHeight === null) {
5958                    t.searchNothingHeight = t.searchNothing.outerHeight(true);
5959                }
5960
5961                t.parent.registerEvent('resizeMainContainer', function() {
5962                    t.parent.height = t.parent.height + t.searchNothingHeight;
5963                    t.parent.obj.style.height = t.parent.height + 'px';
5964                }, true);
5965            } else {
5966                t.searchNothing.detach();
5967            }
5968
5969            // reset filters active class after the search is used
5970            t.parent.triggerEvent('resetFiltersVisual');
5971
5972            return blocksNew;
5973        }, function() {
5974            el.trigger('keyup.cbp');
5975        });
5976    };
5977
5978    Plugin.prototype.destroy = function() {
5979        var t = this;
5980
5981        t.searchInput.off('.cbp');
5982        t.searchInput.next('.cbp-search-icon').off('.cbp');
5983
5984        t.searchInput.each(function(index, el) {
5985            $.removeData(el);
5986        });
5987    };
5988
5989    CubePortfolio.plugins.search = function(parent) {
5990        if (parent.options.search === '') {
5991            return null;
5992        }
5993
5994        return new Plugin(parent);
5995    };
5996})(jQuery, window, document);
5997(function($, window, document, undefined) {
5998    'use strict';
5999
6000    var options = {
6001        /**
6002         *  Pagination custom selector
6003         *  Values: strings that represent the elements in the document (DOM selector).
6004         */
6005        pagination: '',
6006        paginationClass: 'cbp-pagination-active',
6007    };
6008
6009    var CubePortfolio = $.fn.cubeportfolio.constructor;
6010
6011    function Plugin(parent) {
6012        var t = this;
6013
6014        t.parent = parent;
6015
6016        t.options = $.extend({}, options, t.parent.options.plugins.slider);
6017
6018        var customPagination = $(t.options.pagination);
6019
6020        if (customPagination.length > 0) {
6021            t.parent.customPagination = customPagination;
6022            t.parent.customPaginationItems = customPagination.children();
6023            t.parent.customPaginationClass = t.options.paginationClass;
6024
6025            t.parent.customPaginationItems.on('click.cbp', function(e) {
6026                e.preventDefault();
6027                e.stopImmediatePropagation();
6028                e.stopPropagation();
6029
6030                if (t.parent.sliderStopEvents) {
6031                    return;
6032                }
6033
6034                t.parent.jumpToSlider($(this));
6035            });
6036        }
6037
6038        t.parent.registerEvent('gridAdjust', function() {
6039            t.sliderMarkup.call(t.parent);
6040
6041            t.parent.registerEvent('gridAdjust', function() {
6042                t.updateSlider.call(t.parent);
6043            });
6044        }, true);
6045    }
6046
6047    /**
6048     * Create mark-up for slider layout
6049     */
6050    Plugin.prototype.sliderMarkup = function() {
6051        var t = this;
6052
6053        t.sliderStopEvents = false;
6054
6055        t.sliderActive = 0;
6056
6057        t.$obj.one('initComplete.cbp', function() {
6058            t.$obj.addClass('cbp-mode-slider');
6059        });
6060
6061        t.nav = $('<div/>', {
6062            'class': 'cbp-nav'
6063        });
6064
6065        t.nav.on('click.cbp', '[data-slider-action]', function(e) {
6066            e.preventDefault();
6067            e.stopImmediatePropagation();
6068            e.stopPropagation();
6069
6070            if (t.sliderStopEvents) {
6071                return;
6072            }
6073
6074            var el = $(this),
6075                action = el.attr('data-slider-action');
6076
6077            if (t[action + 'Slider']) {
6078                t[action + 'Slider'](el);
6079            }
6080        });
6081
6082        if (t.options.showNavigation) {
6083            t.controls = $('<div/>', {
6084                'class': 'cbp-nav-controls'
6085            });
6086
6087            t.navPrev = $('<div/>', {
6088                'class': 'cbp-nav-prev',
6089                'data-slider-action': 'prev'
6090            }).appendTo(t.controls);
6091
6092            t.navNext = $('<div/>', {
6093                'class': 'cbp-nav-next',
6094                'data-slider-action': 'next'
6095            }).appendTo(t.controls);
6096
6097            t.controls.appendTo(t.nav);
6098        }
6099
6100        if (t.options.showPagination) {
6101            t.navPagination = $('<div/>', {
6102                'class': 'cbp-nav-pagination'
6103            }).appendTo(t.nav);
6104        }
6105
6106        if (t.controls || t.navPagination) {
6107            t.nav.appendTo(t.$obj);
6108        }
6109
6110        t.updateSliderPagination();
6111
6112        if (t.options.auto) {
6113            if (t.options.autoPauseOnHover) {
6114                t.mouseIsEntered = false;
6115                t.$obj.on('mouseenter.cbp', function(e) {
6116                    t.mouseIsEntered = true;
6117                    t.stopSliderAuto();
6118                }).on('mouseleave.cbp', function(e) {
6119                    t.mouseIsEntered = false;
6120                    t.startSliderAuto();
6121                });
6122            }
6123
6124            t.startSliderAuto();
6125        }
6126
6127        if (t.options.drag && CubePortfolio.private.modernBrowser) {
6128            t.dragSlider();
6129        }
6130    };
6131
6132    Plugin.prototype.updateSlider = function() {
6133        var t = this;
6134
6135        t.updateSliderPosition();
6136
6137        t.updateSliderPagination();
6138    };
6139
6140    Plugin.prototype.destroy = function() {
6141        var t = this;
6142
6143        if (t.parent.customPaginationItems) {
6144            t.parent.customPaginationItems.off('.cbp');
6145        }
6146
6147        if (t.parent.controls || t.parent.navPagination) {
6148            t.parent.nav.off('.cbp');
6149            t.parent.nav.remove();
6150        }
6151    };
6152
6153    CubePortfolio.plugins.slider = function(parent) {
6154        if (parent.options.layoutMode !== 'slider') {
6155            return null;
6156        }
6157
6158        return new Plugin(parent);
6159    };
6160})(jQuery, window, document);
6161(function($, window, document, undefined) {
6162    'use strict';
6163
6164    var options = {
6165        /**
6166         *  Define the wrapper for sort
6167         *  Values: strings that represent the elements in the document (DOM selector).
6168         */
6169        element: '',
6170    };
6171
6172    var CubePortfolio = $.fn.cubeportfolio.constructor;
6173
6174    function Plugin(parent) {
6175        var t = this;
6176
6177        t.parent = parent;
6178
6179        t.options = $.extend({}, options, t.parent.options.plugins.sort);
6180
6181        t.element = $(t.options.element);
6182
6183        if (t.element.length === 0) {
6184            return;
6185        }
6186
6187        t.sort = '';
6188        t.sortBy = 'string:asc';
6189
6190        t.element.on('click.cbp', '.cbp-sort-item', function(event) {
6191            event.preventDefault();
6192
6193            t.target = event.target;
6194
6195            if ($(t.target).hasClass('cbp-l-dropdown-item--active') || parent.isAnimating) {
6196                return;
6197            }
6198
6199            t.processSort();
6200            parent.$obj.cubeportfolio('filter', parent.defaultFilter);
6201        });
6202
6203        // reset filters active class after the search is used
6204        parent.registerEvent('triggerSort', function() {
6205            if (t.target) {
6206                t.processSort();
6207                parent.$obj.cubeportfolio('filter', parent.defaultFilter);
6208            }
6209        });
6210
6211        t.dropdownWrap = t.element.find('.cbp-l-dropdown-wrap')
6212            .on({
6213                'mouseover.cbp': function() {
6214                    $(this).addClass('cbp-l-dropdown-wrap--open');
6215                },
6216                'mouseleave.cbp': function() {
6217                    $(this).removeClass('cbp-l-dropdown-wrap--open');
6218                }
6219            });
6220
6221        t.dropdownHeader = t.element.find('.cbp-l-dropdown-header');
6222    }
6223
6224    Plugin.prototype.processSort = function() {
6225        var t = this;
6226        var parent = t.parent;
6227
6228        var target = t.target;
6229        var hasSort = target.hasAttribute('data-sort');
6230        var hasSortBy = target.hasAttribute('data-sortBy');
6231
6232        if (hasSort && hasSortBy) {
6233            t.sort = target.getAttribute('data-sort');
6234            t.sortBy = target.getAttribute('data-sortBy');
6235        } else if (hasSort) {
6236            t.sort = target.getAttribute('data-sort');
6237        } else if (hasSortBy) {
6238            t.sortBy = target.getAttribute('data-sortBy');
6239        } else {
6240            return;
6241        }
6242
6243        var sortByArr = t.sortBy.split(':');
6244        var sortByType = 'string';
6245        var sortByDirection = 1;
6246
6247        if (sortByArr[0] === 'int') {
6248            sortByType = 'int';
6249        } else if (sortByArr[0] === 'float') {
6250            sortByType = 'float';
6251        }
6252
6253        if (sortByArr[1] === 'desc') {
6254            sortByDirection = -1;
6255        }
6256
6257        if (t.sort) {
6258            var obj = [];
6259
6260            parent.blocks.each(function(index, el) {
6261                var block = $(el);
6262
6263                var sortText = block.find(t.sort).text();
6264
6265                if (sortByType === 'int') {
6266                    sortText = parseInt(sortText, 10);
6267                }
6268
6269                if (sortByType === 'float') {
6270                    sortText = parseFloat(sortText, 10);
6271                }
6272
6273                obj.push({
6274                    sortText: sortText,
6275                    data: block.data('cbp'),
6276                });
6277            });
6278
6279            obj.sort(function(obj1, obj2) {
6280                var sortText1 = obj1.sortText;
6281                var sortText2 = obj2.sortText;
6282
6283                if (sortByType === 'string') {
6284                    sortText1 = sortText1.toUpperCase(); // ignore upper and lowercase
6285                    sortText2 = sortText2.toUpperCase(); // ignore upper and lowercase
6286                }
6287
6288                if (sortText1 < sortText2) {
6289                    return -sortByDirection;
6290                } else if (sortText1 > sortText2) {
6291                    return sortByDirection;
6292                }
6293
6294                // names must be equal
6295                return 0;
6296            });
6297
6298            $.each(obj, function(index, val) {
6299                val.data.index = index;
6300            });
6301        } else {
6302            var sortInvers = [];
6303
6304            if (sortByDirection === -1) {
6305                parent.blocks.each(function(index, el) {
6306                    sortInvers.push($(el).data('cbp').indexInitial);
6307                });
6308
6309                // put sortInvers in inverse order
6310                sortInvers.sort(function(a, b) {
6311                    return b - a;
6312                });
6313            }
6314
6315            parent.blocks.each(function(index, el) {
6316                var data = $(el).data('cbp');
6317
6318                if (sortByDirection === -1) {
6319                    data.index = sortInvers[data.indexInitial];
6320                } else {
6321                    data.index = data.indexInitial;
6322                }
6323            });
6324        }
6325
6326        parent.sortBlocks(parent.blocks, 'index');
6327
6328        t.dropdownWrap.trigger('mouseleave.cbp');
6329
6330        var target = $(t.target);
6331        var targetParent = $(t.target).parent();
6332
6333        if (targetParent.hasClass('cbp-l-dropdown-list')) {
6334            t.dropdownHeader.html(target.html());
6335            target.addClass('cbp-l-dropdown-item--active').siblings('.cbp-l-dropdown-item').removeClass('cbp-l-dropdown-item--active');
6336        } else if (targetParent.hasClass('cbp-l-direction')) {
6337            var index = target.index();
6338
6339            if (index === 0) {
6340                targetParent.addClass('cbp-l-direction--second').removeClass('cbp-l-direction--first');
6341            } else {
6342                targetParent.addClass('cbp-l-direction--first').removeClass('cbp-l-direction--second');
6343            }
6344        }
6345
6346    };
6347
6348    Plugin.prototype.destroy = function() {
6349        this.element.off('click.cbp');
6350    };
6351
6352    CubePortfolio.plugins.sort = function(parent) {
6353        return new Plugin(parent);
6354    };
6355})(jQuery, window, document);

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.