(function ($){
function getScrollY(elem){
return window.pageYOffset||document.documentElement.scrollTop;
}
function Sticky(el, options){
var self=this;
this.el=el;
this.$el=$(el);
this.prevStickyHeaderState=null;
this.options={
hideStickyHeader: false,
fullWidth: false,
};
$.extend(this.options, options);
self.init();
}
$.fn.scSticky=function (options){
$(this).each(function (){
return new Sticky(this, options);
});
}
Sticky.prototype={
init: function (){
var self=this;
this.$wrapper=false;
this.$parent=this.getParent();
$(window).scroll(function (){
if(self.useSticky()){
self.wrap();
self.scroll();
}else{
self.unwrap();
}});
$(window).resize(function (){
if(self.useSticky()){
self.wrap();
self.scroll();
}else{
self.unwrap();
}});
},
wrap: function (){
if(!this.$wrapper)
this.$wrapper=this.$el.wrap('<div />').parent();
this.$wrapper.attr('class', this.$el.attr('class')).addClass('gem-sticky-block').css({
padding: 0,
height: this.$el.outerHeight()
});
if(this.options.fullWidth){
this.$el.css({
width: "",
margin: "",
padding: ""
});
var marg=(window.innerWidth - this.$wrapper.outerWidth()) / 2;
this.$el.css({
width: window.innerWidth,
margin: 0,
marginLeft: -marg,
marginRight: -marg,
paddingLeft: parseInt(this.$el.css('padding-left')) + marg,
paddingRight: parseInt(this.$el.css('padding-right')) + marg
});
}else{
this.$el.css({
width: this.$wrapper.outerWidth(),
margin: 0
});
}},
getParent: function (){
return this.$el.parent();
},
useSticky: function (){
var is_sidebar=true;
if(this.$el.hasClass('sidebar')){
if(this.$wrapper){
if(this.$wrapper.outerHeight() > this.$wrapper.siblings('.panel-center:first').outerHeight())
is_sidebar=false;
}else{
if(this.$el.outerHeight() > this.$el.siblings('.panel-center:first').outerHeight())
is_sidebar=false;
}}
return $(window).width() > 1000&&is_sidebar;
},
unwrap: function (){
if(this.$el.parent().is('.gem-sticky-block')){
this.$el.unwrap();
this.$wrapper=false;
}
this.$el.css({
width: "",
top: "",
bottom: "",
margin: "",
padding: ""
});
},
scroll: function (){
var top_offset=parseInt($('html').css('margin-top'));
var $header=$('#site-header');
if($header.hasClass('fixed')&&!this.options.hideStickyHeader){
top_offset +=$header.outerHeight();
}
var scroll=getScrollY();
var offset=this.$wrapper.offset();
var parent_offset=this.$parent.offset();
var parent_bottom=parent_offset.top + this.$parent.outerHeight() - scroll;
var bottom=$(window).height() - parent_bottom;
if((top_offset + this.$el.outerHeight()) >=parent_bottom){
this.$el.addClass('sticky-fixed').css({
top: "",
bottom: bottom,
left: offset.left
});
if(this.options.hideStickyHeader&&this.prevStickyHeaderState!=='hidden'){
this.prevStickyHeaderState='hidden';
$('body').removeClass('shown-sticky-filters').addClass('hidden-sticky-filters');
}
return;
}
if((scroll + top_offset) > offset.top){
this.$el.addClass('sticky-fixed').css({
top: top_offset,
bottom: "",
left: offset.left
});
if(this.options.hideStickyHeader&&this.prevStickyHeaderState!=='shown'){
this.prevStickyHeaderState='shown';
$('body').removeClass('hidden-sticky-filters').addClass('shown-sticky-filters');
}}else{
this.$el.removeClass('sticky-fixed').css({
top: "",
bottom: "",
left: ""
});
if(this.options.hideStickyHeader&&this.prevStickyHeaderState!=='hidden'){
this.prevStickyHeaderState='hidden';
$('body').removeClass('shown-sticky-filters').addClass('hidden-sticky-filters');
}}
}};}(jQuery));
(function ($){
var StickyObject=function (element, userSettings){
var $element,
isSticky=false,
isFollowingParent=false,
isReachedEffectsPoint=false,
elements={},
settings;
var defaultSettings={
to: 'top',
offset: 0,
effectsOffset: 0,
parent: false,
spacerHide: false,
classes: {
sticky: 'sticky-element',
stickyActive: 'sticky-element-active',
stickyEffects: 'sticky-element-effects',
spacer: 'sticky-element-spacer',
},
};
var initElements=function (){
$element=$(element).addClass(settings.classes.sticky);
elements.$window=$(window);
if(settings.parent){
if('parent'===settings.parent){
elements.$parent=$element.parent();
}else{
elements.$parent=$element.closest(settings.parent);
}}
};
var initSettings=function (){
settings=jQuery.extend(true, defaultSettings, userSettings);
};
var bindEvents=function (){
elements.$window.on({
scroll: onWindowScroll,
resize: onWindowResize,
});
};
var unbindEvents=function (){
elements.$window
.off('scroll', onWindowScroll)
.off('resize', onWindowResize);
};
var init=function (){
initSettings();
initElements();
bindEvents();
checkPosition();
};
var backupCSS=function ($elementBackupCSS, backupState, properties){
var css={},
elementStyle=$elementBackupCSS[0].style;
properties.forEach(function (property){
css[property]=undefined!==elementStyle[property] ? elementStyle[property]:'';
});
$elementBackupCSS.data('css-backup-' + backupState, css);
};
var getCSSBackup=function ($elementCSSBackup, backupState){
return $elementCSSBackup.data('css-backup-' + backupState);
};
var addSpacer=function (){
elements.$spacer=$element.clone()
.addClass(settings.classes.spacer);
if(settings.spacerHide&&elements.$spacer.find(settings.spacerHide).length){
elements.$spacer.css({
position: 'absolute',
});
elements.$spacer.find(settings.spacerHide).css({
visibility: 'hidden',
transition: 'none',
animation: 'none',
opacity: 0,
});
}else{
elements.$spacer.css({
visibility: 'hidden',
transition: 'none',
animation: 'none',
opacity: 0,
position: 'absolute',
});
}
$element.before(elements.$spacer);
};
var removeSpacer=function (){
elements.$spacer.remove();
};
var stickElement=function (){
backupCSS($element, 'unsticky', ['position', 'width', 'margin-top', 'margin-bottom', 'top', 'bottom']);
var css={
position: 'fixed',
width: getElementOuterSize($element, 'width'),
marginTop: 0,
marginBottom: 0,
};
css[settings.to]=settings.offset;
css['top'===settings.to ? 'bottom':'top']='';
$element
.css(css)
.addClass(settings.classes.stickyActive);
};
var unstickElement=function (){
try{
$element
.css(getCSSBackup($element, 'unsticky'))
.removeClass(settings.classes.stickyActive);
} catch (e){}};
var followParent=function (){
backupCSS(elements.$parent, 'childNotFollowing', ['position']);
elements.$parent.css('position', 'relative');
backupCSS($element, 'notFollowing', ['position', 'top', 'bottom']);
var css={
position: 'absolute',
};
css[settings.to]='';
css['top'===settings.to ? 'bottom':'top']=0;
$element.css(css);
isFollowingParent=true;
};
var unfollowParent=function (){
elements.$parent.css(getCSSBackup(elements.$parent, 'childNotFollowing'));
$element.css(getCSSBackup($element, 'notFollowing'));
isFollowingParent=false;
};
var getElementOuterSize=function ($elementOuterSize, dimension, includeMargins){
var computedStyle=getComputedStyle($elementOuterSize[0]),
elementSize=parseFloat(computedStyle[dimension]),
sides='height'===dimension ? ['top', 'bottom']:['left', 'right'],
propertiesToAdd=[];
if('border-box'!==computedStyle.boxSizing){
propertiesToAdd.push('border', 'padding');
}
if(includeMargins){
propertiesToAdd.push('margin');
}
propertiesToAdd.forEach(function (property){
sides.forEach(function (side){
elementSize +=parseFloat(computedStyle[property + '-' + side]);
});
});
return elementSize;
};
var getElementViewportOffset=function ($elementViewportOffset){
var windowScrollTop=elements.$window.scrollTop(),
elementHeight=getElementOuterSize($elementViewportOffset, 'height'),
viewportHeight=innerHeight,
elementOffsetFromTop=$elementViewportOffset.offset().top,
distanceFromTop=elementOffsetFromTop - windowScrollTop,
topFromBottom=distanceFromTop - viewportHeight;
return {
top: {
fromTop: distanceFromTop,
fromBottom: topFromBottom,
},
bottom: {
fromTop: distanceFromTop + elementHeight,
fromBottom: topFromBottom + elementHeight,
},
};};
var stick=function (){
addSpacer();
stickElement();
elements.$spacer.css('position', '')
isSticky=true;
$element.trigger('sticky:stick');
};
var unstick=function (){
unstickElement();
removeSpacer();
isSticky=false;
$element.trigger('sticky:unstick');
};
var checkParent=function (){
var elementOffset=getElementViewportOffset($element),
isTop='top'===settings.to;
if(isFollowingParent){
var isNeedUnfollowing=isTop ? elementOffset.top.fromTop > settings.offset:elementOffset.bottom.fromBottom < -settings.offset;
if(isNeedUnfollowing){
unfollowParent();
}}else{
var parentOffset=getElementViewportOffset(elements.$parent),
parentStyle=getComputedStyle(elements.$parent[0]),
borderWidthToDecrease=parseFloat(parentStyle[isTop ? 'borderBottomWidth':'borderTopWidth']),
parentViewportDistance=isTop ? parentOffset.bottom.fromTop - borderWidthToDecrease:parentOffset.top.fromBottom + borderWidthToDecrease,
isNeedFollowing=isTop ? parentViewportDistance <=elementOffset.bottom.fromTop:parentViewportDistance >=elementOffset.top.fromBottom;
if(isNeedFollowing){
followParent();
}}
};
var checkEffectsPoint=function (distanceFromTriggerPoint){
if(isReachedEffectsPoint&&-distanceFromTriggerPoint < settings.effectsOffset){
$element.removeClass(settings.classes.stickyEffects);
isReachedEffectsPoint=false;
}else if(!isReachedEffectsPoint&&-distanceFromTriggerPoint >=settings.effectsOffset){
$element.addClass(settings.classes.stickyEffects);
isReachedEffectsPoint=true;
}};
var checkPosition=function (){
var offset=settings.offset,
distanceFromTriggerPoint;
if(isSticky){
var spacerViewportOffset=getElementViewportOffset(elements.$spacer);
distanceFromTriggerPoint='top'===settings.to ? spacerViewportOffset.top.fromTop - offset:-spacerViewportOffset.bottom.fromBottom - offset;
if(settings.parent){
checkParent();
}
if(distanceFromTriggerPoint > 0){
unstick();
}}else{
var elementViewportOffset=getElementViewportOffset($element);
distanceFromTriggerPoint='top'===settings.to ? elementViewportOffset.top.fromTop - offset:-elementViewportOffset.bottom.fromBottom - offset;
if(distanceFromTriggerPoint <=0){
stick();
if(settings.parent){
checkParent();
}}
}
checkEffectsPoint(distanceFromTriggerPoint);
};
var onWindowScroll=function (){
checkPosition();
};
var onWindowResize=function (){
if(!isSticky){
return;
}
unstick();
stick();
if(settings.parent){
isFollowingParent=false;
checkParent();
}};
this.destroy=function (){
if(isSticky){
unstick();
}
unbindEvents();
$element.removeClass(settings.classes.sticky);
};
init();
};
$.fn.sticky=function (settings){
var isCommand='string'===typeof settings;
this.each(function (){
var $this=$(this);
if(!isCommand){
$this.data('sticky', new StickyObject(this, settings));
return;
}
var instance=$this.data('sticky');
if(!instance){
throw Error('Trying to perform the `' + settings + '` method prior to initialization');
}
if(!instance[settings]){
throw ReferenceError('Method `' + settings + '` not found in sticky instance');
}
instance[settings].apply(instance, Array.prototype.slice.call(arguments, 1));
if('destroy'===settings){
$this.removeData('sticky');
}});
return this;
};
window.StickyObject=StickyObject;
})(jQuery);