55 * @ngdoc module
66 * @name material.components.tooltip
77 */
8- angular . module ( 'material.components.tooltip' , [
9- 'material.core'
10- ] )
11- . directive ( 'mdTooltip' , MdTooltipDirective ) ;
8+ angular
9+ . module ( 'material.components.tooltip' , [ 'material.core' ] )
10+ . directive ( 'mdTooltip' , MdTooltipDirective ) ;
1211
1312/**
1413 * @ngdoc directive
@@ -37,75 +36,89 @@ angular.module('material.components.tooltip', [
3736 */
3837function MdTooltipDirective ( $timeout , $window , $$rAF , $document , $mdUtil , $mdTheming , $rootElement , $animate , $q ) {
3938
40- var TOOLTIP_SHOW_DELAY = 0 ;
39+ var TOOLTIP_SHOW_DELAY = 300 ;
4140 var TOOLTIP_WINDOW_EDGE_SPACE = 8 ;
4241
4342 return {
4443 restrict : 'E' ,
4544 transclude : true ,
46- template :
47- ' <div class="md-background"></div>' +
48- ' <div class="md-content" ng-transclude></div>',
45+ template : '\
46+ <div class="md-background"></div>\
47+ <div class="md-content" ng-transclude></div>' ,
4948 scope : {
5049 visible : '=?mdVisible' ,
5150 delay : '=?mdDelay'
5251 } ,
5352 link : postLink
5453 } ;
5554
56- function postLink ( scope , element , attr , contentCtrl ) {
55+ function postLink ( scope , element , attr ) {
56+
5757 $mdTheming ( element ) ;
58- var parent = element . parent ( ) ;
59- var background = angular . element ( element [ 0 ] . getElementsByClassName ( 'md-background' ) [ 0 ] ) ;
60- var content = angular . element ( element [ 0 ] . getElementsByClassName ( 'md-content' ) [ 0 ] ) ;
61- var direction = attr . mdDirection ;
62-
63- // Keep looking for a higher parent if our current one has no pointer events
64- while ( $window . getComputedStyle ( parent [ 0 ] ) [ 'pointer-events' ] == 'none' ) {
65- parent = parent . parent ( ) ;
66- }
6758
68- // Look for the nearest parent md-content, stopping at the rootElement.
69- var current = element . parent ( ) [ 0 ] ;
70- while ( current && current !== $rootElement [ 0 ] && current !== document . body ) {
71- if ( current . tagName && current . tagName . toLowerCase ( ) == 'md-content' ) break ;
72- current = current . parentNode ;
59+ var parent = getParentWithPointerEvents ( ) ,
60+ background = angular . element ( element [ 0 ] . getElementsByClassName ( 'md-background' ) [ 0 ] ) ,
61+ content = angular . element ( element [ 0 ] . getElementsByClassName ( 'md-content' ) [ 0 ] ) ,
62+ direction = attr . mdDirection ,
63+ current = getNearestContentElement ( ) ,
64+ tooltipParent = angular . element ( current || document . body ) ,
65+ debouncedOnResize = $$rAF . throttle ( function ( ) { if ( scope . visible ) positionTooltip ( ) ; } ) ;
66+
67+ return init ( ) ;
68+
69+ function init ( ) {
70+ setDefaults ( ) ;
71+ manipulateElement ( ) ;
72+ bindEvents ( ) ;
73+ configureWatchers ( ) ;
7374 }
74- var tooltipParent = angular . element ( current || document . body ) ;
7575
76- if ( ! angular . isDefined ( attr . mdDelay ) ) {
77- scope . delay = TOOLTIP_SHOW_DELAY ;
76+ function setDefaults ( ) {
77+ if ( ! angular . isDefined ( attr . mdDelay ) ) scope . delay = TOOLTIP_SHOW_DELAY ;
7878 }
7979
80- // We will re-attach tooltip when visible
81- element . detach ( ) ;
82- element . attr ( 'role' , 'tooltip' ) ;
83- element . attr ( 'id' , attr . id || ( 'tooltip_' + $mdUtil . nextUid ( ) ) ) ;
84-
85- parent . on ( 'focus mouseenter touchstart' , function ( ) { setVisible ( true ) ; } ) ;
86- parent . on ( 'blur mouseleave touchend touchcancel' , function ( ) { if ( $document [ 0 ] . activeElement !== parent [ 0 ] ) setVisible ( false ) ; } ) ;
80+ function configureWatchers ( ) {
81+ scope . $watch ( 'visible' , function ( isVisible ) {
82+ if ( isVisible ) showTooltip ( ) ;
83+ else hideTooltip ( ) ;
84+ } ) ;
85+ scope . $on ( '$destroy' , function ( ) {
86+ scope . visible = false ;
87+ element . remove ( ) ;
88+ angular . element ( $window ) . off ( 'resize' , debouncedOnResize ) ;
89+ } ) ;
90+ }
8791
88- scope . $watch ( 'visible' , function ( isVisible ) {
89- if ( isVisible ) showTooltip ( ) ;
90- else hideTooltip ( ) ;
91- } ) ;
92+ function manipulateElement ( ) {
93+ element . detach ( ) ;
94+ element . attr ( 'role' , 'tooltip' ) ;
95+ element . attr ( 'id' , attr . id || ( 'tooltip_' + $mdUtil . nextUid ( ) ) ) ;
96+ }
9297
93- var debouncedOnResize = $$rAF . throttle ( function ( ) { if ( scope . visible ) positionTooltip ( ) ; } ) ;
94- angular . element ( $window ) . on ( 'resize' , debouncedOnResize ) ;
98+ function getParentWithPointerEvents ( ) {
99+ var parent = element . parent ( ) ;
100+ while ( $window . getComputedStyle ( parent [ 0 ] ) [ 'pointer-events' ] == 'none' ) {
101+ parent = parent . parent ( ) ;
102+ }
103+ return parent ;
104+ }
95105
96- // Be sure to completely cleanup the element on destroy
97- scope . $on ( '$destroy' , function ( ) {
98- scope . visible = false ;
99- element . remove ( ) ;
100- angular . element ( $window ) . off ( 'resize' , debouncedOnResize ) ;
101- } ) ;
106+ function getNearestContentElement ( ) {
107+ var current = element . parent ( ) [ 0 ] ;
108+ // Look for the nearest parent md-content, stopping at the rootElement.
109+ while ( current && current !== $rootElement [ 0 ] && current !== document . body ) {
110+ if ( current . tagName && current . tagName . toLowerCase ( ) == 'md-content' ) break ;
111+ current = current . parentNode ;
112+ }
113+ return current ;
114+ }
102115
103- // *******
104- // Methods
105- // *******
116+ function bindEvents ( ) {
117+ parent . on ( 'focus mouseenter touchstart' , function ( ) { setVisible ( true ) ; } ) ;
118+ parent . on ( 'blur mouseleave touchend touchcancel' , function ( ) { if ( $document [ 0 ] . activeElement !== parent [ 0 ] ) setVisible ( false ) ; } ) ;
119+ angular . element ( $window ) . on ( 'resize' , debouncedOnResize ) ;
120+ }
106121
107- // If setting visible to true, debounce to scope.delay ms
108- // If setting visible to false and no timeout is active, instantly hide the tooltip.
109122 function setVisible ( value ) {
110123 setVisible . value = ! ! value ;
111124 if ( ! setVisible . queued ) {
@@ -115,7 +128,6 @@ function MdTooltipDirective($timeout, $window, $$rAF, $document, $mdUtil, $mdThe
115128 scope . visible = setVisible . value ;
116129 setVisible . queued = false ;
117130 } , scope . delay ) ;
118-
119131 } else {
120132 $timeout ( function ( ) { scope . visible = false ; } ) ;
121133 }
@@ -127,12 +139,10 @@ function MdTooltipDirective($timeout, $window, $$rAF, $document, $mdUtil, $mdThe
127139 parent . attr ( 'aria-describedby' , element . attr ( 'id' ) ) ;
128140 tooltipParent . append ( element ) ;
129141
130- // Wait until the element has been in the dom for two frames before fading it in.
131- // Additionally, we position the tooltip twice to avoid positioning bugs
132142 positionTooltip ( ) ;
133- $animate . addClass ( element , 'md-show' ) ;
134- $animate . addClass ( background , 'md-show' ) ;
135- $animate . addClass ( content , 'md-show' ) ;
143+ angular . forEach ( [ element , background , content ] , function ( element ) {
144+ $animate . addClass ( element , 'md-show' ) ;
145+ } ) ;
136146 }
137147
138148 function hideTooltip ( ) {
0 commit comments