2021-06-18 10:37:33 +02:00

159 lines
5.2 KiB
JavaScript

(function(window) {
'use strict';
/* -------------------- Sticky Observer -------------------- */
function Stickyobserver(options) {
this.options = extend({}, this.options);
extend(this.options, options);
this.container = $(this.options.container)[0];
this.selector = this.options.selector;
this.stucked = this.options.stucked;
this.IntObsEnabled = (this.checkSticky($(this.selector)[0]) && window.IntersectionObserver);
if (!this.IntObsEnabled) {
this.sentinels = [];
this.issticky = $(this.options.container).find('.sticky');
}
this._init();
this._initEvents();
}
Stickyobserver.prototype.options = {};
Stickyobserver.prototype._init = function() {
this.observeBoundaries(this.container, 'top');
this.observeBoundaries(this.container, 'bottom');
};
Stickyobserver.prototype._initEvents = function() {
var $this = this;
$(document).on('sticky-change', function(e) {
let [header, stuck] = [e.detail.target, e.detail.stuck],
evt;
header.classList.toggle($this.stucked, stuck);
evt = new CustomEvent('updatescrollnavoffset', {
detail: (stuck)
? $(header).outerHeight(true) + Math.abs(parseInt($(header).css('margin-top')))
: 0
});
document.dispatchEvent(evt);
setTimeout(function() {
$($this.selector).find('.isflickity ')
.flickity('resize')
.flickity('select', 0);
}, 300);
});
if (!this.IntObsEnabled) {
try {
var opts = Object.defineProperty({}, 'passive', {
get: function() {
this.supportsPassive = true;
}
});
window.addEventListener('test', null, opts);
} catch (e) {}
document.addEventListener('scroll', function() {
clearTimeout($this.checkTo);
$this.checkTo = setTimeout(function() {
$.each($this.issticky, function(index, entry) {
$this.check(entry, $(entry).hasClass('sticky-top'));
});
}, 300);
}, this.supportsPassive ? { passive: true } : false);
$.each($this.issticky, function(index, entry) {
$this.check(entry, $(entry).hasClass('sticky-top'));
});
}
};
Stickyobserver.prototype.checkSticky = function(obj) {
return getComputedStyle(obj).position.match('sticky') !== null;
};
Stickyobserver.prototype.observeBoundaries = function(container, type) {
var $this = this,
observer;
if (this.IntObsEnabled)
observer = new IntersectionObserver((records, observer) => {
for (let record of records) {
let targetInfo = record.boundingClientRect,
stickyTarget = $(record.target).siblings('.sticky')[0],
rootBoundsInfo = record.rootBounds,
istop = $(record.target).hasClass('sticky-top');
switch (type) {
case 'top' :
if (istop) {
if (targetInfo.bottom < rootBoundsInfo.top)
this.triggerEvent(true, stickyTarget);
if (targetInfo.bottom >= rootBoundsInfo.top && targetInfo.bottom < rootBoundsInfo.bottom)
this.triggerEvent(false, stickyTarget);
} else {
if (targetInfo.top > rootBoundsInfo.top)
this.triggerEvent(false, stickyTarget);
if (targetInfo.top <= rootBoundsInfo.bottom && targetInfo.top > rootBoundsInfo.top)
this.triggerEvent(true, stickyTarget);
}
break;
case 'bottom' :
if (istop) {
if (targetInfo.top > rootBoundsInfo.top && targetInfo.top <= targetInfo.height * 2)
this.triggerEvent(true, stickyTarget);
if (targetInfo.top < rootBoundsInfo.top)
this.triggerEvent(false, stickyTarget);
} else {
if (targetInfo.bottom > rootBoundsInfo.bottom)
this.triggerEvent(true, stickyTarget);
else if (targetInfo.bottom < rootBoundsInfo.bottom)
this.triggerEvent(false, stickyTarget);
}
break;
}
}
}, {
threshold: [((type == 'top') ? 0 : 1)]
});
let sentinels = this.addObservers(container, 'sticky-observer--' + type);
if (this.IntObsEnabled)
sentinels.forEach(el => observer.observe(el));
};
Stickyobserver.prototype.check = function(el, istop) {
let top = $(el).siblings('.sticky-observer--top'),
bottom = $(el).siblings('.sticky-observer--bottom'),
offset = window.pageYOffset,
topExceed,
bottomExceed;
switch (istop) {
case true :
topExceed = (top.offset().top + top.height() - offset) <= 0;
bottomExceed = (bottom.offset().top - offset) <= 0;
this.triggerEvent((topExceed && !bottomExceed), el);
break;
case false :
topExceed = top.offset().top < (offset + window.innerHeight);
bottomExceed = bottom.offset().top < (offset - bottom.height() + window.innerHeight);
this.triggerEvent(topExceed && !bottomExceed, el);
break;
}
};
Stickyobserver.prototype.addObservers = function(container, className) {
return Array.from(container.querySelectorAll(this.selector)).map(el => {
let type = 'sticky-' + (($(el).attr('class').indexOf('sticky-bottom') < 0) ? 'top' : 'bottom'),
observer = $('<div class="sticky-observer ' + className + ' ' + type + '" />').appendTo($(el).parent());
return observer[0];
});
};
Stickyobserver.prototype.triggerEvent = function(stuck, target) {
let evt = new CustomEvent('sticky-change', {detail: {stuck, target}});
document.dispatchEvent(evt);
};
window.Stickyobserver = Stickyobserver;
})(window);