'use strict';/* Services */angular.module('tooltip',[]).factory('tooltip',['$rootScope','$compile',function($rootScope,$compile){// init tooltipvarscope=$rootScope.$new(true);varisMouseInTooltip=false;scope.onmouseenter=function(){// mouse enters tooltipisMouseInTooltip=true;};scope.onmouseleave=function(){// mouse leaves tooltipisMouseInTooltip=false;hide();};var_left=0;var_top=0;vartooltip=$compile('<div class="tooltip" ng-mouseenter="onmouseenter()" ng-mouseleave="onmouseleave()"></div>')(scope);tooltip.css('max-width',viewWidth()+'px');// append tooltip to the end of body elementangular.element(document.getElementsByTagName('body')[0]).append(tooltip);functionviewWidth(){// FIXME: why -32 here?return(window.innerWidth||document.documentElement.clientWidth)-32;}functionsetContent(content){tooltip.children().remove();if(angular.isUndefined(content)){throw'In tooltip: content undefined!';}elseif(angular.isString(content)){tooltip.html(content);}else{tooltip.append(content);}}functionsetPosition(position){_left=parseInt(position.left.replace('px',''));_top=parseInt(position.top.replace('px',''));}functionshow(){// move tooltip to the right// (don't cross the right side of browser inner window)var_right=_left+tooltip.prop('offsetWidth');if(_right>viewWidth())_left-=(_right-viewWidth());tooltip.css('left',_left+'px');tooltip.css('top',_top+'px');}functionhide(){if(!isMouseInTooltip)tooltip.css('left','-9999px');}varserviceInstance={viewWidth:viewWidth,isHidden:function(){return(tooltip.css('left')==='-9999px');},getLeftSpace:function(){return_left;},getRightSpace:function(){returnviewWidth()-_left-tooltip.prop('offsetWidth');},setContent:setContent,setPosition:setPosition,show:show,hide:hide};returnserviceInstance;}]).factory('AddTooltipToElement',['tooltip',function(tooltip){// when user's mouse hovers over words,// delay a period of time before look up.varDELAY_INTERVAL=1000;// msvarisMouseInWord=false;functiononWordMouseOver(e){isMouseInWord=true;this.style.color='red';setTimeout(angular.bind(this,function(){// 'this' keyword here refers to raw dom elementif(this.style.color==='red'){// mouse is still on wordvarword=this.innerHTML.toLowerCase();tooltip.setContent(word+' '+word+'<br>'+'<span>'+word+'</span>'+' '+word);tooltip.setPosition({'left':(this.getBoundingClientRect().left+'px'),'top':(this.getBoundingClientRect().top+this.offsetHeight+'px'),});tooltip.show();}}),DELAY_INTERVAL);}functiononWordMouseOut(e){isMouseInWord=false;this.style.color='';setTimeout(angular.bind(this,function(){if(!isMouseInWord){tooltip.hide();}}),DELAY_INTERVAL);}functionadd(elm){elm.onmouseover=onWordMouseOver;elm.onmouseout=onWordMouseOut;}varserviceInstance={add:add};returnserviceInstance;}]);
/** * keyword: css long word force line break * http://webdesignerwall.com/tutorials/word-wrap-force-text-to-wrap */.tooltip{position:absolute;left:-9999px;background-color:#CCFFFF;border-radius:10px;font-family:Tahoma,Arial,serif;word-wrap:break-word;}
Tested on: Chromium Version 50.0.2661.102 Ubuntu 16.04 (64-bit), AngularJS 1.5.5.