PageSourceSearch

https://www.turitop.com/wp-content/plugins/turitop-tooltips/assets/turitop-tooltips.js?ver=3.0.0

js turitop.com collected 2026-10-02 14:30:51 UTC 8,338 bytes, 302 lines download raw bytes

1(function () {
2  'use strict';
3
4  var VERSION = (window.TuriTopTooltipsConfig && window.TuriTopTooltipsConfig.version) || '3.0.0';
5  var ANCHOR_SELECTOR = '.turitop-tooltip-anchor';
6  var overlays = [];
7  var tooltip = null;
8  var activeOverlay = null;
9  var raf = null;
10
11  window.turitopTooltipsVersion = VERSION;
12
13  function ready(fn) {
14    if (document.readyState === 'loading') {
15      document.addEventListener('DOMContentLoaded', fn, { once: true });
16    } else {
17      fn();
18    }
19  }
20
21  function getTooltip() {
22    if (tooltip && document.body.contains(tooltip)) {
23      return tooltip;
24    }
25
26    tooltip = document.createElement('div');
27    tooltip.className = 'turitop-tooltip-floating';
28    tooltip.setAttribute('role', 'tooltip');
29    tooltip.setAttribute('aria-hidden', 'true');
30    document.body.appendChild(tooltip);
31    return tooltip;
32  }
33
34  function getText(anchor) {
35    return (anchor.getAttribute('data-turitop-tooltip') || anchor.getAttribute('aria-label') || '').trim();
36  }
37
38  function createOverlay(anchor, index) {
39    if (anchor._turitopOverlay) {
40      return anchor._turitopOverlay;
41    }
42
43    var text = getText(anchor);
44    var label = (anchor.textContent || '?').trim() || '?';
45
46    var button = document.createElement('button');
47    button.type = 'button';
48    button.className = 'turitop-tooltip-overlay-button';
49    button.textContent = label;
50    button.setAttribute('aria-label', text);
51    button.setAttribute('data-turitop-tooltip', text);
52    button.setAttribute('data-turitop-index', String(index));
53
54    button._turitopAnchor = anchor;
55    anchor._turitopOverlay = button;
56    anchor.classList.add('turitop-tooltip-anchor-enhanced');
57
58    button.addEventListener('mouseenter', function () {
59      show(button);
60    });
61
62    button.addEventListener('mouseleave', function () {
63      hide();
64    });
65
66    button.addEventListener('focus', function () {
67      show(button);
68    });
69
70    button.addEventListener('blur', function () {
71      hide();
72    });
73
74    button.addEventListener('click', function (event) {
75      event.preventDefault();
76      event.stopPropagation();
77
78      if (activeOverlay === button && tooltip && tooltip.classList.contains('is-visible')) {
79        hide();
80      } else {
81        show(button);
82      }
83    });
84
85    document.body.appendChild(button);
86    overlays.push(button);
87    return button;
88  }
89
90  function updateOverlayPosition(button) {
91    var anchor = button._turitopAnchor;
92
93    if (!anchor || !document.body.contains(anchor)) {
94      button.style.display = 'none';
95      return;
96    }
97
98    var rect = anchor.getBoundingClientRect();
99    var viewportWidth = window.innerWidth || document.documentElement.clientWidth;
100    var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
101
102    if (
103      rect.width <= 0 ||
104      rect.height <= 0 ||
105      rect.bottom < 0 ||
106      rect.right < 0 ||
107      rect.top > viewportHeight ||
108      rect.left > viewportWidth
109    ) {
110      button.style.display = 'none';
111      return;
112    }
113
114    button.style.display = 'inline-flex';
115    button.style.left = Math.round(rect.left) + 'px';
116    button.style.top = Math.round(rect.top) + 'px';
117    button.style.width = Math.max(18, Math.round(rect.width)) + 'px';
118    button.style.height = Math.max(18, Math.round(rect.height)) + 'px';
119  }
120
121  function updateAllOverlayPositions() {
122    overlays.forEach(updateOverlayPosition);
123
124    if (activeOverlay && tooltip && tooltip.classList.contains('is-visible')) {
125      positionTooltip(activeOverlay, tooltip);
126    }
127  }
128
129  function scheduleUpdate() {
130    if (raf) {
131      return;
132    }
133
134    raf = window.requestAnimationFrame(function () {
135      raf = null;
136      updateAllOverlayPositions();
137    });
138  }
139
140  function positionTooltip(button, tip) {
141    var rect = button.getBoundingClientRect();
142    var padding = 8;
143    var gap = 10;
144
145    tip.style.left = '-9999px';
146    tip.style.top = '-9999px';
147    tip.classList.add('is-visible');
148
149    var tipRect = tip.getBoundingClientRect();
150    var viewportWidth = window.innerWidth || document.documentElement.clientWidth;
151    var viewportHeight = window.innerHeight || document.documentElement.clientHeight;
152
153    var left = rect.left + (rect.width / 2) - (tipRect.width / 2);
154    var top = rect.top - tipRect.height - gap;
155    var placement = 'top';
156
157    if (top < padding) {
158      top = rect.bottom + gap;
159      placement = 'bottom';
160    }
161
162    if (left < padding) {
163      left = padding;
164    }
165
166    if (left + tipRect.width > viewportWidth - padding) {
167      left = viewportWidth - tipRect.width - padding;
168    }
169
170    if (top + tipRect.height > viewportHeight - padding) {
171      top = Math.max(padding, viewportHeight - tipRect.height - padding);
172    }
173
174    var arrowLeft = (rect.left + rect.width / 2) - left;
175    if (arrowLeft < 14) arrowLeft = 14;
176    if (arrowLeft > tipRect.width - 14) arrowLeft = tipRect.width - 14;
177
178    tip.dataset.placement = placement;
179    tip.style.setProperty('--turitop-arrow-left', arrowLeft + 'px');
180    tip.style.left = Math.round(left) + 'px';
181    tip.style.top = Math.round(top) + 'px';
182  }
183
184  function show(button) {
185    if (!button) {
186      return false;
187    }
188
189    updateOverlayPosition(button);
190
191    var text = (button.getAttribute('data-turitop-tooltip') || button.getAttribute('aria-label') || '').trim();
192    if (!text) {
193      return false;
194    }
195
196    var tip = getTooltip();
197    tip.textContent = text;
198    tip.setAttribute('aria-hidden', 'false');
199
200    if (activeOverlay && activeOverlay !== button) {
201      activeOverlay.classList.remove('is-active');
202    }
203
204    activeOverlay = button;
205    activeOverlay.classList.add('is-active');
206
207    positionTooltip(button, tip);
208    return true;
209  }
210
211  function hide() {
212    if (activeOverlay) {
213      activeOverlay.classList.remove('is-active');
214    }
215
216    activeOverlay = null;
217
218    if (tooltip) {
219      tooltip.classList.remove('is-visible');
220      tooltip.setAttribute('aria-hidden', 'true');
221    }
222  }
223
224  function enhance() {
225    var anchors = document.querySelectorAll(ANCHOR_SELECTOR);
226
227    anchors.forEach(function (anchor, index) {
228      createOverlay(anchor, index);
229    });
230
231    updateAllOverlayPositions();
232  }
233
234  function init() {
235    enhance();
236
237    window.addEventListener('scroll', scheduleUpdate, true);
238    window.addEventListener('resize', scheduleUpdate);
239    window.addEventListener('orientationchange', scheduleUpdate);
240
241    document.addEventListener('click', function (event) {
242      if (activeOverlay && !event.target.closest('.turitop-tooltip-overlay-button')) {
243        hide();
244      }
245    }, true);
246
247    document.addEventListener('keydown', function (event) {
248      if (event.key === 'Escape') {
249        hide();
250      }
251    }, true);
252
253    if (window.MutationObserver) {
254      var observer = new MutationObserver(function () {
255        enhance();
256        scheduleUpdate();
257      });
258
259      observer.observe(document.body, {
260        childList: true,
261        subtree: true
262      });
263    }
264
265    /* Layout can shift after fonts/images/cards finish loading. */
266    window.setTimeout(updateAllOverlayPositions, 250);
267    window.setTimeout(updateAllOverlayPositions, 750);
268    window.setTimeout(updateAllOverlayPositions, 1500);
269    window.setTimeout(updateAllOverlayPositions, 3000);
270  }
271
272  ready(init);
273
274  window.TuriTopTooltips = {
275    version: VERSION,
276    enhance: enhance,
277    update: updateAllOverlayPositions,
278    showFirst: function () {
279      enhance();
280      return show(overlays[0]);
281    },
282    debug: function () {
283      var firstAnchor = document.querySelector(ANCHOR_SELECTOR);
284      var firstOverlay = overlays[0] || null;
285
286      return {
287        version: VERSION,
288        anchors: document.querySelectorAll(ANCHOR_SELECTOR).length,
289        overlays: overlays.length,
290        firstAnchor: firstAnchor,
291        firstAnchorRect: firstAnchor ? firstAnchor.getBoundingClientRect() : null,
292        firstOverlay: firstOverlay,
293        firstOverlayRect: firstOverlay ? firstOverlay.getBoundingClientRect() : null,
294        elementAtOverlayCenter: firstOverlay ? document.elementFromPoint(
295          firstOverlay.getBoundingClientRect().left + firstOverlay.getBoundingClientRect().width / 2,
296          firstOverlay.getBoundingClientRect().top + firstOverlay.getBoundingClientRect().height / 2
297        ) : null,
298        tooltip: tooltip
299      };
300    }
301  };
302})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.