-
Notifications
You must be signed in to change notification settings - Fork 0
Stickable Object
Pair programming with Ellie
/*eslint no-self-assign: 0*/ // adding this exception to pass no-self-assign error untill this code is properly refactored
import { addClasses, setStyles, getNodesFromQuerySelector, hasClass } from '../../../utils/utils.js';
/**
* This object contains three functions per stickable object. The first key 'decideAction', is a function
which
* determines what action we will take (stick/unstick/nothing). 'stick' and 'unstick' keys do exactly that -
sticking and unsticking
*/
const stickableToFunctionMap = {
/**
* HEADER WRAPPER
*/
'header-wrapper': {
decideAction: (node, scrollTop) => {
let cssTop = ~~node.style['top'].replace('px', '') + ~~node.style['margin-top'].replace('px', '');
if (shouldUnstick(node, scrollTop, cssTop)) {
return 'unstick';
} else {
return shouldStick(node, scrollTop, cssTop) ? 'stick' : null;
}
},
stick: (node) => addClasses(node, ['wt-grid-main']),
unstick: () => {}
}, /**
-
ACCORDION SHOWHIDE */ 'accordion__title': { decideAction: (node, scrollTop) => { const accordionButton = node.querySelector('.accordion__button'); const isOpenShowHide = hasClass(accordionButton, 'show-hide--open');
if (!isOpenShowHide && !isSticky(node)) return null; const ariaControlsId = accordionButton.getAttribute('aria-controls'); const content = document.getElementById(ariaControlsId);
// I have minused 200 pixels from the calculation so it doesn't overlap with the stickiness of the next accordion let shouldUnstickShowHide = shouldUnstick(node, scrollTop, 0) || scrollTop > content.offsetTop + content.offsetHeight; if (shouldUnstickShowHide) { return 'unstick'; } else { return shouldStick(node, scrollTop, 0) ? 'stick' : null; } }, stick: (node) => { const collapsibleStickyTop = getNodesFromQuerySelector('.header-wrapper')[0].offsetHeight; addClasses(node, ['wt-grid-center']); setStyles(node, {'top': collapsibleStickyTop, 'left': node.offsetLeft}); }, unstick: (node) => (node) => setStyles(node.nextElementSibling, {'padding-top': ''}) }, /**
-
HORIZONTAL SLIDER / 'horizontal-slider': { decideAction: (node, scrollTop) => { let cssTop = ~~node.style['top'].replace('px', '') + ~~node.style['margin-top'].replace('px', ''); if (shouldUnstick(node, scrollTop, 0)) { return 'unstick'; } else { return shouldStick(node, scrollTop, cssTop) ? 'stick' : null; } }, stick: (node) => { node.style.width = node.style.width; // i am not sure what this is doing but just leaving here until // i can refactor at a later date. addClasses(node, ['wt-grid-center wt-grid-section-center']); // ugly line inherited from pre-refactor to make sure page layout doesn't change when the filter becomes sticky. setStyles(node.parentElement, { width: node.offsetWidth, height: node.clientHeight }); }, unstick: (node) => { if (!hasClass(node.parentNode, 'wt-grid-right')) { setStyles(node.parentElement, {height: 'auto', width: 'auto'}); } } }, /*
-
LIST HIGHLIGHT */ 'list-highlight': { decideAction: (node, scrollTop) => {
if (shouldUnstick(node, scrollTop, 0)) { console.log(scrollTop); return 'unstick'; } else { return shouldStick(node, scrollTop, 0) ? 'stick' : null;
} },
stick: (node) => {
node.style.width = node.style.width; // i am not sure what this is doing but just leaving here until
// i can refactor at a later date.
addClasses(node, ['']);
// ugly jquery line to make sure page layout doesn't change when the filter becomes js-sticky.
setStyles(node.parentElement, { width: node.offsetWidth, height: node.clientHeight });
},
unstick: (node) => {
if (!hasClass(node.parentElement, 'wt-grid-right')) {
setStyles(node.parentElement, {height: 'auto', width: 'auto'});
}
}
} };
/**
- Searches the class list and identifies the type of stickable from the object above
- @param {HTMLElement} node
- @return {array} array of nodes with the same class name / const getStickableType = (node) => Object.keys(stickableToFunctionMap).filter(className => hasClass(node, className)); /*
- Checks if the object has sticky class
- @param {HTMLElement} node
- @return {boolean} boolean to indicate stickiness / const isSticky = (node) => hasClass(node, 'sticky'); /*
- Checks if the object has native stickiness class
- @param {HTMLElement} node
- @return {boolean} boolean to indicate stickiness / const hasNativeStickyPositioning = (node) => node.style.position.indexOf('sticky') > -1 || node.style.position.indexOf('-webkit-sticky') > -1; /*
- Checks if the node is above where it normally sits in the HTML
- @param {HTMLElement} node
- @param {number} scrollTop This is how far down the page you have scrolled down
- @param {number} csstop This is how far down the page, the node sits.
- @return {boolean} boolean to indicate stickiness */
const shouldStick = (node, scrollTop, cssTop) => { return scrollTop > node.offsetTop - cssTop && !isSticky(node); }; // indicates when a sticky element is above its stick position and then decides whether it should be unstuck const shouldUnstick = (node, scrollTop, cssTop) => scrollTop < parseFloat(node.getAttribute('data-offsettop')) - cssTop || scrollTop === 0; export { stickableToFunctionMap, getStickableType, hasNativeStickyPositioning };