1/**
2 * Javascript for the autotooltip plugin.
3 *
4 * @type {{show:function, hide:function}}
5 */
6var autotooltip = function($) {
7	var MAX_WIDTH = 500;
8	var m_tt;
9	var m_visible;
10	var m_timer;
11	var m_moveCounter = 0;
12
13	/**
14	 * Initialize the module.
15	 *
16	 * @private
17	 */
18	var _init = function() {
19		if (m_tt) {
20			return;
21		}
22
23		m_tt = $('<div class="plugin-autotooltip_tip" role="tooltip"></div>');
24		// Cover the various templates.
25		var container = $('.dokuwiki .bodyContent, .dokuwiki .wiki-content, #dokuwiki__content');
26		// Use the root .dokuwiki if we have to, though we might lose some font information.
27		if (!container.length) {
28			container = $('.dokuwiki');
29		}
30		// In case the template is really strange.
31		if (!container.length) {
32			container = $('body');
33		}
34		container.first().append(m_tt);
35
36		$(document).on('mousemove', _moveDebounced);
37	};
38
39
40	/**
41	 * Move the the tooltip to the current mouse position.
42	 *
43	 * @param {MouseEvent} e
44	 * @private
45	 */
46	var _move = function(e) {
47		if (!m_visible) {
48			return;
49		}
50		var top = Math.max(e.pageY - window.scrollY - m_tt.outerHeight() - 4, 8);
51		var left = Math.max(e.pageX + 4, 8);
52		var right = '';
53		var winWidth = window.innerWidth;
54		var width;
55		if (winWidth - left < MAX_WIDTH && left > winWidth / 2) {
56			// Show left of the cursor.
57			left = '';
58			right = winWidth - e.pageX - 4;
59			width = Math.min(e.pageX - 4, MAX_WIDTH);
60		} else {
61			// Show right of the cursor.
62			left = left + 'px';
63			width = Math.min(winWidth - e.pageX - 4, MAX_WIDTH);
64		}
65
66		m_tt.css({top: top + 'px', left: left, right: right, width: 'auto', 'max-width': width + 'px'});
67	};
68
69	/**
70	 * Mousemove handler. When the mouse moves, so does the tooltip.
71	 *
72	 * @param {MouseEvent} e
73	 * @private
74	 */
75	var _moveDebounced = function(e) {
76		if (!m_visible) {
77			return;
78		}
79		var closureCounter = ++m_moveCounter;
80		requestAnimationFrame(function() {
81			if (closureCounter == m_moveCounter) {
82				_move(e);
83			}
84		});
85	};
86
87	return {
88		/**
89		 * Show a tooltip.
90		 *
91		 * @param {MouseEvent} evt
92		 */
93		show: function(evt) {
94			m_visible = true;
95			_init();
96
97			var elt = evt.currentTarget;
98			var extraClasses = $('.plugin-autotooltip-hidden-classes', elt).text();
99			m_tt
100				.html($('.plugin-autotooltip-hidden-tip', elt).html())
101				.attr('class', 'plugin-autotooltip_tip ' + extraClasses);
102			// This isn't strictly needed because of the attachment to document.mousemove,
103			// but it forces proper initial placement when the mouse is moving rapidly (so
104			// move is throttled).
105			_move(evt);
106			clearInterval(m_timer);
107			m_timer = setTimeout(function() {
108				if (m_visible) {
109					m_tt.addClass('plugin-autotooltip--visible');
110				}
111			}, parseInt($(elt).attr('data-delay')) || 50);
112		},
113
114
115		/**
116		 * Hide the tooltip.
117		 */
118		hide: function() {
119			m_visible = false;
120			m_timer = setTimeout(function() {
121				m_tt.removeClass('plugin-autotooltip--visible');
122			}, 50);
123		}
124	};
125}(jQuery);
126