Skip to content

Commit 02b2ce2

Browse files
demo(popover): add popover demo and tooltip fixes
1 parent 8dc26d9 commit 02b2ce2

File tree

5 files changed

+485
-21
lines changed

5 files changed

+485
-21
lines changed

index.html

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060

6161
<li><a href="#pagination">Pagination</a></li>
6262

63+
<li><a href="#popover">Popover</a></li>
64+
6365
<li><a href="#tabs">Tabs</a></li>
6466

6567
<li><a href="#tooltip">Tooltip</a></li>
@@ -844,6 +846,93 @@ <h1>Pagination</h1>
844846
$scope.currentPage = pageNo;
845847
};
846848
};
849+
</script>
850+
851+
<section id="popover">
852+
<div class="page-header">
853+
<h1>Popover</h1>
854+
</div>
855+
<div class="row">
856+
<div class="span6">
857+
<div ng-controller="PopoverDemoCtrl">
858+
<div class="well">
859+
<div>
860+
<h4>Dynamic</h4>
861+
<div>Dynamic Popover : <input type="text" ng-model="dynamicPopoverText"></div>
862+
<div>Dynamic Popover Popup Text: <input type="text" ng-model="dynamicPopover"></div>
863+
<div>Dynamic Popover Popup Title: <input type="text" ng-model="dynamicPopoverTitle"></div>
864+
<div><button popover="{{dynamicPopover}}" popover-title="{{dynamicPopoverTitle}}" class="btn">{{dynamicPopoverText}}</button></div>
865+
</div>
866+
<div>
867+
<h4>Positional</h4>
868+
<button popover-placement="top" popover="On the Top!" class="btn">Top</button>
869+
<button popover-placement="left" popover="On the Left!" class="btn">Left</button>
870+
<button popover-placement="right" popover="On the Right!" class="btn">Right</button>
871+
<button popover-placement="bottom" popover="On the Bottom!" class="btn">Bottom</button>
872+
</div>
873+
<div>
874+
<h4>Other</h4>
875+
<button Popover-animation="true" popover="I fade in and out!" class="btn">fading</button>
876+
<button popover="I have a title!" popover-title="The title." class="btn">title</button>
877+
</div>
878+
</div>
879+
</div>
880+
881+
</div>
882+
<div class="span6">
883+
<p>A lightweight, extensible directive for fancy popover creation. The popover
884+
directive supports multiple placements, optional transition animation, and more.</p>
885+
<section>
886+
Directive is found in the module <a href="https://github.com/angular-ui/bootstrap/tree/master/src/popover">ui.bootstrap.popover</a>
887+
</section>
888+
</div>
889+
</div>
890+
<hr>
891+
<div class="row">
892+
<div class="span12" ng-controller="PlunkerCtrl">
893+
<div class="pull-right">
894+
<button class="btn btn-info" id="plunk-btn" ng-click="edit('1.0.4', '0.1.0-SNAPSHOT', 'popover')"><i class="icon-edit icon-white"></i> Edit in plunker</button>
895+
</div>
896+
<tabs>
897+
<pane heading="Markup" plunker-content="markup"><pre ng-non-bindable><code data-language="html">&lt;div ng-controller=&quot;PopoverDemoCtrl&quot;&gt;
898+
&lt;div class=&quot;well&quot;&gt;
899+
&lt;div&gt;
900+
&lt;h4&gt;Dynamic&lt;&#x2F;h4&gt;
901+
&lt;div&gt;Dynamic Popover : &lt;input type=&quot;text&quot; ng-model=&quot;dynamicPopoverText&quot;&gt;&lt;&#x2F;div&gt;
902+
&lt;div&gt;Dynamic Popover Popup Text: &lt;input type=&quot;text&quot; ng-model=&quot;dynamicPopover&quot;&gt;&lt;&#x2F;div&gt;
903+
&lt;div&gt;Dynamic Popover Popup Title: &lt;input type=&quot;text&quot; ng-model=&quot;dynamicPopoverTitle&quot;&gt;&lt;&#x2F;div&gt;
904+
&lt;div&gt;&lt;button popover=&quot;{{dynamicPopover}}&quot; popover-title=&quot;{{dynamicPopoverTitle}}&quot; class=&quot;btn&quot;&gt;{{dynamicPopoverText}}&lt;&#x2F;button&gt;&lt;&#x2F;div&gt;
905+
&lt;&#x2F;div&gt;
906+
&lt;div&gt;
907+
&lt;h4&gt;Positional&lt;&#x2F;h4&gt;
908+
&lt;button popover-placement=&quot;top&quot; popover=&quot;On the Top!&quot; class=&quot;btn&quot;&gt;Top&lt;&#x2F;button&gt;
909+
&lt;button popover-placement=&quot;left&quot; popover=&quot;On the Left!&quot; class=&quot;btn&quot;&gt;Left&lt;&#x2F;button&gt;
910+
&lt;button popover-placement=&quot;right&quot; popover=&quot;On the Right!&quot; class=&quot;btn&quot;&gt;Right&lt;&#x2F;button&gt;
911+
&lt;button popover-placement=&quot;bottom&quot; popover=&quot;On the Bottom!&quot; class=&quot;btn&quot;&gt;Bottom&lt;&#x2F;button&gt;
912+
&lt;&#x2F;div&gt;
913+
&lt;div&gt;
914+
&lt;h4&gt;Other&lt;&#x2F;h4&gt;
915+
&lt;button Popover-animation=&quot;true&quot; popover=&quot;I fade in and out!&quot; class=&quot;btn&quot;&gt;fading&lt;&#x2F;button&gt;
916+
&lt;button popover=&quot;I have a title!&quot; popover-title=&quot;The title.&quot; class=&quot;btn&quot;&gt;title&lt;&#x2F;button&gt;
917+
&lt;&#x2F;div&gt;
918+
&lt;&#x2F;div&gt;
919+
&lt;&#x2F;div&gt;
920+
</code></pre></pane>
921+
<pane heading="JavaScript" plunker-content="javascript"><pre ng-non-bindable><code data-language="javascript">var PopoverDemoCtrl = function ($scope) {
922+
$scope.dynamicPopover = &quot;Hello, World!&quot;;
923+
$scope.dynamicPopoverText = &quot;dynamic&quot;;
924+
$scope.dynamicPopoverTitle = &quot;Title&quot;;
925+
};
926+
</code></pre></pane>
927+
</tabs>
928+
</div>
929+
</div>
930+
</section>
931+
<script>var PopoverDemoCtrl = function ($scope) {
932+
$scope.dynamicPopover = "Hello, World!";
933+
$scope.dynamicPopoverText = "dynamic";
934+
$scope.dynamicPopoverTitle = "Title";
935+
};
847936
</script>
848937

849938
<section id="tabs">
@@ -1022,6 +1111,8 @@ <h3 style="text-align: center;">{{buildErrorText}}</h3>
10221111

10231112
<option value="pagination">Pagination</option>
10241113

1114+
<option value="popover">Popover</option>
1115+
10251116
<option value="tabs">Tabs</option>
10261117

10271118
<option value="tooltip">Tooltip</option>

ui-bootstrap-0.1.0-SNAPSHOT.js

Lines changed: 189 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
angular.module("ui.bootstrap", ["ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.carousel","ui.bootstrap.collapse","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.tabs","ui.bootstrap.tooltip","ui.bootstrap.transition"]);
1+
angular.module("ui.bootstrap", ["ui.bootstrap.accordion","ui.bootstrap.alert","ui.bootstrap.carousel","ui.bootstrap.collapse","ui.bootstrap.dialog","ui.bootstrap.dropdownToggle","ui.bootstrap.modal","ui.bootstrap.pagination","ui.bootstrap.popover","ui.bootstrap.tabs","ui.bootstrap.tooltip","ui.bootstrap.transition"]);
22

33
angular.module('ui.bootstrap.accordion', ['ui.bootstrap.collapse'])
44

@@ -316,7 +316,20 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
316316
link: function(scope, element, attrs) {
317317

318318
var isCollapsed;
319-
319+
var initialAnimSkip = true;
320+
scope.$watch(function (){ return element[0].scrollHeight; }, function (value) {
321+
//The listener is called when scollHeight changes
322+
//It actually does on 2 scenarios:
323+
// 1. Parent is set to display none
324+
// 2. angular bindings inside are resolved
325+
//When we have a change of scrollHeight we are setting again the correct height if the group is opened
326+
if (element[0].scrollHeight !== 0) {
327+
if (!isCollapsed) {
328+
fixUpHeight(scope, element, element[0].scrollHeight + 'px');
329+
}
330+
}
331+
});
332+
320333
scope.$watch(attrs.collapse, function(value) {
321334
if (value) {
322335
collapse();
@@ -340,21 +353,33 @@ angular.module('ui.bootstrap.collapse',['ui.bootstrap.transition'])
340353
};
341354

342355
var expand = function() {
343-
doTransition({ height : element[0].scrollHeight + 'px' })
344-
.then(function() {
345-
// This check ensures that we don't accidentally update the height if the user has closed
346-
// the group while the animation was still running
356+
if (initialAnimSkip) {
357+
initialAnimSkip = false;
347358
if ( !isCollapsed ) {
348359
fixUpHeight(scope, element, 'auto');
349360
}
350-
});
361+
} else {
362+
doTransition({ height : element[0].scrollHeight + 'px' })
363+
.then(function() {
364+
// This check ensures that we don't accidentally update the height if the user has closed
365+
// the group while the animation was still running
366+
if ( !isCollapsed ) {
367+
fixUpHeight(scope, element, 'auto');
368+
}
369+
});
370+
}
351371
isCollapsed = false;
352372
};
353373

354374
var collapse = function() {
355375
isCollapsed = true;
356-
fixUpHeight(scope, element, element[0].scrollHeight + 'px');
357-
doTransition({'height':'0'});
376+
if (initialAnimSkip) {
377+
initialAnimSkip = false;
378+
fixUpHeight(scope, element, 0);
379+
} else {
380+
fixUpHeight(scope, element, element[0].scrollHeight + 'px');
381+
doTransition({'height':'0'});
382+
}
358383
};
359384
}
360385
};
@@ -828,6 +853,161 @@ angular.module('ui.bootstrap.pagination', [])
828853
}
829854
};
830855
});
856+
/**
857+
* The following features are still outstanding: popup delay, animation as a
858+
* function, placement as a function, inside, support for more triggers than
859+
* just mouse enter/leave, html popovers, and selector delegatation.
860+
*/
861+
angular.module( 'ui.bootstrap.popover', [] )
862+
.directive( 'popoverPopup', function () {
863+
return {
864+
restrict: 'EA',
865+
replace: true,
866+
scope: { popoverTitle: '@', popoverContent: '@', placement: '@', animation: '&', isOpen: '&' },
867+
templateUrl: 'template/popover/popover.html'
868+
};
869+
})
870+
.directive( 'popover', [ '$compile', '$timeout', '$parse', function ( $compile, $timeout, $parse ) {
871+
872+
var template =
873+
'<popover-popup '+
874+
'popover-title="{{tt_title}}" '+
875+
'popover-content="{{tt_popover}}" '+
876+
'placement="{{tt_placement}}" '+
877+
'animation="tt_animation()" '+
878+
'is-open="tt_isOpen"'+
879+
'>'+
880+
'</popover-popup>';
881+
882+
return {
883+
scope: true,
884+
link: function ( scope, element, attr ) {
885+
var popover = $compile( template )( scope ),
886+
transitionTimeout;
887+
888+
attr.$observe( 'popover', function ( val ) {
889+
scope.tt_popover = val;
890+
});
891+
892+
attr.$observe( 'popoverTitle', function ( val ) {
893+
scope.tt_title = val;
894+
});
895+
896+
attr.$observe( 'popoverPlacement', function ( val ) {
897+
// If no placement was provided, default to 'top'.
898+
scope.tt_placement = val || 'top';
899+
});
900+
901+
attr.$observe( 'popoverAnimation', function ( val ) {
902+
scope.tt_animation = $parse( val );
903+
});
904+
905+
// By default, the popover is not open.
906+
scope.tt_isOpen = false;
907+
908+
// Calculate the current position and size of the directive element.
909+
function getPosition() {
910+
return {
911+
width: element.prop( 'offsetWidth' ),
912+
height: element.prop( 'offsetHeight' ),
913+
top: element.prop( 'offsetTop' ),
914+
left: element.prop( 'offsetLeft' )
915+
};
916+
}
917+
918+
// Show the popover popup element.
919+
function show() {
920+
var position,
921+
ttWidth,
922+
ttHeight,
923+
ttPosition;
924+
925+
// If there is a pending remove transition, we must cancel it, lest the
926+
// toolip be mysteriously removed.
927+
if ( transitionTimeout ) {
928+
$timeout.cancel( transitionTimeout );
929+
}
930+
931+
// Set the initial positioning.
932+
popover.css({ top: 0, left: 0, display: 'block' });
933+
934+
// Now we add it to the DOM because need some info about it. But it's not
935+
// visible yet anyway.
936+
element.after( popover );
937+
938+
// Get the position of the directive element.
939+
position = getPosition();
940+
941+
// Get the height and width of the popover so we can center it.
942+
ttWidth = popover.prop( 'offsetWidth' );
943+
ttHeight = popover.prop( 'offsetHeight' );
944+
945+
// Calculate the popover's top and left coordinates to center it with
946+
// this directive.
947+
switch ( scope.tt_placement ) {
948+
case 'right':
949+
ttPosition = {
950+
top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
951+
left: (position.left + position.width) + 'px'
952+
};
953+
break;
954+
case 'bottom':
955+
ttPosition = {
956+
top: (position.top + position.height) + 'px',
957+
left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
958+
};
959+
break;
960+
case 'left':
961+
ttPosition = {
962+
top: (position.top + position.height / 2 - ttHeight / 2) + 'px',
963+
left: (position.left - ttWidth) + 'px'
964+
};
965+
break;
966+
default:
967+
ttPosition = {
968+
top: (position.top - ttHeight) + 'px',
969+
left: (position.left + position.width / 2 - ttWidth / 2) + 'px'
970+
};
971+
break;
972+
}
973+
974+
// Now set the calculated positioning.
975+
popover.css( ttPosition );
976+
977+
// And show the popover.
978+
scope.tt_isOpen = true;
979+
}
980+
981+
// Hide the popover popup element.
982+
function hide() {
983+
// First things first: we don't show it anymore.
984+
//popover.removeClass( 'in' );
985+
scope.tt_isOpen = false;
986+
987+
// And now we remove it from the DOM. However, if we have animation, we
988+
// need to wait for it to expire beforehand.
989+
// FIXME: this is a placeholder for a port of the transitions library.
990+
if ( angular.isDefined( scope.tt_animation ) && scope.tt_animation() ) {
991+
transitionTimeout = $timeout( function () { popover.remove(); }, 500 );
992+
} else {
993+
popover.remove();
994+
}
995+
}
996+
997+
// Register the event listeners.
998+
element.bind( 'click', function() {
999+
if(scope.tt_isOpen){
1000+
scope.$apply( hide );
1001+
} else {
1002+
scope.$apply( show );
1003+
}
1004+
1005+
});
1006+
}
1007+
};
1008+
}]);
1009+
1010+
8311011
angular.module('ui.bootstrap.tabs', [])
8321012
.controller('TabsController', ['$scope', '$element', function($scope, $element) {
8331013
var panes = $scope.panes = [];

0 commit comments

Comments
 (0)