mirror of
https://github.com/moexe/FFFGateway-Monitoring.git
synced 2024-11-25 07:03:41 +01:00
1001 lines
33 KiB
JavaScript
1001 lines
33 KiB
JavaScript
|
|
||
|
/**
|
||
|
* Responsive Menu
|
||
|
* Version: 0.2.1
|
||
|
* URL: private
|
||
|
* Description: A drop-down responsive Menu for responsive layouts
|
||
|
* Requires: jQuery
|
||
|
* Optional: Modernizr
|
||
|
* Author: jbowyers
|
||
|
* Copyright: 2014-2015 jbowyers
|
||
|
* License: This file is part of Responsive Menu.
|
||
|
* Responsive Menu is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* Responsive Menu is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see http://www.gnu.org/licenses/
|
||
|
*/
|
||
|
|
||
|
;(function( $, window, document, Math, undefined ) {
|
||
|
|
||
|
'use strict';
|
||
|
var pluginName = 'rMenu';
|
||
|
|
||
|
/**
|
||
|
* The plugin
|
||
|
* @param {object} el - The menu container typically a nav element
|
||
|
* @param {object} options - plugin options object litteral
|
||
|
* @returns {Plugin}
|
||
|
* @constructor
|
||
|
*/
|
||
|
var Plugin = function( el, options ) {
|
||
|
|
||
|
// Clone this object
|
||
|
var o = this;
|
||
|
|
||
|
/**
|
||
|
* Initialize option defaults and set options =============================
|
||
|
* @type {{minWidth: string, toggleSel: string, menuSel: string, menuItemsSel: string, transitionSpeed: number, animateBool: string, accelerateBool: string}}
|
||
|
*/
|
||
|
o.optionsInit = {
|
||
|
|
||
|
/**
|
||
|
* Minimum width for expanded layout in pixels - String Should match media query in css file
|
||
|
* Must be in pixels and include px units if not using Modernizr.
|
||
|
* @default '769px'
|
||
|
*/
|
||
|
minWidth: '769px',
|
||
|
|
||
|
/**
|
||
|
* The opening and closing speed of the menus in milliseconds
|
||
|
* @default 400
|
||
|
*/
|
||
|
transitionSpeed: 400,
|
||
|
|
||
|
/**
|
||
|
* The jQuery easing function - used with jQuery transitions
|
||
|
* @default 'swing'
|
||
|
* @options 'swing', 'linear'
|
||
|
*/
|
||
|
jqueryEasing: 'swing',
|
||
|
|
||
|
/**
|
||
|
* The CSS3 transitions easing function - used with CSS3 transitions
|
||
|
* @default 'ease'
|
||
|
*/
|
||
|
css3Easing: 'ease',
|
||
|
|
||
|
/**
|
||
|
* Use button as Toggle Link - instead of text
|
||
|
* @default true
|
||
|
*/
|
||
|
toggleBtnBool: true,
|
||
|
|
||
|
/**
|
||
|
* The Toggle Link selector
|
||
|
* @default '.rm-toggle'
|
||
|
*/
|
||
|
toggleSel: '.rm-toggle',
|
||
|
|
||
|
/**
|
||
|
* The menu/sub-menu selector
|
||
|
* @default 'ul'
|
||
|
*/
|
||
|
menuSel: 'ul',
|
||
|
|
||
|
/**
|
||
|
* The menu items selector
|
||
|
* @default 'li'
|
||
|
*/
|
||
|
menuItemsSel: 'li',
|
||
|
|
||
|
/**
|
||
|
* Use CSS3 animation/transitions Boolean
|
||
|
* @default true
|
||
|
* Do not use animation/transitions: false
|
||
|
*/
|
||
|
animateBool: true,
|
||
|
|
||
|
/**
|
||
|
* Force GPU Acceleration Boolean
|
||
|
* @default false
|
||
|
* Do not force: false
|
||
|
*/
|
||
|
accelerateBool: false,
|
||
|
|
||
|
/**
|
||
|
* the setup complete callback function
|
||
|
* @default 'false'
|
||
|
*/
|
||
|
setupCallback: false,
|
||
|
|
||
|
/**
|
||
|
* the tabindex start value - integer
|
||
|
* @default 1
|
||
|
*/
|
||
|
tabindexStart: 1,
|
||
|
|
||
|
/**
|
||
|
* Use development mode - outputs information to console
|
||
|
* @default false
|
||
|
*/
|
||
|
developmentMode: false
|
||
|
};
|
||
|
o.options = $.extend( {}, o.optionsInit, options );
|
||
|
|
||
|
// Define public objects and vars =========================================
|
||
|
|
||
|
// Toggle Link object
|
||
|
o.tButton = $( o.options.toggleSel );
|
||
|
|
||
|
// The class applied to the toggle Link element to make it a button
|
||
|
o.tButtonClass = 'rm-button';
|
||
|
|
||
|
// The class applied to the toggle Link element when it is visible
|
||
|
o.tButtonShowClass = 'rm-show';
|
||
|
|
||
|
// The class applied to the toggle Link element when it is visible
|
||
|
o.tButtonActiveClass = 'rm-active';
|
||
|
|
||
|
// Nav element object - contains the menus
|
||
|
o.el = $( el );
|
||
|
|
||
|
// The class the plugin adds to the nav element
|
||
|
o.navElementClass = 'rm-nav';
|
||
|
|
||
|
// Container object - contains everything - the Nav element and Toggle Link
|
||
|
o.container = o.el.parent();
|
||
|
|
||
|
// The class the plugin adds to the container of the nav element
|
||
|
o.containerClass = 'rm-container';
|
||
|
|
||
|
// The class applied to container element to trigger expanded layout
|
||
|
o.expandedClass = 'rm-layout-expanded';
|
||
|
|
||
|
// The class applied to container element to trigger contracted layout
|
||
|
o.contractedClass = 'rm-layout-contracted';
|
||
|
|
||
|
// The class that is removed from the toggle and nav element when JS is supported
|
||
|
o.noJSClass = 'rm-nojs';
|
||
|
|
||
|
// All menu elements
|
||
|
o.menus = o.el.find( o.options.menuSel );
|
||
|
|
||
|
// The class applied to all menu elements
|
||
|
o.menuClass = 'rm-menu';
|
||
|
|
||
|
// Top level menu object - contains the menus
|
||
|
o.topMenu = o.el.children( o.options.menuSel );
|
||
|
|
||
|
// The class the plugin adds to the top menu element
|
||
|
o.topMenuClass = 'rm-top-menu';
|
||
|
|
||
|
// The class applied to menu/sub-menu element when menu is expanded
|
||
|
o.menuExpandedClass = 'rm-menu-expanded';
|
||
|
|
||
|
// The class applied to menu/sub-menu element when menu is hidden
|
||
|
o.menuHiddenClass = 'accessibly-hidden';
|
||
|
|
||
|
// The class the plugin adds to the menu elements when calculating height
|
||
|
o.menuCalcClass = 'rm-calculate';
|
||
|
|
||
|
// The class applied to all menu items
|
||
|
o.menuItemClass = 'rm-menu-item';
|
||
|
|
||
|
// The focused parent element
|
||
|
o.itemFocused = false;
|
||
|
|
||
|
// The class applied to menu items that contain a sub-menu
|
||
|
o.parentClass = 'rm-parent';
|
||
|
|
||
|
// The class applied to a menu item when its menu is expanded
|
||
|
o.itemHoverClass = 'rm-hover';
|
||
|
|
||
|
// The class applied to the first menu item
|
||
|
o.itemFirst = 'rm-first';
|
||
|
|
||
|
// The class applied to the last menu item
|
||
|
o.itemLast = 'rm-last';
|
||
|
|
||
|
// The class applied to the second to last menu item
|
||
|
o.item2ndLast = 'rm-2nd-last';
|
||
|
|
||
|
// The CSS3 animate class variable
|
||
|
o.animateClass = 'rm-css-animate';
|
||
|
|
||
|
// The CSS3 animate Boolean
|
||
|
o.animateBool = o.options.animateBool;
|
||
|
|
||
|
// The GPU accelerate class variable
|
||
|
o.accelerateClass = 'rm-accelerate';
|
||
|
|
||
|
// The GPU accelerate Boolean
|
||
|
o.accelerateBool = o.options.accelerateBool;
|
||
|
|
||
|
// The touchmove Boolean - did a touchmove event just occur
|
||
|
o.touchMoveBool = false;
|
||
|
|
||
|
// Resize and Pause hover event timer function
|
||
|
o.timer = false;
|
||
|
|
||
|
// The window width - used to verify a window width change
|
||
|
o.windowWidth = $( window ).width();
|
||
|
|
||
|
|
||
|
/**
|
||
|
* Initiate plugin =========================================
|
||
|
* @returns {Plugin}
|
||
|
*/
|
||
|
o.init = function() { // Should only be called once
|
||
|
|
||
|
// Set up the plugin
|
||
|
o.setup();
|
||
|
|
||
|
// Window event handlers
|
||
|
$( window ).on({
|
||
|
|
||
|
// Reset on screen resize
|
||
|
'resize': function() {
|
||
|
|
||
|
// Test if width has resized - as opposed to height
|
||
|
if ($( window ).width() !== o.windowWidth) {
|
||
|
|
||
|
// Update the window width
|
||
|
o.windowWidth = $( window ).width();
|
||
|
|
||
|
// Adjust layout
|
||
|
clearTimeout( o.timer );
|
||
|
o.timer = setTimeout( o.adjust, 500 );
|
||
|
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Run setupCallback function
|
||
|
if ( typeof( o.options.setupCallback ) === "function" ) {
|
||
|
o.options.setupCallback();
|
||
|
}
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Setup plugin ============================================================
|
||
|
* @returns {Plugin}
|
||
|
*/
|
||
|
o.setup = function() { // Can be called again to reset plugin
|
||
|
|
||
|
// Add the container class to the nav element's parent element
|
||
|
o.container.addClass( o.containerClass );
|
||
|
|
||
|
// add rm-button class if using button
|
||
|
if ( o.options.toggleBtnBool ) {
|
||
|
o.tButton.addClass( o.tButtonClass );
|
||
|
} else {
|
||
|
o.tButton.removeClass( o.tButtonClass );
|
||
|
}
|
||
|
|
||
|
// Remove o.noJSClass class and add click event to Toggle Link
|
||
|
o.tButton
|
||
|
.removeClass( o.noJSClass )
|
||
|
.off( 'mousedown.rm focusin.rm click.rm' )
|
||
|
|
||
|
// Use mousedown and focus to trigger toggle
|
||
|
.on( 'mousedown.rm focusin.rm', tButtonFocus )
|
||
|
|
||
|
// Disable click events
|
||
|
.on( 'click.rm', tButtonClick )
|
||
|
|
||
|
.attr( 'tabindex', 0 )
|
||
|
;
|
||
|
|
||
|
// Add menu class and make submenus accessibly hidden
|
||
|
o.menus
|
||
|
.addClass( o.menuClass )
|
||
|
.attr( 'aria-hidden', 'false' )
|
||
|
.hide();
|
||
|
|
||
|
// Add top menu class
|
||
|
o.topMenu.addClass( o.topMenuClass );
|
||
|
|
||
|
// Adjust o.animateBool
|
||
|
if ( o.animateBool ) { // using CSS3 transitions
|
||
|
|
||
|
// Check if transitions and acceleration are supported
|
||
|
if ( typeof Modernizr !== 'undefined' ) { // Test with Modernizr
|
||
|
if ( !Modernizr.csstransitions ) {
|
||
|
o.animateBool = false;
|
||
|
o.accelerateBool = false;
|
||
|
} else if ( !Modernizr.csstransforms3d ) {
|
||
|
o.accelerateBool = false;
|
||
|
}
|
||
|
} else if ( !transitionsSupported() ) {
|
||
|
o.animateBool = false;
|
||
|
o.accelerateBool = false;
|
||
|
} else if ( !transform3DSupported() ) {
|
||
|
o.accelerateBool = false;
|
||
|
}
|
||
|
} else {
|
||
|
o.accelerateBool = false;
|
||
|
}
|
||
|
|
||
|
// Add animate and accelerate classes if CSS3 animation
|
||
|
if ( o.animateBool ) {
|
||
|
o.menus.addClass( o.animateClass );
|
||
|
if ( o.accelerateBool ) {
|
||
|
o.menus.addClass( o.accelerateClass );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Add and remove classes and click events
|
||
|
o.el
|
||
|
.removeClass( o.noJSClass )
|
||
|
.addClass( o.navElementClass )
|
||
|
.off( 'focusin.rm focusout.rm click.rm touchend.rm touchmove.rm' )
|
||
|
|
||
|
// Use focus to trigger menu item focus/hover behaviour
|
||
|
.on( 'focusin.rm', o.options.menuItemsSel, itemFocus )
|
||
|
|
||
|
// De-focus menu on focus out
|
||
|
.on( 'focusout.rm', o.topMenu, menuBlur )
|
||
|
|
||
|
// Use click and touchend to trigger click behaviour
|
||
|
.on( 'click.rm touchend.rm', o.options.menuItemsSel, itemClick )
|
||
|
|
||
|
// Set touchMoveBool to true on touchmove event
|
||
|
.on( 'touchmove.rm', o.options.menuItemsSel, touchMove )
|
||
|
.find( o.options.menuItemsSel )
|
||
|
.each( function(i) {
|
||
|
var $el = $( this );
|
||
|
$el
|
||
|
.addClass( o.menuItemClass)
|
||
|
.children( 'a' ).attr( 'tabindex', 0 )
|
||
|
;
|
||
|
if ( $el.is( ':first-child') ) {
|
||
|
$el.addClass( o.itemFirst );
|
||
|
}
|
||
|
if ( $el.is( ':last-child') ) {
|
||
|
$el.addClass( o.itemLast )
|
||
|
.prev().addClass( o.item2ndLast );
|
||
|
}
|
||
|
})
|
||
|
.addBack()
|
||
|
.removeClass( o.parentClass )
|
||
|
.has( o.options.menuSel )
|
||
|
.addClass( o.parentClass )
|
||
|
;
|
||
|
|
||
|
// Apply initial layout and adjustments
|
||
|
o.adjust();
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Adjust plugin ============================================================
|
||
|
* @param {String} minWidth - the min-width value (including units)
|
||
|
* minWidth must be in pixels if not using Modernizr. Should match media query in css file
|
||
|
*/
|
||
|
o.adjust = function( minWidth ) {
|
||
|
|
||
|
// Get the breakpoint minimum width
|
||
|
minWidth = typeof minWidth !== 'undefined' ? minWidth : o.options.minWidth;
|
||
|
|
||
|
// Check browser width - set menu layout
|
||
|
if ( typeof Modernizr !== 'undefined' && Modernizr.mq('only all') ) { // MQs supported - Test with Modernizr
|
||
|
if ( o.options.developmentMode ) {
|
||
|
console.log( 'Modernizr: MQ supported' );
|
||
|
}
|
||
|
if ( !Modernizr.mq( '( min-width: ' + minWidth + ' )' ) ) {
|
||
|
o.layoutContracted();
|
||
|
} else {
|
||
|
o.layoutExpanded();
|
||
|
}
|
||
|
|
||
|
} else { // Unable to detect MQ support - Test width using outerWidth - less reliable
|
||
|
if ( o.options.developmentMode ) {
|
||
|
console.log( 'unable to detect MQ support' );
|
||
|
}
|
||
|
if ( $( window ).outerWidth() < parseInt( minWidth ) ) {
|
||
|
o.layoutContracted();
|
||
|
} else {
|
||
|
o.layoutExpanded();
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// External Helper Functions ===============================================
|
||
|
|
||
|
/**
|
||
|
* Contracted layout
|
||
|
* @returns {Plugin}
|
||
|
*/
|
||
|
o.layoutContracted = function() {
|
||
|
|
||
|
if ( !o.container.hasClass( o.contractedClass ) ) { // not contracted
|
||
|
|
||
|
// Contract any expanded siblings and their children
|
||
|
menuBlur( { 'type': 'layoutContracted' } );
|
||
|
|
||
|
// Apply Contracted class
|
||
|
o.container
|
||
|
.removeClass( o.expandedClass )
|
||
|
.addClass( o.contractedClass )
|
||
|
.find( '.' + o.itemHoverClass ).removeClass( o.itemHoverClass );
|
||
|
|
||
|
if ( o.animateBool ) { // using CSS3 transitions
|
||
|
|
||
|
// Recalculate menu heights
|
||
|
o.calculateHeights();
|
||
|
}
|
||
|
|
||
|
// Remove hover events
|
||
|
o.el.off( 'mouseenter.le mouseleave.le' );
|
||
|
|
||
|
// Show Toggle Link and setup topMenu
|
||
|
o.tButton.addClass( o.tButtonShowClass );
|
||
|
if ( !o.tButton.hasClass( o.tButtonActiveClass ) ) { // topMenu not active
|
||
|
|
||
|
// Hide topMenu
|
||
|
o.topMenu
|
||
|
.addClass( o.menuHiddenClass )
|
||
|
.show()
|
||
|
.removeClass( o.menuExpandedClass )
|
||
|
;
|
||
|
} else { // topMenu is active
|
||
|
|
||
|
// Show topMenu
|
||
|
o.topMenu
|
||
|
.removeClass( o.menuHiddenClass )
|
||
|
.show()
|
||
|
.addClass( o.menuExpandedClass );
|
||
|
if ( o.animateBool ) { // Using CSS3 transitions
|
||
|
o.topMenu
|
||
|
.css({
|
||
|
'max-height': 'none'
|
||
|
})
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( o.options.developmentMode ) {
|
||
|
console.log( 'responsive-menu: contracted layout' );
|
||
|
}
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Expanded layout
|
||
|
* @returns {Plugin}
|
||
|
*/
|
||
|
o.layoutExpanded = function() {
|
||
|
|
||
|
if ( !o.container.hasClass( o.expandedClass ) ) { // not expanded
|
||
|
|
||
|
// Contract any expanded siblings and their children
|
||
|
menuBlur( { 'type': 'layoutExpanded' } );
|
||
|
|
||
|
// Apply expanded class to container
|
||
|
o.container
|
||
|
.removeClass( o.contractedClass )
|
||
|
.addClass( o.expandedClass )
|
||
|
.find( '.' + o.itemHoverClass ).removeClass( o.itemHoverClass );
|
||
|
|
||
|
if ( o.animateBool ) { // using CSS3 transitions
|
||
|
|
||
|
// Recalculate menu heights
|
||
|
o.calculateHeights();
|
||
|
}
|
||
|
|
||
|
// Re-apply mouse events
|
||
|
o.el.off( 'mouseenter.le mouseleave.le' )
|
||
|
|
||
|
// Add mouseenter to all menu items to trigger focus
|
||
|
.on( 'mouseenter.le', o.options.menuItemsSel, itemFocus )
|
||
|
|
||
|
// Add mouseleave to trigger focus when re-entering parent of expanded menu
|
||
|
.on( 'mouseleave.le', o.options.menuItemsSel, itemLeave )
|
||
|
|
||
|
// Add mouseleave on topmenu to trigger menu blur
|
||
|
.on( 'mouseleave.le', o.topMenu, menuBlur )
|
||
|
;
|
||
|
|
||
|
// Show Menu - Hide Toggle Link
|
||
|
o.tButton.removeClass( o.tButtonShowClass );
|
||
|
o.topMenu.removeClass( o.menuHiddenClass )
|
||
|
.show()
|
||
|
.addClass( o.menuExpandedClass );
|
||
|
if ( o.animateBool ) { // Using CSS3 transitions
|
||
|
o.topMenu
|
||
|
.css({
|
||
|
'max-height': 'none',
|
||
|
'overflow': 'visible'
|
||
|
})
|
||
|
;
|
||
|
}
|
||
|
}
|
||
|
if ( o.options.developmentMode ) {
|
||
|
console.log( 'responsive-menu: expanded layout' );
|
||
|
}
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Calculate the heights of each submenu and store in data object, reset styles
|
||
|
* Used when CSS3 transitions are enabled
|
||
|
* @returns {Plugin}
|
||
|
*/
|
||
|
o.calculateHeights = function() {
|
||
|
|
||
|
// Unstyle menus to original state to measure heights and then reapply styles
|
||
|
o.menus
|
||
|
.addClass( o.menuCalcClass )
|
||
|
.removeClass( o.menuExpandedClass )
|
||
|
.attr( 'style', '' )
|
||
|
.show( 0 );
|
||
|
|
||
|
// Reselect to force application of styles
|
||
|
o.menus.each( function () {
|
||
|
var $el = $( this );
|
||
|
$el
|
||
|
.data( 'height', $el.height() )
|
||
|
;
|
||
|
})
|
||
|
.css( {
|
||
|
'max-height': '0'
|
||
|
})
|
||
|
.removeClass( o.menuCalcClass )
|
||
|
;
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Toggle visibility of entire menu
|
||
|
* @param {Object} el - The toggle Link element
|
||
|
*/
|
||
|
o.toggleMenu = function( el ) {
|
||
|
|
||
|
// Contract all sub-menus
|
||
|
contract( o.topMenu );
|
||
|
|
||
|
if ( !o.topMenu.hasClass( o.menuHiddenClass ) ) { // topMenu is visible
|
||
|
|
||
|
// Hide topMenu
|
||
|
$( el ).removeClass( o.tButtonActiveClass );
|
||
|
contract( o.container );
|
||
|
|
||
|
} else { // menu is hidden
|
||
|
|
||
|
// Show topMenu
|
||
|
$( el ).addClass( o.tButtonActiveClass );
|
||
|
o.topMenu.removeClass( o.menuHiddenClass );
|
||
|
if ( o.animateBool ) { // Using CSS3 transitions
|
||
|
o.topMenu.css( 'max-height', '0' );
|
||
|
} else { // Use jQuery animation
|
||
|
o.topMenu.hide( 0 );
|
||
|
}
|
||
|
expand( o.el );
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
// internal Event Handler Functions ===============================================
|
||
|
|
||
|
/**
|
||
|
* Toggle Btn focus and mousedown event handler
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var tButtonFocus = function( e ) {
|
||
|
|
||
|
e.stopPropagation();
|
||
|
|
||
|
var $el = $( e.target );
|
||
|
|
||
|
clearTimeout( o.timer );
|
||
|
o.timer = setTimeout( function () {
|
||
|
o.toggleMenu( e.target );
|
||
|
}, 100 );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Toggle Btn Click event handler
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var tButtonClick = function( e ) {
|
||
|
|
||
|
e.preventDefault();
|
||
|
e.stopPropagation();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Item click and touchend event handler
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var itemClick = function( e ) {
|
||
|
|
||
|
var $el = $( e.currentTarget );
|
||
|
|
||
|
e.stopPropagation();
|
||
|
|
||
|
if ( ( $el.hasClass( o.itemHoverClass ) || !$el.hasClass( o.parentClass ) ) && !o.touchMoveBool ) {
|
||
|
location.href = $el.children( 'a' ).attr('href');
|
||
|
menuBlur( e );
|
||
|
} else if ( e.type !== 'touchend' ) {
|
||
|
e.preventDefault();
|
||
|
}
|
||
|
|
||
|
o.touchMoveBool = false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Menu item focus and mouseenter event handler -
|
||
|
* Triggers: focus, mouseenter
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var itemFocus = function( e ) {
|
||
|
|
||
|
// get current target before it changes
|
||
|
var $el = $( e.currentTarget );
|
||
|
|
||
|
e.stopPropagation();
|
||
|
|
||
|
// Add focus if item does not have focus
|
||
|
if ( e.type !== 'focusin' ) {
|
||
|
$el.children( 'a' ).not( ':focus' ).focus();
|
||
|
}
|
||
|
o.itemFocused = $el;
|
||
|
|
||
|
clearTimeout( o.timer );
|
||
|
o.timer = setTimeout( function () {
|
||
|
|
||
|
// Expand topmenu if toggle button is active and menu is contracted
|
||
|
if ( o.tButton.hasClass( o.tButtonShowClass ) && !o.tButton.hasClass( o.tButtonActiveClass )) {
|
||
|
o.toggleMenu( o.tButton.get(0) );
|
||
|
}
|
||
|
|
||
|
// Expand menu
|
||
|
if ( $el.hasClass( o.parentClass ) ) {
|
||
|
|
||
|
if ( !$el.hasClass( o.itemHoverClass ) ) {
|
||
|
|
||
|
// Contract any expanded siblings and their children
|
||
|
contract( $el.parent() );
|
||
|
|
||
|
expand( $el );
|
||
|
}
|
||
|
} else {
|
||
|
// Contract any expanded siblings and their children
|
||
|
contract( $el.parent() );
|
||
|
}
|
||
|
}, 100 );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Touchmove event handler
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var touchMove = function( e ) {
|
||
|
o.touchMoveBool = true;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Topmenu mouseleave and foucusout event handler
|
||
|
* Triggers: mouseleave, focusout
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var menuBlur = function( e ) {
|
||
|
|
||
|
// Define event type if e is undefined
|
||
|
e = e || { 'type': 'callback' };
|
||
|
|
||
|
clearTimeout( o.timer );
|
||
|
o.timer = setTimeout( function () {
|
||
|
|
||
|
if ( o.itemFocused ) {
|
||
|
o.itemFocused.children( 'a' ).blur();
|
||
|
o.itemFocused = false;
|
||
|
}
|
||
|
contract( o.topMenu );
|
||
|
}, 100 );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Sub-menu item mouseleave event handler - used with expanded layout
|
||
|
* Triggers: mouseleave
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var itemLeave = function( e ) {
|
||
|
|
||
|
// get current target before it changes
|
||
|
var $el = $( e.currentTarget );
|
||
|
|
||
|
clearTimeout( o.timer );
|
||
|
o.timer = setTimeout( function () {
|
||
|
|
||
|
// Focus the parent element of the expanded menu
|
||
|
$el.parent().parent().children( 'a' ).focus();
|
||
|
}, 100 );
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* The CSS3 Transition End Contract event handler - used to add call-back functions to CSS3 transitions
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var transitionEndContract = function( e ) {
|
||
|
|
||
|
if ( e.originalEvent.propertyName === 'max-height' ) {
|
||
|
|
||
|
var $el = $( e.currentTarget );
|
||
|
e.stopPropagation();
|
||
|
|
||
|
// Menu Contracted
|
||
|
$el
|
||
|
.css( {
|
||
|
'transition': '',
|
||
|
'max-height': '0',
|
||
|
'overflow': 'hidden'
|
||
|
} )
|
||
|
.removeClass( o.menuExpandedClass )
|
||
|
.off( 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd' )
|
||
|
.parent().find( '.' + o.itemHoverClass ).addBack().removeClass( o.itemHoverClass )
|
||
|
;
|
||
|
|
||
|
if ( $el.hasClass( o.topMenuClass ) ) { // is topMenu
|
||
|
|
||
|
// accessibly hide topMenu
|
||
|
$el
|
||
|
.addClass( o.menuHiddenClass )
|
||
|
.show( 0 );
|
||
|
}
|
||
|
|
||
|
// Scroll to expanded menu
|
||
|
scrollMenu( o.itemFocused );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* The CSS3 Transition End Expand event handler - used to add call-back functions to CSS3 transitions
|
||
|
* @param {event} e - event object
|
||
|
*/
|
||
|
var transitionEndExpand = function( e ) {
|
||
|
|
||
|
if ( e.originalEvent.propertyName === 'max-height' ) {
|
||
|
var $el = $( e.currentTarget );
|
||
|
e.stopPropagation();
|
||
|
|
||
|
// Menu expanded
|
||
|
$el
|
||
|
.removeClass( o.menuHiddenClass )
|
||
|
.css( {
|
||
|
'transition': '',
|
||
|
'max-height': 'none',
|
||
|
'overflow': 'visible'
|
||
|
} )
|
||
|
.addClass( o.menuExpandedClass )
|
||
|
.off( 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd' )
|
||
|
;
|
||
|
$el.parent( '.' + o.parentClass ).addClass( o.itemHoverClass );
|
||
|
|
||
|
// Scroll to expanded menu
|
||
|
scrollMenu( o.itemFocused );
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// Internal Helper Functions ===============================================
|
||
|
|
||
|
/**
|
||
|
* Contract sub-menus
|
||
|
* @param {Object} $parent - The parent element of the menu Item initiating the event
|
||
|
*/
|
||
|
var contract = function( $parent ) {
|
||
|
|
||
|
var $menus = $parent.find( o.options.menuSel );
|
||
|
|
||
|
if ( o.animateBool ) { // Using CSS3 transitions
|
||
|
|
||
|
// Set max-height to height of each expanded menu
|
||
|
$menus.each( function(){
|
||
|
var $el = $( this );
|
||
|
if ( $el.height() !== 0 ) {
|
||
|
$el
|
||
|
.css({
|
||
|
'max-height': $el.height(),
|
||
|
'transition': 'max-height ' + String( o.options.transitionSpeed / 1000 ) + 's ' + o.options.css3Easing,
|
||
|
'overflow': 'hidden'
|
||
|
})
|
||
|
.on( 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', transitionEndContract )
|
||
|
;
|
||
|
} else {
|
||
|
$menus.not( $el );
|
||
|
}
|
||
|
});
|
||
|
|
||
|
// Must force a redraw so transition will occur
|
||
|
$menus.hide(0).show(0);
|
||
|
|
||
|
// Contract menu
|
||
|
$menus
|
||
|
.css({
|
||
|
'max-height': '0'
|
||
|
})
|
||
|
.removeClass( o.menuExpandedClass )
|
||
|
;
|
||
|
|
||
|
} else { // Use jQuery animation
|
||
|
|
||
|
// Contract menus
|
||
|
$menus.each( function() {
|
||
|
|
||
|
var $el = $( this );
|
||
|
|
||
|
if ( $el.height() !== 0 ) {
|
||
|
|
||
|
$el
|
||
|
.slideUp( o.options.transitionSpeed, o.options.jqueryEasing, function () {
|
||
|
|
||
|
$el
|
||
|
.css( 'overflow', 'visible' )
|
||
|
.removeClass( o.menuExpandedClass )
|
||
|
.parent( '.' + o.parentClass )
|
||
|
.removeClass( o.itemHoverClass )
|
||
|
;
|
||
|
|
||
|
if ( $el.hasClass( o.topMenuClass ) ) {
|
||
|
o.topMenu.addClass( o.menuHiddenClass );
|
||
|
}
|
||
|
|
||
|
// Scroll to expanded menu
|
||
|
scrollMenu( o.itemFocused );
|
||
|
})
|
||
|
;
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Expand sub-menu
|
||
|
* @param {Object} $el - The menu Item initiating the event
|
||
|
*/
|
||
|
var expand = function( $el ) {
|
||
|
|
||
|
// Define menu
|
||
|
var $menu = $el.children( o.options.menuSel );
|
||
|
|
||
|
// Remove hover class from siblings
|
||
|
$el.siblings( '.' + o.itemHoverClass )
|
||
|
.removeClass( o.itemHoverClass );
|
||
|
|
||
|
if ( o.animateBool ) { // Using CSS3 transitions
|
||
|
|
||
|
// Expand menu
|
||
|
$menu
|
||
|
.css({
|
||
|
'transition': 'max-height ' + String( o.options.transitionSpeed / 1000 ) + 's ' + o.options.css3Easing,
|
||
|
'max-height': $menu.data('height')
|
||
|
})
|
||
|
.on( 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', transitionEndExpand )
|
||
|
;
|
||
|
} else { // Use jQuery animation
|
||
|
|
||
|
// Expand menu
|
||
|
$menu
|
||
|
.slideDown( o.options.transitionSpeed, o.options.jqueryEasing, function() {
|
||
|
$el.addClass( o.itemHoverClass );
|
||
|
$menu
|
||
|
.addClass( o.menuExpandedClass )
|
||
|
.css( 'overflow','visible' )
|
||
|
;
|
||
|
console.log('jquery expand');
|
||
|
|
||
|
// Scroll to expanded menu
|
||
|
scrollMenu( o.itemFocused );
|
||
|
})
|
||
|
;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
// initialize ----------------------------------------------------------------
|
||
|
o.init( el );
|
||
|
|
||
|
return this;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Create plugin obects
|
||
|
* @param {Object} options - Plugin options
|
||
|
* @returns {*}
|
||
|
*/
|
||
|
$.fn[ pluginName ] = function( options ) {
|
||
|
|
||
|
// Return collection of elements
|
||
|
return this.each( function() {
|
||
|
var $el = $( this );
|
||
|
if ( !$el.data( pluginName ) ) {
|
||
|
$el.data( pluginName, new Plugin( this, options ) );
|
||
|
}
|
||
|
});
|
||
|
};
|
||
|
|
||
|
// Out of Scope Private functions ==================================================
|
||
|
|
||
|
/**
|
||
|
* Test for transform3d support
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
var transform3DSupported = function() {
|
||
|
var el = document.createElement('p'),
|
||
|
has3d,
|
||
|
transforms = {
|
||
|
'webkitTransform':'-webkit-transform',
|
||
|
'OTransform':'-o-transform',
|
||
|
'msTransform':'-ms-transform',
|
||
|
'MozTransform':'-moz-transform',
|
||
|
'transform':'transform'
|
||
|
};
|
||
|
|
||
|
// Add it to the body to get the computed style
|
||
|
document.body.insertBefore(el, null);
|
||
|
|
||
|
for(var t in transforms){
|
||
|
if( el.style[t] !== undefined ){
|
||
|
el.style[t] = 'translate3d(1px,1px,1px)';
|
||
|
has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
document.body.removeChild(el);
|
||
|
|
||
|
return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Test for CSS3 transitions support
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
var transitionsSupported = function() {
|
||
|
var b = document.body || document.documentElement,
|
||
|
s = b.style,
|
||
|
p = 'transition';
|
||
|
|
||
|
if (typeof s[p] === 'string') { return true; }
|
||
|
|
||
|
// Tests for vendor specific prop
|
||
|
var v = ['Moz', 'webkit', 'Webkit', 'Khtml', 'O', 'ms'];
|
||
|
p = p.charAt(0).toUpperCase() + p.substr(1);
|
||
|
|
||
|
for (var i=0; i<v.length; i++) {
|
||
|
if (typeof s[v[i] + p] === 'string') { return true; }
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Scroll Menu into viewport if off screen
|
||
|
* @returns {boolean}
|
||
|
*/
|
||
|
var scrollMenu = function( $el ) {
|
||
|
|
||
|
if ( $el.length ) {
|
||
|
|
||
|
var viewTop = $( window ).scrollTop();
|
||
|
var viewBottom = viewTop + $( window ).height();
|
||
|
var boundsTop = $el.offset().top;
|
||
|
var boundsBottom = boundsTop + $el.outerHeight();
|
||
|
|
||
|
if ( boundsBottom > viewBottom || boundsTop < viewTop ) {
|
||
|
$( 'html, body' ).animate( { scrollTop: boundsTop }, 'slow' );
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
})( jQuery, window, document, Math );
|