(function ($, Modernizr, Flags) {
window.flags = new Flags(['transitions', 'transforms', 'flexbox', 'mobile', 'tablet', 'desktop', 'touch']);
var windowWidth = function(){
/**
* This function uses the existing CSS breakpoint values to define the JS breakpoints through the 'font-family' value on the body (debug/styles/sass/layout/layout.scss, line 7)
*/
var breakpointController = function(){
// Grab the value of the body element's content ('.split('"')'' removes the quote the IE puts on this value)
var bodyContentValue = $('body').css('font-family');
bodyContentValue = bodyContentValue.match(/\w+/);
// Check the bodyContentValue value to see if the device width is 'tablet'
if(bodyContentValue[0] === 'tablet'){
window.flags.remove('desktop');
window.flags.remove('mobile');
window.flags.add('tablet');
// Check the bodyContentValue value to see if the device width is 'mobile'
} else if(bodyContentValue[0] === 'mobile'){
window.flags.remove('desktop');
window.flags.remove('tablet');
window.flags.add('mobile');
// Check device is defaults to 'desktop'
} else {
window.flags.remove('tablet');
window.flags.remove('mobile');
window.flags.add('desktop');
}
};
breakpointController();
};
if(Modernizr.touch){
window.flags.add('touch');
}
if(Modernizr.csstransitions){
window.flags.add('transitions');
}
if(Modernizr.csstransforms){
window.flags.add('transforms');
}
if(Modernizr.flexbox){
window.flags.add('flexbox');
}
var adminAdjust = function(){
var toolbar = $('#toolbar');
var adminMenu = $('#admin-menu');
if(toolbar.length === 1){
$('.touch-nav, .touch-nav .scroll, body').css('padding-top', toolbar.height());
} else if(adminMenu.length === 1){
$('.touch-nav, .touch-nav .scroll, body').css('padding-top', adminMenu.height());
}
};
var backgroundImageAdjust = function(){
if(typeof $('.layout').data('background') !== 'undefined'){
$('.layout')
.addClass('has-background')
.css('background-image', 'url(' + $('.layout').data('background') + ')');
if(typeof $('.layout').data('background-image-style') !== 'undefined'){
$('.layout').addClass('background-' + $('.layout').data('background-image-style'));
}
}
if(typeof $('.layout').data('background-color') !== 'undefined'){
$('.layout')
.addClass('has-background')
.css('background-color', $('.layout').data('background-color'));
}
if(typeof $('.layout').data('background-transparent') !== 'undefined'){
$('.layout')
.addClass('has-transparent');
}
};
var pageHeaderAdjust = function(){
var container = $('.title-row');
var socialPaneOpt1 = container.find($('.pane-node-janrain-share-settings'));
var socialPaneOpt2 = container.find($('.pane-janrain-janrain-page-share'));
if(container.hasClass('align-bottom')){
if( socialPaneOpt1.length > 0 || socialPaneOpt2.length > 0){
var socialPane;
if (socialPaneOpt1.length){
socialPane = socialPaneOpt1;
} else if(socialPaneOpt2.length){
socialPane = socialPaneOpt2;
}
var titlePane = socialPane.find('.janrain-social-share-text-button');
socialPane.css('height', 'auto');
var socialHeight = titlePane.outerHeight();
socialPane.css('height', socialHeight);
}
}
};
// Add CSS to make sticky header function correctly and/or preserve stack order when footer scrolls to top.
var stickyHeaderAdjust = function(onScrollOnly){
var stickyEnabled = $('body.sticky-page, body.sticky-page-desktop, body.sticky-page-tablet, body.sticky-page-mobile');
if(typeof stickyEnabled !== undefined && stickyEnabled.length > 0) {
var contentContainer = $('.layout');
var footerDistance = $('#footer').offset().top;
var moveClass = 'moved';
var scrollTop = $(window).scrollTop();
var stickyHeader = $('.sticky-header-wrap');
var stickyHeaderHeight = stickyHeader.height();
var toolbar = $('#toolbar');
var toolbarHeight;
if(toolbar.length === 1){
toolbarHeight = toolbar.height();
} else {
toolbarHeight = 0;
}
var topDistance = footerDistance - (toolbarHeight + stickyHeaderHeight);
if((topDistance <= scrollTop) && (stickyHeader.hasClass(moveClass)) === false){
stickyHeader.insertBefore(contentContainer).addClass(moveClass);
} else if((topDistance > scrollTop) && (stickyHeader.hasClass(moveClass))){
stickyHeader.prependTo(contentContainer).removeClass(moveClass);
}
if(onScrollOnly === undefined){
stickyHeader.css('top', toolbarHeight);
contentContainer.css('padding-top', stickyHeaderHeight);
}
}
};
var pageShareTray = function() {
var container = $('.title-row');
var pageShare = container.find($('.pane-janrain-janrain-page-share'));
var pageShareSettings = container.find($('.pane-node-janrain-share-settings'));
var pageTaxonomyShare = $('.taxonomy-term__content').parent('div:not(.taxonomy-term--product-categories)');
if ((pageShare.length > 0) || (pageShareSettings.length > 0) || (pageTaxonomyShare.length > 0)) {
var $shareButtonDiv = $('
',
{
'class': 'janrain-social-share-button'
});
// jshint scripturl:true
var $shareButtonA = $('',
{
'href': 'javascript:void(0);',
'aria-expanded': false
});
// jshint scripturl:false
var $shareButtonSpan = $('',
{
'id': 'janrain-social-share-text-button'
}).text(Drupal.t('Share'));
var $shareButton = '';
if (Drupal.settings.accessibilityEnabled) {
$shareButton = $shareButtonDiv.append($shareButtonA.append($shareButtonSpan));
// Implement support for keyboard-only users.
$shareButtonA.keydown(function (e) {
var code = e.which;
// 13 = Return, 32 = Space.
if ((code === 13) || (code === 32)) {
// Prevent default scrolling by space.
e.preventDefault();
$(this).find('span').click();
}
});
}
else {
$shareButton = $shareButtonDiv.append($shareButtonSpan);
}
pageShare.prepend($shareButtonDiv);
pageShareSettings.prepend($shareButton);
pageTaxonomyShare.prepend($shareButton);
}
var pageShareContainer = container.find($('.janrainSocialContainer'));
var pageShareButton = container.find($('#janrain-social-share-text-button'));
var taxonomyShareContainer = pageTaxonomyShare.find($('.janrainSocialContainer'));
var taxonomyShareButton = pageTaxonomyShare.find($('#janrain-social-share-text-button'));
// Toggle accessibility attributes.
var shareButtonExpanded = function () {
if (Drupal.settings.accessibilityEnabled) {
$('.janrain-social-share-button a').attr('aria-expanded', function (_, attr) { return (attr !== 'true'); });
}
};
// hide the social icons by default on nodes
pageShareContainer.hide();
pageShareButton.click(function() {
pageShareContainer.toggleClass('hide');
shareButtonExpanded();
if ($('html').attr('dir') === 'ltr') {
pageShareContainer.animate({
marginLeft: function() {
var pageShareContainerWidth = '-' + pageShareContainer.outerWidth() + 'px';
pageShareContainerWidth();
},
opacity: 'toggle'
}, 500);
} else {
pageShareContainer.animate({
marginRight: function() {
var pageShareContainerWidth = '-' + pageShareContainer.outerWidth() + 'px';
pageShareContainerWidth();
},
opacity: 'toggle'
}, 500);
}
});
// hide the social icons by default on taxonomy nodes
taxonomyShareContainer.hide();
taxonomyShareButton.click(function() {
taxonomyShareContainer.toggleClass('hide');
shareButtonExpanded();
if ($('html').attr('dir') === 'ltr') {
taxonomyShareContainer.animate({
marginLeft: function() {
var taxonomyShareContainerWidth = '-' + taxonomyShareContainer.outerWidth() + 'px';
taxonomyShareContainerWidth();
},
opacity: 'toggle'
}, 500);
} else {
taxonomyShareContainer.animate({
marginRight: function() {
var taxonomyShareContainerWidth = '-' + taxonomyShareContainer.outerWidth() + 'px';
taxonomyShareContainerWidth();
},
opacity: 'toggle'
}, 500);
}
});
};
$(window).ready(function () {
pageShareTray();
// Add specific class for IE10.
if ($.browser.msie && $.browser.version === '10.0') {
$('html').addClass('ie10');
}
// Add specific class for IE11.
if (document.body.style['msTextCombineHorizontal'] !== undefined) {
$('html').addClass('ie11');
}
});
$(window).on('scroll', function(){
stickyHeaderAdjust(true);
});
$(window).on('resize', function(){
pageHeaderAdjust();
stickyHeaderAdjust();
windowWidth();
if ($('body').hasClass('logged-in') ){
adminAdjust();
}
});
if ($('body').hasClass('logged-in') ){
adminAdjust();
}
// This functionality was moved from jj-quiz-module.js since it affects all pages.
var resultsPage = function(){
if(!$('.pane-node-field-quiz-result-image').length && !$('.pane-node-field-quiz-result-content-solr').length && !$('.quizzes-intro').length){
$('.main-row').addClass('no-image');
}
};
backgroundImageAdjust();
pageHeaderAdjust();
stickyHeaderAdjust();
windowWidth();
resultsPage();
})(jQuery, window.Modernizr, window.Flags, window.tappable);
// Set jnj global if not already set.
var jnj = jnj || {};
(function ($) {
// This function is now only used in browsers that do not support flexbox
jnj.setEqualHeight = function($equalHeightElements, offset){
offset = offset || 0;
$equalHeightElements.css('height', '');
var maxHeight = 0;
$equalHeightElements.each(function(){
maxHeight = Math.max($(this).outerHeight(), maxHeight);
});
// Add offset.
maxHeight += offset;
$equalHeightElements.outerHeight(maxHeight);
return maxHeight;
};
// This function is used on elements within a grid-item that need to be equal heights.
jnj.setEqualHeightRow = function($element, $parentElement){
$element.css('height', 'auto');
//Set parent variables to determine setSize
var $equalHeightParent = $parentElement || $element.closest('.grid-item');
var $equalHeightElement = $element;
//Set the size of the group by dividing width of the element by the width of its parent
var containerWidth = $equalHeightParent.parents().width();
var setSize = $equalHeightParent.width();
//Round down to nearest whole number.
var size = Math.floor(containerWidth / setSize);
if(size > 1){
//Create an array out of the $equalHeightParent
var gridItemArray = [];
var gridRowArray = [];
$($equalHeightParent).each(function(){
gridItemArray.push($(this));
});
// Split array of elements into gridRowArray based on size of groups
while(gridItemArray.length > 0) {
var newArray = gridItemArray.splice(0, size);
gridRowArray.push(newArray);
}
var heightArray = [];
$.each(gridRowArray, function(index, gridRow){
var gridRowHeight = 0;
$.each(gridRow, function(innerIndex, gridItem){
var thisHeight = gridItem.find($equalHeightElement).height();
gridRowHeight = Math.max(thisHeight, gridRowHeight);
});
heightArray.push(gridRowHeight);
});
$.each(gridRowArray, function(i){
$.each(gridRowArray[i], function(){
$(this).find($equalHeightElement).css('height', heightArray[i]);
});
});
} else {
//If rows are only one item long, set height to auto.
$element.css('height', 'auto');
}
};
})(jQuery);
;
// Desktop Menu + Mobile Menu
(function ($) {
$(document).ready(function(){
// Desktop Menu
//$(".main-menu > ul.menu").hide();
//$(".main-menu > ul.menu").delay(500).fadeIn(500);
$('.main-menu ul.menu li.expanded > a').each(function() {
$(this).append('');
});
$('.main-menu ul.menu li.expanded > ul').each(function() {
$(this).append('');
});
setTimeout(function () {
$(".main-menu > ul.menu").show();
$('.main-menu ul.menu li.expanded .menu.dropdown').addClass('visible-all');
$('.main-menu ul.menu li.expanded > a').on("click", function (e) {
if (e.pageX > $(this).find(".arrow-span").offset().left) {
e.preventDefault();
$('.main-menu ul.menu li.expanded > a').not(this).siblings('.menu.dropdown').css('display', 'none');
$('.main-menu ul.menu li.expanded > a').parent().removeClass("active-arrow");
if($(this).parents().eq(4).siblings('.menu.dropdown').css('display') === "none") {
$(this).parents().eq(4).siblings('.menu.dropdown').css('display', 'block').css('height', 'auto');
$(this).parent().addClass("active-arrow");
$('.main-menu ul.menu li.expanded > .bordered').each(function() {
$(this).append('');
});
}
else{
$(this).parents().eq(4).siblings('.menu.dropdown').css('display', 'none');
$(this).parent().removeClass("active-arrow");
$(this).removeClass("hovered");
}
}
else {
window.location = $(this).attr("href");
}
});
}, 2000);
//Mobile Menu
$('.touch-nav .menu-container ul.menu li.expanded > a').each(function() {
$(this).prepend('');
});
$('.menu .close').on('click', function () {
$('.html .content-outer-wrapper').removeClass('moved');
$('.html #footer').removeClass('moved');
$('.html .touch-nav').removeClass('moved');
$('html').removeClass('hidden');
});
setTimeout(function () {
$('.touch-nav .menu-container ul.menu li.expanded > a').off('click').on("click", function (e) {
if (e.pageX > $(this).find(".arrow-span").offset().left) {
e.preventDefault();
$('.touch-nav li.expanded > a').not(this).siblings('ul').css('display', 'none');
$('.touch-nav .menu-container ul.menu li.expanded > a').parent().removeClass("active-arrow");
if($(this).siblings('ul').css('display') == "block") {
$(this).siblings('ul').css('display', 'none');
$(this).parent().removeClass("active-arrow");
}
else{
$(this).siblings('ul').css('display', 'block').css('height', 'auto');
$(this).parent().addClass("active-arrow");
}
}
else {
window.location = $(this).attr("href");
}
});
}, 2000);
});
})(jQuery);;
// Homepage Banner
(function ($, Drupal) {
$(document).ready(function() {
$(".banner-desktop").slick({
infinite: true,
dots: true,
});
$(".banner-mobile").slick({
infinite: true,
dots: true,
});
});
})(jQuery, Drupal);;
// Mobile Back to Top
(function ($) {
$(document).ready(function(){
var btn = $('.top-link');
$(window).scroll(function() {
if ($(window).scrollTop() > 300) {
btn.addClass('show');
} else {
btn.removeClass('show');
}
});
btn.on('click', function(e) {
e.preventDefault();
$('html, body').animate({scrollTop:0}, '300');
});
});
})(jQuery);;
/* globals customWindowLoad */
(function ($, Masonry) {
var tacoGroupArray = [];
var tacoGroupWrapperArray = [];
/**
* Updates the margin-bottoms on all grid-items (this is a work around because Firefox cannot calculate a percentage margin or padding on a display:flex element)
*/
var gridMarginAdjust = function(){
// Calculate the value of 2% of the .equal height
var margin = $('.equal-height').width() * 0.02;
// Apply the margin value to all .grid-item elements
$('.taco-polls, .node--taco').css('margin-bottom', margin);
};
var tacoWrapper = function(element){
var groupTarget = $('.content-row .taco-polls[data-taco-group="' + element + '"] ');
var groupTargetAll = $('.taco-polls[data-taco-group="' + element + '"] ');
groupTarget.wrapAll('');
groupTargetAll.each(function(){
// Add the div with the class .grid-inner inside each .grid-item
$(this).html('
' + $(this).html() + '
');
});
};
var socialStreamAdjust = function(){
var tacoRows = $('.equal-height');
var socialStream = $('.pane-jquery-social-stream');
var socialContent = socialStream.find($('.campaign-social-content .dcsns-content'));
// If there is a social stream on the page
if(socialStream.length > 0){
// For each row of tacos/polls/socialstreams
tacoRows.each(function(){
// Calculate socialHeaderHeight, cocialFooterHeight and socialContentHeight
var socialHeaderHeight = socialStream.find($('.campaign-social-header')).outerHeight();
var socialFooterHeight = socialStream.find($('.campaign-social-footer')).outerHeight();
var socialContentHeight = socialStream.find($('.campaign-social-content .dcsns-content')).outerHeight();
// Calculate the combined height of socialHeaderHeight and socialFooterHeight
var headerFooterHeight = socialHeaderHeight + socialFooterHeight;
// Set tallest variable equal to 0 to reset height for each row.
var tallest = 0;
if ($(this).find($('.taco-polls')).length > 1) {
// For each tacos/polls/socialstreams within this row calculate its height, and if taller than tallest, set tallest equal to newHeight
$(this).find($('.taco-polls')).each(function(){
var newHeight = $(this).outerHeight();
if (newHeight > tallest){
tallest = newHeight;
}
if (tallest > socialContentHeight){
var setStreamHeight = tallest - headerFooterHeight;
$(this).find(socialContent).css('max-height', 'none');
socialContent.find($('.mCustomScrollBox')).css('max-height', 'none');
$(this).find(socialContent).css('height', setStreamHeight);
}
});
}
});
}
// Social Stream selector for Page Builder pages (within a column slice).
socialStream = $('.paragraphs-items .col .pane-jquery-social-stream');
// If there is a social stream on the PB page.
if (socialStream.length > 0) {
socialStream.each(function() {
var socialContent = $(this).find('.campaign-social-content .dcsns-content');
// Calculate socialHeaderHeight, cocialFooterHeight and socialContentHeight
var socialHeaderHeight = $(this).find('.campaign-social-header').outerHeight();
var socialFooterHeight = $(this).find('.campaign-social-footer').outerHeight();
var socialContentHeight = $(this).find('.campaign-social-content .dcsns-content').outerHeight();
var socialContentToolBar = 0;
// Case: multi-stream will have toolbar.
// Get the height of that as well.
if ($(this).hasClass('multi-stream')) {
socialContentToolBar = $(this).find('.campaign-social-content .dcsns-toolbar').outerHeight();
}
// Calculate the combined height of socialHeaderHeight and socialFooterHeight
var headerFooterHeight = socialHeaderHeight + socialFooterHeight + socialContentToolBar;
// If the social stream is present in a column layout.
// Adjust the height to match the other column in the page.
var closestCol = $(this).closest('.col');
if (closestCol.length > 0) {
var siblingCol = $(this).closest('.col').siblings('.col').first();
var newHeight = siblingCol.outerHeight();
if (newHeight > socialContentHeight) {
var setStreamHeight = newHeight - headerFooterHeight;
socialContent.css('max-height', 'none');
socialContent.find('.mCustomScrollBox').css('max-height', 'none');
// Calculate and substract borders.
var sc_parent = socialContent.parent('.campaign-social-content');
var border_bottom_width = parseInt(sc_parent.css('border-bottom-width'), 10);
var border_top_width = parseInt(sc_parent.css('border-top-width'), 10);
// Sometimes there is some extra added by tacos, video, text slices.
// We need to handle it.
// Adjust the height of Social Stream ...
var last_slice = siblingCol.find('.entity-paragraphs-item').last();
var extra = 0;
if (last_slice.is('.paragraphs-item-paragraphs-pack-text')) {
// ... according to the last
in the sibling column.
// Find extra margin in text if line-height > font-height:
// it works because letters are centered vertically.
// [(line-height - font-size) / 2].
var last_slice_el = last_slice.find('*:last').last();
var last_slice_el_lh = parseFloat(last_slice_el.css('line-height'));
var last_slice_el_fs = parseFloat(last_slice_el.css('font-size'));
extra = Math.ceil((last_slice_el_lh - last_slice_el_fs) / 2);
} else if (last_slice.is('.paragraphs-item-paragraphs-pack-tout')) {
// ... according to the margin of the last tout in the sibling column.
extra = parseInt(last_slice.find('.node').css('margin-bottom'), 10);
} else if (last_slice.is('.paragraphs-item-paragraphs-pack-video')) {
// ... according to the margin of the
tag in the video slice.
var video_last_el = last_slice.find('*:visible').last();
if (video_last_el.prop('tagName') === 'H2') {
var extra_margin_lh = 0;
// If background color is set, it fills the gaps.
if (last_slice.css('background-color') === 'none') {
// Find extra margin in text if line-height > font-height.
var video_last_el_lh = parseFloat(video_last_el.css('line-height'));
var video_last_el_fs = parseFloat(video_last_el.css('font-size'));
extra_margin_lh = Math.ceil((video_last_el_lh - video_last_el_fs) / 2);
}
// Subtract the extra margin that is added dynamically above.
var video_title_h2_mb = parseFloat(video_last_el.css('margin-bottom'));
extra = Math.ceil(video_title_h2_mb + extra_margin_lh);
}
}
// Substract top and bottom borders and any extra.
socialContent.css('height', setStreamHeight - border_bottom_width - border_top_width - extra);
}
}
});
}
};
var masonry = function(){
if ($('.masonry').length){
$('.masonry .equal-height').masonry({
itemSelector : '.taco-polls',
isAnimated: false
});
}
};
// Use different arrays for 'ctaAdjust' and 'tacoWrapper' functions.
$('.taco-polls').each(function () {
if (!$(this).hasClass('html-touts') && tacoGroupWrapperArray.indexOf($(this).attr('data-taco-group')) === -1) {
tacoGroupWrapperArray.push($(this).attr('data-taco-group'));
}
if (tacoGroupArray.indexOf($(this).attr('data-taco-group')) === -1) {
tacoGroupArray.push($(this).attr('data-taco-group'));
}
if ($(this).hasClass('add-taco-inner')) {
$(this).html('
' + $(this).html() + '
');
}
});
var ctaAdjust = function(element){
var groupTarget = $('.taco-polls[data-taco-group="' + element + '"] ');
if (window.flags.hasAny('mobile')) {
var horizontalGroupTarget = groupTarget.filter('.horizontal');
var verticalGroupTarget = groupTarget.filter('.vertical');
verticalGroupTarget.each(function(i, el) {
var thisCTAHeight = $(this).find('.call-to-action a:visible').outerHeight();
$(this).find('.content-col').css('padding-bottom', thisCTAHeight);
});
horizontalGroupTarget.find('.content-col').css('padding-bottom', 0);
}
else {
var groupCTAHeight = 0;
groupTarget.find('.call-to-action a').css('height', 'auto');
groupTarget.each(function(){
var callToActionLink = $(this).find('.call-to-action a');
var thisCTAHeight = callToActionLink.length ? callToActionLink.outerHeight() : 0;
groupCTAHeight = Math.max(thisCTAHeight, groupCTAHeight);
});
if(groupCTAHeight < 42){
groupTarget.find('.content-col').css('padding-bottom', '42px');
} else {
if(groupTarget.find('.call-to-action a').length){
groupTarget.find('.content-col').css('padding-bottom', groupCTAHeight);
}
groupTarget.find('.call-to-action a').css('height', groupCTAHeight);
}
if (groupTarget.parents().hasClass('masonry') ) {
groupTarget.each(function() {
if ($(this).find('.field--name-field-taco-link-call-to-action a').length) {
var thisCTAHeight = $(this).find('.call-to-action a').outerHeight();
$(this).find('.content-col').css('padding-bottom', thisCTAHeight);
}
});
}
}
};
for (var i = 0; i < tacoGroupWrapperArray.length; i++) {
tacoWrapper(tacoGroupWrapperArray[i]);
}
for (var i = 0; i < tacoGroupArray.length; i++) {
ctaAdjust(tacoGroupArray[i]);
}
gridMarginAdjust();
// Run the functionality when the DOM is loaded.
var tacoWhenDOMIsLoaded = function() {
socialStreamAdjust();
masonry();
};
customWindowLoad(tacoWhenDOMIsLoaded);
$(window).on('throttledresize', function(){
for(var i = 0; i < tacoGroupArray.length; i++){
ctaAdjust(tacoGroupArray[i]);
}
gridMarginAdjust();
$('.pane-jquery-social-stream .campaign-social-content .dcsns-content').css('max-height', '250px');
$('.pane-jquery-social-stream .campaign-social-content .dcsns-content .mCustomScrollBox').css('max-height', 'none');
socialStreamAdjust();
});
Drupal.behaviors.jjTacos = {
attach: function () {
/**
* This function setups the tacos on page load (adjust the margins and make sure they are all the same height)
*/
var legacyAdjust = function(){
// Update the .pane-taco-pane height to 'auto' to grab the natural height of the element
$('.taco-polls').css('height', 'auto');
// Update the .pane-taco-pane CTA with padding '0' to allow correct resizing
$('.taco-polls[data-taco-group]').find('.field--name-field-taco-link-call-to-action a').css('padding', '0');
// Create a tacoGroupObj (this will be used to store the height information for the tacos to determine tallest)
var tacoGroupObj = {};
// Loop through each .pane-taco-pane to determine the taco height
$('.taco-polls').each(function(){
// Grab the height of the current taco CTA
var ctaHeight = $(this).find('.field--name-field-taco-link-call-to-action a').height();
// Add a padding-bottom to the current taco's content area to allow for space for the CTA
$(this).find('.content-col .content').css('padding-bottom', ctaHeight + 50);
// Grab the current taco's data-taco-group to be used to adjust the height (each taco group will have a different height)
var tacoGroup = $(this).data('taco-group');
// Grab the height of the current taco
var elHeight = $(this).height();
// If the taco group of the current taco is not included in the tacoGroupObj object
if(!tacoGroupObj[tacoGroup]){
// Add the current taco's height and current taco's CTA height to the tacoGroupObj (the CTA will be used to make sure all the CTA are the same height as well)
tacoGroupObj[tacoGroup] = {height: elHeight, linkHeight: ctaHeight};
// If the taco group of the current taco is included int he tacoGroupObj object
} else{
// If the current taco's CTA height is greater than the value currently on the tacoGroupObj object
if(ctaHeight > tacoGroupObj[tacoGroup].linkHeight){
// Update the tacoGroupObj ctaHeight value to the current tacos CTA height (this will only affect the current taco group and will ensure the largest number is added to the object)
tacoGroupObj[tacoGroup].linkHeight = ctaHeight;
}
// If the current taco's height is greater than the value currently on the tacoGroupObj object
if(elHeight > tacoGroupObj[tacoGroup].height){
// Update the tacoGroupObj elHeight value to the current tacos height (this will only affect the current taco group and will ensure the largest number is added to the object)
tacoGroupObj[tacoGroup].height = elHeight;
}
}
});
// Preform a for-in loop to target the individual taco groups (at this point each group will have one height value and one CTA height value)
for(var group in tacoGroupObj){
// This is a work around that will update the objects prototype to make it useful to us
if(tacoGroupObj.hasOwnProperty(group)){
// Check the page direction to update the margin on the tacos
var pageDirection = $('html').attr('dir');
// Target the first taco in the taco group
var firstTaco = $('.taco-polls[data-taco-group="' + group + '"]:first');
// Target the CTA within the TACOs
var tacoCTA = $('.taco-polls[data-taco-group="' + group + '"]').find('.field--name-field-taco-link-call-to-action a');
// If the pageDirection value is 'rtl'
if(pageDirection === 'rtl'){
// Update the margin-right attribute to '0'
firstTaco.css('margin-right', 0);
// Update the padding of the CTA to 'rtl' styling
tacoCTA.css('padding', '15px 15px 15px 31px');
// Else the pageDirection value is 'ltr'
} else {
// Update the margin-left attribute to '0'
firstTaco.css('margin-left', 0);
// Update the padding of the CTA to 'ltr' styling
tacoCTA.css('padding', '15px 31px 15px 15px');
}
// Using the height key value stored in the tacoGroupObj object, update all the taco's height within a taco group
$('.taco-polls[data-taco-group="' + group + '"]').css('height', tacoGroupObj[group].height);
// Using the linkHeight key value stored in the tacoGroupObj object, update all the taco's CTA height within a taco group
$('.taco-polls[data-taco-group="' + group + '"]').find('.field--name-field-taco-link-call-to-action a').css('height', tacoGroupObj[group].linkHeight);
}
}
};
if(!window.flags.hasAny('flexbox')){
legacyAdjust();
}
$(window).on('throttledresize', function(){
if(!window.flags.hasAny('flexbox')){
legacyAdjust();
}
});
}
};
})(jQuery, window.Masonry);
;
(function ($, jnj) {
Drupal.behaviors.jjFooterNav = {
attach: function (context) {
/**
* Controls the sticky footer logic
*/
var stickyAdjust = function(){
//Gather window, content, and footer height measurements
var $footer = $('.footer-row');
var windowHeight = $(window).height();
var contentHeight = $('body').height();
var footerHeight = $footer.outerHeight();
var footerHeightWithMargin = $footer.outerHeight(true);
//If the content height is smaller than the window height
if (contentHeight < windowHeight){
// Add .height-adjust to the html element
$('html').addClass('height-adjust');
// Update .layout's margin-bottom to the negative value of the footer height
$('.layout').css('margin-bottom', -footerHeightWithMargin);
// Update .sticky-footer height to the value of the footer height
$('.sticky-footer').css('height', footerHeight);
// Update .footer-row height to the value of the footer height
$('.footer-row').css('height', footerHeight);
}
};
/**
* Make sure each menu row is the same height.
*/
var equalHeightRows = function () {
// Target only the first level list items.
var footerListItems = $('.menu-footer').find('.menu:first').children('li');
// Grab the list item outer widths.
var gridWidth = footerListItems.outerWidth();
// Grab the closest .menu-footer width value.
var innerContentWidth = footerListItems.closest('.menu-footer').css('width');
// Divide the closest .menu-footer width value by the list item outer
// width to get the number of columns (basically something like this,
// ie. 100 / 25 = 4)
var numberOfColumns = parseInt(gridWidth, 10) / parseInt(innerContentWidth, 10) * 100;
// Divide the number of columns by 100 to move the decimal place to
// make it a whole number.
var nthNumber = Math.floor(100 / numberOfColumns);
// If the nthNumber variable (number of columns) and the device width
// is either 'tablet' or 'desktop'.
if (nthNumber > 1 && window.flags.hasAny(['tablet', 'desktop'])) {
// Split 'footerListItems' on rows based on 'nthNumber' value.
var itemRows = chunkArray(footerListItems, nthNumber);
// Remove .no-margin (this step needs to be done to allow for responsive support).
footerListItems.removeClass('no-margin');
$.each(itemRows, function (i) {
jnj.setEqualHeight(itemRows[i]);
$(this).first().addClass('no-margin');
});
// Else if the device width is 'mobile'.
}
else {
// Set the list item's height to auto.
footerListItems.css('height', 'auto');
}
};
/**
* Splits array into chunks.
*
* @param itemsArray
* @param chunkSize
*
* @returns array
*/
var chunkArray = function (itemsArray, chunkSize) {
var index = 0;
var arrayLength = itemsArray.length;
var resultArray = [];
var chunk = [];
for (index = 0; index < arrayLength; index += chunkSize) {
chunk = itemsArray.slice(index, index + chunkSize);
resultArray.push(chunk);
}
return resultArray;
};
var cookieBannerAdjust = function(){
var slidingPopup = $('#sliding-popup');
if(slidingPopup.length > 0){
var slidingPopupHeight = slidingPopup.outerHeight();
$('.footer-row').css('padding-bottom', slidingPopupHeight);
// Remove padding-bottom after popup is closed.
$('.hide-popup-button, .agree-button', '#sliding-popup', context).once('click').on('click', function() {
$('.footer-row', context).css('padding-bottom', '');
});
}
};
// Run the functionality when the DOM is loaded.
var whenDOMIsLoaded = function() {
// On page load run the equalHeightRows function
equalHeightRows();
// If the device size is 'mobile' or touch is enabled
if( window.flags.hasAllOf(['mobile', 'touch']) ){
// Add .mobile to the .footer-row
$('.footer-row').addClass('mobile');
}
// On page load run the adjust function to update the sticky footer
stickyAdjust();
// On page load adjust the footer to prevent the cookie banner from covering the footer
cookieBannerAdjust();
var recalculateHeights = function () {
// Change .footer-row height to 'auto' to prevent the content from being cut off
$('.footer-row').css('height', 'auto');
// Run the adjust function that will update the sticky footer
stickyAdjust();
// Run the footer to prevent the cookie banner from covering the footer
cookieBannerAdjust();
// Run the equalHeightRows function to make adjustments to the footer list item column heights
equalHeightRows();
};
// Recalculate on resize.
$(window).on('throttledresize', function () {
recalculateHeights();
});
// Recalculate on social filter change.
$('#dcsns-filter li a', context).on('click', function () {
recalculateHeights();
});
// recalculateHeights should be called after closing touch menu.
const mutationConfig = {
attributes: true,
attributeFilter: ['class']
};
let targets = document.querySelectorAll('.touch-nav');
let isMutated;
let onMutate = function (mutations) {
mutations.forEach(function (mutation) {
const touchNavOpened = $(mutation.target).hasClass('moved');
if (!isMutated && !touchNavOpened) {
isMutated = true;
recalculateHeights();
}
if (touchNavOpened) {
isMutated = false;
}
});
};
let observer = new MutationObserver(onMutate);
targets.forEach(function (target) {
observer.observe(target, mutationConfig);
});
};
window.customWindowLoad(whenDOMIsLoaded);
}
};
})(jQuery, window.jnj);
;
(function ($) {
Drupal.behaviors.jjMobileDesktopToggle = {
attach: function () {
//For later instantiation
var deviceToggle;
/**
* Constructor for switching back and forth between mobile/desktop nav states.
*/
function DeviceToggle(){
//Flag to check if menu height has already been calculated
this.alreadyCalculated = false;
//Scope
var that = this;
// Bind resize to check state for change
$(window).on( 'throttledresize', function(){
// If the device size is 'tablet'
if ( window.flags.hasAny('tablet') ){
// Run the touchSwitch function to update the page layout to touch optimized
that.touchSwitch();
// Else 'desktop' device size
} else {
// Run the desktopSwitch function to update the page layout to desktop optimized
that.desktopSwitch();
}
});
// If the device size is 'tablet'
if ( window.flags.hasAny('tablet') ){
// Run the touchSwitch function to update the page layout to touch optimized
that.touchSwitch();
// Else 'desktop' device size
} else {
// Run the desktopSwitch function to update the page layout to desktop optimized
that.desktopSwitch();
}
}
/**
* Set up initial heights of the menus
* NOTE: Only want to run this once, so set our calculation flag to true
*/
DeviceToggle.prototype.menuSetup = function(){
var that = this;
// Grab the first .menu in the .navigation-row region
var listItems = $('.navigation-row').find('.menu:first');
// Grab the children of the first .menu items
var menuLinks = listItems.children();
//Go through all menu links to check their submenu heights and apply accordingly.
menuLinks.each(function(){
// Grab the unordered list of each child of the first .menu
var links = $(this).children('ul');
// Get the height of each unordered list
var linksHeight = $(links).height();
// Set the 'data-height' value on the unordered list to the height of the unordered list
links.data('height', linksHeight);
});
//Set calculation flag to true
that.alreadyCalculated = true;
};
/**
* If touch/mobile/tablet...
*/
DeviceToggle.prototype.touchSwitch = function(){
//Remove hoverIntent bindings
var unbindHoverIntent = function(selector){
// Unbind the mouseenter and mouseleave (this will prevent unintended bugs on tablet/mobile in the navigation-row)
selector.unbind('mouseenter').unbind('mouseleave');
// Remove the hoverIntent_t properties (this will prevent unintended bugs on tablet/mobile in the navigation-row))
selector.removeProp('hoverIntent_t');
// Remove the hoverIntent_s properties (this will prevent unintended bugs on tablet/mobile in the navigation-row))
selector.removeProp('hoverIntent_s');
};
// Unbind the .top-level element through unbindHoverIntent function
unbindHoverIntent( $('.top-level') );
// Unbind the .search-button element through unbindHoverIntent function
unbindHoverIntent( $('.search-button') );
// Unbind the .navigation-row element through unbindHoverIntent function
unbindHoverIntent( $('.navigation-row') );
//Clean up
$('.search-button').removeClass('search-expanded');
//Bind nav button
$('.mobile-nav-button').on('click', function(e){
e.preventDefault();
});
};
/**
* If desktop
*/
DeviceToggle.prototype.desktopSwitch = function(){
//If menu heights haven't been calculated yet, do so...
if (!this.alreadyCalculated){
this.menuSetup();
}
/**
* Set up hoverIntent and apply bindings
* @param {[object]} selector
*/
var bindHoverIntent = function(selector){
// Bind the mouseenter and mouseleave
selector.bind('mouseenter').bind('mouseleave');
// Bind the hoverIntent_t property
selector.prop('hoverIntent_t');
// Bind the hoverIntent_s property
selector.prop('hoverIntent_s');
};
// Bind the .top-level element through bindHoverIntent function
bindHoverIntent( $('.top-level') );
// Bind the .search-button element through bindHoverIntent function
bindHoverIntent( $('.search-button') );
// Bind the .navigation-row element through bindHoverIntent function
bindHoverIntent( $('.navigation-row') );
//Clean up
$('.container').removeClass('moved, ie-moved');
};
//Instantiation
deviceToggle = new DeviceToggle();
}
};
})(jQuery);
;
// Tell JSHint that jnj is a global
/*global jnj: true */
(function ($) {
Drupal.behaviors.jjGrid = {
attach: function (context) {
// Grab all .grid-items on the page.
var gridElements = $('.grid-item', context);
// Adjusts media pages, if one-quarter class doesnt exists then it will
// change the three-quarters to full width.
var lengthNode = $('.section-media .main-row .pane-node-body.one-quarter', context).length;
var imageWrapper = $('.section-media .main-row .pane-node-field-image-detail-image', context);
if(lengthNode < 1){
imageWrapper.removeClass('three-quarters');
imageWrapper.addClass('full');
}
/**
* Updates the margin-bottoms on all grid-items (this is a work around
* because Firefox cannot calculate a percentage margin or padding on a
* display:flex element).
*/
var gridMarginAdjust = function(){
// Calculate the value of 2% of the .equal height.
var margin = $('.equal-height').width() * 0.02;
// Apply the margin value to all .grid-item elements.
if (!$('.node-type-page-builder').length){
gridElements.css('margin-bottom', margin);
}
};
/**
* Calculate the height of all the .grid-item CTA.
* @param {[object]} link
* @param {[string]} scope
*/
var ctaAdjust = function(link, scope){
// Reset the height of the CTA
var ctaHeight = 0;
// Loop through each CTA link
$(link).each(function(){
// Reset 'height' value to get natural height on resize.
var linkHeight = $(this).css('height', 'auto').outerHeight();
if (Drupal.settings.accessibilityEnabled && $(this).find('img').length > 0) {
$(this).css({'padding': '0', 'position': 'static'});
linkHeight = $(this).find('.related-cta-title').css('height', 'auto').outerHeight();
}
$(this).hide();
$(this).css('height', 'auto');
// Compare the CTA height of the current grid-item with the value of
// ctaHeight and define ctaHeight to the largest number.
ctaHeight = Math.max(linkHeight, ctaHeight);
$(this).show();
});
// Check to see if the scope parameter is defined (this will keep the
// padding-bottom added to only the grid-items within the scoped div
// class).
if(scope !== undefined){
// Set the grid-item padding-bottom to the ctaHeight value.
$(scope).find(gridElements).css('padding-bottom', ctaHeight);
}
else {
gridElements.css('padding-bottom', ctaHeight);
}
link.css('height', ctaHeight);
if (Drupal.settings.accessibilityEnabled) {
link.each(function() {
if ($(this).find('img').length > 0) {
$(this).css('height', 'auto').find('.related-cta-title').css('height', ctaHeight);
}
});
}
};
/**
* This function will adjust the grid-item to support the CTA adjustments.
*/
var ctaDeclarations = function(){
$('.equal-height').each(function(){
// If /coupons
if($('.grid-area').hasClass('.coupons')){
// Run the ctaAdjust function with the argument as
// .offer-id-container.
ctaAdjust($('.bean-coupon .offer-id-container'));
// Else if /articles
}
if($('.view-articles').length > 0){
// Run the ctaAdjust function with the argument as .read-more a.
ctaAdjust($('.node-readmore a'), '.view-articles');
// Else if /product-categories.
}
if($('.grid-area').hasClass('categories')){
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.grid-area.categories .grid-item a'), '.view-product-categories');
}
if($('.related-content-carousel-container').length > 0) {
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.related-content-carousel-container .related-cta'), '.related-content-carousel-container');
}
if($('.simple-search-carousel-container').length > 0) {
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.simple-search-carousel-container .related-cta'), '.simple-search-carousel-container');
}
if($('.view-videos').length > 0) {
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.view-videos .field--name-title-field a'), '.view-videos');
}
if($('.view-polls').length > 0) {
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.view-polls .poll-cta a'), '.view-polls');
}
if($('.view-media-collection-gallary').length > 0) {
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.view-media-collection-gallary .node-readmore a'), '.view-media-collection-gallary');
}
if($('.view-quizzes').length > 0) {
// Run the ctaAdjust function with the argument as a.
ctaAdjust($('.view-quizzes .quiz-cta a'), '.view-quizzes');
}
});
};
/**
* Updates the grid item layout
*/
var legacyAdjust = function(){
// Exclude the .coupons .grid-item from running the setEqualHeight
// helper.
jnj.setEqualHeight($('.grid-item'));
};
// Run the setEqualHeight function on the coupons .grid-item.
var coupontextAdjust = function(){
if($('.grid-area').hasClass('coupons')){
jnj.setEqualHeightRow($('.coupons .grid-item').find($('.main-content')));
}
};
// Run the setEqualHeight function on the products .grid-item.
var productsGridAdjust = function(){
if($('.grid-area').hasClass('products')){
jnj.setEqualHeightRow($('.pane-products-panel-pane-1 .grid-item').find($('.node__title')));
}
};
var quizGridAdjust = function(){
if ($('.view-quizzes').length){
jnj.setEqualHeightRow($('.view-quizzes .grid-item').find($('.pane-node-title-field')));
}
};
var quizResultGridAdjust = function(){
var quizResultsPage = $('.node-type-quiz-result-page');
var quizMainContent = quizResultsPage.find($('.main-row'));
var quizThreeQuarters = quizMainContent.find($('.three-quarters'));
var quizOneQuarter = quizMainContent.find($('.one-quarter'));
var oneQuarterImage = quizOneQuarter.find($('img'));
if (quizThreeQuarters.length || quizThreeQuarters.next(quizOneQuarter).length) {
oneQuarterImage.clone().prependTo( quizThreeQuarters.find($('.pane-node-title-field')) );
}
};
var equalHeight = function() {
gridElements.each(function() {
// Add the class .equal-height to the parent element to initial the
// flex box styling.
$(this).parent().addClass('equal-height');
});
};
var gridInner = function() {
gridElements.each(function () {
// Add the div with the class .grid-inner inside each .grid-item.
if(!$(this).children().hasClass("grid-inner")) {
$(this).wrapInner('');
}
});
};
// Run the gridAdjust function.
coupontextAdjust();
productsGridAdjust();
quizGridAdjust();
quizResultGridAdjust();
equalHeight();
gridInner();
// Run the gridMarginAdjust function.
gridMarginAdjust();
// Run the ctaDeclarations function.
ctaDeclarations();
// On page load run the gridAdjust function if browser does not support
// flex box.
if(!window.flags.hasAny('flexbox')){
legacyAdjust();
}
// On page resize run the gridAdjust function if browser does not support
// flex box.
$(window).on('debouncedresize', function(){
coupontextAdjust();
productsGridAdjust();
quizGridAdjust();
if(!window.flags.hasAny('flexbox')){
legacyAdjust();
}
// Run the gridMarginAdjust function on page resize.
gridMarginAdjust();
// Run the ctaDeclarations function on page resize.
ctaDeclarations();
});
}
};
})(jQuery);
;
(function ($) {
Drupal.behaviors.jjNavigation = {
navigationAPI:{
// This variable controls the speed that the navigation drop down opens and closes
// @options = 'auto'
// @options = a number value
animationSpeed: 'auto',
// This variable controls the option to make the third level menu lists be full width or contained in a drop down like the default two-level
// @option = true
// @option = false
supportThreeLevelFullWidth: true
},
attach: function() {
var listCount;
// Create a variable for .main-menu
var mainMenu = $('.navigation-row .main-menu');
// Isolate the first level .expanded li as a selector
var firstLevelLinks = mainMenu.find('ul:first > li.expanded');
// Grab the dir attribute from the html (language direction control)
var pageDirection = $('html').attr('dir');
$(window).load(function(){
$('.navigation-row .main-menu .menu .expanded').on('mouseenter',function(){
$(this).find('.menu').show();
}).on('mouseleave', function(){
$(this).find('.menu').hide();
});
// On resize adjust the multi level dropdown width and all dropdown heights
$(window).on('debouncedresize', function(){
});
});
}
};
})(jQuery);
;
(function ($) {
Drupal.behaviors.jjFancyBox = {
attach: function () {
// Adds the default modal styling to all fancybox modal by extending fancybox default values
var jjDefaults = {
'transitionIn':'fade',
'transitionOut':'fade',
'speedIn':150,
'speedOut':150,
'changeSpeed':150,
'changeFade':150,
'overlayOpacity':0.1,
'overlayColor':'#000000',
'closeSpeed':150,
'closeOpacity':false,
'padding':20,
'titleShow':false,
'centerOnScroll':true
};
$('.fancybox').fancybox(jjDefaults);
}
};
})(jQuery);
;
(function ($) {
Drupal.behaviors.jjLoginDropdown = {
loginDropdownAPI: {
// This variable controls the speed that the login dropdown opens and closes
// @options = a number value
animationSpeed: 100
},
attach: function () {
var loggedIn;
/**
* Set up the login dropdown element
* @param {[object]} $dropDown
* @param {[boolean]} loggedIn
*/
var clickInitialize = function($dropDown, loggedIn){
// Find the .login-toggle-link in each .login-dropdown element
var $dropDownLink = $dropDown.find('.login-toggle-link');
// Find the ul inside the .login-dropdown, this will be the target reveal element
var list = $dropDown.find('.menu-loggedin ul');
// Grab the outer height of the target reveal element
// Define a active class
var activeClass = 'active-dropdown';
// If a user is logged
if( loggedIn ){
// When the .login-toggle-link is clicked
$dropDownLink.off('click').on('click', function(e){
e.preventDefault();
list.stop(true, true).slideToggle(Drupal.behaviors.jjLoginDropdown.loginDropdownAPI.animationSpeed);
$(this).toggleClass(activeClass);
});
// If not logged in
} else {
// Show the .menu-login (this will contain the 'Log In / Sign Up' link)
$(this).find('.menu-login').show();
if (!Drupal.settings.janrain.janrain_embed_form) {
$('.login').on('click', 'a', function (e) {
e.preventDefault();
});
$('.signup').on('click', 'a', function (e) {
e.preventDefault();
});
}
}
};
// For each .login-dropdown
$('.login-dropdown').once('login-dropdown').each(function(){
// Check to see the body has .logged-in (this is added by drupal)
if( $('body').hasClass('logged-in') ){
// Set the loggedIn variable to true, this will be used in a conditional in the clickInitialize function (line 15)
loggedIn = true;
// Else the user is not logged in (body has class .not-logged-in)
} else {
// Set the loggedIn variable to false, this will be used in a conditional in the clickInitialize function (line 15)
loggedIn = false;
}
// Run the clickInitialize function on page load, this will set up the login dropdown
clickInitialize($(this), loggedIn);
$(window).on('debouncedresize', function(){
// Run the clickInitialize function on page resize, this will update the login dropdown
clickInitialize($(this), loggedIn);
});
});
if (typeof Drupal.behaviors.janrainCaptureCallbacks === 'object' && typeof Drupal.behaviors.janrainCaptureCallbacks.addCaptureLoadCallback === 'function') {
Drupal.behaviors.janrainCaptureCallbacks.addCaptureLoadCallback(function() {
$('.login-dropdown .menu-login').removeClass('disabled');
});
}
}
};
})(jQuery);
;
(function ($, tappable) {
var MobileMenuViewModel = (function() {
var emulateTab = function(offset) {
offset = offset || 1;
var focusable = $('a[href]').not(':disabled').not(':hidden').not(':empty');
var currentElement = this.lastFocusedElement;
var currentIndex = focusable.index(currentElement);
var nextIndex = (currentIndex + offset) % focusable.length;
if (nextIndex <= -1) {
nextIndex = focusable.length + nextIndex;
}
var nextElement = focusable.eq(nextIndex);
nextElement.focus();
};
/**
* Return list of currently visible items.
*/
var findVisibleItems = function() {
return $(this.parentNode).find('.block--jjbos-where-to-buy2 .block__content a:visible, .block--janrain .block__content a:visible, ul[class!=contextual-links] li a:visible');
};
/**
* Return last index of currently visible items.
*/
var getLastIndex = function() {
return findVisibleItems.call(this).length - 1;
};
/**
* Calcualte index for the currently selected tab item.
*
* @param {currentItem} Node
* @returns number
*/
var findCurrentIndex = function(currentItem) {
var currentIndex = 0;
var items = findVisibleItems.call(this);
$(items).each(function(index, item) {
if (currentItem === item) {
currentIndex = index;
return false;
}
});
return currentIndex;
};
/**
* Return current state of the tab.
*
* @returns boolean
*/
var isTabExpanded = function() {
return $(this).hasClass('active-accordion');
};
/**
* Focus on the tab item.
*
* @param {index} number
*/
var move = function(index) {
var items = findVisibleItems.call(this);
items[index].focus();
};
/**
* Focus on the first item.
*/
var moveFirst = function() {
move.call(this, 0);
};
/**
* Focus on the last item.
*/
var moveLast = function() {
move.call(this, getLastIndex.call(this));
};
/**
* Move forward on tab items.
*
* @param {currentItem} Node
*/
var moveForward = function(currentItem) {
if (findCurrentIndex.call(this, currentItem) === getLastIndex.call(this)) {
moveFirst.call(this);
}
else {
emulateTab.call(this);
}
};
/**
* Move backward on tab items.
*
* @param {currentItem} Node
*/
var moveBackward = function(currentItem) {
if (findCurrentIndex.call(this, currentItem) === 0) {
moveLast.call(this);
}
else {
emulateTab.call(this, -1);
}
};
/**
* Process the key.
*/
var Tab_OnKeyDown = function(e) {
switch (e.keyCode) {
// SPACE
case 32:
$(e.target).click();
break;
// END
case 35:
moveLast.call(e.data.accordion, e.target);
break;
// HOME
case 36:
moveFirst.call(e.data.accordion, e.target);
break;
// LEFT
case 37:
// UP
case 38:
moveBackward.call(e.data.accordion, e.target);
break;
//RIGHT
case 39:
// DOWN
case 40:
moveForward.call(e.data.accordion, e.target);
break;
}
};
/**
* Handle click on tab.
*/
var Tab_OnClick = function(e) {
var tab = $(e.target);
// Toggle related content focusable state depends from the
// expanded state of the tab.
if (isTabExpanded.call(tab)) {
tab.attr('aria-selected', 'true');
tab.attr('aria-expanded', 'true');
} else {
tab.attr('aria-selected', 'false');
tab.attr('aria-expanded', 'false');
}
};
/**
* Prevent default behavior of the keys.
*/
var Tab_OnKeyDown_PreventDefault = function(e) {
switch (e.keyCode) {
// END
case 35:
// HOME
case 36:
// LEFT
case 37:
// UP
case 38:
//RIGHT
case 39:
// DOWN
case 40:
e.preventDefault();
break;
}
};
/**
* Interact with the DOM.
*
* @private
*/
var renderUI = function() {
// Prevent non-used links to receive focus.
$('.block--janrain-janrain-user-menu .block__title').attr('tabindex', -1);
$('.touch-nav .block__title').attr('tabindex', -1);
$('.touch-nav .login-toggle-link').attr('tabindex', -1);
if (window.flags.hasAny(['tablet', 'mobile'])) {
// Prevent hidden menu links from receiving focus on mobile devices.
$('.block--janrain-janrain-user-menu .block__content a').attr('tabindex', -1);
}
};
/**
* Assign listeners to the node events.
*
* @private
*/
var bindUI = function() {
this.items.keydown({ accordion: this }, Tab_OnKeyDown);
this.items.keydown({ accordion: this }, Tab_OnKeyDown_PreventDefault);
this.items.click({ accordion: this }, Tab_OnClick);
$('.nav-button').blur(function() {
if (mobileMenu.isOpened) {
$('.nav-button').attr('aria-label', $('.nav-button').data('label-expand'));
} else {
$('.nav-button').attr('aria-label', $('.nav-button').data('label-collapse'));
}
});
// Control focus guards to marshall user focus to the menu items.
var menuFocusGuards = $('.touch-nav .focus-guard');
var buttonFocusGuards = $('.nav-button').siblings('.focus-guard');
$(menuFocusGuards).on('focus', function() {
$('.nav-button').focus();
});
var mobileMenu = this;
$(buttonFocusGuards).on('focus', function(e) {
if (mobileMenu.isOpened) {
if (e.target === buttonFocusGuards[0]) {
moveLast.call(mobileMenu);
} else {
moveFirst.call(mobileMenu);
}
}
});
$(window).keyup(function(e) {
// Handle ESC button.
if (e.keyCode === 27 && mobileMenu.isOpened) {
$('.nav-button').click().focus();
}
});
$(document).on('focusin', function(e) {
mobileMenu.lastFocusedElement = e.target;
});
};
/**
* Mobile menu view model.
*
* Helper class for the mobile menu.
* @constructor
*/
var viewModel = function() {};
/**
* @property {boolean}
*/
viewModel.prototype.isOpened = false,
/**
* @property {array}
*/
viewModel.prototype.items = [],
/**
* @property {array}
*/
viewModel.prototype.visibleItems = [],
/**
* @property {number}
*/
viewModel.prototype.currentIndex = 0,
/**
* @property {number}
*/
viewModel.prototype.firstIndex = 0,
/**
* @property {Node}
*/
viewModel.prototype.parentNode = null;
/**
* @property {Node}
*/
viewModel.prototype.lastFocusedElement = null;
/**
* Initialize the mobile menu.
*
* Store menu items, calculate items length and bind events to the focus
* guards to marshall user agent focus to the menu items.
*
* @argument {Node} parentNode Menu parent node
*/
viewModel.prototype.initialize = function(parentNode) {
this.parentNode = parentNode;
this.items = $(parentNode).find('.block--jjbos-where-to-buy2 .block__content a:visible, .block--janrain .block__content a:visible, ul[class!=contextual-links] li a');
renderUI.call(this);
bindUI.call(this);
};
/**
* Toggle menu state: open or close.
*/
viewModel.prototype.toggle = function() {
if (this.isOpened) {
this.close();
} else {
this.open();
}
};
/**
* Open the mobile menu.
*
* Focus to the first menu item then opened.
*/
viewModel.prototype.open = function () {
this.isOpened = true;
$('.touch-nav .focus-guard').show().attr('tabindex', '0');
$('.nav-button').siblings('.focus-guard').show().attr('tabindex', '0');
$('.nav-button').attr('aria-label', $('.nav-button').data('label-titles'));
$('.nav-button').focus();
};
/**
* Close the mobile menu.
*/
viewModel.prototype.close = function () {
$('.touch-nav .focus-guard').hide().attr('tabindex', '-1');
$('.nav-button').siblings('.focus-guard').hide().attr('tabindex', '-1');
$('.nav-button').attr('aria-label', $('.nav-button').data('label-collapse'));
this.isOpened = false;
};
return viewModel;
})();
Drupal.behaviors.jjMobileNavButton = {
mobileNavButtonAPI:{
// This variable controls the amount IE9 will animate the side menu over (this should match the $touchNavWidth variable value, located on line 21 of debug/styles/sass/core/_base.scss)
// @options = a number value
legacySlideAmount: 265
},
attach: function () {
//For future instantiation
var mobileNavButtonTimer;
// Define the containers that will be targeted when animating the side menu
var $containersSelectors = [
'#content',
'#footer',
'.touch-nav',
'.sticky-page .sticky-header-inner',
'.sticky-page-desktop .sticky-header-inner',
'.sticky-page-tablet .sticky-header-inner',
'.sticky-page-mobile .sticky-header-inner'
];
var $containers = $($containersSelectors.join(', '));
// Define the cover that will prevent the user from pressing on links before the animation is finished
var $clickCover = $('.click-cover');
// Define the button that will be clicked
var $navButton = $('.nav-button');
/**
* Use CSS3 to toggle mobile nav when the browser supports 'transitions' and 'transforms' this is being determined by modernizr.js)
* @param {[string]} textDirection
*/
var handleModern = function(textDirection) {
//If the containers have .moved (this means that is it opened)
if ( $containers.hasClass('moved') ){
// Remove the classes .moved and .right
$containers.removeClass('moved right');
// Remove the .hidden and .height-adjust classes from the html
$('html').removeClass('hidden height-adjust');
// Hide the click cover after 200 ms to prevent pre-animation finished clicks
setTimeout(function(){
// Hide the click cover element
$clickCover.hide();
}, 200);
// Remove the .active-nav class from the nav button to remove the active state
$navButton.removeClass('active-nav');
// Remove .active-accordion from the side menu list items
$('.touch-nav li').removeClass('active-accordion');
// Remove .active-accordion from the side menu list items links
$('.touch-nav li a').removeClass('active-accordion');
// Remove .active-accordion from the menu items.
$('.touch-nav li span.nolink').removeClass('active-accordion');
// Reset the side menu unordered lists heights back to zero (closing them)
$('.touch-nav li ul').css('height', 0);
//If the containers do not have .moved (this means that is it closed)
} else {
// Determine which side the side menu will be on (rtl site the menu will be on the right)
// If 'rtl' page orientation
if ( textDirection === 'rtl' ){
// Add the classes .moved and .right to the container elements
$containers.addClass('moved right');
// Else 'ltr' page orientation
} else {
// Add the class .moved to the container elements
$containers.addClass('moved');
}
// Add the class .active-nav to the nav-button to display active state
$navButton.addClass('active-nav');
// Add the classes .hidden and .height-adjust to the html tag to disable the page scrollign
$('html').addClass('hidden height-adjust');
// Show the click cover element to prevent the clicking of links before the animation is complete
$clickCover.show();
}
};
/**
* Use JS to toggle mobile nav when the browser does not support 'transitions' or 'transforms (this is being determined by modernizr.js)
* @param {[string]} textDirection
*/
var handleLegacy = function(textDirection) {
// Determine how far the legacy animation functionality will move (the value is defined on line 7)
var slideAmount = Drupal.behaviors.jjMobileNavButton.mobileNavButtonAPI.legacySlideAmount;
// Determine the containers IE will be targeting
var $ieContainers = $('#content, #footer');
//If the containers have .moved (this means that is it opened)
if ( $containers.hasClass('ie-moved') ){
// Remove the classes .ie-moved and .right from the containers
$containers.removeClass('ie-moved right');
// Determine which side the side menu will be on (rtl site the menu will be on the right)
// If 'rtl' page orientation
if ( textDirection === 'rtl' ) {
// Animate the IE container to right 0
$ieContainers.stop(true, true).animate({
right:'0'
});
// Animate the .touch-nav (side menu container) the legacySlideAmount value on the right
$('.touch-nav').stop(true, true).animate({
right: -slideAmount
});
//If the containers do not have .moved (this means that is it closed)
} else {
// Animate the IE container to left 0
$ieContainers.stop(true, true).animate({
left:'0'
});
// Animate the .touch-nav (side menu container) the slideAmount value on the left
$('.touch-nav').stop(true, true).animate({
left: -slideAmount
});
}
// Remove the .hidden and .height-adjust classes from the html
$('html').removeClass('hidden height-adjust');
// Hide the click cover after 400 ms to prevent pre-animation finished clicks
mobileNavButtonTimer = setTimeout(function(){
$clickCover.hide();
}, 400);
// Remove .active-accordion from the side menu list items
$('.touch-nav li').removeClass('active-accordion');
// Remove .active-accordion from the side menu list items links
$('.touch-nav li a').removeClass('active-accordion');
// Reset the side menu unordered lists heights back to zero (closing them)
$('.touch-nav li ul').css('height', 0);
//If the containers do not have .moved (this means that is it closed)
} else {
// Add the classes .ie-moved and .right to the container
$containers.addClass('ie-moved right');
// Determine which side the side menu will be on (rtl site the menu will be on the right)
// If 'rtl' page orientation
if ( textDirection === 'rtl' ) {
// Animate the IE containers the value of the legacySlideAmount variables
$ieContainers.stop(true, true).animate({
right:slideAmount
});
// Animate the .touch-nav (side menu container) to the right 0
$('.touch-nav').stop(true, true).animate({
right:0
});
// Else 'ltr' page orientation
} else {
// Animate the IE containers the value of the legacySlideAmount variables
$ieContainers.stop(true, true).animate({
left:slideAmount
});
// Animate the .touch-nav (side menu container) to the left 0
$('.touch-nav').stop(true, true).animate({
left:0
});
}
// Add the classes .hidden and .height-adjust to html
$('html').addClass('hidden height-adjust');
// Show the click cover element to prevent the clicking of links before the animation is complete
$clickCover.show();
}
};
/**
* We'll use CSS3 to animate if supported, if not, javascript.
* This method determines the browser's capabilities
*/
var determineHandler = function() {
if ( $containers.hasClass('moving') ){
return;
}
$containers.addClass('moving');
var textDirection;
// Determine if the site orientation is 'rtl'
if ($('html').attr('dir') === 'rtl' ){
// Set the textDirection variable to 'rtl', this will be used inside the handleModern and handleLegacy function to make adjustments for rtl
textDirection = 'rtl';
}
//If the browser supports 'transitions' and 'transforms'
if( window.flags.hasAllOf('transitions', 'transforms') ){
//Use the CSS3 handleModern function
handleModern(textDirection);
// Else if the broswer does not support 'transitions' and 'transforms''
} else{
// Use javscript to animate with the handleLegacy function
handleLegacy(textDirection);
}
$containers.removeClass('moving');
};
// This is to only provide tappable functionality if tappable library is present (IE8 doesn't support)
if(tappable){
tappable('.nav-button', {
activeClass: 'tapped',
allowClick: true,
noScrollDelay: 100,
activeClassDelay: 100,
inactiveClassDelay: 100
});
}
var debouncedresize_handler = function() {
if (!window.flags.hasAny(['desktop'])) {
return;
}
// On resize clear the click Cover hide setTimeout
clearTimeout(mobileNavButtonTimer);
//If already open, close it...
if( $containers.hasClass('moved') || $containers.hasClass('ie-moved') ){
// Run the determineHandler function to run either CSS3 or JS animation depending on browser capabilities
determineHandler();
}
};
// Initialize mobile menu.
var mobileMenu = new MobileMenuViewModel();
mobileMenu.initialize('.touch-nav');
// The side nave 'hamburger' icon
$navButton.once($navButton).off('click').on('click', function(e){
// Prevent debouncedresize event on 'hamburger' icon.
$(window).off('debouncedresize');
e.preventDefault();
// Clear the clickCover hide setTimeout
clearTimeout(mobileNavButtonTimer);
if($('.knob-container').hasClass('prevent-click')){
// Add the class .prevent-click to stop a user from click the timer
$('.knob-container').removeClass('prevent-click');
} else {
// Add the class .prevent-click to stop a user from click the timer
$('.knob-container').addClass('prevent-click');
}
// Trigger the .knob-container click, this will pause /play the carousel (when the side menu is open the carousel will pause)
$('.knob-container').trigger('click');
// Run the determineHandler function to run either CSS3 or JS animation depending on browser capabilities
determineHandler();
// Toggle mobile menu on button click.
mobileMenu.toggle();
// Attach debouncedresize event back after mobile menu is ready.
$(window).on('debouncedresize', debouncedresize_handler);
});
$(window).on('debouncedresize', debouncedresize_handler);
}
};
})(jQuery, window.tappable);
;
/* jshint esnext:true */
(function ($, imagesLoaded) {
Drupal.behaviors.jjNavigation = {
navigationAPI:{
// This variable controls the speed that the navigation drop down opens and closes
// @options = 'auto'
// @options = a number value
animationSpeed: 'auto',
// This variable controls the option to make the third level menu lists be full width or contained in a drop down like the default two-level
// @option = true
// @option = false
supportThreeLevelFullWidth: true
}
};
var listCount;
// Create a variable for .main-menu
var mainMenu = $('.navigation-row .main-menu');
// Isolate the first level .expanded li as a selector
var $firstLevelLinks = mainMenu.find('ul:first > li.expanded');
// Grab the dir attribute from the html (language direction control)
var pageDirection = $('html').attr('dir');
/**
* Dynamically adjust the reveal speed based on the elementHeight
* @param {[number]} elementHeight
* @return {[number]}
*/
var animationSpeedAdjust = function(elementHeight){
// If the animationSpeed variable is set to 'auto'
if(Drupal.behaviors.jjNavigation.navigationAPI.animationSpeed === 'auto'){
// Set a base pixels per millisecond value
var pixelsPerMilliSecond = 2;
// Return the value of the elementHeight divided by pixelsPerMilliSecond value
return elementHeight / pixelsPerMilliSecond;
// Else the animationSpeed a number
} else {
// Return the value of the animationSpeed
return Drupal.behaviors.jjNavigation.navigationAPI.animationSpeed;
}
};
/**
* Adjusts the content-row in case the drop down height is larger than the content-row height
* @param {[string]} dropdownOperation
* @param {[number]} contentRowHeight
* @param {[number]} dropdownHeight
*/
var contentHeightCheck = function(dropdownOperation, contentRowHeight, dropdownHeight){
// If the dropdownHeight paramter is undefined
if(dropdownHeight === undefined){
// Set is to 0
dropdownHeight = 0;
}
// If the animation is opening and the dropdownHeight is larger than .content-row height
if(dropdownOperation === 'open' && parseInt(contentRowHeight, 10) < parseInt(dropdownHeight, 10)){
// Set .content-row's height the the dropdown height + 30 (+30 adds a small buffer)
$('.content-row').css('height', parseInt(dropdownHeight, 10) + 30);
// If the animation is closing and the initial .content-row height (defined on page load on line 7) is not equal to the current .content-row's height
} else if(dropdownOperation === 'close' && contentRowHeight !== $('.content-row').outerHeight()) {
// Animate .content-row back to its original height
$('.content-row').animate({
// contentRowHeight is defined on page load on page 7
'height': contentRowHeight
// Adjust the animation duration based on the height of contentRowHeight
}, animationSpeedAdjust(contentRowHeight), function(){
// After the animate finished the content-row height to auto to prevent content from being cut off
$('.content-row').css('height', 'auto');
});
}
};
/**
* Calculates the height and creates the data-height attribute on the ul
*/
var dropdownHeightUpdate = function(){
// Only target the .dropdown class if is inside the .layout container
var contentDropdown = $('.layout .dropdown');
// Loop through .dropdown to target only nested ul
contentDropdown.each(function(){
// Add ul.dropdown's height to its data-height attribute
$(this).attr('data-height', $(this).outerHeight());
});
// Update .dropdown height to 0 to setup the animation
contentDropdown.css('height', '0');
};
/**
* Controls .two-levels orientaion to prevent the menu from overhanging past the menu
*/
var overHangCheck = function(){
// Isolate the first ul as a selector
var mainMenu = $('.main-menu ul:first');
// Grab the .main-menu width
var mainMenuWidth = mainMenu.width();
// Loop through each .two-levels .dropdown
$('.two-levels .dropdown').each(function(){
var dropdown = $(this);
// Grab the width of the .dropdown
var dropdownWidth = $(this).width();
// Find the .main-menu offset
var mainMenuOffset = mainMenu.offset();
// Find the offset of the .dropdown
var dropdownOffset = dropdown.offset();
// If the page orientaion is left ot right
if(pageDirection === 'ltr' ){
// Check to see if the width and the offset of the .dropdown is greater than the width and the offset of the .main-menu
if(dropdownWidth + dropdownOffset.left > mainMenuWidth + mainMenuOffset.left){
// Add .change-side to .dropdown (css will control the adjustment)
$(this).addClass('change-side');
}
// If the page is right to left
} else {
// Check to see if .dropdown offset is less than .main-menu's offset
if(dropdownOffset.left < mainMenuOffset.left){
// Add .change-side to .dropdown (css will control the adjustment)
$(this).addClass('change-side');
}
}
});
};
/**
* Triggers the blur event on search field to prevent sub-menu overlapping.
*/
var focusBlur = function() {
var $searchField = $('.apachesolr-autocomplete');
if ($searchField.is(':focus')) {
$searchField.blur();
}
};
/*********************/
// IF NOT MEGA MENU
/*********************/
if($('.mega-menu').length === 0){
/**
* Setups the dropdown functionality by calculating the number of nest lists in each first-level li.expanded
*/
var dropdownSetup = function(){
$firstLevelLinks.each(function(){
// Count the number of nested ul
listCount = $(this).find('ul').length;
// If listCount is one then add .two-levels to adjust the styles
if(listCount === 1){
// Add .two-levels to first-level li.expanded
$(this).addClass('two-levels');
// If listCount is greater than one than add .three-levels to adjust the styles
} else if(listCount > 1){
// Isolate the first ul
var thisNestList = $(this).find('ul:first');
// If supportThreeLevelFullWidth is supported
if(Drupal.behaviors.jjNavigation.navigationAPI.supportThreeLevelFullWidth === true){
// Add .three-levels to first-level li.expanded
$(this).addClass('three-levels');
// Wrap the nested ul in a div with the class .dropdown-full-width (this accounts for the full screen background required)
$(thisNestList).wrap('');
} else {
// Add .two-levels to first-level li.expanded
$(this).addClass('two-levels multi');
}
}
$('.navigation-row').removeClass('hidden');
});
/**
* Add .dropdown to the first nested ul based on the selector
* @param {[object]} selector
*/
var dropdownLoop = function(selector){
selector.each(function(){
// Add .dropdown to first ul
$(this).find('ul:first').addClass('dropdown');
});
};
// Loop through all .two-levels
dropdownLoop($('.two-levels'));
// If supportThreeLevelFullWidth is supported
if(Drupal.behaviors.jjNavigation.navigationAPI.supportThreeLevelFullWidth === true){
// Loop through all .three-levels
dropdownLoop($('.three-levels'));
}
// Adds custom event.
$('.main-menu:first').trigger('dropdownSetup');
};
/**
* Applies accessibility attributes to the main menu for desktop resolution.
*/
var accessibilitySetup = function () {
mainMenu.find('ul:first').attr('role', 'menubar');
mainMenu.find('li').attr('role', 'none').each(function () {
$(this).find('a:first').attr('role', 'menuitem').removeAttr('aria-selected');
// Apply specific attributes if current item contains submenu.
if ($(this).find('.dropdown').length) {
$(this).find('ul').attr('role', 'menu');
$(this).find('a:first').attr('aria-haspopup', 'true');
// Toggle attributes on element hover.
$(this).hover(function () {
$(this).find('a[aria-expanded]').attr('aria-expanded', 'true');
}, function () {
$(this).find('a[aria-expanded]').attr('aria-expanded', 'false');
});
}
});
};
/**
* Handles sub-menu expand.
* @param {[object]} element
*/
const showSubMenu = function ($element) {
// Adjust the multi-level dropdown.
$('.dropdown-full-width').css('width', $(window).width());
// Change .dropdown's height to auto so we can calculate the correct height.
$firstLevelLinks.find('.dropdown').css('height', 'auto');
// Update the data-height value based on the new .dropdown height.
dropdownHeightUpdate();
// Update the content-row height.
const contentRowHeight = $('.content-row').outerHeight();
// Find .dropdown in this first level .expanded li.
const $targetList = $element.find('.dropdown');
// Find .ac_results dropdown.
const acResults = $('.ac_results');
// 'Bordered' class.
const dropdownClass = 'bordered';
// Add .hovered to the link to keep the hovered state while hover is enabled.
$element.find('span.nolink, a:first').eq(0).addClass('hovered');
// Add .bordered to add the border at the bottom of the multi-level dropdown.
$element.find('.dropdown-full-width').addClass(dropdownClass);
// Add .bordered to add the border at the bottom of the one-level dropdown.
$targetList.addClass(dropdownClass);
// Check to see if the dropdown height is large than the .content-row height.
contentHeightCheck('open', contentRowHeight, $targetList.attr('data-height'));
if (acResults.length > 0) {
// Hide autocomplete result element.
acResults.hide();
}
// Remove focus from search field.
focusBlur();
// Show the target list before animation.
$targetList.show();
// Animate .dropdown.
$targetList.stop(true, true).animate({
// Change the height to the value on the data-height.
'height': '' + $targetList.attr('data-height') + 'px'
// Adjust the animation duration based on the value on the data-height.
}, animationSpeedAdjust($targetList.attr('data-height')));
};
/**
* Handles sub-menu hide.
* @param {[object]} $element
* @param {number} contentRowHeight
*/
const hideSubMenu = function ($element, contentRowHeight) {
// Find .dropdown in this first level .expanded li.
const $targetList = $element.find('.dropdown');
// 'Bordered' class.
const dropdownClass = 'bordered';
// Remove .hovered to the link to remove the hovered state.
$element.find('span.nolink, a:first').eq(0).removeClass('hovered');
// Remove .bordered to remove the border at the bottom of the multi-level dropdown.
$element.find('.dropdown-full-width').removeClass(dropdownClass);
// Remove .bordered to remove the border at the bottom of the one-level dropdown.
$targetList.removeClass(dropdownClass);
// Close the .content-row (sets the height to the original on load value.
contentHeightCheck('close', contentRowHeight);
// Close the .dropdown animation.
$targetList.stop(true, true).animate({
// Change the height back to 0
'height': 0
// Adjust the animation duration based on the value on the data-height.
}, animationSpeedAdjust($targetList.attr('data-height')));
$targetList.hide();
};
$(window).ready(function(){
// Get .content-row's height (this will be used later in contentHeightCheck())
var contentRowHeight = $('.content-row').outerHeight();
// Controls the initialization of the dropdown
dropdownSetup();
$('.dropdown-full-width').css('width', $(window).width());
// Adds the height to the DOM element for value storage
dropdownHeightUpdate();
// Adjust the one level dropdown if it is overhanging past the .main-menu
overHangCheck();
// Adds accessibility attributes to the main menu for desktop resolution.
accessibilitySetup();
// On resize adjust the multi level dropdown width and all dropdown heights
$(window).on('debouncedresize', function(){
// Adjust the multi-level dropdown
$('.dropdown-full-width').css('width', $(window).width());
// Change .dropdown's height to auto so we can calculate the correct height
$firstLevelLinks.find('.dropdown').css('height', 'auto');
// Update the data-height value based on the new .dropdown height
dropdownHeightUpdate();
// Update the content-row height
contentRowHeight = $('.content-row').outerHeight();
});
// On keypress open/close the dropdown.
$firstLevelLinks.find('> a').on('keydown', function (e) {
// Enter or space key.
if (e.which === 13 || e.which === 32) {
e.preventDefault();
let $parent = $(this).parent('li.expanded');
if ($parent.find('.dropdown').is(':visible')) {
hideSubMenu($parent, contentRowHeight);
}
else {
showSubMenu($parent);
}
}
});
// On hover open/close the dropdown.
$firstLevelLinks.once($firstLevelLinks).hoverIntent(function () {
showSubMenu($(this));
}, function () {
hideSubMenu($(this), contentRowHeight);
});
});
}
/*********************/
// IF MEGA MENU
/*********************/
if($('.mega-menu').length > 0){
var targetList;
var megaMenuNode = $('.node-mega-menu');
var megaMenuView = $('.mega-menu .views-row');
var topRowLink = $('.mega-menu').find('ul:first > li.views-row');
var defaultContentRowHeight;
var navigationHeightReset = 44;
var megaMenuSetup = function(){
var columnWrap = function(){
megaMenuNode.each(function(){
var topHtml = $(this).find('.top-row').html();
var mainHtml = $(this).find('.main-row').html();
var bottomHtml = $(this).find('.bottom-row').html();
if(typeof mainHtml === 'string' && typeof bottomHtml === 'string'){
$(this).html('
');
}
});
};
columnWrap();
// Reset the mega-menu width
$('.mega-menu .views-row').css('width', 'auto');
// Prevent screen reader from reading submenu links.
$('.mega-menu-dropdown a').attr('tabindex', '-1');
};
var megamenuDropdownHeightUpdate = function(){
megaMenuNode.each(function(){
$('.mega-menu-dropdown').css('height', 'auto');
var megaMenuHeight = $(this).find('.mega-menu-dropdown').outerHeight();
if (typeof megaMenuHeight === 'number') {
let topRow = $('.top-row', $(this));
let selector = topRow.find('a').length ? $('a', topRow) : $('.nolink', topRow);
selector.addClass('menu-dropdown').attr('data-dropdown-height', megaMenuHeight);
}
});
$('.mega-menu-dropdown').css('height', 0);
$('.navigation-row').removeClass('hidden');
megaMenuView.attr('data-navigation-reset', navigationHeightReset);
};
$(window).ready(function(){
megaMenuSetup();
imagesLoaded($('.mega-menu')).on( 'always', function() {
// Update the data-height value based on the new .mega-menu-dropdown height
megamenuDropdownHeightUpdate();
});
// On resize adjust the multi level dropdown width and all dropdown heights
$(window).on('throttledresize', function(){
defaultContentRowHeight = $('.content-row').outerHeight();
// Update the data-height value based on the new .mega-menu-dropdown height
megamenuDropdownHeightUpdate();
});
// On hover open the dropdown
$(topRowLink).once(topRowLink).hoverIntent(function(){
if (typeof defaultContentRowHeight === 'undefined') {
defaultContentRowHeight = $('.content-row').outerHeight();
}
let selector = $(this).find('.top-row a').length ? '.top-row a' : '.top-row .nolink';
var megaMenuDropdownHeight = parseInt($(this).find(selector).attr('data-dropdown-height'), 10);
$('.mega-menu-dropdown').hide();
// Find .dropdown in this first level .expanded li
targetList = $(this).find('.mega-menu-dropdown');
// Add .hovered to the link to keep the hovered state while hover is enabled
$(this).find('a:first').addClass('hovered');
// Add .bordered to add the border at the bottom of the one-level dropdown
$(targetList).addClass('bordered');
// Update 'tabindex' attribute for submenu links when dropdown is open.
targetList.find('a').attr('tabindex', 0);
// Check to see if the dropdown height is large than the .content-row height
contentHeightCheck('open', defaultContentRowHeight, megaMenuDropdownHeight);
if ($('.ac_results').length > 0) {
// Hide autocomplete result element.
$('.ac_results').hide();
}
// Remove focus from search field.
focusBlur();
// Show the target list before animation
$(targetList).show();
// Animate .dropdown
$(this).find('.mega-menu-dropdown').stop(true, true).animate({
// Change the height to the value on the data-height
'height': '' + megaMenuDropdownHeight + 'px'
// Adjust the animation duration based on the value on the data-height
}, animationSpeedAdjust(megaMenuDropdownHeight));
// On hover off close the dropdown
}, function(){
let selector = $(this).find('.top-row a').length ? '.top-row a' : '.top-row .nolink';
var megaMenuDropdownHeight = parseInt($(this).find(selector).attr('data-dropdown-height'), 10);
// Find .dropdown in this first level .expanded li
targetList = $(this).find('.mega-menu-dropdown');
// Remove .hovered to the link to remove the hovered state
$(this).find('a:first').removeClass('hovered');
// Close the .content-row (sets the height to the original on load value
contentHeightCheck('close', defaultContentRowHeight);
// Close the .dropdown animation
$(this).find('.mega-menu-dropdown').stop(true, true).animate({
// Change the height to the value on the data-height
'height': 0
// Adjust the animation duration based on the value on the data-height
}, animationSpeedAdjust(megaMenuDropdownHeight));
});
});
}
})(jQuery, window.imagesLoaded);
;
/* global windowMessagePromise, windowMessagePromiseCallback */
(function ($) {
Drupal.behaviors.jjPageBuilder = {
pbCarouselVideo: [],
attach: function (context) {
var paragraphItem = $('.entity-paragraphs-item');
var paragraphItems = $('.paragraphs-items');
var carouselContainer = $('.pb-carousel-row-container');
var direction;
var timers = {};
var directionCheck = function() {
if ($('html').attr('dir') === 'ltr') {
direction = 'left';
} else {
direction = 'right';
}
};
var bgSliceResize = function() {
directionCheck();
var fullWidth = $('body').width();
var pageWidth = paragraphItems.width();
paragraphItem.each(function() {
if ($(this).hasClass('full-width-slice')) {
var marginShift = fullWidth - pageWidth;
var multiAttr= {};
multiAttr['margin-' + direction] = -marginShift/2;
multiAttr['width'] = fullWidth;
$(this).css(multiAttr);
$(this).closest('.paragraphs-items').css('overflow', 'visible');
if ($(this).hasClass('full-width-content')) {
$(this).css({'padding-left': 0, 'padding-right': 0});
$(this).children('.content').css('width', '100%');
} else {
$(this).css({'padding-left': marginShift/2, 'padding-right': marginShift/2});
$(this).children('.content').css('width', pageWidth);
}
}
});
};
var carouselResize = function(carousel) {
var fullWidth = $('body').width();
var pageWidth = $('#main-content .main-row', context).width();
var marginShift = fullWidth - pageWidth;
carousel.find('.content-container').css('margin-' + direction, -pageWidth/2);
if ( carousel.hasClass('full-width')) {
// Mobile and tablets need left margin to offset left padding.
if (window.flags.hasAny('mobile') || window.flags.hasAny('tablet')) {
carousel.css('margin-' + direction, "-2%");
} else {
carousel.css('margin-' + direction, - marginShift / 2);
}
carousel.css({'width': fullWidth, 'overflow': 'visible'});
carousel.closest('.pb-carousel-row').css('overflow', 'visible');
carousel.find('.content-container').css('max-width', pageWidth);
}
};
var slideResize = function(slideContainer){
var slide = slideContainer.find('.slide');
slide.each(function() {
$(this).css('min-height', 'auto');
var slideMinHeight = $(this).find('.content-container').outerHeight();
$(this).css('min-height', slideMinHeight);
});
};
/**
* Initializes knob play/pause functionality.
* @param carouselInstance
*/
var initKnobControls = function (carouselInstance) {
// Start/Stop click.
carouselInstance.find('.knob-container').once('knob').on('click', function (e) {
var id = $(this).parents('.pb-carousel-row-container').attr('id');
// If the .knob-container has 'play' class.
if ($(this).hasClass('play')) {
$(this).removeClass('play');
// Start slide rotation.
timers[id].play();
}
else {
$(this).addClass('play');
// Stop the auto rotate function.
timers[id].pause();
}
accessibilityKnobToggle();
});
};
/**
* Creates play/pause knob.
* @param carouselInstance
*/
var timerCreate = function (carouselInstance) {
var $link = $('', {
'html': Drupal.t('Play/Pause'),
'href': '#',
'class': 'knob'
});
carouselInstance.find('.slick-dots').append($link);
var colorValue = $('a').css('color');
// Create the timer using jquery.knob library.
carouselInstance.find('.knob').knob({
'thickness': 0.2,
'width': '35',
'height': '35',
'displayInput': false,
'fgColor': colorValue,
'bgColor': '#fff',
'min': 0,
'readOnly': true,
'dynamicDraw': true,
'tab-index': 0,
'value': 0
});
carouselInstance.find('.knob').closest('div').addClass('knob-container');
// Adjust the timer styles to put it inline with the pagination links.
carouselInstance.find('.knob-container').on('keypress', function (e) {
if (e.keyCode === 32 || e.keyCode === 13) {
e.preventDefault();
$(this).trigger('click');
}
}).css({
'display': 'inline-block'
}).attr({
'tabindex': 0
});
initKnobControls(carouselInstance);
};
/**
* Controls the timer animation.
* @param carouselId
* @param carouselInstance
* @param autoRotateCarouselSpeed
*/
var initProgressbar = function (carouselId, carouselInstance, autoRotateCarouselSpeed) {
timers[carouselId] = new Ticker(carouselId, carouselInstance, autoRotateCarouselSpeed);
timers[carouselId].play();
accessibilityKnobToggle();
};
/**
* Creates a Ticker constructor and implements play and pause methods.
*/
function Ticker(carouselId, carouselInstance, autoRotateCarouselSpeed) {
var count = 0;
var maxValue = 100;
var intervalId;
// Start the slide countdown, change slides when finished.
this.play = function () {
intervalId = setInterval(function () {
++count;
carouselInstance.find('.knob').val(count).trigger('change');
if (count === maxValue) {
carouselInstance.slick('slickNext');
}
}, autoRotateCarouselSpeed / 100);
};
this.pause = function () {
clearInterval(intervalId);
};
}
/**
* Updates aria-label attribute for knob on click.
*/
var accessibilityKnobToggle = function () {
var $knob = $('.knob-container');
if ($knob.hasClass('play')) {
$knob.attr('aria-label', Drupal.t('Play to continue'));
}
else {
$knob.attr('aria-label', Drupal.t('Pause to stop slides'));
}
};
/**
* Updates live region text.
* @param carouselInstance
*/
var updateLiveRegionText = function (carouselInstance) {
var currentSlide = carouselInstance.find('.slick-active').attr('data-slick-index');
var totalCount = carouselInstance.find('.slide').not('.slick-cloned').length;
return Drupal.t('Item @slide of @count', {
'@slide': Number(currentSlide) + 1,
'@count': totalCount
});
};
/**
* Creates hidden div with accessibility attributes.
* @param carouselInstance
*/
var initLiveRegion = function (carouselInstance) {
var liveRegionText = updateLiveRegionText(carouselInstance);
$('', {
'class': 'pb-carousel-accessibility visuallyhidden',
'aria-live': 'polite',
'aria-atomic': 'true',
'text': liveRegionText
}).appendTo(carouselInstance);
};
bgSliceResize();
carouselContainer.once('slick').each(function(index) {
var carouselId = "carousel" + index;
this.id = carouselId;
carouselResize($(this));
// Check for auto-rotate.
var autoRotateSetting;
// Slick default autoplaySpeed value (microseconds).
var autoRotateCarouselSpeed = 3000;
if ($(this).hasClass('auto-rotate')) {
autoRotateSetting = true;
// Set auto rotate speed only if group carousel speed is available.
var slideSpeedSet = $(this).attr('class').match(/jjbos_page_builder_group_carousel_speed_[0-9]+/g);
if (slideSpeedSet && (slideSpeedSet.length === 1)) {
var autoRotateSpeedSet = Drupal.settings[slideSpeedSet[0]];
if (autoRotateSpeedSet.type === 'carousel_speed') {
autoRotateCarouselSpeed = autoRotateSpeedSet.carousel_speed * 1000;
}
else {
// Per slide speed to be implemented. Before it, use default slide speed (microseconds).
autoRotateCarouselSpeed = autoRotateSpeedSet.default_slide_speed * 1000;
}
}
}
// Check for arrow-hide.
if ($(this).hasClass('hide-arrows')) {
$(this).siblings('.arrow-container').hide();
}
// Direction check.
var SetRTL;
if ( direction === 'right'){
SetRTL = true;
}
if (!$(this).hasClass('featured-content')) {
// On carousel init or after change, set proper aria attr.
$(this).on('init afterChange', function(event, slick, currentSlide) {
slick.$slides.each(function (index, slide) {
// Current slide.
var tabIndex = index === slick.slickCurrentSlide() ? 0 : -1;
$(slide).find('.button, .accessibility-slide-headline, .field--name-body p').attr('tabindex', tabIndex);
});
$(this).find('.slick-dots li').each(function(index, item) {
var text = '';
$(item).attr('aria-hidden', 'false');
if ($(item).hasClass('slick-active')) {
text = Drupal.t('Current Slide: Slide @slide', {'@slide' : index + 1});
$(item).attr('aria-selected', 'true');
} else {
text = Drupal.t('Slide @slide', {'@slide' : index + 1});
$(item).attr('aria-selected', 'false');
}
$(item).find('button').text(text);
});
$(this).find('.slick-cloned h1').each(function(index, item) {
// Replace H1 tag in cloned slide.
$(item).replaceWith(function(){
return $("", {class: 'slick-cloned-h1-replace', html: $(this).html()});
});
});
$(this).find('.knob-container').removeClass('play');
if (autoRotateSetting) {
initProgressbar(carouselId, $(this), autoRotateCarouselSpeed);
}
// Update Live Region text after slide rotates.
var liveRegionText = updateLiveRegionText($(this));
$(this).find('.pb-carousel-accessibility').text(liveRegionText);
});
$(this).on('beforeChange', function () {
if (autoRotateSetting) {
timers[carouselId].pause();
}
});
$(this).slick({
accessibility: true,
slide: "#" + carouselId + " .slide",
appendArrows: $(this).siblings('.arrow-container'),
dots: true,
draggable: false,
rows: 0,
rtl: SetRTL,
prevArrow: '',
nextArrow: '',
customPagingADALabel: function(slider, i, numDotGroups, slide) {
if (slider.slickCurrentSlide() + 1 === i) {
return Drupal.t('Current Slide: Slide @current of @all', {'@current': i, '@all': numDotGroups});
}
return Drupal.t('Slide @current of @all', {'@current': i, '@all': numDotGroups});
}
});
}
slideResize($(this));
initLiveRegion($(this));
if (autoRotateSetting) {
timerCreate($(this));
}
});
// Receive Window.postMessage from embedded iframe.
var receiveMessage = function(event) {
if (typeof Drupal.settings.jjbos_pb_iframe === 'undefined' || typeof event.originalEvent.data === 'undefined') {
return;
}
// Use originalEvent to retrieve event data since jQuery might preprocess event.data.
var origin = event.originalEvent.origin;
var data = event.originalEvent.data;
// Postmessage origin check.
if (origin !== Drupal.settings.jjbos_pb_iframe.target_origin) {
return;
}
var iFrames = $('#' + Drupal.settings.jjbos_pb_iframe.iframe_id, context);
if (iFrames.length) {
if (typeof data.outerHeight !== 'undefined') {
iFrames[0].style.height = data.outerHeight + 'px';
iFrames[0].scrolling = 'no';
}
if (typeof data.ready !== 'undefined' && data.ready === true) {
// Get the window displayed in the iframe.
var iFrameUCU = iFrames[0].contentWindow;
// Send a message to iframe src window.
iFrameUCU.postMessage(Drupal.settings.jjbos_pb_iframe.ucu_css, Drupal.settings.jjbos_pb_iframe.target_origin);
}
}
};
// Resolve the Promise defined previously.
if (typeof windowMessagePromise === 'object' && windowMessagePromise !==null) {
windowMessagePromise.then(function (value) {
// Receive the resolved value.
receiveMessage(value);
$(window).off('message', windowMessagePromiseCallback);
$(window).on('message', receiveMessage);
// Return value to allow other modules implementing message handler.
return value;
});
}
// On prev/next arrow click, pause video.
$(document).on('click','.slick-arrow', function(e) {
$.each(Drupal.behaviors.jjPageBuilder.pbCarouselVideo, function(i,v){
if (typeof Drupal.behaviors.jjPageBuilder.pbCarouselVideo[i].pauseVideo === 'function') {
Drupal.behaviors.jjPageBuilder.pbCarouselVideo[i].pauseVideo();
}
});
});
$(window).on('throttledresize', function() {
bgSliceResize();
carouselContainer.each(function(){
carouselResize($(this));
slideResize($(this));
});
});
}
};
})(jQuery);
/**
* Implementation of the native YouTube Iframe API "onYouTubeIframeAPIReady"
* handler.
*
* This handler is added via Drupal.settings.youtube_api_ready_callbacks and
* then being called within "onYouTubeIframeAPIReady" itself.
*/
function jjPageBuilderOnYouTubeIframeAPIReady() {
var videoInit = function(currentCarousel, YT) {
var videoID = currentCarousel.find('iframe').attr('id');
if (typeof videoID !== 'undefined' && videoID !== '') {
var video = new YT.Player(videoID, {
videoId: videoID
});
Drupal.behaviors.jjPageBuilder.pbCarouselVideo.push(video);
}
};
jQuery('.pb-carousel-row-container .slide').each(function() {
if (jQuery(this).find('.image-container').hasClass('video')) {
var currentVideoSlide = jQuery(this).find('.image-container.video').closest('.slide');
currentVideoSlide.addClass('video-slide');
videoInit(currentVideoSlide, window.YT);
}
});
}
;
(function ($) {
Drupal.settings.jjProductTacosAdjust = {
// Define the product image pane, product taco pane and the product accordion selectors as variables.
leftColumnSelector: '.content-row .main-row > .no-padding-left',
productTacosSelector: '.pane-node-field-product-tacos, .pane-node-field-product-tacos2',
productAccordionSelector: '.content-row .main-row .region-col .accordion',
productHalfSelector: '.node-type-product .content-row .main-row .half',
productFullSelector: '.node-type-product .content-row .main-row .full',
productMainRowSelector: '.node-type-product .content-row .main-row .region-col',
panelProductsSelector: '.section-products .pane-node-field-product-tacos, .section-products .pane-node-field-product-tacos2',
paneTacoPaneSelector: '.pane-taco-pane'
};
Drupal.behaviors.jjProductTacosAdjust = {
API: {
// This variable will initialize the auto rotate functionality on the carousel.
// @option = ['mobile']
// @option = ['mobile', 'tablet']
devices: ['mobile', 'tablet'],
deviceMobile: ['mobile'],
deviceTablet: ['tablet'],
deviceDesktop: ['desktop']
},
methods: {
devicesAdjust: function (context) {
var settings = Drupal.settings.jjProductTacosAdjust;
var productTacos = $(settings.productTacosSelector, context);
var productAccordion = $(settings.productAccordionSelector, context);
// Remove the existing product taco pane from both columns.
productTacos.detach();
// Add the product tacos after product accordion.
productAccordion.after(productTacos);
},
deviceTabletAdjust: function (context) {
var settings = Drupal.settings.jjProductTacosAdjust;
var productHalf = $(settings.productHalfSelector, context);
var paneTaco = $(settings.productTacosSelector, context).find(settings.paneTacoPaneSelector);
var productTaco = $(settings.panelProductsSelector, context).find(settings.paneTacoPaneSelector);
// If half, make full.
if (productHalf.length) {
productHalf.removeClass('half');
productHalf.addClass('full');
}
// If full, make half.
if (paneTaco.hasClass('full')) {
paneTaco.removeClass('full');
paneTaco.addClass('half');
}
// Adjust the height of tacos to equal height.
var heightAdjust = function() {
var elementHeights = productTaco.map(function() {
return $(this).height();
}).get();
// Math.max takes a variable number of arguments.
// 'apply' is equivalent to passing each height as an argument.
var maxHeight = Math.max.apply(null, elementHeights);
// Set each height to the max height.
productTaco.height(maxHeight);
};
heightAdjust();
},
deviceDesktopAdjust: function (context) {
var settings = Drupal.settings.jjProductTacosAdjust;
var productMainRow = $(settings.productMainRowSelector, context);
var paneTaco = $(settings.productTacosSelector, context).find(settings.paneTacoPaneSelector);
var productTacos = $(settings.productTacosSelector, context);
var productTaco = $(settings.panelProductsSelector, context).find(settings.paneTacoPaneSelector);
var leftColumn = $(settings.leftColumnSelector, context);
// Remove the existing product taco pane from both columns.
productTacos.detach();
// Add the product tacos after the product image.
leftColumn.append(productTacos);
// If full, make half.
if (productMainRow.length) {
productMainRow.removeClass('full');
productMainRow.addClass('half');
}
// If half, make full.
if (paneTaco.hasClass('half')) {
paneTaco.removeClass('half');
paneTaco.addClass('full');
}
// Reset product taco heights to auto for desktop.
productTaco.css('height', 'auto');
},
deviceMobileAdjust: function (context) {
var settings = Drupal.settings.jjProductTacosAdjust;
var paneTaco = $(settings.productTacosSelector, context).find(settings.paneTacoPaneSelector);
// If half, make full.
if (paneTaco.hasClass('half')) {
paneTaco.removeClass('half');
paneTaco.addClass('full');
}
}
},
attach: function (context) {
var productLayoutAdjust = function () {
if (window.flags.hasAny(Drupal.behaviors.jjProductTacosAdjust.API.devices)) {
Drupal.behaviors.jjProductTacosAdjust.methods.devicesAdjust(context);
}
if (window.flags.hasAny(Drupal.behaviors.jjProductTacosAdjust.API.deviceTablet)) {
Drupal.behaviors.jjProductTacosAdjust.methods.deviceTabletAdjust(context);
}
if (window.flags.hasAny(Drupal.behaviors.jjProductTacosAdjust.API.deviceDesktop)) {
Drupal.behaviors.jjProductTacosAdjust.methods.deviceDesktopAdjust(context);
}
if (window.flags.hasAny(Drupal.behaviors.jjProductTacosAdjust.API.deviceMobile)) {
Drupal.behaviors.jjProductTacosAdjust.methods.deviceMobileAdjust(context);
}
};
// Run the adjust function on load.
productLayoutAdjust();
$(window).on('resize', function() {
// Run the adjust function on resize.
productLayoutAdjust();
});
}
};
})(jQuery);
;
/**
* @file
* Additional functionality of External Links module.
*/
(function ($) {
Drupal.behaviors.jjExternalLinks = {
attach: function (context, settings) {
const $newWindowLink = $('.new-window-link', context);
if ($newWindowLink.length && $newWindowLink.attr('target') === '_blank') {
const extHelper = '- ' + Drupal.t('Open link in new window');
const newWindowHelper = '' + extHelper + '';
$newWindowLink.append(newWindowHelper);
}
}
};
})(jQuery);
;
(function ($) {
Drupal.behaviors.jjSubNavigation = {
subNavigationAPI: {
// This variable controls the speed that the sub navigation dropdown opens and closes
// @options = a number value
animationSpeed: 200,
subMenuSelector: '.content-row .top-row [class*=" pane-menu"]'
},
methods: {
/**
* This method updates the DOM elements height.
*/
heightAdjust: function(subMenu) {
// Grab the height for the current .menu-pane item
var containerHeight = subMenu.outerHeight();
// Find the height of the sibling button to the current .menu-pane
var buttonHeight = $(subMenu).siblings('.sub-nav-button').outerHeight();
// If the buttonHeight (sibling button to the current .menu-pane height) is less than 47
if(buttonHeight < 47){
// Set the buttonHeight variable to 47
buttonHeight = 47;
}
// Add the containerHeight value to the current .menu-pane as a value for data-height-max
subMenu.attr('data-height-max', containerHeight);
// Add the buttonHeight value to the current .menu-pane as a value for data-height-min
subMenu.attr('data-height-min', buttonHeight);
},
/**
* Update the .pane-menu elements by wrapping them in a .sub-nav-wrapper
*/
subMenuSetup: function(subMenu) {
// Define the sub nav wrapper class and structure
var subNavWrapper = '';
// Wrap th.pane-menu element in the newly created sub nav wrapper
subMenu.wrapAll(subNavWrapper);
var no_title = $(subMenu).hasClass('paragraphs-item-no-title');
var list_view = $(subMenu).hasClass('menu-list-view');
if (no_title || list_view) {
// Do not render "In this section" heading of the SubNav menu and
// leave the menu expanded.
return;
}
// Before the .pane-menu element put in a toggle link
$(subMenu).closest('.sub-nav-wrapper').prepend('' + Drupal.t('In this section') + '');
// Run the heightAdjust function to update the DOM element heights
Drupal.behaviors.jjSubNavigation.methods.heightAdjust(subMenu);
// Locate the data-height-min value on the closest (moving up the DOM) .sub-nav-wrapper to close the accordion
$(subMenu).closest('.sub-nav-wrapper').css('height', subMenu.data('height-min'));
},
/**
* Animates the subnavigation opened
*/
openSectionMenu: function(subMenu) {
// Add .opened to the containing
$(subMenu).closest('.sub-nav-wrapper').addClass('opened');
// Animate the height of the containing
to the data-height-max value
if (parseInt($(subMenu).attr('data-height-max'), 10) === 0) {
// In case we initialized the height on the desktop mode we
// have to recheck it after moving to mobile view.
Drupal.behaviors.jjSubNavigation.methods.heightAdjust(subMenu);
}
$(subMenu).closest('.sub-nav-wrapper').stop(true, true).animate({
'height': parseInt($(subMenu).attr('data-height-max'), 10) + parseInt($(subMenu).attr('data-height-min'), 10)
}, Drupal.behaviors.jjSubNavigation.subNavigationAPI.animationSpeed);
},
/**
* Animates the subnavigation closed
*/
closeSectionMenu: function(subMenu) {
// Remove .opened to the containing
$(subMenu).closest('.sub-nav-wrapper').removeClass('opened');
// Animate the height of the containing
to the data-height-min value
$(subMenu).closest('.sub-nav-wrapper').stop(true, true).animate({
'height': $(subMenu).attr('data-height-min')
}, Drupal.behaviors.jjSubNavigation.subNavigationAPI.animationSpeed);
}
},
attach: function (context) {
/**
* This adds accordion-like functionality to the menu's unordered list
* @param {[object]} subMenu
*/
var subMenuSetup = function(subMenu) {
$('body', context).once('jjSubNavigation', function () {
Drupal.behaviors.jjSubNavigation.methods.subMenuSetup(subMenu);
});
// On click animate sub navigation
$(subMenu).siblings('.sub-nav-button').once('sub-nav-button').click(function(e) {
e.preventDefault();
// If this link has .opened then run the close animation
if ($(subMenu).closest('.sub-nav-wrapper').hasClass('opened')) {
Drupal.behaviors.jjSubNavigation.methods.closeSectionMenu(subMenu);
}
else {
// Else run the open animation
Drupal.behaviors.jjSubNavigation.methods.openSectionMenu(subMenu);
}
});
// On window resize recalculate the heights
$(window).on('debouncedresize', function() {
// Close the sub navigation while resizing
Drupal.behaviors.jjSubNavigation.methods.closeSectionMenu(subMenu);
// Update the sub navigation heights
Drupal.behaviors.jjSubNavigation.methods.heightAdjust(subMenu);
});
};
// Run the subMenuSetup function on page load, this adds accordion-like functionality to the menu's unordered list
subMenuSetup($(Drupal.behaviors.jjSubNavigation.subNavigationAPI.subMenuSelector, context));
}
};
})(jQuery);
;
/**
* @file
* Superscript JavaScript functionality.
*/
(function ($) {
Drupal.behaviors.jjbos_text_formats = {
pattern: new RegExp(Drupal.settings.jjbos_text_formats.characters, 'g'),
/**
* Superscript elements.
*
* Wrap preconfigured elements with tag.
*/
superscript: function (context) {
$('body :not(script,iframe,sup,textarea,input,option),h1,h2,h3,h4,h5,p,a,div', context)
.replaceText(Drupal.behaviors.jjbos_text_formats.pattern, '$&<\/sup>');
},
attach: function (context, settings) {
Drupal.behaviors.jjbos_text_formats.superscript(context);
}
};
})(jQuery);
;