Skip to content

Commit

Permalink
fix: highlight js by moving header js
Browse files Browse the repository at this point in the history
  • Loading branch information
Nathan Rogan committed Oct 19, 2020
1 parent 9ca8fa5 commit 76f4802
Show file tree
Hide file tree
Showing 3 changed files with 301 additions and 40 deletions.
5 changes: 3 additions & 2 deletions src/www/_partials/_scripts.njk
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<!-- Highlight JS - display HTML blocks as coloured text -->
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min.js"></script>

<script src="$*cdn/js/wmcads-website.min.js"></script>
<script src="https://polyfill.io/v3/polyfill.min.js"></script>

Expand All @@ -11,5 +14,3 @@
gtag('config', 'UA-151672610-1');
</script>

<!-- Highlight JS - display HTML blocks as coloured text -->
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min.js"></script>
77 changes: 42 additions & 35 deletions src/www/_partials/component-example/_component-example.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,57 @@
function showCode() {
function showCode(ele) {
// for each button we create below
document.querySelectorAll('.wmcads-js-show-code').forEach(ele => {
function showMore(e) {
const btn = e.target || e.srcElement; // Set btn to the element from which the click came

// if the btn clicked contains this class, then it must be active, so reset it back to the norm
if (btn.classList.contains('wmcads-js-show-code--active')) {
btn.previousSibling.querySelector('.hljs').style.maxHeight = '200px';
btn.classList.remove('wmcads-js-show-code--active');
btn.innerText = 'Show more code';
} else {
// Else expand the code preview to 100%
btn.previousSibling.querySelector('.hljs').style.maxHeight = '100%';
btn.classList.add('wmcads-js-show-code--active');
btn.innerText = 'Show less code';
}
function showMore(e) {
const btn = e.target || e.srcElement; // Set btn to the element from which the click came

// if the btn clicked contains this class, then it must be active, so reset it back to the norm
if (btn.classList.contains('wmnds-js-show-code--active')) {
btn.previousSibling.querySelector('.hljs').style.maxHeight = '200px';
btn.classList.remove('wmnds-js-show-code--active');
btn.innerText = 'Show more code';
} else {
// Else expand the code preview to 100%
btn.previousSibling.querySelector('.hljs').style.maxHeight = '100%';
btn.classList.add('wmnds-js-show-code--active');
btn.innerText = 'Show less code';
}
}

// when clicked
ele.addEventListener('click', e => {
e.preventDefault();
showMore(e);
});

// when clicked
ele.addEventListener('click', e => {
// When keyboard "enter" pressed
ele.addEventListener('keydown', e => {
if (e.keyCode === 13) {
e.preventDefault();
showMore(e);
});

// When keyboard "enter" pressed
ele.addEventListener('keydown', e => {
if (e.keyCode === 13) {
e.preventDefault();
showMore(e);
}
});
}
});
}

export { showCode };

const displayShowMore = element => {
// If the code preview is 192 height (without padding) then we need to display the 'show more code' button
if (element.clientHeight >= 192 && !element.classList.contains('wmnds-show-more-ignore')) {
const htmlString = '<a href="#" class="wmnds-link wmnds-js-show-code">Show more code</a>';

element.parentElement.insertAdjacentHTML('afterend', htmlString);
}
};

export { displayShowMore };

export default () => {
const { hljs } = window; // declare higlightJS as global var
document.querySelectorAll('pre code').forEach(element => {
// Run highlightJS for each pre code element found */
hljs.highlightBlock(element);
// If the code preview is 192 height (without padding) then we need to display the 'show more code' button
if (element.clientHeight >= 192 && !element.classList.contains('wmcads-show-more-ignore')) {
const htmlString = '<a href="#" class="wmcads-link wmcads-js-show-code">Show more code</a>';

element.parentElement.insertAdjacentHTML('afterend', htmlString);
}
displayShowMore(element);
});
document.querySelectorAll('.wmnds-js-show-code').forEach(ele => {
showCode(ele); // run show code function above when hljs has init
});

showCode(); // run show code function above when hljs has init
};
259 changes: 256 additions & 3 deletions src/www/wmcads-website.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import forEachPolyfill from './assets/vendor/js/polyfills/ie11-forEach';
import colorPalettes from './pages/styles/colour-palettes/_color-palettes';
import highlightJS from './_partials/component-example/_component-example';
import header from '../wmcads/patterns/header/_header';
import highlight from './_partials/component-example/_component-example';

const icons = () => {
// Ajax SVG in, SVGS are referenced in app (Icon component)
Expand All @@ -16,4 +15,258 @@ const icons = () => {
};
};

window.addEventListener('DOMContentLoaded', (forEachPolyfill, icons(), colorPalettes, highlightJS, header));
const headerJs = () => {
// get mega menu elements
const megaMenus = document.querySelectorAll('.wmcads-mega-menu');

const mobileMenu = window.matchMedia('(max-width: 767px)');

[].forEach.call(megaMenus, menu => {
// mobile nav function
function handleMobileMenu(mq) {
if (mq.matches) {
const mobileToggle = menu.querySelector('.wmcads-mega-menu__mobile-toggle');
const headerEl = menu.parentNode.parentNode;

const topLevelMenuBtn = menu.querySelectorAll('.wmcads-mega-menu__link-arrow-icon-btn');
const mobileMenuIsOpen = { menu: false, primary: false };

// handle mobile menu toggle
mobileToggle.addEventListener('click', () => {
mobileMenuIsOpen.menu = !mobileMenuIsOpen.menu;
if (mobileMenuIsOpen.menu) {
headerEl.classList.add('wmcads-header--mega-menu-open');
document.querySelector('html').classList.add('mobile-menu-open');
} else {
headerEl.classList.remove('wmcads-header--mega-menu-open', 'wmcads-header--mega-menu-submenu-open');
document.querySelector('html').classList.remove('mobile-menu-open');
}
});

// handle sub menu open/close
[].forEach.call(topLevelMenuBtn, menuBtn => {
menuBtn.addEventListener('click', () => {
mobileMenuIsOpen.primary = !mobileMenuIsOpen.primary;
const targetListItem = menuBtn.parentNode;
if (mobileMenuIsOpen.primary) {
targetListItem.classList.add('open');
targetListItem.querySelector('.wmcads-mega-menu__sub-menu-link').focus();
headerEl.classList.add('wmcads-header--mega-menu-submenu-open');
} else {
targetListItem.classList.remove('open');
headerEl.classList.remove('wmcads-header--mega-menu-submenu-open');
}
});
});

// mobile collapse for third level menus
const collapseMenus = menu.querySelectorAll(
'.wmcads-mega-menu__sub-menu-item .wmcads-mega-menu__collapse-toggle'
);
[].forEach.call(collapseMenus, collapseToggle => {
collapseToggle.addEventListener('click', () => {
const panel = collapseToggle.nextElementSibling;
collapseToggle.classList.toggle('open');
if (panel.style.maxHeight) {
panel.style.maxHeight = null;
} else {
panel.style.maxHeight = `${panel.scrollHeight}px`;
}
});
});
}
}
// end mobile nav function

// init mobile nav function
handleMobileMenu(mobileMenu);
mobileMenu.addListener(handleMobileMenu);

const topLevelLinks = menu.querySelectorAll('.wmcads-mega-menu__primary-menu-link');

// handle events within each top level list item
[].forEach.call(topLevelLinks, (topLevelLink, topLevelLinkIndex) => {
// return list item parent of the current link if it exists else return the link
const topLevelListItem = topLevelLink.parentNode.tagName === 'LI' ? topLevelLink.parentNode : topLevelLink;
const subMenuLinks = topLevelListItem.querySelectorAll('.wmcads-mega-menu__sub-menu-link');

// check if level 3 menus are present, if so add modifier class
const hasSubmenuChildren =
topLevelListItem.querySelectorAll('.wmcads-mega-menu__sub-menu-child-menu').length !== 0;
if (hasSubmenuChildren) {
topLevelListItem.querySelectorAll('.wmcads-mega-menu__sub-menu').forEach(subMenu => {
subMenu.classList.add('wmcads-mega-menu__sub-menu--has-child-menus');
});
}

const clearActiveListItems = () => {
// remove active classes from other list items
[].forEach.call(menu.querySelectorAll('.wmcads-mega-menu__primary-menu-item'), menuItem => {
menuItem.classList.remove('active');
});
};

// handle setting the active class on menu and list items
const setMenuActive = (active, focusLink) => {
if (active !== false) {
menu.classList.add('active');
clearActiveListItems();
// add active class to current item
topLevelListItem.classList.add('active');
} else {
menu.classList.remove('active');
topLevelListItem.classList.remove('active');
// set focus on menu close
if (focusLink !== false) {
topLevelLink.focus();
}
}
};

// returns a specified menu link from a specified array
// currentIndex = index of the link that is currently focused
// array = array to move through
// direction = next, prev,
const getMenuLink = (currentIndex, array, direction) => {
let menuLink = null;
if (array) {
if (direction === 'prev') {
// return previous link in specified array if there is one else return null;
menuLink = array[currentIndex - 1] ? array[currentIndex - 1] : null;
} else if (direction === 'next') {
// return next link in specified array if there is one else return null;
menuLink = array[currentIndex + 1] ? array[currentIndex + 1] : null;
} else {
// return link with same index in specified array;
menuLink = array[currentIndex] ? array[currentIndex] : array[array.length - 1];
}
}
return menuLink;
};

const handleKeydown = (e, key) => {
e.stopPropagation();
// if key pressed is enter, space bar or down arrow
if (key === 13 || key === 32 || key === 40) {
// check if list item has a mega menu
const openSubMenu = () => {
if (topLevelListItem.querySelectorAll('.wmcads-mega-menu__container').length) {
e.preventDefault();
// remove keyFocus to allow menu to show
setMenuActive(true);
// focus first menu item
subMenuLinks[0].focus();
}
};
// enter
// check if link exists
if (key === 13) {
if (!topLevelLink.tagName === 'a' || !topLevelLink.getAttribute('href')) {
openSubMenu();
}
} else {
openSubMenu();
}
} else if (key === 37) {
// left arrow
const prevLink = getMenuLink(topLevelLinkIndex, topLevelLinks, 'prev');
if (prevLink) prevLink.focus();
} else if (key === 39) {
// right arrow
const nextLink = getMenuLink(topLevelLinkIndex, topLevelLinks, 'next');
if (nextLink) nextLink.focus();
} else if (key === 27) {
// if escape pressed
setMenuActive(false);
}
};

// if top level link doesn't have a mega-menu child add class to menu to hide overlay when hovered
// has to be added/removed on mouseover to cover menus that have a mix of items with/without mega menus
const isTopLevelWithMenu = topLevelListItem.querySelectorAll('.wmcads-mega-menu__container').length;

if (isTopLevelWithMenu) {
topLevelLink.addEventListener('mouseover', () => {
setMenuActive();
});
topLevelListItem.addEventListener('mouseleave', () => {
setMenuActive(false, false);
clearActiveListItems();
});

// array of mega menu links by column
topLevelListItem.addEventListener('blur', setMenuActive(false, false));
}

topLevelListItem.addEventListener('keydown', e => {
handleKeydown(e, e.keyCode);
});
// top lvl link event listeners
topLevelLink.addEventListener('mousedown', e => {
// prevent link focus on click
e.preventDefault();
// setMenuActive(false);
});
// topLevelLink.addEventListener('focus', handleKeyFocus);

const menuArray = [];
[].forEach.call(subMenuLinks, (menuLink, menuIndex) => {
const thisList = menuLink.parentNode;
const thisListLinks = thisList.querySelectorAll('a');
// push list of links to array
menuArray.push(thisListLinks);

[].forEach.call(thisListLinks, (link, linkIndex) => {
link.addEventListener('keydown', e => {
if (e.keyCode !== 27) {
e.stopPropagation();
if (e.keyCode === 39) {
// right arrow - go to link of same index in next menu list
e.preventDefault();
const nextMenuLink = getMenuLink(linkIndex, menuArray[menuIndex + 1]);
if (nextMenuLink) nextMenuLink.focus();
} else if (e.keyCode === 37) {
// left arrow - go to link of same index in previous menu list
e.preventDefault();
const prevMenuLink = getMenuLink(linkIndex, menuArray[menuIndex - 1]);
if (prevMenuLink) prevMenuLink.focus();
} else if (e.keyCode === 40) {
// down arrow - go to next link in current menu list
e.preventDefault();
// if next link doesn't exist try next menu first item else return null
const nextLink = getMenuLink(linkIndex, thisListLinks, 'next')
? getMenuLink(linkIndex, thisListLinks, 'next')
: getMenuLink(-1, menuArray[menuIndex + 1], 'next');
if (nextLink) {
nextLink.focus();
} else {
setMenuActive(false);
if (getMenuLink(topLevelLinkIndex, topLevelLinks, 'next')) {
getMenuLink(topLevelLinkIndex, topLevelLinks, 'next').focus();
}
}
} else if (e.keyCode === 38) {
// up arrow - go to previous item in current menu list
e.preventDefault();
const prevMenu = menuArray[menuIndex - 1];
let prevLink = null;
if (prevMenu || linkIndex > 0) {
prevLink = getMenuLink(linkIndex, thisListLinks, 'prev')
? getMenuLink(linkIndex, thisListLinks, 'prev')
: getMenuLink(prevMenu.length, prevMenu, 'prev');
}
if (prevLink) {
prevLink.focus();
} else {
setMenuActive(false);
}
}
}
});
});
});
});
});
};

window.addEventListener('DOMContentLoaded', (forEachPolyfill, icons(), headerJs(), colorPalettes, highlight));

0 comments on commit 76f4802

Please sign in to comment.