1
|
|
|
/*! |
2
|
|
|
* @package ElkArte Forum |
3
|
|
|
* @copyright ElkArte Forum contributors |
4
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause (see accompanying LICENSE.txt file) |
5
|
|
|
* |
6
|
|
|
* @version 2.0 dev |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* SiteTooltip, Basic JavaScript function to provide styled tooltips |
11
|
|
|
* |
12
|
|
|
* - shows the tooltip in a div with the class defined in tooltipClass |
13
|
|
|
* - moves all selector titles to a hidden div and removes the title attribute to |
14
|
|
|
* prevent default browser actions |
15
|
|
|
* - attempts to keep the tooltip on screen, prefers it "on top" but will move it below if there |
16
|
|
|
* is not enough screen room above |
17
|
|
|
* |
18
|
|
|
*/ |
19
|
|
|
class SiteTooltip |
20
|
|
|
{ |
21
|
|
|
constructor (settings = {}) |
22
|
|
|
{ |
23
|
|
|
this.defaults = { |
24
|
|
|
tooltipID: 'site_tooltip', // ID used on the outer div |
25
|
|
|
tooltipTextID: 'site_tooltipText', // ID on the inner div holding the text |
26
|
|
|
tooltipClass: 'tooltip', // The class applied to the sibling span, defaults provides a fade cover |
27
|
|
|
tooltipSwapClass: 'site_swaptip', // a class only used internally, change only if you have a conflict |
28
|
|
|
tooltipContent: 'html' // display captured title text as html or text |
29
|
|
|
}; |
30
|
|
|
|
31
|
|
|
// Account for any user options |
32
|
|
|
this.settings = Object.assign({}, this.defaults, settings); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* Creates tooltips for elements. |
37
|
|
|
* |
38
|
|
|
* @param {string} elem - The CSS selector of the elements to create tooltips for. |
39
|
|
|
* |
40
|
|
|
* @returns {null} - Returns null if the device is mobile or touch-enabled. |
41
|
|
|
*/ |
42
|
|
|
create (elem) |
43
|
|
|
{ |
44
|
|
|
// No need here |
45
|
|
|
if (is_mobile === true || is_touch === true) |
|
|
|
|
46
|
|
|
{ |
47
|
|
|
return null; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
// Move passed selector titles to a hidden span, then remove the selector title to prevent any default browser actions |
51
|
|
|
for (let el of document.querySelectorAll(elem)) |
52
|
|
|
{ |
53
|
|
|
let title = el.getAttribute('title'); |
54
|
|
|
|
55
|
|
|
el.removeAttribute('title'); |
56
|
|
|
el.setAttribute('data-title', title); |
57
|
|
|
el.addEventListener('mouseenter', this.showTooltip.bind(this)); |
58
|
|
|
el.addEventListener('mouseleave', this.hideTooltip.bind(this)); |
59
|
|
|
} |
|
|
|
|
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Positions the tooltip element relative to the provided event target. |
64
|
|
|
* |
65
|
|
|
* @param {Event} event - The event object that triggered the tooltip placement. |
66
|
|
|
*/ |
67
|
|
|
positionTooltip (event) |
68
|
|
|
{ |
69
|
|
|
let tooltip = document.getElementById(this.settings.tooltipID); |
70
|
|
|
if (!tooltip) |
71
|
|
|
{ |
72
|
|
|
return; |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
let rect = event.target.getBoundingClientRect(); |
76
|
|
|
let tooltipHeight = tooltip.offsetHeight; |
77
|
|
|
|
78
|
|
|
let x = rect.left; |
79
|
|
|
// Initially trying to position above the element |
80
|
|
|
let y = window.scrollY + rect.top - tooltipHeight - 5; |
81
|
|
|
|
82
|
|
|
// Don't position above if it falls off-screen, instead move it below |
83
|
|
|
if (rect.top - (tooltipHeight + 5) < 0) |
84
|
|
|
{ |
85
|
|
|
y = window.scrollY + rect.bottom + 5; |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
tooltip.style.cssText = 'left:' + x + 'px; top:' + y + 'px'; |
89
|
|
|
} |
90
|
|
|
|
91
|
|
|
/** |
92
|
|
|
* Displays a tooltip on hover over an element. |
93
|
|
|
* |
94
|
|
|
* @param {Event} event - The event object. |
95
|
|
|
*/ |
96
|
|
|
showTooltip (event) |
97
|
|
|
{ |
98
|
|
|
if (this.tooltipTimeout) |
99
|
|
|
{ |
100
|
|
|
clearTimeout(this.tooltipTimeout); |
101
|
|
|
} |
102
|
|
|
|
103
|
|
|
// Represents the timeout for showing a tooltip. |
104
|
|
|
this.tooltipTimeout = setTimeout(function() { |
105
|
|
|
let title = event.target.getAttribute('data-title'); |
106
|
|
|
if (title) |
107
|
|
|
{ |
108
|
|
|
// <div id="site_tooltip"><div id="site_tooltipText"><span class="tooltip" |
109
|
|
|
let tooltip = document.createElement('div'); |
110
|
|
|
tooltip.id = this.settings.tooltipID; |
111
|
|
|
|
112
|
|
|
let tooltipText = document.createElement('div'); |
113
|
|
|
tooltipText.id = this.settings.tooltipTextID; |
114
|
|
|
|
115
|
|
|
let span = document.createElement('span'); |
116
|
|
|
span.className = this.settings.tooltipClass; |
117
|
|
|
|
118
|
|
|
// Create our element and append it to the body. |
119
|
|
|
tooltip.appendChild(tooltipText); |
120
|
|
|
tooltip.appendChild(span); |
121
|
|
|
document.getElementsByTagName('body')[0].appendChild(tooltip); |
122
|
|
|
|
123
|
|
|
// Load the tooltip content with our data-title |
124
|
|
|
if (this.settings.tooltipContent === 'html') |
125
|
|
|
{ |
126
|
|
|
// Regular expression to match content inside .bbc_code_inline span |
127
|
|
|
let regex = new RegExp('(<span class="bbc_code_inline">).*?(<\/span>)', 's'); |
128
|
|
|
|
129
|
|
|
title = title.replace(regex, function(match, p1, p2) |
130
|
|
|
{ |
131
|
|
|
let content = match.slice(p1.length, -p2.length); |
132
|
|
|
let replacedContent = content.replace(/</g, "<"); |
133
|
|
|
return p1 + replacedContent + p2; |
134
|
|
|
}); |
135
|
|
|
|
136
|
|
|
tooltipText.innerHTML = title; |
137
|
|
|
} |
138
|
|
|
else |
139
|
|
|
{ |
140
|
|
|
tooltipText.innerText = title; |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
tooltip.style.display = 'block'; |
144
|
|
|
this.positionTooltip(event); |
145
|
|
|
} |
146
|
|
|
}.bind(this), 1000); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
/** |
150
|
|
|
* Hides the tooltip. |
151
|
|
|
* |
152
|
|
|
* @param {Event} event - The event object. |
153
|
|
|
*/ |
154
|
|
|
hideTooltip (event) |
|
|
|
|
155
|
|
|
{ |
156
|
|
|
if (this.tooltipTimeout) |
157
|
|
|
{ |
158
|
|
|
clearTimeout(this.tooltipTimeout); |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
let tooltip = document.getElementById(this.settings.tooltipID); |
162
|
|
|
if (tooltip) |
163
|
|
|
{ |
164
|
|
|
tooltip.parentElement.removeChild(tooltip); |
165
|
|
|
} |
166
|
|
|
} |
167
|
|
|
} |
168
|
|
|
|
169
|
|
|
window.SiteTooltip = SiteTooltip; |
170
|
|
|
|
This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.
To learn more about declaring variables in Javascript, see the MDN.