Skip to content

Stickable Object

Marie-Louise edited this page Oct 24, 2018 · 4 revisions

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 };

Clone this wiki locally