Skip to content

Instantly share code, notes, and snippets.

@efann
Last active April 29, 2026 13:58
Show Gist options
  • Select an option

  • Save efann/9898823 to your computer and use it in GitHub Desktop.

Select an option

Save efann/9898823 to your computer and use it in GitHub Desktop.
Basic JavaScript Routines for Drupal
// License: Eclipse Public License - v 2.0 (https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html)
// Updated on April 29, 2026
/*
Special note: DO NOT USE document.write
From https://groups.google.com/g/rw-website-help/c/fNNwtIHnThM?pli=1
Pat Asher reply
document.write() has two henchmen, document.open(), and document.close(). When the HTML document is loading,
the document is "open". When the document has finished loading, the document has "closed".
Using document.write() at this point will erase your entire (closed) HTML document and replace it with a
new (open) document. This means your webpage has erased itself and started writing a new page - from scratch."
Sometimes, when logging into a site: user page appears, then goes blank with just the copyright & year from document.write
*/
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
var Beo =
{
foDialogImage: null,
foDialogImageImg: null,
fnDialogImageTitleBarHeight: 0,
fcImageDialogFadeEffect: 'explode',
//----------------------------------------------------------------------------------------------------
initializeBrowserFixes: function ()
{
// Simple, brilliant solution from
// https://amp.reddit.com/r/drupal/comments/3qq70k/d7_cannot_read_property_msie_of_undefined_error
// Fix Drupal admin bar JavaScript errors that look for this deprecated feature.
// And because jQuery and not $ is used, jQuery Migrate can't fix the issue.
jQuery.browser = {version: 0};
let laBrowsers = ['webkit', 'safari', 'opera', 'msie', 'mozilla'];
for (let i = 0; i < laBrowsers.length; i++)
{
jQuery.browser[laBrowsers[i]] = false;
}
try
{
// From https://stackoverflow.com/questions/17367736/jquery-ui-dialog-missing-close-icon
let loBootstrapButton = jQuery.fn.button.noConflict(); // return $.fn.button to previously assigned value
jQuery.fn.bootstrapBtn = loBootstrapButton; // give $().bootstrapBtn the Bootstrap functionality
}
catch (loErr)
{
}
// For browser console
window.onerror = function (message, url, line)
{
console.log('window.onerror was invoked with message = ' + message + ', url ' + url + ', line = ' + line);
};
},
//----------------------------------------------------------------------------------------------------
getCurrentYear: function ()
{
let loNow = new Date();
let lnYear = loNow.getYear();
return ((lnYear < 1000) ? lnYear + 1900 : lnYear);
},
//----------------------------------------------------------------------------------------------------
writeCurrentYear: function (tcID)
{
let loID = jQuery(tcID);
if (loID.length)
{
loID.text(this.getCurrentYear());
}
else
{
console.log('Beo.writeCurrentYear is unable to find ' + tcID);
}
},
//----------------------------------------------------------------------------------------------------
// http://stackoverflow.com/questions/148901/is-there-a-better-way-to-do-optional-function-parameters-in-javascript
writeCurrentDate: function (tcID)
{
let laMonths = new Array('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
let laDays = new Array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
let lnYear = this.getCurrentYear();
let loNow = new Date();
let lcDay = laDays[loNow.getDay()];
let lcMonth = laMonths[loNow.getMonth()];
let loID = jQuery(tcID);
if (loID.length)
{
loID.text(lcDay + ', ' + lcMonth + ' ' + loNow.getDate() + ', ' + lnYear);
}
else
{
console.log('Beo.writeCurrentDate is unable to find ' + tcID);
}
},
//----------------------------------------------------------------------------------------------------
// Set the cursor for buttons, radio, checkboxes and combo boxes.
standardizeControls: function ()
{
jQuery('input:submit, input:button, button, td.views-field.views-field-edit-node a, td.views-field.views-field-delete-node a, a.make-button-from-link, div.date-prev a, div.date-next a, li.calendar-year a, li.calendar-month a, li.calendar-day a').each(function (tnIndex)
{
// If already has been stamped with ui-button, like with the Close Icon for jQuery.dialog.
if (jQuery(this).hasClass('ui-button'))
{
// Equivalent of continue. Return false is the equivalent of break;
return (true);
}
// Used by Bootstrap
if (jQuery(this).hasClass('btn-primary'))
{
// Equivalent of continue. Return false is the equivalent of break;
return (true);
}
// If already has an element with an icon. . . .
if (jQuery(this).find('[class^=\'icon\']').length > 0)
{
// Equivalent of continue. Return false is the equivalent of break;
return (true);
}
jQuery(this).button();
});
jQuery('select').each(function (tnIndex)
{
jQuery(this).css('cursor', 'pointer');
});
jQuery('input:checkbox, input:radio').each(function (tnIndex)
{
jQuery(this).css('cursor', 'pointer');
// Get the label which is in the parent due to the Zen theme.
jQuery(this).parent().css('cursor', 'pointer');
});
},
// -------------------------------------------------------------------------------------------------------------------
// From http://www.mkyong.com/jquery/jquery-watermark-effect-on-text-input/
setupWatermark: function (tcID, tcWatermark)
{
let loInput = jQuery(tcID);
if (loInput.length == 0)
{
return;
}
// initialization: set watermark text and class if empty.
if (loInput.val().trim().length == 0)
{
loInput.val(tcWatermark).addClass('watermark');
}
//if blur and no value inside, set watermark text and class again.
loInput.blur(function ()
{
if (jQuery(this).val().trim().length == 0)
{
jQuery(this).val(tcWatermark).addClass('watermark');
}
});
// if focus and text is watermark, set it to empty and remove the watermark class
loInput.focus(function ()
{
if (jQuery(this).val() == tcWatermark)
{
jQuery(this).val('').removeClass('watermark');
}
});
let loForm = loInput.closest('form');
loForm.submit(function ()
{
if (loInput.val() == tcWatermark)
{
loInput.val('').removeClass('watermark');
}
});
},
//----------------------------------------------------------------------------------------------------
// When an image is clicked, using jQuery dialog, the picture is displayed like
// that of FancyBox.
//
// Unfortunately, at the moment, I don't have a way to determine the title bar height
// before it displays. So I use Chrome Inspect when viewing a dialog box to determine
// the height.
// From https://stackoverflow.com/questions/8998612/how-to-pass-the-value-undefined-to-a-function-with-multiple-parameters
// By the way, to pass undefined as a parameter, use void 0
setupImageDialogBox: function (tnTitleBarHeight, tcFadeEffect, tlCheckClass, tcMainContent, tcDefaultImageClass)
{
// By the way, can't use Boolean here. For example, what if tlCheckClass is
// defined and is false. tlCheckClass would always be reset to true.
tlCheckClass = (typeof tlCheckClass !== 'undefined') ? tlCheckClass : true;
tcMainContent = Boolean(tcMainContent) ? tcMainContent : 'div.main-container';
tcDefaultImageClass = Boolean(tcDefaultImageClass) ? tcDefaultImageClass : 'responsive-image-regular';
Beo.fnDialogImageTitleBarHeight = tnTitleBarHeight;
Beo.fcImageDialogFadeEffect = tcFadeEffect;
Beo.createImageDialog();
// Unfortunately, I can't get the title in the template of field.html.twig.
// to override the image output.
let lcPageTitle = jQuery(document).attr('title').split('|')[0].trim();
jQuery(tcMainContent + ' img').each(function ()
{
let loImage = jQuery(this);
if (!Boolean(loImage.attr('alt')))
{
loImage.attr('alt', lcPageTitle);
}
if (!Boolean(loImage.attr('title')))
{
loImage.attr('title', lcPageTitle);
}
loImage.removeAttr('width');
loImage.removeAttr('height');
loImage.removeAttr('style');
if (tlCheckClass)
{
let lcClasses = loImage.attr('class');
if ((!Boolean(lcClasses)) || (lcClasses.indexOf('responsive-image') < 0))
{
loImage.addClass(tcDefaultImageClass);
}
}
if (!loImage.parent().is('a'))
{
let lcSource = loImage.attr('src');
loImage.wrap('<a class="dialogbox-image" href="' + lcSource + '"></a>');
}
});
jQuery('a.dialogbox-image').click(function (toEvent)
{
toEvent.preventDefault();
Beo.onDialogImageClick(jQuery(this));
});
},
// -------------------------------------------------------------------------------------------------------------------
onDialogImageClick: function (toImageLink)
{
let loDialog = Beo.foDialogImage;
let loDialogImg = Beo.foDialogImageImg;
let loImage = toImageLink.find('img');
let lcSource = loImage.attr('src');
let lcAlt = loImage.attr('alt');
if (!Boolean(lcAlt))
{
lcAlt = 'Image';
}
let lcTitle = loImage.attr('title');
if (!Boolean(lcTitle))
{
lcTitle = lcAlt;
}
loDialogImg.attr('src', lcSource);
loDialogImg.attr('alt', lcAlt);
loDialogImg.attr('title', lcTitle);
let loContainer = loDialogImg.parent();
let lnPaddingWidth = parseFloat(loContainer.css('padding-left')) + parseFloat(loContainer.css('padding-right')) + parseFloat(loContainer.css('margin-left')) + parseFloat(loContainer.css('margin-right'));
let lnPaddingHeight = parseFloat(loContainer.css('padding-top')) + parseFloat(loContainer.css('padding-bottom')) + parseFloat(loContainer.css('margin-top')) + parseFloat(loContainer.css('margin-bottom'));
lnPaddingWidth += parseFloat(loDialog.css('border-top-left-radius')) + parseFloat(loDialog.css('border-top-right-radius'));
lnPaddingHeight += parseFloat(loDialog.css('border-bottom-left-radius')) + parseFloat(loDialog.css('border-top-left-radius'));
// For title bar
lnPaddingHeight += Beo.fnDialogImageTitleBarHeight;
// So that on a mobile or any small screen, the dialog box won't fill the absolute
// entire screen. Leaves a small border.
lnPaddingWidth += 10;
lnPaddingHeight += 20;
// This technique is used to get the actual image size.
let loLoadImage = new Image();
loLoadImage.onload = function ()
{
let lnWidth = this.width * 1.0;
let lnHeight = this.height * 1.0;
// Subtract estimated borders and such.
let lnWidthRatio = (jQuery(window).width() - lnPaddingWidth) / lnWidth;
let lnHeightRatio = (jQuery(window).height() - lnPaddingHeight) / lnHeight;
let lnMinRatio = Math.min(lnHeightRatio, lnWidthRatio);
if (lnMinRatio < 1.0)
{
lnHeight *= lnMinRatio;
lnWidth *= lnMinRatio;
}
loDialogImg.css('width', lnWidth + 'px');
loDialogImg.css('height', lnHeight + 'px');
loDialog.dialog('option', 'title', lcTitle);
loDialog.dialog('open');
};
// Now load the image so the above loLoadImage.onload fires.
loLoadImage.src = lcSource;
},
// -------------------------------------------------------------------------------------------------------------------
createImageDialog: function ()
{
let lcDialog = 'BeoDialogForImage';
let lcDialogImg = 'BeoDialogForImageImg';
jQuery('body').append('<div id="' + lcDialog + '" style="display: none;"><img id="' + lcDialogImg + '" alt="" /></div>');
Beo.foDialogImage = jQuery('#' + lcDialog);
Beo.foDialogImageImg = jQuery('#' + lcDialogImg);
// Unfortunately, I tried querying css('width'): it returns a width in
// pixels. So the below is the actual default: I verified in the
// jquery.ui.css file.
let lcDefaultTitleCSS = '90%';
// Shadowbox advice from http://stackoverflow.com/questions/3448813/jqueryui-how-to-make-a-shadow-around-a-dialog-box
Beo.foDialogImage.dialog({
width: 'auto',
height: 'auto',
modal: true,
autoOpen: false,
draggable: false,
resizable: false,
show: {
effect: 'fade',
duration: 300
},
hide: {
effect: Beo.fcImageDialogFadeEffect,
duration: 400
},
open: function (toEvent, toUI)
{
// This step is needed: if the title is wider than the image
// then there will be empty space to the right of the image.
let loTitleSpan = jQuery(this).parent().find('span.ui-dialog-title');
let lnTitleWidth = loTitleSpan.width();
let lnWidth = parseFloat(jQuery(this).parent().find('img').css('width'));
if ((lnTitleWidth + 50) > lnWidth)
{
let lnNewWidth = lnWidth - 50;
// 120 is really small. . . .
if (lnNewWidth < 120)
{
lnNewWidth = 120;
}
loTitleSpan.css('width', lnNewWidth + 'px');
}
},
beforeClose: function (toEvent, toUI)
{
// Reset to the default so subsequent dialog opens with
// larger images aren't effected.
let loTitleSpan = jQuery(this).parent().find('span.ui-dialog-title');
loTitleSpan.css('width', lcDefaultTitleCSS);
}
});
},
// -------------------------------------------------------------------------------------------------------------------
// Now using Lightbox to display images.
setupLightbox: function (tlCheckClass, tcMainContent, tcDefaultImageClass)
{
// By the way, can't use Boolean here. For example, what if tlCheckClass is
// defined and is false. llCheckClass would always be true.
let llCheckClass = (typeof tlCheckClass !== 'undefined') ? tlCheckClass : true;
let lcMainContent = Boolean(tcMainContent) ? tcMainContent : 'div.main-container';
let lcImageClass = Boolean(tcDefaultImageClass) ? tcDefaultImageClass : 'responsive-image-large';
// Unfortunately, I can't get the title in the template of field.html.twig.
// to override the image output.
let lcPageTitle = jQuery(document).attr('title').split('|')[0].trim();
jQuery(lcMainContent + ' img').each(function ()
{
let loImage = jQuery(this);
let lcAlt = loImage.attr('alt');
if (!Boolean(lcAlt))
{
lcAlt = lcPageTitle;
loImage.attr('alt', lcAlt);
}
let lcTitle = loImage.attr('title');
if (!Boolean(lcTitle))
{
lcTitle = lcPageTitle;
loImage.attr('title', lcTitle);
}
loImage.removeAttr('width');
loImage.removeAttr('height');
loImage.removeAttr('style');
if (llCheckClass)
{
let lcClasses = loImage.attr('class');
if ((!Boolean(lcClasses)) || (lcClasses.indexOf('responsive-image') < 0))
{
loImage.addClass(lcImageClass);
}
}
if (!loImage.parent().is('a'))
{
let lcSource = loImage.attr('src');
// From https://stackoverflow.com/questions/610406/javascript-equivalent-to-printf-string-format
loImage.wrap(`<a class='dialogbox-image' href='${lcSource}' data-lightbox='${lcTitle}' data-alt='${lcAlt}' data-title='${lcTitle}'></a>`);
}
});
},
// -------------------------------------------------------------------------------------------------------------------
// From https://drupal.org/node/249933
disableFormReturn: function ()
{
jQuery('input').keypress(function (toEvent)
{
return ((toEvent.keyCode == 13) ? false : true);
});
},
// -------------------------------------------------------------------------------------------------------------------
isWindowInIFrame: function ()
{
return (window.location != window.parent.location);
},
//----------------------------------------------------------------------------------------------------
adjustTabsAlignment: function (toTabs)
{
let lnWidth = jQuery(window).width();
if (lnWidth >= 768)
{
if (toTabs.tabs().hasClass('ui-tabs-vertical ui-helper-clearfix'))
{
toTabs.tabs().removeClass('ui-tabs-vertical ui-helper-clearfix');
toTabs.find('li').addClass('ui-corner-top').removeClass('ui-corner-left');
}
}
else
{
if (!toTabs.tabs().hasClass('ui-tabs-vertical ui-helper-clearfix'))
{
toTabs.tabs().addClass('ui-tabs-vertical ui-helper-clearfix');
toTabs.find('li').removeClass('ui-corner-top').addClass('ui-corner-left');
}
}
},
//----------------------------------------------------------------------------------------------------
updateLinksWithExternalURLs: function (tcSelect)
{
jQuery(tcSelect).find('a').each(function ()
{
let loThis = jQuery(this);
let lcHref = loThis.attr('href');
let lcHostname = window.location.hostname;
if (Boolean(lcHref) && (!lcHref.startsWith('/')) && (!lcHref.startsWith('?')) && (!lcHref.startsWith('#')) && (!lcHref.includes(lcHostname)))
{
loThis.attr('target', '_blank');
}
});
jQuery(tcSelect).find('form').each(function ()
{
let loThis = jQuery(this);
let lcAction = loThis.attr('action');
let lcHostname = window.location.hostname;
if (Boolean(lcAction) && (!lcAction.startsWith('/')) && (!lcHref.startsWith('?')) && (!lcHref.startsWith('#')) && (!lcAction.includes(lcHostname)))
{
loThis.attr('target', '_blank');
}
});
}
//----------------------------------------------------------------------------------------------------
};
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
/*----------------------------------------------------------------------------------------*/
/*
Updated on November 21, 2019
*/
/*----------------------------------------------------------------------------------------*/
/*
Watermarks
*/
textarea.watermark,
input.watermark
{
color: #999999;
}
/*----------------------------------------------------------------------------------------*/
/*
Menu items.
*/
.navbar-toggle
{
background-color: #62453D;
position: fixed;
top: 10px;
right: 15px;
}
/*
Brilliant. . . .
From https://julienmelissas.com/animated-x-icon-for-the-bootstrap-navbar-toggle/
Make sure that you add the classes to system/page.html.twig
*/
.navbar-toggle .icon-bar
{
width: 22px;
transition: all 0.2s;
}
.navbar-toggle .top-bar
{
-webkit-transform: translateX(3px) rotate(45deg);
-moz-transform: translateX(3px) rotate(45deg);
-o-transform: translateX(3px) rotate(45deg);
transform: translateX(3px) rotate(45deg);
-webkit-transform-origin: 10% 10%;
-moz-transform-origin: 10% 10%;
-o-transform-origin: 10% 10%;
transform-origin: 10% 10%;
}
.navbar-toggle .middle-bar
{
opacity: 0;
}
.navbar-toggle .bottom-bar
{
-webkit-transform: translateX(3px) rotate(-45deg);
-moz-transform: translateX(3px) rotate(-45deg);
-o-transform: rotate(-45deg);
transform: translateX(3px) rotate(-45deg);
-webkit-transform-origin: 10% 90%;
-moz-transform-origin: 10% 90%;
-o-transform-origin: 10% 90%;
transform-origin: 10% 90%;
}
.navbar-toggle.collapsed .top-bar
{
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
.navbar-toggle.collapsed .middle-bar
{
opacity: 1;
}
.navbar-toggle.collapsed .bottom-bar
{
-webkit-transform: rotate(0);
-moz-transform: rotate(0);
-o-transform: rotate(0);
transform: rotate(0);
}
/*
Bootstrap uses min-width: 768px settings,
so max-width: 767px works in concert
*/
@media (max-width: 767px)
{
div.navbar-collapse
{
position: fixed;
width: 150px;
top: 53px;
right: 44px;
padding: 0 10px;
overflow: hidden;
border: 1px solid #333333;
background-color: #FBFBF8;
}
div.navbar-collapse ul li
{
float: none;
width: 100%;
}
}
.navbar-inverse .navbar-nav > li > a
{
color: #62453D;
font-weight: normal;
font-size: 1.25em;
}
.navbar-inverse .navbar-nav > li > a:hover,
.navbar-inverse .navbar-nav > li > a:focus
{
color: #0063A0;
}
.navbar-inverse .navbar-nav > .active > a,
.navbar-inverse .navbar-nav > .active > a:hover,
.navbar-inverse .navbar-nav > .active > a:focus
{
color: #62453D;
background-color: lightgray;
}
/*
From https://bootstrapstudio.io/forums/topic/center-navbar/
Centering the navbar.
*/
@media (min-width: 768px)
{
.navbar .navbar-nav
{
display: inline-block;
float: none;
vertical-align: top;
}
.navbar .navbar-collapse
{
text-align: center;
}
}
.expanded.dropdown .caret
{
-webkit-transform: rotate(0deg);
-moz-transform: rotate(0deg);
-o-transform: rotate(0deg);
transform: rotate(0deg);
-moz-transition: all 0.2s;
-webkit-transition: all 0.2s;
-o-transition: all 0.2s;
transition: all 0.2s;
}
.expanded.dropdown.open .caret
{
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
-moz-transition: all 0.2s;
-webkit-transition: all 0.2s;
-o-transition: all 0.2s;
transition: all 0.2s;
}
/*----------------------------------------------------------------------------------------*/
/*
From https://stackoverflow.com/questions/20751316/how-to-make-div-to-match-image-height-with-css
Otherwise, the <a></a> will not stretch to fit the image.
*/
/*
This way, the image doesn't briefly appear large and then resize.
I'm also assuming that I will be using the Beo.setupImageDialogBox
for all images.
*/
img
{
display: none;
}
.ui-dialog img
{
display: block;
padding: 0;
}
/* ------ */
.dialogbox-image
{
position: relative;
overflow: hidden;
display: inline-block;
text-align: center;
}
a.dialogbox-image img
{
opacity: 1.0;
-moz-transition: opacity 0.25s ease;
-webkit-transition: opacity 0.25s ease;
transition: opacity 0.25s ease;
}
a.dialogbox-image img:hover
{
opacity: 0.75;
-moz-transition: opacity 0.25s ease;
-webkit-transition: opacity 0.25s ease;
transition: opacity 0.25s ease;
}
/*----------------------------------------------------------------------------------------*/
/*
From https://stackoverflow.com/questions/9189810/css-display-inline-vs-inline-block
I'm modifying .img-responsive from Bootstrap. I need to use inline-block.
*/
.responsive-image-small,
.responsive-image-regular,
.responsive-image-large
{
display: inline-block;
max-width: 100%;
height: auto;
}
.responsive-image-small
{
max-height: 240px;
}
.responsive-image-regular
{
max-height: 350px;
}
.responsive-image-large
{
max-height: 480px;
}
/*
Bootstrap uses min-width: 768px settings,
so max-width: 767px works in concert
*/
@media (max-width: 767px)
{
.responsive-image-small
{
max-height: 175px;
}
.responsive-image-regular
{
max-height: 285px;
}
.responsive-image-large
{
max-height: 415px;
}
}
/*----------------------------------------------------------------------------------------*/
/*
jQuery UI
*/
.ui-dialog
{
z-index: 99999;
}
.ui-dialog .ui-dialog-titlebar
{
padding: 0.1em 1.0em;
}
.ui-dialog .ui-dialog-content
{
padding: 0;
}
.ui-corner-all
{
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
.ui-tabs-vertical
{
width: 100%;
}
.ui-tabs-vertical .ui-tabs-nav .ui-tabs-anchor
{
width: 100%;
}
.ui-tabs-vertical .ui-tabs-nav
{
padding: .2em .1em .2em .2em;
float: left;
width: 12em;
}
.ui-tabs-vertical .ui-tabs-nav li
{
clear: left;
width: 100%;
border-bottom-width: 1px !important;
border-right-width: 0 !important;
margin: 0 -1px .2em 0;
}
.ui-tabs-vertical .ui-tabs-nav li a
{
display: block;
}
.ui-tabs-vertical .ui-tabs-nav li.ui-tabs-active
{
padding-bottom: 0;
padding-right: 0.1em;
border-right-width: 1px;
}
.ui-tabs-vertical .ui-tabs-panel
{
padding: 1.0em;
float: left;
width: 100%;
/*
From https://stackoverflow.com/questions/36418352/css-word-wrap-break-word-wont-work
Now, all the text wraps, even the long URLs, and the text no longer overflows the sides.
*/
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-all;
word-break: break-word;
hyphens: auto;
}
/*----------------------------------------------------------------------------------------*/
// Updated on July 19, 2016
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
var Navicon =
{
QUEUE_SCROLL: "MenuScroll",
// -------------------------------------------------------------------------------------------------------------------
setupNavicon: function (tcNavicon, tcMenu, tcWithinMenuList, tfnOnClick)
{
if (jQuery(tcNavicon).length == 0)
{
alert(tcNavicon + " does not exist for setupNavicon.");
return;
}
if (jQuery(tcMenu).length == 0)
{
alert(tcMenu + " does not exist for setupNavicon.");
return;
}
if (jQuery(tcMenu + " " + tcWithinMenuList).length == 0)
{
alert(tcMenu + " " + tcWithinMenuList + " does not exist for setupNavicon.");
return;
}
// Make the menu disappear if window resizing.
jQuery(window).resize(function ()
{
Navicon.toggleNaviconMenu(tcNavicon, tcMenu, true);
});
// Navicon click action.
jQuery(tcNavicon).click(function (toEvent)
{
Navicon.toggleNaviconMenu(tcNavicon, tcMenu, false);
});
// Menu item click action
// Apparently this will include clicking on the <a href> link element.
jQuery(tcMenu + " " + tcWithinMenuList).each(function ()
{
var lcHref = jQuery(this).attr('href');
if (typeof lcHref === "undefined")
{
lcHref = jQuery(this).find('a').attr('href');
}
jQuery(this).click(function (toEvent)
{
toEvent.preventDefault();
Navicon.toggleNaviconMenu(tcNavicon, tcMenu, true);
//it is a good idea to check if the parameter is actually not null
//and that it is a function
if (tfnOnClick && (typeof tfnOnClick == "function"))
{
tfnOnClick(jQuery(this));
}
else
{
Navicon.scrollToAnchor(lcHref);
}
});
});
},
// -------------------------------------------------------------------------------------------------------------------
toggleNaviconMenu: function (tcNavicon, tcMenu, tlForceClose)
{
var loNavicon = jQuery(tcNavicon);
// Should be named something like #navicon-wrapper.
var loWrapper = loNavicon.parent();
var loWrapperParent = loWrapper.parent();
var laLines = [];
loNavicon.find("div.horizontal-line").each(function ()
{
var loLine = jQuery(this);
laLines.push(loLine);
if (!loLine.hasClass('smoothRotateIcon'))
{
loLine.addClass('smoothRotateIcon')
}
});
var loMenu = jQuery(tcMenu);
if (loMenu.is(":visible") || (tlForceClose))
{
loMenu.hide('scale', {percent: 0}, 500);
loWrapper.animate({backgroundColor: "transparent"}, 500);
laLines[1].show();
laLines[0].removeClass('xOn').removeClass('xRotateClockwise');
laLines[2].removeClass('xOn').removeClass('xRotateCounterClockwise');
}
else
{
loMenu.css('top', (loWrapper.position().top + parseInt(loWrapperParent.css("top")) + loWrapper.height()) + 'px');
if (loWrapperParent.css("right") != "auto")
{
loMenu.css('left', (loWrapperParent.position().left) + 'px');
}
else if (loWrapperParent.css("left") != "auto")
{
loMenu.css('left', (parseInt(loWrapperParent.css("left"))) + 'px');
}
else
{
alert("Unable to determine the left side for the menu.\n\n\"" + loWrapperParent.attr('id') + "\" should have either 'left' or 'right' set in the CSS.");
}
laLines[1].hide();
laLines[0].addClass('xOn').addClass('xRotateClockwise');
laLines[2].addClass('xOn').addClass('xRotateCounterClockwise');
loMenu.show('scale', {percent: 100}, 500);
var lcBackgroundColor = loMenu.css("backgroundColor");
loWrapper.animate({backgroundColor: lcBackgroundColor}, 500);
}
},
// -------------------------------------------------------------------------------------------------------------------
// For those times that the front page is launched from a secondary page with an anchor link.
// Something like, /#contact-us.
checkForAnchorLink: function ()
{
if (window.location.hash != '')
{
Navicon.scrollToAnchor(window.location.hash);
}
},
// -------------------------------------------------------------------------------------------------------------------
scrollToAnchor: function (tcHref)
{
// If not on a Drupal front page. . . .
if (jQuery("body.front").length == 0)
{
window.location.href = tcHref;
return;
}
// Get rid of the # character.
// By the way, IE 8 and below doesn't like replace('#', "") and complains
// about illegal character. And IE 8 doesn't have a trim function.
// var lcHref = jQuery.trim(tcHref.replace(/#/g, ""));
var lcSearch = tcHref;
var lnPos = tcHref.indexOf("\#");
if (lnPos == -1)
{
window.location.href = tcHref;
return;
}
lcSearch = tcHref.substr(lnPos);
// If the href has been changed 'cause the menu is on a page other than the front,
// then the anchor reference will be invalid.
if (jQuery(lcSearch).length > 0)
{
// And to work in FireFox you need both body and html.
var lcTop = jQuery(lcSearch).position().top + "px";
// Anything lower than 1000 is just a little too fast, sometimes appearing
// to be immediate.
jQuery("body, html").animate({'scrollTop': lcTop}, {'duration': 1000, 'queue': Navicon.QUEUE_SCROLL});
jQuery("body, html").dequeue(Navicon.QUEUE_SCROLL);
}
}
//----------------------------------------------------------------------------------------------------
}
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment