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

Option to display only one popover at a time #749

Closed
wants to merge 9 commits into from
Closed
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
121 changes: 116 additions & 5 deletions src/tooltip/tooltip.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
var defaultOptions = {
placement: 'top',
animation: true,
popupDelay: 0
popupDelay: 0,
popoverMode: 'multi'
};

// Default hide triggers for each show trigger
var triggerMap = {
'mouseenter': 'mouseleave',
Expand Down Expand Up @@ -98,6 +99,102 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
};
}

/**
* Hides all popovers except for the current one.
* If the current element is not a popover or its child,
* this function will hide all popovers (example on body.click())
* Invoked from show() and from body.click()
*/
function hideOthers(current) {
var isDomEvent = false;
if (current.target !== undefined) {
current = current.target;
isDomEvent = true;
}
/**
* Finds out recursively if an element is a child of another element
*/
function findChildRecursively(parent, child) {
if (parent === undefined) {
return false;
}

var cs = parent.childNodes;
if (cs === undefined) {
return false;
}

for (var i = 0, len = cs.length; i < len; i++) {
if (cs[i] == child) {
return true;
}
else {
// Find it in this tree
if (findChildRecursively(cs[i], child)) {
return true;
}
}
}
return false;
}

//Find all elements with the popover attribute
var popups = document.querySelectorAll('*[popover]');
if (popups) {
//Go through all of them
for (var i = 0; i < popups.length; i++) {
//The following is the popover DOM element
var popup = popups[i];
//The following is the same jQuery lite element
var popupElement = angular.element(popup);
//The following is the tooltips jQuery lite element
var tooltipElement = popupElement.scope().tooltip;
//The following is the toltip DOM element
var tooltip;
if (tooltipElement !== undefined && tooltipElement != null && tooltipElement.length > 0) {
tooltip = tooltipElement[0];
}
//If the element clicked is a child of the current popover's tooltip
var isTooltipChild = findChildRecursively(tooltip, current);
//If the element clicked is a child of the current popover
var isPopoverChild = findChildRecursively(popup, current);

//If the following condition is met, then the click does not correspond
//to a click on the current popover in the loop or one of its children or its content.
//So, we can safely hide the current popover
if (
popup != current && //The click was not on this popup
!isPopoverChild && //And it was not on any child of this popup
tooltip != current && //And it was not on this popups tooltip
!isTooltipChild //And it was not on any child of this popups tooltip
) {
//If we have a tooltip for this popup
if (tooltip !== undefined) {
//And its width/height != 0 (i.e. it is displayed)
var w = tooltip.offsetWidth, h = tooltip.offsetHeight;

if (w !== 0 && h !== 0) {
//Toggle its visibility
if (isDomEvent) {
popupElement.scope().hideTooltipBind();
}
else {
popupElement.scope().hide();
}
}
}
}
}
}
}

//If mode is 'single' then bind to body click
var popoverMode = angular.isDefined(options.popoverMode) ? options.popoverMode : 'multi';
//If this is a popover and mode in options is set to single, then bind to body elements
if (type == 'popover' && popoverMode == 'single') {
angular.element(document.body).bind('click', hideOthers);
}

var directiveName = snake_case( type );
var triggers = setTriggers( undefined );

Expand All @@ -109,10 +206,10 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
'content="'+startSym+'tt_content'+endSym+'" '+
'placement="'+startSym+'tt_placement'+endSym+'" '+
'animation="tt_animation()" '+
'is-open="tt_isOpen"'+
'is-open="tt_isOpen" '+
'style="z-index:9999"' + //Changed z-index so that popover is visible over modal when appendToBody is true
'>'+
'</'+ directiveName +'-popup>';

return {
restrict: 'EA',
scope: true,
Expand All @@ -126,6 +223,10 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
// By default, the tooltip is not open.
// TODO add ability to start tooltip opened
scope.tt_isOpen = false;

//We need access to this if we want to hide
//etc. on body click
scope.tooltip = tooltip;

function toggleTooltipBind () {
if ( ! scope.tt_isOpen ) {
Expand All @@ -134,7 +235,7 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
hideTooltipBind();
}
}

// Show the tooltip with delay if specified, otherwise show it immediately
function showTooltipBind() {
if ( scope.tt_popupDelay ) {
Expand All @@ -149,9 +250,19 @@ angular.module( 'ui.bootstrap.tooltip', [ 'ui.bootstrap.position' ] )
hide();
});
}

//Need to expose above function so that we can globally hide tooltips
scope.hideTooltipBind = hideTooltipBind;
scope.hide = hide;

// Show the tooltip popup element.
function show() {
var popoverMode = angular.isDefined(options.popoverMode) ? options.popoverMode : 'multi';
//If this is a popover and mode in options is set to single, then bind to body elements
if (type == 'popover' && popoverMode == 'single') {
hideOthers(element[0]);
}

var position,
ttWidth,
ttHeight,
Expand Down