1/*! 2 * jScrollPane - v2.0.22 - 2015-04-25 3 * http://jscrollpane.kelvinluck.com/ 4 * 5 * Copyright (c) 2014 Kelvin Luck 6 * Dual licensed under the MIT or GPL licenses. 7 */ 8!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.jScrollPane=function(b){function c(b,c){function d(c){var f,h,j,k,l,o,p=!1,q=!1;if(N=c,void 0===O)l=b.scrollTop(),o=b.scrollLeft(),b.css({overflow:"hidden",padding:0}),P=b.innerWidth()+ra,Q=b.innerHeight(),b.width(P),O=a('<div class="jspPane" />').css("padding",qa).append(b.children()),R=a('<div class="jspContainer" />').css({width:P+"px",height:Q+"px"}).append(O).appendTo(b);else{if(b.css("width",""),p=N.stickToBottom&&A(),q=N.stickToRight&&B(),k=b.innerWidth()+ra!=P||b.outerHeight()!=Q,k&&(P=b.innerWidth()+ra,Q=b.innerHeight(),R.css({width:P+"px",height:Q+"px"})),!k&&sa==S&&O.outerHeight()==T)return void b.width(P);sa=S,O.css("width",""),b.width(P),R.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}O.css("overflow","auto"),S=c.contentWidth?c.contentWidth:O[0].scrollWidth,T=O[0].scrollHeight,O.css("overflow",""),U=S/P,V=T/Q,W=V>1,X=U>1,X||W?(b.addClass("jspScrollable"),f=N.maintainPosition&&($||ba),f&&(h=y(),j=z()),e(),g(),i(),f&&(w(q?S-P:h,!1),v(p?T-Q:j,!1)),F(),C(),L(),N.enableKeyboardNavigation&&H(),N.clickOnTrack&&m(),J(),N.hijackInternalLinks&&K()):(b.removeClass("jspScrollable"),O.css({top:0,left:0,width:R.width()-ra}),D(),G(),I(),n()),N.autoReinitialise&&!pa?pa=setInterval(function(){d(N)},N.autoReinitialiseDelay):!N.autoReinitialise&&pa&&clearInterval(pa),l&&b.scrollTop(0)&&v(l,!1),o&&b.scrollLeft(0)&&w(o,!1),b.trigger("jsp-initialised",[X||W])}function e(){W&&(R.append(a('<div class="jspVerticalBar" />').append(a('<div class="jspCap jspCapTop" />'),a('<div class="jspTrack" />').append(a('<div class="jspDrag" />').append(a('<div class="jspDragTop" />'),a('<div class="jspDragBottom" />'))),a('<div class="jspCap jspCapBottom" />'))),ca=R.find(">.jspVerticalBar"),da=ca.find(">.jspTrack"),Y=da.find(">.jspDrag"),N.showArrows&&(ha=a('<a class="jspArrow jspArrowUp" />').bind("mousedown.jsp",k(0,-1)).bind("click.jsp",E),ia=a('<a class="jspArrow jspArrowDown" />').bind("mousedown.jsp",k(0,1)).bind("click.jsp",E),N.arrowScrollOnHover&&(ha.bind("mouseover.jsp",k(0,-1,ha)),ia.bind("mouseover.jsp",k(0,1,ia))),j(da,N.verticalArrowPositions,ha,ia)),fa=Q,R.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){fa-=a(this).outerHeight()}),Y.hover(function(){Y.addClass("jspHover")},function(){Y.removeClass("jspHover")}).bind("mousedown.jsp",function(b){a("html").bind("dragstart.jsp selectstart.jsp",E),Y.addClass("jspActive");var c=b.pageY-Y.position().top;return a("html").bind("mousemove.jsp",function(a){p(a.pageY-c,!1)}).bind("mouseup.jsp mouseleave.jsp",o),!1}),f())}function f(){da.height(fa+"px"),$=0,ea=N.verticalGutter+da.outerWidth(),O.width(P-ea-ra);try{0===ca.position().left&&O.css("margin-left",ea+"px")}catch(a){}}function g(){X&&(R.append(a('<div class="jspHorizontalBar" />').append(a('<div class="jspCap jspCapLeft" />'),a('<div class="jspTrack" />').append(a('<div class="jspDrag" />').append(a('<div class="jspDragLeft" />'),a('<div class="jspDragRight" />'))),a('<div class="jspCap jspCapRight" />'))),ja=R.find(">.jspHorizontalBar"),ka=ja.find(">.jspTrack"),_=ka.find(">.jspDrag"),N.showArrows&&(na=a('<a class="jspArrow jspArrowLeft" />').bind("mousedown.jsp",k(-1,0)).bind("click.jsp",E),oa=a('<a class="jspArrow jspArrowRight" />').bind("mousedown.jsp",k(1,0)).bind("click.jsp",E),N.arrowScrollOnHover&&(na.bind("mouseover.jsp",k(-1,0,na)),oa.bind("mouseover.jsp",k(1,0,oa))),j(ka,N.horizontalArrowPositions,na,oa)),_.hover(function(){_.addClass("jspHover")},function(){_.removeClass("jspHover")}).bind("mousedown.jsp",function(b){a("html").bind("dragstart.jsp selectstart.jsp",E),_.addClass("jspActive");var c=b.pageX-_.position().left;return a("html").bind("mousemove.jsp",function(a){r(a.pageX-c,!1)}).bind("mouseup.jsp mouseleave.jsp",o),!1}),la=R.innerWidth(),h())}function h(){R.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){la-=a(this).outerWidth()}),ka.width(la+"px"),ba=0}function i(){if(X&&W){var b=ka.outerHeight(),c=da.outerWidth();fa-=b,a(ja).find(">.jspCap:visible,>.jspArrow").each(function(){la+=a(this).outerWidth()}),la-=c,Q-=c,P-=b,ka.parent().append(a('<div class="jspCorner" />').css("width",b+"px")),f(),h()}X&&O.width(R.outerWidth()-ra+"px"),T=O.outerHeight(),V=T/Q,X&&(ma=Math.ceil(1/U*la),ma>N.horizontalDragMaxWidth?ma=N.horizontalDragMaxWidth:ma<N.horizontalDragMinWidth&&(ma=N.horizontalDragMinWidth),_.width(ma+"px"),aa=la-ma,s(ba)),W&&(ga=Math.ceil(1/V*fa),ga>N.verticalDragMaxHeight?ga=N.verticalDragMaxHeight:ga<N.verticalDragMinHeight&&(ga=N.verticalDragMinHeight),Y.height(ga+"px"),Z=fa-ga,q($))}function j(a,b,c,d){var e,f="before",g="after";"os"==b&&(b=/Mac/.test(navigator.platform)?"after":"split"),b==f?g=b:b==g&&(f=b,e=c,c=d,d=e),a[f](c)[g](d)}function k(a,b,c){return function(){return l(a,b,this,c),this.blur(),!1}}function l(b,c,d,e){d=a(d).addClass("jspActive");var f,g,h=!0,i=function(){0!==b&&ta.scrollByX(b*N.arrowButtonSpeed),0!==c&&ta.scrollByY(c*N.arrowButtonSpeed),g=setTimeout(i,h?N.initialDelay:N.arrowRepeatFreq),h=!1};
8i(),f=e?"mouseout.jsp":"mouseup.jsp",e=e||a("html"),e.bind(f,function(){d.removeClass("jspActive"),g&&clearTimeout(g),g=null,e.unbind(f)})}function m(){n(),W&&da.bind("mousedown.jsp",function(b){if(void 0===b.originalTarget||b.originalTarget==b.currentTarget){var c,d=a(this),e=d.offset(),f=b.pageY-e.top-$,g=!0,h=function(){var a=d.offset(),e=b.pageY-a.top-ga/2,j=Q*N.scrollPagePercent,k=Z*j/(T-Q);if(0>f)$-k>e?ta.scrollByY(-j):p(e);else{if(!(f>0))return void i();e>$+k?ta.scrollByY(j):p(e)}c=setTimeout(h,g?N.initialDelay:N.trackClickRepeatFreq),g=!1},i=function(){c&&clearTimeout(c),c=null,a(document).unbind("mouseup.jsp",i)};return h(),a(document).bind("mouseup.jsp",i),!1}}),X&&ka.bind("mousedown.jsp",function(b){if(void 0===b.originalTarget||b.originalTarget==b.currentTarget){var c,d=a(this),e=d.offset(),f=b.pageX-e.left-ba,g=!0,h=function(){var a=d.offset(),e=b.pageX-a.left-ma/2,j=P*N.scrollPagePercent,k=aa*j/(S-P);if(0>f)ba-k>e?ta.scrollByX(-j):r(e);else{if(!(f>0))return void i();e>ba+k?ta.scrollByX(j):r(e)}c=setTimeout(h,g?N.initialDelay:N.trackClickRepeatFreq),g=!1},i=function(){c&&clearTimeout(c),c=null,a(document).unbind("mouseup.jsp",i)};return h(),a(document).bind("mouseup.jsp",i),!1}})}function n(){ka&&ka.unbind("mousedown.jsp"),da&&da.unbind("mousedown.jsp")}function o(){a("html").unbind("dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp"),Y&&Y.removeClass("jspActive"),_&&_.removeClass("jspActive")}function p(a,b){W&&(0>a?a=0:a>Z&&(a=Z),void 0===b&&(b=N.animateScroll),b?ta.animate(Y,"top",a,q):(Y.css("top",a),q(a)))}function q(a){void 0===a&&(a=Y.position().top),R.scrollTop(0),$=a||0;var c=0===$,d=$==Z,e=a/Z,f=-e*(T-Q);(ua!=c||wa!=d)&&(ua=c,wa=d,b.trigger("jsp-arrow-change",[ua,wa,va,xa])),t(c,d),O.css("top",f),b.trigger("jsp-scroll-y",[-f,c,d]).trigger("scroll")}function r(a,b){X&&(0>a?a=0:a>aa&&(a=aa),void 0===b&&(b=N.animateScroll),b?ta.animate(_,"left",a,s):(_.css("left",a),s(a)))}function s(a){void 0===a&&(a=_.position().left),R.scrollTop(0),ba=a||0;var c=0===ba,d=ba==aa,e=a/aa,f=-e*(S-P);(va!=c||xa!=d)&&(va=c,xa=d,b.trigger("jsp-arrow-change",[ua,wa,va,xa])),u(c,d),O.css("left",f),b.trigger("jsp-scroll-x",[-f,c,d]).trigger("scroll")}function t(a,b){N.showArrows&&(ha[a?"addClass":"removeClass"]("jspDisabled"),ia[b?"addClass":"removeClass"]("jspDisabled"))}function u(a,b){N.showArrows&&(na[a?"addClass":"removeClass"]("jspDisabled"),oa[b?"addClass":"removeClass"]("jspDisabled"))}function v(a,b){var c=a/(T-Q);p(c*Z,b)}function w(a,b){var c=a/(S-P);r(c*aa,b)}function x(b,c,d){var e,f,g,h,i,j,k,l,m,n=0,o=0;try{e=a(b)}catch(p){return}for(f=e.outerHeight(),g=e.outerWidth(),R.scrollTop(0),R.scrollLeft(0);!e.is(".jspPane");)if(n+=e.position().top,o+=e.position().left,e=e.offsetParent(),/^body|html$/i.test(e[0].nodeName))return;h=z(),j=h+Q,h>n||c?l=n-N.horizontalGutter:n+f>j&&(l=n-Q+f+N.horizontalGutter),isNaN(l)||v(l,d),i=y(),k=i+P,i>o||c?m=o-N.horizontalGutter:o+g>k&&(m=o-P+g+N.horizontalGutter),isNaN(m)||w(m,d)}function y(){return-O.position().left}function z(){return-O.position().top}function A(){var a=T-Q;return a>20&&a-z()<10}function B(){var a=S-P;return a>20&&a-y()<10}function C(){R.unbind(za).bind(za,function(a,b,c,d){ba||(ba=0),$||($=0);var e=ba,f=$,g=a.deltaFactor||N.mouseWheelSpeed;return ta.scrollBy(c*g,-d*g,!1),e==ba&&f==$})}function D(){R.unbind(za)}function E(){return!1}function F(){O.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(a){x(a.target,!1)})}function G(){O.find(":input,a").unbind("focus.jsp")}function H(){function c(){var a=ba,b=$;switch(d){case 40:ta.scrollByY(N.keyboardSpeed,!1);break;case 38:ta.scrollByY(-N.keyboardSpeed,!1);break;case 34:case 32:ta.scrollByY(Q*N.scrollPagePercent,!1);break;case 33:ta.scrollByY(-Q*N.scrollPagePercent,!1);break;case 39:ta.scrollByX(N.keyboardSpeed,!1);break;case 37:ta.scrollByX(-N.keyboardSpeed,!1)}return e=a!=ba||b!=$}var d,e,f=[];X&&f.push(ja[0]),W&&f.push(ca[0]),O.bind("focus.jsp",function(){b.focus()}),b.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(b){if(b.target===this||f.length&&a(b.target).closest(f).length){var g=ba,h=$;switch(b.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:d=b.keyCode,c();break;case 35:v(T-Q),d=null;break;case 36:v(0),d=null}return e=b.keyCode==d&&g!=ba||h!=$,!e}}).bind("keypress.jsp",function(a){return a.keyCode==d&&c(),!e}),N.hideFocus?(b.css("outline","none"),"hideFocus"in R[0]&&b.attr("hideFocus",!0)):(b.css("outline",""),"hideFocus"in R[0]&&b.attr("hideFocus",!1))}function I(){b.attr("tabindex","-1").removeAttr("tabindex").unbind("
8keydown.jsp keypress.jsp"),O.unbind(".jsp")}function J(){if(location.hash&&location.hash.length>1){var b,c,d=escape(location.hash.substr(1));try{b=a("#"+d+', a[name="'+d+'"]')}catch(e){return}b.length&&O.find(d)&&(0===R.scrollTop()?c=setInterval(function(){R.scrollTop()>0&&(x(b,!0),a(document).scrollTop(R.position().top),clearInterval(c))},50):(x(b,!0),a(document).scrollTop(R.position().top)))}}function K(){a(document.body).data("jspHijack")||(a(document.body).data("jspHijack",!0),a(document.body).delegate("a[href*=#]","click",function(b){var c,d,e,f,g,h,i=this.href.substr(0,this.href.indexOf("#")),j=location.href;if(-1!==location.href.indexOf("#")&&(j=location.href.substr(0,location.href.indexOf("#"))),i===j){c=escape(this.href.substr(this.href.indexOf("#")+1));try{d=a("#"+c+', a[name="'+c+'"]')}catch(k){return}d.length&&(e=d.closest(".jspScrollable"),f=e.data("jsp"),f.scrollToElement(d,!0),e[0].scrollIntoView&&(g=a(window).scrollTop(),h=d.offset().top,(g>h||h>g+a(window).height())&&e[0].scrollIntoView()),b.preventDefault())}}))}function L(){var a,b,c,d,e,f=!1;R.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(g){var h=g.originalEvent.touches[0];a=y(),b=z(),c=h.pageX,d=h.pageY,e=!1,f=!0}).bind("touchmove.jsp",function(g){if(f){var h=g.originalEvent.touches[0],i=ba,j=$;return ta.scrollTo(a+c-h.pageX,b+d-h.pageY),e=e||Math.abs(c-h.pageX)>5||Math.abs(d-h.pageY)>5,i==ba&&j==$}}).bind("touchend.jsp",function(a){f=!1}).bind("click.jsp-touchclick",function(a){return e?(e=!1,!1):void 0})}function M(){var a=z(),c=y();b.removeClass("jspScrollable").unbind(".jsp"),O.unbind(".jsp"),b.replaceWith(ya.append(O.children())),ya.scrollTop(a),ya.scrollLeft(c),pa&&clearInterval(pa)}var N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba,ca,da,ea,fa,ga,ha,ia,ja,ka,la,ma,na,oa,pa,qa,ra,sa,ta=this,ua=!0,va=!0,wa=!1,xa=!1,ya=b.clone(!1,!1).empty(),za=a.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";"border-box"===b.css("box-sizing")?(qa=0,ra=0):(qa=b.css("paddingTop")+" "+b.css("paddingRight")+" "+b.css("paddingBottom")+" "+b.css("paddingLeft"),ra=(parseInt(b.css("paddingLeft"),10)||0)+(parseInt(b.css("paddingRight"),10)||0)),a.extend(ta,{reinitialise:function(b){b=a.extend({},N,b),d(b)},scrollToElement:function(a,b,c){x(a,b,c)},scrollTo:function(a,b,c){w(a,c),v(b,c)},scrollToX:function(a,b){w(a,b)},scrollToY:function(a,b){v(a,b)},scrollToPercentX:function(a,b){w(a*(S-P),b)},scrollToPercentY:function(a,b){v(a*(T-Q),b)},scrollBy:function(a,b,c){ta.scrollByX(a,c),ta.scrollByY(b,c)},scrollByX:function(a,b){var c=y()+Math[0>a?"floor":"ceil"](a),d=c/(S-P);r(d*aa,b)},scrollByY:function(a,b){var c=z()+Math[0>a?"floor":"ceil"](a),d=c/(T-Q);p(d*Z,b)},positionDragX:function(a,b){r(a,b)},positionDragY:function(a,b){p(a,b)},animate:function(a,b,c,d){var e={};e[b]=c,a.animate(e,{duration:N.animateDuration,easing:N.animateEase,queue:!1,step:d})},getContentPositionX:function(){return y()},getContentPositionY:function(){return z()},getContentWidth:function(){return S},getContentHeight:function(){return T},getPercentScrolledX:function(){return y()/(S-P)},getPercentScrolledY:function(){return z()/(T-Q)},getIsScrollableH:function(){return X},getIsScrollableV:function(){return W},getContentPane:function(){return O},scrollToBottom:function(a){p(Z,a)},hijackInternalLinks:a.noop,destroy:function(){M()}}),d(c)}return b=a.extend({},a.fn.jScrollPane.defaults,b),a.each(["arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){b[this]=b[this]||b.speed}),this.each(function(){var d=a(this),e=d.data("jsp");e?e.reinitialise(b):(a("script",d).filter('[type="text/javascript"],:not([type])').remove(),e=new c(d,b),d.data("jsp",e))})},a.fn.jScrollPane.defaults={showArrows:!1,maintainPosition:!0,stickToBottom:!1,stickToRight:!1,clickOnTrack:!0,autoReinitialise:!1,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:void 0,animateScroll:!1,animateDuration:300,animateEase:"linear",hijackInternalLinks:!1,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:3,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:!1,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:!0,hideFocus:!1,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:.8}}); 9 10 11 12(function($) { 13 "use strict"; 14 15 var sliderId = 0; 16 17 /** 18 * Pexeto Portfolio Slider. Displays an image slider with content on the side 19 * or below it.
20 * Dependencies: 21 * - jQuery 22 * - jQuery Easing : http://gsgd.co.uk/sandbox/jquery/easing/ 23 * - Images Loaded : http://github.com/desandro/imagesloaded 24 * - Touchwipe by Andreas Waltl, netCU Internetagentur (http://www.netcu.de) 25 * - jScrollPane : http://jscrollpane.kelvinluck.com/ 26 * - MouseWheel : http://adomas.org/javascript-mouse-wheel/ 27 * 28 * @author Pexeto 29 * http://pexetothemes.com 30 */ 31 $.fn.pexetoPortfolioSlider = function(options) { 32 sliderId++; 33 34 var defaults = { 35 images : [], 36 navigation : null, 37 easing : 'easeOutExpo', 38 //number of images to load on portions 39 loadPortions : 5, 40 animationSpeed : 700, 41 //events namespace 42 namespace : 'pexslider' + sliderId, 43 minHeight : 200, 44 45 //selectors, IDs and classes 46 imgContainerSel : '.ps-images:first', 47 contentSel : '.ps-content:first', 48 contentTexSel : '.ps-content-text:first', 49 leftArrowClass : 'ps-left-arrow', 50 rightArrowClass : 'ps-right-arrow', 51 loadingClass : 'ps-loading', 52 navigationSel : '.ps-navigation', 53 fullwidthClass : 'ps-fullwidth', 54 navLoadingClass : 'ps-nav-loading', 55 descClass : 'ps-desc', 56 numClass : 'ps-imgnum', 57 videoContainerSel : '.ps-video:first', 58 shareSel : '.ps-share' 59 }, 60 //define some helper variables that will be used globally by the plugin 61 o = $.extend(defaults, options), 62 $root = this, 63 $mediaContainer = $root.find(o.imgContainerSel), 64 $contentContainer = $root.find(o.contentSel), 65 $navWrapper = $('.pg-nav-wrapper'), 66 inAnimation = false, 67 $larrow = null, 68 $rarrow = null, 69 images = o.images, 70 imgContWidth = $mediaContainer.width(), 71 imgContHeight = 0, 72 lastLoaded = 0, 73 imgNum = images.length, 74 pendingImg = -1, 75 current = 0, 76 fullwidth = $root.hasClass(o.fullwidthClass), 77 contentPadding = parseInt($contentContainer.css('paddingTop'), 10) + parseInt($contentContainer.css('border-top-width'), 10), 78 $desc = $('<div />', { 79 'class' : o.descClass 80 }).appendTo($mediaContainer), 81 $numContainer = null, 82 video = false, 83 jscrollApi = null; 84 85 /** 86 * Inits the main functionality - calls the initialization functions. 87 */ 88 function init() { 89 90 PEXETO.init.tabs(); 91 92 var $share = $contentContainer.find(o.shareSel); 93 if($share.length) { 94 PEXETO.init.share($share); 95 } 96 97 if(!$mediaContainer.length) { 98 //it's a video slider 99 $mediaContainer = $root.find(o.videoContainerSel); 100 video = true; 101 102 $root.trigger("sliderLoaded"); 103 PEXETO.init.ieIframeFix(); 104 105 } else { 106 //it's an image slider, load the images 107 loadSlider(); 108 if(imgNum > 1) { 109 addNavigation(); 110 } 111 loadNextImages(); 112 } 113 114 bindEventHandlers(); 115 116 PEXETO.init.lightbox(null, {deeplinking:false}); 117 } 118 119 /** 120 * Loads the slider once all the images are loaded. 121 */ 122 function loadSlider() { 123 var img, $img, doOnImgLoaded; 124 125 //add the first image 126 img = new Image(); 127 img.setAttribute("src", images[0].img); 128 $img = $(img); 129 images[0].el = $img; 130 131 $mediaContainer.append($img, false); 132 133 doOnImgLoaded = function() { 134 //the first image has been loaded, show the slider 135 $root.css({ 136 opacity: 0, 137 display: 'block' 138 }); 139 imgContWidth = $mediaContainer.width(); 140 141 $img.css({ 142 opacity: 1 143 }); 144 setContainerHeight($img, true); 145 $root.trigger("sliderLoaded"); 146 showDescription(images[0].desc); 147 }; 148 149 $mediaContainer.find('img').pexetoOnImgLoaded({callback: doOnImgLoaded}); 150 151 if(imgNum > 1) {
152 $numContainer = $('<div />', { 153 'class': o.numClass, 154 'html': '1 / ' + imgNum 155 }).appendTo($mediaContainer); 156 } 157 158 } 159 160 161 /** 162 * Binds event handlers. 163 */ 164 function bindEventHandlers() { 165 if(!video && imgNum > 1) { 166 //navigation event handlers 167 $larrow.on('click.' + o.namespace, doOnPreviousClicked); 168 $rarrow.on('click.' + o.namespace, doOnNextClicked); 169 170 $mediaContainer.touchwipe({ 171 wipeLeft: doOnNextClicked, 172 wipeRight: doOnPreviousClicked, 173 preventDefaultEvents: false 174 }); 175 } 176 177 $(window).on('resize.' + o.namespace, doOnWindowResize); 178 $root.on('destroy.' + o.namespace, destroySlider); 179 180 181 var obj = video ? null : $root.find('img').eq(0); 182 $root.on('sliderVisible.' + o.namespace, function() { 183 addSliderNavigation(); 184 setContainerHeight(obj, false); 185 }); 186 187 188 } 189 190 function addSliderNavigation(){ 191 if(o.navigation){ 192 193 $navWrapper.append(o.navigation).find(o.navigationSel).on('click.' + o.namespace, 'a', doOnNavigationClick); 194 195 } 196 } 197 198 /** 199 * Loads the next portion of images. The images are loaded in background 200 * on portions of n-images. 201 * - creates an image element 202 * - binds on images loaded event 203 */ 204 function loadNextImages() { 205 var i, image, len = (lastLoaded + o.loadPortions >= imgNum) ? 206 (imgNum - 1) : (lastLoaded + o.loadPortions); 207 208 for(i = lastLoaded + 1; i <= len; i += 1) { 209 if(!images[i].loaded) { 210 image = new Image(); 211 image.setAttribute("src", images[i].img); 212 213 (function(i) { 214 images[i].el = $(image).imagesLoaded(function() { 215 images[i].loaded = true; 216 if(pendingImg === i) { 217 //image has been selected to show, but wasn't loaded yet 218 pendingImg = -1; 219 hideLoading(); 220 showImage(true); 221 } 222 }); 223 })(i); 224 } 225 } 226 227 lastLoaded = len; 228 } 229 230 /** 231 * Displays an image in the slider. 232 * @param {boolean} next sets whether it is the next image (when it 233 * is set to true) or the previous one (when it is set to false) 234 */ 235 function showImage(next) { 236 inAnimation = true; 237 var i = next ? 1 : -1, 238 $img = images[current + i].el.appendTo($mediaContainer).css({ 239 left: imgContWidth * i 240 }); 241 242 setContainerHeight($img, true); 243 244 if(imgNum > 1) { 245 $numContainer.html((current + i + 1) + ' / ' + imgNum); 246 } 247 248 //hide the current image 249 images[current].el.animate({ 250 opacity: 0.5, 251 left: -imgContWidth * i 252 }, o.animationSpeed, o.easing, function() { 253 $(this).detach(); 254 }); 255 256 //show the next umage 257 $img.animate({ 258 left: 0, 259 opacity: 1 260 }, o.animationSpeed, o.easing, function() { 261 current = current + i; 262 inAnimation = false; 263 }); 264 265 showDescription(images[current + i].desc); 266 } 267 268 /** 269 * Displays the descriptuon of the current image. 270 * @param {string} desc the description text 271 */ 272 function showDescription(desc) { 273 if(desc) { 274 $desc.html(desc).fadeIn(); 275 } else { 276 $desc.fadeOut(); 277 } 278 } 279 280 /** 281 * Calculates and sets the container height according to the current 282 * image height. 283 * @param {object} $img the current image displayed, it can be null 284 * if it is a video currently displayed. 285 * @param {boolean} animate sets whether to animate the container to the 286 * new height or just change it with CSS. 287 */ 288 function setContainerHeight($img, animate) { 289 var height = video ? $mediaContainer.height() : Math.max($img.get(0).clientHeight, o.minHeight), 290 func = animate ? $.fn.animate : $.fn.css, 291 args = [{ 292 height: height 293 }], 294 width, infoHeight = 0, 295 textHeight, full = fullwidth || $contentContainer.css('width') == $mediaContainer.css('width'); 296 297 if(!video && full && PEXETO.utils.checkIfMobile()){ 298 args[0]['height'] = $img.get(0).clientHeight; 299 } 300 301 302 if(animate) { 303 args.push(o.animationSpeed); 304 } 305 306 if(!video) { 307 func.apply($mediaContainer, args); 308 } 309 310 if($img && PEXETO.getBrowser().msie && (PEXETO.getBrowser().version=='10.0' || PEXETO.getBrowser().version=='9.0')){ 311 //fix a stretching image problem on IE 312 var params = PEXETO.url.getCustomUrlParameters($img.attr('src')); 313 if(params.h && parseInt(params.h,10)<height){ 314 $mediaContainer.css({maxHeight:params.h+'px'}); 315 $img.css({maxHeight:params.h+'px'}); 316 } 317 } 318 319 if(!full) { 320 321 //it is not in a full-width layout 322 width = $contentContainer.width(); 323 $contentContainer.children().not(o.contentTexSel).each(function() { 324 infoHeight += $(this).outerHeight(); 325 }); 326 327 func.apply($root, args); 328 textHeight = height - infoHeight - 2 * contentPadding; 329 330 //init the scrolling plugin for longer texts in the description 331 jscrollApi = $contentContainer.find(o.contentTexSel).css({ 332 height: textHeight, 333 width: width 334 }).jScrollPane().data('jsp'); 335 336 if(!fullwidth) { 337 $root.find('img').on('imgmasonryloaded.'+ o.namespace,function(){ 338 jscrollApi = $contentContainer.find(o.contentTexSel).jScrollPane().data('jsp'); 339 }); 340 } 341 342 } else { 343 344 if(jscrollApi) { 345 var $text = $contentContainer.find(o.contentTexSel).clone(); 346 //disable the scrolling plugin 347 jscrollApi.destroy(); 348 if(!$contentContainer.find(o.contentTexSel).length){ 349 350 $text.insertAfter($contentContainer.find('.ps-categories')); 351 } 352 } 353 354 //set an automatic height to the text area 355 $contentContainer.find(o.contentTexSel).css({ 356 height: 'auto', 357 width: 'auto' 358 }); 359 360 } 361 } 362 363 /** 364 * Displays a loader on the current image. 365 */ 366 function showLoading() { 367 $mediaContainer.append('<div class="' + o.loadingClass + '"></div>'); 368 } 369 370 /** 371 * Hides the loader on the current image. 372 */ 373 function hideLoading() { 374 $mediaContainer.find("." + o.loadingClass).remove(); 375 } 376 377 378 /** 379 * Adds the navigation elements. 380 */ 381 function addNavigation() { 382 //previous/next arrows 383 $larrow = $('<div class="' + o.leftArrowClass + '" ></div>').appendTo($mediaContainer); 384 $rarrow = $('<div class="' + o.rightArrowClass + '" ></div>').appendTo($mediaContainer); 385 386 } 387 388 /** 389 * On next arrow click event handler. Shows the next image if there is 390 * one. 391 */ 392 function doOnNextClicked() { 393 if(!inAnimation) { 394 if((current + 1) < imgNum) { 395 //show next image 396 if(images[current + 1].loaded) { 397 showImage(images[current + 1].el); 398 } else { 399 pendingImg = current + 1; 400 showLoading(); 401 } 402 if(current + 1 === lastLoaded && lastLoaded + 1 < imgNum) { 403 loadNextImages(); 404 } 405 } else { 406 animateLastImage(true); 407 } 408 } 409 } 410 411 /** 412 * On previous arrow click event handler. Shows the previous one if 413 * there is one. 414 */ 415 function doOnPreviousClicked() { 416 if(!inAnimation) { 417 if(current !== 0) { 418 //show previous image 419 showImage(false); 420 } else { 421 animateLastImage(false); 422 } 423 } 424 } 425 426 /** 427 * Animates the slider in a way to show that there isn't anymore images 428 * to display. 429 * @param {boolean} last sets whether it is the last image (when set 430 * to true) or whether it is the first image (when set to false) 431 */ 432 function animateLastImage(last) { 433 var i = last ? -1 : 1; 434 images[current].el.stop().animate({ 435 left: i * 10 436 }, 100, function() { 437 $(this).stop().animate({ 438 left: 0 439 }, 300); 440 }); 441 } 442 443 /** 444 * On window resize event handler. Resets the container size. 445 */ 446 function doOnWindowResize() { 447 var currentObj = video ? null : images[current].el; 448 setContainerHeight(currentObj, false); 449 } 450 451 /** 452 * On navigation click event handler. Fired when one of the 453 * "next project", "previous project" or "back to gallery" buttons 454 * is clicked. 455 * @param {object} e the even object 456 */ 457 function doOnNavigationClick(e) { 458 e.preventDefault(); 459 460 if(!$(this).hasClass('disabled')) { 461 $root.trigger('navigationClick', [$(this).attr('rel')]); 462 $(e.delegateTarget).addClass(o.navLoadingClass); 463 } 464 } 465 466 /** 467 * Destroys the slider. Removes all the registered event handlers. 468 */ 469 function destroySlider() { 470 $(window).off('.' + o.namespace); 471 $root.off('.' + o.namespace).children().off('.' + o.namespace); 472 $navWrapper.off('.' + o.namespace).find(o.navigationSel).eq(0).remove(); 473 } 474 475 init(); 476 477 478 }; 479}(jQuery)); 480 481 482 483/** 484 * Portfolio gallery. 485 * 486 * Dependencies: 487 * - jQuery 488 * - jQuery Masonry : http://masonry.desandro.com 489 * - PEXETO.init.masonry 490 * - Images Loaded : http://github.com/desandro/imagesloaded 491 * - jQuery Easing : http://gsgd.co.uk/sandbox/jquery/easing/ 492 * 493 * @author Pexeto 494 * http://pexetothemes.com 495 */ 496(function($) { 497 "use strict"; 498 499 $.fn.pexetoGallery = function(options) { 500 var defaults = { 501 ajaxUrl : '', 502 itemsPerPage : 10, 503 currentPage : 1, 504 currentCat : '-1', 505 imgheight : 200, 506 additionalWidth : 8,
507 columns : 3, 508 filterCats : [], 509 filterType : 'exclude', 510 masonry : false, 511 enableAJAX : true, 512 animationSpeed : 800, 513 sliderAnimationSpeed : 700, 514 pageUrl : '', 515 singleItem : false, 516 relatedLightbox : false, 517 categoryFilter : true, 518 itemsMap : [], 519 easing : 'easeOutExpo', 520 521 //selectors, classes and IDs 522 itemSel : '.pg-item', 523 imgWrapperSel : '.pg-img-wrapper', 524 itemInfoSel : '.pg-details', 525 paginationSel : '.pg-pagination:first', 526 categorySel : '.pg-cat-filter:first', 527 itemsContainerSel : '.pg-items:first', 528 itemsWrapperSel : '.pg-items-wrapper:first', 529 pageWrapperClass : 'pg-page-wrapper', 530 parentSel : '#full-width', 531 currentClass : 'current', 532 loadingClass : 'pg-loading', 533 elementLoadingClass : 'pg-element-loading', 534 sliderSel : '.ps-wrapper', 535 carItemClass : 'pc-item', 536 carSel : '.portfolio-carousel:first', 537 noCatLoadingClass : 'pg-nocat-loading', 538 filterBtnSel : '.pg-filter-btn', 539 openedClass : 'filter-opened', 540 galleryHiddenClass : 'pg-gallery-hidden' 541 }, 542 o = $.extend(defaults, options), 543 $root = this, 544 $itemsContainer = null, 545 $categoryContainer = null, 546 $paginationContainer = null, 547 $itemsWrapper = null, 548 $parent = $root.parent(), 549 $loadingContainer = null, 550 currentPage = o.currentPage, 551 previousPage = currentPage, 552 cachedItems = [], 553 cachedSliderItems = [], 554 currentXhr = null, 555 $currentPage = null, 556 containerWidth = 0, 557 supportsHistory = (window.history && window.history.pushState) ? true : false, 558 currentCat = o.currentCat, 559 currentItem = o.itemId || 0, 560 inAnimation = false, 561 $slider = null, 562 $prevSlider = null, 563 $carousel = null, 564 $prevCarousel = null, 565 pendingLoadings = [], 566 $filterBtn = $(o.filterBtnSel), 567 filterDisplayed = false, 568 filterInAnimation = false, 569 galleryView = false, 570 $navWrapper = $('.pg-nav-wrapper'), 571 resizeManager = null, 572 $pageTop = null, 573 $itemTop = null, 574 scrollOffset = 0; 575 576 577 578 /** 579 * Inits the main functionality - inits a gallery view if the gallery 580 * has been selected or a slider view if a slider has been selected. 581 */ 582 function init() { 583 var $pageWrapper = null, 584 data, 585 catName; 586 587 if(!o.singleItem) { 588 //load the main gallery elements 589 $itemsContainer = $root.find(o.itemsContainerSel); 590 $categoryContainer = $(o.categorySel); 591 $paginationContainer = $root.find(o.paginationSel); 592 $itemsWrapper = $root.find(o.itemsWrapperSel); 593 } 594 595 setScrollTop(); 596 bindEventHandlers(); 597 598 if(!o.singleItem) { 599 //it is a gallery view 600 $pageWrapper = $root.find('.' + o.pageWrapperClass); 601 galleryView = true; 602 603 //add the currently loaded items to the cache 604 addCachedItem({ 605 cat: currentCat, 606 page: currentPage 607 }, { 608 pageWrapper: $pageWrapper, 609 paginationUl: $paginationContainer.find('ul') 610 }); 611 612 613 $currentPage = $pageWrapper; 614 setContainerWidth($currentPage); 615 616 //display the gallery view 617 showCurrentItems(false); 618 $loadingContainer = $categoryContainer.length ? $categoryContainer : $('<div />', { 619 'class': o.noCatLoadingClass 620 }).insertBefore($parent); 621 622 623 addLoadingTo($loadingContainer, null); 624 625 //init masonry 626 resizeManager = new PEXETO.utils.resizableImageGallery(o.itemSel, { 627 parent: $currentPage, 628 masonry : o.masonry 629 }).init(); 630 631 //init lightbox 632 initLightbox($currentPage); 633 634 //set the current category name to the filter button 635 if(o.categoryFilter){ 636 catName = $categoryContainer.find('a[data-cat="'+currentCat+'"]').html(); 637 setFilterBtnText(catName); 638 } 639 640 } else { 641 //it is a single slider item, load the slider and the images 642 $slider = $root.find(o.sliderSel); 643 $carousel = $root.find(o.carSel); 644 645 if(o.video) { 646 initSlider([], null); 647 $slider.trigger('sliderVisible'); 648 } else { 649 //load the slider images 650 data = { 651 action: 'pexeto_get_slider_images', 652 itemid: o.itemId 653 }; 654 655 getJsonAjax(data).done(function(res) { 656 var images = res || []; 657 658 initSlider(images, null); 659 });
660 } 661 } 662 663 664 } 665 666 667 /*********************************************************************** 668 * GENERAL FUNCTIONS 669 **********************************************************************/ 670 671 672 /** 673 * Retrieves the current page items depending on the category and page 674 * selected. First checks if these items have been already opened and 675 * added to the cache and if so, loads the items from the cache. If not, 676 * makes an AJAX request to load the items. 677 * @param {object} args containing the arguments for the page: 678 * - cat : setting the category to load 679 * - page : setting the number of the page to load 680 * Once the items are retrieved, calls a function to display them. 681 */ 682 function getPageItems(args) { 683 var data, callback = (args.cat && !args.page) ? showCatItems : showPageItems, 684 page = args.page || 1, 685 cat = args.cat || '-1', 686 cachedItem = getCachedItem(args), 687 requireNav = (cachedItem && cachedItem.pagination) ? false : true, 688 $newPagination = null, 689 callbackArgs = {}; 690 691 if(cachedItem && cachedItem.pages[page]) { 692 //the items with these arguments are already loaded 693 //show the cached items 694 if(cat !== currentCat) { 695 callbackArgs.pagination = cachedItem.pagination; 696 } 697 callbackArgs.page = cachedItem.pages[page]; 698 callbackArgs.cached = true; 699 setCurrentVars(args); 700 callback.call(null, callbackArgs); 701 } else { 702 //prepare the data for an AJAX request 703 data = { 704 page: page, 705 number: o.itemsPerPage, 706 imgheight: o.imgheight, 707 columns: o.columns, 708 filter_cats: o.filterCats, 709 filter_type: o.filterType, 710 page_url: o.pageUrl, 711 require_nav: requireNav, 712 orderby: o.orderby, 713 order: o.order, 714 action: 'pexeto_get_portfolio_items' 715 }; 716 717 if(cat !== '-1') { 718 data.cat = cat; 719 } 720 721 //make the AJAX request 722 getJsonAjax(data).done(function(res) { 723 //the AJAX request was successfull 724 var cacheItems = {}, 725 $pagination = null, 726 $newPage = null, 727 args = { 728 cat: cat, 729 page: page 730 }; 731 732 733 if(res.items !== undefined) { 734 setCurrentVars(args); 735 $newPage = $('<div />', { 736 'class': o.pageWrapperClass 737 }).append(res.items); 738 739 $newPage.find(o.itemSel).css({ 740 opacity: 1 741 }); 742 cacheItems.pageWrapper = $newPage; 743 callbackArgs.page = $newPage; 744 745 if(requireNav) { 746 //set the navigation 747 $pagination = $(res.pagination); 748 cacheItems.paginationUl = $pagination; 749 callbackArgs.pagination = $pagination; 750 } 751 752 initLightbox($newPage); 753 addCachedItem(args, cacheItems); 754 callback.call(null, callbackArgs); 755 } 756 }); 757 } 758 } 759 760 /** 761 * Loads a slider item. Checks if the item has been already loaded 762 * and added to the cache and if so, uses the cached item. If not, 763 * makes an AJAX request to load the slider data. After the data 764 * is loaded, adds the slider element to the content wrapper and 765 * initializes it. 766 * @param {int} itemId the ID of the item to be displayed as a slider 767 */ 768 function loadSliderItem(itemId) { 769 var data, doOnSliderContentLoaded; 770 771 if(!inAnimation && currentItem !== itemId) { 772 abortPendingRequests(); 773 774 data = { 775 itemid: itemId, 776 single: o.singleItem, 777 action: 'pexeto_get_portfolio_slider_item' 778 }; 779 780 if(!o.singleItem && getSiblingId(true, itemId) === -1) { 781 data.next = false; 782 } 783 784 if(!o.singleItem && getSiblingId(false, itemId) === -1) { 785 data.prev = false; 786 } 787 788 //set a callback function that will be called when the slider 789 //data is retrieved 790 doOnSliderContentLoaded = function(res) { 791 var images, itemLink, navigation; 792 793 if(res) { 794 $prevSlider = $slider || null; 795 $prevCarousel = $carousel || null; 796 currentItem = itemId; 797 798 if(supportsHistory) { 799 //change the URL in the browser 800 itemLink = res.permalink; 801 if($prevSlider) { 802 window.history.replaceState({ 803 item: itemId 804 }, null, itemLink); 805 } else { 806 window.history.pushState({ 807 item: itemId 808 }, null, itemLink); 809 } 810 } 811 812 //create the slider object 813 $slider = $(res.slider).appendTo($root).eq(0); 814 815 //create the carousel object 816 if(res.carousel) { 817 $carousel = $(res.carousel); 818 $carousel.insertAfter($slider); 819 } 820 images = res.images || []; 821 navigation = res.slider_nav || null; 822 initSlider(images, navigation); 823 824 825 826 if(!cachedSliderItems[itemId]) { 827 //cache the result 828 cachedSliderItems[itemId] = res; 829 } 830 831 } 832 }; 833 834 if(cachedSliderItems[itemId]) { 835 //the slider item is cached, use the cache data 836 doOnSliderContentLoaded(cachedSliderItems[itemId]); 837 } else { 838 //load the data with AJAX 839 getJsonAjax(data).done(doOnSliderContentLoaded); 840 } 841 } 842 } 843 844 /** 845 * Initializes the slider and carousel script. 846 * @param {array} images the images that the slider will display 847 */ 848 function initSlider(images, navigation) { 849 //init the slider 850 $slider.pexetoPortfolioSlider({ 851 images: images, 852 navigation : navigation 853 }); 854 //init the carousel 855 if($carousel) { 856 $carousel.pexetoCarousel({ 857 selfDisplay: false 858 }); 859 } 860 } 861 862 863 /*********************************************************************** 864 * EVENT HANDLER FUNCTIONS 865 **********************************************************************/ 866 867 /** 868 * Binds the event handlers. 869 */ 870 function bindEventHandlers() { 871 872 if(o.enableAJAX) { 873 874 if(!o.singleItem) { 875 //pagination events 876 $paginationContainer.on('click', 'a', doOnPaginationClick); 877 878 if(o.categoryFilter){ 879 //category events 880 $categoryContainer.on('click', 'a', doOnCategoryClick); 881 882 } 883 } 884 885 //item click events 886 $root.on('click', 887 o.itemSel + '[data-type="smallslider"],.' 888 + o.carItemClass + '[data-type="smallslider"], ' 889 + o.itemSel + '[data-type="fullslider"],.' 890 + o.carItemClass + '[data-type="fullslider"]', 891 doOnItemSliderClick) 892 .on('click', 893 o.itemSel + '[data-type="smallvideo"],.' 894 + o.carItemClass + '[data-type="smallvideo"], ' 895 + o.itemSel + '[data-type="fullvideo"],.' 896 + o.carItemClass + '[data-type="fullvideo"]', 897 doOnItemVideoClick) 898 .on('navigationClick', o.sliderSel, doOnNavigationClick); 899 900 if(supportsHistory) { 901 window.onpopstate = function(e) { 902 if(!galleryView && !o.singleItem) { 903 backToGallery(); 904 } 905 }; 906 } 907 } 908 909 if(o.categoryFilter){ 910 $filterBtn.on('click', doOnFilterClick); 911 } 912 913 //lightbox click events 914 $root.on('click', 915 o.itemSel + '[data-type="lightbox"],.' 916 + o.carItemClass + '[data-type="lightbox"]', 917 doOnItemLightboxClick) 918 .on('sliderLoaded', o.sliderSel, showSlider); 919 920 $(window).on('resize', function() { 921 if($currentPage) { 922 setContainerWidth($currentPage); 923 } 924 925 if(o.categoryFilter){ 926 setFilterVisibility(); 927 } 928 }); 929 } 930 931 /** 932 * On pagination click handler. If a new page has been requested, calls 933 * a function to load the items from that page. 934 * @param {e} e the event object 935 */ 936 function doOnPaginationClick(e) { 937 e.preventDefault(); 938 var page = $(this).data('page') || 1; 939 940 if(page !== currentPage && !inAnimation) { 941 abortPendingRequests(); 942 addLoadingTo($paginationContainer, null); 943 getPageItems({ 944 page: page, 945 cat: currentCat 946 }); 947 948 //set the current CSS class to the selected page 949 $paginationContainer.find("." + o.currentClass).removeClass(o.currentClass); 950 $(this).addClass(o.currentClass); 951 952 if(supportsHistory) { 953 //change the URL in the browser 954 window.history.replaceState({ 955 gallery: true 956 }, null, $(this).attr('href')); 957 } 958 } 959 } 960 961 /** 962 * On category click handler. If a new category has been requested, 963 * calls a function to load the items from that category. 964 * @param {e} e the event object 965 */ 966 function doOnCategoryClick(e) { 967 e.preventDefault(); 968 var cat = $(this).data('cat') || '-1'; 969 cat = String(cat); 970 971 if(cat !== currentCat && !inAnimation) { 972 abortPendingRequests(); 973 974 addLoadingTo($categoryContainer, null); 975 getPageItems({ 976 cat: cat 977 }); 978 979 //set the current CSS class to the selected category 980 $categoryContainer.find("." + o.currentClass).removeClass(o.currentClass); 981 $(this).addClass(o.currentClass); 982 983 setFilterBtnText($(this).html()); 984 985 if(filterDisplayed){ 986 hideFilter(); 987 } 988 989 if(supportsHistory) { 990 //change the URL in the browser 991 window.history.replaceState({ 992 gallery: true 993 }, null, $(this).attr('href')); 994 } 995 } 996 } 997 998 999 /** 1000 * On slider item click event handler. Calls a function to load the 1001 * slider data of this item. 1002 * @param {object} e the event object 1003 */ 1004 function doOnItemSliderClick(e) { 1005 e.preventDefault(); 1006 1007 var itemId = parseInt($(this).data('itemid'), 10); 1008 1009 loadSliderItem(itemId); 1010 1011 addLoadingTo(null, $(this)); 1012 } 1013 1014 /** 1015 * On video item click event handler. Calls a function to load the 1016 * video slider data of this item. 1017 * @param {object} e the event object 1018 */ 1019 function doOnItemVideoClick(e) { 1020 e.preventDefault(); 1021 1022 var itemId = parseInt($(this).data('itemid'), 10); 1023 1024 loadSliderItem(itemId); 1025 1026 addLoadingTo(null, $(this)); 1027 } 1028 1029 /** 1030 * On lightbox item click event handler. Calls a function to load the 1031 * lightbox preview image of this item. 1032 * @param {object} e the event object 1033 */ 1034 function doOnItemLightboxClick(e) { 1035 var data, 1036 $el; 1037 1038 if(!o.relatedLightbox || $(this).hasClass(o.carItemClass)) { 1039 e.preventDefault(); 1040 1041 data = { 1042 action: 'pexeto_get_slider_images', 1043 itemid: $(this).data('itemid') 1044 }; 1045 1046 addLoadingTo(null, $(this)); 1047 1048 //load the item images with an AJAX request 1049 getJsonAjax(data).done(function(res) { 1050 var images = res || [], 1051 pp_images = [], 1052 pp_titles = [], 1053 pp_descs = [], 1054 i, len; 1055 1056 for(i = 0, len = images.length; i < len; i++) { 1057 pp_images[i] = images[i].img; 1058 pp_titles[i] = ''; 1059 pp_descs[i] = images[i].desc; 1060 } 1061 1062 removeLoading(); 1063 1064 $.prettyPhoto.open(pp_images, pp_titles, pp_descs); 1065 }); 1066 } 1067 } 1068 1069 /** 1070 * Slider navigation click event handler - fired when one of the 1071 * "next project", "previous project" or "back to gallery" button 1072 * was clicked. 1073 * @param {object} e the event object 1074 * @param {string} rel the rel attribute of the clicked button which 1075 * sets the type of the action to perform. 1076 */ 1077 function doOnNavigationClick(e, rel) { 1078 var newItemId; 1079 1080 switch(rel) { 1081 case 'back': 1082 //back to gallery 1083 backToGallery(); 1084 break; 1085 case 'prev': 1086 //load the previous item 1087 newItemId = getSiblingId(false, currentItem); 1088 if(newItemId !== -1) { 1089 loadSliderItem(newItemId); 1090 } 1091 break; 1092 case 'next': 1093 //load the next item 1094 newItemId = getSiblingId(true, currentItem); 1095 if(newItemId !== -1) { 1096 loadSliderItem(newItemId); 1097 } 1098 break; 1099 } 1100 } 1101 1102 function doOnFilterClick() { 1103 var that = $(this); 1104 1105 if(filterDisplayed){ 1106 hideFilter(); 1107 }else{ 1108 showFilter(); 1109 } 1110 } 1111 1112 function hideFilter(){ 1113 if (!filterInAnimation) { 1114 filterInAnimation = true; 1115 $filterBtn.removeClass(o.openedClass); 1116 $categoryContainer.find('ul').animate({height:'hide'}, function() { 1117 filterInAnimation = false; 1118 filterDisplayed = false; 1119 }); 1120 } 1121 } 1122 1123 function showFilter(){ 1124 if (!filterInAnimation) { 1125 filterInAnimation = true; 1126 $filterBtn.addClass(o.openedClass); 1127 $categoryContainer.find('ul').animate({height:'show'}, function() { 1128 filterInAnimation = false; 1129 filterDisplayed = true; 1130 }); 1131 } 1132 } 1133 1134 1135 /*********************************************************************** 1136 * AJAX FUNCTIONS 1137 **********************************************************************/ 1138 1139 /** 1140 * Makes a JSON AJAX request with the specified data. 1141 * @param {object} data the data that will be sent in the request. 1142 * @return {object} the XHR object of the request 1143 */ 1144 function getJsonAjax(data) { 1145 if(!currentXhr) { 1146 currentXhr = $.ajax({
1147 url: o.ajaxUrl, 1148 data: data, 1149 dataType: 'json', 1150 type: 'GET' 1151 }).always(function() { 1152 currentXhr = null; 1153 }); 1154 } 1155 1156 return currentXhr; 1157 } 1158 1159 /*********************************************************************** 1160 * ELEMENT ACCESS AND CHANGE FUNCTIONS 1161 **********************************************************************/ 1162 1163 1164 /** 1165 * Displays the slider. Hides the current elements (can be a gallery 1166 * or another slider) and then displays the slider with its carousel 1167 * (if there is one set). 1168 */ 1169 function showSlider() { 1170 galleryView = false; 1171 removeLoading(); 1172 1173 //set the display slider animation 1174 var displaySlider = function() { 1175 $slider.css({ 1176 opacity: 0, 1177 display: 'block', 1178 marginTop: 200 1179 }).trigger('sliderVisible').animate({ 1180 opacity: 1, 1181 marginTop: 0 1182 }, o.sliderAnimationSpeed); 1183 PEXETO.init.quickGallery(); 1184 setTimeout(function() { 1185 1186 1187 if(PEXETO.getBrowser().msie){ 1188 $carousel.css({ 1189 marginTop: 0, 1190 opacity: 1 1191 }); 1192 }else{ 1193 $carousel.css({ 1194 opacity: 0, 1195 marginTop: 200 1196 }).animate({ 1197 opacity: 1, 1198 marginTop: 0 1199 }, o.sliderAnimationSpeed); 1200 } 1201 }, o.sliderAnimationSpeed / 2); 1202 1203 }; 1204 1205 if(o.singleItem && !$prevSlider) { 1206 //it is a single item page where just the slider should be 1207 //displayed 1208 displaySlider(); 1209 } else { 1210 //scroll to the top, in case the slider has been opened 1211 //from the bottom of a long gallery 1212 $.scrollTo($pageTop, { 1213 duration: 500 1214 ,offset: { 1215 top: scrollOffset 1216 } 1217 }); 1218 1219 1220 1221 if($prevSlider) { 1222 //a slider is currently displayed, hide its elements 1223 1224 //hide the carousel 1225 if($prevCarousel) { 1226 $prevCarousel.animate({ 1227 opacity: 0 1228 }, o.sliderAnimationSpeed - 100, function() { 1229 $prevCarousel.trigger('destroy').remove(); 1230 }); 1231 } 1232 1233 //hide the slider 1234 $prevSlider.animate({ 1235 marginTop: 500, 1236 opacity: 0 1237 }, o.sliderAnimationSpeed, function() { 1238 displaySlider(); 1239 $(this).trigger('destroy').remove(); 1240 }); 1241 1242 } else { 1243 //a gallery is currently displayed, hide the gallery 1244 $itemsWrapper.animate({ 1245 marginTop: 500, 1246 opacity: 0, 1247 height: 'hide' 1248 }, o.sliderAnimationSpeed, function() { 1249 $('body').addClass(o.galleryHiddenClass); 1250 displaySlider(); 1251 if($categoryContainer.length){ 1252 $categoryContainer.hide(); 1253 } 1254 if(resizeManager){ 1255 resizeManager.pause(); 1256 } 1257 }); 1258 } 1259 } 1260 } 1261 1262 /** 1263 * Shows the gallery after a slider's back to gallery button has been 1264 * clickec. 1265 */ 1266 function backToGallery() { 1267 if(o.singleItem || !$slider) { 1268 return false; 1269 } 1270 1271 removeLoading(); 1272 1273 //hide the slider 1274 $slider.animate({ 1275 marginTop: 500, 1276 opacity: 0 1277 }, o.sliderAnimationSpeed, function() { 1278 $slider.trigger('destroy').remove(); 1279 $slider = null; 1280 currentItem = 0; 1281 galleryView = true; 1282 1283 if($categoryContainer.length){ 1284 $categoryContainer.fadeIn(); 1285 } 1286 1287 //show the gallery items 1288 $itemsWrapper.animate({ 1289 height: 'show' 1290 }, 0); 1291 setContainerWidth($currentPage); 1292 1293 setMasonry($currentPage, false); 1294 1295 $itemsWrapper.animate({ 1296 marginTop: 0, 1297 opacity: 1, 1298 height: 'show' 1299 }, o.sliderAnimationSpeed); 1300 1301 $('body').removeClass(o.galleryHiddenClass); 1302 }); 1303 1304 //hide the carousel 1305 if($carousel) { 1306 $carousel.animate({ 1307 marginTop: 500, 1308 opacity: 0 1309 }, o.sliderAnimationSpeed, function() { 1310 $carousel.trigger('destroy').remove(); 1311 $carousel = null; 1312 }); 1313 } 1314 1315 if(supportsHistory) { 1316 //change the URL of the current page in the browser address bar 1317 window.history.pushState({ 1318 back: true 1319 }, null, o.pageUrl); 1320 } 1321 } 1322 1323 /** 1324 * Shows a new set of items to be displayed. 1325 * @param {boolean} cached setting whether the items have been cached 1326 * (loaded earlier) or they have been just loaded to the page. 1327 * @return {object} a $.Deferred object, which will be resolved 1328 * once the animation has finished and the items are displayed. 1329 */ 1330 function showCurrentItems(cached) { 1331 1332 var loadedItems = [], 1333 $items = $currentPage.find(o.itemSel).css({ 1334 opacity: 0 1335 }), 1336 itemNum = $items.length, 1337 pendingIndex = 0, 1338 def = new $.Deferred(), 1339 //timer animation function that will display the items one by one 1340 //with a delay after each item's animation 1341 timeoutAnimation = function(index) { 1342 setTimeout(function() { 1343 showItem(index); 1344 }, 100); 1345 if(index + 1 === itemNum) { 1346 def.resolve(); 1347 removeLoading(); 1348 } 1349 }, 1350 //displays an item with the index set 1351 showItem = function(index) { 1352 var initArgs = o.masonry ? {marginTop:100} : {top:100}, 1353 endArgs = o.masonry ? {marginTop:0} : {top:0}; 1354 1355 endArgs.opacity = 1; 1356
1357 $items.eq(index).css(initArgs).animate(endArgs, function(){ 1358 if(o.masonry && resizeManager){ 1359 //refresh the masonry layout to position the items better 1360 resizeManager.refresh(); 1361 } 1362 }); 1363 1364 if(cached || loadedItems[index + 1]) { 1365 timeoutAnimation(index + 1); 1366 } else { 1367 pendingIndex = index + 1; 1368 } 1369 }; 1370 1371 if(!cached) { 1372 $currentPage.find('img').on('imgmasonryloaded', function() { 1373 //an item's image has been loaded, set its index as loaded 1374 var $parent = $(this).parents(o.itemSel), 1375 index = $items.index($parent); 1376 1377 loadedItems[index] = true; 1378 1379 if(pendingIndex == index) { 1380 timeoutAnimation(index); 1381 } 1382 }); 1383 } else { 1384 timeoutAnimation(0); 1385 } 1386 1387 return def.promise(); 1388 } 1389 1390 1391 /** 1392 * Displays a set of items after a new category has been selected. 1393 * @param {object} args arguments setting: 1394 * - page - the jQuery page wrapper object 1395 * - cached - boolean setting whether the items have been cached or just 1396 * loaded to the page 1397 * - pagination - a juery pagination object 1398 */ 1399 function showCatItems(args) { 1400 var $newPage = args.page, 1401 cached = args.cached, 1402 $pagination = args.pagination, 1403 def; 1404 1405 inAnimation = true; 1406 1407 //hide the current pagination 1408 $paginationContainer.css({ 1409 opacity: 0 1410 }); 1411 1412 //hide the current page 1413 $currentPage.animate({ 1414 opacity: 0 1415 }, function() { 1416 //insert the new page 1417 $newPage.insertAfter($currentPage).css({ 1418 opacity: 1, 1419 marginLeft: 0 1420 }); 1421 1422 setContainerWidth($newPage); 1423 1424 $currentPage.detach(); 1425 $currentPage = $newPage; 1426 1427 //animate the items in the page 1428 def = showCurrentItems(cached).done(function() { 1429 inAnimation = false; 1430 if($pagination) { 1431 $paginationContainer.css({ 1432 opacity: 1 1433 }).html($pagination); 1434 } 1435 }); 1436 $paginationContainer.find("." + o.currentClass).removeClass(o.currentClass); 1437 $paginationContainer.find('li:first a').addClass(o.currentClass); 1438 1439 setMasonry($newPage, false); 1440 }); 1441 } 1442 1443 /** 1444 * Displays a set of items after a new page has been selected. 1445 * @param {object} args arguments setting: 1446 * - page - the jQuery page wrapper object 1447 * - cached - boolean setting whether the items have been cached or just 1448 * loaded to the page 1449 */ 1450 function showPageItems(args) { 1451 var $newPage = args.page, 1452 cached = args.cached, 1453 showNext = parseInt(previousPage, 10) > parseInt(currentPage, 10) ? false : true, 1454 currentHeight = 0, 1455 newPageMargin = showNext ? 0 : -containerWidth, 1456 currentPageMargin = showNext ? -containerWidth : 0; 1457 1458 1459 inAnimation = true; 1460 1461 $newPage.find('img').pexetoOnImgLoaded({callback:function() { 1462 //the images are loaded, show the new page 1463 //set the new page initial position for the animation 1464 //hide the loadings 1465 removeLoading(); 1466 1467 setContainerWidth($newPage); 1468 $newPage.show().css({ 1469 marginLeft: newPageMargin, 1470 opacity: 0 1471 }); 1472 1473 $.scrollTo($itemTop, { 1474 duration: 600, 1475 offset: { 1476 top: scrollOffset 1477 }, 1478 onAfter : function(){ 1479 //insert the new page 1480 if(showNext) { 1481 $newPage.insertAfter($currentPage).animate({ 1482 opacity: 1 1483 }); 1484 } else { 1485 $newPage.insertBefore($currentPage).animate({ 1486 marginLeft: 0, 1487 opacity: 1 1488 }, o.animationSpeed, o.easing); 1489 } 1490 1491 $newPage.find(o.itemSel).css({opacity:1}); 1492 1493 setMasonry($newPage, false); 1494 1495 //set the container height according to the new page height 1496 setContainerHeight($newPage, true); 1497 1498 //animate the current page to get hidden 1499 $currentPage.animate({ 1500 marginLeft: currentPageMargin, 1501 opacity: 0 1502 }, o.animationSpeed, o.easing, function() { 1503 $(this).detach(); 1504 inAnimation = false; 1505 }); 1506 1507 $currentPage = $newPage; 1508 1509 }}); 1510 }}); 1511 } 1512 1513 /** 1514 * Sets the containerWidth variable and refreshes the current page 1515 * width with this value. 1516 * @param {object} $page a jQuery object of the current page element 1517 */ 1518 function setContainerWidth($page) { 1519 if(galleryView) { 1520 containerWidth = $parent.width() + o.additionalWidth; 1521 $page.width(containerWidth);
1522 } 1523 } 1524 1525 /** 1526 * Sets the items container height according to the wrapping page 1527 * height. 1528 * @param {object} $page a jQuery object of the current page element 1529 * @param {boolean} animate sets whether to animate the height change 1530 * or to just apply it with CSS. 1531 */ 1532 function setContainerHeight($page, animate) { 1533 var pageHeight = $page.height(); 1534 if(animate) { 1535 $itemsContainer.animate({ 1536 height: pageHeight 1537 }, o.animationSpeed); 1538 } else { 1539 $itemsContainer.css({ 1540 height: pageHeight 1541 }); 1542 } 1543 } 1544 1545 /** 1546 * Populates the filter button text with the currently selected category 1547 * name. This button is displayed on small screen devices only. 1548 * @param {string} catName the name of the selected category 1549 */ 1550 function setFilterBtnText(catName){ 1551 $filterBtn.find("span:first").html(catName); 1552 } 1553 1554 function setFilterVisibility(){ 1555 if(galleryView && !$filterBtn.is(':visible') && !$categoryContainer.find('ul').is(':visible')){ 1556 $categoryContainer.find('ul').css({display:'inline-block'}); 1557 } 1558 } 1559 1560 /*********************************************************************** 1561 * HELPER FUNCTIONS 1562 **********************************************************************/ 1563 1564 /** 1565 * Inits the Masonry script to the page wrapper element. 1566 * @param {object} $page jQuery page wrapper element that contains 1567 * the masonry items 1568 * @param {boolean} cached sets whether the items have been already 1569 * cached and in this case will just refresh the script or whether 1570 * they have been just loaded (will initialize the script) 1571 */ 1572 function setMasonry($page, cached) { 1573 if(cached && resizeManager) { 1574 //refresh the masonry 1575 resizeManager.resume(); 1576 resizeManager.refresh(); 1577 } else { 1578 //init the masonry 1579 resizeManager = new PEXETO.utils.resizableImageGallery(o.itemSel, { 1580 parent: $page, 1581 masonry : o.masonry 1582 }).init(); 1583 } 1584 } 1585 1586 1587 /** 1588 * Retrieves the ID of the next/previous sibling element. 1589 * @param {boolean} next sets if it is the next item or the previous 1590 * whose ID should be retrieved 1591 * @param {int} itemId the ID of the current item 1592 * @return {int} the ID of the next/previous item if 1593 * there is one or -1 of there isn't such an item. 1594 */ 1595 function getSiblingId(next, itemId) { 1596 var i = next ? 1 : -1, 1597 itemIndex = $.inArray(itemId, o.itemsMap), 1598 newItemId = -1; 1599 if(itemIndex !== -1 && o.itemsMap[itemIndex + i]) { 1600 newItemId = o.itemsMap[itemIndex + i]; 1601 } 1602 return newItemId; 1603 } 1604 1605 /** 1606 * Inits the lightbox when the preview images of all the items are set 1607 * to be related to each other in the lightbox. 1608 * @param {object} $wrapper a jQuery wrapper object that contains all 1609 * the items 1610 */ 1611 function initLightbox($wrapper) { 1612 if(o.relatedLightbox) { 1613 PEXETO.init.lightbox($wrapper.find(o.itemSel 1614 + '[data-type="lightbox"] a,.' + o.carItemClass 1615 + '[data-type="lightbox"] a'), {deeplinking:false}); 1616 } 1617 } 1618 1619 /** 1620 * Sets the current page and category variables. 1621 * @param {object} args containing the new variables that should be set: 1622 * - page : the current page number 1623 * - cat : the current category ID 1624 */ 1625 function setCurrentVars(args) { 1626 previousPage = currentPage; 1627 currentPage = args.page || 1; 1628 currentCat = args.cat || '-1'; 1629 } 1630 1631 /** 1632 * Adss a loaded page with items to the cache. 1633 * @param {object} args setting the current page and category: 1634 * - page : the current page number 1635 * - cat : the current category ID 1636 * @param {object} items object containing the elements that will be 1637 * cached with the following keys: 1638 * - pageWrapper : the page wrapper object 1639 * - paginationUL : the pagination object 1640 */ 1641 function addCachedItem(args, items) { 1642 var cat = args.cat || '-1', 1643 page = args.page || 1, 1644 cachedItem = null; 1645 1646 if(!cachedItems[cat]) { 1647 //add a cached item for this category 1648 cachedItems[cat] = { 1649 pages: [], 1650 pagination: null 1651 }; 1652 } 1653 cachedItem = cachedItems[cat]; 1654 if(!cachedItem.pages[page]) { 1655 //add a cached item for this page 1656 cachedItem.pages[page] = items.pageWrapper; 1657 } 1658 1659 if(items.paginationUl && !cachedItem.pagination) { 1660 //cache the pagination 1661 cachedItem.pagination = items.paginationUl; 1662 } 1663 1664 } 1665 1666 /** 1667 * Retrieves an item from a cache according to the selected page and 1668 * category. 1669 * @param {object} args setting the current page and category: 1670 * - page : the current page number 1671 * - cat : the current category ID 1672 * @return the cached object if it exists or null if it doesn't exist 1673 */ 1674 function getCachedItem(args) { 1675 var cat = args.cat || '-1', 1676 page = args.page || 1; 1677 1678 return cachedItems[cat] || null; 1679 } 1680 1681 /** 1682 * Aborts the current pending requests. 1683 */ 1684 function abortPendingRequests() { 1685 if(currentXhr) { 1686 //there is a request pending, abort it and execute this one 1687 currentXhr.abort(); 1688 } 1689 removeLoading(); 1690 } 1691 1692 /** 1693 * Appends a loader element to the specified element. 1694 * @param {object} $el a jQuery element to which to append the loading 1695 * @param {object} $parent the parent element to which to assign a loading 1696 * class. If set to null, the loading class will be assigned to the $el 1697 * element. 1698 */ 1699 function addLoadingTo($el, $parent) { 1700 var loadingEl = {}; 1701 1702 if($el){ 1703 var $pendingLoading = $('<div />', { 1704 "class": o.loadingClass 1705 }); 1706 $el.append($pendingLoading).addClass(o.elementLoadingClass); 1707 loadingEl.loading = $pendingLoading; 1708 } 1709 1710 1711 $parent = $parent || $el; 1712 $parent.addClass(o.elementLoadingClass); 1713 loadingEl.el = $parent; 1714 1715 pendingLoadings.push(loadingEl); 1716 } 1717 1718 /** 1719 * Removes a loader element. 1720 * @return {object} the jQuery loader element to remove. 1721 */ 1722 function removeLoading() { 1723 var pendingItem = null; 1724 1725 while(pendingLoadings.length) { 1726 pendingItem = pendingLoadings.pop(); 1727 if(pendingItem.loading){ 1728 pendingItem.loading.remove(); 1729 } 1730 1731 pendingItem.el.removeClass(o.elementLoadingClass); 1732 1733 } 1734 } 1735 1736 function setScrollTop(){ 1737 $pageTop = $navWrapper.length ? $navWrapper : $('#content-container'); 1738 $itemTop = $navWrapper; 1739 1740 if($('body').hasClass('fixed-header')){ 1741 scrollOffset = -90; 1742 }else{ 1743 scrollOffset = -15; 1744 } 1745 1746 } 1747 1748 init(); 1749 1750 return this; 1751 1752 }; 1753}(jQuery));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.