Permalink
Browse files

feat(popover+tooltip): Add hide event listener on $root (#1003)

* feat(popover/tooltip): Add hide on $root events

Optimized adding/removing of events.

Only listen/watch to certain events while the tooltip/popover is open

Adds listener for `bv::hide::(popover|tooltip)` event on root to allow user to close all popovers or tooltips via emitting on $root.

* [popover component] Document bv:hide::popover event

* [tooltip component] Document bv:hide:tooltip event

* [popover directive] Document bv:hide:popover event

* [tooltip directive]: Document bv:hide::tooltip event
  • Loading branch information...
tmorehouse committed Sep 6, 2017
1 parent 36acf4e commit 6b12629da279e7f85b4314b7f663b49cc496b5ff
@@ -284,6 +284,13 @@ small screens can be harder to deal with on mobile devices (such as smart-phones
<!-- popover-advanced-1.vue -->
```

## Closing popovers
You can close all open popovers by emitting the `bv::hide::popover` event on $root:

```js
this.$root.$emit('bv::hide::popover');
```

## Accessibility
Popovers, in their current state, are not overly accessible when used as interactive
components. Content may not be activly read to screen reader users, and the popover
@@ -108,3 +108,11 @@ The `v-b-tooltip` directive makes adding tooltips even easier, without additiona

Refer to the [`v-b-tooltip` documentation](/docs/directives/tooltip) for more information
and features of the directive format.

## Closing tooltips
You can close all open tooltips by emitting the `bv::hide::tooltip` event on $root:

```js
this.$root.$emit('bv::hide::tooltip');
```

@@ -206,3 +206,10 @@ a focus change via pressing the <kbd>TAB</kbd> key). Some call this behavior _se

<!-- popover-2.vue -->
```

## Closing popovers
You can close all open popovers by emitting the `bv::hide::popover` event on $root:

```js
this.$root.$emit('bv::hide::popover');
```
@@ -143,3 +143,10 @@ receives focus.
Note that your elment **must** be in the document tab sequence for this to work. If
your element is not tabable, add the `tabindex="0"` attribute to the element.


## Closing tooltips
You can close all open tooltips by emitting the `bv::hide::tooltip` event on $root:

```js
this.$root.$emit('bv::hide::tooltip');
```
@@ -178,21 +178,26 @@ class ToolTip {

// Destroy this instance
destroy() {
this.visibleCheck(false);
// Stop listening to trigger events
this.unListen();
// Disable while open listeners/watchers
this.setWhileOpenListeners(false);
// Clear any timouts
clearTimeout(this.$hoverTimeout);
this.$hoverTimeout = null;
clearTimeout(this.$fadeTimeout);
this.$fadeTimeout = null;
this.unListen();
this.setOnTouchStartListener(false);
// Remove popper
if (this.$popper) {
this.$popper.destroy();
}
this.$popper = null;
// Remove tip from document
if (this.$tip && this.$tip.parentElement) {
this.$tip.parentElement.removeChild(this.$tip);
}
this.$tip = null;
// Null out other properties
this.$id = null
this.$root = null;
this.$element = null;
@@ -289,13 +294,11 @@ class ToolTip {
this.emitEvent(shownEvt);
};

// Enable while open listeners/watchers
this.setWhileOpenListeners(true);

// Show tip
tip.classList.add(ClassName.SHOW);
this.setOnTouchStartListener(true);

// Periodically check to make sure $element is visible
// For handling when tip is in <keepalive>, tabs, carousel, etc
this.visibleCheck(true);

// Start the transition/animation
this.transitionOnce(tip, complete);
@@ -316,6 +319,20 @@ class ToolTip {
}
}

setWhileOpenListeners(on) {
// Ontouch start listeners
this.setOnTouchStartListener(on);
// Global hide events
this.setRootListener(on);
// Modal close events
this.setModalListener(on);
// Route change events
this.setRouteWatcher(on);
// Periodic $element visibility check
// For handling when tip is in <keepalive>, tabs, carousel, etc
this.visibleCheck(on);
}

// force hide of tip (internal method)
forceHide() {
const tip = this.getTipElement();
@@ -349,9 +366,6 @@ class ToolTip {
return;
}

// Stop checking for visibility of element.
this.visibleCheck(false);

// Transitionend Callback
const complete = () => {
if (this.$hoverState !== HoverState.SHOW && tip.parentNode) {
@@ -374,8 +388,10 @@ class ToolTip {
this.emitEvent(hiddenEvt);
};

// Disable while open listeners/watchers
this.setWhileOpenListeners(false);

// Hide tip
this.setOnTouchStartListener(false);
tip.classList.remove(ClassName.SHOW);

this.$activeTrigger.click = false;
@@ -582,10 +598,6 @@ class ToolTip {
this.$element.addEventListener('mouseleave', this);
}
}, this);
// If we are in a modal, we need to hide when it closes
this.setModalListener(true);
// Watch for route changes
this.setRouteWatcher(true);
}

unListen() {
@@ -594,9 +606,6 @@ class ToolTip {
events.forEach(evt => {
this.$element.removeEventListener(evt, this);
}, this);
this.setModalListener(false);
// stop watching for route changes
this.setRouteWatcher(false);
}

handleEvent(e) {
@@ -648,15 +657,16 @@ class ToolTip {
}
// We can listen for modal hidden events on $root
if (this.$root) {
if (on) {
MODAL_CLOSE_EVENT.forEach(evtName => {
this.$root.$on(evtName, this.forceHide.bind(this));
});
} else {
MODAL_CLOSE_EVENT.forEach(evtName => {
this.$root.$off(evtName, this.forceHide.bind(this));
});
}
MODAL_CLOSE_EVENT.forEach(evtName => {
this.$root[on ? '$on' : '$off'](evtName, this.forceHide.bind(this));
});
}
}

setRootListener(on) {
// We can listen for global 'bv::hide::popover/tooltip' hide request event
if (this.$root) {
this.$root[on ? '$on' : '$off'](`bv::hide::${this.constructor.NAME}`, this.forceHide.bind(this));
}
}

@@ -667,11 +677,7 @@ class ToolTip {
// https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
if ('ontouchstart' in document.documentElement) {
arrayFrom(document.body.children).forEach(el => {
if (on) {
el.addEventListener('mouseover', this.noop);
} else {
el.removeEventListener('mouseover', this.noop);
}
el[on ? 'addEventListener' : 'removeEventListener']('mouseover', this.noop);
});
}
}

0 comments on commit 6b12629

Please sign in to comment.