2 // var $ = require('jquery');
3 var Marionette = require('backbone.marionette');
4 var behaviourLookup = require('./lookup');
5 var matchesSelector = require('../../utils/matches-selector');
6 var RAF = require('../../utils/raf');
7 var isCompact = require('../../utils/detect-compact');
9 require('../../utils/tooltip');
11 // if a an element was created in this event loop under
12 // the user's pointer, this function will trigger a mouseover.
13 function triggerMouseoverForHover(el) {
14 // browser doent know that something is hovered or not until
15 // the next animation frame
17 if (!matchesSelector(el, ':hover')) return;
19 // Force a mouseover event to wake up the tooltip
22 evt = new MouseEvent('mouseover');
24 /* Internet Explorer, good times */
25 evt = document.createEvent('MouseEvents');
44 el.dispatchEvent(evt);
48 var Behavior = Marionette.Behavior.extend({
49 onRender: function() {
50 if (isCompact()) return;
52 // existing tooltips are no longer on the dom due to render.
53 // so we clean up the listeners etc.
54 this.destroyTooltips();
56 if (!this.tooltips) this.tooltips = {};
57 if (!this.handlers) this.handlers = {};
61 Object.keys(this.options).forEach(function(selector) {
62 var $el = selector === '' ? self.$el : self.$el.find(selector);
65 // Cannot find element? Don't continue
69 var handler = self.createHandler($el, el, selector);
70 el.addEventListener('mouseover', handler, false);
71 self.handlers[selector] = handler;
73 triggerMouseoverForHover(el);
77 createHandler: function($el, el, selector) {
82 handleEvent: function() {
83 el.removeEventListener('mouseover', this, false);
84 delete self.handlers[selector];
86 self.initTooltip(selector, $el, el);
91 initTooltip: function(selector, $el, el) {
92 var tooltipOptions = this.options[selector];
94 var title = tooltipOptions.title || el.getAttribute('title');
95 if (typeof tooltipOptions.titleFn === 'function') {
96 title = tooltipOptions.titleFn.bind(this.view)();
97 } else if (tooltipOptions.titleFn) {
98 title = this.view[tooltipOptions.titleFn].bind(this.view);
101 this.tooltips[selector] = $el;
103 html: tooltipOptions.html,
105 placement: tooltipOptions.placement,
106 container: tooltipOptions.container || 'body'
109 var customUpdateEventName = tooltipOptions.customUpdateEvent;
110 if (customUpdateEventName) {
111 this.view.on(customUpdateEventName, this.updateTooltip.bind(this, $el));
114 triggerMouseoverForHover(el);
117 onDestroy: function() {
118 this.destroyHandlers();
119 this.destroyTooltips();
122 destroyHandlers: function() {
123 var handlers = this.handlers;
124 delete this.handlers;
126 if (!handlers) return;
128 Object.keys(handlers).forEach(function(selector) {
129 var handler = handlers[selector];
131 el.removeEventListener('mouseover', handler, false);
135 destroyTooltips: function() {
136 var tooltips = this.tooltips;
137 delete this.tooltips;
139 if (!tooltips) return;
141 Object.keys(tooltips).forEach(function(selector) {
142 var $el = tooltips[selector];
143 $el.tooltip('destroy');
147 // Limitation of bootstrap tooltip library
148 // We do this so that when you click a toggle for example,
149 // the tooltip text is properly updated to show the inverse hint
150 updateTooltip: function($el) {
156 behaviourLookup.register('Tooltip', Behavior);
158 module.exports = Behavior;