All files / src/directives v-tooltip.js

0% Statements 0/12
0% Branches 0/12
0% Functions 0/1
0% Lines 0/12
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216                                                                                                                                                                                                                                                                                                                                                                                                                                               
import Tooltip from '../lib/tooltip'
import { addClasses, removeClasses } from '../utils'
 
export let state = {
	enabled: true,
}
 
const positions = [
	'top',
	'top-start',
	'top-end',
	'right',
	'right-start',
	'right-end',
	'bottom',
	'bottom-start',
	'bottom-end',
	'left',
	'left-start',
	'left-end',
]
 
export const defaultOptions = {
	// Default tooltip placement relative to target element
	defaultPlacement: 'top',
	// Default CSS classes applied to the tooltip element
	defaultClass: 'vue-tooltip-theme',
	// Default CSS classes applied to the target element of the tooltip
	defaultTargetClass: 'has-tooltip',
	// Default HTML template of the tooltip element
	// It must include `tooltip-arrow` & `tooltip-inner` CSS classes (can be configured, see below)
	// Change if the classes conflict with other libraries (for example bootstrap)
	defaultTemplate: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
	// Selector used to get the arrow element in the tooltip template
	defaultArrowSelector: '.tooltip-arrow, .tooltip__arrow',
	// Selector used to get the inner content element in the tooltip template
	defaultInnerSelector: '.tooltip-inner, .tooltip__inner',
	// Delay (ms)
	defaultDelay: 0,
	// Default events that trigger the tooltip
	defaultTrigger: 'hover focus',
	// Default position offset (px)
	defaultOffset: 0,
	// Default container where the tooltip will be appended
	defaultContainer: 'body',
	defaultBoundariesElement: undefined,
	defaultPopperOptions: {},
	// Class added when content is loading
	defaultLoadingClass: 'tooltip-loading',
	// Displayed when tooltip content is loading
	defaultLoadingContent: '...',
	// Hide on mouseover tooltip
	autoHide: true,
	// Auto destroy tooltip DOM nodes (ms)
	disposeTimeout: 5000,
	// Options for popover
	popover: {
		defaultPlacement: 'bottom',
		// Use the `popoverClass` prop for theming
		defaultClass: 'vue-popover-theme',
		// Base class (change if conflicts with other libraries)
		defaultBaseClass: 'tooltip popover',
		// Wrapper class (contains arrow and inner)
		defaultWrapperClass: 'wrapper',
		// Inner content class
		defaultInnerClass: 'tooltip-inner popover-inner',
		// Arrow class
		defaultArrowClass: 'tooltip-arrow popover-arrow',
		defaultDelay: 0,
		defaultTrigger: 'click',
		defaultOffset: 0,
		defaultContainer: 'body',
		defaultBoundariesElement: undefined,
		defaultPopperOptions: {},
		// Hides if clicked outside of popover
		defaultAutoHide: true,
		// Update popper on content resize
		defaultHandleResize: true,
	},
}
 
export function getOptions (options) {
	const result = {
		placement: typeof options.placement !== 'undefined' ? options.placement : directive.options.defaultPlacement,
		delay: typeof options.delay !== 'undefined' ? options.delay : directive.options.defaultDelay,
		template: typeof options.template !== 'undefined' ? options.template : directive.options.defaultTemplate,
		arrowSelector: typeof options.arrowSelector !== 'undefined' ? options.arrowSelector : directive.options.defaultArrowSelector,
		innerSelector: typeof options.innerSelector !== 'undefined' ? options.innerSelector : directive.options.defaultInnerSelector,
		trigger: typeof options.trigger !== 'undefined' ? options.trigger : directive.options.defaultTrigger,
		offset: typeof options.offset !== 'undefined' ? options.offset : directive.options.defaultOffset,
		container: typeof options.container !== 'undefined' ? options.container : directive.options.defaultContainer,
		boundariesElement: typeof options.boundariesElement !== 'undefined' ? options.boundariesElement : directive.options.defaultBoundariesElement,
		autoHide: typeof options.autoHide !== 'undefined' ? options.autoHide : directive.options.autoHide,
		loadingClass: typeof options.loadingClass !== 'undefined' ? options.loadingClass : directive.options.defaultLoadingClass,
		loadingContent: typeof options.loadingContent !== 'undefined' ? options.loadingContent : directive.options.defaultLoadingContent,
		popperOptions: {
			...(typeof options.popperOptions !== 'undefined' ? options.popperOptions : directive.options.defaultPopperOptions),
		},
	}
 
	if (result.offset) {
		const typeofOffset = typeof result.offset
		let offset = result.offset
 
		// One value -> switch
		if (typeofOffset === 'number' || (typeofOffset === 'string' && offset.indexOf(',') === -1)) {
			offset = `0, ${offset}`
		}
 
		if (!result.popperOptions.modifiers) {
			result.popperOptions.modifiers = {}
		}
		result.popperOptions.modifiers.offset = {
			offset,
		}
	}
 
	return result
}
 
export function getPlacement (value, modifiers) {
	var placement = value.placement
	for (var i = 0; i < positions.length; i++) {
		var pos = positions[i]
		if (modifiers[pos]) {
			placement = pos
		}
	}
	return placement
}
 
export function getContent (value) {
	const type = typeof value
	if (type === 'string') {
		return value
	} else if (value && type === 'object') {
		return value.content
	} else {
		return false
	}
}
 
export function createTooltip (el, value, modifiers = {}) {
	const content = getContent(value)
	let classes = typeof value.classes !== 'undefined' ? value.classes : directive.options.defaultClass
	const opts = {
		title: content,
		html: true,
		...getOptions({
			...value,
			placement: getPlacement(value, modifiers),
		}),
	}
	const tooltip = el._tooltip = new Tooltip(el, opts)
	tooltip.setClasses(classes)
	tooltip._vueEl = el
 
	// Class on target
	const targetClasses = typeof value.targetClasses !== 'undefined' ? value.targetClasses : directive.options.defaultTargetClass
	el._tooltipTargetClasses = targetClasses
	addClasses(el, targetClasses)
 
	return tooltip
}
 
export function destroyTooltip (el) {
	if (el._tooltip) {
		el._tooltip.dispose()
		delete el._tooltip
		delete el._tooltipOldShow
	}
 
	if (el._tooltipTargetClasses) {
		removeClasses(el, el._tooltipTargetClasses)
		delete el._tooltipTargetClasses
	}
}
 
export function bind (el, { value, oldValue, modifiers }) {
	const content = getContent(value)
	if (!content || !state.enabled) {
		destroyTooltip(el)
	} else {
		let tooltip
		if (el._tooltip) {
			tooltip = el._tooltip
			// Content
			tooltip.setContent(content)
			// Options
			tooltip.setOptions({
				...value,
				placement: getPlacement(value, modifiers),
			})
		} else {
			tooltip = createTooltip(el, value, modifiers)
		}
 
		// Manual show
		if (typeof value.show !== 'undefined' && value.show !== el._tooltipOldShow) {
			el._tooltipOldShow = value.show
			value.show ? tooltip.show() : tooltip.hide()
		}
	}
}
 
export const directive = {
	options: defaultOptions,
	bind,
	update: bind,
	unbind (el) {
		destroyTooltip(el)
	},
}
 
export default directive