1/** 2 * cbpTooltipMenu.js v1.0.0 3 * http://www.codrops.com 4 * 5 * Licensed under the MIT license. 6 * http://www.opensource.org/licenses/mit-license.php 7 * 8 * Copyright 2013, Codrops 9 * http://www.codrops.com 10 */ 11;( function( window ) { 12 13 'use strict'; 14 15 var document = window.document, 16 docElem = document.documentElement; 17 18 function extend( a, b ) { 19 for( var key in b ) { 20 if( b.hasOwnProperty( key ) ) { 21 a[key] = b[key]; 22 } 23 } 24 return a; 25 } 26 27 // from https://github.com/ryanve/response.js/blob/master/response.js 28 function getViewportH() { 29 var client = docElem['clientHeight'], 30 inner = window['innerHeight']; 31 if( client < inner ) 32 return inner; 33 else 34 return client; 35 } 36 37 // http://stackoverflow.com/a/11396681/989439 38 function getOffset( el ) { 39 return el.getBoundingClientRect(); 40 } 41 42 // http://snipplr.com/view.php?codeview&id=5259 43 function isMouseLeaveOrEnter(e, handler) { 44 if (e.type != 'mouseout' && e.type != 'mouseover') return false; 45 var reltg = e.relatedTarget ? e.relatedTarget : 46 e.type == 'mouseout' ? e.toElement : e.fromElement; 47 while (reltg && reltg != handler) reltg = reltg.parentNode; 48 return (reltg != handler); 49 } 50 51 function cbpTooltipMenu( el, options ) { 52 this.el = el; 53 this.options = extend( this.defaults, options ); 54 this._init(); 55 } 56 57 cbpTooltipMenu.prototype = { 58 defaults : { 59 // add a timeout to avoid the menu to open instantly 60 delayMenu : 100 61 }, 62 _init : function() { 63 this.touch = Modernizr.touch; 64 this.menuItems = document.querySelectorAll( '#' + this.el.id + ' > li' ); 65 this._initEvents(); 66 }, 67 _initEvents : function() { 68 69 var self = this; 70 71 Array.prototype.slice.call( this.menuItems ).forEach( function( el, i ) { 72 var trigger = el.querySelector( 'a' ); 73 if( self.touch ) { 74 trigger.addEventListener( 'click', function( ev ) { self._handleClick( this, ev ); } ); 75 } 76 else { 77 trigger.addEventListener( 'click', function( ev ) { 78 if( this.parentNode.querySelector( 'ul.cbp-tm-submenu' ) ) { 79 ev.preventDefault(); 80 } 81 } ); 82 el.addEventListener( 'mouseover', function(ev) { if( isMouseLeaveOrEnter( ev, this ) ) self._openMenu( this ); } ); 83 el.addEventListener( 'mouseout', function(ev) { if( isMouseLeaveOrEnter( ev, this ) ) self._closeMenu( this ); } ); 84 } 85 } ); 86 87 }, 88 _openMenu : function( el ) { 89 90 var self = this; 91 clearTimeout( this.omtimeout ); 92 this.omtimeout = setTimeout( function() { 93 var submenu = el.querySelector( 'ul.cbp-tm-submenu' ); 94 95 if( submenu ) { 96 el.className = 'cbp-tm-show'; 97 if( self._positionMenu( el ) === 'top' ) { 98 el.className += ' cbp-tm-show-above'; 99 } 100 else { 101 el.className += ' cbp-tm-show-below'; 102 } 103 } 104 }, this.touch ? 0 : this.options.delayMenu ); 105 106 }, 107 _closeMenu : function( el ) { 108 109 clearTimeout( this.omtimeout ); 110 111 var submenu = el.querySelector( 'ul.cbp-tm-submenu' ); 112 113 if( submenu ) { 114 // based on https://github.com/desandro/classie/blob/master/classie.js 115 el.className = el.className.replace(new RegExp("(^|\\s+)" + "cbp-tm-show" + "(\\s+|$)"), ' '); 116 el.className = el.className.replace(new RegExp("(^|\\s+)" + "cbp-tm-show-below" + "(\\s+|$)"), ' '); 117 el.className = el.className.replace(new RegExp("(^|\\s+)" + "cbp-tm-show-above" + "(\\s+|$)"), ' '); 118 } 119 120 }, 121 _handleClick : function( el, ev ) { 122 var item = el.parentNode, 123 items = Array.prototype.slice.call( this.menuItems ), 124 submenu = item.querySelector( 'ul.cbp-tm-submenu' ) 125 126 // first close any opened one.. 127 if( typeof this.current !== 'undefined' && items.indexOf( item ) !== this.current ) { 128 this._closeMenu( this.el.children[ this.current ] ); 129 this.el.children[ this.current ].querySelector( 'ul.cbp-tm-submenu' ).setAttribute( 'data-open', 'false' ); 130 } 131 132 if( submenu ) { 133 ev.preventDefault(); 134 135 var isOpen = submenu.getAttribute( 'data-open' ); 136 137 if( isOpen === 'true' ) { 138 this._closeMenu( item ); 139 submenu.setAttribute( 'data-open', 'false' ); 140 } 141 else { 142 this._openMenu( item ); 143 this.current = items.indexOf( item ); 144 submenu.setAttribute( 'data-open', 'true' ); 145 } 146 } 147 148 }, 149 _positionMenu : function( el ) { 150 // checking where's more space left in the viewport: above or below the element 151 var vH = getViewportH(), 152 ot = getOffset(el), 153 spaceUp = ot.top , 154 spaceDown = vH - spaceUp - el.offsetHeight; 155 156 return ( spaceDown <= spaceUp ? 'top' : 'bottom' ); 157 } 158 } 159 160 // add to global namespace 161 window.cbpTooltipMenu = cbpTooltipMenu; 162 163} )( window );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.