WS_OK_7.4.33
var FE = {};
jQuery(function() {
homebrew.Carousel.prototype.options.transitions.enable = Modernizr.csstransitions;
homebrew.Tooltip.prototype.options.appendTo = '#mainContent';
homebrew.Tooltip.prototype.options.transitions.enable = Modernizr.csstransitions;
jQuery.extend(FE, {
$els : {
backToTop : jQuery('#globalBackToTop'),
body : jQuery('body'),
mainSite : jQuery('#mainSite'),
pageOverlay : jQuery('#pageOverlay'),
root : jQuery('html')
},
events: {
transitionEnd : homebrew.events.transitionEnd || 'transitionend oTransitionEnd otransitionend webkitTransitionEnd msTransitionEnd',
animationEnd: homebrew.events.animationEnd || 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'
},
browser : homebrew.browser,
baseURL : (typeof fileUrl === 'string')
? fileUrl
: (window.location.href.indexOf('') > -1)
? ''
: ''
});
if(!FE.$els.pageOverlay.length) {
FE.$els.pageOverlay = jQuery('<div class="page-overlay" id="pageOverlay" />').appendTo(FE.$els.mainSite);
}
if(!FE.$els.backToTop.length) {
FE.$els.backToTop = jQuery('<a href="#top" title="Back To Top" class="main-back-to-top" id="mainBackToTop" />').appendTo('#mainContent');
FE.$els.backToTop.on('click', function(e) {
e.preventDefault();
jQuery('html, body').animate({
scrollTop : 0
}, 400);
});
jQuery(window).on('scroll.toggleBackToTop', homebrew.utils.throttle(function() {
FE.$els.backToTop.toggleClass('is-shown', jQuery(window).scrollTop() > jQuery(window).height()*0.5);
}, 50));
}
if(typeof FE.browser === 'undefined') {
FE.browser = {
ie : FE.$els.root.hasClass('ie'),
ie9 : FE.$els.root.hasClass('ie9'),
lt9 : FE.$els.root.hasClass('lt9'),
ie8 : FE.$els.root.hasClass('ie8'),
lt8 : FE.$els.root.hasClass('lt8'),
ie7 : FE.$els.root.hasClass('ie7'),
firefox : (window.mozIndexedDB !== undefined)
}
}
jQuery.extend(true, FE, {
alert : function(args) {
this.showAlertPopup(args, 'alert');
},
confirm : function(args) {
this.showAlertPopup(args, 'confirm');
},
showAlertPopup : function(args, method) {
args = args || {};
var $popup = jQuery('#FE__alertPopup');
if(!$popup.length) {
$popup = jQuery([
'<div class="ssf-popup text-center" id="FE__alertPopup">',
'<h2 class="title space-bottom-2x" />',
'<div class="popup-message" />',
'<div class="space-top-2x">',
'<a href="#/" class="button padded xlarge okay-button">Okay</a>',
'<a href="#/" class="button padded xlarge space-left cancel-button" style="display: none;">Cancel</a>',
'</div>',
'</div>'
].join('')).appendTo('body');
$popup.popupify({
addCloseBtns : false,
closeOnOverlay : false
});
}
/* Alerts/Confirm dialog boxes should only happen one at a time,
* so if it is already shown, then do not proceed. */
if(jQuery('body').hasClass('popup-is-shown')
&& $popup.hasClass('is-shown')) {
return;
}
var $title = $popup.find('.title'),
$message = $popup.find('.popup-message'),
$prevPopup = jQuery('.popup-is-shown').find('.ssf-popup.is-shown');
if(args.title) $title.html(args.title);
if(args.message) $message.html(args.message);
$popup.find('.cancel-button').toggle(method === 'confirm');
$popup.find('.okay-button, .cancel-button')
.off('.alert')
.on('click.alert', function() {
if($prevPopup.length
&& typeof $prevPopup.eq(0).data('popupify') !== 'undefined') {
$prevPopup.data('popupify').reveal();
} else {
$popup.data('popupify').conceal();
}
if(typeof args.onConfirm === 'function') {
if(method === 'confirm') {
args.onConfirm(jQuery(this).is('.okay-button'));
} else {
args.onConfirm();
}
}
});
$popup.data('popupify').reveal();
},
FootnoteAnchor : function() {
this.init.apply(this, arguments);
},
Hasher : function(options) {
this.options = options;
},
HeightSlider : function(heightSlider) {
if(typeof heightSlider === 'string') heightSlider = jQuery(heightSlider);
var self = this;
jQuery.extend(self, {
reveal : function() {
if(Modernizr.csstransitions) {
if(heightSlider.height() !== 0) return;
var targetHeight = 0;
heightSlider.css('height', 'auto');
targetHeight = heightSlider.height();
heightSlider.css('height', '');
setTimeout(function() {
heightSlider
.off(FE.events.transitionEnd)
.on(FE.events.transitionEnd, function() {
heightSlider
.off(FE.events.transitionEnd)
.removeClass('is-transitionable')
.css('height', '')
.addClass('is-toggled');
})
.addClass('is-transitionable')
.css('height', targetHeight + 'px');
}, 1);
} else {
if(heightSlider.css('display') !== 'none') return;
heightSlider.slideDown(400, function() {
jQuery(this).addClass('is-toggled');
});
}
},
conceal : function() {
if(Modernizr.csstransitions) {
if(heightSlider.height() === 0) return;
heightSlider
.css('height', heightSlider.height() + 'px')
.removeClass('is-toggled');
setTimeout(function() {
heightSlider
.off(FE.events.transitionEnd)
.on(FE.events.transitionEnd, function() {
heightSlider.off(FE.events.transitionEnd);
heightSlider.removeClass('is-transitionable');
heightSlider.css('height', '');
})
.addClass('is-transitionable')
.css('height', '0px');
}, 1);
} else {
if(heightSlider.css('display') === 'none') return;
heightSlider
.removeClass('is-toggled')
.slideUp(400);
}
},
toggle : function() {
if(Modernizr.csstransitions) {
heightSlider.trigger((heightSlider.height() === 0) ? 'reveal' : 'conceal');
} else {
heightSlider.trigger((heightSlider.css('display') === 'none') ? 'reveal' : 'conceal');
}
}
});
heightSlider.data('height-slider', self);
},
/* End HeightSlider */
StickyColumn : function() {
this.load.apply(this, arguments);
},
getHash : function() {
var hash = window.location.hash;
/*
* Need to check if second character is a period; sometimes
* AddThis adds its own hash to the URL, and its second
* character is always a period, which is problematic.
*/
if(hash === '' || hash.substr(1,1) === '.') {
return '';
} else {
return hash;
}
},
/* End getHash */
getQueryStr: function(str) {
var search = window.location.search;
if(!search) return false;
if(search.substr(0,1) === '?') {
search = search.substr(1);
}
var splitSearch = search.split('&');
keyValuePairs = {};
splitSearch.map(function(searchStr) {
var splitSearchStr = searchStr.split('=');
splitSearchStr = splitSearchStr.map(function(str) {
return jQuery.trim(str);
});
keyValuePairs[splitSearchStr[0]] = splitSearchStr[1];
});
if(typeof str === 'string') {
return (typeof keyValuePairs[str] === 'undefined') ? false : keyValuePairs[str];
} else {
return keyValuePairs;
}
},
/* End getQueryStr */
initContentTabbers : function() {
/* For tabs that toggle contents instead of going to new pages */
jQuery('.js-togglerify-tabs').each(function() {
var $this = jQuery(this),
$nestedTabs = $this.find('.js-togglerify-tabs').find('.tab'),
$tabs = $this.find('.tab').not($nestedTabs),
$nestedContents = $this.find('.js-togglerify-tabs').find('.tab-content'),
$contents = $this.find('.tab-content').not($nestedContents);
$tabs
.togglerify('destroy')
.togglerify({
toggledClass: 'current',
selfToggleable: false,
singleActive: true,
content: function(index) {
return $contents.eq(index);
}
})
.on('afterToggleOn', function() {
jQuery(window).trigger('resize');
})
.on('toggleOff', function(e, $thisTab, $thisContent) {
/* Pause videos if available */
$thisContent.find('.video-holder').find('iframe').each(function() {
this.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}', '*');
});
});
});
},
/* End initContentTabbers */
initContentShowers : function() {
var types = {
TAB: 'tab',
TOGGLER: 'toggler',
NOTES: 'notes'
},
$notesToggler = jQuery('#notesToggler'),
$notesContent = jQuery('#notesContent');
jQuery('.js-show-content').each(function() {
var $this = jQuery(this),
thisHref = $this.attr('href');
if(typeof thisHref !== 'string') {
console.log($this);
console.error("No target specified. Set the target's ID as the `href` attribute on the element.");
return
}
var $target = jQuery($this.attr('href'));
if(!$target.length) {
console.log($this);
console.error("Target `" + $this.attr('href') + "` does not exist.");
return;
}
var data = $this.data('show-content-options');
if(!data) {
console.log($this);
console.error('Options undeclared. Declare the options using the `data-show-content-options` attribute on the element.');
return;
}
var options = (typeof data === 'string')
? homebrew.getKeyValuePairsFromString(data)
: {};
if(!options.type) {
console.log($this);
console.error('Options declared, but no type specified.');
return;
}
var scrollArgs = [$target];
if(options.smoothScroll !== true) {
scrollArgs.push('snap');
}
switch(options.type) {
case types.TAB:
$this.on('click', function(e) {
e.preventDefault();
var $tabContent = $target.closest('.tab-content'),
$heightSyncers = $tabContent.find('.js-sync-height-wrapper');
if($tabContent.hasClass('current')) {
FE.scrollTo.apply(null, scrollArgs);
} else {
if($heightSyncers.length) {
$heightSyncers.last().one('afterSync', function() {
FE.scrollTo.apply(null, scrollArgs);
});
$tabContent.data('togglerify').toggleOn();
} else {
$tabContent.data('togglerify').toggleOn();
FE.scrollTo.apply(null, scrollArgs);
}
}
});
break;
case types.NOTES:
if(!$notesToggler.length || !$notesContent.length) {
return;
}
$this.on('click', function(e) {
e.preventDefault();
if(!$notesToggler.hasClass('is-toggled')) {
$notesToggler.togglerify('toggleOn', { noSlide : true });
}
FE.scrollTo($target);
});
break;
default:
console.log($this);
var errorMsg = [
'The type `', options.type, '` is not supported. Our currently supported types are: '
];
jQuery.each(types, function(key, value) {
errorMsg.push('\n' + value);
});
errorMsg.push('\n\nCheck the type again.');
console.error(errorMsg.join(''));
break;
}
});
},
/* End initContentShowers */
initDropdownSwitchers : function($scope) {
var $holders = ($scope && $scope.length)
? $scope.find('.dropdown-switcher-holder')
: jQuery('.dropdown-switcher-holder');
if(!$holders.length) return;
$holders.each(function() {
var $dropdown = jQuery(this).find('.dropdown-switcher'),
$contents = jQuery(this).find('.dropdown-content');
$dropdown
.on('change', function() {
$contents
.hide()
.eq(this.selectedIndex)
.show();
})
.trigger('change');
});
},
initNumberTabbers : function() {
jQuery('.number-tabber').each(function() {
var $tabs = jQuery(this).find('.number-tabber__tabs').children('li'),
$contents = jQuery(this).find('.number-tabber__contents').children('li');
$tabs
.togglerify('destroy')
.togglerify({
toggledClass: 'current',
singleActive: true,
selfToggleable: false,
content: function(index) {
return $contents.eq(index);
}
});
});
},
/* End initNumberTabbers */
initPage : function() {
jQuery('.js-dropdownify').dropdownify();
jQuery('.js-inputify').inputify();
jQuery.each(FE, function(key, value) {
if(key.indexOf('init') === 0 && key !== 'initPage') value();
});
FE.loadXMLForm(jQuery('.js-xml-form-holder'));
FE.loadXMLTable(jQuery('.js-xml-tbl-holder'));
FE.loadXMLLocations(jQuery('.js-xml-locations-holder'));
if(FE.browser.ie) jQuery('[placeholder]').placeholderify();
},
/* End initPage */
initSectionSnap : function() {
/* Only needed for touchscreens, where the header does not
* automatically hide itself. */
if(!Modernizr.touch) return;
var hash = FE.getHash();
if(!hash || hash.indexOf('#/') > -1) return;
var $hash = jQuery(hash);
if(!$hash.length || !$hash.is('.section')) return;
setTimeout(function() {
FE.scrollTo($hash);
}, 25);
},
/* End initSectionSnap */
initSelfTogglers : function() {
/* Self Togglers - for things like FAQ questions */
jQuery('.self-toggler__toggler').togglerify({
singleActive: false,
slide: true,
content: function() {
return jQuery(this).next();
}
});
},
/* End initSelfTogglers */
initSectionContentToggler : function() {
/* Section Content togglers - for pages like Popular FAQs */
var $sectionContentTogglers = jQuery('.section-content-toggler');
if(!$sectionContentTogglers.length) return;
var $sectionToggleableContents = jQuery('.section-toggleable-content'),
$sectionDropdown = jQuery('<select>'),
optionsStrArray = [];
$sectionContentTogglers
.togglerify({
selfToggleable: false,
singleActive : true,
content : function(index) {
return $sectionToggleableContents.eq(index);
}
})
.each(function(index) {
var $dropdownOption = jQuery(['<option>', jQuery.trim(jQuery(this).find('.toggler__title').text()), '</option>'].join(''));
$dropdownOption.data('section-content-toggler', jQuery(this));
$dropdownOption.appendTo($sectionDropdown);
});
jQuery('<div class="column show-for-small-down" />')
.prepend($sectionDropdown)
.prependTo($sectionContentTogglers.eq(0).closest('.row'));
$sectionDropdown
.dropdownify({
markups : {
holder : '<div class="expand space-bottom" />'
}
})
.on('change', function() {
var $thisToggler = jQuery(this).find('option:checked').data('section-content-toggler');
$thisToggler.togglerify('toggleOn');
});
FE.watchSize('small', function(isSmallScreen) {
var method = (isSmallScreen) ? 'deactivate' : 'activate';
$sectionContentTogglers.togglerify(method);
});
},
/* End initSectionContentToggler */
initSmallNav : function() {
if(Modernizr.touch || jQuery('#mainSmallNav').data('initSmallNav') === true) return;
jQuery('#mainSmallNav').data('initSmallNav', true);
var prevScrollTop = jQuery(window).scrollTop(),
navHeight = jQuery('#mainSmallNav').height() + jQuery('#mainNav').height();
jQuery(window)
.on('resize.navHider', function() {
navHeight = jQuery('#mainSmallNav').height() + jQuery('#mainNav').height();
})
.trigger('resize.navHider')
.on('scroll.navHider', function() {
var currentScrollTop = jQuery(window).scrollTop(),
partialHiddenBool = currentScrollTop > 47,
hiddenBool = currentScrollTop >= prevScrollTop && currentScrollTop > navHeight && !FE.$els.body.hasClass('mobile-nav-is-shown');
jQuery('body').toggleClass('main-header-is-partially-hidden', partialHiddenBool);
jQuery('body').toggleClass('main-header-is-hidden', hiddenBool);
prevScrollTop = currentScrollTop;
})
.trigger('scroll.navHider');
},
/* End initSmallNav */
initSyncHeightWrappers : function($scope) {
var $syncHeightWrappers = jQuery('.js-sync-height-wrapper');
if(!$syncHeightWrappers.length) return;
$syncHeightWrappers.each(function() {
var selectors = jQuery(this).data('sync-height-selector');
if(!selectors) return;
var selectorsSplitArray = selectors.split(',');
for(var i = selectorsSplitArray.length-1; i > -1; i--) {
selectorsSplitArray[i] = jQuery.trim(selectorsSplitArray[i]);
}
jQuery(this).heightSyncify({
items : selectorsSplitArray
});
});
},
/* End initSyncHeightWrappers */
initTooltips : function() {
var $els = jQuery('.icon--question[title], .js-tooltipify');
$els.tooltipify();
},
/* End initTooltips */
initQuickLinks : function() {
var $quicklinksToggler = jQuery('#mainNav__quicklinksToggler'),
$quicklinks = jQuery('#mainNav__quicklinks');
if(!$quicklinksToggler.length || !$quicklinks.length) return;
if($quicklinksToggler.data('initQuickLinks') === true) return;
$quicklinksToggler.data('initQuickLinks', true);
var mouseupEv = 'mouseup.mainNavQuicklinksFauxBlur',
resizeEv = 'resize.limitQuicklinksHeight';
$quicklinksToggler
.togglerify({
slide: true,
content: function() {
return $quicklinks;
}
})
.togglerify('deactivate')
.on({
click : function(e) {
e.preventDefault();
var $thisToggler = jQuery(this);
if($thisToggler.hasClass('is-toggled')) {
$thisToggler.togglerify('toggleOff');
} else {
var heightLimit = jQuery(window).height() - jQuery('#mainNav').height(),
contentHeight;
$quicklinks.css('height', 'auto');
contentHeight = $quicklinks.height();
$quicklinks.css('height', '');
if(contentHeight >= heightLimit) {
$thisToggler.togglerify('toggleOn', { contentHeight : heightLimit });
} else {
$thisToggler.togglerify('toggleOn');
}
}
},
toggleOn : function(e, $thisToggler, $target) {
jQuery(document).on(mouseupEv, function(e) {
var container = $thisToggler.add($target);
if(!container.is(e.target) && container.has(e.target).length === 0) {
jQuery(document).off(mouseupEv);
$target.data('togglerify').toggleOff();
}
});
jQuery(window).on(resizeEv, function() {
if(!$thisToggler.hasClass('is-toggled')) return;
var heightLimit = jQuery(window).height() - jQuery('#mainNav').height();
$quicklinks.css('height', '');
if($quicklinks.height() >= heightLimit) {
$quicklinks.height(heightLimit);
}
});
},
toggleOff : function() {
jQuery(document).off(mouseupEv);
jQuery(window).off(resizeEv);
}
});
},
/* End initQuickLinks */
loadXMLForm : function($holders) {
$holders = jQuery($holders);
if(!$holders.length) return;
$holders.each(function() {
var $thisHolder = jQuery(this);
if(jQuery.data(this, 'loaded-xml-form') === true) return;
var xmlURL = $thisHolder.data('xml-form-url');
if(typeof xmlURL !== 'string') return;
jQuery.ajax({
type: 'GET',
url: xmlURL,
dataType: 'xml',
success: function(data) {
makeXMLForm(data, $thisHolder);
FE.initFancyPlaceholders($thisHolder);
FE.initInputFocus($thisHolder);
$thisHolder.find('.js-inputify').inputify();
$thisHolder.find('.js-dropdownify').dropdownify();
$thisHolder.data('loaded-xml-form', true);
},
error: function(d) {
console.log(d);
}
});
});
function makeXMLForm(data, $holder) {
var $data = jQuery(data),
$inputs = $data.find('formInput'),
uniqueID = new Date().getTime() + '_' + Math.round(Math.random()*10000),
$xmlForm = jQuery([
'<form action="https://docs.google.com/forms/d/', getText($data.find('formID')), '/formResponse"',
'target="hiddenIframe_', uniqueID, '"',
'method="post" class="xml-form-asset xml-form-contents" />'
].join('')).prependTo($holder),
xmlFormStrArray = [];
xmlFormStrArray.push([
'<div class="row collapse space-bottom medium-space-bottom-2x">',
makeTitle($data.find('formTitle')),
'</div>'
].join(''));
$inputs.each(function(index) {
var $thisInput = jQuery(this),
uniqueInputID = new Date().getTime() + '_' + index,
name = getText($thisInput.find('name')),
label = getText($thisInput.find('label')),
type = getText($thisInput.find('type')).toLowerCase(),
required = getText($thisInput.find('required')).toLowerCase(),
pattern = getText($thisInput.find('pattern')),
tooltip = getText($thisInput.find('tooltip'));
switch(type) {
case 'text':
case 'number':
case 'email':
case 'textarea':
var validifyStrArray = ['response: #response_' + uniqueInputID],
floaterStrArray = [];
if(!pattern) {
if(type === 'number') {
validifyStrArray.unshift('pattern: numbers');
} else if(type === 'email') {
validifyStrArray.unshift('pattern: email');
}
}
if(required === 'yes') {
validifyStrArray.unshift('required: true');
}
validifyStrArray.push('floater: #floater_roi_' + uniqueInputID);
floaterStrArray.push('<div class="validify-floater" id="floater_roi_', uniqueInputID, '">');
if(required === 'yes') {
floaterStrArray.push([
'<span class="validify-floater__message validify-floater__message--failed-required">',
'This input is required.',
'</span>'
].join(''));
}
var errorMessage = getText($thisInput.find('errorMessage'));
/*if(!errorMessage) {*/
if(type === 'number') {
errorMessage = 'This input should consist of numbers only.'
} else if(type === 'email') {
errorMessage = 'The address should be in this format: username@youremail.com'
} else if(!errorMessage) {
errorMessage = 'Invalid input.'
}
/*}*/
floaterStrArray.push([
'<span class="validify-floater__message validify-floater__message--failed-pattern">',
errorMessage,
'</span>'
].join(''));
floaterStrArray.push('</div>');
var elementStr;
if(type === 'textarea') {
elementStr = [
'<textarea'
];
} else {
elementStr = [
'<input',
' type="', (type === 'email') ? 'email' : 'text', '"'
];
}
elementStr.push(
' data-validify="', validifyStrArray.join(', '), '"',
(pattern)
? ' data-validify-pattern="' + pattern + '"'
: '',
' name="', name, '"',
' class="field expand"',
' id="roi_', uniqueInputID ,'"',
(type === 'textarea')
? '></textarea>'
: ' />'
);
xmlFormStrArray.push([
'<div class="form-obj', (tooltip) ? ' form-obj--with-tooltip' : '', '">',
'<div class="field-holder expand">',
elementStr.join(''),
'<label for="roi_', uniqueInputID, '" class="field-holder__label">',
label, (required === 'yes') ? '<span class="text-red">*</span>' : '',
'</label>',
'</div>',
'<span class="validify-responses form-obj__icon" id="response_', uniqueInputID, '">',
'<span class="validify-response validify-response--success">',
'<i class="icon icon--success-tick"></i>',
'</span>',
'</span>',
(tooltip)
? '<i title="' + tooltip + '" class="icon icon--question round-circle form-obj__icon"></i>'
: '',
floaterStrArray.join(''),
'</div>'
].join(''));
break;
case 'dropdown':
var validifyStrArray = ['response: #response_' + uniqueInputID],
floaterStr = '';
if(required === 'yes') {
validifyStrArray.unshift('required: true');
validifyStrArray.push('floater: #floater_roi_' + uniqueInputID);
floaterStr = [
'<div class="validify-floater" id="floater_roi_', uniqueInputID, '">',
'<span class="validify-floater__message validify-floater__message--failed-required">',
'This input is required.',
'</span>',
'</div>'
].join('');
}
var optionsArray = getText($thisInput.find('options')).split('\n'),
options = [];
while(optionsArray.length) {
options.push([
'<option value="', optionsArray[0], '">',
optionsArray[0],
'</option>'
].join(''));
optionsArray.shift();
}
xmlFormStrArray.push([
'<div class="form-obj', (tooltip) ? ' form-obj--with-tooltip' : '', '">',
'<span class="expand js-dropdownify">',
'<select data-validify="', validifyStrArray.join(', '), '" name="', name, '">',
'<option value="">', label, (required === 'yes') ? '*' : '', '</option>',
options.join(''),
'</select>',
'</span>',
'<span class="validify-responses form-obj__icon" id="response_', uniqueInputID, '">',
'<span class="validify-response validify-response--success">',
'<i class="icon icon--success-tick"></i>',
'</span>',
'</span>',
(tooltip)
? '<i title="' + tooltip + '" class="icon icon--question round-circle form-obj__icon"></i>'
: '',
floaterStr,
'</div>'
].join(''));
break;
case 'radio':
case 'checkbox':
var validifyStrArray = ['groupResponse: #response_' + uniqueInputID],
validifyRequiredStr = '';
if(required === 'yes') {
validifyStrArray.unshift('required: true');
validifyRequiredStr = [
'<span class="validify-response validify-response--failed-required">',
'<br />This input is required.',
'</span>'
].join('');
}
var optionsArray = getText($thisInput.find('options')).split('\n'),
optionsLabelsArray = getText($thisInput.find('optionsLabels')).split('\n'),
options = [],
currentOption;
for(var i = 0, ii = optionsArray.length; i < ii; i++) {
if(optionsArray[i] === '__other_option__') {
/*options.push([
'<label>',
'<input type="', type, '" name="', name, '" data-validify value="others" class="js-inputify" /> ',
'Others',
'</label>',
'<input type="text" disabled class="field" />'
].join(''));*/
} else {
options.push([
'<label>',
'<input type="', type, '" name="', name, '" data-validify value="', optionsArray[i], '" class="js-inputify" /> ',
(typeof optionsLabelsArray[i] === 'string'
&& optionsLabelsArray[i])
? optionsLabelsArray[i]
: optionsArray[i],
'</label>'
].join(''));
}
}
xmlFormStrArray.push([
'<div class="form-obj" data-validify-group="', validifyStrArray.join(', '), '">',
'<p class="form-obj__label">',
label, (required === 'yes') ? '<span class="text-red">*</span>' : '',
(tooltip)
? ' <i title="' + tooltip + '" class="icon icon--question round-circle"></i>'
: '',
' <span class="validify-responses" id="response_', uniqueInputID, '">',
'<span class="validify-response validify-response--success">',
'<i class="icon icon--success-tick"></i>',
'</span>',
validifyRequiredStr,
'</span>',
'</p>',
options.join(''),
'</div>'
].join(''));
break;
}
});
xmlFormStrArray.push([
'<div class="text-center space-top medium-space-top-2x">',
'<input type="submit" value="Submit" class="button padded xlarge" />',
'</div>'
].join(''));
$xmlForm.append(xmlFormStrArray.join(''));
$xmlForm.find('.icon--question[title]').tooltipify();
var $hiddenIframe = jQuery('<iframe data-submitted="false" name="hiddenIframe_' + uniqueID + '" style="display: none;" />').appendTo($xmlForm);
$hiddenIframe.on('load', function() {
if(jQuery(this).data('submitted') !== true) return;
$xmlForm.addClass('is-hidden');
$holder.find('.xml-form-thanks').addClass('is-shown');
FE.scrollTo($holder.find('.xml-form-thanks'));
});
$xmlForm.validify().on('submit', function(e) {
var validifyData = jQuery.data(this, 'validify');
validifyData.set('strict', true).validate();
if(validifyData.valid !== true) {
//alert('Please check the form!');
var $errorInput = jQuery(this).find('.is-failed').eq(0);
FE.scrollTo($errorInput, function() {
$errorInput.focus().select();
});
e.preventDefault();
} else {
$hiddenIframe.data('submitted', true);
$xmlForm.find('input[type="submit"]').addClass('is-loading').prop('disabled', true);
}
});
}
function getText($node) {
return ($node.length) ? jQuery.trim($node.text()) : '';
}
function makeTitle($title) {
var title = getText($title);
if(title) {
return [
'<div class="large-6 column">',
'<h3>', title, '</h3>',
'</div>',
'<div class="large-6 column medium-down-pad-vertical large-text-right align-to-h3 text-dark-grey">',
'<span class="text-red">*</span> Please fill in the mandatory fields.',
'</div>'
].join('');
} else {
return [
'<div class="column medium-down-pad-vertical large-text-right text-dark-grey">',
'<span class="text-red">*</span> Please fill in the mandatory fields.',
'</div>'
].join('');
}
}
},
/* End loadXMLForm */
loadXMLTable : function($holders) {
$holders = jQuery($holders);
if(!$holders.length) return;
var worksheets = {},
xmlSerializer = new XMLSerializer(); // Needed for makeCellInlineFormats
$holders.each(function() {
var $thisHolder = jQuery(this);
if($thisHolder.data('loaded-xml-table') === true) return;
var xmlURL = $thisHolder.data('xml-table-url');
if(typeof xmlURL !== 'string') return;
jQuery.ajax({
type: 'GET',
url: xmlURL,
dataType: 'xml',
success: function(data) {
var xmlStyles = getXMLStyles(data);
makeXMLTable(data, xmlStyles, $thisHolder);
attachRowHoverers();
$thisHolder.data('loaded-xml-table', true);
},
error: function(d) {
console.log(d);
}
});
});
function makeXMLTable(data, xmlStyles, $holder) {
var $data = jQuery(data),
$worksheets = $data.find('Worksheet'),
dropdown = {},
finalTableStrArr = [];
worksheets = {};
$worksheets.each(function() {
var $thisWorksheet = jQuery(this),
thisWorksheetName = $thisWorksheet.attr('ss:Name').toLowerCase();
if(thisWorksheetName.indexOf('dropdown') === 0) {
$thisWorksheet.find('Data').each(function() {
var $Data = jQuery(this),
DataIndex = $Data.index(),
DataText = jQuery(this).text().toLowerCase();
switch(DataText) {
case 'dropdown label':
dropdown.__label = jQuery(this).closest('Row').next('Row').find('Data').text();
break;
case 'option label':
jQuery(this).closest('Row').nextUntil().each(function() {
var optionLabelText = jQuery(this).find('Data').eq(DataIndex).text();
if(optionLabelText === '') return;
dropdown[jQuery(this).find('Data').eq(DataIndex).text()] = jQuery(this).find('Data').eq(DataIndex+1).text().toLowerCase();
});
break;
}
});
} else {
worksheets[thisWorksheetName] = $thisWorksheet;
}
});
if(jQuery.isEmptyObject(dropdown)) {
var worksheetNames = [];
jQuery.each(worksheets, function(key, value) {
worksheetNames.push(key);
});
finalTableStrArr.push(iterateWorksheetsArray(worksheetNames, xmlStyles));
} else {
var dropdownOptionsArray = [],
dropdownContentsArray = [];
jQuery.each(dropdown, function(key, value) {
if(key === '__label') return;
dropdownOptionsArray.push(key);
var dropdownWorksheets = {},
valueSplitArray = value.split('\n');
if(valueSplitArray.length === 1) {
valueSplitArray = valueSplitArray[0].split(',');
}
for(var i = valueSplitArray.length-1; i > -1; i--) {
valueSplitArray[i] = jQuery.trim(valueSplitArray[i]);
}
dropdownContentsArray.push(iterateWorksheetsArray(valueSplitArray, xmlStyles));
});
var dropdownOptionsStrArray = [],
dropdownContentsStrArray = [];
while(dropdownOptionsArray.length) {
dropdownOptionsStrArray.push([
'<option>', dropdownOptionsArray.shift(), '</option>'
].join(''));
}
while(dropdownContentsArray.length) {
dropdownContentsStrArray.push([
'<div class="dropdown-content">',
dropdownContentsArray.shift(),
'</div>'
].join(''));
}
finalTableStrArr.push([
'<div class="dropdown-switcher-holder">',
'<div class="text-center text-large">',
dropdown.__label,
'<span class="js-dropdownify tbl-dropdown">',
'<select class="dropdown-switcher">',
dropdownOptionsStrArray.join(''),
'</select>',
'</span>',
'</div>',
'<div class="dropdown-contents-holder">',
dropdownContentsStrArray.join(''),
'</div>',
'</div>'
].join(''));
}
$holder.append(finalTableStrArr.join(''));
FE.initFootnotes($holder);
if(!$holder.find('.js-dropdownify').length) return;
$holder.find('.js-dropdownify').dropdownify();
FE.initDropdownSwitchers($holder);
}
function iterateWorksheetsArray(worksheetNames, xmlStyles) {
var worksheetStrArr = [],
currentWorksheetName,
mediaClass;
while(worksheetNames.length) {
currentWorksheetName = worksheetNames.shift();
if(typeof worksheets[currentWorksheetName] === 'undefined') {
console.error("FE.loadXMLTable(): Can't find the worksheet '" + currentWorksheetName + "'");
continue;
}
if(currentWorksheetName.indexOf('desktop') === 0) {
mediaClass = 'show-for-large-up';
} else if(currentWorksheetName.indexOf('tabletup') === 0) {
mediaClass = 'show-for-medium-up';
} else if(currentWorksheetName.indexOf('tabletonly') === 0) {
mediaClass = 'show-for-medium-only';
} else if(currentWorksheetName.indexOf('tabletdown') === 0) {
mediaClass = 'show-for-medium-down';
} else if(currentWorksheetName.indexOf('mobile') === 0) {
mediaClass = 'show-for-small-down';
}
worksheetStrArr.push([
'<div class="tbl-holder', (typeof mediaClass === 'string') ? ' ' + mediaClass : '', '">'
].join(''));
worksheetStrArr.push(makeTableString(worksheets[currentWorksheetName], xmlStyles));
worksheetStrArr.push('</div>');
}
return (worksheetStrArr.length) ? worksheetStrArr.join('') : false;
}
function getColumnCount($worksheet) {
var $worksheetRows = $worksheet.find('Row'),
_columnCount = [];
$worksheetRows.each(function() {
var $cells = jQuery(this).find('Cell');
/* Filter out empty cells */
$cells.each(function() {
if(!jQuery(this).text()) {
$cells = $cells.not(jQuery(this));
}
});
_columnCount.push($cells.length);
});
return Math.max.apply(null, _columnCount);
}
function getXMLStyles(data) {
var $styles = jQuery(data).find('Style'),
styleObj = {};
$styles.each(function() {
var $thisStyle = jQuery(this),
$alignment = $thisStyle.find('Alignment'),
$interior = $thisStyle.find('Interior'),
$numberFormat = $thisStyle.find('NumberFormat'),
$font = $thisStyle.find('Font'),
thisStyleObj = {};
/* Allow adjustment of alignment in the Excel spreadsheet */
if($alignment.length && hasAttributes($alignment, ['ss:Horizontal', 'ss:Vertical'])) {
var verticalAlignment, horizontalAlignment;
switch($alignment.attr('ss:Vertical')) {
case 'Top' : verticalAlignment = 'top'; break;
case 'Center' : verticalAlignment = 'middle'; break;
case 'Bottom' : verticalAlignment = 'bottom'; break;
}
switch($alignment.attr('ss:Horizontal')) {
case 'Top' : horizontalAlignment = 'top'; break;
case 'Center' : horizontalAlignment = 'center'; break;
case 'Bottom' : horizontalAlignment = 'bottom'; break;
}
thisStyleObj.alignment = {
'vertical' : verticalAlignment,
'horizontal' : horizontalAlignment
};
}
/* Interior is where the cell's background color data is stored */
if($interior.length && hasAttributes($interior, ['ss:Color'])) {
thisStyleObj.bgColor = $interior.attr('ss:Color');
}
if($font.length && hasAttributes($font, ['ss:Italic', 'ss:Bold', 'ss:Underline', 'ss:Color', 'ss:Size'])) {
thisStyleObj.font = {
'italic' : $font.attr('ss:Italic'),
'bold' : $font.attr('ss:Bold'),
'underline' : $font.attr('ss:Underline'),
'color' : $font.attr('ss:Color'),
'size' : $font.attr('ss:Size')
};
}
if($numberFormat.length && hasAttributes($numberFormat, ['ss:Format'])) {
thisStyleObj.numberFormat = $numberFormat.attr('ss:Format');
}
styleObj[$thisStyle.attr('ss:ID')] = thisStyleObj;
});
return styleObj;
}
function makeTableString($worksheet, xmlStyles) {
var $rows = filterOutEmptyRows($worksheet.find('Row'));
if(!$rows.length) return '';
var totalColumns = parseInt(getColumnCount($worksheet), 10),
totalRows = $rows.length,
i, ii, j, jj,
tableLayout = [];
for(i = $rows.length-1; i >-1; i--) {
tableLayout.push(new Array(totalColumns));
}
$rows.each(function(rowIndex) {
var cellCount = 0;
jQuery(this).find('Cell').each(function(cellIndex) {
if(cellCount >= totalColumns) return;
var $thisCell = jQuery(this),
cellMergeDown = parseInt($thisCell.attr('ss:MergeDown'), 10) || 0,
cellMergeAcross = parseInt($thisCell.attr('ss:MergeAcross'), 10) || 0;
while(typeof tableLayout[rowIndex][cellCount] === 'number') {
cellCount++;
}
tableLayout[rowIndex][cellCount] = $thisCell;
/* If there's colspan, then denote the overlapping cells
* as 0 so that it won't be rendered later. */
if(cellMergeAcross) {
for(i = cellCount, ii = cellCount+cellMergeAcross; i < ii; i++) {
tableLayout[rowIndex][i+1] = 0;
}
cellCount += cellMergeAcross;
}
/* Same thing, if there's rowspan, then denote the
* overlapping cells as 0 so that it won't be
* rendered later. */
if(cellMergeDown) {
for(i = rowIndex+1, ii = rowIndex+cellMergeDown; i <= ii; i++) {
tableLayout[i][cellCount] = 0;
/* Same thing; this is to account for both rowspan
* and colspan from the same cell. */
if(cellMergeAcross) {
for(j = cellCount+1, jj = cellCount+cellMergeAcross; j <= jj; j++) {
tableLayout[i][j] = 0;
}
}
}
}
cellCount++;
});
});
var tableStrArr = [],
tableStyleID = $worksheet.find('Table').attr('ss:StyleID'),
defaultStyle = (xmlStyles[tableStyleID]) ? xmlStyles[tableStyleID] : {};
tableStrArr.push('<table class="default-tbl">');
var cellStrArr, cellArray, cell, k, kk;
while(tableLayout.length) {
cellStrArr = [];
cellArray = tableLayout.shift();
for(k = 0, kk = cellArray.length; k < kk; k++) {
if(typeof cellArray[k] === 'undefined') {
cellStrArr.push('<td></td>');
} else if(typeof cellArray[k] === 'object') {
cellStrArr.push(makeCellString(cellArray[k], k));
}
}
if(cellStrArr.length) {
cellStrArr.unshift('<tr>');
cellStrArr.push('</tr>');
tableStrArr.push(cellStrArr.join(''));
}
}
tableStrArr.push('</table>');
return tableStrArr.join('');
function makeCellString($cell, cellIndex, log) {
var $thisCell = $cell,
cellContent = $thisCell.text();
if(cellContent === '') {
if(cellIndex % 2 === 1) {
return '<td class="alt"></td>';
} else {
return '<td></td>';
}
}
var cellStyle = jQuery.extend({}, defaultStyle),
cellData = $thisCell.find('Data'),
cellDataType = cellData.attr('ss:Type');
if(cellDataType === 'Number') {
var decimalSplit = cellContent.split('.');
if(decimalSplit.length > 1 && decimalSplit[1].length > 2) {
cellContent = parseFloat(cellContent, 10).toFixed(2);
}
}
if(xmlStyles[$thisCell.attr('ss:StyleID')]) {
jQuery.extend(cellStyle, xmlStyles[$thisCell.attr('ss:StyleID')]);
}
var cellNumberFormat = cellStyle.numberFormat,
cellMergeDown = parseInt($thisCell.attr('ss:MergeDown'), 10) || 0,
cellMergeAcross = parseInt($thisCell.attr('ss:MergeAcross'), 10) || 0,
cellSSData = $thisCell.children('ss\\:Data'),
cellInlineTags = {
'italic' : 0,
'bold' : 0,
'underline' : 0
},
cellTagName = (cellStyle.bgColor && cellStyle.bgColor !== '#FFFFFF') ? 'th' : 'td',
cellClassNames = [],
cellClassName = '',
cellRowspan = '',
cellColspan = '',
cellInlineStyles = [];
if(cellIndex % 2 === 1) {
cellClassNames.push('alt');
}
if(cellSSData.length) {
cellInlineTags = {
'bold' : cellSSData.find('B').length,
'italic' : cellSSData.find('I').length,
'underline' : cellSSData.find('U').length
};
cellContent = makeCellInlineFormats(cellSSData);
}
if(typeof cellStyle.bgColor === 'string') {
cellInlineStyles.push('background-color: ' + cellStyle.bgColor);
}
if(typeof cellStyle.alignment === 'object') {
if(typeof cellStyle.alignment.horizontal === 'string') {
cellInlineStyles.push('text-align: ' + cellStyle.alignment.horizontal);
}
if(typeof cellStyle.alignment.vertical === 'string') {
cellInlineStyles.push('vertical-align: ' + cellStyle.alignment.vertical);
}
}
if(typeof cellStyle.font === 'object') {
if(typeof cellStyle.font.italic !== 'undefined') {
cellInlineStyles.push('font-style: italic');
}
if(typeof cellStyle.font.bold !== 'undefined') {
cellInlineStyles.push('font-weight: bold');
}
if(typeof cellStyle.font.underline !== 'undefined') {
cellInlineStyles.push('text-decoration: underline');
}
if(typeof cellStyle.font.color !== 'undefined') {
cellInlineStyles.push('color: ' + cellStyle.font.color);
}
}
/* Compile all the attributes */
if(cellClassNames.length) {
cellClassName = [' class="', cellClassNames.join(' '), '"'].join('');
}
if(cellMergeDown) {
cellRowspan = [' rowspan="', cellMergeDown+1, '"'].join('');
}
if(cellMergeAcross) {
cellColspan = [' colspan="', cellMergeAcross+1, '"'].join('');
}
if(typeof cellNumberFormat !== 'undefined') {
cellContent = makeCellCurrency(cellNumberFormat, cellContent);
}
if(cellInlineStyles.length) {
cellInlineStyles = [' style="', cellInlineStyles.join('; '), '"'].join('');
} else {
cellInlineStyles = '';
}
cellContent = cellContent.replace(/\n/g, '<br />');
if(typeof cellStyle.font === 'object'
&& typeof cellStyle.font.size !== 'undefined'
&& cellStyle.font.size !== '11') {
cellContent = [
'<span style="font-size: ', Math.round(parseFloat(cellStyle.font.size, 10) / 11 * 100, 10), '%;">',
cellContent,
'</span>'
].join('');
}
return [
'<', cellTagName, cellClassName, cellRowspan, cellColspan, cellInlineStyles, '>',
cellContent,
'</', cellTagName, '>'
].join('');
}
}
function makeCellInlineFormats($ssData) {
/*
* $ssData.html() was initially used to get the string of the
* contents. However, that produced an error in all versions
* of IE as well as Safari. This was with jQuery 1.11.0.
*
* To work around this, an XMLSerializer is used instead.
* https://developer.mozilla.org/en-US/docs/XMLSerializer
*/
var ssDataChildNodes = jQuery.makeArray($ssData[0].childNodes),
contentsStr = [];
while(ssDataChildNodes.length) {
contentsStr.push(xmlSerializer.serializeToString(ssDataChildNodes.shift()));
}
contentsStr = contentsStr.join('');
var cellContentStr = contentsStr,
fontMatchArray = cellContentStr.match(/<Font+(.*?)>/g);
var inlineStyles;
for(var i = 0, ii = fontMatchArray.length; i < ii; i++) {
inlineStyles = getInlineStyles(fontMatchArray[i]);
if(inlineStyles === '') {
cellContentStr = cellContentStr
.replace(fontMatchArray[i], '')
.replace('</Font>', '');
} else {
cellContentStr = cellContentStr
.replace(fontMatchArray[i], '<span style="' + inlineStyles + '">')
.replace('</Font>', '</span>');
}
}
var inlineTags = ['b', 'i', 'u', 'sup'],
tagName;
while(inlineTags.length) {
tagName = inlineTags.shift();
cellContentStr = cellContentStr
.replace(new RegExp('<' + tagName + '+(.*?)>', 'gi'), '<' + tagName + '>')
.replace(new RegExp('<\/' + tagName + '+(.*?)>', 'gi'), '</' + tagName + '>');
}
return cellContentStr;
function getInlineStyles(fontHTMLStr) {
/*
* The subtstring is to remove the opening and closing
* angled brackets (`<` and `>`) at the start and end
* of the string.
*/
var splitArray = fontHTMLStr.substring(1, fontHTMLStr.length-1).split(' '),
attrStr,
splitAttrArray,
inlineStylesArray = [];
while(splitArray.length) {
attrStr = splitArray.shift();
if(attrStr.indexOf('html:') === -1) continue;
splitAttrArray = attrStr.replace(/(html\:)|"/g, '').toLowerCase().split('=');
switch(splitAttrArray[0]) {
case 'color':
if(splitAttrArray[1] === '#000000') continue;
inlineStylesArray.push(['color: ', splitAttrArray[1]].join(''));
break;
case 'size':
inlineStylesArray.push(['font-size: ', Math.round((parseFloat(splitAttrArray[1], 10) / 11 * 100), 10), '%'].join(''));
break;
}
}
return inlineStylesArray.join('; ');
}
}
function makeCellCurrency(cellNumberFormat, cellContent) {
if(cellNumberFormat === '@'
|| cellNumberFormat === '0') return cellContent;
var splitCellContentArray;
if(cellNumberFormat === 'Currency') {
splitCellContentArray = parseFloat(cellContent, 10).toFixed(2).split('.');
cellContent = 'RM' + contentWithcommas();
if(splitCellContentArray.length > 1) {
cellContent += '.' + splitCellContentArray[1];
}
} else if(cellNumberFormat === 'Fixed') {
splitCellContentArray = parseFloat(cellContent, 10).toFixed(2).split('.');
cellContent = contentWithcommas();
if(splitCellContentArray.length > 1) {
cellContent += '.' + splitCellContentArray[1];
}
} else {
var currencyFormatArray = cellNumberFormat.split(';')[0].split(','),
currency = currencyFormatArray[0].replace(/\[|\]| |#|\\|"/g, '').replace(/\$/, '').split('-'),
decimals = currencyFormatArray[1].split('.');
if(currency.length > 1) currency = currency[0];
if(decimals.length === 1) {
decimals = 0;
} else {
decimals = decimals[1].replace(/_\)/g, '').length;
}
splitCellContentArray = parseFloat(cellContent, 10).toFixed(decimals).split('.');
cellContent = currency + contentWithcommas();
if(splitCellContentArray.length > 1) {
cellContent += '.' + splitCellContentArray[1];
}
}
return cellContent;
function contentWithcommas() {
return splitCellContentArray[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
}
function attachRowHoverers() {
$holders.find('[rowspan]').each(function() {
var $thisCell = jQuery(this),
rowspan = $thisCell.attr('rowspan');
if(typeof rowspan !== 'string') return;
rowspan = parseInt(rowspan, 10);
var $thisRow = $thisCell.closest('tr'),
$nextRows = $thisRow.nextAll('tr').slice(0, rowspan-1);
$nextRows.each(function() {
jQuery(this).on({
mouseenter : function() {
$thisCell.addClass('is-hovered');
},
mouseleave : function() {
$thisCell.removeClass('is-hovered');
}
});
});
});
}
function filterOutEmptyRows($rows) {
/* Filter out rows that only have empty cells */
$rows.each(function() {
var empty = true;
jQuery(this).find('Cell').each(function() {
if(jQuery(this).text() !== '') empty = false;
return false;
});
if(empty) $rows = $rows.not(jQuery(this));
});
return $rows;
}
function hasAttributes($obj, attrArr) {
while(attrArr.length) {
if(typeof $obj.attr(attrArr.shift()) !== 'undefined') {
return true;
}
}
return false;
}
},
/* End loadXMLTable */
loadXMLLocations : function($holders) {
$holders = jQuery($holders);
if(!$holders.length) return;
$holders.each(function() {
var $thisHolder = jQuery(this);
if($thisHolder.data('loaded-xml-locations') === true) return;
var xmlURL = $thisHolder.data('xml-locations-url');
if(typeof xmlURL !== 'string') return;
jQuery.ajax({
type: 'GET',
url: xmlURL,
dataType: 'xml',
success: function(data) {
makeLocationsList(data, $thisHolder);
$thisHolder.data('loaded-xml-locations', true);
},
error: function(d) {
console.log(d);
}
});
});
function makeLocationsList(data, $holder) {
var $locations = jQuery(data).find('obj'),
regions = [];
$locations.each(function() {
var $region = jQuery(this).find('region'),
regionStr = jQuery.trim($region.text());
regionStr = (regionStr) ? regionStr : 'Default';
if(regions.length) {
for(var i = regions.length-1; i > -1; i--) {
if(regions[i].name === regionStr) {
regions[i].$els.push(jQuery(this));
return;
}
}
}
regions.push({
'name' : regionStr,
'$els' : [jQuery(this)]
});
});
regions.sort(function(a,b) {
var strA = a.name.toLowerCase(),
strB = b.name.toLowerCase();
if(strA < strB) return -1; // sort ascending
if(strA > strB) return 1;
return 0; // do nothing
});
var output = [],
switcherStrArr = ['<span class="location-dropdown"><select>', '', '</select></span>'],
rowMarkup = ['<div class="row location-list', 1, '"><div class="row__flexi-width ', 3, '">'],
i, ii, totalLocationsInRegion;
for(i = 0, ii = regions.length; i < ii; i++) {
rowMarkup[1] = (i === 0) ? ' current' : '';
totalLocationsInRegion = regions[i].$els.length;
if(totalLocationsInRegion < 2) {
rowMarkup[3] = 'has-1-item';
} else if(totalLocationsInRegion === 2) {
rowMarkup[3] = 'has-2-items';
} else if(totalLocationsInRegion === 3) {
rowMarkup[3] = 'has-3-items';
} else {
rowMarkup[3] = 'more-than-3-items';
}
output.push(rowMarkup.join(''));
while(regions[i].$els.length) {
output.push([
'<div class="column">',
'<div class="location">',
'<div class="location__name">',
jQuery.trim(regions[i].$els[0].find('storeName').text()),
'</div>',
'<div class="location__address">',
jQuery.trim(regions[i].$els[0].find('storeAddress').text()),
'</div>',
'<div class="location__footer">',
'<a href="https://maps.google.com/maps?daddr=',
jQuery.trim(regions[i].$els[0].find('storeLat').text()), ',',
jQuery.trim(regions[i].$els[0].find('storeLng').text()), '" target="_blank">',
'Get Directions',
'</a>',
'</div>',
'</div>',
'</div>'
].join(''));
regions[i].$els.shift();
}
output.push('</div></div>');
}
$holder.html(output.join(''));
if(regions.length > 1) {
for(i = 0, ii = regions.length; i < ii; i++) {
switcherStrArr[1] += [
'<option value="', i, '">', regions[i].name, '</option>'
].join('');
}
var $switcher = jQuery(switcherStrArr.join(''));
jQuery('<div class="text-center" />')
.prependTo($holder)
.append($switcher);
$switcher.dropdownify();
var $locationLists = $holder.find('.location-list');
$holder.find('select').on('change', function() {
var targetIndex = parseInt(jQuery(this).val(), 10);
$locationLists.each(function(index) {
if(index === targetIndex) {
jQuery(this)
.addClass('current')
.heightSyncify('enable')
.heightSyncify('sync');
} else {
jQuery(this)
.removeClass('current')
.heightSyncify('disable');
}
});
});
}
var syncHeightSelectors = ['.location__name', '.location__address'];
$holder.find('.location-list').heightSyncify({
items : syncHeightSelectors
});
}
},
/* End loadXMLLocations */
scrollTo : function($obj, callback) {
if(typeof $obj !== 'object'
|| !$obj instanceof jQuery
|| !$obj.length) {
return;
}
var targetScrollPos = $obj.offset().top - 50;
if(targetScrollPos < jQuery(window).scrollTop()) {
targetScrollPos -= jQuery('#mainNav').outerHeight();
if(jQuery('#mainSmallNav').css('display') !== 'none'
&& !jQuery('#mainHeader').hasClass('is-partially-hidden')) {
targetScrollPos -= jQuery('#mainSmallNav').outerHeight();
}
}
if(callback === 'snap') {
jQuery(window).scrollTop(targetScrollPos);
} else {
jQuery('html, body').animate({
scrollTop : targetScrollPos
}, 400, callback);
}
},
/* End scrollTo */
watchSize : function() {
homebrew.watchSize.apply(homebrew, arguments);
}
/* End watchSize */
});
jQuery.extend(FE.FootnoteAnchor.prototype, {
init : function($el, $footnote) {
if(!$el.length || !$footnote.length) return;
var instance = this;
instance.$el = $el;
instance.$footnote = $footnote;
$el.tooltipify({
contents : $footnote.html()
});
instance.$el.data('footnote-anchor', this);
instance.enable();
},
enable : function() {
if(Modernizr.touch) return this;
var instance = this;
instance.$el.on({
'click.footnotesTooltip' : function(e) {
e.preventDefault();
e.stopPropagation();
var $thisFootnote = instance.$footnote;
if(!jQuery('#notesToggler').hasClass('is-toggled')) {
jQuery('#notesToggler').togglerify('toggleOn', { noSlide : true });
}
FE.scrollTo($thisFootnote);
$thisFootnote.addClass('is-active');
jQuery(document)
.off('mouseup.notesFauxBlur')
.on('mouseup.notesFauxBlur', function(e) {
if(!$thisFootnote.is(e.target) && $thisFootnote.has(e.target).length === 0) {
jQuery(document).off('mouseup.notesFauxBlur');
$thisFootnote.removeClass('is-active');
}
});
}
});
return this;
},
disable : function() {
var instance = this;
instance.$el.off('click.footnotesTooltip');
instance.$el.tooltipify('disable');
return instance;
}
});
jQuery.extend(FE.Hasher.prototype, {
get : function(args) {
var instance = this,
hash = window.location.hash;
if(hash === ''
|| hash === '#/'
|| hash.substr(0,2) !== '#/') {
instance.data = {};
return instance;
}
var splitHash = hash.substring(2).split('&'),
keyValuePairs,
dataObj = {};
while(splitHash.length) {
keyValuePairs = splitHash.shift().split('=');
dataObj[jQuery.trim(keyValuePairs[0])] = decodeURIComponent(jQuery.trim(keyValuePairs[1]));
}
instance.data = dataObj;
return instance;
},
setData : function(data) {
if(!data || !jQuery.isPlainObject(data)) return this;
this.data = jQuery.extend({}, data);
return this;
},
extendData : function(data) {
if(!data || !jQuery.isPlainObject(data)) return this;
if(this.data) {
jQuery.extend(this.data, data);
} else {
this.data = data;
}
return this;
},
set : function(args) {
args = args || {};
var instance = this,
options = jQuery.extend(instance.options, args);
if(options.ignoreDefault && !instance.data) return instance;
instance.data = instance.data || {};
var hashKeys = [],
hash = [],
sequence = options.sequence;
if(sequence === 'alphabetical'
|| typeof sequence === 'function') {
jQuery.each(instance.data, function(key, value) {
if(key === '' || value === '') return;
hashKeys.push(key);
});
var sorter;
if(sequence === 'alphabetical') {
sorter = function(a, b) {
var _a = a.toLowerCase(),
_b = b.toLowerCase();
if(_a < _b) return -1;
if(_a > _b) return 1;
return 0;
};
} else if(typeof sequence === 'function') {
sorter = sequence;
}
hashKeys.sort(sorter);
var currentHashKey;
while(hashKeys.length) {
currentHashKey = hashKeys.shift();
hash.push([currentHashKey, encodeURIComponent(instance.data[currentHashKey])].join('='));
}
} else if(typeof sequence === 'string') {
var splitSequence = sequence.split(','),
i, ii, currentSequenceKey;
for(i = 0, ii = splitSequence.length; i < ii; i++) {
currentSequenceKey = splitSequence[i];
if(instance.data[currentSequenceKey]) {
hash.push([currentSequenceKey, encodeURIComponent(instance.data[currentSequenceKey])].join('='));
}
}
jQuery.each(instance.data, function(key, value) {
if(key === '' || value === '') return;
for(i = splitSequence.length-1; i > -1; i--) {
if(key === splitSequence[i]) return;
}
hash.push([key, encodeURIComponent(value)].join('='));
});
} else {
jQuery.each(instance.data, function(key, value) {
if(key === '' || value === '') return;
hash.push([key, encodeURIComponent(value)].join('='));
});
}
window.location.hash = '#/' + hash.join('&');
},
isSameWith : function(data) {
if(!data) return false;
var same = true,
count = 0,
instance = this;
jQuery.each(data, function(key, value) {
if(typeof instance.data[key] === 'undefined'
|| instance.data[key] !== value) {
same = false;
return false;
} else {
count++;
}
});
if(same) {
var refCount = 0;
jQuery.each(instance.data, function() {
refCount++;
});
same = (count === refCount);
}
return same;
}
});
jQuery.extend(FE.StickyColumn.prototype, {
callbacks : jQuery({}),
hasMousewheel : Boolean(jQuery.fn.mousewheel),
classes : {
stickyColumn : 'sticky-column',
sticky : 'is-sticky',
stickBottom : 'is-stick-to-bottom'
},
load : function(args) {
var instance = this,
proto = FE.StickyColumn.prototype;
/* If Mousewheel isn't available, load it now. */
if(!proto.hasMousewheel) {
if(!proto.loadingMousewheel) {
proto.loadingMousewheel = true;
jQuery.getScript(FE.baseURL + 'js/plugins/jquery.mousewheel.min.js', function() {
FE.StickyColumn.prototype.hasMousewheel = true;
proto.callbacks.dequeue('mousewheelLoaded');
});
}
proto.callbacks.queue('mousewheelLoaded', function(next) {
instance.init(args);
if(typeof next === 'function') next();
});
}
},
init : function(args) {
var $el = args.$el,
$comparee = args.$comparee;
if(!$el || !$comparee
|| !$el instanceof jQuery || !$comparee instanceof jQuery
|| !$el.length || !$comparee.length) {
return;
}
var instance = this,
proto = FE.StickyColumn.prototype;
instance.$el = $el;
instance.$comparee = $comparee;
instance.uniqueID = homebrew.generateUniqueID();
$el.addClass(instance.classes.stickyColumn);
FE.watchSize('large', function(isLargeScreen) {
if(isLargeScreen) {
instance.watch();
} else {
instance.rest();
instance.unstick();
instance.updatePosition();
}
});
return instance;
},
determineState : function() {
if(!homebrew.screenSize.large) return 'should-be-unstuck';
var instance = this,
$stickyCol = instance.$el,
$comparee = instance.$comparee,
windowTop = jQuery(window).scrollTop(),
stickyColMarginTop = parseInt($stickyCol.css('margin-top'), 10);
instance.offsetTop = (jQuery('#mainHeader').css('position') === 'fixed') ? /*instance.$els.mainNav.height()*/ 0 : 0;
instance.offsetBottom = parseInt($comparee.find('.column').css('margin-bottom'), 10)*2;
if(!$comparee.is(':visible') || $stickyCol.height() >= $comparee.height()) {
return 'should-be-unstuck';
} else if($stickyCol.hasClass(instance.classes.stickBottom) && $stickyCol.offset().top >= windowTop + instance.offsetTop) {
return 'should-be-stuck';
} else if((windowTop + $stickyCol.height() + stickyColMarginTop + instance.offsetTop) > ($comparee.offset().top + $comparee.height() - instance.offsetBottom)) {
return 'should-be-stuck-to-bottom';
} else if($comparee.offset().top <= windowTop + instance.offsetTop) {
return 'should-be-stuck';
} else {
return 'should-be-unstuck';
}
},
updatePosition : function() {
var instance = this,
$el = instance.$el;
if($el.hasClass(instance.classes.stickBottom) || !$el.hasClass(instance.classes.sticky)) {
$el.css('top', '');
} else {
$el.css('top', jQuery(window).scrollTop() - instance.$comparee.offset().top + instance.offsetTop + 'px');
}
return instance;
},
stick : function() {
var instance = this;
instance.$el
.addClass(instance.classes.sticky)
.removeClass(instance.classes.stickBottom);
return instance;
},
stickToBottom : function() {
var instance = this;
instance.$el
.addClass([
instance.classes.sticky,
instance.classes.stickBottom
].join(' '))
.css('margin-top', '');
return instance;
},
unstick : function() {
var instance = this;
instance.$el
.removeClass([
instance.classes.sticky,
instance.classes.stickBottom
].join(' '))
.css('margin-top', '');
return instance;
},
watch : function() {
var instance = this;
jQuery(window).on([
'scroll.', instance.uniqueID,
' resize.', instance.uniqueID
].join(''), function() {
var state = instance.determineState();
switch(state) {
case 'should-be-stuck' : instance.stick(); break;
case 'should-be-stuck-to-bottom' : instance.stickToBottom(); break;
case 'should-be-unstuck' : instance.unstick(); break;
}
instance.updatePosition();
}).trigger('scroll');
instance.$el.on('mousewheel', function(e) {
if(instance.determineState() !== 'should-be-stuck') return;
var vector;
if(e.deltaY < 0) {
var bottomDiff = jQuery(window).scrollTop() + jQuery(window).height() - jQuery(this).offset().top - jQuery(this).height();
if(bottomDiff >= 0) {
return;
} else if(Math.abs(bottomDiff) < 100) {
vector = bottomDiff;
} else {
vector = -100;
}
} else if(e.deltaY > 0) {
var topDiff = jQuery(window).scrollTop() + instance.offsetTop - jQuery(this).offset().top;
if(topDiff === 0) {
return;
} else if(topDiff < 100) {
vector = topDiff;
} else {
vector = 100;
}
}
e.preventDefault();
instance.$el.css('margin-top', [parseInt(instance.$el.css('margin-top'), 10) + vector, 'px'].join(''));
});
return instance;
},
rest : function() {
jQuery(window).off('.' + this.uniqueID);
return this;
}
});
/*---- Init page ----*/
FE.initPage();
/* Run through any queued callbacks if available. */
if(typeof FE__callbacks === 'object'
&& FE__callbacks instanceof Array
&& FE__callbacks.length) {
while(FE__callbacks.length) {
FE__callbacks.shift()();
}
}
});