PageSourceSearch

https://clacksandstirlinghscp.org/wp-content/themes/inovado/framework/js/functions.js?ver=8.4.3

js clacksandstirlinghscp.org collected 2026-10-07 02:53:17 UTC 15,998 bytes, 491 lines download raw bytes

1/* ------------------------------------------------------------------------ */
2/* Javascripts
3/* ------------------------------------------------------------------------ */
4
5document.addEventListener('DOMContentLoaded', () => {
6
7/* ------------------------------------------------------------------------ */
8/* Image Hovers for News and Videos
9/* ------------------------------------------------------------------------ */
10
11const hoverGroups = [
12  { selector: '.post-image a, .post-gallery a', overlayClass: 'overlay' },
13  { selector: '.portfolio-item', overlayClass: 'portfolio-overlay', links: ['.overlay-link', '.overlay-lightbox'] },
14  { selector: '.portfolio-item-one .portfolio-picwrap', overlayClass: 'portfolio-overlay', links: ['.overlay-link', '.overlay-lightbox'] },
15  { selector: '.blog-item', overlayClass: 'blog-overlay', links: ['.post-icon'] },
16];
17
18// PRE-CREATE overlays for all elements on page load
19hoverGroups.forEach(group => {
20  document.querySelectorAll(group.selector).forEach(el => {
21    let overlay = el.querySelector(`.${group.overlayClass}`);
22    if (!overlay) {
23      overlay = document.createElement('div');
24      overlay.className = group.overlayClass;
25      overlay.style.opacity = 0;
26      overlay.style.transition = 'opacity 0.3s';
27      el.appendChild(overlay);
28    }
29
30    if (group.links) {
31      group.links.forEach(linkSelector => {
32        const linkEl = el.querySelector(linkSelector);
33        if (linkEl) {
34          linkEl.style.opacity = 0;
35          linkEl.style.transition = 'opacity 0.16s';
36        }
37      });
38    }
39
40    // Hover events now only toggle opacity
41    el.addEventListener('mouseenter', () => {
42      overlay.style.opacity = 1;
43      if (group.links) {
44        group.links.forEach(linkSelector => {
45          const linkEl = el.querySelector(linkSelector);
46          if (linkEl) linkEl.style.opacity = 1;
47        });
48      }
49    });
50
51    el.addEventListener('mouseleave', () => {
52      overlay.style.opacity = 0;
53      if (group.links) {
54        group.links.forEach(linkSelector => {
55          const linkEl = el.querySelector(linkSelector);
56          if (linkEl) linkEl.style.opacity = 0;
57        });
58      }
59    });
60  });
61});
62
63  /* ------------------------------------------------------------------------ */
64  /* Exit site button
65  /* ------------------------------------------------------------------------ */
66
67  const exitBtn = document.getElementById('exitButton');
68  if (exitBtn) {
69    exitBtn.addEventListener('click', () => {
70      const newTab = window.open('https://www.bbc.co.uk/scotland', '_blank', 'noopener,noreferrer');
71      if (newTab) newTab.opener = null;
72      window.location.replace('https://google.com');
73    });
74  }
75
76  /* ------------------------------------------------------------------------ */
77  /* Tooltips
78  /* ------------------------------------------------------------------------ */
79
80  class Tooltip {
81    constructor(element, options = {}) {
82      this.element = element;
83      this.options = Object.assign({
84        placement: 'top',
85        trigger: 'hover',
86        animation: true,
87        html: true,
88        delay: 0,
89        template: `<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>`
90      }, options);
91
92      this.enabled = true;
93      this._hoverState = null;
94      this._timeout = null;
95      this.tooltip = null;
96
97      this._setTitle();
98      this._initEvents();
99    }
100
101    _setTitle() {
102      if (!this.element.dataset.originalTitle) {
103        this.element.dataset.originalTitle = this.element.getAttribute('title') || '';
104        this.element.removeAttribute('title');
105      }
106    }
107
108    _initEvents() {
109      const { trigger } = this.options;
110
111      if (trigger === 'hover') {
112        this.element.addEventListener('mouseenter', () => this._enter());
113        this.element.addEventListener('mouseleave', () => this._leave());
114      } else if (trigger === 'focus') {
115        this.element.addEventListener('focus', () => this._enter());
116        this.element.addEventListener('blur', () => this._leave());
117      } else if (trigger === 'click') {
118        this.element.addEventListener('click', () => this.toggle());
119      }
120    }
121
122    _enter() {
123      clearTimeout(this._timeout);
124      if (this.options.delay && this.options.delay.show) {
125        this._hoverState = 'in';
126        this._timeout = setTimeout(() => {
127          if (this._hoverState === 'in') this.show();
128        }, this.options.delay.show);
129      } else {
130        this.show();
131      }
132    }
133
134    _leave() {
135      clearTimeout(this._timeout);
136      if (this.options.delay && this.options.delay.hide) {
137        this._hoverState = 'out';
138        this._timeout = setTimeout(() => {
139          if (this._hoverState === 'out') this.hide();
140        }, this.options.delay.hide);
141      } else {
142        this.hide();
143      }
144    }
145
146    show() {
147      if (!this.enabled || !this.element.dataset.originalTitle) return;
148
149      if (!this.tooltip) {
150        const wrapper = document.createElement('div');
151        wrapper.innerHTML = this.options.template;
152        this.tooltip = wrapper.firstElementChild;
153        this.tooltip.querySelector('.tooltip-inner')[this.options.html ? 'innerHTML' : 'innerText'] =
154          this.element.dataset.originalTitle;
155        document.body.appendChild(this.tooltip);
156      }
157
158      if (this.options.animation) this.tooltip.classList.add('fade');
159
160      const rect = this.element.getBoundingClientRect();
161      const tipRect = this.tooltip.getBoundingClientRect();
162      let top, left;
163
164      switch (this.options.placement) {
165        case 'top':
166          top = rect.top - tipRect.height;
167          left = rect.left + rect.width / 2 - tipRect.width / 2;
168          break;
169        case 'bottom':
170          top = rect.bottom;
171          left = rect.left + rect.width / 2 - tipRect.width / 2;
172          break;
173        case 'left':
174          top = rect.top + rect.height / 2 - tipRect.height / 2;
175          left = rect.left - tipRect.width;
176          break;
177        case 'right':
178          top = rect.top + rect.height / 2 - tipRect.height / 2;
179          left = rect.right;
180          break;
181      }
182
183      this.tooltip.style.top = `${top + window.scrollY}px`;
184      this.tooltip.style.left = `${left + window.scrollX}px`;
185      this.tooltip.classList.add(this.options.placement, 'in');
186    }
187
188    hide() {
189      if (this.tooltip) {
190        this.tooltip.classList.remove('in');
191        setTimeout(() => {
192          if (this.tooltip) this.tooltip.remove();
193          this.tooltip = null;
194        }, 200);
195      }
196    }
197
198    toggle() {
199      if (this.tooltip) this.hide();
200      else this.show();
201    }
202
203    enable() { this.enabled = true; }
204    disable() { this.enabled = false; }
205  }
206
207  const initTooltips = (selector, options = {}) => {
208    document.querySelectorAll(selector).forEach(el => new Tooltip(el, options));
209  };
210
211  // Initialize tooltips
212  initTooltips('.meta-category a, .meta-author a', { placement: 'top' });
213  initTooltips('.tooltips a[rel="tooltip"]');
214  initTooltips('#topbar .social-icons a', { placement: 'bottom', animation: true });
215  initTooltips('.member-social a', { placement: 'top' });
216  initTooltips('#copyright .social-icons a', { placement: 'top' });
217  initTooltips('.social-icon a', { placement: 'top' });
218  initTooltips('.videos-widget-item a', { placement: 'bottom' });
219
220  /* ------------------------------------------------------------------------ */
221  /* Desktop Navigation (Superfish)
222  /* ------------------------------------------------------------------------ */
223
224  (function ($) {
225	"use strict";
226
227    var methods = (function () {
228    
229      var c = {
230          bcClass: 'sf-breadcrumb',
231          menuClass: 'sf-js-enabled',
232          anchorClass: 'sf-with-ul',
233          menuArrowClass: 'sf-arrows'
234        },
235        ios = (function () {
236          var ios = /iPhone|iPad|iPod/i.test(navigator.userAgent);
237          if (ios) {
238            $(window).on('load', function () {
239              $('body').children().on('click', $.noop);
240            });
241          }
242          return ios;
243        })(),
244        wp7 = (function () {
245          var style = document.documentElement.style;
246          return ('behavior' in style && 'fill' in style && /iemobile/i.test(navigator.userAgent));
247        })(),
248        toggleMenuClasses = function ($menu, o) {
249          var classes = c.menuClass;
250          if (o.cssArrows) {
251            classes += ' ' + c.menuArrowClass;
252          }
253          $menu.toggleClass(classes);
254        },
255        setPathToCurrent = function ($menu, o) {
256          return $menu.find('li.' + o.pathClass).slice(0, o.pathLevels)
257            .addClass(o.hoverClass + ' ' + c.bcClass)
258              .filter(function () {
259                return ($(this).children(o.popUpSelector).hide().show().length);
260              }).removeClass(o.pathClass);
261        },
262        toggleAnchorClass = function ($li) {
263          $li.children('a').toggleClass(c.anchorClass);
264        },
265        toggleTouchAction = function ($menu) {
266          var touchAction = $menu.css('ms-touch-action');
267          touchAction = (touchAction === 'pan-y') ? 'auto' : 'pan-y';
268          $menu.css('ms-touch-action', touchAction);
269        },
270        applyHandlers = function ($menu, o) {
271          var targets = 'li:has(' + o.popUpSelector + ')';
272          if ($.fn.hoverIntent && !o.disableHI) {
273            $menu.hoverIntent(over, out, targets);
274          }
275          else {
276            $menu
277              .on('mouseenter.superfish', targets, over)
278              .on('mouseleave.superfish', targets, out);
279          }
280          var touchevent = 'MSPointerDown.superfish';
281          if (!ios) {
282            touchevent += ' touchend.superfish';
283          }
284          if (wp7) {
285            touchevent += ' mousedown.superfish';
286          }
287          $menu
288            .on('focusin.superfish', 'li', over)
289            .on('focusout.superfish', 'li', out)
290            .on(touchevent, 'a', o, touchHandler);
291        },
292        touchHandler = function (e) {
293          var $this = $(this),
294            $ul = $this.siblings(e.data.popUpSelector);
295
296          if ($ul.length > 0 && $ul.is(':hidden')) {
297            $this.one('click.superfish', false);
298            if (e.type === 'MSPointerDown') {
299              $this.trigger('focus');
300            } else {
301              $.proxy(over, $this.parent('li'))();
302            }
303          }
304        },
305        over = function () {
306          var $this = $(this),
307            o = getOptions($this);
308          clearTimeout(o.sfTimer);
309          $this.siblings().superfish('hide').end().superfish('show');
310        },
311        out = function () {
312          var $this = $(this),
313            o = getOptions($this);
314          if (ios) {
315            $.proxy(close, $this, o)();
316          }
317          else {
318            clearTimeout(o.sfTimer);
319            o.sfTimer = setTimeout($.proxy(close, $this, o), o.delay);
320          }
321        },
322        close = function (o) {
323          o.retainPath = ($.inArray(this[0], o.$path) > -1);
324          this.superfish('hide');
325
326          if (!this.parents('.' + o.hoverClass).length) {
327            o.onIdle.call(getMenu(this));
328            if (o.$path.length) {
329              $.proxy(over, o.$path)();
330            }
331          }
332        },
333        getMenu = function ($el) {
334          return $el.closest('.' + c.menuClass);
335        },
336        getOptions = function ($el) {
337          return getMenu($el).data('sf-options');
338        };
339
340      return {
341    
342        hide: function (instant) {
343          if (this.length) {
344            var $this = this,
345              o = getOptions($this);
346            if (!o) {
347              return this;
348            }
349            var not = (o.retainPath === true) ? o.$path : '',
350              $ul = $this.find('li.' + o.hoverClass).add(this).not(not).removeClass(o.hoverClass).children(o.popUpSelector),
351              speed = o.speedOut;
352
353            if (instant) {
354              $ul.show();
355              speed = 0;
356            }
357            o.retainPath = false;
358            o.onBeforeHide.call($ul);
359            $ul.stop(true, true).animate(o.animationOut, speed, function () {
360              var $this = $(this);
361              o.onHide.call($this);
362            });
363          }
364          return this;
365        },
366        show: function () {
367          var o = getOptions(this);
368          if (!o) {
369            return this;
370          }
371          var $this = this.addClass(o.hoverClass),
372            $ul = $this.children(o.popUpSelector);
373
374          o.onBeforeShow.call($ul);
375          $ul.stop(true, true).animate(o.animation, o.speed, function () {
376            o.onShow.call($ul);
377          });
378          return this;
379        },
380        destroy: function () {
381          return this.each(function () {
382            var $this = $(this),
383              o = $this.data('sf-options'),
384              $hasPopUp;
385            if (!o) {
386              return false;
387            }
388            $hasPopUp = $this.find(o.popUpSelector).parent('li');
389            clearTimeout(o.sfTimer);
390            toggleMenuClasses($this, o);
391            toggleAnchorClass($hasPopUp);
392            toggleTouchAction($this);
393          
394            $this.off('.superfish').off('.hoverIntent');
395    
396            $hasPopUp.children(o.popUpSelector).attr('style', function (i, style) {
397              return style.replace(/display[^;]+;?/g, '');
398            });
399
400            o.$path.removeClass(o.hoverClass + ' ' + c.bcClass).addClass(o.pathClass);
401            $this.find('.' + o.hoverClass).removeClass(o.hoverClass);
402            o.onDestroy.call($this);
403            $this.removeData('sf-options');
404          });
405        },
406        init: function (op) {
407          return this.each(function () {
408            var $this = $(this);
409            if ($this.data('sf-options')) {
410              return false;
411            }
412            var o = $.extend({}, $.fn.superfish.defaults, op),
413              $hasPopUp = $this.find(o.popUpSelector).parent('li');
414            o.$path = setPathToCurrent($this, o);
415
416            $this.data('sf-options', o);
417
418            toggleMenuClasses($this, o);
419            toggleAnchorClass($hasPopUp);
420            toggleTouchAction($this);
421            applyHandlers($this, o);
422
423            $hasPopUp.not('.' + c.bcClass).superfish('hide', true);
424
425            o.onInit.call(this);
426          });
427        }
428      };
429    })();
430
431    $.fn.superfish = function (method, args) {
432      if (methods[method]) {
433        return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
434      }
435      else if (typeof method === 'object' || ! method) {
436        return methods.init.apply(this, arguments);
437      }
438      else {
439        return $.error('Method ' +  method + ' does not exist on jQuery.fn.superfish');
440      }
441    };
442
443    $.fn.superfish.defaults = {
444      popUpSelector: 'ul,.sf-mega',
445      hoverClass: 'sfHover',
446      pathClass: 'overrideThisToUse',
447      pathLevels: 1,
448      delay: 600,
449      animation: {opacity: 'show'},
450      animationOut: {opacity: 'hide'},
451      speed: 'normal',
452      speedOut: 'fast',
453      cssArrows: true,
454      disableHI: false,
455      onInit: $.noop,
456      onBeforeShow: $.noop,
457      onShow: $.noop,
458      onBeforeHide: $.noop,
459      onHide: $.noop,
460      onIdle: $.noop,
461      onDestroy: $.noop
462    };
463
464    $.fn.extend({
465      hideSuperfishUl: methods.hide,
466      showSuperfishUl: methods.show
467    });
468
469  })(jQuery);
470
471  // Initialise Superfish only if the menu exists on this page
472  if (window.jQuery && jQuery.fn && jQuery.fn.superfish) {
473    const $menu = jQuery("#navigation ul.menu");
474    if ($menu.length) {
475      $menu.superfish({
476        delay: 300,
477        hoverClass: 'sfHover',
478        animation: 	 {height:'show', height:'show'},
479        animationOut: {opacity: 'hide'},
480        speed: 300,
481        speedOut: 300,
482        cssArrows: true
483      });
484    }
485  }
486
487});
488
489/* ------------------------------------------------------------------------ */
490/* EOF
491/* ------------------------------------------------------------------------ */

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.