PageSourceSearch

https://www.aldenestatesofshorewood.com/wp-content/plugins/smart4y…/public/js/smart4y-tooltip.js?ver=1.1.5

js aldenestatesofshorewood.com collected 2026-09-30 19:32:44 UTC 17,544 bytes, 471 lines download raw bytes

1!(function() {
2    'use strict';
3
4    function callback() {
5        var ua               = navigator.userAgent,
6            hasTouch         = 'ontouchstart' in window && !(/chrome/i.exec(ua) && !/android/i.exec(ua)),
7            lastEl           = null,
8            lastEventType    = null,
9            lastInteractive  = false,
10            lastTooltip      = null,
11            preventMouseOver = false,
12            prevTarget       = null,
13            stack            = [],
14            startEvent       = hasTouch ? 'touchstart' : 'mousedown',
15            stopEvent        = hasTouch ? 'touchend' : 'mouseup',
16            style            = document.documentElement.style,
17            transition       = style.transition != undefined ? {event: 'transitionend', prefix: ''}
18                : style.WebkitTransition != undefined ? {event: 'webkitTransitionEnd', prefix: '-webkit-'} : null;
19
20        /**
21         * classList polyfill
22         */
23        if (!('classList' in document.documentElement) && Object.defineProperty && typeof HTMLElement !== 'undefined') {
24            Object.defineProperty(HTMLElement.prototype, 'classList', {
25                get: function() {
26                    var self = this;
27                    function update(fn) {
28                        return function(value) {
29                            var classes = self.className.split(/\s+/),
30                                index = classes.indexOf(value);
31
32                            fn(classes, index, value);
33                            self.className = classes.join(' ');
34                        }
35                    }
36
37                    var ret = {
38                        add: update(function(classes, index, value) {
39                            ~index || classes.push(value);
40                        }),
41
42                        remove: update(function(classes, index) {
43                            ~index && classes.splice(index, 1);
44                        }),
45
46                        toggle: update(function(classes, index, value) {
47                            ~index ? classes.splice(index, 1) : classes.push(value);
48                        }),
49
50                        contains: function(value) {
51                            return !!~self.className.split(/\s+/).indexOf(value);
52                        },
53
54                        item: function(i) {
55                            return self.className.split(/\s+/)[i] || null;
56                        }
57                    };
58
59                    Object.defineProperty(ret, 'length', {
60                        get: function() {
61                            return self.className.split(/\s+/).length;
62                        }
63                    });
64
65                    return ret;
66                }
67            });
68        }
69
70        /**
71         * closest pollyfill
72         */
73        if (window.Element && !Element.prototype.closest) {
74            Element.prototype.closest =
75                function(s) {
76                    var matches = (this.document || this.ownerDocument).querySelectorAll(s),
77                        i,
78                        el = this;
79                    do {
80                        i = matches.length;
81                        while (--i >= 0 && matches.item(i) !== el) {};
82                    } while ((i < 0) && (el = el.parentElement));
83                    return el;
84                };
85        }
86
87        /**
88         * Close all tooltips
89         */
90        var closeAllTooltips = function() {
91            for (var i = stack.length - 1; i >= 0; i--) {
92                var item = stack[i];
93
94                if (lastEventType == 'mouseover' && item.getOptions().event == 'click') {
95                    continue;
96                }
97
98                item.close();
99            }
100        };
101
102        var body = document.body;
103        var matchesSelector = body.matches || body.webkitMatchesSelector || body.mozMatchesSelector || body.msMatchesSelector;
104
105        /**
106         * Prevent close tooltip
107         *
108         * @param {MouseEvent} e - Event.
109         */
110        function preventClosing(e) {
111            if (!lastInteractive || !lastTooltip || !lastEl) {
112                return false;
113            }
114
115            var elRect     = lastEl.getBoundingClientRect(),
116                tRect      = lastTooltip.getBoundingClientRect(),
117                vertical   = (e.clientY >= tRect.bottom && e.clientY <= elRect.top) || (e.clientY >= elRect.bottom && e.clientY <= tRect.top),
118                horizontal = e.clientX >= Math.max(elRect.left, tRect.left) && e.clientX <= Math.min(elRect.right, tRect.right);
119
120            return vertical && horizontal;
121        }
122
123        /**
124         * Transition event callback
125         *
126         * @param {HTMLElement} el - Element.
127         * @param {Function} callback - Callback.
128         */
129        var transitionCallback = function(el, callback) {
130            var delay = transition && el.classList.contains('open')
131                && Math.max.apply(null, getComputedStyle(el)[transition.prefix + 'transition-duration'].match(/\d+(\.\d+)?/g) || [0]);
132
133            if (delay) {
134                el.addEventListener(transition.event, function transitionListener(e) {
135                    e.target.removeEventListener(transition.event, transitionListener);
136
137                    if (e.target === e.currentTarget) {
138                        callback();
139                    } else {
140                        transitionCallback(el, callback);
141                    }
142                });
143            } else {
144                callback();
145            }
146        };
147
148        /**
149         * Tooltip
150         *
151         * @param {HTMLElement} target - Target element.
152         * @param {Object} options - Tooltip options.
153         * @returns {Tooltip}
154         */
155        var Tooltip = function(target, options) {
156            var autoCloseTimer, closeTimer, openTimer, transTimer, tooltip, that = this;
157
158            // repos tooltip on image load or load error
159            function imgCallback() {
160                that.pos();
161                this.removeEventListener('load', imgCallback);
162                this.removeEventListener('error', imgCallback);
163            }
164
165            /**
166             * Sets attributes
167             */
168            function setAttrs(el, attrs) {
169                for (var prop in attrs) {
170                    if (attrs.hasOwnProperty(prop)) {
171                        var value = attrs[prop];
172
173                        if (value == null) {
174                            continue;
175                        }
176
177                        if ('transform transition'.indexOf(prop) > -1) {
178                            transition && (el.style[transition.prefix + prop] = value);
179                        } else {
180                            var key = prop == '_class' ? 'className' : prop;
181
182                            if (el[key] == undefined && el.style[key] != undefined) {
183                                el.style[key] = value;
184                            } else {
185                                el[key] = value;
186                            }
187                        }
188                    }
189                }
190                return el;
191            }
192
193            /**
194             * Create tooltip
195             */
196            that.create = function() {
197                if (!tooltip) {
198                    tooltip = setAttrs(document.createElement('span'), {
199                        _class: 's4yt' + (options.effect ? ' s4yt-' + options.effect : '') + (options._class ? ' ' + options._class : ''),
200                        innerHTML: options.content.replace(/^\s*[\r\n]/gm, '<span class="s4yt-br"></span>').replace(/\n/g, '<br>') + '<span class="s4yt-arrow"></span>',
201                        transform: 'none',
202                        transition: 'none'
203                    });
204
205                    Array.prototype.forEach.call(tooltip.querySelectorAll('img'), function(img) {
206                        img.addEventListener('load', imgCallback);
207                        img.addEventListener('error', imgCallback);
208                    });
209
210                    // /^\s*[\r\n]/gm - regex for replace empty new lines for span
211                    document.body.appendChild(tooltip);
212                }
213
214                that.pos();
215                lastInteractive = options.interactive && options.event != 'click';
216
217                transTimer = setTimeout(function() {
218                    setAttrs(tooltip, {transition: ''});
219                    tooltip.classList.add('open');
220                }, 30);
221            };
222
223            /**
224             * Close tooltip
225             */
226            that.close = function() {
227                that.reset();
228
229                closeTimer = setTimeout(function() {
230                    var index = stack.indexOf(that);
231
232                    if (index > -1) {
233                        stack.splice(index, 1);
234                    }
235
236                    if (!tooltip) {
237                        return;
238                    }
239
240                    transitionCallback(tooltip, function() {
241                        tooltip = !tooltip.parentNode.removeChild(tooltip);
242                    });
243                    tooltip && tooltip.classList.remove('open');
244                }, lastEventType == 'mouseover' ? parseInt(options.closeDelay) || 0 : 0);
245            };
246
247            /**
248             * Equals target element with entered element
249             *
250             * @param compareEl
251             * @returns {boolean}
252             */
253            that.equals = function(compareEl) {
254                return compareEl === target;
255            };
256
257            /**
258             * Open tooltip
259             */
260            that.open = function() {
261                that.reset();
262                stack.push(that);
263
264                openTimer = setTimeout(function() {
265                    that.create();
266                    autoCloseTimer = options.autoClose
267                        && setTimeout(function() { that.close(); }, parseInt(options.autoClose) || 0);
268                }, lastEventType == 'mouseover' ? parseInt(options.openDelay) || 0 : 0);
269            };
270
271            /**
272             * Sets tooltip position
273             */
274            that.pos = function() {
275                if (!tooltip) {
276                    return;
277                }
278
279                var arrow        = tooltip.querySelector('.s4yt-arrow'),
280                    arrowHeight  = arrow.offsetHeight,
281                    arrowWidth   = arrow.offsetWidth,
282                    clientHeight = document.documentElement.clientHeight,
283                    clientWidth  = document.documentElement.clientWidth,
284                    scrollYPos   = window.pageYOffset,
285                    pos          = target.getBoundingClientRect(),
286                    tPos         = {left: 0, top: 0};
287
288                tooltip.style.maxWidth = Math.min(clientWidth - arrowWidth * 2, parseInt(getComputedStyle(tooltip).maxWidth)) + 'px';
289                tPos.left = pos.left + (pos.width - tooltip.offsetWidth) * .5;
290
291                var tHeight = tooltip.offsetHeight + arrowWidth,
292                    toDown  = options.position == 'bottom' ? pos.bottom + tHeight < clientHeight : tHeight > pos.top;
293
294                if (toDown) {
295                    tPos.top = scrollYPos + pos.bottom + arrowHeight;
296                    tooltip.classList.add('top');
297                } else {
298                    tPos.top = scrollYPos + pos.top - tooltip.offsetHeight - arrowHeight;
299                    tooltip.classList.remove('top');
300                }
301
302                if (tPos.left - arrowWidth < 0) {
303                    tPos.left = arrowWidth;
304                    tPos.maxWidth = clientWidth - arrowWidth * 2;
305                } else if (tPos.left + tooltip.offsetWidth + arrowWidth > clientWidth) {
306                    tPos.left = clientWidth - tooltip.offsetWidth - arrowWidth;
307                }
308
309                arrow.style.left = (pos.left < tPos.left ? tooltip.offsetWidth * .5 - arrowWidth * .5 : pos.left - tPos.left + pos.width * .5 - arrowWidth * .5) + 'px';
310
311                setAttrs(tooltip, {
312                    left: Math.round(tPos.left) + 'px',
313                    top: Math.round(tPos.top) + 'px',
314                    transform: ''
315                });
316
317
318                lastTooltip = tooltip;
319            };
320
321            /**
322             * Reset timeouts
323             */
324            that.reset = function() {
325                // clearTimeout(autoCloseTimer); na mobilech se spustí mouseover
326                clearTimeout(closeTimer);
327                clearTimeout(openTimer);
328                clearTimeout(transTimer);
329            };
330
331            /**
332             * Get tooltip options
333             *
334             * @returns {Object}
335             */
336            that.getOptions = function() {
337                return options;
338            };
339
340            /**
341             * Get target element
342             *
343             * @returns {HTMLElement}
344             */
345            that.getTarget = function() {
346                return target;
347            };
348
349            /**
350             * Get tooltip element
351             *
352             * @returns {*}
353             */
354            that.getTooltip = function() {
355                return tooltip;
356            };
357
358            that.open();
359            return this;
360        };
361
362        /**
363         * Tooltip plugin
364         */
365        window.smart4yTooltip = function(el, options) {
366            if (!el.parentNode || !options || typeof options !== 'object' || (typeof options === 'object' && !options.content)) {
367                return;
368            }
369
370            var clickable = el.classList.contains('s4yt-click');
371            closeAllTooltips();
372            lastEl = el;
373
374            // extend options
375            for (var i in smart4yTooltipDefaults) {
376                if (options[i] == null && smart4yTooltipDefaults.hasOwnProperty(i)) {
377                    options[i] = i == 'event' && clickable ? 'click' : smart4yTooltipDefaults[i];
378                }
379            }
380
381            return new Tooltip(el, options);
382        };
383
384        /**
385         * Start event handler
386         *
387         * @param {Event} e - Event.
388         */
389        function startHandler(e) {
390            if (e.which > 1) {
391                return;
392            }
393
394            prevTarget = e.target;
395        }
396
397        /**
398         * Stop event handler
399         *
400         * @param {Event} e - Event.
401         */
402        function stopHandler(e) {
403            var currentTarget = e.type == 'mouseup' ? e.target : document.elementFromPoint(e.changedTouches[0].clientX, e.changedTouches[0].clientY);
404
405            if (currentTarget === prevTarget) {
406                baseHandler(e);
407            }
408        }
409
410        /**
411         * Base event handler
412         *
413         * @param {Event} e - Event.
414         */
415        function baseHandler(e) {
416            var target          = e.target.nodeType != 9 && e.target.closest('.s4yt, .s4yt-click, .s4yt-hover'),
417                clickable       = target && target.classList.contains('s4yt-click'),
418                existingTooltip = stack.filter(function(item) { return item.getTarget() === target; }),
419                hoverable       = target && target.classList.contains('s4yt-hover'),
420                tooltip         = target && target.classList.contains('s4yt'),
421                wasClicked      = 'mouseup touchend'.indexOf(lastEventType = e.type) > -1;
422
423            if ((clickable && wasClicked) || (hasTouch && hoverable)) {
424                // click
425                preventMouseOver = true;
426                // prevent execute mouseover event on mobile devices that produce unwanted closure of tooltip
427                setTimeout(function() { preventMouseOver = false; }, 0);
428
429                if (!existingTooltip.length) {
430                    return smart4yTooltip(target, JSON.parse(target.getAttribute('data-s4yt')));
431                }
432            }
433
434            if (!wasClicked) {
435                // hover
436                if (preventMouseOver || preventClosing(e) || tooltip) {
437                    return;
438                }
439
440                if (hoverable) {
441                    return existingTooltip.length ?
442                        existingTooltip[0].reset() : smart4yTooltip(target, JSON.parse(target.getAttribute('data-s4yt')));
443                }
444            }
445
446            closeAllTooltips();
447        }
448
449        // attach events
450        document.addEventListener(startEvent, startHandler);
451        document.addEventListener(stopEvent, stopHandler);
452        document.addEventListener('mouseleave', closeAllTooltips);
453
454        if (!/iemobile/i.test(ua.toLowerCase())) {
455            // exclude ie phones - mouseover is calling before touchstart
456            document.addEventListener('mouseover', baseHandler);
457        }
458
459        window.addEventListener('resize', function() {
460            for (var i = stack.length - 1; i >= 0; i--) {
461                stack[i].pos();
462            }
463        });
464    }
465
466    if (document.readyState != 'loading') {
467        callback();
468    } else {
469        document.addEventListener('DOMContentLoaded', callback);
470    }
471})();

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.