Repository URL to install this package:
|
Version:
2.0.0 ▾
|
(function ($, _, window) {
function StickyDrawer(options) {
this.setupVars(options);
this.setupEvents();
}
StickyDrawer.prototype.defaults = {
target: '.sticky-drawer',
targetWrapper: '.sticky-drawer-wrapper',
toggle: '.sticky-drawer-toggle',
scrollToContainer: '.sticky-drawer-wrapper',
fixedClass: 'is-fixed',
isResizing: false,
toggleAction: 'scroll'
};
/**
* Sets up all of the variables to be used across the different methods
*
* @param {object} options - object that will override defaults
*
*/
StickyDrawer.prototype.setupVars = function setupVars(options) {
this.options = _.merge(this.defaults, drupalSettings.meltStickyDrawer, options);
this.target = this.options.target;
this.targetWrapper = this.options.targetWrapper;
this.toggle = this.options.toggle;
this.toggleAction = this.options.toggleAction;
this.toggleEl = document.querySelector(this.toggle);
this.targetEl = document.querySelector(this.target);
// Exit if target element is not found.
if (!this.targetEl) {
throw new Error('StickyDrawerError: Can not find HTML element with the selector of ' + this.target)
};
this.isFixed = this.targetEl.classList.contains(this.options.fixedClass);
this.targetElHeight = this.targetEl.getBoundingClientRect().height;
this.targetWrapperEl = document.querySelector(this.targetWrapper);
this.windowHeight = Math.min(window.innerHeight, document.documentElement.clientHeight);
var fixedHeights = this.getFixedHeights();
this.targetFixedHeight = fixedHeights.target;
this.wrapperFixedHeight = fixedHeights.wrapper;
if (!this.isFixed) {
this.setTargetWrapperHeight();
}
this.triggerHeight = (this.targetWrapperEl.offsetTop - this.windowHeight) + this.targetFixedHeight;
}
StickyDrawer.prototype.setupEvents = function setupEvents() {
var stickyDrawer = this;
var fixedClass = this.options.fixedClass;
// Handle scroll
$(window).scroll(_.throttle(function () {
stickyDrawer.init();
}, 100));
// Handle window resize
$(window).resize(_.debounce(function () {
stickyDrawer.options.isResizing = true;
stickyDrawer.init();
stickyDrawer.options.isResizing = false;
}, 200));
// Handle click
$(document).on('click', this.toggle, function (event) {
event.preventDefault();
// Custom `stickydrawer:toggle` event that allows developers to
// manipulate the stickyDrawer before we scroll.
$(event.currentTarget).trigger('stickydrawer:toggle', [stickyDrawer]);
// Add 'is-expanded' class if user selected "expand" action
if(stickyDrawer.toggleAction === 'expand') {
var body = document.body;
// Prevent scrolling when expanded.
if(stickyDrawer.isFixed && !stickyDrawer.targetEl.classList.contains('is-expanded')){
stickyDrawer.targetEl.classList.add('is-expanded');
body.style.overflow = 'hidden';
} else {
stickyDrawer.targetEl.classList.remove('is-expanded');
body.style.overflow = '';
}
}
// If the action type is not expanded, then the default will be to scroll.
if (stickyDrawer.toggleAction !== 'expand') {
if (stickyDrawer.isFixed) {
//or to scroll to the element with the ID "#someID":
TweenLite.to(window, .3, {
scrollTo: {
y: stickyDrawer.options.targetWrapper,
offsetY: stickyDrawer.options.scrollToOffset || 30,
autoKill: false // needed to use this for Safari mobile
}
});
} else {
TweenLite.to(window, .3, {
scrollTo: {
y: 0,
autoKill: false // needed to use this for Safari mobile
}
})
}
}
});
}
/**
* Adds the unfixed height to the target's wrapper to maintain scroll positioning
*/
StickyDrawer.prototype.setTargetWrapperHeight = function setTargetWrapperHeight() {
this.targetWrapperEl.style.height = (this.targetElHeight + this.wrapperFixedHeight) + 'px';
};
/**
* This quickly sets the target to it's fixed state so we can
* get it's height and then sets it back to its original state
*
* @returns {number} height - height of target when fixed
*
*/
StickyDrawer.prototype.getFixedHeights = function () {
var fixedClass = this.options.fixedClass;
var targetHeight, targetElRect;
// Only add class if target hasn't already been fixed
if (!this.isFixed) {
this.targetEl.classList.add(fixedClass);
}
// Get the rect after we add the fixed class so we can get the correct top value
targetElRect = this.targetEl.getBoundingClientRect();
if (this.toggleAction === 'expand') {
targetHeight = Math.abs(this.windowHeight - targetElRect.y);
} else {
targetHeight = targetElRect.height;
}
var wrapperHeight = this.targetWrapperEl.getBoundingClientRect().height;
// Only add class if target hasn't already been fixed
if (!this.isFixed) {
this.targetEl.classList.remove(fixedClass);
}
return {
target: targetHeight,
wrapper: wrapperHeight
};
};
/**
* Removes transition state from sticky drawer when in "expand" mode.
*/
StickyDrawer.prototype.removeTransition = function removeTransition() {
if (this.toggleAction === 'expand') {
this.targetEl.style.transition = '';
document.body.style.overflow = '';
}
}
/**
* Removes transition state from sticky drawer when in "expand" mode.
*/
StickyDrawer.prototype.addTransition = function addTransition() {
if (this.toggleAction === 'expand') {
this.targetEl.style.transition = 'transform .2s'
}
}
/**
* Main function that initializes the sticky drawer
*/
StickyDrawer.prototype.init = function init() {
var fixedClass = this.options.fixedClass;
// Reset variables when resizing windows
if (this.options.isResizing) {
this.targetWrapperEl.style = null;
this.targetEl.classList.remove(fixedClass);
this.targetEl.classList.remove('is-expanded');
this.removeTransition();
this.setupVars();
}
var scrollPos = window.pageYOffset || document.documentElement.scrollTop;
var wrapperInView = scrollPos > this.triggerHeight;
var isExpanded = this.targetEl.classList.contains('is-expanded');
// Remove fixed class if wrapper in view of the viewport
if (wrapperInView && this.isFixed) {
this.targetEl.classList.remove(fixedClass);
this.toggleEl.classList.remove(fixedClass);
this.isFixed = false;
this.removeTransition();
}
// Add the fixed class when the wrapper is out of the viewport
if (!wrapperInView && !this.isFixed) {
this.targetEl.classList.add(fixedClass);
this.toggleEl.classList.add(fixedClass);
this.isFixed = true;
// Set the transition after setting the class, otherwise it'll animate in when
// the fixedClass is set. We need to set it AFTER the window resize event has fired
// which is after 250ms.
setTimeout(function () {
this.addTransition();
}.bind(this), 300);
}
if(!wrapperInView && this.isFixed && !this.targetEl.style.transition) {
setTimeout(function () {
this.addTransition();
}.bind(this), 300);
}
};
// Execute code
setTimeout(function () {
try {
var stickyDrawer = new StickyDrawer();
stickyDrawer.init();
} catch (err) {
// Silently fail.
}
}, 250);
})(jQuery, _.noConflict(), window);