diff options
Diffstat (limited to 'app/assets/javascripts/tooltips/components/tooltips.vue')
-rw-r--r-- | app/assets/javascripts/tooltips/components/tooltips.vue | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/app/assets/javascripts/tooltips/components/tooltips.vue b/app/assets/javascripts/tooltips/components/tooltips.vue new file mode 100644 index 00000000000..8307f878def --- /dev/null +++ b/app/assets/javascripts/tooltips/components/tooltips.vue @@ -0,0 +1,116 @@ +<script> +import { GlTooltip, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; +import { uniqueId } from 'lodash'; + +const getTooltipTitle = element => { + return element.getAttribute('title') || element.dataset.title; +}; + +const newTooltip = (element, config = {}) => { + const { placement, container, boundary, html, triggers } = element.dataset; + const title = getTooltipTitle(element); + + return { + id: uniqueId('gl-tooltip'), + target: element, + title, + html, + placement, + container, + boundary, + triggers, + disabled: !title, + ...config, + }; +}; + +export default { + components: { + GlTooltip, + }, + directives: { + SafeHtml, + }, + data() { + return { + tooltips: [], + }; + }, + created() { + this.observer = new MutationObserver(mutations => { + mutations.forEach(mutation => { + mutation.removedNodes.forEach(this.dispose); + }); + }); + }, + beforeDestroy() { + this.observer.disconnect(); + }, + methods: { + addTooltips(elements, config) { + const newTooltips = elements + .filter(element => !this.tooltipExists(element)) + .map(element => newTooltip(element, config)); + + newTooltips.forEach(tooltip => this.observe(tooltip)); + + this.tooltips.push(...newTooltips); + }, + observe(tooltip) { + this.observer.observe(tooltip.target.parentElement, { + childList: true, + }); + }, + dispose(target) { + if (!target) { + this.tooltips = []; + } 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 Boolean(this.findTooltipByTarget(element)); + }, + findTooltipByTarget(element) { + return this.tooltips.find(tooltip => tooltip.target === element); + }, + }, +}; +</script> +<template> + <div> + <gl-tooltip + v-for="(tooltip, index) in tooltips" + :id="tooltip.id" + :ref="tooltip.id" + :key="index" + :target="tooltip.target" + :triggers="tooltip.triggers" + :placement="tooltip.placement" + :container="tooltip.container" + :boundary="tooltip.boundary" + :disabled="tooltip.disabled" + > + <span v-if="tooltip.html" v-safe-html="tooltip.title"></span> + <span v-else>{{ tooltip.title }}</span> + </gl-tooltip> + </div> +</template> |