diff -r e804ae133f27 -r 22377c9e2eae Resources/public/js/jquery.clickmenu.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/public/js/jquery.clickmenu.js Wed Dec 07 15:06:35 2011 +0100 @@ -0,0 +1,515 @@ +/* clickMenu - v0.1.6 + * Copyright (c) 2007 Roman Weich + * http://p.sohei.org + * + * Changelog: + * v 0.1.6 - 2007-09-06 + * -fix: having a link in the top-level menu would not open the menu but call the link instead + * v 0.1.5 - 2007-07-07 + * -change/fix: menu opening/closing now through simple show() and hide() calls - before fadeIn and fadeOut were used for which extra functions to stop a already running animation were created -> they were + * buggy (not working with the interface plugin in jquery1.1.2 and not working with jquery1.1.3 at all) and now removed + * -change: removed option: fadeTime + * -change: now using the bgiframe plugin for adding iframes in ie6 when available + * v 0.1.4 - 2007-03-20 + * -fix: the default options were overwritten by the context related options + * -fix: hiding a submenu all hover- and click-events were unbound, even the ones not defined in this plugin - unbinding should work now + * v 0.1.3 - 2007-03-13 + * -fix: some display problems ie had when no width was set on the submenu, so on ie the width for each submenu will be explicitely set + * -fix: the fix to the ie-width-problem is a fix to the "ie does not support css min-width stuff" problem too which displayed some submenus too narrow (it looked just not right) + * -fix: some bugs, when user the was too fast with the mouse + * v 0.1.2 - 2007-03-11 + * -change: made a lot changes in the traversing routines to speed things up (having better memory usage now as well) + * -change: added $.fn.clickMenu.setDefaults() for setting global defaults + * -fix: hoverbug when a main menu item had no submenu + * -fix: some bugs i found while rewriting most of the stuff + * v 0.1.1 - 2007-03-04 + * -change: the width of the submenus is no longer fixed, its set in the plugin now + * -change: the submenu-arrow is now an img, not the background-img of the list element - that allows better positioning, and background-changes on hover (you have to set the image through the arrowSrc option) + * -fix: clicking on a clickMenu while another was already open, didn't close the open one + * -change: clicking on the open main menu item will close it + * -fix: on an open menu moving the mouse to a main menu item and moving it fastly elsewere hid the whole menu + * v 0.1.0 - 2007-03-03 + */ + +(function($) +{ + var defaults = { + onClick: function(){ + $(this).find('>a').each(function(){ + if ( this.href ) + { + window.location = this.href; + } + }); + }, + arrowSrc: '', + subDelay: 300, + mainDelay: 10 + }; + + $.fn.clickMenu = function(options) + { + var shown = false; + var liOffset = ( ($.browser.msie) ? 4 : 2 ); + + var settings = $.extend({}, defaults, options); + + var hideDIV = function(div, delay) + { + //a timer running to show the div? + if ( div.timer && !div.isVisible ) + { + clearTimeout(div.timer); + } + else if (div.timer) + { + return; //hide-timer already running + } + if ( div.isVisible ) + { + div.timer = setTimeout(function() + { + //remove events + $(getAllChilds(getOneChild(div, 'UL'), 'LI')).unbind('mouseover', liHoverIn).unbind('mouseout', liHoverOut).unbind('click', settings.onClick); + //hide it + $(div).hide(); + div.isVisible = false; + div.timer = null; + }, delay); + } + }; + + var showDIV = function(div, delay) + { + if ( div.timer ) + { + clearTimeout(div.timer); + } + if ( !div.isVisible ) + { + div.timer = setTimeout(function() + { + //check if the mouse is still over the parent item - if not dont show the submenu + if ( !checkClass(div.parentNode, 'hover') ) + { + return; + } + //assign events to all div>ul>li-elements + $(getAllChilds(getOneChild(div, 'UL'), 'LI')).mouseover(liHoverIn).mouseout(liHoverOut).click(settings.onClick); + //positioning + if ( !checkClass(div.parentNode, 'main') ) + { + $(div).css('left', div.parentNode.offsetWidth - liOffset); + } + //show it + div.isVisible = true; //we use this over :visible to speed up traversing + $(div).show(); + if ( $.browser.msie ) //fixing a display-bug in ie6 and adding min-width + { + var cW = $(getOneChild(div, 'UL')).width(); + if ( cW < 100 ) + { + cW = 100; + } + $(div).css('width', cW); + } + div.timer = null; + }, delay); + } + }; + + //same as hover.handlehover in jquery - just can't use hover() directly - need the ability to unbind only the one hover event + var testHandleHover = function(e) + { + // Check if mouse(over|out) are still within the same parent element + var p = (e.type == "mouseover" ? e.fromElement : e.toElement) || e.relatedTarget; + // Traverse up the tree + while ( p && p != this ) + { + try + { + p = p.parentNode; + } + catch(e) + { + p = this; + } + } + // If we actually just moused on to a sub-element, ignore it + if ( p == this ) + { + return false; + } + return true; + }; + + var mainHoverIn = function(e) + { + //no need to test e.target==this, as no child has the same event binded + //its possible, that a main menu item still has hover (if it has no submenu) - thus remove it + var lis = getAllChilds(this.parentNode, 'LI'); + var pattern = new RegExp("(^|\\s)hover(\\s|$)"); + for (var i = 0; i < lis.length; i++) + { + if ( pattern.test(lis[i].className) ) + { + $(lis[i]).removeClass('hover'); + } + } + $(this).addClass('hover'); + if ( shown ) + { + hoverIn(this, settings.mainDelay); + } + }; + + var liHoverIn = function(e) + { + if ( !testHandleHover(e) ) + { + return false; + } + if ( e.target != this ) + { + //look whether the target is a direct child of this (maybe an image) + if ( !isChild(this, e.target) ) + { + return; + } + } + hoverIn(this, settings.subDelay); + }; + + var hoverIn = function(li, delay) + { + var innerDiv = getOneChild(li, 'DIV'); + //stop running timers from the other menus on the same level - a little faster than $('>*>div', li.parentNode) + var n = li.parentNode.firstChild; + for ( ; n; n = n.nextSibling ) + { + if ( n.nodeType == 1 && n.nodeName.toUpperCase() == 'LI' ) + { + var div = getOneChild(n, 'DIV'); + if ( div && div.timer && !div.isVisible ) //clear show-div timer + { + clearTimeout(div.timer); + div.timer = null; + } + } + } + //is there a timer running to hide one of the parent divs? stop it + var pNode = li.parentNode; + for ( ; pNode; pNode = pNode.parentNode ) + { + if ( pNode.nodeType == 1 && pNode.nodeName.toUpperCase() == 'DIV' ) + { + if (pNode.timer) + { + clearTimeout(pNode.timer); + pNode.timer = null; + $(pNode.parentNode).addClass('hover'); + } + } + } + //highlight the current element + $(li).addClass('hover'); + //is the submenu already visible? + if ( innerDiv && innerDiv.isVisible ) + { + //hide-timer running? + if ( innerDiv.timer ) + { + clearTimeout(innerDiv.timer); + innerDiv.timer = null; + } + else + { + return; + } + } + //hide all open menus on the same level and below and unhighlight the li item (but not the current submenu!) + $(li.parentNode.getElementsByTagName('DIV')).each(function(){ + if ( this != innerDiv && this.isVisible ) + { + hideDIV(this, delay); + $(this.parentNode).removeClass('hover'); + } + }); + //show the submenu, if there is one + if ( innerDiv ) + { + showDIV(innerDiv, delay); + } + }; + + var liHoverOut = function(e) + { + if ( !testHandleHover(e) ) + { + return false; + } + if ( e.target != this ) + { + if ( !isChild(this, e.target) ) //return only if the target is no direct child of this + { + return; + } + } + //remove the hover from the submenu item, if the mouse is hovering out of the menu (this is only for the last open (levelwise) (sub-)menu) + var div = getOneChild(this, 'DIV'); + if ( !div ) + { + $(this).removeClass('hover'); + } + else + { + if ( !div.isVisible ) + { + $(this).removeClass('hover'); + } + } + }; + + var mainHoverOut = function(e) + { + //no need to test e.target==this, as no child has the same event binded + //remove hover + var div = getOneChild(this, 'DIV'); + var relTarget = e.relatedTarget || e.toElement; //this is undefined sometimes (e.g. when the mouse moves out of the window), so dont remove hover then + var p; + if ( !shown ) + { + $(this).removeClass('hover'); + } + else if ( !div && relTarget ) //menuitem has no submenu, so dont remove the hover if the mouse goes outside the menu + { + p = findParentWithClass(e.target, 'UL', 'clickMenu'); + if ( p.contains(relTarget)) + { + $(this).removeClass('hover'); + } + } + else if ( relTarget ) + { + //remove hover only when moving to anywhere inside the clickmenu + p = findParentWithClass(e.target, 'UL', 'clickMenu'); + if ( !div.isVisible && (p.contains(relTarget)) ) + { + $(this).removeClass('hover'); + } + } + }; + + var mainClick = function() + { + var div = getOneChild(this, 'DIV'); + if ( div && div.isVisible ) //clicked on an open main-menu-item + { + clean(); + $(this).addClass('hover'); + } + else + { + hoverIn(this, settings.mainDelay); + shown = true; + $(document).bind('mousedown', checkMouse); + } + return false; + }; + + var checkMouse = function(e) + { + //is the mouse inside a clickmenu? if yes, is it an open (the current) one? + var vis = false; + var cm = findParentWithClass(e.target, 'UL', 'clickMenu'); + if ( cm ) + { + $(cm.getElementsByTagName('DIV')).each(function(){ + if ( this.isVisible ) + { + vis = true; + } + }); + } + if ( !vis ) + { + clean(); + } + }; + + var clean = function() + { + //remove timeout and hide the divs + $('ul.clickMenu div.outerbox').each(function(){ + if ( this.timer ) + { + clearTimeout(this.timer); + this.timer = null; + } + if ( this.isVisible ) + { + $(this).hide(); + this.isVisible = false; + } + }); + $('ul.clickMenu li').removeClass('hover'); + //remove events + $('ul.clickMenu>li li').unbind('mouseover', liHoverIn).unbind('mouseout', liHoverOut).unbind('click', settings.onClick); + $(document).unbind('mousedown', checkMouse); + shown = false; + }; + + var getOneChild = function(elem, name) + { + if ( !elem ) + { + return null; + } + var n = elem.firstChild; + for ( ; n; n = n.nextSibling ) + { + if ( n.nodeType == 1 && n.nodeName.toUpperCase() == name ) + { + return n; + } + } + return null; + }; + + var getAllChilds = function(elem, name) + { + if ( !elem ) + { + return []; + } + var r = []; + var n = elem.firstChild; + for ( ; n; n = n.nextSibling ) + { + if ( n.nodeType == 1 && n.nodeName.toUpperCase() == name ) + { + r[r.length] = n; + } + } + return r; + }; + + var findParentWithClass = function(elem, searchTag, searchClass) + { + var pNode = elem.parentNode; + var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)"); + for ( ; pNode; pNode = pNode.parentNode ) + { + if ( pNode.nodeType == 1 && pNode.nodeName.toUpperCase() == searchTag && pattern.test(pNode.className) ) + { + return pNode; + } + } + return null; + }; + + var checkClass = function(elem, searchClass) + { + var pattern = new RegExp("(^|\\s)" + searchClass + "(\\s|$)"); + if ( pattern.test(elem.className) ) + { + return true; + } + return false; + }; + + var isChild = function(elem, childElem) + { + var n = elem.firstChild; + for ( ; n; n = n.nextSibling ) + { + if ( n == childElem ) + { + return true; + } + } + return false; + }; + + return this.each(function() + { + //add .contains() to mozilla - http://www.quirksmode.org/blog/archives/2006/01/contains_for_mo.html + if (window.Node && Node.prototype && !Node.prototype.contains) + { + Node.prototype.contains = function(arg) + { + return !!(this.compareDocumentPosition(arg) & 16); + }; + } + //add class + if ( !checkClass(this, 'clickMenu') ) + { + $(this).addClass('clickMenu'); + } + //add shadows + $('ul', this).shadowBox(); + //ie6? - add iframes + if ( $.browser.msie && (!$.browser.version || parseInt($.browser.version) <= 6) ) + { + if ( $.fn.bgiframe ) + { + $('div.outerbox', this).bgiframe(); + } + else + { + /* thanks to Mark Gibson - http://www.nabble.com/forum/ViewPost.jtp?post=6504414&framed=y */ + $('div.outerbox', this).append('