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

feat(tooltip): added tooltip-html-unsafe directive #257

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/popover/docs/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,14 @@ directive supports multiple placements, optional transition animation, and more.

Like the Twitter Bootstrap jQuery plugin, the popover **requires** the tooltip
module.

The popover directives provides several optional attributes to control how it
will display:

- `popover-title`: A string to display as a fancy title.
- `popover-placement`: Where to place it? Defaults to "top", but also accepts
"bottom", "left", or "right".
- `popover-animation`: Should it fade in and out? Defaults to "true".
- `popover-popup-delay`: For how long should the user have to have the mouse
over the element before the popover shows (in milliseconds)? Defaults to 0.

2 changes: 1 addition & 1 deletion src/popover/popover.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@ angular.module( 'ui.bootstrap.popover', [ 'ui.bootstrap.tooltip' ] )
};
})
.directive( 'popover', [ '$compile', '$timeout', '$parse', '$window', '$tooltip', function ( $compile, $timeout, $parse, $window, $tooltip ) {
return $tooltip( 'popover', 'click' );
return $tooltip( 'popover', 'popover', 'click' );
}]);

4 changes: 4 additions & 0 deletions src/tooltip/docs/demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@
at elementum eu, facilisis sed odio morbi quis commodo odio. In cursus
<a><span tooltip-popup-delay='1000' tooltip='appears with delay'>delayed</span></a> turpis massa tincidunt dui ut.
</p>

<p>
I can even contain HTML. <a><span tooltip-html-unsafe="{{htmlTooltip}}">Check me out!</span></a>
</p>
</div>
</div>
1 change: 1 addition & 0 deletions src/tooltip/docs/demo.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var TooltipDemoCtrl = function ($scope) {
$scope.dynamicTooltip = "Hello, World!";
$scope.dynamicTooltipText = "dynamic";
$scope.htmlTooltip = "I've been made <b>bold</b>!";
};
16 changes: 16 additions & 0 deletions src/tooltip/docs/readme.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,18 @@
A lightweight, extensible directive for fancy tooltip creation. The tooltip
directive supports multiple placements, optional transition animation, and more.

There are two versions of the tooltip: `tooltip` and `tooltip-html-unsafe`. The
former takes text only and will escape any HTML provided. The latter takes
whatever HTML is provided and displays it in a tooltip; it called "unsafe"
because the HTML is not sanitized. *The user is responsible for ensuring the
content is safe to put into the DOM!*

The tooltip directives provide several optional attributes to control how they
will display:

- `tooltip-placement`: Where to place it? Defaults to "top", but also accepts
"bottom", "left", or "right".
- `tooltip-animation`: Should it fade in and out? Defaults to "true".
- `tooltip-popup-delay`: For how long should the user have to have the mouse
over the element before the tooltip shows (in milliseconds)? Defaults to 0.

37 changes: 37 additions & 0 deletions src/tooltip/test/tooltip.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,43 @@ describe('tooltip', function() {

});

describe( 'tooltipHtmlUnsafe', function() {
var elm, elmBody, scope;

// load the tooltip code
beforeEach(module('ui.bootstrap.tooltip', function ( $tooltipProvider ) {
$tooltipProvider.options({ animation: false });
}));

// load the template
beforeEach(module('template/tooltip/tooltip-html-unsafe-popup.html'));

beforeEach(inject(function($rootScope, $compile) {
scope = $rootScope;
scope.html = '<span class="hello">Hello!</span>';

elmBody = $compile( angular.element(
'<div><span tooltip-html-unsafe="{{html}}">Selector Text</span></div>'
))( scope );
scope.$digest();
elm = elmBody.find('span');
elmScope = elm.scope();
}));

it( 'should show on mouseenter and hide on mouseleave', inject( function () {
dump(elmScope);
expect( elmScope.tt_isOpen ).toBe( false );

elm.trigger( 'mouseenter' );
expect( elmScope.tt_isOpen ).toBe( true );
expect( elmBody.children().length ).toBe( 2 );

elm.trigger( 'mouseleave' );
expect( elmScope.tt_isOpen ).toBe( false );
expect( elmBody.children().length ).toBe( 1 );
}));
});

describe( '$tooltipProvider', function() {

describe( 'popupDelay', function() {
Expand Down
45 changes: 36 additions & 9 deletions src/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,23 +33,35 @@ angular.module( 'ui.bootstrap.tooltip', [] )
angular.extend( globalOptions, value );
};

/**
* This is a helper function for translating camel-case to snake-case.
*/
function snake_case(name){
var regexp = /[A-Z]/g;
var separator = '-';
return name.replace(regexp, function(letter, pos) {
return (pos ? separator : '') + letter.toLowerCase();
});
}

/**
* Returns the actual instance of the $tooltip service.
* TODO support multiple triggers
*/
this.$get = [ '$window', '$compile', '$timeout', '$parse', '$document', function ( $window, $compile, $timeout, $parse, $document ) {
return function $tooltip ( type, defaultTriggerShow, defaultTriggerHide ) {
return function $tooltip ( type, prefix, defaultTriggerShow, defaultTriggerHide ) {
var options = angular.extend( {}, defaultOptions, globalOptions );
var directiveName = snake_case( type );

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

// Calculate the current position and size of the directive element.
function getPosition( element ) {
Expand All @@ -75,19 +87,19 @@ angular.module( 'ui.bootstrap.tooltip', [] )
scope.tt_content = val;
});

attrs.$observe( type+'Title', function ( val ) {
attrs.$observe( prefix+'Title', function ( val ) {
scope.tt_title = val;
});

attrs.$observe( type+'Placement', function ( val ) {
attrs.$observe( prefix+'Placement', function ( val ) {
scope.tt_placement = angular.isDefined( val ) ? val : options.placement;
});

attrs.$observe( type+'Animation', function ( val ) {
attrs.$observe( prefix+'Animation', function ( val ) {
scope.tt_animation = angular.isDefined( val ) ? $parse( val ) : function(){ return options.animation; };
});

attrs.$observe( type+'PopupDelay', function ( val ) {
attrs.$observe( prefix+'PopupDelay', function ( val ) {
var delay = parseInt( val, 10 );
scope.tt_popupDelay = ! isNaN(delay) ? delay : options.popupDelay;
});
Expand Down Expand Up @@ -232,6 +244,21 @@ angular.module( 'ui.bootstrap.tooltip', [] )
})

.directive( 'tooltip', [ '$tooltip', function ( $tooltip ) {
return $tooltip( 'tooltip', 'mouseenter', 'mouseleave' );
}]);
return $tooltip( 'tooltip', 'tooltip', 'mouseenter', 'mouseleave' );
}])

.directive( 'tooltipHtmlUnsafePopup', function () {
return {
restrict: 'E',
replace: true,
scope: { content: '@', placement: '@', animation: '&', isOpen: '&' },
templateUrl: 'template/tooltip/tooltip-html-unsafe-popup.html'
};
})

.directive( 'tooltipHtmlUnsafe', [ '$tooltip', function ( $tooltip ) {
return $tooltip( 'tooltipHtmlUnsafe', 'tooltip', 'mouseenter', 'mouseleave' );
}])

;

4 changes: 4 additions & 0 deletions template/tooltip/tooltip-html-unsafe-popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<div class="tooltip {{placement}}" ng-class="{ in: isOpen(), fade: animation() }">
<div class="tooltip-arrow"></div>
<div class="tooltip-inner" ng-bind-html-unsafe="content"></div>
</div>