1(function ($) { 2 3 // Add posibility to scroll to selected option 4 // usefull for select for example 5 $.fn.scrollTo = function(elem) { 6 $(this).scrollTop($(this).scrollTop() - $(this).offset().top + $(elem).offset().top); 7 return this; 8 }; 9 10 $.fn.dropdown = function (option) { 11 var defaults = { 12 inDuration: 300, 13 outDuration: 225, 14 constrain_width: true, // Constrains width of dropdown to the activator 15 hover: false, 16 gutter: 0, // Spacing from edge 17 belowOrigin: false, 18 alignment: 'left' 19 }; 20 21 this.each(function(){ 22 var origin = $(this); 23 var options = $.extend({}, defaults, option); 24 var isFocused = false; 25 26 // Dropdown menu 27 var activates = $("#"+ origin.attr('data-activates')); 28 29 function updateOptions() { 30 if (origin.data('induration') !== undefined) 31 options.inDuration = origin.data('inDuration'); 32 if (origin.data('outduration') !== undefined) 33 options.outDuration = origin.data('outDuration'); 34 if (origin.data('constrainwidth') !== undefined) 35 options.constrain_width = origin.data('constrainwidth'); 36 if (origin.data('hover') !== undefined) 37 options.hover = origin.data('hover'); 38 if (origin.data('gutter') !== undefined) 39 options.gutter = origin.data('gutter'); 40 if (origin.data('beloworigin') !== undefined) 41 options.belowOrigin = origin.data('beloworigin'); 42 if (origin.data('alignment') !== undefined) 43 options.alignment = origin.data('alignment'); 44 } 45 46 updateOptions(); 47 48 // Attach dropdown to its activator 49 origin.after(activates); 50 51 /* 52 Helper function to position and resize dropdown. 53 Used in hover and click handler. 54 */ 55 function placeDropdown(eventType) { 56 // Check for simultaneous focus and click events. 57 if (eventType === 'focus') { 58 isFocused = true; 59 } 60 61 // Check html data attributes 62 updateOptions(); 63 64 // Set Dropdown state 65 activates.addClass('active'); 66 origin.addClass('active'); 67 68 // Constrain width 69 if (options.constrain_width === true) { 70 activates.css('width', origin.outerWidth()); 71 72 } else { 73 activates.css('white-space', 'nowrap'); 74 } 75 76 // Offscreen detection 77 var windowHeight = window.innerHeight; 78 var originHeight = origin.innerHeight(); 79 var offsetLeft = origin.offset().left; 80 var offsetTop = origin.offset().top - $(window).scrollTop(); 81 var currAlignment = options.alignment; 82 var gutterSpacing = 0; 83 var leftPosition = 0; 84 85 // Below Origin 86 var verticalOffset = 0; 87 if (options.belowOrigin === true) { 88 verticalOffset = originHeight; 89 } 90 91 // Check for scrolling positioned container. 92 var scrollOffset = 0; 93 var wrapper = origin.parent(); 94 if (!wrapper.is('body') && wrapper[0].scrollHeight > wrapper[0].clientHeight) { 95 scrollOffset = wrapper[0].scrollTop; 96 } 97 98 99 if (offsetLeft + activates.innerWidth() > $(window).width()) { 100 // Dropdown goes past screen on right, force right alignment 101 currAlignment = 'right'; 102 103 } else if (offsetLeft - activates.innerWidth() + origin.innerWidth() < 0) { 104 // Dropdown goes past screen on left, force left alignment 105 currAlignment = 'left'; 106 } 107 // Vertical bottom offscreen detection 108 if (offsetTop + activates.innerHeight() > windowHeight) { 109 // If going upwards still goes offscreen, just crop height of dropdown. 110 if (offsetTop + originHeight - activates.innerHeight() < 0) { 111 var adjustedHeight = windowHeight - offsetTop - verticalOffset; 112 activates.css('max-height', adjustedHeight); 113 } else { 114 // Flow upwards. 115 if (!verticalOffset) { 116 verticalOffset += originHeight; 117 } 118 verticalOffset -= activates.innerHeight(); 119 } 120 } 121 122 // Handle edge alignment 123 if (currAlignment === 'left') { 124 gutterSpacing = options.gutter; 125 leftPosition = origin.position().left + gutterSpacing; 126 } 127 else if (currAlignment === 'right') { 128 var offsetRight = origin.position().left + origin.outerWidth() - activates.outerWidth(); 129 gutterSpacing = -options.gutter; 130 leftPosition = offsetRight + gutterSpacing; 131 } 132 133 // Position dropdown 134 activates.css({ 135 position: 'absolute', 136 top: origin.position().top + verticalOffset + scrollOffset, 137 left: leftPosition 138 }); 139 140 141 // Show dropdown 142 activates.stop(true, true).css('opacity', 0) 143 .slideDown({ 144 queue: false, 145 duration: options.inDuration, 146 easing: 'easeOutCubic', 147 complete: function() { 148 $(this).css('height', ''); 149 } 150 }) 151 .animate( {opacity: 1}, {queue: false, duration: options.inDuration, easing: 'easeOutSine'}); 152 } 153 154 function hideDropdown() { 155 // Check for simultaneous focus and click events. 156 isFocused = false;
157 activates.fadeOut(options.outDuration); 158 activates.removeClass('active'); 159 origin.removeClass('active'); 160 setTimeout(function() { activates.css('max-height', ''); }, options.outDuration); 161 } 162 163 // Hover 164 if (options.hover) { 165 var open = false; 166 origin.unbind('click.' + origin.attr('id')); 167 // Hover handler to show dropdown 168 origin.on('mouseenter', function(e){ // Mouse over 169 if (open === false) { 170 placeDropdown(); 171 open = true; 172 } 173 }); 174 origin.on('mouseleave', function(e){ 175 // If hover on origin then to something other than dropdown content, then close 176 var toEl = e.toElement || e.relatedTarget; // added browser compatibility for target element 177 if(!$(toEl).closest('.dropdown-contenido').is(activates)) { 178 activates.stop(true, true); 179 hideDropdown(); 180 open = false; 181 } 182 }); 183 184 activates.on('mouseleave', function(e){ // Mouse out 185 var toEl = e.toElement || e.relatedTarget; 186 if(!$(toEl).closest('.dropdown-button').is(origin)) { 187 activates.stop(true, true); 188 hideDropdown(); 189 open = false; 190 } 191 }); 192 193 // Click 194 } else { 195 // Click handler to show dropdown 196 origin.unbind('click.' + origin.attr('id')); 197 origin.bind('click.'+origin.attr('id'), function(e){ 198 if (!isFocused) { 199 if ( origin[0] == e.currentTarget && 200 !origin.hasClass('active') && 201 ($(e.target).closest('.dropdown-content').length === 0)) { 202 e.preventDefault(); // Prevents button click from moving window 203 placeDropdown('click'); 204 } 205 // If origin is clicked and menu is open, close menu 206 else if (origin.hasClass('active')) { 207 hideDropdown(); 208 $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); 209 } 210 // If menu open, add click close handler to document 211 if (activates.hasClass('active')) { 212 $(document).bind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id'), function (e) { 213 if (!activates.is(e.target) && !origin.is(e.target) && (!origin.find(e.target).length) ) { 214 hideDropdown(); 215 $(document).unbind('click.'+ activates.attr('id') + ' touchstart.' + activates.attr('id')); 216 } 217 }); 218 } 219 } 220 }); 221 222 } // End else 223 224 // Listen to open and close event - useful for select component 225 origin.on('open', function(e, eventType) { 226 placeDropdown(eventType); 227 }); 228 origin.on('close', hideDropdown); 229 230 231 }); 232 }; // End dropdown plugin 233 234 $(document).ready(function(){ 235 $('.dropdown-button').dropdown(); 236 }); 237}( jQuery ));
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.