Skip to content
This repository has been archived by the owner on May 29, 2019. It is now read-only.

Commit

Permalink
feat(tooltip,popover): logic moved to $tooltip svc
Browse files Browse the repository at this point in the history
Popover and tooltip directive creation is now performed through the help
of the `$tooltip` service that manages all aspects of directive
creation and management based on only the name of the component and
their default triggers.

The tooltip and popover sub-directives and their templates were
refactored to use common scope variables that the new service can
provide, yielding even greater flexibility.

Animation is now enabled by default.

Lastly, the `$tooltipProvider` has been established to allow setting
default global options for the tooltip and popover, but these features
are not yet public as the API is sure to change drastically as we flesh
out which global options to allow. But the framework is in place as this
was a logical time to incorporate it.
  • Loading branch information
joshdmiller authored and pkozlowski-opensource committed Mar 13, 2013
1 parent 98b5f8e commit e22f28b
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 283 deletions.
3 changes: 3 additions & 0 deletions src/popover/docs/readme.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
A lightweight, extensible directive for fancy popover creation. The popover
directive supports multiple placements, optional transition animation, and more.

Like the Twitter Bootstrap jQuery plugin, the popover **requires** the tooltip
module.
144 changes: 4 additions & 140 deletions src/popover/popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,152 +3,16 @@
* function, placement as a function, inside, support for more triggers than
* just mouse enter/leave, html popovers, and selector delegatation.
*/
angular.module( 'ui.bootstrap.popover', [] )
angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
.directive( 'popoverPopup', function () {
return {
restrict: 'EA',
replace: true,
scope: { popoverTitle: '@', popoverContent: '@', placement: '@', animation: '&', isOpen: '&' },
scope: { title: '@', content: '@', placement: '@', animation: '&', isOpen: '&' },
templateUrl: 'template/popover/popover.html'
};
})
.directive( 'popover', [ '$compile', '$timeout', '$parse', '$window', function ( $compile, $timeout, $parse, $window ) {

var template =
'<popover-popup '+
'popover-title="{{tt_title}}" '+
'popover-content="{{tt_popover}}" '+
'placement="{{tt_placement}}" '+
'animation="tt_animation()" '+
'is-open="tt_isOpen"'+
'>'+
'</popover-popup>';

return {
scope: true,
link: function ( scope, element, attr ) {
var popover = $compile( template )( scope ),
transitionTimeout;

attr.$observe( 'popover', function ( val ) {
scope.tt_popover = val;
});

attr.$observe( 'popoverTitle', function ( val ) {
scope.tt_title = val;
});

attr.$observe( 'popoverPlacement', function ( val ) {
// If no placement was provided, default to 'top'.
scope.tt_placement = val || 'top';
});

attr.$observe( 'popoverAnimation', function ( val ) {
scope.tt_animation = $parse( val );
});

// By default, the popover is not open.
scope.tt_isOpen = false;

// Calculate the current position and size of the directive element.
function getPosition() {
var boundingClientRect = element[0].getBoundingClientRect();
return {
width: element.prop( 'offsetWidth' ),
height: element.prop( 'offsetHeight' ),
top: boundingClientRect.top + $window.pageYOffset,
left: boundingClientRect.left + $window.pageXOffset
};
}

function show() {
var position,
ttWidth,
ttHeight,
ttPosition;

// If there is a pending remove transition, we must cancel it, lest the
// toolip be mysteriously removed.
if ( transitionTimeout ) {
$timeout.cancel( transitionTimeout );
}

// Set the initial positioning.
popover.css({ top: 0, left: 0, display: 'block' });

// Now we add it to the DOM because need some info about it. But it's not
// visible yet anyway.
element.after( popover );

// Get the position of the directive element.
position = getPosition();

// Get the height and width of the popover so we can center it.
ttWidth = popover.prop( 'offsetWidth' );
ttHeight = popover.prop( 'offsetHeight' );

// Calculate the popover's top and left coordinates to center it with
// this directive.
switch ( scope.tt_placement ) {
case 'right':
ttPosition = {
top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
left: (position.left + position.width) + 'px'
};
break;
case 'bottom':
ttPosition = {
top: (position.top + position.height) + 'px',
left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
};
break;
case 'left':
ttPosition = {
top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
left: (position.left - ttWidth) + 'px'
};
break;
default:
ttPosition = {
top: (position.top - ttHeight) + 'px',
left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
};
break;
}

// Now set the calculated positioning.
popover.css( ttPosition );

// And show the popover.
scope.tt_isOpen = true;
}

// Hide the popover popup element.
function hide() {
// First things first: we don't show it anymore.
//popover.removeClass( 'in' );
scope.tt_isOpen = false;

// And now we remove it from the DOM. However, if we have animation, we
// need to wait for it to expire beforehand.
// FIXME: this is a placeholder for a port of the transitions library.
if ( angular.isDefined( scope.tt_animation ) && scope.tt_animation() ) {
transitionTimeout = $timeout( function () { popover.remove(); }, 500 );
} else {
popover.remove();
}
}

// Register the event listeners.
element.bind( 'click', function() {
if(scope.tt_isOpen){
scope.$apply( hide );
} else {
scope.$apply( show );
}

});
}
};
.directive( 'popover', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
return $tooltip( 'popover', 'click' );
}]);

12 changes: 6 additions & 6 deletions src/popover/test/popoverSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,20 +81,20 @@ describe('popover', function() {
tt.trigger( 'click' );

expect( tt.text() ).toBe( scope.items[0].name );
expect( tt.scope().tt_popover ).toBe( scope.items[0].popover );
expect( tt.scope().tt_content ).toBe( scope.items[0].popover );

tt.trigger( 'click' );
}));

it('should only have an isolate scope on the popup', inject( function ( $compile ) {
var ttScope;

scope.popoverMsg = "popover Text";
scope.popoverTitle = "popover Text";
scope.popoverContent = "Popover Content";
scope.popoverTitle = "Popover Title";
scope.alt = "Alt Message";

elmBody = $compile( angular.element(
'<div><span alt={{alt}} popover="{{popoverMsg}}" popover-title="{{popoverTitle}}">Selector Text</span></div>'
'<div><span alt={{alt}} popover="{{popoverContent}}" popover-title="{{popoverTitle}}">Selector Text</span></div>'
) )( scope );

$compile( elmBody )( scope );
Expand All @@ -107,8 +107,8 @@ describe('popover', function() {

ttScope = angular.element( elmBody.children()[1] ).scope();
expect( ttScope.placement ).toBe( 'top' );
expect( ttScope.popoverTitle ).toBe( scope.popoverTitle );
expect( ttScope.popoverContent ).toBe( scope.popoverMsg );
expect( ttScope.title ).toBe( scope.popoverTitle );
expect( ttScope.content ).toBe( scope.popoverContent );

elm.trigger( 'click' );
}));
Expand Down
2 changes: 1 addition & 1 deletion src/tooltip/docs/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
nunc sed velit dignissim sodales ut eu sem integer vitae. Turpis egestas
<a><span tooltip-placement="bottom" tooltip="On the Bottom!">bottom</span></a>
pharetra convallis posuere morbi leo urna,
<a><span tooltip-animation="true" tooltip="I fade in and out!">fading</span></a>
<a><span tooltip-animation="false" tooltip="I don't fade. :-(">fading</span></a>
at elementum eu, facilisis sed odio morbi quis commodo odio. In cursus
turpis massa tincidunt dui ut.
</p>
Expand Down
4 changes: 2 additions & 2 deletions src/tooltip/test/tooltip.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ describe('tooltip', function() {
tt.trigger( 'mouseenter' );

expect( tt.text() ).toBe( scope.items[0].name );
expect( tt.scope().tt_tooltip ).toBe( scope.items[0].tooltip );
expect( tt.scope().tt_content ).toBe( scope.items[0].tooltip );

tt.trigger( 'mouseleave' );
}));
Expand All @@ -106,7 +106,7 @@ describe('tooltip', function() {

ttScope = angular.element( elmBody.children()[1] ).scope();
expect( ttScope.placement ).toBe( 'top' );
expect( ttScope.tooltipTitle ).toBe( scope.tooltipMsg );
expect( ttScope.content ).toBe( scope.tooltipMsg );

elm.trigger( 'mouseleave' );
}));
Expand Down

0 comments on commit e22f28b

Please sign in to comment.