// Sticky
/* Smart Resize */
(function ($, sr) {
'use strict';
// debouncing function from John Hann
// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
var debounce = function (func, threshold, execAsap) {
var timeout;
return function debounced() {
var obj = this, args = arguments;
function delayed() {
if (!execAsap)
func.apply(obj, args);
timeout = null;
}
if (timeout)
clearTimeout(timeout);
else if (execAsap)
func.apply(obj, args);
timeout = setTimeout(delayed, threshold || 100);
};
};
// smartresize
jQuery.fn[sr] = function (fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
})(jQuery, 'smartresize');
(function ($) {
'use strict';
// jQuery Pin plugin
$.fn.themePin = function (options) {
var scrollY = 0, lastScrollY = 0, elements = [], disabled = false, $window = $(window), fixedSideTop = [], fixedSideBottom = [], prevDataTo = [];
options = options || {};
var recalculateLimits = function () {
for (var i = 0, len = elements.length; i < len; i++) {
var $this = elements[i];
if (options.minWidth && $window.width() <= options.minWidth) {
if ($this.parent().is(".pin-wrapper")) { $this.unwrap(); }
$this.css({ width: "", left: "", top: "", position: "" });
disabled = true;
continue;
} else {
disabled = false;
}
var $container = options.containerSelector ? ($this.closest(options.containerSelector).length ? $this.closest(options.containerSelector) : $(options.containerSelector)) : $(document.body);
var offset = $this.offset();
var containerOffset = $container.offset();
if (typeof containerOffset == 'undefined') {
continue;
}
var parentOffset = $this.parent().offset();
if (!$this.parent().is(".pin-wrapper")) {
$this.wrap("
");
}
var pad = $.extend({
top: 0,
bottom: 0
}, options.padding || {});
var pt = parseInt($this.parent().parent().css('padding-top')), pb = parseInt($this.parent().parent().css('padding-bottom'));
if (typeof options.paddingOffsetTop != 'undefined') {
pad.top += parseInt(options.paddingOffsetTop, 10);
} else {
pad.top += 18;
}
if (typeof options.paddingOffsetBottom != 'undefined') {
pad.bottom = parseInt(options.paddingOffsetBottom, 10);
} else {
pad.bottom = 0;
}
var bb = $this.css('border-bottom'), h = $this.outerHeight();
$this.css('border-bottom', '1px solid transparent');
var o_h = $this.outerHeight() - h - 1;
$this.css('border-bottom', bb);
$this.css({ width: $this.outerWidth() <= $this.parent().width() ? $this.outerWidth() : $this.parent().width() });
$this.parent().css("height", $this.outerHeight() + o_h);
if ($this.outerHeight() <= $window.height()) {
$this.data("themePin", {
pad: pad,
from: (options.containerSelector ? containerOffset.top : offset.top) - pad.top + pt,
pb: pb,
parentTop: parentOffset.top - pt,
offset: o_h
});
} else {
$this.data("themePin", {
pad: pad,
fromFitTop: (options.containerSelector ? containerOffset.top : offset.top) - pad.top + pt,
from: (options.containerSelector ? containerOffset.top : offset.top) + $this.outerHeight() - $(window).height() + pt,
pb: pb,
parentTop: parentOffset.top - pt,
offset: o_h
});
}
}
};
var onScroll = function () {
if (disabled) { return; }
scrollY = $window.scrollTop();
var window_height = window.innerHeight || $window.height();
for (var i = 0, len = elements.length; i < len; i++) {
var $this = $(elements[i]),
data = $this.data("themePin"),
sidebarTop;
if (!data) { // Removed element
continue;
}
var $container = options.containerSelector ? ($this.closest(options.containerSelector).length ? $this.closest(options.containerSelector) : $(options.containerSelector)) : $(document.body),
isFitToTop = ($this.outerHeight() + data.pad.top) <= window_height;
data.end = $container.offset().top + $container.height();
if (isFitToTop) {
data.to = $container.offset().top + $container.height() - $this.outerHeight() - data.pad.bottom - data.pb;
} else {
data.to = $container.offset().top + $container.height() - window_height - data.pb;
data.to2 = $container.height() - $this.outerHeight() - data.pad.bottom - data.pb;
}
if (prevDataTo[i] === 0) {
prevDataTo[i] = data.to;
}
if (prevDataTo[i] != data.to) {
if (fixedSideBottom[i] && $this.outerHeight() + $this.offset().top + data.pad.bottom < scrollY + window_height) {
fixedSideBottom[i] = false;
}
}
if (isFitToTop) {
var from = data.from - data.pad.bottom,
to = data.to - data.pad.top - data.offset;
if (typeof data.fromFitTop != 'undefined' && data.fromFitTop) {
from = data.fromFitTop - data.pad.bottom;
}
if (from + $this.outerHeight() > data.end || from >= to) {
$this.css({ position: "", top: "", left: "" });
if (options.activeClass) { $this.removeClass(options.activeClass); }
continue;
}
if (scrollY > from && scrollY < to) {
!($this.css("position") == "fixed") && $this.css({
left: $this.offset().left,
top: data.pad.top
}).css("position", "fixed");
if (options.activeClass) { $this.addClass(options.activeClass); }
} else if (scrollY >= to) {
$this.css({
left: "",
top: to - data.parentTop + data.pad.top
}).css("position", "absolute");
if (options.activeClass) { $this.addClass(options.activeClass); }
} else {
$this.css({ position: "", top: "", left: "" });
if (options.activeClass) { $this.removeClass(options.activeClass); }
}
} else if (($this.outerHeight() + data.pad.top + data.pad.bottom) > window_height || fixedSideTop[i] || fixedSideBottom[i]) {
var padTop = parseInt($this.parent().parent().css('padding-top'));
// Reset the sideSortables style when scrolling to the top.
if (scrollY + data.pad.top - padTop <= data.parentTop) {
$this.css({ position: "", top: "", bottom: "", left: "" });
fixedSideTop[i] = fixedSideBottom[i] = false;
if (options.activeClass) { $this.removeClass(options.activeClass); }
} else if (scrollY >= data.to) {
$this.css({
left: "",
top: data.to2,
bottom: ""
}).css("position", "absolute");
if (options.activeClass) { $this.addClass(options.activeClass); }
} else {
// When scrolling down.
if (scrollY >= lastScrollY) {
if (fixedSideTop[i]) {
// Let it scroll.
fixedSideTop[i] = false;
sidebarTop = $this.offset().top - data.parentTop;
$this.css({
left: "",
top: sidebarTop,
bottom: ""
}).css("position", "absolute");
if (options.activeClass) { $this.addClass(options.activeClass); }
} else if (!fixedSideBottom[i] && $this.outerHeight() + $this.offset().top + data.pad.bottom < scrollY + window_height) {
// Pin the bottom.
fixedSideBottom[i] = true;
!($this.css("position") == "fixed") && $this.css({
left: $this.offset().left,
bottom: data.pad.bottom,
top: ""
}).css("position", "fixed");
if (options.activeClass) { $this.addClass(options.activeClass); }
}
// When scrolling up.
} else if (scrollY < lastScrollY) {
if (fixedSideBottom[i]) {
// Let it scroll.
fixedSideBottom[i] = false;
sidebarTop = $this.offset().top - data.parentTop;
$this.css({
left: "",
top: sidebarTop,
bottom: ""
}).css("position", "absolute");
if (options.activeClass) { $this.addClass(options.activeClass); }
} else if (!fixedSideTop[i] && $this.offset().top >= scrollY + data.pad.top) {
// Pin the top.
fixedSideTop[i] = true;
!($this.css("position") == "fixed") && $this.css({
left: $this.offset().left,
top: data.pad.top,
bottom: ''
}).css("position", "fixed");
if (options.activeClass) { $this.addClass(options.activeClass); }
} else if ( ! fixedSideBottom[i] && fixedSideTop[i] && $this.css('position') == 'absolute' && $this.offset().top >= scrollY + data.pad.top) {
fixedSideTop[i] = false;
}
} else {
fixedSideTop[i] = false;
fixedSideTop[i] = false;
}
}
} else {
// If the sidebar container is smaller than the viewport, then pin/unpin the top when scrolling.
if (scrollY >= (data.parentTop - data.pad.top)) {
$this.css({
position: 'fixed',
top: data.pad.top
});
} else {
$this.css({ position: "", top: "", bottom: "", left: "" });
}
fixedSideTop[i] = fixedSideBottom[i] = false;
}
prevDataTo[i] = data.to;
}
lastScrollY = scrollY;
};
var recalculateLeft = function (timeout) {
if (typeof timeout == 'undefined') {
timeout = 400;
}
for (var i = 0, len = elements.length; i < len; i++) {
var $this = $(elements[i]),
data = $this.data("themePin"),
sidebarTop;
if (!data) { // Removed element
continue;
}
var $container = options.containerSelector ? ($this.closest(options.containerSelector).length ? $this.closest(options.containerSelector) : $(options.containerSelector)) : $(document.body);
if ($this.css("position") == "fixed") {
var offset = $this.offset().top - $container.offset().top;
$this.css({
'position': 'absolute',
left: '',
top: offset,
bottom: ''
});
setTimeout(function () {
$this.css({
left: $this.offset().left,
top: data.pad.top,
bottom: ''
}).css('position', 'fixed');
}, timeout);
}
}
};
var update = function () { recalculateLimits(); onScroll(); },
r_timer = null;
this.each(function () {
var $this = $(this),
data = $(this).data('themePin') || {};
if (data && data.update) { return; }
elements.push($this);
$( "img", this ).one( "load", function () {
if ( r_timer ) {
Wolmart.deleteTimeout( r_timer );
}
r_timer = Wolmart.requestTimeout( recalculateLimits, 20 );
} );
data.update = update;
$(this).data('themePin', data);
fixedSideTop.push(false);
fixedSideBottom.push(false);
prevDataTo.push(0);
});
$window.on('touchmove scroll', onScroll);
recalculateLimits();
$window.on('load', update);
$(this).on('recalc.pin', function () {
recalculateLimits();
onScroll();
});
$(this).on('recalc.pinleft', function (e, timeout) {
recalculateLeft(timeout);
});
return this;
};
var instanceName = '__sticky';
var Sticky = function ($el, opts) {
return this.initialize($el, opts);
};
Sticky.defaults = {
autoInit: false,
minWidth: 767,
padding: {
top: 0,
bottom: 0
},
offsetTop: 0,
offsetBottom: 0
};
Sticky.prototype = {
initialize: function ($el, opts) {
if ($el.data(instanceName)) {
return this;
}
this.$el = $el;
this
.setData()
.setOptions(opts)
.build();
return this;
},
setData: function () {
this.$el.data(instanceName, this);
return this;
},
setOptions: function (opts) {
this.options = $.extend(true, {}, Sticky.defaults, opts, {
wrapper: this.$el
});
return this;
},
build: function () {
if (!($.isFunction($.fn.themePin))) {
return this;
}
var self = this,
$el = this.options.wrapper,
stickyResizeTrigger;
$el.themePin(this.options);
setTimeout(function() {
if ( typeof Wolmart.sticky_top_height != 'undefined' && $el.data('themePin').pad ) {
$el.data('themePin').pad.top = Wolmart.sticky_top_height;
}
}, 300);
$(window).smartresize(function () {
if (stickyResizeTrigger) {
clearTimeout(stickyResizeTrigger);
}
stickyResizeTrigger = setTimeout(function () {
$el.trigger('recalc.pin');
}, 800);
var $parent = $el.parent();
if ( typeof Wolmart.sticky_top_height != 'undefined' && $el.data('themePin').pad) {
$el.data('themePin').pad.top = Wolmart.sticky_top_height;
}
$el.outerWidth($parent.width());
if ($el.css('position') == 'fixed') {
$el.css('left', $parent.offset().left);
}
});
return this;
}
};
// jquery plugin
$.fn.themeSticky = function (opts) {
return this.map(function () {
var $this = $(this);
if ($this.data(instanceName)) {
$this.trigger('recalc.pin');
setTimeout(function () {
$this.trigger('recalc.pin');
}, 800);
return $this.data(instanceName);
} else {
return new Sticky($this, opts);
}
});
}
}).apply(this, [jQuery]);