1// File#: _1_tooltip 2// Usage: codyhouse.co/license 3(function() { 4 var Tooltip = function(element) { 5 this.element = element; 6 this.tooltip = false; 7 this.tooltipIntervalId = false; 8 this.tooltipContent = this.element.getAttribute('title'); 9 this.tooltipPosition = (this.element.getAttribute('data-tooltip-position')) ? this.element.getAttribute('data-tooltip-position') : 'top'; 10 this.tooltipClasses = (this.element.getAttribute('data-tooltip-class')) ? this.element.getAttribute('data-tooltip-class') : false; 11 this.tooltipId = 'js-tooltip-element'; // id of the tooltip element -> trigger will have the same aria-describedby attr 12 // there are cases where you only need the aria-label -> SR do not need to read the tooltip content (e.g., footnotes) 13 this.tooltipDescription = (this.element.getAttribute('data-tooltip-describedby') && this.element.getAttribute('data-tooltip-describedby') == 'false') ? false : true; 14 15 this.tooltipDelay = 300; // show tooltip after a delay (in ms) 16 this.tooltipDelta = 10; // distance beetwen tooltip and trigger element (in px) 17 this.tooltipTriggerHover = false; 18 // tooltp sticky option 19 this.tooltipSticky = (this.tooltipClasses && this.tooltipClasses.indexOf('tooltip--sticky') > -1); 20 this.tooltipHover = false; 21 if(this.tooltipSticky) { 22 this.tooltipHoverInterval = false; 23 } 24 resetTooltipContent(this); 25 initTooltip(this); 26 }; 27 28 function resetTooltipContent(tooltip) { 29 var htmlContent = tooltip.element.getAttribute('data-tooltip-title'); 30 if(htmlContent) { 31 tooltip.tooltipContent = htmlContent; 32 } 33 }; 34 35 function initTooltip(tooltipObj) { 36 // reset trigger element 37 tooltipObj.element.removeAttribute('title'); 38 tooltipObj.element.setAttribute('tabindex', '0'); 39 // add event listeners 40 tooltipObj.element.addEventListener('mouseenter', handleEvent.bind(tooltipObj)); 41 tooltipObj.element.addEventListener('focus', handleEvent.bind(tooltipObj)); 42 }; 43 44 function removeTooltipEvents(tooltipObj) { 45 // remove event listeners 46 tooltipObj.element.removeEventListener('mouseleave', handleEvent.bind(tooltipObj)); 47 tooltipObj.element.removeEventListener('blur', handleEvent.bind(tooltipObj)); 48 }; 49 50 function handleEvent(event) { 51 // handle events 52 switch(event.type) { 53 case 'mouseenter': 54 case 'focus': 55 showTooltip(this, event); 56 break; 57 case 'mouseleave': 58 case 'blur': 59 checkTooltip(this); 60 break; 61 } 62 }; 63 64 function showTooltip(tooltipObj, event) { 65 // tooltip has already been triggered 66 if(tooltipObj.tooltipIntervalId) return; 67 tooltipObj.tooltipTriggerHover = true; 68 // listen to close events 69 tooltipObj.element.addEventListener('mouseleave', handleEvent.bind(tooltipObj)); 70 tooltipObj.element.addEventListener('blur', handleEvent.bind(tooltipObj)); 71 // show tooltip with a delay 72 tooltipObj.tooltipIntervalId = setTimeout(function(){ 73 createTooltip(tooltipObj); 74 }, tooltipObj.tooltipDelay); 75 }; 76 77 function createTooltip(tooltipObj) { 78 tooltipObj.tooltip = document.getElementById(tooltipObj.tooltipId); 79 80 if( !tooltipObj.tooltip ) { // tooltip element does not yet exist 81 tooltipObj.tooltip = document.createElement('div'); 82 document.body.appendChild(tooltipObj.tooltip); 83 } 84 85 // reset tooltip content/position 86 Util.setAttributes(tooltipObj.tooltip, {'id': tooltipObj.tooltipId, 'class': 'tooltip tooltip--is-hidden js-tooltip', 'role': 'tooltip'}); 87 tooltipObj.tooltip.innerHTML = tooltipObj.tooltipContent; 88 if(tooltipObj.tooltipDescription) tooltipObj.element.setAttribute('aria-describedby', tooltipObj.tooltipId); 89 if(tooltipObj.tooltipClasses) Util.addClass(tooltipObj.tooltip, tooltipObj.tooltipClasses); 90 if(tooltipObj.tooltipSticky) Util.addClass(tooltipObj.tooltip, 'tooltip--sticky'); 91 placeTooltip(tooltipObj); 92 Util.removeClass(tooltipObj.tooltip, 'tooltip--is-hidden'); 93 94 // if tooltip is sticky, listen to mouse events 95 if(!tooltipObj.tooltipSticky) return; 96 tooltipObj.tooltip.addEventListener('mouseenter', function cb(){ 97 tooltipObj.tooltipHover = true; 98 if(tooltipObj.tooltipHoverInterval) { 99 clearInterval(tooltipObj.tooltipHoverInterval); 100 tooltipObj.tooltipHoverInterval = false;
101 } 102 tooltipObj.tooltip.removeEventListener('mouseenter', cb); 103 tooltipLeaveEvent(tooltipObj); 104 }); 105 }; 106 107 function tooltipLeaveEvent(tooltipObj) { 108 tooltipObj.tooltip.addEventListener('mouseleave', function cb(){ 109 tooltipObj.tooltipHover = false; 110 tooltipObj.tooltip.removeEventListener('mouseleave', cb); 111 hideTooltip(tooltipObj); 112 }); 113 }; 114 115 function placeTooltip(tooltipObj) { 116 // set top and left position of the tooltip according to the data-tooltip-position attr of the trigger 117 var dimention = [tooltipObj.tooltip.offsetHeight, tooltipObj.tooltip.offsetWidth], 118 positionTrigger = tooltipObj.element.getBoundingClientRect(), 119 position = [], 120 scrollY = window.scrollY || window.pageYOffset; 121 122 position['top'] = [ (positionTrigger.top - dimention[0] - tooltipObj.tooltipDelta + scrollY), (positionTrigger.right/2 + positionTrigger.left/2 - dimention[1]/2)]; 123 position['bottom'] = [ (positionTrigger.bottom + tooltipObj.tooltipDelta + scrollY), (positionTrigger.right/2 + positionTrigger.left/2 - dimention[1]/2)]; 124 position['left'] = [(positionTrigger.top/2 + positionTrigger.bottom/2 - dimention[0]/2 + scrollY), positionTrigger.left - dimention[1] - tooltipObj.tooltipDelta]; 125 position['right'] = [(positionTrigger.top/2 + positionTrigger.bottom/2 - dimention[0]/2 + scrollY), positionTrigger.right + tooltipObj.tooltipDelta]; 126 127 var direction = tooltipObj.tooltipPosition; 128 if( direction == 'top' && position['top'][0] < scrollY) direction = 'bottom'; 129 else if( direction == 'bottom' && position['bottom'][0] + tooltipObj.tooltipDelta + dimention[0] > scrollY + window.innerHeight) direction = 'top'; 130 else if( direction == 'left' && position['left'][1] < 0 ) direction = 'right'; 131 else if( direction == 'right' && position['right'][1] + dimention[1] > window.innerWidth ) direction = 'left'; 132 133 if(direction == 'top' || direction == 'bottom') { 134 if(position[direction][1] < 0 ) position[direction][1] = 0; 135 if(position[direction][1] + dimention[1] > window.innerWidth ) position[direction][1] = window.innerWidth - dimention[1]; 136 } 137 tooltipObj.tooltip.style.top = position[direction][0]+'px'; 138 tooltipObj.tooltip.style.left = position[direction][1]+'px'; 139 Util.addClass(tooltipObj.tooltip, 'tooltip--'+direction); 140 }; 141 142 function checkTooltip(tooltipObj) { 143 tooltipObj.tooltipTriggerHover = false; 144 if(!tooltipObj.tooltipSticky) hideTooltip(tooltipObj); 145 else { 146 if(tooltipObj.tooltipHover) return; 147 if(tooltipObj.tooltipHoverInterval) return; 148 tooltipObj.tooltipHoverInterval = setTimeout(function(){ 149 hideTooltip(tooltipObj); 150 tooltipObj.tooltipHoverInterval = false; 151 }, 300); 152 } 153 }; 154 155 function hideTooltip(tooltipObj) { 156 if(tooltipObj.tooltipHover || tooltipObj.tooltipTriggerHover) return; 157 clearInterval(tooltipObj.tooltipIntervalId); 158 if(tooltipObj.tooltipHoverInterval) { 159 clearInterval(tooltipObj.tooltipHoverInterval); 160 tooltipObj.tooltipHoverInterval = false; 161 } 162 tooltipObj.tooltipIntervalId = false; 163 if(!tooltipObj.tooltip) return; 164 // hide tooltip 165 removeTooltip(tooltipObj); 166 // remove events 167 removeTooltipEvents(tooltipObj); 168 }; 169 170 function removeTooltip(tooltipObj) { 171 Util.addClass(tooltipObj.tooltip, 'tooltip--is-hidden'); 172 if(tooltipObj.tooltipDescription) tooltipObj.element.removeAttribute('aria-describedby'); 173 }; 174 175 window.Tooltip = Tooltip; 176 177 //initialize the Tooltip objects 178 var tooltips = document.getElementsByClassName('js-tooltip-trigger'); 179 if( tooltips.length > 0 ) { 180 for( var i = 0; i < tooltips.length; i++) { 181 (function(i){new Tooltip(tooltips[i]);})(i); 182 } 183 } 184}());
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.