Commit 0faf72b0 authored by Enrique Alcantara's avatar Enrique Alcantara

Implement tooltip API for the following actions

Hide and show a tooltip
Enable or disable a tooltip
Update a tooltip content
parent 81e77674
......@@ -39,7 +39,7 @@ export default {
created() {
this.observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
this.dispose(mutation.removedNodes);
mutation.removedNodes.forEach(this.dispose);
});
});
},
......@@ -61,22 +61,36 @@ export default {
childList: true,
});
},
dispose(elements) {
if (!elements) {
dispose(target) {
if (!target) {
this.tooltips = [];
return;
}
elements.forEach(element => {
const index = this.tooltips.findIndex(tooltip => tooltip.target === element);
} else {
const index = this.tooltips.indexOf(this.findTooltipByTarget(target));
if (index > -1) {
this.tooltips.splice(index, 1);
}
});
}
},
fixTitle(target) {
const tooltip = this.findTooltipByTarget(target);
if (tooltip) {
tooltip.title = target.getAttribute('title');
}
},
triggerEvent(target, event) {
const tooltip = this.findTooltipByTarget(target);
if (tooltip) {
this.$refs[tooltip.id][0].$emit(event);
}
},
tooltipExists(element) {
return this.tooltips.some(tooltip => tooltip.target === element);
return Boolean(this.findTooltipByTarget(element));
},
findTooltipByTarget(element) {
return this.tooltips.find(tooltip => tooltip.target === element);
},
},
};
......@@ -86,6 +100,7 @@ export default {
<gl-tooltip
v-for="(tooltip, index) in tooltips"
:id="tooltip.id"
:ref="tooltip.id"
:key="index"
:target="tooltip.target"
:triggers="tooltip.triggers"
......
import Vue from 'vue';
import { toArray } from 'lodash';
import Tooltips from './components/tooltips.vue';
let app;
......@@ -31,13 +32,13 @@ const tooltipsApp = () => {
}).$mount(container);
}
return app;
return app.$refs.tooltips;
};
const isTooltip = (node, selector) => node.matches && node.matches(selector);
const addTooltips = (elements, config) => {
tooltipsApp().$refs.tooltips.addTooltips(Array.from(elements), config);
tooltipsApp().addTooltips(toArray(elements), config);
};
const handleTooltipEvent = (rootTarget, e, selector, config = {}) => {
......@@ -63,9 +64,14 @@ export const initTooltips = (selector, config = {}) => {
return tooltipsApp();
};
export const dispose = elements => {
return tooltipsApp().$refs.tooltips.dispose(elements);
};
const elementsIterator = handler => elements => toArray(elements).forEach(handler);
export const dispose = elementsIterator(element => tooltipsApp().dispose(element));
export const fixTitle = elementsIterator(element => tooltipsApp().fixTitle(element));
export const enable = elementsIterator(element => tooltipsApp().triggerEvent(element, 'enable'));
export const disable = elementsIterator(element => tooltipsApp().triggerEvent(element, 'disable'));
export const hide = elementsIterator(element => tooltipsApp().triggerEvent(element, 'close'));
export const show = elementsIterator(element => tooltipsApp().triggerEvent(element, 'open'));
export const destroy = () => {
tooltipsApp().$destroy();
......
......@@ -120,7 +120,7 @@ describe('tooltips/components/tooltips.vue', () => {
wrapper.vm.addTooltips([target, createTooltipTarget()]);
await wrapper.vm.$nextTick();
wrapper.vm.dispose([target]);
wrapper.vm.dispose(target);
await wrapper.vm.$nextTick();
expect(allTooltips()).toHaveLength(1);
......@@ -148,6 +148,48 @@ describe('tooltips/components/tooltips.vue', () => {
});
});
describe('triggerEvent', () => {
it('triggers a bootstrap-vue tooltip global event for the tooltip specified', async () => {
const target = createTooltipTarget();
const event = 'hide';
buildWrapper();
wrapper.vm.addTooltips([target]);
await wrapper.vm.$nextTick();
wrapper.vm.triggerEvent(target, event);
expect(wrapper.find(GlTooltip).emitted(event)).toHaveLength(1);
});
});
describe('fixTitle', () => {
it('updates tooltip content with the latest value the target title property', async () => {
const target = createTooltipTarget();
const currentTitle = 'title';
const newTitle = 'new title';
target.setAttribute('title', currentTitle);
buildWrapper();
wrapper.vm.addTooltips([target]);
await wrapper.vm.$nextTick();
expect(wrapper.find(GlTooltip).text()).toBe(currentTitle);
target.setAttribute('title', newTitle);
wrapper.vm.fixTitle(target);
await wrapper.vm.$nextTick();
expect(wrapper.find(GlTooltip).text()).toBe(newTitle);
});
});
it('disconnects mutation observer on beforeDestroy', () => {
buildWrapper();
wrapper.vm.addTooltips([createTooltipTarget()]);
......
import { initTooltips, dispose, destroy } from '~/tooltips';
import { initTooltips, dispose, destroy, hide, show, enable, disable, fixTitle } from '~/tooltips';
describe('tooltips/index.js', () => {
let tooltipsApp;
......@@ -80,4 +80,41 @@ describe('tooltips/index.js', () => {
expect(document.querySelector('.gl-tooltip')).toBe(null);
});
});
it.each`
methodName | method | event
${'enable'} | ${enable} | ${'enable'}
${'disable'} | ${disable} | ${'disable'}
${'hide'} | ${hide} | ${'close'}
${'show'} | ${show} | ${'open'}
`(
'$methodName calls triggerEvent in tooltip app with $event event',
async ({ method, event }) => {
const target = createTooltipTarget();
buildTooltipsApp();
await tooltipsApp.$nextTick();
jest.spyOn(tooltipsApp, 'triggerEvent');
method([target]);
expect(tooltipsApp.triggerEvent).toHaveBeenCalledWith(target, event);
},
);
it('fixTitle calls fixTitle in tooltip app with the target specified', async () => {
const target = createTooltipTarget();
buildTooltipsApp();
await tooltipsApp.$nextTick();
jest.spyOn(tooltipsApp, 'fixTitle');
fixTitle([target]);
expect(tooltipsApp.fixTitle).toHaveBeenCalledWith(target);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment